Experimental volume face batching changes (Cursory testing shows: +~10% larger mean batch size).

-Drive pass selection by face pools. Doing such removes a fair bit of redundant (and often buggy) code.
-Ignore irrelivant batch breakers depending on pass/pool type.
-Face sorting algorithm modified to potentially allow larger batches.
-Removed a few unused/broken things (bake_sunlight/no_materials)
-Fullbright handling should hopefully be a little more consistent.
-Prevent fullbright faces from being placed in 'simple' pool. (They are already simple-er)

Fixed attribute error that popped up with bump faces when batching was disabled.
This commit is contained in:
Shyotl
2014-02-18 11:43:50 -06:00
parent ac8d5e5ab3
commit bdc0ad2b8f
5 changed files with 633 additions and 106 deletions

View File

@@ -240,5 +240,16 @@
<key>Value</key>
<real>.5</real>
</map>
<key>SHAltBatching</key>
<map>
<key>Comment</key>
<string>Experimental retooling of face batching.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<real>1</real>
</map>
</map>
</llsd>

View File

@@ -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<bool> 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)
{

View File

@@ -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);
};

View File

@@ -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<bool> 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<bool> 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<bool> 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<bool> 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<bool> 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<U32> 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<bool> 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<bool> 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;
}

View File

@@ -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<bool> 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;
}
}
}