diff options
author | Dave Parks <davep@lindenlab.com> | 2024-06-21 13:13:08 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-21 13:13:08 -0500 |
commit | 80ea30af1a8b38360f71c29cc45872c4399dab0d (patch) | |
tree | db07a706a4c896b11b8abca8a7d8815797a8d0be /indra/newview/gltfscenemanager.cpp | |
parent | 9fb9e8f33cb33a1535f43b4be030009c192ea92b (diff) |
#1769 gltf optimization pass (#1816)
#1814 and #1517 Fix mirror update rate and occlusion culling
Diffstat (limited to 'indra/newview/gltfscenemanager.cpp')
-rw-r--r-- | indra/newview/gltfscenemanager.cpp | 350 |
1 files changed, 168 insertions, 182 deletions
diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index e01aec0497..7b2de4d6de 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -437,6 +437,8 @@ void GLTFSceneManager::onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType a void GLTFSceneManager::update() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; + for (U32 i = 0; i < mObjects.size(); ++i) { if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr) @@ -552,6 +554,7 @@ void GLTFSceneManager::render(bool opaque, bool rigged, bool unlit) void GLTFSceneManager::render(U8 variant) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; // just render the whole scene by traversing the whole scenegraph // Assumes camera transform is already set and appropriate shader is already bound. // Eventually we'll want a smarter render pipe that has pre-sorted the scene graph @@ -563,8 +566,6 @@ void GLTFSceneManager::render(U8 variant) render((U8) (variant | LLGLSLShader::GLTFVariant::MULTI_UV)); } - gGL.matrixMode(LLRender::MM_MODELVIEW); - bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED; for (U32 i = 0; i < mObjects.size(); ++i) @@ -581,19 +582,11 @@ void GLTFSceneManager::render(U8 variant) LLMatrix4a mat = mObjects[i]->getGLTFAssetToAgentTransform(); - LLMatrix4a modelview; - modelview.loadu(gGLModelView); - - matMul(mat, modelview, modelview); - - mat4 mdv = glm::make_mat4(modelview.getF32ptr()); - asset->updateRenderTransforms(mdv); + // provide a modelview matrix that goes from asset to camera space + // (matrix palettes are in asset space) + gGL.loadMatrix(gGLModelView); + gGL.multMatrix(mat.getF32ptr()); - if (rigged) - { // provide a modelview matrix that goes from asset to camera space for rigged render passes - // (matrix palettes are in asset space) - gGL.loadMatrix(glm::value_ptr(mdv)); - } render(*asset, variant); gGL.popMatrix(); @@ -602,176 +595,185 @@ void GLTFSceneManager::render(U8 variant) void GLTFSceneManager::render(Asset& asset, U8 variant) { - bool opaque = !(variant & LLGLSLShader::GLTFVariant::ALPHA_BLEND); - bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED; + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; - if (opaque) + for (U32 ds = 0; ds < 2; ++ds) { - gGLTFPBRMetallicRoughnessProgram.bind(variant); - } - else - { // alpha shaders need all the shadow map setup etc - gPipeline.bindDeferredShader(gGLTFPBRMetallicRoughnessProgram.mGLTFVariants[variant]); - } + RenderData& rd = asset.mRenderData[ds]; + auto& batches = rd.mBatches[variant]; - for (auto& node : asset.mNodes) - { - if (node.mSkin != INVALID_INDEX) + if (batches.empty()) { - if (rigged) - { - Skin& skin = asset.mSkins[node.mSkin]; - glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_JOINTS, skin.mUBO); - } + return; } - if (node.mMesh != INVALID_INDEX) + LLGLDisable cull_face(ds == 1 ? GL_CULL_FACE : 0); + + bool opaque = !(variant & LLGLSLShader::GLTFVariant::ALPHA_BLEND); + bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED; + + bool shader_bound = false; + + for (U32 i = 0; i < batches.size(); ++i) { - Mesh& mesh = asset.mMeshes[node.mMesh]; - for (auto& primitive : mesh.mPrimitives) + if (batches[i].mPrimitives.empty() || batches[i].mVertexBuffer.isNull()) { - if (primitive.mShaderVariant != variant) + continue; + } + + if (!shader_bound) + { // don't bind the shader until we know we have somthing to render + if (opaque) { - continue; + gGLTFPBRMetallicRoughnessProgram.bind(variant); + } + else + { // alpha shaders need all the shadow map setup etc + gPipeline.bindDeferredShader(gGLTFPBRMetallicRoughnessProgram.mGLTFVariants[variant]); } if (!rigged) { - gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix)); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_NODES, asset.mNodesUBO); } - bool cull = true; - if (primitive.mMaterial != INVALID_INDEX) - { - Material& material = asset.mMaterials[primitive.mMaterial]; - bind(asset, material); - cull = !material.mDoubleSided; - } - else + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_MATERIALS, asset.mMaterialsUBO); + + for (U32 i = 0; i < TEXTURE_TYPE_COUNT; ++i) { - LLFetchedGLTFMaterial::sDefault.bind(); + mLastTexture[i] = -2; } - LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0); + gGL.syncMatrices(); + shader_bound = true; + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfdc - set vb"); + batches[i].mVertexBuffer->setBuffer(); + } + + S32 mat_idx = i - 1; + if (mat_idx != INVALID_INDEX) + { + Material& material = asset.mMaterials[mat_idx]; + bind(asset, material); + } + else + { + LLFetchedGLTFMaterial::sDefault.bind(); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::GLTF_MATERIAL_ID, -1); + } + + for (auto& pdata : batches[i].mPrimitives) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("GLTF draw call"); + Node& node = asset.mNodes[pdata.mNodeIndex]; + Mesh& mesh = asset.mMeshes[node.mMesh]; + Primitive& primitive = mesh.mPrimitives[pdata.mPrimitiveIndex]; - primitive.mVertexBuffer->setBuffer(); - if (primitive.mVertexBuffer->getNumIndices() > 0) + if (rigged) { - primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0); + LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfdc - bind skin"); + llassert(node.mSkin != INVALID_INDEX); + Skin& skin = asset.mSkins[node.mSkin]; + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_JOINTS, skin.mUBO); } else { - primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts()); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::GLTF_NODE_ID, pdata.mNodeIndex); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfdc - push vb"); + + primitive.mVertexBuffer->drawRangeFast(primitive.mGLMode, primitive.mVertexOffset, primitive.mVertexOffset + primitive.getVertexCount() - 1, primitive.getIndexCount(), primitive.mIndexOffset); } } } } } -static void bindTexture(Asset& asset, S32 uniform, Material::TextureInfo& info, LLViewerTexture* fallback) +void GLTFSceneManager::bindTexture(Asset& asset, TextureType texture_type, TextureInfo& info, LLViewerTexture* fallback) { - if (info.mIndex != INVALID_INDEX) + U8 type_idx = (U8)texture_type; + + if (info.mIndex == mLastTexture[type_idx]) + { //already bound + return; + } + + S32 uniform[] = { - Texture& texture = asset.mTextures[info.mIndex]; + LLShaderMgr::DIFFUSE_MAP, + LLShaderMgr::NORMAL_MAP, + LLShaderMgr::METALLIC_ROUGHNESS_MAP, + LLShaderMgr::OCCLUSION_MAP, + LLShaderMgr::EMISSIVE_MAP + }; - LLViewerTexture* tex = asset.mImages[texture.mSource].mTexture; - if (tex) + S32 channel = LLGLSLShader::sCurBoundShaderPtr->getTextureChannel(uniform[(U8)type_idx]); + + if (channel > -1) + { + glActiveTexture(GL_TEXTURE0 + channel); + + if (info.mIndex != INVALID_INDEX) { - tex->addTextureStats(2048.f * 2048.f); - S32 channel = LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, tex); + Texture& texture = asset.mTextures[info.mIndex]; + + LLViewerTexture* tex = asset.mImages[texture.mSource].mTexture; + if (tex) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gl bind texture"); + glBindTexture(GL_TEXTURE_2D, tex->getTexName()); - if (channel != -1 && texture.mSampler != -1) - { // set sampler state - Sampler& sampler = asset.mSamplers[texture.mSampler]; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sampler.mWrapS); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, sampler.mWrapT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, sampler.mMagFilter); + if (channel != -1 && texture.mSampler != -1) + { // set sampler state + Sampler& sampler = asset.mSamplers[texture.mSampler]; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sampler.mWrapS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, sampler.mWrapT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, sampler.mMagFilter); - // NOTE: do not set min filter. Always respect client preference for min filter + // NOTE: do not set min filter. Always respect client preference for min filter + } + else + { + // set default sampler state + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } } else { - // set default sampler state - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, fallback->getTexName()); } } else { - LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback); + glBindTexture(GL_TEXTURE_2D, fallback->getTexName()); } } - else - { - LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback); - } } void GLTFSceneManager::bind(Asset& asset, Material& material) { - // bind for rendering (derived from LLFetchedGLTFMaterial::bind) - // glTF 2.0 Specification 3.9.4. Alpha Coverage - // mAlphaCutoff is only valid for LLGLTFMaterial::ALPHA_MODE_MASK - F32 min_alpha = -1.0; - + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - if (!LLPipeline::sShadowRender || (material.mAlphaMode == Material::AlphaMode::BLEND)) - { - if (material.mAlphaMode == Material::AlphaMode::MASK) - { - // dividing the alpha cutoff by transparency here allows the shader to compare against - // the alpha value of the texture without needing the transparency value - if (material.mPbrMetallicRoughness.mBaseColorFactor.a > 0.f) - { - min_alpha = material.mAlphaCutoff / material.mPbrMetallicRoughness.mBaseColorFactor.a; - } - else - { - min_alpha = 1024.f; - } - } - shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha); - } - - bindTexture(asset, LLShaderMgr::DIFFUSE_MAP, material.mPbrMetallicRoughness.mBaseColorTexture, LLViewerFetchedTexture::sWhiteImagep); - - F32 tf[8]; - material.mPbrMetallicRoughness.mBaseColorTexture.mTextureTransform.getPacked(tf); - shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, tf); - shader->uniform1i(LLShaderMgr::BASE_COLOR_TEXCOORD, material.mPbrMetallicRoughness.mBaseColorTexture.getTexCoord()); + bindTexture(asset, TextureType::BASE_COLOR, material.mPbrMetallicRoughness.mBaseColorTexture, LLViewerFetchedTexture::sWhiteImagep); if (!LLPipeline::sShadowRender) { - bindTexture(asset, LLShaderMgr::NORMAL_MAP, material.mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep); - bindTexture(asset, LLShaderMgr::METALLIC_ROUGHNESS_MAP, material.mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep); - bindTexture(asset, LLShaderMgr::OCCLUSION_MAP, material.mOcclusionTexture, LLViewerFetchedTexture::sWhiteImagep); - bindTexture(asset, LLShaderMgr::EMISSIVE_MAP, material.mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep); - - // NOTE: base color factor is baked into vertex stream - - shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, material.mPbrMetallicRoughness.mRoughnessFactor); - shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, material.mPbrMetallicRoughness.mMetallicFactor); - shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, glm::value_ptr(material.mEmissiveFactor)); - - material.mNormalTexture.mTextureTransform.getPacked(tf); - shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, tf); - shader->uniform1i(LLShaderMgr::NORMAL_TEXCOORD, material.mNormalTexture.getTexCoord()); - - material.mPbrMetallicRoughness.mMetallicRoughnessTexture.mTextureTransform.getPacked(tf); - shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, tf); - shader->uniform1i(LLShaderMgr::METALLIC_ROUGHNESS_TEXCOORD, material.mPbrMetallicRoughness.mMetallicRoughnessTexture.getTexCoord()); - - material.mOcclusionTexture.mTextureTransform.getPacked(tf); - shader->uniform4fv(LLShaderMgr::TEXTURE_OCCLUSION_TRANSFORM, 2, tf); - shader->uniform1i(LLShaderMgr::OCCLUSION_TEXCOORD, material.mOcclusionTexture.getTexCoord()); - - material.mEmissiveTexture.mTextureTransform.getPacked(tf); - shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, tf); - shader->uniform1i(LLShaderMgr::EMISSIVE_TEXCOORD, material.mEmissiveTexture.getTexCoord()); + bindTexture(asset, TextureType::NORMAL, material.mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep); + bindTexture(asset, TextureType::METALLIC_ROUGHNESS, material.mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep); + bindTexture(asset, TextureType::OCCLUSION, material.mOcclusionTexture, LLViewerFetchedTexture::sWhiteImagep); + bindTexture(asset, TextureType::EMISSIVE, material.mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep); } + + shader->uniform1i(LLShaderMgr::GLTF_MATERIAL_ID, &material - &asset.mMaterials[0]); } LLMatrix4a inverse(const LLMatrix4a& mat) @@ -931,10 +933,11 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset) // assumes modelview matrix is already set gGL.pushMatrix(); - // get raycast in asset space LLMatrix4a agent_to_asset = obj->getAgentToGLTFAssetTransform(); + gGL.multMatrix(agent_to_asset.getF32ptr()); + vec4 start; vec4 end; @@ -952,7 +955,8 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset) if (node.mMesh != INVALID_INDEX) { - gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix)); + gGL.pushMatrix(); + gGL.multMatrix((F32*)glm::value_ptr(node.mAssetMatrix)); // draw bounding box of mesh primitives if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) @@ -995,6 +999,7 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } #endif + gGL.popMatrix(); } } @@ -1013,35 +1018,15 @@ void GLTFSceneManager::renderDebug() gDebugProgram.bind(); + gGL.pushMatrix(); + gGL.loadMatrix(gGLModelView); + LLGLDisable cullface(GL_CULL_FACE); LLGLEnable blend(GL_BLEND); gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gPipeline.disableLights(); - // force update all mRenderMatrix, not just nodes with meshes - for (auto& obj : mObjects) - { - if (obj->isDead() || obj->mGLTFAsset == nullptr) - { - continue; - } - - mat4 mat = glm::make_mat4(obj->getGLTFAssetToAgentTransform().getF32ptr()); - - mat4 modelview = glm::make_mat4(gGLModelView); - - - modelview = modelview * mat; - - Asset* asset = obj->mGLTFAsset.get(); - - for (auto& node : asset->mNodes) - { - node.mRenderMatrix = modelview * node.mAssetMatrix; - } - } - for (auto& obj : mObjects) { if (obj->isDead() || obj->mGLTFAsset == nullptr) @@ -1062,9 +1047,6 @@ void GLTFSceneManager::renderDebug() LLGLDepthTest depth(GL_TRUE, i == 0 ? GL_FALSE : GL_TRUE, i == 0 ? GL_GREATER : GL_LEQUAL); LLGLState blend(GL_BLEND, i == 0 ? GL_TRUE : GL_FALSE); - - gGL.pushMatrix(); - for (auto& obj : mObjects) { if (obj->isDead() || obj->mGLTFAsset == nullptr) @@ -1072,20 +1054,16 @@ void GLTFSceneManager::renderDebug() continue; } - mat4 mat = glm::make_mat4(obj->getGLTFAssetToAgentTransform().getF32ptr()); + gGL.pushMatrix(); - mat4 modelview = glm::make_mat4(gGLModelView); - - modelview = modelview * mat; + gGL.multMatrix(obj->getGLTFAssetToAgentTransform().getF32ptr()); Asset* asset = obj->mGLTFAsset.get(); for (auto& node : asset->mNodes) { - // force update all mRenderMatrix, not just nodes with meshes - node.mRenderMatrix = modelview * node.mAssetMatrix; - - gGL.loadMatrix(glm::value_ptr(node.mRenderMatrix)); + gGL.pushMatrix(); + gGL.multMatrix(glm::value_ptr(node.mAssetMatrix)); // render x-axis red, y-axis green, z-axis blue gGL.color4f(1.f, 0.f, 0.f, 0.5f); gGL.begin(LLRender::LINES); @@ -1121,12 +1099,12 @@ void GLTFSceneManager::renderDebug() } gGL.end(); gGL.flush(); + gGL.popMatrix(); } - } - gGL.popMatrix(); + gGL.popMatrix(); + } } - } @@ -1140,28 +1118,36 @@ void GLTFSceneManager::renderDebug() if (drawable) { - gGL.pushMatrix(); - Asset* asset = drawable->getVObj()->mGLTFAsset.get(); - Node* node = &asset->mNodes[node_hit]; - Primitive* primitive = &asset->mMeshes[node->mMesh].mPrimitives[primitive_hit]; - gGL.flush(); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - gGL.color3f(1, 0, 1); - drawBoxOutline(intersection, LLVector4a(0.1f, 0.1f, 0.1f, 0.f)); + LLViewerObject* obj = drawable->getVObj(); + if (obj) + { + gGL.pushMatrix(); + gGL.multMatrix(obj->getGLTFAssetToAgentTransform().getF32ptr()); + Asset* asset = obj->mGLTFAsset.get(); + Node* node = &asset->mNodes[node_hit]; + Primitive* primitive = &asset->mMeshes[node->mMesh].mPrimitives[primitive_hit]; - gGL.loadMatrix(glm::value_ptr(node->mRenderMatrix)); + gGL.flush(); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.color3f(1, 0, 1); + drawBoxOutline(intersection, LLVector4a(0.1f, 0.1f, 0.1f, 0.f)); + gGL.multMatrix(glm::value_ptr(node->mAssetMatrix)); - auto* listener = (LLVolumeOctreeListener*) primitive->mOctree->getListener(0); - drawBoxOutline(listener->mBounds[0], listener->mBounds[1]); + auto* listener = (LLVolumeOctreeListener*)primitive->mOctree->getListener(0); + drawBoxOutline(listener->mBounds[0], listener->mBounds[1]); - gGL.flush(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - gGL.popMatrix(); + gGL.flush(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.popMatrix(); + } } } + + gGL.popMatrix(); gDebugProgram.unbind(); + } |