summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
authornat-goodspeed <nat@lindenlab.com>2024-09-05 15:40:12 -0400
committerGitHub <noreply@github.com>2024-09-05 15:40:12 -0400
commit04568da18d2261f3f7b851cf5341b766c9648204 (patch)
tree83d5db1c173636bb77ebb33e860fac77ab5d79e8 /indra/llrender
parent18d81e20f0b0044c16615953d7b69d7fb34d3449 (diff)
parentff2d79906ccef217194d5d9ec9d7025db03592a8 (diff)
Merge pull request #2513 from secondlife/lua-merge-dev
Merge develop branch into Lua project branch.
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/CMakeLists.txt2
-rw-r--r--indra/llrender/llcubemaparray.cpp14
-rw-r--r--indra/llrender/llfontbitmapcache.cpp2
-rw-r--r--indra/llrender/llfontfreetype.cpp2
-rw-r--r--indra/llrender/llfontfreetypesvg.cpp20
-rw-r--r--indra/llrender/llfontgl.cpp25
-rw-r--r--indra/llrender/llfontregistry.cpp2
-rw-r--r--indra/llrender/llfontvertexbuffer.cpp211
-rw-r--r--indra/llrender/llfontvertexbuffer.h119
-rw-r--r--indra/llrender/llgl.cpp15
-rw-r--r--indra/llrender/llgl.h4
-rw-r--r--indra/llrender/llglslshader.cpp76
-rw-r--r--indra/llrender/llglslshader.h14
-rw-r--r--indra/llrender/llgltexture.cpp21
-rw-r--r--indra/llrender/llgltexture.h8
-rw-r--r--indra/llrender/llimagegl.cpp582
-rw-r--r--indra/llrender/llimagegl.h50
-rw-r--r--indra/llrender/llpostprocess.cpp2
-rw-r--r--indra/llrender/llrender.cpp266
-rw-r--r--indra/llrender/llrender.h39
-rw-r--r--indra/llrender/llrender2dutils.cpp16
-rw-r--r--indra/llrender/llrender2dutils.h7
-rw-r--r--indra/llrender/llrendertarget.cpp23
-rw-r--r--indra/llrender/llrendertarget.h6
-rw-r--r--indra/llrender/llshadermgr.cpp27
-rw-r--r--indra/llrender/llshadermgr.h9
-rw-r--r--indra/llrender/lluiimage.cpp12
-rw-r--r--indra/llrender/llvertexbuffer.cpp60
-rw-r--r--indra/llrender/llvertexbuffer.h40
29 files changed, 1137 insertions, 537 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index 7f881c8bb3..ccff7c7a8c 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 be69b997da..4f5e13765a 100644
--- a/indra/llrender/llcubemaparray.cpp
+++ b/indra/llrender/llcubemaparray.cpp
@@ -125,27 +125,25 @@ void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool us
mImage->setHasMipMaps(use_mips);
bind(0);
+ free_cur_tex_image();
U32 format = components == 4 ? GL_RGBA16F : GL_RGB16F;
-
U32 mip = 0;
-
- free_cur_tex_image();
-
- while (resolution >= 1)
+ U32 mip_resolution = resolution;
+ while (mip_resolution >= 1)
{
- 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);
if (!use_mips)
{
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/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp
index 46c2e89797..ee9cfd0719 100644
--- a/indra/llrender/llfontbitmapcache.cpp
+++ b/indra/llrender/llfontbitmapcache.cpp
@@ -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].push_back(new LLImageGL(image_raw, false, false));
LLImageGL* image_gl = getImageGL(bitmap_type, bitmap_num);
// Start at beginning of the new image.
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index 741ed993b0..6128e03fa7 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -178,7 +178,7 @@ unsigned long ft_read_cb(FT_Stream stream, unsigned long offset, unsigned char *
llifstream *file_stream = static_cast<llifstream *>(stream->descriptor.pointer);
file_stream->seekg(offset, std::ios::beg);
file_stream->read((char*)buffer, count);
- return file_stream->gcount();
+ return (unsigned long)file_stream->gcount();
}
void ft_close_cb(FT_Stream stream) {
diff --git a/indra/llrender/llfontfreetypesvg.cpp b/indra/llrender/llfontfreetypesvg.cpp
index 355e8432aa..71f751329e 100644
--- a/indra/llrender/llfontfreetypesvg.cpp
+++ b/indra/llrender/llfontfreetypesvg.cpp
@@ -136,18 +136,18 @@ FT_Error LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot(FT_GlyphSlot glyph_slot,
float svg_scale = llmin(svg_x_scale, svg_y_scale);
datap->Scale = svg_scale;
- glyph_slot->bitmap.width = floorf(svg_width) * svg_scale;
- glyph_slot->bitmap.rows = floorf(svg_height) * svg_scale;
+ glyph_slot->bitmap.width = (unsigned int)(floorf(svg_width) * svg_scale);
+ glyph_slot->bitmap.rows = (unsigned int)(floorf(svg_height) * svg_scale);
glyph_slot->bitmap_left = (document->metrics.x_ppem - glyph_slot->bitmap.width) / 2;
- glyph_slot->bitmap_top = glyph_slot->face->size->metrics.ascender / 64.f;
+ glyph_slot->bitmap_top = (FT_Int)(glyph_slot->face->size->metrics.ascender / 64.f);
glyph_slot->bitmap.pitch = glyph_slot->bitmap.width * 4;
glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
/* Copied as-is from fcft (MIT license) */
// Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box.
- float horiBearingX = 0.;
- float horiBearingY = -glyph_slot->bitmap_top;
+ float horiBearingX = 0.f;
+ float horiBearingY = -(float)glyph_slot->bitmap_top;
// XXX parentheses correct?
float vertBearingX = glyph_slot->metrics.horiBearingX / 64.0f - glyph_slot->metrics.horiAdvance / 64.0f / 2;
@@ -156,13 +156,13 @@ FT_Error LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot(FT_GlyphSlot glyph_slot,
// Do conversion in two steps to avoid 'bad function cast' warning
glyph_slot->metrics.width = glyph_slot->bitmap.width * 64;
glyph_slot->metrics.height = glyph_slot->bitmap.rows * 64;
- glyph_slot->metrics.horiBearingX = horiBearingX * 64;
- glyph_slot->metrics.horiBearingY = horiBearingY * 64;
- glyph_slot->metrics.vertBearingX = vertBearingX * 64;
- glyph_slot->metrics.vertBearingY = vertBearingY * 64;
+ glyph_slot->metrics.horiBearingX = (FT_Pos)(horiBearingX * 64);
+ glyph_slot->metrics.horiBearingY = (FT_Pos)(horiBearingY * 64);
+ glyph_slot->metrics.vertBearingX = (FT_Pos)(vertBearingX * 64);
+ glyph_slot->metrics.vertBearingY = (FT_Pos)(vertBearingY * 64);
if (glyph_slot->metrics.vertAdvance == 0)
{
- glyph_slot->metrics.vertAdvance = glyph_slot->bitmap.rows * 1.2f * 64;
+ glyph_slot->metrics.vertAdvance = (FT_Pos)(glyph_slot->bitmap.rows * 1.2f * 64);
}
return FT_Err_Ok;
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 59ee8ef84f..9721b020c7 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -112,7 +112,7 @@ S32 LLFontGL::getNumFaces(const std::string& filename)
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
{
- LLRectf rect_float(rect.mLeft, rect.mTop, rect.mRight, rect.mBottom);
+ LLRectf rect_float((F32)rect.mLeft, (F32)rect.mTop, (F32)rect.mRight, (F32)rect.mBottom);
return render(wstr, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses, use_color);
}
@@ -138,7 +138,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rec
y = rect.mBottom;
break;
}
- return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses, use_color);
+ return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, (S32)rect.getWidth(), right_x, use_ellipses, use_color);
}
@@ -270,10 +270,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
const LLFontGlyphInfo* next_glyph = NULL;
- const S32 GLYPH_BATCH_SIZE = 30;
- LLVector3 vertices[GLYPH_BATCH_SIZE * 4];
- LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
- LLColor4U colors[GLYPH_BATCH_SIZE * 4];
+ static constexpr S32 GLYPH_BATCH_SIZE = 30;
+ static thread_local LLVector3 vertices[GLYPH_BATCH_SIZE * 4];
+ static thread_local LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
+ static thread_local LLColor4U colors[GLYPH_BATCH_SIZE * 4];
LLColor4U text_color(color);
// Preserve the transparency to render fading emojis in fading text (e.g.
@@ -402,11 +402,11 @@ 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();
- renderUTF8(std::string("..."),
+ static LLWString elipses_wstr(utf8string_to_wstring(std::string("...")));
+ render(elipses_wstr,
0,
(cur_x - origin.mV[VX]) / sScaleX, (F32)y,
color,
@@ -503,6 +503,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;
@@ -560,7 +561,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
void LLFontGL::generateASCIIglyphs()
{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
for (U32 i = 32; (i < 127); i++)
{
mFontFreetype->getGlyphInfo(i, EFontGlyphType::Grayscale);
@@ -570,7 +571,7 @@ void LLFontGL::generateASCIIglyphs()
// Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, EWordWrapStyle end_on_word_boundary) const
{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
if (!wchars || !wchars[0] || max_chars == 0)
{
return 0;
@@ -881,7 +882,7 @@ void LLFontGL::dumpFontTextures()
// static
bool LLFontGL::loadDefaultFonts()
{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
bool succ = true;
succ &= (NULL != getFontSansSerifSmall());
succ &= (NULL != getFontSansSerif());
@@ -894,7 +895,7 @@ bool LLFontGL::loadDefaultFonts()
void LLFontGL::loadCommonFonts()
{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
getFont(LLFontDescriptor("SansSerif", "Small", BOLD));
getFont(LLFontDescriptor("SansSerif", "Large", BOLD));
getFont(LLFontDescriptor("SansSerif", "Huge", BOLD));
diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp
index 62f4f35e3d..c48a389f6a 100644
--- a/indra/llrender/llfontregistry.cpp
+++ b/indra/llrender/llfontregistry.cpp
@@ -500,7 +500,7 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
// *HACK: Fallback fonts don't render, so we can use that to suppress
// creation of OpenGL textures for test apps. JC
bool is_fallback = !is_first_found || !mCreateGLTextures;
- F32 extra_scale = (is_fallback)?fallback_scale:1.0;
+ F32 extra_scale = (is_fallback) ? fallback_scale : 1.0f;
F32 point_size_scale = extra_scale * point_size;
bool is_font_loaded = false;
for(string_vec_t::iterator font_search_path_it = font_search_paths.begin();
diff --git a/indra/llrender/llfontvertexbuffer.cpp b/indra/llrender/llfontvertexbuffer.cpp
new file mode 100644
index 0000000000..392f235aad
--- /dev/null
+++ b/indra/llrender/llfontvertexbuffer.cpp
@@ -0,0 +1,211 @@
+/**
+ * @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"
+
+
+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 (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
+ || mLastOrigin != LLFontGL::sCurOrigin)
+ {
+ 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();
+
+ 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;
+ mLastOrigin = LLFontGL::sCurOrigin;
+
+ if (right_x)
+ {
+ mLastRightX = *right_x;
+ }
+}
+
+void LLFontVertexBuffer::renderBuffers()
+{
+ gGL.flush(); // deliberately empty pending verts
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+ gGL.pushUIMatrix();
+ 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..67cf2ca13c
--- /dev/null
+++ b/indra/llrender/llfontvertexbuffer.h
@@ -0,0 +1,119 @@
+/**
+ * @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);
+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;
+ LLCoordGL mLastOrigin;
+};
+
+#endif
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 7959b3bb57..0db1e27b01 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -1038,6 +1038,7 @@ void LLGLManager::initWGL()
GLH_EXT_NAME(wglGetGPUIDsAMD) = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD");
GLH_EXT_NAME(wglGetGPUInfoAMD) = (PFNWGLGETGPUINFOAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUInfoAMD");
}
+ mHasNVXGpuMemoryInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts);
if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts))
{
@@ -1205,6 +1206,17 @@ bool LLGLManager::initGL()
LL_WARNS("RenderInit") << "VRAM Detected (AMDAssociations):" << mVRAM << LL_ENDL;
}
}
+ else if (mHasNVXGpuMemoryInfo)
+ {
+ GLint mem_kb = 0;
+ glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &mem_kb);
+ mVRAM = mem_kb / 1024;
+
+ if (mVRAM != 0)
+ {
+ LL_WARNS("RenderInit") << "VRAM Detected (NVXGpuMemoryInfo):" << mVRAM << LL_ENDL;
+ }
+ }
#endif
#if LL_WINDOWS
@@ -2742,7 +2754,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)
@@ -2775,6 +2787,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G
LLGLDepthTest::~LLGLDepthTest()
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
checkState();
if (sDepthEnabled != mPrevDepthEnabled )
{
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 909dad2e85..cd1ba55b16 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -97,11 +97,15 @@ public:
// Vendor-specific extensions
bool mHasAMDAssociations = false;
+ bool mHasNVXGpuMemoryInfo = false;
bool mIsAMD;
bool mIsNVIDIA;
bool mIsIntel;
+ // hints to the render pipe
+ U32 mDownScaleMethod = 0; // see settings.xml RenderDownScaleMethod
+
#if LL_DARWIN
// Needed to distinguish problem cards on older Macs that break with Materials
bool mIsMobileGF;
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 25e4a88f28..a157bfee21 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -190,7 +190,7 @@ void LLGLSLShader::dumpStats()
tris_sec /= seconds;
F32 pct_samples = (F32)((F64)mSamplesDrawn / (F64)sTotalSamplesDrawn) * 100.f;
- F32 samples_sec = (F32)mSamplesDrawn / 1000000000.0;
+ F32 samples_sec = (F32)(mSamplesDrawn / 1000000000.0);
samples_sec /= seconds;
F32 pct_binds = (F32)mBinds / (F32)sTotalBinds * 100.f;
@@ -1087,17 +1087,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;
@@ -1113,7 +1113,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;
@@ -1194,7 +1193,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;
@@ -1211,12 +1210,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;
@@ -1229,7 +1227,7 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTe
S32 index = mTexture[uniform];
if (index != -1 && gGL.getTexUnit(index)->getCurrType() != LLTexUnit::TT_NONE)
{
- if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode && gGL.getTexUnit(index)->getCurrColorSpace() != space)
+ if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode)
{
if (gDebugSession)
{
@@ -1265,7 +1263,7 @@ void LLGLSLShader::uniform1i(U32 index, GLint x)
if (iter == mValue.end() || iter->second.mV[0] != x)
{
glUniform1i(mUniform[index], x);
- mValue[mUniform[index]] = LLVector4(x, 0.f, 0.f, 0.f);
+ mValue[mUniform[index]] = LLVector4((F32)x, 0.f, 0.f, 0.f);
}
}
}
@@ -1405,7 +1403,7 @@ void LLGLSLShader::uniform1iv(U32 index, U32 count, const GLint* v)
if (mUniform[index] >= 0)
{
const auto& iter = mValue.find(mUniform[index]);
- LLVector4 vec(v[0], 0.f, 0.f, 0.f);
+ LLVector4 vec((F32)v[0], 0.f, 0.f, 0.f);
if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
{
glUniform1iv(mUniform[index], count, v);
@@ -1432,7 +1430,7 @@ void LLGLSLShader::uniform4iv(U32 index, U32 count, const GLint* v)
if (mUniform[index] >= 0)
{
const auto& iter = mValue.find(mUniform[index]);
- LLVector4 vec(v[0], v[1], v[2], v[3]);
+ LLVector4 vec((F32)v[0], (F32)v[1], (F32)v[2], (F32)v[3]);
if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
{
glUniform1iv(mUniform[index], count, v);
@@ -1552,6 +1550,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;
@@ -1702,7 +1728,7 @@ void LLGLSLShader::uniform1i(const LLStaticHashedString& uniform, GLint v)
if (location >= 0)
{
const auto& iter = mValue.find(location);
- LLVector4 vec(v, 0.f, 0.f, 0.f);
+ LLVector4 vec((F32)v, 0.f, 0.f, 0.f);
if (iter == mValue.end() || shouldChange(iter->second, vec))
{
glUniform1i(location, v);
@@ -1718,7 +1744,7 @@ void LLGLSLShader::uniform1iv(const LLStaticHashedString& uniform, U32 count, co
if (location >= 0)
{
- LLVector4 vec(v[0], 0, 0, 0);
+ LLVector4 vec((F32)v[0], 0.f, 0.f, 0.f);
const auto& iter = mValue.find(location);
if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
{
@@ -1736,7 +1762,7 @@ void LLGLSLShader::uniform4iv(const LLStaticHashedString& uniform, U32 count, co
if (location >= 0)
{
- LLVector4 vec(v[0], v[1], v[2], v[3]);
+ 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)
{
@@ -1755,7 +1781,7 @@ void LLGLSLShader::uniform2i(const LLStaticHashedString& uniform, GLint i, GLint
if (location >= 0)
{
const auto& iter = mValue.find(location);
- LLVector4 vec(i, j, 0.f, 0.f);
+ LLVector4 vec((F32)i, (F32)j, 0.f, 0.f);
if (iter == mValue.end() || shouldChange(iter->second, vec))
{
glUniform2i(location, i, j);
@@ -1886,6 +1912,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..27c8f0b7d0 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -208,6 +208,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);
@@ -223,6 +224,7 @@ public:
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 +241,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 +253,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);
diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp
index e614f45986..4dcca5a726 100644
--- a/indra/llrender/llgltexture.cpp
+++ b/indra/llrender/llgltexture.cpp
@@ -351,20 +351,6 @@ void LLGLTexture::forceUpdateBindStats(void) const
return mGLTexturep->forceUpdateBindStats() ;
}
-U32 LLGLTexture::getTexelsInAtlas() const
-{
- llassert(mGLTexturep.notNull()) ;
-
- return mGLTexturep->getTexelsInAtlas() ;
-}
-
-U32 LLGLTexture::getTexelsInGLTexture() const
-{
- llassert(mGLTexturep.notNull()) ;
-
- return mGLTexturep->getTexelsInGLTexture() ;
-}
-
bool LLGLTexture::isGLTextureCreated() const
{
llassert(mGLTexturep.notNull()) ;
@@ -372,13 +358,6 @@ bool LLGLTexture::isGLTextureCreated() const
return mGLTexturep->isGLTextureCreated() ;
}
-S32 LLGLTexture::getDiscardLevelInAtlas() const
-{
- llassert(mGLTexturep.notNull()) ;
-
- return mGLTexturep->getDiscardLevelInAtlas() ;
-}
-
void LLGLTexture::destroyGLTexture()
{
if(mGLTexturep.notNull() && mGLTexturep->getHasGLTexture())
diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h
index 0901243f8f..122d2a7f9c 100644
--- a/indra/llrender/llgltexture.h
+++ b/indra/llrender/llgltexture.h
@@ -51,10 +51,10 @@ public:
BOOST_NONE = 0,
BOOST_AVATAR ,
BOOST_AVATAR_BAKED ,
- BOOST_SCULPTED ,
BOOST_TERRAIN , // Needed for minimap generation for now. Lower than BOOST_HIGH so the texture stats don't get forced, i.e. texture stats are manually managed by minimap/terrain instead.
BOOST_HIGH = 10,
+ BOOST_SCULPTED ,
BOOST_BUMP ,
BOOST_UNUSED_1 , // Placeholder to avoid disrupting habits around texture debug
BOOST_SELECTED ,
@@ -75,7 +75,6 @@ public:
AVATAR_SCRATCH_TEX,
DYNAMIC_TEX,
MEDIA,
- ATLAS,
OTHER,
MAX_GL_IMAGE_CATEGORY
};
@@ -83,8 +82,6 @@ public:
typedef enum
{
DELETED = 0, //removed from memory
- DELETION_CANDIDATE, //ready to be removed from memory
- INACTIVE, //not be used for the last certain period (i.e., 30 seconds).
ACTIVE, //just being used, can become inactive if not being used for a certain time (10 seconds).
NO_DELETE = 99 //stay in memory, can not be removed.
} LLGLTextureState;
@@ -156,10 +153,7 @@ public:
bool isJustBound()const ;
void forceUpdateBindStats(void) const;
- U32 getTexelsInAtlas() const ;
- U32 getTexelsInGLTexture() const ;
bool isGLTextureCreated() const ;
- S32 getDiscardLevelInAtlas() const ;
LLGLTextureState getTextureState() const { return mTextureState; }
//---------------------------------------------------------------------------------------------
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 7e5cd628c1..68c20048ec 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -41,6 +41,7 @@
#include "llrender.h"
#include "llwindow.h"
#include "llframetimer.h"
+#include <unordered_set>
extern LL_COMMON_API bool on_main_thread();
@@ -56,6 +57,9 @@ const F32 MIN_TEXTURE_LIFETIME = 10.f;
U32 wpo2(U32 i);
+U32 LLImageGL::sFrameCount = 0;
+
+
// texture memory accounting (for macOS)
static LLMutex sTexMemMutex;
static std::unordered_map<U32, U64> sTextureAllocs;
@@ -63,15 +67,19 @@ 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);
sTexMemMutex.lock();
+
+ // it is a precondition that no existing allocation exists for this texture
llassert(sTextureAllocs.find(texName) == sTextureAllocs.end());
sTextureAllocs[texName] = size;
@@ -85,7 +93,7 @@ void LLImageGLMemory::free_tex_image(U32 texName)
{
sTexMemMutex.lock();
auto iter = sTextureAllocs.find(texName);
- if (iter != sTextureAllocs.end())
+ if (iter != sTextureAllocs.end()) // sometimes a texName will be "freed" before allocated (e.g. first call to setManualImage for a given texName)
{
llassert(iter->second <= sTextureBytes); // sTextureBytes MUST NOT go below zero
@@ -110,6 +118,7 @@ void LLImageGLMemory::free_tex_images(U32 count, const U32* texNames)
void LLImageGLMemory::free_cur_tex_image()
{
U32 texUnit = gGL.getCurrentTexUnitIndex();
+ llassert(texUnit == 0); // frees should always be done on tex unit 0
U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture();
free_tex_image(texName);
}
@@ -130,10 +139,9 @@ S32 LLImageGL::sCount = 0;
bool LLImageGL::sGlobalUseAnisotropic = false;
F32 LLImageGL::sLastFrameTime = 0.f;
-bool LLImageGL::sAllowReadBackRaw = false ;
LLImageGL* LLImageGL::sDefaultGLTexture = NULL ;
bool LLImageGL::sCompressTextures = false;
-std::set<LLImageGL*> LLImageGL::sImageList;
+std::unordered_set<LLImageGL*> LLImageGL::sImageList;
bool LLImageGLThread::sEnabledTextures = false;
@@ -150,6 +158,9 @@ S32 LLImageGL::sMaxCategories = 1 ;
//optimization for when we don't need to calculate mIsMask
bool LLImageGL::sSkipAnalyzeAlpha;
+U32 LLImageGL::sScratchPBO = 0;
+U32 LLImageGL::sScratchPBOSize = 0;
+
//------------------------
//****************************************************************************************************
@@ -159,20 +170,6 @@ bool LLImageGL::sSkipAnalyzeAlpha;
//**************************************************************************************
//below are functions for debug use
//do not delete them even though they are not currently being used.
-void check_all_images()
-{
- for (std::set<LLImageGL*>::iterator iter = LLImageGL::sImageList.begin();
- iter != LLImageGL::sImageList.end(); iter++)
- {
- LLImageGL* glimage = *iter;
- if (glimage->getTexName() && glimage->isGLTextureCreated())
- {
- gGL.getTexUnit(0)->bind(glimage) ;
- glimage->checkTexSize() ;
- gGL.getTexUnit(0)->unbind(glimage->getTarget()) ;
- }
- }
-}
void LLImageGL::checkTexSize(bool forced) const
{
@@ -252,6 +249,11 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, bool skip_analyz
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
sSkipAnalyzeAlpha = skip_analyze_alpha;
+ if (sScratchPBO == 0)
+ {
+ glGenBuffers(1, &sScratchPBO);
+ }
+
if (thread_texture_loads || thread_media_updates)
{
LLImageGLThread::createInstance(window);
@@ -265,6 +267,12 @@ void LLImageGL::cleanupClass()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
LLImageGLThread::deleteSingleton();
+ if (sScratchPBO != 0)
+ {
+ glDeleteBuffers(1, &sScratchPBO);
+ sScratchPBO = 0;
+ sScratchPBOSize = 0;
+ }
}
@@ -273,6 +281,15 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
{
switch (dataformat)
{
+ case GL_COMPRESSED_RED: return 8;
+ case GL_COMPRESSED_RG: return 16;
+ case GL_COMPRESSED_RGB: return 24;
+ case GL_COMPRESSED_SRGB: return 32;
+ case GL_COMPRESSED_RGBA: return 32;
+ case GL_COMPRESSED_SRGB_ALPHA: return 32;
+ case GL_COMPRESSED_LUMINANCE: return 8;
+ case GL_COMPRESSED_LUMINANCE_ALPHA: return 16;
+ case GL_COMPRESSED_ALPHA: return 8;
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4;
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return 4;
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8;
@@ -280,21 +297,35 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 8;
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 8;
case GL_LUMINANCE: return 8;
+ case GL_LUMINANCE8: return 8;
case GL_ALPHA: return 8;
+ case GL_ALPHA8: return 8;
case GL_RED: return 8;
+ case GL_R8: return 8;
case GL_COLOR_INDEX: return 8;
case GL_LUMINANCE_ALPHA: return 16;
+ case GL_LUMINANCE8_ALPHA8: 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_RGBA: return 32;
+ case GL_RGBA8: return 32;
case GL_SRGB_ALPHA: return 32;
case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac
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;
}
}
@@ -337,13 +368,14 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
case GL_RED: return 1;
case GL_COLOR_INDEX: return 1;
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;
case GL_SRGB_ALPHA: return 4;
case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac
default:
- LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL;
+ LL_ERRS() << "LLImageGL::Unknown format: " << std::hex << dataformat << std::dec << LL_ENDL;
return 0;
}
}
@@ -360,66 +392,19 @@ void LLImageGL::updateStats(F32 current_time)
//----------------------------------------------------------------------------
//static
-void LLImageGL::destroyGL(bool save_state)
+void LLImageGL::destroyGL()
{
for (S32 stage = 0; stage < gGLManager.mNumTextureImageUnits; stage++)
{
gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE);
}
-
- sAllowReadBackRaw = true ;
- for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
- iter != sImageList.end(); iter++)
- {
- LLImageGL* glimage = *iter;
- if (glimage->mTexName)
- {
- if (save_state && glimage->isGLTextureCreated() && glimage->mComponents)
- {
- glimage->mSaveData = new LLImageRaw;
- if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it.
- {
- glimage->mSaveData = NULL ;
- }
- }
-
- glimage->destroyGLTexture();
- stop_glerror();
- }
- }
- sAllowReadBackRaw = false ;
-}
-
-//static
-void LLImageGL::restoreGL()
-{
- for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
- iter != sImageList.end(); iter++)
- {
- LLImageGL* glimage = *iter;
- if(glimage->getTexName())
- {
- LL_ERRS() << "tex name is not 0." << LL_ENDL ;
- }
- if (glimage->mSaveData.notNull())
- {
- if (glimage->getComponents() && glimage->mSaveData->getComponents())
- {
- glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData, 0, true, glimage->getCategory());
- stop_glerror();
- }
- glimage->mSaveData = NULL; // deletes data
- }
- }
}
//static
void LLImageGL::dirtyTexOptions()
{
- for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
- iter != sImageList.end(); iter++)
+ for (auto& glimage : sImageList)
{
- LLImageGL* glimage = *iter;
glimage->mTexOptionsDirty = true;
stop_glerror();
}
@@ -451,29 +436,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++;
@@ -490,7 +475,7 @@ LLImageGL::LLImageGL(
LLGLenum formatType,
LLTexUnit::eTextureAddressMode addressMode)
{
- init(false);
+ init(false, true);
mTexName = texName;
mTarget = target;
mComponents = components;
@@ -512,7 +497,7 @@ LLImageGL::~LLImageGL()
}
}
-void LLImageGL::init(bool usemipmaps)
+void LLImageGL::init(bool usemipmaps, bool allow_compression)
{
#if LL_IMAGEGL_THREAD_CHECK
mActiveThread = LLThread::currentID();
@@ -542,11 +527,7 @@ void LLImageGL::init(bool usemipmaps)
mHeight = 0;
mCurrentDiscardLevel = -1;
- mDiscardLevelInAtlas = -1 ;
- mTexelsInAtlas = 0 ;
- mTexelsInGLTexture = 0 ;
-
- mAllowCompression = true;
+ mAllowCompression = allow_compression;
mTarget = GL_TEXTURE_2D;
mBindTarget = LLTexUnit::TT_TEXTURE;
@@ -622,9 +603,6 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve
return false;
}
- // pickmask validity depends on old image size, delete it
- freePickMask();
-
mWidth = width;
mHeight = height;
mComponents = ncomponents;
@@ -789,7 +767,7 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32
}
if (is_compressed)
{
- S32 tex_size = dataFormatBytes(mFormatPrimary, w, h);
+ GLsizei tex_size = (GLsizei)dataFormatBytes(mFormatPrimary, w, h);
glCompressedTexImage2D(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in);
stop_glerror();
}
@@ -992,7 +970,7 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32
S32 h = getHeight();
if (is_compressed)
{
- S32 tex_size = dataFormatBytes(mFormatPrimary, w, h);
+ GLsizei tex_size = (GLsizei)dataFormatBytes(mFormatPrimary, w, h);
glCompressedTexImage2D(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in);
stop_glerror();
}
@@ -1025,98 +1003,6 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32
return true;
}
-bool LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
-{
- //not compatible with core GL profile
- llassert(!LLRender::sGLCoreProfile);
-
- if (gGLManager.mIsDisabled)
- {
- LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
- return false;
- }
- llassert(gGLManager.mInited);
- stop_glerror();
-
- if (discard_level < 0)
- {
- llassert(mCurrentDiscardLevel >= 0);
- discard_level = mCurrentDiscardLevel;
- }
-
- // Actual image width/height = raw image width/height * 2^discard_level
- S32 w = raw_image->getWidth() << discard_level;
- S32 h = raw_image->getHeight() << discard_level;
-
- // setSize may call destroyGLTexture if the size does not match
- if (!setSize(w, h, raw_image->getComponents(), discard_level))
- {
- LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL;
- return false;
- }
-
- if (!mHasExplicitFormat)
- {
- switch (mComponents)
- {
- case 1:
- // Use luminance alpha (for fonts)
- mFormatInternal = GL_LUMINANCE8;
- mFormatPrimary = GL_LUMINANCE;
- mFormatType = GL_UNSIGNED_BYTE;
- break;
- case 2:
- // Use luminance alpha (for fonts)
- mFormatInternal = GL_LUMINANCE8_ALPHA8;
- mFormatPrimary = GL_LUMINANCE_ALPHA;
- mFormatType = GL_UNSIGNED_BYTE;
- break;
- case 3:
- mFormatInternal = GL_RGB8;
- mFormatPrimary = GL_RGB;
- mFormatType = GL_UNSIGNED_BYTE;
- break;
- case 4:
- mFormatInternal = GL_RGBA8;
- mFormatPrimary = GL_RGBA;
- mFormatType = GL_UNSIGNED_BYTE;
- break;
- default:
- LL_ERRS() << "Bad number of components for texture: " << (U32) getComponents() << LL_ENDL;
- }
- }
-
- mCurrentDiscardLevel = discard_level;
- mDiscardLevelInAtlas = discard_level;
- mTexelsInAtlas = raw_image->getWidth() * raw_image->getHeight() ;
- mLastBindTime = sLastFrameTime;
- mGLTextureCreated = false ;
-
- glPixelStorei(GL_UNPACK_ROW_LENGTH, raw_image->getWidth());
- stop_glerror();
-
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
- stop_glerror();
- }
-
- return true ;
-}
-
-void LLImageGL::postAddToAtlas()
-{
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
- stop_glerror();
- }
-
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption);
- stop_glerror();
-}
-
U32 type_width_from_pixtype(U32 pixtype)
{
U32 type_width = 0;
@@ -1149,7 +1035,7 @@ bool should_stagger_image_set(bool compressed)
#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
- return !compressed && on_main_thread();
+ return !compressed && on_main_thread() && !gGLManager.mIsIntel;
#endif
}
@@ -1332,12 +1218,36 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
}
// static
+void LLImageGL::updateClass()
+{
+ sFrameCount++;
+}
+
+// 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)
{
- free_tex_images(numTextures, textures);
- glDeleteTextures(numTextures, textures);
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ U32 idx = sFrameCount % 4;
+
+ 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);
+ }
}
}
@@ -1345,90 +1255,122 @@ 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;
+ std::unique_ptr<U32[]> scratch;
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 >= 3.29f)
+ {
+ if (pixformat == GL_ALPHA)
+ { //GL_ALPHA is deprecated, convert to RGBA
+ const GLint mask[] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
+ 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
+ const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
+ 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
+ const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
+ 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;
- }
+ scratch.reset(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;
+ }
- 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];
+ 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];
+ }
- U8* pix = (U8*)&scratch[i];
- pix[0] = pix[1] = pix[2] = lum;
- pix[3] = alpha;
+ pixels = scratch.get();
}
- }
- 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_ALPHA && pixtype == GL_UNSIGNED_BYTE)
+ { //GL_LUMINANCE_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;
+ scratch.reset(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;
+ }
+
+ 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;
+ }
+
+ pixels = scratch.get();
}
- U32 pixel_count = (U32)(width * height);
- for (U32 i = 0; i < pixel_count; i++)
+ 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)
{
- U8 lum = ((U8*)pixels)[i];
+ scratch.reset(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;
+ }
+
+ U32 pixel_count = (U32)(width * height);
+ for (U32 i = 0; i < pixel_count; i++)
+ {
+ U8 lum = ((U8*)pixels)[i];
- U8* pix = (U8*)&scratch[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 = scratch.get();
}
+ pixformat = GL_RGBA;
+ intformat = GL_RGB8;
}
- pixformat = GL_RGBA;
- intformat = GL_RGB8;
}
}
@@ -1437,6 +1379,14 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
{
switch (intformat)
{
+ case GL_RED:
+ case GL_R8:
+ intformat = GL_COMPRESSED_RED;
+ break;
+ case GL_RG:
+ case GL_RG8:
+ intformat = GL_COMPRESSED_RG;
+ break;
case GL_RGB:
case GL_RGB8:
intformat = GL_COMPRESSED_RGB;
@@ -1465,12 +1415,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
case GL_ALPHA8:
intformat = GL_COMPRESSED_ALPHA;
break;
- case GL_RED:
- case GL_R8:
- intformat = GL_COMPRESSED_RED;
- 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;
}
}
@@ -1486,7 +1432,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
{
@@ -1496,21 +1442,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
@@ -1752,7 +1693,6 @@ bool LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, bool data_
mTextureMemory = (S64Bytes)getMipBytes(mCurrentDiscardLevel);
- mTexelsInGLTexture = getWidth() * getHeight();
// mark this as bound at this point, so we don't throw it out immediately
mLastBindTime = sLastFrameTime;
@@ -1830,8 +1770,7 @@ void LLImageGL::syncTexName(LLGLuint texname)
bool LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
{
- llassert_always(sAllowReadBackRaw) ;
- //LL_ERRS() << "should not call this function!" << LL_ENDL ;
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
if (discard_level < 0)
{
@@ -2297,6 +2236,8 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
//----------------------------------------------------------------------------
U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ freePickMask();
U32 pick_width = pWidth/2 + 1;
U32 pick_height = pHeight/2 + 1;
@@ -2314,7 +2255,6 @@ U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight)
//----------------------------------------------------------------------------
void LLImageGL::freePickMask()
{
- // pickmask validity depends on old image size, delete it
if (mPickMask != NULL)
{
delete [] mPickMask;
@@ -2352,16 +2292,16 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)
return ;
}
- freePickMask();
-
if (mFormatType != GL_UNSIGNED_BYTE ||
((mFormatPrimary != GL_RGBA)
&& (mFormatPrimary != GL_SRGB_ALPHA)))
{
//cannot generate a pick mask for this texture
+ freePickMask();
return;
}
+
#ifdef SHOW_ASSERT
const U32 pickSize = createPickMask(width, height);
#else // SHOW_ASSERT
@@ -2460,6 +2400,114 @@ void LLImageGL::resetCurTexSizebar()
sCurTexSizeBar = -1 ;
sCurTexPickSize = -1 ;
}
+
+bool LLImageGL::scaleDown(S32 desired_discard)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+
+ if (mTarget != GL_TEXTURE_2D)
+ {
+ return false;
+ }
+
+ desired_discard = llmin(desired_discard, mMaxDiscardLevel);
+
+ if (desired_discard <= mCurrentDiscardLevel)
+ {
+ return false;
+ }
+
+ S32 mip = desired_discard - mCurrentDiscardLevel;
+
+ S32 desired_width = getWidth(desired_discard);
+ S32 desired_height = getHeight(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, mFormatInternal, desired_width, desired_height, 0, mFormatPrimary, mFormatType, NULL);
+ }
+
+ // account for new texture getting created
+ alloc_tex_image(desired_width, desired_height, mFormatInternal, 1);
+
+ // 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);
+
+ // delete old texture and assign new texture name
+ deleteTextures(1, &mTexName);
+ mTexName = temp_texname;
+
+ 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
+ { // use a PBO to downscale the texture
+ U64 size = getBytes(desired_discard);
+ llassert(size <= 2048 * 2048 * 4); // we shouldn't be using this method to downscale huge textures, but it'll work
+ gGL.getTexUnit(0)->bind(this, false, true);
+
+ if (sScratchPBO == 0)
+ {
+ glGenBuffers(1, &sScratchPBO);
+ sScratchPBOSize = 0;
+ }
+
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, sScratchPBO);
+
+ if (size > sScratchPBOSize)
+ {
+ glBufferData(GL_PIXEL_PACK_BUFFER, size, NULL, GL_STREAM_COPY);
+ sScratchPBOSize = (U32)size;
+ }
+
+ glGetTexImage(mTarget, mip, mFormatPrimary, mFormatType, nullptr);
+
+ free_tex_image(mTexName);
+
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sScratchPBO);
+ 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, mFormatInternal, 1);
+
+ if (mHasMipMaps)
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap");
+ glGenerateMipmap(mTarget);
+ }
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+
+ mCurrentDiscardLevel = desired_discard;
+
+ return true;
+}
+
+
//----------------------------------------------------------------------------
#if LL_IMAGEGL_THREAD_CHECK
void LLImageGL::checkActiveThread()
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 5c7a5ce821..a8b94bd5b0 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -39,6 +39,7 @@
#include "llrender.h"
#include "threadpool.h"
#include "workqueue.h"
+#include <unordered_set>
#define LL_IMAGEGL_THREAD_CHECK 0 //set to 1 to enable thread debugging for ImageGL
@@ -49,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();
@@ -61,6 +62,9 @@ class LLImageGL : public LLRefCount
friend class LLTexUnit;
public:
+ // call once per frame
+ static void updateClass();
+
// Get an estimate of how many bytes have been allocated in vram for textures.
// Does not include mipmaps.
// NOTE: multiplying this number by two gives a good estimate for total
@@ -83,9 +87,8 @@ public:
// needs to be called every frame
static void updateStats(F32 current_time);
- // Save off / restore GL textures
- static void destroyGL(bool save_state = true);
- static void restoreGL();
+ // cleanup GL state
+ static void destroyGL();
static void dirtyTexOptions();
static bool checkSize(S32 width, S32 height);
@@ -98,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);
@@ -148,6 +151,10 @@ public:
S32 getDiscardLevel() const { return mCurrentDiscardLevel; }
S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; }
+ // override the current discard level
+ // should only be used for local textures where you know exactly what you're doing
+ void setDiscardLevel(S32 level) { mCurrentDiscardLevel = level; }
+
S32 getCurrentWidth() const { return mWidth ;}
S32 getCurrentHeight() const { return mHeight ;}
S32 getWidth(S32 discard_level = -1) const;
@@ -194,26 +201,26 @@ public:
void setFilteringOption(LLTexUnit::eTextureFilterOptions option);
LLTexUnit::eTextureFilterOptions getFilteringOption(void) const { return mFilterOption; }
- LLGLenum getTexTarget()const { return mTarget ;}
- S8 getDiscardLevelInAtlas()const {return mDiscardLevelInAtlas;}
- U32 getTexelsInAtlas()const { return mTexelsInAtlas ;}
- U32 getTexelsInGLTexture()const {return mTexelsInGLTexture;}
+ 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);
- bool preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image);
- void postAddToAtlas() ;
-
#if LL_IMAGEGL_THREAD_CHECK
// thread debugging
std::thread::id mActiveThread;
void checkActiveThread();
#endif
+ // scale down to the desired discard level using GPU
+ // returns true if texture was scaled down
+ // desired discard will be clamped to max discard
+ // if desired discard is less than or equal to current discard, no scaling will occur
+ // only works for GL_TEXTURE_2D target
+ bool scaleDown(S32 desired_discard);
+
public:
// Various GL/Rendering options
S64Bytes mTextureMemory;
@@ -240,15 +247,10 @@ private:
bool mGLTextureCreated ;
LLGLuint mTexName;
- //LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread
U16 mWidth;
U16 mHeight;
S8 mCurrentDiscardLevel;
- S8 mDiscardLevelInAtlas;
- U32 mTexelsInAtlas ;
- U32 mTexelsInGLTexture;
-
bool mAllowCompression;
protected:
@@ -275,9 +277,9 @@ protected:
// STATICS
public:
- static std::set<LLImageGL*> sImageList;
+ static std::unordered_set<LLImageGL*> sImageList;
static S32 sCount;
-
+ static U32 sFrameCount;
static F32 sLastFrameTime;
// Global memory statistics
@@ -301,6 +303,8 @@ public:
private:
static S32 sMaxCategories;
static bool sSkipAnalyzeAlpha;
+ static U32 sScratchPBO;
+ static U32 sScratchPBOSize;
//the flag to allow to call readBackRaw(...).
//can be removed if we do not use that function at all.
diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp
index 8ebd09f20d..eef7193c92 100644
--- a/indra/llrender/llpostprocess.cpp
+++ b/indra/llrender/llpostprocess.cpp
@@ -343,7 +343,7 @@ void LLPostProcess::viewOrthogonal(unsigned int width, unsigned int height)
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
gGL.loadIdentity();
- gGL.ortho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f );
+ gGL.ortho( 0.f, (GLfloat) width , (GLfloat) height , 0.f, -1.f, 1.f );
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.pushMatrix();
gGL.loadIdentity();
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index a0209fab43..828a509971 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -77,6 +77,7 @@ struct LLVBCache
};
static std::unordered_map<U64, LLVBCache> sVBCache;
+static thread_local std::list<LLVertexBufferData> *sBufferDataList = nullptr;
static const GLenum sGLTextureType[] =
{
@@ -115,7 +116,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)
{
@@ -145,8 +146,6 @@ void LLTexUnit::refreshState(void)
{
glBindTexture(GL_TEXTURE_2D, 0);
}
-
- setTextureColorSpace(mTexColorSpace);
}
void LLTexUnit::activate(void)
@@ -241,7 +240,6 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
setTextureAddressMode(gl_tex->mAddressMode);
setTextureFilteringOption(gl_tex->mFilterOption);
}
- setTextureColorSpace(mTexColorSpace);
}
}
else
@@ -318,7 +316,6 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind, S32
setTextureFilteringOption(texture->mFilterOption);
stop_glerror();
}
- setTextureColorSpace(mTexColorSpace);
}
stop_glerror();
@@ -354,7 +351,6 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap)
setTextureAddressMode(cubeMap->mImages[0]->mAddressMode);
setTextureFilteringOption(cubeMap->mImages[0]->mFilterOption);
}
- setTextureColorSpace(mTexColorSpace);
return true;
}
else
@@ -403,7 +399,6 @@ bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips)
mCurrTexture = texture;
glBindTexture(sGLTextureType[type], texture);
mHasMipMaps = hasMips;
- setTextureColorSpace(mTexColorSpace);
}
return true;
}
@@ -424,8 +419,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);
@@ -447,8 +440,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);
@@ -642,11 +633,6 @@ void LLTexUnit::debugTextureUnit(void)
}
}
-void LLTexUnit::setTextureColorSpace(eTextureColorSpace space)
-{
- mTexColorSpace = space;
-}
-
LLLightState::LLLightState(S32 index)
: mIndex(index),
mEnabled(false),
@@ -1514,7 +1500,7 @@ LLLightState* LLRender::getLight(U32 index)
void LLRender::setAmbientLightColor(const LLColor4& color)
{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
if (color != mAmbientLightColor)
{
++mLightHash;
@@ -1543,6 +1529,30 @@ 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)
@@ -1585,6 +1595,7 @@ void LLRender::end()
flush();
}
}
+
void LLRender::flush()
{
STOP_GLERROR;
@@ -1633,127 +1644,166 @@ void LLRender::flush()
if (mBuffer)
{
- HBXXH64 hash;
+ LLVertexBuffer *vb;
+
U32 attribute_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
+ if (sBufferDataList)
+ {
+ 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
{
- LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache hash");
+ 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((LLVector4a*) 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);
+
+ 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_TEXCOORD0)
+ 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->setTexCoord0Data(mTexcoordsp.get());
+ iter = sVBCache.erase(iter);
}
-
- if (attribute_mask & LLVertexBuffer::MAP_COLOR)
+ else
{
- vb->setColorData(mColorsp.get());
+ ++iter;
}
+ }
+ }
+ }
+ return vb;
+}
-#if LL_DARWIN
- vb->unmapBuffer();
-#endif
- 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((LLVector4a*)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();
- mCount = 0;
+ if (mode == LLRender::QUADS && sGLCoreProfile)
+ {
+ vb->drawArrays(LLRender::TRIANGLES, 0, count);
+ mQuadCycle = 1;
+ }
+ else
+ {
+ vb->drawArrays(mode, 0, count);
}
}
+void LLRender::resetStriders(S32 count)
+{
+ mVerticesp[0] = mVerticesp[count];
+ mTexcoordsp[0] = mTexcoordsp[count];
+ mColorsp[0] = mColorsp[count];
+
+ mCount = 0;
+}
+
void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
{
//the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095]
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index be9f3895e7..39c13e328a 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -45,12 +45,14 @@
#include "glh/glh_linear.h"
#include <array>
+#include <list>
class LLVertexBuffer;
class LLCubeMap;
class LLImageGL;
class LLRenderTarget;
-class LLTexture ;
+class LLTexture;
+class LLVertexBufferData;
#define LL_MATRIX_STACK_DEPTH 32
@@ -219,17 +221,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;
@@ -293,11 +290,18 @@ public:
enum eTexIndex : U8
{
- DIFFUSE_MAP = 0,
- ALTERNATE_DIFFUSE_MAP = 1,
- NORMAL_MAP = 1,
- SPECULAR_MAP = 2,
- NUM_TEXTURE_CHANNELS = 3,
+ // Channels for material textures
+ DIFFUSE_MAP = 0,
+ ALTERNATE_DIFFUSE_MAP = 1,
+ NORMAL_MAP = 1,
+ SPECULAR_MAP = 2,
+ // Channels for PBR textures
+ BASECOLOR_MAP = 3,
+ METALLIC_ROUGHNESS_MAP = 4,
+ GLTF_NORMAL_MAP = 5,
+ EMISSIVE_MAP = 6,
+ // Total number of channels
+ NUM_TEXTURE_CHANNELS = 7,
};
enum eVolumeTexIndex : U8
@@ -413,8 +417,15 @@ 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();
+
+ 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);
@@ -483,6 +494,11 @@ public:
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];
@@ -513,7 +529,6 @@ private:
std::vector<LLVector3> mUIOffset;
std::vector<LLVector3> mUIScale;
-
};
extern F32 gGLModelView[16];
diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp
index ef02fbd071..428370057e 100644
--- a/indra/llrender/llrender2dutils.cpp
+++ b/indra/llrender/llrender2dutils.cpp
@@ -364,7 +364,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
{
// add in offset of current image to current UI translation
const LLVector3 ui_scale = gGL.getUIScale();
- const LLVector3 ui_translation = (gGL.getUITranslation() + LLVector3(x, y, 0.f)).scaledVec(ui_scale);
+ const LLVector3 ui_translation = (gGL.getUITranslation() + LLVector3((F32)x, (F32)y, 0.f)).scaledVec(ui_scale);
F32 uv_width = uv_outer_rect.getWidth();
F32 uv_height = uv_outer_rect.getHeight();
@@ -375,8 +375,8 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
uv_outer_rect.mLeft + (center_rect.mRight * uv_width),
uv_outer_rect.mBottom + (center_rect.mBottom * uv_height));
- F32 image_width = image->getWidth(0);
- F32 image_height = image->getHeight(0);
+ F32 image_width = (F32)image->getWidth(0);
+ F32 image_height = (F32)image->getHeight(0);
S32 image_natural_width = ll_round(image_width * uv_width);
S32 image_natural_height = ll_round(image_height * uv_height);
@@ -413,10 +413,10 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
draw_center_rect.setCenterAndSize(uv_center_rect.getCenterX() * width, uv_center_rect.getCenterY() * height, scaled_width, scaled_height);
}
- draw_center_rect.mLeft = ll_round(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * ui_scale.mV[VX]);
- draw_center_rect.mTop = ll_round(ui_translation.mV[VY] + (F32)draw_center_rect.mTop * ui_scale.mV[VY]);
- draw_center_rect.mRight = ll_round(ui_translation.mV[VX] + (F32)draw_center_rect.mRight * ui_scale.mV[VX]);
- draw_center_rect.mBottom = ll_round(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * ui_scale.mV[VY]);
+ draw_center_rect.mLeft = (F32)ll_round(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * ui_scale.mV[VX]);
+ draw_center_rect.mTop = (F32)ll_round(ui_translation.mV[VY] + (F32)draw_center_rect.mTop * ui_scale.mV[VY]);
+ draw_center_rect.mRight = (F32)ll_round(ui_translation.mV[VX] + (F32)draw_center_rect.mRight * ui_scale.mV[VX]);
+ draw_center_rect.mBottom = (F32)ll_round(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * ui_scale.mV[VY]);
LLRectf draw_outer_rect(ui_translation.mV[VX],
ui_translation.mV[VY] + height * ui_scale.mV[VY],
@@ -726,7 +726,7 @@ void gl_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& c
}
gGL.end();
- LLRender2D::getInstance()->setLineWidth(1.f);
+ LLRender2D::setLineWidth(1.f);
}
void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, bool filled, F32 start_angle, F32 end_angle)
diff --git a/indra/llrender/llrender2dutils.h b/indra/llrender/llrender2dutils.h
index 0d3efc38d6..096e7584f1 100644
--- a/indra/llrender/llrender2dutils.h
+++ b/indra/llrender/llrender2dutils.h
@@ -122,12 +122,13 @@ inline void gl_rect_2d_offset_local( const LLRect& rect, S32 pixel_offset, bool
class LLImageProviderInterface;
-class LLRender2D : public LLParamSingleton<LLRender2D>
+class LLRender2D : public LLSimpleton<LLRender2D>
{
- LLSINGLETON(LLRender2D, LLImageProviderInterface* image_provider);
LOG_CLASS(LLRender2D);
- ~LLRender2D();
public:
+ LLRender2D(LLImageProviderInterface* image_provider);
+ ~LLRender2D();
+
static void pushMatrix();
static void popMatrix();
static void loadIdentity();
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index efdde77a32..38bc5ff331 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -123,7 +123,7 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, LLT
if (mGenerateMipMaps != LLTexUnit::TMG_NONE) {
// Calculate the number of mip levels based upon resolution that we should have.
- mMipLevels = 1 + floor(log10((float)llmax(mResX, mResY))/log10(2.0));
+ mMipLevels = 1 + (U32)floor(log10((float)llmax(mResX, mResY)) / log10(2.0));
}
if (depth)
@@ -426,14 +426,17 @@ void LLRenderTarget::bindTarget()
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3};
- glDrawBuffers(static_cast<GLsizei>(mTex.size()), drawbuffers);
if (mTex.empty())
{ //no color buffer to draw to
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
}
-
+ else
+ {
+ glDrawBuffers(static_cast<GLsizei>(mTex.size()), drawbuffers);
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ }
check_framebuffer_status();
glViewport(0, 0, mResX, mResY);
@@ -472,12 +475,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];
@@ -508,7 +509,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()
@@ -519,7 +519,8 @@ void LLRenderTarget::flush()
llassert(sCurFBO == mFBO);
llassert(sBoundTarget == this);
- if (mGenerateMipMaps == LLTexUnit::TMG_AUTO) {
+ if (mGenerateMipMaps == LLTexUnit::TMG_AUTO)
+ {
LL_PROFILE_GPU_ZONE("rt generate mipmaps");
bindTexture(0, 0, LLTexUnit::TFO_TRILINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
@@ -540,6 +541,8 @@ void LLRenderTarget::flush()
glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
sCurResX = gGLViewport[2];
sCurResY = gGLViewport[3];
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_BACK);
}
}
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index 340276a752..cd3290cf66 100644
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -61,7 +61,7 @@
class LLRenderTarget
{
public:
- //whether or not to use FBO implementation
+ // Whether or not to use FBO implementation
static bool sUseFBO;
static U32 sBytesAllocated;
static U32 sCurFBO;
@@ -172,6 +172,8 @@ public:
// *HACK
void swapFBORefs(LLRenderTarget& other);
+ static LLRenderTarget* sBoundTarget;
+
protected:
U32 mResX;
U32 mResY;
@@ -186,8 +188,6 @@ protected:
U32 mMipLevels;
LLTexUnit::eTextureType mUsage;
-
- static LLRenderTarget* sBoundTarget;
};
#endif
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index a8e9f20b40..150277c8df 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -44,7 +44,6 @@ using std::make_pair;
using std::string;
LLShaderMgr * LLShaderMgr::sInstance = NULL;
-bool LLShaderMgr::sMirrorsEnabled = false;
LLShaderMgr::LLShaderMgr()
{
@@ -596,13 +595,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 (sMirrorsEnabled)
+ 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 HERO_PROBES 1\n");
+ extra_code_text[extra_code_count++] = strdup("#define VERTEX_SHADER 1\n");
}
// Use alpha float to store bit flags
@@ -1003,7 +1004,7 @@ void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version,
ProgramBinaryData binary_info = ProgramBinaryData();
binary_info.mBinaryFormat = data_pair.second["binary_format"].asInteger();
binary_info.mBinaryLength = data_pair.second["binary_size"].asInteger();
- binary_info.mLastUsedTime = data_pair.second["last_used"].asReal();
+ binary_info.mLastUsedTime = (F32)data_pair.second["last_used"].asReal();
mShaderBinaryCache.insert_or_assign(LLUUID(data_pair.first), binary_info);
}
}
@@ -1034,7 +1035,7 @@ void LLShaderMgr::persistShaderCacheMetadata()
LLSD out = LLSD::emptyMap();
static const F32 LRU_TIME = (60.f * 60.f) * 24.f * 7.f; // 14 days
- const F32 current_time = LLTimer::getTotalSeconds();
+ const F32 current_time = (F32)LLTimer::getTotalSeconds();
for (auto it = mShaderBinaryCache.begin(); it != mShaderBinaryCache.end();)
{
const ProgramBinaryData& shader_metadata = it->second;
@@ -1093,7 +1094,7 @@ bool LLShaderMgr::loadCachedProgramBinary(LLGLSLShader* shader)
glGetProgramiv(shader->mProgramObject, GL_LINK_STATUS, &success);
if (error == GL_NO_ERROR && success == GL_TRUE)
{
- binary_iter->second.mLastUsedTime = LLTimer::getTotalSeconds();
+ binary_iter->second.mLastUsedTime = (F32)LLTimer::getTotalSeconds();
LL_INFOS() << "Loaded cached binary for shader: " << shader->mName << LL_ENDL;
return true;
}
@@ -1131,7 +1132,7 @@ bool LLShaderMgr::saveCachedProgramBinary(LLGLSLShader* shader)
fwrite(program_binary.data(), sizeof(U8), program_binary.size(), outfile);
outfile.close();
- binary_info.mLastUsedTime = LLTimer::getTotalSeconds();
+ binary_info.mLastUsedTime = (F32)LLTimer::getTotalSeconds();
mShaderBinaryCache.insert_or_assign(shader->mShaderHash, binary_info);
return true;
@@ -1415,6 +1416,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("detail_3");
mReservedUniforms.push_back("alpha_ramp");
+ mReservedUniforms.push_back("paint_map");
mReservedUniforms.push_back("detail_0_base_color");
mReservedUniforms.push_back("detail_1_base_color");
@@ -1439,6 +1441,8 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("emissiveColors");
mReservedUniforms.push_back("minimum_alphas");
+ mReservedUniforms.push_back("region_scale");
+
mReservedUniforms.push_back("origin");
mReservedUniforms.push_back("display_gamma");
@@ -1473,6 +1477,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 fe6137c448..0eb9db6715 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -267,6 +267,7 @@ public:
TERRAIN_DETAIL3, // "detail_3"
TERRAIN_ALPHARAMP, // "alpha_ramp"
+ TERRAIN_PAINTMAP, // "paint_map"
TERRAIN_DETAIL0_BASE_COLOR, // "detail_0_base_color" (GLTF)
TERRAIN_DETAIL1_BASE_COLOR, // "detail_1_base_color" (GLTF)
@@ -291,6 +292,8 @@ public:
TERRAIN_EMISSIVE_COLORS, // "emissiveColors" (GLTF)
TERRAIN_MINIMUM_ALPHAS, // "minimum_alphas" (GLTF)
+ REGION_SCALE, // "region_scale" (GLTF)
+
SHINY_ORIGIN, // "origin"
DISPLAY_GAMMA, // "display_gamma"
@@ -329,6 +332,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
@@ -378,7 +386,6 @@ public:
bool mShaderCacheInitialized = false;
bool mShaderCacheEnabled = false;
std::string mShaderCacheDir;
- static bool sMirrorsEnabled;
protected:
diff --git a/indra/llrender/lluiimage.cpp b/indra/llrender/lluiimage.cpp
index bcf665ca18..dc18bf16bf 100644
--- a/indra/llrender/lluiimage.cpp
+++ b/indra/llrender/lluiimage.cpp
@@ -81,10 +81,10 @@ void LLUIImage::draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, c
}
}
- LLRender2D::getInstance()->pushMatrix();
+ LLRender2D::pushMatrix();
{
- LLVector3 rect_origin = origin_agent + (rect.mLeft * x_axis) + (rect.mBottom * y_axis);
- LLRender2D::getInstance()->translate(rect_origin.mV[VX],
+ LLVector3 rect_origin = origin_agent + ((F32)rect.mLeft * x_axis) + ((F32)rect.mBottom * y_axis);
+ LLRender2D::translate(rect_origin.mV[VX],
rect_origin.mV[VY],
rect_origin.mV[VZ]);
gGL.getTexUnit(0)->bind(getImage());
@@ -100,10 +100,10 @@ void LLUIImage::draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, c
(rect.getHeight() - (border_height * border_scale * 0.5f)) / (F32)rect.getHeight(),
(rect.getWidth() - (border_width * border_scale * 0.5f)) / (F32)rect.getWidth(),
(border_height * border_scale * 0.5f) / (F32)rect.getHeight()),
- rect.getWidth() * x_axis,
- rect.getHeight() * y_axis);
+ (F32)rect.getWidth() * x_axis,
+ (F32)rect.getHeight() * y_axis);
- } LLRender2D::getInstance()->popMatrix();
+ } LLRender2D::popMatrix();
}
//#include "lluiimage.inl"
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 2eb7c21f77..156e300853 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -570,6 +570,54 @@ public:
static LLVBOPool* sVBOPool = nullptr;
+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);
+ }
+
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ gGL.loadMatrix(mModelView.m);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadMatrix(mProjection.m);
+ gGL.matrixMode(LLRender::MM_TEXTURE0);
+ gGL.pushMatrix();
+ gGL.loadMatrix(mTexture0.m);
+
+ mVB->setBuffer();
+
+ if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile)
+ {
+ mVB->drawArrays(LLRender::TRIANGLES, 0, mCount);
+ }
+ else
+ {
+ mVB->drawArrays(mMode, 0, mCount);
+ }
+
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+}
+
+//============================================================================
+
//static
U64 LLVertexBuffer::getBytesAllocated()
{
@@ -794,6 +842,18 @@ void LLVertexBuffer::setLabel(const char* label) {
}
#endif
+void LLVertexBuffer::clone(LLVertexBuffer& target) const
+{
+ target.mTypeMask = mTypeMask;
+ target.mIndicesType = mIndicesType;
+ target.mIndicesStride = mIndicesStride;
+ if (target.getNumVerts() != getNumVerts() ||
+ target.getNumIndices() != getNumIndices())
+ {
+ target.allocateBuffer(getNumVerts(), getNumIndices());
+ }
+}
+
void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
{
llassert(validateRange(start, end, count, indices_offset));
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 49500e28ce..2a4affdc60 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -53,6 +53,37 @@
//============================================================================
// base class
class LLPrivateMemoryPool;
+class LLVertexBuffer;
+
+class LLVertexBufferData
+{
+public:
+ LLVertexBufferData()
+ : mVB(nullptr)
+ , mMode(0)
+ , mCount(0)
+ , mTexName(0)
+ {}
+ LLVertexBufferData(LLVertexBuffer* buffer, U8 mode, U32 count, U32 tex_name, glh::matrix4f model_view, glh::matrix4f projection, glh::matrix4f texture0)
+ : mVB(buffer)
+ , mMode(mode)
+ , mCount(count)
+ , mTexName(tex_name)
+ , mProjection(model_view)
+ , mModelView(projection)
+ , mTexture0(texture0)
+ {}
+ void draw();
+ LLPointer<LLVertexBuffer> mVB;
+ U8 mMode;
+ U32 mCount;
+ U32 mTexName;
+ glh::matrix4f mProjection;
+ glh::matrix4f mModelView;
+ glh::matrix4f mTexture0;
+};
+typedef std::list<LLVertexBufferData> buffer_data_list_t;
+
class LLVertexBuffer final : public LLRefCount
{
public:
@@ -163,13 +194,13 @@ public:
// set for rendering
// assumes (and will assert on) the following:
- // - this buffer has no pending unampBuffer call
+ // - this buffer has no pending unmapBuffer call
// - a shader is currently bound
// - This buffer has sufficient attributes within it to satisfy the needs of the currently bound shader
void setBuffer();
// Only call each getVertexPointer, etc, once before calling unmapBuffer()
- // call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer()
+ // call unmapBuffer() after calls to getXXXStrider() before any calls to setBuffer()
// example:
// vb->getVertexBuffer(verts);
// vb->getNormalStrider(norms);
@@ -218,12 +249,12 @@ public:
U32 getNumIndices() const { return mNumIndices; }
U32 getTypeMask() const { return mTypeMask; }
- bool hasDataType(AttributeType type) const { return ((1 << type) & getTypeMask()); }
+ bool hasDataType(AttributeType type) const { return ((1 << type) & getTypeMask()); }
U32 getSize() const { return mSize; }
U32 getIndicesSize() const { return mIndicesSize; }
U8* getMappedData() const { return mMappedData; }
U8* getMappedIndices() const { return mMappedIndexData; }
- U32 getOffset(AttributeType type) const { return mOffsets[type]; }
+ U32 getOffset(AttributeType type) const { return mOffsets[type]; }
// these functions assume (and assert on) the current VBO being bound
// Detailed error checking can be enabled by setting gDebugGL to true
@@ -242,6 +273,7 @@ public:
void setLabel(const char* label);
#endif
+ void clone(LLVertexBuffer& target) const;
protected:
U32 mGLBuffer = 0; // GL VBO handle