summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/CMakeLists.txt2
-rw-r--r--indra/llrender/llcubemaparray.cpp54
-rw-r--r--indra/llrender/llcubemaparray.h4
-rw-r--r--indra/llrender/llfontbitmapcache.cpp6
-rw-r--r--indra/llrender/llfontbitmapcache.h2
-rw-r--r--indra/llrender/llfontfreetype.cpp56
-rw-r--r--indra/llrender/llfontfreetype.h3
-rw-r--r--indra/llrender/llfontgl.cpp60
-rw-r--r--indra/llrender/llfontgl.h2
-rw-r--r--indra/llrender/llfontvertexbuffer.cpp239
-rw-r--r--indra/llrender/llfontvertexbuffer.h130
-rw-r--r--indra/llrender/llgl.cpp114
-rw-r--r--indra/llrender/llgl.h28
-rw-r--r--indra/llrender/llglheaders.h2
-rw-r--r--indra/llrender/llglslshader.cpp226
-rw-r--r--indra/llrender/llglslshader.h27
-rw-r--r--indra/llrender/llimagegl.cpp409
-rw-r--r--indra/llrender/llimagegl.h12
-rw-r--r--indra/llrender/llrender.cpp749
-rw-r--r--indra/llrender/llrender.h84
-rw-r--r--indra/llrender/llrender2dutils.cpp383
-rw-r--r--indra/llrender/llrendersphere.cpp62
-rw-r--r--indra/llrender/llrendersphere.h1
-rw-r--r--indra/llrender/llrendertarget.cpp18
-rw-r--r--indra/llrender/llshadermgr.cpp59
-rw-r--r--indra/llrender/llshadermgr.h9
-rw-r--r--indra/llrender/llvertexbuffer.cpp503
-rw-r--r--indra/llrender/llvertexbuffer.h50
28 files changed, 2033 insertions, 1261 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index 7424356057..d48b508ddc 100644
--- a/indra/llrender/CMakeLists.txt
+++ b/indra/llrender/CMakeLists.txt
@@ -17,6 +17,7 @@ set(llrender_SOURCE_FILES
llfontfreetype.cpp
llfontfreetypesvg.cpp
llfontgl.cpp
+ llfontvertexbuffer.cpp
llfontregistry.cpp
llgl.cpp
llglslshader.cpp
@@ -43,6 +44,7 @@ set(llrender_HEADER_FILES
llcubemap.h
llcubemaparray.h
llfontgl.h
+ llfontvertexbuffer.h
llfontfreetype.h
llfontfreetypesvg.h
llfontbitmapcache.h
diff --git a/indra/llrender/llcubemaparray.cpp b/indra/llrender/llcubemaparray.cpp
index 0242fe60ce..fb35e002df 100644
--- a/indra/llrender/llcubemaparray.cpp
+++ b/indra/llrender/llcubemaparray.cpp
@@ -105,16 +105,48 @@ LLCubeMapArray::LLCubeMapArray()
}
+LLCubeMapArray::LLCubeMapArray(LLCubeMapArray& lhs, U32 width, U32 count) : mTextureStage(0)
+{
+ mWidth = width;
+ mCount = count;
+
+ // Allocate a new cubemap array with the same criteria as the incoming cubemap array
+ allocate(mWidth, lhs.mImage->getComponents(), count, lhs.mImage->getUseMipMaps(), lhs.mHDR);
+
+ // Copy each cubemap from the incoming array to the new array
+ U32 min_count = std::min(count, lhs.mCount);
+ for (U32 i = 0; i < min_count * 6; ++i)
+ {
+ U32 src_resolution = lhs.mWidth;
+ U32 dst_resolution = mWidth;
+ {
+ GLint components = GL_RGB;
+ if (mImage->getComponents() == 4)
+ components = GL_RGBA;
+ GLint format = GL_RGB;
+
+ // Handle different resolutions by scaling the image
+ LLPointer<LLImageRaw> src_image = new LLImageRaw(lhs.mWidth, lhs.mWidth, lhs.mImage->getComponents());
+ glGetTexImage(GL_TEXTURE_CUBE_MAP_ARRAY, 0, components, GL_UNSIGNED_BYTE, src_image->getData());
+
+ LLPointer<LLImageRaw> scaled_image = src_image->scaled(mWidth, mWidth);
+ glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, 0, 0, i, mWidth, mWidth, 1, components, GL_UNSIGNED_BYTE, scaled_image->getData());
+ }
+ }
+}
+
LLCubeMapArray::~LLCubeMapArray()
{
}
-void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool use_mips)
+void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool use_mips, bool hdr)
{
U32 texname = 0;
mWidth = resolution;
mCount = count;
+ mHDR = hdr;
+
LLImageGL::generateTextures(1, &texname);
mImage = new LLImageGL(resolution, resolution, components, use_mips);
@@ -125,17 +157,19 @@ void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool us
mImage->setHasMipMaps(use_mips);
bind(0);
-
- U32 format = components == 4 ? GL_RGBA16F : GL_RGB16F;
-
- U32 mip = 0;
-
free_cur_tex_image();
- while (resolution >= 1)
+ U32 format = components == 4 ? GL_RGBA16F : GL_R11F_G11F_B10F;
+ if (!hdr)
+ {
+ format = components == 4 ? GL_RGBA8 : GL_RGB8;
+ }
+ U32 mip = 0;
+ U32 mip_resolution = resolution;
+ while (mip_resolution >= 1)
{
#if GL_VERSION_4_0
- glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, format, resolution, resolution, count * 6, 0,
+ glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, format, mip_resolution, mip_resolution, count * 6, 0,
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
#endif
@@ -143,11 +177,11 @@ void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool us
{
break;
}
- resolution /= 2;
+ mip_resolution /= 2;
++mip;
}
- alloc_tex_image(resolution * 6, resolution, format);
+ alloc_tex_image(resolution, resolution, format, count * 6);
mImage->setAddressMode(LLTexUnit::TAM_CLAMP);
diff --git a/indra/llrender/llcubemaparray.h b/indra/llrender/llcubemaparray.h
index 675aaaf07c..6b4288cb23 100644
--- a/indra/llrender/llcubemaparray.h
+++ b/indra/llrender/llcubemaparray.h
@@ -36,6 +36,7 @@ class LLCubeMapArray : public LLRefCount
{
public:
LLCubeMapArray();
+ LLCubeMapArray(LLCubeMapArray& lhs, U32 width, U32 count);
static GLenum sTargets[6];
@@ -52,7 +53,7 @@ public:
// components - number of components per pixel
// count - number of cube maps in the array
// use_mips - if true, mipmaps will be allocated for this cube map array and anisotropic filtering will be used
- void allocate(U32 res, U32 components, U32 count, bool use_mips = true);
+ void allocate(U32 res, U32 components, U32 count, bool use_mips = true, bool hdr = true);
void bind(S32 stage);
void unbind();
@@ -73,4 +74,5 @@ protected:
U32 mWidth = 0;
U32 mCount = 0;
S32 mTextureStage;
+ bool mHDR;
};
diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp
index 46c2e89797..6a3af1e608 100644
--- a/indra/llrender/llfontbitmapcache.cpp
+++ b/indra/llrender/llfontbitmapcache.cpp
@@ -107,7 +107,7 @@ bool LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp
mBitmapHeight = image_height;
S32 num_components = getNumComponents(bitmap_type);
- mImageRawVec[bitmap_idx].push_back(new LLImageRaw(mBitmapWidth, mBitmapHeight, num_components));
+ mImageRawVec[bitmap_idx].emplace_back(new LLImageRaw(mBitmapWidth, mBitmapHeight, num_components));
bitmap_num = static_cast<U32>(mImageRawVec[bitmap_idx].size()) - 1;
LLImageRaw* image_raw = getImageRaw(bitmap_type, bitmap_num);
@@ -117,7 +117,7 @@ bool LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp
}
// Make corresponding GL image.
- mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false));
+ mImageGLVec[bitmap_idx].emplace_back(new LLImageGL(image_raw, false, false));
LLImageGL* image_gl = getImageGL(bitmap_type, bitmap_num);
// Start at beginning of the new image.
@@ -141,6 +141,7 @@ bool LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp
bitmap_num = getNumBitmaps(bitmap_type) - 1;
mCurrentOffsetX[bitmap_idx] += width + 1;
+ mGeneration++;
return true;
}
@@ -168,6 +169,7 @@ void LLFontBitmapCache::reset()
mBitmapWidth = 0;
mBitmapHeight = 0;
+ mGeneration++;
}
//static
diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h
index f2dfd87877..0ae4e6bed0 100644
--- a/indra/llrender/llfontbitmapcache.h
+++ b/indra/llrender/llfontbitmapcache.h
@@ -63,6 +63,7 @@ public:
U32 getNumBitmaps(EFontGlyphType bitmapType) const { return (bitmapType < EFontGlyphType::Count) ? static_cast<U32>(mImageRawVec[static_cast<U32>(bitmapType)].size()) : 0U; }
S32 getBitmapWidth() const { return mBitmapWidth; }
S32 getBitmapHeight() const { return mBitmapHeight; }
+ S32 getCacheGeneration() const { return mGeneration; }
protected:
static U32 getNumComponents(EFontGlyphType bitmap_type);
@@ -74,6 +75,7 @@ private:
S32 mCurrentOffsetY[static_cast<U32>(EFontGlyphType::Count)] = { 1 };
S32 mMaxCharWidth = 0;
S32 mMaxCharHeight = 0;
+ S32 mGeneration = 0;
std::vector<LLPointer<LLImageRaw>> mImageRawVec[static_cast<U32>(EFontGlyphType::Count)];
std::vector<LLPointer<LLImageGL>> mImageGLVec[static_cast<U32>(EFontGlyphType::Count)];
};
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index fa76669258..e93c98970b 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -32,7 +32,7 @@
// Freetype stuff
#include <ft2build.h>
#ifdef LL_WINDOWS
-#include <freetype2\freetype\ftsystem.h>
+#include <freetype/ftsystem.h>
#endif
#include "llfontfreetypesvg.h"
@@ -148,7 +148,6 @@ LLFontFreetype::LLFontFreetype()
mIsFallback(false),
mFTFace(NULL),
mRenderGlyphCount(0),
- mAddGlyphCount(0),
mStyle(0),
mPointSize(0)
{
@@ -554,7 +553,7 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
return NULL;
llassert(!mIsFallback);
- fontp->renderGlyph(requested_glyph_type, glyph_index);
+ fontp->renderGlyph(requested_glyph_type, glyph_index, wch);
EFontGlyphType bitmap_glyph_type = EFontGlyphType::Unspecified;
switch (fontp->mFTFace->glyph->bitmap.pixel_mode)
@@ -576,7 +575,6 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
S32 pos_x, pos_y;
U32 bitmap_num;
mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_glyph_type, bitmap_num);
- mAddGlyphCount++;
LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index, requested_glyph_type);
gi->mXBitmapOffset = pos_x;
@@ -658,7 +656,14 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_glyph_type, bitmap_num);
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_glyph_type, bitmap_num);
- image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight());
+ if (image_gl && image_raw)
+ {
+ image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight());
+ }
+ else
+ {
+ llassert(false); //images were just inserted by nextOpenPos, they shouldn't be missing
+ }
return gi;
}
@@ -699,7 +704,7 @@ void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
}
}
-void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const
+void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, llwchar wch) const
{
if (mFTFace == NULL)
return;
@@ -714,11 +719,28 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) co
FT_Error error = FT_Load_Glyph(mFTFace, glyph_index, load_flags);
if (FT_Err_Ok != error)
{
+ if (error == FT_Err_Out_Of_Memory)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS() << "Out of memory loading glyph for character " << llformat("U+%xu", U32(wch)) << LL_ENDL;
+ }
+
std::string message = llformat(
- "Error %d (%s) loading glyph %u: bitmap_type=%u, load_flags=%d",
- error, FT_Error_String(error), glyph_index, bitmap_type, load_flags);
+ "Error %d (%s) loading wchar %u glyph %u/%u: bitmap_type=%u, load_flags=%d",
+ error, FT_Error_String(error), wch, glyph_index, mFTFace->num_glyphs, bitmap_type, load_flags);
LL_WARNS_ONCE() << message << LL_ENDL;
error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR);
+ if (FT_Err_Invalid_Outline == error
+ || FT_Err_Invalid_Composite == error
+ || (FT_Err_Ok != error && LLStringOps::isEmoji(wch)))
+ {
+ // value~0 always corresponds to the 'missing glyph'
+ error = FT_Load_Glyph(mFTFace, 0, FT_LOAD_FORCE_AUTOHINT);
+ if (FT_Err_Ok != error)
+ {
+ LL_ERRS() << "Loading fallback for char '" << (U32)wch << "', glyph " << glyph_index << " failed with error : " << (S32)error << LL_ENDL;
+ }
+ }
llassert_always_msg(FT_Err_Ok == error, message.c_str());
}
@@ -825,7 +847,12 @@ bool LLFontFreetype::setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U1
{
LLImageRaw* image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, bitmap_num);
llassert(!mIsFallback);
- llassert(image_raw && (image_raw->getComponents() == 4));
+ if (!image_raw)
+ {
+ llassert(false);
+ return false;
+ }
+ llassert(image_raw->getComponents() == 4);
// NOTE: inspired by LLImageRaw::setSubImage()
U32* image_data = (U32*)image_raw->getData();
@@ -853,10 +880,17 @@ bool LLFontFreetype::setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U1
void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const
{
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, bitmap_num);
- LLImageDataLock lock(image_raw);
llassert(!mIsFallback);
- llassert(image_raw && (image_raw->getComponents() == 2));
+ if (!image_raw)
+ {
+ llassert(false);
+ return;
+ }
+
+ LLImageDataLock lock(image_raw);
+
+ llassert(image_raw->getComponents() == 2);
U8 *target = image_raw->getData();
llassert(target);
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
index eba89f5def..783bf4a4b3 100644
--- a/indra/llrender/llfontfreetype.h
+++ b/indra/llrender/llfontfreetype.h
@@ -156,7 +156,7 @@ private:
bool hasGlyph(llwchar wch) const; // Has a glyph for this character
LLFontGlyphInfo* addGlyph(llwchar wch, EFontGlyphType glyph_type) const; // Add a new character to the font if necessary
LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType bitmap_type) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found)
- void renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const;
+ void renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, llwchar wch) const;
void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const;
std::string mName;
@@ -187,7 +187,6 @@ private:
mutable LLFontBitmapCache* mFontBitmapCachep;
mutable S32 mRenderGlyphCount;
- mutable S32 mAddGlyphCount;
};
#endif // LL_FONTFREETYPE_H
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 211df92636..16eec1fdd2 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -58,6 +58,7 @@ F32 LLFontGL::sVertDPI = 96.f;
F32 LLFontGL::sHorizDPI = 96.f;
F32 LLFontGL::sScaleX = 1.f;
F32 LLFontGL::sScaleY = 1.f;
+S32 LLFontGL::sResolutionGeneration = 0;
bool LLFontGL::sDisplayFont = true ;
std::string LLFontGL::sAppDir;
@@ -109,6 +110,12 @@ S32 LLFontGL::getNumFaces(const std::string& filename)
return mFontFreetype->getNumFaces(filename);
}
+S32 LLFontGL::getCacheGeneration() const
+{
+ const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();
+ return font_bitmap_cache->getCacheGeneration();
+}
+
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
ShadowType shadow, S32 max_chars, F32* right_x, bool use_ellipses, bool use_color) const
{
@@ -249,6 +256,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();
+ // This looks wrong, value is dynamic.
+ // LLFontBitmapCache::nextOpenPos can alter these values when
+ // new characters get added to cache, which affects whole string.
+ // Todo: Perhaps value should update after symbols were added?
F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth();
F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight();
@@ -270,10 +281,14 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
const LLFontGlyphInfo* next_glyph = NULL;
- const S32 GLYPH_BATCH_SIZE = 120;
- LLVector4a vertices[GLYPH_BATCH_SIZE * 6];
- LLVector2 uvs[GLYPH_BATCH_SIZE * 6];
- LLColor4U colors[GLYPH_BATCH_SIZE * 6];
+ // string can have more than one glyph per char (ex: bold or shadow),
+ // make sure that GLYPH_BATCH_SIZE won't end up with half a symbol.
+ // See drawGlyph.
+ // Ex: with shadows it's 6 glyps per char. 30 fits exactly 5 chars.
+ static constexpr S32 GLYPH_BATCH_SIZE = 30;
+ static thread_local LLVector4a vertices[GLYPH_BATCH_SIZE * 6];
+ static thread_local LLVector2 uvs[GLYPH_BATCH_SIZE * 6];
+ static thread_local LLColor4U colors[GLYPH_BATCH_SIZE * 6];
LLColor4U text_color(color);
// Preserve the transparency to render fading emojis in fading text (e.g.
@@ -282,6 +297,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
std::pair<EFontGlyphType, S32> bitmap_entry = std::make_pair(EFontGlyphType::Grayscale, -1);
S32 glyph_count = 0;
+ llwchar last_char = wstr[begin_offset];
for (i = begin_offset; i < begin_offset + length; i++)
{
llwchar wch = wstr[i];
@@ -299,7 +315,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
}
// Per-glyph bitmap texture.
std::pair<EFontGlyphType, S32> next_bitmap_entry = fgi->mBitmapEntry;
- if (next_bitmap_entry != bitmap_entry)
+ if (next_bitmap_entry != bitmap_entry || last_char != wch)
{
// Actually draw the queued glyphs before switching their texture;
// otherwise the queued glyphs will be taken from wrong textures.
@@ -316,6 +332,11 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
bitmap_entry = next_bitmap_entry;
LLImageGL* font_image = font_bitmap_cache->getImageGL(bitmap_entry.first, bitmap_entry.second);
gGL.getTexUnit(0)->bind(font_image);
+
+ // For some reason it's not enough to compare by bitmap_entry.
+ // Issue hits emojis, japenese and chinese glyphs, only on first run.
+ // Todo: figure it out, there might be a bug with raw image data.
+ last_char = wch;
}
if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
@@ -343,6 +364,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 6);
}
gGL.end();
+
glyph_count = 0;
}
@@ -401,10 +423,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
if (draw_ellipses)
{
-
// recursively render ellipses at end of string
// we've already reserved enough room
- gGL.pushUIMatrix();
static LLWString elipses_wstr(utf8string_to_wstring(std::string("...")));
render(elipses_wstr,
0,
@@ -417,7 +437,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
right_x,
false,
use_color);
- gGL.popUIMatrix();
}
gGL.popUIMatrix();
@@ -503,6 +522,7 @@ F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max
F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars, bool no_padding) const
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
F32 cur_x = 0;
@@ -1230,34 +1250,34 @@ void LLFontGL::renderTriangle(LLVector4a* vertex_out, LLVector2* uv_out, LLColor
{
S32 index = 0;
- vertex_out[index] = LLVector4a(screen_rect.mRight, screen_rect.mTop, 0.f);
- uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
+ vertex_out[index].set(screen_rect.mRight, screen_rect.mTop, 0.f);
+ uv_out[index].set(uv_rect.mRight, uv_rect.mTop);
colors_out[index] = color;
index++;
- vertex_out[index] = LLVector4a(screen_rect.mLeft, screen_rect.mTop, 0.f);
- uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
+ vertex_out[index].set(screen_rect.mLeft, screen_rect.mTop, 0.f);
+ uv_out[index].set(uv_rect.mLeft, uv_rect.mTop);
colors_out[index] = color;
index++;
- vertex_out[index] = LLVector4a(screen_rect.mLeft, screen_rect.mBottom, 0.f);
- uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
+ vertex_out[index].set(screen_rect.mLeft, screen_rect.mBottom, 0.f);
+ uv_out[index].set(uv_rect.mLeft, uv_rect.mBottom);
colors_out[index] = color;
index++;
- vertex_out[index] = LLVector4a(screen_rect.mRight, screen_rect.mTop, 0.f);
- uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
+ vertex_out[index].set(screen_rect.mRight, screen_rect.mTop, 0.f);
+ uv_out[index].set(uv_rect.mRight, uv_rect.mTop);
colors_out[index] = color;
index++;
- vertex_out[index] = LLVector4a(screen_rect.mLeft, screen_rect.mBottom, 0.f);
- uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
+ vertex_out[index].set(screen_rect.mLeft, screen_rect.mBottom, 0.f);
+ uv_out[index].set(uv_rect.mLeft, uv_rect.mBottom);
colors_out[index] = color;
index++;
- vertex_out[index] = LLVector4a(screen_rect.mRight, screen_rect.mBottom, 0.f);
- uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
+ vertex_out[index].set(screen_rect.mRight, screen_rect.mBottom, 0.f);
+ uv_out[index].set(uv_rect.mRight, uv_rect.mBottom);
colors_out[index] = color;
}
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index 4bb6c55c65..1c8e036f58 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -90,6 +90,7 @@ public:
bool loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n);
S32 getNumFaces(const std::string& filename);
+ S32 getCacheGeneration() const;
S32 render(const LLWString &text, S32 begin_offset,
const LLRect& rect,
@@ -224,6 +225,7 @@ public:
static F32 sHorizDPI;
static F32 sScaleX;
static F32 sScaleY;
+ static S32 sResolutionGeneration;
static bool sDisplayFont ;
static std::string sAppDir; // For loading fonts
diff --git a/indra/llrender/llfontvertexbuffer.cpp b/indra/llrender/llfontvertexbuffer.cpp
new file mode 100644
index 0000000000..a223509d30
--- /dev/null
+++ b/indra/llrender/llfontvertexbuffer.cpp
@@ -0,0 +1,239 @@
+/**
+ * @file llfontvertexbuffer.cpp
+ * @brief Buffer storage for font rendering.
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llfontvertexbuffer.h"
+
+#include "llvertexbuffer.h"
+
+
+bool LLFontVertexBuffer::sEnableBufferCollection = true;
+
+LLFontVertexBuffer::LLFontVertexBuffer()
+{
+}
+
+LLFontVertexBuffer::~LLFontVertexBuffer()
+{
+ reset();
+}
+
+void LLFontVertexBuffer::reset()
+{
+ // Todo: some form of debug only frequecy check&assert to see if this is happening too often.
+ // Regenerating this list is expensive
+ mBufferList.clear();
+}
+
+S32 LLFontVertexBuffer::render(
+ const LLFontGL* fontp,
+ const LLWString& text,
+ S32 begin_offset,
+ LLRect rect,
+ const LLColor4& color,
+ LLFontGL::HAlign halign, LLFontGL::VAlign valign,
+ U8 style,
+ LLFontGL::ShadowType shadow,
+ S32 max_chars, S32 max_pixels,
+ F32* right_x,
+ bool use_ellipses,
+ bool use_color)
+{
+ LLRectf rect_float((F32)rect.mLeft, (F32)rect.mTop, (F32)rect.mRight, (F32)rect.mBottom);
+ return render(fontp, text, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses, use_color);
+}
+
+S32 LLFontVertexBuffer::render(
+ const LLFontGL* fontp,
+ const LLWString& text,
+ S32 begin_offset,
+ LLRectf rect,
+ const LLColor4& color,
+ LLFontGL::HAlign halign, LLFontGL::VAlign valign,
+ U8 style,
+ LLFontGL::ShadowType shadow,
+ S32 max_chars,
+ F32* right_x,
+ bool use_ellipses,
+ bool use_color)
+{
+ F32 x = rect.mLeft;
+ F32 y = 0.f;
+
+ switch (valign)
+ {
+ case LLFontGL::TOP:
+ y = rect.mTop;
+ break;
+ case LLFontGL::VCENTER:
+ y = rect.getCenterY();
+ break;
+ case LLFontGL::BASELINE:
+ case LLFontGL::BOTTOM:
+ y = rect.mBottom;
+ break;
+ default:
+ y = rect.mBottom;
+ break;
+ }
+ return render(fontp, text, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, (S32)rect.getWidth(), right_x, use_ellipses, use_color);
+}
+
+S32 LLFontVertexBuffer::render(
+ const LLFontGL* fontp,
+ const LLWString& text,
+ S32 begin_offset,
+ F32 x, F32 y,
+ const LLColor4& color,
+ LLFontGL::HAlign halign, LLFontGL::VAlign valign,
+ U8 style,
+ LLFontGL::ShadowType shadow,
+ S32 max_chars , S32 max_pixels,
+ F32* right_x,
+ bool use_ellipses,
+ bool use_color )
+{
+ if (!LLFontGL::sDisplayFont) //do not display texts
+ {
+ return static_cast<S32>(text.length());
+ }
+ if (!sEnableBufferCollection)
+ {
+ // For debug purposes and performance testing
+ return fontp->render(text, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
+ }
+ if (mBufferList.empty())
+ {
+ genBuffers(fontp, text, begin_offset, x, y, color, halign, valign,
+ style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
+ }
+ else if (mLastX != x
+ || mLastY != y
+ || mLastFont != fontp
+ || mLastColor != color // alphas change often
+ || mLastHalign != halign
+ || mLastValign != valign
+ || mLastOffset != begin_offset
+ || mLastMaxChars != max_chars
+ || mLastMaxPixels != max_pixels
+ || mLastStyle != style
+ || mLastShadow != shadow // ex: buttons change shadow state
+ || mLastScaleX != LLFontGL::sScaleX
+ || mLastScaleY != LLFontGL::sScaleY
+ || mLastVertDPI != LLFontGL::sVertDPI
+ || mLastHorizDPI != LLFontGL::sHorizDPI
+ || mLastOrigin != LLFontGL::sCurOrigin
+ || mLastResGeneration != LLFontGL::sResolutionGeneration
+ || mLastFontCacheGen != fontp->getCacheGeneration())
+ {
+ genBuffers(fontp, text, begin_offset, x, y, color, halign, valign,
+ style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
+ }
+ else
+ {
+ renderBuffers();
+
+ if (right_x)
+ {
+ *right_x = mLastRightX;
+ }
+ }
+ return mChars;
+}
+
+void LLFontVertexBuffer::genBuffers(
+ const LLFontGL* fontp,
+ const LLWString& text,
+ S32 begin_offset,
+ F32 x, F32 y,
+ const LLColor4& color,
+ LLFontGL::HAlign halign, LLFontGL::VAlign valign,
+ U8 style, LLFontGL::ShadowType shadow,
+ S32 max_chars, S32 max_pixels,
+ F32* right_x,
+ bool use_ellipses,
+ bool use_color)
+{
+ // todo: add a debug build assert if this triggers too often for to long?
+ mBufferList.clear();
+ // Save before rendreing, it can change mid-render,
+ // so will need to rerender previous characters
+ mLastFontCacheGen = fontp->getCacheGeneration();
+
+ gGL.beginList(&mBufferList);
+ mChars = fontp->render(text, begin_offset, x, y, color, halign, valign,
+ style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
+ gGL.endList();
+
+ mLastFont = fontp;
+ mLastOffset = begin_offset;
+ mLastMaxChars = max_chars;
+ mLastMaxPixels = max_pixels;
+ mLastX = x;
+ mLastY = y;
+ mLastColor = color;
+ mLastHalign = halign;
+ mLastValign = valign;
+ mLastStyle = style;
+ mLastShadow = shadow;
+
+ mLastScaleX = LLFontGL::sScaleX;
+ mLastScaleY = LLFontGL::sScaleY;
+ mLastVertDPI = LLFontGL::sVertDPI;
+ mLastHorizDPI = LLFontGL::sHorizDPI;
+ mLastOrigin = LLFontGL::sCurOrigin;
+ mLastResGeneration = LLFontGL::sResolutionGeneration;
+
+ if (right_x)
+ {
+ mLastRightX = *right_x;
+ }
+}
+
+void LLFontVertexBuffer::renderBuffers()
+{
+ gGL.flush(); // deliberately empty pending verts
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+ gGL.pushUIMatrix();
+
+ gGL.loadUIIdentity();
+
+ // Depth translation, so that floating text appears 'in-world'
+ // and is correctly occluded.
+ gGL.translatef(0.f, 0.f, LLFontGL::sCurDepth);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ // Note: ellipses should technically be covered by push/load/translate of their own
+ // but it's more complexity, values do not change, skipping doesn't appear to break
+ // anything, so we can skip that until it proves to cause issues.
+ for (LLVertexBufferData& buffer : mBufferList)
+ {
+ buffer.draw();
+ }
+ gGL.popUIMatrix();
+}
+
diff --git a/indra/llrender/llfontvertexbuffer.h b/indra/llrender/llfontvertexbuffer.h
new file mode 100644
index 0000000000..a9e1e2337c
--- /dev/null
+++ b/indra/llrender/llfontvertexbuffer.h
@@ -0,0 +1,130 @@
+/**
+ * @file llfontgl.h
+ * @author Andrii Kleshchev
+ * @brief Buffer storage for font rendering.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFONTVERTEXBUFFER_H
+#define LL_LLFONTVERTEXBUFFER_H
+
+#include "llfontgl.h"
+
+class LLVertexBufferData;
+
+class LLFontVertexBuffer
+{
+public:
+ LLFontVertexBuffer();
+ ~LLFontVertexBuffer();
+
+ void reset();
+
+ S32 render(const LLFontGL* fontp,
+ const LLWString& text,
+ S32 begin_offset,
+ LLRect rect,
+ const LLColor4& color,
+ LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE,
+ U8 style = LLFontGL::NORMAL,
+ LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW,
+ S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX,
+ F32* right_x = NULL,
+ bool use_ellipses = false,
+ bool use_color = true);
+
+ S32 render(const LLFontGL* fontp,
+ const LLWString& text,
+ S32 begin_offset,
+ LLRectf rect,
+ const LLColor4& color,
+ LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE,
+ U8 style = LLFontGL::NORMAL,
+ LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW,
+ S32 max_chars = S32_MAX,
+ F32* right_x = NULL,
+ bool use_ellipses = false,
+ bool use_color = true);
+
+ S32 render(const LLFontGL* fontp,
+ const LLWString& text,
+ S32 begin_offset,
+ F32 x, F32 y,
+ const LLColor4& color,
+ LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE,
+ U8 style = LLFontGL::NORMAL,
+ LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW,
+ S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX,
+ F32* right_x = NULL,
+ bool use_ellipses = false,
+ bool use_color = true);
+
+ static void enableBufferCollection(bool enable) { sEnableBufferCollection = enable; }
+private:
+
+ void genBuffers(const LLFontGL* fontp,
+ const LLWString& text,
+ S32 begin_offset,
+ F32 x, F32 y,
+ const LLColor4& color,
+ LLFontGL::HAlign halign, LLFontGL::VAlign valign,
+ U8 style,
+ LLFontGL::ShadowType shadow,
+ S32 max_chars, S32 max_pixels,
+ F32* right_x,
+ bool use_ellipses,
+ bool use_color);
+
+ void renderBuffers();
+
+ std::list<LLVertexBufferData> mBufferList;
+ S32 mChars = 0;
+ const LLFontGL *mLastFont = nullptr;
+ S32 mLastOffset = 0;
+ S32 mLastMaxChars = 0;
+ S32 mLastMaxPixels = 0;
+ F32 mLastX = 0.f;
+ F32 mLastY = 0.f;
+ LLColor4 mLastColor;
+ LLFontGL::HAlign mLastHalign = LLFontGL::LEFT;
+ LLFontGL::VAlign mLastValign = LLFontGL::BASELINE;
+ U8 mLastStyle = LLFontGL::NORMAL;
+ LLFontGL::ShadowType mLastShadow = LLFontGL::NO_SHADOW;
+ F32 mLastRightX = 0.f;
+
+ // LLFontGL's statics
+ F32 mLastScaleX = 1.f;
+ F32 mLastScaleY = 1.f;
+ F32 mLastVertDPI = 0.f;
+ F32 mLastHorizDPI = 0.f;
+ S32 mLastResGeneration = 0;
+ LLCoordGL mLastOrigin;
+
+ // Adding new characters to bitmap cache can alter value from getBitmapWidth();
+ // which alters whole string. So rerender when new characters were added to cache.
+ S32 mLastFontCacheGen = 0;
+
+ static bool sEnableBufferCollection;
+};
+
+#endif
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 2f2c58ce73..ac66faaf5a 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -50,10 +50,9 @@
#include "llglheaders.h"
#include "llglslshader.h"
-#include "llvertexbuffer.h"
-#include "llcontrol.h"
-extern LLControlGroup gSavedSettings;
-
+#include "glm/glm.hpp"
+#include <glm/gtc/matrix_access.hpp>
+#include "glm/gtc/type_ptr.hpp"
#if LL_WINDOWS
#include "lldxhardware.h"
@@ -239,8 +238,6 @@ PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC wglBlitContextFramebufferAMD = n
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr;
PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = nullptr;
-/*
-
// GL_VERSION_1_2
//PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements = nullptr;
//PFNGLTEXIMAGE3DPROC glTexImage3D = nullptr;
@@ -985,7 +982,6 @@ PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC glMultiDrawArraysIndirectCount = nullpt
PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC glMultiDrawElementsIndirectCount = nullptr;
PFNGLPOLYGONOFFSETCLAMPPROC glPolygonOffsetClamp = nullptr;
-*/
#endif
LLGLManager gGLManager;
@@ -1002,7 +998,6 @@ LLGLManager::LLGLManager() :
mIsAMD(false),
mIsNVIDIA(false),
mIsIntel(false),
- mIsApple(false),
#if LL_DARWIN
mIsMobileGF(false),
#endif
@@ -1177,10 +1172,10 @@ bool LLGLManager::initGL()
mGLVendorShort = "INTEL";
mIsIntel = true;
}
- else if(mGLVendor.find("APPLE") != std::string::npos)
+ else if (mGLVendor.find("APPLE") != std::string::npos)
{
mGLVendorShort = "APPLE";
- mIsApple = TRUE;
+ mIsApple = true;
}
else
{
@@ -1235,28 +1230,9 @@ bool LLGLManager::initGL()
}
#endif
-#if LL_WINDOWS
- if (mVRAM < 256)
- {
- // Something likely went wrong using the above extensions
- // try WMI first and fall back to old method (from dxdiag) if all else fails
- // Function will check all GPUs WMI knows of and will pick up the one with most
- // memory. We need to check all GPUs because system can switch active GPU to
- // weaker one, to preserve power when not under load.
- U32 mem = LLDXHardware::getMBVideoMemoryViaWMI();
- if (mem != 0)
- {
- mVRAM = mem;
- LL_WARNS("RenderInit") << "VRAM Detected (WMI):" << mVRAM<< LL_ENDL;
- }
- }
-#endif
-
if (mVRAM < 256 && old_vram > 0)
{
// fall back to old method
- // Note: on Windows value will be from LLDXHardware.
- // Either received via dxdiag or via WMI by id from dxdiag.
mVRAM = old_vram;
}
@@ -1268,31 +1244,20 @@ bool LLGLManager::initGL()
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
#endif
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &mMaxVaryingVectors);
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &mMaxUniformBlockSize);
// sanity clamp max uniform block size to 64k just in case
// there's some implementation that reports a crazy value
mMaxUniformBlockSize = llmin(mMaxUniformBlockSize, 65536);
- if (mGLVersion >= 4.59f)
+ if (mHasAnisotropic)
{
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &mMaxAnisotropy);
}
initGLStates();
- U32 MPVBufferOptiMode = gSavedSettings.getU32("MPVBufferOptiMode");
- if (MPVBufferOptiMode == 0)
- {
- if(mIsApple) MPVBufferOptiMode = 2;
- else MPVBufferOptiMode = 1;
- gSavedSettings.setU32("MPVBufferOptiMode",MPVBufferOptiMode);
- }
- LLVertexBuffer::sMappingMode = MPVBufferOptiMode;
- //LLRender::sMappingMode = MPVBufferOptiMode;
-
- LL_INFOS() << "milo init sMappingMode " << MPVBufferOptiMode << LL_ENDL;
-
return true;
}
@@ -1409,7 +1374,6 @@ void LLGLManager::asLLSD(LLSD& info)
info["is_ati"] = mIsAMD; // note, do not rename is_ati to is_amd without coordinating with DW
info["is_nvidia"] = mIsNVIDIA;
info["is_intel"] = mIsIntel;
- info["is_apple"] = mIsApple;
info["gl_renderer"] = mGLRenderer;
}
@@ -1454,6 +1418,11 @@ void LLGLManager::initExtensions()
mHasCubeMapArray = mGLVersion >= 3.99f;
mHasTransformFeedback = mGLVersion >= 3.99f;
mHasDebugOutput = mGLVersion >= 4.29f;
+ mHasAnisotropic = mGLVersion >= 4.59f;
+ if(!mHasAnisotropic && gGLHExts.mSysExts)
+ {
+ mHasAnisotropic = ExtensionExists("GL_EXT_texture_filter_anisotropic", gGLHExts.mSysExts);
+ }
// Misc
glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange);
@@ -1462,7 +1431,6 @@ void LLGLManager::initExtensions()
mInited = true;
-/*
#if LL_WINDOWS
LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL;
@@ -2300,7 +2268,6 @@ void LLGLManager::initExtensions()
glPolygonOffsetClamp = (PFNGLPOLYGONOFFSETCLAMPPROC)GLH_EXT_GET_PROC_ADDRESS("glPolygonOffsetClamp");
#endif
-*/
}
void rotate_quat(LLQuaternion& rotation)
@@ -2489,12 +2456,15 @@ void LLGLState::checkStates(GLboolean writeAlpha)
return;
}
- GLint src;
- GLint dst;
- glGetIntegerv(GL_BLEND_SRC, &src);
- glGetIntegerv(GL_BLEND_DST, &dst);
- llassert_always(src == GL_SRC_ALPHA);
- llassert_always(dst == GL_ONE_MINUS_SRC_ALPHA);
+ GLint srcRGB, dstRGB, srcAlpha, dstAlpha;
+ glGetIntegerv(GL_BLEND_SRC_RGB, &srcRGB);
+ glGetIntegerv(GL_BLEND_DST_RGB, &dstRGB);
+ glGetIntegerv(GL_BLEND_SRC_ALPHA, &srcAlpha);
+ glGetIntegerv(GL_BLEND_DST_ALPHA, &dstAlpha);
+ llassert_always(srcRGB == GL_SRC_ALPHA);
+ llassert_always(srcAlpha == GL_SRC_ALPHA);
+ llassert_always(dstRGB == GL_ONE_MINUS_SRC_ALPHA);
+ llassert_always(dstAlpha == GL_ONE_MINUS_SRC_ALPHA);
// disable for now until usage is consistent
//GLboolean colorMask[4];
@@ -2736,7 +2706,7 @@ void parse_glsl_version(S32& major, S32& minor)
LLStringUtil::convertToS32(minor_str, minor);
}
-LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply)
+LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glm::mat4& modelview, const glm::mat4& projection, bool apply)
{
mApply = apply;
@@ -2763,13 +2733,12 @@ void LLGLUserClipPlane::disable()
void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
{
- glh::matrix4f& P = mProjection;
- glh::matrix4f& M = mModelview;
+ const glm::mat4& P = mProjection;
+ const glm::mat4& M = mModelview;
- glh::matrix4f invtrans_MVP = (P * M).inverse().transpose();
- glh::vec4f oplane(a,b,c,d);
- glh::vec4f cplane;
- invtrans_MVP.mult_matrix_vec(oplane, cplane);
+ glm::mat4 invtrans_MVP = glm::transpose(glm::inverse(P*M));
+ glm::vec4 oplane(a,b,c,d);
+ glm::vec4 cplane = invtrans_MVP * oplane;
cplane /= fabs(cplane[2]); // normalize such that depth is not scaled
cplane[3] -= 1;
@@ -2777,13 +2746,13 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
if(cplane[2] < 0)
cplane *= -1;
- glh::matrix4f suffix;
- suffix.set_row(2, cplane);
- glh::matrix4f newP = suffix * P;
+ glm::mat4 suffix;
+ suffix = glm::row(suffix, 2, cplane);
+ glm::mat4 newP = suffix * P;
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
- gGL.loadMatrix(newP.m);
- gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m);
+ gGL.loadMatrix(glm::value_ptr(newP));
+ gGLObliqueProjectionInverse = LLMatrix4(glm::value_ptr(glm::transpose(glm::inverse(newP))));
gGL.matrixMode(LLRender::MM_MODELVIEW);
}
@@ -2796,7 +2765,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G
: mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled)
{
stop_glerror();
-
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
checkState();
if (!depth_enabled)
@@ -2829,6 +2798,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G
LLGLDepthTest::~LLGLDepthTest()
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
checkState();
if (sDepthEnabled != mPrevDepthEnabled )
{
@@ -2879,31 +2849,27 @@ void LLGLDepthTest::checkState()
LLGLSquashToFarClip::LLGLSquashToFarClip()
{
- glh::matrix4f proj = get_current_projection();
+ glm::mat4 proj = get_current_projection();
setProjectionMatrix(proj, 0);
}
-LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f& P, U32 layer)
+LLGLSquashToFarClip::LLGLSquashToFarClip(const glm::mat4& P, U32 layer)
{
setProjectionMatrix(P, layer);
}
-
-void LLGLSquashToFarClip::setProjectionMatrix(glh::matrix4f& projection, U32 layer)
+void LLGLSquashToFarClip::setProjectionMatrix(glm::mat4 projection, U32 layer)
{
-
F32 depth = 0.99999f - 0.0001f * layer;
- for (U32 i = 0; i < 4; i++)
- {
- projection.element(2, i) = projection.element(3, i) * depth;
- }
+ glm::vec4 P_row_3 = glm::row(projection, 3) * depth;
+ projection = glm::row(projection, 2, P_row_3);
LLRender::eMatrixMode last_matrix_mode = gGL.getMatrixMode();
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
- gGL.loadMatrix(projection.m);
+ gGL.loadMatrix(glm::value_ptr(projection));
gGL.matrixMode(last_matrix_mode);
}
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 506baec03d..bf8368a7b3 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -43,7 +43,7 @@
#include "llinstancetracker.h"
#include "llglheaders.h"
-#include "glh/glh_linear.h"
+#include "glm/mat4x4.hpp"
extern bool gDebugGL;
extern bool gDebugSession;
@@ -88,6 +88,7 @@ public:
S32 mGLMaxTextureSize;
F32 mMaxAnisotropy = 0.f;
S32 mMaxUniformBlockSize = 0;
+ S32 mMaxVaryingVectors = 0;
// GL 4.x capabilities
bool mHasCubeMapArray = false;
@@ -102,7 +103,7 @@ public:
bool mIsAMD;
bool mIsNVIDIA;
bool mIsIntel;
- bool mIsApple;
+ bool mIsApple = false;
// hints to the render pipe
U32 mDownScaleMethod = 0; // see settings.xml RenderDownScaleMethod
@@ -159,18 +160,17 @@ void assert_glerror();
void clear_glerror();
+#if !LL_RELEASE_FOR_DOWNLOAD
# define stop_glerror() assert_glerror()
# define llglassertok() assert_glerror()
-
-// stop_glerror is still needed on OS X but has performance implications
-// use macro below to conditionally add stop_glerror to non-release builds
-// on OS X
-#if LL_DARWIN && !LL_RELEASE_FOR_DOWNLOAD
-#define STOP_GLERROR stop_glerror()
+# define STOP_GLERROR stop_glerror()
#else
-#define STOP_GLERROR
+# define stop_glerror()
+# define llglassertok()
+# define STOP_GLERROR
#endif
+
#define llglassertok_always() assert_glerror()
////////////////////////
@@ -318,7 +318,7 @@ class LLGLUserClipPlane
{
public:
- LLGLUserClipPlane(const LLPlane& plane, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply = true);
+ LLGLUserClipPlane(const LLPlane& plane, const glm::mat4& modelview, const glm::mat4& projection, bool apply = true);
~LLGLUserClipPlane();
void setPlane(F32 a, F32 b, F32 c, F32 d);
@@ -327,8 +327,8 @@ public:
private:
bool mApply;
- glh::matrix4f mProjection;
- glh::matrix4f mModelview;
+ glm::mat4 mProjection;
+ glm::mat4 mModelview;
};
/*
@@ -342,9 +342,9 @@ class LLGLSquashToFarClip
{
public:
LLGLSquashToFarClip();
- LLGLSquashToFarClip(glh::matrix4f& projection, U32 layer = 0);
+ LLGLSquashToFarClip(const glm::mat4& projection, U32 layer = 0);
- void setProjectionMatrix(glh::matrix4f& projection, U32 layer);
+ void setProjectionMatrix(glm::mat4 projection, U32 layer);
~LLGLSquashToFarClip();
};
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 7d56f12766..a2685376cd 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -62,7 +62,7 @@
// LL_WINDOWS
// windows gl headers depend on things like APIENTRY, so include windows.
-#include "llwin32headerslean.h"
+#include "llwin32headers.h"
//----------------------------------------------------------------------------
#include <GL/gl.h>
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 439cf46684..aac5e3abc8 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -63,6 +63,7 @@ U64 LLGLSLShader::sTotalTimeElapsed = 0;
U32 LLGLSLShader::sTotalTrianglesDrawn = 0;
U64 LLGLSLShader::sTotalSamplesDrawn = 0;
U32 LLGLSLShader::sTotalBinds = 0;
+boost::json::value LLGLSLShader::sDefaultStats;
//UI shader -- declared here so llui_libtest will link properly
LLGLSLShader gUIProgram;
@@ -101,9 +102,9 @@ void LLGLSLShader::initProfile()
sTotalSamplesDrawn = 0;
sTotalBinds = 0;
- for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+ for (auto ptr : sInstances)
{
- (*iter)->clearStats();
+ ptr->clearStats();
}
}
@@ -117,45 +118,57 @@ struct LLGLSLShaderCompareTimeElapsed
};
//static
-void LLGLSLShader::finishProfile(bool emit_report)
+void LLGLSLShader::finishProfile(boost::json::value& statsv)
{
sProfileEnabled = false;
- if (emit_report)
+ if (! statsv.is_null())
{
- std::vector<LLGLSLShader*> sorted;
-
- for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
- {
- sorted.push_back(*iter);
- }
-
+ std::vector<LLGLSLShader*> sorted(sInstances.begin(), sInstances.end());
std::sort(sorted.begin(), sorted.end(), LLGLSLShaderCompareTimeElapsed());
+ auto& stats = statsv.as_object();
+ auto shadersit = stats.emplace("shaders", boost::json::array_kind).first;
+ auto& shaders = shadersit->value().as_array();
bool unbound = false;
- for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
+ for (auto ptr : sorted)
{
- (*iter)->dumpStats();
- if ((*iter)->mBinds == 0)
+ if (ptr->mBinds == 0)
{
unbound = true;
}
+ else
+ {
+ auto& shaderit = shaders.emplace_back(boost::json::object_kind);
+ ptr->dumpStats(shaderit.as_object());
+ }
}
+ constexpr float mega = 1'000'000.f;
+ float totalTimeMs = sTotalTimeElapsed / mega;
LL_INFOS() << "-----------------------------------" << LL_ENDL;
- LL_INFOS() << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed / 1000000.f) << LL_ENDL;
- LL_INFOS() << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn / 1000000.f) << LL_ENDL;
- LL_INFOS() << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn / 1000000.f) << LL_ENDL;
+ LL_INFOS() << "Total rendering time: " << llformat("%.4f ms", totalTimeMs) << LL_ENDL;
+ LL_INFOS() << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn / mega) << LL_ENDL;
+ LL_INFOS() << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn / mega) << LL_ENDL;
LL_INFOS() << "-----------------------------------" << LL_ENDL;
-
+ auto totalsit = stats.emplace("totals", boost::json::object_kind).first;
+ auto& totals = totalsit->value().as_object();
+ totals.emplace("time", totalTimeMs / 1000.0);
+ totals.emplace("binds", sTotalBinds);
+ totals.emplace("samples", sTotalSamplesDrawn);
+ totals.emplace("triangles", sTotalTrianglesDrawn);
+
+ auto unusedit = stats.emplace("unused", boost::json::array_kind).first;
+ auto& unused = unusedit->value().as_array();
if (unbound)
{
LL_INFOS() << "The following shaders were unused: " << LL_ENDL;
- for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
+ for (auto ptr : sorted)
{
- if ((*iter)->mBinds == 0)
+ if (ptr->mBinds == 0)
{
- LL_INFOS() << (*iter)->mName << LL_ENDL;
+ LL_INFOS() << ptr->mName << LL_ENDL;
+ unused.emplace_back(ptr->mName);
}
}
}
@@ -170,36 +183,43 @@ void LLGLSLShader::clearStats()
mBinds = 0;
}
-void LLGLSLShader::dumpStats()
+void LLGLSLShader::dumpStats(boost::json::object& stats)
{
- if (mBinds > 0)
+ stats.emplace("name", mName);
+ auto filesit = stats.emplace("files", boost::json::array_kind).first;
+ auto& files = filesit->value().as_array();
+ LL_INFOS() << "=============================================" << LL_ENDL;
+ LL_INFOS() << mName << LL_ENDL;
+ for (U32 i = 0; i < mShaderFiles.size(); ++i)
{
- LL_INFOS() << "=============================================" << LL_ENDL;
- LL_INFOS() << mName << LL_ENDL;
- for (U32 i = 0; i < mShaderFiles.size(); ++i)
- {
- LL_INFOS() << mShaderFiles[i].first << LL_ENDL;
- }
- LL_INFOS() << "=============================================" << LL_ENDL;
+ LL_INFOS() << mShaderFiles[i].first << LL_ENDL;
+ files.emplace_back(mShaderFiles[i].first);
+ }
+ LL_INFOS() << "=============================================" << LL_ENDL;
- F32 ms = mTimeElapsed / 1000000.f;
- F32 seconds = ms / 1000.f;
+ constexpr float mega = 1'000'000.f;
+ constexpr double giga = 1'000'000'000.0;
+ F32 ms = mTimeElapsed / mega;
+ F32 seconds = ms / 1000.f;
- F32 pct_tris = (F32)mTrianglesDrawn / (F32)sTotalTrianglesDrawn * 100.f;
- F32 tris_sec = (F32)(mTrianglesDrawn / 1000000.0);
- tris_sec /= seconds;
+ F32 pct_tris = (F32)mTrianglesDrawn / (F32)sTotalTrianglesDrawn * 100.f;
+ F32 tris_sec = (F32)(mTrianglesDrawn / mega);
+ tris_sec /= seconds;
- F32 pct_samples = (F32)((F64)mSamplesDrawn / (F64)sTotalSamplesDrawn) * 100.f;
- F32 samples_sec = (F32)(mSamplesDrawn / 1000000000.0);
- samples_sec /= seconds;
+ F32 pct_samples = (F32)((F64)mSamplesDrawn / (F64)sTotalSamplesDrawn) * 100.f;
+ F32 samples_sec = (F32)(mSamplesDrawn / giga);
+ samples_sec /= seconds;
- F32 pct_binds = (F32)mBinds / (F32)sTotalBinds * 100.f;
+ F32 pct_binds = (F32)mBinds / (F32)sTotalBinds * 100.f;
- LL_INFOS() << "Triangles Drawn: " << mTrianglesDrawn << " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec) << LL_ENDL;
- LL_INFOS() << "Binds: " << mBinds << " " << llformat("(%.2f pct of total)", pct_binds) << LL_ENDL;
- LL_INFOS() << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << LL_ENDL;
- LL_INFOS() << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32)((F64)mTimeElapsed / (F64)sTotalTimeElapsed) * 100.f, ms) << LL_ENDL;
- }
+ LL_INFOS() << "Triangles Drawn: " << mTrianglesDrawn << " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec) << LL_ENDL;
+ LL_INFOS() << "Binds: " << mBinds << " " << llformat("(%.2f pct of total)", pct_binds) << LL_ENDL;
+ LL_INFOS() << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << LL_ENDL;
+ LL_INFOS() << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32)((F64)mTimeElapsed / (F64)sTotalTimeElapsed) * 100.f, ms) << LL_ENDL;
+ stats.emplace("time", seconds);
+ stats.emplace("binds", mBinds);
+ stats.emplace("samples", mSamplesDrawn);
+ stats.emplace("triangles", mTrianglesDrawn);
}
//static
@@ -307,16 +327,15 @@ bool LLGLSLShader::readProfileQuery(bool for_runtime, bool force_read)
GLuint64 primitives_generated = 0;
glGetQueryObjectui64v(mPrimitivesQuery, GL_QUERY_RESULT, &primitives_generated);
#else
- GLuint samples_passed = 0;
- glGetQueryObjectuiv(mSamplesQuery, GL_QUERY_RESULT, &samples_passed);
-
GLuint primitives_generated = 0;
glGetQueryObjectuiv(mPrimitivesQuery, GL_QUERY_RESULT, &primitives_generated);
#endif
sTotalTimeElapsed += time_elapsed;
+#if GL_VERSION_1_5
sTotalSamplesDrawn += samples_passed;
mSamplesDrawn += samples_passed;
+#endif
U32 tri_count = (U32)primitives_generated / 3;
@@ -1065,7 +1084,7 @@ void LLGLSLShader::bind()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(mProgramObject != 0);
+ llassert_always(mProgramObject != 0);
gGL.flush();
@@ -1088,12 +1107,15 @@ void LLGLSLShader::bind()
LLShaderMgr::instance()->updateShaderUniforms(this);
mUniformsDirty = false;
}
+
+ llassert_always(sCurBoundShaderPtr != nullptr);
+ llassert_always(sCurBoundShader == mProgramObject);
}
void LLGLSLShader::bind(U8 variant)
{
- llassert(mGLTFVariants.size() == LLGLSLShader::NUM_GLTF_VARIANTS);
- llassert(variant < LLGLSLShader::NUM_GLTF_VARIANTS);
+ llassert_always(mGLTFVariants.size() == LLGLSLShader::NUM_GLTF_VARIANTS);
+ llassert_always(variant < LLGLSLShader::NUM_GLTF_VARIANTS);
mGLTFVariants[variant].bind();
}
@@ -1101,7 +1123,7 @@ void LLGLSLShader::bind(bool rigged)
{
if (rigged)
{
- llassert(mRiggedVariant);
+ llassert_always(mRiggedVariant);
mRiggedVariant->bind();
}
else
@@ -1126,17 +1148,17 @@ void LLGLSLShader::unbind(void)
sCurBoundShaderPtr = NULL;
}
-S32 LLGLSLShader::bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
+S32 LLGLSLShader::bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
S32 channel = 0;
channel = getUniformLocation(uniform);
- return bindTexture(channel, texture, mode, colorspace);
+ return bindTexture(channel, texture, mode);
}
-S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
+S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@@ -1152,7 +1174,6 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextu
if (uniform > -1)
{
gGL.getTexUnit(uniform)->bindFast(texture);
- gGL.getTexUnit(uniform)->setTextureColorSpace(colorspace);
}
return uniform;
@@ -1233,7 +1254,7 @@ S32 LLGLSLShader::getTextureChannel(S32 uniform) const
return mTexture[uniform];
}
-S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
+S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@@ -1250,12 +1271,11 @@ S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTex
{
gGL.getTexUnit(index)->activate();
gGL.getTexUnit(index)->enable(mode);
- gGL.getTexUnit(index)->setTextureColorSpace(space);
}
return index;
}
-S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
+S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@@ -1265,23 +1285,40 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTe
llassert(false);
return -1;
}
+
S32 index = mTexture[uniform];
- if (index != -1 && gGL.getTexUnit(index)->getCurrType() != LLTexUnit::TT_NONE)
+ if (index < 0)
+ {
+ // Invalid texture index - nothing to disable
+ return index;
+ }
+
+ LLTexUnit* tex_unit = gGL.getTexUnit(index);
+ if (!tex_unit)
{
- if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode && gGL.getTexUnit(index)->getCurrColorSpace() != space)
+ // Invalid texture unit
+ LL_WARNS_ONCE("Shader") << "Invalid texture unit at index: " << index << LL_ENDL;
+ return index;
+ }
+
+ LLTexUnit::eTextureType curr_type = tex_unit->getCurrType();
+ if (curr_type != LLTexUnit::TT_NONE)
+ {
+ if (gDebugGL && curr_type != mode)
{
if (gDebugSession)
{
- gFailLog << "Texture channel " << index << " texture type corrupted." << std::endl;
+ gFailLog << "Texture channel " << index << " texture type corrupted. Expected: " << mode << ", Found: " << curr_type << std::endl;
ll_fail("LLGLSLShader::disableTexture failed");
}
else
{
- LL_ERRS() << "Texture channel " << index << " texture type corrupted." << LL_ENDL;
+ LL_ERRS() << "Texture channel " << index << " texture type corrupted. Expected: " << mode << ", Found: " << curr_type << LL_ENDL;
}
}
- gGL.getTexUnit(index)->disable();
+ tex_unit->disable();
}
+
return index;
}
@@ -1591,6 +1628,34 @@ void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v)
}
}
+void LLGLSLShader::uniform4uiv(U32 index, U32 count, const GLuint* v)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+ llassert(sCurBoundShaderPtr == this);
+
+ if (mProgramObject)
+ {
+ if (mUniform.size() <= index)
+ {
+ LL_WARNS_ONCE("Shader") << "Uniform index out of bounds. Size: " << (S32)mUniform.size() << " index: " << index << LL_ENDL;
+ llassert(false);
+ return;
+ }
+
+ if (mUniform[index] >= 0)
+ {
+ const auto& iter = mValue.find(mUniform[index]);
+ LLVector4 vec((F32)v[0], (F32)v[1], (F32)v[2], (F32)v[3]);
+ if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+ glUniform4uiv(mUniform[index], count, v);
+ mValue[mUniform[index]] = vec;
+ }
+ }
+ }
+}
+
void LLGLSLShader::uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@@ -1856,6 +1921,23 @@ void LLGLSLShader::uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLf
}
}
+void LLGLSLShader::uniform4f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+ GLint location = getUniformLocation(uniform);
+
+ if (location >= 0)
+ {
+ const auto& iter = mValue.find(location);
+ LLVector4 vec(x, y, z, w);
+ if (iter == mValue.end() || shouldChange(iter->second, vec))
+ {
+ glUniform4f(location, x, y, z, w);
+ mValue[location] = vec;
+ }
+ }
+}
+
void LLGLSLShader::uniform1fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@@ -1925,6 +2007,24 @@ void LLGLSLShader::uniform4fv(const LLStaticHashedString& uniform, U32 count, co
}
}
+void LLGLSLShader::uniform4uiv(const LLStaticHashedString& uniform, U32 count, const GLuint* v)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+ GLint location = getUniformLocation(uniform);
+
+ if (location >= 0)
+ {
+ LLVector4 vec((F32)v[0], (F32)v[1], (F32)v[2], (F32)v[3]);
+ const auto& iter = mValue.find(location);
+ if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+ glUniform4uiv(location, count, v);
+ mValue[location] = vec;
+ }
+ }
+}
+
void LLGLSLShader::uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 86e5625dca..873ab0cff5 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -30,6 +30,7 @@
#include "llgl.h"
#include "llrender.h"
#include "llstaticstringtable.h"
+#include <boost/json.hpp>
#include <unordered_map>
class LLShaderFeatures
@@ -51,12 +52,14 @@ public:
bool hasAmbientOcclusion = false;
bool hasSrgb = false;
bool isDeferred = false;
+ bool hasFullGBuffer = false;
bool hasScreenSpaceReflections = false;
bool hasAlphaMask = false;
bool hasReflectionProbes = false;
bool attachNothing = false;
bool hasHeroProbes = false;
bool isPBRTerrain = false;
+ bool hasTonemap = false;
};
// ============= Structure for caching shader uniforms ===============
@@ -169,14 +172,14 @@ public:
static U32 sMaxGLTFNodes;
static void initProfile();
- static void finishProfile(bool emit_report = true);
+ static void finishProfile(boost::json::value& stats=sDefaultStats);
static void startProfile();
static void stopProfile();
void unload();
void clearStats();
- void dumpStats();
+ void dumpStats(boost::json::object& stats);
// place query objects for profiling if profiling is enabled
// if for_runtime is true, will place timer query only whether or not profiling is enabled
@@ -208,6 +211,7 @@ public:
void uniform2fv(U32 index, U32 count, const GLfloat* v);
void uniform3fv(U32 index, U32 count, const GLfloat* v);
void uniform4fv(U32 index, U32 count, const GLfloat* v);
+ void uniform4uiv(U32 index, U32 count, const GLuint* v);
void uniform2i(const LLStaticHashedString& uniform, GLint i, GLint j);
void uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v);
void uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v);
@@ -219,10 +223,12 @@ public:
void uniform1f(const LLStaticHashedString& uniform, GLfloat v);
void uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y);
void uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z);
+ void uniform4f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void uniform1fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
void uniform2fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
void uniform3fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
void uniform4fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
+ void uniform4uiv(const LLStaticHashedString& uniform, U32 count, const GLuint* v);
void uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat* v);
void setMinimumAlpha(F32 minimum);
@@ -239,6 +245,10 @@ public:
void clearPermutations();
void addPermutation(std::string name, std::string value);
+ void addPermutations(const std::map<std::string, std::string>& defines)
+ {
+ mDefines.insert(defines.begin(), defines.end());
+ }
void removePermutation(std::string name);
void addConstant(const LLGLSLShader::eShaderConsts shader_const);
@@ -247,16 +257,16 @@ public:
//if given texture uniform is active in the shader,
//the corresponding channel will be active upon return
//returns channel texture is enabled in from [0-MAX)
- S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
- S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
+ S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
+ S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
// get the texture channel of the given uniform, or -1 if uniform is not used as a texture
S32 getTextureChannel(S32 uniform) const;
// bindTexture returns the texture unit we've bound the texture to.
// You can reuse the return value to unbind a texture when required.
- S32 bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
- S32 bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
+ S32 bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
+ S32 bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
S32 bindTexture(const std::string& uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR);
S32 bindTexture(S32 uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR, U32 index = 0);
S32 unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
@@ -357,6 +367,11 @@ public:
private:
void unloadInternal();
+ // This must be static because finishProfile() is called at least once
+ // within a __try block. If we default its stats parameter to a temporary
+ // json::value, that temporary must be destroyed when the stack is
+ // unwound, which __try forbids.
+ static boost::json::value sDefaultStats;
};
//UI shader (declared here so llui_libtest will link properly)
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 23216e586f..0146ed3119 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -51,6 +51,7 @@ extern LL_COMMON_API bool on_main_thread();
//----------------------------------------------------------------------------
const F32 MIN_TEXTURE_LIFETIME = 10.f;
+const F32 CONVERSION_SCRATCH_BUFFER_GL_VERSION = 3.29f;
//which power of 2 is i?
//assumes i is a power of 2 > 0
@@ -67,12 +68,13 @@ static U64 sTextureBytes = 0;
// track a texture alloc on the currently bound texture.
// asserts that no currently tracked alloc exists
-void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 pixformat)
+void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 intformat, U32 count)
{
U32 texUnit = gGL.getCurrentTexUnitIndex();
llassert(texUnit == 0); // allocations should always be done on tex unit 0
U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture();
- U64 size = LLImageGL::dataFormatBytes(pixformat, width, height);
+ U64 size = LLImageGL::dataFormatBytes(intformat, width, height);
+ size *= count;
llassert(size >= 0);
@@ -159,6 +161,7 @@ S32 LLImageGL::sMaxCategories = 1 ;
bool LLImageGL::sSkipAnalyzeAlpha;
U32 LLImageGL::sScratchPBO = 0;
U32 LLImageGL::sScratchPBOSize = 0;
+U32* LLImageGL::sManualScratch = nullptr;
//------------------------
@@ -256,8 +259,24 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, bool skip_analyz
if (thread_texture_loads || thread_media_updates)
{
LLImageGLThread::createInstance(window);
- LLImageGLThread::sEnabledTextures = thread_texture_loads;
- LLImageGLThread::sEnabledMedia = thread_media_updates;
+ LLImageGLThread::sEnabledTextures = gGLManager.mGLVersion > 3.95f ? thread_texture_loads : false;
+ LLImageGLThread::sEnabledMedia = gGLManager.mGLVersion > 3.95f ? thread_media_updates : false;
+ }
+}
+
+void LLImageGL::allocateConversionBuffer()
+{
+ if (gGLManager.mGLVersion < CONVERSION_SCRATCH_BUFFER_GL_VERSION)
+ {
+ try
+ {
+ sManualScratch = new U32[MAX_IMAGE_AREA];
+ }
+ catch (std::bad_alloc&)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS() << "Failed to allocate sManualScratch" << LL_ENDL;
+ }
}
}
@@ -272,6 +291,8 @@ void LLImageGL::cleanupClass()
sScratchPBO = 0;
sScratchPBOSize = 0;
}
+
+ delete[] sManualScratch;
}
@@ -280,6 +301,27 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
{
switch (dataformat)
{
+#if GL_VERSION_3_0
+ case GL_COMPRESSED_RED: return 8;
+ case GL_COMPRESSED_RG: return 16;
+#endif
+#if GL_VERSION_1_3
+ case GL_COMPRESSED_RGB: return 24;
+#endif
+#if GL_VERSION_2_1
+ case GL_COMPRESSED_SRGB: return 32;
+#endif
+#if GL_VERSION_1_3
+ case GL_COMPRESSED_RGBA: return 32;
+#endif
+#if GL_VERSION_2_1
+ case GL_COMPRESSED_SRGB_ALPHA: return 32;
+#endif
+#if GL_VERSION_1_3
+ case GL_COMPRESSED_LUMINANCE: return 8;
+ case GL_COMPRESSED_LUMINANCE_ALPHA: return 16;
+ case GL_COMPRESSED_ALPHA: return 8;
+#endif
#if GL_EXT_texture_compression_s3tc || GL_EXT_texture_compression_dxt1
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4;
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8;
@@ -293,23 +335,39 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
case GL_LUMINANCE: return 8;
case GL_ALPHA: return 8;
case GL_RED: return 8;
+ case GL_R8: return 8;
#if GL_VERSION_1_1
+ case GL_LUMINANCE8: return 8;
+ case GL_ALPHA8: return 8;
case GL_COLOR_INDEX: return 8;
+ case GL_LUMINANCE8_ALPHA8: return 16;
#endif
case GL_LUMINANCE_ALPHA: return 16;
+ case GL_RG: return 16;
+ case GL_RG8: return 16;
case GL_RGB: return 24;
case GL_SRGB: return 24;
case GL_RGB8: return 24;
+ case GL_R11F_G11F_B10F: return 32;
case GL_RGBA: return 32;
+ case GL_RGBA8: return 32;
+ case GL_RGB10_A2: return 32;
#if GL_VERSION_2_1
case GL_SRGB_ALPHA: return 32;
case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac
#endif
case GL_DEPTH_COMPONENT: return 24;
+ case GL_DEPTH_COMPONENT24: return 24;
+ case GL_R16F: return 16;
+ case GL_RG16F: return 32;
case GL_RGB16F: return 48;
case GL_RGBA16F: return 64;
+ case GL_R32F: return 32;
+ case GL_RG32F: return 64;
+ case GL_RGB32F: return 96;
+ case GL_RGBA32F: return 128;
default:
- LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL;
+ LL_ERRS() << "LLImageGL::Unknown format: " << std::hex << dataformat << std::dec << LL_ENDL;
return 0;
}
}
@@ -361,6 +419,7 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
case GL_COLOR_INDEX: return 1;
#endif
case GL_LUMINANCE_ALPHA: return 2;
+ case GL_RG: return 2;
case GL_RGB: return 3;
case GL_SRGB: return 3;
case GL_RGBA: return 4;
@@ -369,7 +428,7 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac
#endif
default:
- LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL;
+ LL_ERRS() << "LLImageGL::Unknown format: " << std::hex << dataformat << std::dec << LL_ENDL;
return 0;
}
}
@@ -381,6 +440,8 @@ void LLImageGL::updateStats(F32 current_time)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
sLastFrameTime = current_time;
+ sBindCount = 0;
+ sUniqueCount = 0;
}
//----------------------------------------------------------------------------
@@ -430,29 +491,29 @@ bool LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, b
//----------------------------------------------------------------------------
-LLImageGL::LLImageGL(bool usemipmaps)
+LLImageGL::LLImageGL(bool usemipmaps/* = true*/, bool allow_compression/* = true*/)
: mSaveData(0), mExternalTexture(false)
{
- init(usemipmaps);
+ init(usemipmaps, allow_compression);
setSize(0, 0, 0);
sImageList.insert(this);
sCount++;
}
-LLImageGL::LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps)
+LLImageGL::LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps/* = true*/, bool allow_compression/* = true*/)
: mSaveData(0), mExternalTexture(false)
{
llassert( components <= 4 );
- init(usemipmaps);
+ init(usemipmaps, allow_compression);
setSize(width, height, components);
sImageList.insert(this);
sCount++;
}
-LLImageGL::LLImageGL(const LLImageRaw* imageraw, bool usemipmaps)
+LLImageGL::LLImageGL(const LLImageRaw* imageraw, bool usemipmaps/* = true*/, bool allow_compression/* = true*/)
: mSaveData(0), mExternalTexture(false)
{
- init(usemipmaps);
+ init(usemipmaps, allow_compression);
setSize(0, 0, 0);
sImageList.insert(this);
sCount++;
@@ -469,7 +530,7 @@ LLImageGL::LLImageGL(
LLGLenum formatType,
LLTexUnit::eTextureAddressMode addressMode)
{
- init(false);
+ init(false, true);
mTexName = texName;
mTarget = target;
mComponents = components;
@@ -491,7 +552,7 @@ LLImageGL::~LLImageGL()
}
}
-void LLImageGL::init(bool usemipmaps)
+void LLImageGL::init(bool usemipmaps, bool allow_compression)
{
#if LL_IMAGEGL_THREAD_CHECK
mActiveThread = LLThread::currentID();
@@ -521,7 +582,7 @@ void LLImageGL::init(bool usemipmaps)
mHeight = 0;
mCurrentDiscardLevel = -1;
- mAllowCompression = true;
+ mAllowCompression = allow_compression;
mTarget = GL_TEXTURE_2D;
mBindTarget = LLTexUnit::TT_TEXTURE;
@@ -1045,7 +1106,7 @@ U32 type_width_from_pixtype(U32 pixtype)
bool should_stagger_image_set(bool compressed)
{
#if LL_DARWIN
- return false;
+ return !compressed && on_main_thread() && gGLManager.mIsAMD;
#else
// glTexSubImage2D doesn't work with compressed textures on select tested Nvidia GPUs on Windows 10 -Cosmic,2023-03-08
// Setting media textures off-thread seems faster when not using sub_image_lines (Nvidia/Windows 10) -Cosmic,2023-03-31
@@ -1059,15 +1120,47 @@ void sub_image_lines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 w
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ LL_PROFILE_ZONE_NUM(width);
+ LL_PROFILE_ZONE_NUM(height);
+
U32 components = LLImageGL::dataFormatComponents(pixformat);
U32 type_width = type_width_from_pixtype(pixtype);
const U32 line_width = data_width * components * type_width;
const U32 y_offset_end = y_offset + height;
- for (U32 y_pos = y_offset; y_pos < y_offset_end; ++y_pos)
+
+ if (width == data_width && height % 32 == 0)
{
- glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src);
- src += line_width;
+ LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("subimage - batched lines");
+
+ // full width, batch multiple lines at a time
+ // set batch size based on width
+ U32 batch_size = 32;
+
+ if (width > 1024)
+ {
+ batch_size = 8;
+ }
+ else if (width > 512)
+ {
+ batch_size = 16;
+ }
+
+ // full width texture, do 32 lines at a time
+ for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += batch_size)
+ {
+ glTexSubImage2D(target, miplevel, x_offset, y_pos, width, batch_size, pixformat, pixtype, src);
+ src += line_width * batch_size;
+ }
+ }
+ else
+ {
+ // partial width or strange height
+ for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += 1)
+ {
+ glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src);
+ src += line_width;
+ }
}
}
@@ -1235,37 +1328,37 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
}
}
+constexpr int DELETE_DELAY = 3; // number of frames to wait before deleting textures
+static std::vector<U32> sFreeList[DELETE_DELAY+1];
+
// static
void LLImageGL::updateClass()
{
sFrameCount++;
+
+ // wait a few frames before actually deleting the textures to avoid
+ // synchronization issues with the GPU
+ U32 idx = (sFrameCount+DELETE_DELAY) % (DELETE_DELAY+1);
+
+ if (!sFreeList[idx].empty())
+ {
+ free_tex_images((GLsizei) sFreeList[idx].size(), sFreeList[idx].data());
+ glDeleteTextures((GLsizei)sFreeList[idx].size(), sFreeList[idx].data());
+ sFreeList[idx].resize(0);
+ }
}
// static
void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures)
{
- // wait a few frames before actually deleting the textures to avoid
- // synchronization issues with the GPU
- static std::vector<U32> sFreeList[4];
-
if (gGLManager.mInited)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- U32 idx = sFrameCount % 4;
-
+ U32 idx = sFrameCount % (DELETE_DELAY+1);
for (S32 i = 0; i < numTextures; ++i)
{
sFreeList[idx].push_back(textures[i]);
}
-
- idx = (sFrameCount + 3) % 4;
-
- if (!sFreeList[idx].empty())
- {
- free_tex_images((GLsizei) sFreeList[idx].size(), sFreeList[idx].data());
- glDeleteTextures((GLsizei)sFreeList[idx].size(), sFreeList[idx].data());
- sFreeList[idx].resize(0);
- }
}
}
@@ -1273,90 +1366,103 @@ void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures)
void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void* pixels, bool allow_compression)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- bool use_scratch = false;
- U32* scratch = NULL;
if (LLRender::sGLCoreProfile)
{
- if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)
- { //GL_ALPHA is deprecated, convert to RGBA
- if (pixels != nullptr)
- {
- use_scratch = true;
- scratch = new(std::nothrow) U32[width * height];
- if (!scratch)
- {
- LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
- << " bytes for a manual image W" << width << " H" << height << LL_ENDL;
- }
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ if (gGLManager.mGLVersion >= CONVERSION_SCRATCH_BUFFER_GL_VERSION)
+ {
+ if (pixformat == GL_ALPHA)
+ { //GL_ALPHA is deprecated, convert to RGBA
+#if GL_VERSION_3_3
+ const GLint mask[] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
+#endif
+ pixformat = GL_RED;
+ intformat = GL_R8;
+ }
- U32 pixel_count = (U32)(width * height);
- for (U32 i = 0; i < pixel_count; i++)
- {
- U8* pix = (U8*)&scratch[i];
- pix[0] = pix[1] = pix[2] = 0;
- pix[3] = ((U8*)pixels)[i];
- }
+ if (pixformat == GL_LUMINANCE)
+ { //GL_LUMINANCE is deprecated, convert to GL_RGBA
+#if GL_VERSION_3_3
+ const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
+#endif
+ pixformat = GL_RED;
+ intformat = GL_R8;
}
- pixformat = GL_RGBA;
- intformat = GL_RGBA8;
+ if (pixformat == GL_LUMINANCE_ALPHA)
+ { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
+#if GL_VERSION_3_3
+ const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
+#endif
+ pixformat = GL_RG;
+ intformat = GL_RG8;
+ }
}
-
- if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE)
- { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
- if (pixels != nullptr)
- {
- use_scratch = true;
- scratch = new(std::nothrow) U32[width * height];
- if (!scratch)
+ else
+ {
+ if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)
+ { //GL_ALPHA is deprecated, convert to RGBA
+ if (pixels != nullptr)
{
- LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
- << " bytes for a manual image W" << width << " H" << height << LL_ENDL;
+ U32 pixel_count = (U32)(width * height);
+ for (U32 i = 0; i < pixel_count; i++)
+ {
+ U8* pix = (U8*)&sManualScratch[i];
+ pix[0] = pix[1] = pix[2] = 0;
+ pix[3] = ((U8*)pixels)[i];
+ }
+
+ pixels = sManualScratch;
}
- U32 pixel_count = (U32)(width * height);
- for (U32 i = 0; i < pixel_count; i++)
+ pixformat = GL_RGBA;
+ intformat = GL_RGBA8;
+ }
+
+ if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE)
+ { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
+ if (pixels != nullptr)
{
- U8 lum = ((U8*)pixels)[i * 2 + 0];
- U8 alpha = ((U8*)pixels)[i * 2 + 1];
+ U32 pixel_count = (U32)(width * height);
+ for (U32 i = 0; i < pixel_count; i++)
+ {
+ U8 lum = ((U8*)pixels)[i * 2 + 0];
+ U8 alpha = ((U8*)pixels)[i * 2 + 1];
- U8* pix = (U8*)&scratch[i];
- pix[0] = pix[1] = pix[2] = lum;
- pix[3] = alpha;
+ U8* pix = (U8*)&sManualScratch[i];
+ pix[0] = pix[1] = pix[2] = lum;
+ pix[3] = alpha;
+ }
+
+ pixels = sManualScratch;
}
- }
- pixformat = GL_RGBA;
- intformat = GL_RGBA8;
- }
+ pixformat = GL_RGBA;
+ intformat = GL_RGBA8;
+ }
- if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE)
- { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
- if (pixels != nullptr)
- {
- use_scratch = true;
- scratch = new(std::nothrow) U32[width * height];
- if (!scratch)
+ if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE)
+ { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
+ if (pixels != nullptr)
{
- LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
- << " bytes for a manual image W" << width << " H" << height << LL_ENDL;
- }
+ U32 pixel_count = (U32)(width * height);
+ for (U32 i = 0; i < pixel_count; i++)
+ {
+ U8 lum = ((U8*)pixels)[i];
- U32 pixel_count = (U32)(width * height);
- for (U32 i = 0; i < pixel_count; i++)
- {
- U8 lum = ((U8*)pixels)[i];
+ U8* pix = (U8*)&sManualScratch[i];
+ pix[0] = pix[1] = pix[2] = lum;
+ pix[3] = 255;
+ }
- U8* pix = (U8*)&scratch[i];
- pix[0] = pix[1] = pix[2] = lum;
- pix[3] = 255;
+ pixels = sManualScratch;
}
+ pixformat = GL_RGBA;
+ intformat = GL_RGB8;
}
- pixformat = GL_RGBA;
- intformat = GL_RGB8;
}
}
@@ -1365,6 +1471,18 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
{
switch (intformat)
{
+ case GL_RED:
+ case GL_R8:
+#if GL_VERSION_3_0
+ intformat = GL_COMPRESSED_RED;
+#endif
+ break;
+ case GL_RG:
+ case GL_RG8:
+#if GL_VERSION_3_0
+ intformat = GL_COMPRESSED_RG;
+#endif
+ break;
case GL_RGB:
case GL_RGB8:
#if GL_VERSION_1_3
@@ -1413,14 +1531,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
intformat = GL_COMPRESSED_ALPHA;
#endif
break;
- case GL_RED:
- case GL_R8:
-#if GL_VERSION_3_0
- intformat = GL_COMPRESSED_RED;
-#endif
- break;
default:
- LL_WARNS() << "Could not compress format: " << std::hex << intformat << LL_ENDL;
+ LL_WARNS() << "Could not compress format: " << std::hex << intformat << std::dec << LL_ENDL;
break;
}
}
@@ -1436,7 +1548,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
if (!use_sub_image)
{
LL_PROFILE_ZONE_NAMED("glTexImage2D alloc + copy");
- glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
+ glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels);
}
else
{
@@ -1446,21 +1558,16 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, nullptr);
}
- U8* src = (U8*)(use_scratch ? scratch : pixels);
+ U8* src = (U8*)(pixels);
if (src)
{
LL_PROFILE_ZONE_NAMED("glTexImage2D copy");
sub_image_lines(target, miplevel, 0, 0, width, height, pixformat, pixtype, src, width);
}
}
- alloc_tex_image(width, height, pixformat);
+ alloc_tex_image(width, height, intformat, 1);
}
stop_glerror();
-
- if (use_scratch)
- {
- delete[] scratch;
- }
}
//create an empty GL texture: just create a texture name
@@ -1762,7 +1869,7 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name)
ref();
LL::WorkQueue::postMaybe(
mMainQueue,
- [=]()
+ [=, this]()
{
LL_PROFILE_ZONE_NAMED("cglt - delete callback");
syncTexName(new_tex_name);
@@ -2170,6 +2277,8 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
return ;
}
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+
U32 length = w * h;
U32 alphatotal = 0;
@@ -2183,13 +2292,13 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
// suffer the worst from aliasing when used as alpha masks.
if (w >= 2 && h >= 2)
{
- llassert(w%2 == 0);
- llassert(h%2 == 0);
+ llassert(w % 2 == 0);
+ llassert(h % 2 == 0);
const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset;
- for (U32 y = 0; y < h; y+=2)
+ for (U32 y = 0; y < h; y += 2)
{
const GLubyte* current = rowstart;
- for (U32 x = 0; x < w; x+=2)
+ for (U32 x = 0; x < w; x += 2)
{
const U32 s1 = current[0];
alphatotal += s1;
@@ -2212,7 +2321,6 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
sample[asum/(16*4)] += 4;
}
-
rowstart += 2 * w * mAlphaStride;
}
length *= 2; // we sampled everything twice, essentially
@@ -2442,7 +2550,9 @@ bool LLImageGL::scaleDown(S32 desired_discard)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- if (mTarget != GL_TEXTURE_2D)
+ if (mTarget != GL_TEXTURE_2D
+ || mFormatInternal == -1 // not initialized
+ )
{
return false;
}
@@ -2461,41 +2571,32 @@ bool LLImageGL::scaleDown(S32 desired_discard)
if (gGLManager.mDownScaleMethod == 0)
{ // use an FBO to downscale the texture
- // allocate new texture
- U32 temp_texname = 0;
- generateTextures(1, &temp_texname);
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, temp_texname, true);
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glTexImage2D");
- glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, NULL);
- }
-
- // account for new texture getting created
- alloc_tex_image(desired_width, desired_height, mFormatPrimary);
-
- // Use render-to-texture to scale down the texture
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glFramebufferTexture2D");
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTarget, temp_texname, 0);
- }
-
glViewport(0, 0, desired_width, desired_height);
// draw a full screen triangle
- gGL.getTexUnit(0)->bind(this);
- glDrawArrays(GL_TRIANGLES, 0, 3);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ if (gGL.getTexUnit(0)->bind(this, true, true))
+ {
+ glDrawArrays(GL_TRIANGLES, 0, 3);
- // delete old texture and assign new texture name
- deleteTextures(1, &mTexName);
- mTexName = temp_texname;
+ free_tex_image(mTexName);
+ glTexImage2D(mTarget, 0, mFormatInternal, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr);
+ glCopyTexSubImage2D(mTarget, 0, 0, 0, 0, 0, desired_width, desired_height);
+ alloc_tex_image(desired_width, desired_height, mFormatInternal, 1);
- if (mHasMipMaps)
- { // generate mipmaps if needed
- LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap");
- gGL.getTexUnit(0)->bind(this);
- glGenerateMipmap(mTarget);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ mTexOptionsDirty = true;
+
+ if (mHasMipMaps)
+ { // generate mipmaps if needed
+ LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap");
+ gGL.getTexUnit(0)->bind(this);
+ glGenerateMipmap(mTarget);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+ }
+ else
+ {
+ LL_WARNS_ONCE("LLImageGL") << "Failed to bind texture for downscaling." << LL_ENDL;
+ return false;
}
}
else
@@ -2518,17 +2619,19 @@ bool LLImageGL::scaleDown(S32 desired_discard)
sScratchPBOSize = (U32)size;
}
+#if GL_VERSION_1_3
glGetTexImage(mTarget, mip, mFormatPrimary, mFormatType, nullptr);
+#endif
free_tex_image(mTexName);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sScratchPBO);
- glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr);
+ glTexImage2D(mTarget, 0, mFormatInternal, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- alloc_tex_image(desired_width, desired_height, mFormatPrimary);
+ alloc_tex_image(desired_width, desired_height, mFormatInternal, 1);
if (mHasMipMaps)
{
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 5073701c30..6b4492c09e 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -50,7 +50,7 @@ class LLWindow;
namespace LLImageGLMemory
{
- void alloc_tex_image(U32 width, U32 height, U32 pixformat);
+ void alloc_tex_image(U32 width, U32 height, U32 intformat, U32 count);
void free_tex_image(U32 texName);
void free_tex_images(U32 count, const U32* texNames);
void free_cur_tex_image();
@@ -101,9 +101,9 @@ public:
static bool create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, bool usemipmaps = true);
public:
- LLImageGL(bool usemipmaps = true);
- LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps = true);
- LLImageGL(const LLImageRaw* imageraw, bool usemipmaps = true);
+ LLImageGL(bool usemipmaps = true, bool allow_compression = true);
+ LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps = true, bool allow_compression = true);
+ LLImageGL(const LLImageRaw* imageraw, bool usemipmaps = true, bool allow_compression = true);
// For wrapping textures created via GL elsewhere with our API only. Use with caution.
LLImageGL(LLGLuint mTexName, U32 components, LLGLenum target, LLGLint formatInternal, LLGLenum formatPrimary, LLGLenum formatType, LLTexUnit::eTextureAddressMode addressMode);
@@ -203,7 +203,7 @@ public:
LLGLenum getTexTarget()const { return mTarget; }
- void init(bool usemipmaps);
+ void init(bool usemipmaps, bool allow_compression);
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);
@@ -298,6 +298,7 @@ public:
public:
static void initClass(LLWindow* window, S32 num_catagories, bool skip_analyze_alpha = false, bool thread_texture_loads = false, bool thread_media_updates = false);
+ static void allocateConversionBuffer();
static void cleanupClass() ;
private:
@@ -305,6 +306,7 @@ private:
static bool sSkipAnalyzeAlpha;
static U32 sScratchPBO;
static U32 sScratchPBOSize;
+ static U32* sManualScratch;
//the flag to allow to call readBackRaw(...).
//can be removed if we do not use that function at all.
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index ca10e10b00..cbb178b6f8 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -36,6 +36,7 @@
#include "lltexture.h"
#include "llshadermgr.h"
#include "hbxxh.h"
+#include "glm/gtc/type_ptr.hpp"
#if LL_WINDOWS
extern void APIENTRY gl_debug_callback(GLenum source,
@@ -50,8 +51,6 @@ extern void APIENTRY gl_debug_callback(GLenum source,
thread_local LLRender gGL;
-const U32 BATCH_SIZE = 16334;
-
// Handy copies of last good GL matrices
F32 gGLModelView[16];
F32 gGLLastModelView[16];
@@ -59,8 +58,8 @@ F32 gGLLastProjection[16];
F32 gGLProjection[16];
// transform from last frame's camera space to this frame's camera space (and inverse)
-F32 gGLDeltaModelView[16];
-F32 gGLInverseDeltaModelView[16];
+glm::mat4 gGLDeltaModelView;
+glm::mat4 gGLInverseDeltaModelView;
S32 gGLViewport[4];
@@ -68,9 +67,10 @@ S32 gGLViewport[4];
U32 LLRender::sUICalls = 0;
U32 LLRender::sUIVerts = 0;
U32 LLTexUnit::sWhiteTexture = 0;
-bool LLRender::sGLCoreProfile = true;
+bool LLRender::sGLCoreProfile = false;
bool LLRender::sNsightDebugSupport = false;
LLVector2 LLRender::sUIGLScaleFactor = LLVector2(1.f, 1.f);
+bool LLRender::sClassicMode = false;
struct LLVBCache
{
@@ -79,6 +79,7 @@ struct LLVBCache
};
static std::unordered_map<U64, LLVBCache> sVBCache;
+static thread_local std::list<LLVertexBufferData> *sBufferDataList = nullptr;
static const GLenum sGLTextureType[] =
{
@@ -123,7 +124,7 @@ static const GLenum sGLBlendFactor[] =
LLTexUnit::LLTexUnit(S32 index)
: mCurrTexType(TT_NONE),
- mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), mTexColorSpace(TCS_LINEAR),
+ mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0),
mHasMipMaps(false),
mIndex(index)
{
@@ -153,8 +154,6 @@ void LLTexUnit::refreshState(void)
{
glBindTexture(GL_TEXTURE_2D, 0);
}
-
- setTextureColorSpace(mTexColorSpace);
}
void LLTexUnit::activate(void)
@@ -249,7 +248,6 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
setTextureAddressMode(gl_tex->mAddressMode);
setTextureFilteringOption(gl_tex->mFilterOption);
}
- setTextureColorSpace(mTexColorSpace);
}
}
else
@@ -326,7 +324,6 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind, S32
setTextureFilteringOption(texture->mFilterOption);
stop_glerror();
}
- setTextureColorSpace(mTexColorSpace);
}
stop_glerror();
@@ -362,7 +359,6 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap)
setTextureAddressMode(cubeMap->mImages[0]->mAddressMode);
setTextureFilteringOption(cubeMap->mImages[0]->mFilterOption);
}
- setTextureColorSpace(mTexColorSpace);
return true;
}
else
@@ -411,7 +407,6 @@ bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips)
mCurrTexture = texture;
glBindTexture(sGLTextureType[type], texture);
mHasMipMaps = hasMips;
- setTextureColorSpace(mTexColorSpace);
}
return true;
}
@@ -432,8 +427,6 @@ void LLTexUnit::unbind(eTextureType type)
{
mCurrTexture = 0;
- // Always make sure our texture color space is reset to linear. SRGB sampling should be opt-in in the vast majority of cases. Also prevents color space "popping".
- mTexColorSpace = TCS_LINEAR;
if (type == LLTexUnit::TT_TEXTURE)
{
glBindTexture(sGLTextureType[type], sWhiteTexture);
@@ -455,8 +448,6 @@ void LLTexUnit::unbindFast(eTextureType type)
{
mCurrTexture = 0;
- // Always make sure our texture color space is reset to linear. SRGB sampling should be opt-in in the vast majority of cases. Also prevents color space "popping".
- mTexColorSpace = TCS_LINEAR;
if (type == LLTexUnit::TT_TEXTURE)
{
glBindTexture(sGLTextureType[type], sWhiteTexture);
@@ -526,7 +517,7 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
}
}
- if (gGLManager.mGLVersion >= 4.59f)
+ if (gGLManager.mHasAnisotropic)
{
if (LLImageGL::sGlobalUseAnisotropic && option == TFO_ANISOTROPIC)
{
@@ -658,11 +649,6 @@ void LLTexUnit::debugTextureUnit(void)
}
}
-void LLTexUnit::setTextureColorSpace(eTextureColorSpace space)
-{
- mTexColorSpace = space;
-}
-
LLLightState::LLLightState(S32 index)
: mIndex(index),
mEnabled(false),
@@ -765,10 +751,9 @@ void LLLightState::setPosition(const LLVector4& position)
++gGL.mLightHash;
mPosition = position;
//transform position by current modelview matrix
- glh::vec4f pos(position.mV);
- const glh::matrix4f& mat = gGL.getModelviewMatrix();
- mat.mult_matrix_vec(pos);
- mPosition.set(pos.v);
+ glm::vec4 pos(position);
+ pos = gGL.getModelviewMatrix() * pos;
+ mPosition.set(glm::value_ptr(pos));
}
void LLLightState::setConstantAttenuation(const F32& atten)
@@ -820,19 +805,18 @@ void LLLightState::setSpotDirection(const LLVector3& direction)
{
//always set direction because modelview matrix may have changed
++gGL.mLightHash;
- mSpotDirection = direction;
+
//transform direction by current modelview matrix
- glh::vec3f dir(direction.mV);
- const glh::matrix4f& mat = gGL.getModelviewMatrix();
- mat.mult_matrix_dir(dir);
+ glm::vec3 dir(direction);
+ const glm::mat3 mat(gGL.getModelviewMatrix());
+ dir = mat * dir;
- mSpotDirection.set(dir.v);
+ mSpotDirection.set(glm::value_ptr(dir));
}
LLRender::LLRender()
: mDirty(false),
mCount(0),
- mQuadCycle(0),
mMode(LLRender::TRIANGLES),
mCurrTextureUnitIndex(0)
{
@@ -860,6 +844,10 @@ LLRender::LLRender()
for (U32 i = 0; i < NUM_MATRIX_MODES; ++i)
{
+ for (U32 j = 0; j < LL_MATRIX_STACK_DEPTH; ++j)
+ {
+ mMatrix[i][j] = glm::identity<glm::mat4>();
+ }
mMatIdx[i] = 0;
mMatHash[i] = 0;
mCurMatHash[i] = 0xFFFFFFFF;
@@ -922,7 +910,7 @@ void LLRender::initVertexBuffer()
llassert_always(mBuffer.isNull());
stop_glerror();
mBuffer = new LLVertexBuffer(immediate_mask);
- mBuffer->allocateBuffer(BATCH_SIZE, 0);
+ mBuffer->allocateBuffer(4096, 0);
mBuffer->getVertexStrider(mVerticesp);
mBuffer->getTexCoord0Strider(mTexcoordsp);
mBuffer->getColorStrider(mColorsp);
@@ -1000,9 +988,13 @@ void LLRender::syncLightState()
shader->uniform3fv(LLShaderMgr::LIGHT_DIFFUSE, LL_NUM_LIGHT_UNITS, diffuse[0].mV);
shader->uniform3fv(LLShaderMgr::LIGHT_AMBIENT, 1, mAmbientLightColor.mV);
shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_primary[0] ? 1 : 0);
- //shader->uniform3fv(LLShaderMgr::AMBIENT, 1, mAmbientLightColor.mV);
- //shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV);
- //shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, 1, diffuse_b[0].mV);
+
+ if (sClassicMode)
+ {
+ shader->uniform3fv(LLShaderMgr::AMBIENT, 1, mAmbientLightColor.mV);
+ shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV);
+ shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, 1, diffuse_b[0].mV);
+ }
}
}
@@ -1023,12 +1015,12 @@ void LLRender::syncMatrices()
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
- static glh::matrix4f cached_mvp;
- static glh::matrix4f cached_inv_mdv;
+ static glm::mat4 cached_mvp;
+ static glm::mat4 cached_inv_mdv;
static U32 cached_mvp_mdv_hash = 0xFFFFFFFF;
static U32 cached_mvp_proj_hash = 0xFFFFFFFF;
- static glh::matrix4f cached_normal;
+ static glm::mat4 cached_normal;
static U32 cached_normal_hash = 0xFFFFFFFF;
if (shader)
@@ -1038,15 +1030,15 @@ void LLRender::syncMatrices()
U32 i = MM_MODELVIEW;
if (mMatHash[MM_MODELVIEW] != shader->mMatHash[MM_MODELVIEW])
{ //update modelview, normal, and MVP
- glh::matrix4f& mat = mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]];
+ const glm::mat4& mat = mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]];
// if MDV has changed, update the cached inverse as well
if (cached_mvp_mdv_hash != mMatHash[MM_MODELVIEW])
{
- cached_inv_mdv = mat.inverse();
+ cached_inv_mdv = glm::inverse(mat);
}
- shader->uniformMatrix4fv(name[MM_MODELVIEW], 1, GL_FALSE, mat.m);
+ shader->uniformMatrix4fv(name[MM_MODELVIEW], 1, GL_FALSE, glm::value_ptr(mat));
shader->mMatHash[MM_MODELVIEW] = mMatHash[MM_MODELVIEW];
//update normal matrix
@@ -1055,17 +1047,17 @@ void LLRender::syncMatrices()
{
if (cached_normal_hash != mMatHash[i])
{
- cached_normal = cached_inv_mdv.transpose();
+ cached_normal = glm::transpose(cached_inv_mdv);
cached_normal_hash = mMatHash[i];
}
- glh::matrix4f& norm = cached_normal;
+ auto norm = glm::value_ptr(cached_normal);
F32 norm_mat[] =
{
- norm.m[0], norm.m[1], norm.m[2],
- norm.m[4], norm.m[5], norm.m[6],
- norm.m[8], norm.m[9], norm.m[10]
+ norm[0], norm[1], norm[2],
+ norm[4], norm[5], norm[6],
+ norm[8], norm[9], norm[10]
};
shader->uniformMatrix3fv(LLShaderMgr::NORMAL_MATRIX, 1, GL_FALSE, norm_mat);
@@ -1073,7 +1065,7 @@ void LLRender::syncMatrices()
if (shader->getUniformLocation(LLShaderMgr::INVERSE_MODELVIEW_MATRIX))
{
- shader->uniformMatrix4fv(LLShaderMgr::INVERSE_MODELVIEW_MATRIX, 1, GL_FALSE, cached_inv_mdv.m);
+ shader->uniformMatrix4fv(LLShaderMgr::INVERSE_MODELVIEW_MATRIX, 1, GL_FALSE, glm::value_ptr(cached_inv_mdv));
}
//update MVP matrix
@@ -1086,36 +1078,36 @@ void LLRender::syncMatrices()
if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION])
{
cached_mvp = mat;
- cached_mvp.mult_left(mMatrix[proj][mMatIdx[proj]]);
+ cached_mvp = mMatrix[proj][mMatIdx[proj]] * cached_mvp;
cached_mvp_mdv_hash = mMatHash[i];
cached_mvp_proj_hash = mMatHash[MM_PROJECTION];
}
- shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m);
+ shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, glm::value_ptr(cached_mvp));
}
}
i = MM_PROJECTION;
if (mMatHash[MM_PROJECTION] != shader->mMatHash[MM_PROJECTION])
{ //update projection matrix, normal, and MVP
- glh::matrix4f& mat = mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]];
+ const glm::mat4& mat = mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]];
// GZ: This was previously disabled seemingly due to a bug involving the deferred renderer's regular pushing and popping of mats.
// We're reenabling this and cleaning up the code around that - that would've been the appropriate course initially.
// Anything beyond the standard proj and inv proj mats are special cases. Please setup special uniforms accordingly in the future.
if (shader->getUniformLocation(LLShaderMgr::INVERSE_PROJECTION_MATRIX))
{
- glh::matrix4f inv_proj = mat.inverse();
- shader->uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, false, inv_proj.m);
+ glm::mat4 inv_proj = glm::inverse(mat);
+ shader->uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, false, glm::value_ptr(inv_proj));
}
// Used by some full screen effects - such as full screen lights, glow, etc.
if (shader->getUniformLocation(LLShaderMgr::IDENTITY_MATRIX))
{
- shader->uniformMatrix4fv(LLShaderMgr::IDENTITY_MATRIX, 1, GL_FALSE, glh::matrix4f::identity().m);
+ shader->uniformMatrix4fv(LLShaderMgr::IDENTITY_MATRIX, 1, GL_FALSE, glm::value_ptr(glm::identity<glm::mat4>()));
}
- shader->uniformMatrix4fv(name[MM_PROJECTION], 1, GL_FALSE, mat.m);
+ shader->uniformMatrix4fv(name[MM_PROJECTION], 1, GL_FALSE, glm::value_ptr(mat));
shader->mMatHash[MM_PROJECTION] = mMatHash[MM_PROJECTION];
if (!mvp_done)
@@ -1128,12 +1120,12 @@ void LLRender::syncMatrices()
{
U32 mdv = MM_MODELVIEW;
cached_mvp = mat;
- cached_mvp.mult_right(mMatrix[mdv][mMatIdx[mdv]]);
+ cached_mvp *= mMatrix[mdv][mMatIdx[mdv]];
cached_mvp_mdv_hash = mMatHash[MM_MODELVIEW];
cached_mvp_proj_hash = mMatHash[MM_PROJECTION];
}
- shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m);
+ shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, glm::value_ptr(cached_mvp));
}
}
}
@@ -1142,7 +1134,7 @@ void LLRender::syncMatrices()
{
if (mMatHash[i] != shader->mMatHash[i])
{
- shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mMatrix[i][mMatIdx[i]].m);
+ shader->uniformMatrix4fv(name[i], 1, GL_FALSE, glm::value_ptr(mMatrix[i][mMatIdx[i]]));
shader->mMatHash[i] = mMatHash[i];
}
}
@@ -1161,12 +1153,7 @@ void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
flush();
{
- glh::matrix4f trans_mat(1,0,0,x,
- 0,1,0,y,
- 0,0,1,z,
- 0,0,0,1);
-
- mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(trans_mat);
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]] = glm::translate(mMatrix[mMatrixMode][mMatIdx[mMatrixMode]], glm::vec3(x, y, z));
mMatHash[mMatrixMode]++;
}
}
@@ -1176,12 +1163,7 @@ void LLRender::scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
flush();
{
- glh::matrix4f scale_mat(x,0,0,0,
- 0,y,0,0,
- 0,0,z,0,
- 0,0,0,1);
-
- mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(scale_mat);
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]] = glm::scale(mMatrix[mMatrixMode][mMatIdx[mMatrixMode]], glm::vec3(x, y, z));
mMatHash[mMatrixMode]++;
}
}
@@ -1191,13 +1173,7 @@ void LLRender::ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zF
flush();
{
-
- glh::matrix4f ortho_mat(2.f/(right-left),0,0, -(right+left)/(right-left),
- 0,2.f/(top-bottom),0, -(top+bottom)/(top-bottom),
- 0,0,-2.f/(zFar-zNear), -(zFar+zNear)/(zFar-zNear),
- 0,0,0,1);
-
- mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(ortho_mat);
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]] *= glm::ortho(left, right, bottom, top, zNear, zFar);
mMatHash[mMatrixMode]++;
}
}
@@ -1207,19 +1183,7 @@ void LLRender::rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, con
flush();
{
- F32 r = a * DEG_TO_RAD;
-
- F32 c = cosf(r);
- F32 s = sinf(r);
-
- F32 ic = 1.f-c;
-
- glh::matrix4f rot_mat(x*x*ic+c, x*y*ic-z*s, x*z*ic+y*s, 0,
- x*y*ic+z*s, y*y*ic+c, y*z*ic-x*s, 0,
- x*z*ic-y*s, y*z*ic+x*s, z*z*ic+c, 0,
- 0,0,0,1);
-
- mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(rot_mat);
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]] = glm::rotate(mMatrix[mMatrixMode][mMatIdx[mMatrixMode]], glm::radians(a), glm::vec3(x,y,z));
mMatHash[mMatrixMode]++;
}
}
@@ -1261,7 +1225,7 @@ void LLRender::loadMatrix(const GLfloat* m)
{
flush();
{
- mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].set_value((GLfloat*) m);
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]] = glm::make_mat4((GLfloat*) m);
mMatHash[mMatrixMode]++;
}
}
@@ -1270,9 +1234,7 @@ void LLRender::multMatrix(const GLfloat* m)
{
flush();
{
- glh::matrix4f mat((GLfloat*) m);
-
- mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(mat);
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]] *= glm::make_mat4(m);
mMatHash[mMatrixMode]++;
}
}
@@ -1315,17 +1277,17 @@ void LLRender::loadIdentity()
{
llassert_always(mMatrixMode < NUM_MATRIX_MODES) ;
- mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].make_identity();
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]] = glm::identity<glm::mat4>();
mMatHash[mMatrixMode]++;
}
}
-const glh::matrix4f& LLRender::getModelviewMatrix()
+const glm::mat4& LLRender::getModelviewMatrix()
{
return mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]];
}
-const glh::matrix4f& LLRender::getProjectionMatrix()
+const glm::mat4& LLRender::getProjectionMatrix()
{
return mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]];
}
@@ -1337,8 +1299,9 @@ void LLRender::translateUI(F32 x, F32 y, F32 z)
LL_ERRS() << "Need to push a UI translation frame before offsetting" << LL_ENDL;
}
- LLVector4a add(x,y,z);
- mUIOffset.back().add(add);
+ mUIOffset.back().mV[0] += x;
+ mUIOffset.back().mV[1] += y;
+ mUIOffset.back().mV[2] += z;
}
void LLRender::scaleUI(F32 x, F32 y, F32 z)
@@ -1348,15 +1311,14 @@ void LLRender::scaleUI(F32 x, F32 y, F32 z)
LL_ERRS() << "Need to push a UI transformation frame before scaling." << LL_ENDL;
}
- LLVector4a scale(x,y,z);
- mUIScale.back().mul(scale);
+ mUIScale.back().scaleVec(LLVector3(x,y,z));
}
void LLRender::pushUIMatrix()
{
if (mUIOffset.empty())
{
- mUIOffset.emplace_back(LLVector4a::getZero());
+ mUIOffset.emplace_back(0.f,0.f,0.f);
}
else
{
@@ -1365,7 +1327,7 @@ void LLRender::pushUIMatrix()
if (mUIScale.empty())
{
- mUIScale.emplace_back(LLVector4a(1.f));
+ mUIScale.emplace_back(1.f,1.f,1.f);
}
else
{
@@ -1389,7 +1351,7 @@ LLVector3 LLRender::getUITranslation()
{
return LLVector3(0,0,0);
}
- return LLVector3(mUIOffset.back().getF32ptr());
+ return mUIOffset.back();
}
LLVector3 LLRender::getUIScale()
@@ -1398,17 +1360,18 @@ LLVector3 LLRender::getUIScale()
{
return LLVector3(1,1,1);
}
- return LLVector3(mUIScale.back().getF32ptr());
+ return mUIScale.back();
}
+
void LLRender::loadUIIdentity()
{
if (mUIOffset.empty())
{
LL_ERRS() << "Need to push UI translation frame before clearing offset." << LL_ENDL;
}
- mUIOffset.back().splat(0.f);
- mUIScale.back().splat(1.f);
+ mUIOffset.back().setVec(0,0,0);
+ mUIScale.back().setVec(1,1,1);
}
void LLRender::setColorMask(bool writeColor, bool writeAlpha)
@@ -1560,17 +1523,35 @@ void LLRender::clearErrors()
}
}
+void LLRender::beginList(std::list<LLVertexBufferData> *list)
+{
+ if (sBufferDataList)
+ {
+ LL_ERRS() << "beginList called while another list is open." << LL_ENDL;
+ }
+ llassert(LLGLSLShader::sCurBoundShaderPtr == &gUIProgram);
+ flush();
+ sBufferDataList = list;
+}
+
+void LLRender::endList()
+{
+ if (sBufferDataList)
+ {
+ flush();
+ sBufferDataList = nullptr;
+ }
+ else
+ {
+ llassert(false); // endList called without an open list
+ }
+}
+
void LLRender::begin(const GLuint& mode)
{
if (mode != mMode)
{
- if (mode == LLRender::QUADS)
- {
- mQuadCycle = 1;
- }
-
- if (mMode == LLRender::QUADS ||
- mMode == LLRender::LINES ||
+ if (mMode == LLRender::LINES ||
mMode == LLRender::TRIANGLES ||
mMode == LLRender::POINTS)
{
@@ -1593,22 +1574,23 @@ void LLRender::end()
//IMM_ERRS << "GL begin and end called with no vertices specified." << LL_ENDL;
}
- if ((mMode != LLRender::QUADS &&
- mMode != LLRender::LINES &&
+ if ((mMode != LLRender::LINES &&
mMode != LLRender::TRIANGLES &&
mMode != LLRender::POINTS) ||
- mCount > (BATCH_SIZE / 2))
+ mCount > 2048)
{
flush();
}
}
+
void LLRender::flush()
{
STOP_GLERROR;
if (mCount > 0)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
- llassert(LLGLSLShader::sCurBoundShaderPtr != nullptr);
+ llassert_always(LLGLSLShader::sCurBoundShaderPtr != nullptr);
+
if (!mUIOffset.empty())
{
sUICalls++;
@@ -1618,21 +1600,12 @@ void LLRender::flush()
//store mCount in a local variable to avoid re-entrance (drawArrays may call flush)
U32 count = mCount;
- if (mMode == LLRender::QUADS && !sGLCoreProfile)
- {
- if (mCount%4 != 0)
- {
- count -= (mCount % 4);
- LL_WARNS() << "Incomplete quad requested." << LL_ENDL;
- }
- }
-
if (mMode == LLRender::TRIANGLES)
{
if (mCount%3 != 0)
{
- count -= (mCount % 3);
- LL_WARNS() << "Incomplete triangle requested." << LL_ENDL;
+ count -= (mCount % 3);
+ LL_WARNS() << "Incomplete triangle requested." << LL_ENDL;
}
}
@@ -1650,177 +1623,184 @@ void LLRender::flush()
if (mBuffer)
{
- HBXXH64 hash;
+ LLVertexBuffer *vb;
+
U32 attribute_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
+ if (sBufferDataList)
{
- LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache hash");
+ vb = genBuffer(attribute_mask, count);
+ sBufferDataList->emplace_back(
+ vb,
+ mMode,
+ count,
+ gGL.getTexUnit(0)->mCurrTexture,
+ mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]],
+ mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]],
+ mMatrix[MM_TEXTURE0][mMatIdx[MM_TEXTURE0]]
+ );
+ }
+ else
+ {
+ vb = bufferfromCache(attribute_mask, count);
+ }
- hash.update((U8*)mVerticesp.get(), count * sizeof(LLVector4a));
- if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0)
- {
- hash.update((U8*)mTexcoordsp.get(), count * sizeof(LLVector2));
- }
+ drawBuffer(vb, mMode, count);
+ }
+ else
+ {
+ // mBuffer is present in main thread and not present in an image thread
+ LL_ERRS() << "A flush call from outside main rendering thread" << LL_ENDL;
+ }
- if (attribute_mask & LLVertexBuffer::MAP_COLOR)
- {
- hash.update((U8*)mColorsp.get(), count * sizeof(LLColor4U));
- }
+ resetStriders(count);
+ }
+}
- hash.finalize();
- }
+LLVertexBuffer* LLRender::bufferfromCache(U32 attribute_mask, U32 count)
+{
+ LLVertexBuffer *vb = nullptr;
+ HBXXH64 hash;
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache hash");
- U64 vhash = hash.digest();
+ hash.update((U8*)mVerticesp.get(), count * sizeof(LLVector4a));
+ if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0)
+ {
+ hash.update((U8*)mTexcoordsp.get(), count * sizeof(LLVector2));
+ }
- // check the VB cache before making a new vertex buffer
- // This is a giant hack to deal with (mostly) our terrible UI rendering code
- // that was built on top of OpenGL immediate mode. Huge performance wins
- // can be had by not uploading geometry to VRAM unless absolutely necessary.
- // Most of our usage of the "immediate mode" style draw calls is actually
- // sending the same geometry over and over again.
- // To leverage this, we maintain a running hash of the vertex stream being
- // built up before a flush, and then check that hash against a VB
- // cache just before creating a vertex buffer in VRAM
- std::unordered_map<U64, LLVBCache>::iterator cache = sVBCache.find(vhash);
+ if (attribute_mask & LLVertexBuffer::MAP_COLOR)
+ {
+ hash.update((U8*)mColorsp.get(), count * sizeof(LLColor4U));
+ }
- LLPointer<LLVertexBuffer> vb;
+ hash.finalize();
+ }
- if (cache != sVBCache.end())
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache hit");
- // cache hit, just use the cached buffer
- vb = cache->second.vb;
- cache->second.touched = std::chrono::steady_clock::now();
- }
- else
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache miss");
- vb = new LLVertexBuffer(attribute_mask);
- vb->allocateBuffer(count, 0);
+ U64 vhash = hash.digest();
- vb->setBuffer();
+ // check the VB cache before making a new vertex buffer
+ // This is a giant hack to deal with (mostly) our terrible UI rendering code
+ // that was built on top of OpenGL immediate mode. Huge performance wins
+ // can be had by not uploading geometry to VRAM unless absolutely necessary.
+ // Most of our usage of the "immediate mode" style draw calls is actually
+ // sending the same geometry over and over again.
+ // To leverage this, we maintain a running hash of the vertex stream being
+ // built up before a flush, and then check that hash against a VB
+ // cache just before creating a vertex buffer in VRAM
+ std::unordered_map<U64, LLVBCache>::iterator cache = sVBCache.find(vhash);
- vb->setPositionData(mVerticesp.get());
+ if (cache != sVBCache.end())
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache hit");
+ // cache hit, just use the cached buffer
+ vb = cache->second.vb;
+ cache->second.touched = std::chrono::steady_clock::now();
+ }
+ else
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache miss");
+ vb = genBuffer(attribute_mask, count);
- if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0)
- {
- vb->setTexCoord0Data(mTexcoordsp.get());
- }
+ sVBCache[vhash] = { vb , std::chrono::steady_clock::now() };
+
+ static U32 miss_count = 0;
+ miss_count++;
+ if (miss_count > 1024)
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache clean");
+ miss_count = 0;
+ auto now = std::chrono::steady_clock::now();
- if (attribute_mask & LLVertexBuffer::MAP_COLOR)
+ using namespace std::chrono_literals;
+ // every 1024 misses, clean the cache of any VBs that haven't been touched in the last second
+ for (std::unordered_map<U64, LLVBCache>::iterator iter = sVBCache.begin(); iter != sVBCache.end(); )
+ {
+ if (now - iter->second.touched > 1s)
{
- vb->setColorData(mColorsp.get());
+ iter = sVBCache.erase(iter);
}
-
- //LL_INFOS() << "LLVertexBuffer::sMappingMode " << LLVertexBuffer::sMappingMode << LL_ENDL;
- if(LLVertexBuffer::sMappingMode == 3)
+ else
{
- vb->unmapBuffer();
+ ++iter;
}
+ }
+ }
+ }
+ return vb;
+}
- vb->unbind();
+LLVertexBuffer* LLRender::genBuffer(U32 attribute_mask, S32 count)
+{
+ LLVertexBuffer * vb = new LLVertexBuffer(attribute_mask);
+ vb->allocateBuffer(count, 0);
- sVBCache[vhash] = { vb , std::chrono::steady_clock::now() };
+ vb->setBuffer();
- static U32 miss_count = 0;
- miss_count++;
- if (miss_count > 1024)
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache clean");
- miss_count = 0;
- auto now = std::chrono::steady_clock::now();
+ vb->setPositionData(mVerticesp.get());
- using namespace std::chrono_literals;
- // every 1024 misses, clean the cache of any VBs that haven't been touched in the last second
- for (std::unordered_map<U64, LLVBCache>::iterator iter = sVBCache.begin(); iter != sVBCache.end(); )
- {
- if (now - iter->second.touched > 1s)
- {
- iter = sVBCache.erase(iter);
- }
- else
- {
- ++iter;
- }
- }
- }
- }
+ if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0)
+ {
+ vb->setTexCoord0Data(mTexcoordsp.get());
+ }
- vb->setBuffer();
+ if (attribute_mask & LLVertexBuffer::MAP_COLOR)
+ {
+ vb->setColorData(mColorsp.get());
+ }
- if (mMode == LLRender::QUADS && sGLCoreProfile)
- {
- vb->drawArrays(LLRender::TRIANGLES, 0, count);
- mQuadCycle = 1;
- }
- else
- {
- vb->drawArrays(mMode, 0, count);
- }
- }
- else
- {
- // mBuffer is present in main thread and not present in an image thread
- LL_ERRS() << "A flush call from outside main rendering thread" << LL_ENDL;
- }
+#if LL_DARWIN
+ vb->unmapBuffer();
+#endif
+ vb->unbind();
+ return vb;
+}
- mVerticesp[0] = mVerticesp[count];
- mTexcoordsp[0] = mTexcoordsp[count];
- mColorsp[0] = mColorsp[count];
+void LLRender::drawBuffer(LLVertexBuffer* vb, U32 mode, S32 count)
+{
+ vb->setBuffer();
+ vb->drawArrays(mode, 0, count);
+}
- mCount = 0;
- }
+void LLRender::resetStriders(S32 count)
+{
+ mVerticesp[0] = mVerticesp[count];
+ mTexcoordsp[0] = mTexcoordsp[count];
+ mColorsp[0] = mColorsp[count];
+
+ mCount = 0;
}
-void LLRender::vertex4a(const LLVector4a& vertex)
+void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
{
//the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095]
- if (mCount > BATCH_SIZE / 2)
+ if (mCount > 2048)
{ //break when buffer gets reasonably full to keep GL command buffers happy and avoid overflow below
switch (mMode)
{
case LLRender::POINTS: flush(); break;
case LLRender::TRIANGLES: if (mCount%3==0) flush(); break;
- case LLRender::QUADS: if(mCount%4 == 0) flush(); break;
case LLRender::LINES: if (mCount%2 == 0) flush(); break;
}
}
- if (mCount > BATCH_SIZE - 2)
+ if (mCount > 4094)
{
- LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL;
+ // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL;
return;
}
if (mUIOffset.empty())
{
- mVerticesp[mCount] = vertex;
+ mVerticesp[mCount].set(x,y,z);
}
else
{
- mVerticesp[mCount].setAdd(vertex, mUIOffset.back());
- mVerticesp[mCount].mul(mUIScale.back());
- }
-
- if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile)
- {
- mQuadCycle++;
- if (mQuadCycle == 4)
- { //copy two vertices so fourth quad element will add a triangle
- mQuadCycle = 0;
-
- mCount++;
- mVerticesp[mCount] = mVerticesp[mCount-3];
- mColorsp[mCount] = mColorsp[mCount-3];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-3];
-
- mCount++;
- mVerticesp[mCount] = mVerticesp[mCount-2];
- mColorsp[mCount] = mColorsp[mCount-2];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-2];
- }
+ LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back());
+ mVerticesp[mCount].set(vert.mV[VX], vert.mV[VY], vert.mV[VZ]);
}
mCount++;
@@ -1831,56 +1811,19 @@ void LLRender::vertex4a(const LLVector4a& vertex)
void LLRender::vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count)
{
- if (mCount + vert_count > BATCH_SIZE - 2)
+ if (mCount + vert_count > 4094)
{
// LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL;
return;
}
- if (sGLCoreProfile && mMode == LLRender::QUADS)
- { //quads are deprecated, convert to triangle list
- S32 i = 0;
-
- while (i < vert_count)
- {
- //read first three
- mVerticesp[mCount++] = verts[i++];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
- mColorsp[mCount] = mColorsp[mCount-1];
-
- mVerticesp[mCount++] = verts[i++];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
- mColorsp[mCount] = mColorsp[mCount-1];
-
- mVerticesp[mCount++] = verts[i++];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
- mColorsp[mCount] = mColorsp[mCount-1];
-
- //copy two
- mVerticesp[mCount++] = verts[i-3];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
- mColorsp[mCount] = mColorsp[mCount-1];
-
- mVerticesp[mCount++] = verts[i-1];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
- mColorsp[mCount] = mColorsp[mCount-1];
-
- //copy last one
- mVerticesp[mCount++] = verts[i++];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
- mColorsp[mCount] = mColorsp[mCount-1];
- }
- }
- else
+ for (S32 i = 0; i < vert_count; i++)
{
- for (S32 i = 0; i < vert_count; i++)
- {
- mVerticesp[mCount] = verts[i];
+ mVerticesp[mCount] = verts[i];
- mCount++;
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
- mColorsp[mCount] = mColorsp[mCount-1];
- }
+ mCount++;
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
}
if( mCount > 0 ) // ND: Guard against crashes if mCount is zero, yes it can happen
@@ -1889,56 +1832,19 @@ void LLRender::vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count)
void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count)
{
- if (mCount + vert_count > BATCH_SIZE - 2)
+ if (mCount + vert_count > 4094)
{
// LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL;
return;
}
- if (sGLCoreProfile && mMode == LLRender::QUADS)
- { //quads are deprecated, convert to triangle list
- S32 i = 0;
-
- while (i < vert_count)
- {
- //read first three
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount++] = uvs[i++];
- mColorsp[mCount] = mColorsp[mCount-1];
-
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount++] = uvs[i++];
- mColorsp[mCount] = mColorsp[mCount-1];
-
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount++] = uvs[i++];
- mColorsp[mCount] = mColorsp[mCount-1];
-
- //copy last two
- mVerticesp[mCount] = verts[i-3];
- mTexcoordsp[mCount++] = uvs[i-3];
- mColorsp[mCount] = mColorsp[mCount-1];
-
- mVerticesp[mCount] = verts[i-1];
- mTexcoordsp[mCount++] = uvs[i-1];
- mColorsp[mCount] = mColorsp[mCount-1];
-
- //copy last one
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount++] = uvs[i++];
- mColorsp[mCount] = mColorsp[mCount-1];
- }
- }
- else
+ for (S32 i = 0; i < vert_count; i++)
{
- for (S32 i = 0; i < vert_count; i++)
- {
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount] = uvs[i];
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
- mCount++;
- mColorsp[mCount] = mColorsp[mCount-1];
- }
+ mCount++;
+ mColorsp[mCount] = mColorsp[mCount-1];
}
if (mCount > 0)
@@ -1950,57 +1856,19 @@ void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32
void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count)
{
- if (mCount + vert_count > BATCH_SIZE - 2)
+ if (mCount + vert_count > 4094)
{
// LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL;
return;
}
-
- if (sGLCoreProfile && mMode == LLRender::QUADS)
- { //quads are deprecated, convert to triangle list
- S32 i = 0;
-
- while (i < vert_count)
- {
- //read first three
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount] = uvs[i];
- mColorsp[mCount++] = colors[i++];
-
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount] = uvs[i];
- mColorsp[mCount++] = colors[i++];
-
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount] = uvs[i];
- mColorsp[mCount++] = colors[i++];
-
- //copy last two
- mVerticesp[mCount] = verts[i-3];
- mTexcoordsp[mCount] = uvs[i-3];
- mColorsp[mCount++] = colors[i-3];
-
- mVerticesp[mCount] = verts[i-1];
- mTexcoordsp[mCount] = uvs[i-1];
- mColorsp[mCount++] = colors[i-1];
-
- //copy last one
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount] = uvs[i];
- mColorsp[mCount++] = colors[i++];
- }
- }
- else
+ for (S32 i = 0; i < vert_count; i++)
{
- for (S32 i = 0; i < vert_count; i++)
- {
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount] = uvs[i];
- mColorsp[mCount] = colors[i];
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount] = colors[i];
- mCount++;
- }
+ mCount++;
}
if (mCount > 0)
@@ -2011,6 +1879,25 @@ void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLCo
}
}
+void LLRender::vertex2i(const GLint& x, const GLint& y)
+{
+ vertex3f((GLfloat) x, (GLfloat) y, 0);
+}
+
+void LLRender::vertex2f(const GLfloat& x, const GLfloat& y)
+{
+ vertex3f(x,y,0);
+}
+
+void LLRender::vertex2fv(const GLfloat* v)
+{
+ vertex3f(v[0], v[1], 0);
+}
+
+void LLRender::vertex3fv(const GLfloat* v)
+{
+ vertex3f(v[0], v[1], v[2]);
+}
void LLRender::texCoord2f(const GLfloat& x, const GLfloat& y)
{
@@ -2149,9 +2036,11 @@ void LLRender::debugTexUnits(void)
case LLTexUnit::TT_TEXTURE:
LL_CONT << "Texture 2D";
break;
+#if GL_VERSION_3_1
case LLTexUnit::TT_RECT_TEXTURE:
LL_CONT << "Texture Rectangle";
break;
+#endif
case LLTexUnit::TT_CUBE_MAP:
LL_CONT << "Cube Map";
break;
@@ -2165,85 +2054,93 @@ void LLRender::debugTexUnits(void)
LL_INFOS("TextureUnit") << "Active TexUnit Enabled : " << active_enabled << LL_ENDL;
}
-
-
-glh::matrix4f copy_matrix(F32* src)
+glm::mat4 get_current_modelview()
{
- glh::matrix4f ret;
- ret.set_value(src);
- return ret;
+ return glm::make_mat4(gGLModelView);
}
-glh::matrix4f get_current_modelview()
+glm::mat4 get_current_projection()
{
- return copy_matrix(gGLModelView);
+ return glm::make_mat4(gGLProjection);
}
-glh::matrix4f get_current_projection()
+glm::mat4 get_last_modelview()
{
- return copy_matrix(gGLProjection);
+ return glm::make_mat4(gGLLastModelView);
}
-glh::matrix4f get_last_modelview()
+glm::mat4 get_last_projection()
{
- return copy_matrix(gGLLastModelView);
+ return glm::make_mat4(gGLLastProjection);
}
-glh::matrix4f get_last_projection()
-{
- return copy_matrix(gGLLastProjection);
-}
-
-void copy_matrix(const glh::matrix4f& src, F32* dst)
+void copy_matrix(const glm::mat4& src, F32* dst)
{
+ auto matp = glm::value_ptr(src);
for (U32 i = 0; i < 16; i++)
{
- dst[i] = src.m[i];
+ dst[i] = matp[i];
}
}
-void set_current_modelview(const glh::matrix4f& mat)
+void set_current_modelview(const glm::mat4& mat)
{
copy_matrix(mat, gGLModelView);
}
-void set_current_projection(glh::matrix4f& mat)
+void set_current_projection(const glm::mat4& mat)
{
copy_matrix(mat, gGLProjection);
}
-glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar)
+void set_last_modelview(const glm::mat4& mat)
{
- glh::matrix4f ret(
- 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left),
- 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom),
- 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear),
- 0.f, 0.f, 0.f, 1.f);
-
- return ret;
+ copy_matrix(mat, gGLLastModelView);
}
-glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
+void set_last_projection(const glm::mat4& mat)
{
- GLfloat f = 1.f/tanf(DEG_TO_RAD*fovy/2.f);
-
- return glh::matrix4f(f/aspect, 0, 0, 0,
- 0, f, 0, 0,
- 0, 0, (zFar+zNear)/(zNear-zFar), (2.f*zFar*zNear)/(zNear-zFar),
- 0, 0, -1.f, 0);
+ copy_matrix(mat, gGLLastProjection);
}
-glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up)
+glm::vec3 mul_mat4_vec3(const glm::mat4& mat, const glm::vec3& vec)
{
- LLVector3 f = center-eye;
- f.normVec();
- up.normVec();
- LLVector3 s = f % up;
- LLVector3 u = s % f;
+#if 1 // SIMD path results in strange crashes. Fall back to scalar for now.
+ const float w = vec[0] * mat[0][3] + vec[1] * mat[1][3] + vec[2] * mat[2][3] + mat[3][3];
+ return glm::vec3(
+ (vec[0] * mat[0][0] + vec[1] * mat[1][0] + vec[2] * mat[2][0] + mat[3][0]) / w,
+ (vec[0] * mat[0][1] + vec[1] * mat[1][1] + vec[2] * mat[2][1] + mat[3][1]) / w,
+ (vec[0] * mat[0][2] + vec[1] * mat[1][2] + vec[2] * mat[2][2] + mat[3][2]) / w
+ );
+#else
+ LLVector4a x, y, z, s, t, p, q;
+
+ x.splat(vec.x);
+ y.splat(vec.y);
+ z.splat(vec.z);
+
+ s.splat<3>(mat[0].data);
+ t.splat<3>(mat[1].data);
+ p.splat<3>(mat[2].data);
+ q.splat<3>(mat[3].data);
- return glh::matrix4f(s[0], s[1], s[2], 0,
- u[0], u[1], u[2], 0,
- -f[0], -f[1], -f[2], 0,
- 0, 0, 0, 1);
+ s.mul(x);
+ t.mul(y);
+ p.mul(z);
+ q.add(s);
+ t.add(p);
+ q.add(t);
+ x.mul(mat[0].data);
+ y.mul(mat[1].data);
+ z.mul(mat[2].data);
+
+ x.add(y);
+ z.add(mat[3].data);
+ LLVector4a res;
+ res.load3(glm::value_ptr(vec));
+ res.setAdd(x, z);
+ res.div(q);
+ return glm::make_vec3(res.getF32ptr());
+#endif
}
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index d198b0cd7c..97c47bcae9 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -43,15 +43,17 @@
#include "llpointer.h"
#include "llglheaders.h"
#include "llmatrix4a.h"
-#include "glh/glh_linear.h"
+#include "glm/mat4x4.hpp"
#include <array>
+#include <list>
class LLVertexBuffer;
class LLCubeMap;
class LLImageGL;
class LLRenderTarget;
-class LLTexture ;
+class LLTexture;
+class LLVertexBufferData;
#define LL_MATRIX_STACK_DEPTH 32
@@ -67,10 +69,16 @@ public:
typedef enum
{
TT_TEXTURE = 0, // Standard 2D Texture
+#if GL_VERSION_3_1
TT_RECT_TEXTURE, // Non power of 2 texture
+#endif
TT_CUBE_MAP, // 6-sided cube map texture
+#if GL_VERSION_4_0
TT_CUBE_MAP_ARRAY, // Array of cube maps
+#endif
+#if GL_VERSION_3_2
TT_MULTISAMPLE_TEXTURE, // see GL_ARB_texture_multisample
+#endif
TT_TEXTURE_3D, // standard 3D Texture
TT_NONE, // No texture type is currently enabled
} eTextureType;
@@ -220,17 +228,12 @@ public:
void setHasMipMaps(bool hasMips) { mHasMipMaps = hasMips; }
- void setTextureColorSpace(eTextureColorSpace space);
-
- eTextureColorSpace getCurrColorSpace() { return mTexColorSpace; }
-
protected:
friend class LLRender;
S32 mIndex;
U32 mCurrTexture;
eTextureType mCurrTexType;
- eTextureColorSpace mTexColorSpace;
S32 mCurrColorScale;
S32 mCurrAlphaScale;
bool mHasMipMaps;
@@ -323,7 +326,6 @@ public:
POINTS,
LINES,
LINE_STRIP,
- QUADS,
LINE_LOOP,
NUM_MODES
};
@@ -405,8 +407,8 @@ public:
void matrixMode(eMatrixMode mode);
eMatrixMode getMatrixMode();
- const glh::matrix4f& getModelviewMatrix();
- const glh::matrix4f& getProjectionMatrix();
+ const glm::mat4& getModelviewMatrix();
+ const glm::mat4& getProjectionMatrix();
void syncMatrices();
void syncLightState();
@@ -421,17 +423,20 @@ public:
void flush();
+ // if list is set, will store buffers in list for later use, if list isn't set, will use cache
+ void beginList(std::list<LLVertexBufferData> *list);
+ void endList();
+
void begin(const GLuint& mode);
void end();
- LL_FORCE_INLINE void vertex2i(const GLint& x, const GLint& y) { vertex4a(LLVector4a((GLfloat)x,(GLfloat)y,0.f)); }
- LL_FORCE_INLINE void vertex2f(const GLfloat& x, const GLfloat& y) { vertex4a(LLVector4a(x,y,0.f)); }
- LL_FORCE_INLINE void vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) { vertex4a(LLVector4a(x,y,z)); }
- LL_FORCE_INLINE void vertex2fv(const GLfloat* v) { vertex4a(LLVector4a(v[0],v[1],0.f)); }
- LL_FORCE_INLINE void vertex3fv(const GLfloat* v) { vertex4a(LLVector4a(v[0],v[1],v[2])); }
-
- void vertex4a(const LLVector4a& v);
+ U8 getMode() const { return mMode; }
+ void vertex2i(const GLint& x, const GLint& y);
+ void vertex2f(const GLfloat& x, const GLfloat& y);
+ void vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z);
+ void vertex2fv(const GLfloat* v);
+ void vertex3fv(const GLfloat* v);
void texCoord2i(const GLint& x, const GLint& y);
void texCoord2f(const GLfloat& x, const GLfloat& y);
@@ -491,29 +496,32 @@ public:
static bool sGLCoreProfile;
static bool sNsightDebugSupport;
static LLVector2 sUIGLScaleFactor;
-
- //static U32 sMappingMode;
+ static bool sClassicMode; // classic sky mode active
private:
friend class LLLightState;
+ LLVertexBuffer* bufferfromCache(U32 attribute_mask, U32 count);
+ LLVertexBuffer* genBuffer(U32 attribute_mask, S32 count);
+ void drawBuffer(LLVertexBuffer* vb, U32 mode, S32 count);
+ void resetStriders(S32 count);
+
eMatrixMode mMatrixMode;
U32 mMatIdx[NUM_MATRIX_MODES];
U32 mMatHash[NUM_MATRIX_MODES];
- glh::matrix4f mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH];
+ glm::mat4 mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH];
U32 mCurMatHash[NUM_MATRIX_MODES];
U32 mLightHash;
LLColor4 mAmbientLightColor;
bool mDirty;
- U32 mQuadCycle;
U32 mCount;
U32 mMode;
U32 mCurrTextureUnitIndex;
bool mCurrColorMask[4];
LLPointer<LLVertexBuffer> mBuffer;
- LLStrider<LLVector4a> mVerticesp;
+ LLStrider<LLVector4a> mVerticesp;
LLStrider<LLVector2> mTexcoordsp;
LLStrider<LLColor4U> mColorsp;
std::array<LLTexUnit, LL_NUM_TEXTURE_LAYERS> mTexUnits;
@@ -525,9 +533,8 @@ private:
eBlendFactor mCurrBlendAlphaSFactor;
eBlendFactor mCurrBlendAlphaDFactor;
- std::vector<LLVector4a> mUIOffset;
- std::vector<LLVector4a> mUIScale;
-
+ std::vector<LLVector3> mUIOffset;
+ std::vector<LLVector3> mUIScale;
};
extern F32 gGLModelView[16];
@@ -535,8 +542,8 @@ extern F32 gGLLastModelView[16];
extern F32 gGLLastProjection[16];
extern F32 gGLProjection[16];
extern S32 gGLViewport[4];
-extern F32 gGLDeltaModelView[16];
-extern F32 gGLInverseDeltaModelView[16];
+extern glm::mat4 gGLDeltaModelView;
+extern glm::mat4 gGLInverseDeltaModelView;
extern thread_local LLRender gGL;
@@ -547,19 +554,20 @@ const F32 OGL_TO_CFR_ROTATION[16] = { 0.f, 0.f, -1.f, 0.f, // -Z becomes X
0.f, 1.f, 0.f, 0.f, // Y becomes Z
0.f, 0.f, 0.f, 1.f };
-glh::matrix4f copy_matrix(F32* src);
-glh::matrix4f get_current_modelview();
-glh::matrix4f get_current_projection();
-glh::matrix4f get_last_modelview();
-glh::matrix4f get_last_projection();
+glm::mat4 copy_matrix(F32* src);
+glm::mat4 get_current_modelview();
+glm::mat4 get_current_projection();
+glm::mat4 get_last_modelview();
+glm::mat4 get_last_projection();
-void copy_matrix(const glh::matrix4f& src, F32* dst);
-void set_current_modelview(const glh::matrix4f& mat);
-void set_current_projection(glh::matrix4f& mat);
+void copy_matrix(const glm::mat4& src, F32* dst);
+void set_current_modelview(const glm::mat4& mat);
+void set_current_projection(const glm::mat4& mat);
+void set_last_modelview(const glm::mat4& mat);
+void set_last_projection(const glm::mat4& mat);
-glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar);
-glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar);
-glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up);
+// glh compat
+glm::vec3 mul_mat4_vec3(const glm::mat4& mat, const glm::vec3& vec);
#define LL_SHADER_LOADING_WARNS(...) LL_WARNS()
diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp
index fe770027f6..9144ce6d62 100644
--- a/indra/llrender/llrender2dutils.cpp
+++ b/indra/llrender/llrender2dutils.cpp
@@ -119,10 +119,10 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, bool filled )
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ // Counterclockwise quad will face the viewer
if( filled )
{
gGL.begin( LLRender::TRIANGLES );
- {
gGL.vertex2i(left, top);
gGL.vertex2i(left, bottom);
gGL.vertex2i(right, bottom);
@@ -130,7 +130,6 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, bool filled )
gGL.vertex2i(left, top);
gGL.vertex2i(right, bottom);
gGL.vertex2i(right, top);
- }
gGL.end();
}
else
@@ -175,73 +174,71 @@ void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &st
LLColor4 end_color = start_color;
end_color.mV[VALPHA] = 0.f;
+
gGL.begin(LLRender::TRIANGLES);
- // Right edge
+ // Right edge, CCW faces screen
gGL.color4fv(start_color.mV);
- gGL.vertex2i(right, top-lines);
+ gGL.vertex2i(right, top - lines);
gGL.vertex2i(right, bottom);
gGL.color4fv(end_color.mV);
- gGL.vertex2i(right+lines, bottom);
+ gGL.vertex2i(right + lines, bottom);
gGL.color4fv(start_color.mV);
- gGL.vertex2i(right, top-lines);
+ gGL.vertex2i(right, top - lines);
gGL.color4fv(end_color.mV);
- gGL.vertex2i(right+lines, bottom);
- gGL.vertex2i(right+lines, top-lines);
+ gGL.vertex2i(right + lines, bottom);
+ gGL.vertex2i(right + lines, top - lines);
- // Bottom edge
+ // Bottom edge, CCW faces screen
gGL.color4fv(start_color.mV);
gGL.vertex2i(right, bottom);
- gGL.vertex2i(left+lines, bottom);
+ gGL.vertex2i(left + lines, bottom);
gGL.color4fv(end_color.mV);
- gGL.vertex2i(left+lines, bottom-lines);
+ gGL.vertex2i(left + lines, bottom - lines);
gGL.color4fv(start_color.mV);
gGL.vertex2i(right, bottom);
gGL.color4fv(end_color.mV);
- gGL.vertex2i(left+lines, bottom-lines);
- gGL.vertex2i(right, bottom-lines);
+ gGL.vertex2i(left + lines, bottom - lines);
+ gGL.vertex2i(right, bottom - lines);
// bottom left Corner
gGL.color4fv(start_color.mV);
- gGL.vertex2i(left+lines, bottom);
+ gGL.vertex2i(left + lines, bottom);
gGL.color4fv(end_color.mV);
gGL.vertex2i(left, bottom);
-
- // bottom left corner
- gGL.vertex2i(left+1, bottom-lines+1);
+ // make the bottom left corner not sharp
+ gGL.vertex2i(left + 1, bottom - lines + 1);
gGL.color4fv(start_color.mV);
- gGL.vertex2i(left+lines, bottom);
+ gGL.vertex2i(left + lines, bottom);
gGL.color4fv(end_color.mV);
- gGL.vertex2i(left+1, bottom-lines+1);
- gGL.vertex2i(left+lines, bottom-lines);
+ gGL.vertex2i(left + 1, bottom - lines + 1);
+ gGL.vertex2i(left + lines, bottom - lines);
// bottom right corner
gGL.color4fv(start_color.mV);
gGL.vertex2i(right, bottom);
gGL.color4fv(end_color.mV);
- gGL.vertex2i(right, bottom-lines);
-
+ gGL.vertex2i(right, bottom - lines);
// make the rightmost corner not sharp
- gGL.vertex2i(right+lines-1, bottom-lines+1);
+ gGL.vertex2i(right + lines - 1, bottom - lines + 1);
gGL.color4fv(start_color.mV);
gGL.vertex2i(right, bottom);
gGL.color4fv(end_color.mV);
- gGL.vertex2i(right+lines-1, bottom-lines+1);
- gGL.vertex2i(right+lines, bottom);
+ gGL.vertex2i(right + lines - 1, bottom - lines + 1);
+ gGL.vertex2i(right + lines, bottom);
// top right corner
gGL.color4fv(start_color.mV);
- gGL.vertex2i( right, top-lines );
+ gGL.vertex2i(right, top - lines);
gGL.color4fv(end_color.mV);
- gGL.vertex2i( right+lines, top-lines );
-
+ gGL.vertex2i(right + lines, top - lines);
// make the corner not sharp
- gGL.vertex2i( right+lines-1, top-1 );
+ gGL.vertex2i(right + lines - 1, top - 1);
gGL.color4fv(start_color.mV);
- gGL.vertex2i( right, top-lines );
+ gGL.vertex2i(right, top - lines);
gGL.color4fv(end_color.mV);
- gGL.vertex2i( right+lines-1, top-1 );
- gGL.vertex2i( right, top );
+ gGL.vertex2i(right + lines - 1, top - 1);
+ gGL.vertex2i(right, top);
gGL.end();
stop_glerror();
@@ -449,243 +446,251 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
ui_translation.mV[VX] + width * ui_scale.mV[VX],
ui_translation.mV[VY]);
- LLGLSUIDefault gls_ui;
-
gGL.getTexUnit(0)->bind(image, true);
gGL.color4fv(color.mV);
- const S32 NUM_VERTICES = 9 * 6;
- LLVector2 uv[NUM_VERTICES];
- LLVector4a pos[NUM_VERTICES];
+ constexpr S32 NUM_VERTICES = 9 * 2 * 3; // 9 quads, 2 triangles per quad, 3 vertices per triangle
+ static thread_local LLVector2 uv[NUM_VERTICES];
+ static thread_local LLVector4a pos[NUM_VERTICES];
S32 index = 0;
gGL.begin(LLRender::TRIANGLES);
{
- // draw bottom left
- uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
- pos[index] = LLVector4a(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+ // draw bottom left triangles
+ // 1
+ uv[index].set(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
+ pos[index].set(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mBottom);
+ pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
- pos[index] = LLVector4a(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+ // 2
+ uv[index].set(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
+ pos[index].set(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mBottom);
+ pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
- // draw bottom middle
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+ // draw bottom middle triangles
+ uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mBottom);
+ pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_outer_rect.mBottom);
+ pos[index].set(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+ // 2
+ uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mBottom);
+ pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
- // draw bottom right
- uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
+ // draw bottom right triangles
+ uv[index].set(uv_center_rect.mRight, uv_outer_rect.mBottom);
+ pos[index].set(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mBottom);
- pos[index] = LLVector4a(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f);
+ uv[index].set(uv_outer_rect.mRight, uv_outer_rect.mBottom);
+ pos[index].set(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_outer_rect.mRight, uv_center_rect.mBottom);
+ pos[index].set(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
+ // 2
+ uv[index].set(uv_center_rect.mRight, uv_outer_rect.mBottom);
+ pos[index].set(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_outer_rect.mRight, uv_center_rect.mBottom);
+ pos[index].set(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
- // draw left
- uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ // draw left triangles
+ uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mBottom);
+ pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ // 2
+ uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mBottom);
+ pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mTop);
+ pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
- // draw middle
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ // draw middle triangles
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ // 2
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
- // draw right
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ // draw right triangles
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
+ uv[index].set(uv_outer_rect.mRight, uv_center_rect.mBottom);
+ pos[index].set(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_outer_rect.mRight, uv_center_rect.mTop);
+ pos[index].set(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ // 2
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_outer_rect.mRight, uv_center_rect.mTop);
+ pos[index].set(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
- // draw top left
- uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
+ // draw top left triangles
+ uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mTop);
+ pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mTop);
+ pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
+ // 2
+ uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mTop);
+ pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mTop);
+ pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mTop);
- pos[index] = LLVector4a(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f);
+ uv[index].set(uv_outer_rect.mLeft, uv_outer_rect.mTop);
+ pos[index].set(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f);
index++;
- // draw top middle
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ // draw top middle triangles
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_outer_rect.mTop);
+ pos[index].set(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ // 2
+ uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_outer_rect.mTop);
+ pos[index].set(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mTop);
+ pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
index++;
- // draw top right
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ // draw top right triangles
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
+ uv[index].set(uv_outer_rect.mRight, uv_center_rect.mTop);
+ pos[index].set(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop);
- pos[index] = LLVector4a(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
+ uv[index].set(uv_outer_rect.mRight, uv_outer_rect.mTop);
+ pos[index].set(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ // 2
+ uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop);
- pos[index] = LLVector4a(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
+ uv[index].set(uv_outer_rect.mRight, uv_outer_rect.mTop);
+ pos[index].set(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
index++;
- uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
- pos[index] = LLVector4a(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
+ uv[index].set(uv_center_rect.mRight, uv_outer_rect.mTop);
+ pos[index].set(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
index++;
gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
@@ -712,8 +717,6 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
return;
}
- LLGLSUIDefault gls_ui;
-
if(image != NULL)
{
gGL.getTexUnit(0)->bind(image, true);
@@ -727,9 +730,9 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
if (degrees == 0.f)
{
- const S32 NUM_VERTICES = 6;
- LLVector2 uv[NUM_VERTICES];
- LLVector4a pos[NUM_VERTICES];
+ constexpr S32 NUM_VERTICES = 2 * 3;
+ static thread_local LLVector2 uv[NUM_VERTICES +1];
+ static thread_local LLVector4a pos[NUM_VERTICES +1];
gGL.begin(LLRender::TRIANGLES);
{
@@ -742,28 +745,28 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
S32 scaled_width = ll_round(width * ui_scale.mV[VX]);
S32 scaled_height = ll_round(height * ui_scale.mV[VY]);
- uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
- pos[index] = LLVector4a(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f);
+ uv[index].set(uv_rect.mRight, uv_rect.mTop);
+ pos[index].set(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f);
index++;
- uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
- pos[index] = LLVector4a(ui_translation.mV[VX], ui_translation.mV[VY] + scaled_height, 0.f);
+ uv[index].set(uv_rect.mLeft, uv_rect.mTop);
+ pos[index].set(ui_translation.mV[VX], ui_translation.mV[VY] + scaled_height, 0.f);
index++;
- uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
- pos[index] = LLVector4a(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
+ uv[index].set(uv_rect.mLeft, uv_rect.mBottom);
+ pos[index].set(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
index++;
- uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
- pos[index] = LLVector4a(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f);
+ uv[index].set(uv_rect.mRight, uv_rect.mTop);
+ pos[index].set(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f);
index++;
- uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
- pos[index] = LLVector4a(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
+ uv[index].set(uv_rect.mLeft, uv_rect.mBottom);
+ pos[index].set(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
index++;
- uv[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
- pos[index] = LLVector4a(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY], 0.f);
+ uv[index].set(uv_rect.mRight, uv_rect.mBottom);
+ pos[index].set(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY], 0.f);
index++;
gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
@@ -795,30 +798,32 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
gGL.begin(LLRender::TRIANGLES);
{
- LLVector3 v1 = LLVector3(offset_x, offset_y, 0.f) * quat;
- LLVector3 v2 = LLVector3(-offset_x, offset_y, 0.f) * quat;
- LLVector3 v3 = LLVector3(-offset_x, -offset_y, 0.f) * quat;
- LLVector3 v4 = LLVector3(offset_x, -offset_y, 0.f) * quat;
+ LLVector3 v;
+ v = LLVector3(offset_x, offset_y, 0.f) * quat;
gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
- gGL.vertex2f(v1.mV[0], v1.mV[1] );
+ gGL.vertex2f(v.mV[0], v.mV[1] );
+ v = LLVector3(-offset_x, offset_y, 0.f) * quat;
gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
- gGL.vertex2f(v2.mV[0], v2.mV[1] );
+ gGL.vertex2f(v.mV[0], v.mV[1] );
+ v = LLVector3(-offset_x, -offset_y, 0.f) * quat;
gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
- gGL.vertex2f(v3.mV[0], v3.mV[1] );
+ gGL.vertex2f(v.mV[0], v.mV[1] );
+ v = LLVector3(offset_x, offset_y, 0.f) * quat;
gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
- gGL.vertex2f(v1.mV[0], v1.mV[1] );
+ gGL.vertex2f(v.mV[0], v.mV[1]);
+ v = LLVector3(-offset_x, -offset_y, 0.f) * quat;
gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
- gGL.vertex2f(v3.mV[0], v3.mV[1] );
+ gGL.vertex2f(v.mV[0], v.mV[1]);
+ v = LLVector3(offset_x, -offset_y, 0.f) * quat;
gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
- gGL.vertex2f(v4.mV[0], v4.mV[1] );
+ gGL.vertex2f(v.mV[0], v.mV[1] );
}
-
gGL.end();
gGL.popUIMatrix();
}
@@ -1061,7 +1066,7 @@ void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians,
void gl_rect_2d_simple_tex( S32 width, S32 height )
{
gGL.begin( LLRender::TRIANGLES );
- {
+
gGL.texCoord2f(1.f, 1.f);
gGL.vertex2i(width, height);
@@ -1079,14 +1084,13 @@ void gl_rect_2d_simple_tex( S32 width, S32 height )
gGL.texCoord2f(1.f, 0.f);
gGL.vertex2i(width, 0);
- }
+
gGL.end();
}
void gl_rect_2d_simple( S32 width, S32 height )
{
gGL.begin( LLRender::TRIANGLES );
- {
gGL.vertex2i(width, height);
gGL.vertex2i(0, height);
gGL.vertex2i(0, 0);
@@ -1094,7 +1098,6 @@ void gl_rect_2d_simple( S32 width, S32 height )
gGL.vertex2i(width, height);
gGL.vertex2i(0, 0);
gGL.vertex2i(width, 0);
- }
gGL.end();
}
@@ -1563,7 +1566,7 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
- gGL.begin(LLRender::TRIANGLES);
+ gGL.begin(LLRender::TRIANGLES);
{
// draw bottom left
gGL.texCoord2f(clip_rect.mLeft, clip_rect.mBottom);
@@ -1671,7 +1674,7 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
- gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
+ gGL.vertex3fv((center_draw_rect.mRight* width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV);
@@ -1712,7 +1715,7 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop);
- gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV);
+ gGL.vertex3fv((center_draw_rect.mRight* width_vec + height_vec).mV);
gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV);
@@ -1728,7 +1731,7 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.vertex3fv((width_vec + height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
- gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
+ gGL.vertex3fv((center_draw_rect.mRight* width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(clip_rect.mRight, clip_rect.mTop);
gGL.vertex3fv((width_vec + height_vec).mV);
diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp
index 9570180554..cd8ef7d68e 100644
--- a/indra/llrender/llrendersphere.cpp
+++ b/indra/llrender/llrendersphere.cpp
@@ -34,6 +34,8 @@
#include "llerror.h"
#include "llglheaders.h"
+#include "llvertexbuffer.h"
+#include "llglslshader.h"
LLRenderSphere gSphere;
@@ -53,12 +55,20 @@ inline LLVector3 polar_to_cart(F32 latitude, F32 longitude)
void LLRenderSphere::renderGGL()
{
+ LL_PROFILE_ZONE_SCOPED;
S32 const LATITUDE_SLICES = 20;
S32 const LONGITUDE_SLICES = 30;
- if (mSpherePoints.empty())
+ if (mVertexBuffer.isNull())
{
mSpherePoints.resize(LATITUDE_SLICES + 1);
+ mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX);
+
+ mVertexBuffer->allocateBuffer((U32)(LATITUDE_SLICES + 1) * (LONGITUDE_SLICES + 1), LATITUDE_SLICES * LONGITUDE_SLICES * 6);
+
+ LLStrider<LLVector3> v;
+ mVertexBuffer->getVertexStrider(v);
+
for (S32 lat_i = 0; lat_i < LATITUDE_SLICES + 1; lat_i++)
{
mSpherePoints[lat_i].resize(LONGITUDE_SLICES + 1);
@@ -68,24 +78,52 @@ void LLRenderSphere::renderGGL()
F32 lon = (F32)lon_i / LONGITUDE_SLICES;
mSpherePoints[lat_i][lon_i] = polar_to_cart(lat, lon);
+ v[lat_i * (LONGITUDE_SLICES + 1) + lon_i] = mSpherePoints[lat_i][lon_i];
}
}
+
+ LLStrider<U16> i;
+ mVertexBuffer->getIndexStrider(i);
+
+ for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++)
+ {
+ for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++)
+ {
+ i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 0] = lat_i * (LONGITUDE_SLICES + 1) + lon_i;
+ i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 1] = lat_i * (LONGITUDE_SLICES + 1) + lon_i + 1;
+ i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 2] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i;
+
+ i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 3] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i;
+ i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 4] = lat_i * (LONGITUDE_SLICES + 1) + lon_i + 1;
+ i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 5] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i + 1;
+ }
+ }
+
+ mVertexBuffer->unmapBuffer();
}
- gGL.begin(LLRender::TRIANGLES);
- for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++)
- {
- for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++)
+ if (LLGLSLShader::sCurBoundShaderPtr->mAttributeMask == LLVertexBuffer::MAP_VERTEX)
+ { // shader expects only vertex positions in vertex buffer, use fast path
+ mVertexBuffer->setBuffer();
+ mVertexBuffer->drawRange(LLRender::TRIANGLES, 0, mVertexBuffer->getNumVerts(), mVertexBuffer->getNumIndices(), 0);
+ }
+ else
+ { //shader wants colors in the vertex stream, use slow path
+ gGL.begin(LLRender::TRIANGLES);
+ for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++)
{
- gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV);
- gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV);
- gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV);
+ for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++)
+ {
+ gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV);
+ gGL.vertex3fv(mSpherePoints[lat_i][lon_i + 1].mV);
+ gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i].mV);
- gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV);
- gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV);
- gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i+1].mV);
+ gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i].mV);
+ gGL.vertex3fv(mSpherePoints[lat_i][lon_i + 1].mV);
+ gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i + 1].mV);
+ }
}
+ gGL.end();
}
- gGL.end();
}
diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h
index e2e886fa06..5b6eabecb8 100644
--- a/indra/llrender/llrendersphere.h
+++ b/indra/llrender/llrendersphere.h
@@ -45,6 +45,7 @@ public:
private:
std::vector< std::vector<LLVector3> > mSpherePoints;
+ LLPointer<LLVertexBuffer> mVertexBuffer;
};
extern LLRenderSphere gSphere;
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index af068d5dd6..0e4aa2ee7a 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -255,12 +255,14 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
stop_glerror();
}
+#if GL_VERSION_3_1
if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
{
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
stop_glerror();
}
else
+#endif
{
// ATI doesn't support mirrored repeat for rectangular textures.
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
@@ -429,8 +431,8 @@ void LLRenderTarget::bindTarget()
if (mTex.empty())
{ //no color buffer to draw to
- GLenum drawbuffers[] = {GL_NONE};
- glDrawBuffers(0, drawbuffers);
+ GLenum buffers[] = {GL_NONE};
+ glDrawBuffers(0, buffers);
glReadBuffer(GL_NONE);
}
else
@@ -476,12 +478,10 @@ void LLRenderTarget::clear(U32 mask_in)
U32 LLRenderTarget::getTexture(U32 attachment) const
{
- if (attachment > mTex.size()-1)
- {
- LL_ERRS() << "Invalid attachment index." << LL_ENDL;
- }
- if (mTex.empty())
+ if (attachment >= mTex.size())
{
+ LL_WARNS() << "Invalid attachment index " << attachment << " for size " << mTex.size() << LL_ENDL;
+ llassert(false);
return 0;
}
return mTex[attachment];
@@ -514,7 +514,6 @@ void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilt
}
gGL.getTexUnit(channel)->setTextureFilteringOption(filter_options);
- gGL.getTexUnit(channel)->setTextureColorSpace(isSRGB ? LLTexUnit::TCS_SRGB : LLTexUnit::TCS_LINEAR);
}
void LLRenderTarget::flush()
@@ -548,7 +547,8 @@ void LLRenderTarget::flush()
sCurResX = gGLViewport[2];
sCurResY = gGLViewport[3];
glReadBuffer(GL_BACK);
- glDrawBuffer(GL_BACK);
+ GLenum drawbuffers[] = {GL_BACK};
+ glDrawBuffers(1, drawbuffers);
}
}
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 512ef340f9..4807c12226 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -79,7 +79,7 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
//////////////////////////////////////
// NOTE order of shader object attaching is VERY IMPORTANT!!!
- if (features->calculatesAtmospherics)
+ if (features->calculatesAtmospherics || features->hasGamma || features->isDeferred)
{
if (!shader->attachVertexObject("windlight/atmosphericsVarsV.glsl"))
{
@@ -223,6 +223,14 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
}
}
+ if (features->hasFullGBuffer)
+ {
+ if (!shader->attachFragmentObject("deferred/gbufferUtil.glsl"))
+ {
+ return false;
+ }
+ }
+
if (features->hasScreenSpaceReflections || features->hasReflectionProbes)
{
if (!shader->attachFragmentObject("deferred/screenSpaceReflUtil.glsl"))
@@ -283,6 +291,14 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
}
}
+ if (features->hasTonemap)
+ {
+ if (!shader->attachFragmentObject("deferred/tonemapUtilF.glsl"))
+ {
+ return false;
+ }
+ }
+
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if (features->hasAtmospherics)
{
@@ -458,6 +474,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
if (filename.empty())
{
+ LL_WARNS("ShaderLoading") << "tried loading empty filename" << LL_ENDL;
return 0;
}
@@ -559,17 +576,11 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
}
else if (major_version == 3)
{
- if (minor_version < 10)
+ if (minor_version <= 29)
{
- shader_code_text[shader_code_count++] = strdup("#version 300\n");
- }
- else if (minor_version <= 19)
- {
- shader_code_text[shader_code_count++] = strdup("#version 310\n");
- }
- else if (minor_version <= 29)
- {
- shader_code_text[shader_code_count++] = strdup("#version 320\n");
+ // OpenGL 3.2 had GLSL version 1.50. anything after that the version numbers match.
+ // https://www.khronos.org/opengl/wiki/Core_Language_(GLSL)#OpenGL_and_GLSL_versions
+ shader_code_text[shader_code_count++] = strdup("#version 150\n");
}
else
{
@@ -578,7 +589,8 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
}
else
{
- if (type == GL_GEOMETRY_SHADER)
+ // OpenGL 3.2 had GLSL version 1.50. anything after that the version numbers match.
+ if (type == GL_GEOMETRY_SHADER || minor_version >= 50)
{
//set version to 1.50
shader_code_text[shader_code_count++] = strdup("#version 150\n");
@@ -595,8 +607,15 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
extra_code_text[extra_code_count++] = strdup("precision highp float;\n");
}
}
+ }
- extra_code_text[extra_code_count++] = strdup("#define FXAA_GLSL_130 1\n");
+ if (type == GL_FRAGMENT_SHADER)
+ {
+ extra_code_text[extra_code_count++] = strdup("#define FRAGMENT_SHADER 1\n");
+ }
+ else
+ {
+ extra_code_text[extra_code_count++] = strdup("#define VERTEX_SHADER 1\n");
}
// Use alpha float to store bit flags
@@ -605,7 +624,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_ATMOS 0.34\n"); // bit 0
extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_PBR 0.67\n"); // bit 1
extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_HDRI 1.0\n"); // bit 2
- extra_code_text[extra_code_count++] = strdup("#define GET_GBUFFER_FLAG(flag) (abs(norm.w-flag)< 0.1)\n");
+ extra_code_text[extra_code_count++] = strdup("#define GET_GBUFFER_FLAG(data, flag) (abs(data-flag)< 0.1)\n");
if (defines)
{
@@ -716,6 +735,9 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
}
}
+ // Master definition can be found in deferredUtil.glsl
+ extra_code_text[extra_code_count++] = strdup("struct GBufferInfo { vec4 albedo; vec4 specular; vec3 normal; vec4 emissive; float gbufferFlag; float envIntensity; };\n");
+
//copy file into memory
enum {
flag_write_to_out_of_extra_block_area = 0x01
@@ -910,6 +932,8 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
}
LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL;
}
+
+ LL_DEBUGS("ShaderLoading") << "loadShaderFile() completed, ret: " << U32(ret) << LL_ENDL;
return ret;
}
@@ -1248,6 +1272,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("sky_hdr_scale");
mReservedUniforms.push_back("sky_sunlight_scale");
mReservedUniforms.push_back("sky_ambient_scale");
+ mReservedUniforms.push_back("classic_mode");
mReservedUniforms.push_back("blue_horizon");
mReservedUniforms.push_back("blue_density");
mReservedUniforms.push_back("haze_horizon");
@@ -1375,6 +1400,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("screenTex");
mReservedUniforms.push_back("screenDepth");
mReservedUniforms.push_back("refTex");
+ mReservedUniforms.push_back("exclusionTex");
mReservedUniforms.push_back("eyeVec");
mReservedUniforms.push_back("time");
mReservedUniforms.push_back("waveDir1");
@@ -1470,6 +1496,11 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("debug_normal_draw_length");
+ mReservedUniforms.push_back("edgesTex");
+ mReservedUniforms.push_back("areaTex");
+ mReservedUniforms.push_back("searchTex");
+ mReservedUniforms.push_back("blendTex");
+
llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
std::set<std::string> dupe_check;
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index 2b76ef664b..46788841a5 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -36,6 +36,8 @@ public:
LLShaderMgr();
virtual ~LLShaderMgr();
+ // Note: although you can use statically hashed strings to just bind a random uniform, it's generally preferably that you use this.
+ // Always document what the actual shader uniform is next to the shader uniform in this struct.
// clang-format off
typedef enum
{ // Shader uniform name, set in LLShaderMgr::initAttribsAndUniforms()
@@ -121,6 +123,7 @@ public:
SKY_HDR_SCALE, // "sky_hdr_scale"
SKY_SUNLIGHT_SCALE, // "sky_sunlight_scale"
SKY_AMBIENT_SCALE, // "sky_ambient_scale"
+ CLASSIC_MODE, // "classic_mode"
BLUE_HORIZON, // "blue_horizon"
BLUE_DENSITY, // "blue_density"
HAZE_HORIZON, // "haze_horizon"
@@ -233,6 +236,7 @@ public:
WATER_SCREENTEX, // "screenTex"
WATER_SCREENDEPTH, // "screenDepth"
WATER_REFTEX, // "refTex"
+ WATER_EXCLUSIONTEX, // "exclusionTex"
WATER_EYEVEC, // "eyeVec"
WATER_TIME, // "time"
WATER_WAVE_DIR1, // "waveDir1"
@@ -332,6 +336,11 @@ public:
DEBUG_NORMAL_DRAW_LENGTH, // "debug_normal_draw_length"
+ SMAA_EDGE_TEX, // "edgesTex"
+ SMAA_AREA_TEX, // "areaTex"
+ SMAA_SEARCH_TEX, // "searchTex"
+ SMAA_BLEND_TEX, // "blendTex"
+
END_RESERVED_UNIFORMS
} eGLSLReservedUniforms;
// clang-format on
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index ee491b79e3..ac6db0b34f 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -36,10 +36,7 @@
#include "llshadermgr.h"
#include "llglslshader.h"
#include "llmemory.h"
-
-#include "llcontrol.h"
-
-extern LLControlGroup gSavedSettings;
+#include <glm/gtc/type_ptr.hpp>
//Next Highest Power Of Two
//helper function, returns first number > v that is a power of 2, or v if v is already a power of 2
@@ -275,11 +272,13 @@ static GLuint gen_buffer()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("gen buffer");
sIndex = pool_size;
+#if !LL_DARWIN
if (!gGLManager.mIsAMD)
{
glGenBuffers(pool_size, sNamePool);
}
else
+#endif
{ // work around for AMD driver bug
for (U32 i = 0; i < pool_size; ++i)
{
@@ -292,22 +291,58 @@ static GLuint gen_buffer()
return ret;
}
-#define ANALYZE_VBO_POOL 0
+static void delete_buffers(S32 count, GLuint* buffers)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+ // wait a few frames before actually deleting the buffers to avoid
+ // synchronization issues with the GPU
+ static std::vector<GLuint> sFreeList[4];
-#if 0 // LL_DARWIN
+ if (gGLManager.mInited)
+ {
+ U32 idx = LLImageGL::sFrameCount % 4;
+
+ for (S32 i = 0; i < count; ++i)
+ {
+ sFreeList[idx].push_back(buffers[i]);
+ }
+
+ idx = (LLImageGL::sFrameCount + 3) % 4;
-// experimental -- disable VBO pooling on OS X and use glMapBuffer
+ if (!sFreeList[idx].empty())
+ {
+ glDeleteBuffers((GLsizei)sFreeList[idx].size(), sFreeList[idx].data());
+ sFreeList[idx].resize(0);
+ }
+ }
+}
+
+
+#define ANALYZE_VBO_POOL 0
+
+// VBO Pool interface
class LLVBOPool
{
+ public:
+ virtual ~LLVBOPool() = default;
+ virtual void allocate(GLenum type, U32 size, GLuint& name, U8*& data) = 0;
+ virtual void free(GLenum type, U32 size, GLuint name, U8* data) = 0;
+ virtual U64 getVramBytesUsed() = 0;
+};
+
+// VBO Pool for Apple GPUs (as in M1/M2 etc, not Intel macs)
+// Effectively disables VBO pooling
+class LLAppleVBOPool final: public LLVBOPool
+{
public:
U64 mAllocated = 0;
- U64 getVramBytesUsed()
+ U64 getVramBytesUsed() override
{
return mAllocated;
}
- void allocate(GLenum type, U32 size, GLuint& name, U8*& data)
+ void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
STOP_GLERROR;
@@ -327,7 +362,7 @@ public:
}
}
- void free(GLenum type, U32 size, GLuint name, U8* data)
+ void free(GLenum type, U32 size, GLuint name, U8* data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
@@ -342,21 +377,17 @@ public:
STOP_GLERROR;
if (name)
{
- glDeleteBuffers(1, &name);
+ delete_buffers(1, &name);
}
STOP_GLERROR;
}
};
-#else
-
-class LLVBOPool
+// VBO Pool for GPUs that benefit from VBO pooling
+class LLDefaultVBOPool final : public LLVBOPool
{
public:
typedef std::chrono::steady_clock::time_point Time;
-
- U32 mMappingMode;
-
struct Entry
{
U8* mData;
@@ -364,16 +395,8 @@ public:
Time mAge;
};
- /*
- LLVBOPool()
+ ~LLDefaultVBOPool() override
{
-
- }
- */
-
- ~LLVBOPool()
- {
- if(mMappingMode == 3) return;
clear();
}
@@ -390,10 +413,9 @@ public:
U32 mMisses = 0;
U32 mHits = 0;
- U64 getVramBytesUsed()
+ U64 getVramBytesUsed() override
{
- if(mMappingMode == 3) return mAllocated;
- else return mAllocated + mReserved;
+ return mAllocated + mReserved;
}
// increase the size to some common value (e.g. a power of two) to increase hit rate
@@ -407,7 +429,7 @@ public:
size += block_size - (size % block_size);
}
- void allocate(GLenum type, U32 size, GLuint& name, U8*& data)
+ void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
@@ -415,20 +437,6 @@ public:
llassert(data == nullptr); // non null data indicates a buffer that wasn't freed
llassert(size >= 2); // any buffer size smaller than a single index is nonsensical
- if(mMappingMode == 3)
- {
- mAllocated += size;
-
- { //allocate a new buffer
- LL_PROFILE_GPU_ZONE("vbo alloc");
- // ON OS X, we don't allocate a VBO until the last possible moment
- // in unmapBuffer
- data = (U8*) ll_aligned_malloc_16(size);
- //STOP_GLERROR;
- }
- return;
- }
-
mDistributed += size;
adjustSize(size);
mAllocated += size;
@@ -477,30 +485,11 @@ public:
clean();
}
- void free(GLenum type, U32 size, GLuint name, U8* data)
+ void free(GLenum type, U32 size, GLuint name, U8* data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
llassert(size >= 2);
-
- if(mMappingMode == 3)
- {
- if (data)
- {
- ll_aligned_free_16(data);
- }
-
- mAllocated -= size;
- //STOP_GLERROR;
- if (name)
- {
- glDeleteBuffers(1, &name);
- }
- //STOP_GLERROR;
-
- return;
- }
-
llassert(name != 0);
llassert(data != nullptr);
@@ -559,7 +548,7 @@ public:
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vbo cache timeout");
auto& entry = entries.back();
ll_aligned_free_16(entry.mData);
- glDeleteBuffers(1, &entry.mGLName);
+ delete_buffers(1, &entry.mGLName);
llassert(mReserved >= iter->first);
mReserved -= iter->first;
entries.pop_back();
@@ -595,7 +584,7 @@ public:
for (auto& entry : entries.second)
{
ll_aligned_free_16(entry.mData);
- glDeleteBuffers(1, &entry.mGLName);
+ delete_buffers(1, &entry.mGLName);
}
}
@@ -604,7 +593,7 @@ public:
for (auto& entry : entries.second)
{
ll_aligned_free_16(entry.mData);
- glDeleteBuffers(1, &entry.mGLName);
+ delete_buffers(1, &entry.mGLName);
}
}
@@ -614,10 +603,71 @@ public:
mVBOPool.clear();
}
};
-#endif
static LLVBOPool* sVBOPool = nullptr;
+void LLVertexBufferData::drawWithMatrix()
+{
+ if (!mVB)
+ {
+ llassert(false);
+ // Not supposed to happen, check buffer generation
+ return;
+ }
+
+ if (mTexName)
+ {
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTexName);
+ }
+ else
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ gGL.loadMatrix(glm::value_ptr(mModelView));
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadMatrix(glm::value_ptr(mProjection));
+ gGL.matrixMode(LLRender::MM_TEXTURE0);
+ gGL.pushMatrix();
+ gGL.loadMatrix(glm::value_ptr(mTexture0));
+
+ mVB->setBuffer();
+ mVB->drawArrays(mMode, 0, mCount);
+
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+}
+
+void LLVertexBufferData::draw()
+{
+ if (!mVB)
+ {
+ llassert(false);
+ // Not supposed to happen, check buffer generation
+ return;
+ }
+
+ if (mTexName)
+ {
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTexName);
+ }
+ else
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+
+ mVB->setBuffer();
+ mVB->drawArrays(mMode, 0, mCount);
+}
+
+//============================================================================
+
//static
U64 LLVertexBuffer::getBytesAllocated()
{
@@ -632,7 +682,6 @@ U32 LLVertexBuffer::sGLRenderIndices = 0;
U32 LLVertexBuffer::sLastMask = 0;
U32 LLVertexBuffer::sVertexCount = 0;
-U32 LLVertexBuffer::sMappingMode = 0;
//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware
const U32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
@@ -681,7 +730,6 @@ const U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
- GL_QUADS,
GL_LINE_LOOP,
};
@@ -896,10 +944,17 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
void LLVertexBuffer::initClass(LLWindow* window)
{
llassert(sVBOPool == nullptr);
- sVBOPool = new LLVBOPool();
- sVBOPool->mMappingMode = sMappingMode;
- //LL_INFOS() << "sVBOPool intialized with mapping mode: " << sMappingMode << LL_ENDL;
+ if (gGLManager.mIsApple)
+ {
+ LL_INFOS() << "VBO Pooling Disabled" << LL_ENDL;
+ sVBOPool = new LLAppleVBOPool();
+ }
+ else
+ {
+ LL_INFOS() << "VBO Pooling Enabled" << LL_ENDL;
+ sVBOPool = new LLDefaultVBOPool();
+ }
#if ENABLE_GL_WORK_QUEUE
sQueue = new GLWorkQueue();
@@ -958,6 +1013,24 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask)
}
}
+// list of mapped buffers
+// NOTE: must not be LLPointer<LLVertexBuffer> to avoid breaking non-ref-counted LLVertexBuffer instances
+static std::vector<LLVertexBuffer*> sMappedBuffers;
+
+//static
+void LLVertexBuffer::flushBuffers()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+ // must only be called from main thread
+ for (auto& buffer : sMappedBuffers)
+ {
+ buffer->_unmapBuffer();
+ buffer->mMapped = false;
+ }
+
+ sMappedBuffers.resize(0);
+}
+
//static
U32 LLVertexBuffer::calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices)
{
@@ -1001,6 +1074,12 @@ U32 LLVertexBuffer::calcVertexSize(const U32& typemask)
//virtual
LLVertexBuffer::~LLVertexBuffer()
{
+ if (mMapped)
+ { // is on the mapped buffer list but doesn't need to be flushed
+ mMapped = false;
+ unmapBuffer();
+ }
+
destroyGLBuffer();
destroyGLIndices();
@@ -1202,13 +1281,14 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, U32 start, U32 end)
U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 index, S32 count)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+ _mapBuffer();
if (count == -1)
{
count = mNumVerts - index;
}
- if(sMappingMode != 3)
+ if (!gGLManager.mIsApple)
{
U32 start = mOffsets[type] + sTypeSize[type] * index;
U32 end = start + sTypeSize[type] * count-1;
@@ -1231,7 +1311,6 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde
mMappedVertexRegions.push_back({ start, end });
}
}
-
return mMappedData+mOffsets[type]+sTypeSize[type]*index;
}
@@ -1239,13 +1318,14 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde
U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+ _mapBuffer();
if (count == -1)
{
count = mNumIndices-index;
}
- if(sMappingMode != 3)
+ if (!gGLManager.mIsApple)
{
U32 start = sizeof(U16) * index;
U32 end = start + sizeof(U16) * count-1;
@@ -1280,57 +1360,64 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
// dst -- mMappedData or mMappedIndexData
void LLVertexBuffer::flush_vbo(GLenum target, U32 start, U32 end, void* data, U8* dst)
{
- if(sMappingMode == 2)
- {
- //LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb glMapBufferRange");
- if (end == 0) return;
- U32 buffer_size = end-start+1;
- U8 * mptr = (U8*) glMapBufferRange( target, start, end-start+1, GL_MAP_WRITE_BIT);
-
- if (mptr)
- {
- std::memcpy(mptr, (U8*) data, buffer_size);
- if(!glUnmapBuffer(target)) LL_WARNS() << "glUnmapBuffer() failed" << LL_ENDL;
- }
- else LL_WARNS() << "glMapBufferRange() returned NULL" << LL_ENDL;
- return;
- }
-
- if(sMappingMode == 3)
+ if (gGLManager.mIsApple)
{
+ // on OS X, flush_vbo doesn't actually write to the GL buffer, so be sure to call
+ // _mapBuffer to tag the buffer for flushing to GL
+ _mapBuffer();
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb memcpy");
- //STOP_GLERROR;
+ STOP_GLERROR;
// copy into mapped buffer
memcpy(dst+start, data, end-start+1);
- return;
}
-
- llassert(target == GL_ARRAY_BUFFER ? sGLRenderBuffer == mGLBuffer : sGLRenderIndices == mGLIndices);
-
- // skip mapped data and stream to GPU via glBufferSubData
- if (end != 0)
+ else
{
- LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData");
- LL_PROFILE_ZONE_NUM(start);
- LL_PROFILE_ZONE_NUM(end);
- LL_PROFILE_ZONE_NUM(end-start);
+ llassert(target == GL_ARRAY_BUFFER ? sGLRenderBuffer == mGLBuffer : sGLRenderIndices == mGLIndices);
- constexpr U32 block_size = 8192;
-
- for (U32 i = start; i <= end; i += block_size)
+ // skip mapped data and stream to GPU via glBufferSubData
+ if (end != 0)
{
- LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block");
- //LL_PROFILE_GPU_ZONE("glBufferSubData");
- U32 tend = llmin(i + block_size, end);
- U32 size = tend - i + 1;
- glBufferSubData(target, i, size, (U8*) data + (i-start));
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData");
+ LL_PROFILE_ZONE_NUM(start);
+ LL_PROFILE_ZONE_NUM(end);
+ LL_PROFILE_ZONE_NUM(end-start);
+
+ constexpr U32 block_size = 65536;
+
+ for (U32 i = start; i <= end; i += block_size)
+ {
+ //LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block");
+ //LL_PROFILE_GPU_ZONE("glBufferSubData");
+ U32 tend = llmin(i + block_size, end);
+ U32 size = tend - i + 1;
+ glBufferSubData(target, i, size, (U8*) data + (i-start));
+ }
}
}
}
void LLVertexBuffer::unmapBuffer()
{
+ flushBuffers();
+}
+
+void LLVertexBuffer::_mapBuffer()
+{
+ if (!mMapped)
+ {
+ mMapped = true;
+ sMappedBuffers.push_back(this);
+ }
+}
+
+void LLVertexBuffer::_unmapBuffer()
+{
STOP_GLERROR;
+ if (!mMapped)
+ {
+ return;
+ }
+
struct SortMappedRegion
{
bool operator()(const MappedRegion& lhs, const MappedRegion& rhs)
@@ -1339,114 +1426,115 @@ void LLVertexBuffer::unmapBuffer()
}
};
- if(sMappingMode == 3)
+ if (gGLManager.mIsApple)
{
- //STOP_GLERROR;
+ STOP_GLERROR;
if (mMappedData)
{
if (mGLBuffer)
{
- glDeleteBuffers(1, &mGLBuffer);
+ delete_buffers(1, &mGLBuffer);
}
mGLBuffer = gen_buffer();
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
- glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_STATIC_DRAW);
}
else if (mGLBuffer != sGLRenderBuffer)
{
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
}
- //STOP_GLERROR;
+ STOP_GLERROR;
if (mMappedIndexData)
{
if (mGLIndices)
{
- glDeleteBuffers(1, &mGLIndices);
+ delete_buffers(1, &mGLIndices);
}
mGLIndices = gen_buffer();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mMappedIndexData, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mMappedIndexData, GL_STATIC_DRAW);
}
else if (mGLIndices != sGLRenderIndices)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
}
- //STOP_GLERROR;
- return;
+ STOP_GLERROR;
}
-
- if (!mMappedVertexRegions.empty())
+ else
{
- LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
-
- if (sGLRenderBuffer != mGLBuffer)
+ if (!mMappedVertexRegions.empty())
{
- glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
- sGLRenderBuffer = mGLBuffer;
- }
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
- U32 start = 0;
- U32 end = 0;
-
- std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion());
-
- for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
- {
- const MappedRegion& region = mMappedVertexRegions[i];
- if (region.mStart == end + 1)
+ if (sGLRenderBuffer != mGLBuffer)
{
- end = region.mEnd;
+ glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
+ sGLRenderBuffer = mGLBuffer;
}
- else
- {
- flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
- start = region.mStart;
- end = region.mEnd;
- }
- }
- flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
- mMappedVertexRegions.clear();
- }
+ U32 start = 0;
+ U32 end = 0;
- if (!mMappedIndexRegions.empty())
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
+ std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion());
- if (mGLIndices != sGLRenderIndices)
- {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
- sGLRenderIndices = mGLIndices;
- }
- U32 start = 0;
- U32 end = 0;
+ for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
+ {
+ const MappedRegion& region = mMappedVertexRegions[i];
+ if (region.mStart == end + 1)
+ {
+ end = region.mEnd;
+ }
+ else
+ {
+ flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
+ start = region.mStart;
+ end = region.mEnd;
+ }
+ }
- std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion());
+ flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
+ mMappedVertexRegions.clear();
+ }
- for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+ if (!mMappedIndexRegions.empty())
{
- const MappedRegion& region = mMappedIndexRegions[i];
- if (region.mStart == end + 1)
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
+
+ if (mGLIndices != sGLRenderIndices)
{
- end = region.mEnd;
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
+ sGLRenderIndices = mGLIndices;
}
- else
+ U32 start = 0;
+ U32 end = 0;
+
+ std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion());
+
+ for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
{
- flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
- start = region.mStart;
- end = region.mEnd;
+ const MappedRegion& region = mMappedIndexRegions[i];
+ if (region.mStart == end + 1)
+ {
+ end = region.mEnd;
+ }
+ else
+ {
+ flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
+ start = region.mStart;
+ end = region.mEnd;
+ }
}
- }
- flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
- mMappedIndexRegions.clear();
+ flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
+ mMappedIndexRegions.clear();
+ }
}
}
@@ -1568,12 +1656,12 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, U32 in
// Set for rendering
void LLVertexBuffer::setBuffer()
{
- if(sMappingMode == 3)
+ STOP_GLERROR;
+
+ if (mMapped)
{
- if (!mGLBuffer)
- {
- return;
- }
+ LL_WARNS_ONCE() << "Missing call to unmapBuffer or flushBuffers" << LL_ENDL;
+ _unmapBuffer();
}
// no data may be pending
@@ -1619,55 +1707,58 @@ void LLVertexBuffer::setupVertexBuffer()
STOP_GLERROR;
U8* base = nullptr;
+ AttributeType loc;
+ void* ptr = nullptr;
+
U32 data_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
if (data_mask & MAP_NORMAL)
{
- AttributeType loc = TYPE_NORMAL;
- void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
+ loc = TYPE_NORMAL;
+ ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
}
if (data_mask & MAP_TEXCOORD3)
{
- AttributeType loc = TYPE_TEXCOORD3;
- void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
+ loc = TYPE_TEXCOORD3;
+ ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
}
if (data_mask & MAP_TEXCOORD2)
{
- AttributeType loc = TYPE_TEXCOORD2;
- void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
+ loc = TYPE_TEXCOORD2;
+ ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
}
if (data_mask & MAP_TEXCOORD1)
{
- AttributeType loc = TYPE_TEXCOORD1;
- void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
+ loc = TYPE_TEXCOORD1;
+ ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
}
if (data_mask & MAP_TANGENT)
{
- AttributeType loc = TYPE_TANGENT;
- void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
+ loc = TYPE_TANGENT;
+ ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
}
if (data_mask & MAP_TEXCOORD0)
{
- AttributeType loc = TYPE_TEXCOORD0;
- void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
+ loc = TYPE_TEXCOORD0;
+ ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
}
if (data_mask & MAP_COLOR)
{
- AttributeType loc = TYPE_COLOR;
+ loc = TYPE_COLOR;
//bind emissive instead of color pointer if emissive is present
- void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
+ ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
}
if (data_mask & MAP_EMISSIVE)
{
- AttributeType loc = TYPE_EMISSIVE;
- void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
+ loc = TYPE_EMISSIVE;
+ ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
if (!(data_mask & MAP_COLOR))
@@ -1678,38 +1769,38 @@ void LLVertexBuffer::setupVertexBuffer()
}
if (data_mask & MAP_WEIGHT)
{
- AttributeType loc = TYPE_WEIGHT;
- void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
+ loc = TYPE_WEIGHT;
+ ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
glVertexAttribPointer(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
}
if (data_mask & MAP_WEIGHT4)
{
- AttributeType loc = TYPE_WEIGHT4;
- void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT4]);
+ loc = TYPE_WEIGHT4;
+ ptr = (void*)(base + mOffsets[TYPE_WEIGHT4]);
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
}
if (data_mask & MAP_JOINT)
{
- AttributeType loc = TYPE_JOINT;
- void* ptr = (void*)(base + mOffsets[TYPE_JOINT]);
+ loc = TYPE_JOINT;
+ ptr = (void*)(base + mOffsets[TYPE_JOINT]);
glVertexAttribIPointer(loc, 4, GL_UNSIGNED_SHORT, LLVertexBuffer::sTypeSize[TYPE_JOINT], ptr);
}
if (data_mask & MAP_CLOTHWEIGHT)
{
- AttributeType loc = TYPE_CLOTHWEIGHT;
- void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
+ loc = TYPE_CLOTHWEIGHT;
+ ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
}
if (data_mask & MAP_TEXTURE_INDEX)
{
- AttributeType loc = TYPE_TEXTURE_INDEX;
- void* ptr = (void*)(base + mOffsets[TYPE_VERTEX] + 12);
+ loc = TYPE_TEXTURE_INDEX;
+ ptr = (void*)(base + mOffsets[TYPE_VERTEX] + 12);
glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
}
if (data_mask & MAP_VERTEX)
{
- AttributeType loc = TYPE_VERTEX;
- void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
+ loc = TYPE_VERTEX;
+ ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
}
STOP_GLERROR;
@@ -1826,7 +1917,3 @@ void LLVertexBuffer::setIndexData(const U32* data, U32 offset, U32 count)
}
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, offset * sizeof(U32), (offset + count) * sizeof(U32) - 1, (U8*)data, mMappedIndexData);
}
-
-
-
-
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 293f740497..375ad76fb8 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -38,6 +38,7 @@
#include <set>
#include <vector>
#include <list>
+#include <glm/gtc/matrix_transform.hpp>
#define LL_MAX_VERTEX_ATTRIB_LOCATION 64
@@ -53,6 +54,41 @@
//============================================================================
// base class
class LLPrivateMemoryPool;
+class LLVertexBuffer;
+
+class LLVertexBufferData
+{
+public:
+ LLVertexBufferData()
+ : mVB(nullptr)
+ , mMode(0)
+ , mCount(0)
+ , mTexName(0)
+ , mProjection(glm::identity<glm::mat4>())
+ , mModelView(glm::identity<glm::mat4>())
+ , mTexture0(glm::identity<glm::mat4>())
+ {}
+ LLVertexBufferData(LLVertexBuffer* buffer, U8 mode, U32 count, U32 tex_name, const glm::mat4& model_view, const glm::mat4& projection, const glm::mat4& texture0)
+ : mVB(buffer)
+ , mMode(mode)
+ , mCount(count)
+ , mTexName(tex_name)
+ , mProjection(model_view)
+ , mModelView(projection)
+ , mTexture0(texture0)
+ {}
+ void drawWithMatrix();
+ void draw();
+ LLPointer<LLVertexBuffer> mVB;
+ U8 mMode;
+ U32 mCount;
+ U32 mTexName;
+ glm::mat4 mProjection;
+ glm::mat4 mModelView;
+ glm::mat4 mTexture0;
+};
+typedef std::list<LLVertexBufferData> buffer_data_list_t;
+
class LLVertexBuffer final : public LLRefCount
{
public:
@@ -89,6 +125,9 @@ public:
// indexed by the following enum
static U32 calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices);
+ // flush any pending mapped buffers
+ static void flushBuffers();
+
//WARNING -- when updating these enums you MUST
// 1 - update LLVertexBuffer::sTypeSize
// 2 - update LLVertexBuffer::vb_type_name
@@ -159,6 +198,8 @@ public:
// map for data access (see also getFooStrider below)
U8* mapVertexBuffer(AttributeType type, U32 index, S32 count = -1);
U8* mapIndexBuffer(U32 index, S32 count = -1);
+
+ // synonym for flushBuffers
void unmapBuffer();
// set for rendering
@@ -281,6 +322,13 @@ private:
bool allocateBuffer(S32 nverts, S32 nindices, bool create) { return allocateBuffer(nverts, nindices); }
+ // actually unmap buffer
+ void _unmapBuffer();
+
+ // add to set of mapped buffers
+ void _mapBuffer();
+ bool mMapped = false;
+
public:
static U64 getBytesAllocated();
@@ -290,8 +338,6 @@ public:
static U32 sGLRenderIndices;
static U32 sLastMask;
static U32 sVertexCount;
-
- static U32 sMappingMode;
};
#ifdef LL_PROFILER_ENABLE_RENDER_DOC