diff options
Diffstat (limited to 'indra/llrender')
-rw-r--r-- | indra/llrender/llcubemap.cpp | 37 | ||||
-rw-r--r-- | indra/llrender/llfontfreetype.cpp | 7 | ||||
-rw-r--r-- | indra/llrender/llfontgl.cpp | 3 | ||||
-rw-r--r-- | indra/llrender/llgl.cpp | 391 | ||||
-rw-r--r-- | indra/llrender/llgl.h | 17 | ||||
-rw-r--r-- | indra/llrender/llglheaders.h | 91 | ||||
-rw-r--r-- | indra/llrender/llglslshader.cpp | 74 | ||||
-rw-r--r-- | indra/llrender/llglslshader.h | 18 | ||||
-rw-r--r-- | indra/llrender/llimagegl.cpp | 128 | ||||
-rw-r--r-- | indra/llrender/llpostprocess.cpp | 22 | ||||
-rw-r--r-- | indra/llrender/llrender.cpp | 834 | ||||
-rw-r--r-- | indra/llrender/llrender.h | 64 | ||||
-rw-r--r-- | indra/llrender/llrendersphere.cpp | 98 | ||||
-rw-r--r-- | indra/llrender/llrendersphere.h | 5 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.cpp | 139 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.h | 16 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.cpp | 413 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.h | 128 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 1681 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.h | 132 |
20 files changed, 3167 insertions, 1131 deletions
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index fb22d7f1f5..45a3b18179 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -36,6 +36,7 @@ #include "m4math.h" #include "llrender.h" +#include "llglslshader.h" #include "llglheaders.h" @@ -195,7 +196,7 @@ void LLCubeMap::enableTexture(S32 stage) void LLCubeMap::enableTextureCoords(S32 stage) { mTextureCoordStage = stage; - if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps) + if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps) { if (stage > 0) { @@ -237,7 +238,7 @@ void LLCubeMap::disableTexture(void) void LLCubeMap::disableTextureCoords(void) { - if (gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps) + if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps) { if (mTextureCoordStage > 0) { @@ -259,47 +260,47 @@ void LLCubeMap::setMatrix(S32 stage) if (mMatrixStage < 0) return; - if (stage > 0) + //if (stage > 0) { gGL.getTexUnit(stage)->activate(); } - LLVector3 x(LLVector3d(gGLModelView+0)); - LLVector3 y(LLVector3d(gGLModelView+4)); - LLVector3 z(LLVector3d(gGLModelView+8)); + LLVector3 x(gGLModelView+0); + LLVector3 y(gGLModelView+4); + LLVector3 z(gGLModelView+8); LLMatrix3 mat3; mat3.setRows(x,y,z); LLMatrix4 trans(mat3); trans.transpose(); - glMatrixMode(GL_TEXTURE); - glPushMatrix(); - glLoadMatrixf((F32 *)trans.mMatrix); - glMatrixMode(GL_MODELVIEW); + gGL.matrixMode(LLRender::MM_TEXTURE); + gGL.pushMatrix(); + gGL.loadMatrix((F32 *)trans.mMatrix); + gGL.matrixMode(LLRender::MM_MODELVIEW); - if (stage > 0) + /*if (stage > 0) { gGL.getTexUnit(0)->activate(); - } + }*/ } void LLCubeMap::restoreMatrix() { if (mMatrixStage < 0) return; - if (mMatrixStage > 0) + //if (mMatrixStage > 0) { gGL.getTexUnit(mMatrixStage)->activate(); } - glMatrixMode(GL_TEXTURE); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); + gGL.matrixMode(LLRender::MM_TEXTURE); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); - if (mMatrixStage > 0) + /*if (mMatrixStage > 0) { gGL.getTexUnit(0)->activate(); - } + }*/ } void LLCubeMap::setReflection (void) diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index 91c8a37022..66d4ad2d87 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -55,7 +55,10 @@ FT_Library gFTLibrary = NULL; //static void LLFontManager::initClass() { - gFontManagerp = new LLFontManager; + if (!gFontManagerp) + { + gFontManagerp = new LLFontManager; + } } //static @@ -136,7 +139,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v FT_Done_Face(mFTFace); mFTFace = NULL; } - + int error; error = FT_New_Face( gFTLibrary, diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 180ae4dfa6..607473d416 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -189,6 +189,9 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons origin.mV[VX] -= llround((F32)sCurOrigin.mX) - (sCurOrigin.mX); origin.mV[VY] -= llround((F32)sCurOrigin.mY) - (sCurOrigin.mY); + // Depth translation, so that floating text appears 'inworld' + // and is correclty occluded. + gGL.translatef(0.f,0.f,sCurOrigin.mZ); S32 chars_drawn = 0; S32 i; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index c224ab0e9b..946e602fee 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -48,6 +48,7 @@ #include "llstacktrace.h" #include "llglheaders.h" +#include "llglslshader.h" #ifdef _DEBUG //#define GL_STATE_VERIFY @@ -66,6 +67,36 @@ static const std::string HEADLESS_VERSION_STRING("1.0"); std::ofstream gFailLog; +#if GL_ARB_debug_output + +#ifndef APIENTRY +#define APIENTRY +#endif + +void APIENTRY gl_debug_callback(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + 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; +} +#endif + void ll_init_fail_log(std::string filename) { gFailLog.open(filename.c_str()); @@ -109,6 +140,11 @@ std::list<LLGLUpdate*> LLGLUpdate::sGLQ; #if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS // ATI prototypes + +#if LL_WINDOWS +PFNGLGETSTRINGIPROC glGetStringi = NULL; +#endif + // vertex blending prototypes PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB = NULL; PFNGLVERTEXBLENDARBPROC glVertexBlendARB = NULL; @@ -127,10 +163,28 @@ PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL; PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL; PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = NULL; -// GL_ARB_map_buffer_range -PFNGLMAPBUFFERRANGEPROC glMapBufferRange; -PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange; +//GL_ARB_vertex_array_object +PFNGLBINDVERTEXARRAYPROC glBindVertexArray = NULL; +PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = NULL; +PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = NULL; +PFNGLISVERTEXARRAYPROC glIsVertexArray = NULL; +// GL_ARB_map_buffer_range +PFNGLMAPBUFFERRANGEPROC glMapBufferRange = NULL; +PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange = NULL; + +// GL_ARB_sync +PFNGLFENCESYNCPROC glFenceSync = NULL; +PFNGLISSYNCPROC glIsSync = NULL; +PFNGLDELETESYNCPROC glDeleteSync = NULL; +PFNGLCLIENTWAITSYNCPROC glClientWaitSync = NULL; +PFNGLWAITSYNCPROC glWaitSync = NULL; +PFNGLGETINTEGER64VPROC glGetInteger64v = NULL; +PFNGLGETSYNCIVPROC glGetSynciv = NULL; + +// GL_APPLE_flush_buffer_range +PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE = NULL; +PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE = NULL; // vertex object prototypes PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI = NULL; @@ -184,10 +238,16 @@ PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = NULL; PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = NULL; //GL_ARB_texture_multisample -PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample; -PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; -PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; -PFNGLSAMPLEMASKIPROC glSampleMaski; +PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample = NULL; +PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL; +PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL; +PFNGLSAMPLEMASKIPROC glSampleMaski = NULL; + +//GL_ARB_debug_output +PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL; +PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL; +PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB = NULL; +PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB = NULL; // GL_EXT_blend_func_separate PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL; @@ -236,6 +296,10 @@ PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB = NULL; PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL; PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL; +#if LL_WINDOWS +PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; +#endif + // vertex shader prototypes #if LL_LINUX || LL_SOLARIS PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB = NULL; @@ -334,9 +398,11 @@ LLGLManager::LLGLManager() : mHasFramebufferObject(FALSE), mMaxSamples(0), mHasBlendFuncSeparate(FALSE), - + mHasSync(FALSE), mHasVertexBufferObject(FALSE), + mHasVertexArrayObject(FALSE), mHasMapBufferRange(FALSE), + mHasFlushBufferRange(FALSE), mHasPBuffer(FALSE), mHasShaderObjects(FALSE), mHasVertexShader(FALSE), @@ -356,6 +422,7 @@ LLGLManager::LLGLManager() : mHasAnisotropic(FALSE), mHasARBEnvCombine(FALSE), mHasCubeMap(FALSE), + mHasDebugOutput(FALSE), mIsATI(FALSE), mIsNVIDIA(FALSE), @@ -395,6 +462,15 @@ void LLGLManager::initWGL() LL_WARNS("RenderInit") << "No ARB pixel format extensions" << LL_ENDL; } + if (ExtensionExists("WGL_ARB_create_context",gGLHExts.mSysExts)) + { + GLH_EXT_NAME(wglCreateContextAttribsARB) = (PFNWGLCREATECONTEXTATTRIBSARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreateContextAttribsARB"); + } + else + { + LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL; + } + if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts)) { GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT"); @@ -424,12 +500,44 @@ bool LLGLManager::initGL() LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL; } - GLint alpha_bits; - glGetIntegerv( GL_ALPHA_BITS, &alpha_bits ); - if( 8 != alpha_bits ) + stop_glerror(); + +#if LL_WINDOWS + if (!glGetStringi) + { + glGetStringi = (PFNGLGETSTRINGIPROC) GLH_EXT_GET_PROC_ADDRESS("glGetStringi"); + } + + //reload extensions string (may have changed after using wglCreateContextAttrib) + if (glGetStringi) { - LL_WARNS("RenderInit") << "Frame buffer has less than 8 bits of alpha. Avatar texture compositing will fail." << LL_ENDL; + std::stringstream str; + + GLint count = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &count); + for (GLint i = 0; i < count; ++i) + { + std::string ext((const char*) glGetStringi(GL_EXTENSIONS, i)); + str << ext << " "; + LL_DEBUGS("GLExtensions") << ext << llendl; + } + + { + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0; + wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); + if(wglGetExtensionsStringARB) + { + str << (const char*) wglGetExtensionsStringARB(wglGetCurrentDC()); + } + } + + free(gGLHExts.mSysExts); + std::string extensions = str.str(); + gGLHExts.mSysExts = strdup(extensions.c_str()); } +#endif + + stop_glerror(); // Extract video card strings and convert to upper case to // work around driver-to-driver variation in capitalization. @@ -445,7 +553,7 @@ bool LLGLManager::initGL() &mDriverVersionVendorString ); mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f; - + // Trailing space necessary to keep "nVidia Corpor_ati_on" cards // from being recognized as ATI. if (mGLVendor.substr(0,4) == "ATI ") @@ -517,8 +625,12 @@ bool LLGLManager::initGL() mGLVendorShort = "MISC"; } + stop_glerror(); // This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture. initExtensions(); + stop_glerror(); + + S32 old_vram = mVRAM; if (mHasATIMemInfo) { //ask the gl how much vram is free at startup and attempt to use no more than half of that @@ -534,7 +646,27 @@ bool LLGLManager::initGL() mVRAM = dedicated_memory/1024; } - if (mHasMultitexture) + if (mVRAM < 256) + { //something likely went wrong using the above extensions, fall back to old method + mVRAM = old_vram; + } + + stop_glerror(); + + stop_glerror(); + + if (mHasFragmentShader) + { + GLint num_tex_image_units; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units); + mNumTextureImageUnits = llmin(num_tex_image_units, 32); + } + + if (LLRender::sGLCoreProfile) + { + mNumTextureUnits = llmin(mNumTextureImageUnits, MAX_GL_TEXTURE_UNITS); + } + else if (mHasMultitexture) { GLint num_tex_units; glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &num_tex_units); @@ -553,12 +685,7 @@ bool LLGLManager::initGL() return false; } - if (mHasFragmentShader) - { - GLint num_tex_image_units; - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units); - mNumTextureImageUnits = llmin(num_tex_image_units, 32); - } + stop_glerror(); if (mHasTextureMultisample) { @@ -568,6 +695,21 @@ bool LLGLManager::initGL() glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords); } + stop_glerror(); + +#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); + glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + } +#endif + + stop_glerror(); + + //HACK always disable texture multisample, use FXAA instead + mHasTextureMultisample = FALSE; #if LL_WINDOWS if (mIsATI) { //using multisample textures on ATI results in black screen for some reason @@ -579,10 +721,17 @@ bool LLGLManager::initGL() { glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples); } + + stop_glerror(); setToDebugGPU(); + stop_glerror(); + initGLStates(); + + stop_glerror(); + return true; } @@ -686,14 +835,6 @@ std::string LLGLManager::getRawGLString() return gl_string; } -U32 LLGLManager::getNumFBOFSAASamples(U32 samples) -{ - samples = llmin(samples, (U32) mMaxColorTextureSamples); - samples = llmin(samples, (U32) mMaxDepthTextureSamples); - samples = llmin(samples, (U32) 4); - return samples; -} - void LLGLManager::shutdownGL() { if (mInited) @@ -760,7 +901,7 @@ void LLGLManager::initExtensions() mHasVertexShader = FALSE; mHasFragmentShader = FALSE; mHasTextureRectangle = FALSE; -#else // LL_MESA_HEADLESS +#else // LL_MESA_HEADLESS //important, gGLHExts.mSysExts is uninitialized until after glh_init_extensions is called mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); @@ -774,7 +915,10 @@ void LLGLManager::initExtensions() mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_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); // mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad #ifdef GL_ARB_framebuffer_object @@ -790,13 +934,14 @@ void LLGLManager::initExtensions() mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts); mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts); + mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts); #if !LL_DARWIN mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); #endif - mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts); + mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts)); mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts) - && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts); - mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts); + && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts)); + mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts)); #endif #if LL_LINUX || LL_SOLARIS @@ -969,6 +1114,23 @@ void LLGLManager::initExtensions() mHasVertexBufferObject = FALSE; } } + if (mHasVertexArrayObject) + { + glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) GLH_EXT_GET_PROC_ADDRESS("glBindVertexArray"); + glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteVertexArrays"); + glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenVertexArrays"); + glIsVertexArray = (PFNGLISVERTEXARRAYPROC) GLH_EXT_GET_PROC_ADDRESS("glIsVertexArray"); + } + if (mHasSync) + { + glFenceSync = (PFNGLFENCESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glFenceSync"); + glIsSync = (PFNGLISSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glIsSync"); + glDeleteSync = (PFNGLDELETESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteSync"); + glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glClientWaitSync"); + glWaitSync = (PFNGLWAITSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glWaitSync"); + glGetInteger64v = (PFNGLGETINTEGER64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInteger64v"); + glGetSynciv = (PFNGLGETSYNCIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetSynciv"); + } if (mHasMapBufferRange) { glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glMapBufferRange"); @@ -1013,6 +1175,13 @@ void LLGLManager::initExtensions() glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv"); glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski"); } + if (mHasDebugOutput) + { + glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB"); + glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageInsertARB"); + glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageCallbackARB"); + glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetDebugMessageLogARB"); + } #if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS // This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements"); @@ -1167,7 +1336,7 @@ void rotate_quat(LLQuaternion& rotation) { F32 angle_radians, x, y, z; rotation.getAngleAxis(&angle_radians, &x, &y, &z); - glRotatef(angle_radians * RAD_TO_DEG, x, y, z); + gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z); } void flush_glerror() @@ -1204,10 +1373,6 @@ void log_glerror() void do_assert_glerror() { - if (LL_UNLIKELY(!gGLManager.mInited)) - { - LL_ERRS("RenderInit") << "GL not initialized" << LL_ENDL; - } // Create or update texture to be used with this data GLenum error; error = glGetError(); @@ -1300,11 +1465,6 @@ void LLGLState::initClass() //make sure multisample defaults to disabled sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE; glDisable(GL_MULTISAMPLE_ARB); - - sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE; - glDisable(GL_MULTISAMPLE_ARB); - - glEnableClientState(GL_VERTEX_ARRAY); } //static @@ -1354,6 +1514,8 @@ void LLGLState::checkStates(const std::string& msg) glGetIntegerv(GL_BLEND_SRC, &src); glGetIntegerv(GL_BLEND_DST, &dst); + stop_glerror(); + BOOL error = FALSE; if (src != GL_SRC_ALPHA || dst != GL_ONE_MINUS_SRC_ALPHA) @@ -1374,7 +1536,9 @@ void LLGLState::checkStates(const std::string& msg) { LLGLenum state = iter->first; LLGLboolean cur_state = iter->second; + stop_glerror(); LLGLboolean gl_state = glIsEnabled(state); + stop_glerror(); if(cur_state != gl_state) { dumpStates(); @@ -1399,11 +1563,11 @@ void LLGLState::checkStates(const std::string& msg) void LLGLState::checkTextureChannels(const std::string& msg) { +#if 0 if (!gDebugGL) { return; } - stop_glerror(); GLint activeTexture; @@ -1569,11 +1733,12 @@ void LLGLState::checkTextureChannels(const std::string& msg) LL_GL_ERRS << "GL texture state corruption detected. " << msg << LL_ENDL; } } +#endif } void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) { - if (!gDebugGL) + if (!gDebugGL || LLGLSLShader::sNoFixedFunction) { return; } @@ -1594,7 +1759,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) error = TRUE; } - glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture); + /*glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture); if (active_texture != GL_TEXTURE0_ARB) { llwarns << "Active texture corrupted: " << active_texture << llendl; @@ -1603,7 +1768,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) gFailLog << "Active texture corrupted: " << active_texture << std::endl; } error = TRUE; - } + }*/ static const char* label[] = { @@ -1630,7 +1795,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) }; - for (S32 j = 0; j < 4; j++) + for (S32 j = 1; j < 4; j++) { if (glIsEnabled(value[j])) { @@ -1685,7 +1850,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) } } - if (glIsEnabled(GL_TEXTURE_2D)) + /*if (glIsEnabled(GL_TEXTURE_2D)) { if (!(data_mask & 0x0008)) { @@ -1708,7 +1873,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) gFailLog << "GL does not have GL_TEXTURE_2D enabled on channel 1." << std::endl; } } - } + }*/ glClientActiveTextureARB(GL_TEXTURE0_ARB); gGL.getTexUnit(0)->activate(); @@ -1751,8 +1916,27 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) LLGLState::LLGLState(LLGLenum state, S32 enabled) : mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE) { + if (LLGLSLShader::sNoFixedFunction) + { //always ignore state that's deprecated post GL 3.0 + switch (state) + { + case GL_ALPHA_TEST: + case GL_NORMALIZE: + case GL_TEXTURE_GEN_R: + case GL_TEXTURE_GEN_S: + case GL_TEXTURE_GEN_T: + case GL_TEXTURE_GEN_Q: + case GL_LIGHTING: + case GL_COLOR_MATERIAL: + case GL_FOG: + case GL_LINE_STIPPLE: + mState = 0; + break; + } + } + stop_glerror(); - if (state) + if (mState) { mWasEnabled = sStateMap[state]; llassert(mWasEnabled == glIsEnabled(state)); @@ -1834,79 +2018,6 @@ void LLGLManager::initGLStates() //////////////////////////////////////////////////////////////////////////////// -void enable_vertex_weighting(const S32 index) -{ -#if GL_ARB_vertex_program - if (index > 0) glEnableVertexAttribArrayARB(index); // vertex weights -#endif -} - -void disable_vertex_weighting(const S32 index) -{ -#if GL_ARB_vertex_program - if (index > 0) glDisableVertexAttribArrayARB(index); // vertex weights -#endif -} - -void enable_binormals(const S32 index) -{ -#if GL_ARB_vertex_program - if (index > 0) - { - glEnableVertexAttribArrayARB(index); // binormals - } -#endif -} - -void disable_binormals(const S32 index) -{ -#if GL_ARB_vertex_program - if (index > 0) - { - glDisableVertexAttribArrayARB(index); // binormals - } -#endif -} - - -void enable_cloth_weights(const S32 index) -{ -#if GL_ARB_vertex_program - if (index > 0) glEnableVertexAttribArrayARB(index); -#endif -} - -void disable_cloth_weights(const S32 index) -{ -#if GL_ARB_vertex_program - if (index > 0) glDisableVertexAttribArrayARB(index); -#endif -} - -void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights) -{ -#if GL_ARB_vertex_program - if (index > 0) glVertexAttribPointerARB(index, 1, GL_FLOAT, FALSE, stride, weights); - stop_glerror(); -#endif -} - -void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights) -{ -#if GL_ARB_vertex_program - if (index > 0) glVertexAttribPointerARB(index, 4, GL_FLOAT, TRUE, stride, weights); - stop_glerror(); -#endif -} - -void set_binormals(const S32 index, const U32 stride,const LLVector3 *binormals) -{ -#if GL_ARB_vertex_program - if (index > 0) glVertexAttribPointerARB(index, 3, GL_FLOAT, FALSE, stride, binormals); - stop_glerror(); -#endif -} - void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific ) { // GL_VERSION returns a null-terminated string with the format: @@ -2019,20 +2130,20 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d) glh::matrix4f suffix; suffix.set_row(2, cplane); glh::matrix4f newP = suffix * P; - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadMatrixf(newP.m); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadMatrix(newP.m); gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m); - glMatrixMode(GL_MODELVIEW); + gGL.matrixMode(LLRender::MM_MODELVIEW); } LLGLUserClipPlane::~LLGLUserClipPlane() { if (mApply) { - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); } } @@ -2110,8 +2221,7 @@ void LLGLNamePool::release(GLuint name) void LLGLNamePool::upkeepPools() { LLMemType mt(LLMemType::MTYPE_UPKEEP_POOLS); - tracker_t::LLInstanceTrackerScopedGuard guard; - for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter) + for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter) { LLGLNamePool & pool = *iter; pool.upkeep(); @@ -2121,8 +2231,7 @@ void LLGLNamePool::upkeepPools() //static void LLGLNamePool::cleanupPools() { - tracker_t::LLInstanceTrackerScopedGuard guard; - for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter) + for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter) { LLGLNamePool & pool = *iter; pool.cleanup(); @@ -2224,16 +2333,16 @@ LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P, U32 layer) P.element(2, i) = P.element(3, i) * depth; } - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadMatrixf(P.m); - glMatrixMode(GL_MODELVIEW); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadMatrix(P.m); + gGL.matrixMode(LLRender::MM_MODELVIEW); } LLGLSquashToFarClip::~LLGLSquashToFarClip() { - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); } diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index d1bee00161..6a147b8e19 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -88,7 +88,10 @@ public: // ARB Extensions BOOL mHasVertexBufferObject; + BOOL mHasVertexArrayObject; + BOOL mHasSync; BOOL mHasMapBufferRange; + BOOL mHasFlushBufferRange; BOOL mHasPBuffer; BOOL mHasShaderObjects; BOOL mHasVertexShader; @@ -110,6 +113,7 @@ public: BOOL mHasAnisotropic; BOOL mHasARBEnvCombine; BOOL mHasCubeMap; + BOOL mHasDebugOutput; // Vendor-specific extensions BOOL mIsATI; @@ -146,7 +150,6 @@ public: void printGLInfoString(); void getGLInfo(LLSD& info); - U32 getNumFBOFSAASamples(U32 desired_samples = 32); // In ALL CAPS std::string mGLVendor; std::string mGLVendorShort; @@ -250,7 +253,7 @@ public: static void dumpStates(); static void checkStates(const std::string& msg = ""); static void checkTextureChannels(const std::string& msg = ""); - static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0x0001); + static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0); protected: static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap; @@ -417,15 +420,7 @@ extern LLMatrix4 gGLObliqueProjectionInverse; #include "llglstates.h" void init_glstates(); -void enable_vertex_weighting(const S32 index); -void disable_vertex_weighting(const S32 index); -void enable_binormals(const S32 index); -void disable_binormals(const S32 index); -void enable_cloth_weights(const S32 index); -void disable_cloth_weights(const S32 index); -void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights); -void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights); -void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals); + void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific ); extern BOOL gClothRipple; diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index f35f329f00..10aad202e1 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -68,6 +68,25 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; +// GL_ARB_vertex_array_object +extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; +extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; +extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; +extern PFNGLISVERTEXARRAYPROC glIsVertexArray; + +// GL_ARB_sync +extern PFNGLFENCESYNCPROC glFenceSync; +extern PFNGLISSYNCPROC glIsSync; +extern PFNGLDELETESYNCPROC glDeleteSync; +extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync; +extern PFNGLWAITSYNCPROC glWaitSync; +extern PFNGLGETINTEGER64VPROC glGetInteger64v; +extern PFNGLGETSYNCIVPROC glGetSynciv; + +// GL_APPLE_flush_buffer_range +extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE; +extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE; + // GL_ARB_map_buffer_range extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange; extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange; @@ -297,6 +316,12 @@ extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB; extern PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements; #endif // LL_LINUX_NV_GL_HEADERS +// GL_ARB_vertex_array_object +extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; +extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; +extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; +extern PFNGLISVERTEXARRAYPROC glIsVertexArray; + // GL_ARB_vertex_buffer_object extern PFNGLBINDBUFFERARBPROC glBindBufferARB; extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; @@ -310,6 +335,19 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; +// GL_ARB_sync +extern PFNGLFENCESYNCPROC glFenceSync; +extern PFNGLISSYNCPROC glIsSync; +extern PFNGLDELETESYNCPROC glDeleteSync; +extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync; +extern PFNGLWAITSYNCPROC glWaitSync; +extern PFNGLGETINTEGER64VPROC glGetInteger64v; +extern PFNGLGETSYNCIVPROC glGetSynciv; + +// GL_APPLE_flush_buffer_range +extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE; +extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE; + // GL_ARB_map_buffer_range extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange; extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange; @@ -505,6 +543,9 @@ extern PFNGLSAMPLEMASKIPROC glSampleMaski; #include "GL/glext.h" #include "GL/glh_extensions.h" +// WGL_ARB_create_context +extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; +extern PFNGLGETSTRINGIPROC glGetStringi; // GL_ARB_vertex_buffer_object extern PFNGLBINDBUFFERARBPROC glBindBufferARB; @@ -519,6 +560,25 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; +// GL_ARB_vertex_array_object +extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; +extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; +extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; +extern PFNGLISVERTEXARRAYPROC glIsVertexArray; + +// GL_ARB_sync +extern PFNGLFENCESYNCPROC glFenceSync; +extern PFNGLISSYNCPROC glIsSync; +extern PFNGLDELETESYNCPROC glDeleteSync; +extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync; +extern PFNGLWAITSYNCPROC glWaitSync; +extern PFNGLGETINTEGER64VPROC glGetInteger64v; +extern PFNGLGETSYNCIVPROC glGetSynciv; + +// GL_APPLE_flush_buffer_range +extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE; +extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE; + // GL_ARB_map_buffer_range extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange; extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange; @@ -696,6 +756,12 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; extern PFNGLSAMPLEMASKIPROC glSampleMaski; +//GL_ARB_debug_output +extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB; +extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB; +extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB; +extern PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB; + #elif LL_DARWIN //---------------------------------------------------------------------------- // LL_DARWIN @@ -860,6 +926,31 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *); #endif /* GL_GLEXT_FUNCTION_POINTERS */ #endif +#ifndef GL_ARB_texture_rg +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#endif + // May be needed for DARWIN... // #ifndef GL_ARB_compressed_tex_image // #define GL_ARB_compressed_tex_image 1 diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index ad2c662dfc..5a6f3d8292 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -31,6 +31,7 @@ #include "llshadermgr.h" #include "llfile.h" #include "llrender.h" +#include "llvertexbuffer.h" #if LL_DARWIN #include "OpenGL/OpenGL.h" @@ -49,6 +50,13 @@ using std::make_pair; using std::string; GLhandleARB LLGLSLShader::sCurBoundShader = 0; +LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL; +S32 LLGLSLShader::sIndexedTextureChannels = 0; +bool LLGLSLShader::sNoFixedFunction = false; + +//UI shader -- declared here so llui_libtest will link properly +LLGLSLShader gUIProgram; +LLGLSLShader gSolidColorProgram; BOOL shouldChange(const LLVector4& v1, const LLVector4& v2) { @@ -58,7 +66,8 @@ BOOL shouldChange(const LLVector4& v1, const LLVector4& v2) LLShaderFeatures::LLShaderFeatures() : calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false), hasTransport(false), hasSkinning(false), hasObjectSkinning(false), hasAtmospherics(false), isSpecular(false), -hasGamma(false), hasLighting(false), calculatesAtmospherics(false), mIndexedTextureChannels(0), disableTextureIndex(false) +hasGamma(false), hasLighting(false), calculatesAtmospherics(false), mIndexedTextureChannels(0), disableTextureIndex(false), +hasAlphaMask(false) { } @@ -68,6 +77,7 @@ hasGamma(false), hasLighting(false), calculatesAtmospherics(false), mIndexedText LLGLSLShader::LLGLSLShader() : mProgramObject(0), mActiveTextureChannels(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT), mUniformsDirty(FALSE) { + } void LLGLSLShader::unload() @@ -103,17 +113,19 @@ void LLGLSLShader::unload() BOOL LLGLSLShader::createShader(vector<string> * attributes, vector<string> * uniforms) { + //reloading, reset matrix hash values + for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i) + { + mMatHash[i] = 0xFFFFFFFF; + } + mLightHash = 0xFFFFFFFF; + llassert_always(!mShaderFiles.empty()); BOOL success = TRUE; // Create program mProgramObject = glCreateProgramObjectARB(); - if (gGLManager.mGLVersion < 3.1f) - { //force indexed texture channels to 1 if GL version is old (performance improvement for drivers with poor branching shader model support) - mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1); - } - //compile new source vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin(); for ( ; fileIter != mShaderFiles.end(); fileIter++ ) @@ -228,6 +240,13 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count) BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes) { + //before linking, make sure reserved attributes always have consistent locations + for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++) + { + const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str(); + glBindAttribLocationARB(mProgramObject, i, (const GLcharARB *) name); + } + //link the program BOOL res = link(); @@ -301,7 +320,7 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms) for (S32 i = 0; i < (S32) LLShaderMgr::instance()->mReservedUniforms.size(); i++) { if ( (mUniform[i] == -1) - && (LLShaderMgr::instance()->mReservedUniforms[i].compare(0, length, name, LLShaderMgr::instance()->mReservedUniforms[i].length()) == 0)) + && (LLShaderMgr::instance()->mReservedUniforms[i] == name)) { //found it mUniform[i] = location; @@ -315,7 +334,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].compare(0, length, name, (*uniforms)[i].length()) == 0)) + && ((*uniforms)[i] == name)) { //found it mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] = location; @@ -376,10 +395,13 @@ BOOL LLGLSLShader::link(BOOL suppress_errors) void LLGLSLShader::bind() { + gGL.flush(); if (gGLManager.mHasShaderObjects) { + LLVertexBuffer::unbind(); glUseProgramObjectARB(mProgramObject); sCurBoundShader = mProgramObject; + sCurBoundShaderPtr = this; if (mUniformsDirty) { LLShaderMgr::instance()->updateShaderUniforms(this); @@ -390,6 +412,7 @@ void LLGLSLShader::bind() void LLGLSLShader::unbind() { + gGL.flush(); if (gGLManager.mHasShaderObjects) { stop_glerror(); @@ -401,16 +424,23 @@ void LLGLSLShader::unbind() stop_glerror(); } } + LLVertexBuffer::unbind(); glUseProgramObjectARB(0); sCurBoundShader = 0; + sCurBoundShaderPtr = NULL; stop_glerror(); } } void LLGLSLShader::bindNoShader(void) { - glUseProgramObjectARB(0); - sCurBoundShader = 0; + LLVertexBuffer::unbind(); + if (gGLManager.mHasShaderObjects) + { + glUseProgramObjectARB(0); + sCurBoundShader = 0; + sCurBoundShaderPtr = NULL; + } } S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode) @@ -756,13 +786,17 @@ GLint LLGLSLShader::getUniformLocation(const string& uniform) } } - /*if (gDebugGL) + return ret; +} + +GLint LLGLSLShader::getUniformLocation(U32 index) +{ + GLint ret = -1; + if (mProgramObject > 0) { - if (ret == -1 && ret != glGetUniformLocationARB(mProgramObject, uniform.c_str())) - { - llerrs << "Uniform map invalid." << llendl; - } - }*/ + llassert(index < mUniform.size()); + return mUniform[index]; + } return ret; } @@ -918,7 +952,9 @@ void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v std::map<GLint, LLVector4>::iterator iter = mValue.find(location); if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) { + stop_glerror(); glUniform4fvARB(location, count, v); + stop_glerror(); mValue[location] = vec; } } @@ -972,3 +1008,9 @@ void LLGLSLShader::vertexAttrib4fv(U32 index, GLfloat* v) glVertexAttrib4fvARB(mAttribute[index], v); } } + +void LLGLSLShader::setMinimumAlpha(F32 minimum) +{ + gGL.flush(); + uniform1f(LLShaderMgr::MINIMUM_ALPHA, minimum); +} diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 4922eb6d67..2a6c050eac 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -47,6 +47,7 @@ public: bool hasGamma; S32 mIndexedTextureChannels; bool disableTextureIndex; + bool hasAlphaMask; // char numLights; @@ -67,6 +68,9 @@ public: LLGLSLShader(); static GLhandleARB sCurBoundShader; + static LLGLSLShader* sCurBoundShaderPtr; + static S32 sIndexedTextureChannels; + static bool sNoFixedFunction; void unload(); BOOL createShader(std::vector<std::string> * attributes, @@ -104,14 +108,17 @@ public: 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 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(U32 index); + GLint getAttribLocation(U32 attrib); GLint mapUniformTextureChannel(GLint location, GLenum type); - //enable/disable texture channel for specified uniform //if given texture uniform is active in the shader, //the corresponding channel will be active upon return @@ -126,6 +133,9 @@ public: // Unbinds any previously bound shader by explicitly binding no shader. static void bindNoShader(void); + U32 mMatHash[LLRender::NUM_MATRIX_MODES]; + U32 mLightHash; + GLhandleARB mProgramObject; std::vector<GLint> mAttribute; //lookup table of attribute enum to attribute channel std::vector<GLint> mUniform; //lookup table of uniform enum to uniform location @@ -141,4 +151,10 @@ public: std::string mName; }; +//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; + + #endif diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 60a5962234..78591ddd38 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -36,7 +36,9 @@ #include "llmath.h" #include "llgl.h" +#include "llglslshader.h" #include "llrender.h" + //---------------------------------------------------------------------------- const F32 MIN_TEXTURE_LIFETIME = 10.f; @@ -725,7 +727,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { if (mAutoGenMips) { - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE); + if (!gGLManager.mHasFramebufferObject) + { + glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE); + } stop_glerror(); { // LLFastTimer t2(FTM_TEMP4); @@ -754,6 +759,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) stop_glerror(); } } + + if (gGLManager.mHasFramebufferObject) + { + glGenerateMipmap(LLTexUnit::getInternalType(mBindTarget)); + } } else { @@ -875,6 +885,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image) { + //not compatible with core GL profile + llassert(!LLRender::sGLCoreProfile); + if (gGLManager.mIsDisabled) { llwarns << "Trying to create a texture while GL is disabled!" << llendl; @@ -901,29 +914,29 @@ BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image) { switch (mComponents) { - case 1: + case 1: // Use luminance alpha (for fonts) mFormatInternal = GL_LUMINANCE8; mFormatPrimary = GL_LUMINANCE; mFormatType = GL_UNSIGNED_BYTE; break; - case 2: + case 2: // Use luminance alpha (for fonts) mFormatInternal = GL_LUMINANCE8_ALPHA8; mFormatPrimary = GL_LUMINANCE_ALPHA; mFormatType = GL_UNSIGNED_BYTE; break; - case 3: + case 3: mFormatInternal = GL_RGB8; mFormatPrimary = GL_RGB; mFormatType = GL_UNSIGNED_BYTE; break; - case 4: + case 4: mFormatInternal = GL_RGBA8; mFormatPrimary = GL_RGBA; mFormatType = GL_UNSIGNED_BYTE; break; - default: + default: llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl; } } @@ -1099,8 +1112,75 @@ void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate) // static void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels) { - glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels); + bool use_scratch = false; + U32* scratch = NULL; + if (LLRender::sGLCoreProfile) + { + if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) + { //GL_ALPHA is deprecated, convert to RGBA + use_scratch = true; + scratch = new U32[width*height]; + + U32 pixel_count = (U32) (width*height); + for (U32 i = 0; i < pixel_count; i++) + { + U8* pix = (U8*) &scratch[i]; + pix[0] = pix[1] = pix[2] = 0; + pix[3] = ((U8*) pixels)[i]; + } + + pixformat = GL_RGBA; + intformat = GL_RGBA8; + } + + if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) + { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA + use_scratch = true; + scratch = new U32[width*height]; + + U32 pixel_count = (U32) (width*height); + for (U32 i = 0; i < pixel_count; i++) + { + U8 lum = ((U8*) pixels)[i*2+0]; + U8 alpha = ((U8*) pixels)[i*2+1]; + + U8* pix = (U8*) &scratch[i]; + pix[0] = pix[1] = pix[2] = lum; + pix[3] = alpha; + } + + pixformat = GL_RGBA; + intformat = GL_RGBA8; + } + + if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) + { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB + use_scratch = true; + scratch = new U32[width*height]; + + U32 pixel_count = (U32) (width*height); + for (U32 i = 0; i < pixel_count; i++) + { + U8 lum = ((U8*) pixels)[i]; + + U8* pix = (U8*) &scratch[i]; + pix[0] = pix[1] = pix[2] = lum; + pix[3] = 255; + } + + pixformat = GL_RGBA; + intformat = GL_RGB8; + } + } + + stop_glerror(); + glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); stop_glerror(); + + if (use_scratch) + { + delete [] scratch; + } } //create an empty GL texture: just create a texture name @@ -1167,29 +1247,29 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S { switch (mComponents) { - case 1: + case 1: // Use luminance alpha (for fonts) mFormatInternal = GL_LUMINANCE8; mFormatPrimary = GL_LUMINANCE; mFormatType = GL_UNSIGNED_BYTE; break; - case 2: + case 2: // Use luminance alpha (for fonts) mFormatInternal = GL_LUMINANCE8_ALPHA8; mFormatPrimary = GL_LUMINANCE_ALPHA; mFormatType = GL_UNSIGNED_BYTE; break; - case 3: + case 3: mFormatInternal = GL_RGB8; mFormatPrimary = GL_RGB; mFormatType = GL_UNSIGNED_BYTE; break; - case 4: + case 4: mFormatInternal = GL_RGBA8; mFormatPrimary = GL_RGBA; mFormatType = GL_UNSIGNED_BYTE; break; - default: + default: llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl; } @@ -1212,6 +1292,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) { llassert(data_in); + stop_glerror(); if (discard_level < 0) { @@ -1240,8 +1321,11 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ stop_glerror(); { llverify(gGL.getTexUnit(0)->bind(this)); + stop_glerror(); glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0); + stop_glerror(); glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel-discard_level); + stop_glerror(); } } if (!mTexName) @@ -1414,6 +1498,8 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre void LLImageGL::deleteDeadTextures() { + bool reset = false; + while (!sDeadTextureList.empty()) { GLuint tex = sDeadTextureList.front(); @@ -1422,16 +1508,26 @@ void LLImageGL::deleteDeadTextures() { LLTexUnit* tex_unit = gGL.getTexUnit(i); - if (tex_unit->getCurrTexture() == tex) + if (tex_unit && tex_unit->getCurrTexture() == tex) { tex_unit->unbind(tex_unit->getCurrType()); stop_glerror(); + + if (i > 0) + { + reset = true; + } } } glDeleteTextures(1, &tex); stop_glerror(); } + + if (reset) + { + gGL.getTexUnit(0)->activate(); + } } void LLImageGL::destroyGLTexture() @@ -1742,7 +1838,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) // this to be an intentional effect and don't treat as a mask. U32 midrangetotal = 0; - for (U32 i = 4; i < 11; i++) + for (U32 i = 2; i < 13; i++) { midrangetotal += sample[i]; } @@ -1757,7 +1853,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) upperhalftotal += sample[i]; } - if (midrangetotal > length/16 || // lots of midrange, or + if (midrangetotal > length/48 || // lots of midrange, or (lowerhalftotal == length && alphatotal != 0) || // all close to transparent but not all totally transparent, or (upperhalftotal == length && alphatotal != 255*length)) // all close to opaque but not all totally opaque { @@ -1875,6 +1971,7 @@ BOOL LLImageGL::getMask(const LLVector2 &tc) void LLImageGL::setCategory(S32 category) { +#if 0 //turn this off temporarily because it is not in use now. if(!gAuditTexture) { return ; @@ -1895,6 +1992,7 @@ void LLImageGL::setCategory(S32 category) mCategory = -1 ; } } +#endif } //for debug use diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp index d76b2d9004..c0045c8044 100644 --- a/indra/llrender/llpostprocess.cpp +++ b/indra/llrender/llpostprocess.cpp @@ -466,21 +466,21 @@ void LLPostProcess::drawOrthoQuad(unsigned int width, unsigned int height, QuadT void LLPostProcess::viewOrthogonal(unsigned int width, unsigned int height) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f ); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.ortho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f ); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); } void LLPostProcess::viewPerspective(void) { - glMatrixMode( GL_PROJECTION ); - glPopMatrix(); - glMatrixMode( GL_MODELVIEW ); - glPopMatrix(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); } void LLPostProcess::changeOrthogonal(unsigned int width, unsigned int height) diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 1d82dda30f..812fa7024b 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -1,4 +1,4 @@ -/** + /** * @file llrender.cpp * @brief LLRender implementation * @@ -34,18 +34,21 @@ #include "llimagegl.h" #include "llrendertarget.h" #include "lltexture.h" +#include "llshadermgr.h" LLRender gGL; // Handy copies of last good GL matrices -F64 gGLModelView[16]; -F64 gGLLastModelView[16]; -F64 gGLLastProjection[16]; -F64 gGLProjection[16]; +F32 gGLModelView[16]; +F32 gGLLastModelView[16]; +F32 gGLLastProjection[16]; +F32 gGLProjection[16]; S32 gGLViewport[4]; U32 LLRender::sUICalls = 0; U32 LLRender::sUIVerts = 0; +U32 LLTexUnit::sWhiteTexture = 0; +bool LLRender::sGLCoreProfile = false; static const U32 LL_NUM_TEXTURE_LAYERS = 32; static const U32 LL_NUM_LIGHT_UNITS = 8; @@ -126,7 +129,8 @@ void LLTexUnit::refreshState(void) // Per apple spec, don't call glEnable/glDisable when index exceeds max texture units // http://www.mailinglistarchive.com/html/mac-opengl@lists.apple.com/2008-07/msg00653.html // - bool enableDisable = (mIndex < gGLManager.mNumTextureUnits) && mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE; + bool enableDisable = !LLGLSLShader::sNoFixedFunction && + (mIndex < gGLManager.mNumTextureUnits) && mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE; if (mCurrTexType != TT_NONE) { @@ -176,18 +180,24 @@ void LLTexUnit::enable(eTextureType type) if ( (mCurrTexType != type || gGL.mDirty) && (type != TT_NONE) ) { + stop_glerror(); activate(); + stop_glerror(); if (mCurrTexType != TT_NONE && !gGL.mDirty) { disable(); // Force a disable of a previous texture type if it's enabled. + stop_glerror(); } mCurrTexType = type; gGL.flush(); - if (type != LLTexUnit::TT_MULTISAMPLE_TEXTURE && + if (!LLGLSLShader::sNoFixedFunction && + type != LLTexUnit::TT_MULTISAMPLE_TEXTURE && mIndex < gGLManager.mNumTextureUnits) { + stop_glerror(); glEnable(sGLTextureType[type]); + stop_glerror(); } } } @@ -201,7 +211,8 @@ void LLTexUnit::disable(void) activate(); unbind(mCurrTexType); gGL.flush(); - if (mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE && + if (!LLGLSLShader::sNoFixedFunction && + mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE && mIndex < gGLManager.mNumTextureUnits) { glDisable(sGLTextureType[mCurrTexType]); @@ -282,26 +293,35 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) { return bind(LLImageGL::sDefaultGLTexture) ; } + stop_glerror(); return false ; } if ((mCurrTexture != texture->getTexName()) || forceBind) { gGL.flush(); + stop_glerror(); activate(); + stop_glerror(); enable(texture->getTarget()); + stop_glerror(); mCurrTexture = texture->getTexName(); glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture); + stop_glerror(); texture->updateBindStats(texture->mTextureMemory); mHasMipMaps = texture->mHasMipMaps; if (texture->mTexOptionsDirty) { + stop_glerror(); texture->mTexOptionsDirty = false; setTextureAddressMode(texture->mAddressMode); setTextureFilteringOption(texture->mFilterOption); + stop_glerror(); } } + stop_glerror(); + return true; } @@ -403,7 +423,14 @@ void LLTexUnit::unbind(eTextureType type) activate(); mCurrTexture = 0; - glBindTexture(sGLTextureType[type], 0); + if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE) + { + glBindTexture(sGLTextureType[type], sWhiteTexture); + } + else + { + glBindTexture(sGLTextureType[type], 0); + } stop_glerror(); } } @@ -474,6 +501,11 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio void LLTexUnit::setTextureBlendType(eTextureBlendType type) { + if (LLGLSLShader::sNoFixedFunction) + { //texture blend type means nothing when using shaders + return; + } + if (mIndex < 0) return; // Do nothing if it's already correctly set. @@ -594,6 +626,11 @@ GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha) void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha) { + if (LLGLSLShader::sNoFixedFunction) + { //register combiners do nothing when not using fixed function + return; + } + if (mIndex < 0) return; activate(); @@ -793,14 +830,16 @@ LLLightState::LLLightState(S32 index) mAmbient.set(0,0,0,1); mPosition.set(0,0,1,0); mSpotDirection.set(0,0,-1); - } void LLLightState::enable() { if (!mEnabled) { - glEnable(GL_LIGHT0+mIndex); + if (!LLGLSLShader::sNoFixedFunction) + { + glEnable(GL_LIGHT0+mIndex); + } mEnabled = true; } } @@ -809,7 +848,10 @@ void LLLightState::disable() { if (mEnabled) { - glDisable(GL_LIGHT0+mIndex); + if (!LLGLSLShader::sNoFixedFunction) + { + glDisable(GL_LIGHT0+mIndex); + } mEnabled = false; } } @@ -818,8 +860,12 @@ void LLLightState::setDiffuse(const LLColor4& diffuse) { if (mDiffuse != diffuse) { + ++gGL.mLightHash; mDiffuse = diffuse; - glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV); + if (!LLGLSLShader::sNoFixedFunction) + { + glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV); + } } } @@ -827,8 +873,12 @@ void LLLightState::setAmbient(const LLColor4& ambient) { if (mAmbient != ambient) { + ++gGL.mLightHash; mAmbient = ambient; - glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV); + if (!LLGLSLShader::sNoFixedFunction) + { + glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV); + } } } @@ -836,16 +886,34 @@ void LLLightState::setSpecular(const LLColor4& specular) { if (mSpecular != specular) { + ++gGL.mLightHash; mSpecular = specular; - glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV); + if (!LLGLSLShader::sNoFixedFunction) + { + glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV); + } } } void LLLightState::setPosition(const LLVector4& position) { //always set position because modelview matrix may have changed + ++gGL.mLightHash; mPosition = position; - glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV); + if (!LLGLSLShader::sNoFixedFunction) + { + glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV); + } + else + { //transform position by current modelview matrix + glh::vec4f pos(position.mV); + + const glh::matrix4f& mat = gGL.getModelviewMatrix(); + mat.mult_matrix_vec(pos); + + mPosition.set(pos.v); + } + } void LLLightState::setConstantAttenuation(const F32& atten) @@ -853,7 +921,11 @@ void LLLightState::setConstantAttenuation(const F32& atten) if (mConstantAtten != atten) { mConstantAtten = atten; - glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten); + ++gGL.mLightHash; + if (!LLGLSLShader::sNoFixedFunction) + { + glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten); + } } } @@ -861,8 +933,12 @@ void LLLightState::setLinearAttenuation(const F32& atten) { if (mLinearAtten != atten) { + ++gGL.mLightHash; mLinearAtten = atten; - glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten); + if (!LLGLSLShader::sNoFixedFunction) + { + glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten); + } } } @@ -870,8 +946,12 @@ void LLLightState::setQuadraticAttenuation(const F32& atten) { if (mQuadraticAtten != atten) { + ++gGL.mLightHash; mQuadraticAtten = atten; - glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten); + if (!LLGLSLShader::sNoFixedFunction) + { + glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten); + } } } @@ -879,8 +959,12 @@ void LLLightState::setSpotExponent(const F32& exponent) { if (mSpotExponent != exponent) { + ++gGL.mLightHash; mSpotExponent = exponent; - glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent); + if (!LLGLSLShader::sNoFixedFunction) + { + glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent); + } } } @@ -888,31 +972,43 @@ void LLLightState::setSpotCutoff(const F32& cutoff) { if (mSpotCutoff != cutoff) { + ++gGL.mLightHash; mSpotCutoff = cutoff; - glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff); + if (!LLGLSLShader::sNoFixedFunction) + { + glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff); + } } } void LLLightState::setSpotDirection(const LLVector3& direction) { //always set direction because modelview matrix may have changed + ++gGL.mLightHash; mSpotDirection = direction; - glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV); + if (!LLGLSLShader::sNoFixedFunction) + { + glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV); + } + else + { //transform direction by current modelview matrix + glh::vec3f dir(direction.mV); + + const glh::matrix4f& mat = gGL.getModelviewMatrix(); + mat.mult_matrix_dir(dir); + + mSpotDirection.set(direction); + } } LLRender::LLRender() : mDirty(false), mCount(0), + mQuadCycle(0), mMode(LLRender::TRIANGLES), mCurrTextureUnitIndex(0), mMaxAnisotropy(0.f) -{ - mBuffer = new LLVertexBuffer(immediate_mask, 0); - mBuffer->allocateBuffer(4096, 0, TRUE); - mBuffer->getVertexStrider(mVerticesp); - mBuffer->getTexCoord0Strider(mTexcoordsp); - mBuffer->getColorStrider(mColorsp); - +{ mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS); for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++) { @@ -936,6 +1032,17 @@ LLRender::LLRender() mCurrBlendAlphaSFactor = BF_UNDEF; mCurrBlendColorDFactor = BF_UNDEF; mCurrBlendAlphaDFactor = BF_UNDEF; + + mMatrixMode = LLRender::MM_MODELVIEW; + + for (U32 i = 0; i < NUM_MATRIX_MODES; ++i) + { + mMatIdx[i] = 0; + mMatHash[i] = 0; + mCurMatHash[i] = 0xFFFFFFFF; + } + + mLightHash = 0; } LLRender::~LLRender() @@ -943,6 +1050,18 @@ LLRender::~LLRender() shutdown(); } +void LLRender::init() +{ + llassert_always(mBuffer.isNull()) ; + stop_glerror(); + mBuffer = new LLVertexBuffer(immediate_mask, 0); + mBuffer->allocateBuffer(4096, 0, TRUE); + mBuffer->getVertexStrider(mVerticesp); + mBuffer->getTexCoord0Strider(mTexcoordsp); + mBuffer->getColorStrider(mColorsp); + stop_glerror(); +} + void LLRender::shutdown() { for (U32 i = 0; i < mTexUnits.size(); i++) @@ -958,6 +1077,7 @@ void LLRender::shutdown() delete mLightState[i]; } mLightState.clear(); + mBuffer = NULL ; } void LLRender::refreshState(void) @@ -980,28 +1100,348 @@ void LLRender::refreshState(void) mDirty = false; } +void LLRender::syncLightState() +{ + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + if (!shader) + { + return; + } + + if (shader->mLightHash != mLightHash) + { + shader->mLightHash = mLightHash; + + LLVector4 position[8]; + LLVector3 direction[8]; + LLVector3 attenuation[8]; + LLVector3 diffuse[8]; + + for (U32 i = 0; i < 8; i++) + { + LLLightState* light = mLightState[i]; + + position[i] = light->mPosition; + direction[i] = light->mSpotDirection; + attenuation[i].set(light->mLinearAtten, light->mQuadraticAtten, light->mSpecular.mV[3]); + diffuse[i].set(light->mDiffuse.mV); + } + + shader->uniform4fv(LLShaderMgr::LIGHT_POSITION, 8, position[0].mV); + shader->uniform3fv(LLShaderMgr::LIGHT_DIRECTION, 8, direction[0].mV); + shader->uniform3fv(LLShaderMgr::LIGHT_ATTENUATION, 8, attenuation[0].mV); + shader->uniform3fv(LLShaderMgr::LIGHT_DIFFUSE, 8, diffuse[0].mV); + shader->uniform4fv(LLShaderMgr::LIGHT_AMBIENT, 1, mAmbientLightColor.mV); + //HACK -- duplicate sunlight color for compatibility with drivers that can't deal with multiple shader objects referencing the same uniform + shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV); + } +} + +void LLRender::syncMatrices() +{ + stop_glerror(); + + U32 name[] = + { + LLShaderMgr::MODELVIEW_MATRIX, + LLShaderMgr::PROJECTION_MATRIX, + LLShaderMgr::TEXTURE_MATRIX0, + LLShaderMgr::TEXTURE_MATRIX1, + LLShaderMgr::TEXTURE_MATRIX2, + LLShaderMgr::TEXTURE_MATRIX3, + }; + + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + static glh::matrix4f cached_mvp; + static U32 cached_mvp_mdv_hash = 0xFFFFFFFF; + static U32 cached_mvp_proj_hash = 0xFFFFFFFF; + + static glh::matrix4f cached_normal; + static U32 cached_normal_hash = 0xFFFFFFFF; + + if (shader) + { + llassert(shader); + + bool mvp_done = false; + + U32 i = MM_MODELVIEW; + if (mMatHash[i] != shader->mMatHash[i]) + { //update modelview, normal, and MVP + glh::matrix4f& mat = mMatrix[i][mMatIdx[i]]; + + shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m); + shader->mMatHash[i] = mMatHash[i]; + + //update normal matrix + S32 loc = shader->getUniformLocation(LLShaderMgr::NORMAL_MATRIX); + if (loc > -1) + { + if (cached_normal_hash != mMatHash[i]) + { + cached_normal = mat.inverse().transpose(); + cached_normal_hash = mMatHash[i]; + } + + glh::matrix4f& norm = cached_normal; + + F32 norm_mat[] = + { + norm.m[0], norm.m[1], norm.m[2], + norm.m[4], norm.m[5], norm.m[6], + norm.m[8], norm.m[9], norm.m[10] + }; + + shader->uniformMatrix3fv(LLShaderMgr::NORMAL_MATRIX, 1, GL_FALSE, norm_mat); + } + + //update MVP matrix + mvp_done = true; + loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX); + if (loc > -1) + { + U32 proj = MM_PROJECTION; + + if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION]) + { + cached_mvp = mat; + cached_mvp.mult_left(mMatrix[proj][mMatIdx[proj]]); + cached_mvp_mdv_hash = mMatHash[i]; + cached_mvp_proj_hash = mMatHash[MM_PROJECTION]; + } + + shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m); + } + } + + + i = MM_PROJECTION; + if (mMatHash[i] != shader->mMatHash[i]) + { //update projection matrix, normal, and MVP + glh::matrix4f& mat = mMatrix[i][mMatIdx[i]]; + + shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m); + shader->mMatHash[i] = mMatHash[i]; + + if (!mvp_done) + { + //update MVP matrix + S32 loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX); + if (loc > -1) + { + if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION]) + { + U32 mdv = MM_MODELVIEW; + cached_mvp = mat; + cached_mvp.mult_right(mMatrix[mdv][mMatIdx[mdv]]); + cached_mvp_mdv_hash = mMatHash[MM_MODELVIEW]; + cached_mvp_proj_hash = mMatHash[MM_PROJECTION]; + } + + shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m); + } + } + } + + for (i = MM_TEXTURE0; i < NUM_MATRIX_MODES; ++i) + { + if (mMatHash[i] != shader->mMatHash[i]) + { + shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mMatrix[i][mMatIdx[i]].m); + shader->mMatHash[i] = mMatHash[i]; + } + } + + + if (shader->mFeatures.hasLighting || shader->mFeatures.calculatesLighting) + { //also sync light state + syncLightState(); + } + } + else if (!LLGLSLShader::sNoFixedFunction) + { + GLenum mode[] = + { + GL_MODELVIEW, + GL_PROJECTION, + GL_TEXTURE, + GL_TEXTURE, + GL_TEXTURE, + GL_TEXTURE, + }; + + for (U32 i = 0; i < 2; ++i) + { + if (mMatHash[i] != mCurMatHash[i]) + { + glMatrixMode(mode[i]); + glLoadMatrixf(mMatrix[i][mMatIdx[i]].m); + mCurMatHash[i] = mMatHash[i]; + } + } + + for (U32 i = 2; i < NUM_MATRIX_MODES; ++i) + { + if (mMatHash[i] != mCurMatHash[i]) + { + gGL.getTexUnit(i-2)->activate(); + glMatrixMode(mode[i]); + glLoadMatrixf(mMatrix[i][mMatIdx[i]].m); + mCurMatHash[i] = mMatHash[i]; + } + } + } + + stop_glerror(); +} + void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z) { flush(); - glTranslatef(x,y,z); + + { + glh::matrix4f trans_mat(1,0,0,x, + 0,1,0,y, + 0,0,1,z, + 0,0,0,1); + + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(trans_mat); + mMatHash[mMatrixMode]++; + } } void LLRender::scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z) { flush(); - glScalef(x,y,z); + + { + glh::matrix4f scale_mat(x,0,0,0, + 0,y,0,0, + 0,0,z,0, + 0,0,0,1); + + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(scale_mat); + mMatHash[mMatrixMode]++; + } +} + +void LLRender::ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar) +{ + flush(); + + { + + glh::matrix4f ortho_mat(2.f/(right-left),0,0, -(right+left)/(right-left), + 0,2.f/(top-bottom),0, -(top+bottom)/(top-bottom), + 0,0,-2.f/(zFar-zNear), -(zFar+zNear)/(zFar-zNear), + 0,0,0,1); + + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(ortho_mat); + mMatHash[mMatrixMode]++; + } +} + +void LLRender::rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z) +{ + flush(); + + { + F32 r = a * DEG_TO_RAD; + + F32 c = cosf(r); + F32 s = sinf(r); + + F32 ic = 1.f-c; + + glh::matrix4f rot_mat(x*x*ic+c, x*y*ic-z*s, x*z*ic+y*s, 0, + x*y*ic+z*s, y*y*ic+c, y*z*ic-x*s, 0, + x*z*ic-y*s, y*z*ic+x*s, z*z*ic+c, 0, + 0,0,0,1); + + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(rot_mat); + mMatHash[mMatrixMode]++; + } } void LLRender::pushMatrix() { flush(); - glPushMatrix(); + + { + if (mMatIdx[mMatrixMode] < LL_MATRIX_STACK_DEPTH-1) + { + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]+1] = mMatrix[mMatrixMode][mMatIdx[mMatrixMode]]; + ++mMatIdx[mMatrixMode]; + } + else + { + llwarns << "Matrix stack overflow." << llendl; + } + } } void LLRender::popMatrix() { flush(); - glPopMatrix(); + { + if (mMatIdx[mMatrixMode] > 0) + { + --mMatIdx[mMatrixMode]; + mMatHash[mMatrixMode]++; + } + else + { + llwarns << "Matrix stack underflow." << llendl; + } + } +} + +void LLRender::loadMatrix(const GLfloat* m) +{ + flush(); + { + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].set_value((GLfloat*) m); + mMatHash[mMatrixMode]++; + } +} + +void LLRender::multMatrix(const GLfloat* m) +{ + flush(); + { + glh::matrix4f mat((GLfloat*) m); + + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(mat); + mMatHash[mMatrixMode]++; + } +} + +void LLRender::matrixMode(U32 mode) +{ + if (mode == MM_TEXTURE) + { + mode = MM_TEXTURE0 + gGL.getCurrentTexUnitIndex(); + } + + llassert(mode < NUM_MATRIX_MODES); + mMatrixMode = mode; +} + +void LLRender::loadIdentity() +{ + flush(); + + { + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].make_identity(); + mMatHash[mMatrixMode]++; + } +} + +const glh::matrix4f& LLRender::getModelviewMatrix() +{ + return mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]]; } void LLRender::translateUI(F32 x, F32 y, F32 z) @@ -1147,6 +1587,11 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value) { flush(); + if (LLGLSLShader::sNoFixedFunction) + { //glAlphaFunc is deprecated in OpenGL 3.3 + return; + } + if (mCurrAlphaFunc != func || mCurrAlphaFuncVal != value) { @@ -1161,6 +1606,30 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value) glAlphaFunc(sGLCompareFunc[func], value); } } + + if (gDebugGL) + { //make sure cached state is correct + GLint cur_func = 0; + glGetIntegerv(GL_ALPHA_TEST_FUNC, &cur_func); + + if (func == CF_DEFAULT) + { + func = CF_GREATER; + } + + if (cur_func != sGLCompareFunc[func]) + { + llerrs << "Alpha test function corrupted!" << llendl; + } + + F32 ref = 0.f; + glGetFloatv(GL_ALPHA_TEST_REF, &ref); + + if (ref != value) + { + llerrs << "Alpha test value corrupted!" << llendl; + } + } } void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor) @@ -1228,6 +1697,19 @@ LLLightState* LLRender::getLight(U32 index) return NULL; } +void LLRender::setAmbientLightColor(const LLColor4& color) +{ + if (color != mAmbientLightColor) + { + ++mLightHash; + mAmbientLightColor = color; + if (!LLGLSLShader::sNoFixedFunction) + { + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.mV); + } + } +} + bool LLRender::verifyTexUnitActive(U32 unitToVerify) { if (mCurrTextureUnitIndex == unitToVerify) @@ -1253,6 +1735,11 @@ void LLRender::begin(const GLuint& mode) { if (mode != mMode) { + if (mode == LLRender::QUADS) + { + mQuadCycle = 1; + } + if (mMode == LLRender::QUADS || mMode == LLRender::LINES || mMode == LLRender::TRIANGLES || @@ -1340,7 +1827,7 @@ void LLRender::flush() if (gDebugGL) { - if (mMode == LLRender::QUADS) + if (mMode == LLRender::QUADS && !sGLCoreProfile) { if (mCount%4 != 0) { @@ -1365,12 +1852,34 @@ void LLRender::flush() } } + //store mCount in a local variable to avoid re-entrance (drawArrays may call flush) + U32 count = mCount; + mCount = 0; + + if (mBuffer->useVBOs() && !mBuffer->isLocked()) + { //hack to only flush the part of the buffer that was updated (relies on stream draw using buffersubdata) + mBuffer->getVertexStrider(mVerticesp, 0, count); + mBuffer->getTexCoord0Strider(mTexcoordsp, 0, count); + mBuffer->getColorStrider(mColorsp, 0, count); + } + + mBuffer->flush(); mBuffer->setBuffer(immediate_mask); - mBuffer->drawArrays(mMode, 0, mCount); + + if (mMode == LLRender::QUADS && sGLCoreProfile) + { + mBuffer->drawArrays(LLRender::TRIANGLES, 0, count); + mQuadCycle = 1; + } + else + { + mBuffer->drawArrays(mMode, 0, count); + } + + mVerticesp[0] = mVerticesp[count]; + mTexcoordsp[0] = mTexcoordsp[count]; + mColorsp[0] = mColorsp[count]; - mVerticesp[0] = mVerticesp[mCount]; - mTexcoordsp[0] = mTexcoordsp[mCount]; - mColorsp[0] = mColorsp[mCount]; mCount = 0; } } @@ -1378,6 +1887,17 @@ void LLRender::flush() void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) { //the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095] + if (mCount > 2048) + { //break when buffer gets reasonably full to keep GL command buffers happy and avoid overflow below + switch (mMode) + { + case LLRender::POINTS: flush(); break; + case LLRender::TRIANGLES: if (mCount%3==0) flush(); break; + case LLRender::QUADS: if(mCount%4 == 0) flush(); break; + case LLRender::LINES: if (mCount%2 == 0) flush(); break; + } + } + if (mCount > 4094) { // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl; @@ -1394,10 +1914,29 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) mVerticesp[mCount] = vert; } + if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile) + { + mQuadCycle++; + if (mQuadCycle == 4) + { //copy two vertices so fourth quad element will add a triangle + mQuadCycle = 0; + + mCount++; + mVerticesp[mCount] = mVerticesp[mCount-3]; + mColorsp[mCount] = mColorsp[mCount-3]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-3]; + + mCount++; + mVerticesp[mCount] = mVerticesp[mCount-2]; + mColorsp[mCount] = mColorsp[mCount-2]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-2]; + } + } + mCount++; mVerticesp[mCount] = mVerticesp[mCount-1]; mColorsp[mCount] = mColorsp[mCount-1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; } void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count) @@ -1408,13 +1947,50 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count) return; } - for (S32 i = 0; i < vert_count; i++) + if (sGLCoreProfile && mMode == LLRender::QUADS) + { //quads are deprecated, convert to triangle list + S32 i = 0; + + while (i < vert_count) + { + //read first three + mVerticesp[mCount++] = verts[i++]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount++] = verts[i++]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount++] = verts[i++]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + //copy two + mVerticesp[mCount++] = verts[i-3]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount++] = verts[i-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + //copy last one + mVerticesp[mCount++] = verts[i++]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + } + } + else { - mVerticesp[mCount] = verts[i]; + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; - mCount++; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; + mCount++; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + } } mVerticesp[mCount] = mVerticesp[mCount-1]; @@ -1428,13 +2004,50 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 v return; } - for (S32 i = 0; i < vert_count; i++) + if (sGLCoreProfile && mMode == LLRender::QUADS) + { //quads are deprecated, convert to triangle list + S32 i = 0; + + while (i < vert_count) + { + //read first three + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount++] = uvs[i++]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount++] = uvs[i++]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount++] = uvs[i++]; + mColorsp[mCount] = mColorsp[mCount-1]; + + //copy last two + mVerticesp[mCount] = verts[i-3]; + mTexcoordsp[mCount++] = uvs[i-3]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount] = verts[i-1]; + mTexcoordsp[mCount++] = uvs[i-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + //copy last one + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount++] = uvs[i++]; + mColorsp[mCount] = mColorsp[mCount-1]; + } + } + else { - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; - mCount++; - mColorsp[mCount] = mColorsp[mCount-1]; + mCount++; + mColorsp[mCount] = mColorsp[mCount-1]; + } } mVerticesp[mCount] = mVerticesp[mCount-1]; @@ -1449,13 +2062,51 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLCol return; } - for (S32 i = 0; i < vert_count; i++) + + if (sGLCoreProfile && mMode == LLRender::QUADS) + { //quads are deprecated, convert to triangle list + S32 i = 0; + + while (i < vert_count) + { + //read first three + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount++] = colors[i++]; + + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount++] = colors[i++]; + + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount++] = colors[i++]; + + //copy last two + mVerticesp[mCount] = verts[i-3]; + mTexcoordsp[mCount] = uvs[i-3]; + mColorsp[mCount++] = colors[i-3]; + + mVerticesp[mCount] = verts[i-1]; + mTexcoordsp[mCount] = uvs[i-1]; + mColorsp[mCount++] = colors[i-1]; + + //copy last one + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount++] = colors[i++]; + } + } + else { - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - mColorsp[mCount] = colors[i]; + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount] = colors[i]; - mCount++; + mCount++; + } } mVerticesp[mCount] = mVerticesp[mCount-1]; @@ -1530,6 +2181,81 @@ void LLRender::color3fv(const GLfloat* c) color4f(c[0],c[1],c[2],1); } +void LLRender::diffuseColor3f(F32 r, F32 g, F32 b) +{ + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + + if (shader) + { + shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,1.f); + } + else + { + glColor3f(r,g,b); + } +} + +void LLRender::diffuseColor3fv(const F32* c) +{ + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + + if (shader) + { + shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0], c[1], c[2], 1.f); + } + else + { + glColor3fv(c); + } +} + +void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a) +{ + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + + if (shader) + { + shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,a); + } + else + { + glColor4f(r,g,b,a); + } +} + +void LLRender::diffuseColor4fv(const F32* c) +{ + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + + if (shader) + { + shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, c); + } + else + { + glColor4fv(c); + } +} + +void LLRender::diffuseColor4ubv(const U8* c) +{ + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + + if (shader) + { + shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f); + } + else + { + glColor4ubv(c); + } +} + 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 41e7b35341..7581b9f908 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -41,6 +41,8 @@ #include "llstrider.h" #include "llpointer.h" #include "llglheaders.h" +#include "llmatrix4a.h" +#include "glh/glh_linear.h" class LLVertexBuffer; class LLCubeMap; @@ -48,10 +50,14 @@ class LLImageGL; class LLRenderTarget; class LLTexture ; +#define LL_MATRIX_STACK_DEPTH 32 + class LLTexUnit { friend class LLRender; public: + static U32 sWhiteTexture; + typedef enum { TT_TEXTURE = 0, // Standard 2D Texture @@ -233,6 +239,8 @@ public: void setSpotDirection(const LLVector3& direction); protected: + friend class LLRender; + S32 mIndex; bool mEnabled; LLColor4 mDiffuse; @@ -306,8 +314,21 @@ public: BF_UNDEF } eBlendFactor; + typedef enum + { + MM_MODELVIEW = 0, + MM_PROJECTION, + MM_TEXTURE0, + MM_TEXTURE1, + MM_TEXTURE2, + MM_TEXTURE3, + NUM_MATRIX_MODES, + MM_TEXTURE + } eMatrixMode; + LLRender(); ~LLRender(); + void init() ; void shutdown(); // Refreshes renderer state to the cached values @@ -316,8 +337,20 @@ public: void translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z); void scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z); + void rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z); + void ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar); + void pushMatrix(); void popMatrix(); + void loadMatrix(const GLfloat* m); + void loadIdentity(); + void multMatrix(const GLfloat* m); + void matrixMode(U32 mode); + + const glh::matrix4f& getModelviewMatrix(); + + void syncMatrices(); + void syncLightState(); void translateUI(F32 x, F32 y, F32 z); void scaleUI(F32 x, F32 y, F32 z); @@ -348,6 +381,12 @@ public: void color3fv(const GLfloat* c); void color4ubv(const GLubyte* c); + void diffuseColor3f(F32 r, F32 g, F32 b); + void diffuseColor3fv(const F32* c); + void diffuseColor4f(F32 r, F32 g, F32 b, F32 a); + void diffuseColor4fv(const F32* c); + void diffuseColor4ubv(const U8* c); + void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count); void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count); void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count); @@ -365,7 +404,8 @@ public: eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor); LLLightState* getLight(U32 index); - + void setAmbientLightColor(const LLColor4& color); + LLTexUnit* getTexUnit(U32 index); U32 getCurrentTexUnitIndex(void) const { return mCurrTextureUnitIndex; } @@ -386,9 +426,21 @@ public: public: static U32 sUICalls; static U32 sUIVerts; + static bool sGLCoreProfile; private: - bool mDirty; + friend class LLLightState; + + U32 mMatrixMode; + U32 mMatIdx[NUM_MATRIX_MODES]; + U32 mMatHash[NUM_MATRIX_MODES]; + glh::matrix4f mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH]; + U32 mCurMatHash[NUM_MATRIX_MODES]; + U32 mLightHash; + LLColor4 mAmbientLightColor; + + bool mDirty; + U32 mQuadCycle; U32 mCount; U32 mMode; U32 mCurrTextureUnitIndex; @@ -416,10 +468,10 @@ private: }; -extern F64 gGLModelView[16]; -extern F64 gGLLastModelView[16]; -extern F64 gGLLastProjection[16]; -extern F64 gGLProjection[16]; +extern F32 gGLModelView[16]; +extern F32 gGLLastModelView[16]; +extern F32 gGLLastProjection[16]; +extern F32 gGLProjection[16]; extern S32 gGLViewport[4]; extern LLRender gGL; diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp index a5cd70445f..26bfe036e8 100644 --- a/indra/llrender/llrendersphere.cpp +++ b/indra/llrender/llrendersphere.cpp @@ -35,106 +35,12 @@ #include "llglheaders.h" -GLUquadricObj *gQuadObj2 = NULL; LLRenderSphere gSphere; -void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks); - -void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks) -{ - if (!gQuadObj2) - { - gQuadObj2 = gluNewQuadric(); - if (!gQuadObj2) - { - llwarns << "drawSolidSphere couldn't allocate quadric" << llendl; - return; - } - } - - gluQuadricDrawStyle(gQuadObj2, GLU_FILL); - gluQuadricNormals(gQuadObj2, GLU_SMOOTH); - // If we ever changed/used the texture or orientation state - // of quadObj, we'd need to change it to the defaults here - // with gluQuadricTexture and/or gluQuadricOrientation. - gluQuadricTexture(gQuadObj2, GL_TRUE); - gluSphere(gQuadObj2, radius, slices, stacks); -} - - -// A couple thoughts on sphere drawing: -// 1) You need more slices than stacks, but little less than 2:1 -// 2) At low LOD, setting stacks to an odd number avoids a "band" around the equator, making things look smoother -void LLRenderSphere::prerender() -{ - // Create a series of display lists for different LODs - mDList[0] = glGenLists(1); - glNewList(mDList[0], GL_COMPILE); - drawSolidSphere(1.0, 30, 20); - glEndList(); - - mDList[1] = glGenLists(1); - glNewList(mDList[1], GL_COMPILE); - drawSolidSphere(1.0, 20, 15); - glEndList(); - - mDList[2] = glGenLists(1); - glNewList(mDList[2], GL_COMPILE); - drawSolidSphere(1.0, 12, 8); - glEndList(); - - mDList[3] = glGenLists(1); - glNewList(mDList[3], GL_COMPILE); - drawSolidSphere(1.0, 8, 5); - glEndList(); -} - -void LLRenderSphere::cleanupGL() -{ - for (S32 detail = 0; detail < 4; detail++) - { - glDeleteLists(mDList[detail], 1); - mDList[detail] = 0; - } - - if (gQuadObj2) - { - gluDeleteQuadric(gQuadObj2); - gQuadObj2 = NULL; - } -} - -// Constants here are empirically derived from my eyeballs, JNC -// -// The toughest adjustment is the cutoff for the lowest LOD -// Maybe we should have more LODs at the low end? -void LLRenderSphere::render(F32 pixel_area) -{ - S32 level_of_detail; - - if (pixel_area > 10000.f) - { - level_of_detail = 0; - } - else if (pixel_area > 800.f) - { - level_of_detail = 1; - } - else if (pixel_area > 100.f) - { - level_of_detail = 2; - } - else - { - level_of_detail = 3; - } - glCallList(mDList[level_of_detail]); -} - - void LLRenderSphere::render() { - glCallList(mDList[0]); + renderGGL(); + gGL.flush(); } inline LLVector3 polar_to_cart(F32 latitude, F32 longitude) diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h index 96a6bec80c..f8e9e86e7f 100644 --- a/indra/llrender/llrendersphere.h +++ b/indra/llrender/llrendersphere.h @@ -40,11 +40,6 @@ void lat2xyz(LLVector3 * result, F32 lat, F32 lon); // utility routine class LLRenderSphere { public: - LLGLuint mDList[5]; - - void prerender(); - void cleanupGL(); - void render(F32 pixel_area); // of a box of size 1.0 at that position void render(); // render at highest LOD void renderGGL(); // render using LLRender diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index b6463309e1..1aa12614ea 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -31,8 +31,7 @@ #include "llgl.h" LLRenderTarget* LLRenderTarget::sBoundTarget = NULL; - - +U32 LLRenderTarget::sBytesAllocated = 0; void check_framebuffer_status() { @@ -62,8 +61,7 @@ LLRenderTarget::LLRenderTarget() : mStencil(0), mUseDepth(false), mRenderDepth(false), - mUsage(LLTexUnit::TT_TEXTURE), - mSamples(0) + mUsage(LLTexUnit::TT_TEXTURE) { } @@ -72,11 +70,11 @@ LLRenderTarget::~LLRenderTarget() release(); } -void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples) +bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples) { stop_glerror(); - release(); + stop_glerror(); mResX = resx; mResY = resy; @@ -84,28 +82,16 @@ void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo mStencil = stencil; mUsage = usage; mUseDepth = depth; - mSamples = samples; - - mSamples = gGLManager.getNumFBOFSAASamples(mSamples); - - if (mSamples > 1 && gGLManager.mHasTextureMultisample) - { - mUsage = LLTexUnit::TT_MULTISAMPLE_TEXTURE; - //no support for multisampled stencil targets yet - mStencil = false; - } - else - { - mSamples = 0; - } if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject) { if (depth) { - stop_glerror(); - allocateDepth(); - stop_glerror(); + if (!allocateDepth()) + { + llwarns << "Failed to allocate depth buffer for render target." << llendl; + return false; + } } glGenFramebuffers(1, (GLuint *) &mFBO); @@ -131,14 +117,14 @@ void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo stop_glerror(); } - addColorAttachment(color_fmt); + return addColorAttachment(color_fmt); } -void LLRenderTarget::addColorAttachment(U32 color_fmt) +bool LLRenderTarget::addColorAttachment(U32 color_fmt) { if (color_fmt == 0) { - return; + return true; } U32 offset = mTex.size(); @@ -155,45 +141,42 @@ void LLRenderTarget::addColorAttachment(U32 color_fmt) stop_glerror(); -#ifdef GL_ARB_texture_multisample - if (mSamples > 1) - { - glTexImage2DMultisample(LLTexUnit::getInternalType(mUsage), mSamples, color_fmt, mResX, mResY, GL_TRUE); - } - else -#else - llassert_always(mSamples <= 1); -#endif { + clear_glerror(); LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + if (glGetError() != GL_NO_ERROR) + { + llwarns << "Could not allocate color buffer for render target." << llendl; + return false; + } } + sBytesAllocated += mResX*mResY*4; + stop_glerror(); - if (mSamples == 0) - { - if (offset == 0) - { //use bilinear filtering on single texture render targets that aren't multisampled - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - stop_glerror(); - } - else - { //don't filter data attachments - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - stop_glerror(); - } + + if (offset == 0) + { //use bilinear filtering on single texture render targets that aren't multisampled + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + stop_glerror(); + } + else + { //don't filter data attachments + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + stop_glerror(); + } - if (mUsage != LLTexUnit::TT_RECT_TEXTURE) - { - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR); - stop_glerror(); - } - else - { - // ATI doesn't support mirrored repeat for rectangular textures. - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - stop_glerror(); - } + if (mUsage != LLTexUnit::TT_RECT_TEXTURE) + { + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR); + stop_glerror(); + } + else + { + // ATI doesn't support mirrored repeat for rectangular textures. + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + stop_glerror(); } if (mFBO) @@ -217,15 +200,18 @@ void LLRenderTarget::addColorAttachment(U32 color_fmt) flush(); } + return true; } -void LLRenderTarget::allocateDepth() +bool LLRenderTarget::allocateDepth() { if (mStencil) { //use render buffers where stencil buffers are in play glGenRenderbuffers(1, (GLuint *) &mDepth); glBindRenderbuffer(GL_RENDERBUFFER, mDepth); + stop_glerror(); + clear_glerror(); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY); glBindRenderbuffer(GL_RENDERBUFFER, 0); } @@ -233,21 +219,23 @@ void LLRenderTarget::allocateDepth() { LLImageGL::generateTextures(1, &mDepth); gGL.getTexUnit(0)->bindManual(mUsage, mDepth); - if (mSamples == 0) - { - U32 internal_type = LLTexUnit::getInternalType(mUsage); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - } -#ifdef GL_ARB_texture_multisample - else - { - glTexImage2DMultisample(LLTexUnit::getInternalType(mUsage), mSamples, GL_DEPTH_COMPONENT32, mResX, mResY, GL_TRUE); - } -#else - llassert_always(mSamples <= 1); -#endif + + U32 internal_type = LLTexUnit::getInternalType(mUsage); + stop_glerror(); + clear_glerror(); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } + + sBytesAllocated += mResX*mResY*4; + + if (glGetError() != GL_NO_ERROR) + { + llwarns << "Unable to allocate depth buffer for render target." << llendl; + return false; + } + + return true; } void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target) @@ -310,14 +298,16 @@ void LLRenderTarget::release() stop_glerror(); } mDepth = 0; + + sBytesAllocated -= mResX*mResY*4; } else if (mUseDepth && mFBO) { //detach shared depth buffer glBindFramebuffer(GL_FRAMEBUFFER, mFBO); if (mStencil) { //attached as a renderbuffer - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); mStencil = false; } else @@ -335,6 +325,7 @@ void LLRenderTarget::release() if (mTex.size() > 0) { + sBytesAllocated -= mResX*mResY*4*mTex.size(); LLImageGL::deleteTextures(mTex.size(), &mTex[0], true); mTex.clear(); } diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 094b58b562..2735ab21c5 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -64,32 +64,33 @@ class LLRenderTarget public: //whether or not to use FBO implementation static bool sUseFBO; + static U32 sBytesAllocated; LLRenderTarget(); - virtual ~LLRenderTarget(); + ~LLRenderTarget(); //allocate resources for rendering //must be called before use //multiple calls will release previously allocated resources - void allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = false, S32 samples = 0); + bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = false, S32 samples = 0); //add color buffer attachment //limit of 4 color attachments per render target - virtual void addColorAttachment(U32 color_fmt); + bool addColorAttachment(U32 color_fmt); //allocate a depth texture - virtual void allocateDepth(); + bool allocateDepth(); //share depth buffer with provided render target - virtual void shareDepthBuffer(LLRenderTarget& target); + void shareDepthBuffer(LLRenderTarget& target); //free any allocated resources //safe to call redundantly - virtual void release(); + void release(); //bind target for rendering //applies appropriate viewport - virtual void bindTarget(); + void bindTarget(); //unbind target for rendering static void unbindTarget(); @@ -147,7 +148,6 @@ protected: bool mUseDepth; bool mRenderDepth; LLTexUnit::eTextureType mUsage; - U32 mSamples; static LLRenderTarget* sBoundTarget; }; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 751b250d96..eea768a3ea 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -81,7 +81,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) // NOTE order of shader object attaching is VERY IMPORTANT!!! if (features->calculatesAtmospherics) { - if (!shader->attachObject("windlight/atmosphericsVarsV.glsl")) + if (features->hasWaterFog) + { + if (!shader->attachObject("windlight/atmosphericsVarsWaterV.glsl")) + { + return FALSE; + } + } + else if (!shader->attachObject("windlight/atmosphericsVarsV.glsl")) { return FALSE; } @@ -161,7 +168,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) if(features->calculatesAtmospherics) { - if (!shader->attachObject("windlight/atmosphericsVarsF.glsl")) + if (features->hasWaterFog) + { + if (!shader->attachObject("windlight/atmosphericsVarsWaterF.glsl")) + { + return FALSE; + } + } + else if (!shader->attachObject("windlight/atmosphericsVarsF.glsl")) { return FALSE; } @@ -206,23 +220,42 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) if (features->hasLighting) { - if (features->hasWaterFog) { if (features->disableTextureIndex) { - if (!shader->attachObject("lighting/lightWaterNonIndexedF.glsl")) + if (features->hasAlphaMask) { - return FALSE; + if (!shader->attachObject("lighting/lightWaterAlphaMaskNonIndexedF.glsl")) + { + return FALSE; + } + } + else + { + if (!shader->attachObject("lighting/lightWaterNonIndexedF.glsl")) + { + return FALSE; + } } } else { - if (!shader->attachObject("lighting/lightWaterF.glsl")) + if (features->hasAlphaMask) { - return FALSE; + if (!shader->attachObject("lighting/lightWaterAlphaMaskF.glsl")) + { + return FALSE; + } } - shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1; + else + { + if (!shader->attachObject("lighting/lightWaterF.glsl")) + { + return FALSE; + } + } + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } } @@ -230,18 +263,38 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->disableTextureIndex) { - if (!shader->attachObject("lighting/lightNonIndexedF.glsl")) + if (features->hasAlphaMask) { - return FALSE; + if (!shader->attachObject("lighting/lightAlphaMaskNonIndexedF.glsl")) + { + return FALSE; + } + } + else + { + if (!shader->attachObject("lighting/lightNonIndexedF.glsl")) + { + return FALSE; + } } } else { - if (!shader->attachObject("lighting/lightF.glsl")) + if (features->hasAlphaMask) { - return FALSE; + if (!shader->attachObject("lighting/lightAlphaMaskF.glsl")) + { + return FALSE; + } + } + else + { + if (!shader->attachObject("lighting/lightF.glsl")) + { + return FALSE; + } } - shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1; + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } } } @@ -265,25 +318,39 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { return FALSE; } - shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1; + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } } else if (features->hasWaterFog) { if (features->disableTextureIndex) { - if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedF.glsl")) + if (features->hasAlphaMask) + { + if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl")) + { + return FALSE; + } + } + else if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedF.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl")) + if (features->hasAlphaMask) + { + if (!shader->attachObject("lighting/lightFullbrightWaterAlphaMaskF.glsl")) + { + return FALSE; + } + } + else if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl")) { return FALSE; } - shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1; + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } } @@ -302,7 +369,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { return FALSE; } - shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1; + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } } @@ -310,18 +377,39 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->disableTextureIndex) { - if (!shader->attachObject("lighting/lightFullbrightNonIndexedF.glsl")) + + if (features->hasAlphaMask) { - return FALSE; + if (!shader->attachObject("lighting/lightFullbrightNonIndexedAlphaMaskF.glsl")) + { + return FALSE; + } + } + else + { + if (!shader->attachObject("lighting/lightFullbrightNonIndexedF.glsl")) + { + return FALSE; + } } } else { - if (!shader->attachObject("lighting/lightFullbrightF.glsl")) + if (features->hasAlphaMask) { - return FALSE; + if (!shader->attachObject("lighting/lightFullbrightAlphaMaskF.glsl")) + { + return FALSE; + } } - shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1; + else + { + if (!shader->attachObject("lighting/lightFullbrightF.glsl")) + { + return FALSE; + } + } + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } } } @@ -345,7 +433,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { return FALSE; } - shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1; + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } } @@ -364,10 +452,26 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { return FALSE; } - shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1; + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } } } + + if (features->mIndexedTextureChannels <= 1) + { + if (!shader->attachObject("objects/nonindexedTextureV.glsl")) + { + return FALSE; + } + } + else + { + if (!shader->attachObject("objects/indexedTextureV.glsl")) + { + return FALSE; + } + } + return TRUE; } @@ -403,10 +507,10 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns) } else { - LL_DEBUGS("ShaderLoading") << log << LL_ENDL; + LL_INFOS("ShaderLoading") << log << LL_ENDL; } } -} + } GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels) { @@ -457,23 +561,64 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade } //we can't have any lines longer than 1024 characters - //or any shaders longer than 1024 lines... deal - DaveP + //or any shaders longer than 4096 lines... deal - DaveP GLcharARB buff[1024]; - GLcharARB* text[1024]; + GLcharARB* text[4096]; GLuint count = 0; - if (gGLManager.mGLVersion < 2.1f) + F32 version = gGLManager.mGLVersion; + +//hack to never use GLSL > 1.20 on OSX +#if LL_DARWIN + version = llmin(version, 2.9f); +#endif + + if (version < 2.1f) { text[count++] = strdup("#version 110\n"); + text[count++] = strdup("#define ATTRIBUTE attribute\n"); + text[count++] = strdup("#define VARYING varying\n"); } - else if (gGLManager.mGLVersion < 3.f) + else if (version < 3.f) { //set version to 1.20 text[count++] = strdup("#version 120\n"); + text[count++] = strdup("#define FXAA_GLSL_120 1\n"); + text[count++] = strdup("#define FXAA_FAST_PIXEL_OFFSET 0\n"); + text[count++] = strdup("#define ATTRIBUTE attribute\n"); + text[count++] = strdup("#define VARYING varying\n"); } else - { //set version to 1.30 - text[count++] = strdup("#version 130\n"); + { + if (version < 4.f) + { + //set version to 1.30 + text[count++] = strdup("#version 130\n"); + } + else + { //set version to 400 + text[count++] = strdup("#version 400\n"); + } + + text[count++] = strdup("#define DEFINE_GL_FRAGCOLOR 1\n"); + text[count++] = strdup("#define FXAA_GLSL_130 1\n"); + + text[count++] = strdup("#define ATTRIBUTE in\n"); + + if (type == GL_VERTEX_SHADER_ARB) + { //"varying" state is "out" in a vertex program, "in" in a fragment program + // ("varying" is deprecated after version 1.20) + text[count++] = strdup("#define VARYING out\n"); + } + else + { + text[count++] = strdup("#define VARYING in\n"); + } + + //backwards compatibility with legacy texture lookup syntax + text[count++] = strdup("#define textureCube texture\n"); + text[count++] = strdup("#define texture2DLod textureLod\n"); + text[count++] = strdup("#define shadow2D(a,b) vec2(texture(a,b))\n"); } //copy preprocessor definitions into buffer @@ -497,7 +642,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade . uniform sampler2D texN; - varying float vary_texture_index; + VARYING float vary_texture_index; vec4 diffuseLookup(vec2 texcoord) { @@ -523,7 +668,11 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade text[count++] = strdup(decl.c_str()); } - text[count++] = strdup("varying float vary_texture_index;\n"); + if (texture_index_channels > 1) + { + text[count++] = strdup("VARYING float vary_texture_index;\n"); + } + text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n"); text[count++] = strdup("{\n"); @@ -546,7 +695,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade } text[count++] = strdup("\t}\n"); - text[count++] = strdup("\treturn vec4(0,0,0,0);\n"); + text[count++] = strdup("\treturn vec4(1,0,1,1);\n"); text[count++] = strdup("}\n"); } else @@ -569,13 +718,13 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade text[count++] = strdup(if_str.c_str()); } - text[count++] = strdup("\treturn vec4(0,0,0,0);\n"); + text[count++] = strdup("\treturn vec4(1,0,1,1);\n"); text[count++] = strdup("}\n"); } } //copy file into memory - while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(buff) ) + while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(text) ) { text[count++] = (GLcharARB *)strdup((char *)buff); } @@ -630,14 +779,24 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL; dumpObjectLog(ret); +#if LL_WINDOWS std::stringstream ostr; //dump shader source for debugging for (GLuint i = 0; i < count; i++) { ostr << i << ": " << text[i]; + + if (i % 128 == 0) + { //dump every 128 lines + + LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl; + ostr = std::stringstream(); + } + } LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl; +#endif // LL_WINDOWS ret = 0; } @@ -745,3 +904,181 @@ BOOL LLShaderMgr::validateProgramObject(GLhandleARB obj) return success; } +//virtual +void LLShaderMgr::initAttribsAndUniforms() +{ + //MUST match order of enum in LLVertexBuffer.h + mReservedAttribs.push_back("position"); + mReservedAttribs.push_back("normal"); + mReservedAttribs.push_back("texcoord0"); + mReservedAttribs.push_back("texcoord1"); + mReservedAttribs.push_back("texcoord2"); + mReservedAttribs.push_back("texcoord3"); + mReservedAttribs.push_back("diffuse_color"); + mReservedAttribs.push_back("emissive"); + mReservedAttribs.push_back("binormal"); + mReservedAttribs.push_back("weight"); + mReservedAttribs.push_back("weight4"); + mReservedAttribs.push_back("clothing"); + mReservedAttribs.push_back("texture_index"); + + //matrix state + mReservedUniforms.push_back("modelview_matrix"); + mReservedUniforms.push_back("projection_matrix"); + mReservedUniforms.push_back("inv_proj"); + mReservedUniforms.push_back("modelview_projection_matrix"); + mReservedUniforms.push_back("normal_matrix"); + mReservedUniforms.push_back("texture_matrix0"); + 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("viewport"); + + mReservedUniforms.push_back("light_position"); + mReservedUniforms.push_back("light_direction"); + mReservedUniforms.push_back("light_attenuation"); + mReservedUniforms.push_back("light_diffuse"); + mReservedUniforms.push_back("light_ambient"); + mReservedUniforms.push_back("light_count"); + mReservedUniforms.push_back("light"); + mReservedUniforms.push_back("light_col"); + mReservedUniforms.push_back("far_z"); + + llassert(mReservedUniforms.size() == LLShaderMgr::MULTI_LIGHT_FAR_Z+1); + + + mReservedUniforms.push_back("proj_mat"); + mReservedUniforms.push_back("proj_near"); + mReservedUniforms.push_back("proj_p"); + mReservedUniforms.push_back("proj_n"); + mReservedUniforms.push_back("proj_origin"); + mReservedUniforms.push_back("proj_range"); + mReservedUniforms.push_back("proj_ambiance"); + mReservedUniforms.push_back("proj_shadow_idx"); + mReservedUniforms.push_back("shadow_fade"); + mReservedUniforms.push_back("proj_focus"); + mReservedUniforms.push_back("proj_lod"); + mReservedUniforms.push_back("proj_ambient_lod"); + + llassert(mReservedUniforms.size() == LLShaderMgr::PROJECTOR_AMBIENT_LOD+1); + + mReservedUniforms.push_back("color"); + + mReservedUniforms.push_back("diffuseMap"); + mReservedUniforms.push_back("specularMap"); + mReservedUniforms.push_back("bumpMap"); + mReservedUniforms.push_back("environmentMap"); + mReservedUniforms.push_back("cloude_noise_texture"); + mReservedUniforms.push_back("fullbright"); + mReservedUniforms.push_back("lightnorm"); + mReservedUniforms.push_back("sunlight_color_copy"); + mReservedUniforms.push_back("ambient"); + mReservedUniforms.push_back("blue_horizon"); + mReservedUniforms.push_back("blue_density"); + mReservedUniforms.push_back("haze_horizon"); + mReservedUniforms.push_back("haze_density"); + mReservedUniforms.push_back("cloud_shadow"); + mReservedUniforms.push_back("density_multiplier"); + mReservedUniforms.push_back("distance_multiplier"); + mReservedUniforms.push_back("max_y"); + mReservedUniforms.push_back("glow"); + mReservedUniforms.push_back("cloud_color"); + mReservedUniforms.push_back("cloud_pos_density1"); + mReservedUniforms.push_back("cloud_pos_density2"); + mReservedUniforms.push_back("cloud_scale"); + mReservedUniforms.push_back("gamma"); + mReservedUniforms.push_back("scene_light_strength"); + + llassert(mReservedUniforms.size() == LLShaderMgr::SCENE_LIGHT_STRENGTH+1); + + mReservedUniforms.push_back("center"); + mReservedUniforms.push_back("size"); + mReservedUniforms.push_back("falloff"); + + + mReservedUniforms.push_back("minLuminance"); + mReservedUniforms.push_back("maxExtractAlpha"); + mReservedUniforms.push_back("lumWeights"); + mReservedUniforms.push_back("warmthWeights"); + mReservedUniforms.push_back("warmthAmount"); + mReservedUniforms.push_back("glowStrength"); + mReservedUniforms.push_back("glowDelta"); + + llassert(mReservedUniforms.size() == LLShaderMgr::GLOW_DELTA+1); + + + mReservedUniforms.push_back("minimum_alpha"); + + mReservedUniforms.push_back("shadow_matrix"); + mReservedUniforms.push_back("env_mat"); + mReservedUniforms.push_back("shadow_clip"); + mReservedUniforms.push_back("sun_wash"); + mReservedUniforms.push_back("shadow_noise"); + mReservedUniforms.push_back("blur_size"); + mReservedUniforms.push_back("ssao_radius"); + mReservedUniforms.push_back("ssao_max_radius"); + mReservedUniforms.push_back("ssao_factor"); + mReservedUniforms.push_back("ssao_factor_inv"); + mReservedUniforms.push_back("ssao_effect_mat"); + mReservedUniforms.push_back("screen_res"); + mReservedUniforms.push_back("near_clip"); + mReservedUniforms.push_back("shadow_offset"); + mReservedUniforms.push_back("shadow_bias"); + mReservedUniforms.push_back("spot_shadow_bias"); + mReservedUniforms.push_back("spot_shadow_offset"); + mReservedUniforms.push_back("sun_dir"); + mReservedUniforms.push_back("shadow_res"); + mReservedUniforms.push_back("proj_shadow_res"); + mReservedUniforms.push_back("depth_cutoff"); + mReservedUniforms.push_back("norm_cutoff"); + + llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_NORM_CUTOFF+1); + + mReservedUniforms.push_back("tc_scale"); + mReservedUniforms.push_back("rcp_screen_res"); + mReservedUniforms.push_back("rcp_frame_opt"); + mReservedUniforms.push_back("rcp_frame_opt2"); + + mReservedUniforms.push_back("focal_distance"); + mReservedUniforms.push_back("blur_constant"); + mReservedUniforms.push_back("tan_pixel_angle"); + mReservedUniforms.push_back("magnification"); + mReservedUniforms.push_back("max_cof"); + mReservedUniforms.push_back("res_scale"); + + mReservedUniforms.push_back("depthMap"); + mReservedUniforms.push_back("shadowMap0"); + mReservedUniforms.push_back("shadowMap1"); + mReservedUniforms.push_back("shadowMap2"); + mReservedUniforms.push_back("shadowMap3"); + mReservedUniforms.push_back("shadowMap4"); + mReservedUniforms.push_back("shadowMap5"); + + llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW5+1); + + mReservedUniforms.push_back("normalMap"); + mReservedUniforms.push_back("positionMap"); + mReservedUniforms.push_back("diffuseRect"); + mReservedUniforms.push_back("specularRect"); + mReservedUniforms.push_back("noiseMap"); + mReservedUniforms.push_back("lightFunc"); + mReservedUniforms.push_back("lightMap"); + mReservedUniforms.push_back("bloomMap"); + mReservedUniforms.push_back("projectionMap"); + + llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS); + + std::set<std::string> dupe_check; + + for (U32 i = 0; i < mReservedUniforms.size(); ++i) + { + if (dupe_check.find(mReservedUniforms[i]) != dupe_check.end()) + { + llerrs << "Duplicate reserved uniform name found: " << mReservedUniforms[i] << llendl; + } + dupe_check.insert(mReservedUniforms[i]); + } +} + diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 2f30103811..950e6c9c2f 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -36,9 +36,137 @@ public: LLShaderMgr(); virtual ~LLShaderMgr(); + typedef enum + { + MODELVIEW_MATRIX = 0, + PROJECTION_MATRIX, + INVERSE_PROJECTION_MATRIX, + MODELVIEW_PROJECTION_MATRIX, + NORMAL_MATRIX, + TEXTURE_MATRIX0, + TEXTURE_MATRIX1, + TEXTURE_MATRIX2, + TEXTURE_MATRIX3, + VIEWPORT, + LIGHT_POSITION, + LIGHT_DIRECTION, + LIGHT_ATTENUATION, + LIGHT_DIFFUSE, + LIGHT_AMBIENT, + MULTI_LIGHT_COUNT, + MULTI_LIGHT, + MULTI_LIGHT_COL, + MULTI_LIGHT_FAR_Z, + PROJECTOR_MATRIX, + PROJECTOR_NEAR, + PROJECTOR_P, + PROJECTOR_N, + PROJECTOR_ORIGIN, + PROJECTOR_RANGE, + PROJECTOR_AMBIANCE, + PROJECTOR_SHADOW_INDEX, + PROJECTOR_SHADOW_FADE, + PROJECTOR_FOCUS, + PROJECTOR_LOD, + PROJECTOR_AMBIENT_LOD, + DIFFUSE_COLOR, + DIFFUSE_MAP, + SPECULAR_MAP, + BUMP_MAP, + ENVIRONMENT_MAP, + CLOUD_NOISE_MAP, + FULLBRIGHT, + LIGHTNORM, + SUNLIGHT_COLOR, + AMBIENT, + BLUE_HORIZON, + BLUE_DENSITY, + HAZE_HORIZON, + HAZE_DENSITY, + CLOUD_SHADOW, + DENSITY_MULTIPLIER, + DISTANCE_MULTIPLIER, + MAX_Y, + GLOW, + CLOUD_COLOR, + CLOUD_POS_DENSITY1, + CLOUD_POS_DENSITY2, + CLOUD_SCALE, + GAMMA, + SCENE_LIGHT_STRENGTH, + LIGHT_CENTER, + LIGHT_SIZE, + LIGHT_FALLOFF, + + GLOW_MIN_LUMINANCE, + GLOW_MAX_EXTRACT_ALPHA, + GLOW_LUM_WEIGHTS, + GLOW_WARMTH_WEIGHTS, + GLOW_WARMTH_AMOUNT, + GLOW_STRENGTH, + GLOW_DELTA, + + MINIMUM_ALPHA, + + DEFERRED_SHADOW_MATRIX, + DEFERRED_ENV_MAT, + DEFERRED_SHADOW_CLIP, + DEFERRED_SUN_WASH, + DEFERRED_SHADOW_NOISE, + DEFERRED_BLUR_SIZE, + DEFERRED_SSAO_RADIUS, + DEFERRED_SSAO_MAX_RADIUS, + DEFERRED_SSAO_FACTOR, + DEFERRED_SSAO_FACTOR_INV, + DEFERRED_SSAO_EFFECT_MAT, + DEFERRED_SCREEN_RES, + DEFERRED_NEAR_CLIP, + DEFERRED_SHADOW_OFFSET, + DEFERRED_SHADOW_BIAS, + DEFERRED_SPOT_SHADOW_BIAS, + DEFERRED_SPOT_SHADOW_OFFSET, + DEFERRED_SUN_DIR, + DEFERRED_SHADOW_RES, + DEFERRED_PROJ_SHADOW_RES, + DEFERRED_DEPTH_CUTOFF, + DEFERRED_NORM_CUTOFF, + + FXAA_TC_SCALE, + FXAA_RCP_SCREEN_RES, + FXAA_RCP_FRAME_OPT, + FXAA_RCP_FRAME_OPT2, + + DOF_FOCAL_DISTANCE, + DOF_BLUR_CONSTANT, + DOF_TAN_PIXEL_ANGLE, + DOF_MAGNIFICATION, + DOF_MAX_COF, + DOF_RES_SCALE, + + DEFERRED_DEPTH, + DEFERRED_SHADOW0, + DEFERRED_SHADOW1, + DEFERRED_SHADOW2, + DEFERRED_SHADOW3, + DEFERRED_SHADOW4, + DEFERRED_SHADOW5, + DEFERRED_NORMAL, + DEFERRED_POSITION, + DEFERRED_DIFFUSE, + DEFERRED_SPECULAR, + DEFERRED_NOISE, + DEFERRED_LIGHTFUNC, + DEFERRED_LIGHT, + DEFERRED_BLOOM, + DEFERRED_PROJECTION, + END_RESERVED_UNIFORMS + } eGLSLReservedUniforms; + // singleton pattern implementation static LLShaderMgr * instance(); + virtual void initAttribsAndUniforms(void); + BOOL attachShaderFeatures(LLGLSLShader * shader); void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE); BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE); diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 4a0b964e61..20a450fbfb 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -25,7 +25,6 @@ */ #include "linden_common.h" -#include "llmemory.h" #include <boost/static_assert.hpp> #include "llsys.h" @@ -35,6 +34,21 @@ #include "llmemtype.h" #include "llrender.h" #include "llvector4a.h" +#include "llshadermgr.h" +#include "llglslshader.h" +#include "llmemory.h" + +//Next Highest Power Of Two +//helper function, returns first number > v that is a power of 2, or v if v is already a power of 2 +U32 nhpo2(U32 v) +{ + U32 r = 1; + while (r < v) { + r *= 2; + } + return r; +} + //============================================================================ @@ -43,7 +57,9 @@ LLVBOPool LLVertexBuffer::sStreamVBOPool; LLVBOPool LLVertexBuffer::sDynamicVBOPool; LLVBOPool LLVertexBuffer::sStreamIBOPool; LLVBOPool LLVertexBuffer::sDynamicIBOPool; +U32 LLVBOPool::sBytesPooled = 0; +LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL ; U32 LLVertexBuffer::sBindCount = 0; U32 LLVertexBuffer::sSetCount = 0; S32 LLVertexBuffer::sCount = 0; @@ -52,6 +68,7 @@ S32 LLVertexBuffer::sMappedCount = 0; BOOL LLVertexBuffer::sDisableVBOMapping = FALSE ; BOOL LLVertexBuffer::sEnableVBOs = TRUE; U32 LLVertexBuffer::sGLRenderBuffer = 0; +U32 LLVertexBuffer::sGLRenderArray = 0; U32 LLVertexBuffer::sGLRenderIndices = 0; U32 LLVertexBuffer::sLastMask = 0; BOOL LLVertexBuffer::sVBOActive = FALSE; @@ -59,12 +76,166 @@ BOOL LLVertexBuffer::sIBOActive = FALSE; U32 LLVertexBuffer::sAllocatedBytes = 0; BOOL LLVertexBuffer::sMapped = FALSE; BOOL LLVertexBuffer::sUseStreamDraw = TRUE; +BOOL LLVertexBuffer::sUseVAO = FALSE; BOOL LLVertexBuffer::sPreferStreamDraw = FALSE; -S32 LLVertexBuffer::sWeight4Loc = -1; -std::vector<U32> LLVertexBuffer::sDeleteList; +const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms + +class LLGLSyncFence : public LLGLFence +{ +public: +#ifdef GL_ARB_sync + GLsync mSync; +#endif + + LLGLSyncFence() + { +#ifdef GL_ARB_sync + mSync = 0; +#endif + } + + virtual ~LLGLSyncFence() + { +#ifdef GL_ARB_sync + if (mSync) + { + glDeleteSync(mSync); + } +#endif + } + + void placeFence() + { +#ifdef GL_ARB_sync + if (mSync) + { + glDeleteSync(mSync); + } + mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +#endif + } + + void wait() + { +#ifdef GL_ARB_sync + if (mSync) + { + while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) + { //track the number of times we've waited here + static S32 waits = 0; + waits++; + } + } +#endif + } + + +}; + + +//which power of 2 is i? +//assumes i is a power of 2 > 0 +U32 wpo2(U32 i) +{ + llassert(i > 0); + llassert(nhpo2(i) == i); + + U32 r = 0; + + while (i >>= 1) ++r; + + return r; +} + +U8* LLVBOPool::allocate(U32& name, U32 size) +{ + llassert(nhpo2(size) == size); + + U32 i = wpo2(size); + + if (mFreeList.size() <= i) + { + mFreeList.resize(i+1); + } + + U8* ret = NULL; + + if (mFreeList[i].empty()) + { + //make a new buffer + glGenBuffersARB(1, &name); + glBindBufferARB(mType, name); + glBufferDataARB(mType, size, 0, mUsage); + LLVertexBuffer::sAllocatedBytes += size; + + if (LLVertexBuffer::sDisableVBOMapping) + { + ret = (U8*) ll_aligned_malloc_16(size); + } + glBindBufferARB(mType, 0); + } + else + { + name = mFreeList[i].front().mGLName; + ret = mFreeList[i].front().mClientData; + + sBytesPooled -= size; + + mFreeList[i].pop_front(); + } + + return ret; +} + +void LLVBOPool::release(U32 name, U8* buffer, U32 size) +{ + llassert(nhpo2(size) == size); + + U32 i = wpo2(size); + + llassert(mFreeList.size() > i); + + Record rec; + rec.mGLName = name; + rec.mClientData = buffer; + + sBytesPooled += size; + + mFreeList[i].push_back(rec); +} + +void LLVBOPool::cleanup() +{ + U32 size = 1; + + for (U32 i = 0; i < mFreeList.size(); ++i) + { + record_list_t& l = mFreeList[i]; + + while (!l.empty()) + { + Record& r = l.front(); + + glDeleteBuffersARB(1, &r.mGLName); + + if (r.mClientData) + { + ll_aligned_free_16(r.mClientData); + } + + l.pop_front(); + + LLVertexBuffer::sAllocatedBytes -= size; + sBytesPooled -= size; + } + + size *= 2; + } +} +//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] = { sizeof(LLVector4), // TYPE_VERTEX, @@ -74,10 +245,12 @@ S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] = sizeof(LLVector2), // TYPE_TEXCOORD2, sizeof(LLVector2), // TYPE_TEXCOORD3, sizeof(LLColor4U), // TYPE_COLOR, + sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently sizeof(LLVector4), // TYPE_BINORMAL, 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 }; U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = @@ -92,146 +265,147 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = GL_LINE_LOOP, }; + //static void LLVertexBuffer::setupClientArrays(U32 data_mask) { - /*if (LLGLImmediate::sStarted) - { - llerrs << "Cannot use LLGLImmediate and LLVertexBuffer simultaneously!" << llendl; - }*/ - if (sLastMask != data_mask) { - U32 mask[] = + BOOL error = FALSE; + + if (LLGLSLShader::sNoFixedFunction) { - MAP_VERTEX, - MAP_NORMAL, - MAP_TEXCOORD0, - MAP_COLOR, - }; - - GLenum array[] = + for (U32 i = 0; i < TYPE_MAX; ++i) + { + S32 loc = i; + + U32 mask = 1 << i; + + if (sLastMask & (1 << i)) + { //was enabled + if (!(data_mask & mask)) + { //needs to be disabled + glDisableVertexAttribArrayARB(loc); + } + } + else + { //was disabled + if (data_mask & mask) + { //needs to be enabled + glEnableVertexAttribArrayARB(loc); + } + } + } + } + else { - GL_VERTEX_ARRAY, - GL_NORMAL_ARRAY, - GL_TEXTURE_COORD_ARRAY, - GL_COLOR_ARRAY, - }; - BOOL error = FALSE; - for (U32 i = 0; i < 4; ++i) - { - if (sLastMask & mask[i]) - { //was enabled - if (!(data_mask & mask[i]) && i > 0) - { //needs to be disabled - glDisableClientState(array[i]); + GLenum array[] = + { + GL_VERTEX_ARRAY, + GL_NORMAL_ARRAY, + GL_TEXTURE_COORD_ARRAY, + GL_COLOR_ARRAY, + }; + + GLenum mask[] = + { + MAP_VERTEX, + MAP_NORMAL, + MAP_TEXCOORD0, + MAP_COLOR + }; + + + + for (U32 i = 0; i < 4; ++i) + { + if (sLastMask & mask[i]) + { //was enabled + if (!(data_mask & mask[i])) + { //needs to be disabled + glDisableClientState(array[i]); + } + else if (gDebugGL) + { //needs to be enabled, make sure it was (DEBUG) + if (!glIsEnabled(array[i])) + { + if (gDebugSession) + { + error = TRUE; + gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl; + } + else + { + llerrs << "Bad client state! " << array[i] << " disabled." << llendl; + } + } + } } - else if (gDebugGL) - { //needs to be enabled, make sure it was (DEBUG TEMPORARY) - if (i > 0 && !glIsEnabled(array[i])) - { + else + { //was disabled + if (data_mask & mask[i]) + { //needs to be enabled + glEnableClientState(array[i]); + } + else if (gDebugGL && glIsEnabled(array[i])) + { //needs to be disabled, make sure it was (DEBUG TEMPORARY) if (gDebugSession) { error = TRUE; - gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl; + gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl; } else { - llerrs << "Bad client state! " << array[i] << " disabled." << llendl; + llerrs << "Bad client state! " << array[i] << " enabled." << llendl; } } } } - else - { //was disabled - if (data_mask & mask[i] && i > 0) - { //needs to be enabled - glEnableClientState(array[i]); - } - else if (gDebugGL && i > 0 && glIsEnabled(array[i])) - { //needs to be disabled, make sure it was (DEBUG TEMPORARY) - if (gDebugSession) - { - error = TRUE; - gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl; - } - else - { - llerrs << "Bad client state! " << array[i] << " enabled." << llendl; + + U32 map_tc[] = + { + MAP_TEXCOORD1, + MAP_TEXCOORD2, + MAP_TEXCOORD3 + }; + + for (U32 i = 0; i < 3; i++) + { + if (sLastMask & map_tc[i]) + { + if (!(data_mask & map_tc[i])) + { //disable + glClientActiveTextureARB(GL_TEXTURE1_ARB+i); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTextureARB(GL_TEXTURE0_ARB); } } + else if (data_mask & map_tc[i]) + { + glClientActiveTextureARB(GL_TEXTURE1_ARB+i); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } } - } - if (error) - { - ll_fail("LLVertexBuffer::setupClientArrays failed"); - } - - U32 map_tc[] = - { - MAP_TEXCOORD1, - MAP_TEXCOORD2, - MAP_TEXCOORD3 - }; - - for (U32 i = 0; i < 3; i++) - { - if (sLastMask & map_tc[i]) + if (sLastMask & MAP_BINORMAL) { - if (!(data_mask & map_tc[i])) + if (!(data_mask & MAP_BINORMAL)) { - glClientActiveTextureARB(GL_TEXTURE1_ARB+i); + glClientActiveTextureARB(GL_TEXTURE2_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTextureARB(GL_TEXTURE0_ARB); } } - else if (data_mask & map_tc[i]) - { - glClientActiveTextureARB(GL_TEXTURE1_ARB+i); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - } - - if (sLastMask & MAP_BINORMAL) - { - if (!(data_mask & MAP_BINORMAL)) + else if (data_mask & MAP_BINORMAL) { glClientActiveTextureARB(GL_TEXTURE2_ARB); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTextureARB(GL_TEXTURE0_ARB); } } - else if (data_mask & MAP_BINORMAL) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - - if (sLastMask & MAP_WEIGHT4) - { - if (sWeight4Loc < 0) - { - llerrs << "Weighting disabled but vertex buffer still bound!" << llendl; - } - - if (!(data_mask & MAP_WEIGHT4)) - { //disable 4-component skin weight - glDisableVertexAttribArrayARB(sWeight4Loc); - } - } - else if (data_mask & MAP_WEIGHT4) - { - if (sWeight4Loc >= 0) - { //enable 4-component skin weight - glEnableVertexAttribArrayARB(sWeight4Loc); - } - } - sLastMask = data_mask; } } @@ -239,31 +413,90 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) //static void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm) { + llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); + gGL.syncMatrices(); + U32 count = pos.size(); - llassert(norm.size() >= pos.size()); + llassert_always(norm.size() >= pos.size()); + llassert_always(count > 0) ; unbind(); setupClientArrays(MAP_VERTEX | MAP_NORMAL); - glVertexPointer(3, GL_FLOAT, 0, pos[0].mV); - glNormalPointer(GL_FLOAT, 0, norm[0].mV); + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + if (shader) + { + S32 loc = LLVertexBuffer::TYPE_VERTEX; + if (loc > -1) + { + glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV); + } + loc = LLVertexBuffer::TYPE_NORMAL; + if (loc > -1) + { + glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV); + } + } + else + { + glVertexPointer(3, GL_FLOAT, 0, pos[0].mV); + glNormalPointer(GL_FLOAT, 0, norm[0].mV); + } glDrawArrays(sGLMode[mode], 0, count); } +//static +void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp) +{ + llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); + + gGL.syncMatrices(); + + U32 mask = LLVertexBuffer::MAP_VERTEX; + if (tc) + { + mask = mask | LLVertexBuffer::MAP_TEXCOORD0; + } + + unbind(); + + setupClientArrays(mask); + + if (LLGLSLShader::sNoFixedFunction) + { + S32 loc = LLVertexBuffer::TYPE_VERTEX; + glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos); + + if (tc) + { + loc = LLVertexBuffer::TYPE_TEXCOORD0; + glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc); + } + } + else + { + glTexCoordPointer(2, GL_FLOAT, 0, tc); + glVertexPointer(3, GL_FLOAT, 16, pos); + } + + glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp); +} + void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const { - if (start >= (U32) mRequestedNumVerts || - end >= (U32) mRequestedNumVerts) + if (start >= (U32) mNumVerts || + end >= (U32) mNumVerts) { - llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mRequestedNumVerts << llendl; + llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << llendl; } - llassert(mRequestedNumIndices >= 0); + llassert(mNumIndices >= 0); - if (indices_offset >= (U32) mRequestedNumIndices || - indices_offset + count > (U32) mRequestedNumIndices) + if (indices_offset >= (U32) mNumIndices || + indices_offset + count > (U32) mNumIndices) { llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; } @@ -278,6 +511,25 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl; } } + + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + if (shader && shader->mFeatures.mIndexedTextureChannels > 1) + { + LLStrider<LLVector4a> v; + //hack to get non-const reference + LLVertexBuffer* vb = (LLVertexBuffer*) this; + vb->getVertexStrider(v); + + for (U32 i = start; i < end; i++) + { + S32 idx = (S32) (v[i][3]+0.25f); + if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels) + { + llerrs << "Bad texture index found in vertex data stream." << llendl; + } + } + } } } @@ -285,16 +537,40 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi { validateRange(start, end, count, indices_offset); - llassert(mRequestedNumVerts >= 0); + gGL.syncMatrices(); + + llassert(mNumVerts >= 0); + llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - if (mGLIndices != sGLRenderIndices) + if (mGLArray) { - llerrs << "Wrong index buffer bound." << llendl; + if (mGLArray != sGLRenderArray) + { + llerrs << "Wrong vertex array bound." << llendl; + } + } + else + { + if (mGLIndices != sGLRenderIndices) + { + llerrs << "Wrong index buffer bound." << llendl; + } + + if (mGLBuffer != sGLRenderBuffer) + { + llerrs << "Wrong vertex buffer bound." << llendl; + } } - if (mGLBuffer != sGLRenderBuffer) + if (gDebugGL && !mGLArray && useVBOs()) { - llerrs << "Wrong vertex buffer bound." << llendl; + GLint elem = 0; + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem); + + if (elem != mGLIndices) + { + llerrs << "Wrong index buffer bound!" << llendl; + } } if (mode >= LLRender::NUM_MODES) @@ -309,25 +585,40 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, idx); stop_glerror(); + placeFence(); } void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const { - llassert(mRequestedNumIndices >= 0); - if (indices_offset >= (U32) mRequestedNumIndices || - indices_offset + count > (U32) mRequestedNumIndices) + llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); + + gGL.syncMatrices(); + + llassert(mNumIndices >= 0); + if (indices_offset >= (U32) mNumIndices || + indices_offset + count > (U32) mNumIndices) { llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; } - if (mGLIndices != sGLRenderIndices) + if (mGLArray) { - llerrs << "Wrong index buffer bound." << llendl; + if (mGLArray != sGLRenderArray) + { + llerrs << "Wrong vertex array bound." << llendl; + } } - - if (mGLBuffer != sGLRenderBuffer) + else { - llerrs << "Wrong vertex buffer bound." << llendl; + if (mGLIndices != sGLRenderIndices) + { + llerrs << "Wrong index buffer bound." << llendl; + } + + if (mGLBuffer != sGLRenderBuffer) + { + llerrs << "Wrong vertex buffer bound." << llendl; + } } if (mode >= LLRender::NUM_MODES) @@ -340,20 +631,35 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT, ((U16*) getIndicesPointer()) + indices_offset); stop_glerror(); + placeFence(); } void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { - llassert(mRequestedNumVerts >= 0); - if (first >= (U32) mRequestedNumVerts || - first + count > (U32) mRequestedNumVerts) + llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); + + gGL.syncMatrices(); + + llassert(mNumVerts >= 0); + if (first >= (U32) mNumVerts || + first + count > (U32) mNumVerts) { llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl; } - if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive) + if (mGLArray) { - llerrs << "Wrong vertex buffer bound." << llendl; + if (mGLArray != sGLRenderArray) + { + llerrs << "Wrong vertex array bound." << llendl; + } + } + else + { + if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive) + { + llerrs << "Wrong vertex buffer bound." << llendl; + } } if (mode >= LLRender::NUM_MODES) @@ -365,29 +671,44 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const stop_glerror(); glDrawArrays(sGLMode[mode], first, count); stop_glerror(); + placeFence(); } //static void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping) { sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject ; - if(sEnableVBOs) - { - //llassert_always(glBindBufferARB) ; //double check the extention for VBO is loaded. + sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ; - llinfos << "VBO is enabled." << llendl ; - } - else - { - llinfos << "VBO is disabled." << llendl ; + if(!sPrivatePoolp) + { + sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC) ; } - sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ; + sStreamVBOPool.mType = GL_ARRAY_BUFFER_ARB; + sStreamVBOPool.mUsage= GL_STREAM_DRAW_ARB; + sStreamIBOPool.mType = GL_ELEMENT_ARRAY_BUFFER_ARB; + sStreamIBOPool.mUsage= GL_STREAM_DRAW_ARB; + + sDynamicVBOPool.mType = GL_ARRAY_BUFFER_ARB; + sDynamicVBOPool.mUsage= GL_DYNAMIC_DRAW_ARB; + sDynamicIBOPool.mType = GL_ELEMENT_ARRAY_BUFFER_ARB; + sDynamicIBOPool.mUsage= GL_DYNAMIC_DRAW_ARB; } //static void LLVertexBuffer::unbind() { + if (sGLRenderArray) + { +#if GL_ARB_vertex_array_object + glBindVertexArray(0); +#endif + sGLRenderArray = 0; + sGLRenderIndices = 0; + sIBOActive = FALSE; + } + if (sVBOActive) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); @@ -410,17 +731,16 @@ void LLVertexBuffer::cleanupClass() { LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS); unbind(); - clientCopy(); // deletes GL buffers - - //llassert_always(!sCount) ; -} + + sStreamIBOPool.cleanup(); + sDynamicIBOPool.cleanup(); + sStreamVBOPool.cleanup(); + sDynamicVBOPool.cleanup(); -void LLVertexBuffer::clientCopy(F64 max_time) -{ - if (!sDeleteList.empty()) + if(sPrivatePoolp) { - glDeleteBuffersARB(sDeleteList.size(), (GLuint*) &(sDeleteList[0])); - sDeleteList.clear(); + LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ; + sPrivatePoolp = NULL ; } } @@ -431,22 +751,20 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : mNumVerts(0), mNumIndices(0), - mRequestedNumVerts(-1), - mRequestedNumIndices(-1), mUsage(usage), mGLBuffer(0), + mGLArray(0), mGLIndices(0), mMappedData(NULL), mMappedIndexData(NULL), mVertexLocked(FALSE), mIndexLocked(FALSE), mFinal(FALSE), - mFilthy(FALSE), mEmpty(TRUE), - mResized(FALSE), - mDynamicSize(FALSE) + mFence(NULL) { LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR); + mFence = NULL; if (!sEnableVBOs) { mUsage = 0 ; @@ -462,6 +780,16 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : mUsage = GL_STREAM_DRAW_ARB; } + if (mUsage == 0 && LLRender::sGLCoreProfile) + { //MUST use VBOs for all rendering + mUsage = GL_STREAM_DRAW_ARB; + } + + if (mUsage && mUsage != GL_STREAM_DRAW_ARB) + { //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default + mUsage = GL_DYNAMIC_DRAW_ARB; + } + //zero out offsets for (U32 i = 0; i < TYPE_MAX; i++) { @@ -470,6 +798,7 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : mTypeMask = typemask; mSize = 0; + mIndicesSize = 0; mAlignedOffset = 0; mAlignedIndexOffset = 0; @@ -480,12 +809,12 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices) { S32 offset = 0; - for (S32 i=0; i<TYPE_MAX; i++) + for (S32 i=0; i<TYPE_TEXTURE_INDEX; i++) { U32 mask = 1<<i; if (typemask & mask) { - if (offsets) + if (offsets && LLVertexBuffer::sTypeSize[i]) { offsets[i] = offset; offset += LLVertexBuffer::sTypeSize[i]*num_vertices; @@ -494,6 +823,8 @@ S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_verti } } + offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12; + return offset+16; } @@ -501,7 +832,7 @@ S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_verti S32 LLVertexBuffer::calcVertexSize(const U32& typemask) { S32 size = 0; - for (S32 i = 0; i < TYPE_MAX; i++) + for (S32 i = 0; i < TYPE_TEXTURE_INDEX; i++) { U32 mask = 1<<i; if (typemask & mask) @@ -525,46 +856,81 @@ LLVertexBuffer::~LLVertexBuffer() LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR); destroyGLBuffer(); destroyGLIndices(); + + if (mGLArray) + { +#if GL_ARB_vertex_array_object + glDeleteVertexArrays(1, &mGLArray); +#endif + } + sCount--; + if (mFence) + { + delete mFence; + } + + mFence = NULL; + llassert_always(!mMappedData && !mMappedIndexData) ; }; +void LLVertexBuffer::placeFence() const +{ + /*if (!mFence && useVBOs()) + { + if (gGLManager.mHasSync) + { + mFence = new LLGLSyncFence(); + } + } + + if (mFence) + { + mFence->placeFence(); + }*/ +} + +void LLVertexBuffer::waitFence() const +{ + /*if (mFence) + { + mFence->wait(); + }*/ +} + //---------------------------------------------------------------------------- -void LLVertexBuffer::genBuffer() +void LLVertexBuffer::genBuffer(U32 size) { + mSize = nhpo2(size); + if (mUsage == GL_STREAM_DRAW_ARB) { - mGLBuffer = sStreamVBOPool.allocate(); - } - else if (mUsage == GL_DYNAMIC_DRAW_ARB) - { - mGLBuffer = sDynamicVBOPool.allocate(); + mMappedData = sStreamVBOPool.allocate(mGLBuffer, mSize); } else { - BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint)); - glGenBuffersARB(1, (GLuint*)&mGLBuffer); + mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize); } + sGLCount++; } -void LLVertexBuffer::genIndices() +void LLVertexBuffer::genIndices(U32 size) { + mIndicesSize = nhpo2(size); + if (mUsage == GL_STREAM_DRAW_ARB) { - mGLIndices = sStreamIBOPool.allocate(); - } - else if (mUsage == GL_DYNAMIC_DRAW_ARB) - { - mGLIndices = sDynamicIBOPool.allocate(); + mMappedIndexData = sStreamIBOPool.allocate(mGLIndices, mIndicesSize); } else { - BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint)); - glGenBuffersARB(1, (GLuint*)&mGLIndices); + mMappedIndexData = sDynamicIBOPool.allocate(mGLIndices, mIndicesSize); } + sGLCount++; } @@ -572,16 +938,16 @@ void LLVertexBuffer::releaseBuffer() { if (mUsage == GL_STREAM_DRAW_ARB) { - sStreamVBOPool.release(mGLBuffer); - } - else if (mUsage == GL_DYNAMIC_DRAW_ARB) - { - sDynamicVBOPool.release(mGLBuffer); + sStreamVBOPool.release(mGLBuffer, mMappedData, mSize); } else { - sDeleteList.push_back(mGLBuffer); + sDynamicVBOPool.release(mGLBuffer, mMappedData, mSize); } + + mGLBuffer = 0; + mMappedData = NULL; + sGLCount--; } @@ -589,24 +955,23 @@ void LLVertexBuffer::releaseIndices() { if (mUsage == GL_STREAM_DRAW_ARB) { - sStreamIBOPool.release(mGLIndices); - } - else if (mUsage == GL_DYNAMIC_DRAW_ARB) - { - sDynamicIBOPool.release(mGLIndices); + sStreamIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); } else { - sDeleteList.push_back(mGLIndices); + sDynamicIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); } + + mGLIndices = 0; + mMappedIndexData = NULL; + sGLCount--; } -void LLVertexBuffer::createGLBuffer() +void LLVertexBuffer::createGLBuffer(U32 size) { LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES); - U32 size = getSize(); if (mGLBuffer) { destroyGLBuffer(); @@ -621,23 +986,21 @@ void LLVertexBuffer::createGLBuffer() if (useVBOs()) { - mMappedData = NULL; - genBuffer(); - mResized = TRUE; + genBuffer(size); } else { static int gl_buffer_idx = 0; mGLBuffer = ++gl_buffer_idx; - mMappedData = (U8*) ll_aligned_malloc_16(size); + mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); + mSize = size; } } -void LLVertexBuffer::createGLIndices() +void LLVertexBuffer::createGLIndices(U32 size) { LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES); - U32 size = getIndicesSize(); - + if (mGLIndices) { destroyGLIndices(); @@ -657,15 +1020,14 @@ void LLVertexBuffer::createGLIndices() { //pad by another 16 bytes for VBO pointer adjustment size += 16; - mMappedIndexData = NULL; - genIndices(); - mResized = TRUE; + genIndices(size); } else { - mMappedIndexData = (U8*) ll_aligned_malloc_16(size); + mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); static int gl_buffer_idx = 0; mGLIndices = ++gl_buffer_idx; + mIndicesSize = size; } } @@ -676,22 +1038,14 @@ void LLVertexBuffer::destroyGLBuffer() { if (useVBOs()) { - freeClientBuffer() ; - - if (mMappedData || mMappedIndexData) - { - llerrs << "Vertex buffer destroyed while mapped!" << llendl; - } releaseBuffer(); } else { - ll_aligned_free_16(mMappedData); + FREE_MEM(sPrivatePoolp, mMappedData) ; mMappedData = NULL; mEmpty = TRUE; } - - sAllocatedBytes -= getSize(); } mGLBuffer = 0; @@ -705,22 +1059,14 @@ void LLVertexBuffer::destroyGLIndices() { if (useVBOs()) { - freeClientBuffer() ; - - if (mMappedData || mMappedIndexData) - { - llerrs << "Vertex buffer destroyed while mapped." << llendl; - } releaseIndices(); } else { - ll_aligned_free_16(mMappedIndexData); + FREE_MEM(sPrivatePoolp, mMappedIndexData) ; mMappedIndexData = NULL; mEmpty = TRUE; } - - sAllocatedBytes -= getIndicesSize(); } mGLIndices = 0; @@ -739,23 +1085,14 @@ void LLVertexBuffer::updateNumVerts(S32 nverts) nverts = 65535; } - mRequestedNumVerts = nverts; + U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts); - if (!mDynamicSize) + if (needed_size > mSize || needed_size <= mSize/2) { - mNumVerts = nverts; + createGLBuffer(needed_size); } - else if (mUsage == GL_STATIC_DRAW_ARB || - nverts > mNumVerts || - nverts < mNumVerts/2) - { - if (mUsage != GL_STATIC_DRAW_ARB && nverts + nverts/4 <= 65535) - { - nverts += nverts/4; - } - mNumVerts = nverts; - } - mSize = calcOffsets(mTypeMask, mOffsets, mNumVerts); + + mNumVerts = nverts; } void LLVertexBuffer::updateNumIndices(S32 nindices) @@ -764,28 +1101,22 @@ void LLVertexBuffer::updateNumIndices(S32 nindices) llassert(nindices >= 0); - mRequestedNumIndices = nindices; - if (!mDynamicSize) + U32 needed_size = sizeof(U16) * nindices; + + if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2) { - mNumIndices = nindices; + createGLIndices(needed_size); } - else if (mUsage == GL_STATIC_DRAW_ARB || - nindices > mNumIndices || - nindices < mNumIndices/2) - { - if (mUsage != GL_STATIC_DRAW_ARB) - { - nindices += nindices/4; - } - mNumIndices = nindices; - } + mNumIndices = nindices; } void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) { LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER); - + + stop_glerror(); + if (nverts < 0 || nindices < 0 || nverts > 65536) { @@ -795,96 +1126,127 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) updateNumVerts(nverts); updateNumIndices(nindices); - if (mMappedData) - { - llerrs << "LLVertexBuffer::allocateBuffer() called redundantly." << llendl; - } if (create && (nverts || nindices)) { - createGLBuffer(); - createGLIndices(); + //actually allocate space for the vertex buffer if using VBO mapping + flush(); + + if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO)) + { +#if GL_ARB_vertex_array_object + glGenVertexArrays(1, &mGLArray); +#endif + setupVertexArray(); + } } - - sAllocatedBytes += getSize() + getIndicesSize(); } -void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) -{ - llassert(newnverts >= 0); - llassert(newnindices >= 0); +static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO"); - mRequestedNumVerts = newnverts; - mRequestedNumIndices = newnindices; - - LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER); - mDynamicSize = TRUE; - if (mUsage == GL_STATIC_DRAW_ARB) - { //always delete/allocate static buffers on resize - destroyGLBuffer(); - destroyGLIndices(); - allocateBuffer(newnverts, newnindices, TRUE); - mFinal = FALSE; - } - else if (newnverts > mNumVerts || newnindices > mNumIndices || - newnverts < mNumVerts/2 || newnindices < mNumIndices/2) +void LLVertexBuffer::setupVertexArray() +{ + if (!mGLArray) { - sAllocatedBytes -= getSize() + getIndicesSize(); - - updateNumVerts(newnverts); - updateNumIndices(newnindices); - - S32 newsize = getSize(); - S32 new_index_size = getIndicesSize(); - - sAllocatedBytes += newsize + new_index_size; + return; + } - if (newsize) - { - if (!mGLBuffer) - { //no buffer exists, create a new one - createGLBuffer(); - } - else - { - if (!useVBOs()) - { - ll_aligned_free_16(mMappedData); - mMappedData = (U8*) ll_aligned_malloc_16(newsize); - } - mResized = TRUE; - } - } - else if (mGLBuffer) + LLFastTimer t(FTM_SETUP_VERTEX_ARRAY); +#if GL_ARB_vertex_array_object + glBindVertexArray(mGLArray); +#endif + sGLRenderArray = mGLArray; + + U32 attrib_size[] = + { + 3, //TYPE_VERTEX, + 3, //TYPE_NORMAL, + 2, //TYPE_TEXCOORD0, + 2, //TYPE_TEXCOORD1, + 2, //TYPE_TEXCOORD2, + 2, //TYPE_TEXCOORD3, + 4, //TYPE_COLOR, + 4, //TYPE_EMISSIVE, + 3, //TYPE_BINORMAL, + 1, //TYPE_WEIGHT, + 4, //TYPE_WEIGHT4, + 4, //TYPE_CLOTHWEIGHT, + 1, //TYPE_TEXTURE_INDEX + }; + + U32 attrib_type[] = + { + GL_FLOAT, //TYPE_VERTEX, + GL_FLOAT, //TYPE_NORMAL, + GL_FLOAT, //TYPE_TEXCOORD0, + GL_FLOAT, //TYPE_TEXCOORD1, + GL_FLOAT, //TYPE_TEXCOORD2, + GL_FLOAT, //TYPE_TEXCOORD3, + GL_UNSIGNED_BYTE, //TYPE_COLOR, + GL_UNSIGNED_BYTE, //TYPE_EMISSIVE, + GL_FLOAT, //TYPE_BINORMAL, + GL_FLOAT, //TYPE_WEIGHT, + GL_FLOAT, //TYPE_WEIGHT4, + GL_FLOAT, //TYPE_CLOTHWEIGHT, + GL_FLOAT, //TYPE_TEXTURE_INDEX + }; + + U32 attrib_normalized[] = + { + GL_FALSE, //TYPE_VERTEX, + GL_FALSE, //TYPE_NORMAL, + GL_FALSE, //TYPE_TEXCOORD0, + GL_FALSE, //TYPE_TEXCOORD1, + GL_FALSE, //TYPE_TEXCOORD2, + GL_FALSE, //TYPE_TEXCOORD3, + GL_TRUE, //TYPE_COLOR, + GL_TRUE, //TYPE_EMISSIVE, + GL_FALSE, //TYPE_BINORMAL, + GL_FALSE, //TYPE_WEIGHT, + GL_FALSE, //TYPE_WEIGHT4, + GL_FALSE, //TYPE_CLOTHWEIGHT, + GL_FALSE, //TYPE_TEXTURE_INDEX + }; + + bindGLBuffer(true); + bindGLIndices(true); + + for (U32 i = 0; i < TYPE_MAX; ++i) + { + if (mTypeMask & (1 << i)) { - destroyGLBuffer(); + glEnableVertexAttribArrayARB(i); + glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]); } - - if (new_index_size) - { - if (!mGLIndices) - { - createGLIndices(); - } - else - { - if (!useVBOs()) - { - ll_aligned_free_16(mMappedIndexData); - mMappedIndexData = (U8*) ll_aligned_malloc_16(new_index_size); - } - mResized = TRUE; - } - } - else if (mGLIndices) + else { - destroyGLIndices(); + glDisableVertexAttribArrayARB(i); } } - if (mResized && useVBOs()) + //draw a dummy triangle to set index array pointer + //glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, NULL); + + unbind(); +} + +void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) +{ + llassert(newnverts >= 0); + llassert(newnindices >= 0); + + LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER); + + updateNumVerts(newnverts); + updateNumIndices(newnindices); + + if (useVBOs()) { - freeClientBuffer() ; - setBuffer(0); + flush(); + + if (mGLArray) + { //if size changed, offsets changed + setupVertexArray(); + } } } @@ -892,47 +1254,15 @@ BOOL LLVertexBuffer::useVBOs() const { //it's generally ineffective to use VBO for things that are streaming on apple -#if LL_DARWIN - if (!mUsage || mUsage == GL_STREAM_DRAW_ARB) - { - return FALSE; - } -#else if (!mUsage) { return FALSE; } -#endif + return TRUE; } //---------------------------------------------------------------------------- -void LLVertexBuffer::freeClientBuffer() -{ - if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData)) - { - ll_aligned_free_16(mMappedData) ; - ll_aligned_free_16(mMappedIndexData) ; - mMappedData = NULL ; - mMappedIndexData = NULL ; - } -} - -void LLVertexBuffer::allocateClientVertexBuffer() -{ - if(!mMappedData) - { - mMappedData = (U8*)ll_aligned_malloc_16(getSize()); - } -} - -void LLVertexBuffer::allocateClientIndexBuffer() -{ - if(!mMappedIndexData) - { - mMappedIndexData = (U8*)ll_aligned_malloc_16(getIndicesSize()); - } -} bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) { @@ -955,6 +1285,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) // Map for data access U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) { + bindGLBuffer(true); LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER); if (mFinal) { @@ -967,8 +1298,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran if (useVBOs()) { - - if (sDisableVBOMapping || gGLManager.mHasMapBufferRange) + if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) { if (count == -1) { @@ -1006,41 +1336,73 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran if (!mVertexLocked) { LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES); - setBuffer(0, type); mVertexLocked = TRUE; + sMappedCount++; stop_glerror(); if(sDisableVBOMapping) { map_range = false; - allocateClientVertexBuffer() ; } else { U8* src = NULL; -#ifdef GL_ARB_map_buffer_range + waitFence(); if (gGLManager.mHasMapBufferRange) { if (map_range) { +#ifdef GL_ARB_map_buffer_range S32 offset = mOffsets[type] + sTypeSize[type]*index; S32 length = (sTypeSize[type]*count+0xF) & ~0xF; - src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_INVALIDATE_RANGE_BIT); + src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, + GL_MAP_WRITE_BIT | + GL_MAP_FLUSH_EXPLICIT_BIT | + GL_MAP_INVALIDATE_RANGE_BIT); +#endif } else { - src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); +#ifdef GL_ARB_map_buffer_range + + if (gDebugGL) + { + GLint size = 0; + glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size); + + if (size < mSize) + { + llerrs << "Invalid buffer size." << llendl; + } + } + + src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, + GL_MAP_WRITE_BIT | + GL_MAP_FLUSH_EXPLICIT_BIT); +#endif + } + } + else if (gGLManager.mHasFlushBufferRange) + { + if (map_range) + { + glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE); + glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE); + src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + } + else + { + src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); } } else -#else - llassert_always(!gGLManager.mHasMapBufferRange); -#endif { map_range = false; src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); } + llassert(src != NULL); + mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src); mAlignedOffset = mMappedData - src; @@ -1051,12 +1413,9 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran { log_glerror(); - //check the availability of memory - U32 avail_phy_mem, avail_vir_mem; - LLMemoryInfo::getAvailableMemoryKB(avail_phy_mem, avail_vir_mem) ; - llinfos << "Available physical mwmory(KB): " << avail_phy_mem << llendl ; - llinfos << "Available virtual memory(KB): " << avail_vir_mem << llendl; - + //check the availability of memory + LLMemory::logMemoryInfo(TRUE) ; + if(!sDisableVBOMapping) { //-------------------- @@ -1082,7 +1441,6 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran llerrs << "memory allocation for vertex data failed." << llendl ; } } - sMappedCount++; } } else @@ -1090,7 +1448,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran map_range = false; } - if (map_range && !sDisableVBOMapping) + if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping) { return mMappedData; } @@ -1103,6 +1461,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) { LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER); + bindGLIndices(true); if (mFinal) { llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl; @@ -1114,7 +1473,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) if (useVBOs()) { - if (sDisableVBOMapping || gGLManager.mHasMapBufferRange) + if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) { if (count == -1) { @@ -1150,41 +1509,73 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) { LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES); - setBuffer(0, TYPE_INDEX); mIndexLocked = TRUE; + 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(sDisableVBOMapping) { map_range = false; - allocateClientIndexBuffer() ; } else { U8* src = NULL; -#ifdef GL_ARB_map_buffer_range + waitFence(); if (gGLManager.mHasMapBufferRange) { if (map_range) { +#ifdef GL_ARB_map_buffer_range S32 offset = sizeof(U16)*index; S32 length = sizeof(U16)*count; - src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_INVALIDATE_RANGE_BIT); + src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, + GL_MAP_WRITE_BIT | + GL_MAP_FLUSH_EXPLICIT_BIT | + GL_MAP_INVALIDATE_RANGE_BIT); +#endif + } + else + { +#ifdef GL_ARB_map_buffer_range + src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, + GL_MAP_WRITE_BIT | + GL_MAP_FLUSH_EXPLICIT_BIT); +#endif + } + } + else if (gGLManager.mHasFlushBufferRange) + { + if (map_range) + { + 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); + src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); } else { - src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); + src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); } } else -#else - llassert_always(!gGLManager.mHasMapBufferRange); -#endif { map_range = false; src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); } + llassert(src != NULL); + + mMappedIndexData = src; //LL_NEXT_ALIGNED_ADDRESS<U8>(src); mAlignedIndexOffset = mMappedIndexData - src; stop_glerror(); @@ -1194,6 +1585,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) if (!mMappedIndexData) { log_glerror(); + LLMemory::logMemoryInfo(TRUE) ; if(!sDisableVBOMapping) { @@ -1211,15 +1603,13 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) llerrs << "memory allocation for Index data failed. " << llendl ; } } - - sMappedCount++; } else { map_range = false; } - if (map_range && !sDisableVBOMapping) + if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping) { return mMappedIndexData; } @@ -1229,19 +1619,20 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) } } -void LLVertexBuffer::unmapBuffer(S32 type) +void LLVertexBuffer::unmapBuffer() { LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER); - if (!useVBOs() || type == -2) + if (!useVBOs()) { return ; //nothing to unmap } bool updated_all = false ; - if (mMappedData && mVertexLocked && type != TYPE_INDEX) + if (mMappedData && mVertexLocked) { - updated_all = (mIndexLocked && type < 0) ; //both vertex and index buffers done updating + bindGLBuffer(true); + updated_all = mIndexLocked; //both vertex and index buffers done updating if(sDisableVBOMapping) { @@ -1268,8 +1659,7 @@ void LLVertexBuffer::unmapBuffer(S32 type) } else { -#ifdef GL_ARB_map_buffer_range - if (gGLManager.mHasMapBufferRange) + if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) { if (!mMappedVertexRegions.empty()) { @@ -1279,16 +1669,22 @@ void LLVertexBuffer::unmapBuffer(S32 type) 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; - glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length); + if (gGLManager.mHasMapBufferRange) + { +#ifdef GL_ARB_map_buffer_range + glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length); +#endif + } + else if (gGLManager.mHasFlushBufferRange) + { + glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length); + } stop_glerror(); } mMappedVertexRegions.clear(); } } -#else - llassert_always(!gGLManager.mHasMapBufferRange); -#endif stop_glerror(); glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); stop_glerror(); @@ -1300,8 +1696,9 @@ void LLVertexBuffer::unmapBuffer(S32 type) sMappedCount--; } - if (mMappedIndexData && mIndexLocked && (type < 0 || type == TYPE_INDEX)) + if (mMappedIndexData && mIndexLocked) { + bindGLIndices(); if(sDisableVBOMapping) { if (!mMappedIndexRegions.empty()) @@ -1326,8 +1723,7 @@ void LLVertexBuffer::unmapBuffer(S32 type) } else { -#ifdef GL_ARB_map_buffer_range - if (gGLManager.mHasMapBufferRange) + if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) { if (!mMappedIndexRegions.empty()) { @@ -1336,16 +1732,24 @@ void LLVertexBuffer::unmapBuffer(S32 type) const MappedRegion& region = mMappedIndexRegions[i]; S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; S32 length = sizeof(U16)*region.mCount; - glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); + if (gGLManager.mHasMapBufferRange) + { +#ifdef GL_ARB_map_buffer_range + glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); +#endif + } + else if (gGLManager.mHasFlushBufferRange) + { +#ifdef GL_APPLE_flush_buffer_range + glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); +#endif + } stop_glerror(); } mMappedIndexRegions.clear(); } } -#else - llassert_always(!gGLManager.mHasMapBufferRange); -#endif stop_glerror(); glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); stop_glerror(); @@ -1359,21 +1763,7 @@ void LLVertexBuffer::unmapBuffer(S32 type) if(updated_all) { - if(mUsage == GL_STATIC_DRAW_ARB) - { - //static draw buffers can only be mapped a single time - //throw out client data (we won't be using it again) - mEmpty = TRUE; - mFinal = TRUE; - if(sDisableVBOMapping) - { - freeClientBuffer() ; - } - } - else - { - mEmpty = FALSE; - } + mEmpty = FALSE; } } @@ -1428,6 +1818,10 @@ bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index, { return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count, map_range); } +bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range) +{ + return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count, map_range); +} bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index, S32 count, bool map_range) { return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count, map_range); @@ -1453,6 +1847,10 @@ bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S { return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range); } +bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range) +{ + return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range); +} bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range) { return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range); @@ -1470,43 +1868,151 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 in //---------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array"); +bool LLVertexBuffer::bindGLArray() +{ + if (mGLArray && sGLRenderArray != mGLArray) + { + { + LLFastTimer t(FTM_BIND_GL_ARRAY); +#if GL_ARB_vertex_array_object + glBindVertexArray(mGLArray); +#endif + sGLRenderArray = mGLArray; + } + + //really shouldn't be necessary, but some drivers don't properly restore the + //state of GL_ELEMENT_ARRAY_BUFFER_BINDING + bindGLIndices(); + + return true; + } + + return false; +} + +static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer"); + +bool LLVertexBuffer::bindGLBuffer(bool force_bind) +{ + bindGLArray(); + + bool ret = false; + + if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive)))) + { + LLFastTimer t(FTM_BIND_GL_BUFFER); + /*if (sMapped) + { + llerrs << "VBO bound while another VBO mapped!" << llendl; + }*/ + glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer); + sGLRenderBuffer = mGLBuffer; + sBindCount++; + sVBOActive = TRUE; + + if (mGLArray) + { + llassert(sGLRenderArray == mGLArray); + //mCachedRenderBuffer = mGLBuffer; + } + + ret = true; + } + + return ret; +} + +static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices"); + +bool LLVertexBuffer::bindGLIndices(bool force_bind) +{ + bindGLArray(); + + bool ret = false; + if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive)))) + { + LLFastTimer t(FTM_BIND_GL_INDICES); + /*if (sMapped) + { + llerrs << "VBO bound while another VBO mapped!" << llendl; + }*/ + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices); + sGLRenderIndices = mGLIndices; + stop_glerror(); + sBindCount++; + sIBOActive = TRUE; + ret = true; + } + + return ret; +} + +void LLVertexBuffer::flush() +{ + if (useVBOs()) + { + unmapBuffer(); + } +} + // Set for rendering -void LLVertexBuffer::setBuffer(U32 data_mask, S32 type) +void LLVertexBuffer::setBuffer(U32 data_mask) { + flush(); + LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER); //set up pointers if the data mask is different ... BOOL setup = (sLastMask != data_mask); + if (gDebugGL && data_mask != 0) + { //make sure data requirements are fulfilled + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + if (shader) + { + U32 required_mask = 0; + for (U32 i = 0; i < LLVertexBuffer::TYPE_TEXTURE_INDEX; ++i) + { + if (shader->getAttribLocation(i) > -1) + { + U32 required = 1 << i; + if ((data_mask & required) == 0) + { + llwarns << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << llendl; + } + + required_mask |= required; + } + } + + if ((data_mask & required_mask) != required_mask) + { + llerrs << "Shader consumption mismatches data provision." << llendl; + } + } + } + if (useVBOs()) { - if (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive)) + if (mGLArray) { - /*if (sMapped) - { - llerrs << "VBO bound while another VBO mapped!" << llendl; - }*/ - stop_glerror(); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer); - stop_glerror(); - sBindCount++; - sVBOActive = TRUE; - setup = TRUE; // ... or the bound buffer changed + bindGLArray(); + setup = FALSE; //do NOT perform pointer setup if using VAO } - if (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive)) + else { - /*if (sMapped) + if (bindGLBuffer()) { - llerrs << "VBO bound while another VBO mapped!" << llendl; - }*/ - stop_glerror(); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices); - stop_glerror(); - sBindCount++; - sIBOActive = TRUE; + setup = TRUE; + } + if (bindGLIndices()) + { + setup = TRUE; + } } - + BOOL error = FALSE; - if (gDebugGL) + if (gDebugGL && !mGLArray) { GLint buff; glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); @@ -1541,81 +2047,20 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type) } } - if (mResized) + + } + else + { + if (sGLRenderArray) { - if (gDebugGL) - { - GLint buff; - glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLBuffer) - { - if (gDebugSession) - { - error = TRUE; - gFailLog << "Invalid GL vertex buffer bound: " << std::endl; - } - else - { - llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; - } - } - - if (mGLIndices != 0) - { - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLIndices) - { - if (gDebugSession) - { - error = TRUE; - gFailLog << "Invalid GL index buffer bound: "<< std::endl; - } - else - { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; - } - } - } - } - - if (mGLBuffer) - { - stop_glerror(); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), NULL, mUsage); - stop_glerror(); - } - if (mGLIndices) - { - stop_glerror(); - glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), NULL, mUsage); - stop_glerror(); - } - - mEmpty = TRUE; - mResized = FALSE; - - if (data_mask != 0) - { - if (gDebugSession) - { - error = TRUE; - gFailLog << "Buffer set for rendering before being filled after resize." << std::endl; - } - else - { - llerrs << "Buffer set for rendering before being filled after resize." << llendl; - } - } +#if GL_ARB_vertex_array_object + glBindVertexArray(0); +#endif + sGLRenderArray = 0; + sGLRenderIndices = 0; + sIBOActive = FALSE; } - if (error) - { - ll_fail("LLVertexBuffer::mapBuffer failed"); - } - unmapBuffer(type); - } - else - { if (mGLBuffer) { if (sVBOActive) @@ -1627,30 +2072,30 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type) } if (sGLRenderBuffer != mGLBuffer) { + sGLRenderBuffer = mGLBuffer; setup = TRUE; // ... or a client memory pointer changed } } - if (mGLIndices && sIBOActive) + if (mGLIndices) { - /*if (sMapped) + if (sIBOActive) { - llerrs << "VBO unbound while potentially mapped!" << llendl; - }*/ - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - sBindCount++; - sIBOActive = FALSE; + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + sBindCount++; + sIBOActive = FALSE; + } + + sGLRenderIndices = mGLIndices; } } - setupClientArrays(data_mask); - - if (mGLIndices) + if (!mGLArray) { - sGLRenderIndices = mGLIndices; + setupClientArrays(data_mask); } + if (mGLBuffer) { - sGLRenderBuffer = mGLBuffer; if (data_mask && setup) { setupVertexBuffer(data_mask); // subclass specific setup (virtual function) @@ -1660,80 +2105,150 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type) } // virtual (default) -void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const +void LLVertexBuffer::setupVertexBuffer(U32 data_mask) { LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER); stop_glerror(); U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; - if ((data_mask & mTypeMask) != data_mask) + /*if ((data_mask & mTypeMask) != data_mask) { llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; - } - - if (data_mask & MAP_NORMAL) - { - glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL])); - } - if (data_mask & MAP_TEXCOORD3) - { - glClientActiveTextureARB(GL_TEXTURE3_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD2) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD1) - { - glClientActiveTextureARB(GL_TEXTURE1_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_BINORMAL) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD0) - { - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); - } - if (data_mask & MAP_COLOR) - { - glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR])); - } - - if (data_mask & MAP_WEIGHT) - { - glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT])); - } - - if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1) - { - glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4])); - } + }*/ - if (data_mask & MAP_CLOTHWEIGHT) - { - glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT])); - } - if (data_mask & MAP_VERTEX) + if (LLGLSLShader::sNoFixedFunction) { + if (data_mask & MAP_NORMAL) + { + S32 loc = TYPE_NORMAL; + void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]); + glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr); + } + if (data_mask & MAP_TEXCOORD3) + { + S32 loc = TYPE_TEXCOORD3; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]); + glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr); + } + if (data_mask & MAP_TEXCOORD2) + { + S32 loc = TYPE_TEXCOORD2; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]); + glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr); + } + if (data_mask & MAP_TEXCOORD1) + { + S32 loc = TYPE_TEXCOORD1; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]); + glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr); + } + if (data_mask & MAP_BINORMAL) + { + S32 loc = TYPE_BINORMAL; + void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]); + glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr); + } + if (data_mask & MAP_TEXCOORD0) + { + S32 loc = TYPE_TEXCOORD0; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]); + glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr); + } + if (data_mask & MAP_COLOR) + { + S32 loc = TYPE_COLOR; + void* ptr = (void*)(base + mOffsets[TYPE_COLOR]); + glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr); + } + if (data_mask & MAP_EMISSIVE) + { + 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_WEIGHT) + { + S32 loc = TYPE_WEIGHT; + void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]); + glVertexAttribPointerARB(loc, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr); + } + if (data_mask & MAP_WEIGHT4) + { + S32 loc = TYPE_WEIGHT4; + void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]); + glVertexAttribPointerARB(loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr); + } + if (data_mask & MAP_CLOTHWEIGHT) + { + S32 loc = TYPE_CLOTHWEIGHT; + void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]); + glVertexAttribPointerARB(loc, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr); + } if (data_mask & MAP_TEXTURE_INDEX) { - glVertexPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0)); + S32 loc = TYPE_TEXTURE_INDEX; + void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12); + glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); } - else + if (data_mask & MAP_VERTEX) { - glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0)); + S32 loc = TYPE_VERTEX; + void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]); + glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); + } + } + else + { + if (data_mask & MAP_NORMAL) + { + glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL])); } + if (data_mask & MAP_TEXCOORD3) + { + glClientActiveTextureARB(GL_TEXTURE3_ARB); + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } + if (data_mask & MAP_TEXCOORD2) + { + glClientActiveTextureARB(GL_TEXTURE2_ARB); + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } + if (data_mask & MAP_TEXCOORD1) + { + glClientActiveTextureARB(GL_TEXTURE1_ARB); + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } + if (data_mask & MAP_BINORMAL) + { + glClientActiveTextureARB(GL_TEXTURE2_ARB); + glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } + if (data_mask & MAP_TEXCOORD0) + { + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); + } + if (data_mask & MAP_COLOR) + { + glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR])); + } + if (data_mask & MAP_VERTEX) + { + glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0)); + } } llglassertok(); } +LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count) +: mType(type), mIndex(index), mCount(count) +{ + llassert(mType == LLVertexBuffer::TYPE_INDEX || + mType < LLVertexBuffer::TYPE_TEXTURE_INDEX); +} + + diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index aa5df305a6..3e6f6a959a 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -38,6 +38,8 @@ #include <vector> #include <list> +#define LL_MAX_VERTEX_ATTRIB_LOCATION 64 + //============================================================================ // NOTES // Threading: @@ -49,31 +51,44 @@ //============================================================================ // gl name pools for dynamic and streaming buffers - -class LLVBOPool : public LLGLNamePool +class LLVBOPool { -protected: - virtual GLuint allocateName() - { - GLuint name; - stop_glerror(); - glGenBuffersARB(1, &name); - stop_glerror(); - return name; - } +public: + static U32 sBytesPooled; + + U32 mUsage; + U32 mType; + + //size MUST be a power of 2 + U8* allocate(U32& name, U32 size); + + //size MUST be the size provided to allocate that returned the given name + void release(U32 name, U8* buffer, U32 size); + + //destroy all records in mFreeList + void cleanup(); - virtual void releaseName(GLuint name) + class Record { - stop_glerror(); - glDeleteBuffersARB(1, &name); - stop_glerror(); - } + public: + U32 mGLName; + U8* mClientData; + }; + + typedef std::list<Record> record_list_t; + std::vector<record_list_t> mFreeList; }; +class LLGLFence +{ +public: + virtual void placeFence() = 0; + virtual void wait() = 0; +}; //============================================================================ // base class - +class LLPrivateMemoryPool ; class LLVertexBuffer : public LLRefCount { public: @@ -84,9 +99,7 @@ public: S32 mIndex; S32 mCount; - MappedRegion(S32 type, S32 index, S32 count) - : mType(type), mIndex(index), mCount(count) - { } + MappedRegion(S32 type, S32 index, S32 count); }; LLVertexBuffer(const LLVertexBuffer& rhs) @@ -105,18 +118,17 @@ public: static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; - static S32 sWeight4Loc; - static BOOL sUseStreamDraw; + static BOOL sUseVAO; static BOOL sPreferStreamDraw; static void initClass(bool use_vbo, bool no_vbo_mapping); static void cleanupClass(); static void setupClientArrays(U32 data_mask); static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm); + static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp); - static void clientCopy(F64 max_time = 0.005); //copy data from client to GL - static void unbind(); //unbind any bound vertex buffer + static void unbind(); //unbind any bound vertex buffer //get the size of a vertex with the given typemask static S32 calcVertexSize(const U32& typemask); @@ -127,24 +139,29 @@ public: static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices); + //WARNING -- when updating these enums you MUST + // 1 - update LLVertexBuffer::sTypeSize + // 2 - add a strider accessor + // 3 - modify LLVertexBuffer::setupVertexBuffer + // 4 - modify LLVertexBuffer::setupClientArray + // 5 - modify LLViewerShaderMgr::mReservedAttribs + // 6 - update LLVertexBuffer::setupVertexArray enum { - TYPE_VERTEX, + TYPE_VERTEX = 0, TYPE_NORMAL, TYPE_TEXCOORD0, TYPE_TEXCOORD1, TYPE_TEXCOORD2, TYPE_TEXCOORD3, TYPE_COLOR, - // These use VertexAttribPointer and should possibly be made generic + TYPE_EMISSIVE, TYPE_BINORMAL, TYPE_WEIGHT, TYPE_WEIGHT4, TYPE_CLOTHWEIGHT, - TYPE_MAX, - TYPE_INDEX, - - //no actual additional data, but indicates position.w is texture index TYPE_TEXTURE_INDEX, + TYPE_MAX, + TYPE_INDEX, }; enum { MAP_VERTEX = (1<<TYPE_VERTEX), @@ -154,6 +171,7 @@ public: MAP_TEXCOORD2 = (1<<TYPE_TEXCOORD2), MAP_TEXCOORD3 = (1<<TYPE_TEXCOORD3), 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_WEIGHT = (1<<TYPE_WEIGHT), @@ -167,24 +185,25 @@ protected: virtual ~LLVertexBuffer(); // use unref() - virtual void setupVertexBuffer(U32 data_mask) const; // pure virtual, called from mapBuffer() + virtual void setupVertexBuffer(U32 data_mask); // pure virtual, called from mapBuffer() + void setupVertexArray(); - void genBuffer(); - void genIndices(); + void genBuffer(U32 size); + void genIndices(U32 size); + bool bindGLBuffer(bool force_bind = false); + bool bindGLIndices(bool force_bind = false); + bool bindGLArray(); void releaseBuffer(); void releaseIndices(); - void createGLBuffer(); - void createGLIndices(); + void createGLBuffer(U32 size); + void createGLIndices(U32 size); void destroyGLBuffer(); void destroyGLIndices(); void updateNumVerts(S32 nverts); void updateNumIndices(S32 nindices); virtual BOOL useVBOs() const; - void unmapBuffer(S32 type); - void freeClientBuffer() ; - void allocateClientVertexBuffer() ; - void allocateClientIndexBuffer() ; - + void unmapBuffer(); + public: LLVertexBuffer(U32 typemask, S32 usage); @@ -193,7 +212,8 @@ public: U8* mapIndexBuffer(S32 index, S32 count, bool map_range); // set for rendering - virtual void setBuffer(U32 data_mask, S32 type = -1); // calls setupVertexBuffer() if data_mask is not 0 + virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0 + void flush(); //flush pending data to GL memory // allocate buffer void allocateBuffer(S32 nverts, S32 nindices, bool create); virtual void resizeBuffer(S32 newnverts, S32 newnindices); @@ -206,29 +226,30 @@ public: // setVertsNorms(verts, norms); // vb->unmapBuffer(); bool getVertexStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getVertexStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false); 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 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 getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false); + BOOL isEmpty() const { return mEmpty; } BOOL isLocked() const { return mVertexLocked || mIndexLocked; } S32 getNumVerts() const { return mNumVerts; } S32 getNumIndices() const { return mNumIndices; } - S32 getRequestedVerts() const { return mRequestedNumVerts; } - S32 getRequestedIndices() const { return mRequestedNumIndices; } - + U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; } U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; } U32 getTypeMask() const { return mTypeMask; } bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); } S32 getSize() const; - S32 getIndicesSize() const { return mNumIndices * sizeof(U16); } + S32 getIndicesSize() const { return mIndicesSize; } U8* getMappedData() const { return mMappedData; } U8* getMappedIndices() const { return mMappedIndexData; } S32 getOffset(S32 type) const { return mOffsets[type]; } @@ -246,36 +267,42 @@ public: protected: S32 mNumVerts; // Number of vertices allocated S32 mNumIndices; // Number of indices allocated - S32 mRequestedNumVerts; // Number of vertices requested - S32 mRequestedNumIndices; // Number of indices requested - + ptrdiff_t mAlignedOffset; ptrdiff_t mAlignedIndexOffset; S32 mSize; + S32 mIndicesSize; U32 mTypeMask; S32 mUsage; // GL usage U32 mGLBuffer; // GL VBO handle U32 mGLIndices; // GL IBO handle + U32 mGLArray; // GL VAO handle + U8* mMappedData; // pointer to currently mapped data (NULL if unmapped) U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped) BOOL mVertexLocked; // if TRUE, vertex buffer is being or has been written to in client memory BOOL mIndexLocked; // if TRUE, index buffer is being or has been written to in client memory BOOL mFinal; // if TRUE, buffer can not be mapped again - BOOL mFilthy; // if TRUE, entire buffer must be copied (used to prevent redundant dirty flags) BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded. - BOOL mResized; // if TRUE, client buffer has been resized and GL buffer has not - BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded) S32 mOffsets[TYPE_MAX]; std::vector<MappedRegion> mMappedVertexRegions; std::vector<MappedRegion> mMappedIndexRegions; + mutable LLGLFence* mFence; + + void placeFence() const; + void waitFence() const; + + +private: + static LLPrivateMemoryPool* sPrivatePoolp ; + public: static S32 sCount; static S32 sGLCount; static S32 sMappedCount; static BOOL sMapped; - static std::vector<U32> sDeleteList; typedef std::list<LLVertexBuffer*> buffer_list_t; static BOOL sDisableVBOMapping; //disable glMapBufferARB @@ -283,6 +310,7 @@ public: static S32 sTypeSize[TYPE_MAX]; static U32 sGLMode[LLRender::NUM_MODES]; static U32 sGLRenderBuffer; + static U32 sGLRenderArray; static U32 sGLRenderIndices; static BOOL sVBOActive; static BOOL sIBOActive; |