From bdc0ad2b8f51cf3c4fc0a81539cb33bc082a1fca Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 18 Feb 2014 11:43:50 -0600 Subject: [PATCH] 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. --- indra/newview/app_settings/settings_sh.xml | 11 + indra/newview/llface.cpp | 23 +- indra/newview/llspatialpartition.h | 2 +- indra/newview/llvovolume.cpp | 646 +++++++++++++++++---- indra/newview/pipeline.cpp | 57 +- 5 files changed, 633 insertions(+), 106 deletions(-) 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 + + Comment + Experimental retooling of face batching. + Persist + 1 + Type + Boolean + Value + 1 + 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; + } + } }