diff options
Diffstat (limited to 'indra/llrender/llglslshader.cpp')
-rw-r--r-- | indra/llrender/llglslshader.cpp | 3904 |
1 files changed, 1952 insertions, 1952 deletions
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 5c19931956..1651835b59 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -1,1952 +1,1952 @@ -/**
- * @file llglslshader.cpp
- * @brief GLSL helper functions and state.
- *
- * $LicenseInfo:firstyear=2005&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 "llglslshader.h"
-
-#include "llshadermgr.h"
-#include "llfile.h"
-#include "llrender.h"
-#include "llvertexbuffer.h"
-#include "llrendertarget.h"
-
-#include "hbxxh.h"
-#include "llsdserialize.h"
-
-#if LL_DARWIN
-#include "OpenGL/OpenGL.h"
-#endif
-
- // Print-print list of shader included source files that are linked together via glAttachShader()
- // i.e. On macOS / OSX the AMD GLSL linker will display an error if a varying is left in an undefined state.
-#define DEBUG_SHADER_INCLUDES 0
-
-// Lots of STL stuff in here, using namespace std to keep things more readable
-using std::vector;
-using std::pair;
-using std::make_pair;
-using std::string;
-
-GLuint LLGLSLShader::sCurBoundShader = 0;
-LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
-S32 LLGLSLShader::sIndexedTextureChannels = 0;
-bool LLGLSLShader::sProfileEnabled = false;
-std::set<LLGLSLShader*> LLGLSLShader::sInstances;
-LLGLSLShader::defines_map_t LLGLSLShader::sGlobalDefines;
-U64 LLGLSLShader::sTotalTimeElapsed = 0;
-U32 LLGLSLShader::sTotalTrianglesDrawn = 0;
-U64 LLGLSLShader::sTotalSamplesDrawn = 0;
-U32 LLGLSLShader::sTotalBinds = 0;
-
-//UI shader -- declared here so llui_libtest will link properly
-LLGLSLShader gUIProgram;
-LLGLSLShader gSolidColorProgram;
-
-// NOTE: Keep gShaderConsts* and LLGLSLShader::ShaderConsts_e in sync!
-const std::string gShaderConstsKey[LLGLSLShader::NUM_SHADER_CONSTS] =
-{
- "LL_SHADER_CONST_CLOUD_MOON_DEPTH"
- , "LL_SHADER_CONST_STAR_DEPTH"
-};
-
-// NOTE: Keep gShaderConsts* and LLGLSLShader::ShaderConsts_e in sync!
-const std::string gShaderConstsVal[LLGLSLShader::NUM_SHADER_CONSTS] =
-{
- "0.99998" // SHADER_CONST_CLOUD_MOON_DEPTH // SL-14113
- , "0.99999" // SHADER_CONST_STAR_DEPTH // SL-14113
-};
-
-
-bool shouldChange(const LLVector4& v1, const LLVector4& v2)
-{
- return v1 != v2;
-}
-
-//===============================
-// LLGLSL Shader implementation
-//===============================
-
-//static
-void LLGLSLShader::initProfile()
-{
- sProfileEnabled = true;
- sTotalTimeElapsed = 0;
- sTotalTrianglesDrawn = 0;
- sTotalSamplesDrawn = 0;
- sTotalBinds = 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(bool emit_report)
-{
- sProfileEnabled = false;
-
- if (emit_report)
- {
- 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());
-
- bool unbound = false;
- for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
- {
- (*iter)->dumpStats();
- if ((*iter)->mBinds == 0)
- {
- unbound = true;
- }
- }
-
- LL_INFOS() << "-----------------------------------" << LL_ENDL;
- LL_INFOS() << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed / 1000000.f) << LL_ENDL;
- LL_INFOS() << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn / 1000000.f) << LL_ENDL;
- LL_INFOS() << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn / 1000000.f) << LL_ENDL;
- LL_INFOS() << "-----------------------------------" << LL_ENDL;
-
- if (unbound)
- {
- LL_INFOS() << "The following shaders were unused: " << LL_ENDL;
- for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
- {
- if ((*iter)->mBinds == 0)
- {
- LL_INFOS() << (*iter)->mName << LL_ENDL;
- }
- }
- }
- }
-}
-
-void LLGLSLShader::clearStats()
-{
- mTrianglesDrawn = 0;
- mTimeElapsed = 0;
- mSamplesDrawn = 0;
- mBinds = 0;
-}
-
-void LLGLSLShader::dumpStats()
-{
- if (mBinds > 0)
- {
- LL_INFOS() << "=============================================" << LL_ENDL;
- LL_INFOS() << mName << LL_ENDL;
- for (U32 i = 0; i < mShaderFiles.size(); ++i)
- {
- LL_INFOS() << mShaderFiles[i].first << LL_ENDL;
- }
- LL_INFOS() << "=============================================" << LL_ENDL;
-
- 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_binds = (F32)mBinds / (F32)sTotalBinds * 100.f;
-
- LL_INFOS() << "Triangles Drawn: " << mTrianglesDrawn << " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec) << LL_ENDL;
- LL_INFOS() << "Binds: " << mBinds << " " << llformat("(%.2f pct of total)", pct_binds) << LL_ENDL;
- LL_INFOS() << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << LL_ENDL;
- LL_INFOS() << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32)((F64)mTimeElapsed / (F64)sTotalTimeElapsed) * 100.f, ms) << LL_ENDL;
- }
-}
-
-//static
-void LLGLSLShader::startProfile()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- if (sProfileEnabled && sCurBoundShaderPtr)
- {
- sCurBoundShaderPtr->placeProfileQuery();
- }
-
-}
-
-//static
-void LLGLSLShader::stopProfile()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- if (sProfileEnabled && sCurBoundShaderPtr)
- {
- sCurBoundShaderPtr->unbind();
- }
-}
-
-void LLGLSLShader::placeProfileQuery(bool for_runtime)
-{
- if (sProfileEnabled || for_runtime)
- {
- if (mTimerQuery == 0)
- {
- glGenQueries(1, &mSamplesQuery);
- glGenQueries(1, &mTimerQuery);
- glGenQueries(1, &mPrimitivesQuery);
- }
-
- glBeginQuery(GL_TIME_ELAPSED, mTimerQuery);
-
- if (!for_runtime)
- {
- glBeginQuery(GL_SAMPLES_PASSED, mSamplesQuery);
- glBeginQuery(GL_PRIMITIVES_GENERATED, mPrimitivesQuery);
- }
- }
-}
-
-bool LLGLSLShader::readProfileQuery(bool for_runtime, bool force_read)
-{
- if (sProfileEnabled || for_runtime)
- {
- if (!mProfilePending)
- {
- glEndQuery(GL_TIME_ELAPSED);
- if (!for_runtime)
- {
- glEndQuery(GL_SAMPLES_PASSED);
- glEndQuery(GL_PRIMITIVES_GENERATED);
- }
- mProfilePending = for_runtime;
- }
-
- if (mProfilePending && for_runtime && !force_read)
- {
- GLuint64 result = 0;
- glGetQueryObjectui64v(mTimerQuery, GL_QUERY_RESULT_AVAILABLE, &result);
-
- if (result != GL_TRUE)
- {
- return false;
- }
- }
-
- GLuint64 time_elapsed = 0;
- glGetQueryObjectui64v(mTimerQuery, GL_QUERY_RESULT, &time_elapsed);
- mTimeElapsed += time_elapsed;
- mProfilePending = false;
-
- if (!for_runtime)
- {
- GLuint64 samples_passed = 0;
- glGetQueryObjectui64v(mSamplesQuery, GL_QUERY_RESULT, &samples_passed);
-
- U64 primitives_generated = 0;
- glGetQueryObjectui64v(mPrimitivesQuery, GL_QUERY_RESULT, &primitives_generated);
- sTotalTimeElapsed += time_elapsed;
-
- sTotalSamplesDrawn += samples_passed;
- mSamplesDrawn += samples_passed;
-
- U32 tri_count = (U32)primitives_generated / 3;
-
- mTrianglesDrawn += tri_count;
- sTotalTrianglesDrawn += tri_count;
-
- sTotalBinds++;
- mBinds++;
- }
- }
-
- return true;
-}
-
-
-
-LLGLSLShader::LLGLSLShader()
- : mProgramObject(0),
- mAttributeMask(0),
- mTotalUniformSize(0),
- mActiveTextureChannels(0),
- mShaderLevel(0),
- mShaderGroup(SG_DEFAULT),
- mFeatures(),
- mUniformsDirty(false),
- mTimerQuery(0),
- mSamplesQuery(0),
- mPrimitivesQuery(0)
-{
-
-}
-
-LLGLSLShader::~LLGLSLShader()
-{
-}
-
-void LLGLSLShader::unload()
-{
- mShaderFiles.clear();
- mDefines.clear();
- mFeatures = LLShaderFeatures();
-
- unloadInternal();
-}
-
-void LLGLSLShader::unloadInternal()
-{
- sInstances.erase(this);
-
- stop_glerror();
- mAttribute.clear();
- mTexture.clear();
- mUniform.clear();
-
- if (mProgramObject)
- {
- GLuint obj[1024];
- GLsizei count = 0;
- glGetAttachedShaders(mProgramObject, 1024, &count, obj);
-
- for (GLsizei i = 0; i < count; i++)
- {
- glDetachShader(mProgramObject, obj[i]);
- }
-
- for (GLsizei i = 0; i < count; i++)
- {
- if (glIsShader(obj[i]))
- {
- glDeleteShader(obj[i]);
- }
- }
-
- glDeleteProgram(mProgramObject);
-
- mProgramObject = 0;
- }
-
- if (mTimerQuery)
- {
- glDeleteQueries(1, &mTimerQuery);
- mTimerQuery = 0;
- }
-
- if (mSamplesQuery)
- {
- glDeleteQueries(1, &mSamplesQuery);
- mSamplesQuery = 0;
- }
-
- //hack to make apple not complain
- glGetError();
-
- stop_glerror();
-}
-
-bool LLGLSLShader::createShader(std::vector<LLStaticHashedString>* attributes,
- std::vector<LLStaticHashedString>* uniforms,
- U32 varying_count,
- const char** varyings)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- unloadInternal();
-
- sInstances.insert(this);
-
- //reloading, reset matrix hash values
- for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i)
- {
- mMatHash[i] = 0xFFFFFFFF;
- }
- mLightHash = 0xFFFFFFFF;
-
- llassert_always(!mShaderFiles.empty());
-
-#if LL_DARWIN
- // work-around missing mix(vec3,vec3,bvec3)
- mDefines["OLD_SELECT"] = "1";
-#endif
-
- mShaderHash = hash();
-
- // Create program
- mProgramObject = glCreateProgram();
- if (mProgramObject == 0)
- {
- // Shouldn't happen if shader related extensions, like ARB_vertex_shader, exist.
- LL_SHADER_LOADING_WARNS() << "Failed to create handle for shader: " << mName << LL_ENDL;
- unloadInternal();
- return false;
- }
-
- bool success = true;
-
- mUsingBinaryProgram = LLShaderMgr::instance()->loadCachedProgramBinary(this);
-
- if (!mUsingBinaryProgram)
- {
-#if DEBUG_SHADER_INCLUDES
- fprintf(stderr, "--- %s ---\n", mName.c_str());
-#endif // DEBUG_SHADER_INCLUDES
-
- //compile new source
- vector< pair<string, GLenum> >::iterator fileIter = mShaderFiles.begin();
- for (; fileIter != mShaderFiles.end(); fileIter++)
- {
- GLuint 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)
- {
- attachObject(shaderhandle);
- }
- else
- {
- success = false;
- }
- }
- }
-
- // Attach existing objects
- if (!LLShaderMgr::instance()->attachShaderFeatures(this))
- {
- unloadInternal();
- return false;
- }
- // Map attributes and uniforms
- if (success)
- {
- success = mapAttributes(attributes);
- }
- if (success)
- {
- success = mapUniforms(uniforms);
- }
- if (!success)
- {
- LL_SHADER_LOADING_WARNS() << "Failed to link shader: " << mName << LL_ENDL;
-
- // Try again using a lower shader level;
- if (mShaderLevel > 0)
- {
- LL_SHADER_LOADING_WARNS() << "Failed to link using shader level " << mShaderLevel << " trying again using shader level " << (mShaderLevel - 1) << LL_ENDL;
- mShaderLevel--;
- return createShader(attributes, uniforms);
- }
- else
- {
- // Give up and unload shader.
- unloadInternal();
- }
- }
- else if (mFeatures.mIndexedTextureChannels > 0)
- { //override texture channels for indexed texture rendering
- bind();
- S32 channel_count = mFeatures.mIndexedTextureChannels;
-
- for (S32 i = 0; i < channel_count; i++)
- {
- LLStaticHashedString uniName(llformat("tex%d", i));
- uniform1i(uniName, i);
- }
-
- S32 cur_tex = channel_count; //adjust any texture channels that might have been overwritten
- for (U32 i = 0; i < mTexture.size(); i++)
- {
- if (mTexture[i] > -1 && mTexture[i] < channel_count)
- {
- llassert(cur_tex < gGLManager.mNumTextureImageUnits);
- uniform1i(i, cur_tex);
- mTexture[i] = cur_tex++;
- }
- }
- unbind();
- }
-
-#ifdef LL_PROFILER_ENABLE_RENDER_DOC
- setLabel(mName.c_str());
-#endif
-
- return success;
-}
-
-#if DEBUG_SHADER_INCLUDES
-void dumpAttachObject(const char* func_name, GLuint program_object, const std::string& object_path)
-{
- GLchar* info_log;
- GLint info_len_expect = 0;
- GLint info_len_actual = 0;
-
- glGetShaderiv(program_object, GL_INFO_LOG_LENGTH, , &info_len_expect);
- fprintf(stderr, " * %-20s(), log size: %d, %s\n", func_name, info_len_expect, object_path.c_str());
-
- if (info_len_expect > 0)
- {
- fprintf(stderr, " ========== %s() ========== \n", func_name);
- info_log = new GLchar[info_len_expect];
- glGetProgramInfoLog(program_object, info_len_expect, &info_len_actual, info_log);
- fprintf(stderr, "%s\n", info_log);
- delete[] info_log;
- }
-}
-#endif // DEBUG_SHADER_INCLUDES
-
-bool LLGLSLShader::attachVertexObject(std::string object_path)
-{
- if (LLShaderMgr::instance()->mVertexShaderObjects.count(object_path) > 0)
- {
- stop_glerror();
- glAttachShader(mProgramObject, LLShaderMgr::instance()->mVertexShaderObjects[object_path]);
-#if DEBUG_SHADER_INCLUDES
- dumpAttachObject("attachVertexObject", mProgramObject, object_path);
-#endif // DEBUG_SHADER_INCLUDES
- stop_glerror();
- return true;
- }
- else
- {
- LL_SHADER_LOADING_WARNS() << "Attempting to attach shader object: '" << object_path << "' that hasn't been compiled." << LL_ENDL;
- return false;
- }
-}
-
-bool LLGLSLShader::attachFragmentObject(std::string object_path)
-{
- if(mUsingBinaryProgram)
- return true;
-
- if (LLShaderMgr::instance()->mFragmentShaderObjects.count(object_path) > 0)
- {
- stop_glerror();
- glAttachShader(mProgramObject, LLShaderMgr::instance()->mFragmentShaderObjects[object_path]);
-#if DEBUG_SHADER_INCLUDES
- dumpAttachObject("attachFragmentObject", mProgramObject, object_path);
-#endif // DEBUG_SHADER_INCLUDES
- stop_glerror();
- return true;
- }
- else
- {
- LL_SHADER_LOADING_WARNS() << "Attempting to attach shader object: '" << object_path << "' that hasn't been compiled." << LL_ENDL;
- return false;
- }
-}
-
-void LLGLSLShader::attachObject(GLuint object)
-{
- if(mUsingBinaryProgram)
- return;
-
- if (object != 0)
- {
- stop_glerror();
- glAttachShader(mProgramObject, object);
-#if DEBUG_SHADER_INCLUDES
- std::string object_path("???");
- dumpAttachObject("attachObject", mProgramObject, object_path);
-#endif // DEBUG_SHADER_INCLUDES
- stop_glerror();
- }
- else
- {
- LL_SHADER_LOADING_WARNS() << "Attempting to attach non existing shader object. " << LL_ENDL;
- }
-}
-
-void LLGLSLShader::attachObjects(GLuint* objects, S32 count)
-{
- if(mUsingBinaryProgram)
- return;
-
- for (S32 i = 0; i < count; i++)
- {
- attachObject(objects[i]);
- }
-}
-
-bool LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString>* attributes)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- bool res = true;
- if (!mUsingBinaryProgram)
- {
- //before linking, make sure reserved attributes always have consistent locations
- for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
- {
- const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str();
- glBindAttribLocation(mProgramObject, i, (const GLchar*)name);
- }
-
- //link the program
- res = link();
- }
-
- mAttribute.clear();
- U32 numAttributes = (attributes == NULL) ? 0 : attributes->size();
-#if LL_RELEASE_WITH_DEBUG_INFO
- mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size() + numAttributes, { -1, NULL });
-#else
- mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size() + numAttributes, -1);
-#endif
-
- if (res)
- { //read back channel locations
-
- mAttributeMask = 0;
-
- //read back reserved channels first
- for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
- {
- const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str();
- S32 index = glGetAttribLocation(mProgramObject, (const GLchar*)name);
- if (index != -1)
- {
-#if LL_RELEASE_WITH_DEBUG_INFO
- mAttribute[i] = { index, name };
-#else
- mAttribute[i] = index;
-#endif
- mAttributeMask |= 1 << i;
- LL_DEBUGS("ShaderUniform") << "Attribute " << name << " assigned to channel " << index << LL_ENDL;
- }
- }
- if (attributes != NULL)
- {
- for (U32 i = 0; i < numAttributes; i++)
- {
- const char* name = (*attributes)[i].String().c_str();
- S32 index = glGetAttribLocation(mProgramObject, name);
- if (index != -1)
- {
- mAttribute[LLShaderMgr::instance()->mReservedAttribs.size() + i] = index;
- LL_DEBUGS("ShaderUniform") << "Attribute " << name << " assigned to channel " << index << LL_ENDL;
- }
- }
- }
-
- return true;
- }
-
- return false;
-}
-
-void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString>* uniforms)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- if (index == -1)
- {
- return;
- }
-
- GLenum type;
- GLsizei length;
- GLint size = -1;
- char name[1024]; /* Flawfinder: ignore */
- name[0] = 0;
-
-
- glGetActiveUniform(mProgramObject, index, 1024, &length, &size, &type, (GLchar*)name);
- 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;
- }
-
- S32 location = glGetUniformLocation(mProgramObject, name);
- if (location != -1)
- {
- //chop off "[0]" so we can always access the first element
- //of an array by the array name
- char* is_array = strstr(name, "[0]");
- if (is_array)
- {
- is_array[0] = 0;
- }
-
- LLStaticHashedString hashedName(name);
- mUniformMap[hashedName] = location;
-
- LL_DEBUGS("ShaderUniform") << "Uniform " << name << " is at location " << location << LL_ENDL;
-
- //find the index of this uniform
- for (S32 i = 0; i < (S32)LLShaderMgr::instance()->mReservedUniforms.size(); i++)
- {
- if ((mUniform[i] == -1)
- && (LLShaderMgr::instance()->mReservedUniforms[i] == name))
- {
- //found it
- mUniform[i] = location;
- mTexture[i] = mapUniformTextureChannel(location, type, size);
- return;
- }
- }
-
- if (uniforms != NULL)
- {
- for (U32 i = 0; i < uniforms->size(); i++)
- {
- if ((mUniform[i + LLShaderMgr::instance()->mReservedUniforms.size()] == -1)
- && ((*uniforms)[i].String() == name))
- {
- //found it
- mUniform[i + LLShaderMgr::instance()->mReservedUniforms.size()] = location;
- mTexture[i + LLShaderMgr::instance()->mReservedUniforms.size()] = mapUniformTextureChannel(location, type, size);
- return;
- }
- }
- }
- }
-}
-
-void LLGLSLShader::clearPermutations()
-{
- mDefines.clear();
-}
-
-void LLGLSLShader::addPermutation(std::string name, std::string value)
-{
- mDefines[name] = value;
-}
-
-void LLGLSLShader::addConstant(const LLGLSLShader::eShaderConsts shader_const)
-{
- addPermutation(gShaderConstsKey[shader_const], gShaderConstsVal[shader_const]);
-}
-
-void LLGLSLShader::removePermutation(std::string name)
-{
- mDefines.erase(name);
-}
-
-GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type, GLint size)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- if ((type >= GL_SAMPLER_1D && type <= GL_SAMPLER_2D_RECT_SHADOW) ||
- type == GL_SAMPLER_2D_MULTISAMPLE ||
- type == GL_SAMPLER_CUBE_MAP_ARRAY)
- { //this here is a texture
- GLint ret = mActiveTextureChannels;
- if (size == 1)
- {
- glUniform1i(location, mActiveTextureChannels);
- LL_DEBUGS("ShaderUniform") << "Assigned to texture channel " << mActiveTextureChannels << LL_ENDL;
- mActiveTextureChannels++;
- }
- else
- {
- //is array of textures, make sequential after this texture
- GLint channel[32]; // <=== only support up to 32 texture channels
- llassert(size <= 32);
- size = llmin(size, 32);
- for (int i = 0; i < size; ++i)
- {
- channel[i] = mActiveTextureChannels++;
- }
- glUniform1iv(location, size, channel);
- LL_DEBUGS("ShaderUniform") << "Assigned to texture channel " <<
- (mActiveTextureChannels - size) << " through " << (mActiveTextureChannels - 1) << LL_ENDL;
- }
-
- llassert(mActiveTextureChannels <= 32); // too many textures (probably)
- return ret;
- }
- return -1;
-}
-
-bool LLGLSLShader::mapUniforms(const vector<LLStaticHashedString>* uniforms)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- bool res = true;
-
- mTotalUniformSize = 0;
- mActiveTextureChannels = 0;
- mUniform.clear();
- mUniformMap.clear();
- mTexture.clear();
- mValue.clear();
- //initialize arrays
- U32 numUniforms = (uniforms == NULL) ? 0 : uniforms->size();
- mUniform.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1);
- mTexture.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1);
-
- bind();
-
- //get the number of active uniforms
- GLint activeCount;
- glGetProgramiv(mProgramObject, GL_ACTIVE_UNIFORMS, &activeCount);
-
- //........................................................................................................................................
- //........................................................................................
-
- /*
- EXPLANATION:
- This is part of code is temporary because as the final result the mapUniform() should be rewrited.
- But it's a huge a volume of work which is need to be a more carefully performed for avoid possible
- regression's (i.e. it should be formalized a separate ticket in JIRA).
-
- RESON:
- The reason of this code is that SL engine is very sensitive to fact that "diffuseMap" should be appear
- first as uniform parameter which is should get 0-"texture channel" index (see mapUniformTextureChannel() and mActiveTextureChannels)
- it influence to which is texture matrix will be updated during rendering.
-
- But, order of indexe's of uniform variables is not defined and GLSL compiler can change it as want
- , even if the "diffuseMap" will be appear and use first in shader code.
-
- As example where this situation appear see: "Deferred Material Shader 28/29/30/31"
- And tickets: MAINT-4165, MAINT-4839, MAINT-3568, MAINT-6437
-
- --- davep TODO -- pretty sure the entire block here is superstitious and that the uniform index has nothing to do with the texture channel
- texture channel should follow the uniform VALUE
- */
-
-
- S32 diffuseMap = glGetUniformLocation(mProgramObject, "diffuseMap");
- S32 specularMap = glGetUniformLocation(mProgramObject, "specularMap");
- S32 bumpMap = glGetUniformLocation(mProgramObject, "bumpMap");
- S32 altDiffuseMap = glGetUniformLocation(mProgramObject, "altDiffuseMap");
- S32 environmentMap = glGetUniformLocation(mProgramObject, "environmentMap");
- S32 reflectionMap = glGetUniformLocation(mProgramObject, "reflectionMap");
-
- std::set<S32> skip_index;
-
- if (-1 != diffuseMap && (-1 != specularMap || -1 != bumpMap || -1 != environmentMap || -1 != altDiffuseMap))
- {
- GLenum type;
- GLsizei length;
- GLint size = -1;
- char name[1024];
-
- diffuseMap = altDiffuseMap = specularMap = bumpMap = environmentMap = -1;
-
- for (S32 i = 0; i < activeCount; i++)
- {
- name[0] = '\0';
-
- glGetActiveUniform(mProgramObject, i, 1024, &length, &size, &type, (GLchar*)name);
-
- if (-1 == diffuseMap && std::string(name) == "diffuseMap")
- {
- diffuseMap = i;
- continue;
- }
-
- if (-1 == specularMap && std::string(name) == "specularMap")
- {
- specularMap = i;
- continue;
- }
-
- if (-1 == bumpMap && std::string(name) == "bumpMap")
- {
- bumpMap = i;
- continue;
- }
-
- if (-1 == environmentMap && std::string(name) == "environmentMap")
- {
- environmentMap = i;
- continue;
- }
-
- if (-1 == reflectionMap && std::string(name) == "reflectionMap")
- {
- reflectionMap = i;
- continue;
- }
-
- if (-1 == altDiffuseMap && std::string(name) == "altDiffuseMap")
- {
- altDiffuseMap = i;
- continue;
- }
- }
-
- bool specularDiff = specularMap < diffuseMap && -1 != specularMap;
- bool bumpLessDiff = bumpMap < diffuseMap && -1 != bumpMap;
- bool envLessDiff = environmentMap < diffuseMap && -1 != environmentMap;
- bool refLessDiff = reflectionMap < diffuseMap && -1 != reflectionMap;
-
- if (specularDiff || bumpLessDiff || envLessDiff || refLessDiff)
- {
- mapUniform(diffuseMap, uniforms);
- skip_index.insert(diffuseMap);
-
- if (-1 != specularMap) {
- mapUniform(specularMap, uniforms);
- skip_index.insert(specularMap);
- }
-
- if (-1 != bumpMap) {
- mapUniform(bumpMap, uniforms);
- skip_index.insert(bumpMap);
- }
-
- if (-1 != environmentMap) {
- mapUniform(environmentMap, uniforms);
- skip_index.insert(environmentMap);
- }
-
- if (-1 != reflectionMap) {
- mapUniform(reflectionMap, uniforms);
- skip_index.insert(reflectionMap);
- }
- }
- }
-
- //........................................................................................
-
- for (S32 i = 0; i < activeCount; i++)
- {
- //........................................................................................
- if (skip_index.end() != skip_index.find(i)) continue;
- //........................................................................................
-
- mapUniform(i, uniforms);
- }
- //........................................................................................................................................
-
- if (mFeatures.hasReflectionProbes) // Set up block binding, in a way supported by Apple (rather than binding = 1 in .glsl).
- { // See slide 35 and more of https://docs.huihoo.com/apple/wwdc/2011/session_420__advances_in_opengl_for_mac_os_x_lion.pdf
- static const GLuint BLOCKBINDING = 1; //picked by us
- //Get the index, similar to a uniform location
- GLuint UBOBlockIndex = glGetUniformBlockIndex(mProgramObject, "ReflectionProbes");
- if (UBOBlockIndex != GL_INVALID_INDEX)
- {
- //Set this index to a binding index
- glUniformBlockBinding(mProgramObject, UBOBlockIndex, BLOCKBINDING);
- }
- }
- unbind();
-
- LL_DEBUGS("ShaderUniform") << "Total Uniform Size: " << mTotalUniformSize << LL_ENDL;
- return res;
-}
-
-
-bool LLGLSLShader::link(bool suppress_errors)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- bool success = LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors);
-
- if (!success && !suppress_errors)
- {
- LLShaderMgr::instance()->dumpObjectLog(mProgramObject, !success, mName);
- }
-
- if (success)
- {
- LLShaderMgr::instance()->saveCachedProgramBinary(this);
- }
-
- return success;
-}
-
-void LLGLSLShader::bind()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- llassert(mProgramObject != 0);
-
- gGL.flush();
-
- if (sCurBoundShader != mProgramObject) // Don't re-bind current shader
- {
- if (sCurBoundShaderPtr)
- {
- sCurBoundShaderPtr->readProfileQuery();
- }
- LLVertexBuffer::unbind();
- glUseProgram(mProgramObject);
- sCurBoundShader = mProgramObject;
- sCurBoundShaderPtr = this;
- placeProfileQuery();
- LLVertexBuffer::setupClientArrays(mAttributeMask);
- }
-
- if (mUniformsDirty)
- {
- LLShaderMgr::instance()->updateShaderUniforms(this);
- mUniformsDirty = false;
- }
-}
-
-void LLGLSLShader::bind(bool rigged)
-{
- if (rigged)
- {
- llassert(mRiggedVariant);
- mRiggedVariant->bind();
- }
- else
- {
- bind();
- }
-}
-
-void LLGLSLShader::unbind(void)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- gGL.flush();
- LLVertexBuffer::unbind();
-
- if (sCurBoundShaderPtr)
- {
- sCurBoundShaderPtr->readProfileQuery();
- }
-
- glUseProgram(0);
- sCurBoundShader = 0;
- sCurBoundShaderPtr = NULL;
-}
-
-S32 LLGLSLShader::bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- S32 channel = 0;
- channel = getUniformLocation(uniform);
-
- return bindTexture(channel, texture, mode, colorspace);
-}
-
-S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- if (uniform < 0 || uniform >= (S32)mTexture.size())
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
- return -1;
- }
-
- uniform = mTexture[uniform];
-
- if (uniform > -1)
- {
- gGL.getTexUnit(uniform)->bindFast(texture);
- gGL.getTexUnit(uniform)->setTextureColorSpace(colorspace);
- }
-
- return uniform;
-}
-
-S32 LLGLSLShader::bindTexture(S32 uniform, LLRenderTarget* texture, bool depth, LLTexUnit::eTextureFilterOptions mode, U32 index)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- if (uniform < 0 || uniform >= (S32)mTexture.size())
- {
- return -1;
- }
-
- uniform = getTextureChannel(uniform);
-
- if (uniform > -1)
- {
- if (depth) {
- gGL.getTexUnit(uniform)->bind(texture, true);
- }
- else {
- bool has_mips = mode == LLTexUnit::TFO_TRILINEAR || mode == LLTexUnit::TFO_ANISOTROPIC;
- gGL.getTexUnit(uniform)->bindManual(texture->getUsage(), texture->getTexture(index), has_mips);
- }
-
- gGL.getTexUnit(uniform)->setTextureFilteringOption(mode);
- }
-
- return uniform;
-}
-
-S32 LLGLSLShader::bindTexture(const std::string& uniform, LLRenderTarget* texture, bool depth, LLTexUnit::eTextureFilterOptions mode)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- S32 channel = 0;
- channel = getUniformLocation(uniform);
-
- return bindTexture(channel, texture, depth, mode);
-}
-
-S32 LLGLSLShader::unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- S32 channel = 0;
- channel = getUniformLocation(uniform);
-
- return unbindTexture(channel);
-}
-
-S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- if (uniform < 0 || uniform >= (S32)mTexture.size())
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
- return -1;
- }
-
- uniform = mTexture[uniform];
-
- if (uniform > -1)
- {
- gGL.getTexUnit(uniform)->unbindFast(mode);
- }
-
- return uniform;
-}
-
-S32 LLGLSLShader::getTextureChannel(S32 uniform) const
-{
- return mTexture[uniform];
-}
-
-S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- if (uniform < 0 || uniform >= (S32)mTexture.size())
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
- return -1;
- }
- S32 index = mTexture[uniform];
- if (index != -1)
- {
- gGL.getTexUnit(index)->activate();
- gGL.getTexUnit(index)->enable(mode);
- gGL.getTexUnit(index)->setTextureColorSpace(space);
- }
- return index;
-}
-
-S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- if (uniform < 0 || uniform >= (S32)mTexture.size())
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
- return -1;
- }
- S32 index = mTexture[uniform];
- if (index != -1 && gGL.getTexUnit(index)->getCurrType() != LLTexUnit::TT_NONE)
- {
- if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode && gGL.getTexUnit(index)->getCurrColorSpace() != space)
- {
- if (gDebugSession)
- {
- gFailLog << "Texture channel " << index << " texture type corrupted." << std::endl;
- ll_fail("LLGLSLShader::disableTexture failed");
- }
- else
- {
- LL_ERRS() << "Texture channel " << index << " texture type corrupted." << LL_ENDL;
- }
- }
- gGL.getTexUnit(index)->disable();
- }
- return index;
-}
-
-void LLGLSLShader::uniform1i(U32 index, GLint x)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- const auto& iter = mValue.find(mUniform[index]);
- if (iter == mValue.end() || iter->second.mV[0] != x)
- {
- glUniform1i(mUniform[index], x);
- mValue[mUniform[index]] = LLVector4(x, 0.f, 0.f, 0.f);
- }
- }
- }
-}
-
-void LLGLSLShader::uniform1f(U32 index, GLfloat x)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- const auto& iter = mValue.find(mUniform[index]);
- if (iter == mValue.end() || iter->second.mV[0] != x)
- {
- glUniform1f(mUniform[index], x);
- mValue[mUniform[index]] = LLVector4(x, 0.f, 0.f, 0.f);
- }
- }
- }
-}
-
-void LLGLSLShader::fastUniform1f(U32 index, GLfloat x)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
- llassert(mProgramObject);
- llassert(mUniform.size() <= index);
- llassert(mUniform[index] >= 0);
- glUniform1f(mUniform[index], x);
-}
-
-void LLGLSLShader::uniform2f(U32 index, GLfloat x, GLfloat y)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- const auto& iter = mValue.find(mUniform[index]);
- LLVector4 vec(x, y, 0.f, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec))
- {
- glUniform2f(mUniform[index], x, y);
- mValue[mUniform[index]] = vec;
- }
- }
- }
-}
-
-void LLGLSLShader::uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- const auto& iter = mValue.find(mUniform[index]);
- LLVector4 vec(x, y, z, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec))
- {
- glUniform3f(mUniform[index], x, y, z);
- mValue[mUniform[index]] = vec;
- }
- }
- }
-}
-
-void LLGLSLShader::uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- const auto& iter = mValue.find(mUniform[index]);
- LLVector4 vec(x, y, z, w);
- if (iter == mValue.end() || shouldChange(iter->second, vec))
- {
- glUniform4f(mUniform[index], x, y, z, w);
- mValue[mUniform[index]] = vec;
- }
- }
- }
-}
-
-void LLGLSLShader::uniform1iv(U32 index, U32 count, const GLint* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- const auto& iter = mValue.find(mUniform[index]);
- LLVector4 vec(v[0], 0.f, 0.f, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- glUniform1iv(mUniform[index], count, v);
- mValue[mUniform[index]] = vec;
- }
- }
- }
-}
-
-void LLGLSLShader::uniform4iv(U32 index, U32 count, const GLint* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- const auto& iter = mValue.find(mUniform[index]);
- LLVector4 vec(v[0], v[1], v[2], v[3]);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- glUniform1iv(mUniform[index], count, v);
- mValue[mUniform[index]] = vec;
- }
- }
- }
-}
-
-
-void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- const auto& iter = mValue.find(mUniform[index]);
- LLVector4 vec(v[0], 0.f, 0.f, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- glUniform1fv(mUniform[index], count, v);
- mValue[mUniform[index]] = vec;
- }
- }
- }
-}
-
-void LLGLSLShader::uniform2fv(U32 index, U32 count, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- const auto& iter = mValue.find(mUniform[index]);
- LLVector4 vec(v[0], v[1], 0.f, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- glUniform2fv(mUniform[index], count, v);
- mValue[mUniform[index]] = vec;
- }
- }
- }
-}
-
-void LLGLSLShader::uniform3fv(U32 index, U32 count, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- const auto& iter = mValue.find(mUniform[index]);
- LLVector4 vec(v[0], v[1], v[2], 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- glUniform3fv(mUniform[index], count, v);
- mValue[mUniform[index]] = vec;
- }
- }
- }
-}
-
-void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- const auto& iter = mValue.find(mUniform[index]);
- LLVector4 vec(v[0], v[1], v[2], v[3]);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- glUniform4fv(mUniform[index], count, v);
- mValue[mUniform[index]] = vec;
- }
- }
- }
-}
-
-void LLGLSLShader::uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- glUniformMatrix2fv(mUniform[index], count, transpose, v);
- }
- }
-}
-
-void LLGLSLShader::uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- glUniformMatrix3fv(mUniform[index], count, transpose, v);
- }
- }
-}
-
-void LLGLSLShader::uniformMatrix3x4fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- glUniformMatrix3x4fv(mUniform[index], count, transpose, v);
- }
- }
-}
-
-void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- llassert(sCurBoundShaderPtr == this);
-
- if (mProgramObject)
- {
- if (mUniform.size() <= index)
- {
- LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
- return;
- }
-
- if (mUniform[index] >= 0)
- {
- glUniformMatrix4fv(mUniform[index], count, transpose, v);
- }
- }
-}
-
-GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- GLint ret = -1;
- if (mProgramObject)
- {
- LLStaticStringTable<GLint>::iterator iter = mUniformMap.find(uniform);
- if (iter != mUniformMap.end())
- {
- if (gDebugGL)
- {
- stop_glerror();
- if (iter->second != glGetUniformLocation(mProgramObject, uniform.String().c_str()))
- {
- LL_ERRS() << "Uniform does not match." << LL_ENDL;
- }
- stop_glerror();
- }
- ret = iter->second;
- }
- }
-
- return ret;
-}
-
-GLint LLGLSLShader::getUniformLocation(U32 index)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- GLint ret = -1;
- if (mProgramObject)
- {
- if (index >= mUniform.size())
- {
- LL_WARNS_ONCE("Shader") << "Uniform index " << index << " out of bounds " << (S32)mUniform.size() << LL_ENDL;
- return ret;
- }
- return mUniform[index];
- }
-
- return ret;
-}
-
-GLint LLGLSLShader::getAttribLocation(U32 attrib)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
-
- if (attrib < mAttribute.size())
- {
- return mAttribute[attrib];
- }
- else
- {
- return -1;
- }
-}
-
-void LLGLSLShader::uniform1i(const LLStaticHashedString& uniform, GLint v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- const auto& iter = mValue.find(location);
- LLVector4 vec(v, 0.f, 0.f, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec))
- {
- glUniform1i(location, v);
- mValue[location] = vec;
- }
- }
-}
-
-void LLGLSLShader::uniform1iv(const LLStaticHashedString& uniform, U32 count, const GLint* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- LLVector4 vec(v[0], 0, 0, 0);
- const auto& iter = mValue.find(location);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- glUniform1iv(location, count, v);
- mValue[location] = vec;
- }
- }
-}
-
-void LLGLSLShader::uniform4iv(const LLStaticHashedString& uniform, U32 count, const GLint* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- LLVector4 vec(v[0], v[1], v[2], v[3]);
- const auto& iter = mValue.find(location);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- glUniform4iv(location, count, v);
- mValue[location] = vec;
- }
- }
-}
-
-void LLGLSLShader::uniform2i(const LLStaticHashedString& uniform, GLint i, GLint j)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- const auto& iter = mValue.find(location);
- LLVector4 vec(i, j, 0.f, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec))
- {
- glUniform2i(location, i, j);
- mValue[location] = vec;
- }
- }
-}
-
-
-void LLGLSLShader::uniform1f(const LLStaticHashedString& uniform, GLfloat v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- const auto& iter = mValue.find(location);
- LLVector4 vec(v, 0.f, 0.f, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec))
- {
- glUniform1f(location, v);
- mValue[location] = vec;
- }
- }
-}
-
-void LLGLSLShader::uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- const auto& iter = mValue.find(location);
- LLVector4 vec(x, y, 0.f, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec))
- {
- glUniform2f(location, x, y);
- mValue[location] = vec;
- }
- }
-
-}
-
-void LLGLSLShader::uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- const auto& iter = mValue.find(location);
- LLVector4 vec(x, y, z, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec))
- {
- glUniform3f(location, x, y, z);
- mValue[location] = vec;
- }
- }
-}
-
-void LLGLSLShader::uniform1fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- const auto& iter = mValue.find(location);
- LLVector4 vec(v[0], 0.f, 0.f, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- glUniform1fv(location, count, v);
- mValue[location] = vec;
- }
- }
-}
-
-void LLGLSLShader::uniform2fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- const auto& iter = mValue.find(location);
- LLVector4 vec(v[0], v[1], 0.f, 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- glUniform2fv(location, count, v);
- mValue[location] = vec;
- }
- }
-}
-
-void LLGLSLShader::uniform3fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- const auto& iter = mValue.find(location);
- LLVector4 vec(v[0], v[1], v[2], 0.f);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- glUniform3fv(location, count, v);
- mValue[location] = vec;
- }
- }
-}
-
-void LLGLSLShader::uniform4fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- LLVector4 vec(v);
- const auto& iter = mValue.find(location);
- if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
- {
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- glUniform4fv(location, count, v);
- mValue[location] = vec;
- }
- }
-}
-
-void LLGLSLShader::uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat* v)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- GLint location = getUniformLocation(uniform);
-
- if (location >= 0)
- {
- stop_glerror();
- glUniformMatrix4fv(location, count, transpose, v);
- stop_glerror();
- }
-}
-
-
-void LLGLSLShader::vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
- if (mAttribute[index] > 0)
- {
- glVertexAttrib4f(mAttribute[index], x, y, z, w);
- }
-}
-
-void LLGLSLShader::vertexAttrib4fv(U32 index, GLfloat* v)
-{
- if (mAttribute[index] > 0)
- {
- glVertexAttrib4fv(mAttribute[index], v);
- }
-}
-
-void LLGLSLShader::setMinimumAlpha(F32 minimum)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- gGL.flush();
- uniform1f(LLShaderMgr::MINIMUM_ALPHA, minimum);
-}
-
-void LLShaderUniforms::apply(LLGLSLShader* shader)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
- for (auto& uniform : mIntegers)
- {
- shader->uniform1i(uniform.mUniform, uniform.mValue);
- }
-
- for (auto& uniform : mFloats)
- {
- shader->uniform1f(uniform.mUniform, uniform.mValue);
- }
-
- for (auto& uniform : mVectors)
- {
- shader->uniform4fv(uniform.mUniform, 1, uniform.mValue.mV);
- }
-
- for (auto& uniform : mVector3s)
- {
- shader->uniform3fv(uniform.mUniform, 1, uniform.mValue.mV);
- }
-}
-
-LLUUID LLGLSLShader::hash()
-{
- HBXXH128 hash_obj;
- hash_obj.update(mName);
- hash_obj.update(&mShaderGroup, sizeof(mShaderGroup));
- hash_obj.update(&mShaderLevel, sizeof(mShaderLevel));
- for (const auto& shdr_pair : mShaderFiles)
- {
- hash_obj.update(shdr_pair.first);
- hash_obj.update(&shdr_pair.second, sizeof(GLenum));
- }
- for (const auto& define_pair : mDefines)
- {
- hash_obj.update(define_pair.first);
- hash_obj.update(define_pair.second);
-
- }
- for (const auto& define_pair : LLGLSLShader::sGlobalDefines)
- {
- hash_obj.update(define_pair.first);
- hash_obj.update(define_pair.second);
-
- }
- hash_obj.update(&mFeatures, sizeof(LLShaderFeatures));
- hash_obj.update(gGLManager.mGLVendor);
- hash_obj.update(gGLManager.mGLRenderer);
- hash_obj.update(gGLManager.mGLVersionString);
- return hash_obj.digest();
-}
-
-#ifdef LL_PROFILER_ENABLE_RENDER_DOC
-void LLGLSLShader::setLabel(const char* label) {
- LL_LABEL_OBJECT_GL(GL_PROGRAM, mProgramObject, strlen(label), label);
-}
-#endif
+/** + * @file llglslshader.cpp + * @brief GLSL helper functions and state. + * + * $LicenseInfo:firstyear=2005&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 "llglslshader.h" + +#include "llshadermgr.h" +#include "llfile.h" +#include "llrender.h" +#include "llvertexbuffer.h" +#include "llrendertarget.h" + +#include "hbxxh.h" +#include "llsdserialize.h" + +#if LL_DARWIN +#include "OpenGL/OpenGL.h" +#endif + + // Print-print list of shader included source files that are linked together via glAttachShader() + // i.e. On macOS / OSX the AMD GLSL linker will display an error if a varying is left in an undefined state. +#define DEBUG_SHADER_INCLUDES 0 + +// Lots of STL stuff in here, using namespace std to keep things more readable +using std::vector; +using std::pair; +using std::make_pair; +using std::string; + +GLuint LLGLSLShader::sCurBoundShader = 0; +LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL; +S32 LLGLSLShader::sIndexedTextureChannels = 0; +bool LLGLSLShader::sProfileEnabled = false; +std::set<LLGLSLShader*> LLGLSLShader::sInstances; +LLGLSLShader::defines_map_t LLGLSLShader::sGlobalDefines; +U64 LLGLSLShader::sTotalTimeElapsed = 0; +U32 LLGLSLShader::sTotalTrianglesDrawn = 0; +U64 LLGLSLShader::sTotalSamplesDrawn = 0; +U32 LLGLSLShader::sTotalBinds = 0; + +//UI shader -- declared here so llui_libtest will link properly +LLGLSLShader gUIProgram; +LLGLSLShader gSolidColorProgram; + +// NOTE: Keep gShaderConsts* and LLGLSLShader::ShaderConsts_e in sync! +const std::string gShaderConstsKey[LLGLSLShader::NUM_SHADER_CONSTS] = +{ + "LL_SHADER_CONST_CLOUD_MOON_DEPTH" + , "LL_SHADER_CONST_STAR_DEPTH" +}; + +// NOTE: Keep gShaderConsts* and LLGLSLShader::ShaderConsts_e in sync! +const std::string gShaderConstsVal[LLGLSLShader::NUM_SHADER_CONSTS] = +{ + "0.99998" // SHADER_CONST_CLOUD_MOON_DEPTH // SL-14113 + , "0.99999" // SHADER_CONST_STAR_DEPTH // SL-14113 +}; + + +bool shouldChange(const LLVector4& v1, const LLVector4& v2) +{ + return v1 != v2; +} + +//=============================== +// LLGLSL Shader implementation +//=============================== + +//static +void LLGLSLShader::initProfile() +{ + sProfileEnabled = true; + sTotalTimeElapsed = 0; + sTotalTrianglesDrawn = 0; + sTotalSamplesDrawn = 0; + sTotalBinds = 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(bool emit_report) +{ + sProfileEnabled = false; + + if (emit_report) + { + 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()); + + bool unbound = false; + for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter) + { + (*iter)->dumpStats(); + if ((*iter)->mBinds == 0) + { + unbound = true; + } + } + + LL_INFOS() << "-----------------------------------" << LL_ENDL; + LL_INFOS() << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed / 1000000.f) << LL_ENDL; + LL_INFOS() << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn / 1000000.f) << LL_ENDL; + LL_INFOS() << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn / 1000000.f) << LL_ENDL; + LL_INFOS() << "-----------------------------------" << LL_ENDL; + + if (unbound) + { + LL_INFOS() << "The following shaders were unused: " << LL_ENDL; + for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter) + { + if ((*iter)->mBinds == 0) + { + LL_INFOS() << (*iter)->mName << LL_ENDL; + } + } + } + } +} + +void LLGLSLShader::clearStats() +{ + mTrianglesDrawn = 0; + mTimeElapsed = 0; + mSamplesDrawn = 0; + mBinds = 0; +} + +void LLGLSLShader::dumpStats() +{ + if (mBinds > 0) + { + LL_INFOS() << "=============================================" << LL_ENDL; + LL_INFOS() << mName << LL_ENDL; + for (U32 i = 0; i < mShaderFiles.size(); ++i) + { + LL_INFOS() << mShaderFiles[i].first << LL_ENDL; + } + LL_INFOS() << "=============================================" << LL_ENDL; + + 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_binds = (F32)mBinds / (F32)sTotalBinds * 100.f; + + LL_INFOS() << "Triangles Drawn: " << mTrianglesDrawn << " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec) << LL_ENDL; + LL_INFOS() << "Binds: " << mBinds << " " << llformat("(%.2f pct of total)", pct_binds) << LL_ENDL; + LL_INFOS() << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << LL_ENDL; + LL_INFOS() << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32)((F64)mTimeElapsed / (F64)sTotalTimeElapsed) * 100.f, ms) << LL_ENDL; + } +} + +//static +void LLGLSLShader::startProfile() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + if (sProfileEnabled && sCurBoundShaderPtr) + { + sCurBoundShaderPtr->placeProfileQuery(); + } + +} + +//static +void LLGLSLShader::stopProfile() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + if (sProfileEnabled && sCurBoundShaderPtr) + { + sCurBoundShaderPtr->unbind(); + } +} + +void LLGLSLShader::placeProfileQuery(bool for_runtime) +{ + if (sProfileEnabled || for_runtime) + { + if (mTimerQuery == 0) + { + glGenQueries(1, &mSamplesQuery); + glGenQueries(1, &mTimerQuery); + glGenQueries(1, &mPrimitivesQuery); + } + + glBeginQuery(GL_TIME_ELAPSED, mTimerQuery); + + if (!for_runtime) + { + glBeginQuery(GL_SAMPLES_PASSED, mSamplesQuery); + glBeginQuery(GL_PRIMITIVES_GENERATED, mPrimitivesQuery); + } + } +} + +bool LLGLSLShader::readProfileQuery(bool for_runtime, bool force_read) +{ + if (sProfileEnabled || for_runtime) + { + if (!mProfilePending) + { + glEndQuery(GL_TIME_ELAPSED); + if (!for_runtime) + { + glEndQuery(GL_SAMPLES_PASSED); + glEndQuery(GL_PRIMITIVES_GENERATED); + } + mProfilePending = for_runtime; + } + + if (mProfilePending && for_runtime && !force_read) + { + GLuint64 result = 0; + glGetQueryObjectui64v(mTimerQuery, GL_QUERY_RESULT_AVAILABLE, &result); + + if (result != GL_TRUE) + { + return false; + } + } + + GLuint64 time_elapsed = 0; + glGetQueryObjectui64v(mTimerQuery, GL_QUERY_RESULT, &time_elapsed); + mTimeElapsed += time_elapsed; + mProfilePending = false; + + if (!for_runtime) + { + GLuint64 samples_passed = 0; + glGetQueryObjectui64v(mSamplesQuery, GL_QUERY_RESULT, &samples_passed); + + U64 primitives_generated = 0; + glGetQueryObjectui64v(mPrimitivesQuery, GL_QUERY_RESULT, &primitives_generated); + sTotalTimeElapsed += time_elapsed; + + sTotalSamplesDrawn += samples_passed; + mSamplesDrawn += samples_passed; + + U32 tri_count = (U32)primitives_generated / 3; + + mTrianglesDrawn += tri_count; + sTotalTrianglesDrawn += tri_count; + + sTotalBinds++; + mBinds++; + } + } + + return true; +} + + + +LLGLSLShader::LLGLSLShader() + : mProgramObject(0), + mAttributeMask(0), + mTotalUniformSize(0), + mActiveTextureChannels(0), + mShaderLevel(0), + mShaderGroup(SG_DEFAULT), + mFeatures(), + mUniformsDirty(false), + mTimerQuery(0), + mSamplesQuery(0), + mPrimitivesQuery(0) +{ + +} + +LLGLSLShader::~LLGLSLShader() +{ +} + +void LLGLSLShader::unload() +{ + mShaderFiles.clear(); + mDefines.clear(); + mFeatures = LLShaderFeatures(); + + unloadInternal(); +} + +void LLGLSLShader::unloadInternal() +{ + sInstances.erase(this); + + stop_glerror(); + mAttribute.clear(); + mTexture.clear(); + mUniform.clear(); + + if (mProgramObject) + { + GLuint obj[1024]; + GLsizei count = 0; + glGetAttachedShaders(mProgramObject, 1024, &count, obj); + + for (GLsizei i = 0; i < count; i++) + { + glDetachShader(mProgramObject, obj[i]); + } + + for (GLsizei i = 0; i < count; i++) + { + if (glIsShader(obj[i])) + { + glDeleteShader(obj[i]); + } + } + + glDeleteProgram(mProgramObject); + + mProgramObject = 0; + } + + if (mTimerQuery) + { + glDeleteQueries(1, &mTimerQuery); + mTimerQuery = 0; + } + + if (mSamplesQuery) + { + glDeleteQueries(1, &mSamplesQuery); + mSamplesQuery = 0; + } + + //hack to make apple not complain + glGetError(); + + stop_glerror(); +} + +bool LLGLSLShader::createShader(std::vector<LLStaticHashedString>* attributes, + std::vector<LLStaticHashedString>* uniforms, + U32 varying_count, + const char** varyings) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + unloadInternal(); + + sInstances.insert(this); + + //reloading, reset matrix hash values + for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i) + { + mMatHash[i] = 0xFFFFFFFF; + } + mLightHash = 0xFFFFFFFF; + + llassert_always(!mShaderFiles.empty()); + +#if LL_DARWIN + // work-around missing mix(vec3,vec3,bvec3) + mDefines["OLD_SELECT"] = "1"; +#endif + + mShaderHash = hash(); + + // Create program + mProgramObject = glCreateProgram(); + if (mProgramObject == 0) + { + // Shouldn't happen if shader related extensions, like ARB_vertex_shader, exist. + LL_SHADER_LOADING_WARNS() << "Failed to create handle for shader: " << mName << LL_ENDL; + unloadInternal(); + return false; + } + + bool success = true; + + mUsingBinaryProgram = LLShaderMgr::instance()->loadCachedProgramBinary(this); + + if (!mUsingBinaryProgram) + { +#if DEBUG_SHADER_INCLUDES + fprintf(stderr, "--- %s ---\n", mName.c_str()); +#endif // DEBUG_SHADER_INCLUDES + + //compile new source + vector< pair<string, GLenum> >::iterator fileIter = mShaderFiles.begin(); + for (; fileIter != mShaderFiles.end(); fileIter++) + { + GLuint 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) + { + attachObject(shaderhandle); + } + else + { + success = false; + } + } + } + + // Attach existing objects + if (!LLShaderMgr::instance()->attachShaderFeatures(this)) + { + unloadInternal(); + return false; + } + // Map attributes and uniforms + if (success) + { + success = mapAttributes(attributes); + } + if (success) + { + success = mapUniforms(uniforms); + } + if (!success) + { + LL_SHADER_LOADING_WARNS() << "Failed to link shader: " << mName << LL_ENDL; + + // Try again using a lower shader level; + if (mShaderLevel > 0) + { + LL_SHADER_LOADING_WARNS() << "Failed to link using shader level " << mShaderLevel << " trying again using shader level " << (mShaderLevel - 1) << LL_ENDL; + mShaderLevel--; + return createShader(attributes, uniforms); + } + else + { + // Give up and unload shader. + unloadInternal(); + } + } + else if (mFeatures.mIndexedTextureChannels > 0) + { //override texture channels for indexed texture rendering + bind(); + S32 channel_count = mFeatures.mIndexedTextureChannels; + + for (S32 i = 0; i < channel_count; i++) + { + LLStaticHashedString uniName(llformat("tex%d", i)); + uniform1i(uniName, i); + } + + S32 cur_tex = channel_count; //adjust any texture channels that might have been overwritten + for (U32 i = 0; i < mTexture.size(); i++) + { + if (mTexture[i] > -1 && mTexture[i] < channel_count) + { + llassert(cur_tex < gGLManager.mNumTextureImageUnits); + uniform1i(i, cur_tex); + mTexture[i] = cur_tex++; + } + } + unbind(); + } + +#ifdef LL_PROFILER_ENABLE_RENDER_DOC + setLabel(mName.c_str()); +#endif + + return success; +} + +#if DEBUG_SHADER_INCLUDES +void dumpAttachObject(const char* func_name, GLuint program_object, const std::string& object_path) +{ + GLchar* info_log; + GLint info_len_expect = 0; + GLint info_len_actual = 0; + + glGetShaderiv(program_object, GL_INFO_LOG_LENGTH, , &info_len_expect); + fprintf(stderr, " * %-20s(), log size: %d, %s\n", func_name, info_len_expect, object_path.c_str()); + + if (info_len_expect > 0) + { + fprintf(stderr, " ========== %s() ========== \n", func_name); + info_log = new GLchar[info_len_expect]; + glGetProgramInfoLog(program_object, info_len_expect, &info_len_actual, info_log); + fprintf(stderr, "%s\n", info_log); + delete[] info_log; + } +} +#endif // DEBUG_SHADER_INCLUDES + +bool LLGLSLShader::attachVertexObject(std::string object_path) +{ + if (LLShaderMgr::instance()->mVertexShaderObjects.count(object_path) > 0) + { + stop_glerror(); + glAttachShader(mProgramObject, LLShaderMgr::instance()->mVertexShaderObjects[object_path]); +#if DEBUG_SHADER_INCLUDES + dumpAttachObject("attachVertexObject", mProgramObject, object_path); +#endif // DEBUG_SHADER_INCLUDES + stop_glerror(); + return true; + } + else + { + LL_SHADER_LOADING_WARNS() << "Attempting to attach shader object: '" << object_path << "' that hasn't been compiled." << LL_ENDL; + return false; + } +} + +bool LLGLSLShader::attachFragmentObject(std::string object_path) +{ + if(mUsingBinaryProgram) + return true; + + if (LLShaderMgr::instance()->mFragmentShaderObjects.count(object_path) > 0) + { + stop_glerror(); + glAttachShader(mProgramObject, LLShaderMgr::instance()->mFragmentShaderObjects[object_path]); +#if DEBUG_SHADER_INCLUDES + dumpAttachObject("attachFragmentObject", mProgramObject, object_path); +#endif // DEBUG_SHADER_INCLUDES + stop_glerror(); + return true; + } + else + { + LL_SHADER_LOADING_WARNS() << "Attempting to attach shader object: '" << object_path << "' that hasn't been compiled." << LL_ENDL; + return false; + } +} + +void LLGLSLShader::attachObject(GLuint object) +{ + if(mUsingBinaryProgram) + return; + + if (object != 0) + { + stop_glerror(); + glAttachShader(mProgramObject, object); +#if DEBUG_SHADER_INCLUDES + std::string object_path("???"); + dumpAttachObject("attachObject", mProgramObject, object_path); +#endif // DEBUG_SHADER_INCLUDES + stop_glerror(); + } + else + { + LL_SHADER_LOADING_WARNS() << "Attempting to attach non existing shader object. " << LL_ENDL; + } +} + +void LLGLSLShader::attachObjects(GLuint* objects, S32 count) +{ + if(mUsingBinaryProgram) + return; + + for (S32 i = 0; i < count; i++) + { + attachObject(objects[i]); + } +} + +bool LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString>* attributes) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + bool res = true; + if (!mUsingBinaryProgram) + { + //before linking, make sure reserved attributes always have consistent locations + for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++) + { + const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str(); + glBindAttribLocation(mProgramObject, i, (const GLchar*)name); + } + + //link the program + res = link(); + } + + mAttribute.clear(); + U32 numAttributes = (attributes == NULL) ? 0 : attributes->size(); +#if LL_RELEASE_WITH_DEBUG_INFO + mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size() + numAttributes, { -1, NULL }); +#else + mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size() + numAttributes, -1); +#endif + + if (res) + { //read back channel locations + + mAttributeMask = 0; + + //read back reserved channels first + for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++) + { + const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str(); + S32 index = glGetAttribLocation(mProgramObject, (const GLchar*)name); + if (index != -1) + { +#if LL_RELEASE_WITH_DEBUG_INFO + mAttribute[i] = { index, name }; +#else + mAttribute[i] = index; +#endif + mAttributeMask |= 1 << i; + LL_DEBUGS("ShaderUniform") << "Attribute " << name << " assigned to channel " << index << LL_ENDL; + } + } + if (attributes != NULL) + { + for (U32 i = 0; i < numAttributes; i++) + { + const char* name = (*attributes)[i].String().c_str(); + S32 index = glGetAttribLocation(mProgramObject, name); + if (index != -1) + { + mAttribute[LLShaderMgr::instance()->mReservedAttribs.size() + i] = index; + LL_DEBUGS("ShaderUniform") << "Attribute " << name << " assigned to channel " << index << LL_ENDL; + } + } + } + + return true; + } + + return false; +} + +void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString>* uniforms) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + if (index == -1) + { + return; + } + + GLenum type; + GLsizei length; + GLint size = -1; + char name[1024]; /* Flawfinder: ignore */ + name[0] = 0; + + + glGetActiveUniform(mProgramObject, index, 1024, &length, &size, &type, (GLchar*)name); + 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; + } + + S32 location = glGetUniformLocation(mProgramObject, name); + if (location != -1) + { + //chop off "[0]" so we can always access the first element + //of an array by the array name + char* is_array = strstr(name, "[0]"); + if (is_array) + { + is_array[0] = 0; + } + + LLStaticHashedString hashedName(name); + mUniformMap[hashedName] = location; + + LL_DEBUGS("ShaderUniform") << "Uniform " << name << " is at location " << location << LL_ENDL; + + //find the index of this uniform + for (S32 i = 0; i < (S32)LLShaderMgr::instance()->mReservedUniforms.size(); i++) + { + if ((mUniform[i] == -1) + && (LLShaderMgr::instance()->mReservedUniforms[i] == name)) + { + //found it + mUniform[i] = location; + mTexture[i] = mapUniformTextureChannel(location, type, size); + return; + } + } + + if (uniforms != NULL) + { + for (U32 i = 0; i < uniforms->size(); i++) + { + if ((mUniform[i + LLShaderMgr::instance()->mReservedUniforms.size()] == -1) + && ((*uniforms)[i].String() == name)) + { + //found it + mUniform[i + LLShaderMgr::instance()->mReservedUniforms.size()] = location; + mTexture[i + LLShaderMgr::instance()->mReservedUniforms.size()] = mapUniformTextureChannel(location, type, size); + return; + } + } + } + } +} + +void LLGLSLShader::clearPermutations() +{ + mDefines.clear(); +} + +void LLGLSLShader::addPermutation(std::string name, std::string value) +{ + mDefines[name] = value; +} + +void LLGLSLShader::addConstant(const LLGLSLShader::eShaderConsts shader_const) +{ + addPermutation(gShaderConstsKey[shader_const], gShaderConstsVal[shader_const]); +} + +void LLGLSLShader::removePermutation(std::string name) +{ + mDefines.erase(name); +} + +GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type, GLint size) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + if ((type >= GL_SAMPLER_1D && type <= GL_SAMPLER_2D_RECT_SHADOW) || + type == GL_SAMPLER_2D_MULTISAMPLE || + type == GL_SAMPLER_CUBE_MAP_ARRAY) + { //this here is a texture + GLint ret = mActiveTextureChannels; + if (size == 1) + { + glUniform1i(location, mActiveTextureChannels); + LL_DEBUGS("ShaderUniform") << "Assigned to texture channel " << mActiveTextureChannels << LL_ENDL; + mActiveTextureChannels++; + } + else + { + //is array of textures, make sequential after this texture + GLint channel[32]; // <=== only support up to 32 texture channels + llassert(size <= 32); + size = llmin(size, 32); + for (int i = 0; i < size; ++i) + { + channel[i] = mActiveTextureChannels++; + } + glUniform1iv(location, size, channel); + LL_DEBUGS("ShaderUniform") << "Assigned to texture channel " << + (mActiveTextureChannels - size) << " through " << (mActiveTextureChannels - 1) << LL_ENDL; + } + + llassert(mActiveTextureChannels <= 32); // too many textures (probably) + return ret; + } + return -1; +} + +bool LLGLSLShader::mapUniforms(const vector<LLStaticHashedString>* uniforms) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + bool res = true; + + mTotalUniformSize = 0; + mActiveTextureChannels = 0; + mUniform.clear(); + mUniformMap.clear(); + mTexture.clear(); + mValue.clear(); + //initialize arrays + U32 numUniforms = (uniforms == NULL) ? 0 : uniforms->size(); + mUniform.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1); + mTexture.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1); + + bind(); + + //get the number of active uniforms + GLint activeCount; + glGetProgramiv(mProgramObject, GL_ACTIVE_UNIFORMS, &activeCount); + + //........................................................................................................................................ + //........................................................................................ + + /* + EXPLANATION: + This is part of code is temporary because as the final result the mapUniform() should be rewrited. + But it's a huge a volume of work which is need to be a more carefully performed for avoid possible + regression's (i.e. it should be formalized a separate ticket in JIRA). + + RESON: + The reason of this code is that SL engine is very sensitive to fact that "diffuseMap" should be appear + first as uniform parameter which is should get 0-"texture channel" index (see mapUniformTextureChannel() and mActiveTextureChannels) + it influence to which is texture matrix will be updated during rendering. + + But, order of indexe's of uniform variables is not defined and GLSL compiler can change it as want + , even if the "diffuseMap" will be appear and use first in shader code. + + As example where this situation appear see: "Deferred Material Shader 28/29/30/31" + And tickets: MAINT-4165, MAINT-4839, MAINT-3568, MAINT-6437 + + --- davep TODO -- pretty sure the entire block here is superstitious and that the uniform index has nothing to do with the texture channel + texture channel should follow the uniform VALUE + */ + + + S32 diffuseMap = glGetUniformLocation(mProgramObject, "diffuseMap"); + S32 specularMap = glGetUniformLocation(mProgramObject, "specularMap"); + S32 bumpMap = glGetUniformLocation(mProgramObject, "bumpMap"); + S32 altDiffuseMap = glGetUniformLocation(mProgramObject, "altDiffuseMap"); + S32 environmentMap = glGetUniformLocation(mProgramObject, "environmentMap"); + S32 reflectionMap = glGetUniformLocation(mProgramObject, "reflectionMap"); + + std::set<S32> skip_index; + + if (-1 != diffuseMap && (-1 != specularMap || -1 != bumpMap || -1 != environmentMap || -1 != altDiffuseMap)) + { + GLenum type; + GLsizei length; + GLint size = -1; + char name[1024]; + + diffuseMap = altDiffuseMap = specularMap = bumpMap = environmentMap = -1; + + for (S32 i = 0; i < activeCount; i++) + { + name[0] = '\0'; + + glGetActiveUniform(mProgramObject, i, 1024, &length, &size, &type, (GLchar*)name); + + if (-1 == diffuseMap && std::string(name) == "diffuseMap") + { + diffuseMap = i; + continue; + } + + if (-1 == specularMap && std::string(name) == "specularMap") + { + specularMap = i; + continue; + } + + if (-1 == bumpMap && std::string(name) == "bumpMap") + { + bumpMap = i; + continue; + } + + if (-1 == environmentMap && std::string(name) == "environmentMap") + { + environmentMap = i; + continue; + } + + if (-1 == reflectionMap && std::string(name) == "reflectionMap") + { + reflectionMap = i; + continue; + } + + if (-1 == altDiffuseMap && std::string(name) == "altDiffuseMap") + { + altDiffuseMap = i; + continue; + } + } + + bool specularDiff = specularMap < diffuseMap && -1 != specularMap; + bool bumpLessDiff = bumpMap < diffuseMap && -1 != bumpMap; + bool envLessDiff = environmentMap < diffuseMap && -1 != environmentMap; + bool refLessDiff = reflectionMap < diffuseMap && -1 != reflectionMap; + + if (specularDiff || bumpLessDiff || envLessDiff || refLessDiff) + { + mapUniform(diffuseMap, uniforms); + skip_index.insert(diffuseMap); + + if (-1 != specularMap) { + mapUniform(specularMap, uniforms); + skip_index.insert(specularMap); + } + + if (-1 != bumpMap) { + mapUniform(bumpMap, uniforms); + skip_index.insert(bumpMap); + } + + if (-1 != environmentMap) { + mapUniform(environmentMap, uniforms); + skip_index.insert(environmentMap); + } + + if (-1 != reflectionMap) { + mapUniform(reflectionMap, uniforms); + skip_index.insert(reflectionMap); + } + } + } + + //........................................................................................ + + for (S32 i = 0; i < activeCount; i++) + { + //........................................................................................ + if (skip_index.end() != skip_index.find(i)) continue; + //........................................................................................ + + mapUniform(i, uniforms); + } + //........................................................................................................................................ + + if (mFeatures.hasReflectionProbes) // Set up block binding, in a way supported by Apple (rather than binding = 1 in .glsl). + { // See slide 35 and more of https://docs.huihoo.com/apple/wwdc/2011/session_420__advances_in_opengl_for_mac_os_x_lion.pdf + static const GLuint BLOCKBINDING = 1; //picked by us + //Get the index, similar to a uniform location + GLuint UBOBlockIndex = glGetUniformBlockIndex(mProgramObject, "ReflectionProbes"); + if (UBOBlockIndex != GL_INVALID_INDEX) + { + //Set this index to a binding index + glUniformBlockBinding(mProgramObject, UBOBlockIndex, BLOCKBINDING); + } + } + unbind(); + + LL_DEBUGS("ShaderUniform") << "Total Uniform Size: " << mTotalUniformSize << LL_ENDL; + return res; +} + + +bool LLGLSLShader::link(bool suppress_errors) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + bool success = LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors); + + if (!success && !suppress_errors) + { + LLShaderMgr::instance()->dumpObjectLog(mProgramObject, !success, mName); + } + + if (success) + { + LLShaderMgr::instance()->saveCachedProgramBinary(this); + } + + return success; +} + +void LLGLSLShader::bind() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + llassert(mProgramObject != 0); + + gGL.flush(); + + if (sCurBoundShader != mProgramObject) // Don't re-bind current shader + { + if (sCurBoundShaderPtr) + { + sCurBoundShaderPtr->readProfileQuery(); + } + LLVertexBuffer::unbind(); + glUseProgram(mProgramObject); + sCurBoundShader = mProgramObject; + sCurBoundShaderPtr = this; + placeProfileQuery(); + LLVertexBuffer::setupClientArrays(mAttributeMask); + } + + if (mUniformsDirty) + { + LLShaderMgr::instance()->updateShaderUniforms(this); + mUniformsDirty = false; + } +} + +void LLGLSLShader::bind(bool rigged) +{ + if (rigged) + { + llassert(mRiggedVariant); + mRiggedVariant->bind(); + } + else + { + bind(); + } +} + +void LLGLSLShader::unbind(void) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + gGL.flush(); + LLVertexBuffer::unbind(); + + if (sCurBoundShaderPtr) + { + sCurBoundShaderPtr->readProfileQuery(); + } + + glUseProgram(0); + sCurBoundShader = 0; + sCurBoundShaderPtr = NULL; +} + +S32 LLGLSLShader::bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + S32 channel = 0; + channel = getUniformLocation(uniform); + + return bindTexture(channel, texture, mode, colorspace); +} + +S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; + return -1; + } + + uniform = mTexture[uniform]; + + if (uniform > -1) + { + gGL.getTexUnit(uniform)->bindFast(texture); + gGL.getTexUnit(uniform)->setTextureColorSpace(colorspace); + } + + return uniform; +} + +S32 LLGLSLShader::bindTexture(S32 uniform, LLRenderTarget* texture, bool depth, LLTexUnit::eTextureFilterOptions mode, U32 index) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + return -1; + } + + uniform = getTextureChannel(uniform); + + if (uniform > -1) + { + if (depth) { + gGL.getTexUnit(uniform)->bind(texture, true); + } + else { + bool has_mips = mode == LLTexUnit::TFO_TRILINEAR || mode == LLTexUnit::TFO_ANISOTROPIC; + gGL.getTexUnit(uniform)->bindManual(texture->getUsage(), texture->getTexture(index), has_mips); + } + + gGL.getTexUnit(uniform)->setTextureFilteringOption(mode); + } + + return uniform; +} + +S32 LLGLSLShader::bindTexture(const std::string& uniform, LLRenderTarget* texture, bool depth, LLTexUnit::eTextureFilterOptions mode) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + S32 channel = 0; + channel = getUniformLocation(uniform); + + return bindTexture(channel, texture, depth, mode); +} + +S32 LLGLSLShader::unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + S32 channel = 0; + channel = getUniformLocation(uniform); + + return unbindTexture(channel); +} + +S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; + return -1; + } + + uniform = mTexture[uniform]; + + if (uniform > -1) + { + gGL.getTexUnit(uniform)->unbindFast(mode); + } + + return uniform; +} + +S32 LLGLSLShader::getTextureChannel(S32 uniform) const +{ + return mTexture[uniform]; +} + +S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; + return -1; + } + S32 index = mTexture[uniform]; + if (index != -1) + { + gGL.getTexUnit(index)->activate(); + gGL.getTexUnit(index)->enable(mode); + gGL.getTexUnit(index)->setTextureColorSpace(space); + } + return index; +} + +S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; + return -1; + } + S32 index = mTexture[uniform]; + if (index != -1 && gGL.getTexUnit(index)->getCurrType() != LLTexUnit::TT_NONE) + { + if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode && gGL.getTexUnit(index)->getCurrColorSpace() != space) + { + if (gDebugSession) + { + gFailLog << "Texture channel " << index << " texture type corrupted." << std::endl; + ll_fail("LLGLSLShader::disableTexture failed"); + } + else + { + LL_ERRS() << "Texture channel " << index << " texture type corrupted." << LL_ENDL; + } + } + gGL.getTexUnit(index)->disable(); + } + return index; +} + +void LLGLSLShader::uniform1i(U32 index, GLint x) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + const auto& iter = mValue.find(mUniform[index]); + if (iter == mValue.end() || iter->second.mV[0] != x) + { + glUniform1i(mUniform[index], x); + mValue[mUniform[index]] = LLVector4(x, 0.f, 0.f, 0.f); + } + } + } +} + +void LLGLSLShader::uniform1f(U32 index, GLfloat x) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + const auto& iter = mValue.find(mUniform[index]); + if (iter == mValue.end() || iter->second.mV[0] != x) + { + glUniform1f(mUniform[index], x); + mValue[mUniform[index]] = LLVector4(x, 0.f, 0.f, 0.f); + } + } + } +} + +void LLGLSLShader::fastUniform1f(U32 index, GLfloat x) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + llassert(mProgramObject); + llassert(mUniform.size() <= index); + llassert(mUniform[index] >= 0); + glUniform1f(mUniform[index], x); +} + +void LLGLSLShader::uniform2f(U32 index, GLfloat x, GLfloat y) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + const auto& iter = mValue.find(mUniform[index]); + LLVector4 vec(x, y, 0.f, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec)) + { + glUniform2f(mUniform[index], x, y); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + const auto& iter = mValue.find(mUniform[index]); + LLVector4 vec(x, y, z, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec)) + { + glUniform3f(mUniform[index], x, y, z); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + const auto& iter = mValue.find(mUniform[index]); + LLVector4 vec(x, y, z, w); + if (iter == mValue.end() || shouldChange(iter->second, vec)) + { + glUniform4f(mUniform[index], x, y, z, w); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform1iv(U32 index, U32 count, const GLint* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + const auto& iter = mValue.find(mUniform[index]); + LLVector4 vec(v[0], 0.f, 0.f, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + glUniform1iv(mUniform[index], count, v); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform4iv(U32 index, U32 count, const GLint* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + const auto& iter = mValue.find(mUniform[index]); + LLVector4 vec(v[0], v[1], v[2], v[3]); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + glUniform1iv(mUniform[index], count, v); + mValue[mUniform[index]] = vec; + } + } + } +} + + +void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + const auto& iter = mValue.find(mUniform[index]); + LLVector4 vec(v[0], 0.f, 0.f, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + glUniform1fv(mUniform[index], count, v); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform2fv(U32 index, U32 count, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + const auto& iter = mValue.find(mUniform[index]); + LLVector4 vec(v[0], v[1], 0.f, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + glUniform2fv(mUniform[index], count, v); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform3fv(U32 index, U32 count, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + const auto& iter = mValue.find(mUniform[index]); + LLVector4 vec(v[0], v[1], v[2], 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + glUniform3fv(mUniform[index], count, v); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + const auto& iter = mValue.find(mUniform[index]); + LLVector4 vec(v[0], v[1], v[2], v[3]); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + glUniform4fv(mUniform[index], count, v); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + glUniformMatrix2fv(mUniform[index], count, transpose, v); + } + } +} + +void LLGLSLShader::uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + glUniformMatrix3fv(mUniform[index], count, transpose, v); + } + } +} + +void LLGLSLShader::uniformMatrix3x4fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + glUniformMatrix3x4fv(mUniform[index], count, transpose, v); + } + } +} + +void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + llassert(sCurBoundShaderPtr == this); + + if (mProgramObject) + { + if (mUniform.size() <= index) + { + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + glUniformMatrix4fv(mUniform[index], count, transpose, v); + } + } +} + +GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + GLint ret = -1; + if (mProgramObject) + { + LLStaticStringTable<GLint>::iterator iter = mUniformMap.find(uniform); + if (iter != mUniformMap.end()) + { + if (gDebugGL) + { + stop_glerror(); + if (iter->second != glGetUniformLocation(mProgramObject, uniform.String().c_str())) + { + LL_ERRS() << "Uniform does not match." << LL_ENDL; + } + stop_glerror(); + } + ret = iter->second; + } + } + + return ret; +} + +GLint LLGLSLShader::getUniformLocation(U32 index) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + GLint ret = -1; + if (mProgramObject) + { + if (index >= mUniform.size()) + { + LL_WARNS_ONCE("Shader") << "Uniform index " << index << " out of bounds " << (S32)mUniform.size() << LL_ENDL; + return ret; + } + return mUniform[index]; + } + + return ret; +} + +GLint LLGLSLShader::getAttribLocation(U32 attrib) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + if (attrib < mAttribute.size()) + { + return mAttribute[attrib]; + } + else + { + return -1; + } +} + +void LLGLSLShader::uniform1i(const LLStaticHashedString& uniform, GLint v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + const auto& iter = mValue.find(location); + LLVector4 vec(v, 0.f, 0.f, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec)) + { + glUniform1i(location, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform1iv(const LLStaticHashedString& uniform, U32 count, const GLint* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + LLVector4 vec(v[0], 0, 0, 0); + const auto& iter = mValue.find(location); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + glUniform1iv(location, count, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform4iv(const LLStaticHashedString& uniform, U32 count, const GLint* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + LLVector4 vec(v[0], v[1], v[2], v[3]); + const auto& iter = mValue.find(location); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + glUniform4iv(location, count, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform2i(const LLStaticHashedString& uniform, GLint i, GLint j) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + const auto& iter = mValue.find(location); + LLVector4 vec(i, j, 0.f, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec)) + { + glUniform2i(location, i, j); + mValue[location] = vec; + } + } +} + + +void LLGLSLShader::uniform1f(const LLStaticHashedString& uniform, GLfloat v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + const auto& iter = mValue.find(location); + LLVector4 vec(v, 0.f, 0.f, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec)) + { + glUniform1f(location, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + const auto& iter = mValue.find(location); + LLVector4 vec(x, y, 0.f, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec)) + { + glUniform2f(location, x, y); + mValue[location] = vec; + } + } + +} + +void LLGLSLShader::uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + const auto& iter = mValue.find(location); + LLVector4 vec(x, y, z, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec)) + { + glUniform3f(location, x, y, z); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform1fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + const auto& iter = mValue.find(location); + LLVector4 vec(v[0], 0.f, 0.f, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + glUniform1fv(location, count, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform2fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + const auto& iter = mValue.find(location); + LLVector4 vec(v[0], v[1], 0.f, 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + glUniform2fv(location, count, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform3fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + const auto& iter = mValue.find(location); + LLVector4 vec(v[0], v[1], v[2], 0.f); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + glUniform3fv(location, count, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform4fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + LLVector4 vec(v); + const auto& iter = mValue.find(location); + if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + glUniform4fv(location, count, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat* v) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + stop_glerror(); + glUniformMatrix4fv(location, count, transpose, v); + stop_glerror(); + } +} + + +void LLGLSLShader::vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + if (mAttribute[index] > 0) + { + glVertexAttrib4f(mAttribute[index], x, y, z, w); + } +} + +void LLGLSLShader::vertexAttrib4fv(U32 index, GLfloat* v) +{ + if (mAttribute[index] > 0) + { + glVertexAttrib4fv(mAttribute[index], v); + } +} + +void LLGLSLShader::setMinimumAlpha(F32 minimum) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + gGL.flush(); + uniform1f(LLShaderMgr::MINIMUM_ALPHA, minimum); +} + +void LLShaderUniforms::apply(LLGLSLShader* shader) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + for (auto& uniform : mIntegers) + { + shader->uniform1i(uniform.mUniform, uniform.mValue); + } + + for (auto& uniform : mFloats) + { + shader->uniform1f(uniform.mUniform, uniform.mValue); + } + + for (auto& uniform : mVectors) + { + shader->uniform4fv(uniform.mUniform, 1, uniform.mValue.mV); + } + + for (auto& uniform : mVector3s) + { + shader->uniform3fv(uniform.mUniform, 1, uniform.mValue.mV); + } +} + +LLUUID LLGLSLShader::hash() +{ + HBXXH128 hash_obj; + hash_obj.update(mName); + hash_obj.update(&mShaderGroup, sizeof(mShaderGroup)); + hash_obj.update(&mShaderLevel, sizeof(mShaderLevel)); + for (const auto& shdr_pair : mShaderFiles) + { + hash_obj.update(shdr_pair.first); + hash_obj.update(&shdr_pair.second, sizeof(GLenum)); + } + for (const auto& define_pair : mDefines) + { + hash_obj.update(define_pair.first); + hash_obj.update(define_pair.second); + + } + for (const auto& define_pair : LLGLSLShader::sGlobalDefines) + { + hash_obj.update(define_pair.first); + hash_obj.update(define_pair.second); + + } + hash_obj.update(&mFeatures, sizeof(LLShaderFeatures)); + hash_obj.update(gGLManager.mGLVendor); + hash_obj.update(gGLManager.mGLRenderer); + hash_obj.update(gGLManager.mGLVersionString); + return hash_obj.digest(); +} + +#ifdef LL_PROFILER_ENABLE_RENDER_DOC +void LLGLSLShader::setLabel(const char* label) { + LL_LABEL_OBJECT_GL(GL_PROGRAM, mProgramObject, strlen(label), label); +} +#endif |