diff options
32 files changed, 1945 insertions, 955 deletions
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 76cf9de613..2e6f9e2f71 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -54,6 +54,7 @@ class LLVolumeTriangle; #include "llstrider.h" #include "v4coloru.h" #include "llrefcount.h" +#include "llpointer.h" #include "llfile.h" //============================================================================ @@ -919,6 +920,10 @@ public: LLVector2* mTexCoords; U16* mIndices; + //vertex buffer filled in by LLFace to cache this volume face geometry in vram + // (declared as a LLPointer to LLRefCount to avoid dependency on LLVertexBuffer) + mutable LLPointer<LLRefCount> mVertexBuffer; + std::vector<S32> mEdge; //list of skin weights for rigged volumes diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 45a3b18179..32e4c0d18e 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -81,7 +81,7 @@ void LLCubeMap::initGL() { U32 texname = 0; - LLImageGL::generateTextures(1, &texname); + LLImageGL::generateTextures(LLTexUnit::TT_CUBE_MAP, 1, &texname); for (int i = 0; i < 6; i++) { diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 639d967853..3946c43929 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -249,6 +249,12 @@ PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL; PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL; PFNGLSAMPLEMASKIPROC glSampleMaski = NULL; +//transform feedback (4.0 core) +PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = NULL; +PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = NULL; +PFNGLBINDBUFFERRANGEPROC glBindBufferRange = NULL; + //GL_ARB_debug_output PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL; PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL; @@ -421,6 +427,7 @@ LLGLManager::LLGLManager() : mHasDrawBuffers(FALSE), mHasTextureRectangle(FALSE), mHasTextureMultisample(FALSE), + mHasTransformFeedback(FALSE), mMaxSampleMaskWords(0), mMaxColorTextureSamples(0), mMaxDepthTextureSamples(0), @@ -969,6 +976,7 @@ void LLGLManager::initExtensions() mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts); mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts); + mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE; #if !LL_DARWIN mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); #endif @@ -1208,7 +1216,14 @@ void LLGLManager::initExtensions() glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage3DMultisample"); glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv"); glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski"); - } + } + if (mHasTransformFeedback) + { + glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glBeginTransformFeedback"); + glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glEndTransformFeedback"); + glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) GLH_EXT_GET_PROC_ADDRESS("glTransformFeedbackVaryings"); + glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferRange"); + } if (mHasDebugOutput) { glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB"); @@ -2433,3 +2448,65 @@ LLGLSquashToFarClip::~LLGLSquashToFarClip() gGL.matrixMode(LLRender::MM_MODELVIEW); } + + +LLGLSyncFence::LLGLSyncFence() +{ +#ifdef GL_ARB_sync + mSync = 0; +#endif +} + +LLGLSyncFence::~LLGLSyncFence() +{ +#ifdef GL_ARB_sync + if (mSync) + { + glDeleteSync(mSync); + } +#endif +} + +void LLGLSyncFence::placeFence() +{ +#ifdef GL_ARB_sync + if (mSync) + { + glDeleteSync(mSync); + } + mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +#endif +} + +bool LLGLSyncFence::isCompleted() +{ + bool ret = true; +#ifdef GL_ARB_sync + if (mSync) + { + GLenum status = glClientWaitSync(mSync, 0, 1); + if (status == GL_TIMEOUT_EXPIRED) + { + ret = false; + } + } +#endif + return ret; +} + +void LLGLSyncFence::wait() +{ +#ifdef GL_ARB_sync + if (mSync) + { + while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) + { //track the number of times we've waited here + static S32 waits = 0; + waits++; + } + } +#endif +} + + + diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 9c3a47bd50..c26b75eff7 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -104,6 +104,7 @@ public: BOOL mHasDepthClamp; BOOL mHasTextureRectangle; BOOL mHasTextureMultisample; + BOOL mHasTransformFeedback; S32 mMaxSampleMaskWords; S32 mMaxColorTextureSamples; S32 mMaxDepthTextureSamples; @@ -418,6 +419,31 @@ public: virtual void updateGL() = 0; }; +const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms + +class LLGLFence +{ +public: + virtual void placeFence() = 0; + virtual bool isCompleted() = 0; + virtual void wait() = 0; +}; + +class LLGLSyncFence : public LLGLFence +{ +public: +#ifdef GL_ARB_sync + GLsync mSync; +#endif + + LLGLSyncFence(); + virtual ~LLGLSyncFence(); + + void placeFence(); + bool isCompleted(); + void wait(); +}; + extern LLMatrix4 gGLObliqueProjectionInverse; #include "llglstates.h" diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index d61ec707f0..a0727b8686 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -528,6 +528,13 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; extern PFNGLSAMPLEMASKIPROC glSampleMaski; +//transform feedback (4.0 core) +extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; +extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; +extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; +extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; + + #elif LL_WINDOWS //---------------------------------------------------------------------------- // LL_WINDOWS @@ -759,6 +766,12 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; extern PFNGLSAMPLEMASKIPROC glSampleMaski; +//transform feedback (4.0 core) +extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; +extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; +extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; +extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; + //GL_ARB_debug_output extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB; extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB; diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 4b7e639aed..149e8cc548 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -129,7 +129,9 @@ void LLGLSLShader::unload() } BOOL LLGLSLShader::createShader(vector<string> * attributes, - vector<string> * uniforms) + vector<string> * uniforms, + U32 varying_count, + const char** varyings) { //reloading, reset matrix hash values for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i) @@ -172,6 +174,11 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes, mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1); } + if (varying_count > 0 && varyings) + { + glTransformFeedbackVaryings(mProgramObject, varying_count, varyings, GL_INTERLEAVED_ATTRIBS); + } + // Map attributes and uniforms if (success) { diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 7873fe3c4e..5c68cb46eb 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -76,7 +76,9 @@ public: void unload(); BOOL createShader(std::vector<std::string> * attributes, - std::vector<std::string> * uniforms); + std::vector<std::string> * uniforms, + U32 varying_count = 0, + const char** varyings = NULL); BOOL attachObject(std::string object); void attachObject(GLhandleARB object); void attachObjects(GLhandleARB* objects = NULL, S32 count = 0); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 17131c9d8a..3bdee6cade 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -51,7 +51,8 @@ S32 LLImageGL::sGlobalTextureMemoryInBytes = 0; S32 LLImageGL::sBoundTextureMemoryInBytes = 0; S32 LLImageGL::sCurBoundTextureMemory = 0; S32 LLImageGL::sCount = 0; -std::list<U32> LLImageGL::sDeadTextureList; +std::list<U32> LLImageGL::sDeadTextureList[LLTexUnit::TT_NONE]; +U32 LLImageGL::sCurTexName = 1; BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; F32 LLImageGL::sLastFrameTime = 0.f; @@ -1093,23 +1094,49 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_ } // static -void LLImageGL::generateTextures(S32 numTextures, U32 *textures) +void LLImageGL::generateTextures(LLTexUnit::eTextureType type, S32 numTextures, U32 *textures) { - glGenTextures(numTextures, (GLuint*)textures); + for (S32 i = 0; i < numTextures; ++i) + { + if (!sDeadTextureList[type].empty()) + { + textures[i] = sDeadTextureList[type].front(); + sDeadTextureList[type].pop_front(); + } + else + { + textures[i] = sCurTexName++; + } + } } // static -void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate) +void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, S32 numTextures, U32 *textures, bool immediate) { - for (S32 i = 0; i < numTextures; i++) - { - sDeadTextureList.push_back(textures[i]); - } + for (S32 i = 0; i < numTextures; ++i) + { //remove texture from VRAM by setting its size to zero + gGL.getTexUnit(0)->bindManual(type, textures[i]); - if (immediate) + if (type == LLTexUnit::TT_CUBE_MAP) + { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + else + { + glTexImage2D(LLTexUnit::getInternalType(type), 0, GL_RGBA, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + sDeadTextureList[type].push_back(textures[i]); + } + + /*if (immediate) { LLImageGL::deleteDeadTextures(); - } + }*/ } // static @@ -1234,10 +1261,11 @@ BOOL LLImageGL::createGLTexture() if(mTexName) { - glDeleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ; + LLImageGL::deleteTextures(mBindTarget, 1, (reinterpret_cast<GLuint*>(&mTexName))) ; } - glGenTextures(1, (GLuint*)&mTexName); + + LLImageGL::generateTextures(mBindTarget, 1, &mTexName); stop_glerror(); if (!mTexName) { @@ -1350,7 +1378,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ } else { - LLImageGL::generateTextures(1, &mTexName); + LLImageGL::generateTextures(mBindTarget, 1, &mTexName); stop_glerror(); { llverify(gGL.getTexUnit(0)->bind(this)); @@ -1400,7 +1428,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ decTextureCounter(mTextureMemory, mComponents, mCategory) ; } - LLImageGL::deleteTextures(1, &old_name); + LLImageGL::deleteTextures(mBindTarget,1, &old_name); stop_glerror(); } @@ -1533,7 +1561,7 @@ void LLImageGL::deleteDeadTextures() { bool reset = false; - while (!sDeadTextureList.empty()) + /*while (!sDeadTextureList.empty()) { GLuint tex = sDeadTextureList.front(); sDeadTextureList.pop_front(); @@ -1555,7 +1583,7 @@ void LLImageGL::deleteDeadTextures() glDeleteTextures(1, &tex); stop_glerror(); - } + }*/ if (reset) { @@ -1577,7 +1605,7 @@ void LLImageGL::destroyGLTexture() mTextureMemory = 0; } - LLImageGL::deleteTextures(1, &mTexName); + LLImageGL::deleteTextures(mBindTarget, 1, &mTexName); mTexName = 0; mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. mGLTextureCreated = FALSE ; diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index e23005fe29..8c9cea111e 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -45,8 +45,12 @@ class LLImageGL : public LLRefCount { friend class LLTexUnit; public: - static std::list<U32> sDeadTextureList; + static U32 sCurTexName; + static std::list<U32> sDeadTextureList[LLTexUnit::TT_NONE]; + // These 2 functions replace glGenTextures() and glDeleteTextures() + static void generateTextures(LLTexUnit::eTextureType type, S32 numTextures, U32 *textures); + static void deleteTextures(LLTexUnit::eTextureType type, S32 numTextures, U32 *textures, bool immediate = false); static void deleteDeadTextures(); // Size calculation @@ -96,10 +100,6 @@ public: void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;} void setAllowCompression(bool allow) { mAllowCompression = allow; } - // These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D() - // for tracking purposes and will be deprecated in the future - static void generateTextures(S32 numTextures, U32 *textures); - static void deleteTextures(S32 numTextures, U32 *textures, bool immediate = false); static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true); BOOL createGLTexture() ; diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 780f1dc484..f0dd6f3bd6 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -135,7 +135,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) } U32 tex; - LLImageGL::generateTextures(1, &tex); + LLImageGL::generateTextures(mUsage, 1, &tex); gGL.getTexUnit(0)->bindManual(mUsage, tex); stop_glerror(); @@ -217,7 +217,7 @@ bool LLRenderTarget::allocateDepth() } else { - LLImageGL::generateTextures(1, &mDepth); + LLImageGL::generateTextures(mUsage, 1, &mDepth); gGL.getTexUnit(0)->bindManual(mUsage, mDepth); U32 internal_type = LLTexUnit::getInternalType(mUsage); @@ -294,7 +294,7 @@ void LLRenderTarget::release() } else { - LLImageGL::deleteTextures(1, &mDepth, true); + LLImageGL::deleteTextures(mUsage, 1, &mDepth, true); stop_glerror(); } mDepth = 0; @@ -326,7 +326,7 @@ void LLRenderTarget::release() if (mTex.size() > 0) { sBytesAllocated -= mResX*mResY*4*mTex.size(); - LLImageGL::deleteTextures(mTex.size(), &mTex[0], true); + LLImageGL::deleteTextures(mUsage, mTex.size(), &mTex[0], true); mTex.clear(); } diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 1b179bdbb1..6a218e7734 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -38,7 +38,7 @@ #include "llglslshader.h" #include "llmemory.h" -#define LL_VBO_POOLING 0 +#define LL_VBO_POOLING 1 //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 @@ -67,6 +67,7 @@ U32 wpo2(U32 i) const U32 LL_VBO_BLOCK_SIZE = 2048; +const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024; U32 vbo_block_size(U32 size) { //what block size will fit size? @@ -79,6 +80,7 @@ U32 vbo_block_index(U32 size) return vbo_block_size(size)/LL_VBO_BLOCK_SIZE; } +const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE); //============================================================================ @@ -91,6 +93,11 @@ LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_ U32 LLVBOPool::sBytesPooled = 0; U32 LLVBOPool::sIndexBytesPooled = 0; +U32 LLVBOPool::sCurGLName = 1; + +std::list<U32> LLVertexBuffer::sAvailableVAOName; +U32 LLVertexBuffer::sCurVAOName = 1; + U32 LLVertexBuffer::sAllocatedIndexBytes = 0; U32 LLVertexBuffer::sIndexCount = 0; @@ -115,62 +122,51 @@ bool LLVertexBuffer::sUseStreamDraw = true; bool LLVertexBuffer::sUseVAO = false; bool LLVertexBuffer::sPreferStreamDraw = false; -const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms -class LLGLSyncFence : public LLGLFence +U32 LLVBOPool::genBuffer() { -public: -#ifdef GL_ARB_sync - GLsync mSync; -#endif - - LLGLSyncFence() - { -#ifdef GL_ARB_sync - mSync = 0; -#endif - } + U32 ret = 0; - virtual ~LLGLSyncFence() + if (mGLNamePool.empty()) { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } -#endif + ret = sCurGLName++; } - - void placeFence() + else { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } - mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); -#endif + ret = mGLNamePool.front(); + mGLNamePool.pop_front(); } - 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 - } + return ret; +} +void LLVBOPool::deleteBuffer(U32 name) +{ + LLVertexBuffer::unbind(); -}; + glBindBufferARB(mType, name); + glBufferDataARB(mType, 0, NULL, mUsage); + + llassert(std::find(mGLNamePool.begin(), mGLNamePool.end(), name) == mGLNamePool.end()); + + mGLNamePool.push_back(name); + + LLVertexBuffer::unbind(); +} + + +LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType) +: mUsage(vboUsage), mType(vboType) +{ + mMissCount.resize(LL_VBO_POOL_SEED_COUNT); + std::fill(mMissCount.begin(), mMissCount.end(), 0); +} +static LLFastTimer::DeclareTimer FTM_VBO_GEN_BUFFER("gen buffers"); +static LLFastTimer::DeclareTimer FTM_VBO_BUFFER_DATA("glBufferData"); -volatile U8* LLVBOPool::allocate(U32& name, U32 size) + +volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) { llassert(vbo_block_size(size) == size); @@ -183,14 +179,23 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size) if (mFreeList.size() <= i) { mFreeList.resize(i+1); + mMissCount.resize(i+1); } - if (mFreeList[i].empty()) + if (mFreeList[i].empty() || for_seed) { //make a new buffer - glGenBuffersARB(1, &name); + { + LLFastTimer t(FTM_VBO_GEN_BUFFER); + name = genBuffer(); + } glBindBufferARB(mType, name); + if (!for_seed && i < LL_VBO_POOL_SEED_COUNT) + { //record this miss + mMissCount[i]++; + } + if (mType == GL_ARRAY_BUFFER_ARB) { LLVertexBuffer::sAllocatedBytes += size; @@ -207,10 +212,30 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size) } else { //always use a true hint of static draw when allocating non-client-backed buffers + LLFastTimer t(FTM_VBO_BUFFER_DATA); glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB); } glBindBufferARB(mType, 0); + + if (for_seed) + { //put into pool for future use + llassert(mFreeList.size() > i); + + Record rec; + rec.mGLName = name; + rec.mClientData = ret; + + if (mType == GL_ARRAY_BUFFER_ARB) + { + sBytesPooled += size; + } + else + { + sIndexBytesPooled += size; + } + mFreeList[i].push_back(rec); + } } else { @@ -263,7 +288,7 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) { llassert(vbo_block_size(size) == size); -#if LL_VBO_POOLING +#if 0 && LL_VBO_POOLING U32 i = vbo_block_index(size); @@ -290,7 +315,7 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) mFreeList[i].push_back(rec); } #else //no pooling - glDeleteBuffersARB(1, &name); + deleteBuffer(name); ll_aligned_free_16((U8*) buffer); if (mType == GL_ARRAY_BUFFER_ARB) @@ -304,6 +329,31 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) #endif } +void LLVBOPool::seedPool() +{ + U32 dummy_name = 0; + + if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT) + { + mFreeList.resize(LL_VBO_POOL_SEED_COUNT); + } + + for (U32 i = 0; i < LL_VBO_POOL_SEED_COUNT; i++) + { + if (mMissCount[i] > mFreeList[i].size()) + { + U32 size = i*LL_VBO_BLOCK_SIZE; + + S32 count = mMissCount[i] - mFreeList[i].size(); + for (U32 j = 0; j < count; ++j) + { + allocate(dummy_name, size, true); + } + } + } +} + + void LLVBOPool::cleanup() { U32 size = 1; @@ -316,8 +366,8 @@ void LLVBOPool::cleanup() { Record& r = l.front(); - glDeleteBuffersARB(1, &r.mGLName); - + deleteBuffer(r.mGLName); + if (r.mClientData) { ll_aligned_free_16((void*) r.mClientData); @@ -339,6 +389,9 @@ void LLVBOPool::cleanup() size *= 2; } + + //reset miss counts + std::fill(mMissCount.begin(), mMissCount.end(), 0); } @@ -372,6 +425,39 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = GL_LINE_LOOP, }; +//static +U32 LLVertexBuffer::getVAOName() +{ + U32 ret = 0; + + if (!sAvailableVAOName.empty()) + { + ret = sAvailableVAOName.front(); + sAvailableVAOName.pop_front(); + } + else + { + glGenVertexArrays(1, &ret); + } + + return ret; +} + +//static +void LLVertexBuffer::releaseVAOName(U32 name) +{ + sAvailableVAOName.push_back(name); +} + + +//static +void LLVertexBuffer::seedPools() +{ + sStreamVBOPool.seedPool(); + sDynamicVBOPool.seedPool(); + sStreamIBOPool.seedPool(); + sDynamicIBOPool.seedPool(); +} //static void LLVertexBuffer::setupClientArrays(U32 data_mask) @@ -981,7 +1067,7 @@ LLVertexBuffer::~LLVertexBuffer() if (mGLArray) { #if GL_ARB_vertex_array_object - glDeleteVertexArrays(1, &mGLArray); + releaseVAOName(mGLArray); #endif } @@ -1266,7 +1352,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO)) { #if GL_ARB_vertex_array_object - glGenVertexArrays(1, &mGLArray); + mGLArray = getVAOName(); #endif setupVertexArray(); } @@ -2136,6 +2222,14 @@ void LLVertexBuffer::flush() } } +// bind for transform feedback (quick 'n dirty) +void LLVertexBuffer::bindForFeedback(U32 channel, U32 type, U32 index, U32 count) +{ + U32 offset = mOffsets[type] + sTypeSize[type]*index; + U32 size= (sTypeSize[type]*count); + glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, channel, mGLBuffer, offset, size); +} + // Set for rendering void LLVertexBuffer::setBuffer(U32 data_mask) { diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 7477dec3ad..11fa4ab6a0 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -57,23 +57,28 @@ public: static U32 sBytesPooled; static U32 sIndexBytesPooled; - LLVBOPool(U32 vboUsage, U32 vboType) - : mUsage(vboUsage) - , mType(vboType) - {} + static U32 sCurGLName; + LLVBOPool(U32 vboUsage, U32 vboType); + const U32 mUsage; const U32 mType; //size MUST be a power of 2 - volatile U8* allocate(U32& name, U32 size); + volatile U8* allocate(U32& name, U32 size, bool for_seed = false); //size MUST be the size provided to allocate that returned the given name void release(U32 name, volatile U8* buffer, U32 size); + //batch allocate buffers to be provided to the application on demand + void seedPool(); + //destroy all records in mFreeList void cleanup(); + U32 genBuffer(); + void deleteBuffer(U32 name); + class Record { public: @@ -81,17 +86,15 @@ public: volatile U8* mClientData; }; + std::list<U32> mGLNamePool; + typedef std::list<Record> record_list_t; std::vector<record_list_t> mFreeList; -}; + std::vector<U32> mMissCount; -class LLGLFence -{ -public: - virtual void placeFence() = 0; - virtual void wait() = 0; }; + //============================================================================ // base class class LLPrivateMemoryPool; @@ -125,13 +128,22 @@ public: static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; + static std::list<U32> sAvailableVAOName; + static U32 sCurVAOName; + static bool sUseStreamDraw; static bool sUseVAO; static bool sPreferStreamDraw; + static void seedPools(); + + static U32 getVAOName(); + static void releaseVAOName(U32 name); + static void initClass(bool use_vbo, bool no_vbo_mapping); static void cleanupClass(); static void setupClientArrays(U32 data_mask); + static void pushPositions(U32 mode, const LLVector4a* pos, U32 count); static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm); static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp); @@ -208,7 +220,6 @@ protected: void destroyGLIndices(); void updateNumVerts(S32 nverts); void updateNumIndices(S32 nindices); - bool useVBOs() const; void unmapBuffer(); public: @@ -218,6 +229,8 @@ public: volatile U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range); volatile U8* mapIndexBuffer(S32 index, S32 count, bool map_range); + void bindForFeedback(U32 channel, U32 type, U32 index, U32 count); + // set for rendering virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0 void flush(); //flush pending data to GL memory @@ -240,12 +253,14 @@ public: 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 getTextureIndexStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool useVBOs() const; bool isEmpty() const { return mEmpty; } bool isLocked() const { return mVertexLocked || mIndexLocked; } S32 getNumVerts() const { return mNumVerts; } diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index bd109120cf..8cb456b4fd 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -9162,7 +9162,7 @@ <key>RenderUseVAO</key> <map> <key>Comment</key> - <string>Use GL Vertex Array Objects</string> + <string>[EXPERIMENTAL] Use GL Vertex Array Objects</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -9170,7 +9170,19 @@ <key>Value</key> <integer>0</integer> </map> - <key>RenderVBOMappingDisable</key> + <key>RenderUseTransformFeedback</key> + <map> + <key>Comment</key> + <string>[EXPERIMENTAL] Use transform feedback shaders for LoD updates</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + + <key>RenderVBOMappingDisable</key> <map> <key>Comment</key> <string>Disable VBO glMapBufferARB</string> @@ -12140,6 +12152,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>RenderSynchronousOcclusion</key> + <map> + <key>Comment</key> + <string>Don't let occlusion queries get more than one frame behind (block until they complete).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>RenderDelayVBUpdate</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl new file mode 100644 index 0000000000..b4aab0f3ca --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl @@ -0,0 +1,36 @@ +/** + * @file binormalV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat3 normal_matrix; + +ATTRIBUTE vec3 binormal; + +VARYING vec3 binormal_out; + +void main() +{ + binormal_out = normal_matrix * binormal; +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/colorV.glsl b/indra/newview/app_settings/shaders/class1/transform/colorV.glsl new file mode 100644 index 0000000000..59c4a7d895 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/colorV.glsl @@ -0,0 +1,36 @@ +/** + * @file colorV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform int color_in; + +ATTRIBUTE vec3 position; + +VARYING int color_out; + +void main() +{ + color_out = color_in; +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/normalV.glsl b/indra/newview/app_settings/shaders/class1/transform/normalV.glsl new file mode 100644 index 0000000000..a213aa0ae8 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/normalV.glsl @@ -0,0 +1,36 @@ +/** + * @file normalV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat3 normal_matrix; + +ATTRIBUTE vec3 normal; + +VARYING vec4 normal_out; + +void main() +{ + normal_out = vec4(normalize(normal_matrix * normal), 0.0); +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/positionV.glsl b/indra/newview/app_settings/shaders/class1/transform/positionV.glsl new file mode 100644 index 0000000000..01eed18de4 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/positionV.glsl @@ -0,0 +1,40 @@ +/** + * @file positionV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat4 modelview_matrix; + +uniform int texture_index_in; + +ATTRIBUTE vec3 position; + +VARYING vec3 position_out; +VARYING int texture_index_out; + +void main() +{ + texture_index_out = texture_index_in; + position_out = (modelview_matrix*vec4(position, 1.0)).xyz; +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl b/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl new file mode 100644 index 0000000000..0e074f3cec --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl @@ -0,0 +1,35 @@ +/** + * @file texcoordV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 texcoord_out; + +void main() +{ + texcoord_out = texcoord0; +} + diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 5b62dbc560..a56e71baa8 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -405,6 +405,12 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) { LLDrawInfo& params = **k; + if ((params.mVertexBuffer->getTypeMask() & mask) != mask) + { //FIXME! + //llwarns << "Missing required components, skipping render batch." << llendl; + continue; + } + LLRenderPass::applyModelMatrix(params); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 97b832520d..2824b1a32d 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -50,6 +50,8 @@ #include "pipeline.h" #include "llviewerregion.h" #include "llviewerwindow.h" +#include "llviewershadermgr.h" + #define LL_MAX_INDICES_COUNT 1000000 @@ -57,7 +59,6 @@ BOOL LLFace::sSafeRenderSelect = TRUE; // FALSE #define DOTVEC(a,b) (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2]) - /* For each vertex, given: B - binormal @@ -1111,6 +1112,73 @@ bool LLFace::canRenderAsMask() } +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_VOLUME("Volume VB Cache"); + +//static +void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf) +{ + LLFastTimer t(FTM_FACE_GEOM_VOLUME); + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL; + + if (vf.mWeights) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + LLVertexBuffer* buff = new LLVertexBuffer(mask, GL_STATIC_DRAW_ARB); + vf.mVertexBuffer = buff; + + buff->allocateBuffer(vf.mNumVertices, 0, true); + + LLStrider<LLVector4a> f_vert; + LLStrider<LLVector3> f_binorm; + LLStrider<LLVector3> f_norm; + LLStrider<LLVector2> f_tc; + + buff->getBinormalStrider(f_binorm); + buff->getVertexStrider(f_vert); + buff->getNormalStrider(f_norm); + buff->getTexCoord0Strider(f_tc); + + for (U32 i = 0; i < vf.mNumVertices; ++i) + { + *f_vert++ = vf.mPositions[i]; + (*f_binorm++).set(vf.mBinormals[i].getF32ptr()); + *f_tc++ = vf.mTexCoords[i]; + (*f_norm++).set(vf.mNormals[i].getF32ptr()); + } + + if (vf.mWeights) + { + LLStrider<LLVector4> f_wght; + buff->getWeight4Strider(f_wght); + for (U32 i = 0; i < vf.mNumVertices; ++i) + { + (*f_wght++).set(vf.mWeights[i].getF32ptr()); + } + } + + buff->flush(); +} + +//helper function for pushing primitives for transform shaders and cleaning up +//uninitialized data on the tail, plus tracking number of expected primitives +void push_for_transform(LLVertexBuffer* buff, U32 source_count, U32 dest_count) +{ + if (source_count > 0 && dest_count >= source_count) //protect against possible U32 wrapping + { + //push source primitives + buff->drawArrays(LLRender::POINTS, 0, source_count); + U32 tail = dest_count-source_count; + for (U32 i = 0; i < tail; ++i) + { //copy last source primitive into each element in tail + buff->drawArrays(LLRender::POINTS, source_count-1, 1); + } + gPipeline.mTransformFeedbackPrimitives += dest_count; + } +} + static LLFastTimer::DeclareTimer FTM_FACE_GET_GEOM("Face Geom"); static LLFastTimer::DeclareTimer FTM_FACE_GEOM_POSITION("Position"); static LLFastTimer::DeclareTimer FTM_FACE_GEOM_NORMAL("Normal"); @@ -1128,7 +1196,6 @@ static LLFastTimer::DeclareTimer FTM_FACE_TEX_DEFAULT("Default"); static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK("Quick"); static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_NO_XFORM("No Xform"); static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_XFORM("Xform"); - static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_PLANAR("Quick Planar"); BOOL LLFace::getGeometryVolume(const LLVolume& volume, @@ -1301,17 +1368,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLMatrix4a mat_normal; mat_normal.loadu(mat_norm_in); - //if it's not fullbright and has no normals, bake sunlight based on face normal - //bool bake_sunlight = !getTextureEntry()->getFullbright() && - // !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; - + bool do_xform = false; if (rebuild_tcoord) { - LLFastTimer t(FTM_FACE_GEOM_TEXTURE); - bool do_xform; - if (tep) { r = tep->getRotation(); @@ -1340,599 +1400,757 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { do_xform = false; } + } + + static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback"); + + if (use_transform_feedback && + gTransformPositionProgram.mProgramObject && //transform shaders are loaded + mVertexBuffer->useVBOs() && //target buffer is in VRAM + !rebuild_weights && //TODO: add support for weights + !volume.isUnique()) //source volume is NOT flexi + { //use transform feedback to pack vertex buffer + + LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get(); + + if (vf.mVertexBuffer.isNull() || buff->getNumVerts() != vf.mNumVertices) + { + mVObjp->getVolume()->genBinormals(f); + LLFace::cacheFaceInVRAM(vf); + buff = (LLVertexBuffer*) vf.mVertexBuffer.get(); + } + + LLGLSLShader* cur_shader = LLGLSLShader::sCurBoundShaderPtr; + + gGL.pushMatrix(); + gGL.loadMatrix((GLfloat*) mat_vert_in.mMatrix); + + if (rebuild_pos) + { + LLFastTimer t(FTM_FACE_GEOM_POSITION); + gTransformPositionProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount); + + U8 index = mTextureIndex < 255 ? mTextureIndex : 0; + + S32 val = 0.f; + U8* vp = (U8*) &val; + vp[0] = index; + vp[1] = 0; + vp[2] = 0; + vp[3] = 0; + + gTransformPositionProgram.uniform1i("texture_index_in", val); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + + push_for_transform(buff, vf.mNumVertices, mGeomCount); + + glEndTransformFeedback(); + } + + if (rebuild_color) + { + LLFastTimer t(FTM_FACE_GEOM_COLOR); + gTransformColorProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount); + + S32 val = *((S32*) color.mV); + + gTransformColorProgram.uniform1i("color_in", val); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } + + if (rebuild_emissive) + { + LLFastTimer t(FTM_FACE_GEOM_EMISSIVE); + gTransformColorProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount); + + U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); + + S32 glow32 = glow | + (glow << 8) | + (glow << 16) | + (glow << 24); + + gTransformColorProgram.uniform1i("color_in", glow32); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } + + if (rebuild_normal) + { + LLFastTimer t(FTM_FACE_GEOM_NORMAL); + gTransformNormalProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount); - //bump setup - LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); - LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f); - LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_NORMAL); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } - LLQuaternion bump_quat; - if (mDrawablep->isActive()) + if (rebuild_binormal) { - bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); + LLFastTimer t(FTM_FACE_GEOM_BINORMAL); + gTransformBinormalProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_BINORMAL, mGeomIndex, mGeomCount); + + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_BINORMAL); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); } - - if (bump_code) + + if (rebuild_tcoord) { - mVObjp->getVolume()->genBinormals(f); - F32 offset_multiple; - switch( bump_code ) - { - case BE_NO_BUMP: - offset_multiple = 0.f; - break; - case BE_BRIGHTNESS: - case BE_DARKNESS: - if( mTexture.notNull() && mTexture->hasGLTexture()) - { - // Offset by approximately one texel - S32 cur_discard = mTexture->getDiscardLevel(); - S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); - max_size <<= cur_discard; - const F32 ARTIFICIAL_OFFSET = 2.f; - offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; - } - else - { - offset_multiple = 1.f/256; - } - break; + LLFastTimer t(FTM_FACE_GEOM_TEXTURE); + gTransformTexCoordProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount); + + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); - default: // Standard bumpmap textures. Assumed to be 256x256 - offset_multiple = 1.f / 256; - break; - } + bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); - F32 s_scale = 1.f; - F32 t_scale = 1.f; - if( tep ) + if (do_bump) { - tep->getScale( &s_scale, &t_scale ); - } - // Use the nudged south when coming from above sun angle, such - // that emboss mapping always shows up on the upward faces of cubes when - // it's noon (since a lot of builders build with the sun forced to noon). - LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; - LLVector3 moon_ray = gSky.getMoonDirection(); - LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; - - bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV); - bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV); + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD1, mGeomIndex, mGeomCount); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } } - U8 texgen = getTextureEntry()->getTexGen(); - if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) - { //planar texgen needs binormals - mVObjp->getVolume()->genBinormals(f); + glBindBufferARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0); + + gGL.popMatrix(); + + if (cur_shader) + { + cur_shader->bind(); } + } + else + { + //if it's not fullbright and has no normals, bake sunlight based on face normal + //bool bake_sunlight = !getTextureEntry()->getFullbright() && + // !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - U8 tex_mode = 0; - - if (isState(TEXTURE_ANIM)) + if (rebuild_tcoord) { - LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; - tex_mode = vobj->mTexAnimMode; + LLFastTimer t(FTM_FACE_GEOM_TEXTURE); + + //bump setup + LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); + LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f); + LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f); - if (!tex_mode) + LLQuaternion bump_quat; + if (mDrawablep->isActive()) { - clearState(TEXTURE_ANIM); + bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); } - else + + if (bump_code) { - os = ot = 0.f; - r = 0.f; - cos_ang = 1.f; - sin_ang = 0.f; - ms = mt = 1.f; + mVObjp->getVolume()->genBinormals(f); + F32 offset_multiple; + switch( bump_code ) + { + case BE_NO_BUMP: + offset_multiple = 0.f; + break; + case BE_BRIGHTNESS: + case BE_DARKNESS: + if( mTexture.notNull() && mTexture->hasGLTexture()) + { + // Offset by approximately one texel + S32 cur_discard = mTexture->getDiscardLevel(); + S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); + max_size <<= cur_discard; + const F32 ARTIFICIAL_OFFSET = 2.f; + offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; + } + else + { + offset_multiple = 1.f/256; + } + break; - do_xform = false; + default: // Standard bumpmap textures. Assumed to be 256x256 + offset_multiple = 1.f / 256; + break; + } + + F32 s_scale = 1.f; + F32 t_scale = 1.f; + if( tep ) + { + tep->getScale( &s_scale, &t_scale ); + } + // Use the nudged south when coming from above sun angle, such + // that emboss mapping always shows up on the upward faces of cubes when + // it's noon (since a lot of builders build with the sun forced to noon). + LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; + LLVector3 moon_ray = gSky.getMoonDirection(); + LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; + + bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV); + bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV); } - if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) - { //don't override texture transform during tc bake - tex_mode = 0; + U8 texgen = getTextureEntry()->getTexGen(); + if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) + { //planar texgen needs binormals + mVObjp->getVolume()->genBinormals(f); } - } - LLVector4a scalea; - scalea.load3(scale.mV); + U8 tex_mode = 0; + + if (isState(TEXTURE_ANIM)) + { + LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; + tex_mode = vobj->mTexAnimMode; + + if (!tex_mode) + { + clearState(TEXTURE_ANIM); + } + else + { + os = ot = 0.f; + r = 0.f; + cos_ang = 1.f; + sin_ang = 0.f; + ms = mt = 1.f; - bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); - bool do_tex_mat = tex_mode && mTextureMatrix; + do_xform = false; + } - if (!in_atlas && !do_bump) - { //not in atlas or not bump mapped, might be able to do a cheap update - mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount); + if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) + { //don't override texture transform during tc bake + tex_mode = 0; + } + } - if (texgen != LLTextureEntry::TEX_GEN_PLANAR) - { - LLFastTimer t(FTM_FACE_TEX_QUICK); - if (!do_tex_mat) + LLVector4a scalea; + scalea.load3(scale.mV); + + bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); + bool do_tex_mat = tex_mode && mTextureMatrix; + + if (!in_atlas && !do_bump) + { //not in atlas or not bump mapped, might be able to do a cheap update + mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount); + + if (texgen != LLTextureEntry::TEX_GEN_PLANAR) { - if (!do_xform) + LLFastTimer t(FTM_FACE_TEX_QUICK); + if (!do_tex_mat) { - LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM); - LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); - } - else - { - LLFastTimer t(FTM_FACE_TEX_QUICK_XFORM); - F32* dst = (F32*) tex_coords.get(); - LLVector4a* src = (LLVector4a*) vf.mTexCoords; + if (!do_xform) + { + LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM); + LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); + } + else + { + LLFastTimer t(FTM_FACE_TEX_QUICK_XFORM); + F32* dst = (F32*) tex_coords.get(); + LLVector4a* src = (LLVector4a*) vf.mTexCoords; - LLVector4a trans; - trans.splat(-0.5f); + LLVector4a trans; + trans.splat(-0.5f); - LLVector4a rot0; - rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang); + LLVector4a rot0; + rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang); - LLVector4a rot1; - rot1.set(sin_ang, cos_ang, sin_ang, cos_ang); + LLVector4a rot1; + rot1.set(sin_ang, cos_ang, sin_ang, cos_ang); - LLVector4a scale; - scale.set(ms, mt, ms, mt); + LLVector4a scale; + scale.set(ms, mt, ms, mt); - LLVector4a offset; - offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f); + LLVector4a offset; + offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f); - LLVector4Logical mask; - mask.clear(); - mask.setElement<2>(); - mask.setElement<3>(); + LLVector4Logical mask; + mask.clear(); + mask.setElement<2>(); + mask.setElement<3>(); - U32 count = num_vertices/2 + num_vertices%2; + U32 count = num_vertices/2 + num_vertices%2; - for (S32 i = 0; i < count; i++) + for (S32 i = 0; i < count; i++) + { + LLVector4a res = *src++; + xform4a(res, trans, mask, rot0, rot1, offset, scale); + res.store4a(dst); + dst += 4; + } + } + } + else + { //do tex mat, no texgen, no atlas, no bump + for (S32 i = 0; i < num_vertices; i++) { - LLVector4a res = *src++; - xform4a(res, trans, mask, rot0, rot1, offset, scale); - res.store4a(dst); - dst += 4; + LLVector2 tc(vf.mTexCoords[i]); + //LLVector4a& norm = vf.mNormals[i]; + //LLVector4a& center = *(vf.mCenter); + + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; + *tex_coords++ = tc; } } } else - { //do tex mat, no texgen, no atlas, no bump - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - //LLVector4a& norm = vf.mNormals[i]; - //LLVector4a& center = *(vf.mCenter); - - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; - *tex_coords++ = tc; - } - } - } - else - { //no bump, no atlas, tex gen planar - LLFastTimer t(FTM_FACE_TEX_QUICK_PLANAR); - if (do_tex_mat) - { - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - LLVector4a& norm = vf.mNormals[i]; - LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; - vec.mul(scalea); - planarProjection(tc, norm, center, vec); + { //no bump, no atlas, tex gen planar + LLFastTimer t(FTM_FACE_TEX_QUICK_PLANAR); + if (do_tex_mat) + { + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + LLVector4a& norm = vf.mNormals[i]; + LLVector4a& center = *(vf.mCenter); + LLVector4a vec = vf.mPositions[i]; + vec.mul(scalea); + planarProjection(tc, norm, center, vec); - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; - *tex_coords++ = tc; + *tex_coords++ = tc; + } } - } - else - { - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - LLVector4a& norm = vf.mNormals[i]; - LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; - vec.mul(scalea); - planarProjection(tc, norm, center, vec); + else + { + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + LLVector4a& norm = vf.mNormals[i]; + LLVector4a& center = *(vf.mCenter); + LLVector4a vec = vf.mPositions[i]; + vec.mul(scalea); + planarProjection(tc, norm, center, vec); - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - *tex_coords++ = tc; + *tex_coords++ = tc; + } } } - } - if (map_range) - { - mVertexBuffer->flush(); + if (map_range) + { + mVertexBuffer->flush(); + } } - } - else - { //either bump mapped or in atlas, just do the whole expensive loop - LLFastTimer t(FTM_FACE_TEX_DEFAULT); - mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, map_range); + else + { //either bump mapped or in atlas, just do the whole expensive loop + LLFastTimer t(FTM_FACE_TEX_DEFAULT); + mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, map_range); - std::vector<LLVector2> bump_tc; + std::vector<LLVector2> bump_tc; - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); - LLVector4a& norm = vf.mNormals[i]; + LLVector4a& norm = vf.mNormals[i]; - LLVector4a& center = *(vf.mCenter); + LLVector4a& center = *(vf.mCenter); - if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) - { - LLVector4a vec = vf.mPositions[i]; + if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) + { + LLVector4a vec = vf.mPositions[i]; - vec.mul(scalea); + vec.mul(scalea); + + switch (texgen) + { + case LLTextureEntry::TEX_GEN_PLANAR: + planarProjection(tc, norm, center, vec); + break; + case LLTextureEntry::TEX_GEN_SPHERICAL: + sphericalProjection(tc, norm, center, vec); + break; + case LLTextureEntry::TEX_GEN_CYLINDRICAL: + cylindricalProjection(tc, norm, center, vec); + break; + default: + break; + } + } - switch (texgen) + if (tex_mode && mTextureMatrix) { - case LLTextureEntry::TEX_GEN_PLANAR: - planarProjection(tc, norm, center, vec); + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; + } + else + { + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + } + + if(in_atlas) + { + // + //manually calculate tex-coord per vertex for varying address modes. + //should be removed if shader can handle this. + // + + S32 int_part = 0 ; + switch(mTexture->getAddressMode()) + { + case LLTexUnit::TAM_CLAMP: + if(tc.mV[0] < 0.f) + { + tc.mV[0] = 0.f ; + } + else if(tc.mV[0] > 1.f) + { + tc.mV[0] = 1.f; + } + + if(tc.mV[1] < 0.f) + { + tc.mV[1] = 0.f ; + } + else if(tc.mV[1] > 1.f) + { + tc.mV[1] = 1.f; + } break; - case LLTextureEntry::TEX_GEN_SPHERICAL: - sphericalProjection(tc, norm, center, vec); + case LLTexUnit::TAM_MIRROR: + if(tc.mV[0] < 0.f) + { + tc.mV[0] = -tc.mV[0] ; + } + int_part = (S32)tc.mV[0] ; + if(int_part & 1) //odd number + { + tc.mV[0] = int_part + 1 - tc.mV[0] ; + } + else //even number + { + tc.mV[0] -= int_part ; + } + + if(tc.mV[1] < 0.f) + { + tc.mV[1] = -tc.mV[1] ; + } + int_part = (S32)tc.mV[1] ; + if(int_part & 1) //odd number + { + tc.mV[1] = int_part + 1 - tc.mV[1] ; + } + else //even number + { + tc.mV[1] -= int_part ; + } break; - case LLTextureEntry::TEX_GEN_CYLINDRICAL: - cylindricalProjection(tc, norm, center, vec); + case LLTexUnit::TAM_WRAP: + if(tc.mV[0] > 1.f) + tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ; + else if(tc.mV[0] < -1.f) + tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ; + + if(tc.mV[1] > 1.f) + tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ; + else if(tc.mV[1] < -1.f) + tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ; + + if(tc.mV[0] < 0.f) + { + tc.mV[0] = 1.0f + tc.mV[0] ; + } + if(tc.mV[1] < 0.f) + { + tc.mV[1] = 1.0f + tc.mV[1] ; + } break; default: break; - } - } + } + + tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ; + tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ; + } + - if (tex_mode && mTextureMatrix) - { - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; + *tex_coords++ = tc; + if (do_bump) + { + bump_tc.push_back(tc); + } } - else + + if (map_range) { - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + mVertexBuffer->flush(); } - if(in_atlas) + if (do_bump) { - // - //manually calculate tex-coord per vertex for varying address modes. - //should be removed if shader can handle this. - // - - S32 int_part = 0 ; - switch(mTexture->getAddressMode()) + mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, map_range); + + for (S32 i = 0; i < num_vertices; i++) { - case LLTexUnit::TAM_CLAMP: - if(tc.mV[0] < 0.f) - { - tc.mV[0] = 0.f ; - } - else if(tc.mV[0] > 1.f) - { - tc.mV[0] = 1.f; - } - - if(tc.mV[1] < 0.f) - { - tc.mV[1] = 0.f ; - } - else if(tc.mV[1] > 1.f) - { - tc.mV[1] = 1.f; - } - break; - case LLTexUnit::TAM_MIRROR: - if(tc.mV[0] < 0.f) - { - tc.mV[0] = -tc.mV[0] ; - } - int_part = (S32)tc.mV[0] ; - if(int_part & 1) //odd number - { - tc.mV[0] = int_part + 1 - tc.mV[0] ; - } - else //even number + LLVector4a tangent; + tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]); + + LLMatrix4a tangent_to_object; + tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]); + LLVector4a t; + tangent_to_object.rotate(binormal_dir, t); + LLVector4a binormal; + mat_normal.rotate(t, binormal); + + //VECTORIZE THIS + if (mDrawablep->isActive()) { - tc.mV[0] -= int_part ; + LLVector3 t; + t.set(binormal.getF32ptr()); + t *= bump_quat; + binormal.load3(t.mV); } - if(tc.mV[1] < 0.f) - { - tc.mV[1] = -tc.mV[1] ; - } - int_part = (S32)tc.mV[1] ; - if(int_part & 1) //odd number - { - tc.mV[1] = int_part + 1 - tc.mV[1] ; - } - else //even number - { - tc.mV[1] -= int_part ; - } - break; - case LLTexUnit::TAM_WRAP: - if(tc.mV[0] > 1.f) - tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ; - else if(tc.mV[0] < -1.f) - tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ; - - if(tc.mV[1] > 1.f) - tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ; - else if(tc.mV[1] < -1.f) - tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ; - - if(tc.mV[0] < 0.f) - { - tc.mV[0] = 1.0f + tc.mV[0] ; - } - if(tc.mV[1] < 0.f) - { - tc.mV[1] = 1.0f + tc.mV[1] ; - } - break; - default: - break; + binormal.normalize3fast(); + LLVector2 tc = bump_tc[i]; + tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); + + *tex_coords2++ = tc; } - - tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ; - tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ; - } - - - *tex_coords++ = tc; - if (do_bump) - { - bump_tc.push_back(tc); - } - } - - if (map_range) - { - mVertexBuffer->flush(); - } - if (do_bump) - { - mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, map_range); - - for (S32 i = 0; i < num_vertices; i++) - { - LLVector4a tangent; - tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]); - - LLMatrix4a tangent_to_object; - tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]); - LLVector4a t; - tangent_to_object.rotate(binormal_dir, t); - LLVector4a binormal; - mat_normal.rotate(t, binormal); - - //VECTORIZE THIS - if (mDrawablep->isActive()) + if (map_range) { - LLVector3 t; - t.set(binormal.getF32ptr()); - t *= bump_quat; - binormal.load3(t.mV); + mVertexBuffer->flush(); } - - binormal.normalize3fast(); - LLVector2 tc = bump_tc[i]; - tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); - - *tex_coords2++ = tc; - } - - if (map_range) - { - mVertexBuffer->flush(); } } } - } - if (rebuild_pos) - { - LLFastTimer t(FTM_FACE_GEOM_POSITION); - llassert(num_vertices > 0); + if (rebuild_pos) + { + LLFastTimer t(FTM_FACE_GEOM_POSITION); + llassert(num_vertices > 0); - mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range); + mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range); - LLMatrix4a mat_vert; - mat_vert.loadu(mat_vert_in); + LLMatrix4a mat_vert; + mat_vert.loadu(mat_vert_in); - LLVector4a* src = vf.mPositions; - volatile F32* dst = (volatile F32*) vert.get(); + LLVector4a* src = vf.mPositions; + volatile F32* dst = (volatile F32*) vert.get(); - volatile F32* end = dst+num_vertices*4; - LLVector4a res; + volatile F32* end = dst+num_vertices*4; + LLVector4a res; - LLVector4a texIdx; + LLVector4a texIdx; - U8 index = mTextureIndex < 255 ? mTextureIndex : 0; + U8 index = mTextureIndex < 255 ? mTextureIndex : 0; - F32 val = 0.f; - U8* vp = (U8*) &val; - vp[0] = index; - vp[1] = 0; - vp[2] = 0; - vp[3] = 0; + F32 val = 0.f; + U8* vp = (U8*) &val; + vp[0] = index; + vp[1] = 0; + vp[2] = 0; + vp[3] = 0; - llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); + llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); - LLVector4Logical mask; - mask.clear(); - mask.setElement<3>(); + LLVector4Logical mask; + mask.clear(); + mask.setElement<3>(); - texIdx.set(0,0,0,val); - - { - LLFastTimer t(FTM_FACE_POSITION_STORE); - LLVector4a tmp; + texIdx.set(0,0,0,val); - do - { - mat_vert.affineTransform(*src++, res); - tmp.setSelectWithMask(mask, texIdx, res); - tmp.store4a((F32*) dst); - dst += 4; + { + LLFastTimer t(FTM_FACE_POSITION_STORE); + LLVector4a tmp; + + do + { + mat_vert.affineTransform(*src++, res); + tmp.setSelectWithMask(mask, texIdx, res); + tmp.store4a((F32*) dst); + dst += 4; + } + while(dst < end); } - while(dst < end); - } - { - LLFastTimer t(FTM_FACE_POSITION_PAD); - S32 aligned_pad_vertices = mGeomCount - num_vertices; - res.set(res[0], res[1], res[2], 0.f); + { + LLFastTimer t(FTM_FACE_POSITION_PAD); + S32 aligned_pad_vertices = mGeomCount - num_vertices; + res.set(res[0], res[1], res[2], 0.f); + + while (aligned_pad_vertices > 0) + { + --aligned_pad_vertices; + res.store4a((F32*) dst); + dst += 4; + } + } - while (aligned_pad_vertices > 0) + if (map_range) { - --aligned_pad_vertices; - res.store4a((F32*) dst); - dst += 4; + mVertexBuffer->flush(); } } - if (map_range) - { - mVertexBuffer->flush(); - } - } - if (rebuild_normal) - { - LLFastTimer t(FTM_FACE_GEOM_NORMAL); - mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range); - F32* normals = (F32*) norm.get(); + if (rebuild_normal) + { + LLFastTimer t(FTM_FACE_GEOM_NORMAL); + mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range); + F32* normals = (F32*) norm.get(); - for (S32 i = 0; i < num_vertices; i++) - { - LLVector4a normal; - mat_normal.rotate(vf.mNormals[i], normal); - normal.normalize3fast(); - normal.store4a(normals); - normals += 4; - } + for (S32 i = 0; i < num_vertices; i++) + { + LLVector4a normal; + mat_normal.rotate(vf.mNormals[i], normal); + normal.normalize3fast(); + normal.store4a(normals); + normals += 4; + } - if (map_range) - { - mVertexBuffer->flush(); + if (map_range) + { + mVertexBuffer->flush(); + } } - } - if (rebuild_binormal) - { - LLFastTimer t(FTM_FACE_GEOM_BINORMAL); - mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range); - F32* binormals = (F32*) binorm.get(); + if (rebuild_binormal) + { + LLFastTimer t(FTM_FACE_GEOM_BINORMAL); + mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range); + F32* binormals = (F32*) binorm.get(); - for (S32 i = 0; i < num_vertices; i++) - { - LLVector4a binormal; - mat_normal.rotate(vf.mBinormals[i], binormal); - binormal.normalize3fast(); - binormal.store4a(binormals); - binormals += 4; - } + for (S32 i = 0; i < num_vertices; i++) + { + LLVector4a binormal; + mat_normal.rotate(vf.mBinormals[i], binormal); + binormal.normalize3fast(); + binormal.store4a(binormals); + binormals += 4; + } - if (map_range) - { - mVertexBuffer->flush(); + if (map_range) + { + mVertexBuffer->flush(); + } } - } - if (rebuild_weights && vf.mWeights) - { - LLFastTimer t(FTM_FACE_GEOM_WEIGHTS); - mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range); - F32* weights = (F32*) wght.get(); - LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); - if (map_range) + if (rebuild_weights && vf.mWeights) { - mVertexBuffer->flush(); + LLFastTimer t(FTM_FACE_GEOM_WEIGHTS); + mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range); + F32* weights = (F32*) wght.get(); + LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); + if (map_range) + { + mVertexBuffer->flush(); + } } - } - if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) ) - { - LLFastTimer t(FTM_FACE_GEOM_COLOR); - mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range); + if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) ) + { + LLFastTimer t(FTM_FACE_GEOM_COLOR); + mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range); - LLVector4a src; + LLVector4a src; - U32 vec[4]; - vec[0] = vec[1] = vec[2] = vec[3] = color.mAll; + U32 vec[4]; + vec[0] = vec[1] = vec[2] = vec[3] = color.mAll; - src.loadua((F32*) vec); + src.loadua((F32*) vec); - F32* dst = (F32*) colors.get(); - S32 num_vecs = num_vertices/4; - if (num_vertices%4 > 0) - { - ++num_vecs; - } + F32* dst = (F32*) colors.get(); + S32 num_vecs = num_vertices/4; + if (num_vertices%4 > 0) + { + ++num_vecs; + } - for (S32 i = 0; i < num_vecs; i++) - { - src.store4a(dst); - dst += 4; - } + for (S32 i = 0; i < num_vecs; i++) + { + src.store4a(dst); + dst += 4; + } - if (map_range) - { - mVertexBuffer->flush(); + if (map_range) + { + mVertexBuffer->flush(); + } } - } - if (rebuild_emissive) - { - LLFastTimer t(FTM_FACE_GEOM_EMISSIVE); - LLStrider<LLColor4U> emissive; - mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range); + if (rebuild_emissive) + { + LLFastTimer t(FTM_FACE_GEOM_EMISSIVE); + LLStrider<LLColor4U> emissive; + mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range); - U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); + U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); - LLVector4a src; + LLVector4a src; - U32 glow32 = glow | - (glow << 8) | - (glow << 16) | - (glow << 24); + U32 glow32 = glow | + (glow << 8) | + (glow << 16) | + (glow << 24); - U32 vec[4]; - vec[0] = vec[1] = vec[2] = vec[3] = glow32; + U32 vec[4]; + vec[0] = vec[1] = vec[2] = vec[3] = glow32; - src.loadua((F32*) vec); + src.loadua((F32*) vec); - F32* dst = (F32*) emissive.get(); - S32 num_vecs = num_vertices/4; - if (num_vertices%4 > 0) - { - ++num_vecs; - } + F32* dst = (F32*) emissive.get(); + S32 num_vecs = num_vertices/4; + if (num_vertices%4 > 0) + { + ++num_vecs; + } - for (S32 i = 0; i < num_vecs; i++) - { - src.store4a(dst); - dst += 4; - } + for (S32 i = 0; i < num_vecs; i++) + { + src.store4a(dst); + dst += 4; + } - if (map_range) - { - mVertexBuffer->flush(); + if (map_range) + { + mVertexBuffer->flush(); + } } } + if (rebuild_tcoord) { mTexExtents[0].setVec(0,0); diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 82e4ab61b7..c31f357693 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -83,6 +83,8 @@ public: static void initClass(); + static void cacheFaceInVRAM(const LLVolumeFace& vf); + public: LLFace(LLDrawable* drawablep, LLViewerObject* objp) { init(drawablep, objp); } ~LLFace() { destroy(); } diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 7448f2bb2a..b362fa340c 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -540,7 +540,7 @@ LLFloaterModelPreview::~LLFloaterModelPreview() if (mGLName) { - LLImageGL::deleteTextures(1, &mGLName ); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 1, &mGLName ); } delete mStatusLock; diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index e886f83671..06604fba6f 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -85,12 +85,32 @@ static F32 sCurMaxTexPriority = 1.f; class LLOcclusionQueryPool : public LLGLNamePool { +public: + LLOcclusionQueryPool() + { + mCurQuery = 1; + } + protected: + + std::list<GLuint> mAvailableName; + GLuint mCurQuery; + virtual GLuint allocateName() { - GLuint name; - glGenQueriesARB(1, &name); - return name; + GLuint ret = 0; + + if (!mAvailableName.empty()) + { + ret = mAvailableName.front(); + mAvailableName.pop_front(); + } + else + { + ret = mCurQuery++; + } + + return ret; } virtual void releaseName(GLuint name) @@ -98,7 +118,8 @@ protected: #if LL_TRACK_PENDING_OCCLUSION_QUERIES LLSpatialGroup::sPendingQueries.erase(name); #endif - glDeleteQueriesARB(1, &name); + llassert(std::find(mAvailableName.begin(), mAvailableName.end(), name) == mAvailableName.end()); + mAvailableName.push_back(name); } }; @@ -687,6 +708,11 @@ void LLSpatialGroup::rebuildGeom() if (!isDead()) { mSpatialPartition->rebuildGeom(this); + + if (isState(LLSpatialGroup::MESH_DIRTY)) + { + gPipeline.markMeshDirty(this); + } } } @@ -1587,7 +1613,7 @@ BOOL LLSpatialGroup::rebound() } static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Wait"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Occlusion Wait"); void LLSpatialGroup::checkOcclusion() { @@ -1607,7 +1633,9 @@ void LLSpatialGroup::checkOcclusion() { glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) + static LLCachedControl<bool> wait_for_query(gSavedSettings, "RenderSynchronousOcclusion"); + + if (wait_for_query && mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) { //query was issued last frame, wait until it's available S32 max_loop = 1024; LLFastTimer t(FTM_OCCLUSION_WAIT); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 001d8e184a..99ed04d1af 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -755,12 +755,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) gTextureList.updateImages(max_image_decode_time); } - { + /*{ LLFastTimer t(FTM_IMAGE_UPDATE_DELETE); //remove dead textures from GL LLImageGL::deleteDeadTextures(); stop_glerror(); - } + }*/ } LLGLState::checkStates(); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 0473e2b7c0..485e3af62d 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -63,6 +63,13 @@ bool LLViewerShaderMgr::sSkipReload = false; LLVector4 gShinyOrigin; +//transform shaders +LLGLSLShader gTransformPositionProgram; +LLGLSLShader gTransformTexCoordProgram; +LLGLSLShader gTransformNormalProgram; +LLGLSLShader gTransformColorProgram; +LLGLSLShader gTransformBinormalProgram; + //utility shaders LLGLSLShader gOcclusionProgram; LLGLSLShader gCustomAlphaProgram; @@ -438,7 +445,8 @@ void LLViewerShaderMgr::setShaders() S32 wl_class = 2; S32 water_class = 2; S32 deferred_class = 0; - + S32 transform_class = gGLManager.mHasTransformFeedback ? 1 : 0; + if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && gSavedSettings.getBOOL("RenderDeferred") && gSavedSettings.getBOOL("RenderAvatarVP") && @@ -476,6 +484,7 @@ void LLViewerShaderMgr::setShaders() gSky.mVOSkyp->forceSkyUpdate(); } + // Load lighting shaders mVertexShaderLevel[SHADER_LIGHTING] = light_class; mVertexShaderLevel[SHADER_INTERFACE] = light_class; @@ -485,6 +494,7 @@ void LLViewerShaderMgr::setShaders() mVertexShaderLevel[SHADER_EFFECT] = effect_class; mVertexShaderLevel[SHADER_WINDLIGHT] = wl_class; mVertexShaderLevel[SHADER_DEFERRED] = deferred_class; + mVertexShaderLevel[SHADER_TRANSFORM] = transform_class; BOOL loaded = loadBasicShaders(); @@ -518,6 +528,11 @@ void LLViewerShaderMgr::setShaders() if (loaded) { + loaded = loadTransformShaders(); + } + + if (loaded) + { // Load max avatar shaders to set the max level mVertexShaderLevel[SHADER_AVATAR] = 3; mMaxAvatarShaderLevel = 3; @@ -733,6 +748,12 @@ void LLViewerShaderMgr::unloadShaders() gDeferredSkinnedBumpProgram.unload(); gDeferredSkinnedAlphaProgram.unload(); + gTransformPositionProgram.unload(); + gTransformTexCoordProgram.unload(); + gTransformNormalProgram.unload(); + gTransformColorProgram.unload(); + gTransformBinormalProgram.unload(); + mVertexShaderLevel[SHADER_LIGHTING] = 0; mVertexShaderLevel[SHADER_OBJECT] = 0; mVertexShaderLevel[SHADER_AVATAR] = 0; @@ -741,6 +762,7 @@ void LLViewerShaderMgr::unloadShaders() mVertexShaderLevel[SHADER_INTERFACE] = 0; mVertexShaderLevel[SHADER_EFFECT] = 0; mVertexShaderLevel[SHADER_WINDLIGHT] = 0; + mVertexShaderLevel[SHADER_TRANSFORM] = 0; gPipeline.mVertexShadersLoaded = 0; } @@ -2763,6 +2785,95 @@ BOOL LLViewerShaderMgr::loadShadersWindLight() return success; } +BOOL LLViewerShaderMgr::loadTransformShaders() +{ + BOOL success = TRUE; + + if (mVertexShaderLevel[SHADER_TRANSFORM] < 1) + { + gTransformPositionProgram.unload(); + gTransformTexCoordProgram.unload(); + gTransformNormalProgram.unload(); + gTransformColorProgram.unload(); + gTransformBinormalProgram.unload(); + return TRUE; + } + + if (success) + { + gTransformPositionProgram.mName = "Position Transform Shader"; + gTransformPositionProgram.mShaderFiles.clear(); + gTransformPositionProgram.mShaderFiles.push_back(make_pair("transform/positionV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformPositionProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "position_out", + "texture_index_out", + }; + + success = gTransformPositionProgram.createShader(NULL, NULL, 2, varyings); + } + + if (success) + { + gTransformTexCoordProgram.mName = "TexCoord Transform Shader"; + gTransformTexCoordProgram.mShaderFiles.clear(); + gTransformTexCoordProgram.mShaderFiles.push_back(make_pair("transform/texcoordV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformTexCoordProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "texcoord_out", + }; + + success = gTransformTexCoordProgram.createShader(NULL, NULL, 1, varyings); + } + + if (success) + { + gTransformNormalProgram.mName = "Normal Transform Shader"; + gTransformNormalProgram.mShaderFiles.clear(); + gTransformNormalProgram.mShaderFiles.push_back(make_pair("transform/normalV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformNormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "normal_out", + }; + + success = gTransformNormalProgram.createShader(NULL, NULL, 1, varyings); + } + + if (success) + { + gTransformColorProgram.mName = "Color Transform Shader"; + gTransformColorProgram.mShaderFiles.clear(); + gTransformColorProgram.mShaderFiles.push_back(make_pair("transform/colorV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformColorProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "color_out", + }; + + success = gTransformColorProgram.createShader(NULL, NULL, 1, varyings); + } + + if (success) + { + gTransformBinormalProgram.mName = "Binormal Transform Shader"; + gTransformBinormalProgram.mShaderFiles.clear(); + gTransformBinormalProgram.mShaderFiles.push_back(make_pair("transform/binormalV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformBinormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "binormal_out", + }; + + success = gTransformBinormalProgram.createShader(NULL, NULL, 1, varyings); + } + + + return success; +} + std::string LLViewerShaderMgr::getShaderDirPrefix(void) { return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "shaders/class"); diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index d10aba85c7..03d686e07e 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -54,6 +54,7 @@ public: BOOL loadShadersWater(); BOOL loadShadersInterface(); BOOL loadShadersWindLight(); + BOOL loadTransformShaders(); std::vector<S32> mVertexShaderLevel; S32 mMaxAvatarShaderLevel; @@ -69,6 +70,7 @@ public: SHADER_WINDLIGHT, SHADER_WATER, SHADER_DEFERRED, + SHADER_TRANSFORM, SHADER_COUNT }; @@ -209,6 +211,15 @@ inline bool operator != (LLViewerShaderMgr::shader_iter const & a, LLViewerShade extern LLVector4 gShinyOrigin; +//transform shaders +extern LLGLSLShader gTransformPositionProgram; +extern LLGLSLShader gTransformTexCoordProgram; +extern LLGLSLShader gTransformNormalProgram; +extern LLGLSLShader gTransformColorProgram; +extern LLGLSLShader gTransformBinormalProgram; + + + //utility shaders extern LLGLSLShader gOcclusionProgram; extern LLGLSLShader gCustomAlphaProgram; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index c221c7fdd8..083ad622cd 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -896,7 +896,7 @@ void LLVOAvatar::deleteLayerSetCaches(bool clearAll) } if (mBakedTextureDatas[i].mMaskTexName) { - glDeleteTextures(1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName)); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName)); mBakedTextureDatas[i].mMaskTexName = 0 ; } } @@ -7394,7 +7394,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture } U32 gl_name; - LLImageGL::generateTextures(1, &gl_name ); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, 1, &gl_name ); stop_glerror(); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name); @@ -7431,7 +7431,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture maskData->mLastDiscardLevel = discard_level; if (self->mBakedTextureDatas[baked_index].mMaskTexName) { - LLImageGL::deleteTextures(1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); } self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name; found_texture_id = true; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index f063653cc5..b6d4d6b56f 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -2605,7 +2605,7 @@ void LLVOAvatarSelf::deleteScratchTextures() namep; namep = sScratchTexNames.getNextData() ) { - LLImageGL::deleteTextures(1, (U32 *)namep ); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 1, (U32 *)namep ); stop_glerror(); } diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index b6adc776cc..fca97987a2 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -125,7 +125,7 @@ S32 LLVOPartGroup::findAvailableVBSlot() void LLVOPartGroup::freeVBSlot(S32 idx) { llassert(idx < LL_MAX_PARTICLE_COUNT && idx >= 0); - llassert(sVBSlotCursor > sVBSlotFree); + //llassert(sVBSlotCursor > sVBSlotFree); if (sVBSlotCursor > sVBSlotFree) { diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 75ab807c39..6bb4e9e63b 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -639,7 +639,7 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { LLViewerObject::idleUpdate(agent, world, time); - static LLFastTimer::DeclareTimer ftm("Volume"); + static LLFastTimer::DeclareTimer ftm("Volume Idle"); LLFastTimer t(ftm); if (mDead || mDrawable.isNull()) @@ -1089,9 +1089,33 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo } } + + static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback"); + + bool cache_in_vram = use_transform_feedback && gTransformPositionProgram.mProgramObject && + (!mVolumeImpl || !mVolumeImpl->isVolumeUnique()); + + if (cache_in_vram) + { //this volume might be used as source data for a transform object, put it in vram + LLVolume* volume = getVolume(); + for (S32 i = 0; i < volume->getNumFaces(); ++i) + { + const LLVolumeFace& face = volume->getVolumeFace(i); + if (face.mVertexBuffer.notNull()) + { //already cached + break; + } + volume->genBinormals(i); + LLFace::cacheFaceInVRAM(face); + } + } + + return TRUE; } + + return FALSE; } @@ -3945,8 +3969,11 @@ bool can_batch_texture(LLFace* facep) return true; } +static LLFastTimer::DeclareTimer FTM_REGISTER_FACE("Register Face"); + void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type) { + LLFastTimer t(FTM_REGISTER_FACE); LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) @@ -4091,7 +4118,9 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) } -static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume VB"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_FACE_LIST("Build Face List"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_GEN_DRAW_INFO("Gen Draw Info"); static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) { @@ -4122,6 +4151,8 @@ static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { + + if (group->changeLOD()) { group->mLastUpdateDistance = group->mDistance; @@ -4133,17 +4164,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate) { - LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); - rebuildMesh(group); } return; } + LLFastTimer ftm(FTM_REBUILD_VOLUME_VB); + group->mBuilt = 1.f; - LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); - LLVOAvatar* pAvatarVO = NULL; LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); @@ -4192,371 +4221,375 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) bool emissive = false; - //get all the faces into a list - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) { - LLDrawable* drawablep = *drawable_iter; - - if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) + LLFastTimer t(FTM_REBUILD_VOLUME_FACE_LIST); + + //get all the faces into a list + for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) { - continue; - } + LLDrawable* drawablep = *drawable_iter; + + if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) + { + continue; + } - if (drawablep->isAnimating()) - { //fall back to stream draw for animating verts - useage = GL_STREAM_DRAW_ARB; - } + if (drawablep->isAnimating()) + { //fall back to stream draw for animating verts + useage = GL_STREAM_DRAW_ARB; + } - LLVOVolume* vobj = drawablep->getVOVolume(); + LLVOVolume* vobj = drawablep->getVOVolume(); - if (!vobj) - { - continue; - } + if (!vobj) + { + continue; + } - if (vobj->isMesh() && - (vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled())) - { - continue; - } + if (vobj->isMesh() && + (vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled())) + { + continue; + } - LLVolume* volume = vobj->getVolume(); - if (volume) - { - const LLVector3& scale = vobj->getScale(); - group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); - } + LLVolume* volume = vobj->getVolume(); + if (volume) + { + const LLVector3& scale = vobj->getScale(); + group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); + } - llassert_always(vobj); - vobj->updateTextureVirtualSize(true); - vobj->preRebuild(); + llassert_always(vobj); + vobj->updateTextureVirtualSize(true); + vobj->preRebuild(); - drawablep->clearState(LLDrawable::HAS_ALPHA); + drawablep->clearState(LLDrawable::HAS_ALPHA); - bool rigged = vobj->isAttachment() && - vobj->isMesh() && - gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); + bool rigged = vobj->isAttachment() && + vobj->isMesh() && + gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); - bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); + bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); - bool is_rigged = false; + bool is_rigged = false; - //for each face - for (S32 i = 0; i < drawablep->getNumFaces(); i++) - { - LLFace* facep = drawablep->getFace(i); - if (!facep) + //for each face + for (S32 i = 0; i < drawablep->getNumFaces(); i++) { - continue; - } + LLFace* facep = drawablep->getFace(i); + if (!facep) + { + continue; + } - //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render - // batch, it will recover its vertex buffer reference from the spatial group - facep->setVertexBuffer(NULL); + //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render + // batch, it will recover its vertex buffer reference from the spatial group + facep->setVertexBuffer(NULL); - //sum up face verts and indices - drawablep->updateFaceSize(i); + //sum up face verts and indices + drawablep->updateFaceSize(i); - if (rigged) - { - if (!facep->isState(LLFace::RIGGED)) - { //completely reset vertex buffer - facep->clearVertexBuffer(); - } + if (rigged) + { + if (!facep->isState(LLFace::RIGGED)) + { //completely reset vertex buffer + facep->clearVertexBuffer(); + } - facep->setState(LLFace::RIGGED); - is_rigged = true; + facep->setState(LLFace::RIGGED); + is_rigged = true; - //get drawpool of avatar with rigged face - LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); + //get drawpool of avatar with rigged face + LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); - //Determine if we've received skininfo that contains an - //alternate bind matrix - if it does then apply the translational component - //to the joints of the avatar. - bool pelvisGotSet = false; + //Determine if we've received skininfo that contains an + //alternate bind matrix - if it does then apply the translational component + //to the joints of the avatar. + bool pelvisGotSet = false; - if ( pAvatarVO ) - { - LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); - const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); - - if ( pSkinData ) + if ( pAvatarVO ) { - const int bindCnt = pSkinData->mAlternateBindMatrix.size(); - if ( bindCnt > 0 ) - { - const int jointCnt = pSkinData->mJointNames.size(); - const F32 pelvisZOffset = pSkinData->mPelvisOffset; - bool fullRig = (jointCnt>=20) ? true : false; - if ( fullRig ) - { - for ( int i=0; i<jointCnt; ++i ) + LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); + const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); + + if ( pSkinData ) + { + const int bindCnt = pSkinData->mAlternateBindMatrix.size(); + if ( bindCnt > 0 ) + { + const int jointCnt = pSkinData->mJointNames.size(); + const F32 pelvisZOffset = pSkinData->mPelvisOffset; + bool fullRig = (jointCnt>=20) ? true : false; + if ( fullRig ) { - std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); - //llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl; - LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint ); - if ( pJoint && pJoint->getId() != currentId ) - { - pJoint->setId( currentId ); - const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); - //Set the joint position - pJoint->storeCurrentXform( jointPos ); - //If joint is a pelvis then handle old/new pelvis to foot values - if ( lookingForJoint == "mPelvis" ) - { + for ( int i=0; i<jointCnt; ++i ) + { + std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); + //llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl; + LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint ); + if ( pJoint && pJoint->getId() != currentId ) + { + pJoint->setId( currentId ); + const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); + //Set the joint position pJoint->storeCurrentXform( jointPos ); - if ( !pAvatarVO->hasPelvisOffset() ) - { - pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); - //Trigger to rebuild viewer AV - pelvisGotSet = true; + //If joint is a pelvis then handle old/new pelvis to foot values + if ( lookingForJoint == "mPelvis" ) + { + pJoint->storeCurrentXform( jointPos ); + if ( !pAvatarVO->hasPelvisOffset() ) + { + pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); + //Trigger to rebuild viewer AV + pelvisGotSet = true; + } } - } + } } - } - } + } + } } } - } - //If we've set the pelvis to a new position we need to also rebuild some information that the - //viewer does at launch (e.g. body size etc.) - if ( pelvisGotSet ) - { - pAvatarVO->postPelvisSetRecalc(); - } - - if (pool) - { - const LLTextureEntry* te = facep->getTextureEntry(); - - //remove face from old pool if it exists - LLDrawPool* old_pool = facep->getPool(); - if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR) + //If we've set the pelvis to a new position we need to also rebuild some information that the + //viewer does at launch (e.g. body size etc.) + if ( pelvisGotSet ) { - ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep); + pAvatarVO->postPelvisSetRecalc(); } - //add face to new pool - LLViewerTexture* tex = facep->getTexture(); - U32 type = gPipeline.getPoolTypeFromTE(te, tex); - - if (type == LLDrawPool::POOL_ALPHA) + if (pool) { - if (te->getColor().mV[3] > 0.f) + const LLTextureEntry* te = facep->getTextureEntry(); + + //remove face from old pool if it exists + LLDrawPool* old_pool = facep->getPool(); + if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR) + { + ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep); + } + + //add face to new pool + LLViewerTexture* tex = facep->getTexture(); + U32 type = gPipeline.getPoolTypeFromTE(te, tex); + + if (type == LLDrawPool::POOL_ALPHA) + { + if (te->getColor().mV[3] > 0.f) + { + if (te->getFullbright()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA); + } + } + } + else if (te->getShiny()) { if (te->getFullbright()) { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA); + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY); } else { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA); + if (LLPipeline::sRenderDeferred) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY); + } } } - } - else if (te->getShiny()) - { - if (te->getFullbright()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY); - } else { - if (LLPipeline::sRenderDeferred) + if (te->getFullbright()) { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); } else { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY); + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); } } - } - else - { - if (te->getFullbright()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); - } - else + + if (te->getGlow()) { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW); } - } - if (te->getGlow()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW); - } - - if (LLPipeline::sRenderDeferred) - { - if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright()) + if (LLPipeline::sRenderDeferred) { - if (te->getBumpmap()) + if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright()) { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP); - } - else - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); + if (te->getBumpmap()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); + } } } } - } - continue; - } - else - { - if (facep->isState(LLFace::RIGGED)) - { //face is not rigged but used to be, remove from rigged face pool - LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool(); - if (pool) - { - pool->removeRiggedFace(facep); - } - facep->clearState(LLFace::RIGGED); + continue; } - } - - - if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) - { - facep->clearVertexBuffer(); - continue; - } - - cur_total += facep->getGeomCount(); - - if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) - { - const LLTextureEntry* te = facep->getTextureEntry(); - LLViewerTexture* tex = facep->getTexture(); - - if (te->getGlow() >= 1.f/255.f) - { - emissive = true; - } - - if (facep->isState(LLFace::TEXTURE_ANIM)) + else { - if (!vobj->mTexAnimMode) - { - facep->clearState(LLFace::TEXTURE_ANIM); + if (facep->isState(LLFace::RIGGED)) + { //face is not rigged but used to be, remove from rigged face pool + LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool(); + if (pool) + { + pool->removeRiggedFace(facep); + } + facep->clearState(LLFace::RIGGED); } } - BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); - U32 type = gPipeline.getPoolTypeFromTE(te, tex); - if (type != LLDrawPool::POOL_ALPHA && force_simple) - { - type = LLDrawPool::POOL_SIMPLE; - } - facep->setPoolType(type); - if (vobj->isHUDAttachment()) + if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) { - facep->setState(LLFace::FULLBRIGHT); + facep->clearVertexBuffer(); + continue; } - if (vobj->mTextureAnimp && vobj->mTexAnimMode) + cur_total += facep->getGeomCount(); + + if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) { - if (vobj->mTextureAnimp->mFace <= -1) + const LLTextureEntry* te = facep->getTextureEntry(); + LLViewerTexture* tex = facep->getTexture(); + + if (te->getGlow() >= 1.f/255.f) { - S32 face; - for (face = 0; face < vobj->getNumTEs(); face++) - { - LLFace * facep = drawablep->getFace(face); - if (facep) - { - facep->setState(LLFace::TEXTURE_ANIM); - } - } + emissive = true; } - else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs()) + + if (facep->isState(LLFace::TEXTURE_ANIM)) { - LLFace * facep = drawablep->getFace(vobj->mTextureAnimp->mFace); - if (facep) + if (!vobj->mTexAnimMode) { - facep->setState(LLFace::TEXTURE_ANIM); + facep->clearState(LLFace::TEXTURE_ANIM); } } - } - if (type == LLDrawPool::POOL_ALPHA) - { - if (facep->canRenderAsMask()) - { //can be treated as alpha mask - simple_faces.push_back(facep); - } - else + BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); + U32 type = gPipeline.getPoolTypeFromTE(te, tex); + if (type != LLDrawPool::POOL_ALPHA && force_simple) { - if (te->getColor().mV[3] > 0.f) - { //only treat as alpha in the pipeline if < 100% transparent - drawablep->setState(LLDrawable::HAS_ALPHA); - } - alpha_faces.push_back(facep); + type = LLDrawPool::POOL_SIMPLE; } - } - else - { - if (drawablep->isState(LLDrawable::REBUILD_VOLUME)) + facep->setPoolType(type); + + if (vobj->isHUDAttachment()) { - facep->mLastUpdateTime = gFrameTimeSeconds; + facep->setState(LLFace::FULLBRIGHT); } - if (gPipeline.canUseWindLightShadersOnObjects() - && LLPipeline::sRenderBump) + if (vobj->mTextureAnimp && vobj->mTexAnimMode) { - if (te->getBumpmap()) - { //needs normal + binormal - bump_faces.push_back(facep); + if (vobj->mTextureAnimp->mFace <= -1) + { + S32 face; + for (face = 0; face < vobj->getNumTEs(); face++) + { + LLFace * facep = drawablep->getFace(face); + if (facep) + { + facep->setState(LLFace::TEXTURE_ANIM); + } + } } - else if (te->getShiny() || !te->getFullbright()) - { //needs normal + else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs()) + { + LLFace * facep = drawablep->getFace(vobj->mTextureAnimp->mFace); + if (facep) + { + facep->setState(LLFace::TEXTURE_ANIM); + } + } + } + + if (type == LLDrawPool::POOL_ALPHA) + { + if (facep->canRenderAsMask()) + { //can be treated as alpha mask simple_faces.push_back(facep); } - else - { //doesn't need normal - facep->setState(LLFace::FULLBRIGHT); - fullbright_faces.push_back(facep); + else + { + if (te->getColor().mV[3] > 0.f) + { //only treat as alpha in the pipeline if < 100% transparent + drawablep->setState(LLDrawable::HAS_ALPHA); + } + alpha_faces.push_back(facep); } } else { - if (te->getBumpmap() && LLPipeline::sRenderBump) - { //needs normal + binormal - bump_faces.push_back(facep); + if (drawablep->isState(LLDrawable::REBUILD_VOLUME)) + { + facep->mLastUpdateTime = gFrameTimeSeconds; } - else if ((te->getShiny() && LLPipeline::sRenderBump) || - !(te->getFullbright() || bake_sunlight)) - { //needs normal - simple_faces.push_back(facep); + + if (gPipeline.canUseWindLightShadersOnObjects() + && LLPipeline::sRenderBump) + { + if (te->getBumpmap()) + { //needs normal + binormal + bump_faces.push_back(facep); + } + else if (te->getShiny() || !te->getFullbright()) + { //needs normal + simple_faces.push_back(facep); + } + else + { //doesn't need normal + facep->setState(LLFace::FULLBRIGHT); + fullbright_faces.push_back(facep); + } } - else - { //doesn't need normal - facep->setState(LLFace::FULLBRIGHT); - fullbright_faces.push_back(facep); + else + { + if (te->getBumpmap() && LLPipeline::sRenderBump) + { //needs normal + binormal + bump_faces.push_back(facep); + } + else if ((te->getShiny() && LLPipeline::sRenderBump) || + !(te->getFullbright() || bake_sunlight)) + { //needs normal + simple_faces.push_back(facep); + } + else + { //doesn't need normal + facep->setState(LLFace::FULLBRIGHT); + fullbright_faces.push_back(facep); + } } } } + else + { //face has no renderable geometry + facep->clearVertexBuffer(); + } } - else - { //face has no renderable geometry - facep->clearVertexBuffer(); - } - } - if (is_rigged) - { - drawablep->setState(LLDrawable::RIGGED); - } - else - { - drawablep->clearState(LLDrawable::RIGGED); + if (is_rigged) + { + drawablep->setState(LLDrawable::RIGGED); + } + else + { + drawablep->clearState(LLDrawable::RIGGED); + } } } @@ -4623,15 +4656,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } -static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry"); -static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM_PARTIAL("Terse Rebuild"); void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { llassert(group); if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY)) { - LLFastTimer tm(FTM_VOLUME_GEOM); + LLFastTimer ftm(FTM_REBUILD_VOLUME_VB); + LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers + S32 num_mapped_veretx_buffer = LLVertexBuffer::sMappedCount ; group->mBuilt = 1.f; @@ -4640,7 +4673,6 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) { - LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL); LLDrawable* drawablep = *drawable_iter; if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) ) @@ -4747,8 +4779,20 @@ struct CompareBatchBreakerModified } }; +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_SORT("Draw Info Face Sort"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FACE_SIZE("Face Sizing"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_ALLOCATE("Allocate VB"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FIND_VB("Find VB"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB"); + + + + + void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort, BOOL batch_textures) { + LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); + U32 buffer_usage = group->mBufferUsage; #if LL_DARWIN @@ -4766,15 +4810,18 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); max_vertices = llmin(max_vertices, (U32) 65535); - if (!distance_sort) { - //sort faces by things that break batches - std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified()); - } - else - { - //sort faces by distance - std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater()); + LLFastTimer t(FTM_GEN_DRAW_INFO_SORT); + if (!distance_sort) + { + //sort faces by things that break batches + std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified()); + } + else + { + //sort faces by distance + std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater()); + } } bool hud_group = group->isHUDGroup() ; @@ -4839,57 +4886,86 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: std::vector<LLViewerTexture*> texture_list; - if (batch_textures) { - U8 cur_tex = 0; - facep->setTextureIndex(cur_tex); - texture_list.push_back(tex); - - //if (can_batch_texture(facep)) + LLFastTimer t(FTM_GEN_DRAW_INFO_FACE_SIZE); + if (batch_textures) { - while (i != faces.end()) + U8 cur_tex = 0; + facep->setTextureIndex(cur_tex); + texture_list.push_back(tex); + + //if (can_batch_texture(facep)) { - facep = *i; - if (facep->getTexture() != tex) + while (i != faces.end()) { - if (distance_sort) - { //textures might be out of order, see if texture exists in current batch - bool found = false; - for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx) - { - if (facep->getTexture() == texture_list[tex_idx]) + facep = *i; + if (facep->getTexture() != tex) + { + if (distance_sort) + { //textures might be out of order, see if texture exists in current batch + bool found = false; + for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx) { - cur_tex = tex_idx; - found = true; - break; + if (facep->getTexture() == texture_list[tex_idx]) + { + cur_tex = tex_idx; + found = true; + break; + } } - } - if (!found) + if (!found) + { + cur_tex = texture_list.size(); + } + } + else { - cur_tex = texture_list.size(); + cur_tex++; } - } - else - { - cur_tex++; - } - if (!can_batch_texture(facep)) - { //face is bump mapped or has an animated texture matrix -- can't - //batch more than 1 texture at a time - break; + if (!can_batch_texture(facep)) + { //face is bump mapped or has an animated texture matrix -- can't + //batch more than 1 texture at a time + break; + } + + if (cur_tex >= texture_index_channels) + { //cut batches when index channels are depleted + break; + } + + tex = facep->getTexture(); + + texture_list.push_back(tex); } - if (cur_tex >= texture_index_channels) - { //cut batches when index channels are depleted + if (geom_count + facep->getGeomCount() > max_vertices) + { //cut batches on geom count too big break; } - tex = facep->getTexture(); + ++i; + index_count += facep->getIndicesCount(); + geom_count += facep->getGeomCount(); - texture_list.push_back(tex); + facep->setTextureIndex(cur_tex); } + } + + tex = texture_list[0]; + } + else + { + while (i != faces.end() && + (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex))) + { + facep = *i; + + + //face has no texture index + facep->mDrawInfo = NULL; + facep->setTextureIndex(255); if (geom_count + facep->getGeomCount() > max_vertices) { //cut batches on geom count too big @@ -4899,40 +4975,16 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: ++i; index_count += facep->getIndicesCount(); geom_count += facep->getGeomCount(); - - facep->setTextureIndex(cur_tex); } } - - tex = texture_list[0]; } - else - { - while (i != faces.end() && - (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex))) - { - facep = *i; - - - //face has no texture index - facep->mDrawInfo = NULL; - facep->setTextureIndex(255); - - if (geom_count + facep->getGeomCount() > max_vertices) - { //cut batches on geom count too big - break; - } - ++i; - index_count += facep->getIndicesCount(); - geom_count += facep->getGeomCount(); - } - } - //create/delete/resize vertex buffer if needed LLVertexBuffer* buffer = NULL; + if (group->mBufferUsage != GL_DYNAMIC_DRAW_ARB) { //try to find a buffer to reuse + LLFastTimer t(FTM_GEN_DRAW_INFO_FIND_VB); LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter); if (found_iter != group->mBufferMap[mask].end()) @@ -4943,23 +4995,28 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: } } } - - if (!buffer || !buffer->isWriteable()) - { //create new buffer if needed - buffer = createVertexBuffer(mask, buffer_usage); - buffer->allocateBuffer(geom_count, index_count, TRUE); - } - else - { //resize pre-existing buffer - if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != buffer_usage || - buffer->getTypeMask() != mask) - { + + { + LLFastTimer t(FTM_GEN_DRAW_INFO_ALLOCATE); + + if (!buffer || !buffer->isWriteable()) + { //create new buffer if needed buffer = createVertexBuffer(mask, buffer_usage); buffer->allocateBuffer(geom_count, index_count, TRUE); } - else - { - buffer->resizeBuffer(geom_count, index_count); + else + { //resize pre-existing buffer + LLFastTimer t(FTM_GEN_DRAW_INFO_RESIZE_VB); + if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != buffer_usage || + buffer->getTypeMask() != mask) + { + buffer = createVertexBuffer(mask, buffer_usage); + buffer->allocateBuffer(geom_count, index_count, TRUE); + } + else + { + buffer->resizeBuffer(geom_count, index_count); + } } } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 34dd15c9a1..a76a32f834 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -51,6 +51,10 @@ // newview includes #include "llagent.h" #include "llagentcamera.h" +#include "llappviewer.h" +#include "lltexturecache.h" +#include "lltexturefetch.h" +#include "llimageworker.h" #include "lldrawable.h" #include "lldrawpoolalpha.h" #include "lldrawpoolavatar.h" @@ -403,9 +407,11 @@ LLPipeline::LLPipeline() : mInitialized(FALSE), mVertexShadersEnabled(FALSE), mVertexShadersLoaded(0), + mTransformFeedbackPrimitives(0), mRenderDebugFeatureMask(0), mRenderDebugMask(0), mOldRenderDebugMask(0), + mMeshDirtyQueryObject(0), mGroupQ1Locked(false), mGroupQ2Locked(false), mResetVertexBuffers(false), @@ -693,6 +699,12 @@ void LLPipeline::destroyGL() { LLVertexBuffer::sEnableVBOs = FALSE; } + + if (mMeshDirtyQueryObject) + { + glDeleteQueriesARB(1, &mMeshDirtyQueryObject); + mMeshDirtyQueryObject = 0; + } } static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); @@ -1028,19 +1040,19 @@ void LLPipeline::releaseGLBuffers() if (mNoiseMap) { - LLImageGL::deleteTextures(1, &mNoiseMap); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 1, &mNoiseMap); mNoiseMap = 0; } if (mTrueNoiseMap) { - LLImageGL::deleteTextures(1, &mTrueNoiseMap); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 1, &mTrueNoiseMap); mTrueNoiseMap = 0; } if (mLightFunc) { - LLImageGL::deleteTextures(1, &mLightFunc); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 1, &mLightFunc); mLightFunc = 0; } @@ -1131,7 +1143,7 @@ void LLPipeline::createGLBuffers() noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f; } - LLImageGL::generateTextures(1, &mNoiseMap); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, 1, &mNoiseMap); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap); LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise, false); @@ -1147,7 +1159,7 @@ void LLPipeline::createGLBuffers() noise[i] = ll_frand()*2.0-1.0; } - LLImageGL::generateTextures(1, &mTrueNoiseMap); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, 1, &mTrueNoiseMap); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap); LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise, false); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); @@ -1183,7 +1195,7 @@ void LLPipeline::createGLBuffers() } } - LLImageGL::generateTextures(1, &mLightFunc); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, 1, &mLightFunc); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, lg, false); gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); @@ -2450,6 +2462,8 @@ BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) return update_complete; } +static LLFastTimer::DeclareTimer FTM_SEED_VBO_POOLS("Seed VBO Pool"); + void LLPipeline::updateGL() { while (!LLGLUpdate::sGLQ.empty()) @@ -2459,6 +2473,11 @@ void LLPipeline::updateGL() glu->mInQ = FALSE; LLGLUpdate::sGLQ.pop_front(); } + + { //seed VBO Pools + LLFastTimer t(FTM_SEED_VBO_POOLS); + LLVertexBuffer::seedPools(); + } } void LLPipeline::rebuildPriorityGroups() @@ -2822,6 +2841,11 @@ void LLPipeline::processPartitionQ() mPartitionQ.clear(); } +void LLPipeline::markMeshDirty(LLSpatialGroup* group) +{ + mMeshDirtyGroup.push_back(group); +} + void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) { LLMemType mt(LLMemType::MTYPE_PIPELINE); @@ -3430,15 +3454,43 @@ void LLPipeline::postSort(LLCamera& camera) } } } + + //flush particle VB + LLVOPartGroup::sVB->flush(); + + /*bool use_transform_feedback = gTransformPositionProgram.mProgramObject && !mMeshDirtyGroup.empty(); + + if (use_transform_feedback) + { //place a query around potential transform feedback code for synchronization + mTransformFeedbackPrimitives = 0; + + if (!mMeshDirtyQueryObject) + { + glGenQueriesARB(1, &mMeshDirtyQueryObject); + } + + glBeginQueryARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, mMeshDirtyQueryObject); + }*/ + + //pack vertex buffers for groups that chose to delay their updates + for (LLSpatialGroup::sg_vector_t::iterator iter = mMeshDirtyGroup.begin(); iter != mMeshDirtyGroup.end(); ++iter) + { + (*iter)->rebuildMesh(); + } + + /*if (use_transform_feedback) + { + glEndQueryARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); + }*/ + + mMeshDirtyGroup.clear(); + if (!sShadowRender) { std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater()); } - //flush particle VB - LLVOPartGroup::sVB->flush(); - llpushcallstacks ; // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender) @@ -3525,6 +3577,33 @@ void LLPipeline::postSort(LLCamera& camera) } } + /*static LLFastTimer::DeclareTimer FTM_TRANSFORM_WAIT("Transform Fence"); + static LLFastTimer::DeclareTimer FTM_TRANSFORM_DO_WORK("Transform Work"); + if (use_transform_feedback) + { //using transform feedback, wait for transform feedback to complete + LLFastTimer t(FTM_TRANSFORM_WAIT); + + S32 done = 0; + //glGetQueryivARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_CURRENT_QUERY, &count); + + glGetQueryObjectivARB(mMeshDirtyQueryObject, GL_QUERY_RESULT_AVAILABLE, &done); + + while (!done) + { + { + LLFastTimer t(FTM_TRANSFORM_DO_WORK); + F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f); + //do some useful work while we wait + LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread + LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread + LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread + } + glGetQueryObjectivARB(mMeshDirtyQueryObject, GL_QUERY_RESULT_AVAILABLE, &done); + } + + mTransformFeedbackPrimitives = 0; + }*/ + //LLSpatialGroup::sNoDelete = FALSE; llpushcallstacks ; } diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 252fe1346c..9eebe3831f 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -161,6 +161,7 @@ public: void markRebuild(LLSpatialGroup* group, BOOL priority = FALSE); void markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag = LLDrawable::REBUILD_ALL, BOOL priority = FALSE); void markPartitionMove(LLDrawable* drawablep); + void markMeshDirty(LLSpatialGroup* group); //get the object between start and end that's closest to start. LLViewerObject* lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end, @@ -592,6 +593,7 @@ public: BOOL mVertexShadersEnabled; S32 mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed + U32 mTransformFeedbackPrimitives; //number of primitives expected to be generated by transform feedback protected: BOOL mRenderTypeEnabled[NUM_RENDER_TYPES]; std::stack<std::string> mRenderTypeEnableStack; @@ -649,6 +651,9 @@ protected: LLSpatialGroup::sg_vector_t mGroupQ1; //priority LLSpatialGroup::sg_vector_t mGroupQ2; // non-priority + LLSpatialGroup::sg_vector_t mMeshDirtyGroup; //groups that need rebuildMesh called + U32 mMeshDirtyQueryObject; + LLDrawable::drawable_list_t mPartitionQ; //drawables that need to update their spatial partition radius bool mGroupQ2Locked; |