diff options
Diffstat (limited to 'indra/llrender')
-rw-r--r-- | indra/llrender/llcubemap.cpp | 13 | ||||
-rw-r--r-- | indra/llrender/llfontbitmapcache.cpp | 4 | ||||
-rw-r--r-- | indra/llrender/llfontfreetype.cpp | 42 | ||||
-rw-r--r-- | indra/llrender/llfontfreetype.h | 5 | ||||
-rw-r--r-- | indra/llrender/llfontgl.cpp | 202 | ||||
-rw-r--r-- | indra/llrender/llfontgl.h | 11 | ||||
-rw-r--r-- | indra/llrender/llfontregistry.cpp | 7 | ||||
-rw-r--r-- | indra/llrender/llgl.cpp | 70 | ||||
-rw-r--r-- | indra/llrender/llgl.h | 1 | ||||
-rw-r--r-- | indra/llrender/llglheaders.h | 22 | ||||
-rw-r--r-- | indra/llrender/llglslshader.cpp | 2 | ||||
-rw-r--r-- | indra/llrender/llglstates.h | 2 | ||||
-rw-r--r-- | indra/llrender/llimagegl.cpp | 573 | ||||
-rw-r--r-- | indra/llrender/llimagegl.h | 91 | ||||
-rw-r--r-- | indra/llrender/llpostprocess.cpp | 2 | ||||
-rw-r--r-- | indra/llrender/llrender.cpp | 235 | ||||
-rw-r--r-- | indra/llrender/llrender.h | 32 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.cpp | 11 | ||||
-rw-r--r-- | indra/llrender/lltexture.h | 4 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 109 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.h | 7 |
21 files changed, 1100 insertions, 345 deletions
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 08a96b4e31..036714e5cb 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -63,6 +63,12 @@ LLCubeMap::LLCubeMap() mTextureCoordStage(0), mMatrixStage(0) { + mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB; + mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; + mTargets[2] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB; + mTargets[3] = GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB; + mTargets[4] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB; + mTargets[5] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB; } LLCubeMap::~LLCubeMap() @@ -75,13 +81,6 @@ void LLCubeMap::initGL() if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) { - mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB; - mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; - mTargets[2] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB; - mTargets[3] = GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB; - mTargets[4] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB; - mTargets[5] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB; - // Not initialized, do stuff. if (mImages[0].isNull()) { diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp index f01878642a..fa231c9e6a 100644 --- a/indra/llrender/llfontbitmapcache.cpp +++ b/indra/llrender/llfontbitmapcache.cpp @@ -64,7 +64,7 @@ void LLFontBitmapCache::init(S32 num_components, LLImageRaw *LLFontBitmapCache::getImageRaw(U32 bitmap_num) const { - if ((bitmap_num < 0) || (bitmap_num >= mImageRawVec.size())) + if (bitmap_num >= mImageRawVec.size()) return NULL; return mImageRawVec[bitmap_num]; @@ -72,7 +72,7 @@ LLImageRaw *LLFontBitmapCache::getImageRaw(U32 bitmap_num) const LLImageGL *LLFontBitmapCache::getImageGL(U32 bitmap_num) const { - if ((bitmap_num < 0) || (bitmap_num >= mImageGLVec.size())) + if (bitmap_num >= mImageGLVec.size()) return NULL; return mImageGLVec[bitmap_num]; diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index 786dc64452..a86bbbffff 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -91,14 +91,15 @@ LLFontManager::~LLFontManager() LLFontGlyphInfo::LLFontGlyphInfo(U32 index) : mGlyphIndex(index), + mWidth(0), // In pixels + mHeight(0), // In pixels + mXAdvance(0.f), // In pixels + mYAdvance(0.f), // In pixels mXBitmapOffset(0), // Offset to the origin in the bitmap mYBitmapOffset(0), // Offset to the origin in the bitmap mXBearing(0), // Distance from baseline to left in pixels mYBearing(0), // Distance from baseline to top in pixels - mWidth(0), // In pixels - mHeight(0), // In pixels - mXAdvance(0.f), // In pixels - mYAdvance(0.f) // In pixels + mBitmapNum(0) // Which bitmap in the bitmap cache contains this glyph { } @@ -112,6 +113,7 @@ LLFontFreetype::LLFontFreetype() mFTFace(NULL), mRenderGlyphCount(0), mAddGlyphCount(0), + mStyle(0), mPointSize(0) { } @@ -268,6 +270,14 @@ F32 LLFontFreetype::getXAdvance(llwchar wch) const return (F32)mFontBitmapCachep->getMaxCharWidth(); } +F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const +{ + if (mFTFace == NULL) + return 0.0; + + return glyph->mXAdvance; +} + F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const { if (mFTFace == NULL) @@ -287,6 +297,21 @@ F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const return delta.x*(1.f/64.f); } +F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const +{ + if (mFTFace == NULL) + return 0.0; + + U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; + U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; + + FT_Vector delta; + + llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); + + return delta.x*(1.f/64.f); +} + BOOL LLFontFreetype::hasGlyph(llwchar wch) const { llassert(!mIsFallback); @@ -502,8 +527,13 @@ void LLFontFreetype::resetBitmapCache() mCharGlyphInfoMap.clear(); mFontBitmapCachep->reset(); - // Add the empty glyph - addGlyphFromFont(this, 0, 0); + // Adding default glyph is skipped for fallback fonts here as well as in loadFace(). + // This if was added as fix for EXT-4971. + if(!mIsFallback) + { + // Add the empty glyph + addGlyphFromFont(this, 0, 0); + } } void LLFontFreetype::destroyGL() diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h index 1325b4995b..f60d09316d 100644 --- a/indra/llrender/llfontfreetype.h +++ b/indra/llrender/llfontfreetype.h @@ -58,9 +58,8 @@ private: ~LLFontManager(); }; -class LLFontGlyphInfo +struct LLFontGlyphInfo { -public: LLFontGlyphInfo(U32 index); U32 mGlyphIndex; @@ -129,7 +128,9 @@ public: }; F32 getXAdvance(llwchar wc) const; + F32 getXAdvance(const LLFontGlyphInfo* glyph) const; F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters + F32 getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const; // Get the kerning between the two characters LLFontGlyphInfo* getGlyphInfo(llwchar wch) const; diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index c9163d2890..82db922368 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -135,7 +135,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX); - // determine which style flags need to be added programmatically by striping off the + // determine which style flags need to be added programmatically by stripping off the // style bits that are drawn by the underlying Freetype font U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle(); @@ -151,14 +151,16 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons } } - gGL.pushMatrix(); - glLoadIdentity(); - gGL.translatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ); + gGL.pushUIMatrix(); + + gGL.loadUIIdentity(); + + gGL.translateUI(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ); // this code snaps the text origin to a pixel grid to start with F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX); F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY); - gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f); + gGL.translateUI(-pixel_offset_x, -pixel_offset_y, 0.f); LLFastTimer t(FTM_RENDER_FONTS); @@ -195,7 +197,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons cur_y += mFontFreetype->getDescenderHeight(); break; case VCENTER: - cur_y -= ((mFontFreetype->getAscenderHeight() - mFontFreetype->getDescenderHeight())/2.f); + cur_y -= (mFontFreetype->getAscenderHeight() - mFontFreetype->getDescenderHeight()) / 2.f; break; case BASELINE: // Baseline, do nothing. @@ -221,7 +223,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons cur_render_y = cur_y; cur_render_x = cur_x; - F32 start_x = cur_x; + F32 start_x = llround(cur_x); const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache(); @@ -235,7 +237,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons if (use_ellipses) { // check for too long of a string - if (getWidthF32(wstr.c_str(), begin_offset, max_chars) * sScaleX > scaled_max_pixels) + S32 string_width = llround(getWidthF32(wstr.c_str(), begin_offset, max_chars) * sScaleX); + if (string_width > scaled_max_pixels) { // use four dots for ellipsis width to generate padding const LLWString dots(utf8str_to_wstring(std::string("...."))); @@ -244,15 +247,18 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons } } - - // Remember last-used texture to avoid unnecesssary bind calls. - LLImageGL *last_bound_texture = NULL; + const LLFontGlyphInfo* next_glyph = NULL; for (i = begin_offset; i < begin_offset + length; i++) { llwchar wch = wstr[i]; - const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch); + const LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) + { + fgi = mFontFreetype->getGlyphInfo(wch); + } if (!fgi) { llerrs << "Missing Glyph Info" << llendl; @@ -260,12 +266,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons } // Per-glyph bitmap texture. LLImageGL *image_gl = mFontFreetype->getFontBitmapCache()->getImageGL(fgi->mBitmapNum); - if (last_bound_texture != image_gl) - { - gGL.getTexUnit(0)->bind(image_gl); - last_bound_texture = image_gl; - } - + gGL.getTexUnit(0)->bind(image_gl); + if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth)) { // Not enough room for this character. @@ -294,15 +296,16 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons if (next_char && (next_char < LAST_CHARACTER)) { // Kern this puppy. - cur_x += mFontFreetype->getXKerning(wch, next_char); + next_glyph = mFontFreetype->getGlyphInfo(next_char); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); } // Round after kerning. // Must do this to cur_x, not just to cur_render_x, otherwise you // will squish sub-pixel kerned characters too close together. // For example, "CCCCC" looks bad. - cur_x = (F32)llfloor(cur_x + 0.5f); - //cur_y = (F32)llfloor(cur_y + 0.5f); + cur_x = (F32)llround(cur_x); + //cur_y = (F32)llround(cur_y); cur_render_x = cur_x; cur_render_y = cur_y; @@ -329,10 +332,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons // recursively render ellipses at end of string // we've already reserved enough room - gGL.pushMatrix(); - //glLoadIdentity(); - //gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f); - //glScalef(sScaleX, sScaleY, 1.f); + gGL.pushUIMatrix(); renderUTF8(std::string("..."), 0, cur_x / sScaleX, (F32)y, @@ -343,10 +343,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons S32_MAX, max_pixels, right_x, FALSE); - gGL.popMatrix(); + gGL.popUIMatrix(); } - gGL.popMatrix(); + gGL.popUIMatrix(); return chars_drawn; } @@ -434,19 +434,28 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars F32 cur_x = 0; const S32 max_index = begin_offset + max_chars; + const LLFontGlyphInfo* next_glyph = NULL; + F32 width_padding = 0.f; for (S32 i = begin_offset; i < max_index && wchars[i] != 0; i++) { llwchar wch = wchars[i]; - const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch); + const LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) + { + fgi = mFontFreetype->getGlyphInfo(wch); + } - F32 advance = mFontFreetype->getXAdvance(wch); + F32 advance = mFontFreetype->getXAdvance(fgi); // for the last character we want to measure the greater of its width and xadvance values // so keep track of the difference between these values for the each character we measure // so we can fix things up at the end - width_padding = llmax(0.f, (F32)fgi->mWidth - advance); + width_padding = llmax( 0.f, // always use positive padding amount + width_padding - advance, // previous padding left over after advance of current character + (F32)(fgi->mWidth + fgi->mXBearing) - advance); // difference between width of this character and advance to next character cur_x += advance; llwchar next_char = wchars[i+1]; @@ -456,10 +465,11 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars && (next_char < LAST_CHARACTER)) { // Kern this puppy. - cur_x += mFontFreetype->getXKerning(wch, next_char); + next_glyph = mFontFreetype->getGlyphInfo(next_char); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); } // Round after kerning. - cur_x = (F32)llfloor(cur_x + 0.5f); + cur_x = (F32)llround(cur_x); } // add in extra pixels for last character's width past its xadvance @@ -469,7 +479,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars } // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels -S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, BOOL end_on_word_boundary) const +S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, EWordWrapStyle end_on_word_boundary) const { if (!wchars || !wchars[0] || max_chars == 0) { @@ -488,6 +498,9 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch // avoid S32 overflow when max_pixels == S32_MAX by staying in floating point F32 scaled_max_pixels = ceil(max_pixels * sScaleX); + F32 width_padding = 0.f; + + LLFontGlyphInfo* next_glyph = NULL; S32 i; for (i=0; (i < max_chars); i++) @@ -530,10 +543,23 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch in_word = TRUE; } } + + LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) + { + fgi = mFontFreetype->getGlyphInfo(wch); + } + + // account for glyphs that run beyond the starting point for the next glyphs + width_padding = llmax( 0.f, // always use positive padding amount + width_padding - fgi->mXAdvance, // previous padding left over after advance of current character + (F32)(fgi->mWidth + fgi->mXBearing) - fgi->mXAdvance); // difference between width of this character and advance to next character - cur_x += mFontFreetype->getXAdvance(wch); + cur_x += fgi->mXAdvance; - if (scaled_max_pixels < cur_x) + // clip if current character runs past scaled_max_pixels (using width_padding) + if (scaled_max_pixels < cur_x + width_padding) { clip = TRUE; break; @@ -542,17 +568,33 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch if (((i+1) < max_chars) && wchars[i+1]) { // Kern this puppy. - cur_x += mFontFreetype->getXKerning(wch, wchars[i+1]); + next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1]); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); } // Round after kerning. - cur_x = (F32)llfloor(cur_x + 0.5f); + cur_x = llround(cur_x); drawn_x = cur_x; } - if( clip && end_on_word_boundary && (start_of_last_word != 0) ) + if( clip ) { - i = start_of_last_word; + switch (end_on_word_boundary) + { + case ONLY_WORD_BOUNDARIES: + i = start_of_last_word; + break; + case WORD_BOUNDARY_IF_POSSIBLE: + if (start_of_last_word != 0) + { + i = start_of_last_word; + } + break; + default: + case ANYWHERE: + // do nothing + break; + } } return i; } @@ -574,14 +616,20 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ { llwchar wch = wchars[i]; - F32 char_width = mFontFreetype->getXAdvance(wch); + const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch); + + // last character uses character width, since the whole character needs to be visible + // other characters just use advance + F32 width = (i == start) + ? (F32)(fgi->mWidth + fgi->mXBearing) // use actual width for last character + : fgi->mXAdvance; // use advance for all other characters - if( scaled_max_pixels < (total_width + char_width) ) + if( scaled_max_pixels < (total_width + width) ) { break; } - total_width += char_width; + total_width += width; drawable_chars++; if( max_chars >= 0 && drawable_chars >= max_chars ) @@ -599,7 +647,17 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ total_width = llround(total_width); } - return start_pos - drawable_chars; + if (drawable_chars == 0) + { + return start_pos; // just draw last character + } + else + { + // if only 1 character is drawable, we want to return start_pos as the first character to draw + // if 2 are drawable, return start_pos and character before start_pos, etc. + return start_pos + 1 - drawable_chars; + } + } S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round) const @@ -614,9 +672,11 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 t target_x *= sScaleX; // max_chars is S32_MAX by default, so make sure we don't get overflow - const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars); + const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars - 1); F32 scaled_max_pixels = max_pixels * sScaleX; + + const LLFontGlyphInfo* next_glyph = NULL; S32 pos; for (pos = begin_offset; pos < max_index; pos++) @@ -626,7 +686,15 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 t { break; // done } - F32 char_width = mFontFreetype->getXAdvance(wch); + + const LLFontGlyphInfo* glyph = next_glyph; + next_glyph = NULL; + if(!glyph) + { + glyph = mFontFreetype->getGlyphInfo(wch); + } + + F32 char_width = mFontFreetype->getXAdvance(glyph); if (round) { @@ -652,13 +720,14 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 t if (((pos + 1) < max_index) && (wchars[(pos + 1)])) { - llwchar next_char = wchars[pos + 1]; // Kern this puppy. - cur_x += mFontFreetype->getXKerning(wch, next_char); + next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1]); + cur_x += mFontFreetype->getXKerning(glyph, next_glyph); } + // Round after kerning. - cur_x = (F32)llfloor(cur_x + 0.5f); + cur_x = llround(cur_x); } return llmin(max_chars, pos - begin_offset); @@ -749,11 +818,41 @@ U8 LLFontGL::getStyleFromString(const std::string &style) } // static +std::string LLFontGL::getStringFromStyle(U8 style) +{ + std::string style_string; + if (style & NORMAL) + { + style_string += "|NORMAL"; + } + if (style & BOLD) + { + style_string += "|BOLD"; + } + if (style & ITALIC) + { + style_string += "|ITALIC"; + } + if (style & UNDERLINE) + { + style_string += "|UNDERLINE"; + } + return style_string; +} + +// static std::string LLFontGL::nameFromFont(const LLFontGL* fontp) { return fontp->mFontDescriptor.getName(); } + +// static +std::string LLFontGL::sizeFromFont(const LLFontGL* fontp) +{ + return fontp->mFontDescriptor.getSize(); +} + // static std::string LLFontGL::nameFromHAlign(LLFontGL::HAlign align) { @@ -893,6 +992,13 @@ LLFontGL* LLFontGL::getFontByName(const std::string& name) } } +//static +LLFontGL* LLFontGL::getFontDefault() +{ + return getFontSansSerif(); // Fallback to sans serif as default font +} + + // static std::string LLFontGL::getFontPathSystem() { diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index a278d88287..dfa4cf8ce5 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -122,7 +122,13 @@ public: // The following are called often, frequently with large buffers, so do not use a string interface // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels - S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX, BOOL end_on_word_boundary = FALSE) const; + typedef enum e_word_wrap_style + { + ONLY_WORD_BOUNDARIES, + WORD_BOUNDARY_IF_POSSIBLE, + ANYWHERE + } EWordWrapStyle ; + S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX, EWordWrapStyle end_on_word_boundary = ANYWHERE) const; // Returns the index of the first complete characters from text that can be drawn in max_pixels // given that the character at start_pos should be the last character (or as close to last as possible). @@ -144,8 +150,10 @@ public: // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC" static U8 getStyleFromString(const std::string &style); + static std::string getStringFromStyle(U8 style); static std::string nameFromFont(const LLFontGL* fontp); + static std::string sizeFromFont(const LLFontGL* fontp); static std::string nameFromHAlign(LLFontGL::HAlign align); static LLFontGL::HAlign hAlignFromName(const std::string& name); @@ -165,6 +173,7 @@ public: static LLFontGL* getFont(const LLFontDescriptor& desc); // Use with legacy names like "SANSSERIF_SMALL" or "OCRA" static LLFontGL* getFontByName(const std::string& name); + static LLFontGL* getFontDefault(); // default fallback font static std::string getFontPathLocal(); static std::string getFontPathSystem(); diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index 45573cd817..e619f89e1d 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -380,7 +380,10 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) LLFontDescriptor nearest_exact_desc = *match_desc; nearest_exact_desc.setSize(norm_desc.getSize()); font_reg_map_t::iterator it = mFontMap.find(nearest_exact_desc); - if (it != mFontMap.end()) + // If we fail to find a font in the fonts directory, it->second might be NULL. + // We shouldn't construcnt a font with a NULL mFontFreetype. + // This may not be the best solution, but it at least prevents a crash. + if (it != mFontMap.end() && it->second != NULL) { llinfos << "-- matching font exists: " << nearest_exact_desc.getName() << " size " << nearest_exact_desc.getSize() << " style " << ((S32) nearest_exact_desc.getStyle()) << llendl; @@ -466,6 +469,8 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) else { fontlist.push_back(fontp->mFontFreetype); + delete fontp; + fontp = NULL; } } } diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 10315bacf1..97019d48c4 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -185,6 +185,9 @@ PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = // GL_EXT_framebuffer_blit PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT = NULL; +// GL_EXT_blend_func_separate +PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL; + // GL_ARB_draw_buffers PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB = NULL; @@ -324,6 +327,7 @@ LLGLManager::LLGLManager() : mHasCompressedTextures(FALSE), mHasFramebufferObject(FALSE), mHasFramebufferMultisample(FALSE), + mHasBlendFuncSeparate(FALSE), mHasVertexBufferObject(FALSE), mHasPBuffer(FALSE), @@ -332,6 +336,8 @@ LLGLManager::LLGLManager() : mHasFragmentShader(FALSE), mHasOcclusionQuery(FALSE), mHasPointParameters(FALSE), + mHasDrawBuffers(FALSE), + mHasTextureRectangle(FALSE), mHasAnisotropic(FALSE), mHasARBEnvCombine(FALSE), @@ -593,8 +599,6 @@ void LLGLManager::shutdownGL() // these are used to turn software blending on. They appear in the Debug/Avatar menu // presence of vertex skinning/blending or vertex programs will set these to FALSE by default. -extern LLCPUInfo gSysCPU; - void LLGLManager::initExtensions() { #if LL_MESA_HEADLESS @@ -633,6 +637,11 @@ void LLGLManager::initExtensions() #else mHasDrawBuffers = FALSE; # endif +# if GL_EXT_blend_func_separate + mHasBlendFuncSeparate = TRUE; +#else + mHasBlendFuncSeparate = FALSE; +# endif mHasMipMapGeneration = FALSE; mHasSeparateSpecularColor = FALSE; mHasAnisotropic = FALSE; @@ -659,6 +668,7 @@ void LLGLManager::initExtensions() && ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts); mHasFramebufferMultisample = mHasFramebufferObject && ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts); mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); + mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts); mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); #if !LL_DARWIN mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); @@ -673,7 +683,7 @@ void LLGLManager::initExtensions() llinfos << "initExtensions() checking shell variables to adjust features..." << llendl; // Our extension support for the Linux Client is very young with some // potential driver gotchas, so offer a semi-secret way to turn it off. - if (getenv("LL_GL_NOEXT")) /* Flawfinder: ignore */ + if (getenv("LL_GL_NOEXT")) { //mHasMultitexture = FALSE; // NEEDED! mHasARBEnvCombine = FALSE; @@ -682,6 +692,7 @@ void LLGLManager::initExtensions() mHasFramebufferObject = FALSE; mHasFramebufferMultisample = FALSE; mHasDrawBuffers = FALSE; + mHasBlendFuncSeparate = FALSE; mHasMipMapGeneration = FALSE; mHasSeparateSpecularColor = FALSE; mHasAnisotropic = FALSE; @@ -706,6 +717,7 @@ void LLGLManager::initExtensions() mHasShaderObjects = FALSE; mHasVertexShader = FALSE; mHasFragmentShader = FALSE; + mHasBlendFuncSeparate = FALSE; LL_WARNS("RenderInit") << "GL extension support forced to SIMPLE level via LL_GL_BASICEXT" << LL_ENDL; } if (getenv("LL_GL_BLACKLIST")) /* Flawfinder: ignore */ @@ -734,7 +746,8 @@ void LLGLManager::initExtensions() if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE; if (strchr(blacklist,'t')) mHasTextureRectangle = FALSE; - + if (strchr(blacklist,'u')) mHasBlendFuncSeparate = FALSE;//S + } #endif // LL_LINUX || LL_SOLARIS @@ -782,6 +795,14 @@ void LLGLManager::initExtensions() { LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_fragment_shader" << LL_ENDL; } + if (!mHasBlendFuncSeparate) + { + LL_INFOS("RenderInit") << "Couldn't initialize GL_EXT_blend_func_separate" << LL_ENDL; + } + if (!mHasDrawBuffers) + { + LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_draw_buffers" << LL_ENDL; + } // Disable certain things due to known bugs if (mIsIntel && mHasMipMapGeneration) @@ -852,6 +873,10 @@ void LLGLManager::initExtensions() { glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDrawBuffersARB"); } + if (mHasBlendFuncSeparate) + { + glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlendFuncSeparateEXT"); + } #if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS // This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements"); @@ -1921,6 +1946,16 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled) { stop_glerror(); + + checkState(); + + if (!depth_enabled) + { // always disable depth writes if depth testing is disabled + // GL spec defines this as a requirement, but some implementations allow depth writes with testing disabled + // The proper way to write to depth buffer with testing disabled is to enable testing and use a depth_func of GL_ALWAYS + write_enabled = FALSE; + } + if (depth_enabled != sDepthEnabled) { gGL.flush(); @@ -1944,6 +1979,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G LLGLDepthTest::~LLGLDepthTest() { + checkState(); if (sDepthEnabled != mPrevDepthEnabled ) { gGL.flush(); @@ -1965,6 +2001,32 @@ LLGLDepthTest::~LLGLDepthTest() } } +void LLGLDepthTest::checkState() +{ + if (gDebugGL) + { + GLint func = 0; + GLboolean mask = FALSE; + + glGetIntegerv(GL_DEPTH_FUNC, &func); + glGetBooleanv(GL_DEPTH_WRITEMASK, &mask); + + if (glIsEnabled(GL_DEPTH_TEST) != sDepthEnabled || + sWriteEnabled != mask || + sDepthFunc != func) + { + if (gDebugSession) + { + gFailLog << "Unexpected depth testing state." << std::endl; + } + else + { + LL_GL_ERRS << "Unexpected depth testing state." << LL_ENDL; + } + } + } +} + LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P) { for (U32 i = 0; i < 4; i++) diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 91421f3c95..0c2da7dd08 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -87,6 +87,7 @@ public: BOOL mHasCompressedTextures; BOOL mHasFramebufferObject; BOOL mHasFramebufferMultisample; + BOOL mHasBlendFuncSeparate; // ARB Extensions BOOL mHasVertexBufferObject; diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index f33ae7d8f0..f6d35bc766 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -216,6 +216,9 @@ extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; extern PFNGLCOLORTABLEEXTPROC glColorTableEXT; +//GL_EXT_blend_func_separate +extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; + //GL_EXT_framebuffer_object extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; @@ -249,7 +252,10 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; # include "GL/glh_extensions.h" # undef __APPLE__ -#elif LL_LINUX +#elif LL_LINUX +//---------------------------------------------------------------------------- +// LL_LINUX + //---------------------------------------------------------------------------- // Linux, MESA headers, but not necessarily assuming MESA runtime. // quotes so we get libraries/.../GL/ version @@ -285,6 +291,7 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; # define LL_LINUX_NV_GL_HEADERS 0 #endif // LL_LINUX && defined(WINGDIAPI) + #if LL_LINUX_NV_GL_HEADERS // Missing functions when using nvidia headers: extern PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; @@ -445,6 +452,9 @@ extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; +//GL_EXT_blend_func_separate +extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; + //GL_EXT_framebuffer_object extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; @@ -473,7 +483,10 @@ extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT; //GL_ARB_draw_buffers extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; + #elif LL_WINDOWS +//---------------------------------------------------------------------------- +// LL_WINDOWS // windows gl headers depend on things like APIENTRY, so include windows. #define WIN32_LEAN_AND_MEAN @@ -641,6 +654,9 @@ extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB; extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB; extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; +//GL_EXT_blend_func_separate +extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; + //GL_EXT_framebuffer_object extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; @@ -669,6 +685,7 @@ extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT; //GL_ARB_draw_buffers extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; + #elif LL_DARWIN //---------------------------------------------------------------------------- // LL_DARWIN @@ -685,6 +702,9 @@ extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; // Note that they also must not be called on 10.3.9. This should be taken care of by a runtime check for the existence of the GL extension. #include <AvailabilityMacros.h> +//GL_EXT_blend_func_separate +extern void glBlendFuncSeparateEXT(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + // GL_EXT_framebuffer_object extern GLboolean glIsRenderbufferEXT(GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; extern void glBindRenderbufferEXT(GLenum target, GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 830617063b..ca92cb6580 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -70,7 +70,7 @@ hasGamma(false), hasLighting(false), calculatesAtmospherics(false) // LLGLSL Shader implementation //=============================== LLGLSLShader::LLGLSLShader() -: mProgramObject(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT) + : mProgramObject(0), mActiveTextureChannels(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT), mUniformsDirty(FALSE) { } diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h index 4a51cac438..968a37cab0 100644 --- a/indra/llrender/llglstates.h +++ b/indra/llrender/llglstates.h @@ -46,6 +46,8 @@ public: ~LLGLDepthTest(); + void checkState(); + GLboolean mPrevDepthEnabled; GLenum mPrevDepthFunc; GLboolean mPrevWriteEnabled; diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index e5fea5b995..2ab6e327b7 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -43,7 +43,6 @@ #include "llmath.h" #include "llgl.h" #include "llrender.h" - //---------------------------------------------------------------------------- const F32 MIN_TEXTURE_LIFETIME = 10.f; @@ -60,21 +59,34 @@ std::list<U32> LLImageGL::sDeadTextureList; BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; F32 LLImageGL::sLastFrameTime = 0.f; +BOOL LLImageGL::sAllowReadBackRaw = FALSE ; LLImageGL* LLImageGL::sDefaultGLTexture = NULL ; + std::set<LLImageGL*> LLImageGL::sImageList; -#if !LL_RELEASE_FOR_DOWNLOAD +//**************************************************************************************************** +//The below for texture auditing use only +//**************************************************************************************************** //----------------------- //debug use +BOOL gAuditTexture = FALSE ; #define MAX_TEXTURE_LOG_SIZE 22 //2048 * 2048 std::vector<S32> LLImageGL::sTextureLoadedCounter(MAX_TEXTURE_LOG_SIZE + 1) ; std::vector<S32> LLImageGL::sTextureBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ; std::vector<S32> LLImageGL::sTextureCurBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ; S32 LLImageGL::sCurTexSizeBar = -1 ; S32 LLImageGL::sCurTexPickSize = -1 ; -LLPointer<LLImageGL> LLImageGL::sDefaultTexturep = NULL; +LLPointer<LLImageGL> LLImageGL::sHighlightTexturep = NULL; +S32 LLImageGL::sMaxCatagories = 1 ; + +std::vector<S32> LLImageGL::sTextureMemByCategory; +std::vector<S32> LLImageGL::sTextureMemByCategoryBound ; +std::vector<S32> LLImageGL::sTextureCurMemByCategoryBound ; //------------------------ -#endif +//**************************************************************************************************** +//End for texture auditing use only +//**************************************************************************************************** + //************************************************************************************** //below are functions for debug use //do not delete them even though they are not currently being used. @@ -144,6 +156,60 @@ void LLImageGL::checkTexSize() const //************************************************************************************** //---------------------------------------------------------------------------- +BOOL is_little_endian() +{ + S32 a = 0x12345678; + U8 *c = (U8*)(&a); + + return (*c == 0x78) ; +} +//static +void LLImageGL::initClass(S32 num_catagories) +{ + sMaxCatagories = num_catagories ; + + sTextureMemByCategory.resize(sMaxCatagories); + sTextureMemByCategoryBound.resize(sMaxCatagories) ; + sTextureCurMemByCategoryBound.resize(sMaxCatagories) ; +} + +//static +void LLImageGL::cleanupClass() +{ + sTextureMemByCategory.clear() ; + sTextureMemByCategoryBound.clear() ; + sTextureCurMemByCategoryBound.clear() ; +} + +//static +void LLImageGL::setHighlightTexture(S32 category) +{ + const S32 dim = 128; + sHighlightTexturep = new LLImageGL() ; + LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3); + U8* data = image_raw->getData(); + for (S32 i = 0; i<dim; i++) + { + for (S32 j = 0; j<dim; j++) + { + const S32 border = 2; + if (i<border || j<border || i>=(dim-border) || j>=(dim-border)) + { + *data++ = 0xff; + *data++ = 0xff; + *data++ = 0xff; + } + else + { + *data++ = 0xff; + *data++ = 0xff; + *data++ = 0x00; + } + } + } + sHighlightTexturep->createGLTexture(0, image_raw, 0, TRUE, category); + image_raw = NULL; +} //static S32 LLImageGL::dataFormatBits(S32 dataformat) @@ -211,19 +277,31 @@ void LLImageGL::updateStats(F32 current_time) sBoundTextureMemoryInBytes = sCurBoundTextureMemory; sCurBoundTextureMemory = 0; -#if !LL_RELEASE_FOR_DOWNLOAD - for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++) + if(gAuditTexture) { - sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ; - sTextureCurBoundCounter[i] = 0 ; + for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++) + { + sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ; + sTextureCurBoundCounter[i] = 0 ; + } + for(U32 i = 0 ; i < sTextureCurMemByCategoryBound.size() ; i++) + { + sTextureMemByCategoryBound[i] = sTextureCurMemByCategoryBound[i] ; + sTextureCurMemByCategoryBound[i] = 0 ; + } } -#endif } //static -S32 LLImageGL::updateBoundTexMem(const S32 delta) +S32 LLImageGL::updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category) { - LLImageGL::sCurBoundTextureMemory += delta; + if(gAuditTexture && ncomponents > 0 && category > -1) + { + sTextureCurBoundCounter[getTextureCounterIndex(mem / ncomponents)]++ ; + sTextureCurMemByCategoryBound[category] += mem ; + } + + LLImageGL::sCurBoundTextureMemory += mem ; return LLImageGL::sCurBoundTextureMemory; } @@ -237,6 +315,7 @@ void LLImageGL::destroyGL(BOOL save_state) gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE); } + sAllowReadBackRaw = true ; for (std::set<LLImageGL*>::iterator iter = sImageList.begin(); iter != sImageList.end(); iter++) { @@ -246,7 +325,7 @@ void LLImageGL::destroyGL(BOOL save_state) if (save_state && glimage->isGLTextureCreated() && glimage->mComponents) { glimage->mSaveData = new LLImageRaw; - if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) + if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it. { glimage->mSaveData = NULL ; } @@ -256,6 +335,7 @@ void LLImageGL::destroyGL(BOOL save_state) stop_glerror(); } } + sAllowReadBackRaw = false ; } //static @@ -273,7 +353,7 @@ void LLImageGL::restoreGL() { if (glimage->getComponents() && glimage->mSaveData->getComponents()) { - glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData); + glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData, 0, TRUE, glimage->getCategory()); stop_glerror(); } glimage->mSaveData = NULL; // deletes data @@ -348,45 +428,58 @@ LLImageGL::~LLImageGL() void LLImageGL::init(BOOL usemipmaps) { -#ifdef DEBUG_MISS - mMissed = FALSE; -#endif + // keep these members in the same order as declared in llimagehl.h + // so that it is obvious by visual inspection if we forgot to + // init a field. - mPickMask = NULL; - mTextureMemory = 0; - mLastBindTime = 0.f; + mTextureMemory = 0; + mLastBindTime = 0.f; - mTarget = GL_TEXTURE_2D; - mBindTarget = LLTexUnit::TT_TEXTURE; - mUseMipMaps = usemipmaps; - mHasMipMaps = false; - mAutoGenMips = FALSE; - mTexName = 0; - mIsResident = 0; + mPickMask = NULL; + mPickMaskWidth = 0; + mPickMaskHeight = 0; + mUseMipMaps = usemipmaps; + mHasExplicitFormat = FALSE; + mAutoGenMips = FALSE; + + mIsMask = FALSE; + mNeedsAlphaAndPickMask = TRUE ; + mAlphaStride = 0 ; + mAlphaOffset = 0 ; + + mGLTextureCreated = FALSE ; + mTexName = 0; + mWidth = 0; + mHeight = 0; + mCurrentDiscardLevel = -1; + + mDiscardLevelInAtlas = -1 ; + mTexelsInAtlas = 0 ; + mTexelsInGLTexture = 0 ; + + mTarget = GL_TEXTURE_2D; + mBindTarget = LLTexUnit::TT_TEXTURE; + mHasMipMaps = false; + + mIsResident = 0; + + mComponents = 0; + mMaxDiscardLevel = MAX_DISCARD_LEVEL; mTexOptionsDirty = true; mAddressMode = LLTexUnit::TAM_WRAP; mFilterOption = LLTexUnit::TFO_ANISOTROPIC; - mWidth = 0; - mHeight = 0; - mComponents = 0; - - mMaxDiscardLevel = MAX_DISCARD_LEVEL; - mCurrentDiscardLevel = -1; mFormatInternal = -1; mFormatPrimary = (LLGLenum) 0; mFormatType = GL_UNSIGNED_BYTE; mFormatSwapBytes = FALSE; - mHasExplicitFormat = FALSE; - mGLTextureCreated = FALSE ; - mIsMask = FALSE; - mNeedsAlphaAndPickMask = TRUE ; +#ifdef DEBUG_MISS + mMissed = FALSE; +#endif - mDiscardLevelInAtlas = -1 ; - mTexelsInAtlas = 0 ; - mTexelsInGLTexture = 0 ; + mCategory = -1; } void LLImageGL::cleanup() @@ -436,7 +529,12 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents) // llwarns << "Setting Size of LLImageGL with existing mTexName = " << mTexName << llendl; destroyGLTexture(); } - + + // pickmask validity depends on old image size, delete it + delete [] mPickMask; + mPickMask = NULL; + mPickMaskWidth = mPickMaskHeight = 0; + mWidth = width; mHeight = height; mComponents = ncomponents; @@ -486,6 +584,10 @@ void LLImageGL::dump() } //---------------------------------------------------------------------------- +void LLImageGL::forceUpdateBindStats(void) const +{ + mLastBindTime = sLastFrameTime; +} BOOL LLImageGL::updateBindStats(S32 tex_mem) const { @@ -499,7 +601,7 @@ BOOL LLImageGL::updateBindStats(S32 tex_mem) const { // we haven't accounted for this texture yet this frame sUniqueCount++; - updateBoundTexMem(tex_mem); + updateBoundTexMem(tex_mem, mComponents, mCategory); mLastBindTime = sLastFrameTime; return TRUE ; @@ -525,6 +627,8 @@ void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_for else mFormatType = type_format; mFormatSwapBytes = swap_bytes; + + calcAlphaChannelOffsetAndStride() ; } //---------------------------------------------------------------------------- @@ -540,7 +644,6 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { - llpushcallstacks ; bool is_compressed = false; if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) { @@ -749,7 +852,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } stop_glerror(); mGLTextureCreated = true; - llpushcallstacks ; } BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image) @@ -840,7 +942,6 @@ void LLImageGL::postAddToAtlas() BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update) { - llpushcallstacks ; if (!width || !height) { return TRUE; @@ -930,7 +1031,6 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 stop_glerror(); mGLTextureCreated = true; } - llpushcallstacks ; return TRUE; } @@ -942,8 +1042,9 @@ BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S3 // Copy sub image from frame buffer BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height) { - if (gGL.getTexUnit(0)->bind(this)) + if (gGL.getTexUnit(0)->bind(this, false, true)) { + //checkTexSize() ; glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height); mGLTextureCreated = true; stop_glerror(); @@ -1007,7 +1108,7 @@ BOOL LLImageGL::createGLTexture() return TRUE ; } -BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/) +BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category) { if (gGLManager.mIsDisabled) { @@ -1027,8 +1128,10 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); // Actual image width/height = raw image width/height * 2^discard_level - S32 w = imageraw->getWidth() << discard_level; - S32 h = imageraw->getHeight() << discard_level; + S32 raw_w = imageraw->getWidth() ; + S32 raw_h = imageraw->getHeight() ; + S32 w = raw_w << discard_level; + S32 h = raw_h << discard_level; // setSize may call destroyGLTexture if the size does not match setSize(w, h, imageraw->getComponents()); @@ -1062,15 +1165,25 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S default: llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl; } + + calcAlphaChannelOffsetAndStride() ; + } + + if(!to_create) //not create a gl texture + { + destroyGLTexture(); + mCurrentDiscardLevel = discard_level; + mLastBindTime = sLastFrameTime; + return TRUE ; } + setCategory(category) ; const U8* rawdata = imageraw->getData(); return createGLTexture(discard_level, rawdata, FALSE, usename); } BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) { - llpushcallstacks ; llassert(data_in); if (discard_level < 0) @@ -1137,11 +1250,14 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ if (old_name != 0) { sGlobalTextureMemoryInBytes -= mTextureMemory; -#if !LL_RELEASE_FOR_DOWNLOAD - decTextureCounter(mTextureMemory / mComponents) ; -#endif + + if(gAuditTexture) + { + decTextureCounter(mTextureMemory, mComponents, mCategory) ; + } LLImageGL::deleteTextures(1, &old_name); + stop_glerror(); } @@ -1149,82 +1265,20 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ sGlobalTextureMemoryInBytes += mTextureMemory; mTexelsInGLTexture = getWidth() * getHeight() ; -#if !LL_RELEASE_FOR_DOWNLOAD - incTextureCounter(mTextureMemory / mComponents) ; -#endif - + if(gAuditTexture) + { + incTextureCounter(mTextureMemory, mComponents, mCategory) ; + } // mark this as bound at this point, so we don't throw it out immediately mLastBindTime = sLastFrameTime; - - llpushcallstacks ; return TRUE; } -BOOL LLImageGL::setDiscardLevel(S32 discard_level) -{ - llassert(discard_level >= 0); - llassert(mCurrentDiscardLevel >= 0); - - discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); - - if (discard_level == mCurrentDiscardLevel) - { - // nothing to do - return FALSE; - } - else if (discard_level < mCurrentDiscardLevel) - { - // larger image - dump(); - llerrs << "LLImageGL::setDiscardLevel() called with larger discard level; use createGLTexture()" << llendl; - return FALSE; - } - else if (mUseMipMaps) - { - LLPointer<LLImageRaw> imageraw = new LLImageRaw; - while(discard_level > mCurrentDiscardLevel) - { - if (readBackRaw(discard_level, imageraw, false)) - { - break; - } - discard_level--; - } - if (discard_level == mCurrentDiscardLevel) - { - // unable to increase the discard level - return FALSE; - } - return createGLTexture(discard_level, imageraw); - } - else - { -#if !LL_LINUX && !LL_SOLARIS - // *FIX: This should not be skipped for the linux client. - llerrs << "LLImageGL::setDiscardLevel() called on image without mipmaps" << llendl; -#endif - return FALSE; - } -} - -BOOL LLImageGL::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) -{ - assert_glerror(); - S32 gl_discard = discard_level - mCurrentDiscardLevel; - LLGLint glwidth = 0; - glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth); - LLGLint glheight = 0; - glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_HEIGHT, (GLint*)&glheight); - LLGLint glcomponents = 0 ; - glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&glcomponents); - assert_glerror(); - - return glwidth >= image_width && glheight >= image_height && (GL_RGB8 == glcomponents || GL_RGBA8 == glcomponents) ; -} - BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const { - llpushcallstacks ; + llassert_always(sAllowReadBackRaw) ; + //llerrs << "should not call this function!" << llendl ; + if (discard_level < 0) { discard_level = mCurrentDiscardLevel; @@ -1327,7 +1381,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre return FALSE ; } //----------------------------------------------------------------------------------------------- - llpushcallstacks ; + return TRUE ; } @@ -1345,25 +1399,26 @@ void LLImageGL::deleteDeadTextures() stop_glerror(); } } - + glDeleteTextures(1, &tex); stop_glerror(); } } - + void LLImageGL::destroyGLTexture() { if (mTexName != 0) { if(mTextureMemory) { -#if !LL_RELEASE_FOR_DOWNLOAD - decTextureCounter(mTextureMemory / mComponents) ; -#endif + if(gAuditTexture) + { + decTextureCounter(mTextureMemory, mComponents, mCategory) ; + } sGlobalTextureMemoryInBytes -= mTextureMemory; mTextureMemory = 0; } - + LLImageGL::deleteTextures(1, &mTexName); mTexName = 0; mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. @@ -1479,6 +1534,11 @@ S32 LLImageGL::getMipBytes(S32 discard_level) const return res; } +BOOL LLImageGL::isJustBound() const +{ + return (BOOL)(sLastFrameTime - mLastBindTime < 0.5f); +} + BOOL LLImageGL::getBoundRecently() const { return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME); @@ -1490,61 +1550,161 @@ void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType b mBindTarget = bind_target; } -void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h) +const S8 INVALID_OFFSET = -99 ; +void LLImageGL::setNeedsAlphaAndPickMask(BOOL need_mask) { - if(!mNeedsAlphaAndPickMask) + if(mNeedsAlphaAndPickMask != need_mask) { - return ; + mNeedsAlphaAndPickMask = need_mask; + + if(mNeedsAlphaAndPickMask) + { + mAlphaOffset = 0 ; + } + else //do not need alpha mask + { + mAlphaOffset = INVALID_OFFSET ; + mIsMask = FALSE; + } } +} - if (mFormatType != GL_UNSIGNED_BYTE) +void LLImageGL::calcAlphaChannelOffsetAndStride() +{ + if(mAlphaOffset == INVALID_OFFSET)//do not need alpha mask { - llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl; + return ; } - U32 stride = 0; + mAlphaStride = -1 ; switch (mFormatPrimary) { case GL_LUMINANCE: case GL_ALPHA: - stride = 1; + mAlphaStride = 1; break; case GL_LUMINANCE_ALPHA: - stride = 2; + mAlphaStride = 2; break; case GL_RGB: - //no alpha + mNeedsAlphaAndPickMask = FALSE ; mIsMask = FALSE; - return; + return ; //no alpha channel. case GL_RGBA: - stride = 4; + mAlphaStride = 4; break; case GL_BGRA_EXT: - stride = 4; + mAlphaStride = 4; break; default: - return; + break; + } + + mAlphaOffset = -1 ; + if (mFormatType == GL_UNSIGNED_BYTE) + { + mAlphaOffset = mAlphaStride - 1 ; + } + else if(is_little_endian()) + { + if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) + { + mAlphaOffset = 0 ; + } + else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) + { + mAlphaOffset = 3 ; + } + } + else //big endian + { + if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) + { + mAlphaOffset = 3 ; + } + else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) + { + mAlphaOffset = 0 ; + } + } + + if( mAlphaStride < 1 || //unsupported format + mAlphaOffset < 0 || //unsupported type + (mFormatPrimary == GL_BGRA_EXT && mFormatType != GL_UNSIGNED_BYTE)) //unknown situation + { + llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl; + + mNeedsAlphaAndPickMask = FALSE ; + mIsMask = FALSE; + } +} + +void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) +{ + if(!mNeedsAlphaAndPickMask) + { + return ; } U32 length = w * h; - const GLubyte* current = ((const GLubyte*) data_in)+stride-1; - S32 sample[16]; - memset(sample, 0, sizeof(S32)*16); - - for (U32 i = 0; i < length; i++) + U32 sample[16]; + memset(sample, 0, sizeof(U32)*16); + + // generate histogram of quantized alpha. + // also add-in the histogram of a 2x2 box-sampled version. The idea is + // this will mid-skew the data (and thus increase the chances of not + // being used as a mask) from high-frequency alpha maps which + // suffer the worst from aliasing when used as alpha masks. + if (w >= 2 && h >= 2) + { + llassert(w%2 == 0); + llassert(h%2 == 0); + const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset; + for (U32 y = 0; y < h; y+=2) + { + const GLubyte* current = rowstart; + for (U32 x = 0; x < w; x+=2) + { + U32 s1 = current[0]; + U32 s2 = current[w * mAlphaStride]; + current += mAlphaStride; + U32 s3 = current[0]; + U32 s4 = current[w * mAlphaStride]; + current += mAlphaStride; + + ++sample[s1/16]; + ++sample[s2/16]; + ++sample[s3/16]; + ++sample[s4/16]; + + sample[(s1+s2+s3+s4)/(16 * 4)] += 4; + } + + rowstart += 2 * w * mAlphaStride; + } + length += length; + } + else { - ++sample[*current/16]; - current += stride; + const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset; + for (U32 i = 0; i < length; i++) + { + ++sample[*current/16]; + current += mAlphaStride; + } } + + // if more than 1/16th of alpha samples are mid-range, this + // shouldn't be treated as a 1-bit mask - U32 total = 0; + U32 midrangetotal = 0; for (U32 i = 4; i < 11; i++) { - total += sample[i]; + midrangetotal += sample[i]; } - if (total > length/16) + if (midrangetotal > length/16) { mIsMask = FALSE; } @@ -1562,24 +1722,25 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) return ; } + delete [] mPickMask; + mPickMask = NULL; + mPickMaskWidth = mPickMaskHeight = 0; + if (mFormatType != GL_UNSIGNED_BYTE || - mFormatPrimary != GL_RGBA) + mFormatPrimary != GL_RGBA) { //cannot generate a pick mask for this texture - delete [] mPickMask; - mPickMask = NULL; return; } - U32 pick_width = width/2; - U32 pick_height = height/2; - - U32 size = llmax(pick_width, (U32) 1) * llmax(pick_height, (U32) 1); + U32 pick_width = width/2 + 1; + U32 pick_height = height/2 + 1; - size = size/8 + 1; - - delete[] mPickMask; + U32 size = pick_width * pick_height; + size = (size + 7) / 8; // pixelcount-to-bits mPickMask = new U8[size]; + mPickMaskWidth = pick_width - 1; + mPickMaskHeight = pick_height - 1; memset(mPickMask, 0, sizeof(U8) * size); @@ -1595,10 +1756,7 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { U32 pick_idx = pick_bit/8; U32 pick_offset = pick_bit%8; - if (pick_idx >= size) - { - llerrs << "WTF?" << llendl; - } + llassert(pick_idx < size); mPickMask[pick_idx] |= 1 << pick_offset; } @@ -1614,22 +1772,32 @@ BOOL LLImageGL::getMask(const LLVector2 &tc) if (mPickMask) { - S32 width = getWidth()/2; - S32 height = getHeight()/2; - F32 u = tc.mV[0] - floorf(tc.mV[0]); F32 v = tc.mV[1] - floorf(tc.mV[1]); - if (u < 0.f || u > 1.f || - v < 0.f || v > 1.f) + if (LL_UNLIKELY(u < 0.f || u > 1.f || + v < 0.f || v > 1.f)) { - llerrs << "WTF?" << llendl; + LL_WARNS_ONCE("render") << "Ugh, u/v out of range in image mask pick" << LL_ENDL; + u = v = 0.f; + llassert(false); } - - S32 x = (S32)(u * width); - S32 y = (S32)(v * height); - S32 idx = y*width+x; + S32 x = llfloor(u * mPickMaskWidth); + S32 y = llfloor(v * mPickMaskHeight); + + if (LL_UNLIKELY(x > mPickMaskWidth)) + { + LL_WARNS_ONCE("render") << "Ooh, width overrun on pick mask read, that coulda been bad." << LL_ENDL; + x = llmax((U16)0, mPickMaskWidth); + } + if (LL_UNLIKELY(y > mPickMaskHeight)) + { + LL_WARNS_ONCE("render") << "Ooh, height overrun on pick mask read, that woulda been bad." << LL_ENDL; + y = llmax((U16)0, mPickMaskHeight); + } + + S32 idx = y*mPickMaskWidth+x; S32 offset = idx%8; res = mPickMask[idx/8] & (1 << offset) ? TRUE : FALSE; @@ -1638,8 +1806,30 @@ BOOL LLImageGL::getMask(const LLVector2 &tc) return res; } -//---------------------------------------------------------------------------- -#if !LL_RELEASE_FOR_DOWNLOAD +void LLImageGL::setCategory(S32 category) +{ + if(!gAuditTexture) + { + return ; + } + if(mCategory != category) + { + if(mCategory > -1) + { + sTextureMemByCategory[mCategory] -= mTextureMemory ; + } + if(category > -1 && category < sMaxCatagories) + { + sTextureMemByCategory[category] += mTextureMemory ; + mCategory = category; + } + else + { + mCategory = -1 ; + } + } +} + //for debug use //val is a "power of two" number S32 LLImageGL::getTextureCounterIndex(U32 val) @@ -1663,18 +1853,33 @@ S32 LLImageGL::getTextureCounterIndex(U32 val) return ret ; } } -void LLImageGL::incTextureCounter(U32 val) + +//static +void LLImageGL::incTextureCounter(U32 val, S32 ncomponents, S32 category) { sTextureLoadedCounter[getTextureCounterIndex(val)]++ ; + sTextureMemByCategory[category] += (S32)val * ncomponents ; } -void LLImageGL::decTextureCounter(U32 val) + +//static +void LLImageGL::decTextureCounter(U32 val, S32 ncomponents, S32 category) { sTextureLoadedCounter[getTextureCounterIndex(val)]-- ; + sTextureMemByCategory[category] += (S32)val * ncomponents ; } -void LLImageGL::setCurTexSizebar(S32 index) + +void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size) { sCurTexSizeBar = index ; - sCurTexPickSize = (1 << index) ; + + if(set_pick_size) + { + sCurTexPickSize = (1 << index) ; + } + else + { + sCurTexPickSize = -1 ; + } } void LLImageGL::resetCurTexSizebar() { @@ -1682,7 +1887,9 @@ void LLImageGL::resetCurTexSizebar() sCurTexPickSize = -1 ; } //---------------------------------------------------------------------------- -#endif + +//---------------------------------------------------------------------------- + // Manual Mip Generation /* diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index a094605607..1b303307f6 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -47,7 +47,6 @@ class LLTextureAtlas ; #define MEGA_BYTES_TO_BYTES(x) ((x) << 20) //============================================================================ - class LLImageGL : public LLRefCount { friend class LLTexUnit; @@ -63,6 +62,7 @@ public: BOOL updateBindStats(S32 tex_mem) const ; F32 getTimePassedSinceLastBound(); + void forceUpdateBindStats(void) const; // needs to be called every frame static void updateStats(F32 current_time); @@ -71,8 +71,9 @@ public: static void destroyGL(BOOL save_state = TRUE); static void restoreGL(); - // Sometimes called externally for textures not using LLImageGL (should go away...) - static S32 updateBoundTexMem(const S32 delta); + // Sometimes called externally for textures not using LLImageGL (should go away...) + static S32 updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category) ; + static bool checkSize(S32 width, S32 height); //for server side use only. @@ -90,7 +91,8 @@ public: protected: virtual ~LLImageGL(); - void analyzeAlpha(const void* data_in, S32 w, S32 h); + void analyzeAlpha(const void* data_in, U32 w, U32 h); + void calcAlphaChannelOffsetAndStride(); public: virtual void dump(); // debugging info to llinfos @@ -105,14 +107,15 @@ public: static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels); BOOL createGLTexture() ; - BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0); + BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, + S32 category = sMaxCatagories - 1); BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0); void setImage(const LLImageRaw* imageraw); void setImage(const U8* data_in, BOOL data_hasmips = FALSE); BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); - BOOL setDiscardLevel(S32 discard_level); + // Read back a raw image for this discard level, if it exists BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const; void destroyGLTexture(); @@ -131,6 +134,7 @@ public: S32 getBytes(S32 discard_level = -1) const; S32 getMipBytes(S32 discard_level = -1) const; BOOL getBoundRecently() const; + BOOL isJustBound() const; LLGLenum getPrimaryFormat() const { return mFormatPrimary; } LLGLenum getFormatType() const { return mFormatType; } @@ -150,8 +154,6 @@ public: BOOL getUseMipMaps() const { return mUseMipMaps; } void setUseMipMaps(BOOL usemips) { mUseMipMaps = usemips; } - BOOL isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) ; - void updatePickMask(S32 width, S32 height, const U8* data_in); BOOL getMask(const LLVector2 &tc); @@ -178,7 +180,7 @@ public: void init(BOOL usemipmaps); virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors - void setNeedsAlphaAndPickMask(BOOL need_mask) {mNeedsAlphaAndPickMask = need_mask;} + void setNeedsAlphaAndPickMask(BOOL need_mask); BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image); void postAddToAtlas() ; @@ -187,23 +189,27 @@ public: // Various GL/Rendering options S32 mTextureMemory; mutable F32 mLastBindTime; // last time this was bound, by discard level - + private: LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel + U16 mPickMaskWidth; + U16 mPickMaskHeight; S8 mUseMipMaps; S8 mHasExplicitFormat; // If false (default), GL format is f(mComponents) S8 mAutoGenMips; BOOL mIsMask; BOOL mNeedsAlphaAndPickMask; - + S8 mAlphaStride ; + S8 mAlphaOffset ; + bool mGLTextureCreated ; LLGLuint mTexName; U16 mWidth; U16 mHeight; S8 mCurrentDiscardLevel; - + S8 mDiscardLevelInAtlas; U32 mTexelsInAtlas ; U32 mTexelsInGLTexture; @@ -220,7 +226,7 @@ protected: bool mTexOptionsDirty; LLTexUnit::eTextureAddressMode mAddressMode; // Defaults to TAM_WRAP - LLTexUnit::eTextureFilterOptions mFilterOption; // Defaults to TFO_TRILINEAR + LLTexUnit::eTextureFilterOptions mFilterOption; // Defaults to TFO_ANISOTROPIC LLGLint mFormatInternal; // = GL internalformat LLGLenum mFormatPrimary; // = GL format (pixel data format) @@ -233,7 +239,7 @@ public: static S32 sCount; static F32 sLastFrameTime; - + static LLGLuint sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS]; // Currently bound texture ID // Global memory statistics @@ -246,30 +252,61 @@ public: static LLImageGL* sDefaultGLTexture ; static BOOL sAutomatedTest; -#if !LL_RELEASE_FOR_DOWNLOAD +#if DEBUG_MISS + BOOL mMissed; // Missed on last bind? + BOOL getMissed() const { return mMissed; }; +#else + BOOL getMissed() const { return FALSE; }; +#endif + +public: + static void initClass(S32 num_catagories) ; + static void cleanupClass() ; +private: + static S32 sMaxCatagories ; + + //the flag to allow to call readBackRaw(...). + //can be removed if we do not use that function at all. + static BOOL sAllowReadBackRaw ; +// +//**************************************************************************************************** +//The below for texture auditing use only +//**************************************************************************************************** +private: + S32 mCategory ; +public: + void setCategory(S32 category) ; + S32 getCategory()const {return mCategory ;} + //for debug use: show texture size distribution //---------------------------------------- - static LLPointer<LLImageGL> sDefaultTexturep; //default texture to replace normal textures + static LLPointer<LLImageGL> sHighlightTexturep; //default texture to replace normal textures static std::vector<S32> sTextureLoadedCounter ; static std::vector<S32> sTextureBoundCounter ; static std::vector<S32> sTextureCurBoundCounter ; static S32 sCurTexSizeBar ; static S32 sCurTexPickSize ; - + + static void setHighlightTexture(S32 category) ; static S32 getTextureCounterIndex(U32 val) ; - static void incTextureCounter(U32 val) ; - static void decTextureCounter(U32 val) ; - static void setCurTexSizebar(S32 index) ; + static void incTextureCounter(U32 val, S32 ncomponents, S32 category) ; + static void decTextureCounter(U32 val, S32 ncomponents, S32 category) ; + static void setCurTexSizebar(S32 index, BOOL set_pick_size = TRUE) ; static void resetCurTexSizebar(); //---------------------------------------- -#endif -#if DEBUG_MISS - BOOL mMissed; // Missed on last bind? - BOOL getMissed() const { return mMissed; }; -#else - BOOL getMissed() const { return FALSE; }; -#endif + //for debug use: show texture category distribution + //---------------------------------------- + + static std::vector<S32> sTextureMemByCategory; + static std::vector<S32> sTextureMemByCategoryBound ; + static std::vector<S32> sTextureCurMemByCategoryBound ; + //---------------------------------------- +//**************************************************************************************************** +//End of definitions for texture auditing use only +//**************************************************************************************************** + }; +extern BOOL gAuditTexture; #endif // LL_LLIMAGEGL_H diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp index 7f4be6a866..bc7f30cdef 100644 --- a/indra/llrender/llpostprocess.cpp +++ b/indra/llrender/llpostprocess.cpp @@ -59,6 +59,8 @@ LLPostProcess::LLPostProcess(void) : mSceneRenderTexture = NULL ; mNoiseTexture = NULL ; mTempBloomTexture = NULL ; + + noiseTextureScale = 1.0f; /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender. std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index b74d824c9e..43662fbb5c 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -49,6 +49,9 @@ F64 gGLLastProjection[16]; F64 gGLProjection[16]; S32 gGLViewport[4]; +U32 LLRender::sUICalls = 0; +U32 LLRender::sUIVerts = 0; + static const U32 LL_NUM_TEXTURE_LAYERS = 16; static GLenum sGLTextureType[] = @@ -90,7 +93,9 @@ static GLenum sGLBlendFactor[] = GL_DST_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, - GL_ONE_MINUS_SRC_ALPHA + GL_ONE_MINUS_SRC_ALPHA, + + GL_ZERO // 'BF_UNDEF' }; LLTexUnit::LLTexUnit(S32 index) @@ -116,6 +121,8 @@ void LLTexUnit::refreshState(void) // We set dirty to true so that the tex unit knows to ignore caching // and we reset the cached tex unit state + gGL.flush(); + glActiveTextureARB(GL_TEXTURE0_ARB + mIndex); if (mCurrTexType != TT_NONE) { @@ -145,6 +152,7 @@ void LLTexUnit::activate(void) if ((S32)gGL.mCurrTextureUnitIndex != mIndex || gGL.mDirty) { + gGL.flush(); glActiveTextureARB(GL_TEXTURE0_ARB + mIndex); gGL.mCurrTextureUnitIndex = mIndex; } @@ -162,6 +170,8 @@ void LLTexUnit::enable(eTextureType type) disable(); // Force a disable of a previous texture type if it's enabled. } mCurrTexType = type; + + gGL.flush(); glEnable(sGLTextureType[type]); } } @@ -174,12 +184,13 @@ void LLTexUnit::disable(void) { activate(); unbind(mCurrTexType); + gGL.flush(); glDisable(sGLTextureType[mCurrTexType]); mCurrTexType = TT_NONE; } } -bool LLTexUnit::bind(LLTexture* texture, bool forceBind) +bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) { stop_glerror(); if (mIndex < 0) return false; @@ -198,9 +209,19 @@ bool LLTexUnit::bind(LLTexture* texture, bool forceBind) //if deleted, will re-generate it immediately texture->forceImmediateUpdate() ; + gl_tex->forceUpdateBindStats() ; return texture->bindDefaultImage(mIndex); } + //in audit, replace the selected texture by the default one. + if(gAuditTexture && for_rendering && LLImageGL::sCurTexPickSize > 0) + { + if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize) + { + gl_tex->updateBindStats(gl_tex->mTextureMemory); + return bind(LLImageGL::sHighlightTexturep.get()); + } + } if ((mCurrTexture != gl_tex->getTexName()) || forceBind) { activate(); @@ -223,7 +244,7 @@ bool LLTexUnit::bind(LLTexture* texture, bool forceBind) return true; } -bool LLTexUnit::bind(LLImageGL* texture, bool forceBind) +bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) { stop_glerror(); if (mIndex < 0) return false; @@ -243,10 +264,9 @@ bool LLTexUnit::bind(LLImageGL* texture, bool forceBind) return false ; } - gGL.flush(); - if ((mCurrTexture != texture->getTexName()) || forceBind) { + gGL.flush(); activate(); enable(texture->getTarget()); mCurrTexture = texture->getTexName(); @@ -260,6 +280,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool forceBind) setTextureFilteringOption(texture->mFilterOption); } } + return true; } @@ -369,6 +390,8 @@ void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode) { if (mIndex < 0 || mCurrTexture == 0) return; + gGL.flush(); + activate(); glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]); @@ -383,6 +406,8 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio { if (mIndex < 0 || mCurrTexture == 0) return; + gGL.flush(); + if (option == TFO_POINT) { glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -432,6 +457,8 @@ void LLTexUnit::setTextureBlendType(eTextureBlendType type) return; } + gGL.flush(); + activate(); mCurrBlendType = type; S32 scale_amount = 1; @@ -548,6 +575,7 @@ void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eT if (mCurrBlendType != TB_COMBINE || gGL.mDirty) { mCurrBlendType = TB_COMBINE; + gGL.flush(); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); } @@ -558,6 +586,8 @@ void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eT return; } + gGL.flush(); + // Get the gl source enums according to the eTextureBlendSrc sources passed in GLint source1 = getTextureSource(src1); GLint source2 = getTextureSource(src2); @@ -690,6 +720,7 @@ void LLTexUnit::setColorScale(S32 scale) if (mCurrColorScale != scale || gGL.mDirty) { mCurrColorScale = scale; + gGL.flush(); glTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE, scale ); } } @@ -699,6 +730,7 @@ void LLTexUnit::setAlphaScale(S32 scale) if (mCurrAlphaScale != scale || gGL.mDirty) { mCurrAlphaScale = scale; + gGL.flush(); glTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale ); } } @@ -720,8 +752,11 @@ void LLTexUnit::debugTextureUnit(void) LLRender::LLRender() -: mDirty(false), mCount(0), mMode(LLRender::TRIANGLES), - mMaxAnisotropy(0.f) + : mDirty(false), + mCount(0), + mMode(LLRender::TRIANGLES), + mCurrTextureUnitIndex(0), + mMaxAnisotropy(0.f) { mBuffer = new LLVertexBuffer(immediate_mask, 0); mBuffer->allocateBuffer(4096, 0, TRUE); @@ -743,6 +778,11 @@ LLRender::LLRender() mCurrAlphaFunc = CF_DEFAULT; mCurrAlphaFuncVal = 0.01f; + + mCurrBlendColorSFactor = BF_UNDEF; + mCurrBlendAlphaSFactor = BF_UNDEF; + mCurrBlendColorDFactor = BF_UNDEF; + mCurrBlendAlphaDFactor = BF_UNDEF; } LLRender::~LLRender() @@ -805,6 +845,88 @@ void LLRender::popMatrix() glPopMatrix(); } +void LLRender::translateUI(F32 x, F32 y, F32 z) +{ + if (mUIOffset.empty()) + { + llerrs << "Need to push a UI translation frame before offsetting" << llendl; + } + + mUIOffset.front().mV[0] += x; + mUIOffset.front().mV[1] += y; + mUIOffset.front().mV[2] += z; +} + +void LLRender::scaleUI(F32 x, F32 y, F32 z) +{ + if (mUIScale.empty()) + { + llerrs << "Need to push a UI transformation frame before scaling." << llendl; + } + + mUIScale.front().scaleVec(LLVector3(x,y,z)); +} + +void LLRender::pushUIMatrix() +{ + if (mUIOffset.empty()) + { + mUIOffset.push_front(LLVector3(0,0,0)); + } + else + { + mUIOffset.push_front(mUIOffset.front()); + } + + if (mUIScale.empty()) + { + mUIScale.push_front(LLVector3(1,1,1)); + } + else + { + mUIScale.push_front(mUIScale.front()); + } +} + +void LLRender::popUIMatrix() +{ + if (mUIOffset.empty()) + { + llerrs << "UI offset stack blown." << llendl; + } + mUIOffset.pop_front(); + mUIScale.pop_front(); +} + +LLVector3 LLRender::getUITranslation() +{ + if (mUIOffset.empty()) + { + llerrs << "UI offset stack empty." << llendl; + } + return mUIOffset.front(); +} + +LLVector3 LLRender::getUIScale() +{ + if (mUIScale.empty()) + { + llerrs << "UI scale stack empty." << llendl; + } + return mUIScale.front(); +} + + +void LLRender::loadUIIdentity() +{ + if (mUIOffset.empty()) + { + llerrs << "Need to push UI translation frame before clearing offset." << llendl; + } + mUIOffset.front().setVec(0,0,0); + mUIScale.front().setVec(1,1,1); +} + void LLRender::setColorMask(bool writeColor, bool writeAlpha) { setColorMask(writeColor, writeColor, writeColor, writeAlpha); @@ -827,29 +949,28 @@ void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB void LLRender::setSceneBlendType(eBlendType type) { - flush(); switch (type) { case BT_ALPHA: - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + blendFunc(BF_SOURCE_ALPHA, BF_ONE_MINUS_SOURCE_ALPHA); break; case BT_ADD: - glBlendFunc(GL_ONE, GL_ONE); + blendFunc(BF_ONE, BF_ONE); break; case BT_ADD_WITH_ALPHA: - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + blendFunc(BF_SOURCE_ALPHA, BF_ONE); break; case BT_MULT: - glBlendFunc(GL_DST_COLOR, GL_ZERO); + blendFunc(BF_DEST_COLOR, BF_ZERO); break; case BT_MULT_ALPHA: - glBlendFunc(GL_DST_ALPHA, GL_ZERO); + blendFunc(BF_DEST_ALPHA, BF_ZERO); break; case BT_MULT_X2: - glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + blendFunc(BF_DEST_COLOR, BF_SOURCE_COLOR); break; case BT_REPLACE: - glBlendFunc(GL_ONE, GL_ZERO); + blendFunc(BF_ONE, BF_ZERO); break; default: llerrs << "Unknown Scene Blend Type: " << type << llendl; @@ -875,8 +996,44 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value) void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor) { - flush(); - glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]); + llassert(sfactor < BF_UNDEF); + llassert(dfactor < BF_UNDEF); + if (mCurrBlendColorSFactor != sfactor || mCurrBlendColorDFactor != dfactor || + mCurrBlendAlphaSFactor != sfactor || mCurrBlendAlphaDFactor != dfactor) + { + mCurrBlendColorSFactor = sfactor; + mCurrBlendAlphaSFactor = sfactor; + mCurrBlendColorDFactor = dfactor; + mCurrBlendAlphaDFactor = dfactor; + flush(); + glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]); + } +} + +void LLRender::blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor, + eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor) +{ + llassert(color_sfactor < BF_UNDEF); + llassert(color_dfactor < BF_UNDEF); + llassert(alpha_sfactor < BF_UNDEF); + llassert(alpha_dfactor < BF_UNDEF); + if (!gGLManager.mHasBlendFuncSeparate) + { + LL_WARNS_ONCE("render") << "no glBlendFuncSeparateEXT(), using color-only blend func" << llendl; + blendFunc(color_sfactor, color_dfactor); + return; + } + if (mCurrBlendColorSFactor != color_sfactor || mCurrBlendColorDFactor != color_dfactor || + mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor) + { + mCurrBlendColorSFactor = color_sfactor; + mCurrBlendAlphaSFactor = alpha_sfactor; + mCurrBlendColorDFactor = color_dfactor; + mCurrBlendAlphaDFactor = alpha_dfactor; + flush(); + glBlendFuncSeparateEXT(sGLBlendFactor[color_sfactor], sGLBlendFactor[color_dfactor], + sGLBlendFactor[alpha_sfactor], sGLBlendFactor[alpha_dfactor]); + } } LLTexUnit* LLRender::getTexUnit(U32 index) @@ -996,6 +1153,39 @@ void LLRender::flush() } #endif + if (!mUIOffset.empty()) + { + sUICalls++; + sUIVerts += mCount; + } + + if (gDebugGL) + { + if (mMode == LLRender::QUADS) + { + if (mCount%4 != 0) + { + llerrs << "Incomplete quad rendered." << llendl; + } + } + + if (mMode == LLRender::TRIANGLES) + { + if (mCount%3 != 0) + { + llerrs << "Incomplete triangle rendered." << llendl; + } + } + + if (mMode == LLRender::LINES) + { + if (mCount%2 != 0) + { + llerrs << "Incomplete line rendered." << llendl; + } + } + } + mBuffer->setBuffer(immediate_mask); mBuffer->drawArrays(mMode, 0, mCount); @@ -1015,7 +1205,16 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) return; } - mVerticesp[mCount] = LLVector3(x,y,z); + if (mUIOffset.empty()) + { + mVerticesp[mCount] = LLVector3(x,y,z); + } + else + { + LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.front()).scaledVec(mUIScale.front()); + mVerticesp[mCount] = vert; + } + mCount++; if (mCount < 4096) { diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index cb2a4d4450..3cda4b5770 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -149,8 +149,8 @@ public: // Binds the LLImageGL to this texture unit // (automatically enables the unit for the LLImageGL's texture type) - bool bind(LLImageGL* texture, bool forceBind = false); - bool bind(LLTexture* texture, bool forceBind = false); + bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false); + bool bind(LLTexture* texture, bool for_rendering = false, bool forceBind = false); // Binds a cubemap to this texture unit // (automatically enables the texture unit for cubemaps) @@ -270,7 +270,9 @@ public: BF_DEST_ALPHA, BF_SOURCE_ALPHA, BF_ONE_MINUS_DEST_ALPHA, - BF_ONE_MINUS_SOURCE_ALPHA + BF_ONE_MINUS_SOURCE_ALPHA, + + BF_UNDEF } eBlendFactor; LLRender(); @@ -286,6 +288,14 @@ public: void pushMatrix(); void popMatrix(); + void translateUI(F32 x, F32 y, F32 z); + void scaleUI(F32 x, F32 y, F32 z); + void pushUIMatrix(); + void popUIMatrix(); + void loadUIIdentity(); + LLVector3 getUITranslation(); + LLVector3 getUIScale(); + void flush(); void begin(const GLuint& mode); @@ -313,7 +323,11 @@ public: void setAlphaRejectSettings(eCompareFunc func, F32 value = 0.01f); + // applies blend func to both color and alpha void blendFunc(eBlendFactor sfactor, eBlendFactor dfactor); + // applies separate blend functions to color and alpha + void blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor, + eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor); LLTexUnit* getTexUnit(U32 index); @@ -333,7 +347,9 @@ public: }; public: - + static U32 sUICalls; + static U32 sUIVerts; + private: bool mDirty; U32 mCount; @@ -350,7 +366,15 @@ private: std::vector<LLTexUnit*> mTexUnits; LLTexUnit* mDummyTexUnit; + eBlendFactor mCurrBlendColorSFactor; + eBlendFactor mCurrBlendColorDFactor; + eBlendFactor mCurrBlendAlphaSFactor; + eBlendFactor mCurrBlendAlphaDFactor; F32 mMaxAnisotropy; + + std::list<LLVector3> mUIOffset; + std::list<LLVector3> mUIScale; + }; extern F64 gGLModelView[16]; diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index d9520b3bf6..3f2558f1f5 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -390,8 +390,6 @@ void LLRenderTarget::flush(BOOL fetch_depth) } else { -#if !LL_DARWIN - stop_glerror(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); @@ -435,7 +433,6 @@ void LLRenderTarget::flush(BOOL fetch_depth) } } } -#endif glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } @@ -444,7 +441,6 @@ void LLRenderTarget::flush(BOOL fetch_depth) void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1, S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter) { -#if !LL_DARWIN gGL.flush(); if (!source.mFBO || !mFBO) { @@ -483,14 +479,12 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, stop_glerror(); } } -#endif } //static void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1, S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter) { -#if !LL_DARWIN if (!source.mFBO) { llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl; @@ -507,7 +501,6 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); stop_glerror(); } -#endif } BOOL LLRenderTarget::isComplete() const @@ -652,7 +645,6 @@ void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth void LLMultisampleBuffer::addColorAttachment(U32 color_fmt) { -#if !LL_DARWIN if (color_fmt == 0) { return; @@ -693,12 +685,10 @@ void LLMultisampleBuffer::addColorAttachment(U32 color_fmt) } mTex.push_back(tex); -#endif } void LLMultisampleBuffer::allocateDepth() { -#if !LL_DARWIN glGenRenderbuffersEXT(1, (GLuint* ) &mDepth); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth); if (mStencil) @@ -709,6 +699,5 @@ void LLMultisampleBuffer::allocateDepth() { glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH_COMPONENT16_ARB, mResX, mResY); } -#endif } diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h index c18917b663..7034e9199d 100644 --- a/indra/llrender/lltexture.h +++ b/indra/llrender/lltexture.h @@ -61,7 +61,9 @@ public: // //interfaces to access LLViewerTexture // - virtual bool bindDefaultImage(const S32 stage = 0) const = 0 ; + virtual S8 getType() const = 0 ; + virtual void setKnownDrawSize(S32 width, S32 height) = 0 ; + virtual bool bindDefaultImage(const S32 stage = 0) = 0 ; virtual void forceImmediateUpdate() = 0 ; virtual void setActive() = 0 ; virtual S32 getWidth(S32 discard_level = -1) const = 0 ; diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index db4189dfea..d5b00f27a7 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -61,6 +61,8 @@ BOOL LLVertexBuffer::sVBOActive = FALSE; BOOL LLVertexBuffer::sIBOActive = FALSE; U32 LLVertexBuffer::sAllocatedBytes = 0; BOOL LLVertexBuffer::sMapped = FALSE; +BOOL LLVertexBuffer::sUseStreamDraw = TRUE; +S32 LLVertexBuffer::sWeight4Loc = -1; std::vector<U32> LLVertexBuffer::sDeleteList; @@ -75,6 +77,7 @@ S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] = sizeof(LLColor4U), // TYPE_COLOR, sizeof(LLVector3), // TYPE_BINORMAL, sizeof(F32), // TYPE_WEIGHT, + sizeof(LLVector4), // TYPE_WEIGHT4, sizeof(LLVector4), // TYPE_CLOTHWEIGHT, }; @@ -215,14 +218,18 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const { + llassert(mRequestedNumVerts >= 0); + if (start >= (U32) mRequestedNumVerts || - end >= (U32) mRequestedNumVerts) + end >= (U32) mRequestedNumVerts) { llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "]" << llendl; } + llassert(mRequestedNumIndices >= 0); + if (indices_offset >= (U32) mRequestedNumIndices || - indices_offset + count > (U32) mRequestedNumIndices) + indices_offset + count > (U32) mRequestedNumIndices) { llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; } @@ -237,7 +244,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi llerrs << "Wrong vertex buffer bound." << llendl; } - if (mode > LLRender::NUM_MODES) + if (mode >= LLRender::NUM_MODES) { llerrs << "Invalid draw mode: " << mode << llendl; return; @@ -251,8 +258,9 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const { + llassert(mRequestedNumIndices >= 0); if (indices_offset >= (U32) mRequestedNumIndices || - indices_offset + count > (U32) mRequestedNumIndices) + indices_offset + count > (U32) mRequestedNumIndices) { llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; } @@ -267,7 +275,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const llerrs << "Wrong vertex buffer bound." << llendl; } - if (mode > LLRender::NUM_MODES) + if (mode >= LLRender::NUM_MODES) { llerrs << "Invalid draw mode: " << mode << llendl; return; @@ -281,8 +289,9 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { + llassert(mRequestedNumVerts >= 0); if (first >= (U32) mRequestedNumVerts || - first + count > (U32) mRequestedNumVerts) + first + count > (U32) mRequestedNumVerts) { llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl; } @@ -292,7 +301,7 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const llerrs << "Wrong vertex buffer bound." << llendl; } - if (mode > LLRender::NUM_MODES) + if (mode >= LLRender::NUM_MODES) { llerrs << "Invalid draw mode: " << mode << llendl; return; @@ -354,7 +363,14 @@ void LLVertexBuffer::clientCopy(F64 max_time) LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : LLRefCount(), - mNumVerts(0), mNumIndices(0), mUsage(usage), mGLBuffer(0), mGLIndices(0), + + mNumVerts(0), + mNumIndices(0), + mRequestedNumVerts(-1), + mRequestedNumIndices(-1), + mUsage(usage), + mGLBuffer(0), + mGLIndices(0), mMappedData(NULL), mMappedIndexData(NULL), mLocked(FALSE), mFinal(FALSE), @@ -368,6 +384,11 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : { mUsage = 0 ; } + + if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw) + { + mUsage = 0; + } S32 stride = calcStride(typemask, mOffsets); @@ -566,7 +587,7 @@ void LLVertexBuffer::destroyGLBuffer() } mGLBuffer = 0; - unbind(); + //unbind(); } void LLVertexBuffer::destroyGLIndices() @@ -593,13 +614,15 @@ void LLVertexBuffer::destroyGLIndices() } mGLIndices = 0; - unbind(); + //unbind(); } void LLVertexBuffer::updateNumVerts(S32 nverts) { LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS); + llassert(nverts >= 0); + if (nverts >= 65535) { llwarns << "Vertex buffer overflow!" << llendl; @@ -628,6 +651,9 @@ void LLVertexBuffer::updateNumVerts(S32 nverts) void LLVertexBuffer::updateNumIndices(S32 nindices) { LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES); + + llassert(nindices >= 0); + mRequestedNumIndices = nindices; if (!mDynamicSize) { @@ -650,6 +676,12 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) { LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER); + if (nverts < 0 || nindices < 0 || + nverts > 65536) + { + llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl; + } + updateNumVerts(nverts); updateNumIndices(nindices); @@ -668,6 +700,9 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { + llassert(newnverts >= 0); + llassert(newnindices >= 0); + mRequestedNumVerts = newnverts; mRequestedNumIndices = newnindices; @@ -982,6 +1017,12 @@ bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index) { return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index); } + +bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index) +{ + return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index); +} + bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index) { return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index); @@ -1061,17 +1102,20 @@ void LLVertexBuffer::setBuffer(U32 data_mask) } } - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLIndices) + if (mGLIndices) { - if (gDebugSession) - { - error = TRUE; - gFailLog << "Invalid GL index buffer bound: " << buff << std::endl; - } - else + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); + if ((GLuint)buff != mGLIndices) { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; + if (gDebugSession) + { + error = TRUE; + gFailLog << "Invalid GL index buffer bound: " << buff << std::endl; + } + else + { + llerrs << "Invalid GL index buffer bound: " << buff << llendl; + } } } } @@ -1095,17 +1139,20 @@ void LLVertexBuffer::setBuffer(U32 data_mask) } } - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLIndices) + if (mGLIndices != 0) { - if (gDebugSession) - { - error = TRUE; - gFailLog << "Invalid GL index buffer bound: "<< std::endl; - } - else + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); + if ((GLuint)buff != mGLIndices) { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; + if (gDebugSession) + { + error = TRUE; + gFailLog << "Invalid GL index buffer bound: "<< std::endl; + } + else + { + llerrs << "Invalid GL index buffer bound: " << buff << llendl; + } } } } @@ -1245,6 +1292,12 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const { glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_WEIGHT])); } + + if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1) + { + glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, stride, (void*)(base+mOffsets[TYPE_WEIGHT4])); + } + if (data_mask & MAP_CLOTHWEIGHT) { glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, stride, (void*)(base + mOffsets[TYPE_CLOTHWEIGHT])); diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index b785a22976..225237215c 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -83,6 +83,10 @@ public: static LLVBOPool sDynamicVBOPool; static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; + + static S32 sWeight4Loc; + + static BOOL sUseStreamDraw; static void initClass(bool use_vbo); static void cleanupClass(); @@ -107,6 +111,7 @@ public: // These use VertexAttribPointer and should possibly be made generic TYPE_BINORMAL, TYPE_WEIGHT, + TYPE_WEIGHT4, TYPE_CLOTHWEIGHT, TYPE_MAX, TYPE_INDEX, @@ -122,6 +127,7 @@ public: // These use VertexAttribPointer and should possibly be made generic MAP_BINORMAL = (1<<TYPE_BINORMAL), MAP_WEIGHT = (1<<TYPE_WEIGHT), + MAP_WEIGHT4 = (1<<TYPE_WEIGHT4), MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT), }; @@ -171,6 +177,7 @@ public: bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0); bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0); bool getWeightStrider(LLStrider<F32>& strider, S32 index=0); + bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0); bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0); BOOL isEmpty() const { return mEmpty; } |