diff options
Diffstat (limited to 'indra/llrender')
44 files changed, 3905 insertions, 342 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 516af93316..dba12d048e 100644..100755 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -3,7 +3,7 @@ project(llrender) include(00-Common) -include(FindOpenGL) +include(OpenGL) include(FreeType) include(LLCommon) include(LLImage) @@ -25,21 +25,31 @@ include_directories( ${LLXML_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} ) +include_directories(SYSTEM + ${LLCOMMON_SYSTEM_INCLUDE_DIRS} + ${LLXML_SYSTEM_INCLUDE_DIRS} + ) set(llrender_SOURCE_FILES llcubemap.cpp + llfontbitmapcache.cpp llfontfreetype.cpp llfontgl.cpp - llfontbitmapcache.cpp llfontregistry.cpp + llgl.cpp llgldbg.cpp llglslshader.cpp + llgltexture.cpp llimagegl.cpp llpostprocess.cpp + llrender.cpp + llrender2dutils.cpp llrendernavprim.cpp llrendersphere.cpp + llrendertarget.cpp llshadermgr.cpp lltexture.cpp + lluiimage.cpp llvertexbuffer.cpp ) @@ -56,14 +66,17 @@ set(llrender_HEADER_FILES llglheaders.h llglslshader.h llglstates.h + llgltexture.h llgltypes.h llimagegl.h llpostprocess.h llrender.h + llrender2dutils.h llrendernavprim.h llrendersphere.h llshadermgr.h lltexture.h + lluiimage.h llvertexbuffer.h ) @@ -72,33 +85,47 @@ set_source_files_properties(${llrender_HEADER_FILES} list(APPEND llrender_SOURCE_FILES ${llrender_HEADER_FILES}) -if (SERVER AND NOT WINDOWS AND NOT DARWIN) - copy_server_sources( - llgl - llrender - ) - - - set_source_files_properties( - ${server_SOURCE_FILES} - PROPERTIES - COMPILE_FLAGS "-DLL_MESA=1 -DLL_MESA_HEADLESS=1" - ) +if (BUILD_HEADLESS) add_library (llrenderheadless ${llrender_SOURCE_FILES} - ${server_SOURCE_FILES} ) -else (SERVER AND NOT WINDOWS AND NOT DARWIN) - list(APPEND llrender_SOURCE_FILES - llgl.cpp - llrender.cpp - llrendertarget.cpp + + set_property(TARGET llrenderheadless + PROPERTY COMPILE_DEFINITIONS LL_MESA=1 LL_MESA_HEADLESS=1 ) -endif (SERVER AND NOT WINDOWS AND NOT DARWIN) + + target_link_libraries(llrenderheadless + ${LLCOMMON_LIBRARIES} + ${LLIMAGE_LIBRARIES} + ${LLMATH_LIBRARIES} + ${LLRENDER_HEADLESS_LIBRARIES} + ${LLVFS_LIBRARIES} + ${LLXML_LIBRARIES} + ${LLVFS_LIBRARIES} + ${LLWINDOW_HEADLESS_LIBRARIES} + ${OPENGL_HEADLESS_LIBRARIES}) + +endif (BUILD_HEADLESS) + add_library (llrender ${llrender_SOURCE_FILES}) + +if (SDL_FOUND) + set_property(TARGET llrender + PROPERTY COMPILE_DEFINITIONS LL_SDL=1 + ) +endif (SDL_FOUND) + # Libraries on which this library depends, needed for Linux builds # Sort by high-level to low-level target_link_libraries(llrender - llimage + ${LLCOMMON_LIBRARIES} + ${LLIMAGE_LIBRARIES} + ${LLMATH_LIBRARIES} + ${LLRENDER_LIBRARIES} + ${LLVFS_LIBRARIES} + ${LLXML_LIBRARIES} + ${LLVFS_LIBRARIES} + ${LLWINDOW_LIBRARIES} ${FREETYPE_LIBRARIES} ${OPENGL_LIBRARIES}) + diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 362452d837..362452d837 100644..100755 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp diff --git a/indra/llrender/llcubemap.h b/indra/llrender/llcubemap.h index ee2c41e026..ee2c41e026 100644..100755 --- a/indra/llrender/llcubemap.h +++ b/indra/llrender/llcubemap.h diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp index c985f6b959..c985f6b959 100644..100755 --- a/indra/llrender/llfontbitmapcache.cpp +++ b/indra/llrender/llfontbitmapcache.cpp diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h index c93b0c7320..c93b0c7320 100644..100755 --- a/indra/llrender/llfontbitmapcache.h +++ b/indra/llrender/llfontbitmapcache.h diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index 66d4ad2d87..058bef43a5 100644..100755 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -485,14 +485,11 @@ void LLFontFreetype::renderGlyph(U32 glyph_index) const if (mFTFace == NULL) return; - int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT ); - llassert(!error); + llassert_always(! FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT) ); - error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode); + llassert_always(! FT_Render_Glyph(mFTFace->glyph, gFontRenderMode) ); mRenderGlyphCount++; - - llassert(!error); } void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi) diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h index f1b23f22d5..f1b23f22d5 100644..100755 --- a/indra/llrender/llfontfreetype.h +++ b/indra/llrender/llfontfreetype.h diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 647512eb2e..c4f36cabd0 100644..100755 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -541,7 +541,6 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch BOOL clip = FALSE; F32 cur_x = 0; - F32 drawn_x = 0; S32 start_of_last_word = 0; BOOL in_word = FALSE; @@ -599,6 +598,11 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch if(!fgi) { fgi = mFontFreetype->getGlyphInfo(wch); + + if (NULL == fgi) + { + return 0; + } } // account for glyphs that run beyond the starting point for the next glyphs @@ -624,7 +628,6 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch // Round after kerning. cur_x = (F32)llround(cur_x); - drawn_x = cur_x; } if( clip ) diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 0988e99deb..0988e99deb 100644..100755 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index b5bdba996f..f5ca8d5b04 100644..100755 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -223,7 +223,7 @@ std::string currentOsName() return "Windows"; #elif LL_DARWIN return "Mac"; -#elif LL_SDL +#elif LL_SDL || LL_MESA_HEADLESS return "Linux"; #else return ""; diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h index 059248fbbd..059248fbbd 100644..100755 --- a/indra/llrender/llfontregistry.h +++ b/indra/llrender/llfontregistry.h diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 9e4857b6bc..00de61a8cc 100644..100755 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -59,6 +59,7 @@ BOOL gDebugGL = FALSE; BOOL gClothRipple = FALSE; BOOL gHeadlessClient = FALSE; BOOL gGLActive = FALSE; +BOOL gGLDebugLoggingEnabled = TRUE; static const std::string HEADLESS_VENDOR_STRING("Linden Lab"); static const std::string HEADLESS_RENDERER_STRING("Headless"); @@ -72,6 +73,7 @@ std::ofstream gFailLog; #define APIENTRY #endif + void APIENTRY gl_debug_callback(GLenum source, GLenum type, GLuint id, @@ -80,22 +82,25 @@ void APIENTRY gl_debug_callback(GLenum source, const GLchar* message, GLvoid* userParam) { - if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) - { - llwarns << "----- GL ERROR --------" << llendl; - } - else - { - llwarns << "----- GL WARNING -------" << llendl; - } - llwarns << "Type: " << std::hex << type << llendl; - llwarns << "ID: " << std::hex << id << llendl; - llwarns << "Severity: " << std::hex << severity << llendl; - llwarns << "Message: " << message << llendl; - llwarns << "-----------------------" << llendl; - if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) + if (gGLDebugLoggingEnabled) { - llerrs << "Halting on GL Error" << llendl; + if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) + { + llwarns << "----- GL ERROR --------" << llendl; + } + else + { + llwarns << "----- GL WARNING -------" << llendl; + } + llwarns << "Type: " << std::hex << type << llendl; + llwarns << "ID: " << std::hex << id << llendl; + llwarns << "Severity: " << std::hex << severity << llendl; + llwarns << "Message: " << message << llendl; + llwarns << "-----------------------" << llendl; + if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) + { + llerrs << "Halting on GL Error" << llendl; + } } } #endif @@ -216,6 +221,11 @@ PFNGLGETQUERYIVARBPROC glGetQueryivARB = NULL; PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB = NULL; PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL; +// GL_ARB_timer_query +PFNGLQUERYCOUNTERPROC glQueryCounter = NULL; +PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v = NULL; +PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v = NULL; + // GL_ARB_point_parameters PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL; PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = NULL; @@ -253,6 +263,7 @@ PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = NULL; PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = NULL; PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = NULL; PFNGLBINDBUFFERRANGEPROC glBindBufferRange = NULL; +PFNGLBINDBUFFERBASEPROC glBindBufferBase = NULL; //GL_ARB_debug_output PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL; @@ -421,6 +432,7 @@ LLGLManager::LLGLManager() : mHasFragmentShader(FALSE), mNumTextureImageUnits(0), mHasOcclusionQuery(FALSE), + mHasTimerQuery(FALSE), mHasOcclusionQuery2(FALSE), mHasPointParameters(FALSE), mHasDrawBuffers(FALSE), @@ -445,7 +457,9 @@ LLGLManager::LLGLManager() : mIsGFFX(FALSE), mATIOffsetVerticalLines(FALSE), mATIOldDriver(FALSE), - +#if LL_DARWIN + mIsMobileGF(FALSE), +#endif mHasRequirements(TRUE), mHasSeparateSpecularColor(FALSE), @@ -597,11 +611,6 @@ bool LLGLManager::initGL() if (mGLVendor.substr(0,4) == "ATI ") { mGLVendorShort = "ATI"; - BOOL mobile = FALSE; - if (mGLRenderer.find("MOBILITY") != std::string::npos) - { - mobile = TRUE; - } mIsATI = TRUE; #if LL_WINDOWS && !LL_MESA_HEADLESS @@ -642,6 +651,13 @@ bool LLGLManager::initGL() { mIsGF3 = TRUE; } +#if LL_DARWIN + else if ((mGLRenderer.find("9400M") != std::string::npos) + || (mGLRenderer.find("9600M") != std::string::npos)) + { + mIsMobileGF = TRUE; + } +#endif } else if (mGLVendor.find("INTEL") != std::string::npos @@ -735,7 +751,7 @@ bool LLGLManager::initGL() #if LL_WINDOWS if (mHasDebugOutput && gDebugGL) { //setup debug output callback - //glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE); + glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE); glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); } @@ -750,12 +766,13 @@ bool LLGLManager::initGL() { //using multisample textures on ATI results in black screen for some reason mHasTextureMultisample = FALSE; } -#endif + if (mIsIntel && mGLVersion <= 3.f) { //never try to use framebuffer objects on older intel drivers (crashy) mHasFramebufferObject = FALSE; } +#endif if (mHasFramebufferObject) { @@ -952,13 +969,15 @@ void LLGLManager::initExtensions() mHasARBEnvCombine = ExtensionExists("GL_ARB_texture_env_combine", gGLHExts.mSysExts); mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression"); mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts); + mHasTimerQuery = ExtensionExists("GL_ARB_timer_query", gGLHExts.mSysExts); mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts); mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts); mHasVertexArrayObject = ExtensionExists("GL_ARB_vertex_array_object", gGLHExts.mSysExts); mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts); mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts); mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts); - mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts); + //mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts); + mHasDepthClamp = FALSE; // mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad #ifdef GL_ARB_framebuffer_object mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts); @@ -968,6 +987,15 @@ void LLGLManager::initExtensions() ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts) && ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts); #endif +#ifdef GL_EXT_texture_sRGB + mHassRGBTexture = ExtensionExists("GL_EXT_texture_sRGB", gGLHExts.mSysExts); +#endif + +#ifdef GL_ARB_framebuffer_sRGB + mHassRGBFramebuffer = ExtensionExists("GL_ARB_framebuffer_sRGB", gGLHExts.mSysExts); +#else + mHassRGBFramebuffer = ExtensionExists("GL_EXT_framebuffer_sRGB", gGLHExts.mSysExts); +#endif mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f; @@ -1132,7 +1160,8 @@ void LLGLManager::initExtensions() // Misc glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange); glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange); - + glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*) &mGLMaxTextureSize); + #if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL; if (mHasVertexBufferObject) @@ -1223,6 +1252,7 @@ void LLGLManager::initExtensions() glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glEndTransformFeedback"); glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) GLH_EXT_GET_PROC_ADDRESS("glTransformFeedbackVaryings"); glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferRange"); + glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferBase"); } if (mHasDebugOutput) { @@ -1258,6 +1288,13 @@ void LLGLManager::initExtensions() glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectivARB"); glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectuivARB"); } + if (mHasTimerQuery) + { + llinfos << "initExtensions() TimerQuery-related procs..." << llendl; + glQueryCounter = (PFNGLQUERYCOUNTERPROC) GLH_EXT_GET_PROC_ADDRESS("glQueryCounter"); + glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjecti64v"); + glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectui64v"); + } if (mHasPointParameters) { llinfos << "initExtensions() PointParameters-related procs..." << llendl; @@ -1470,7 +1507,7 @@ void do_assert_glerror() void assert_glerror() { - if (!gGLActive) +/* if (!gGLActive) { //llwarns << "GL used while not active!" << llendl; @@ -1479,8 +1516,13 @@ void assert_glerror() //ll_fail("GL used while not active"); } } +*/ - if (gDebugGL) + if (!gDebugGL) + { + //funny looking if for branch prediction -- gDebugGL is almost always false and assert_glerror is called often + } + else { do_assert_glerror(); } @@ -1489,9 +1531,8 @@ void assert_glerror() void clear_glerror() { - // Create or update texture to be used with this data - GLenum error; - error = glGetError(); + glGetError(); + glGetError(); } /////////////////////////////////////////////////////////////// diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index d70e764769..75e5fe86ec 100644..100755 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -98,6 +98,7 @@ public: BOOL mHasFragmentShader; S32 mNumTextureImageUnits; BOOL mHasOcclusionQuery; + BOOL mHasTimerQuery; BOOL mHasOcclusionQuery2; BOOL mHasPointParameters; BOOL mHasDrawBuffers; @@ -115,6 +116,8 @@ public: BOOL mHasARBEnvCombine; BOOL mHasCubeMap; BOOL mHasDebugOutput; + BOOL mHassRGBTexture; + BOOL mHassRGBFramebuffer; // Vendor-specific extensions BOOL mIsATI; @@ -126,6 +129,11 @@ public: BOOL mATIOffsetVerticalLines; BOOL mATIOldDriver; +#if LL_DARWIN + // Needed to distinguish problem cards on older Macs that break with Materials + BOOL mIsMobileGF; +#endif + // Whether this version of GL is good enough for SL to use BOOL mHasRequirements; @@ -147,6 +155,7 @@ public: S32 mVRAM; // VRAM in MB S32 mGLMaxVertexRange; S32 mGLMaxIndexRange; + S32 mGLMaxTextureSize; void getPixelFormat(); // Get the best pixel format diff --git a/indra/llrender/llgldbg.cpp b/indra/llrender/llgldbg.cpp index 4b68194db3..4b68194db3 100644..100755 --- a/indra/llrender/llgldbg.cpp +++ b/indra/llrender/llgldbg.cpp diff --git a/indra/llrender/llgldbg.h b/indra/llrender/llgldbg.h index 963579cb82..963579cb82 100644..100755 --- a/indra/llrender/llgldbg.h +++ b/indra/llrender/llgldbg.h diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 509de51f4d..4a4153ece8 100644..100755 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -116,6 +116,11 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB; extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB; extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB; +// GL_ARB_timer_query +extern PFNGLQUERYCOUNTERPROC glQueryCounter; +extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v; +extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v; + // GL_ARB_point_parameters extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB; extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB; @@ -378,6 +383,11 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB; extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB; extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB; +// GL_ARB_timer_query +extern PFNGLQUERYCOUNTERPROC glQueryCounter; +extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v; +extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v; + // GL_ARB_point_parameters extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB; extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB; @@ -533,6 +543,7 @@ extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; +extern PFNGLBINDBUFFERBASEPROC glBindBufferBase; #elif LL_WINDOWS @@ -619,6 +630,12 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB; extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB; extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB; +// GL_ARB_timer_query +extern PFNGLQUERYCOUNTERPROC glQueryCounter; +extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v; +extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v; + + // GL_ARB_point_parameters extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB; extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB; @@ -771,6 +788,7 @@ extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; +extern PFNGLBINDBUFFERBASEPROC glBindBufferBase; //GL_ARB_debug_output extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB; diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 7cbf39096e..dfb73de6f3 100644..100755 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -53,6 +53,12 @@ GLhandleARB LLGLSLShader::sCurBoundShader = 0; LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL; S32 LLGLSLShader::sIndexedTextureChannels = 0; bool LLGLSLShader::sNoFixedFunction = false; +bool LLGLSLShader::sProfileEnabled = false; +std::set<LLGLSLShader*> LLGLSLShader::sInstances; +U64 LLGLSLShader::sTotalTimeElapsed = 0; +U32 LLGLSLShader::sTotalTrianglesDrawn = 0; +U64 LLGLSLShader::sTotalSamplesDrawn = 0; +U32 LLGLSLShader::sTotalDrawCalls = 0; //UI shader -- declared here so llui_libtest will link properly LLGLSLShader gUIProgram; @@ -87,19 +93,240 @@ LLShaderFeatures::LLShaderFeatures() //=============================== // LLGLSL Shader implementation //=============================== + +//static +void LLGLSLShader::initProfile() +{ + sProfileEnabled = true; + sTotalTimeElapsed = 0; + sTotalTrianglesDrawn = 0; + sTotalSamplesDrawn = 0; + sTotalDrawCalls = 0; + + for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter) + { + (*iter)->clearStats(); + } +} + + +struct LLGLSLShaderCompareTimeElapsed +{ + bool operator()(const LLGLSLShader* const& lhs, const LLGLSLShader* const& rhs) + { + return lhs->mTimeElapsed < rhs->mTimeElapsed; + } +}; + +//static +void LLGLSLShader::finishProfile() +{ + sProfileEnabled = false; + + std::vector<LLGLSLShader*> sorted; + + for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter) + { + sorted.push_back(*iter); + } + + std::sort(sorted.begin(), sorted.end(), LLGLSLShaderCompareTimeElapsed()); + + for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter) + { + (*iter)->dumpStats(); + } + + llinfos << "-----------------------------------" << llendl; + llinfos << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed/1000000.f) << llendl; + llinfos << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn/1000000.f) << llendl; + llinfos << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn/1000000.f) << llendl; +} + +void LLGLSLShader::clearStats() +{ + mTrianglesDrawn = 0; + mTimeElapsed = 0; + mSamplesDrawn = 0; + mDrawCalls = 0; + mTextureStateFetched = false; + mTextureMagFilter.clear(); + mTextureMinFilter.clear(); +} + +void LLGLSLShader::dumpStats() +{ + if (mDrawCalls > 0) + { + llinfos << "=============================================" << llendl; + llinfos << mName << llendl; + for (U32 i = 0; i < mShaderFiles.size(); ++i) + { + llinfos << mShaderFiles[i].first << llendl; + } + for (U32 i = 0; i < mTexture.size(); ++i) + { + GLint idx = mTexture[i]; + + if (idx >= 0) + { + GLint uniform_idx = getUniformLocation(i); + llinfos << mUniformNameMap[uniform_idx] << " - " << std::hex << mTextureMagFilter[i] << "/" << mTextureMinFilter[i] << std::dec << llendl; + } + } + llinfos << "=============================================" << llendl; + + F32 ms = mTimeElapsed/1000000.f; + F32 seconds = ms/1000.f; + + F32 pct_tris = (F32) mTrianglesDrawn/(F32)sTotalTrianglesDrawn*100.f; + F32 tris_sec = (F32) (mTrianglesDrawn/1000000.0); + tris_sec /= seconds; + + F32 pct_samples = (F32) ((F64)mSamplesDrawn/(F64)sTotalSamplesDrawn)*100.f; + F32 samples_sec = (F32) mSamplesDrawn/1000000000.0; + samples_sec /= seconds; + + F32 pct_calls = (F32) mDrawCalls/(F32)sTotalDrawCalls*100.f; + U32 avg_batch = mTrianglesDrawn/mDrawCalls; + + llinfos << "Triangles Drawn: " << mTrianglesDrawn << " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec ) << llendl; + llinfos << "Draw Calls: " << mDrawCalls << " " << llformat("(%.2f pct of total, avg %d tris/call)", pct_calls, avg_batch) << llendl; + llinfos << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << llendl; + llinfos << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32) ((F64)mTimeElapsed/(F64)sTotalTimeElapsed)*100.f, ms) << llendl; + } +} + +//static +void LLGLSLShader::startProfile() +{ + if (sProfileEnabled && sCurBoundShaderPtr) + { + sCurBoundShaderPtr->placeProfileQuery(); + } + +} + +//static +void LLGLSLShader::stopProfile(U32 count, U32 mode) +{ + if (sProfileEnabled) + { + sCurBoundShaderPtr->readProfileQuery(count, mode); + } +} + +void LLGLSLShader::placeProfileQuery() +{ +#if !LL_DARWIN + if (mTimerQuery == 0) + { + glGenQueriesARB(1, &mTimerQuery); + } + + if (!mTextureStateFetched) + { + mTextureStateFetched = true; + mTextureMagFilter.resize(mTexture.size()); + mTextureMinFilter.resize(mTexture.size()); + + U32 cur_active = gGL.getCurrentTexUnitIndex(); + + for (U32 i = 0; i < mTexture.size(); ++i) + { + GLint idx = mTexture[i]; + + if (idx >= 0) + { + gGL.getTexUnit(idx)->activate(); + + U32 mag = 0xFFFFFFFF; + U32 min = 0xFFFFFFFF; + + U32 type = LLTexUnit::getInternalType(gGL.getTexUnit(idx)->getCurrType()); + + glGetTexParameteriv(type, GL_TEXTURE_MAG_FILTER, (GLint*) &mag); + glGetTexParameteriv(type, GL_TEXTURE_MIN_FILTER, (GLint*) &min); + + mTextureMagFilter[i] = mag; + mTextureMinFilter[i] = min; + } + } + + gGL.getTexUnit(cur_active)->activate(); + } + + + glBeginQueryARB(GL_SAMPLES_PASSED, 1); + glBeginQueryARB(GL_TIME_ELAPSED, mTimerQuery); +#endif +} + +void LLGLSLShader::readProfileQuery(U32 count, U32 mode) +{ +#if !LL_DARWIN + glEndQueryARB(GL_TIME_ELAPSED); + glEndQueryARB(GL_SAMPLES_PASSED); + + U64 time_elapsed = 0; + glGetQueryObjectui64v(mTimerQuery, GL_QUERY_RESULT, &time_elapsed); + + U64 samples_passed = 0; + glGetQueryObjectui64v(1, GL_QUERY_RESULT, &samples_passed); + + sTotalTimeElapsed += time_elapsed; + mTimeElapsed += time_elapsed; + + sTotalSamplesDrawn += samples_passed; + mSamplesDrawn += samples_passed; + + U32 tri_count = 0; + switch (mode) + { + case LLRender::TRIANGLES: tri_count = count/3; break; + case LLRender::TRIANGLE_FAN: tri_count = count-2; break; + case LLRender::TRIANGLE_STRIP: tri_count = count-2; break; + default: tri_count = count; break; //points lines etc just use primitive count + } + + mTrianglesDrawn += tri_count; + sTotalTrianglesDrawn += tri_count; + + sTotalDrawCalls++; + mDrawCalls++; +#endif +} + + + LLGLSLShader::LLGLSLShader() - : mProgramObject(0), mActiveTextureChannels(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT), mUniformsDirty(FALSE) + : mProgramObject(0), + mAttributeMask(0), + mTotalUniformSize(0), + mActiveTextureChannels(0), + mShaderLevel(0), + mShaderGroup(SG_DEFAULT), + mUniformsDirty(FALSE), + mTimerQuery(0) { + +} +LLGLSLShader::~LLGLSLShader() +{ + } void LLGLSLShader::unload() { + sInstances.erase(this); + stop_glerror(); mAttribute.clear(); mTexture.clear(); mUniform.clear(); mShaderFiles.clear(); + mDefines.clear(); if (mProgramObject) { @@ -128,11 +355,13 @@ void LLGLSLShader::unload() stop_glerror(); } -BOOL LLGLSLShader::createShader(vector<string> * attributes, - vector<string> * uniforms, +BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes, + std::vector<LLStaticHashedString> * uniforms, U32 varying_count, const char** varyings) { + sInstances.insert(this); + //reloading, reset matrix hash values for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i) { @@ -150,7 +379,7 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes, vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin(); for ( ; fileIter != mShaderFiles.end(); fileIter++ ) { - GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, mFeatures.mIndexedTextureChannels); + GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, &mDefines, mFeatures.mIndexedTextureChannels); LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL; if (shaderhandle > 0) { @@ -209,7 +438,8 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes, for (S32 i = 0; i < channel_count; i++) { - uniform1i(llformat("tex%d", i), i); + LLStaticHashedString uniName(llformat("tex%d", i)); + uniform1i(uniName, i); } S32 cur_tex = channel_count; //adjust any texture channels that might have been overwritten @@ -266,7 +496,7 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count) } } -BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes) +BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attributes) { //before linking, make sure reserved attributes always have consistent locations for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++) @@ -285,6 +515,8 @@ BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes) if (res) { //read back channel locations + mAttributeMask = 0; + //read back reserved channels first for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++) { @@ -293,6 +525,7 @@ BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes) if (index != -1) { mAttribute[i] = index; + mAttributeMask |= 1 << i; LL_DEBUGS("ShaderLoading") << "Attribute " << name << " assigned to channel " << index << LL_ENDL; } } @@ -300,7 +533,7 @@ BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes) { for (U32 i = 0; i < numAttributes; i++) { - const char* name = (*attributes)[i].c_str(); + const char* name = (*attributes)[i].String().c_str(); S32 index = glGetAttribLocationARB(mProgramObject, name); if (index != -1) { @@ -316,7 +549,7 @@ BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes) return FALSE; } -void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms) +void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString> * uniforms) { if (index == -1) { @@ -325,11 +558,56 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms) GLenum type; GLsizei length; - GLint size; + GLint size = -1; char name[1024]; /* Flawfinder: ignore */ name[0] = 0; + glGetActiveUniformARB(mProgramObject, index, 1024, &length, &size, &type, (GLcharARB *)name); +#if !LL_DARWIN + if (size > 0) + { + switch(type) + { + case GL_FLOAT_VEC2: size *= 2; break; + case GL_FLOAT_VEC3: size *= 3; break; + case GL_FLOAT_VEC4: size *= 4; break; + case GL_DOUBLE: size *= 2; break; + case GL_DOUBLE_VEC2: size *= 2; break; + case GL_DOUBLE_VEC3: size *= 6; break; + case GL_DOUBLE_VEC4: size *= 8; break; + case GL_INT_VEC2: size *= 2; break; + case GL_INT_VEC3: size *= 3; break; + case GL_INT_VEC4: size *= 4; break; + case GL_UNSIGNED_INT_VEC2: size *= 2; break; + case GL_UNSIGNED_INT_VEC3: size *= 3; break; + case GL_UNSIGNED_INT_VEC4: size *= 4; break; + case GL_BOOL_VEC2: size *= 2; break; + case GL_BOOL_VEC3: size *= 3; break; + case GL_BOOL_VEC4: size *= 4; break; + case GL_FLOAT_MAT2: size *= 4; break; + case GL_FLOAT_MAT3: size *= 9; break; + case GL_FLOAT_MAT4: size *= 16; break; + case GL_FLOAT_MAT2x3: size *= 6; break; + case GL_FLOAT_MAT2x4: size *= 8; break; + case GL_FLOAT_MAT3x2: size *= 6; break; + case GL_FLOAT_MAT3x4: size *= 12; break; + case GL_FLOAT_MAT4x2: size *= 8; break; + case GL_FLOAT_MAT4x3: size *= 12; break; + case GL_DOUBLE_MAT2: size *= 8; break; + case GL_DOUBLE_MAT3: size *= 18; break; + case GL_DOUBLE_MAT4: size *= 32; break; + case GL_DOUBLE_MAT2x3: size *= 12; break; + case GL_DOUBLE_MAT2x4: size *= 16; break; + case GL_DOUBLE_MAT3x2: size *= 12; break; + case GL_DOUBLE_MAT3x4: size *= 24; break; + case GL_DOUBLE_MAT4x2: size *= 16; break; + case GL_DOUBLE_MAT4x3: size *= 24; break; + } + mTotalUniformSize += size; + } +#endif + S32 location = glGetUniformLocationARB(mProgramObject, name); if (location != -1) { @@ -341,7 +619,10 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms) is_array[0] = 0; } - mUniformMap[name] = location; + LLStaticHashedString hashedName(name); + mUniformNameMap[location] = name; + mUniformMap[hashedName] = location; + LL_DEBUGS("ShaderLoading") << "Uniform " << name << " is at location " << location << LL_ENDL; //find the index of this uniform @@ -362,7 +643,7 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms) for (U32 i = 0; i < uniforms->size(); i++) { if ( (mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] == -1) - && ((*uniforms)[i] == name)) + && ((*uniforms)[i].String() == name)) { //found it mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] = location; @@ -372,11 +653,21 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms) } } } - } +} + +void LLGLSLShader::addPermutation(std::string name, std::string value) +{ + mDefines[name] = value; +} + +void LLGLSLShader::removePermutation(std::string name) +{ + mDefines[name].erase(); +} GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type) { - if (type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB || + if ((type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB) || type == GL_SAMPLER_2D_MULTISAMPLE) { //this here is a texture glUniform1iARB(location, mActiveTextureChannels); @@ -386,13 +677,15 @@ GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type) return -1; } -BOOL LLGLSLShader::mapUniforms(const vector<string> * uniforms) +BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms) { BOOL res = TRUE; + mTotalUniformSize = 0; mActiveTextureChannels = 0; mUniform.clear(); mUniformMap.clear(); + mUniformNameMap.clear(); mTexture.clear(); mValue.clear(); //initialize arrays @@ -413,6 +706,7 @@ BOOL LLGLSLShader::mapUniforms(const vector<string> * uniforms) unbind(); + LL_DEBUGS("ShaderLoading") << "Total Uniform Size: " << mTotalUniformSize << llendl; return res; } @@ -471,6 +765,58 @@ void LLGLSLShader::bindNoShader(void) } } +S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LLTexUnit::eTextureType mode) +{ + S32 channel = 0; + channel = getUniformLocation(uniform); + + return bindTexture(channel, texture, mode); +} + +S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode) +{ + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL; + return -1; + } + + uniform = mTexture[uniform]; + + if (uniform > -1) + { + gGL.getTexUnit(uniform)->bind(texture, mode); + } + + return uniform; +} + +S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureType mode) +{ + S32 channel = 0; + channel = getUniformLocation(uniform); + + return unbindTexture(channel); +} + +S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode) +{ + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL; + return -1; + } + + uniform = mTexture[uniform]; + + if (uniform > -1) + { + gGL.getTexUnit(uniform)->unbind(mode); + } + + return uniform; +} + S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode) { if (uniform < 0 || uniform >= (S32)mTexture.size()) @@ -793,18 +1139,18 @@ void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, c } } -GLint LLGLSLShader::getUniformLocation(const string& uniform) +GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform) { GLint ret = -1; if (mProgramObject > 0) { - std::map<string, GLint>::iterator iter = mUniformMap.find(uniform); + LLStaticStringTable<GLint>::iterator iter = mUniformMap.find(uniform); if (iter != mUniformMap.end()) { if (gDebugGL) { stop_glerror(); - if (iter->second != glGetUniformLocationARB(mProgramObject, uniform.c_str())) + if (iter->second != glGetUniformLocationARB(mProgramObject, uniform.String().c_str())) { llerrs << "Uniform does not match." << llendl; } @@ -841,10 +1187,10 @@ GLint LLGLSLShader::getAttribLocation(U32 attrib) } } -void LLGLSLShader::uniform1i(const string& uniform, GLint v) +void LLGLSLShader::uniform1i(const LLStaticHashedString& uniform, GLint v) { GLint location = getUniformLocation(uniform); - + if (location >= 0) { std::map<GLint, LLVector4>::iterator iter = mValue.find(location); @@ -857,72 +1203,73 @@ void LLGLSLShader::uniform1i(const string& uniform, GLint v) } } -void LLGLSLShader::uniform1f(const string& uniform, GLfloat v) +void LLGLSLShader::uniform2i(const LLStaticHashedString& uniform, GLint i, GLint j) { GLint location = getUniformLocation(uniform); if (location >= 0) { std::map<GLint, LLVector4>::iterator iter = mValue.find(location); - LLVector4 vec(v,0.f,0.f,0.f); + LLVector4 vec(i,j,0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec)) { - glUniform1fARB(location, v); + glUniform2iARB(location, i, j); mValue[location] = vec; } } } -void LLGLSLShader::uniform2f(const string& uniform, GLfloat x, GLfloat y) + +void LLGLSLShader::uniform1f(const LLStaticHashedString& uniform, GLfloat v) { GLint location = getUniformLocation(uniform); - + if (location >= 0) { std::map<GLint, LLVector4>::iterator iter = mValue.find(location); - LLVector4 vec(x,y,0.f,0.f); + LLVector4 vec(v,0.f,0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec)) { - glUniform2fARB(location, x,y); + glUniform1fARB(location, v); mValue[location] = vec; } } - } -void LLGLSLShader::uniform3f(const string& uniform, GLfloat x, GLfloat y, GLfloat z) +void LLGLSLShader::uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y) { GLint location = getUniformLocation(uniform); - + if (location >= 0) { std::map<GLint, LLVector4>::iterator iter = mValue.find(location); - LLVector4 vec(x,y,z,0.f); + LLVector4 vec(x,y,0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec)) { - glUniform3fARB(location, x,y,z); + glUniform2fARB(location, x,y); mValue[location] = vec; } } + } -void LLGLSLShader::uniform4f(const string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +void LLGLSLShader::uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z) { GLint location = getUniformLocation(uniform); if (location >= 0) { std::map<GLint, LLVector4>::iterator iter = mValue.find(location); - LLVector4 vec(x,y,z,w); + LLVector4 vec(x,y,z,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec)) { - glUniform4fARB(location, x,y,z,w); + glUniform3fARB(location, x,y,z); mValue[location] = vec; } } } -void LLGLSLShader::uniform1fv(const string& uniform, U32 count, const GLfloat* v) +void LLGLSLShader::uniform1fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) { GLint location = getUniformLocation(uniform); @@ -938,10 +1285,10 @@ void LLGLSLShader::uniform1fv(const string& uniform, U32 count, const GLfloat* v } } -void LLGLSLShader::uniform2fv(const string& uniform, U32 count, const GLfloat* v) +void LLGLSLShader::uniform2fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) { GLint location = getUniformLocation(uniform); - + if (location >= 0) { std::map<GLint, LLVector4>::iterator iter = mValue.find(location); @@ -954,10 +1301,10 @@ void LLGLSLShader::uniform2fv(const string& uniform, U32 count, const GLfloat* v } } -void LLGLSLShader::uniform3fv(const string& uniform, U32 count, const GLfloat* v) +void LLGLSLShader::uniform3fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) { GLint location = getUniformLocation(uniform); - + if (location >= 0) { std::map<GLint, LLVector4>::iterator iter = mValue.find(location); @@ -970,7 +1317,7 @@ void LLGLSLShader::uniform3fv(const string& uniform, U32 count, const GLfloat* v } } -void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v) +void LLGLSLShader::uniform4fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) { GLint location = getUniformLocation(uniform); @@ -988,27 +1335,7 @@ void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v } } -void LLGLSLShader::uniformMatrix2fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - glUniformMatrix2fvARB(location, count, transpose, v); - } -} - -void LLGLSLShader::uniformMatrix3fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - glUniformMatrix3fvARB(location, count, transpose, v); - } -} - -void LLGLSLShader::uniformMatrix4fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v) +void LLGLSLShader::uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat* v) { GLint location = getUniformLocation(uniform); diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 5c68cb46eb..7b2f5f04c2 100644..100755 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -29,6 +29,7 @@ #include "llgl.h" #include "llrender.h" +#include "llstaticstringtable.h" class LLShaderFeatures { @@ -67,24 +68,39 @@ public: SG_WATER }; + static std::set<LLGLSLShader*> sInstances; + static bool sProfileEnabled; + LLGLSLShader(); + ~LLGLSLShader(); static GLhandleARB sCurBoundShader; static LLGLSLShader* sCurBoundShaderPtr; static S32 sIndexedTextureChannels; static bool sNoFixedFunction; + static void initProfile(); + static void finishProfile(); + + static void startProfile(); + static void stopProfile(U32 count, U32 mode); + void unload(); - BOOL createShader(std::vector<std::string> * attributes, - std::vector<std::string> * uniforms, + void clearStats(); + void dumpStats(); + void placeProfileQuery(); + void readProfileQuery(U32 count, U32 mode); + + BOOL createShader(std::vector<LLStaticHashedString> * attributes, + std::vector<LLStaticHashedString> * uniforms, U32 varying_count = 0, const char** varyings = NULL); BOOL attachObject(std::string object); void attachObject(GLhandleARB object); void attachObjects(GLhandleARB* objects = NULL, S32 count = 0); - BOOL mapAttributes(const std::vector<std::string> * attributes); - BOOL mapUniforms(const std::vector<std::string> * uniforms); - void mapUniform(GLint index, const std::vector<std::string> * uniforms); + BOOL mapAttributes(const std::vector<LLStaticHashedString> * attributes); + BOOL mapUniforms(const std::vector<LLStaticHashedString> *); + void mapUniform(GLint index, const std::vector<LLStaticHashedString> *); void uniform1i(U32 index, GLint i); void uniform1f(U32 index, GLfloat v); void uniform2f(U32 index, GLfloat x, GLfloat y); @@ -95,40 +111,48 @@ public: void uniform2fv(U32 index, U32 count, const GLfloat* v); void uniform3fv(U32 index, U32 count, const GLfloat* v); void uniform4fv(U32 index, U32 count, const GLfloat* v); - void uniform1i(const std::string& uniform, GLint i); - void uniform1f(const std::string& uniform, GLfloat v); - void uniform2f(const std::string& uniform, GLfloat x, GLfloat y); - void uniform3f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z); - void uniform4f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void uniform1iv(const std::string& uniform, U32 count, const GLint* i); - void uniform1fv(const std::string& uniform, U32 count, const GLfloat* v); - void uniform2fv(const std::string& uniform, U32 count, const GLfloat* v); - void uniform3fv(const std::string& uniform, U32 count, const GLfloat* v); - void uniform4fv(const std::string& uniform, U32 count, const GLfloat* v); + void uniform2i(const LLStaticHashedString& uniform, GLint i, GLint j); void uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); void uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); void uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); - void uniformMatrix2fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v); - void uniformMatrix3fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v); - void uniformMatrix4fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v); + void uniform1i(const LLStaticHashedString& uniform, GLint i); + void uniform1f(const LLStaticHashedString& uniform, GLfloat v); + void uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y); + void uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z); + void uniform1fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v); + void uniform2fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v); + void uniform3fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v); + void uniform4fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v); + void uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat *v); void setMinimumAlpha(F32 minimum); void vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); void vertexAttrib4fv(U32 index, GLfloat* v); - GLint getUniformLocation(const std::string& uniform); + //GLint getUniformLocation(const std::string& uniform); + GLint getUniformLocation(const LLStaticHashedString& uniform); GLint getUniformLocation(U32 index); GLint getAttribLocation(U32 attrib); GLint mapUniformTextureChannel(GLint location, GLenum type); + void addPermutation(std::string name, std::string value); + void removePermutation(std::string name); + //enable/disable texture channel for specified uniform //if given texture uniform is active in the shader, //the corresponding channel will be active upon return //returns channel texture is enabled in from [0-MAX) S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); - S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + + // bindTexture returns the texture unit we've bound the texture to. + // You can reuse the return value to unbind a texture when required. + S32 bindTexture(const std::string& uniform, LLTexture *texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + S32 bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + S32 unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + S32 unbindTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); BOOL link(BOOL suppress_errors = FALSE); void bind(); @@ -142,10 +166,13 @@ public: GLhandleARB mProgramObject; std::vector<GLint> mAttribute; //lookup table of attribute enum to attribute channel + U32 mAttributeMask; //mask of which reserved attributes are set (lines up with LLVertexBuffer::getTypeMask()) std::vector<GLint> mUniform; //lookup table of uniform enum to uniform location - std::map<std::string, GLint> mUniformMap; //lookup map of uniform name to uniform location + LLStaticStringTable<GLint> mUniformMap; //lookup map of uniform name to uniform location + std::map<GLint, std::string> mUniformNameMap; //lookup map of uniform location to uniform name std::map<GLint, LLVector4> mValue; //lookup map of uniform location to last known value std::vector<GLint> mTexture; + S32 mTotalUniformSize; S32 mActiveTextureChannels; S32 mShaderLevel; S32 mShaderGroup; @@ -153,12 +180,31 @@ public: LLShaderFeatures mFeatures; std::vector< std::pair< std::string, GLenum > > mShaderFiles; std::string mName; + boost::unordered_map<std::string, std::string> mDefines; + + //statistcis for profiling shader performance + U32 mTimerQuery; + U64 mTimeElapsed; + static U64 sTotalTimeElapsed; + U32 mTrianglesDrawn; + static U32 sTotalTrianglesDrawn; + U64 mSamplesDrawn; + static U64 sTotalSamplesDrawn; + U32 mDrawCalls; + static U32 sTotalDrawCalls; + + bool mTextureStateFetched; + std::vector<U32> mTextureMagFilter; + std::vector<U32> mTextureMinFilter; + }; //UI shader (declared here so llui_libtest will link properly) extern LLGLSLShader gUIProgram; //output vec4(color.rgb,color.a*tex0[tc0].a) extern LLGLSLShader gSolidColorProgram; +//Alpha mask shader (declared here so llappearance can access properly) +extern LLGLSLShader gAlphaMaskProgram; #endif diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h index 0e2c3bcb44..0e2c3bcb44 100644..100755 --- a/indra/llrender/llglstates.h +++ b/indra/llrender/llglstates.h diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp new file mode 100644 index 0000000000..d06ed5e57b --- /dev/null +++ b/indra/llrender/llgltexture.cpp @@ -0,0 +1,396 @@ +/** + * @file llgltexture.cpp + * @brief Opengl texture implementation + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ +#include "linden_common.h" +#include "llgltexture.h" + + +// static +S32 LLGLTexture::getTotalNumOfCategories() +{ + return MAX_GL_IMAGE_CATEGORY - (BOOST_HIGH - BOOST_SCULPTED) + 2 ; +} + +// static +//index starts from zero. +S32 LLGLTexture::getIndexFromCategory(S32 category) +{ + return (category < BOOST_HIGH) ? category : category - (BOOST_HIGH - BOOST_SCULPTED) + 1 ; +} + +//static +S32 LLGLTexture::getCategoryFromIndex(S32 index) +{ + return (index < BOOST_HIGH) ? index : index + (BOOST_HIGH - BOOST_SCULPTED) - 1 ; +} + +LLGLTexture::LLGLTexture(BOOL usemipmaps) +{ + init(); + mUseMipMaps = usemipmaps; +} + +LLGLTexture::LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) +{ + init(); + mFullWidth = width ; + mFullHeight = height ; + mUseMipMaps = usemipmaps; + mComponents = components ; + setTexelsPerImage(); +} + +LLGLTexture::LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps) +{ + init(); + mUseMipMaps = usemipmaps ; + // Create an empty image of the specified size and width + mGLTexturep = new LLImageGL(raw, usemipmaps) ; +} + +LLGLTexture::~LLGLTexture() +{ + cleanup(); +} + +void LLGLTexture::init() +{ + mBoostLevel = LLGLTexture::BOOST_NONE; + + mFullWidth = 0; + mFullHeight = 0; + mTexelsPerImage = 0 ; + mUseMipMaps = FALSE ; + mComponents = 0 ; + + mTextureState = NO_DELETE ; + mDontDiscard = FALSE; + mNeedsGLTexture = FALSE ; +} + +void LLGLTexture::cleanup() +{ + if(mGLTexturep) + { + mGLTexturep->cleanup(); + } +} + +// virtual +void LLGLTexture::dump() +{ + if(mGLTexturep) + { + mGLTexturep->dump(); + } +} + +void LLGLTexture::setBoostLevel(S32 level) +{ + if(mBoostLevel != level) + { + mBoostLevel = level ; + if(mBoostLevel != LLGLTexture::BOOST_NONE) + { + setNoDelete() ; + } + } +} + +void LLGLTexture::forceActive() +{ + mTextureState = ACTIVE ; +} + +void LLGLTexture::setActive() +{ + if(mTextureState != NO_DELETE) + { + mTextureState = ACTIVE ; + } +} + +//set the texture to stay in memory +void LLGLTexture::setNoDelete() +{ + mTextureState = NO_DELETE ; +} + +void LLGLTexture::generateGLTexture() +{ + if(mGLTexturep.isNull()) + { + mGLTexturep = new LLImageGL(mFullWidth, mFullHeight, mComponents, mUseMipMaps) ; + } +} + +LLImageGL* LLGLTexture::getGLTexture() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep ; +} + +BOOL LLGLTexture::createGLTexture() +{ + if(mGLTexturep.isNull()) + { + generateGLTexture() ; + } + + return mGLTexturep->createGLTexture() ; +} + +BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category) +{ + llassert(mGLTexturep.notNull()) ; + + BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ; + + if(ret) + { + mFullWidth = mGLTexturep->getCurrentWidth() ; + mFullHeight = mGLTexturep->getCurrentHeight() ; + mComponents = mGLTexturep->getComponents() ; + setTexelsPerImage(); + } + + return ret ; +} + +void LLGLTexture::setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes) +{ + llassert(mGLTexturep.notNull()) ; + + mGLTexturep->setExplicitFormat(internal_format, primary_format, type_format, swap_bytes) ; +} +void LLGLTexture::setAddressMode(LLTexUnit::eTextureAddressMode mode) +{ + llassert(mGLTexturep.notNull()) ; + mGLTexturep->setAddressMode(mode) ; +} +void LLGLTexture::setFilteringOption(LLTexUnit::eTextureFilterOptions option) +{ + llassert(mGLTexturep.notNull()) ; + mGLTexturep->setFilteringOption(option) ; +} + +//virtual +S32 LLGLTexture::getWidth(S32 discard_level) const +{ + llassert(mGLTexturep.notNull()) ; + return mGLTexturep->getWidth(discard_level) ; +} + +//virtual +S32 LLGLTexture::getHeight(S32 discard_level) const +{ + llassert(mGLTexturep.notNull()) ; + return mGLTexturep->getHeight(discard_level) ; +} + +S32 LLGLTexture::getMaxDiscardLevel() const +{ + llassert(mGLTexturep.notNull()) ; + return mGLTexturep->getMaxDiscardLevel() ; +} +S32 LLGLTexture::getDiscardLevel() const +{ + llassert(mGLTexturep.notNull()) ; + return mGLTexturep->getDiscardLevel() ; +} +S8 LLGLTexture::getComponents() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getComponents() ; +} + +LLGLuint LLGLTexture::getTexName() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getTexName() ; +} + +BOOL LLGLTexture::hasGLTexture() const +{ + if(mGLTexturep.notNull()) + { + return mGLTexturep->getHasGLTexture() ; + } + return FALSE ; +} + +BOOL LLGLTexture::getBoundRecently() const +{ + if(mGLTexturep.notNull()) + { + return mGLTexturep->getBoundRecently() ; + } + return FALSE ; +} + +LLTexUnit::eTextureType LLGLTexture::getTarget(void) const +{ + llassert(mGLTexturep.notNull()) ; + return mGLTexturep->getTarget() ; +} + +BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height) +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height) ; +} + +BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height) +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height) ; +} + +void LLGLTexture::setGLTextureCreated (bool initialized) +{ + llassert(mGLTexturep.notNull()) ; + + mGLTexturep->setGLTextureCreated (initialized) ; +} + +void LLGLTexture::setCategory(S32 category) +{ + llassert(mGLTexturep.notNull()) ; + + mGLTexturep->setCategory(category) ; +} + +LLTexUnit::eTextureAddressMode LLGLTexture::getAddressMode(void) const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getAddressMode() ; +} + +S32 LLGLTexture::getTextureMemory() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->mTextureMemory ; +} + +LLGLenum LLGLTexture::getPrimaryFormat() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getPrimaryFormat() ; +} + +BOOL LLGLTexture::getIsAlphaMask() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getIsAlphaMask() ; +} + +BOOL LLGLTexture::getMask(const LLVector2 &tc) +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getMask(tc) ; +} + +F32 LLGLTexture::getTimePassedSinceLastBound() +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getTimePassedSinceLastBound() ; +} +BOOL LLGLTexture::getMissed() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getMissed() ; +} + +BOOL LLGLTexture::isJustBound() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->isJustBound() ; +} + +void LLGLTexture::forceUpdateBindStats(void) const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->forceUpdateBindStats() ; +} + +U32 LLGLTexture::getTexelsInAtlas() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getTexelsInAtlas() ; +} + +U32 LLGLTexture::getTexelsInGLTexture() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getTexelsInGLTexture() ; +} + +BOOL LLGLTexture::isGLTextureCreated() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->isGLTextureCreated() ; +} + +S32 LLGLTexture::getDiscardLevelInAtlas() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getDiscardLevelInAtlas() ; +} + +void LLGLTexture::destroyGLTexture() +{ + if(mGLTexturep.notNull() && mGLTexturep->getHasGLTexture()) + { + mGLTexturep->destroyGLTexture() ; + mTextureState = DELETED ; + } +} + +void LLGLTexture::setTexelsPerImage() +{ + S32 fullwidth = llmin(mFullWidth,(S32)MAX_IMAGE_SIZE_DEFAULT); + S32 fullheight = llmin(mFullHeight,(S32)MAX_IMAGE_SIZE_DEFAULT); + mTexelsPerImage = (F32)fullwidth * fullheight; +} + + diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h new file mode 100644 index 0000000000..e69b322d60 --- /dev/null +++ b/indra/llrender/llgltexture.h @@ -0,0 +1,199 @@ +/** + * @file llglviewertexture.h + * @brief Object for managing opengl textures + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#ifndef LL_GL_TEXTURE_H +#define LL_GL_TEXTURE_H + +#include "lltexture.h" +#include "llgl.h" + +class LLImageRaw; + +// +//this the parent for the class LLViewerTexture +//through the following virtual functions, the class LLViewerTexture can be reached from /llrender. +// +class LLGLTexture : public LLTexture +{ +public: + enum + { + MAX_IMAGE_SIZE_DEFAULT = 1024, + INVALID_DISCARD_LEVEL = 0x7fff + }; + + enum EBoostLevel + { + BOOST_NONE = 0, + BOOST_AVATAR_BAKED , + BOOST_AVATAR , + BOOST_CLOUDS , + BOOST_SCULPTED , + + BOOST_HIGH = 10, + BOOST_BUMP , + BOOST_TERRAIN , // has to be high priority for minimap / low detail + BOOST_SELECTED , + BOOST_AVATAR_BAKED_SELF , + BOOST_AVATAR_SELF , // needed for baking avatar + BOOST_SUPER_HIGH , //textures higher than this need to be downloaded at the required resolution without delay. + BOOST_HUD , + BOOST_ICON , + BOOST_UI , + BOOST_PREVIEW , + BOOST_MAP , + BOOST_MAP_VISIBLE , + BOOST_MAX_LEVEL, + + //other texture Categories + LOCAL = BOOST_MAX_LEVEL, + AVATAR_SCRATCH_TEX, + DYNAMIC_TEX, + MEDIA, + ATLAS, + OTHER, + MAX_GL_IMAGE_CATEGORY + }; + + typedef enum + { + DELETED = 0, //removed from memory + DELETION_CANDIDATE, //ready to be removed from memory + INACTIVE, //not be used for the last certain period (i.e., 30 seconds). + ACTIVE, //just being used, can become inactive if not being used for a certain time (10 seconds). + NO_DELETE = 99 //stay in memory, can not be removed. + } LLGLTextureState; + + static S32 getTotalNumOfCategories() ; + static S32 getIndexFromCategory(S32 category) ; + static S32 getCategoryFromIndex(S32 index) ; + +protected: + virtual ~LLGLTexture(); + LOG_CLASS(LLGLTexture); + +public: + LLGLTexture(BOOL usemipmaps = TRUE); + LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps) ; + LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ; + + virtual void dump(); // debug info to llinfos + + virtual const LLUUID& getID() const = 0; + + void setBoostLevel(S32 level); + S32 getBoostLevel() { return mBoostLevel; } + + S32 getFullWidth() const { return mFullWidth; } + S32 getFullHeight() const { return mFullHeight; } + + void generateGLTexture() ; + void destroyGLTexture() ; + + //--------------------------------------------------------------------------------------------- + //functions to access LLImageGL + //--------------------------------------------------------------------------------------------- + /*virtual*/S32 getWidth(S32 discard_level = -1) const; + /*virtual*/S32 getHeight(S32 discard_level = -1) const; + + BOOL hasGLTexture() const ; + LLGLuint getTexName() const ; + BOOL createGLTexture() ; + BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER); + + void setFilteringOption(LLTexUnit::eTextureFilterOptions option); + void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); + void setAddressMode(LLTexUnit::eTextureAddressMode mode); + BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height); + BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height); + void setGLTextureCreated (bool initialized); + void setCategory(S32 category) ; + + LLTexUnit::eTextureAddressMode getAddressMode(void) const ; + S32 getMaxDiscardLevel() const; + S32 getDiscardLevel() const; + S8 getComponents() const; + BOOL getBoundRecently() const; + S32 getTextureMemory() const ; + LLGLenum getPrimaryFormat() const; + BOOL getIsAlphaMask() const ; + LLTexUnit::eTextureType getTarget(void) const ; + BOOL getMask(const LLVector2 &tc); + F32 getTimePassedSinceLastBound(); + BOOL getMissed() const ; + BOOL isJustBound()const ; + void forceUpdateBindStats(void) const; + + U32 getTexelsInAtlas() const ; + U32 getTexelsInGLTexture() const ; + BOOL isGLTextureCreated() const ; + S32 getDiscardLevelInAtlas() const ; + LLGLTextureState getTextureState() const { return mTextureState; } + + //--------------------------------------------------------------------------------------------- + //end of functions to access LLImageGL + //--------------------------------------------------------------------------------------------- + + //----------------- + /*virtual*/ void setActive() ; + void forceActive() ; + void setNoDelete() ; + void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; } + BOOL getDontDiscard() const { return mDontDiscard; } + //----------------- + +private: + void cleanup(); + void init(); + +protected: + void setTexelsPerImage(); + + //note: do not make this function public. + /*virtual*/ LLImageGL* getGLTexture() const ; + +protected: + S32 mBoostLevel; // enum describing priority level + S32 mFullWidth; + S32 mFullHeight; + BOOL mUseMipMaps; + S8 mComponents; + F32 mTexelsPerImage; // Texels per image. + mutable S8 mNeedsGLTexture; + + //GL texture + LLPointer<LLImageGL> mGLTexturep ; + S8 mDontDiscard; // Keep full res version of this image (for UI, etc) + +protected: + LLGLTextureState mTextureState ; + + +}; + +#endif // LL_GL_TEXTURE_H + diff --git a/indra/llrender/llgltypes.h b/indra/llrender/llgltypes.h index 6c217ef727..6c217ef727 100644..100755 --- a/indra/llrender/llgltypes.h +++ b/indra/llrender/llgltypes.h diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index a4d7872ec2..6a37d31415 100644..100755 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -74,6 +74,9 @@ S32 LLImageGL::sCurTexSizeBar = -1 ; S32 LLImageGL::sCurTexPickSize = -1 ; S32 LLImageGL::sMaxCategories = 1 ; +//optimization for when we don't need to calculate mIsMask +BOOL LLImageGL::sSkipAnalyzeAlpha; + //------------------------ //**************************************************************************************************** //End for texture auditing use only @@ -169,8 +172,9 @@ BOOL is_little_endian() return (*c == 0x78) ; } //static -void LLImageGL::initClass(S32 num_catagories) +void LLImageGL::initClass(S32 num_catagories, BOOL skip_analyze_alpha /* = false */) { + sSkipAnalyzeAlpha = skip_analyze_alpha; } //static @@ -611,14 +615,16 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) setImage(rawdata, FALSE); } +static LLFastTimer::DeclareTimer FTM_SET_IMAGE("setImage"); void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { + LLFastTimer t(FTM_SET_IMAGE); bool is_compressed = false; if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) { is_compressed = true; } - + if (mUseMipMaps) @@ -709,9 +715,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) mMipLevels = wpo2(llmax(w, h)); - //use legacy mipmap generation mode + //use legacy mipmap generation mode (note: making this condional can cause rendering issues) glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE); - + LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, mFormatPrimary, mFormatType, @@ -726,6 +732,12 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); stop_glerror(); } + + if (LLRender::sGLCoreProfile) + { + glGenerateMipmap(mTarget); + } + stop_glerror(); } } else @@ -736,11 +748,16 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) S32 height = getHeight(mCurrentDiscardLevel); S32 nummips = mMaxDiscardLevel - mCurrentDiscardLevel + 1; S32 w = width, h = height; + + + const U8* new_data = 0; + (void)new_data; + const U8* prev_mip_data = 0; const U8* cur_mip_data = 0; - S32 prev_mip_size = 0; +#ifdef SHOW_ASSERT S32 cur_mip_size = 0; - +#endif mMipLevels = nummips; for (int m=0; m<nummips; m++) @@ -748,20 +765,34 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) if (m==0) { cur_mip_data = data_in; +#ifdef SHOW_ASSERT cur_mip_size = width * height * mComponents; +#endif } else { S32 bytes = w * h * mComponents; +#ifdef SHOW_ASSERT llassert(prev_mip_data); - llassert(prev_mip_size == bytes*4); + llassert(cur_mip_size == bytes*4); +#endif U8* new_data = new U8[bytes]; + +#ifdef SHOW_ASSERT + llassert(prev_mip_data); + llassert(cur_mip_size == bytes*4); llassert_always(new_data); +#endif + LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents); cur_mip_data = new_data; +#ifdef SHOW_ASSERT cur_mip_size = bytes; +#endif + } llassert(w > 0 && h > 0 && cur_mip_data); + (void)cur_mip_data; { // LLFastTimer t1(FTM_TEMP4); if(mFormatSwapBytes) @@ -792,7 +823,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) delete[] prev_mip_data; } prev_mip_data = cur_mip_data; - prev_mip_size = cur_mip_size; w >>= 1; h >>= 1; } @@ -1053,10 +1083,22 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_ } // static +static LLFastTimer::DeclareTimer FTM_GENERATE_TEXTURES("generate textures"); void LLImageGL::generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures) { + LLFastTimer t(FTM_GENERATE_TEXTURES); bool empty = true; + if (LLRender::sGLCoreProfile) + { + switch (format) + { + case GL_LUMINANCE8: format = GL_RGB8; break; + case GL_LUMINANCE8_ALPHA8: + case GL_ALPHA8: format = GL_RGBA8; break; + } + } + dead_texturelist_t::iterator iter = sDeadTextureList[type].find(format); if (iter != sDeadTextureList[type].end()) @@ -1084,7 +1126,21 @@ void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip { if (gGLManager.mInited) { - if (format == 0 || type == LLTexUnit::TT_CUBE_MAP || mip_levels == -1) + switch (format) + { + case 0: + + // We get ARB errors in debug when attempting to use glTexImage2D with these deprecated pix formats + // + case GL_LUMINANCE8: + case GL_INTENSITY8: + case GL_ALPHA8: + glDeleteTextures(numTextures, textures); + break; + + default: + { + if (type == LLTexUnit::TT_CUBE_MAP || mip_levels == -1) { //unknown internal format or unknown number of mip levels, not safe to reuse glDeleteTextures(numTextures, textures); } @@ -1092,11 +1148,13 @@ void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip { for (S32 i = 0; i < numTextures; ++i) { //remove texture from VRAM by setting its size to zero + for (S32 j = 0; j <= mip_levels; j++) { gGL.getTexUnit(0)->bindManual(type, textures[i]); - - glTexImage2D(LLTexUnit::getInternalType(type), j, format, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + U32 internal_type = LLTexUnit::getInternalType(type); + glTexImage2D(internal_type, j, format, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + stop_glerror(); } llassert(std::find(sDeadTextureList[type][format].begin(), @@ -1107,6 +1165,9 @@ void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip } } } + break; + } + } /*if (immediate) { @@ -1115,8 +1176,10 @@ void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip } // static +static LLFastTimer::DeclareTimer FTM_SET_MANUAL_IMAGE("setManualImage"); void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression) { + LLFastTimer t(FTM_SET_MANUAL_IMAGE); bool use_scratch = false; U32* scratch = NULL; if (LLRender::sGLCoreProfile) @@ -1220,9 +1283,10 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt //create an empty GL texture: just create a texture name //the texture is assiciate with some image by calling glTexImage outside LLImageGL +static LLFastTimer::DeclareTimer FTM_CREATE_GL_TEXTURE1("createGLTexture()"); BOOL LLImageGL::createGLTexture() { - if (gHeadlessClient) return FALSE; + LLFastTimer t(FTM_CREATE_GL_TEXTURE1); if (gGLManager.mIsDisabled) { llwarns << "Trying to create a texture while GL is disabled!" << llendl; @@ -1250,9 +1314,10 @@ BOOL LLImageGL::createGLTexture() return TRUE ; } +static LLFastTimer::DeclareTimer FTM_CREATE_GL_TEXTURE2("createGLTexture(raw)"); BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category) { - if (gHeadlessClient) return FALSE; + LLFastTimer t(FTM_CREATE_GL_TEXTURE2); if (gGLManager.mIsDisabled) { llwarns << "Trying to create a texture while GL is disabled!" << llendl; @@ -1324,8 +1389,10 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S return createGLTexture(discard_level, rawdata, FALSE, usename); } +static LLFastTimer::DeclareTimer FTM_CREATE_GL_TEXTURE3("createGLTexture3(data)"); BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) { + LLFastTimer t(FTM_CREATE_GL_TEXTURE3); llassert(data_in); stop_glerror(); @@ -1702,6 +1769,12 @@ BOOL LLImageGL::getBoundRecently() const return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME); } +BOOL LLImageGL::getIsAlphaMask() const +{ + llassert_always(!sSkipAnalyzeAlpha); + return mIsMask; +} + void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target) { mTarget = target; @@ -1799,7 +1872,7 @@ void LLImageGL::calcAlphaChannelOffsetAndStride() void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) { - if(!mNeedsAlphaAndPickMask) + if(sSkipAnalyzeAlpha || !mNeedsAlphaAndPickMask) { return ; } diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index cf3c484c79..57a052b258 100644..100755 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -142,7 +142,7 @@ public: BOOL getHasGLTexture() const { return mTexName != 0; } LLGLuint getTexName() const { return mTexName; } - BOOL getIsAlphaMask() const { return mIsMask; } + BOOL getIsAlphaMask() const; BOOL getIsResident(BOOL test_now = FALSE); // not const @@ -262,11 +262,12 @@ public: #endif public: - static void initClass(S32 num_catagories) ; + static void initClass(S32 num_catagories, BOOL skip_analyze_alpha = false); static void cleanupClass() ; private: static S32 sMaxCategories; + static BOOL sSkipAnalyzeAlpha; //the flag to allow to call readBackRaw(...). //can be removed if we do not use that function at all. diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp index c0045c8044..4c36185b08 100644..100755 --- a/indra/llrender/llpostprocess.cpp +++ b/indra/llrender/llpostprocess.cpp @@ -31,6 +31,21 @@ #include "llsdserialize.h" #include "llrender.h" +static LLStaticHashedString sRenderTexture("RenderTexture"); +static LLStaticHashedString sBrightness("brightness"); +static LLStaticHashedString sContrast("contrast"); +static LLStaticHashedString sContrastBase("contrastBase"); +static LLStaticHashedString sSaturation("saturation"); +static LLStaticHashedString sLumWeights("lumWeights"); +static LLStaticHashedString sNoiseTexture("NoiseTexture"); +static LLStaticHashedString sBrightMult("brightMult"); +static LLStaticHashedString sNoiseStrength("noiseStrength"); +static LLStaticHashedString sExtractLow("extractLow"); +static LLStaticHashedString sExtractHigh("extractHigh"); +static LLStaticHashedString sBloomStrength("bloomStrength"); +static LLStaticHashedString sTexelSize("texelSize"); +static LLStaticHashedString sBlurDirection("blurDirection"); +static LLStaticHashedString sBlurWidth("blurWidth"); LLPostProcess * gPostProcess = NULL; @@ -258,12 +273,12 @@ void LLPostProcess::applyColorFilterShader(void) void LLPostProcess::createColorFilterShader(void) { /// Define uniform names - colorFilterUniforms["RenderTexture"] = 0; - colorFilterUniforms["brightness"] = 0; - colorFilterUniforms["contrast"] = 0; - colorFilterUniforms["contrastBase"] = 0; - colorFilterUniforms["saturation"] = 0; - colorFilterUniforms["lumWeights"] = 0; + colorFilterUniforms[sRenderTexture] = 0; + colorFilterUniforms[sBrightness] = 0; + colorFilterUniforms[sContrast] = 0; + colorFilterUniforms[sContrastBase] = 0; + colorFilterUniforms[sSaturation] = 0; + colorFilterUniforms[sLumWeights] = 0; } void LLPostProcess::applyNightVisionShader(void) @@ -307,11 +322,11 @@ void LLPostProcess::applyNightVisionShader(void) void LLPostProcess::createNightVisionShader(void) { /// Define uniform names - nightVisionUniforms["RenderTexture"] = 0; - nightVisionUniforms["NoiseTexture"] = 0; - nightVisionUniforms["brightMult"] = 0; - nightVisionUniforms["noiseStrength"] = 0; - nightVisionUniforms["lumWeights"] = 0; + nightVisionUniforms[sRenderTexture] = 0; + nightVisionUniforms[sNoiseTexture] = 0; + nightVisionUniforms[sBrightMult] = 0; + nightVisionUniforms[sNoiseStrength] = 0; + nightVisionUniforms[sLumWeights] = 0; createNoiseTexture(mNoiseTexture); } @@ -326,25 +341,25 @@ void LLPostProcess::createBloomShader(void) createTexture(mTempBloomTexture, unsigned(screenW * 0.5), unsigned(screenH * 0.5)); /// Create Bloom Extract Shader - bloomExtractUniforms["RenderTexture"] = 0; - bloomExtractUniforms["extractLow"] = 0; - bloomExtractUniforms["extractHigh"] = 0; - bloomExtractUniforms["lumWeights"] = 0; + bloomExtractUniforms[sRenderTexture] = 0; + bloomExtractUniforms[sExtractLow] = 0; + bloomExtractUniforms[sExtractHigh] = 0; + bloomExtractUniforms[sLumWeights] = 0; /// Create Bloom Blur Shader - bloomBlurUniforms["RenderTexture"] = 0; - bloomBlurUniforms["bloomStrength"] = 0; - bloomBlurUniforms["texelSize"] = 0; - bloomBlurUniforms["blurDirection"] = 0; - bloomBlurUniforms["blurWidth"] = 0; + bloomBlurUniforms[sRenderTexture] = 0; + bloomBlurUniforms[sBloomStrength] = 0; + bloomBlurUniforms[sTexelSize] = 0; + bloomBlurUniforms[sBlurDirection] = 0; + bloomBlurUniforms[sBlurWidth] = 0; } void LLPostProcess::getShaderUniforms(glslUniforms & uniforms, GLhandleARB & prog) { /// Find uniform locations and insert into map - std::map<const char *, GLuint>::iterator i; + glslUniforms::iterator i; for (i = uniforms.begin(); i != uniforms.end(); ++i){ - i->second = glGetUniformLocationARB(prog, i->first); + i->second = glGetUniformLocationARB(prog, i->first.String().c_str()); } } diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h index e19de44c60..ce17b6693d 100644..100755 --- a/indra/llrender/llpostprocess.h +++ b/indra/llrender/llpostprocess.h @@ -31,6 +31,7 @@ #include <fstream> #include "llgl.h" #include "llglheaders.h" +#include "llstaticstringtable.h" class LLPostProcess { @@ -44,7 +45,7 @@ public: } QuadType; /// GLSL Shader Encapsulation Struct - typedef std::map<const char *, GLuint> glslUniforms; + typedef LLStaticStringTable<GLuint> glslUniforms; struct PostProcessTweaks : public LLSD { inline PostProcessTweaks() : LLSD(LLSD::emptyMap()) diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 4597d06260..3393d352de 100644..100755 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -225,26 +225,15 @@ void LLTexUnit::disable(void) bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) { stop_glerror(); - if (mIndex < 0) return false; - + if (mIndex >= 0) + { gGL.flush(); LLImageGL* gl_tex = NULL ; - if (texture == NULL || !(gl_tex = texture->getGLTexture())) + if (texture != NULL && (gl_tex = texture->getGLTexture())) { - llwarns << "NULL LLTexUnit::bind texture" << llendl; - return false; - } - - if (!gl_tex->getTexName()) //if texture does not exist + if (gl_tex->getTexName()) //if texture exists { - //if deleted, will re-generate it immediately - texture->forceImmediateUpdate() ; - - gl_tex->forceUpdateBindStats() ; - return texture->bindDefaultImage(mIndex); - } - //in audit, replace the selected texture by the default one. if ((mCurrTexture != gl_tex->getTexName()) || forceBind) { @@ -265,6 +254,27 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) setTextureFilteringOption(gl_tex->mFilterOption); } } + } + else + { + //if deleted, will re-generate it immediately + texture->forceImmediateUpdate() ; + + gl_tex->forceUpdateBindStats() ; + return texture->bindDefaultImage(mIndex); + } + } + else + { + llwarns << "NULL LLTexUnit::bind texture" << llendl; + return false; + } + } + else + { // mIndex < 0 + return false; + } + return true; } @@ -357,7 +367,6 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap) } // LLRenderTarget is unavailible on the mapserver since it uses FBOs. -#if !LL_MESA_HEADLESS bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) { if (mIndex < 0) return false; @@ -380,7 +389,6 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) return true; } -#endif // LL_MESA_HEADLESS bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips) { @@ -824,8 +832,8 @@ LLLightState::LLLightState(S32 index) : mIndex(index), mEnabled(false), mConstantAtten(1.f), - mLinearAtten(0.f), - mQuadraticAtten(0.f), + mLinearAtten(1.f), + mQuadraticAtten(1.f), mSpotExponent(0.f), mSpotCutoff(180.f) { @@ -1060,6 +1068,16 @@ LLRender::~LLRender() void LLRender::init() { + if (sGLCoreProfile && !LLVertexBuffer::sUseVAO) + { //bind a dummy vertex array object so we're core profile compliant +#ifdef GL_ARB_vertex_array_object + U32 ret; + glGenVertexArrays(1, &ret); + glBindVertexArray(ret); +#endif + } + + llassert_always(mBuffer.isNull()) ; stop_glerror(); mBuffer = new LLVertexBuffer(immediate_mask, 0); @@ -1132,7 +1150,7 @@ void LLRender::syncLightState() position[i] = light->mPosition; direction[i] = light->mSpotDirection; - attenuation[i].set(light->mLinearAtten, light->mQuadraticAtten, light->mSpecular.mV[3]); + attenuation[i].set(1.f/light->mLinearAtten, light->mQuadraticAtten, light->mSpecular.mV[3]); diffuse[i].set(light->mDiffuse.mV); } @@ -1851,35 +1869,36 @@ void LLRender::flush() sUIVerts += mCount; } - if (gDebugGL) + //store mCount in a local variable to avoid re-entrance (drawArrays may call flush) + U32 count = mCount; + + if (mMode == LLRender::QUADS && !sGLCoreProfile) { - if (mMode == LLRender::QUADS && !sGLCoreProfile) + if (mCount%4 != 0) { - if (mCount%4 != 0) - { - llerrs << "Incomplete quad rendered." << llendl; - } + count -= (mCount % 4); + llwarns << "Incomplete quad requested." << llendl; } - - if (mMode == LLRender::TRIANGLES) + } + + if (mMode == LLRender::TRIANGLES) + { + if (mCount%3 != 0) { - if (mCount%3 != 0) - { - llerrs << "Incomplete triangle rendered." << llendl; - } + count -= (mCount % 3); + llwarns << "Incomplete triangle requested." << llendl; } - - if (mMode == LLRender::LINES) + } + + if (mMode == LLRender::LINES) + { + if (mCount%2 != 0) { - if (mCount%2 != 0) - { - llerrs << "Incomplete line rendered." << llendl; - } + count -= (mCount % 2); + llwarns << "Incomplete line requested." << llendl; } } - - //store mCount in a local variable to avoid re-entrance (drawArrays may call flush) - U32 count = mCount; + mCount = 0; if (mBuffer->useVBOs() && !mBuffer->isLocked()) @@ -2282,6 +2301,22 @@ void LLRender::diffuseColor4ubv(const U8* c) } } +void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a) +{ + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + + if (shader) + { + shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r/255.f, g/255.f, b/255.f, a/255.f); + } + else + { + glColor4ub(r,g,b,a); + } +} + + void LLRender::debugTexUnits(void) { LL_INFOS("TextureUnit") << "Active TexUnit: " << mCurrTextureUnitIndex << LL_ENDL; diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 78a310e525..42b02a8159 100644..100755 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -262,6 +262,14 @@ class LLRender friend class LLTexUnit; public: + enum eTexIndex + { + DIFFUSE_MAP = 0, + NORMAL_MAP, + SPECULAR_MAP, + NUM_TEXTURE_CHANNELS, + }; + typedef enum { TRIANGLES = 0, TRIANGLE_STRIP, @@ -388,6 +396,7 @@ public: void diffuseColor4f(F32 r, F32 g, F32 b, F32 a); void diffuseColor4fv(const F32* c); void diffuseColor4ubv(const U8* c); + void diffuseColor4ub(U8 r, U8 g, U8 b, U8 a); void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count); void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count); diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp new file mode 100644 index 0000000000..d3cfbaf03a --- /dev/null +++ b/indra/llrender/llrender2dutils.cpp @@ -0,0 +1,1608 @@ +/** + * @file llrender2dutils.cpp + * @brief GL function implementations for immediate-mode gl drawing. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +// Linden library includes +#include "v2math.h" +#include "m3math.h" +#include "v4color.h" +#include "llfontgl.h" +#include "llrender.h" +#include "llrect.h" +#include "llgl.h" +#include "lltexture.h" + +// Project includes +#include "llrender2dutils.h" +#include "lluiimage.h" + + +// +// Globals +// +const LLColor4 UI_VERTEX_COLOR(1.f, 1.f, 1.f, 1.f); +/*static*/ LLVector2 LLRender2D::sGLScaleFactor(1.f, 1.f); +/*static*/ LLImageProviderInterface* LLRender2D::sImageProvider = NULL; + +// +// Functions +// + +BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom) +{ + if (x < left || right < x) return FALSE; + if (y < bottom || top < y) return FALSE; + return TRUE; +} + + +// Puts GL into 2D drawing mode by turning off lighting, setting to an +// orthographic projection, etc. +void gl_state_for_2d(S32 width, S32 height) +{ + stop_glerror(); + F32 window_width = (F32) width;//gViewerWindow->getWindowWidth(); + F32 window_height = (F32) height;//gViewerWindow->getWindowHeight(); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.loadIdentity(); + gGL.ortho(0.0f, llmax(window_width, 1.f), 0.0f, llmax(window_height,1.f), -1.0f, 1.0f); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadIdentity(); + stop_glerror(); +} + + +void gl_draw_x(const LLRect& rect, const LLColor4& color) +{ + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + gGL.color4fv( color.mV ); + + gGL.begin( LLRender::LINES ); + gGL.vertex2i( rect.mLeft, rect.mTop ); + gGL.vertex2i( rect.mRight, rect.mBottom ); + gGL.vertex2i( rect.mLeft, rect.mBottom ); + gGL.vertex2i( rect.mRight, rect.mTop ); + gGL.end(); +} + + +void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, S32 pixel_offset, BOOL filled) +{ + gGL.color4fv(color.mV); + gl_rect_2d_offset_local(left, top, right, bottom, pixel_offset, filled); +} + +void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset, BOOL filled) +{ + gGL.pushUIMatrix(); + left += LLFontGL::sCurOrigin.mX; + right += LLFontGL::sCurOrigin.mX; + bottom += LLFontGL::sCurOrigin.mY; + top += LLFontGL::sCurOrigin.mY; + + gGL.loadUIIdentity(); + gl_rect_2d(llfloor((F32)left * LLRender2D::sGLScaleFactor.mV[VX]) - pixel_offset, + llfloor((F32)top * LLRender2D::sGLScaleFactor.mV[VY]) + pixel_offset, + llfloor((F32)right * LLRender2D::sGLScaleFactor.mV[VX]) + pixel_offset, + llfloor((F32)bottom * LLRender2D::sGLScaleFactor.mV[VY]) - pixel_offset, + filled); + gGL.popUIMatrix(); +} + + +void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled ) +{ + stop_glerror(); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + // Counterclockwise quad will face the viewer + if( filled ) + { + gGL.begin( LLRender::QUADS ); + gGL.vertex2i(left, top); + gGL.vertex2i(left, bottom); + gGL.vertex2i(right, bottom); + gGL.vertex2i(right, top); + gGL.end(); + } + else + { + if( gGLManager.mATIOffsetVerticalLines ) + { + // Work around bug in ATI driver: vertical lines are offset by (-1,-1) + gGL.begin( LLRender::LINES ); + + // Verticals + gGL.vertex2i(left + 1, top); + gGL.vertex2i(left + 1, bottom); + + gGL.vertex2i(right, bottom); + gGL.vertex2i(right, top); + + // Horizontals + top--; + right--; + gGL.vertex2i(left, bottom); + gGL.vertex2i(right, bottom); + + gGL.vertex2i(left, top); + gGL.vertex2i(right, top); + gGL.end(); + } + else + { + top--; + right--; + gGL.begin( LLRender::LINE_STRIP ); + gGL.vertex2i(left, top); + gGL.vertex2i(left, bottom); + gGL.vertex2i(right, bottom); + gGL.vertex2i(right, top); + gGL.vertex2i(left, top); + gGL.end(); + } + } + stop_glerror(); +} + +void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, BOOL filled ) +{ + gGL.color4fv( color.mV ); + gl_rect_2d( left, top, right, bottom, filled ); +} + + +void gl_rect_2d( const LLRect& rect, const LLColor4& color, BOOL filled ) +{ + gGL.color4fv( color.mV ); + gl_rect_2d( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, filled ); +} + +// Given a rectangle on the screen, draws a drop shadow _outside_ +// the right and bottom edges of it. Along the right it has width "lines" +// and along the bottom it has height "lines". +void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines) +{ + stop_glerror(); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + // HACK: Overlap with the rectangle by a single pixel. + right--; + bottom++; + lines++; + + LLColor4 end_color = start_color; + end_color.mV[VALPHA] = 0.f; + + gGL.begin(LLRender::QUADS); + + // Right edge, CCW faces screen + gGL.color4fv(start_color.mV); + gGL.vertex2i(right, top-lines); + gGL.vertex2i(right, bottom); + gGL.color4fv(end_color.mV); + gGL.vertex2i(right+lines, bottom); + gGL.vertex2i(right+lines, top-lines); + + // Bottom edge, CCW faces screen + gGL.color4fv(start_color.mV); + gGL.vertex2i(right, bottom); + gGL.vertex2i(left+lines, bottom); + gGL.color4fv(end_color.mV); + gGL.vertex2i(left+lines, bottom-lines); + gGL.vertex2i(right, bottom-lines); + + // bottom left Corner + gGL.color4fv(start_color.mV); + gGL.vertex2i(left+lines, bottom); + gGL.color4fv(end_color.mV); + gGL.vertex2i(left, bottom); + // make the bottom left corner not sharp + gGL.vertex2i(left+1, bottom-lines+1); + gGL.vertex2i(left+lines, bottom-lines); + + // bottom right corner + gGL.color4fv(start_color.mV); + gGL.vertex2i(right, bottom); + gGL.color4fv(end_color.mV); + gGL.vertex2i(right, bottom-lines); + // make the rightmost corner not sharp + gGL.vertex2i(right+lines-1, bottom-lines+1); + gGL.vertex2i(right+lines, bottom); + + // top right corner + gGL.color4fv(start_color.mV); + gGL.vertex2i( right, top-lines ); + gGL.color4fv(end_color.mV); + gGL.vertex2i( right+lines, top-lines ); + // make the corner not sharp + gGL.vertex2i( right+lines-1, top-1 ); + gGL.vertex2i( right, top ); + + gGL.end(); + stop_glerror(); +} + +void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 ) +{ + // Work around bug in ATI driver: vertical lines are offset by (-1,-1) + if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines ) + { + x1++; + x2++; + y1++; + y2++; + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + gGL.begin(LLRender::LINES); + gGL.vertex2i(x1, y1); + gGL.vertex2i(x2, y2); + gGL.end(); +} + +void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color ) +{ + // Work around bug in ATI driver: vertical lines are offset by (-1,-1) + if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines ) + { + x1++; + x2++; + y1++; + y2++; + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + gGL.color4fv( color.mV ); + + gGL.begin(LLRender::LINES); + gGL.vertex2i(x1, y1); + gGL.vertex2i(x2, y2); + gGL.end(); +} + +void gl_triangle_2d(S32 x1, S32 y1, S32 x2, S32 y2, S32 x3, S32 y3, const LLColor4& color, BOOL filled) +{ + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + gGL.color4fv(color.mV); + + if (filled) + { + gGL.begin(LLRender::TRIANGLES); + } + else + { + gGL.begin(LLRender::LINE_LOOP); + } + gGL.vertex2i(x1, y1); + gGL.vertex2i(x2, y2); + gGL.vertex2i(x3, y3); + gGL.end(); +} + +void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac) +{ + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + length = llmin((S32)(max_frac*(right - left)), length); + length = llmin((S32)(max_frac*(top - bottom)), length); + gGL.begin(LLRender::LINES); + gGL.vertex2i(left, top); + gGL.vertex2i(left + length, top); + + gGL.vertex2i(left, top); + gGL.vertex2i(left, top - length); + + gGL.vertex2i(left, bottom); + gGL.vertex2i(left + length, bottom); + + gGL.vertex2i(left, bottom); + gGL.vertex2i(left, bottom + length); + + gGL.vertex2i(right, top); + gGL.vertex2i(right - length, top); + + gGL.vertex2i(right, top); + gGL.vertex2i(right, top - length); + + gGL.vertex2i(right, bottom); + gGL.vertex2i(right - length, bottom); + + gGL.vertex2i(right, bottom); + gGL.vertex2i(right, bottom + length); + gGL.end(); +} + + +void gl_draw_image( S32 x, S32 y, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect ) +{ + if (NULL == image) + { + llwarns << "image == NULL; aborting function" << llendl; + return; + } + gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color, uv_rect ); +} + +void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect) +{ + if (NULL == image) + { + llwarns << "image == NULL; aborting function" << llendl; + return; + } + gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color, uv_rect ); +} + +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect) +{ + if (NULL == image) + { + llwarns << "image == NULL; aborting function" << llendl; + return; + } + + // scale screen size of borders down + F32 border_width_fraction = (F32)border_width / (F32)image->getWidth(0); + F32 border_height_fraction = (F32)border_height / (F32)image->getHeight(0); + + LLRectf scale_rect(border_width_fraction, 1.f - border_height_fraction, 1.f - border_width_fraction, border_height_fraction); + gl_draw_scaled_image_with_border(x, y, width, height, image, color, solid_color, uv_rect, scale_rect); +} + +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_outer_rect, const LLRectf& center_rect) +{ + stop_glerror(); + + if (NULL == image) + { + llwarns << "image == NULL; aborting function" << llendl; + return; + } + + // add in offset of current image to current UI translation + const LLVector3 ui_scale = gGL.getUIScale(); + const LLVector3 ui_translation = (gGL.getUITranslation() + LLVector3(x, y, 0.f)).scaledVec(ui_scale); + + F32 uv_width = uv_outer_rect.getWidth(); + F32 uv_height = uv_outer_rect.getHeight(); + + // shrink scaling region to be proportional to clipped image region + LLRectf uv_center_rect( + uv_outer_rect.mLeft + (center_rect.mLeft * uv_width), + uv_outer_rect.mBottom + (center_rect.mTop * uv_height), + uv_outer_rect.mLeft + (center_rect.mRight * uv_width), + uv_outer_rect.mBottom + (center_rect.mBottom * uv_height)); + + F32 image_width = image->getWidth(0); + F32 image_height = image->getHeight(0); + + S32 image_natural_width = llround(image_width * uv_width); + S32 image_natural_height = llround(image_height * uv_height); + + LLRectf draw_center_rect( uv_center_rect.mLeft * image_width, + uv_center_rect.mTop * image_height, + uv_center_rect.mRight * image_width, + uv_center_rect.mBottom * image_height); + + { // scale fixed region of image to drawn region + draw_center_rect.mRight += width - image_natural_width; + draw_center_rect.mTop += height - image_natural_height; + + F32 border_shrink_width = llmax(0.f, draw_center_rect.mLeft - draw_center_rect.mRight); + F32 border_shrink_height = llmax(0.f, draw_center_rect.mBottom - draw_center_rect.mTop); + + F32 shrink_width_ratio = center_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - center_rect.getWidth())); + F32 shrink_height_ratio = center_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - center_rect.getHeight())); + + F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio); + + draw_center_rect.mLeft = llround(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * shrink_scale * ui_scale.mV[VX]); + draw_center_rect.mTop = llround(ui_translation.mV[VY] + lerp((F32)height, (F32)draw_center_rect.mTop, shrink_scale) * ui_scale.mV[VY]); + draw_center_rect.mRight = llround(ui_translation.mV[VX] + lerp((F32)width, (F32)draw_center_rect.mRight, shrink_scale) * ui_scale.mV[VX]); + draw_center_rect.mBottom = llround(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * shrink_scale * ui_scale.mV[VY]); + } + + LLRectf draw_outer_rect(ui_translation.mV[VX], + ui_translation.mV[VY] + height * ui_scale.mV[VY], + ui_translation.mV[VX] + width * ui_scale.mV[VX], + ui_translation.mV[VY]); + + LLGLSUIDefault gls_ui; + + if (solid_color) + { + if (LLGLSLShader::sNoFixedFunction) + { + gSolidColorProgram.bind(); + } + else + { + gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); + gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA); + } + } + + gGL.getTexUnit(0)->bind(image, true); + + gGL.color4fv(color.mV); + + const S32 NUM_VERTICES = 9 * 4; // 9 quads + LLVector2 uv[NUM_VERTICES]; + LLVector3 pos[NUM_VERTICES]; + + S32 index = 0; + + gGL.begin(LLRender::QUADS); + { + // draw bottom left + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom); + pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f); + index++; + + // draw bottom middle + uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); + index++; + + // draw bottom right + uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mBottom); + pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); + index++; + + // draw left + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop); + pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f); + index++; + + // draw middle + uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); + index++; + + // draw right + uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom); + pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f); + index++; + + uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop); + pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); + index++; + + // draw top left + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop); + pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mTop); + pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f); + index++; + + // draw top middle + uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f); + index++; + + // draw top right + uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop); + pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop); + pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f); + index++; + + uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop); + pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f); + index++; + + gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES); + } + gGL.end(); + + if (solid_color) + { + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + else + { + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + } + } +} + +void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect) +{ + gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color, uv_rect ); +} + +void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect) +{ + if (NULL == image) + { + llwarns << "image == NULL; aborting function" << llendl; + return; + } + + LLGLSUIDefault gls_ui; + + + gGL.getTexUnit(0)->bind(image, true); + + gGL.color4fv(color.mV); + + if (degrees == 0.f) + { + const S32 NUM_VERTICES = 4; // 9 quads + LLVector2 uv[NUM_VERTICES]; + LLVector3 pos[NUM_VERTICES]; + + gGL.begin(LLRender::QUADS); + { + LLVector3 ui_scale = gGL.getUIScale(); + LLVector3 ui_translation = gGL.getUITranslation(); + ui_translation.mV[VX] += x; + ui_translation.mV[VY] += y; + ui_translation.scaleVec(ui_scale); + S32 index = 0; + S32 scaled_width = llround(width * ui_scale.mV[VX]); + S32 scaled_height = llround(height * ui_scale.mV[VY]); + + uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop); + pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f); + index++; + + uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop); + pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY] + scaled_height, 0.f); + index++; + + uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom); + pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY], 0.f); + index++; + + uv[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom); + pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY], 0.f); + index++; + + gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES); + } + gGL.end(); + } + else + { + gGL.pushUIMatrix(); + gGL.translateUI((F32)x, (F32)y, 0.f); + + F32 offset_x = F32(width/2); + F32 offset_y = F32(height/2); + + gGL.translateUI(offset_x, offset_y, 0.f); + + LLMatrix3 quat(0.f, 0.f, degrees*DEG_TO_RAD); + + gGL.getTexUnit(0)->bind(image, true); + + gGL.color4fv(color.mV); + + gGL.begin(LLRender::QUADS); + { + LLVector3 v; + + v = LLVector3(offset_x, offset_y, 0.f) * quat; + gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop); + gGL.vertex2f(v.mV[0], v.mV[1] ); + + v = LLVector3(-offset_x, offset_y, 0.f) * quat; + gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop); + gGL.vertex2f(v.mV[0], v.mV[1] ); + + v = LLVector3(-offset_x, -offset_y, 0.f) * quat; + gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom); + gGL.vertex2f(v.mV[0], v.mV[1] ); + + v = LLVector3(offset_x, -offset_y, 0.f) * quat; + gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom); + gGL.vertex2f(v.mV[0], v.mV[1] ); + } + gGL.end(); + gGL.popUIMatrix(); + } +} + + +void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase ) +{ + phase = fmod(phase, 1.f); + + S32 shift = S32(phase * 4.f) % 4; + + // Stippled line + LLGLEnable stipple(GL_LINE_STIPPLE); + + gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], color.mV[VALPHA]); + + gGL.flush(); + glLineWidth(2.5f); + + if (!LLGLSLShader::sNoFixedFunction) + { + glLineStipple(2, 0x3333 << shift); + } + + gGL.begin(LLRender::LINES); + { + gGL.vertex3fv( start.mV ); + gGL.vertex3fv( end.mV ); + } + gGL.end(); + + LLRender2D::setLineWidth(1.f); +} + +void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F32 start_angle, F32 end_angle) +{ + if (end_angle < start_angle) + { + end_angle += F_TWO_PI; + } + + gGL.pushUIMatrix(); + { + gGL.translateUI(center_x, center_y, 0.f); + + // Inexact, but reasonably fast. + F32 delta = (end_angle - start_angle) / steps; + F32 sin_delta = sin( delta ); + F32 cos_delta = cos( delta ); + F32 x = cosf(start_angle) * radius; + F32 y = sinf(start_angle) * radius; + + if (filled) + { + gGL.begin(LLRender::TRIANGLE_FAN); + gGL.vertex2f(0.f, 0.f); + // make sure circle is complete + steps += 1; + } + else + { + gGL.begin(LLRender::LINE_STRIP); + } + + while( steps-- ) + { + // Successive rotations + gGL.vertex2f( x, y ); + F32 x_new = x * cos_delta - y * sin_delta; + y = x * sin_delta + y * cos_delta; + x = x_new; + } + gGL.end(); + } + gGL.popUIMatrix(); +} + +void gl_circle_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled) +{ + gGL.pushUIMatrix(); + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.translateUI(center_x, center_y, 0.f); + + // Inexact, but reasonably fast. + F32 delta = F_TWO_PI / steps; + F32 sin_delta = sin( delta ); + F32 cos_delta = cos( delta ); + F32 x = radius; + F32 y = 0.f; + + if (filled) + { + gGL.begin(LLRender::TRIANGLE_FAN); + gGL.vertex2f(0.f, 0.f); + // make sure circle is complete + steps += 1; + } + else + { + gGL.begin(LLRender::LINE_LOOP); + } + + while( steps-- ) + { + // Successive rotations + gGL.vertex2f( x, y ); + F32 x_new = x * cos_delta - y * sin_delta; + y = x * sin_delta + y * cos_delta; + x = x_new; + } + gGL.end(); + } + gGL.popUIMatrix(); +} + +// Renders a ring with sides (tube shape) +void gl_deep_circle( F32 radius, F32 depth, S32 steps ) +{ + F32 x = radius; + F32 y = 0.f; + F32 angle_delta = F_TWO_PI / (F32)steps; + gGL.begin( LLRender::TRIANGLE_STRIP ); + { + S32 step = steps + 1; // An extra step to close the circle. + while( step-- ) + { + gGL.vertex3f( x, y, depth ); + gGL.vertex3f( x, y, 0.f ); + + F32 x_new = x * cosf(angle_delta) - y * sinf(angle_delta); + y = x * sinf(angle_delta) + y * cosf(angle_delta); + x = x_new; + } + } + gGL.end(); +} + +void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor4& side_color, S32 steps, BOOL render_center ) +{ + gGL.pushUIMatrix(); + { + gGL.translateUI(0.f, 0.f, -width / 2); + if( render_center ) + { + gGL.color4fv(center_color.mV); + gGL.diffuseColor4fv(center_color.mV); + gl_deep_circle( radius, width, steps ); + } + else + { + gGL.diffuseColor4fv(side_color.mV); + gl_washer_2d(radius, radius - width, steps, side_color, side_color); + gGL.translateUI(0.f, 0.f, width); + gl_washer_2d(radius - width, radius, steps, side_color, side_color); + } + } + gGL.popUIMatrix(); +} + +// Draw gray and white checkerboard with black border +void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha) +{ + if (!LLGLSLShader::sNoFixedFunction) + { + // Initialize the first time this is called. + const S32 PIXELS = 32; + static GLubyte checkerboard[PIXELS * PIXELS]; + static BOOL first = TRUE; + if( first ) + { + for( S32 i = 0; i < PIXELS; i++ ) + { + for( S32 j = 0; j < PIXELS; j++ ) + { + checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF; + } + } + first = FALSE; + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + // ...white squares + gGL.color4f( 1.f, 1.f, 1.f, alpha ); + gl_rect_2d(rect); + + // ...gray squares + gGL.color4f( .7f, .7f, .7f, alpha ); + gGL.flush(); + + glPolygonStipple( checkerboard ); + + LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE); + gl_rect_2d(rect); + } + else + { //polygon stipple is deprecated, use "Checker" texture + LLPointer<LLUIImage> img = LLRender2D::getUIImage("Checker"); + gGL.getTexUnit(0)->bind(img->getImage()); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + + LLColor4 color(1.f, 1.f, 1.f, alpha); + LLRectf uv_rect(0, 0, rect.getWidth()/32.f, rect.getHeight()/32.f); + + gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), + img->getImage(), color, uv_rect); + } + + gGL.flush(); +} + + +// Draws the area between two concentric circles, like +// a doughnut or washer. +void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color) +{ + const F32 DELTA = F_TWO_PI / steps; + const F32 SIN_DELTA = sin( DELTA ); + const F32 COS_DELTA = cos( DELTA ); + + F32 x1 = outer_radius; + F32 y1 = 0.f; + F32 x2 = inner_radius; + F32 y2 = 0.f; + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + gGL.begin( LLRender::TRIANGLE_STRIP ); + { + steps += 1; // An extra step to close the circle. + while( steps-- ) + { + gGL.color4fv(outer_color.mV); + gGL.vertex2f( x1, y1 ); + gGL.color4fv(inner_color.mV); + gGL.vertex2f( x2, y2 ); + + F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA; + y1 = x1 * SIN_DELTA + y1 * COS_DELTA; + x1 = x1_new; + + F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA; + y2 = x2 * SIN_DELTA + y2 * COS_DELTA; + x2 = x2_new; + } + } + gGL.end(); +} + +// Draws the area between two concentric circles, like +// a doughnut or washer. +void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color) +{ + const F32 DELTA = (end_radians - start_radians) / steps; + const F32 SIN_DELTA = sin( DELTA ); + const F32 COS_DELTA = cos( DELTA ); + + F32 x1 = outer_radius * cos( start_radians ); + F32 y1 = outer_radius * sin( start_radians ); + F32 x2 = inner_radius * cos( start_radians ); + F32 y2 = inner_radius * sin( start_radians ); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.begin( LLRender::TRIANGLE_STRIP ); + { + steps += 1; // An extra step to close the circle. + while( steps-- ) + { + gGL.color4fv(outer_color.mV); + gGL.vertex2f( x1, y1 ); + gGL.color4fv(inner_color.mV); + gGL.vertex2f( x2, y2 ); + + F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA; + y1 = x1 * SIN_DELTA + y1 * COS_DELTA; + x1 = x1_new; + + F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA; + y2 = x2 * SIN_DELTA + y2 * COS_DELTA; + x2 = x2_new; + } + } + gGL.end(); +} + +void gl_rect_2d_simple_tex( S32 width, S32 height ) +{ + gGL.begin( LLRender::QUADS ); + + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2i(width, height); + + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(0, height); + + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(0, 0); + + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(width, 0); + + gGL.end(); +} + +void gl_rect_2d_simple( S32 width, S32 height ) +{ + gGL.begin( LLRender::QUADS ); + gGL.vertex2i(width, height); + gGL.vertex2i(0, height); + gGL.vertex2i(0, 0); + gGL.vertex2i(width, 0); + gGL.end(); +} + +void gl_segmented_rect_2d_tex(const S32 left, + const S32 top, + const S32 right, + const S32 bottom, + const S32 texture_width, + const S32 texture_height, + const S32 border_size, + const U32 edges) +{ + S32 width = llabs(right - left); + S32 height = llabs(top - bottom); + + gGL.pushUIMatrix(); + + gGL.translateUI((F32)left, (F32)bottom, 0.f); + LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height); + + if (border_uv_scale.mV[VX] > 0.5f) + { + border_uv_scale *= 0.5f / border_uv_scale.mV[VX]; + } + if (border_uv_scale.mV[VY] > 0.5f) + { + border_uv_scale *= 0.5f / border_uv_scale.mV[VY]; + } + + F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f); + LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero; + LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero; + LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero; + LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero; + LLVector2 width_vec((F32)width, 0.f); + LLVector2 height_vec(0.f, (F32)height); + + gGL.begin(LLRender::QUADS); + { + // draw bottom left + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2f(0.f, 0.f); + + gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); + gGL.vertex2fv(border_width_left.mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((border_width_left + border_height_bottom).mV); + + gGL.texCoord2f(0.f, border_uv_scale.mV[VY]); + gGL.vertex2fv(border_height_bottom.mV); + + // draw bottom middle + gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); + gGL.vertex2fv(border_width_left.mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f); + gGL.vertex2fv((width_vec - border_width_right).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((border_width_left + border_height_bottom).mV); + + // draw bottom right + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f); + gGL.vertex2fv((width_vec - border_width_right).mV); + + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2fv(width_vec.mV); + + gGL.texCoord2f(1.f, border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec + border_height_bottom).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); + + // draw left + gGL.texCoord2f(0.f, border_uv_scale.mV[VY]); + gGL.vertex2fv(border_height_bottom.mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((border_width_left + border_height_bottom).mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); + + gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((height_vec - border_height_top).mV); + + // draw middle + gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((border_width_left + border_height_bottom).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); + + // draw right + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); + + gGL.texCoord2f(1.f, border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec + border_height_bottom).mV); + + gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec + height_vec - border_height_top).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); + + // draw top left + gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((height_vec - border_height_top).mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((border_width_left + height_vec).mV); + + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2fv((height_vec).mV); + + // draw top middle + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((width_vec - border_width_right + height_vec).mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((border_width_left + height_vec).mV); + + // draw top right + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); + + gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec + height_vec - border_height_top).mV); + + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2fv((width_vec + height_vec).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((width_vec - border_width_right + height_vec).mV); + } + gGL.end(); + + gGL.popUIMatrix(); +} + +//FIXME: rewrite to use scissor? +void gl_segmented_rect_2d_fragment_tex(const S32 left, + const S32 top, + const S32 right, + const S32 bottom, + const S32 texture_width, + const S32 texture_height, + const S32 border_size, + const F32 start_fragment, + const F32 end_fragment, + const U32 edges) +{ + S32 width = llabs(right - left); + S32 height = llabs(top - bottom); + + gGL.pushUIMatrix(); + + gGL.translateUI((F32)left, (F32)bottom, 0.f); + LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height); + + if (border_uv_scale.mV[VX] > 0.5f) + { + border_uv_scale *= 0.5f / border_uv_scale.mV[VX]; + } + if (border_uv_scale.mV[VY] > 0.5f) + { + border_uv_scale *= 0.5f / border_uv_scale.mV[VY]; + } + + F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f); + LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero; + LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero; + LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero; + LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero; + LLVector2 width_vec((F32)width, 0.f); + LLVector2 height_vec(0.f, (F32)height); + + F32 middle_start = border_scale / (F32)width; + F32 middle_end = 1.f - middle_start; + + F32 u_min; + F32 u_max; + LLVector2 x_min; + LLVector2 x_max; + + gGL.begin(LLRender::QUADS); + { + if (start_fragment < middle_start) + { + u_min = (start_fragment / middle_start) * border_uv_scale.mV[VX]; + u_max = llmin(end_fragment / middle_start, 1.f) * border_uv_scale.mV[VX]; + x_min = (start_fragment / middle_start) * border_width_left; + x_max = llmin(end_fragment / middle_start, 1.f) * border_width_left; + + // draw bottom left + gGL.texCoord2f(u_min, 0.f); + gGL.vertex2fv(x_min.mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); + gGL.vertex2fv(x_max.mV); + + gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).mV); + + gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + border_height_bottom).mV); + + // draw left + gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + border_height_bottom).mV); + + gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).mV); + + gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + + gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + + // draw top left + gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + + gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + + gGL.texCoord2f(u_max, 1.f); + gGL.vertex2fv((x_max + height_vec).mV); + + gGL.texCoord2f(u_min, 1.f); + gGL.vertex2fv((x_min + height_vec).mV); + } + + if (end_fragment > middle_start || start_fragment < middle_end) + { + x_min = border_width_left + ((llclamp(start_fragment, middle_start, middle_end) - middle_start)) * width_vec; + x_max = border_width_left + ((llclamp(end_fragment, middle_start, middle_end) - middle_start)) * width_vec; + + // draw bottom middle + gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); + gGL.vertex2fv(x_min.mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f); + gGL.vertex2fv((x_max).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + border_height_bottom).mV); + + // draw middle + gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + border_height_bottom).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + + // draw top middle + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((x_max + height_vec).mV); + + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((x_min + height_vec).mV); + } + + if (end_fragment > middle_end) + { + u_min = (1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_uv_scale.mV[VX]; + u_max = (1.f - ((end_fragment - middle_end) / middle_start)) * border_uv_scale.mV[VX]; + x_min = width_vec - ((1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_width_right); + x_max = width_vec - ((1.f - ((end_fragment - middle_end) / middle_start)) * border_width_right); + + // draw bottom right + gGL.texCoord2f(u_min, 0.f); + gGL.vertex2fv((x_min).mV); + + gGL.texCoord2f(u_max, 0.f); + gGL.vertex2fv(x_max.mV); + + gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).mV); + + gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + border_height_bottom).mV); + + // draw right + gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + border_height_bottom).mV); + + gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).mV); + + gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + + gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + + // draw top right + gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + + gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + + gGL.texCoord2f(u_max, 1.f); + gGL.vertex2fv((x_max + height_vec).mV); + + gGL.texCoord2f(u_min, 1.f); + gGL.vertex2fv((x_min + height_vec).mV); + } + } + gGL.end(); + + gGL.popUIMatrix(); +} + +void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, + const LLVector3& width_vec, const LLVector3& height_vec) +{ + gGL.begin(LLRender::QUADS); + { + // draw bottom left + gGL.texCoord2f(clip_rect.mLeft, clip_rect.mBottom); + gGL.vertex3f(0.f, 0.f, 0.f); + + gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV); + + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); + + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV); + + // draw bottom middle + gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV); + + gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV); + + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); + + // draw bottom right + gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV); + + gGL.texCoord2f(clip_rect.mRight, clip_rect.mBottom); + gGL.vertex3fv(width_vec.mV); + + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); + + // draw left + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); + + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV); + + // draw middle + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); + + // draw right + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); + + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV); + + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); + + // draw top left + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV); + + gGL.texCoord2f(clip_rect.mLeft, clip_rect.mTop); + gGL.vertex3fv((height_vec).mV); + + // draw top middle + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV); + + // draw top right + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); + + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV); + + gGL.texCoord2f(clip_rect.mRight, clip_rect.mTop); + gGL.vertex3fv((width_vec + height_vec).mV); + + gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV); + } + gGL.end(); + +} + +// static +void LLRender2D::initClass(LLImageProviderInterface* image_provider, + const LLVector2* scale_factor) +{ + sGLScaleFactor = (scale_factor == NULL) ? LLVector2(1.f, 1.f) : *scale_factor; + sImageProvider = image_provider; +} + +// static +void LLRender2D::cleanupClass() +{ + if(sImageProvider) + { + sImageProvider->cleanUp(); + } +} + + +//static +void LLRender2D::translate(F32 x, F32 y, F32 z) +{ + gGL.translateUI(x,y,z); + LLFontGL::sCurOrigin.mX += (S32) x; + LLFontGL::sCurOrigin.mY += (S32) y; + LLFontGL::sCurDepth += z; +} + +//static +void LLRender2D::pushMatrix() +{ + gGL.pushUIMatrix(); + LLFontGL::sOriginStack.push_back(std::make_pair(LLFontGL::sCurOrigin, LLFontGL::sCurDepth)); +} + +//static +void LLRender2D::popMatrix() +{ + gGL.popUIMatrix(); + LLFontGL::sCurOrigin = LLFontGL::sOriginStack.back().first; + LLFontGL::sCurDepth = LLFontGL::sOriginStack.back().second; + LLFontGL::sOriginStack.pop_back(); +} + +//static +void LLRender2D::loadIdentity() +{ + gGL.loadUIIdentity(); + LLFontGL::sCurOrigin.mX = 0; + LLFontGL::sCurOrigin.mY = 0; + LLFontGL::sCurDepth = 0.f; +} + +//static +void LLRender2D::setScaleFactor(const LLVector2 &scale_factor) +{ + sGLScaleFactor = scale_factor; +} + +//static +void LLRender2D::setLineWidth(F32 width) +{ + gGL.flush(); + glLineWidth(width * lerp(sGLScaleFactor.mV[VX], sGLScaleFactor.mV[VY], 0.5f)); +} + +//static +LLPointer<LLUIImage> LLRender2D::getUIImageByID(const LLUUID& image_id, S32 priority) +{ + if (sImageProvider) + { + return sImageProvider->getUIImageByID(image_id, priority); + } + else + { + return NULL; + } +} + +//static +LLPointer<LLUIImage> LLRender2D::getUIImage(const std::string& name, S32 priority) +{ + if (!name.empty() && sImageProvider) + return sImageProvider->getUIImage(name, priority); + else + return NULL; +} + diff --git a/indra/llrender/llrender2dutils.h b/indra/llrender/llrender2dutils.h new file mode 100644 index 0000000000..4884422c58 --- /dev/null +++ b/indra/llrender/llrender2dutils.h @@ -0,0 +1,163 @@ +/** + * @file llrender2dutils.h + * @brief GL function declarations for immediate-mode gl drawing. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// All immediate-mode gl drawing should happen here. + + +#ifndef LL_RENDER2DUTILS_H +#define LL_RENDER2DUTILS_H + +#include "llpointer.h" // LLPointer<> +#include "llrect.h" +#include "llglslshader.h" + +class LLColor4; +class LLVector3; +class LLVector2; +class LLUIImage; +class LLUUID; + +extern const LLColor4 UI_VERTEX_COLOR; + +BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom); +void gl_state_for_2d(S32 width, S32 height); + +void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2); +void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color ); +void gl_triangle_2d(S32 x1, S32 y1, S32 x2, S32 y2, S32 x3, S32 y3, const LLColor4& color, BOOL filled); +void gl_rect_2d_simple( S32 width, S32 height ); + +void gl_draw_x(const LLRect& rect, const LLColor4& color); + +void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled = TRUE ); +void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, BOOL filled = TRUE ); +void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, S32 pixel_offset = 0, BOOL filled = TRUE ); +void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset = 0, BOOL filled = TRUE ); +void gl_rect_2d(const LLRect& rect, BOOL filled = TRUE ); +void gl_rect_2d(const LLRect& rect, const LLColor4& color, BOOL filled = TRUE ); +void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha = 1.0f); + +void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines); + +void gl_circle_2d(F32 x, F32 y, F32 radius, S32 steps, BOOL filled); +void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F32 start_angle, F32 end_angle); +void gl_deep_circle( F32 radius, F32 depth ); +void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor4& side_color, S32 steps, BOOL render_center ); +void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac); +void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color); +void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color); + +void gl_draw_image(S32 x, S32 y, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); + +void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase = 0.f ); + +void gl_rect_2d_simple_tex( S32 width, S32 height ); + +// segmented rectangles + +/* + TL |______TOP_________| TR + /| |\ + _/_|__________________|_\_ + L| | MIDDLE | |R + _|_|__________________|_|_ + \ | BOTTOM | / + BL\|__________________|/ BR + | | +*/ + +typedef enum e_rounded_edge +{ + ROUNDED_RECT_LEFT = 0x1, + ROUNDED_RECT_TOP = 0x2, + ROUNDED_RECT_RIGHT = 0x4, + ROUNDED_RECT_BOTTOM = 0x8, + ROUNDED_RECT_ALL = 0xf +}ERoundedEdge; + + +void gl_segmented_rect_2d_tex(const S32 left, const S32 top, const S32 right, const S32 bottom, const S32 texture_width, const S32 texture_height, const S32 border_size, const U32 edges = ROUNDED_RECT_ALL); +void gl_segmented_rect_2d_fragment_tex(const S32 left, const S32 top, const S32 right, const S32 bottom, const S32 texture_width, const S32 texture_height, const S32 border_size, const F32 start_fragment, const F32 end_fragment, const U32 edges = ROUNDED_RECT_ALL); +void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, const LLVector3& width_vec, const LLVector3& height_vec); + +inline void gl_rect_2d( const LLRect& rect, BOOL filled ) +{ + gl_rect_2d( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, filled ); +} + +inline void gl_rect_2d_offset_local( const LLRect& rect, S32 pixel_offset, BOOL filled) +{ + gl_rect_2d_offset_local( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, pixel_offset, filled ); +} + +class LLImageProviderInterface; + +class LLRender2D +{ + LOG_CLASS(LLRender2D); +public: + static void initClass(LLImageProviderInterface* image_provider, + const LLVector2* scale_factor); + static void cleanupClass(); + + static void pushMatrix(); + static void popMatrix(); + static void loadIdentity(); + static void translate(F32 x, F32 y, F32 z = 0.0f); + + static void setLineWidth(F32 width); + static void setScaleFactor(const LLVector2& scale_factor); + + static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0); + static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0); + + static LLVector2 sGLScaleFactor; +private: + static LLImageProviderInterface* sImageProvider; +}; + +class LLImageProviderInterface +{ +protected: + LLImageProviderInterface() {}; + virtual ~LLImageProviderInterface() {}; +public: + virtual LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority) = 0; + virtual LLPointer<LLUIImage> getUIImageByID(const LLUUID& id, S32 priority) = 0; + virtual void cleanUp() = 0; +}; + + +extern LLGLSLShader gSolidColorProgram; +extern LLGLSLShader gUIProgram; + +#endif // LL_RENDER2DUTILS_H + diff --git a/indra/llrender/llrendernavprim.cpp b/indra/llrender/llrendernavprim.cpp index ca72964832..ca72964832 100644..100755 --- a/indra/llrender/llrendernavprim.cpp +++ b/indra/llrender/llrendernavprim.cpp diff --git a/indra/llrender/llrendernavprim.h b/indra/llrender/llrendernavprim.h index a3a5dfec3a..a3a5dfec3a 100644..100755 --- a/indra/llrender/llrendernavprim.h +++ b/indra/llrender/llrendernavprim.h diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp index 26bfe036e8..26bfe036e8 100644..100755 --- a/indra/llrender/llrendersphere.cpp +++ b/indra/llrender/llrendersphere.cpp diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h index f8e9e86e7f..f8e9e86e7f 100644..100755 --- a/indra/llrender/llrendersphere.h +++ b/indra/llrender/llrendersphere.h diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index c1b96a43da..429b91c878 100644..100755 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -53,11 +53,19 @@ void check_framebuffer_status() bool LLRenderTarget::sUseFBO = false; U32 LLRenderTarget::sCurFBO = 0; + +extern S32 gGLViewport[4]; + +U32 LLRenderTarget::sCurResX = 0; +U32 LLRenderTarget::sCurResY = 0; + LLRenderTarget::LLRenderTarget() : mResX(0), mResY(0), mFBO(0), mPreviousFBO(0), + mPreviousResX(0), + mPreviousResY(0), mDepth(0), mStencil(0), mUseDepth(false), @@ -109,8 +117,8 @@ void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt) bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples) { - resx = llmin(resx, (U32) 4096); - resy = llmin(resy, (U32) 4096); + resx = llmin(resx, (U32) gGLManager.mGLMaxTextureSize); + resy = llmin(resy, (U32) gGLManager.mGLMaxTextureSize); stop_glerror(); release(); @@ -390,13 +398,12 @@ void LLRenderTarget::bindTarget() { if (mFBO) { - mPreviousFBO = sCurFBO; - stop_glerror(); + mPreviousFBO = sCurFBO; glBindFramebuffer(GL_FRAMEBUFFER, mFBO); sCurFBO = mFBO; - + stop_glerror(); if (gGLManager.mHasDrawBuffers) { //setup multiple render targets @@ -418,7 +425,12 @@ void LLRenderTarget::bindTarget() stop_glerror(); } + mPreviousResX = sCurResX; + mPreviousResY = sCurResY; glViewport(0, 0, mResX, mResY); + sCurResX = mResX; + sCurResY = mResY; + sBoundTarget = this; } @@ -458,6 +470,12 @@ U32 LLRenderTarget::getTexture(U32 attachment) const return mTex[attachment]; } +U32 LLRenderTarget::getNumTextures() const +{ + return mTex.size(); +} + + void LLRenderTarget::bindTexture(U32 index, S32 channel) { gGL.getTexUnit(channel)->bindManual(mUsage, getTexture(index)); @@ -489,6 +507,20 @@ void LLRenderTarget::flush(bool fetch_depth) stop_glerror(); glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFBO); sCurFBO = mPreviousFBO; + + if (mPreviousFBO) + { + glViewport(0, 0, mPreviousResX, mPreviousResY); + sCurResX = mPreviousResX; + sCurResY = mPreviousResY; + } + else + { + glViewport(gGLViewport[0],gGLViewport[1],gGLViewport[2],gGLViewport[3]); + sCurResX = gGLViewport[2]; + sCurResY = gGLViewport[3]; + } + stop_glerror(); } } @@ -579,3 +611,5 @@ void LLRenderTarget::getViewport(S32* viewport) viewport[3] = mResY; } + + diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index cf15f66d31..740e25d40d 100644..100755 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -28,7 +28,6 @@ #define LL_LLRENDERTARGET_H // LLRenderTarget is unavailible on the mapserver since it uses FBOs. -#if !LL_MESA_HEADLESS #include "llgl.h" #include "llrender.h" @@ -64,6 +63,9 @@ public: static bool sUseFBO; static U32 sBytesAllocated; static U32 sCurFBO; + static U32 sCurResX; + static U32 sCurResY; + LLRenderTarget(); ~LLRenderTarget(); @@ -113,6 +115,7 @@ public: LLTexUnit::eTextureType getUsage(void) const { return mUsage; } U32 getTexture(U32 attachment = 0) const; + U32 getNumTextures() const; U32 getDepth(void) const { return mDepth; } bool hasStencil() const { return mStencil; } @@ -147,6 +150,9 @@ protected: std::vector<U32> mInternalFormat; U32 mFBO; U32 mPreviousFBO; + U32 mPreviousResX; + U32 mPreviousResY; + U32 mDepth; bool mStencil; bool mUseDepth; @@ -156,7 +162,5 @@ protected: static LLRenderTarget* sBoundTarget; }; -#endif //!LL_MESA_HEADLESS - #endif diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index b6a9a6b653..d1afd2ed28 100644..100755 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -521,7 +521,7 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns) } } -GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels) +GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines, S32 texture_index_channels) { GLenum error = GL_NO_ERROR; if (gDebugGL) @@ -650,13 +650,15 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade text[count++] = strdup("#define shadow2DRect(a,b) vec2(texture(a,b))\n"); } } - - //copy preprocessor definitions into buffer - for (std::map<std::string,std::string>::iterator iter = mDefinitions.begin(); iter != mDefinitions.end(); ++iter) + + if (defines) + { + for (boost::unordered_map<std::string,std::string>::iterator iter = defines->begin(); iter != defines->end(); ++iter) { std::string define = "#define " + iter->first + " " + iter->second + "\n"; text[count++] = (GLcharARB *) strdup(define.c_str()); } + } if (texture_index_channels > 0 && type == GL_FRAGMENT_SHADER_ARB) { @@ -693,6 +695,8 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade } */ + text[count++] = strdup("#define HAS_DIFFUSE_LOOKUP 1\n"); + //uniform declartion for (S32 i = 0; i < texture_index_channels; ++i) { @@ -750,6 +754,10 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade llerrs << "Indexed texture rendering requires GLSL 1.30 or later." << llendl; } } + else + { + text[count++] = strdup("#define HAS_DIFFUSE_LOOKUP 0\n"); + } //copy file into memory while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(text) ) @@ -806,7 +814,6 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade //an error occured, print log LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL; dumpObjectLog(ret); - #if LL_WINDOWS std::stringstream ostr; //dump shader source for debugging @@ -824,8 +831,20 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade } LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl; -#endif // LL_WINDOWS - +#else + std::string str; + + for (GLuint i = 0; i < count; i++) { + str.append(text[i]); + + if (i % 128 == 0) + { + LL_WARNS("ShaderLoading") << str << llendl; + str = ""; + } + } +#endif + ret = 0; } } @@ -854,7 +873,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (shader_level > 1) { shader_level--; - return loadShaderFile(filename,shader_level,type,texture_index_channels); + return loadShaderFile(filename,shader_level,type, defines, texture_index_channels); } LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL; } @@ -958,7 +977,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedAttribs.push_back("texcoord3"); mReservedAttribs.push_back("diffuse_color"); mReservedAttribs.push_back("emissive"); - mReservedAttribs.push_back("binormal"); + mReservedAttribs.push_back("tangent"); mReservedAttribs.push_back("weight"); mReservedAttribs.push_back("weight4"); mReservedAttribs.push_back("clothing"); @@ -974,7 +993,9 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("texture_matrix1"); mReservedUniforms.push_back("texture_matrix2"); mReservedUniforms.push_back("texture_matrix3"); - llassert(mReservedUniforms.size() == LLShaderMgr::TEXTURE_MATRIX3+1); + mReservedUniforms.push_back("object_plane_s"); + mReservedUniforms.push_back("object_plane_t"); + llassert(mReservedUniforms.size() == LLShaderMgr::OBJECT_PLANE_T+1); mReservedUniforms.push_back("viewport"); @@ -1055,6 +1076,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("minimum_alpha"); + mReservedUniforms.push_back("emissive_brightness"); mReservedUniforms.push_back("shadow_matrix"); mReservedUniforms.push_back("env_mat"); @@ -1115,6 +1137,52 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("lightMap"); mReservedUniforms.push_back("bloomMap"); mReservedUniforms.push_back("projectionMap"); + + mReservedUniforms.push_back("global_gamma"); + mReservedUniforms.push_back("texture_gamma"); + + mReservedUniforms.push_back("specular_color"); + mReservedUniforms.push_back("env_intensity"); + + mReservedUniforms.push_back("matrixPalette"); + + mReservedUniforms.push_back("screenTex"); + mReservedUniforms.push_back("screenDepth"); + mReservedUniforms.push_back("refTex"); + mReservedUniforms.push_back("eyeVec"); + mReservedUniforms.push_back("time"); + mReservedUniforms.push_back("d1"); + mReservedUniforms.push_back("d2"); + mReservedUniforms.push_back("lightDir"); + mReservedUniforms.push_back("specular"); + mReservedUniforms.push_back("lightExp"); + mReservedUniforms.push_back("waterFogColor"); + mReservedUniforms.push_back("waterFogDensity"); + mReservedUniforms.push_back("waterFogKS"); + mReservedUniforms.push_back("refScale"); + mReservedUniforms.push_back("waterHeight"); + mReservedUniforms.push_back("waterPlane"); + mReservedUniforms.push_back("normScale"); + mReservedUniforms.push_back("fresnelScale"); + mReservedUniforms.push_back("fresnelOffset"); + mReservedUniforms.push_back("blurMultiplier"); + mReservedUniforms.push_back("sunAngle"); + mReservedUniforms.push_back("scaledAngle"); + mReservedUniforms.push_back("sunAngle2"); + + mReservedUniforms.push_back("camPosLocal"); + + mReservedUniforms.push_back("gWindDir"); + mReservedUniforms.push_back("gSinWaveParams"); + mReservedUniforms.push_back("gGravity"); + + mReservedUniforms.push_back("detail_0"); + mReservedUniforms.push_back("detail_1"); + mReservedUniforms.push_back("detail_2"); + mReservedUniforms.push_back("detail_3"); + mReservedUniforms.push_back("alpha_ramp"); + + mReservedUniforms.push_back("origin"); llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 7a16b7c20f..ba781036eb 100644..100755 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -47,6 +47,8 @@ public: TEXTURE_MATRIX1, TEXTURE_MATRIX2, TEXTURE_MATRIX3, + OBJECT_PLANE_S, + OBJECT_PLANE_T, VIEWPORT, LIGHT_POSITION, LIGHT_DIRECTION, @@ -109,6 +111,7 @@ public: GLOW_DELTA, MINIMUM_ALPHA, + EMISSIVE_BRIGHTNESS, DEFERRED_SHADOW_MATRIX, DEFERRED_ENV_MAT, @@ -164,7 +167,55 @@ public: DEFERRED_LIGHT, DEFERRED_BLOOM, DEFERRED_PROJECTION, + + GLOBAL_GAMMA, + TEXTURE_GAMMA, + + SPECULAR_COLOR, + ENVIRONMENT_INTENSITY, + + AVATAR_MATRIX, + + WATER_SCREENTEX, + WATER_SCREENDEPTH, + WATER_REFTEX, + WATER_EYEVEC, + WATER_TIME, + WATER_WAVE_DIR1, + WATER_WAVE_DIR2, + WATER_LIGHT_DIR, + WATER_SPECULAR, + WATER_SPECULAR_EXP, + WATER_FOGCOLOR, + WATER_FOGDENSITY, + WATER_FOGKS, + WATER_REFSCALE, + WATER_WATERHEIGHT, + WATER_WATERPLANE, + WATER_NORM_SCALE, + WATER_FRESNEL_SCALE, + WATER_FRESNEL_OFFSET, + WATER_BLUR_MULTIPLIER, + WATER_SUN_ANGLE, + WATER_SCALED_ANGLE, + WATER_SUN_ANGLE2, + + WL_CAMPOSLOCAL, + + AVATAR_WIND, + AVATAR_SINWAVE, + AVATAR_GRAVITY, + + TERRAIN_DETAIL0, + TERRAIN_DETAIL1, + TERRAIN_DETAIL2, + TERRAIN_DETAIL3, + TERRAIN_ALPHARAMP, + + SHINY_ORIGIN, + END_RESERVED_UNIFORMS + } eGLSLReservedUniforms; // singleton pattern implementation @@ -176,7 +227,7 @@ public: void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE); BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE); BOOL validateProgramObject(GLhandleARB obj); - GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels = -1); + GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1); // Implemented in the application to actually point to the shader directory. virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual diff --git a/indra/llrender/lltexture.cpp b/indra/llrender/lltexture.cpp index 90fbcec2be..90fbcec2be 100644..100755 --- a/indra/llrender/lltexture.cpp +++ b/indra/llrender/lltexture.cpp diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h index 569a65c2e0..093bac20d1 100644..100755 --- a/indra/llrender/lltexture.h +++ b/indra/llrender/lltexture.h @@ -38,10 +38,9 @@ class LLTexUnit ; class LLFontGL ; // -//this is an abstract class as the parent for the class LLViewerTexture -//through the following virtual functions, the class LLViewerTexture can be reached from /llrender. +//this is an abstract class as the parent for the class LLGLTexture // -class LLTexture : public LLRefCount +class LLTexture : public virtual LLRefCount { friend class LLTexUnit ; friend class LLFontGL ; @@ -53,7 +52,7 @@ public: LLTexture(){} // - //interfaces to access LLViewerTexture + //interfaces to access LLGLTexture // virtual S8 getType() const = 0 ; virtual void setKnownDrawSize(S32 width, S32 height) = 0 ; diff --git a/indra/llrender/lluiimage.cpp b/indra/llrender/lluiimage.cpp new file mode 100644 index 0000000000..b954b66350 --- /dev/null +++ b/indra/llrender/lluiimage.cpp @@ -0,0 +1,243 @@ +/** + * @file lluiimage.cpp + * @brief UI implementation + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// Utilities functions the user interface needs + +//#include "llviewerprecompiledheaders.h" +#include "linden_common.h" + +// Project includes +#include "lluiimage.h" +#include "llrender2dutils.h" + +LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image) +: mName(name), + mImage(image), + mScaleRegion(0.f, 1.f, 1.f, 0.f), + mClipRegion(0.f, 1.f, 1.f, 0.f), + mUniformScaling(TRUE), + mNoClip(TRUE), + mImageLoaded(NULL) +{ +} + +LLUIImage::~LLUIImage() +{ + delete mImageLoaded; +} + +void LLUIImage::setClipRegion(const LLRectf& region) +{ + mClipRegion = region; + mNoClip = mClipRegion.mLeft == 0.f + && mClipRegion.mRight == 1.f + && mClipRegion.mBottom == 0.f + && mClipRegion.mTop == 1.f; +} + +void LLUIImage::setScaleRegion(const LLRectf& region) +{ + mScaleRegion = region; + mUniformScaling = mScaleRegion.mLeft == 0.f + && mScaleRegion.mRight == 1.f + && mScaleRegion.mBottom == 0.f + && mScaleRegion.mTop == 1.f; +} + +//TODO: move drawing implementation inside class +void LLUIImage::draw(S32 x, S32 y, const LLColor4& color) const +{ + gl_draw_scaled_image(x, y, getWidth(), getHeight(), mImage, color, mClipRegion); +} + +void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const +{ + if (mUniformScaling) + { + gl_draw_scaled_image(x, y, width, height, mImage, color, mClipRegion); + } + else + { + gl_draw_scaled_image_with_border( + x, y, + width, height, + mImage, + color, + FALSE, + mClipRegion, + mScaleRegion); + } +} + +void LLUIImage::drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const +{ + gl_draw_scaled_image_with_border( + x, y, + width, height, + mImage, + color, + TRUE, + mClipRegion, + mScaleRegion); +} + +void LLUIImage::drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const +{ + LLRect border_rect; + border_rect.setOriginAndSize(x, y, width, height); + border_rect.stretch(border_width, border_width); + drawSolid(border_rect, color); +} + +void LLUIImage::draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis, + const LLRect& rect, const LLColor4& color) +{ + F32 border_scale = 1.f; + F32 border_height = (1.f - mScaleRegion.getHeight()) * getHeight(); + F32 border_width = (1.f - mScaleRegion.getWidth()) * getWidth(); + if (rect.getHeight() < border_height || rect.getWidth() < border_width) + { + if(border_height - rect.getHeight() > border_width - rect.getWidth()) + { + border_scale = (F32)rect.getHeight() / border_height; + } + else + { + border_scale = (F32)rect.getWidth() / border_width; + } + } + + LLRender2D::pushMatrix(); + { + LLVector3 rect_origin = origin_agent + (rect.mLeft * x_axis) + (rect.mBottom * y_axis); + LLRender2D::translate(rect_origin.mV[VX], + rect_origin.mV[VY], + rect_origin.mV[VZ]); + gGL.getTexUnit(0)->bind(getImage()); + gGL.color4fv(color.mV); + + LLRectf center_uv_rect(mClipRegion.mLeft + mScaleRegion.mLeft * mClipRegion.getWidth(), + mClipRegion.mBottom + mScaleRegion.mTop * mClipRegion.getHeight(), + mClipRegion.mLeft + mScaleRegion.mRight * mClipRegion.getWidth(), + mClipRegion.mBottom + mScaleRegion.mBottom * mClipRegion.getHeight()); + gl_segmented_rect_3d_tex(mClipRegion, + center_uv_rect, + LLRectf(border_width * border_scale * 0.5f / (F32)rect.getWidth(), + (rect.getHeight() - (border_height * border_scale * 0.5f)) / (F32)rect.getHeight(), + (rect.getWidth() - (border_width * border_scale * 0.5f)) / (F32)rect.getWidth(), + (border_height * border_scale * 0.5f) / (F32)rect.getHeight()), + rect.getWidth() * x_axis, + rect.getHeight() * y_axis); + + } LLRender2D::popMatrix(); +} + + +S32 LLUIImage::getWidth() const +{ + // return clipped dimensions of actual image area + return llround((F32)mImage->getWidth(0) * mClipRegion.getWidth()); +} + +S32 LLUIImage::getHeight() const +{ + // return clipped dimensions of actual image area + return llround((F32)mImage->getHeight(0) * mClipRegion.getHeight()); +} + +S32 LLUIImage::getTextureWidth() const +{ + return mImage->getWidth(0); +} + +S32 LLUIImage::getTextureHeight() const +{ + return mImage->getHeight(0); +} + +boost::signals2::connection LLUIImage::addLoadedCallback( const image_loaded_signal_t::slot_type& cb ) +{ + if (!mImageLoaded) + { + mImageLoaded = new image_loaded_signal_t(); + } + return mImageLoaded->connect(cb); +} + + +void LLUIImage::onImageLoaded() +{ + if (mImageLoaded) + { + (*mImageLoaded)(); + } +} + + +namespace LLInitParam +{ + void ParamValue<LLUIImage*>::updateValueFromBlock() + { + // The keyword "none" is specifically requesting a null image + // do not default to current value. Used to overwrite template images. + if (name() == "none") + { + updateValue(NULL); + return; + } + + LLUIImage* imagep = LLRender2D::getUIImage(name()); + if (imagep) + { + updateValue(imagep); + } + } + + void ParamValue<LLUIImage*>::updateBlockFromValue(bool make_block_authoritative) + { + if (getValue() == NULL) + { + name.set("none", make_block_authoritative); + } + else + { + name.set(getValue()->getName(), make_block_authoritative); + } + } + + + bool ParamCompare<LLUIImage*, false>::equals( + LLUIImage* const &a, + LLUIImage* const &b) + { + // force all LLUIImages for XML UI export to be "non-default" + if (!a && !b) + return false; + else + return (a == b); + } +} + diff --git a/indra/llrender/lluiimage.h b/indra/llrender/lluiimage.h new file mode 100644 index 0000000000..7817ba1c7b --- /dev/null +++ b/indra/llrender/lluiimage.h @@ -0,0 +1,126 @@ +/** + * @file lluiimage.h + * @brief wrapper for images used in the UI that handles smart scaling, etc. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLUIIMAGE_H +#define LL_LLUIIMAGE_H + +#include "v4color.h" +#include "llpointer.h" +#include "llrefcount.h" +#include "llrefcount.h" +#include "llrect.h" +#include <boost/function.hpp> +#include <boost/signals2.hpp> +#include "llinitparam.h" +#include "lltexture.h" + +extern const LLColor4 UI_VERTEX_COLOR; + +class LLUIImage : public LLRefCount +{ +public: + typedef boost::signals2::signal<void (void)> image_loaded_signal_t; + + LLUIImage(const std::string& name, LLPointer<LLTexture> image); + virtual ~LLUIImage(); + + void setClipRegion(const LLRectf& region); + void setScaleRegion(const LLRectf& region); + + LLPointer<LLTexture> getImage() { return mImage; } + const LLPointer<LLTexture>& getImage() const { return mImage; } + + void draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color = UI_VERTEX_COLOR) const; + void draw(S32 x, S32 y, const LLColor4& color = UI_VERTEX_COLOR) const; + void draw(const LLRect& rect, const LLColor4& color = UI_VERTEX_COLOR) const { draw(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } + + void drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const; + void drawSolid(const LLRect& rect, const LLColor4& color) const { drawSolid(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } + void drawSolid(S32 x, S32 y, const LLColor4& color) const { drawSolid(x, y, getWidth(), getHeight(), color); } + + void drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const; + void drawBorder(const LLRect& rect, const LLColor4& color, S32 border_width) const { drawBorder(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color, border_width); } + void drawBorder(S32 x, S32 y, const LLColor4& color, S32 border_width) const { drawBorder(x, y, getWidth(), getHeight(), color, border_width); } + + void draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis, const LLRect& rect, const LLColor4& color); + + const std::string& getName() const { return mName; } + + virtual S32 getWidth() const; + virtual S32 getHeight() const; + + // returns dimensions of underlying textures, which might not be equal to ui image portion + S32 getTextureWidth() const; + S32 getTextureHeight() const; + + boost::signals2::connection addLoadedCallback( const image_loaded_signal_t::slot_type& cb ); + + void onImageLoaded(); + +protected: + image_loaded_signal_t* mImageLoaded; + + std::string mName; + LLRectf mScaleRegion; + LLRectf mClipRegion; + LLPointer<LLTexture> mImage; + BOOL mUniformScaling; + BOOL mNoClip; +}; + +namespace LLInitParam +{ + template<> + class ParamValue<LLUIImage*> + : public CustomParamValue<LLUIImage*> + { + typedef boost::add_reference<boost::add_const<LLUIImage*>::type>::type T_const_ref; + typedef CustomParamValue<LLUIImage*> super_t; + public: + Optional<std::string> name; + + ParamValue(LLUIImage* const& image = NULL) + : super_t(image) + { + updateBlockFromValue(false); + addSynonym(name, "name"); + } + + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; + + // Need custom comparison function for our test app, which only loads + // LLUIImage* as NULL. + template<> + struct ParamCompare<LLUIImage*, false> + { + static bool equals(LLUIImage* const &a, LLUIImage* const &b); + }; +} + +typedef LLPointer<LLUIImage> LLUIImagePtr; +#endif diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index dfbd8cd4ee..83ea6fabbb 100644..100755 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -85,6 +85,7 @@ const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE); //static LLVBOPool LLVertexBuffer::sStreamVBOPool(GL_STREAM_DRAW_ARB, GL_ARRAY_BUFFER_ARB); LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_ARB); +LLVBOPool LLVertexBuffer::sDynamicCopyVBOPool(GL_DYNAMIC_COPY_ARB, GL_ARRAY_BUFFER_ARB); LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB); LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB); @@ -199,7 +200,10 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) { glBufferDataARB(mType, size, 0, mUsage); - ret = (U8*) ll_aligned_malloc_16(size); + if (mUsage != GL_DYNAMIC_COPY_ARB) + { //data will be provided by application + ret = (U8*) ll_aligned_malloc(size, 64); + } } else { //always use a true hint of static draw when allocating non-client-backed buffers @@ -252,7 +256,7 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) llassert(vbo_block_size(size) == size); deleteBuffer(name); - ll_aligned_free_16((U8*) buffer); + ll_aligned_free((U8*) buffer); if (mType == GL_ARRAY_BUFFER_ARB) { @@ -306,7 +310,7 @@ void LLVBOPool::cleanup() if (r.mClientData) { - ll_aligned_free_16((void*) r.mClientData); + ll_aligned_free((void*) r.mClientData); } l.pop_front(); @@ -342,13 +346,32 @@ S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] = sizeof(LLVector2), // TYPE_TEXCOORD3, sizeof(LLColor4U), // TYPE_COLOR, sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently - sizeof(LLVector4), // TYPE_BINORMAL, + sizeof(LLVector4), // TYPE_TANGENT, sizeof(F32), // TYPE_WEIGHT, sizeof(LLVector4), // TYPE_WEIGHT4, sizeof(LLVector4), // TYPE_CLOTHWEIGHT, sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes }; +static std::string vb_type_name[] = +{ + "TYPE_VERTEX", + "TYPE_NORMAL", + "TYPE_TEXCOORD0", + "TYPE_TEXCOORD1", + "TYPE_TEXCOORD2", + "TYPE_TEXCOORD3", + "TYPE_COLOR", + "TYPE_EMISSIVE", + "TYPE_TANGENT", + "TYPE_WEIGHT", + "TYPE_WEIGHT4", + "TYPE_CLOTHWEIGHT", + "TYPE_TEXTURE_INDEX", + "TYPE_MAX", + "TYPE_INDEX", +}; + U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = { GL_TRIANGLES, @@ -393,6 +416,7 @@ void LLVertexBuffer::seedPools() { sStreamVBOPool.seedPool(); sDynamicVBOPool.seedPool(); + sDynamicCopyVBOPool.seedPool(); sStreamIBOPool.seedPool(); sDynamicIBOPool.seedPool(); } @@ -402,7 +426,6 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) { if (sLastMask != data_mask) { - bool error = false; if (gGLManager.mGLSLVersionMajor < 2 && gGLManager.mGLSLVersionMinor < 30) { @@ -469,7 +492,6 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) { if (gDebugSession) { - error = true; gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl; } else @@ -489,7 +511,6 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) { //needs to be disabled, make sure it was (DEBUG TEMPORARY) if (gDebugSession) { - error = true; gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl; } else @@ -526,16 +547,16 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) } } - if (sLastMask & MAP_BINORMAL) + if (sLastMask & MAP_TANGENT) { - if (!(data_mask & MAP_BINORMAL)) + if (!(data_mask & MAP_TANGENT)) { glClientActiveTextureARB(GL_TEXTURE2_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTextureARB(GL_TEXTURE0_ARB); } } - else if (data_mask & MAP_BINORMAL) + else if (data_mask & MAP_TANGENT) { glClientActiveTextureARB(GL_TEXTURE2_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -548,8 +569,10 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) } //static +static LLFastTimer::DeclareTimer FTM_VB_DRAW_ARRAYS("drawArrays"); void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm) { + LLFastTimer t(FTM_VB_DRAW_ARRAYS); llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); gGL.syncMatrices(); @@ -594,8 +617,9 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, con glVertexPointer(3, GL_FLOAT, 0, pos[0].mV); glNormalPointer(GL_FLOAT, 0, norm[0].mV); } - + LLGLSLShader::startProfile(); glDrawArrays(sGLMode[mode], 0, count); + LLGLSLShader::stopProfile(count, mode); } //static @@ -632,7 +656,9 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto glVertexPointer(3, GL_FLOAT, 16, pos); } + LLGLSLShader::startProfile(); glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp); + LLGLSLShader::stopProfile(num_indices, mode); } void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const @@ -732,9 +758,14 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi U16* idx = ((U16*) getIndicesPointer())+indices_offset; stop_glerror(); + LLGLSLShader::startProfile(); glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, idx); + LLGLSLShader::stopProfile(count, mode); stop_glerror(); + + + placeFence(); } @@ -778,12 +809,15 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const } stop_glerror(); + LLGLSLShader::startProfile(); glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT, ((U16*) getIndicesPointer()) + indices_offset); + LLGLSLShader::stopProfile(count, mode); stop_glerror(); placeFence(); } +static LLFastTimer::DeclareTimer FTM_GL_DRAW_ARRAYS("GL draw arrays"); void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); @@ -818,8 +852,14 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const return; } + { + LLFastTimer t2(FTM_GL_DRAW_ARRAYS); stop_glerror(); + LLGLSLShader::startProfile(); glDrawArrays(sGLMode[mode], first, count); + LLGLSLShader::stopProfile(count, mode); + } + stop_glerror(); placeFence(); } @@ -875,6 +915,7 @@ void LLVertexBuffer::cleanupClass() sDynamicIBOPool.cleanup(); sStreamVBOPool.cleanup(); sDynamicVBOPool.cleanup(); + sDynamicCopyVBOPool.cleanup(); if(sPrivatePoolp) { @@ -911,13 +952,16 @@ S32 LLVertexBuffer::determineUsage(S32 usage) if (ret_usage && ret_usage != GL_STREAM_DRAW_ARB) { //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default - if (sDisableVBOMapping) - { //always use stream draw if VBO mapping is disabled - ret_usage = GL_STREAM_DRAW_ARB; - } - else + if (ret_usage != GL_DYNAMIC_COPY_ARB) { - ret_usage = GL_DYNAMIC_DRAW_ARB; + if (sDisableVBOMapping) + { //always use stream draw if VBO mapping is disabled + ret_usage = GL_STREAM_DRAW_ARB; + } + else + { + ret_usage = GL_DYNAMIC_DRAW_ARB; + } } } @@ -1067,10 +1111,15 @@ void LLVertexBuffer::genBuffer(U32 size) { mMappedData = sStreamVBOPool.allocate(mGLBuffer, mSize); } - else + else if (mUsage == GL_DYNAMIC_DRAW_ARB) { mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize); } + else + { + mMappedData = sDynamicCopyVBOPool.allocate(mGLBuffer, mSize); + } + sGLCount++; } @@ -1284,7 +1333,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) //actually allocate space for the vertex buffer if using VBO mapping flush(); - if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO)) + if (gGLManager.mHasVertexArrayObject && useVBOs() && (sUseVAO)) { #if GL_ARB_vertex_array_object mGLArray = getVAOName(); @@ -1319,7 +1368,7 @@ void LLVertexBuffer::setupVertexArray() 2, //TYPE_TEXCOORD3, 4, //TYPE_COLOR, 4, //TYPE_EMISSIVE, - 3, //TYPE_BINORMAL, + 4, //TYPE_TANGENT, 1, //TYPE_WEIGHT, 4, //TYPE_WEIGHT4, 4, //TYPE_CLOTHWEIGHT, @@ -1336,7 +1385,7 @@ void LLVertexBuffer::setupVertexArray() GL_FLOAT, //TYPE_TEXCOORD3, GL_UNSIGNED_BYTE, //TYPE_COLOR, GL_UNSIGNED_BYTE, //TYPE_EMISSIVE, - GL_FLOAT, //TYPE_BINORMAL, + GL_FLOAT, //TYPE_TANGENT, GL_FLOAT, //TYPE_WEIGHT, GL_FLOAT, //TYPE_WEIGHT4, GL_FLOAT, //TYPE_CLOTHWEIGHT, @@ -1353,7 +1402,7 @@ void LLVertexBuffer::setupVertexArray() false, //TYPE_TEXCOORD3, false, //TYPE_COLOR, false, //TYPE_EMISSIVE, - false, //TYPE_BINORMAL, + false, //TYPE_TANGENT, false, //TYPE_WEIGHT, false, //TYPE_WEIGHT4, false, //TYPE_CLOTHWEIGHT, @@ -1370,7 +1419,7 @@ void LLVertexBuffer::setupVertexArray() GL_FALSE, //TYPE_TEXCOORD3, GL_TRUE, //TYPE_COLOR, GL_TRUE, //TYPE_EMISSIVE, - GL_FALSE, //TYPE_BINORMAL, + GL_FALSE, //TYPE_TANGENT, GL_FALSE, //TYPE_WEIGHT, GL_FALSE, //TYPE_WEIGHT4, GL_FALSE, //TYPE_CLOTHWEIGHT, @@ -1440,21 +1489,18 @@ bool LLVertexBuffer::useVBOs() const //---------------------------------------------------------------------------- -bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) +bool expand_region(LLVertexBuffer::MappedRegion& region, S32 start, S32 end) { - S32 end = index+count; - S32 region_end = region.mIndex+region.mCount; - if (end < region.mIndex || - index > region_end) + start > region.mEnd) { //gap exists, do not merge return false; } - S32 new_end = llmax(end, region_end); - S32 new_index = llmin(index, region.mIndex); - region.mIndex = new_index; - region.mCount = new_end-new_index; + region.mEnd = llmax(end, region.mEnd); + region.mIndex = llmin(start, region.mIndex); + region.mCount = region.mEnd-region.mIndex; + return true; } @@ -1464,7 +1510,6 @@ static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map"); // Map for data access volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) { - bindGLBuffer(true); if (mFinal) { llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl; @@ -1485,23 +1530,23 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo bool mapped = false; //see if range is already mapped - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) + S32 start_index = mOffsets[type]+index*sTypeSize[type]; + S32 end_index = start_index+count*sTypeSize[type]; + + for (std::vector<MappedRegion>::iterator iter = mMappedVertexRegions.begin(), end = mMappedVertexRegions.end(); iter != end; ++iter) { - MappedRegion& region = mMappedVertexRegions[i]; - if (region.mType == type) + MappedRegion& region = *iter; + if (expand_region(region, index, end_index)) { - if (expand_region(region, index, count)) - { - mapped = true; - break; - } + mapped = true; + break; } } if (!mapped) { //not already mapped, map new region - MappedRegion region(type, mMappable && map_range ? -1 : index, count); + MappedRegion region(mMappable && map_range ? -1 : start_index, end_index-start_index); mMappedVertexRegions.push_back(region); } } @@ -1525,6 +1570,7 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo { volatile U8* src = NULL; waitFence(); + bindGLBuffer(); if (gGLManager.mHasMapBufferRange) { if (map_range) @@ -1565,8 +1611,10 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo { if (map_range) { +#ifndef LL_MESA_HEADLESS glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE); glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE); +#endif src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); } else @@ -1643,7 +1691,6 @@ static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map"); volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) { - bindGLIndices(true); if (mFinal) { llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl; @@ -1662,12 +1709,14 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range count = mNumIndices-index; } + S32 end = index+count; + bool mapped = false; //see if range is already mapped for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) { MappedRegion& region = mMappedIndexRegions[i]; - if (expand_region(region, index, count)) + if (expand_region(region, index, end)) { mapped = true; break; @@ -1677,7 +1726,7 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range if (!mapped) { //not already mapped, map new region - MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count); + MappedRegion region(mMappable && map_range ? -1 : index, count); mMappedIndexRegions.push_back(region); } } @@ -1693,23 +1742,23 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range sMappedCount++; stop_glerror(); - if (gDebugGL && useVBOs()) - { - GLint elem = 0; - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem); - - if (elem != mGLIndices) - { - llerrs << "Wrong index buffer bound!" << llendl; - } - } - if(!mMappable) { map_range = false; } else { + bindGLIndices(); + if (gDebugGL && useVBOs()) + { + GLint elem = 0; + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem); + + if (elem != mGLIndices) + { + llerrs << "Wrong index buffer bound!" << llendl; + } + } volatile U8* src = NULL; waitFence(); if (gGLManager.mHasMapBufferRange) @@ -1740,8 +1789,10 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range { if (map_range) { +#ifndef LL_MESA_HEADLESS glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE); glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE); +#endif src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); } else @@ -1820,8 +1871,10 @@ void LLVertexBuffer::unmapBuffer() if (mMappedData && mVertexLocked) { + llassert(mUsage != GL_DYNAMIC_COPY_ARB); + LLFastTimer t(FTM_VBO_UNMAP); - bindGLBuffer(true); + bindGLBuffer(); updated_all = mIndexLocked; //both vertex and index buffers done updating if(!mMappable) @@ -1832,8 +1885,8 @@ void LLVertexBuffer::unmapBuffer() for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) { const MappedRegion& region = mMappedVertexRegions[i]; - S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; - S32 length = sTypeSize[region.mType]*region.mCount; + S32 offset = region.mIndex; + S32 length = region.mCount; glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset); stop_glerror(); } @@ -1857,8 +1910,8 @@ void LLVertexBuffer::unmapBuffer() for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) { const MappedRegion& region = mMappedVertexRegions[i]; - S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; - S32 length = sTypeSize[region.mType]*region.mCount; + S32 offset = region.mIndex; + S32 length = region.mCount; if (gGLManager.mHasMapBufferRange) { LLFastTimer t(FTM_VBO_FLUSH_RANGE); @@ -1868,7 +1921,9 @@ void LLVertexBuffer::unmapBuffer() } else if (gGLManager.mHasFlushBufferRange) { +#ifndef LL_MESA_HEADLESS glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length); +#endif } stop_glerror(); } @@ -1934,8 +1989,10 @@ void LLVertexBuffer::unmapBuffer() else if (gGLManager.mHasFlushBufferRange) { #ifdef GL_APPLE_flush_buffer_range +#ifndef LL_MESA_HEADLESS glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); #endif +#endif } stop_glerror(); } @@ -2027,14 +2084,21 @@ bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 inde { return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range); } - +bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range) +{ + return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index, count, map_range); +} bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) { return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range); } -bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) +bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) { - return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index, count, map_range); + return VertexBufferStrider<LLVector3,TYPE_TANGENT>::get(*this, strider, index, count, map_range); +} +bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range) +{ + return VertexBufferStrider<LLVector4a,TYPE_TANGENT>::get(*this, strider, index, count, map_range); } bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range) { @@ -2067,7 +2131,6 @@ bool LLVertexBuffer::bindGLArray() if (mGLArray && sGLRenderArray != mGLArray) { { - LLFastTimer t(FTM_BIND_GL_ARRAY); #if GL_ARB_vertex_array_object glBindVertexArray(mGLArray); #endif @@ -2094,22 +2157,15 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind) if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive)))) { - LLFastTimer t(FTM_BIND_GL_BUFFER); - /*if (sMapped) - { - llerrs << "VBO bound while another VBO mapped!" << llendl; - }*/ + //LLFastTimer t(FTM_BIND_GL_BUFFER); <-- this timer is showing up as a hotspot (irony) + glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer); sGLRenderBuffer = mGLBuffer; sBindCount++; sVBOActive = true; - if (mGLArray) - { - llassert(sGLRenderArray == mGLArray); - //mCachedRenderBuffer = mGLBuffer; - } - + llassert(!mGLArray || sGLRenderArray == mGLArray); + ret = true; } @@ -2189,7 +2245,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask) if ((data_mask & required_mask) != required_mask) { - llerrs << "Shader consumption mismatches data provision." << llendl; + llwarns << "Shader consumption mismatches data provision." << llendl; } } } @@ -2209,7 +2265,6 @@ void LLVertexBuffer::setBuffer(U32 data_mask) setup = setup || bindBuffer || bindIndices; } - bool error = false; if (gDebugGL && !mGLArray) { GLint buff; @@ -2218,7 +2273,6 @@ void LLVertexBuffer::setBuffer(U32 data_mask) { if (gDebugSession) { - error = true; gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl; } else @@ -2234,7 +2288,6 @@ void LLVertexBuffer::setBuffer(U32 data_mask) { if (gDebugSession) { - error = true; gFailLog << "Invalid GL index buffer bound: " << buff << std::endl; } else @@ -2310,6 +2363,14 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) if (gDebugGL && ((data_mask & mTypeMask) != data_mask)) { + for (U32 i = 0; i < LLVertexBuffer::TYPE_MAX; ++i) + { + U32 mask = 1 << i; + if (mask & data_mask && !(mask & mTypeMask)) + { //bit set in data_mask, but not set in mTypeMask + llwarns << "Missing required component " << vb_type_name[i] << llendl; + } + } llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; } @@ -2339,11 +2400,11 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]); glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr); } - if (data_mask & MAP_BINORMAL) + if (data_mask & MAP_TANGENT) { - S32 loc = TYPE_BINORMAL; - void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]); - glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr); + S32 loc = TYPE_TANGENT; + void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]); + glVertexAttribPointerARB(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr); } if (data_mask & MAP_TEXCOORD0) { @@ -2354,7 +2415,8 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) if (data_mask & MAP_COLOR) { S32 loc = TYPE_COLOR; - void* ptr = (void*)(base + mOffsets[TYPE_COLOR]); + //bind emissive instead of color pointer if emissive is present + void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]); glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr); } if (data_mask & MAP_EMISSIVE) @@ -2362,6 +2424,12 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) S32 loc = TYPE_EMISSIVE; void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]); glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); + + if (!(data_mask & MAP_COLOR)) + { //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps + loc = TYPE_COLOR; + glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); + } } if (data_mask & MAP_WEIGHT) { @@ -2421,10 +2489,10 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); glClientActiveTextureARB(GL_TEXTURE0_ARB); } - if (data_mask & MAP_BINORMAL) + if (data_mask & MAP_TANGENT) { glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL])); + glTexCoordPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT])); glClientActiveTextureARB(GL_TEXTURE0_ARB); } if (data_mask & MAP_TEXCOORD0) @@ -2444,11 +2512,10 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) llglassertok(); } -LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count) -: mType(type), mIndex(index), mCount(count) +LLVertexBuffer::MappedRegion::MappedRegion(S32 index, S32 count) +: mIndex(index), mCount(count) { - llassert(mType == LLVertexBuffer::TYPE_INDEX || - mType < LLVertexBuffer::TYPE_TEXTURE_INDEX); + mEnd = mIndex+mCount; } diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 11fa4ab6a0..b7597cf60e 100644..100755 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -104,11 +104,11 @@ public: class MappedRegion { public: - S32 mType; S32 mIndex; S32 mCount; + S32 mEnd; - MappedRegion(S32 type, S32 index, S32 count); + MappedRegion(S32 index, S32 count); }; LLVertexBuffer(const LLVertexBuffer& rhs) @@ -125,9 +125,10 @@ public: static LLVBOPool sStreamVBOPool; static LLVBOPool sDynamicVBOPool; + static LLVBOPool sDynamicCopyVBOPool; static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; - + static std::list<U32> sAvailableVAOName; static U32 sCurVAOName; @@ -174,7 +175,7 @@ public: TYPE_TEXCOORD3, TYPE_COLOR, TYPE_EMISSIVE, - TYPE_BINORMAL, + TYPE_TANGENT, TYPE_WEIGHT, TYPE_WEIGHT4, TYPE_CLOTHWEIGHT, @@ -192,7 +193,7 @@ public: MAP_COLOR = (1<<TYPE_COLOR), MAP_EMISSIVE = (1<<TYPE_EMISSIVE), // These use VertexAttribPointer and should possibly be made generic - MAP_BINORMAL = (1<<TYPE_BINORMAL), + MAP_TANGENT = (1<<TYPE_TANGENT), MAP_WEIGHT = (1<<TYPE_WEIGHT), MAP_WEIGHT4 = (1<<TYPE_WEIGHT4), MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT), @@ -250,8 +251,10 @@ public: bool getIndexStrider(LLStrider<U16>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false); - bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getTangentStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getTangentStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getTextureIndexStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); |