summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2012-05-21 23:34:51 -0500
committerDave Parks <davep@lindenlab.com>2012-05-21 23:34:51 -0500
commit336b12e803fdc5f34b5394eae50645870d664d13 (patch)
treed922b43194da6e45bf648cadcaf49b6e07a9bf89 /indra
parent430d384a93284c87b4e8af5d3bfacbf7e22094bf (diff)
parentb44eb2e7a910e65373dfed54b86aff87ddda918d (diff)
merge
Diffstat (limited to 'indra')
-rw-r--r--indra/llmath/llvolume.h5
-rw-r--r--indra/llrender/llcubemap.cpp2
-rw-r--r--indra/llrender/llgl.cpp79
-rw-r--r--indra/llrender/llgl.h26
-rw-r--r--indra/llrender/llglheaders.h13
-rw-r--r--indra/llrender/llglslshader.cpp9
-rw-r--r--indra/llrender/llglslshader.h4
-rw-r--r--indra/llrender/llimagegl.cpp62
-rw-r--r--indra/llrender/llimagegl.h10
-rw-r--r--indra/llrender/llrendertarget.cpp8
-rw-r--r--indra/llrender/llvertexbuffer.cpp200
-rw-r--r--indra/llrender/llvertexbuffer.h39
-rw-r--r--indra/newview/app_settings/settings.xml27
-rw-r--r--indra/newview/app_settings/shaders/class1/transform/binormalV.glsl36
-rw-r--r--indra/newview/app_settings/shaders/class1/transform/colorV.glsl36
-rw-r--r--indra/newview/app_settings/shaders/class1/transform/normalV.glsl36
-rw-r--r--indra/newview/app_settings/shaders/class1/transform/positionV.glsl40
-rw-r--r--indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl35
-rw-r--r--indra/newview/lldrawpoolalpha.cpp6
-rw-r--r--indra/newview/llface.cpp1164
-rw-r--r--indra/newview/llface.h2
-rwxr-xr-xindra/newview/llfloatermodelpreview.cpp2
-rw-r--r--indra/newview/llspatialpartition.cpp40
-rw-r--r--indra/newview/llviewerdisplay.cpp4
-rw-r--r--indra/newview/llviewershadermgr.cpp113
-rw-r--r--indra/newview/llviewershadermgr.h11
-rw-r--r--indra/newview/llvoavatar.cpp6
-rw-r--r--indra/newview/llvoavatarself.cpp2
-rw-r--r--indra/newview/llvopartgroup.cpp2
-rw-r--r--indra/newview/llvovolume.cpp779
-rw-r--r--indra/newview/pipeline.cpp97
-rw-r--r--indra/newview/pipeline.h5
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 &params_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;