diff --git a/indra/newview/app_settings/settings_sh.xml b/indra/newview/app_settings/settings_sh.xml
index 5fb2c4826..83731c3ec 100644
--- a/indra/newview/app_settings/settings_sh.xml
+++ b/indra/newview/app_settings/settings_sh.xml
@@ -240,5 +240,16 @@
Value
.5
+ SHAltBatching
+
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index b7147b9f6..5947a0717 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1297,15 +1297,33 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
if (rebuild_color) // FALSE if tep == NULL
{ //decide if shiny goes in alpha channel of color
+
+ static const LLCachedControl alt_batching("SHAltBatching",true);
if (tep &&
- getPoolType() != LLDrawPool::POOL_ALPHA) // <--- alpha channel MUST contain transparency, not shiny
+ ((!alt_batching && getPoolType() != LLDrawPool::POOL_ALPHA) ||
+ (alt_batching && getPoolType() != LLDrawPool::POOL_ALPHA &&
+ getPoolType() != LLDrawPool::POOL_ALPHA_MASK &&
+ getPoolType() != LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK && // <--- alpha channel MUST contain transparency, not shiny
+ (getPoolType() != LLDrawPool::POOL_SIMPLE || LLPipeline::sRenderDeferred)))) // Impostor pass for simple uses alpha masking. Need to be opaque.
{
LLMaterial* mat = tep->getMaterialParams().get();
- bool shiny_in_alpha = false;
+ bool shiny_in_alpha = alt_batching ? true : false;
+ if(alt_batching)
+ {
if (LLPipeline::sRenderDeferred)
{ //store shiny in alpha if we don't have a specular map
+ if (getPoolType() == LLDrawPool::POOL_MATERIALS && mat->getSpecularID().notNull())
+ {
+ shiny_in_alpha = false;
+ }
+ }
+ }
+ else
+ {
+ if (LLPipeline::sRenderDeferred)
+ {
if (!mat || mat->getSpecularID().isNull())
{
shiny_in_alpha = true;
@@ -1318,6 +1336,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
shiny_in_alpha = true;
}
}
+ }
if (shiny_in_alpha)
{
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 3ab2d2b68..8d2b5a47b 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -711,7 +711,7 @@ class LLVolumeGeometryManager: public LLGeometryManager
virtual void rebuildGeom(LLSpatialGroup* group);
virtual void rebuildMesh(LLSpatialGroup* group);
virtual void getGeometry(LLSpatialGroup* group);
- void genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE, BOOL no_materials = FALSE);
+ void genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE);
void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type);
};
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 371c23580..fc3449826 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -4063,8 +4063,12 @@ LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep)
mSlopRatio = 0.25f;
}
-bool can_batch_texture(LLFace* facep)
+bool can_batch_texture(const LLFace* facep)
{
+ static const LLCachedControl alt_batching("SHAltBatching",true);
+
+ if(!alt_batching)
+ {
if (facep->getTextureEntry()->getBumpmap())
{ //bump maps aren't worked into texture batching yet
return false;
@@ -4084,6 +4088,30 @@ bool can_batch_texture(LLFace* facep)
{ //texture animation breaks batches
return false;
}
+ }
+ else
+ {
+
+ if (facep->getPoolType() == LLDrawPool::POOL_BUMP && (facep->getTextureEntry()->getBumpmap() > 0 && facep->getTextureEntry()->getBumpmap() < 18))
+ { //bump maps aren't worked into texture batching yet
+ return false;
+ }
+
+ if (LLPipeline::sRenderDeferred && (facep->getPoolType() == LLDrawPool::POOL_ALPHA || facep->getPoolType() == LLDrawPool::POOL_MATERIALS) && facep->getTextureEntry()->getMaterialParams().notNull())
+ { //materials don't work with texture batching yet
+ return false;
+ }
+
+ if (facep->getPoolType() != LLDrawPool::POOL_ALPHA && facep->getTexture() && facep->getTexture()->getPrimaryFormat() == GL_ALPHA)
+ { //can't batch invisiprims
+ return false;
+ }
+
+ if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE)
+ { //texture animation breaks batches
+ return false;
+ }
+ }
return true;
}
@@ -4093,10 +4121,10 @@ static LLFastTimer::DeclareTimer FTM_REGISTER_FACE("Register Face");
void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
{
LLFastTimer t(FTM_REGISTER_FACE);
- if (type == LLRenderPass::PASS_ALPHA && facep->getTextureEntry()->getMaterialParams().notNull() && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT))
- {
- LL_WARNS("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL;
- }
+ //if (type == LLRenderPass::PASS_ALPHA && facep->getTextureEntry()->getMaterialParams().notNull() && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT))
+ //{
+ // LL_WARNS("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL;
+ //}
// if (facep->getViewerObject()->isSelected() && gHideSelectedObjects)
// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c
@@ -4115,11 +4143,21 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
S32 idx = draw_vec.size()-1;
- BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) ||
+ static const LLCachedControl alt_batching("SHAltBatching",true);
+ BOOL fullbright;
+ if(!alt_batching)
+ {
+ fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) ||
(type == LLRenderPass::PASS_INVISIBLE) ||
(type == LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK) ||
(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT)) ||
(facep->getTextureEntry()->getFullbright());
+ }
+ else
+ {
+ fullbright = facep->isState(LLFace::FULLBRIGHT);
+ }
+
if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL))
{
@@ -4152,15 +4190,20 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
//drawable->getVObj()->setDebugText(llformat("%d", drawable->isState(LLDrawable::ANIMATED_CHILD)));
- U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0;
+ LLMaterial* mat = facep->getTextureEntry()->getMaterialParams().get();
+
+ bool cmp_bump = (type == LLRenderPass::PASS_BUMP) || (type == LLRenderPass::PASS_POST_BUMP);
+ bool cmp_shiny = !alt_batching ? !!mat : ((type == LLRenderPass::PASS_SHINY) || (type == LLRenderPass::PASS_FULLBRIGHT_SHINY) || (type == LLRenderPass::PASS_INVISI_SHINY));
+ bool cmp_mat = !alt_batching || LLPipeline::sRenderDeferred && ((facep->getPoolType() == LLDrawPool::POOL_MATERIALS) || (facep->getPoolType() == LLDrawPool::POOL_ALPHA));
+
+ U8 bump = facep->getTextureEntry()->getBumpmap();
U8 shiny = facep->getTextureEntry()->getShiny();
LLViewerTexture* tex = facep->getTexture();
U8 index = facep->getTextureIndex();
- LLMaterial* mat = facep->getTextureEntry()->getMaterialParams().get();
- LLMaterialID mat_id = facep->getTextureEntry()->getMaterialID();
+ //LLMaterial* mat = facep->getTextureEntry()->getMaterialParams().get();
bool batchable = false;
@@ -4178,10 +4221,9 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
}
}
-
if (index < 255 && idx >= 0)
{
- if (mat || draw_vec[idx]->mMaterial)
+ if (cmp_mat && (mat || draw_vec[idx]->mMaterial))
{ //can't batch textures when materials are present (yet)
batchable = false;
}
@@ -4202,7 +4244,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
batchable = true;
}
}
-
+
if (idx >= 0 &&
draw_vec[idx]->mVertexBuffer == facep->getVertexBuffer() &&
draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
@@ -4211,14 +4253,15 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
#endif
- draw_vec[idx]->mMaterial == mat &&
- draw_vec[idx]->mMaterialID == mat_id &&
+ (!cmp_mat || draw_vec[idx]->mMaterial == mat) &&
+ //draw_vec[idx]->mMaterialID == mat_id &&
draw_vec[idx]->mFullbright == fullbright &&
- draw_vec[idx]->mBump == bump &&
- (!mat || (draw_vec[idx]->mShiny == shiny)) && // need to break batches when a material is shared, but legacy settings are different
+ (!cmp_bump || draw_vec[idx]->mBump == bump) &&
+ (!cmp_shiny || !!draw_vec[idx]->mShiny == !!shiny) &&
+ //(!mat || (draw_vec[idx]->mShiny == shiny)) && // need to break batches when a material is shared, but legacy settings are different
draw_vec[idx]->mTextureMatrix == tex_mat &&
draw_vec[idx]->mModelMatrix == model_mat &&
- draw_vec[idx]->mShaderMask == shader_mask)
+ (!cmp_mat || draw_vec[idx]->mShaderMask == shader_mask))
{
draw_vec[idx]->mCount += facep->getIndicesCount();
draw_vec[idx]->mEnd += facep->getGeomCount();
@@ -4265,9 +4308,9 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
draw_info->mMaterial = mat;
draw_info->mShaderMask = shader_mask;
- if (mat)
+ if (cmp_mat && mat)
{
- draw_info->mMaterialID = mat_id;
+ //draw_info->mMaterialID = mat_id;
// We have a material. Update our draw info accordingly.
@@ -4288,7 +4331,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
draw_info->mNormalMap = facep->getViewerObject()->getTENormalMap(facep->getTEOffset());
}
- else
+ else
{
if (type == LLRenderPass::PASS_GRASS)
{
@@ -4312,6 +4355,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
draw_info->mTextureList.resize(index+1);
draw_info->mTextureList[index] = tex;
}
+
draw_info->validate();
}
}
@@ -4491,7 +4535,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
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;
@@ -4760,18 +4804,66 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
}
+ static const LLCachedControl alt_batching("SHAltBatching",true);
+
+ bool force_fullbright = group->isHUDGroup();
BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA);
U32 type = gPipeline.getPoolTypeFromTE(te, tex);
+
+ if(!alt_batching)
+ {
if (type != LLDrawPool::POOL_ALPHA && force_simple)
{
type = LLDrawPool::POOL_SIMPLE;
}
+ }
+ else
+ {
+ if (force_fullbright || te->getFullbright())
+ facep->setState(LLFace::FULLBRIGHT);
+
+ if ( type == LLDrawPool::POOL_ALPHA )
+ {
+ if(facep->canRenderAsMask())
+ {
+ if (facep->isState(LLFace::FULLBRIGHT))
+ {
+ type = LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK;
+ }
+ else
+ {
+ type = LLDrawPool::POOL_ALPHA_MASK;
+ }
+ }
+ }
+ else if (force_fullbright)
+ {
+ if(type == LLDrawPool::POOL_ALPHA_MASK)
+ type = LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK;
+ else
+ type = LLDrawPool::POOL_FULLBRIGHT;
+ }
+ else if(force_simple && type != LLDrawPool::POOL_FULLBRIGHT && type != LLDrawPool::POOL_ALPHA_MASK && type != LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK)
+ {
+ type = LLDrawPool::POOL_SIMPLE;
+ }
+ }
+
facep->setPoolType(type);
+ if(!alt_batching)
+ {
if (vobj->isHUDAttachment())
{
facep->setState(LLFace::FULLBRIGHT);
}
+ }
+ /*LLColor4 clr = facep->getFaceColor();
+ LLColor4U clru = LLColor4U(llround(clr.mV[0] * 255.f), llround(clr.mV[0] * 255.f), llround(clr.mV[0] * 255.f), llround(clr.mV[0] * 255.f));
+ if(clru.mV[0] == 164 && clru.mV[1] == 106 && clr.mV[2] == 65)
+ {
+ llinfos << "Facepool = " << type << " alpha = " << clr.mV[3] << llendl;
+ }*/
if (vobj->mTextureAnimp && vobj->mTexAnimMode)
{
@@ -4797,8 +4889,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
}
- if (type == LLDrawPool::POOL_ALPHA)
+ if(!alt_batching)
{
+ if (type == LLDrawPool::POOL_ALPHA)
+ {
if (facep->canRenderAsMask())
{ //can be treated as alpha mask
if (simple_count < MAX_FACE_COUNT)
@@ -4824,7 +4918,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
facep->mLastUpdateTime = gFrameTimeSeconds;
}
-
if (gPipeline.canUseWindLightShadersOnObjects()
&& LLPipeline::sRenderBump)
{
@@ -4832,7 +4925,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
// If we did check, then genDrawInfo would be more lenient than rebuildGeom on deciding if a face verts should have material-related attributes,
// which would result in a face with a vertex buffer that fails to meet shader attribute requirements.
if (LLPipeline::sRenderDeferred && te->getMaterialParams().notNull() /* && !te->getMaterialID().isNull()*/)
- {
+ {
LLMaterial* mat = te->getMaterialParams().get();
if (mat->getNormalID().notNull())
{
@@ -4864,7 +4957,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
simple_faces[simple_count++] = facep;
}
- }
+ }
}
else if (te->getBumpmap())
{ //needs normal + tangent
@@ -4899,7 +4992,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
}
else if ((te->getShiny() && LLPipeline::sRenderBump) ||
- !(te->getFullbright() || bake_sunlight))
+ !(te->getFullbright()))
{ //needs normal
if (simple_count < MAX_FACE_COUNT)
{
@@ -4916,6 +5009,132 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
}
}
+ }
+ else
+ {
+ LLFace*** cur_type = NULL;
+ U32* cur_count = NULL;
+
+ if (type == LLDrawPool::POOL_ALPHA)
+ {
+ cur_type = &alpha_faces;
+ cur_count = &alpha_count;
+
+ if (te->getColor().mV[3] > 0.f)
+ { //only treat as alpha in the pipeline if < 100% transparent
+ drawablep->setState(LLDrawable::HAS_ALPHA);
+ }
+
+ LLMaterial* mat = te->getMaterialParams().get();
+ if(mat && LLPipeline::sRenderDeferred)
+ {
+ if (mat->getNormalID().notNull())
+ {
+ if (mat->getSpecularID().notNull())
+ { //has normal and specular maps (needs texcoord1, texcoord2, and tangent)
+ cur_type = &normspec_faces;
+ cur_count = &normspec_count;
+ }
+ else
+ { //has normal map (needs texcoord1 and tangent)
+ cur_type = &norm_faces;
+ cur_count = &norm_count;
+ }
+ }
+ else if (mat->getSpecularID().notNull())
+ { //has specular map but no normal map, needs texcoord2
+ cur_type = &spec_faces;
+ cur_count = &spec_count;
+ }
+ }
+ }
+ else if(type == LLDrawPool::POOL_ALPHA_MASK)
+ {
+ cur_type = &simple_faces;
+ cur_count = &simple_count;
+ }
+ else if(type == LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK)
+ {
+ cur_type = &fullbright_faces;
+ cur_count = &fullbright_count;
+ }
+ else
+ {
+ if (drawablep->isState(LLDrawable::REBUILD_VOLUME))
+ {
+ facep->mLastUpdateTime = gFrameTimeSeconds;
+ }
+
+ if (type == LLDrawPool::POOL_BUMP)
+ { //needs normal + tangent
+ if(te->getBumpmap() > 0 && te->getBumpmap() < 18)
+ {
+ cur_type = &bump_faces;
+ cur_count = &bump_count;
+ }
+ else if(te->getShiny())
+ {
+ cur_type = &simple_faces;
+ cur_count = &simple_count;
+ }
+ }
+ else if (type == LLDrawPool::POOL_SIMPLE)
+ { //needs normal + tangent
+ cur_type = &simple_faces;
+ cur_count = &simple_count;
+ }
+ else if (type == LLDrawPool::POOL_FULLBRIGHT)
+ { //doesn't need normal...
+ if(LLPipeline::sRenderBump && te->getShiny()) //unless it's shiny..
+ {
+ cur_type = &simple_faces;
+ cur_count = &simple_count;
+ }
+ else
+ {
+ cur_type = &fullbright_faces;
+ cur_count = &fullbright_count;
+ }
+ }
+ /*Singu Note: Don't check the materials ID, as doing such causes a mismatch between rebuildGeom and genDrawInfo.
+ If we did check, then genDrawInfo would be more lenient than rebuildGeom on deciding if a face verts should have material-related attributes,
+ which would result in a face with a vertex buffer that fails to meet shader attribute requirements.*/
+ else if(type == LLDrawPool::POOL_MATERIALS)
+ {
+ LLMaterial* mat = te->getMaterialParams().get();
+ if (mat->getNormalID().notNull())
+ {
+ if (mat->getSpecularID().notNull())
+ { //has normal and specular maps (needs texcoord1, texcoord2, and tangent)
+ cur_type = &normspec_faces;
+ cur_count = &normspec_count;
+ }
+ else
+ { //has normal map (needs texcoord1 and tangent)
+ cur_type = &norm_faces;
+ cur_count = &norm_count;
+ }
+ }
+ else if (mat->getSpecularID().notNull())
+ { //has specular map but no normal map, needs texcoord2
+ cur_type = &spec_faces;
+ cur_count = &spec_count;
+ }
+ else
+ { //has neither specular map nor normal map, only needs texcoord0
+ cur_type = &simple_faces;
+ cur_count = &simple_count;
+ }
+ }
+ else
+ {
+ llerrs << "Unknown pool type: " << type << llendl;
+ }
+ }
+ llassert_always(cur_type);
+ if(*cur_count < MAX_FACE_COUNT)
+ (*cur_type)[(*cur_count)++] = facep;
+ }
}
else
{ //face has no renderable geometry
@@ -4946,7 +5165,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
//PROCESS NON-ALPHA FACES
U32 simple_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
U32 alpha_mask = simple_mask | 0x80000000; //hack to give alpha verts their own VBO
- U32 bump_mask = simple_mask | LLVertexBuffer::MAP_TEXCOORD1;
+ U32 bump_mask = simple_mask | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TANGENT;
U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
U32 norm_mask = simple_mask | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TANGENT;
@@ -4964,23 +5183,21 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
spec_mask = spec_mask | LLVertexBuffer::MAP_EMISSIVE;
}
- BOOL batch_textures = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1;
+ BOOL batch_textures = gPipeline.getUseVertexShaders();
- if (batch_textures)
- {
- bump_mask = bump_mask | LLVertexBuffer::MAP_TANGENT;
- simple_mask = simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX;
- alpha_mask = alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2;
- fullbright_mask = fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX;
- }
+ U32 additional_flags = 0x0;
+ if(batch_textures)
+ additional_flags |= LLVertexBuffer::MAP_TEXTURE_INDEX;
+ if(emissive)
+ additional_flags |= LLVertexBuffer::MAP_EMISSIVE;
- genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, simple_count, FALSE, batch_textures, FALSE);
- genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, fullbright_count, FALSE, batch_textures);
- genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, alpha_count, TRUE, batch_textures);
- genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, bump_count, FALSE, FALSE);
- genDrawInfo(group, norm_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, norm_faces, norm_count, FALSE, FALSE);
- genDrawInfo(group, spec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, spec_faces, spec_count, FALSE, FALSE);
- genDrawInfo(group, normspec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, normspec_faces, normspec_count, FALSE, FALSE);
+ genDrawInfo(group, simple_mask | additional_flags, simple_faces, simple_count, FALSE, batch_textures);
+ genDrawInfo(group, fullbright_mask | additional_flags, fullbright_faces, fullbright_count, FALSE, batch_textures);
+ genDrawInfo(group, alpha_mask | additional_flags, alpha_faces, alpha_count, TRUE, batch_textures);
+ genDrawInfo(group, bump_mask | additional_flags, bump_faces, bump_count, FALSE);
+ genDrawInfo(group, norm_mask | additional_flags, norm_faces, norm_count, FALSE);
+ genDrawInfo(group, spec_mask | additional_flags, spec_faces, spec_count, FALSE);
+ genDrawInfo(group, normspec_mask | additional_flags, normspec_faces, normspec_count, FALSE);
if (!LLPipeline::sDelayVBUpdate)
{
@@ -5132,29 +5349,76 @@ struct CompareBatchBreakerModified
{
bool operator()(const LLFace* const& lhs, const LLFace* const& rhs)
{
+ static const LLCachedControl alt_batching("SHAltBatching",true);
+ if(!alt_batching)
+ {
+ const LLTextureEntry* lte = lhs->getTextureEntry();
+ const LLTextureEntry* rte = rhs->getTextureEntry();
+
+ if (lte->getBumpmap() != rte->getBumpmap())
+ {
+ return lte->getBumpmap() < rte->getBumpmap();
+ }
+ else if (lte->getFullbright() != rte->getFullbright())
+ {
+ return lte->getFullbright() < rte->getFullbright();
+ }
+ else if (LLPipeline::sRenderDeferred && lte->getMaterialParams() != rte->getMaterialParams())
+ {
+ return lte->getMaterialParams() < rte->getMaterialParams();
+ }
+ else if (LLPipeline::sRenderDeferred && (lte->getMaterialParams() == rte->getMaterialParams()) && (lte->getShiny() != rte->getShiny()))
+
+ {
+ return lte->getShiny() < rte->getShiny();
+ }
+
+ else
+ {
+ return lhs->getTexture() < rhs->getTexture();
+ }
+ }
+ else
+ {
+
const LLTextureEntry* lte = lhs->getTextureEntry();
const LLTextureEntry* rte = rhs->getTextureEntry();
- if (lte->getBumpmap() != rte->getBumpmap())
+ bool batch_left = can_batch_texture(lhs);
+ bool batch_right = can_batch_texture(rhs);
+
+ if (lhs->getPoolType() != rhs->getPoolType())
{
- return lte->getBumpmap() < rte->getBumpmap();
+ return lhs->getPoolType() < rhs->getPoolType();
}
- else if (lte->getFullbright() != rte->getFullbright())
+ else if(batch_left != batch_right) //Move non-batchable faces together.
{
- return lte->getFullbright() < rte->getFullbright();
+ return !(batch_left < batch_right);
}
- else if (LLPipeline::sRenderDeferred && lte->getMaterialParams() != rte->getMaterialParams())
+
+ bool batch_shiny = (!LLPipeline::sRenderDeferred || lhs->isState(LLFace::FULLBRIGHT)) && lhs->getPoolType() == LLDrawPool::POOL_BUMP;
+
+ if (lhs->isState(LLFace::FULLBRIGHT) != rhs->isState(LLFace::FULLBRIGHT))
{
- return lte->getMaterialParams() < rte->getMaterialParams();
+ return lhs->isState(LLFace::FULLBRIGHT) < rhs->isState(LLFace::FULLBRIGHT);
}
- else if (LLPipeline::sRenderDeferred && (lte->getMaterialParams() == rte->getMaterialParams()) && (lte->getShiny() != rte->getShiny()))
+ else if(batch_shiny && lte->getShiny() != rte->getShiny())
{
return lte->getShiny() < rte->getShiny();
}
+ else if(lhs->getPoolType() == LLDrawPool::POOL_MATERIALS)
+ {
+ return lte->getMaterialParams().get() < rte->getMaterialParams().get();
+ }
+ else if(lhs->getPoolType() == LLDrawPool::POOL_BUMP)
+ {
+ return lte->getBumpmap() < rte->getBumpmap();
+ }
else
{
return lhs->getTexture() < rhs->getTexture();
}
+ }
}
};
@@ -5168,7 +5432,7 @@ static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB");
-void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures, BOOL no_materials)
+void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures)
{
LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO);
@@ -5203,41 +5467,20 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac
std::sort(faces, faces+face_count, LLFace::CompareDistanceGreater());
}
}
-
+
bool hud_group = group->isHUDGroup() ;
LLFace** face_iter = faces;
LLFace** end_faces = faces+face_count;
LLSpatialGroup::buffer_map_t buffer_map;
- LLViewerTexture* last_tex = NULL;
- S32 buffer_index = 0;
-
- if (distance_sort)
- {
- buffer_index = -1;
- }
-
- S32 texture_index_channels = 1;
-
- if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30)
- {
- static const LLCachedControl no_texture_indexing("ShyotlUseLegacyTextureBatching",false);
- if(!no_texture_indexing)
- texture_index_channels = LLGLSLShader::sIndexedTextureChannels-1; //always reserve one for shiny for now just for simplicity;
- }
+ S32 texture_index_channels = llmax(LLGLSLShader::sIndexedTextureChannels-1,1); //always reserve one for shiny for now just for simplicity
if (LLPipeline::sRenderDeferred && distance_sort)
{
texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels;
}
- static const LLCachedControl max_texture_index("RenderMaxTextureIndex",1);
- texture_index_channels = llmin(texture_index_channels, (S32) max_texture_index.get());
-
- //NEVER use more than 16 texture index channels (workaround for prevalent driver bug)
- texture_index_channels = llmin(texture_index_channels, 16);
-
bool flexi = false;
while (face_iter != end_faces)
@@ -5247,23 +5490,14 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac
LLViewerTexture* tex = facep->getTexture();
LLMaterialPtr mat = facep->getTextureEntry()->getMaterialParams();
- if (distance_sort)
+ //bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic();
+
+ static const LLCachedControl alt_batching("SHAltBatching",true);
+ if (!alt_batching && distance_sort)
{
tex = NULL;
}
- if (last_tex == tex)
- {
- buffer_index++;
- }
- else
- {
- last_tex = tex;
- buffer_index = 0;
- }
-
- bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic();
-
U32 index_count = facep->getIndicesCount();
U32 geom_count = facep->getGeomCount();
@@ -5272,7 +5506,9 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac
//sum up vertices needed for this render batch
LLFace** i = face_iter;
++i;
-
+
+ if(!alt_batching)
+ {
const U32 MAX_TEXTURE_COUNT = 32;
static LLViewerTexture* texture_list[MAX_TEXTURE_COUNT];
@@ -5389,6 +5625,96 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac
}
}
+ }
+ else
+ {
+ LLFastTimer t(FTM_GEN_DRAW_INFO_FACE_SIZE);
+
+ if (batch_textures)
+ {
+ facep->setTextureIndex(0);
+
+ if(can_batch_texture(facep) && texture_index_channels > 1)
+ {
+ static const U8 MAX_TEXTURE_COUNT = 32;
+ static LLViewerTexture* texture_list[MAX_TEXTURE_COUNT];
+ U8 texture_count = 1;
+ U8 cur_tex = 0;
+ texture_list[0] = tex;
+ U8 pool = facep->getPoolType();
+
+ while (i != end_faces)
+ {
+ facep = *i;
+ if ( !
+ (facep) || (geom_count + facep->getGeomCount() > max_vertices) || pool != facep->getPoolType() )
+ { //cut batches on geom count too big
+ break;
+ }
+ else
+ {
+ if(facep->getTexture() != tex)
+ {
+ bool reused = false;
+ if(distance_sort) //Alpha faces aren't sorted by batch criteria, but rather distance WRT camera.
+ {
+ for(U8 j = 0; j < texture_count; ++j)
+ {
+ if(texture_list[j] == facep->getTexture())
+ {
+ tex = facep->getTexture();
+ cur_tex = j;
+ reused = true;
+ break;
+ }
+ }
+ }
+ if(!reused)
+ {
+ if(++texture_count > llmin((U8)texture_index_channels,MAX_TEXTURE_COUNT))
+ break;
+ cur_tex = texture_count - 1;
+ tex = facep->getTexture();
+ texture_list[cur_tex] = tex;
+ }
+ }
+ facep->setTextureIndex(cur_tex);
+ flexi = flexi || facep->getViewerObject()->getVolume()->isUnique();
+ index_count += facep->getIndicesCount();
+ geom_count += facep->getGeomCount();
+ }
+ ++i;
+ }
+ }
+ }
+ else
+ {
+ //face has no texture index
+ facep->mDrawInfo = NULL;
+ facep->setTextureIndex(255);
+
+ while (i != end_faces &&
+ (LLPipeline::sTextureBindTest ||
+ (distance_sort ||
+ ((*i)->getTexture() == tex &&
+ ((*i)->getTextureEntry()->getMaterialParams() == mat)))))
+ {
+ facep = *i;
+
+ if (geom_count + facep->getGeomCount() > max_vertices)
+ { //cut batches on geom count too big
+ break;
+ }
+ //face has no texture index
+ facep->mDrawInfo = NULL;
+ facep->setTextureIndex(255);
+ flexi = flexi || facep->getViewerObject()->getVolume()->isUnique();
+ index_count += facep->getIndicesCount();
+ geom_count += facep->getGeomCount();
+ ++i;
+ }
+ }
+ }
if (flexi && buffer_usage && buffer_usage != GL_STREAM_DRAW_ARB)
{
@@ -5398,14 +5724,19 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac
// Singu Note: Catch insufficient vbos right when they are created. Easier to debug.
if(gDebugGL)
{
- const LLTextureEntry* te = facep->getTextureEntry();
- if (mat && LLPipeline::sRenderDeferred && !hud_group &&
- !no_materials &&
- !te->getFullbright() &&
- !(te->getColor().mV[3] < 0.999f) &&
- !(te->getBumpmap() && (te->getBumpmap() < 18) && (mat->getNormalID().isNull())))
+ if (LLPipeline::sRenderDeferred &&
+ (*face_iter)->getTextureEntry()->getMaterialParams().get() &&
+ ((*face_iter)->getPoolType() == LLDrawPool::POOL_ALPHA ||
+ (*face_iter)->getPoolType() == LLDrawPool::POOL_MATERIALS ))
{
- U32 shader_mask = mat->getShaderMask();
+ LLMaterial* mat = (*face_iter)->getTextureEntry()->getMaterialParams().get();
+
+ U32 shader_mask;
+ if((*face_iter)->getPoolType() == LLDrawPool::POOL_ALPHA)
+ shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND);
+ else
+ shader_mask = mat->getShaderMask();
+
if(shader_mask != 1 && shader_mask != 5 && shader_mask != 9 && shader_mask != 13)
{
LLGLSLShader* shader = &(gDeferredMaterialProgram[shader_mask]);
@@ -5493,8 +5824,12 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac
index_offset += facep->getGeomCount();
indices_index += facep->getIndicesCount();
+ static const LLCachedControl alt_batching("SHAltBatching",true);
+
//append face to appropriate render batch
+ if(!alt_batching)
+ {
BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA;
BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
if ((mask & LLVertexBuffer::MAP_NORMAL) == 0)
@@ -5563,10 +5898,10 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac
}
}
}
- else if (no_materials)
+ /*else if (no_materials)
{
registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
- }
+ }*/
else if (!opaque) //Just use opaque instead of te->getColorblahblah
{
registerFace(group, facep, LLRenderPass::PASS_ALPHA);
@@ -5708,7 +6043,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac
{ //invisiprim
registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
}
- else if (fullbright || bake_sunlight)
+ else if (fullbright)
{ //fullbright
if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
{
@@ -5764,11 +6099,126 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac
registerFace(group, facep, LLRenderPass::PASS_BUMP);
}
}
-
if (!is_alpha && LLPipeline::sRenderGlow && te->getGlow() > 0.f)
{
registerFace(group, facep, LLRenderPass::PASS_GLOW);
}
+ }
+ else
+ {
+ const LLTextureEntry* te = facep->getTextureEntry();
+ tex = facep->getTexture();
+
+ bool is_alpha = facep->getPoolType() == LLDrawPool::POOL_ALPHA;
+ bool is_shiny_shader = facep->getPoolType() == LLDrawPool::POOL_BUMP && gPipeline.canUseVertexShaders() && te->getShiny();
+ bool is_shiny_fixed = facep->getPoolType() == LLDrawPool::POOL_BUMP && !gPipeline.canUseVertexShaders() && te->getShiny();
+ bool is_fullbright = facep->isState(LLFace::FULLBRIGHT);
+
+ if (facep->getPoolType() == LLDrawPool::POOL_MATERIALS)
+ {
+ U32 pass[] =
+ {
+ LLRenderPass::PASS_MATERIAL,
+ LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_MATERIAL_ALPHA,
+ LLRenderPass::PASS_MATERIAL_ALPHA_MASK,
+ LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
+ LLRenderPass::PASS_SPECMAP,
+ LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_SPECMAP_BLEND,
+ LLRenderPass::PASS_SPECMAP_MASK,
+ LLRenderPass::PASS_SPECMAP_EMISSIVE,
+ LLRenderPass::PASS_NORMMAP,
+ LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMMAP_BLEND,
+ LLRenderPass::PASS_NORMMAP_MASK,
+ LLRenderPass::PASS_NORMMAP_EMISSIVE,
+ LLRenderPass::PASS_NORMSPEC,
+ LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMSPEC_BLEND,
+ LLRenderPass::PASS_NORMSPEC_MASK,
+ LLRenderPass::PASS_NORMSPEC_EMISSIVE,
+ };
+
+ U32 mask = mat->getShaderMask();
+
+ llassert(mask < sizeof(pass)/sizeof(U32));
+
+ mask = llmin(mask, (U32)(sizeof(pass)/sizeof(U32)-1));
+
+ registerFace(group, facep, pass[mask]);
+ }
+ else if (facep->getPoolType() == LLDrawPool::POOL_ALPHA)
+ {
+ // can we safely treat this as an alpha mask?
+ if (facep->getFaceColor().mV[3] <= 0.f)
+ { //100% transparent, don't render unless we're highlighting transparent
+ registerFace(group, facep, LLRenderPass::PASS_ALPHA_INVISIBLE);
+ }
+ else
+ {
+ registerFace(group, facep, LLRenderPass::PASS_ALPHA);
+ }
+ }
+ else if (facep->getPoolType() == LLDrawPool::POOL_ALPHA_MASK)
+ {
+ registerFace(group, facep, LLRenderPass::PASS_ALPHA_MASK);
+ }
+ else if (facep->getPoolType() == LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK)
+ {
+ registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
+ }
+ else
+ {
+ if (tex->getPrimaryFormat() == GL_ALPHA)
+ {
+ if(is_shiny_shader && facep->getPoolType() == LLDrawPool::POOL_BUMP)
+ {
+ registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY);
+ }
+ registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
+ }
+ else if (facep->getPoolType() == LLDrawPool::POOL_SIMPLE)
+ {
+ registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
+ }
+ else if (facep->getPoolType() == LLDrawPool::POOL_FULLBRIGHT)
+ {
+ registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
+ }
+ else if (facep->getPoolType() == LLDrawPool::POOL_BUMP)
+ {
+ llassert_always(mask & LLVertexBuffer::MAP_NORMAL);
+
+ bool is_bump = te->getBumpmap() > 0 && te->getBumpmap() < 18;
+
+ if(is_bump)
+ {
+ llassert_always(mask & LLVertexBuffer::MAP_TANGENT);
+ }
+ if(is_shiny_shader || is_shiny_fixed)
+ {
+ llassert_always(mask & LLVertexBuffer::MAP_NORMAL);
+ }
+
+ if (is_fullbright)
+ {
+ registerFace(group, facep, is_shiny_shader ? LLRenderPass::PASS_FULLBRIGHT_SHINY : LLRenderPass::PASS_FULLBRIGHT);
+ if(is_bump)
+ registerFace(group, facep, LLPipeline::sRenderDeferred ? LLRenderPass::PASS_POST_BUMP : LLRenderPass::PASS_BUMP);
+ }
+ else
+ {
+ registerFace(group, facep, (LLPipeline::sRenderDeferred || !is_shiny_shader) ? LLRenderPass::PASS_SIMPLE : LLRenderPass::PASS_SHINY);
+ if(is_bump)
+ registerFace(group, facep, LLRenderPass::PASS_BUMP);
+ }
+
+ if(is_shiny_fixed)
+ registerFace(group, facep, LLRenderPass::PASS_SHINY);
+ }
+ }
+ if (!is_alpha && LLPipeline::sRenderGlow && te->getGlow() > 0.f)
+ {
+ registerFace(group, facep, LLRenderPass::PASS_GLOW);
+ }
+ }
++face_iter;
}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index a94323f71..79d6ad670 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1526,24 +1526,28 @@ U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* ima
{
alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2);
}
-
+
if (alpha && mat)
{
switch (mat->getDiffuseAlphaMode())
{
- case 1:
+ case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND:
alpha = true; // Material's alpha mode is set to blend. Toss it into the alpha draw pool.
break;
- case 0: //alpha mode set to none, never go to alpha pool
- case 3: //alpha mode set to emissive, never go to alpha pool
+ case LLMaterial::DIFFUSE_ALPHA_MODE_NONE: //alpha mode set to none, never go to alpha pool
+ case LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE: //alpha mode set to emissive, never go to alpha pool
alpha = color_alpha;
break;
default: //alpha mode set to "mask", go to alpha pool if fullbright
- alpha = color_alpha; // Material's alpha mode is set to none, mask, or emissive. Toss it into the opaque material draw pool.
+ alpha = color_alpha; // Material's alpha mode is set to mask, or default. Toss it into the opaque material draw pool.
break;
}
}
+ static const LLCachedControl alt_batching("SHAltBatching",true);
+
+ if(!alt_batching)
+ {
if (alpha)
{
return LLDrawPool::POOL_ALPHA;
@@ -1560,6 +1564,49 @@ U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* ima
{
return LLDrawPool::POOL_SIMPLE;
}
+ }
+ else
+ {
+ if (alpha)
+ {
+ return LLDrawPool::POOL_ALPHA;
+ }
+ else if ((!LLPipeline::sRenderDeferred || !mat || mat->getNormalID().isNull()) && LLPipeline::sRenderBump && te->getBumpmap() && te->getBumpmap() < 18)
+ {
+ return LLDrawPool::POOL_BUMP; //Bump goes into bump pool unless using deferred and there's a normal map that takes precedence.
+ }
+ else if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
+ {
+ if(te->getFullbright())
+ {
+ return LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK;
+ }
+ else
+ {
+ return LLPipeline::sRenderDeferred ? LLDrawPool::POOL_MATERIALS : LLDrawPool::POOL_ALPHA_MASK;
+ }
+ }
+ else if(LLPipeline::sRenderDeferred && mat)
+ {
+ if(te->getFullbright() && mat->getEnvironmentIntensity())
+ {
+ return LLDrawPool::POOL_FULLBRIGHT;
+ }
+ return LLDrawPool::POOL_MATERIALS;
+ }
+ else if(te->getFullbright())
+ {
+ return (LLPipeline::sRenderBump && te->getShiny()) ? LLDrawPool::POOL_BUMP : LLDrawPool::POOL_FULLBRIGHT;
+ }
+ else if (!LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getShiny())
+ {
+ return LLDrawPool::POOL_BUMP; //Shiny goes into bump pool when not using deferred rendering.
+ }
+ else
+ {
+ return LLDrawPool::POOL_SIMPLE;
+ }
+ }
}