summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/llcubemap.cpp13
-rw-r--r--indra/llrender/llfontbitmapcache.cpp4
-rw-r--r--indra/llrender/llfontfreetype.cpp42
-rw-r--r--indra/llrender/llfontfreetype.h5
-rw-r--r--indra/llrender/llfontgl.cpp202
-rw-r--r--indra/llrender/llfontgl.h11
-rw-r--r--indra/llrender/llfontregistry.cpp7
-rw-r--r--indra/llrender/llgl.cpp70
-rw-r--r--indra/llrender/llgl.h1
-rw-r--r--indra/llrender/llglheaders.h22
-rw-r--r--indra/llrender/llglslshader.cpp2
-rw-r--r--indra/llrender/llglstates.h2
-rw-r--r--indra/llrender/llimagegl.cpp573
-rw-r--r--indra/llrender/llimagegl.h91
-rw-r--r--indra/llrender/llpostprocess.cpp2
-rw-r--r--indra/llrender/llrender.cpp235
-rw-r--r--indra/llrender/llrender.h32
-rw-r--r--indra/llrender/llrendertarget.cpp11
-rw-r--r--indra/llrender/lltexture.h4
-rw-r--r--indra/llrender/llvertexbuffer.cpp109
-rw-r--r--indra/llrender/llvertexbuffer.h7
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; }