summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llrender')
-rwxr-xr-x[-rw-r--r--]indra/llrender/CMakeLists.txt73
-rwxr-xr-x[-rw-r--r--]indra/llrender/llcubemap.cpp0
-rwxr-xr-x[-rw-r--r--]indra/llrender/llcubemap.h0
-rwxr-xr-x[-rw-r--r--]indra/llrender/llfontbitmapcache.cpp0
-rwxr-xr-x[-rw-r--r--]indra/llrender/llfontbitmapcache.h0
-rwxr-xr-x[-rw-r--r--]indra/llrender/llfontfreetype.cpp7
-rwxr-xr-x[-rw-r--r--]indra/llrender/llfontfreetype.h0
-rwxr-xr-x[-rw-r--r--]indra/llrender/llfontgl.cpp21
-rwxr-xr-x[-rw-r--r--]indra/llrender/llfontgl.h4
-rwxr-xr-x[-rw-r--r--]indra/llrender/llfontregistry.cpp32
-rwxr-xr-x[-rw-r--r--]indra/llrender/llfontregistry.h4
-rwxr-xr-x[-rw-r--r--]indra/llrender/llgl.cpp186
-rwxr-xr-x[-rw-r--r--]indra/llrender/llgl.h42
-rwxr-xr-x[-rw-r--r--]indra/llrender/llgldbg.cpp0
-rwxr-xr-x[-rw-r--r--]indra/llrender/llgldbg.h0
-rwxr-xr-x[-rw-r--r--]indra/llrender/llglheaders.h33
-rwxr-xr-x[-rw-r--r--]indra/llrender/llglslshader.cpp455
-rwxr-xr-x[-rw-r--r--]indra/llrender/llglslshader.h90
-rwxr-xr-x[-rw-r--r--]indra/llrender/llglstates.h5
-rw-r--r--indra/llrender/llgltexture.cpp396
-rw-r--r--indra/llrender/llgltexture.h199
-rwxr-xr-x[-rw-r--r--]indra/llrender/llgltypes.h0
-rwxr-xr-x[-rw-r--r--]indra/llrender/llimagegl.cpp379
-rwxr-xr-x[-rw-r--r--]indra/llrender/llimagegl.h63
-rwxr-xr-x[-rw-r--r--]indra/llrender/llpostprocess.cpp59
-rwxr-xr-x[-rw-r--r--]indra/llrender/llpostprocess.h3
-rwxr-xr-x[-rw-r--r--]indra/llrender/llrender.cpp132
-rwxr-xr-x[-rw-r--r--]indra/llrender/llrender.h10
-rw-r--r--indra/llrender/llrender2dutils.cpp1608
-rw-r--r--indra/llrender/llrender2dutils.h163
-rwxr-xr-xindra/llrender/llrendernavprim.cpp59
-rwxr-xr-xindra/llrender/llrendernavprim.h49
-rwxr-xr-x[-rw-r--r--]indra/llrender/llrendersphere.cpp0
-rwxr-xr-x[-rw-r--r--]indra/llrender/llrendersphere.h0
-rwxr-xr-x[-rw-r--r--]indra/llrender/llrendertarget.cpp187
-rwxr-xr-x[-rw-r--r--]indra/llrender/llrendertarget.h24
-rwxr-xr-x[-rw-r--r--]indra/llrender/llshadermgr.cpp136
-rwxr-xr-x[-rw-r--r--]indra/llrender/llshadermgr.h56
-rwxr-xr-x[-rw-r--r--]indra/llrender/lltexture.cpp0
-rwxr-xr-x[-rw-r--r--]indra/llrender/lltexture.h7
-rw-r--r--indra/llrender/lluiimage.cpp243
-rw-r--r--indra/llrender/lluiimage.h126
-rwxr-xr-x[-rw-r--r--]indra/llrender/llvertexbuffer.cpp539
-rwxr-xr-x[-rw-r--r--]indra/llrender/llvertexbuffer.h51
44 files changed, 4703 insertions, 738 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index 5c13df9f81..dba12d048e 100644..100755
--- a/indra/llrender/CMakeLists.txt
+++ b/indra/llrender/CMakeLists.txt
@@ -3,7 +3,7 @@
project(llrender)
include(00-Common)
-include(FindOpenGL)
+include(OpenGL)
include(FreeType)
include(LLCommon)
include(LLImage)
@@ -25,20 +25,31 @@ include_directories(
${LLXML_INCLUDE_DIRS}
${LLVFS_INCLUDE_DIRS}
)
+include_directories(SYSTEM
+ ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
+ ${LLXML_SYSTEM_INCLUDE_DIRS}
+ )
set(llrender_SOURCE_FILES
llcubemap.cpp
+ llfontbitmapcache.cpp
llfontfreetype.cpp
llfontgl.cpp
- llfontbitmapcache.cpp
llfontregistry.cpp
+ llgl.cpp
llgldbg.cpp
llglslshader.cpp
+ llgltexture.cpp
llimagegl.cpp
llpostprocess.cpp
+ llrender.cpp
+ llrender2dutils.cpp
+ llrendernavprim.cpp
llrendersphere.cpp
+ llrendertarget.cpp
llshadermgr.cpp
lltexture.cpp
+ lluiimage.cpp
llvertexbuffer.cpp
)
@@ -55,13 +66,17 @@ set(llrender_HEADER_FILES
llglheaders.h
llglslshader.h
llglstates.h
+ llgltexture.h
llgltypes.h
llimagegl.h
llpostprocess.h
llrender.h
+ llrender2dutils.h
+ llrendernavprim.h
llrendersphere.h
llshadermgr.h
lltexture.h
+ lluiimage.h
llvertexbuffer.h
)
@@ -70,33 +85,47 @@ set_source_files_properties(${llrender_HEADER_FILES}
list(APPEND llrender_SOURCE_FILES ${llrender_HEADER_FILES})
-if (SERVER AND NOT WINDOWS AND NOT DARWIN)
- copy_server_sources(
- llgl
- llrender
- )
-
-
- set_source_files_properties(
- ${server_SOURCE_FILES}
- PROPERTIES
- COMPILE_FLAGS "-DLL_MESA=1 -DLL_MESA_HEADLESS=1"
- )
+if (BUILD_HEADLESS)
add_library (llrenderheadless
${llrender_SOURCE_FILES}
- ${server_SOURCE_FILES}
)
-else (SERVER AND NOT WINDOWS AND NOT DARWIN)
- list(APPEND llrender_SOURCE_FILES
- llgl.cpp
- llrender.cpp
- llrendertarget.cpp
+
+ set_property(TARGET llrenderheadless
+ PROPERTY COMPILE_DEFINITIONS LL_MESA=1 LL_MESA_HEADLESS=1
)
-endif (SERVER AND NOT WINDOWS AND NOT DARWIN)
+
+ target_link_libraries(llrenderheadless
+ ${LLCOMMON_LIBRARIES}
+ ${LLIMAGE_LIBRARIES}
+ ${LLMATH_LIBRARIES}
+ ${LLRENDER_HEADLESS_LIBRARIES}
+ ${LLVFS_LIBRARIES}
+ ${LLXML_LIBRARIES}
+ ${LLVFS_LIBRARIES}
+ ${LLWINDOW_HEADLESS_LIBRARIES}
+ ${OPENGL_HEADLESS_LIBRARIES})
+
+endif (BUILD_HEADLESS)
+
add_library (llrender ${llrender_SOURCE_FILES})
+
+if (SDL_FOUND)
+ set_property(TARGET llrender
+ PROPERTY COMPILE_DEFINITIONS LL_SDL=1
+ )
+endif (SDL_FOUND)
+
# Libraries on which this library depends, needed for Linux builds
# Sort by high-level to low-level
target_link_libraries(llrender
- llimage
+ ${LLCOMMON_LIBRARIES}
+ ${LLIMAGE_LIBRARIES}
+ ${LLMATH_LIBRARIES}
+ ${LLRENDER_LIBRARIES}
+ ${LLVFS_LIBRARIES}
+ ${LLXML_LIBRARIES}
+ ${LLVFS_LIBRARIES}
+ ${LLWINDOW_LIBRARIES}
${FREETYPE_LIBRARIES}
${OPENGL_LIBRARIES})
+
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
index 45a3b18179..45a3b18179 100644..100755
--- a/indra/llrender/llcubemap.cpp
+++ b/indra/llrender/llcubemap.cpp
diff --git a/indra/llrender/llcubemap.h b/indra/llrender/llcubemap.h
index ee2c41e026..ee2c41e026 100644..100755
--- a/indra/llrender/llcubemap.h
+++ b/indra/llrender/llcubemap.h
diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp
index c985f6b959..c985f6b959 100644..100755
--- a/indra/llrender/llfontbitmapcache.cpp
+++ b/indra/llrender/llfontbitmapcache.cpp
diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h
index c93b0c7320..c93b0c7320 100644..100755
--- a/indra/llrender/llfontbitmapcache.h
+++ b/indra/llrender/llfontbitmapcache.h
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index 66d4ad2d87..058bef43a5 100644..100755
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -485,14 +485,11 @@ void LLFontFreetype::renderGlyph(U32 glyph_index) const
if (mFTFace == NULL)
return;
- int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT );
- llassert(!error);
+ llassert_always(! FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT) );
- error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode);
+ llassert_always(! FT_Render_Glyph(mFTFace->glyph, gFontRenderMode) );
mRenderGlyphCount++;
-
- llassert(!error);
}
void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
index f1b23f22d5..f1b23f22d5 100644..100755
--- a/indra/llrender/llfontfreetype.h
+++ b/indra/llrender/llfontfreetype.h
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index fccbf37a8d..c4f36cabd0 100644..100755
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -422,6 +422,16 @@ S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y
}
// font metrics - override for LLFontFreetype that returns units of virtual pixels
+F32 LLFontGL::getAscenderHeight() const
+{
+ return mFontFreetype->getAscenderHeight() / sScaleY;
+}
+
+F32 LLFontGL::getDescenderHeight() const
+{
+ return mFontFreetype->getDescenderHeight() / sScaleY;
+}
+
S32 LLFontGL::getLineHeight() const
{
return llceil(mFontFreetype->getAscenderHeight() / sScaleY) + llceil(mFontFreetype->getDescenderHeight() / sScaleY);
@@ -531,7 +541,6 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
BOOL clip = FALSE;
F32 cur_x = 0;
- F32 drawn_x = 0;
S32 start_of_last_word = 0;
BOOL in_word = FALSE;
@@ -589,6 +598,11 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
if(!fgi)
{
fgi = mFontFreetype->getGlyphInfo(wch);
+
+ if (NULL == fgi)
+ {
+ return 0;
+ }
}
// account for glyphs that run beyond the starting point for the next glyphs
@@ -614,7 +628,6 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
// Round after kerning.
cur_x = (F32)llround(cur_x);
- drawn_x = cur_x;
}
if( clip )
@@ -779,7 +792,7 @@ const LLFontDescriptor& LLFontGL::getFontDesc() const
}
// static
-void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector<std::string>& xui_paths, bool create_gl_textures)
+void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, bool create_gl_textures)
{
sVertDPI = (F32)llfloor(screen_dpi * y_scale);
sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
@@ -790,7 +803,7 @@ void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::st
// Font registry init
if (!sFontRegistry)
{
- sFontRegistry = new LLFontRegistry(xui_paths, create_gl_textures);
+ sFontRegistry = new LLFontRegistry(create_gl_textures);
sFontRegistry->parseFontInfo("fonts.xml");
}
else
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index 74bdbb43e7..0988e99deb 100644..100755
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -115,6 +115,8 @@ public:
S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const;
// font metrics - override for LLFontFreetype that returns units of virtual pixels
+ F32 getAscenderHeight() const;
+ F32 getDescenderHeight() const;
S32 getLineHeight() const;
S32 getWidth(const std::string& utf8text) const;
@@ -148,7 +150,7 @@ public:
const LLFontDescriptor& getFontDesc() const;
- static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector<std::string>& xui_paths, bool create_gl_textures = true);
+ static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, bool create_gl_textures = true);
// Load sans-serif, sans-serif-small, etc.
// Slow, requires multiple seconds to load fonts.
diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp
index 4d22eba3d9..f5ca8d5b04 100644..100755
--- a/indra/llrender/llfontregistry.cpp
+++ b/indra/llrender/llfontregistry.cpp
@@ -163,14 +163,9 @@ LLFontDescriptor LLFontDescriptor::normalize() const
return LLFontDescriptor(new_name,new_size,new_style,getFileNames());
}
-LLFontRegistry::LLFontRegistry(const string_vec_t& xui_paths,
- bool create_gl_textures)
+LLFontRegistry::LLFontRegistry(bool create_gl_textures)
: mCreateGLTextures(create_gl_textures)
{
- // Propagate this down from LLUICtrlFactory so LLRender doesn't
- // need an upstream dependency on LLUI.
- mXUIPaths = xui_paths;
-
// This is potentially a slow directory traversal, so we want to
// cache the result.
mUltimateFallbackList = LLWindow::getDynamicFallbackFontList();
@@ -183,27 +178,30 @@ LLFontRegistry::~LLFontRegistry()
bool LLFontRegistry::parseFontInfo(const std::string& xml_filename)
{
- bool success = false; // Succeed if we find at least one XUI file
- const string_vec_t& xml_paths = mXUIPaths;
+ bool success = false; // Succeed if we find and read at least one XUI file
+ const string_vec_t xml_paths = gDirUtilp->findSkinnedFilenames(LLDir::XUI, xml_filename);
+ if (xml_paths.empty())
+ {
+ // We didn't even find one single XUI file
+ return false;
+ }
+
for (string_vec_t::const_iterator path_it = xml_paths.begin();
path_it != xml_paths.end();
++path_it)
{
-
LLXMLNodePtr root;
- std::string full_filename = gDirUtilp->findSkinnedFilename(*path_it, xml_filename);
- bool parsed_file = LLXMLNode::parseFile(full_filename, root, NULL);
+ bool parsed_file = LLXMLNode::parseFile(*path_it, root, NULL);
if (!parsed_file)
continue;
-
+
if ( root.isNull() || ! root->hasName( "fonts" ) )
{
- llwarns << "Bad font info file: "
- << full_filename << llendl;
+ llwarns << "Bad font info file: " << *path_it << llendl;
continue;
}
-
+
std::string root_name;
root->getAttributeString("name",root_name);
if (root->hasName("fonts"))
@@ -215,7 +213,7 @@ bool LLFontRegistry::parseFontInfo(const std::string& xml_filename)
}
//if (success)
// dump();
-
+
return success;
}
@@ -225,7 +223,7 @@ std::string currentOsName()
return "Windows";
#elif LL_DARWIN
return "Mac";
-#elif LL_SDL
+#elif LL_SDL || LL_MESA_HEADLESS
return "Linux";
#else
return "";
diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h
index 8b06191c56..059248fbbd 100644..100755
--- a/indra/llrender/llfontregistry.h
+++ b/indra/llrender/llfontregistry.h
@@ -67,8 +67,7 @@ class LLFontRegistry
public:
// create_gl_textures - set to false for test apps with no OpenGL window,
// such as llui_libtest
- LLFontRegistry(const string_vec_t& xui_paths,
- bool create_gl_textures);
+ LLFontRegistry(bool create_gl_textures);
~LLFontRegistry();
// Load standard font info from XML file(s).
@@ -105,7 +104,6 @@ private:
font_size_map_t mFontSizes;
string_vec_t mUltimateFallbackList;
- string_vec_t mXUIPaths;
bool mCreateGLTextures;
};
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 197bc2b422..acfb3c085a 100644..100755
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -44,7 +44,6 @@
#include "llmath.h"
#include "m4math.h"
#include "llstring.h"
-#include "llmemtype.h"
#include "llstacktrace.h"
#include "llglheaders.h"
@@ -60,6 +59,7 @@ BOOL gDebugGL = FALSE;
BOOL gClothRipple = FALSE;
BOOL gHeadlessClient = FALSE;
BOOL gGLActive = FALSE;
+BOOL gGLDebugLoggingEnabled = TRUE;
static const std::string HEADLESS_VENDOR_STRING("Linden Lab");
static const std::string HEADLESS_RENDERER_STRING("Headless");
@@ -81,6 +81,8 @@ void APIENTRY gl_debug_callback(GLenum source,
const GLchar* message,
GLvoid* userParam)
{
+ if (gGLDebugLoggingEnabled)
+ {
if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
{
llwarns << "----- GL ERROR --------" << llendl;
@@ -94,6 +96,11 @@ void APIENTRY gl_debug_callback(GLenum source,
llwarns << "Severity: " << std::hex << severity << llendl;
llwarns << "Message: " << message << llendl;
llwarns << "-----------------------" << llendl;
+ if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
+ {
+ llerrs << "Halting on GL Error" << llendl;
+ }
+}
}
#endif
@@ -213,6 +220,11 @@ PFNGLGETQUERYIVARBPROC glGetQueryivARB = NULL;
PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB = NULL;
PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL;
+// GL_ARB_timer_query
+PFNGLQUERYCOUNTERPROC glQueryCounter = NULL;
+PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v = NULL;
+PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v = NULL;
+
// GL_ARB_point_parameters
PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL;
PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = NULL;
@@ -245,6 +257,13 @@ PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL;
PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL;
PFNGLSAMPLEMASKIPROC glSampleMaski = NULL;
+//transform feedback (4.0 core)
+PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = NULL;
+PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = NULL;
+PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = NULL;
+PFNGLBINDBUFFERRANGEPROC glBindBufferRange = NULL;
+PFNGLBINDBUFFERBASEPROC glBindBufferBase = NULL;
+
//GL_ARB_debug_output
PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL;
PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL;
@@ -412,11 +431,13 @@ LLGLManager::LLGLManager() :
mHasFragmentShader(FALSE),
mNumTextureImageUnits(0),
mHasOcclusionQuery(FALSE),
+ mHasTimerQuery(FALSE),
mHasOcclusionQuery2(FALSE),
mHasPointParameters(FALSE),
mHasDrawBuffers(FALSE),
mHasTextureRectangle(FALSE),
mHasTextureMultisample(FALSE),
+ mHasTransformFeedback(FALSE),
mMaxSampleMaskWords(0),
mMaxColorTextureSamples(0),
mMaxDepthTextureSamples(0),
@@ -435,7 +456,9 @@ LLGLManager::LLGLManager() :
mIsGFFX(FALSE),
mATIOffsetVerticalLines(FALSE),
mATIOldDriver(FALSE),
-
+#if LL_DARWIN
+ mIsMobileGF(FALSE),
+#endif
mHasRequirements(TRUE),
mHasSeparateSpecularColor(FALSE),
@@ -554,7 +577,8 @@ bool LLGLManager::initGL()
parse_gl_version( &mDriverVersionMajor,
&mDriverVersionMinor,
&mDriverVersionRelease,
- &mDriverVersionVendorString );
+ &mDriverVersionVendorString,
+ &mGLVersionString);
mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f;
@@ -572,16 +596,20 @@ bool LLGLManager::initGL()
#endif
}
+ if (mGLVersion >= 2.1f && LLImageGL::sCompressTextures)
+ { //use texture compression
+ glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
+ }
+ else
+ { //GL version is < 3.0, always disable texture compression
+ LLImageGL::sCompressTextures = false;
+ }
+
// Trailing space necessary to keep "nVidia Corpor_ati_on" cards
// from being recognized as ATI.
if (mGLVendor.substr(0,4) == "ATI ")
{
mGLVendorShort = "ATI";
- BOOL mobile = FALSE;
- if (mGLRenderer.find("MOBILITY") != std::string::npos)
- {
- mobile = TRUE;
- }
mIsATI = TRUE;
#if LL_WINDOWS && !LL_MESA_HEADLESS
@@ -592,11 +620,8 @@ bool LLGLManager::initGL()
#endif // LL_WINDOWS
#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
- // release 7277 is a point at which we verify that ATI OpenGL
- // drivers get pretty stable with SL, ~Catalyst 8.2,
- // for both Win32 and Linux.
- if (mDriverVersionRelease < 7277 &&
- mDriverVersionRelease != 0) // 0 == Undetectable driver version - these get to pretend to be new ATI drivers, though that decision may be revisited.
+ // count any pre OpenGL 3.0 implementation as an old driver
+ if (mGLVersion < 3.f)
{
mATIOldDriver = TRUE;
}
@@ -625,6 +650,14 @@ bool LLGLManager::initGL()
{
mIsGF3 = TRUE;
}
+#if LL_DARWIN
+ else if ((mGLRenderer.find("9400M") != std::string::npos)
+ || (mGLRenderer.find("9600M") != std::string::npos)
+ || (mGLRenderer.find("9800M") != std::string::npos))
+ {
+ mIsMobileGF = TRUE;
+ }
+#endif
}
else if (mGLVendor.find("INTEL") != std::string::npos
@@ -733,6 +766,12 @@ bool LLGLManager::initGL()
{ //using multisample textures on ATI results in black screen for some reason
mHasTextureMultisample = FALSE;
}
+
+
+ if (mIsIntel && mGLVersion <= 3.f)
+ { //never try to use framebuffer objects on older intel drivers (crashy)
+ mHasFramebufferObject = FALSE;
+ }
#endif
if (mHasFramebufferObject)
@@ -923,7 +962,6 @@ void LLGLManager::initExtensions()
mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts);
mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts);
- mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap");
mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color");
mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic");
glh_init_extensions("GL_ARB_texture_cube_map");
@@ -931,13 +969,15 @@ void LLGLManager::initExtensions()
mHasARBEnvCombine = ExtensionExists("GL_ARB_texture_env_combine", gGLHExts.mSysExts);
mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression");
mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
+ mHasTimerQuery = ExtensionExists("GL_ARB_timer_query", gGLHExts.mSysExts);
mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);
mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
mHasVertexArrayObject = ExtensionExists("GL_ARB_vertex_array_object", gGLHExts.mSysExts);
mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);
mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);
mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts);
- mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
+ //mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
+ mHasDepthClamp = FALSE;
// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
#ifdef GL_ARB_framebuffer_object
mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts);
@@ -947,12 +987,24 @@ void LLGLManager::initExtensions()
ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts) &&
ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
#endif
+#ifdef GL_EXT_texture_sRGB
+ mHassRGBTexture = ExtensionExists("GL_EXT_texture_sRGB", gGLHExts.mSysExts);
+#endif
+#ifdef GL_ARB_framebuffer_sRGB
+ mHassRGBFramebuffer = ExtensionExists("GL_ARB_framebuffer_sRGB", gGLHExts.mSysExts);
+#else
+ mHassRGBFramebuffer = ExtensionExists("GL_EXT_framebuffer_sRGB", gGLHExts.mSysExts);
+#endif
+
+ mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f;
+
mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts);
mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);
+ mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE;
#if !LL_DARWIN
mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
#endif
@@ -1108,7 +1160,8 @@ void LLGLManager::initExtensions()
// Misc
glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange);
glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange);
-
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*) &mGLMaxTextureSize);
+
#if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS
LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL;
if (mHasVertexBufferObject)
@@ -1192,7 +1245,15 @@ void LLGLManager::initExtensions()
glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage3DMultisample");
glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv");
glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski");
- }
+ }
+ if (mHasTransformFeedback)
+ {
+ glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glBeginTransformFeedback");
+ glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glEndTransformFeedback");
+ glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) GLH_EXT_GET_PROC_ADDRESS("glTransformFeedbackVaryings");
+ glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferRange");
+ glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferBase");
+ }
if (mHasDebugOutput)
{
glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB");
@@ -1227,6 +1288,13 @@ void LLGLManager::initExtensions()
glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectivARB");
glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectuivARB");
}
+ if (mHasTimerQuery)
+ {
+ llinfos << "initExtensions() TimerQuery-related procs..." << llendl;
+ glQueryCounter = (PFNGLQUERYCOUNTERPROC) GLH_EXT_GET_PROC_ADDRESS("glQueryCounter");
+ glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjecti64v");
+ glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectui64v");
+ }
if (mHasPointParameters)
{
llinfos << "initExtensions() PointParameters-related procs..." << llendl;
@@ -1439,7 +1507,7 @@ void do_assert_glerror()
void assert_glerror()
{
- if (!gGLActive)
+/* if (!gGLActive)
{
//llwarns << "GL used while not active!" << llendl;
@@ -1448,8 +1516,13 @@ void assert_glerror()
//ll_fail("GL used while not active");
}
}
+*/
- if (gDebugGL)
+ if (!gDebugGL)
+ {
+ //funny looking if for branch prediction -- gDebugGL is almost always false and assert_glerror is called often
+ }
+ else
{
do_assert_glerror();
}
@@ -1458,9 +1531,8 @@ void assert_glerror()
void clear_glerror()
{
- // Create or update texture to be used with this data
- GLenum error;
- error = glGetError();
+ glGetError();
+ glGetError();
}
///////////////////////////////////////////////////////////////
@@ -1897,7 +1969,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
glClientActiveTextureARB(GL_TEXTURE0_ARB);
gGL.getTexUnit(0)->activate();
- if (gGLManager.mHasVertexShader)
+ if (gGLManager.mHasVertexShader && LLGLSLShader::sNoFixedFunction)
{ //make sure vertex attribs are all disabled
GLint count;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &count);
@@ -1949,6 +2021,7 @@ LLGLState::LLGLState(LLGLenum state, S32 enabled) :
case GL_COLOR_MATERIAL:
case GL_FOG:
case GL_LINE_STIPPLE:
+ case GL_POLYGON_STIPPLE:
mState = 0;
break;
}
@@ -2037,7 +2110,7 @@ void LLGLManager::initGLStates()
////////////////////////////////////////////////////////////////////////////////
-void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific )
+void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string )
{
// GL_VERSION returns a null-terminated string with the format:
// <major>.<minor>[.<release>] [<vendor specific>]
@@ -2053,6 +2126,8 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor
return;
}
+ version_string->assign(version);
+
std::string ver_copy( version );
S32 len = (S32)strlen( version ); /* Flawfinder: ignore */
S32 i = 0;
@@ -2288,7 +2363,6 @@ void LLGLNamePool::release(GLuint name)
//static
void LLGLNamePool::upkeepPools()
{
- LLMemType mt(LLMemType::MTYPE_UPKEEP_POOLS);
for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
{
LLGLNamePool & pool = *iter;
@@ -2414,3 +2488,65 @@ LLGLSquashToFarClip::~LLGLSquashToFarClip()
gGL.matrixMode(LLRender::MM_MODELVIEW);
}
+
+
+LLGLSyncFence::LLGLSyncFence()
+{
+#ifdef GL_ARB_sync
+ mSync = 0;
+#endif
+}
+
+LLGLSyncFence::~LLGLSyncFence()
+{
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ glDeleteSync(mSync);
+ }
+#endif
+}
+
+void LLGLSyncFence::placeFence()
+{
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ glDeleteSync(mSync);
+ }
+ mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+#endif
+}
+
+bool LLGLSyncFence::isCompleted()
+{
+ bool ret = true;
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ GLenum status = glClientWaitSync(mSync, 0, 1);
+ if (status == GL_TIMEOUT_EXPIRED)
+ {
+ ret = false;
+ }
+ }
+#endif
+ return ret;
+}
+
+void LLGLSyncFence::wait()
+{
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
+ { //track the number of times we've waited here
+ static S32 waits = 0;
+ waits++;
+ }
+ }
+#endif
+}
+
+
+
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 5a33c98708..75e5fe86ec 100644..100755
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -98,12 +98,14 @@ public:
BOOL mHasFragmentShader;
S32 mNumTextureImageUnits;
BOOL mHasOcclusionQuery;
+ BOOL mHasTimerQuery;
BOOL mHasOcclusionQuery2;
BOOL mHasPointParameters;
BOOL mHasDrawBuffers;
BOOL mHasDepthClamp;
BOOL mHasTextureRectangle;
BOOL mHasTextureMultisample;
+ BOOL mHasTransformFeedback;
S32 mMaxSampleMaskWords;
S32 mMaxColorTextureSamples;
S32 mMaxDepthTextureSamples;
@@ -114,6 +116,8 @@ public:
BOOL mHasARBEnvCombine;
BOOL mHasCubeMap;
BOOL mHasDebugOutput;
+ BOOL mHassRGBTexture;
+ BOOL mHassRGBFramebuffer;
// Vendor-specific extensions
BOOL mIsATI;
@@ -125,6 +129,11 @@ public:
BOOL mATIOffsetVerticalLines;
BOOL mATIOldDriver;
+#if LL_DARWIN
+ // Needed to distinguish problem cards on older Macs that break with Materials
+ BOOL mIsMobileGF;
+#endif
+
// Whether this version of GL is good enough for SL to use
BOOL mHasRequirements;
@@ -141,10 +150,12 @@ public:
S32 mGLSLVersionMajor;
S32 mGLSLVersionMinor;
std::string mDriverVersionVendorString;
+ std::string mGLVersionString;
S32 mVRAM; // VRAM in MB
S32 mGLMaxVertexRange;
S32 mGLMaxIndexRange;
+ S32 mGLMaxTextureSize;
void getPixelFormat(); // Get the best pixel format
@@ -417,13 +428,42 @@ public:
virtual void updateGL() = 0;
};
+const U32 FENCE_WAIT_TIME_NANOSECONDS = 1000; //1 ms
+
+class LLGLFence
+{
+public:
+ virtual ~LLGLFence()
+ {
+ }
+
+ virtual void placeFence() = 0;
+ virtual bool isCompleted() = 0;
+ virtual void wait() = 0;
+};
+
+class LLGLSyncFence : public LLGLFence
+{
+public:
+#ifdef GL_ARB_sync
+ GLsync mSync;
+#endif
+
+ LLGLSyncFence();
+ virtual ~LLGLSyncFence();
+
+ void placeFence();
+ bool isCompleted();
+ void wait();
+};
+
extern LLMatrix4 gGLObliqueProjectionInverse;
#include "llglstates.h"
void init_glstates();
-void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific );
+void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string );
extern BOOL gClothRipple;
extern BOOL gHeadlessClient;
diff --git a/indra/llrender/llgldbg.cpp b/indra/llrender/llgldbg.cpp
index 4b68194db3..4b68194db3 100644..100755
--- a/indra/llrender/llgldbg.cpp
+++ b/indra/llrender/llgldbg.cpp
diff --git a/indra/llrender/llgldbg.h b/indra/llrender/llgldbg.h
index 963579cb82..963579cb82 100644..100755
--- a/indra/llrender/llgldbg.h
+++ b/indra/llrender/llgldbg.h
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index d61ec707f0..5a80a8faa4 100644..100755
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -116,6 +116,11 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
+// GL_ARB_timer_query
+extern PFNGLQUERYCOUNTERPROC glQueryCounter;
+extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v;
+extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v;
+
// GL_ARB_point_parameters
extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
@@ -378,6 +383,11 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
+// GL_ARB_timer_query
+extern PFNGLQUERYCOUNTERPROC glQueryCounter;
+extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v;
+extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v;
+
// GL_ARB_point_parameters
extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
@@ -528,6 +538,14 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
+//transform feedback (4.0 core)
+extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback;
+extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback;
+extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings;
+extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
+extern PFNGLBINDBUFFERBASEPROC glBindBufferBase;
+
+
#elif LL_WINDOWS
//----------------------------------------------------------------------------
// LL_WINDOWS
@@ -612,6 +630,12 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
+// GL_ARB_timer_query
+extern PFNGLQUERYCOUNTERPROC glQueryCounter;
+extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v;
+extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v;
+
+
// GL_ARB_point_parameters
extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
@@ -759,6 +783,13 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
+//transform feedback (4.0 core)
+extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback;
+extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback;
+extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings;
+extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
+extern PFNGLBINDBUFFERBASEPROC glBindBufferBase;
+
//GL_ARB_debug_output
extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB;
extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;
@@ -980,7 +1011,7 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
}
#endif
-#include <AGL/gl.h>
+#include <OpenGL/gl.h>
#endif // LL_MESA / LL_WINDOWS / LL_DARWIN
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 4b7e639aed..35620bb656 100644..100755
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -53,6 +53,12 @@ GLhandleARB LLGLSLShader::sCurBoundShader = 0;
LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
S32 LLGLSLShader::sIndexedTextureChannels = 0;
bool LLGLSLShader::sNoFixedFunction = false;
+bool LLGLSLShader::sProfileEnabled = false;
+std::set<LLGLSLShader*> LLGLSLShader::sInstances;
+U64 LLGLSLShader::sTotalTimeElapsed = 0;
+U32 LLGLSLShader::sTotalTrianglesDrawn = 0;
+U64 LLGLSLShader::sTotalSamplesDrawn = 0;
+U32 LLGLSLShader::sTotalDrawCalls = 0;
//UI shader -- declared here so llui_libtest will link properly
LLGLSLShader gUIProgram;
@@ -87,19 +93,240 @@ LLShaderFeatures::LLShaderFeatures()
//===============================
// LLGLSL Shader implementation
//===============================
+
+//static
+void LLGLSLShader::initProfile()
+{
+ sProfileEnabled = true;
+ sTotalTimeElapsed = 0;
+ sTotalTrianglesDrawn = 0;
+ sTotalSamplesDrawn = 0;
+ sTotalDrawCalls = 0;
+
+ for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+ {
+ (*iter)->clearStats();
+ }
+}
+
+
+struct LLGLSLShaderCompareTimeElapsed
+{
+ bool operator()(const LLGLSLShader* const& lhs, const LLGLSLShader* const& rhs)
+ {
+ return lhs->mTimeElapsed < rhs->mTimeElapsed;
+ }
+};
+
+//static
+void LLGLSLShader::finishProfile()
+{
+ sProfileEnabled = false;
+
+ std::vector<LLGLSLShader*> sorted;
+
+ for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+ {
+ sorted.push_back(*iter);
+ }
+
+ std::sort(sorted.begin(), sorted.end(), LLGLSLShaderCompareTimeElapsed());
+
+ for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
+ {
+ (*iter)->dumpStats();
+ }
+
+ llinfos << "-----------------------------------" << llendl;
+ llinfos << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed/1000000.f) << llendl;
+ llinfos << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn/1000000.f) << llendl;
+ llinfos << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn/1000000.f) << llendl;
+}
+
+void LLGLSLShader::clearStats()
+{
+ mTrianglesDrawn = 0;
+ mTimeElapsed = 0;
+ mSamplesDrawn = 0;
+ mDrawCalls = 0;
+ mTextureStateFetched = false;
+ mTextureMagFilter.clear();
+ mTextureMinFilter.clear();
+}
+
+void LLGLSLShader::dumpStats()
+{
+ if (mDrawCalls > 0)
+ {
+ llinfos << "=============================================" << llendl;
+ llinfos << mName << llendl;
+ for (U32 i = 0; i < mShaderFiles.size(); ++i)
+ {
+ llinfos << mShaderFiles[i].first << llendl;
+ }
+ for (U32 i = 0; i < mTexture.size(); ++i)
+ {
+ GLint idx = mTexture[i];
+
+ if (idx >= 0)
+ {
+ GLint uniform_idx = getUniformLocation(i);
+ llinfos << mUniformNameMap[uniform_idx] << " - " << std::hex << mTextureMagFilter[i] << "/" << mTextureMinFilter[i] << std::dec << llendl;
+ }
+ }
+ llinfos << "=============================================" << llendl;
+
+ F32 ms = mTimeElapsed/1000000.f;
+ F32 seconds = ms/1000.f;
+
+ F32 pct_tris = (F32) mTrianglesDrawn/(F32)sTotalTrianglesDrawn*100.f;
+ F32 tris_sec = (F32) (mTrianglesDrawn/1000000.0);
+ tris_sec /= seconds;
+
+ F32 pct_samples = (F32) ((F64)mSamplesDrawn/(F64)sTotalSamplesDrawn)*100.f;
+ F32 samples_sec = (F32) mSamplesDrawn/1000000000.0;
+ samples_sec /= seconds;
+
+ F32 pct_calls = (F32) mDrawCalls/(F32)sTotalDrawCalls*100.f;
+ U32 avg_batch = mTrianglesDrawn/mDrawCalls;
+
+ llinfos << "Triangles Drawn: " << mTrianglesDrawn << " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec ) << llendl;
+ llinfos << "Draw Calls: " << mDrawCalls << " " << llformat("(%.2f pct of total, avg %d tris/call)", pct_calls, avg_batch) << llendl;
+ llinfos << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << llendl;
+ llinfos << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32) ((F64)mTimeElapsed/(F64)sTotalTimeElapsed)*100.f, ms) << llendl;
+ }
+}
+
+//static
+void LLGLSLShader::startProfile()
+{
+ if (sProfileEnabled && sCurBoundShaderPtr)
+ {
+ sCurBoundShaderPtr->placeProfileQuery();
+ }
+
+}
+
+//static
+void LLGLSLShader::stopProfile(U32 count, U32 mode)
+{
+ if (sProfileEnabled)
+ {
+ sCurBoundShaderPtr->readProfileQuery(count, mode);
+ }
+}
+
+void LLGLSLShader::placeProfileQuery()
+{
+#if !LL_DARWIN
+ if (mTimerQuery == 0)
+ {
+ glGenQueriesARB(1, &mTimerQuery);
+ }
+
+ if (!mTextureStateFetched)
+ {
+ mTextureStateFetched = true;
+ mTextureMagFilter.resize(mTexture.size());
+ mTextureMinFilter.resize(mTexture.size());
+
+ U32 cur_active = gGL.getCurrentTexUnitIndex();
+
+ for (U32 i = 0; i < mTexture.size(); ++i)
+ {
+ GLint idx = mTexture[i];
+
+ if (idx >= 0)
+ {
+ gGL.getTexUnit(idx)->activate();
+
+ U32 mag = 0xFFFFFFFF;
+ U32 min = 0xFFFFFFFF;
+
+ U32 type = LLTexUnit::getInternalType(gGL.getTexUnit(idx)->getCurrType());
+
+ glGetTexParameteriv(type, GL_TEXTURE_MAG_FILTER, (GLint*) &mag);
+ glGetTexParameteriv(type, GL_TEXTURE_MIN_FILTER, (GLint*) &min);
+
+ mTextureMagFilter[i] = mag;
+ mTextureMinFilter[i] = min;
+ }
+ }
+
+ gGL.getTexUnit(cur_active)->activate();
+ }
+
+
+ glBeginQueryARB(GL_SAMPLES_PASSED, 1);
+ glBeginQueryARB(GL_TIME_ELAPSED, mTimerQuery);
+#endif
+}
+
+void LLGLSLShader::readProfileQuery(U32 count, U32 mode)
+{
+#if !LL_DARWIN
+ glEndQueryARB(GL_TIME_ELAPSED);
+ glEndQueryARB(GL_SAMPLES_PASSED);
+
+ U64 time_elapsed = 0;
+ glGetQueryObjectui64v(mTimerQuery, GL_QUERY_RESULT, &time_elapsed);
+
+ U64 samples_passed = 0;
+ glGetQueryObjectui64v(1, GL_QUERY_RESULT, &samples_passed);
+
+ sTotalTimeElapsed += time_elapsed;
+ mTimeElapsed += time_elapsed;
+
+ sTotalSamplesDrawn += samples_passed;
+ mSamplesDrawn += samples_passed;
+
+ U32 tri_count = 0;
+ switch (mode)
+ {
+ case LLRender::TRIANGLES: tri_count = count/3; break;
+ case LLRender::TRIANGLE_FAN: tri_count = count-2; break;
+ case LLRender::TRIANGLE_STRIP: tri_count = count-2; break;
+ default: tri_count = count; break; //points lines etc just use primitive count
+ }
+
+ mTrianglesDrawn += tri_count;
+ sTotalTrianglesDrawn += tri_count;
+
+ sTotalDrawCalls++;
+ mDrawCalls++;
+#endif
+}
+
+
+
LLGLSLShader::LLGLSLShader()
- : mProgramObject(0), mActiveTextureChannels(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT), mUniformsDirty(FALSE)
+ : mProgramObject(0),
+ mAttributeMask(0),
+ mTotalUniformSize(0),
+ mActiveTextureChannels(0),
+ mShaderLevel(0),
+ mShaderGroup(SG_DEFAULT),
+ mUniformsDirty(FALSE),
+ mTimerQuery(0)
{
+
+}
+LLGLSLShader::~LLGLSLShader()
+{
+
}
void LLGLSLShader::unload()
{
+ sInstances.erase(this);
+
stop_glerror();
mAttribute.clear();
mTexture.clear();
mUniform.clear();
mShaderFiles.clear();
+ mDefines.clear();
if (mProgramObject)
{
@@ -128,9 +355,13 @@ void LLGLSLShader::unload()
stop_glerror();
}
-BOOL LLGLSLShader::createShader(vector<string> * attributes,
- vector<string> * uniforms)
+BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes,
+ std::vector<LLStaticHashedString> * uniforms,
+ U32 varying_count,
+ const char** varyings)
{
+ sInstances.insert(this);
+
//reloading, reset matrix hash values
for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i)
{
@@ -144,11 +375,16 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
// Create program
mProgramObject = glCreateProgramObjectARB();
+#if LL_DARWIN
+ // work-around missing mix(vec3,vec3,bvec3)
+ mDefines["OLD_SELECT"] = "1";
+#endif
+
//compile new source
vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
for ( ; fileIter != mShaderFiles.end(); fileIter++ )
{
- GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, mFeatures.mIndexedTextureChannels);
+ GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, &mDefines, mFeatures.mIndexedTextureChannels);
LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL;
if (shaderhandle > 0)
{
@@ -172,6 +408,13 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
}
+#ifdef GL_INTERLEAVED_ATTRIBS
+ if (varying_count > 0 && varyings)
+ {
+ glTransformFeedbackVaryings(mProgramObject, varying_count, varyings, GL_INTERLEAVED_ATTRIBS);
+ }
+#endif
+
// Map attributes and uniforms
if (success)
{
@@ -200,7 +443,8 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
for (S32 i = 0; i < channel_count; i++)
{
- uniform1i(llformat("tex%d", i), i);
+ LLStaticHashedString uniName(llformat("tex%d", i));
+ uniform1i(uniName, i);
}
S32 cur_tex = channel_count; //adjust any texture channels that might have been overwritten
@@ -257,7 +501,7 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count)
}
}
-BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes)
+BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attributes)
{
//before linking, make sure reserved attributes always have consistent locations
for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
@@ -276,6 +520,8 @@ BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes)
if (res)
{ //read back channel locations
+ mAttributeMask = 0;
+
//read back reserved channels first
for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
{
@@ -284,6 +530,7 @@ BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes)
if (index != -1)
{
mAttribute[i] = index;
+ mAttributeMask |= 1 << i;
LL_DEBUGS("ShaderLoading") << "Attribute " << name << " assigned to channel " << index << LL_ENDL;
}
}
@@ -291,7 +538,7 @@ BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes)
{
for (U32 i = 0; i < numAttributes; i++)
{
- const char* name = (*attributes)[i].c_str();
+ const char* name = (*attributes)[i].String().c_str();
S32 index = glGetAttribLocationARB(mProgramObject, name);
if (index != -1)
{
@@ -307,7 +554,7 @@ BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes)
return FALSE;
}
-void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
+void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString> * uniforms)
{
if (index == -1)
{
@@ -316,11 +563,56 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
GLenum type;
GLsizei length;
- GLint size;
+ GLint size = -1;
char name[1024]; /* Flawfinder: ignore */
name[0] = 0;
+
glGetActiveUniformARB(mProgramObject, index, 1024, &length, &size, &type, (GLcharARB *)name);
+#if !LL_DARWIN
+ if (size > 0)
+ {
+ switch(type)
+ {
+ case GL_FLOAT_VEC2: size *= 2; break;
+ case GL_FLOAT_VEC3: size *= 3; break;
+ case GL_FLOAT_VEC4: size *= 4; break;
+ case GL_DOUBLE: size *= 2; break;
+ case GL_DOUBLE_VEC2: size *= 2; break;
+ case GL_DOUBLE_VEC3: size *= 6; break;
+ case GL_DOUBLE_VEC4: size *= 8; break;
+ case GL_INT_VEC2: size *= 2; break;
+ case GL_INT_VEC3: size *= 3; break;
+ case GL_INT_VEC4: size *= 4; break;
+ case GL_UNSIGNED_INT_VEC2: size *= 2; break;
+ case GL_UNSIGNED_INT_VEC3: size *= 3; break;
+ case GL_UNSIGNED_INT_VEC4: size *= 4; break;
+ case GL_BOOL_VEC2: size *= 2; break;
+ case GL_BOOL_VEC3: size *= 3; break;
+ case GL_BOOL_VEC4: size *= 4; break;
+ case GL_FLOAT_MAT2: size *= 4; break;
+ case GL_FLOAT_MAT3: size *= 9; break;
+ case GL_FLOAT_MAT4: size *= 16; break;
+ case GL_FLOAT_MAT2x3: size *= 6; break;
+ case GL_FLOAT_MAT2x4: size *= 8; break;
+ case GL_FLOAT_MAT3x2: size *= 6; break;
+ case GL_FLOAT_MAT3x4: size *= 12; break;
+ case GL_FLOAT_MAT4x2: size *= 8; break;
+ case GL_FLOAT_MAT4x3: size *= 12; break;
+ case GL_DOUBLE_MAT2: size *= 8; break;
+ case GL_DOUBLE_MAT3: size *= 18; break;
+ case GL_DOUBLE_MAT4: size *= 32; break;
+ case GL_DOUBLE_MAT2x3: size *= 12; break;
+ case GL_DOUBLE_MAT2x4: size *= 16; break;
+ case GL_DOUBLE_MAT3x2: size *= 12; break;
+ case GL_DOUBLE_MAT3x4: size *= 24; break;
+ case GL_DOUBLE_MAT4x2: size *= 16; break;
+ case GL_DOUBLE_MAT4x3: size *= 24; break;
+ }
+ mTotalUniformSize += size;
+ }
+#endif
+
S32 location = glGetUniformLocationARB(mProgramObject, name);
if (location != -1)
{
@@ -332,7 +624,10 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
is_array[0] = 0;
}
- mUniformMap[name] = location;
+ LLStaticHashedString hashedName(name);
+ mUniformNameMap[location] = name;
+ mUniformMap[hashedName] = location;
+
LL_DEBUGS("ShaderLoading") << "Uniform " << name << " is at location " << location << LL_ENDL;
//find the index of this uniform
@@ -353,7 +648,7 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
for (U32 i = 0; i < uniforms->size(); i++)
{
if ( (mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] == -1)
- && ((*uniforms)[i] == name))
+ && ((*uniforms)[i].String() == name))
{
//found it
mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] = location;
@@ -363,11 +658,21 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
}
}
}
- }
+}
+
+void LLGLSLShader::addPermutation(std::string name, std::string value)
+{
+ mDefines[name] = value;
+}
+
+void LLGLSLShader::removePermutation(std::string name)
+{
+ mDefines[name].erase();
+}
GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
{
- if (type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB ||
+ if ((type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB) ||
type == GL_SAMPLER_2D_MULTISAMPLE)
{ //this here is a texture
glUniform1iARB(location, mActiveTextureChannels);
@@ -377,13 +682,15 @@ GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
return -1;
}
-BOOL LLGLSLShader::mapUniforms(const vector<string> * uniforms)
+BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms)
{
BOOL res = TRUE;
+ mTotalUniformSize = 0;
mActiveTextureChannels = 0;
mUniform.clear();
mUniformMap.clear();
+ mUniformNameMap.clear();
mTexture.clear();
mValue.clear();
//initialize arrays
@@ -404,6 +711,7 @@ BOOL LLGLSLShader::mapUniforms(const vector<string> * uniforms)
unbind();
+ LL_DEBUGS("ShaderLoading") << "Total Uniform Size: " << mTotalUniformSize << llendl;
return res;
}
@@ -462,6 +770,58 @@ void LLGLSLShader::bindNoShader(void)
}
}
+S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LLTexUnit::eTextureType mode)
+{
+ S32 channel = 0;
+ channel = getUniformLocation(uniform);
+
+ return bindTexture(channel, texture, mode);
+}
+
+S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode)
+{
+ if (uniform < 0 || uniform >= (S32)mTexture.size())
+ {
+ UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL;
+ return -1;
+ }
+
+ uniform = mTexture[uniform];
+
+ if (uniform > -1)
+ {
+ gGL.getTexUnit(uniform)->bind(texture, mode);
+ }
+
+ return uniform;
+}
+
+S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureType mode)
+{
+ S32 channel = 0;
+ channel = getUniformLocation(uniform);
+
+ return unbindTexture(channel);
+}
+
+S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
+{
+ if (uniform < 0 || uniform >= (S32)mTexture.size())
+ {
+ UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL;
+ return -1;
+ }
+
+ uniform = mTexture[uniform];
+
+ if (uniform > -1)
+ {
+ gGL.getTexUnit(uniform)->unbind(mode);
+ }
+
+ return uniform;
+}
+
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode)
{
if (uniform < 0 || uniform >= (S32)mTexture.size())
@@ -784,18 +1144,18 @@ void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, c
}
}
-GLint LLGLSLShader::getUniformLocation(const string& uniform)
+GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform)
{
GLint ret = -1;
if (mProgramObject > 0)
{
- std::map<string, GLint>::iterator iter = mUniformMap.find(uniform);
+ LLStaticStringTable<GLint>::iterator iter = mUniformMap.find(uniform);
if (iter != mUniformMap.end())
{
if (gDebugGL)
{
stop_glerror();
- if (iter->second != glGetUniformLocationARB(mProgramObject, uniform.c_str()))
+ if (iter->second != glGetUniformLocationARB(mProgramObject, uniform.String().c_str()))
{
llerrs << "Uniform does not match." << llendl;
}
@@ -832,7 +1192,7 @@ GLint LLGLSLShader::getAttribLocation(U32 attrib)
}
}
-void LLGLSLShader::uniform1i(const string& uniform, GLint v)
+void LLGLSLShader::uniform1i(const LLStaticHashedString& uniform, GLint v)
{
GLint location = getUniformLocation(uniform);
@@ -848,72 +1208,73 @@ void LLGLSLShader::uniform1i(const string& uniform, GLint v)
}
}
-void LLGLSLShader::uniform1f(const string& uniform, GLfloat v)
+void LLGLSLShader::uniform2i(const LLStaticHashedString& uniform, GLint i, GLint j)
{
GLint location = getUniformLocation(uniform);
if (location >= 0)
{
std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
- LLVector4 vec(v,0.f,0.f,0.f);
+ LLVector4 vec(i,j,0.f,0.f);
if (iter == mValue.end() || shouldChange(iter->second,vec))
{
- glUniform1fARB(location, v);
+ glUniform2iARB(location, i, j);
mValue[location] = vec;
}
}
}
-void LLGLSLShader::uniform2f(const string& uniform, GLfloat x, GLfloat y)
+
+void LLGLSLShader::uniform1f(const LLStaticHashedString& uniform, GLfloat v)
{
GLint location = getUniformLocation(uniform);
if (location >= 0)
{
std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
- LLVector4 vec(x,y,0.f,0.f);
+ LLVector4 vec(v,0.f,0.f,0.f);
if (iter == mValue.end() || shouldChange(iter->second,vec))
{
- glUniform2fARB(location, x,y);
+ glUniform1fARB(location, v);
mValue[location] = vec;
}
}
-
}
-void LLGLSLShader::uniform3f(const string& uniform, GLfloat x, GLfloat y, GLfloat z)
+void LLGLSLShader::uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y)
{
GLint location = getUniformLocation(uniform);
if (location >= 0)
{
std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
- LLVector4 vec(x,y,z,0.f);
+ LLVector4 vec(x,y,0.f,0.f);
if (iter == mValue.end() || shouldChange(iter->second,vec))
{
- glUniform3fARB(location, x,y,z);
+ glUniform2fARB(location, x,y);
mValue[location] = vec;
}
}
+
}
-void LLGLSLShader::uniform4f(const string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+void LLGLSLShader::uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z)
{
GLint location = getUniformLocation(uniform);
-
+
if (location >= 0)
{
std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
- LLVector4 vec(x,y,z,w);
+ LLVector4 vec(x,y,z,0.f);
if (iter == mValue.end() || shouldChange(iter->second,vec))
{
- glUniform4fARB(location, x,y,z,w);
+ glUniform3fARB(location, x,y,z);
mValue[location] = vec;
}
}
}
-void LLGLSLShader::uniform1fv(const string& uniform, U32 count, const GLfloat* v)
+void LLGLSLShader::uniform1fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
{
GLint location = getUniformLocation(uniform);
@@ -929,7 +1290,7 @@ void LLGLSLShader::uniform1fv(const string& uniform, U32 count, const GLfloat* v
}
}
-void LLGLSLShader::uniform2fv(const string& uniform, U32 count, const GLfloat* v)
+void LLGLSLShader::uniform2fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
{
GLint location = getUniformLocation(uniform);
@@ -945,7 +1306,7 @@ void LLGLSLShader::uniform2fv(const string& uniform, U32 count, const GLfloat* v
}
}
-void LLGLSLShader::uniform3fv(const string& uniform, U32 count, const GLfloat* v)
+void LLGLSLShader::uniform3fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
{
GLint location = getUniformLocation(uniform);
@@ -961,7 +1322,7 @@ void LLGLSLShader::uniform3fv(const string& uniform, U32 count, const GLfloat* v
}
}
-void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v)
+void LLGLSLShader::uniform4fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
{
GLint location = getUniformLocation(uniform);
@@ -979,27 +1340,7 @@ void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v
}
}
-void LLGLSLShader::uniformMatrix2fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v)
-{
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- glUniformMatrix2fvARB(location, count, transpose, v);
- }
-}
-
-void LLGLSLShader::uniformMatrix3fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v)
-{
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- glUniformMatrix3fvARB(location, count, transpose, v);
- }
-}
-
-void LLGLSLShader::uniformMatrix4fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v)
+void LLGLSLShader::uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat* v)
{
GLint location = getUniformLocation(uniform);
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 7873fe3c4e..7b2f5f04c2 100644..100755
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -29,6 +29,7 @@
#include "llgl.h"
#include "llrender.h"
+#include "llstaticstringtable.h"
class LLShaderFeatures
{
@@ -67,22 +68,39 @@ public:
SG_WATER
};
+ static std::set<LLGLSLShader*> sInstances;
+ static bool sProfileEnabled;
+
LLGLSLShader();
+ ~LLGLSLShader();
static GLhandleARB sCurBoundShader;
static LLGLSLShader* sCurBoundShaderPtr;
static S32 sIndexedTextureChannels;
static bool sNoFixedFunction;
+ static void initProfile();
+ static void finishProfile();
+
+ static void startProfile();
+ static void stopProfile(U32 count, U32 mode);
+
void unload();
- BOOL createShader(std::vector<std::string> * attributes,
- std::vector<std::string> * uniforms);
+ void clearStats();
+ void dumpStats();
+ void placeProfileQuery();
+ void readProfileQuery(U32 count, U32 mode);
+
+ BOOL createShader(std::vector<LLStaticHashedString> * attributes,
+ std::vector<LLStaticHashedString> * uniforms,
+ U32 varying_count = 0,
+ const char** varyings = NULL);
BOOL attachObject(std::string object);
void attachObject(GLhandleARB object);
void attachObjects(GLhandleARB* objects = NULL, S32 count = 0);
- BOOL mapAttributes(const std::vector<std::string> * attributes);
- BOOL mapUniforms(const std::vector<std::string> * uniforms);
- void mapUniform(GLint index, const std::vector<std::string> * uniforms);
+ BOOL mapAttributes(const std::vector<LLStaticHashedString> * attributes);
+ BOOL mapUniforms(const std::vector<LLStaticHashedString> *);
+ void mapUniform(GLint index, const std::vector<LLStaticHashedString> *);
void uniform1i(U32 index, GLint i);
void uniform1f(U32 index, GLfloat v);
void uniform2f(U32 index, GLfloat x, GLfloat y);
@@ -93,40 +111,48 @@ 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 uniform1i(const std::string& uniform, GLint i);
- void uniform1f(const std::string& uniform, GLfloat v);
- void uniform2f(const std::string& uniform, GLfloat x, GLfloat y);
- void uniform3f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z);
- void uniform4f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
- void uniform1iv(const std::string& uniform, U32 count, const GLint* i);
- void uniform1fv(const std::string& uniform, U32 count, const GLfloat* v);
- void uniform2fv(const std::string& uniform, U32 count, const GLfloat* v);
- void uniform3fv(const std::string& uniform, U32 count, const GLfloat* v);
- void uniform4fv(const std::string& uniform, U32 count, const GLfloat* 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);
void uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v);
- void uniformMatrix2fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
- void uniformMatrix3fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
- void uniformMatrix4fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
+ void uniform1i(const LLStaticHashedString& uniform, GLint i);
+ void uniform1f(const LLStaticHashedString& uniform, GLfloat v);
+ void uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y);
+ void uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z);
+ void uniform1fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
+ void uniform2fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
+ void uniform3fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
+ void uniform4fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
+ void uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat *v);
void setMinimumAlpha(F32 minimum);
void vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void vertexAttrib4fv(U32 index, GLfloat* v);
- GLint getUniformLocation(const std::string& uniform);
+ //GLint getUniformLocation(const std::string& uniform);
+ GLint getUniformLocation(const LLStaticHashedString& uniform);
GLint getUniformLocation(U32 index);
GLint getAttribLocation(U32 attrib);
GLint mapUniformTextureChannel(GLint location, GLenum type);
+ void addPermutation(std::string name, std::string value);
+ void removePermutation(std::string name);
+
//enable/disable texture channel for specified uniform
//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);
- S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
+ S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
+
+ // 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);
+ S32 bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
+ S32 unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
+ S32 unbindTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
BOOL link(BOOL suppress_errors = FALSE);
void bind();
@@ -140,10 +166,13 @@ public:
GLhandleARB mProgramObject;
std::vector<GLint> mAttribute; //lookup table of attribute enum to attribute channel
+ U32 mAttributeMask; //mask of which reserved attributes are set (lines up with LLVertexBuffer::getTypeMask())
std::vector<GLint> mUniform; //lookup table of uniform enum to uniform location
- std::map<std::string, GLint> mUniformMap; //lookup map of uniform name to uniform location
+ LLStaticStringTable<GLint> mUniformMap; //lookup map of uniform name to uniform location
+ std::map<GLint, std::string> mUniformNameMap; //lookup map of uniform location to uniform name
std::map<GLint, LLVector4> mValue; //lookup map of uniform location to last known value
std::vector<GLint> mTexture;
+ S32 mTotalUniformSize;
S32 mActiveTextureChannels;
S32 mShaderLevel;
S32 mShaderGroup;
@@ -151,12 +180,31 @@ public:
LLShaderFeatures mFeatures;
std::vector< std::pair< std::string, GLenum > > mShaderFiles;
std::string mName;
+ boost::unordered_map<std::string, std::string> mDefines;
+
+ //statistcis for profiling shader performance
+ U32 mTimerQuery;
+ U64 mTimeElapsed;
+ static U64 sTotalTimeElapsed;
+ U32 mTrianglesDrawn;
+ static U32 sTotalTrianglesDrawn;
+ U64 mSamplesDrawn;
+ static U64 sTotalSamplesDrawn;
+ U32 mDrawCalls;
+ static U32 sTotalDrawCalls;
+
+ bool mTextureStateFetched;
+ std::vector<U32> mTextureMagFilter;
+ std::vector<U32> mTextureMinFilter;
+
};
//UI shader (declared here so llui_libtest will link properly)
extern LLGLSLShader gUIProgram;
//output vec4(color.rgb,color.a*tex0[tc0].a)
extern LLGLSLShader gSolidColorProgram;
+//Alpha mask shader (declared here so llappearance can access properly)
+extern LLGLSLShader gAlphaMaskProgram;
#endif
diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h
index e26aead676..0e2c3bcb44 100644..100755
--- a/indra/llrender/llglstates.h
+++ b/indra/llrender/llglstates.h
@@ -59,7 +59,6 @@ protected:
LLGLEnable mColorMaterial;
LLGLDisable mAlphaTest, mBlend, mCullFace, mDither, mFog,
mLineSmooth, mLineStipple, mNormalize, mPolygonSmooth,
- mTextureGenQ, mTextureGenR, mTextureGenS, mTextureGenT,
mGLMultisample;
public:
LLGLSDefault()
@@ -76,10 +75,6 @@ public:
mLineStipple(GL_LINE_STIPPLE),
mNormalize(GL_NORMALIZE),
mPolygonSmooth(GL_POLYGON_SMOOTH),
- mTextureGenQ(GL_TEXTURE_GEN_Q),
- mTextureGenR(GL_TEXTURE_GEN_R),
- mTextureGenS(GL_TEXTURE_GEN_S),
- mTextureGenT(GL_TEXTURE_GEN_T),
mGLMultisample(GL_MULTISAMPLE_ARB)
{ }
};
diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp
new file mode 100644
index 0000000000..d06ed5e57b
--- /dev/null
+++ b/indra/llrender/llgltexture.cpp
@@ -0,0 +1,396 @@
+/**
+ * @file llgltexture.cpp
+ * @brief Opengl texture implementation
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+#include "linden_common.h"
+#include "llgltexture.h"
+
+
+// static
+S32 LLGLTexture::getTotalNumOfCategories()
+{
+ return MAX_GL_IMAGE_CATEGORY - (BOOST_HIGH - BOOST_SCULPTED) + 2 ;
+}
+
+// static
+//index starts from zero.
+S32 LLGLTexture::getIndexFromCategory(S32 category)
+{
+ return (category < BOOST_HIGH) ? category : category - (BOOST_HIGH - BOOST_SCULPTED) + 1 ;
+}
+
+//static
+S32 LLGLTexture::getCategoryFromIndex(S32 index)
+{
+ return (index < BOOST_HIGH) ? index : index + (BOOST_HIGH - BOOST_SCULPTED) - 1 ;
+}
+
+LLGLTexture::LLGLTexture(BOOL usemipmaps)
+{
+ init();
+ mUseMipMaps = usemipmaps;
+}
+
+LLGLTexture::LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps)
+{
+ init();
+ mFullWidth = width ;
+ mFullHeight = height ;
+ mUseMipMaps = usemipmaps;
+ mComponents = components ;
+ setTexelsPerImage();
+}
+
+LLGLTexture::LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps)
+{
+ init();
+ mUseMipMaps = usemipmaps ;
+ // Create an empty image of the specified size and width
+ mGLTexturep = new LLImageGL(raw, usemipmaps) ;
+}
+
+LLGLTexture::~LLGLTexture()
+{
+ cleanup();
+}
+
+void LLGLTexture::init()
+{
+ mBoostLevel = LLGLTexture::BOOST_NONE;
+
+ mFullWidth = 0;
+ mFullHeight = 0;
+ mTexelsPerImage = 0 ;
+ mUseMipMaps = FALSE ;
+ mComponents = 0 ;
+
+ mTextureState = NO_DELETE ;
+ mDontDiscard = FALSE;
+ mNeedsGLTexture = FALSE ;
+}
+
+void LLGLTexture::cleanup()
+{
+ if(mGLTexturep)
+ {
+ mGLTexturep->cleanup();
+ }
+}
+
+// virtual
+void LLGLTexture::dump()
+{
+ if(mGLTexturep)
+ {
+ mGLTexturep->dump();
+ }
+}
+
+void LLGLTexture::setBoostLevel(S32 level)
+{
+ if(mBoostLevel != level)
+ {
+ mBoostLevel = level ;
+ if(mBoostLevel != LLGLTexture::BOOST_NONE)
+ {
+ setNoDelete() ;
+ }
+ }
+}
+
+void LLGLTexture::forceActive()
+{
+ mTextureState = ACTIVE ;
+}
+
+void LLGLTexture::setActive()
+{
+ if(mTextureState != NO_DELETE)
+ {
+ mTextureState = ACTIVE ;
+ }
+}
+
+//set the texture to stay in memory
+void LLGLTexture::setNoDelete()
+{
+ mTextureState = NO_DELETE ;
+}
+
+void LLGLTexture::generateGLTexture()
+{
+ if(mGLTexturep.isNull())
+ {
+ mGLTexturep = new LLImageGL(mFullWidth, mFullHeight, mComponents, mUseMipMaps) ;
+ }
+}
+
+LLImageGL* LLGLTexture::getGLTexture() const
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep ;
+}
+
+BOOL LLGLTexture::createGLTexture()
+{
+ if(mGLTexturep.isNull())
+ {
+ generateGLTexture() ;
+ }
+
+ return mGLTexturep->createGLTexture() ;
+}
+
+BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category)
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ;
+
+ if(ret)
+ {
+ mFullWidth = mGLTexturep->getCurrentWidth() ;
+ mFullHeight = mGLTexturep->getCurrentHeight() ;
+ mComponents = mGLTexturep->getComponents() ;
+ setTexelsPerImage();
+ }
+
+ return ret ;
+}
+
+void LLGLTexture::setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes)
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ mGLTexturep->setExplicitFormat(internal_format, primary_format, type_format, swap_bytes) ;
+}
+void LLGLTexture::setAddressMode(LLTexUnit::eTextureAddressMode mode)
+{
+ llassert(mGLTexturep.notNull()) ;
+ mGLTexturep->setAddressMode(mode) ;
+}
+void LLGLTexture::setFilteringOption(LLTexUnit::eTextureFilterOptions option)
+{
+ llassert(mGLTexturep.notNull()) ;
+ mGLTexturep->setFilteringOption(option) ;
+}
+
+//virtual
+S32 LLGLTexture::getWidth(S32 discard_level) const
+{
+ llassert(mGLTexturep.notNull()) ;
+ return mGLTexturep->getWidth(discard_level) ;
+}
+
+//virtual
+S32 LLGLTexture::getHeight(S32 discard_level) const
+{
+ llassert(mGLTexturep.notNull()) ;
+ return mGLTexturep->getHeight(discard_level) ;
+}
+
+S32 LLGLTexture::getMaxDiscardLevel() const
+{
+ llassert(mGLTexturep.notNull()) ;
+ return mGLTexturep->getMaxDiscardLevel() ;
+}
+S32 LLGLTexture::getDiscardLevel() const
+{
+ llassert(mGLTexturep.notNull()) ;
+ return mGLTexturep->getDiscardLevel() ;
+}
+S8 LLGLTexture::getComponents() const
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->getComponents() ;
+}
+
+LLGLuint LLGLTexture::getTexName() const
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->getTexName() ;
+}
+
+BOOL LLGLTexture::hasGLTexture() const
+{
+ if(mGLTexturep.notNull())
+ {
+ return mGLTexturep->getHasGLTexture() ;
+ }
+ return FALSE ;
+}
+
+BOOL LLGLTexture::getBoundRecently() const
+{
+ if(mGLTexturep.notNull())
+ {
+ return mGLTexturep->getBoundRecently() ;
+ }
+ return FALSE ;
+}
+
+LLTexUnit::eTextureType LLGLTexture::getTarget(void) const
+{
+ llassert(mGLTexturep.notNull()) ;
+ return mGLTexturep->getTarget() ;
+}
+
+BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height)
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height) ;
+}
+
+BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height)
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height) ;
+}
+
+void LLGLTexture::setGLTextureCreated (bool initialized)
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ mGLTexturep->setGLTextureCreated (initialized) ;
+}
+
+void LLGLTexture::setCategory(S32 category)
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ mGLTexturep->setCategory(category) ;
+}
+
+LLTexUnit::eTextureAddressMode LLGLTexture::getAddressMode(void) const
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->getAddressMode() ;
+}
+
+S32 LLGLTexture::getTextureMemory() const
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->mTextureMemory ;
+}
+
+LLGLenum LLGLTexture::getPrimaryFormat() const
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->getPrimaryFormat() ;
+}
+
+BOOL LLGLTexture::getIsAlphaMask() const
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->getIsAlphaMask() ;
+}
+
+BOOL LLGLTexture::getMask(const LLVector2 &tc)
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->getMask(tc) ;
+}
+
+F32 LLGLTexture::getTimePassedSinceLastBound()
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->getTimePassedSinceLastBound() ;
+}
+BOOL LLGLTexture::getMissed() const
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->getMissed() ;
+}
+
+BOOL LLGLTexture::isJustBound() const
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->isJustBound() ;
+}
+
+void LLGLTexture::forceUpdateBindStats(void) const
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ 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()) ;
+
+ return mGLTexturep->isGLTextureCreated() ;
+}
+
+S32 LLGLTexture::getDiscardLevelInAtlas() const
+{
+ llassert(mGLTexturep.notNull()) ;
+
+ return mGLTexturep->getDiscardLevelInAtlas() ;
+}
+
+void LLGLTexture::destroyGLTexture()
+{
+ if(mGLTexturep.notNull() && mGLTexturep->getHasGLTexture())
+ {
+ mGLTexturep->destroyGLTexture() ;
+ mTextureState = DELETED ;
+ }
+}
+
+void LLGLTexture::setTexelsPerImage()
+{
+ S32 fullwidth = llmin(mFullWidth,(S32)MAX_IMAGE_SIZE_DEFAULT);
+ S32 fullheight = llmin(mFullHeight,(S32)MAX_IMAGE_SIZE_DEFAULT);
+ mTexelsPerImage = (F32)fullwidth * fullheight;
+}
+
+
diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h
new file mode 100644
index 0000000000..e69b322d60
--- /dev/null
+++ b/indra/llrender/llgltexture.h
@@ -0,0 +1,199 @@
+/**
+ * @file llglviewertexture.h
+ * @brief Object for managing opengl textures
+ *
+ * $LicenseInfo:firstyear=2012&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_GL_TEXTURE_H
+#define LL_GL_TEXTURE_H
+
+#include "lltexture.h"
+#include "llgl.h"
+
+class LLImageRaw;
+
+//
+//this the parent for the class LLViewerTexture
+//through the following virtual functions, the class LLViewerTexture can be reached from /llrender.
+//
+class LLGLTexture : public LLTexture
+{
+public:
+ enum
+ {
+ MAX_IMAGE_SIZE_DEFAULT = 1024,
+ INVALID_DISCARD_LEVEL = 0x7fff
+ };
+
+ enum EBoostLevel
+ {
+ BOOST_NONE = 0,
+ BOOST_AVATAR_BAKED ,
+ BOOST_AVATAR ,
+ BOOST_CLOUDS ,
+ BOOST_SCULPTED ,
+
+ BOOST_HIGH = 10,
+ BOOST_BUMP ,
+ BOOST_TERRAIN , // has to be high priority for minimap / low detail
+ BOOST_SELECTED ,
+ BOOST_AVATAR_BAKED_SELF ,
+ BOOST_AVATAR_SELF , // needed for baking avatar
+ BOOST_SUPER_HIGH , //textures higher than this need to be downloaded at the required resolution without delay.
+ BOOST_HUD ,
+ BOOST_ICON ,
+ BOOST_UI ,
+ BOOST_PREVIEW ,
+ BOOST_MAP ,
+ BOOST_MAP_VISIBLE ,
+ BOOST_MAX_LEVEL,
+
+ //other texture Categories
+ LOCAL = BOOST_MAX_LEVEL,
+ AVATAR_SCRATCH_TEX,
+ DYNAMIC_TEX,
+ MEDIA,
+ ATLAS,
+ OTHER,
+ MAX_GL_IMAGE_CATEGORY
+ };
+
+ 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;
+
+ static S32 getTotalNumOfCategories() ;
+ static S32 getIndexFromCategory(S32 category) ;
+ static S32 getCategoryFromIndex(S32 index) ;
+
+protected:
+ virtual ~LLGLTexture();
+ LOG_CLASS(LLGLTexture);
+
+public:
+ LLGLTexture(BOOL usemipmaps = TRUE);
+ LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps) ;
+ LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ;
+
+ virtual void dump(); // debug info to llinfos
+
+ virtual const LLUUID& getID() const = 0;
+
+ void setBoostLevel(S32 level);
+ S32 getBoostLevel() { return mBoostLevel; }
+
+ S32 getFullWidth() const { return mFullWidth; }
+ S32 getFullHeight() const { return mFullHeight; }
+
+ void generateGLTexture() ;
+ void destroyGLTexture() ;
+
+ //---------------------------------------------------------------------------------------------
+ //functions to access LLImageGL
+ //---------------------------------------------------------------------------------------------
+ /*virtual*/S32 getWidth(S32 discard_level = -1) const;
+ /*virtual*/S32 getHeight(S32 discard_level = -1) const;
+
+ BOOL hasGLTexture() const ;
+ LLGLuint getTexName() const ;
+ BOOL createGLTexture() ;
+ BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER);
+
+ void setFilteringOption(LLTexUnit::eTextureFilterOptions option);
+ void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
+ void setAddressMode(LLTexUnit::eTextureAddressMode mode);
+ BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height);
+ BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height);
+ void setGLTextureCreated (bool initialized);
+ void setCategory(S32 category) ;
+
+ LLTexUnit::eTextureAddressMode getAddressMode(void) const ;
+ S32 getMaxDiscardLevel() const;
+ S32 getDiscardLevel() const;
+ S8 getComponents() const;
+ BOOL getBoundRecently() const;
+ S32 getTextureMemory() const ;
+ LLGLenum getPrimaryFormat() const;
+ BOOL getIsAlphaMask() const ;
+ LLTexUnit::eTextureType getTarget(void) const ;
+ BOOL getMask(const LLVector2 &tc);
+ F32 getTimePassedSinceLastBound();
+ BOOL getMissed() const ;
+ BOOL isJustBound()const ;
+ void forceUpdateBindStats(void) const;
+
+ U32 getTexelsInAtlas() const ;
+ U32 getTexelsInGLTexture() const ;
+ BOOL isGLTextureCreated() const ;
+ S32 getDiscardLevelInAtlas() const ;
+ LLGLTextureState getTextureState() const { return mTextureState; }
+
+ //---------------------------------------------------------------------------------------------
+ //end of functions to access LLImageGL
+ //---------------------------------------------------------------------------------------------
+
+ //-----------------
+ /*virtual*/ void setActive() ;
+ void forceActive() ;
+ void setNoDelete() ;
+ void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; }
+ BOOL getDontDiscard() const { return mDontDiscard; }
+ //-----------------
+
+private:
+ void cleanup();
+ void init();
+
+protected:
+ void setTexelsPerImage();
+
+ //note: do not make this function public.
+ /*virtual*/ LLImageGL* getGLTexture() const ;
+
+protected:
+ S32 mBoostLevel; // enum describing priority level
+ S32 mFullWidth;
+ S32 mFullHeight;
+ BOOL mUseMipMaps;
+ S8 mComponents;
+ F32 mTexelsPerImage; // Texels per image.
+ mutable S8 mNeedsGLTexture;
+
+ //GL texture
+ LLPointer<LLImageGL> mGLTexturep ;
+ S8 mDontDiscard; // Keep full res version of this image (for UI, etc)
+
+protected:
+ LLGLTextureState mTextureState ;
+
+
+};
+
+#endif // LL_GL_TEXTURE_H
+
diff --git a/indra/llrender/llgltypes.h b/indra/llrender/llgltypes.h
index 6c217ef727..6c217ef727 100644..100755
--- a/indra/llrender/llgltypes.h
+++ b/indra/llrender/llgltypes.h
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 78591ddd38..ab875141c5 100644..100755
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -42,8 +42,11 @@
//----------------------------------------------------------------------------
const F32 MIN_TEXTURE_LIFETIME = 10.f;
+//which power of 2 is i?
+//assumes i is a power of 2 > 0
+U32 wpo2(U32 i);
+
//statics
-LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 };
U32 LLImageGL::sUniqueCount = 0;
U32 LLImageGL::sBindCount = 0;
@@ -51,12 +54,12 @@ S32 LLImageGL::sGlobalTextureMemoryInBytes = 0;
S32 LLImageGL::sBoundTextureMemoryInBytes = 0;
S32 LLImageGL::sCurBoundTextureMemory = 0;
S32 LLImageGL::sCount = 0;
-std::list<U32> LLImageGL::sDeadTextureList;
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;
@@ -65,19 +68,13 @@ std::set<LLImageGL*> LLImageGL::sImageList;
//****************************************************************************************************
//-----------------------
//debug use
-BOOL gAuditTexture = FALSE ;
-#define MAX_TEXTURE_LOG_SIZE 22 //2048 * 2048
-std::vector<S32> LLImageGL::sTextureLoadedCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
-std::vector<S32> LLImageGL::sTextureBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
-std::vector<S32> LLImageGL::sTextureCurBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
S32 LLImageGL::sCurTexSizeBar = -1 ;
S32 LLImageGL::sCurTexPickSize = -1 ;
-LLPointer<LLImageGL> LLImageGL::sHighlightTexturep = NULL;
-S32 LLImageGL::sMaxCatagories = 1 ;
+S32 LLImageGL::sMaxCategories = 1 ;
+
+//optimization for when we don't need to calculate mIsMask
+BOOL LLImageGL::sSkipAnalyzeAlpha;
-std::vector<S32> LLImageGL::sTextureMemByCategory;
-std::vector<S32> LLImageGL::sTextureMemByCategoryBound ;
-std::vector<S32> LLImageGL::sTextureCurMemByCategoryBound ;
//------------------------
//****************************************************************************************************
//End for texture auditing use only
@@ -173,51 +170,14 @@ BOOL is_little_endian()
return (*c == 0x78) ;
}
//static
-void LLImageGL::initClass(S32 num_catagories)
+void LLImageGL::initClass(S32 num_catagories, BOOL skip_analyze_alpha /* = false */)
{
- sMaxCatagories = num_catagories ;
-
- sTextureMemByCategory.resize(sMaxCatagories);
- sTextureMemByCategoryBound.resize(sMaxCatagories) ;
- sTextureCurMemByCategoryBound.resize(sMaxCatagories) ;
+ sSkipAnalyzeAlpha = skip_analyze_alpha;
}
//static
void LLImageGL::cleanupClass()
{
- sTextureMemByCategory.clear() ;
- sTextureMemByCategoryBound.clear() ;
- sTextureCurMemByCategoryBound.clear() ;
-}
-
-//static
-void LLImageGL::setHighlightTexture(S32 category)
-{
- const S32 dim = 128;
- sHighlightTexturep = new LLImageGL() ;
- LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3);
- U8* data = image_raw->getData();
- for (S32 i = 0; i<dim; i++)
- {
- for (S32 j = 0; j<dim; j++)
- {
- const S32 border = 2;
- if (i<border || j<border || i>=(dim-border) || j>=(dim-border))
- {
- *data++ = 0xff;
- *data++ = 0xff;
- *data++ = 0xff;
- }
- else
- {
- *data++ = 0xff;
- *data++ = 0xff;
- *data++ = 0x00;
- }
- }
- }
- sHighlightTexturep->createGLTexture(0, image_raw, 0, TRUE, category);
- image_raw = NULL;
}
//static
@@ -279,37 +239,19 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
//----------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_STATS("Image Stats");
// static
void LLImageGL::updateStats(F32 current_time)
{
+ LLFastTimer t(FTM_IMAGE_UPDATE_STATS);
sLastFrameTime = current_time;
sBoundTextureMemoryInBytes = sCurBoundTextureMemory;
sCurBoundTextureMemory = 0;
-
- if(gAuditTexture)
- {
- for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++)
- {
- sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ;
- sTextureCurBoundCounter[i] = 0 ;
- }
- for(U32 i = 0 ; i < sTextureCurMemByCategoryBound.size() ; i++)
- {
- sTextureMemByCategoryBound[i] = sTextureCurMemByCategoryBound[i] ;
- sTextureCurMemByCategoryBound[i] = 0 ;
- }
- }
}
//static
S32 LLImageGL::updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category)
{
- if(gAuditTexture && ncomponents > 0 && category > -1)
- {
- sTextureCurBoundCounter[getTextureCounterIndex(mem / ncomponents)]++ ;
- sTextureCurMemByCategoryBound[category] += mem ;
- }
-
LLImageGL::sCurBoundTextureMemory += mem ;
return LLImageGL::sCurBoundTextureMemory;
}
@@ -477,10 +419,13 @@ void LLImageGL::init(BOOL usemipmaps)
mDiscardLevelInAtlas = -1 ;
mTexelsInAtlas = 0 ;
mTexelsInGLTexture = 0 ;
+
+ mAllowCompression = true;
mTarget = GL_TEXTURE_2D;
mBindTarget = LLTexUnit::TT_TEXTURE;
mHasMipMaps = false;
+ mMipLevels = -1;
mIsResident = 0;
@@ -535,7 +480,7 @@ bool LLImageGL::checkSize(S32 width, S32 height)
return check_power_of_two(width) && check_power_of_two(height);
}
-void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents)
+void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level)
{
if (width != mWidth || height != mHeight || ncomponents != mComponents)
{
@@ -568,6 +513,11 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents)
width >>= 1;
height >>= 1;
}
+
+ if(discard_level > 0)
+ {
+ mMaxDiscardLevel = llmax(mMaxDiscardLevel, (S8)discard_level);
+ }
}
else
{
@@ -663,16 +613,34 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)
setImage(rawdata, FALSE);
}
+static LLFastTimer::DeclareTimer FTM_SET_IMAGE("setImage");
void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
{
+ LLFastTimer t(FTM_SET_IMAGE);
bool is_compressed = false;
if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
{
is_compressed = true;
}
-
+
+
+
+ if (mUseMipMaps)
+ {
+ //set has mip maps to true before binding image so tex parameters get set properly
+ gGL.getTexUnit(0)->unbind(mBindTarget);
+ mHasMipMaps = true;
+ mTexOptionsDirty = true;
+ setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
+ }
+ else
+ {
+ mHasMipMaps = false;
+ }
+
llverify(gGL.getTexUnit(0)->bind(this));
+
if (mUseMipMaps)
{
if (data_hasmips)
@@ -685,6 +653,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
S32 w = getWidth(d);
S32 h = getHeight(d);
S32 gl_level = d-mCurrentDiscardLevel;
+
+ mMipLevels = llmax(mMipLevels, gl_level);
+
if (d > mCurrentDiscardLevel)
{
data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment
@@ -705,7 +676,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
stop_glerror();
}
- LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in);
+ LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in, mAllowCompression);
if (gl_level == 0)
{
analyzeAlpha(data_in, w, h);
@@ -727,10 +698,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
{
if (mAutoGenMips)
{
- if (!gGLManager.mHasFramebufferObject)
- {
- glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
- }
stop_glerror();
{
// LLFastTimer t2(FTM_TEMP4);
@@ -744,10 +711,20 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
S32 w = getWidth(mCurrentDiscardLevel);
S32 h = getHeight(mCurrentDiscardLevel);
+ mMipLevels = wpo2(llmax(w, h));
+
+ //use legacy mipmap generation mode (note: making this condional can cause rendering issues)
+ // -- but making it not conditional triggers deprecation warnings when core profile is enabled
+ // (some rendering issues while core profile is enabled are acceptable at this point in time)
+ if (!LLRender::sGLCoreProfile)
+ {
+ glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE);
+ }
+
LLImageGL::setManualImage(mTarget, 0, mFormatInternal,
w, h,
mFormatPrimary, mFormatType,
- data_in);
+ data_in, mAllowCompression);
analyzeAlpha(data_in, w, h);
stop_glerror();
@@ -758,45 +735,67 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
stop_glerror();
}
- }
- if (gGLManager.mHasFramebufferObject)
- {
- glGenerateMipmap(LLTexUnit::getInternalType(mBindTarget));
+ if (LLRender::sGLCoreProfile)
+ {
+ glGenerateMipmap(mTarget);
+ }
+ stop_glerror();
}
}
else
{
// Create mips by hand
- // about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800
// ~4x faster than gluBuild2DMipmaps
S32 width = getWidth(mCurrentDiscardLevel);
S32 height = getHeight(mCurrentDiscardLevel);
S32 nummips = mMaxDiscardLevel - mCurrentDiscardLevel + 1;
S32 w = width, h = height;
+
+
+ const U8* new_data = 0;
+ (void)new_data;
+
const U8* prev_mip_data = 0;
const U8* cur_mip_data = 0;
- S32 prev_mip_size = 0;
+#ifdef SHOW_ASSERT
S32 cur_mip_size = 0;
+#endif
+ mMipLevels = nummips;
+
for (int m=0; m<nummips; m++)
{
if (m==0)
{
cur_mip_data = data_in;
+#ifdef SHOW_ASSERT
cur_mip_size = width * height * mComponents;
+#endif
}
else
{
S32 bytes = w * h * mComponents;
+#ifdef SHOW_ASSERT
llassert(prev_mip_data);
- llassert(prev_mip_size == bytes*4);
+ llassert(cur_mip_size == bytes*4);
+#endif
U8* new_data = new U8[bytes];
+
+#ifdef SHOW_ASSERT
+ llassert(prev_mip_data);
+ llassert(cur_mip_size == bytes*4);
llassert_always(new_data);
+#endif
+
LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents);
cur_mip_data = new_data;
+#ifdef SHOW_ASSERT
cur_mip_size = bytes;
+#endif
+
}
llassert(w > 0 && h > 0 && cur_mip_data);
+ (void)cur_mip_data;
{
// LLFastTimer t1(FTM_TEMP4);
if(mFormatSwapBytes)
@@ -805,7 +804,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
stop_glerror();
}
- LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data);
+ LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data, mAllowCompression);
if (m == 0)
{
analyzeAlpha(data_in, w, h);
@@ -827,7 +826,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
delete[] prev_mip_data;
}
prev_mip_data = cur_mip_data;
- prev_mip_size = cur_mip_size;
w >>= 1;
h >>= 1;
}
@@ -842,10 +840,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
{
llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl;
}
- mHasMipMaps = true;
}
else
{
+ mMipLevels = 0;
S32 w = getWidth();
S32 h = getHeight();
if (is_compressed)
@@ -863,7 +861,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
}
LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h,
- mFormatPrimary, mFormatType, (GLvoid *)data_in);
+ mFormatPrimary, mFormatType, (GLvoid *)data_in, mAllowCompression);
analyzeAlpha(data_in, w, h);
updatePickMask(w, h, data_in);
@@ -877,7 +875,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
}
}
- mHasMipMaps = false;
}
stop_glerror();
mGLTextureCreated = true;
@@ -901,14 +898,13 @@ BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
llassert(mCurrentDiscardLevel >= 0);
discard_level = mCurrentDiscardLevel;
}
- discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
-
+
// 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
- setSize(w, h, raw_image->getComponents());
+ setSize(w, h, raw_image->getComponents(), discard_level);
if( !mHasExplicitFormat )
{
@@ -1090,28 +1086,27 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
}
// static
+static LLFastTimer::DeclareTimer FTM_GENERATE_TEXTURES("generate textures");
void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
{
- glGenTextures(numTextures, (GLuint*)textures);
+ LLFastTimer t(FTM_GENERATE_TEXTURES);
+ glGenTextures(numTextures, textures);
}
// static
-void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate)
+void LLImageGL::deleteTextures(S32 numTextures, U32 *textures)
{
- for (S32 i = 0; i < numTextures; i++)
+ if (gGLManager.mInited)
{
- sDeadTextureList.push_back(textures[i]);
- }
-
- if (immediate)
- {
- LLImageGL::deleteDeadTextures();
+ glDeleteTextures(numTextures, textures);
}
}
// static
-void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels)
+static LLFastTimer::DeclareTimer FTM_SET_MANUAL_IMAGE("setManualImage");
+void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression)
{
+ LLFastTimer t(FTM_SET_MANUAL_IMAGE);
bool use_scratch = false;
U32* scratch = NULL;
if (LLRender::sGLCoreProfile)
@@ -1173,6 +1168,36 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
}
}
+ if (LLImageGL::sCompressTextures && allow_compression)
+ {
+ switch (intformat)
+ {
+ case GL_RGB:
+ case GL_RGB8:
+ intformat = GL_COMPRESSED_RGB;
+ break;
+ case GL_RGBA:
+ case GL_RGBA8:
+ intformat = GL_COMPRESSED_RGBA;
+ break;
+ case GL_LUMINANCE:
+ case GL_LUMINANCE8:
+ intformat = GL_COMPRESSED_LUMINANCE;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ case GL_LUMINANCE8_ALPHA8:
+ intformat = GL_COMPRESSED_LUMINANCE_ALPHA;
+ break;
+ case GL_ALPHA:
+ case GL_ALPHA8:
+ intformat = GL_COMPRESSED_ALPHA;
+ break;
+ default:
+ llwarns << "Could not compress format: " << std::hex << intformat << llendl;
+ break;
+ }
+ }
+
stop_glerror();
glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
stop_glerror();
@@ -1185,9 +1210,10 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
//create an empty GL texture: just create a texture name
//the texture is assiciate with some image by calling glTexImage outside LLImageGL
+static LLFastTimer::DeclareTimer FTM_CREATE_GL_TEXTURE1("createGLTexture()");
BOOL LLImageGL::createGLTexture()
{
- if (gHeadlessClient) return FALSE;
+ LLFastTimer t(FTM_CREATE_GL_TEXTURE1);
if (gGLManager.mIsDisabled)
{
llwarns << "Trying to create a texture while GL is disabled!" << llendl;
@@ -1201,10 +1227,11 @@ BOOL LLImageGL::createGLTexture()
if(mTexName)
{
- glDeleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ;
+ LLImageGL::deleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ;
}
- glGenTextures(1, (GLuint*)&mTexName);
+
+ LLImageGL::generateTextures(1, &mTexName);
stop_glerror();
if (!mTexName)
{
@@ -1214,9 +1241,10 @@ BOOL LLImageGL::createGLTexture()
return TRUE ;
}
+static LLFastTimer::DeclareTimer FTM_CREATE_GL_TEXTURE2("createGLTexture(raw)");
BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
{
- if (gHeadlessClient) return FALSE;
+ LLFastTimer t(FTM_CREATE_GL_TEXTURE2);
if (gGLManager.mIsDisabled)
{
llwarns << "Trying to create a texture while GL is disabled!" << llendl;
@@ -1232,8 +1260,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
llassert(mCurrentDiscardLevel >= 0);
discard_level = mCurrentDiscardLevel;
}
- discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
-
+
// Actual image width/height = raw image width/height * 2^discard_level
S32 raw_w = imageraw->getWidth() ;
S32 raw_h = imageraw->getHeight() ;
@@ -1241,7 +1268,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
S32 h = raw_h << discard_level;
// setSize may call destroyGLTexture if the size does not match
- setSize(w, h, imageraw->getComponents());
+ setSize(w, h, imageraw->getComponents(), discard_level);
if( !mHasExplicitFormat )
{
@@ -1284,13 +1311,15 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
return TRUE ;
}
- setCategory(category) ;
+ setCategory(category);
const U8* rawdata = imageraw->getData();
return createGLTexture(discard_level, rawdata, FALSE, usename);
}
+static LLFastTimer::DeclareTimer FTM_CREATE_GL_TEXTURE3("createGLTexture3(data)");
BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
{
+ LLFastTimer t(FTM_CREATE_GL_TEXTURE3);
llassert(data_in);
stop_glerror();
@@ -1362,11 +1391,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
{
sGlobalTextureMemoryInBytes -= mTextureMemory;
- if(gAuditTexture)
- {
- decTextureCounter(mTextureMemory, mComponents, mCategory) ;
- }
-
LLImageGL::deleteTextures(1, &old_name);
stop_glerror();
@@ -1376,10 +1400,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
sGlobalTextureMemoryInBytes += mTextureMemory;
mTexelsInGLTexture = getWidth() * getHeight() ;
- if(gAuditTexture)
- {
- incTextureCounter(mTextureMemory, mComponents, mCategory) ;
- }
// mark this as bound at this point, so we don't throw it out immediately
mLastBindTime = sLastFrameTime;
return TRUE;
@@ -1500,30 +1520,6 @@ void LLImageGL::deleteDeadTextures()
{
bool reset = false;
- while (!sDeadTextureList.empty())
- {
- GLuint tex = sDeadTextureList.front();
- sDeadTextureList.pop_front();
- for (int i = 0; i < gGLManager.mNumTextureImageUnits; i++)
- {
- LLTexUnit* tex_unit = gGL.getTexUnit(i);
-
- if (tex_unit && tex_unit->getCurrTexture() == tex)
- {
- tex_unit->unbind(tex_unit->getCurrType());
- stop_glerror();
-
- if (i > 0)
- {
- reset = true;
- }
- }
- }
-
- glDeleteTextures(1, &tex);
- stop_glerror();
- }
-
if (reset)
{
gGL.getTexUnit(0)->activate();
@@ -1536,22 +1532,29 @@ void LLImageGL::destroyGLTexture()
{
if(mTextureMemory)
{
- if(gAuditTexture)
- {
- decTextureCounter(mTextureMemory, mComponents, mCategory) ;
- }
sGlobalTextureMemoryInBytes -= mTextureMemory;
mTextureMemory = 0;
}
LLImageGL::deleteTextures(1, &mTexName);
- mTexName = 0;
mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
+ mTexName = 0;
mGLTextureCreated = FALSE ;
- }
+ }
}
-
+//force to invalidate the gl texture, most likely a sculpty texture
+void LLImageGL::forceToInvalidateGLTexture()
+{
+ if (mTexName != 0)
+ {
+ destroyGLTexture();
+ }
+ else
+ {
+ mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
+ }
+}
//----------------------------------------------------------------------------
@@ -1669,6 +1672,12 @@ BOOL LLImageGL::getBoundRecently() const
return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME);
}
+BOOL LLImageGL::getIsAlphaMask() const
+{
+ llassert_always(!sSkipAnalyzeAlpha);
+ return mIsMask;
+}
+
void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target)
{
mTarget = target;
@@ -1766,7 +1775,7 @@ void LLImageGL::calcAlphaChannelOffsetAndStride()
void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
{
- if(!mNeedsAlphaAndPickMask)
+ if(sSkipAnalyzeAlpha || !mNeedsAlphaAndPickMask)
{
return ;
}
@@ -1969,70 +1978,6 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
return res;
}
-void LLImageGL::setCategory(S32 category)
-{
-#if 0 //turn this off temporarily because it is not in use now.
- if(!gAuditTexture)
- {
- return ;
- }
- if(mCategory != category)
- {
- if(mCategory > -1)
- {
- sTextureMemByCategory[mCategory] -= mTextureMemory ;
- }
- if(category > -1 && category < sMaxCatagories)
- {
- sTextureMemByCategory[category] += mTextureMemory ;
- mCategory = category;
- }
- else
- {
- mCategory = -1 ;
- }
- }
-#endif
-}
-
-//for debug use
-//val is a "power of two" number
-S32 LLImageGL::getTextureCounterIndex(U32 val)
-{
- //index range is [0, MAX_TEXTURE_LOG_SIZE].
- if(val < 2)
- {
- return 0 ;
- }
- else if(val >= (1 << MAX_TEXTURE_LOG_SIZE))
- {
- return MAX_TEXTURE_LOG_SIZE ;
- }
- else
- {
- S32 ret = 0 ;
- while(val >>= 1)
- {
- ++ret;
- }
- return ret ;
- }
-}
-
-//static
-void LLImageGL::incTextureCounter(U32 val, S32 ncomponents, S32 category)
-{
- sTextureLoadedCounter[getTextureCounterIndex(val)]++ ;
- sTextureMemByCategory[category] += (S32)val * ncomponents ;
-}
-
-//static
-void LLImageGL::decTextureCounter(U32 val, S32 ncomponents, S32 category)
-{
- sTextureLoadedCounter[getTextureCounterIndex(val)]-- ;
- sTextureMemByCategory[category] += (S32)val * ncomponents ;
-}
-
void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size)
{
sCurTexSizeBar = index ;
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 2cfb15b0d9..0c62dd0d33 100644..100755
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -45,8 +45,9 @@ class LLImageGL : public LLRefCount
{
friend class LLTexUnit;
public:
- static std::list<U32> sDeadTextureList;
-
+ // These 2 functions replace glGenTextures() and glDeleteTextures()
+ static void generateTextures(S32 numTextures, U32 *textures);
+ static void deleteTextures(S32 numTextures, U32 *textures);
static void deleteDeadTextures();
// Size calculation
@@ -92,18 +93,15 @@ protected:
public:
virtual void dump(); // debugging info to llinfos
- void setSize(S32 width, S32 height, S32 ncomponents);
+ void setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level = -1);
void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;}
+ void setAllowCompression(bool allow) { mAllowCompression = allow; }
- // These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D()
- // for tracking purposes and will be deprecated in the future
- static void generateTextures(S32 numTextures, U32 *textures);
- static void deleteTextures(S32 numTextures, U32 *textures, bool immediate = false);
- static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels);
+ static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true);
BOOL createGLTexture() ;
- BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE,
- S32 category = sMaxCatagories - 1);
+ BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE,
+ S32 category = sMaxCategories-1);
BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0);
void setImage(const LLImageRaw* imageraw);
void setImage(const U8* data_in, BOOL data_hasmips = FALSE);
@@ -114,6 +112,7 @@ public:
// Read back a raw image for this discard level, if it exists
BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const;
void destroyGLTexture();
+ void forceToInvalidateGLTexture();
void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
void setComponents(S8 ncomponents) { mComponents = ncomponents; }
@@ -136,7 +135,7 @@ public:
BOOL getHasGLTexture() const { return mTexName != 0; }
LLGLuint getTexName() const { return mTexName; }
- BOOL getIsAlphaMask() const { return mIsMask; }
+ BOOL getIsAlphaMask() const;
BOOL getIsResident(BOOL test_now = FALSE); // not const
@@ -209,11 +208,14 @@ private:
U32 mTexelsInAtlas ;
U32 mTexelsInGLTexture;
+ bool mAllowCompression;
+
protected:
LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps)
LLTexUnit::eTextureType mBindTarget; // Normally TT_TEXTURE, sometimes something else (ex. cube maps)
bool mHasMipMaps;
-
+ S32 mMipLevels;
+
LLGLboolean mIsResident;
S8 mComponents;
@@ -234,8 +236,6 @@ public:
static S32 sCount;
static F32 sLastFrameTime;
-
- static LLGLuint sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS]; // Currently bound texture ID
// Global memory statistics
static S32 sGlobalTextureMemoryInBytes; // Tracks main memory texmem
@@ -246,7 +246,7 @@ public:
static BOOL sGlobalUseAnisotropic;
static LLImageGL* sDefaultGLTexture ;
static BOOL sAutomatedTest;
-
+ static bool sCompressTextures; //use GL texture compression
#if DEBUG_MISS
BOOL mMissed; // Missed on last bind?
BOOL getMissed() const { return mMissed; };
@@ -255,11 +255,13 @@ public:
#endif
public:
- static void initClass(S32 num_catagories) ;
+ static void initClass(S32 num_catagories, BOOL skip_analyze_alpha = false);
static void cleanupClass() ;
-private:
- static S32 sMaxCatagories ;
+private:
+ static S32 sMaxCategories;
+ static BOOL sSkipAnalyzeAlpha;
+
//the flag to allow to call readBackRaw(...).
//can be removed if we do not use that function at all.
static BOOL sAllowReadBackRaw ;
@@ -269,39 +271,22 @@ private:
//****************************************************************************************************
private:
S32 mCategory ;
-public:
- void setCategory(S32 category) ;
- S32 getCategory()const {return mCategory ;}
-
+public:
+ void setCategory(S32 category) {mCategory = category;}
+ S32 getCategory()const {return mCategory;}
+
//for debug use: show texture size distribution
//----------------------------------------
- static LLPointer<LLImageGL> sHighlightTexturep; //default texture to replace normal textures
- static std::vector<S32> sTextureLoadedCounter ;
- static std::vector<S32> sTextureBoundCounter ;
- static std::vector<S32> sTextureCurBoundCounter ;
static S32 sCurTexSizeBar ;
static S32 sCurTexPickSize ;
- static void setHighlightTexture(S32 category) ;
- static S32 getTextureCounterIndex(U32 val) ;
- static void incTextureCounter(U32 val, S32 ncomponents, S32 category) ;
- static void decTextureCounter(U32 val, S32 ncomponents, S32 category) ;
static void setCurTexSizebar(S32 index, BOOL set_pick_size = TRUE) ;
static void resetCurTexSizebar();
- //----------------------------------------
- //for debug use: show texture category distribution
- //----------------------------------------
-
- static std::vector<S32> sTextureMemByCategory;
- static std::vector<S32> sTextureMemByCategoryBound ;
- static std::vector<S32> sTextureCurMemByCategoryBound ;
- //----------------------------------------
//****************************************************************************************************
//End of definitions for texture auditing use only
//****************************************************************************************************
};
-extern BOOL gAuditTexture;
#endif // LL_LLIMAGEGL_H
diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp
index c0045c8044..4c36185b08 100644..100755
--- a/indra/llrender/llpostprocess.cpp
+++ b/indra/llrender/llpostprocess.cpp
@@ -31,6 +31,21 @@
#include "llsdserialize.h"
#include "llrender.h"
+static LLStaticHashedString sRenderTexture("RenderTexture");
+static LLStaticHashedString sBrightness("brightness");
+static LLStaticHashedString sContrast("contrast");
+static LLStaticHashedString sContrastBase("contrastBase");
+static LLStaticHashedString sSaturation("saturation");
+static LLStaticHashedString sLumWeights("lumWeights");
+static LLStaticHashedString sNoiseTexture("NoiseTexture");
+static LLStaticHashedString sBrightMult("brightMult");
+static LLStaticHashedString sNoiseStrength("noiseStrength");
+static LLStaticHashedString sExtractLow("extractLow");
+static LLStaticHashedString sExtractHigh("extractHigh");
+static LLStaticHashedString sBloomStrength("bloomStrength");
+static LLStaticHashedString sTexelSize("texelSize");
+static LLStaticHashedString sBlurDirection("blurDirection");
+static LLStaticHashedString sBlurWidth("blurWidth");
LLPostProcess * gPostProcess = NULL;
@@ -258,12 +273,12 @@ void LLPostProcess::applyColorFilterShader(void)
void LLPostProcess::createColorFilterShader(void)
{
/// Define uniform names
- colorFilterUniforms["RenderTexture"] = 0;
- colorFilterUniforms["brightness"] = 0;
- colorFilterUniforms["contrast"] = 0;
- colorFilterUniforms["contrastBase"] = 0;
- colorFilterUniforms["saturation"] = 0;
- colorFilterUniforms["lumWeights"] = 0;
+ colorFilterUniforms[sRenderTexture] = 0;
+ colorFilterUniforms[sBrightness] = 0;
+ colorFilterUniforms[sContrast] = 0;
+ colorFilterUniforms[sContrastBase] = 0;
+ colorFilterUniforms[sSaturation] = 0;
+ colorFilterUniforms[sLumWeights] = 0;
}
void LLPostProcess::applyNightVisionShader(void)
@@ -307,11 +322,11 @@ void LLPostProcess::applyNightVisionShader(void)
void LLPostProcess::createNightVisionShader(void)
{
/// Define uniform names
- nightVisionUniforms["RenderTexture"] = 0;
- nightVisionUniforms["NoiseTexture"] = 0;
- nightVisionUniforms["brightMult"] = 0;
- nightVisionUniforms["noiseStrength"] = 0;
- nightVisionUniforms["lumWeights"] = 0;
+ nightVisionUniforms[sRenderTexture] = 0;
+ nightVisionUniforms[sNoiseTexture] = 0;
+ nightVisionUniforms[sBrightMult] = 0;
+ nightVisionUniforms[sNoiseStrength] = 0;
+ nightVisionUniforms[sLumWeights] = 0;
createNoiseTexture(mNoiseTexture);
}
@@ -326,25 +341,25 @@ void LLPostProcess::createBloomShader(void)
createTexture(mTempBloomTexture, unsigned(screenW * 0.5), unsigned(screenH * 0.5));
/// Create Bloom Extract Shader
- bloomExtractUniforms["RenderTexture"] = 0;
- bloomExtractUniforms["extractLow"] = 0;
- bloomExtractUniforms["extractHigh"] = 0;
- bloomExtractUniforms["lumWeights"] = 0;
+ bloomExtractUniforms[sRenderTexture] = 0;
+ bloomExtractUniforms[sExtractLow] = 0;
+ bloomExtractUniforms[sExtractHigh] = 0;
+ bloomExtractUniforms[sLumWeights] = 0;
/// Create Bloom Blur Shader
- bloomBlurUniforms["RenderTexture"] = 0;
- bloomBlurUniforms["bloomStrength"] = 0;
- bloomBlurUniforms["texelSize"] = 0;
- bloomBlurUniforms["blurDirection"] = 0;
- bloomBlurUniforms["blurWidth"] = 0;
+ bloomBlurUniforms[sRenderTexture] = 0;
+ bloomBlurUniforms[sBloomStrength] = 0;
+ bloomBlurUniforms[sTexelSize] = 0;
+ bloomBlurUniforms[sBlurDirection] = 0;
+ bloomBlurUniforms[sBlurWidth] = 0;
}
void LLPostProcess::getShaderUniforms(glslUniforms & uniforms, GLhandleARB & prog)
{
/// Find uniform locations and insert into map
- std::map<const char *, GLuint>::iterator i;
+ glslUniforms::iterator i;
for (i = uniforms.begin(); i != uniforms.end(); ++i){
- i->second = glGetUniformLocationARB(prog, i->first);
+ i->second = glGetUniformLocationARB(prog, i->first.String().c_str());
}
}
diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h
index e19de44c60..ce17b6693d 100644..100755
--- a/indra/llrender/llpostprocess.h
+++ b/indra/llrender/llpostprocess.h
@@ -31,6 +31,7 @@
#include <fstream>
#include "llgl.h"
#include "llglheaders.h"
+#include "llstaticstringtable.h"
class LLPostProcess
{
@@ -44,7 +45,7 @@ public:
} QuadType;
/// GLSL Shader Encapsulation Struct
- typedef std::map<const char *, GLuint> glslUniforms;
+ typedef LLStaticStringTable<GLuint> glslUniforms;
struct PostProcessTweaks : public LLSD {
inline PostProcessTweaks() : LLSD(LLSD::emptyMap())
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index b0ddacbb05..0ac30b4d63 100644..100755
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -225,35 +225,16 @@ void LLTexUnit::disable(void)
bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
{
stop_glerror();
- if (mIndex < 0) return false;
-
+ if (mIndex >= 0)
+ {
gGL.flush();
LLImageGL* gl_tex = NULL ;
- if (texture == NULL || !(gl_tex = texture->getGLTexture()))
+ if (texture != NULL && (gl_tex = texture->getGLTexture()))
{
- llwarns << "NULL LLTexUnit::bind texture" << llendl;
- return false;
- }
-
- if (!gl_tex->getTexName()) //if texture does not exist
+ if (gl_tex->getTexName()) //if texture exists
{
- //if deleted, will re-generate it immediately
- texture->forceImmediateUpdate() ;
-
- gl_tex->forceUpdateBindStats() ;
- return texture->bindDefaultImage(mIndex);
- }
-
//in audit, replace the selected texture by the default one.
- if(gAuditTexture && for_rendering && LLImageGL::sCurTexPickSize > 0)
- {
- if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize)
- {
- gl_tex->updateBindStats(gl_tex->mTextureMemory);
- return bind(LLImageGL::sHighlightTexturep.get());
- }
- }
if ((mCurrTexture != gl_tex->getTexName()) || forceBind)
{
activate();
@@ -273,6 +254,27 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
setTextureFilteringOption(gl_tex->mFilterOption);
}
}
+ }
+ else
+ {
+ //if deleted, will re-generate it immediately
+ texture->forceImmediateUpdate() ;
+
+ gl_tex->forceUpdateBindStats() ;
+ return texture->bindDefaultImage(mIndex);
+ }
+ }
+ else
+ {
+ llwarns << "NULL LLTexUnit::bind texture" << llendl;
+ return false;
+ }
+ }
+ else
+ { // mIndex < 0
+ return false;
+ }
+
return true;
}
@@ -365,7 +367,6 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap)
}
// LLRenderTarget is unavailible on the mapserver since it uses FBOs.
-#if !LL_MESA_HEADLESS
bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
{
if (mIndex < 0) return false;
@@ -388,7 +389,6 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
return true;
}
-#endif // LL_MESA_HEADLESS
bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips)
{
@@ -416,12 +416,14 @@ void LLTexUnit::unbind(eTextureType type)
if (mIndex < 0) return;
+ //always flush and activate for consistency
+ // some code paths assume unbind always flushes and sets the active texture
+ gGL.flush();
+ activate();
+
// Disabled caching of binding state.
if (mCurrTexType == type)
{
- gGL.flush();
-
- activate();
mCurrTexture = 0;
if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE)
{
@@ -472,11 +474,25 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
}
else if (option >= TFO_BILINEAR)
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ if (mHasMipMaps)
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ }
+ else
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
}
else
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ if (mHasMipMaps)
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ }
+ else
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
}
if (gGLManager.mHasAnisotropic)
@@ -640,7 +656,7 @@ void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eT
gGL.flush();
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
}
-
+
// We want an early out, because this function does a LOT of stuff.
if ( ( (isAlpha && (mCurrAlphaOp == op) && (mCurrAlphaSrc1 == src1) && (mCurrAlphaSrc2 == src2))
|| (!isAlpha && (mCurrColorOp == op) && (mCurrColorSrc1 == src1) && (mCurrColorSrc2 == src2)) ) && !gGL.mDirty)
@@ -1052,6 +1068,16 @@ LLRender::~LLRender()
void LLRender::init()
{
+ if (sGLCoreProfile && !LLVertexBuffer::sUseVAO)
+ { //bind a dummy vertex array object so we're core profile compliant
+#ifdef GL_ARB_vertex_array_object
+ U32 ret;
+ glGenVertexArrays(1, &ret);
+ glBindVertexArray(ret);
+#endif
+ }
+
+
llassert_always(mBuffer.isNull()) ;
stop_glerror();
mBuffer = new LLVertexBuffer(immediate_mask, 0);
@@ -1429,6 +1455,17 @@ void LLRender::matrixMode(U32 mode)
mMatrixMode = mode;
}
+U32 LLRender::getMatrixMode()
+{
+ if (mMatrixMode >= MM_TEXTURE0 && mMatrixMode <= MM_TEXTURE3)
+ { //always return MM_TEXTURE if current matrix mode points at any texture matrix
+ return MM_TEXTURE;
+ }
+
+ return mMatrixMode;
+}
+
+
void LLRender::loadIdentity()
{
flush();
@@ -1832,13 +1869,15 @@ void LLRender::flush()
sUIVerts += mCount;
}
- if (gDebugGL)
- {
+ //store mCount in a local variable to avoid re-entrance (drawArrays may call flush)
+ U32 count = mCount;
+
if (mMode == LLRender::QUADS && !sGLCoreProfile)
{
if (mCount%4 != 0)
{
- llerrs << "Incomplete quad rendered." << llendl;
+ count -= (mCount % 4);
+ llwarns << "Incomplete quad requested." << llendl;
}
}
@@ -1846,7 +1885,8 @@ void LLRender::flush()
{
if (mCount%3 != 0)
{
- llerrs << "Incomplete triangle rendered." << llendl;
+ count -= (mCount % 3);
+ llwarns << "Incomplete triangle requested." << llendl;
}
}
@@ -1854,13 +1894,11 @@ void LLRender::flush()
{
if (mCount%2 != 0)
{
- llerrs << "Incomplete line rendered." << llendl;
- }
+ count -= (mCount % 2);
+ llwarns << "Incomplete line requested." << llendl;
}
}
- //store mCount in a local variable to avoid re-entrance (drawArrays may call flush)
- U32 count = mCount;
mCount = 0;
if (mBuffer->useVBOs() && !mBuffer->isLocked())
@@ -2263,6 +2301,22 @@ void LLRender::diffuseColor4ubv(const U8* c)
}
}
+void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r/255.f, g/255.f, b/255.f, a/255.f);
+ }
+ else
+ {
+ glColor4ub(r,g,b,a);
+ }
+}
+
+
void LLRender::debugTexUnits(void)
{
LL_INFOS("TextureUnit") << "Active TexUnit: " << mCurrTextureUnitIndex << LL_ENDL;
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index fa5f7f311d..42b02a8159 100644..100755
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -262,6 +262,14 @@ class LLRender
friend class LLTexUnit;
public:
+ enum eTexIndex
+ {
+ DIFFUSE_MAP = 0,
+ NORMAL_MAP,
+ SPECULAR_MAP,
+ NUM_TEXTURE_CHANNELS,
+ };
+
typedef enum {
TRIANGLES = 0,
TRIANGLE_STRIP,
@@ -346,6 +354,7 @@ public:
void loadIdentity();
void multMatrix(const GLfloat* m);
void matrixMode(U32 mode);
+ U32 getMatrixMode();
const glh::matrix4f& getModelviewMatrix();
const glh::matrix4f& getProjectionMatrix();
@@ -387,6 +396,7 @@ public:
void diffuseColor4f(F32 r, F32 g, F32 b, F32 a);
void diffuseColor4fv(const F32* c);
void diffuseColor4ubv(const U8* c);
+ void diffuseColor4ub(U8 r, U8 g, U8 b, U8 a);
void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count);
diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp
new file mode 100644
index 0000000000..d3cfbaf03a
--- /dev/null
+++ b/indra/llrender/llrender2dutils.cpp
@@ -0,0 +1,1608 @@
+/**
+ * @file llrender2dutils.cpp
+ * @brief GL function implementations for immediate-mode gl drawing.
+ *
+ * $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$
+ */
+
+#include "linden_common.h"
+
+// Linden library includes
+#include "v2math.h"
+#include "m3math.h"
+#include "v4color.h"
+#include "llfontgl.h"
+#include "llrender.h"
+#include "llrect.h"
+#include "llgl.h"
+#include "lltexture.h"
+
+// Project includes
+#include "llrender2dutils.h"
+#include "lluiimage.h"
+
+
+//
+// Globals
+//
+const LLColor4 UI_VERTEX_COLOR(1.f, 1.f, 1.f, 1.f);
+/*static*/ LLVector2 LLRender2D::sGLScaleFactor(1.f, 1.f);
+/*static*/ LLImageProviderInterface* LLRender2D::sImageProvider = NULL;
+
+//
+// Functions
+//
+
+BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom)
+{
+ if (x < left || right < x) return FALSE;
+ if (y < bottom || top < y) return FALSE;
+ return TRUE;
+}
+
+
+// Puts GL into 2D drawing mode by turning off lighting, setting to an
+// orthographic projection, etc.
+void gl_state_for_2d(S32 width, S32 height)
+{
+ stop_glerror();
+ F32 window_width = (F32) width;//gViewerWindow->getWindowWidth();
+ F32 window_height = (F32) height;//gViewerWindow->getWindowHeight();
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.loadIdentity();
+ gGL.ortho(0.0f, llmax(window_width, 1.f), 0.0f, llmax(window_height,1.f), -1.0f, 1.0f);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.loadIdentity();
+ stop_glerror();
+}
+
+
+void gl_draw_x(const LLRect& rect, const LLColor4& color)
+{
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ gGL.color4fv( color.mV );
+
+ gGL.begin( LLRender::LINES );
+ gGL.vertex2i( rect.mLeft, rect.mTop );
+ gGL.vertex2i( rect.mRight, rect.mBottom );
+ gGL.vertex2i( rect.mLeft, rect.mBottom );
+ gGL.vertex2i( rect.mRight, rect.mTop );
+ gGL.end();
+}
+
+
+void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, S32 pixel_offset, BOOL filled)
+{
+ gGL.color4fv(color.mV);
+ gl_rect_2d_offset_local(left, top, right, bottom, pixel_offset, filled);
+}
+
+void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset, BOOL filled)
+{
+ gGL.pushUIMatrix();
+ left += LLFontGL::sCurOrigin.mX;
+ right += LLFontGL::sCurOrigin.mX;
+ bottom += LLFontGL::sCurOrigin.mY;
+ top += LLFontGL::sCurOrigin.mY;
+
+ gGL.loadUIIdentity();
+ gl_rect_2d(llfloor((F32)left * LLRender2D::sGLScaleFactor.mV[VX]) - pixel_offset,
+ llfloor((F32)top * LLRender2D::sGLScaleFactor.mV[VY]) + pixel_offset,
+ llfloor((F32)right * LLRender2D::sGLScaleFactor.mV[VX]) + pixel_offset,
+ llfloor((F32)bottom * LLRender2D::sGLScaleFactor.mV[VY]) - pixel_offset,
+ filled);
+ gGL.popUIMatrix();
+}
+
+
+void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled )
+{
+ stop_glerror();
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ // Counterclockwise quad will face the viewer
+ if( filled )
+ {
+ gGL.begin( LLRender::QUADS );
+ gGL.vertex2i(left, top);
+ gGL.vertex2i(left, bottom);
+ gGL.vertex2i(right, bottom);
+ gGL.vertex2i(right, top);
+ gGL.end();
+ }
+ else
+ {
+ if( gGLManager.mATIOffsetVerticalLines )
+ {
+ // Work around bug in ATI driver: vertical lines are offset by (-1,-1)
+ gGL.begin( LLRender::LINES );
+
+ // Verticals
+ gGL.vertex2i(left + 1, top);
+ gGL.vertex2i(left + 1, bottom);
+
+ gGL.vertex2i(right, bottom);
+ gGL.vertex2i(right, top);
+
+ // Horizontals
+ top--;
+ right--;
+ gGL.vertex2i(left, bottom);
+ gGL.vertex2i(right, bottom);
+
+ gGL.vertex2i(left, top);
+ gGL.vertex2i(right, top);
+ gGL.end();
+ }
+ else
+ {
+ top--;
+ right--;
+ gGL.begin( LLRender::LINE_STRIP );
+ gGL.vertex2i(left, top);
+ gGL.vertex2i(left, bottom);
+ gGL.vertex2i(right, bottom);
+ gGL.vertex2i(right, top);
+ gGL.vertex2i(left, top);
+ gGL.end();
+ }
+ }
+ stop_glerror();
+}
+
+void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, BOOL filled )
+{
+ gGL.color4fv( color.mV );
+ gl_rect_2d( left, top, right, bottom, filled );
+}
+
+
+void gl_rect_2d( const LLRect& rect, const LLColor4& color, BOOL filled )
+{
+ gGL.color4fv( color.mV );
+ gl_rect_2d( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, filled );
+}
+
+// Given a rectangle on the screen, draws a drop shadow _outside_
+// the right and bottom edges of it. Along the right it has width "lines"
+// and along the bottom it has height "lines".
+void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines)
+{
+ stop_glerror();
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ // HACK: Overlap with the rectangle by a single pixel.
+ right--;
+ bottom++;
+ lines++;
+
+ LLColor4 end_color = start_color;
+ end_color.mV[VALPHA] = 0.f;
+
+ gGL.begin(LLRender::QUADS);
+
+ // Right edge, CCW faces screen
+ gGL.color4fv(start_color.mV);
+ gGL.vertex2i(right, top-lines);
+ gGL.vertex2i(right, bottom);
+ gGL.color4fv(end_color.mV);
+ gGL.vertex2i(right+lines, bottom);
+ gGL.vertex2i(right+lines, top-lines);
+
+ // Bottom edge, CCW faces screen
+ gGL.color4fv(start_color.mV);
+ gGL.vertex2i(right, bottom);
+ gGL.vertex2i(left+lines, bottom);
+ gGL.color4fv(end_color.mV);
+ gGL.vertex2i(left+lines, bottom-lines);
+ gGL.vertex2i(right, bottom-lines);
+
+ // bottom left Corner
+ gGL.color4fv(start_color.mV);
+ gGL.vertex2i(left+lines, bottom);
+ gGL.color4fv(end_color.mV);
+ gGL.vertex2i(left, bottom);
+ // make the bottom left corner not sharp
+ gGL.vertex2i(left+1, bottom-lines+1);
+ gGL.vertex2i(left+lines, bottom-lines);
+
+ // bottom right corner
+ gGL.color4fv(start_color.mV);
+ gGL.vertex2i(right, bottom);
+ gGL.color4fv(end_color.mV);
+ gGL.vertex2i(right, bottom-lines);
+ // make the rightmost corner not sharp
+ gGL.vertex2i(right+lines-1, bottom-lines+1);
+ gGL.vertex2i(right+lines, bottom);
+
+ // top right corner
+ gGL.color4fv(start_color.mV);
+ gGL.vertex2i( right, top-lines );
+ gGL.color4fv(end_color.mV);
+ gGL.vertex2i( right+lines, top-lines );
+ // make the corner not sharp
+ gGL.vertex2i( right+lines-1, top-1 );
+ gGL.vertex2i( right, top );
+
+ gGL.end();
+ stop_glerror();
+}
+
+void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 )
+{
+ // Work around bug in ATI driver: vertical lines are offset by (-1,-1)
+ if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines )
+ {
+ x1++;
+ x2++;
+ y1++;
+ y2++;
+ }
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ gGL.begin(LLRender::LINES);
+ gGL.vertex2i(x1, y1);
+ gGL.vertex2i(x2, y2);
+ gGL.end();
+}
+
+void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color )
+{
+ // Work around bug in ATI driver: vertical lines are offset by (-1,-1)
+ if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines )
+ {
+ x1++;
+ x2++;
+ y1++;
+ y2++;
+ }
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ gGL.color4fv( color.mV );
+
+ gGL.begin(LLRender::LINES);
+ gGL.vertex2i(x1, y1);
+ gGL.vertex2i(x2, y2);
+ gGL.end();
+}
+
+void gl_triangle_2d(S32 x1, S32 y1, S32 x2, S32 y2, S32 x3, S32 y3, const LLColor4& color, BOOL filled)
+{
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ gGL.color4fv(color.mV);
+
+ if (filled)
+ {
+ gGL.begin(LLRender::TRIANGLES);
+ }
+ else
+ {
+ gGL.begin(LLRender::LINE_LOOP);
+ }
+ gGL.vertex2i(x1, y1);
+ gGL.vertex2i(x2, y2);
+ gGL.vertex2i(x3, y3);
+ gGL.end();
+}
+
+void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac)
+{
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ length = llmin((S32)(max_frac*(right - left)), length);
+ length = llmin((S32)(max_frac*(top - bottom)), length);
+ gGL.begin(LLRender::LINES);
+ gGL.vertex2i(left, top);
+ gGL.vertex2i(left + length, top);
+
+ gGL.vertex2i(left, top);
+ gGL.vertex2i(left, top - length);
+
+ gGL.vertex2i(left, bottom);
+ gGL.vertex2i(left + length, bottom);
+
+ gGL.vertex2i(left, bottom);
+ gGL.vertex2i(left, bottom + length);
+
+ gGL.vertex2i(right, top);
+ gGL.vertex2i(right - length, top);
+
+ gGL.vertex2i(right, top);
+ gGL.vertex2i(right, top - length);
+
+ gGL.vertex2i(right, bottom);
+ gGL.vertex2i(right - length, bottom);
+
+ gGL.vertex2i(right, bottom);
+ gGL.vertex2i(right, bottom + length);
+ gGL.end();
+}
+
+
+void gl_draw_image( S32 x, S32 y, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect )
+{
+ if (NULL == image)
+ {
+ llwarns << "image == NULL; aborting function" << llendl;
+ return;
+ }
+ gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color, uv_rect );
+}
+
+void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect)
+{
+ if (NULL == image)
+ {
+ llwarns << "image == NULL; aborting function" << llendl;
+ return;
+ }
+ gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color, uv_rect );
+}
+
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect)
+{
+ if (NULL == image)
+ {
+ llwarns << "image == NULL; aborting function" << llendl;
+ return;
+ }
+
+ // scale screen size of borders down
+ F32 border_width_fraction = (F32)border_width / (F32)image->getWidth(0);
+ F32 border_height_fraction = (F32)border_height / (F32)image->getHeight(0);
+
+ LLRectf scale_rect(border_width_fraction, 1.f - border_height_fraction, 1.f - border_width_fraction, border_height_fraction);
+ gl_draw_scaled_image_with_border(x, y, width, height, image, color, solid_color, uv_rect, scale_rect);
+}
+
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_outer_rect, const LLRectf& center_rect)
+{
+ stop_glerror();
+
+ if (NULL == image)
+ {
+ llwarns << "image == NULL; aborting function" << llendl;
+ return;
+ }
+
+ // 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);
+
+ F32 uv_width = uv_outer_rect.getWidth();
+ F32 uv_height = uv_outer_rect.getHeight();
+
+ // shrink scaling region to be proportional to clipped image region
+ LLRectf uv_center_rect(
+ uv_outer_rect.mLeft + (center_rect.mLeft * uv_width),
+ uv_outer_rect.mBottom + (center_rect.mTop * uv_height),
+ 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);
+
+ S32 image_natural_width = llround(image_width * uv_width);
+ S32 image_natural_height = llround(image_height * uv_height);
+
+ LLRectf draw_center_rect( uv_center_rect.mLeft * image_width,
+ uv_center_rect.mTop * image_height,
+ uv_center_rect.mRight * image_width,
+ uv_center_rect.mBottom * image_height);
+
+ { // scale fixed region of image to drawn region
+ draw_center_rect.mRight += width - image_natural_width;
+ draw_center_rect.mTop += height - image_natural_height;
+
+ F32 border_shrink_width = llmax(0.f, draw_center_rect.mLeft - draw_center_rect.mRight);
+ F32 border_shrink_height = llmax(0.f, draw_center_rect.mBottom - draw_center_rect.mTop);
+
+ F32 shrink_width_ratio = center_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - center_rect.getWidth()));
+ F32 shrink_height_ratio = center_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - center_rect.getHeight()));
+
+ F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio);
+
+ draw_center_rect.mLeft = llround(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * shrink_scale * ui_scale.mV[VX]);
+ draw_center_rect.mTop = llround(ui_translation.mV[VY] + lerp((F32)height, (F32)draw_center_rect.mTop, shrink_scale) * ui_scale.mV[VY]);
+ draw_center_rect.mRight = llround(ui_translation.mV[VX] + lerp((F32)width, (F32)draw_center_rect.mRight, shrink_scale) * ui_scale.mV[VX]);
+ draw_center_rect.mBottom = llround(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * shrink_scale * ui_scale.mV[VY]);
+ }
+
+ LLRectf draw_outer_rect(ui_translation.mV[VX],
+ ui_translation.mV[VY] + height * ui_scale.mV[VY],
+ ui_translation.mV[VX] + width * ui_scale.mV[VX],
+ ui_translation.mV[VY]);
+
+ LLGLSUIDefault gls_ui;
+
+ if (solid_color)
+ {
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gSolidColorProgram.bind();
+ }
+ else
+ {
+ gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
+ gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
+ }
+ }
+
+ gGL.getTexUnit(0)->bind(image, true);
+
+ gGL.color4fv(color.mV);
+
+ const S32 NUM_VERTICES = 9 * 4; // 9 quads
+ LLVector2 uv[NUM_VERTICES];
+ LLVector3 pos[NUM_VERTICES];
+
+ S32 index = 0;
+
+ gGL.begin(LLRender::QUADS);
+ {
+ // draw bottom left
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ // draw bottom middle
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ // draw bottom right
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ // draw left
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
+
+ // draw middle
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
+
+ // draw right
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
+
+ // draw top left
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f);
+ index++;
+
+ // draw top middle
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
+ index++;
+
+ // draw top right
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
+ index++;
+
+ gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
+ }
+ gGL.end();
+
+ if (solid_color)
+ {
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.bind();
+ }
+ else
+ {
+ gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+ }
+ }
+}
+
+void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect)
+{
+ gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color, uv_rect );
+}
+
+void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect)
+{
+ if (NULL == image)
+ {
+ llwarns << "image == NULL; aborting function" << llendl;
+ return;
+ }
+
+ LLGLSUIDefault gls_ui;
+
+
+ gGL.getTexUnit(0)->bind(image, true);
+
+ gGL.color4fv(color.mV);
+
+ if (degrees == 0.f)
+ {
+ const S32 NUM_VERTICES = 4; // 9 quads
+ LLVector2 uv[NUM_VERTICES];
+ LLVector3 pos[NUM_VERTICES];
+
+ gGL.begin(LLRender::QUADS);
+ {
+ LLVector3 ui_scale = gGL.getUIScale();
+ LLVector3 ui_translation = gGL.getUITranslation();
+ ui_translation.mV[VX] += x;
+ ui_translation.mV[VY] += y;
+ ui_translation.scaleVec(ui_scale);
+ S32 index = 0;
+ S32 scaled_width = llround(width * ui_scale.mV[VX]);
+ S32 scaled_height = llround(height * ui_scale.mV[VY]);
+
+ uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
+ pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
+ pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY] + scaled_height, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
+ pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
+ pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY], 0.f);
+ index++;
+
+ gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
+ }
+ gGL.end();
+ }
+ else
+ {
+ gGL.pushUIMatrix();
+ gGL.translateUI((F32)x, (F32)y, 0.f);
+
+ F32 offset_x = F32(width/2);
+ F32 offset_y = F32(height/2);
+
+ gGL.translateUI(offset_x, offset_y, 0.f);
+
+ LLMatrix3 quat(0.f, 0.f, degrees*DEG_TO_RAD);
+
+ gGL.getTexUnit(0)->bind(image, true);
+
+ gGL.color4fv(color.mV);
+
+ gGL.begin(LLRender::QUADS);
+ {
+ LLVector3 v;
+
+ v = LLVector3(offset_x, offset_y, 0.f) * quat;
+ gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
+ gGL.vertex2f(v.mV[0], v.mV[1] );
+
+ v = LLVector3(-offset_x, offset_y, 0.f) * quat;
+ gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
+ gGL.vertex2f(v.mV[0], v.mV[1] );
+
+ v = LLVector3(-offset_x, -offset_y, 0.f) * quat;
+ gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
+ gGL.vertex2f(v.mV[0], v.mV[1] );
+
+ v = LLVector3(offset_x, -offset_y, 0.f) * quat;
+ gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
+ gGL.vertex2f(v.mV[0], v.mV[1] );
+ }
+ gGL.end();
+ gGL.popUIMatrix();
+ }
+}
+
+
+void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase )
+{
+ phase = fmod(phase, 1.f);
+
+ S32 shift = S32(phase * 4.f) % 4;
+
+ // Stippled line
+ LLGLEnable stipple(GL_LINE_STIPPLE);
+
+ gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], color.mV[VALPHA]);
+
+ gGL.flush();
+ glLineWidth(2.5f);
+
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLineStipple(2, 0x3333 << shift);
+ }
+
+ gGL.begin(LLRender::LINES);
+ {
+ gGL.vertex3fv( start.mV );
+ gGL.vertex3fv( end.mV );
+ }
+ gGL.end();
+
+ 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)
+{
+ if (end_angle < start_angle)
+ {
+ end_angle += F_TWO_PI;
+ }
+
+ gGL.pushUIMatrix();
+ {
+ gGL.translateUI(center_x, center_y, 0.f);
+
+ // Inexact, but reasonably fast.
+ F32 delta = (end_angle - start_angle) / steps;
+ F32 sin_delta = sin( delta );
+ F32 cos_delta = cos( delta );
+ F32 x = cosf(start_angle) * radius;
+ F32 y = sinf(start_angle) * radius;
+
+ if (filled)
+ {
+ gGL.begin(LLRender::TRIANGLE_FAN);
+ gGL.vertex2f(0.f, 0.f);
+ // make sure circle is complete
+ steps += 1;
+ }
+ else
+ {
+ gGL.begin(LLRender::LINE_STRIP);
+ }
+
+ while( steps-- )
+ {
+ // Successive rotations
+ gGL.vertex2f( x, y );
+ F32 x_new = x * cos_delta - y * sin_delta;
+ y = x * sin_delta + y * cos_delta;
+ x = x_new;
+ }
+ gGL.end();
+ }
+ gGL.popUIMatrix();
+}
+
+void gl_circle_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled)
+{
+ gGL.pushUIMatrix();
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.translateUI(center_x, center_y, 0.f);
+
+ // Inexact, but reasonably fast.
+ F32 delta = F_TWO_PI / steps;
+ F32 sin_delta = sin( delta );
+ F32 cos_delta = cos( delta );
+ F32 x = radius;
+ F32 y = 0.f;
+
+ if (filled)
+ {
+ gGL.begin(LLRender::TRIANGLE_FAN);
+ gGL.vertex2f(0.f, 0.f);
+ // make sure circle is complete
+ steps += 1;
+ }
+ else
+ {
+ gGL.begin(LLRender::LINE_LOOP);
+ }
+
+ while( steps-- )
+ {
+ // Successive rotations
+ gGL.vertex2f( x, y );
+ F32 x_new = x * cos_delta - y * sin_delta;
+ y = x * sin_delta + y * cos_delta;
+ x = x_new;
+ }
+ gGL.end();
+ }
+ gGL.popUIMatrix();
+}
+
+// Renders a ring with sides (tube shape)
+void gl_deep_circle( F32 radius, F32 depth, S32 steps )
+{
+ F32 x = radius;
+ F32 y = 0.f;
+ F32 angle_delta = F_TWO_PI / (F32)steps;
+ gGL.begin( LLRender::TRIANGLE_STRIP );
+ {
+ S32 step = steps + 1; // An extra step to close the circle.
+ while( step-- )
+ {
+ gGL.vertex3f( x, y, depth );
+ gGL.vertex3f( x, y, 0.f );
+
+ F32 x_new = x * cosf(angle_delta) - y * sinf(angle_delta);
+ y = x * sinf(angle_delta) + y * cosf(angle_delta);
+ x = x_new;
+ }
+ }
+ gGL.end();
+}
+
+void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor4& side_color, S32 steps, BOOL render_center )
+{
+ gGL.pushUIMatrix();
+ {
+ gGL.translateUI(0.f, 0.f, -width / 2);
+ if( render_center )
+ {
+ gGL.color4fv(center_color.mV);
+ gGL.diffuseColor4fv(center_color.mV);
+ gl_deep_circle( radius, width, steps );
+ }
+ else
+ {
+ gGL.diffuseColor4fv(side_color.mV);
+ gl_washer_2d(radius, radius - width, steps, side_color, side_color);
+ gGL.translateUI(0.f, 0.f, width);
+ gl_washer_2d(radius - width, radius, steps, side_color, side_color);
+ }
+ }
+ gGL.popUIMatrix();
+}
+
+// Draw gray and white checkerboard with black border
+void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha)
+{
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ // Initialize the first time this is called.
+ const S32 PIXELS = 32;
+ static GLubyte checkerboard[PIXELS * PIXELS];
+ static BOOL first = TRUE;
+ if( first )
+ {
+ for( S32 i = 0; i < PIXELS; i++ )
+ {
+ for( S32 j = 0; j < PIXELS; j++ )
+ {
+ checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF;
+ }
+ }
+ first = FALSE;
+ }
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ // ...white squares
+ gGL.color4f( 1.f, 1.f, 1.f, alpha );
+ gl_rect_2d(rect);
+
+ // ...gray squares
+ gGL.color4f( .7f, .7f, .7f, alpha );
+ gGL.flush();
+
+ glPolygonStipple( checkerboard );
+
+ LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE);
+ gl_rect_2d(rect);
+ }
+ else
+ { //polygon stipple is deprecated, use "Checker" texture
+ LLPointer<LLUIImage> img = LLRender2D::getUIImage("Checker");
+ gGL.getTexUnit(0)->bind(img->getImage());
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+
+ LLColor4 color(1.f, 1.f, 1.f, alpha);
+ LLRectf uv_rect(0, 0, rect.getWidth()/32.f, rect.getHeight()/32.f);
+
+ gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(),
+ img->getImage(), color, uv_rect);
+ }
+
+ gGL.flush();
+}
+
+
+// Draws the area between two concentric circles, like
+// a doughnut or washer.
+void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color)
+{
+ const F32 DELTA = F_TWO_PI / steps;
+ const F32 SIN_DELTA = sin( DELTA );
+ const F32 COS_DELTA = cos( DELTA );
+
+ F32 x1 = outer_radius;
+ F32 y1 = 0.f;
+ F32 x2 = inner_radius;
+ F32 y2 = 0.f;
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ gGL.begin( LLRender::TRIANGLE_STRIP );
+ {
+ steps += 1; // An extra step to close the circle.
+ while( steps-- )
+ {
+ gGL.color4fv(outer_color.mV);
+ gGL.vertex2f( x1, y1 );
+ gGL.color4fv(inner_color.mV);
+ gGL.vertex2f( x2, y2 );
+
+ F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
+ y1 = x1 * SIN_DELTA + y1 * COS_DELTA;
+ x1 = x1_new;
+
+ F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA;
+ y2 = x2 * SIN_DELTA + y2 * COS_DELTA;
+ x2 = x2_new;
+ }
+ }
+ gGL.end();
+}
+
+// Draws the area between two concentric circles, like
+// a doughnut or washer.
+void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color)
+{
+ const F32 DELTA = (end_radians - start_radians) / steps;
+ const F32 SIN_DELTA = sin( DELTA );
+ const F32 COS_DELTA = cos( DELTA );
+
+ F32 x1 = outer_radius * cos( start_radians );
+ F32 y1 = outer_radius * sin( start_radians );
+ F32 x2 = inner_radius * cos( start_radians );
+ F32 y2 = inner_radius * sin( start_radians );
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.begin( LLRender::TRIANGLE_STRIP );
+ {
+ steps += 1; // An extra step to close the circle.
+ while( steps-- )
+ {
+ gGL.color4fv(outer_color.mV);
+ gGL.vertex2f( x1, y1 );
+ gGL.color4fv(inner_color.mV);
+ gGL.vertex2f( x2, y2 );
+
+ F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
+ y1 = x1 * SIN_DELTA + y1 * COS_DELTA;
+ x1 = x1_new;
+
+ F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA;
+ y2 = x2 * SIN_DELTA + y2 * COS_DELTA;
+ x2 = x2_new;
+ }
+ }
+ gGL.end();
+}
+
+void gl_rect_2d_simple_tex( S32 width, S32 height )
+{
+ gGL.begin( LLRender::QUADS );
+
+ gGL.texCoord2f(1.f, 1.f);
+ gGL.vertex2i(width, height);
+
+ gGL.texCoord2f(0.f, 1.f);
+ gGL.vertex2i(0, height);
+
+ gGL.texCoord2f(0.f, 0.f);
+ gGL.vertex2i(0, 0);
+
+ gGL.texCoord2f(1.f, 0.f);
+ gGL.vertex2i(width, 0);
+
+ gGL.end();
+}
+
+void gl_rect_2d_simple( S32 width, S32 height )
+{
+ gGL.begin( LLRender::QUADS );
+ gGL.vertex2i(width, height);
+ gGL.vertex2i(0, height);
+ gGL.vertex2i(0, 0);
+ gGL.vertex2i(width, 0);
+ gGL.end();
+}
+
+void gl_segmented_rect_2d_tex(const S32 left,
+ const S32 top,
+ const S32 right,
+ const S32 bottom,
+ const S32 texture_width,
+ const S32 texture_height,
+ const S32 border_size,
+ const U32 edges)
+{
+ S32 width = llabs(right - left);
+ S32 height = llabs(top - bottom);
+
+ gGL.pushUIMatrix();
+
+ gGL.translateUI((F32)left, (F32)bottom, 0.f);
+ LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height);
+
+ if (border_uv_scale.mV[VX] > 0.5f)
+ {
+ border_uv_scale *= 0.5f / border_uv_scale.mV[VX];
+ }
+ if (border_uv_scale.mV[VY] > 0.5f)
+ {
+ border_uv_scale *= 0.5f / border_uv_scale.mV[VY];
+ }
+
+ F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f);
+ LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
+ LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
+ LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
+ LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
+ LLVector2 width_vec((F32)width, 0.f);
+ LLVector2 height_vec(0.f, (F32)height);
+
+ gGL.begin(LLRender::QUADS);
+ {
+ // draw bottom left
+ gGL.texCoord2f(0.f, 0.f);
+ gGL.vertex2f(0.f, 0.f);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
+ gGL.vertex2fv(border_width_left.mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((border_width_left + border_height_bottom).mV);
+
+ gGL.texCoord2f(0.f, border_uv_scale.mV[VY]);
+ gGL.vertex2fv(border_height_bottom.mV);
+
+ // draw bottom middle
+ gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
+ gGL.vertex2fv(border_width_left.mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
+ gGL.vertex2fv((width_vec - border_width_right).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((border_width_left + border_height_bottom).mV);
+
+ // draw bottom right
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
+ gGL.vertex2fv((width_vec - border_width_right).mV);
+
+ gGL.texCoord2f(1.f, 0.f);
+ gGL.vertex2fv(width_vec.mV);
+
+ gGL.texCoord2f(1.f, border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec + border_height_bottom).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+
+ // draw left
+ gGL.texCoord2f(0.f, border_uv_scale.mV[VY]);
+ gGL.vertex2fv(border_height_bottom.mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((border_width_left + border_height_bottom).mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((height_vec - border_height_top).mV);
+
+ // draw middle
+ gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((border_width_left + border_height_bottom).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
+
+ // draw right
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+
+ gGL.texCoord2f(1.f, border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec + border_height_bottom).mV);
+
+ gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+
+ // draw top left
+ gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
+ gGL.vertex2fv((border_width_left + height_vec).mV);
+
+ gGL.texCoord2f(0.f, 1.f);
+ gGL.vertex2fv((height_vec).mV);
+
+ // draw top middle
+ gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
+ gGL.vertex2fv((width_vec - border_width_right + height_vec).mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
+ gGL.vertex2fv((border_width_left + height_vec).mV);
+
+ // draw top right
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((width_vec + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(1.f, 1.f);
+ gGL.vertex2fv((width_vec + height_vec).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
+ gGL.vertex2fv((width_vec - border_width_right + height_vec).mV);
+ }
+ gGL.end();
+
+ gGL.popUIMatrix();
+}
+
+//FIXME: rewrite to use scissor?
+void gl_segmented_rect_2d_fragment_tex(const S32 left,
+ const S32 top,
+ const S32 right,
+ const S32 bottom,
+ const S32 texture_width,
+ const S32 texture_height,
+ const S32 border_size,
+ const F32 start_fragment,
+ const F32 end_fragment,
+ const U32 edges)
+{
+ S32 width = llabs(right - left);
+ S32 height = llabs(top - bottom);
+
+ gGL.pushUIMatrix();
+
+ gGL.translateUI((F32)left, (F32)bottom, 0.f);
+ LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height);
+
+ if (border_uv_scale.mV[VX] > 0.5f)
+ {
+ border_uv_scale *= 0.5f / border_uv_scale.mV[VX];
+ }
+ if (border_uv_scale.mV[VY] > 0.5f)
+ {
+ border_uv_scale *= 0.5f / border_uv_scale.mV[VY];
+ }
+
+ F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f);
+ LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
+ LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
+ LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
+ LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
+ LLVector2 width_vec((F32)width, 0.f);
+ LLVector2 height_vec(0.f, (F32)height);
+
+ F32 middle_start = border_scale / (F32)width;
+ F32 middle_end = 1.f - middle_start;
+
+ F32 u_min;
+ F32 u_max;
+ LLVector2 x_min;
+ LLVector2 x_max;
+
+ gGL.begin(LLRender::QUADS);
+ {
+ if (start_fragment < middle_start)
+ {
+ u_min = (start_fragment / middle_start) * border_uv_scale.mV[VX];
+ u_max = llmin(end_fragment / middle_start, 1.f) * border_uv_scale.mV[VX];
+ x_min = (start_fragment / middle_start) * border_width_left;
+ x_max = llmin(end_fragment / middle_start, 1.f) * border_width_left;
+
+ // draw bottom left
+ gGL.texCoord2f(u_min, 0.f);
+ gGL.vertex2fv(x_min.mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
+ gGL.vertex2fv(x_max.mV);
+
+ gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + border_height_bottom).mV);
+
+ gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + border_height_bottom).mV);
+
+ // draw left
+ gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + border_height_bottom).mV);
+
+ gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + border_height_bottom).mV);
+
+ gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
+
+ // draw top left
+ gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(u_max, 1.f);
+ gGL.vertex2fv((x_max + height_vec).mV);
+
+ gGL.texCoord2f(u_min, 1.f);
+ gGL.vertex2fv((x_min + height_vec).mV);
+ }
+
+ if (end_fragment > middle_start || start_fragment < middle_end)
+ {
+ x_min = border_width_left + ((llclamp(start_fragment, middle_start, middle_end) - middle_start)) * width_vec;
+ x_max = border_width_left + ((llclamp(end_fragment, middle_start, middle_end) - middle_start)) * width_vec;
+
+ // draw bottom middle
+ gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
+ gGL.vertex2fv(x_min.mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
+ gGL.vertex2fv((x_max).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + border_height_bottom).mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + border_height_bottom).mV);
+
+ // draw middle
+ gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + border_height_bottom).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + border_height_bottom).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
+
+ // draw top middle
+ gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
+ gGL.vertex2fv((x_max + height_vec).mV);
+
+ gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
+ gGL.vertex2fv((x_min + height_vec).mV);
+ }
+
+ if (end_fragment > middle_end)
+ {
+ u_min = (1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_uv_scale.mV[VX];
+ u_max = (1.f - ((end_fragment - middle_end) / middle_start)) * border_uv_scale.mV[VX];
+ x_min = width_vec - ((1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_width_right);
+ x_max = width_vec - ((1.f - ((end_fragment - middle_end) / middle_start)) * border_width_right);
+
+ // draw bottom right
+ gGL.texCoord2f(u_min, 0.f);
+ gGL.vertex2fv((x_min).mV);
+
+ gGL.texCoord2f(u_max, 0.f);
+ gGL.vertex2fv(x_max.mV);
+
+ gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + border_height_bottom).mV);
+
+ gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + border_height_bottom).mV);
+
+ // draw right
+ gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + border_height_bottom).mV);
+
+ gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + border_height_bottom).mV);
+
+ gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
+
+ // draw top right
+ gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+ gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
+
+ gGL.texCoord2f(u_max, 1.f);
+ gGL.vertex2fv((x_max + height_vec).mV);
+
+ gGL.texCoord2f(u_min, 1.f);
+ gGL.vertex2fv((x_min + height_vec).mV);
+ }
+ }
+ gGL.end();
+
+ gGL.popUIMatrix();
+}
+
+void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect,
+ const LLVector3& width_vec, const LLVector3& height_vec)
+{
+ gGL.begin(LLRender::QUADS);
+ {
+ // draw bottom left
+ gGL.texCoord2f(clip_rect.mLeft, clip_rect.mBottom);
+ gGL.vertex3f(0.f, 0.f, 0.f);
+
+ gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
+
+ gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV);
+
+ // draw bottom middle
+ gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
+
+ // draw bottom right
+ gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV);
+
+ gGL.texCoord2f(clip_rect.mRight, clip_rect.mBottom);
+ gGL.vertex3fv(width_vec.mV);
+
+ gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom);
+ gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
+
+ // draw left
+ gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
+
+ gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV);
+
+ // draw middle
+ gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
+
+ // draw right
+ gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
+
+ gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom);
+ gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV);
+
+ gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop);
+ gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
+
+ // draw top left
+ gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV);
+
+ gGL.texCoord2f(clip_rect.mLeft, clip_rect.mTop);
+ gGL.vertex3fv((height_vec).mV);
+
+ // draw top middle
+ gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV);
+
+ // draw top right
+ gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
+
+ gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop);
+ gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV);
+
+ gGL.texCoord2f(clip_rect.mRight, clip_rect.mTop);
+ gGL.vertex3fv((width_vec + height_vec).mV);
+
+ gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop);
+ gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV);
+ }
+ gGL.end();
+
+}
+
+// static
+void LLRender2D::initClass(LLImageProviderInterface* image_provider,
+ const LLVector2* scale_factor)
+{
+ sGLScaleFactor = (scale_factor == NULL) ? LLVector2(1.f, 1.f) : *scale_factor;
+ sImageProvider = image_provider;
+}
+
+// static
+void LLRender2D::cleanupClass()
+{
+ if(sImageProvider)
+ {
+ sImageProvider->cleanUp();
+ }
+}
+
+
+//static
+void LLRender2D::translate(F32 x, F32 y, F32 z)
+{
+ gGL.translateUI(x,y,z);
+ LLFontGL::sCurOrigin.mX += (S32) x;
+ LLFontGL::sCurOrigin.mY += (S32) y;
+ LLFontGL::sCurDepth += z;
+}
+
+//static
+void LLRender2D::pushMatrix()
+{
+ gGL.pushUIMatrix();
+ LLFontGL::sOriginStack.push_back(std::make_pair(LLFontGL::sCurOrigin, LLFontGL::sCurDepth));
+}
+
+//static
+void LLRender2D::popMatrix()
+{
+ gGL.popUIMatrix();
+ LLFontGL::sCurOrigin = LLFontGL::sOriginStack.back().first;
+ LLFontGL::sCurDepth = LLFontGL::sOriginStack.back().second;
+ LLFontGL::sOriginStack.pop_back();
+}
+
+//static
+void LLRender2D::loadIdentity()
+{
+ gGL.loadUIIdentity();
+ LLFontGL::sCurOrigin.mX = 0;
+ LLFontGL::sCurOrigin.mY = 0;
+ LLFontGL::sCurDepth = 0.f;
+}
+
+//static
+void LLRender2D::setScaleFactor(const LLVector2 &scale_factor)
+{
+ sGLScaleFactor = scale_factor;
+}
+
+//static
+void LLRender2D::setLineWidth(F32 width)
+{
+ gGL.flush();
+ glLineWidth(width * lerp(sGLScaleFactor.mV[VX], sGLScaleFactor.mV[VY], 0.5f));
+}
+
+//static
+LLPointer<LLUIImage> LLRender2D::getUIImageByID(const LLUUID& image_id, S32 priority)
+{
+ if (sImageProvider)
+ {
+ return sImageProvider->getUIImageByID(image_id, priority);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+//static
+LLPointer<LLUIImage> LLRender2D::getUIImage(const std::string& name, S32 priority)
+{
+ if (!name.empty() && sImageProvider)
+ return sImageProvider->getUIImage(name, priority);
+ else
+ return NULL;
+}
+
diff --git a/indra/llrender/llrender2dutils.h b/indra/llrender/llrender2dutils.h
new file mode 100644
index 0000000000..4884422c58
--- /dev/null
+++ b/indra/llrender/llrender2dutils.h
@@ -0,0 +1,163 @@
+/**
+ * @file llrender2dutils.h
+ * @brief GL function declarations for immediate-mode gl drawing.
+ *
+ * $LicenseInfo:firstyear=2012&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$
+ */
+
+// All immediate-mode gl drawing should happen here.
+
+
+#ifndef LL_RENDER2DUTILS_H
+#define LL_RENDER2DUTILS_H
+
+#include "llpointer.h" // LLPointer<>
+#include "llrect.h"
+#include "llglslshader.h"
+
+class LLColor4;
+class LLVector3;
+class LLVector2;
+class LLUIImage;
+class LLUUID;
+
+extern const LLColor4 UI_VERTEX_COLOR;
+
+BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom);
+void gl_state_for_2d(S32 width, S32 height);
+
+void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2);
+void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color );
+void gl_triangle_2d(S32 x1, S32 y1, S32 x2, S32 y2, S32 x3, S32 y3, const LLColor4& color, BOOL filled);
+void gl_rect_2d_simple( S32 width, S32 height );
+
+void gl_draw_x(const LLRect& rect, const LLColor4& color);
+
+void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled = TRUE );
+void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, BOOL filled = TRUE );
+void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, S32 pixel_offset = 0, BOOL filled = TRUE );
+void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset = 0, BOOL filled = TRUE );
+void gl_rect_2d(const LLRect& rect, BOOL filled = TRUE );
+void gl_rect_2d(const LLRect& rect, const LLColor4& color, BOOL filled = TRUE );
+void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha = 1.0f);
+
+void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines);
+
+void gl_circle_2d(F32 x, F32 y, F32 radius, S32 steps, BOOL filled);
+void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F32 start_angle, F32 end_angle);
+void gl_deep_circle( F32 radius, F32 depth );
+void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor4& side_color, S32 steps, BOOL render_center );
+void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac);
+void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color);
+void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color);
+
+void gl_draw_image(S32 x, S32 y, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+
+void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase = 0.f );
+
+void gl_rect_2d_simple_tex( S32 width, S32 height );
+
+// segmented rectangles
+
+/*
+ TL |______TOP_________| TR
+ /| |\
+ _/_|__________________|_\_
+ L| | MIDDLE | |R
+ _|_|__________________|_|_
+ \ | BOTTOM | /
+ BL\|__________________|/ BR
+ | |
+*/
+
+typedef enum e_rounded_edge
+{
+ ROUNDED_RECT_LEFT = 0x1,
+ ROUNDED_RECT_TOP = 0x2,
+ ROUNDED_RECT_RIGHT = 0x4,
+ ROUNDED_RECT_BOTTOM = 0x8,
+ ROUNDED_RECT_ALL = 0xf
+}ERoundedEdge;
+
+
+void gl_segmented_rect_2d_tex(const S32 left, const S32 top, const S32 right, const S32 bottom, const S32 texture_width, const S32 texture_height, const S32 border_size, const U32 edges = ROUNDED_RECT_ALL);
+void gl_segmented_rect_2d_fragment_tex(const S32 left, const S32 top, const S32 right, const S32 bottom, const S32 texture_width, const S32 texture_height, const S32 border_size, const F32 start_fragment, const F32 end_fragment, const U32 edges = ROUNDED_RECT_ALL);
+void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, const LLVector3& width_vec, const LLVector3& height_vec);
+
+inline void gl_rect_2d( const LLRect& rect, BOOL filled )
+{
+ gl_rect_2d( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, filled );
+}
+
+inline void gl_rect_2d_offset_local( const LLRect& rect, S32 pixel_offset, BOOL filled)
+{
+ gl_rect_2d_offset_local( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, pixel_offset, filled );
+}
+
+class LLImageProviderInterface;
+
+class LLRender2D
+{
+ LOG_CLASS(LLRender2D);
+public:
+ static void initClass(LLImageProviderInterface* image_provider,
+ const LLVector2* scale_factor);
+ static void cleanupClass();
+
+ static void pushMatrix();
+ static void popMatrix();
+ static void loadIdentity();
+ static void translate(F32 x, F32 y, F32 z = 0.0f);
+
+ static void setLineWidth(F32 width);
+ static void setScaleFactor(const LLVector2& scale_factor);
+
+ static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0);
+ static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0);
+
+ static LLVector2 sGLScaleFactor;
+private:
+ static LLImageProviderInterface* sImageProvider;
+};
+
+class LLImageProviderInterface
+{
+protected:
+ LLImageProviderInterface() {};
+ virtual ~LLImageProviderInterface() {};
+public:
+ virtual LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority) = 0;
+ virtual LLPointer<LLUIImage> getUIImageByID(const LLUUID& id, S32 priority) = 0;
+ virtual void cleanUp() = 0;
+};
+
+
+extern LLGLSLShader gSolidColorProgram;
+extern LLGLSLShader gUIProgram;
+
+#endif // LL_RENDER2DUTILS_H
+
diff --git a/indra/llrender/llrendernavprim.cpp b/indra/llrender/llrendernavprim.cpp
new file mode 100755
index 0000000000..ca72964832
--- /dev/null
+++ b/indra/llrender/llrendernavprim.cpp
@@ -0,0 +1,59 @@
+/**
+* @file llrendernavprim.cpp
+* @brief Implementation of llrendernavprim
+* @author Prep@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, 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 "llrendernavprim.h"
+
+#include "llrender.h"
+#include "llvertexbuffer.h"
+#include "v4coloru.h"
+#include "v3math.h"
+
+//=============================================================================
+LLRenderNavPrim gRenderNav;
+//=============================================================================
+void LLRenderNavPrim::renderLLTri( const LLVector3& a, const LLVector3& b, const LLVector3& c, const LLColor4U& color ) const
+{
+ LLColor4 cV(color);
+ gGL.color4fv( cV.mV );
+ gGL.begin(LLRender::TRIANGLES);
+ {
+ gGL.vertex3fv( a.mV );
+ gGL.vertex3fv( b.mV );
+ gGL.vertex3fv( c.mV );
+ }
+ gGL.end();
+}
+//=============================================================================
+void LLRenderNavPrim::renderNavMeshVB( U32 mode, LLVertexBuffer* pVBO, int vertCnt )
+{
+ pVBO->setBuffer( LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_NORMAL );
+ pVBO->drawArrays( mode, 0, vertCnt );
+}
+//=============================================================================
diff --git a/indra/llrender/llrendernavprim.h b/indra/llrender/llrendernavprim.h
new file mode 100755
index 0000000000..a3a5dfec3a
--- /dev/null
+++ b/indra/llrender/llrendernavprim.h
@@ -0,0 +1,49 @@
+/**
+* @file llrendernavprim.h
+* @brief Header file for llrendernavprim
+* @author Prep@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, 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_LLRENDERNAVPRIM_H
+#define LL_LLRENDERNAVPRIM_H
+
+#include "stdtypes.h"
+
+class LLColor4U;
+class LLVector3;
+class LLVertexBuffer;
+
+
+class LLRenderNavPrim
+{
+public:
+ //Draw simple tri
+ void renderLLTri( const LLVector3& a, const LLVector3& b, const LLVector3& c, const LLColor4U& color ) const;
+ //Draw the contents of vertex buffer
+ void renderNavMeshVB( U32 mode, LLVertexBuffer* pVBO, int vertCnt );
+private:
+};
+
+extern LLRenderNavPrim gRenderNav;
+
+#endif // LL_LLRENDERNAVPRIM_H
diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp
index 26bfe036e8..26bfe036e8 100644..100755
--- a/indra/llrender/llrendersphere.cpp
+++ b/indra/llrender/llrendersphere.cpp
diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h
index f8e9e86e7f..f8e9e86e7f 100644..100755
--- a/indra/llrender/llrendersphere.h
+++ b/indra/llrender/llrendersphere.h
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index ef2a7395da..fe8110904d 100644..100755
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -51,12 +51,21 @@ void check_framebuffer_status()
}
bool LLRenderTarget::sUseFBO = false;
+U32 LLRenderTarget::sCurFBO = 0;
+
+
+extern S32 gGLViewport[4];
+
+U32 LLRenderTarget::sCurResX = 0;
+U32 LLRenderTarget::sCurResY = 0;
LLRenderTarget::LLRenderTarget() :
mResX(0),
mResY(0),
- mTex(0),
mFBO(0),
+ mPreviousFBO(0),
+ mPreviousResX(0),
+ mPreviousResY(0),
mDepth(0),
mStencil(0),
mUseDepth(false),
@@ -70,8 +79,49 @@ LLRenderTarget::~LLRenderTarget()
release();
}
+void LLRenderTarget::resize(U32 resx, U32 resy)
+{
+ //for accounting, get the number of pixels added/subtracted
+ S32 pix_diff = (resx*resy)-(mResX*mResY);
+
+ mResX = resx;
+ mResY = resy;
+
+ llassert(mInternalFormat.size() == mTex.size());
+
+ for (U32 i = 0; i < mTex.size(); ++i)
+ { //resize color attachments
+ gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, mInternalFormat[i], mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
+ sBytesAllocated += pix_diff*4;
+ }
+
+ if (mDepth)
+ { //resize depth attachment
+ if (mStencil)
+ {
+ //use render buffers where stencil buffers are in play
+ glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ }
+ else
+ {
+ gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
+ U32 internal_type = LLTexUnit::getInternalType(mUsage);
+ LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
+ }
+
+ sBytesAllocated += pix_diff*4;
+ }
+}
+
+
bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples)
{
+ resx = llmin(resx, (U32) gGLManager.mGLMaxTextureSize);
+ resy = llmin(resy, (U32) gGLManager.mGLMaxTextureSize);
+
stop_glerror();
release();
stop_glerror();
@@ -111,7 +161,7 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
stop_glerror();
}
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
}
stop_glerror();
@@ -128,10 +178,19 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
}
U32 offset = mTex.size();
- if (offset >= 4 ||
- (offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers)))
+
+ if( offset >= 4 )
{
- llerrs << "Too many color attachments!" << llendl;
+ llwarns << "Too many color attachments" << llendl;
+ llassert( offset < 4 );
+ return false;
+ }
+ if( offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers) )
+ {
+ llwarns << "FBO not used or no drawbuffers available; mFBO=" << (U32)mFBO << " gGLManager.mHasDrawBuffers=" << (U32)gGLManager.mHasDrawBuffers << llendl;
+ llassert( mFBO != 0 );
+ llassert( gGLManager.mHasDrawBuffers );
+ return false;
}
U32 tex;
@@ -143,7 +202,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
{
clear_glerror();
- LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
if (glGetError() != GL_NO_ERROR)
{
llwarns << "Could not allocate color buffer for render target." << llendl;
@@ -189,17 +248,21 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
check_framebuffer_status();
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
}
mTex.push_back(tex);
+ mInternalFormat.push_back(color_fmt);
+#if !LL_DARWIN
if (gDebugGL)
{ //bind and unbind to validate target
bindTarget();
flush();
}
-
+#endif
+
+
return true;
}
@@ -223,7 +286,7 @@ bool LLRenderTarget::allocateDepth()
U32 internal_type = LLTexUnit::getInternalType(mUsage);
stop_glerror();
clear_glerror();
- LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+ LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
}
@@ -277,7 +340,7 @@ void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
check_framebuffer_status();
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
target.mUseDepth = true;
}
@@ -294,41 +357,62 @@ void LLRenderTarget::release()
}
else
{
- LLImageGL::deleteTextures(1, &mDepth, true);
+ LLImageGL::deleteTextures(1, &mDepth);
stop_glerror();
}
mDepth = 0;
sBytesAllocated -= mResX*mResY*4;
}
- else if (mUseDepth && mFBO)
- { //detach shared depth buffer
+ else if (mFBO)
+ {
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- if (mStencil)
- { //attached as a renderbuffer
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
- mStencil = false;
+
+ if (mUseDepth)
+ { //detach shared depth buffer
+ if (mStencil)
+ { //attached as a renderbuffer
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
+ mStencil = false;
+ }
+ else
+ { //attached as a texture
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
+ }
+ mUseDepth = false;
}
- else
- { //attached as a texture
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
+ }
+
+ // Detach any extra color buffers (e.g. SRGB spec buffers)
+ //
+ if (mFBO && (mTex.size() > 1))
+ {
+ S32 z;
+ for (z = mTex.size() - 1; z >= 1; z--)
+ {
+ sBytesAllocated -= mResX*mResY*4;
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+z, LLTexUnit::getInternalType(mUsage), 0, 0);
+ stop_glerror();
+ LLImageGL::deleteTextures(1, &mTex[z]);
}
- mUseDepth = false;
}
if (mFBO)
{
glDeleteFramebuffers(1, (GLuint *) &mFBO);
+ stop_glerror();
mFBO = 0;
}
if (mTex.size() > 0)
{
- sBytesAllocated -= mResX*mResY*4*mTex.size();
- LLImageGL::deleteTextures(mTex.size(), &mTex[0], true);
- mTex.clear();
+ sBytesAllocated -= mResX*mResY*4;
+ LLImageGL::deleteTextures(1, &mTex[0]);
}
+
+ mTex.clear();
+ mInternalFormat.clear();
mResX = mResY = 0;
@@ -341,7 +425,10 @@ void LLRenderTarget::bindTarget()
{
stop_glerror();
+ mPreviousFBO = sCurFBO;
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+ sCurFBO = mFBO;
+
stop_glerror();
if (gGLManager.mHasDrawBuffers)
{ //setup multiple render targets
@@ -363,18 +450,13 @@ void LLRenderTarget::bindTarget()
stop_glerror();
}
+ mPreviousResX = sCurResX;
+ mPreviousResY = sCurResY;
glViewport(0, 0, mResX, mResY);
- sBoundTarget = this;
-}
+ sCurResX = mResX;
+ sCurResY = mResY;
-// static
-void LLRenderTarget::unbindTarget()
-{
- if (gGLManager.mHasFramebufferObject)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- }
- sBoundTarget = NULL;
+ sBoundTarget = this;
}
void LLRenderTarget::clear(U32 mask_in)
@@ -413,6 +495,12 @@ U32 LLRenderTarget::getTexture(U32 attachment) const
return mTex[attachment];
}
+U32 LLRenderTarget::getNumTextures() const
+{
+ return mTex.size();
+}
+
+
void LLRenderTarget::bindTexture(U32 index, S32 channel)
{
gGL.getTexUnit(channel)->bindManual(mUsage, getTexture(index));
@@ -442,7 +530,22 @@ void LLRenderTarget::flush(bool fetch_depth)
else
{
stop_glerror();
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFBO);
+ sCurFBO = mPreviousFBO;
+
+ if (mPreviousFBO)
+ {
+ glViewport(0, 0, mPreviousResX, mPreviousResY);
+ sCurResX = mPreviousResX;
+ sCurResY = mPreviousResY;
+ }
+ else
+ {
+ glViewport(gGLViewport[0],gGLViewport[1],gGLViewport[2],gGLViewport[3]);
+ sCurResX = gGLViewport[2];
+ sCurResY = gGLViewport[3];
+ }
+
stop_glerror();
}
}
@@ -472,7 +575,7 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
stop_glerror();
glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, srcX0, srcY0, dstX0, dstY0, dstX1, dstY1);
stop_glerror();
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
stop_glerror();
}
else
@@ -489,7 +592,7 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
stop_glerror();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
stop_glerror();
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
stop_glerror();
}
}
@@ -500,8 +603,10 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0
{
if (!source.mFBO)
{
- llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
+ llwarns << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
+ return;
}
+
{
GLboolean write_depth = mask & GL_DEPTH_BUFFER_BIT ? TRUE : FALSE;
@@ -515,7 +620,7 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0
stop_glerror();
glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
stop_glerror();
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
stop_glerror();
}
}
@@ -533,3 +638,5 @@ void LLRenderTarget::getViewport(S32* viewport)
viewport[3] = mResY;
}
+
+
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index 2735ab21c5..6dc84d978d 100644..100755
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -28,7 +28,6 @@
#define LL_LLRENDERTARGET_H
// LLRenderTarget is unavailible on the mapserver since it uses FBOs.
-#if !LL_MESA_HEADLESS
#include "llgl.h"
#include "llrender.h"
@@ -57,14 +56,16 @@
*/
-class LLMultisampleBuffer;
-
class LLRenderTarget
{
public:
//whether or not to use FBO implementation
static bool sUseFBO;
static U32 sBytesAllocated;
+ static U32 sCurFBO;
+ static U32 sCurResX;
+ static U32 sCurResY;
+
LLRenderTarget();
~LLRenderTarget();
@@ -74,6 +75,12 @@ public:
//multiple calls will release previously allocated resources
bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = false, S32 samples = 0);
+ //resize existing attachments to use new resolution and color format
+ // CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined
+ // DO NOT use for screen space buffers or for scratch space for an image that might be uploaded
+ // DO use for render targets that resize often and aren't likely to ruin someone's day if they break
+ void resize(U32 resx, U32 resy);
+
//add color buffer attachment
//limit of 4 color attachments per render target
bool addColorAttachment(U32 color_fmt);
@@ -92,9 +99,6 @@ public:
//applies appropriate viewport
void bindTarget();
- //unbind target for rendering
- static void unbindTarget();
-
//clear render targer, clears depth buffer if present,
//uses scissor rect if in copy-to-texture mode
void clear(U32 mask = 0xFFFFFFFF);
@@ -111,6 +115,7 @@ public:
LLTexUnit::eTextureType getUsage(void) const { return mUsage; }
U32 getTexture(U32 attachment = 0) const;
+ U32 getNumTextures() const;
U32 getDepth(void) const { return mDepth; }
bool hasStencil() const { return mStencil; }
@@ -142,7 +147,12 @@ protected:
U32 mResX;
U32 mResY;
std::vector<U32> mTex;
+ std::vector<U32> mInternalFormat;
U32 mFBO;
+ U32 mPreviousFBO;
+ U32 mPreviousResX;
+ U32 mPreviousResY;
+
U32 mDepth;
bool mStencil;
bool mUseDepth;
@@ -152,7 +162,5 @@ protected:
static LLRenderTarget* sBoundTarget;
};
-#endif //!LL_MESA_HEADLESS
-
#endif
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 7d384450e6..d230574752 100644..100755
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -521,7 +521,7 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns)
}
}
-GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels)
+GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines, S32 texture_index_channels)
{
GLenum error = GL_NO_ERROR;
if (gDebugGL)
@@ -643,20 +643,22 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
text[count++] = strdup("#define textureCube texture\n");
text[count++] = strdup("#define texture2DLod textureLod\n");
text[count++] = strdup("#define shadow2D(a,b) vec2(texture(a,b))\n");
-
+
if (major_version > 1 || minor_version >= 40)
{ //GLSL 1.40 replaces texture2DRect et al with texture
text[count++] = strdup("#define texture2DRect texture\n");
text[count++] = strdup("#define shadow2DRect(a,b) vec2(texture(a,b))\n");
}
}
-
- //copy preprocessor definitions into buffer
- for (std::map<std::string,std::string>::iterator iter = mDefinitions.begin(); iter != mDefinitions.end(); ++iter)
+
+ if (defines)
+ {
+ for (boost::unordered_map<std::string,std::string>::iterator iter = defines->begin(); iter != defines->end(); ++iter)
{
std::string define = "#define " + iter->first + " " + iter->second + "\n";
text[count++] = (GLcharARB *) strdup(define.c_str());
}
+ }
if (texture_index_channels > 0 && type == GL_FRAGMENT_SHADER_ARB)
{
@@ -693,6 +695,8 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
}
*/
+ text[count++] = strdup("#define HAS_DIFFUSE_LOOKUP 1\n");
+
//uniform declartion
for (S32 i = 0; i < texture_index_channels; ++i)
{
@@ -702,7 +706,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
if (texture_index_channels > 1)
{
- text[count++] = strdup("VARYING_FLAT ivec4 vary_texture_index;\n");
+ text[count++] = strdup("VARYING_FLAT int vary_texture_index;\n");
}
text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n");
@@ -716,20 +720,33 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
}
else if (major_version > 1 || minor_version >= 30)
{ //switches are supported in GLSL 1.30 and later
- text[count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n");
- text[count++] = strdup("\tswitch (vary_texture_index.r)\n");
- text[count++] = strdup("\t{\n");
-
- //switch body
- for (S32 i = 0; i < texture_index_channels; ++i)
- {
- std::string case_str = llformat("\t\tcase %d: ret = texture2D(tex%d, texcoord); break;\n", i, i);
- text[count++] = strdup(case_str.c_str());
+ if (gGLManager.mIsNVIDIA)
+ { //switches are unreliable on some NVIDIA drivers
+ for (U32 i = 0; i < texture_index_channels; ++i)
+ {
+ std::string if_string = llformat("\t%sif (vary_texture_index == %d) { return texture2D(tex%d, texcoord); }\n", i > 0 ? "else " : "", i, i);
+ text[count++] = strdup(if_string.c_str());
+ }
+ text[count++] = strdup("\treturn vec4(1,0,1,1);\n");
+ text[count++] = strdup("}\n");
}
+ else
+ {
+ text[count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n");
+ text[count++] = strdup("\tswitch (vary_texture_index)\n");
+ text[count++] = strdup("\t{\n");
+
+ //switch body
+ for (S32 i = 0; i < texture_index_channels; ++i)
+ {
+ std::string case_str = llformat("\t\tcase %d: return texture2D(tex%d, texcoord);\n", i, i);
+ text[count++] = strdup(case_str.c_str());
+ }
- text[count++] = strdup("\t}\n");
- text[count++] = strdup("\treturn ret;\n");
- text[count++] = strdup("}\n");
+ text[count++] = strdup("\t}\n");
+ text[count++] = strdup("\treturn ret;\n");
+ text[count++] = strdup("}\n");
+ }
}
else
{ //should never get here. Indexed texture rendering requires GLSL 1.30 or later
@@ -737,6 +754,10 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
llerrs << "Indexed texture rendering requires GLSL 1.30 or later." << llendl;
}
}
+ else
+ {
+ text[count++] = strdup("#define HAS_DIFFUSE_LOOKUP 0\n");
+ }
//copy file into memory
while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(text) )
@@ -793,7 +814,6 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
//an error occured, print log
LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
dumpObjectLog(ret);
-
#if LL_WINDOWS
std::stringstream ostr;
//dump shader source for debugging
@@ -811,8 +831,20 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
}
LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
-#endif // LL_WINDOWS
-
+#else
+ std::string str;
+
+ for (GLuint i = 0; i < count; i++) {
+ str.append(text[i]);
+
+ if (i % 128 == 0)
+ {
+ LL_WARNS("ShaderLoading") << str << llendl;
+ str = "";
+ }
+ }
+#endif
+
ret = 0;
}
}
@@ -841,7 +873,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
if (shader_level > 1)
{
shader_level--;
- return loadShaderFile(filename,shader_level,type,texture_index_channels);
+ return loadShaderFile(filename,shader_level,type, defines, texture_index_channels);
}
LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL;
}
@@ -945,7 +977,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedAttribs.push_back("texcoord3");
mReservedAttribs.push_back("diffuse_color");
mReservedAttribs.push_back("emissive");
- mReservedAttribs.push_back("binormal");
+ mReservedAttribs.push_back("tangent");
mReservedAttribs.push_back("weight");
mReservedAttribs.push_back("weight4");
mReservedAttribs.push_back("clothing");
@@ -961,7 +993,9 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("texture_matrix1");
mReservedUniforms.push_back("texture_matrix2");
mReservedUniforms.push_back("texture_matrix3");
- llassert(mReservedUniforms.size() == LLShaderMgr::TEXTURE_MATRIX3+1);
+ mReservedUniforms.push_back("object_plane_s");
+ mReservedUniforms.push_back("object_plane_t");
+ llassert(mReservedUniforms.size() == LLShaderMgr::OBJECT_PLANE_T+1);
mReservedUniforms.push_back("viewport");
@@ -1026,6 +1060,9 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("size");
mReservedUniforms.push_back("falloff");
+ mReservedUniforms.push_back("box_center");
+ mReservedUniforms.push_back("box_size");
+
mReservedUniforms.push_back("minLuminance");
mReservedUniforms.push_back("maxExtractAlpha");
@@ -1039,6 +1076,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("minimum_alpha");
+ mReservedUniforms.push_back("emissive_brightness");
mReservedUniforms.push_back("shadow_matrix");
mReservedUniforms.push_back("env_mat");
@@ -1062,8 +1100,9 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("proj_shadow_res");
mReservedUniforms.push_back("depth_cutoff");
mReservedUniforms.push_back("norm_cutoff");
+ mReservedUniforms.push_back("shadow_target_width");
- llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_NORM_CUTOFF+1);
+ llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH+1);
mReservedUniforms.push_back("tc_scale");
mReservedUniforms.push_back("rcp_screen_res");
@@ -1098,7 +1137,54 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("lightMap");
mReservedUniforms.push_back("bloomMap");
mReservedUniforms.push_back("projectionMap");
+ mReservedUniforms.push_back("norm_mat");
+
+ mReservedUniforms.push_back("global_gamma");
+ mReservedUniforms.push_back("texture_gamma");
+
+ mReservedUniforms.push_back("specular_color");
+ mReservedUniforms.push_back("env_intensity");
+
+ mReservedUniforms.push_back("matrixPalette");
+
+ mReservedUniforms.push_back("screenTex");
+ mReservedUniforms.push_back("screenDepth");
+ mReservedUniforms.push_back("refTex");
+ mReservedUniforms.push_back("eyeVec");
+ mReservedUniforms.push_back("time");
+ mReservedUniforms.push_back("d1");
+ mReservedUniforms.push_back("d2");
+ mReservedUniforms.push_back("lightDir");
+ mReservedUniforms.push_back("specular");
+ mReservedUniforms.push_back("lightExp");
+ mReservedUniforms.push_back("waterFogColor");
+ mReservedUniforms.push_back("waterFogDensity");
+ mReservedUniforms.push_back("waterFogKS");
+ mReservedUniforms.push_back("refScale");
+ mReservedUniforms.push_back("waterHeight");
+ mReservedUniforms.push_back("waterPlane");
+ mReservedUniforms.push_back("normScale");
+ mReservedUniforms.push_back("fresnelScale");
+ mReservedUniforms.push_back("fresnelOffset");
+ mReservedUniforms.push_back("blurMultiplier");
+ mReservedUniforms.push_back("sunAngle");
+ mReservedUniforms.push_back("scaledAngle");
+ mReservedUniforms.push_back("sunAngle2");
+
+ mReservedUniforms.push_back("camPosLocal");
+
+ mReservedUniforms.push_back("gWindDir");
+ mReservedUniforms.push_back("gSinWaveParams");
+ mReservedUniforms.push_back("gGravity");
+
+ mReservedUniforms.push_back("detail_0");
+ mReservedUniforms.push_back("detail_1");
+ mReservedUniforms.push_back("detail_2");
+ mReservedUniforms.push_back("detail_3");
+ mReservedUniforms.push_back("alpha_ramp");
+ mReservedUniforms.push_back("origin");
+ mReservedUniforms.push_back("display_gamma");
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 e28bda6de2..51c27fc8b6 100644..100755
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -47,6 +47,8 @@ public:
TEXTURE_MATRIX1,
TEXTURE_MATRIX2,
TEXTURE_MATRIX3,
+ OBJECT_PLANE_S,
+ OBJECT_PLANE_T,
VIEWPORT,
LIGHT_POSITION,
LIGHT_DIRECTION,
@@ -97,6 +99,8 @@ public:
LIGHT_CENTER,
LIGHT_SIZE,
LIGHT_FALLOFF,
+ BOX_CENTER,
+ BOX_SIZE,
GLOW_MIN_LUMINANCE,
GLOW_MAX_EXTRACT_ALPHA,
@@ -107,6 +111,7 @@ public:
GLOW_DELTA,
MINIMUM_ALPHA,
+ EMISSIVE_BRIGHTNESS,
DEFERRED_SHADOW_MATRIX,
DEFERRED_ENV_MAT,
@@ -130,6 +135,7 @@ public:
DEFERRED_PROJ_SHADOW_RES,
DEFERRED_DEPTH_CUTOFF,
DEFERRED_NORM_CUTOFF,
+ DEFERRED_SHADOW_TARGET_WIDTH,
FXAA_TC_SCALE,
FXAA_RCP_SCREEN_RES,
@@ -161,6 +167,54 @@ public:
DEFERRED_LIGHT,
DEFERRED_BLOOM,
DEFERRED_PROJECTION,
+ DEFERRED_NORM_MATRIX,
+
+ GLOBAL_GAMMA,
+ TEXTURE_GAMMA,
+
+ SPECULAR_COLOR,
+ ENVIRONMENT_INTENSITY,
+
+ AVATAR_MATRIX,
+
+ WATER_SCREENTEX,
+ WATER_SCREENDEPTH,
+ WATER_REFTEX,
+ WATER_EYEVEC,
+ WATER_TIME,
+ WATER_WAVE_DIR1,
+ WATER_WAVE_DIR2,
+ WATER_LIGHT_DIR,
+ WATER_SPECULAR,
+ WATER_SPECULAR_EXP,
+ WATER_FOGCOLOR,
+ WATER_FOGDENSITY,
+ WATER_FOGKS,
+ WATER_REFSCALE,
+ WATER_WATERHEIGHT,
+ WATER_WATERPLANE,
+ WATER_NORM_SCALE,
+ WATER_FRESNEL_SCALE,
+ WATER_FRESNEL_OFFSET,
+ WATER_BLUR_MULTIPLIER,
+ WATER_SUN_ANGLE,
+ WATER_SCALED_ANGLE,
+ WATER_SUN_ANGLE2,
+
+ WL_CAMPOSLOCAL,
+
+ AVATAR_WIND,
+ AVATAR_SINWAVE,
+ AVATAR_GRAVITY,
+
+ TERRAIN_DETAIL0,
+ TERRAIN_DETAIL1,
+ TERRAIN_DETAIL2,
+ TERRAIN_DETAIL3,
+ TERRAIN_ALPHARAMP,
+
+ SHINY_ORIGIN,
+DISPLAY_GAMMA,
END_RESERVED_UNIFORMS
} eGLSLReservedUniforms;
@@ -173,7 +227,7 @@ public:
void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE);
BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE);
BOOL validateProgramObject(GLhandleARB obj);
- GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels = -1);
+ GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1);
// Implemented in the application to actually point to the shader directory.
virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual
diff --git a/indra/llrender/lltexture.cpp b/indra/llrender/lltexture.cpp
index 90fbcec2be..90fbcec2be 100644..100755
--- a/indra/llrender/lltexture.cpp
+++ b/indra/llrender/lltexture.cpp
diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h
index 569a65c2e0..093bac20d1 100644..100755
--- a/indra/llrender/lltexture.h
+++ b/indra/llrender/lltexture.h
@@ -38,10 +38,9 @@ class LLTexUnit ;
class LLFontGL ;
//
-//this is an abstract class as the parent for the class LLViewerTexture
-//through the following virtual functions, the class LLViewerTexture can be reached from /llrender.
+//this is an abstract class as the parent for the class LLGLTexture
//
-class LLTexture : public LLRefCount
+class LLTexture : public virtual LLRefCount
{
friend class LLTexUnit ;
friend class LLFontGL ;
@@ -53,7 +52,7 @@ public:
LLTexture(){}
//
- //interfaces to access LLViewerTexture
+ //interfaces to access LLGLTexture
//
virtual S8 getType() const = 0 ;
virtual void setKnownDrawSize(S32 width, S32 height) = 0 ;
diff --git a/indra/llrender/lluiimage.cpp b/indra/llrender/lluiimage.cpp
new file mode 100644
index 0000000000..b954b66350
--- /dev/null
+++ b/indra/llrender/lluiimage.cpp
@@ -0,0 +1,243 @@
+/**
+ * @file lluiimage.cpp
+ * @brief UI implementation
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+// Utilities functions the user interface needs
+
+//#include "llviewerprecompiledheaders.h"
+#include "linden_common.h"
+
+// Project includes
+#include "lluiimage.h"
+#include "llrender2dutils.h"
+
+LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image)
+: mName(name),
+ mImage(image),
+ mScaleRegion(0.f, 1.f, 1.f, 0.f),
+ mClipRegion(0.f, 1.f, 1.f, 0.f),
+ mUniformScaling(TRUE),
+ mNoClip(TRUE),
+ mImageLoaded(NULL)
+{
+}
+
+LLUIImage::~LLUIImage()
+{
+ delete mImageLoaded;
+}
+
+void LLUIImage::setClipRegion(const LLRectf& region)
+{
+ mClipRegion = region;
+ mNoClip = mClipRegion.mLeft == 0.f
+ && mClipRegion.mRight == 1.f
+ && mClipRegion.mBottom == 0.f
+ && mClipRegion.mTop == 1.f;
+}
+
+void LLUIImage::setScaleRegion(const LLRectf& region)
+{
+ mScaleRegion = region;
+ mUniformScaling = mScaleRegion.mLeft == 0.f
+ && mScaleRegion.mRight == 1.f
+ && mScaleRegion.mBottom == 0.f
+ && mScaleRegion.mTop == 1.f;
+}
+
+//TODO: move drawing implementation inside class
+void LLUIImage::draw(S32 x, S32 y, const LLColor4& color) const
+{
+ gl_draw_scaled_image(x, y, getWidth(), getHeight(), mImage, color, mClipRegion);
+}
+
+void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const
+{
+ if (mUniformScaling)
+ {
+ gl_draw_scaled_image(x, y, width, height, mImage, color, mClipRegion);
+ }
+ else
+ {
+ gl_draw_scaled_image_with_border(
+ x, y,
+ width, height,
+ mImage,
+ color,
+ FALSE,
+ mClipRegion,
+ mScaleRegion);
+ }
+}
+
+void LLUIImage::drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const
+{
+ gl_draw_scaled_image_with_border(
+ x, y,
+ width, height,
+ mImage,
+ color,
+ TRUE,
+ mClipRegion,
+ mScaleRegion);
+}
+
+void LLUIImage::drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const
+{
+ LLRect border_rect;
+ border_rect.setOriginAndSize(x, y, width, height);
+ border_rect.stretch(border_width, border_width);
+ drawSolid(border_rect, color);
+}
+
+void LLUIImage::draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis,
+ const LLRect& rect, const LLColor4& color)
+{
+ F32 border_scale = 1.f;
+ F32 border_height = (1.f - mScaleRegion.getHeight()) * getHeight();
+ F32 border_width = (1.f - mScaleRegion.getWidth()) * getWidth();
+ if (rect.getHeight() < border_height || rect.getWidth() < border_width)
+ {
+ if(border_height - rect.getHeight() > border_width - rect.getWidth())
+ {
+ border_scale = (F32)rect.getHeight() / border_height;
+ }
+ else
+ {
+ border_scale = (F32)rect.getWidth() / border_width;
+ }
+ }
+
+ LLRender2D::pushMatrix();
+ {
+ LLVector3 rect_origin = origin_agent + (rect.mLeft * x_axis) + (rect.mBottom * y_axis);
+ LLRender2D::translate(rect_origin.mV[VX],
+ rect_origin.mV[VY],
+ rect_origin.mV[VZ]);
+ gGL.getTexUnit(0)->bind(getImage());
+ gGL.color4fv(color.mV);
+
+ LLRectf center_uv_rect(mClipRegion.mLeft + mScaleRegion.mLeft * mClipRegion.getWidth(),
+ mClipRegion.mBottom + mScaleRegion.mTop * mClipRegion.getHeight(),
+ mClipRegion.mLeft + mScaleRegion.mRight * mClipRegion.getWidth(),
+ mClipRegion.mBottom + mScaleRegion.mBottom * mClipRegion.getHeight());
+ gl_segmented_rect_3d_tex(mClipRegion,
+ center_uv_rect,
+ LLRectf(border_width * border_scale * 0.5f / (F32)rect.getWidth(),
+ (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);
+
+ } LLRender2D::popMatrix();
+}
+
+
+S32 LLUIImage::getWidth() const
+{
+ // return clipped dimensions of actual image area
+ return llround((F32)mImage->getWidth(0) * mClipRegion.getWidth());
+}
+
+S32 LLUIImage::getHeight() const
+{
+ // return clipped dimensions of actual image area
+ return llround((F32)mImage->getHeight(0) * mClipRegion.getHeight());
+}
+
+S32 LLUIImage::getTextureWidth() const
+{
+ return mImage->getWidth(0);
+}
+
+S32 LLUIImage::getTextureHeight() const
+{
+ return mImage->getHeight(0);
+}
+
+boost::signals2::connection LLUIImage::addLoadedCallback( const image_loaded_signal_t::slot_type& cb )
+{
+ if (!mImageLoaded)
+ {
+ mImageLoaded = new image_loaded_signal_t();
+ }
+ return mImageLoaded->connect(cb);
+}
+
+
+void LLUIImage::onImageLoaded()
+{
+ if (mImageLoaded)
+ {
+ (*mImageLoaded)();
+ }
+}
+
+
+namespace LLInitParam
+{
+ void ParamValue<LLUIImage*>::updateValueFromBlock()
+ {
+ // The keyword "none" is specifically requesting a null image
+ // do not default to current value. Used to overwrite template images.
+ if (name() == "none")
+ {
+ updateValue(NULL);
+ return;
+ }
+
+ LLUIImage* imagep = LLRender2D::getUIImage(name());
+ if (imagep)
+ {
+ updateValue(imagep);
+ }
+ }
+
+ void ParamValue<LLUIImage*>::updateBlockFromValue(bool make_block_authoritative)
+ {
+ if (getValue() == NULL)
+ {
+ name.set("none", make_block_authoritative);
+ }
+ else
+ {
+ name.set(getValue()->getName(), make_block_authoritative);
+ }
+ }
+
+
+ bool ParamCompare<LLUIImage*, false>::equals(
+ LLUIImage* const &a,
+ LLUIImage* const &b)
+ {
+ // force all LLUIImages for XML UI export to be "non-default"
+ if (!a && !b)
+ return false;
+ else
+ return (a == b);
+ }
+}
+
diff --git a/indra/llrender/lluiimage.h b/indra/llrender/lluiimage.h
new file mode 100644
index 0000000000..7817ba1c7b
--- /dev/null
+++ b/indra/llrender/lluiimage.h
@@ -0,0 +1,126 @@
+/**
+ * @file lluiimage.h
+ * @brief wrapper for images used in the UI that handles smart scaling, etc.
+ *
+ * $LicenseInfo:firstyear=2007&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_LLUIIMAGE_H
+#define LL_LLUIIMAGE_H
+
+#include "v4color.h"
+#include "llpointer.h"
+#include "llrefcount.h"
+#include "llrefcount.h"
+#include "llrect.h"
+#include <boost/function.hpp>
+#include <boost/signals2.hpp>
+#include "llinitparam.h"
+#include "lltexture.h"
+
+extern const LLColor4 UI_VERTEX_COLOR;
+
+class LLUIImage : public LLRefCount
+{
+public:
+ typedef boost::signals2::signal<void (void)> image_loaded_signal_t;
+
+ LLUIImage(const std::string& name, LLPointer<LLTexture> image);
+ virtual ~LLUIImage();
+
+ void setClipRegion(const LLRectf& region);
+ void setScaleRegion(const LLRectf& region);
+
+ LLPointer<LLTexture> getImage() { return mImage; }
+ const LLPointer<LLTexture>& getImage() const { return mImage; }
+
+ void draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color = UI_VERTEX_COLOR) const;
+ void draw(S32 x, S32 y, const LLColor4& color = UI_VERTEX_COLOR) const;
+ void draw(const LLRect& rect, const LLColor4& color = UI_VERTEX_COLOR) const { draw(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); }
+
+ void drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const;
+ void drawSolid(const LLRect& rect, const LLColor4& color) const { drawSolid(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); }
+ void drawSolid(S32 x, S32 y, const LLColor4& color) const { drawSolid(x, y, getWidth(), getHeight(), color); }
+
+ void drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const;
+ void drawBorder(const LLRect& rect, const LLColor4& color, S32 border_width) const { drawBorder(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color, border_width); }
+ void drawBorder(S32 x, S32 y, const LLColor4& color, S32 border_width) const { drawBorder(x, y, getWidth(), getHeight(), color, border_width); }
+
+ void draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis, const LLRect& rect, const LLColor4& color);
+
+ const std::string& getName() const { return mName; }
+
+ virtual S32 getWidth() const;
+ virtual S32 getHeight() const;
+
+ // returns dimensions of underlying textures, which might not be equal to ui image portion
+ S32 getTextureWidth() const;
+ S32 getTextureHeight() const;
+
+ boost::signals2::connection addLoadedCallback( const image_loaded_signal_t::slot_type& cb );
+
+ void onImageLoaded();
+
+protected:
+ image_loaded_signal_t* mImageLoaded;
+
+ std::string mName;
+ LLRectf mScaleRegion;
+ LLRectf mClipRegion;
+ LLPointer<LLTexture> mImage;
+ BOOL mUniformScaling;
+ BOOL mNoClip;
+};
+
+namespace LLInitParam
+{
+ template<>
+ class ParamValue<LLUIImage*>
+ : public CustomParamValue<LLUIImage*>
+ {
+ typedef boost::add_reference<boost::add_const<LLUIImage*>::type>::type T_const_ref;
+ typedef CustomParamValue<LLUIImage*> super_t;
+ public:
+ Optional<std::string> name;
+
+ ParamValue(LLUIImage* const& image = NULL)
+ : super_t(image)
+ {
+ updateBlockFromValue(false);
+ addSynonym(name, "name");
+ }
+
+ void updateValueFromBlock();
+ void updateBlockFromValue(bool make_block_authoritative);
+ };
+
+ // Need custom comparison function for our test app, which only loads
+ // LLUIImage* as NULL.
+ template<>
+ struct ParamCompare<LLUIImage*, false>
+ {
+ static bool equals(LLUIImage* const &a, LLUIImage* const &b);
+ };
+}
+
+typedef LLPointer<LLUIImage> LLUIImagePtr;
+#endif
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 8b5503229f..e6f20cd40e 100644..100755
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -31,7 +31,6 @@
#include "llvertexbuffer.h"
// #include "llrender.h"
#include "llglheaders.h"
-#include "llmemtype.h"
#include "llrender.h"
#include "llvector4a.h"
#include "llshadermgr.h"
@@ -49,15 +48,55 @@ U32 nhpo2(U32 v)
return r;
}
+//which power of 2 is i?
+//assumes i is a power of 2 > 0
+U32 wpo2(U32 i)
+{
+ llassert(i > 0);
+ llassert(nhpo2(i) == i);
+
+ U32 r = 0;
+
+ while (i >>= 1) ++r;
+
+ return r;
+}
+
+
+const U32 LL_VBO_BLOCK_SIZE = 2048;
+const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024;
+
+U32 vbo_block_size(U32 size)
+{ //what block size will fit size?
+ U32 mod = size % LL_VBO_BLOCK_SIZE;
+ return mod == 0 ? size : size + (LL_VBO_BLOCK_SIZE-mod);
+}
+
+U32 vbo_block_index(U32 size)
+{
+ return vbo_block_size(size)/LL_VBO_BLOCK_SIZE;
+}
+
+const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE);
+
//============================================================================
//static
LLVBOPool LLVertexBuffer::sStreamVBOPool(GL_STREAM_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
+LLVBOPool LLVertexBuffer::sDynamicCopyVBOPool(GL_DYNAMIC_COPY_ARB, GL_ARRAY_BUFFER_ARB);
LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
+
U32 LLVBOPool::sBytesPooled = 0;
+U32 LLVBOPool::sIndexBytesPooled = 0;
+
+std::list<U32> LLVertexBuffer::sAvailableVAOName;
+U32 LLVertexBuffer::sCurVAOName = 1;
+
+U32 LLVertexBuffer::sAllocatedIndexBytes = 0;
+U32 LLVertexBuffer::sIndexCount = 0;
LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL;
U32 LLVertexBuffer::sBindCount = 0;
@@ -74,104 +113,85 @@ U32 LLVertexBuffer::sLastMask = 0;
bool LLVertexBuffer::sVBOActive = false;
bool LLVertexBuffer::sIBOActive = false;
U32 LLVertexBuffer::sAllocatedBytes = 0;
+U32 LLVertexBuffer::sVertexCount = 0;
bool LLVertexBuffer::sMapped = false;
bool LLVertexBuffer::sUseStreamDraw = true;
bool LLVertexBuffer::sUseVAO = false;
bool LLVertexBuffer::sPreferStreamDraw = false;
-const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms
-class LLGLSyncFence : public LLGLFence
+U32 LLVBOPool::genBuffer()
{
-public:
-#ifdef GL_ARB_sync
- GLsync mSync;
-#endif
+ U32 ret = 0;
+
+ glGenBuffersARB(1, &ret);
- LLGLSyncFence()
- {
-#ifdef GL_ARB_sync
- mSync = 0;
-#endif
- }
+ return ret;
+}
- virtual ~LLGLSyncFence()
+void LLVBOPool::deleteBuffer(U32 name)
+{
+ if (gGLManager.mInited)
{
-#ifdef GL_ARB_sync
- if (mSync)
- {
- glDeleteSync(mSync);
- }
-#endif
- }
+ LLVertexBuffer::unbind();
- void placeFence()
- {
-#ifdef GL_ARB_sync
- if (mSync)
- {
- glDeleteSync(mSync);
- }
- mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-#endif
- }
+ glBindBufferARB(mType, name);
+ glBufferDataARB(mType, 0, NULL, mUsage);
+ glBindBufferARB(mType, 0);
- void wait()
- {
-#ifdef GL_ARB_sync
- if (mSync)
- {
- while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
- { //track the number of times we've waited here
- static S32 waits = 0;
- waits++;
- }
- }
-#endif
+ glDeleteBuffersARB(1, &name);
}
+}
-};
-
-
-//which power of 2 is i?
-//assumes i is a power of 2 > 0
-U32 wpo2(U32 i)
+LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType)
+: mUsage(vboUsage), mType(vboType)
{
- llassert(i > 0);
- llassert(nhpo2(i) == i);
-
- U32 r = 0;
-
- while (i >>= 1) ++r;
-
- return r;
+ mMissCount.resize(LL_VBO_POOL_SEED_COUNT);
+ std::fill(mMissCount.begin(), mMissCount.end(), 0);
}
-volatile U8* LLVBOPool::allocate(U32& name, U32 size)
+volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
{
- llassert(nhpo2(size) == size);
+ llassert(vbo_block_size(size) == size);
+
+ volatile U8* ret = NULL;
- U32 i = wpo2(size);
+ U32 i = vbo_block_index(size);
if (mFreeList.size() <= i)
{
mFreeList.resize(i+1);
}
- volatile U8* ret = NULL;
-
- if (mFreeList[i].empty())
+ if (mFreeList[i].empty() || for_seed)
{
//make a new buffer
- glGenBuffersARB(1, &name);
+ name = genBuffer();
+
glBindBufferARB(mType, name);
- LLVertexBuffer::sAllocatedBytes += size;
+
+ if (!for_seed && i < LL_VBO_POOL_SEED_COUNT)
+ { //record this miss
+ mMissCount[i]++;
+ }
+
+ if (mType == GL_ARRAY_BUFFER_ARB)
+ {
+ LLVertexBuffer::sAllocatedBytes += size;
+ }
+ else
+ {
+ LLVertexBuffer::sAllocatedIndexBytes += size;
+ }
if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB)
{
glBufferDataARB(mType, size, 0, mUsage);
- ret = (U8*) ll_aligned_malloc_16(size);
+ if (mUsage != GL_DYNAMIC_COPY_ARB)
+ { //data will be provided by application
+ ret = (U8*) ll_aligned_malloc(size, 64);
+ }
}
else
{ //always use a true hint of static draw when allocating non-client-backed buffers
@@ -179,13 +199,39 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size)
}
glBindBufferARB(mType, 0);
+
+ if (for_seed)
+ { //put into pool for future use
+ llassert(mFreeList.size() > i);
+
+ Record rec;
+ rec.mGLName = name;
+ rec.mClientData = ret;
+
+ if (mType == GL_ARRAY_BUFFER_ARB)
+ {
+ sBytesPooled += size;
+ }
+ else
+ {
+ sIndexBytesPooled += size;
+ }
+ mFreeList[i].push_back(rec);
+ }
}
else
{
name = mFreeList[i].front().mGLName;
ret = mFreeList[i].front().mClientData;
- sBytesPooled -= size;
+ if (mType == GL_ARRAY_BUFFER_ARB)
+ {
+ sBytesPooled -= size;
+ }
+ else
+ {
+ sIndexBytesPooled -= size;
+ }
mFreeList[i].pop_front();
}
@@ -195,30 +241,50 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size)
void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
{
- llassert(nhpo2(size) == size);
+ llassert(vbo_block_size(size) == size);
- U32 i = wpo2(size);
+ deleteBuffer(name);
+ ll_aligned_free((U8*) buffer);
- llassert(mFreeList.size() > i);
-
- Record rec;
- rec.mGLName = name;
- rec.mClientData = buffer;
-
- if (buffer == NULL)
+ if (mType == GL_ARRAY_BUFFER_ARB)
{
- glDeleteBuffersARB(1, &rec.mGLName);
+ LLVertexBuffer::sAllocatedBytes -= size;
}
else
{
- sBytesPooled += size;
- mFreeList[i].push_back(rec);
+ LLVertexBuffer::sAllocatedIndexBytes -= size;
+ }
+}
+
+void LLVBOPool::seedPool()
+{
+ U32 dummy_name = 0;
+
+ if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT)
+ {
+ mFreeList.resize(LL_VBO_POOL_SEED_COUNT);
+ }
+
+ for (U32 i = 0; i < LL_VBO_POOL_SEED_COUNT; i++)
+ {
+ if (mMissCount[i] > mFreeList[i].size())
+ {
+ U32 size = i*LL_VBO_BLOCK_SIZE;
+
+ S32 count = mMissCount[i] - mFreeList[i].size();
+ for (U32 j = 0; j < count; ++j)
+ {
+ allocate(dummy_name, size, true);
+ }
+ }
}
}
+
+
void LLVBOPool::cleanup()
{
- U32 size = 1;
+ U32 size = LL_VBO_BLOCK_SIZE;
for (U32 i = 0; i < mFreeList.size(); ++i)
{
@@ -228,21 +294,32 @@ void LLVBOPool::cleanup()
{
Record& r = l.front();
- glDeleteBuffersARB(1, &r.mGLName);
-
+ deleteBuffer(r.mGLName);
+
if (r.mClientData)
{
- ll_aligned_free_16((void*) r.mClientData);
+ ll_aligned_free((void*) r.mClientData);
}
l.pop_front();
- LLVertexBuffer::sAllocatedBytes -= size;
- sBytesPooled -= size;
+ if (mType == GL_ARRAY_BUFFER_ARB)
+ {
+ sBytesPooled -= size;
+ LLVertexBuffer::sAllocatedBytes -= size;
+ }
+ else
+ {
+ sIndexBytesPooled -= size;
+ LLVertexBuffer::sAllocatedIndexBytes -= size;
+ }
}
- size *= 2;
+ size += LL_VBO_BLOCK_SIZE;
}
+
+ //reset miss counts
+ std::fill(mMissCount.begin(), mMissCount.end(), 0);
}
@@ -257,13 +334,32 @@ S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
sizeof(LLVector2), // TYPE_TEXCOORD3,
sizeof(LLColor4U), // TYPE_COLOR,
sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently
- sizeof(LLVector4), // TYPE_BINORMAL,
+ sizeof(LLVector4), // TYPE_TANGENT,
sizeof(F32), // TYPE_WEIGHT,
sizeof(LLVector4), // TYPE_WEIGHT4,
sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes
};
+static std::string vb_type_name[] =
+{
+ "TYPE_VERTEX",
+ "TYPE_NORMAL",
+ "TYPE_TEXCOORD0",
+ "TYPE_TEXCOORD1",
+ "TYPE_TEXCOORD2",
+ "TYPE_TEXCOORD3",
+ "TYPE_COLOR",
+ "TYPE_EMISSIVE",
+ "TYPE_TANGENT",
+ "TYPE_WEIGHT",
+ "TYPE_WEIGHT4",
+ "TYPE_CLOTHWEIGHT",
+ "TYPE_TEXTURE_INDEX",
+ "TYPE_MAX",
+ "TYPE_INDEX",
+};
+
U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
{
GL_TRIANGLES,
@@ -276,13 +372,48 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
GL_LINE_LOOP,
};
+//static
+U32 LLVertexBuffer::getVAOName()
+{
+ U32 ret = 0;
+
+ if (!sAvailableVAOName.empty())
+ {
+ ret = sAvailableVAOName.front();
+ sAvailableVAOName.pop_front();
+ }
+ else
+ {
+#ifdef GL_ARB_vertex_array_object
+ glGenVertexArrays(1, &ret);
+#endif
+ }
+
+ return ret;
+}
+
+//static
+void LLVertexBuffer::releaseVAOName(U32 name)
+{
+ sAvailableVAOName.push_back(name);
+}
+
+
+//static
+void LLVertexBuffer::seedPools()
+{
+ sStreamVBOPool.seedPool();
+ sDynamicVBOPool.seedPool();
+ sDynamicCopyVBOPool.seedPool();
+ sStreamIBOPool.seedPool();
+ sDynamicIBOPool.seedPool();
+}
//static
void LLVertexBuffer::setupClientArrays(U32 data_mask)
{
if (sLastMask != data_mask)
{
- bool error = false;
if (gGLManager.mGLSLVersionMajor < 2 && gGLManager.mGLSLVersionMinor < 30)
{
@@ -349,7 +480,6 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
{
if (gDebugSession)
{
- error = true;
gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
}
else
@@ -369,7 +499,6 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
if (gDebugSession)
{
- error = true;
gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
}
else
@@ -406,16 +535,16 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
}
}
- if (sLastMask & MAP_BINORMAL)
+ if (sLastMask & MAP_TANGENT)
{
- if (!(data_mask & MAP_BINORMAL))
+ if (!(data_mask & MAP_TANGENT))
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
- else if (data_mask & MAP_BINORMAL)
+ else if (data_mask & MAP_TANGENT)
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -428,14 +557,29 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
}
//static
+static LLFastTimer::DeclareTimer FTM_VB_DRAW_ARRAYS("drawArrays");
void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
{
+ LLFastTimer t(FTM_VB_DRAW_ARRAYS);
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
gGL.syncMatrices();
U32 count = pos.size();
- llassert_always(norm.size() >= pos.size());
- llassert_always(count > 0);
+
+ llassert(norm.size() >= pos.size());
+ llassert(count > 0);
+
+ if( count == 0 )
+ {
+ llwarns << "Called drawArrays with 0 vertices" << llendl;
+ return;
+ }
+
+ if( norm.size() < pos.size() )
+ {
+ llwarns << "Called drawArrays with #" << norm.size() << " normals and #" << pos.size() << " vertices" << llendl;
+ return;
+ }
unbind();
@@ -461,8 +605,9 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, con
glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
glNormalPointer(GL_FLOAT, 0, norm[0].mV);
}
-
+ LLGLSLShader::startProfile();
glDrawArrays(sGLMode[mode], 0, count);
+ LLGLSLShader::stopProfile(count, mode);
}
//static
@@ -499,7 +644,9 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto
glVertexPointer(3, GL_FLOAT, 16, pos);
}
+ LLGLSLShader::startProfile();
glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
+ LLGLSLShader::stopProfile(num_indices, mode);
}
void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
@@ -599,9 +746,14 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
U16* idx = ((U16*) getIndicesPointer())+indices_offset;
stop_glerror();
+ LLGLSLShader::startProfile();
glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
idx);
+ LLGLSLShader::stopProfile(count, mode);
stop_glerror();
+
+
+
placeFence();
}
@@ -645,12 +797,15 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
}
stop_glerror();
+ LLGLSLShader::startProfile();
glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
((U16*) getIndicesPointer()) + indices_offset);
+ LLGLSLShader::stopProfile(count, mode);
stop_glerror();
placeFence();
}
+static LLFastTimer::DeclareTimer FTM_GL_DRAW_ARRAYS("GL draw arrays");
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
{
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
@@ -685,8 +840,14 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
return;
}
+ {
+ LLFastTimer t2(FTM_GL_DRAW_ARRAYS);
stop_glerror();
+ LLGLSLShader::startProfile();
glDrawArrays(sGLMode[mode], first, count);
+ LLGLSLShader::stopProfile(count, mode);
+ }
+
stop_glerror();
placeFence();
}
@@ -736,13 +897,13 @@ void LLVertexBuffer::unbind()
//static
void LLVertexBuffer::cleanupClass()
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS);
unbind();
sStreamIBOPool.cleanup();
sDynamicIBOPool.cleanup();
sStreamVBOPool.cleanup();
sDynamicVBOPool.cleanup();
+ sDynamicCopyVBOPool.cleanup();
if(sPrivatePoolp)
{
@@ -779,6 +940,8 @@ S32 LLVertexBuffer::determineUsage(S32 usage)
if (ret_usage && ret_usage != GL_STREAM_DRAW_ARB)
{ //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default
+ if (ret_usage != GL_DYNAMIC_COPY_ARB)
+ {
if (sDisableVBOMapping)
{ //always use stream draw if VBO mapping is disabled
ret_usage = GL_STREAM_DRAW_ARB;
@@ -788,6 +951,7 @@ S32 LLVertexBuffer::determineUsage(S32 usage)
ret_usage = GL_DYNAMIC_DRAW_ARB;
}
}
+ }
return ret_usage;
}
@@ -817,8 +981,6 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
mMappable(false),
mFence(NULL)
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR);
-
mMappable = (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping);
//zero out offsets
@@ -878,14 +1040,13 @@ S32 LLVertexBuffer::getSize() const
//virtual
LLVertexBuffer::~LLVertexBuffer()
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR);
destroyGLBuffer();
destroyGLIndices();
if (mGLArray)
{
#if GL_ARB_vertex_array_object
- glDeleteVertexArrays(1, &mGLArray);
+ releaseVAOName(mGLArray);
#endif
}
@@ -898,6 +1059,9 @@ LLVertexBuffer::~LLVertexBuffer()
mFence = NULL;
+ sVertexCount -= mNumVerts;
+ sIndexCount -= mNumIndices;
+
llassert_always(!mMappedData && !mMappedIndexData);
};
@@ -929,23 +1093,28 @@ void LLVertexBuffer::waitFence() const
void LLVertexBuffer::genBuffer(U32 size)
{
- mSize = nhpo2(size);
+ mSize = vbo_block_size(size);
if (mUsage == GL_STREAM_DRAW_ARB)
{
mMappedData = sStreamVBOPool.allocate(mGLBuffer, mSize);
}
- else
+ else if (mUsage == GL_DYNAMIC_DRAW_ARB)
{
mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize);
}
+ else
+ {
+ mMappedData = sDynamicCopyVBOPool.allocate(mGLBuffer, mSize);
+ }
+
sGLCount++;
}
void LLVertexBuffer::genIndices(U32 size)
{
- mIndicesSize = nhpo2(size);
+ mIndicesSize = vbo_block_size(size);
if (mUsage == GL_STREAM_DRAW_ARB)
{
@@ -995,8 +1164,6 @@ void LLVertexBuffer::releaseIndices()
void LLVertexBuffer::createGLBuffer(U32 size)
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES);
-
if (mGLBuffer)
{
destroyGLBuffer();
@@ -1026,8 +1193,6 @@ void LLVertexBuffer::createGLBuffer(U32 size)
void LLVertexBuffer::createGLIndices(U32 size)
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES);
-
if (mGLIndices)
{
destroyGLIndices();
@@ -1062,7 +1227,6 @@ void LLVertexBuffer::createGLIndices(U32 size)
void LLVertexBuffer::destroyGLBuffer()
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER);
if (mGLBuffer)
{
if (mMappedDataUsingVBOs)
@@ -1083,7 +1247,6 @@ void LLVertexBuffer::destroyGLBuffer()
void LLVertexBuffer::destroyGLIndices()
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES);
if (mGLIndices)
{
if (mMappedIndexDataUsingVBOs)
@@ -1104,14 +1267,12 @@ void LLVertexBuffer::destroyGLIndices()
void LLVertexBuffer::updateNumVerts(S32 nverts)
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS);
-
llassert(nverts >= 0);
- if (nverts >= 65535)
+ if (nverts > 65536)
{
llwarns << "Vertex buffer overflow!" << llendl;
- nverts = 65535;
+ nverts = 65536;
}
U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
@@ -1121,13 +1282,13 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
createGLBuffer(needed_size);
}
+ sVertexCount -= mNumVerts;
mNumVerts = nverts;
+ sVertexCount += mNumVerts;
}
void LLVertexBuffer::updateNumIndices(S32 nindices)
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES);
-
llassert(nindices >= 0);
U32 needed_size = sizeof(U16) * nindices;
@@ -1137,13 +1298,13 @@ void LLVertexBuffer::updateNumIndices(S32 nindices)
createGLIndices(needed_size);
}
+ sIndexCount -= mNumIndices;
mNumIndices = nindices;
+ sIndexCount += mNumIndices;
}
void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER);
-
stop_glerror();
if (nverts < 0 || nindices < 0 ||
@@ -1160,10 +1321,10 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
//actually allocate space for the vertex buffer if using VBO mapping
flush();
- if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO))
+ if (gGLManager.mHasVertexArrayObject && useVBOs() && sUseVAO)
{
#if GL_ARB_vertex_array_object
- glGenVertexArrays(1, &mGLArray);
+ mGLArray = getVAOName();
#endif
setupVertexArray();
}
@@ -1195,11 +1356,11 @@ void LLVertexBuffer::setupVertexArray()
2, //TYPE_TEXCOORD3,
4, //TYPE_COLOR,
4, //TYPE_EMISSIVE,
- 3, //TYPE_BINORMAL,
+ 4, //TYPE_TANGENT,
1, //TYPE_WEIGHT,
4, //TYPE_WEIGHT4,
4, //TYPE_CLOTHWEIGHT,
- 4, //TYPE_TEXTURE_INDEX
+ 1, //TYPE_TEXTURE_INDEX
};
U32 attrib_type[] =
@@ -1212,11 +1373,11 @@ void LLVertexBuffer::setupVertexArray()
GL_FLOAT, //TYPE_TEXCOORD3,
GL_UNSIGNED_BYTE, //TYPE_COLOR,
GL_UNSIGNED_BYTE, //TYPE_EMISSIVE,
- GL_FLOAT, //TYPE_BINORMAL,
+ GL_FLOAT, //TYPE_TANGENT,
GL_FLOAT, //TYPE_WEIGHT,
GL_FLOAT, //TYPE_WEIGHT4,
GL_FLOAT, //TYPE_CLOTHWEIGHT,
- GL_UNSIGNED_BYTE, //TYPE_TEXTURE_INDEX
+ GL_UNSIGNED_INT, //TYPE_TEXTURE_INDEX
};
bool attrib_integer[] =
@@ -1229,7 +1390,7 @@ void LLVertexBuffer::setupVertexArray()
false, //TYPE_TEXCOORD3,
false, //TYPE_COLOR,
false, //TYPE_EMISSIVE,
- false, //TYPE_BINORMAL,
+ false, //TYPE_TANGENT,
false, //TYPE_WEIGHT,
false, //TYPE_WEIGHT4,
false, //TYPE_CLOTHWEIGHT,
@@ -1246,7 +1407,7 @@ void LLVertexBuffer::setupVertexArray()
GL_FALSE, //TYPE_TEXCOORD3,
GL_TRUE, //TYPE_COLOR,
GL_TRUE, //TYPE_EMISSIVE,
- GL_FALSE, //TYPE_BINORMAL,
+ GL_FALSE, //TYPE_TANGENT,
GL_FALSE, //TYPE_WEIGHT,
GL_FALSE, //TYPE_WEIGHT4,
GL_FALSE, //TYPE_CLOTHWEIGHT,
@@ -1294,8 +1455,6 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
llassert(newnverts >= 0);
llassert(newnindices >= 0);
- LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER);
-
updateNumVerts(newnverts);
updateNumIndices(newnindices);
@@ -1343,7 +1502,6 @@ static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map");
volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
{
bindGLBuffer(true);
- LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
if (mFinal)
{
llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl;
@@ -1392,7 +1550,6 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
if (!mVertexLocked)
{
- LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES);
mVertexLocked = true;
sMappedCount++;
stop_glerror();
@@ -1445,8 +1602,10 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
{
if (map_range)
{
+#ifndef LL_MESA_HEADLESS
glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
+#endif
src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
else
@@ -1523,7 +1682,6 @@ static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map");
volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
bindGLIndices(true);
if (mFinal)
{
@@ -1570,8 +1728,6 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
if (!mIndexLocked)
{
- LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
-
mIndexLocked = true;
sMappedCount++;
stop_glerror();
@@ -1623,8 +1779,10 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
{
if (map_range)
{
+#ifndef LL_MESA_HEADLESS
glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
+#endif
src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
else
@@ -1694,7 +1852,6 @@ static LLFastTimer::DeclareTimer FTM_IBO_FLUSH_RANGE("Flush IBO Range");
void LLVertexBuffer::unmapBuffer()
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER);
if (!useVBOs())
{
return; //nothing to unmap
@@ -1752,7 +1909,9 @@ void LLVertexBuffer::unmapBuffer()
}
else if (gGLManager.mHasFlushBufferRange)
{
+#ifndef LL_MESA_HEADLESS
glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length);
+#endif
}
stop_glerror();
}
@@ -1818,8 +1977,10 @@ void LLVertexBuffer::unmapBuffer()
else if (gGLManager.mHasFlushBufferRange)
{
#ifdef GL_APPLE_flush_buffer_range
+#ifndef LL_MESA_HEADLESS
glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
#endif
+#endif
}
stop_glerror();
}
@@ -1911,14 +2072,21 @@ bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 inde
{
return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range);
}
-
+bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index, count, map_range);
+}
bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
{
return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range);
}
-bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector3,TYPE_TANGENT>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range)
{
- return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLVector4a,TYPE_TANGENT>::get(*this, strider, index, count, map_range);
}
bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
{
@@ -1978,21 +2146,14 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind)
if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
{
- LLFastTimer t(FTM_BIND_GL_BUFFER);
- /*if (sMapped)
- {
- llerrs << "VBO bound while another VBO mapped!" << llendl;
- }*/
+ //LLFastTimer t(FTM_BIND_GL_BUFFER); <-- this timer is showing up as a hotspot (irony)
+
glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
sBindCount++;
sVBOActive = true;
- if (mGLArray)
- {
- llassert(sGLRenderArray == mGLArray);
- //mCachedRenderBuffer = mGLBuffer;
- }
+ llassert(!mGLArray || sGLRenderArray == mGLArray);
ret = true;
}
@@ -2033,12 +2194,21 @@ void LLVertexBuffer::flush()
}
}
+// bind for transform feedback (quick 'n dirty)
+void LLVertexBuffer::bindForFeedback(U32 channel, U32 type, U32 index, U32 count)
+{
+#ifdef GL_TRANSFORM_FEEDBACK_BUFFER
+ U32 offset = mOffsets[type] + sTypeSize[type]*index;
+ U32 size= (sTypeSize[type]*count);
+ glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, channel, mGLBuffer, offset, size);
+#endif
+}
+
// Set for rendering
void LLVertexBuffer::setBuffer(U32 data_mask)
{
flush();
- LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER);
//set up pointers if the data mask is different ...
bool setup = (sLastMask != data_mask);
@@ -2064,6 +2234,37 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
if ((data_mask & required_mask) != required_mask)
{
+
+ U32 unsatisfied_mask = (required_mask & ~data_mask);
+ U32 i = 0;
+
+ while (i < TYPE_MAX)
+ {
+ U32 unsatisfied_flag = unsatisfied_mask & (1 << i);
+ switch (unsatisfied_flag)
+ {
+ case MAP_VERTEX: llinfos << "Missing vert pos" << llendl; break;
+ case MAP_NORMAL: llinfos << "Missing normals" << llendl; break;
+ case MAP_TEXCOORD0: llinfos << "Missing TC 0" << llendl; break;
+ case MAP_TEXCOORD1: llinfos << "Missing TC 1" << llendl; break;
+ case MAP_TEXCOORD2: llinfos << "Missing TC 2" << llendl; break;
+ case MAP_TEXCOORD3: llinfos << "Missing TC 3" << llendl; break;
+ case MAP_COLOR: llinfos << "Missing vert color" << llendl; break;
+ case MAP_EMISSIVE: llinfos << "Missing emissive" << llendl; break;
+ case MAP_TANGENT: llinfos << "Missing tangent" << llendl; break;
+ case MAP_WEIGHT: llinfos << "Missing weight" << llendl; break;
+ case MAP_WEIGHT4: llinfos << "Missing weightx4" << llendl; break;
+ case MAP_CLOTHWEIGHT: llinfos << "Missing clothweight" << llendl; break;
+ case MAP_TEXTURE_INDEX: llinfos << "Missing tex index" << llendl; break;
+ default: llinfos << "Missing who effin knows: " << unsatisfied_flag << llendl;
+ }
+ }
+
+ if (unsatisfied_mask & (1 << TYPE_INDEX))
+ {
+ llinfos << "Missing indices" << llendl;
+ }
+
llerrs << "Shader consumption mismatches data provision." << llendl;
}
}
@@ -2084,7 +2285,6 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
setup = setup || bindBuffer || bindIndices;
}
- bool error = false;
if (gDebugGL && !mGLArray)
{
GLint buff;
@@ -2093,7 +2293,6 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
{
if (gDebugSession)
{
- error = true;
gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl;
}
else
@@ -2109,7 +2308,6 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
{
if (gDebugSession)
{
- error = true;
gFailLog << "Invalid GL index buffer bound: " << buff << std::endl;
}
else
@@ -2180,14 +2378,21 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
// virtual (default)
void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER);
stop_glerror();
volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
- /*if ((data_mask & mTypeMask) != data_mask)
+ if (gDebugGL && ((data_mask & mTypeMask) != data_mask))
{
+ for (U32 i = 0; i < LLVertexBuffer::TYPE_MAX; ++i)
+ {
+ U32 mask = 1 << i;
+ if (mask & data_mask && !(mask & mTypeMask))
+ { //bit set in data_mask, but not set in mTypeMask
+ llwarns << "Missing required component " << vb_type_name[i] << llendl;
+ }
+ }
llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
- }*/
+ }
if (LLGLSLShader::sNoFixedFunction)
{
@@ -2215,11 +2420,11 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
}
- if (data_mask & MAP_BINORMAL)
+ if (data_mask & MAP_TANGENT)
{
- S32 loc = TYPE_BINORMAL;
- void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]);
- glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr);
+ S32 loc = TYPE_TANGENT;
+ void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
+ glVertexAttribPointerARB(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
}
if (data_mask & MAP_TEXCOORD0)
{
@@ -2230,7 +2435,8 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
if (data_mask & MAP_COLOR)
{
S32 loc = TYPE_COLOR;
- void* ptr = (void*)(base + mOffsets[TYPE_COLOR]);
+ //bind emissive instead of color pointer if emissive is present
+ void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
}
if (data_mask & MAP_EMISSIVE)
@@ -2238,6 +2444,12 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
S32 loc = TYPE_EMISSIVE;
void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
+
+ if (!(data_mask & MAP_COLOR))
+ { //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps
+ loc = TYPE_COLOR;
+ glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
+ }
}
if (data_mask & MAP_WEIGHT)
{
@@ -2263,7 +2475,7 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
#if !LL_DARWIN
S32 loc = TYPE_TEXTURE_INDEX;
void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
- glVertexAttribIPointer(loc, 4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+ glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
#endif
}
if (data_mask & MAP_VERTEX)
@@ -2297,10 +2509,10 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
- if (data_mask & MAP_BINORMAL)
+ if (data_mask & MAP_TANGENT)
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+ glTexCoordPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT]));
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
if (data_mask & MAP_TEXCOORD0)
@@ -2323,8 +2535,7 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count)
: mType(type), mIndex(index), mCount(count)
{
- llassert(mType == LLVertexBuffer::TYPE_INDEX ||
- mType < LLVertexBuffer::TYPE_TEXTURE_INDEX);
+ mEnd = mIndex+mCount;
}
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index d859199663..619a0cec46 100644..100755
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -55,24 +55,28 @@ class LLVBOPool
{
public:
static U32 sBytesPooled;
+ static U32 sIndexBytesPooled;
- LLVBOPool(U32 vboUsage, U32 vboType)
- : mUsage(vboUsage)
- , mType(vboType)
- {}
-
+ LLVBOPool(U32 vboUsage, U32 vboType);
+
const U32 mUsage;
const U32 mType;
//size MUST be a power of 2
- volatile U8* allocate(U32& name, U32 size);
+ volatile U8* allocate(U32& name, U32 size, bool for_seed = false);
//size MUST be the size provided to allocate that returned the given name
void release(U32 name, volatile U8* buffer, U32 size);
+ //batch allocate buffers to be provided to the application on demand
+ void seedPool();
+
//destroy all records in mFreeList
void cleanup();
+ U32 genBuffer();
+ void deleteBuffer(U32 name);
+
class Record
{
public:
@@ -82,15 +86,11 @@ public:
typedef std::list<Record> record_list_t;
std::vector<record_list_t> mFreeList;
-};
+ std::vector<U32> mMissCount;
-class LLGLFence
-{
-public:
- virtual void placeFence() = 0;
- virtual void wait() = 0;
};
+
//============================================================================
// base class
class LLPrivateMemoryPool;
@@ -103,6 +103,7 @@ public:
S32 mType;
S32 mIndex;
S32 mCount;
+ S32 mEnd;
MappedRegion(S32 type, S32 index, S32 count);
};
@@ -121,16 +122,26 @@ public:
static LLVBOPool sStreamVBOPool;
static LLVBOPool sDynamicVBOPool;
+ static LLVBOPool sDynamicCopyVBOPool;
static LLVBOPool sStreamIBOPool;
static LLVBOPool sDynamicIBOPool;
+
+ static std::list<U32> sAvailableVAOName;
+ static U32 sCurVAOName;
static bool sUseStreamDraw;
static bool sUseVAO;
static bool sPreferStreamDraw;
+ static void seedPools();
+
+ static U32 getVAOName();
+ static void releaseVAOName(U32 name);
+
static void initClass(bool use_vbo, bool no_vbo_mapping);
static void cleanupClass();
static void setupClientArrays(U32 data_mask);
+ static void pushPositions(U32 mode, const LLVector4a* pos, U32 count);
static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
@@ -161,7 +172,7 @@ public:
TYPE_TEXCOORD3,
TYPE_COLOR,
TYPE_EMISSIVE,
- TYPE_BINORMAL,
+ TYPE_TANGENT,
TYPE_WEIGHT,
TYPE_WEIGHT4,
TYPE_CLOTHWEIGHT,
@@ -179,7 +190,7 @@ public:
MAP_COLOR = (1<<TYPE_COLOR),
MAP_EMISSIVE = (1<<TYPE_EMISSIVE),
// These use VertexAttribPointer and should possibly be made generic
- MAP_BINORMAL = (1<<TYPE_BINORMAL),
+ MAP_TANGENT = (1<<TYPE_TANGENT),
MAP_WEIGHT = (1<<TYPE_WEIGHT),
MAP_WEIGHT4 = (1<<TYPE_WEIGHT4),
MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
@@ -207,7 +218,6 @@ protected:
void destroyGLIndices();
void updateNumVerts(S32 nverts);
void updateNumIndices(S32 nindices);
- bool useVBOs() const;
void unmapBuffer();
public:
@@ -217,6 +227,8 @@ public:
volatile U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
volatile U8* mapIndexBuffer(S32 index, S32 count, bool map_range);
+ void bindForFeedback(U32 channel, U32 type, U32 index, U32 count);
+
// set for rendering
virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0
void flush(); //flush pending data to GL memory
@@ -236,15 +248,19 @@ public:
bool getIndexStrider(LLStrider<U16>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+ bool getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+ bool getTangentStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+ bool getTangentStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+ bool getTextureIndexStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+ bool useVBOs() const;
bool isEmpty() const { return mEmpty; }
bool isLocked() const { return mVertexLocked || mIndexLocked; }
S32 getNumVerts() const { return mNumVerts; }
@@ -332,6 +348,9 @@ public:
static bool sIBOActive;
static U32 sLastMask;
static U32 sAllocatedBytes;
+ static U32 sAllocatedIndexBytes;
+ static U32 sVertexCount;
+ static U32 sIndexCount;
static U32 sBindCount;
static U32 sSetCount;
};