From c6f8baa058decbf3159bb16c2d655a3230de228a Mon Sep 17 00:00:00 2001 From: kaetemi Date: Fri, 28 May 2021 05:59:40 +0800 Subject: [PATCH] Use streaming vertex buffer for animating regular skinned meshes, writing to a read locked and shared vertex buffer is illegal, fix kaetemi/ryzomclassic#93 --- nel/include/nel/3d/mesh.h | 2 +- nel/src/3d/mesh.cpp | 100 ++++++++++++++++++++++++++++++++++---- 2 files changed, 91 insertions(+), 11 deletions(-) diff --git a/nel/include/nel/3d/mesh.h b/nel/include/nel/3d/mesh.h index 25872a063..0d47037aa 100644 --- a/nel/include/nel/3d/mesh.h +++ b/nel/include/nel/3d/mesh.h @@ -837,7 +837,7 @@ private: void restoreOriginalSkinVertices(); // apply Skin to all vertices from _OriginalSkin* to _VBuffer. - void applySkin(CSkeletonModel *skeleton); + void applySkin(void *dstVb, CSkeletonModel *skeleton); void flagSkinVerticesForMatrixBlock(uint8 *skinFlags, CMatrixBlock &mb); diff --git a/nel/src/3d/mesh.cpp b/nel/src/3d/mesh.cpp index 51b07fdec..f5a391f6e 100644 --- a/nel/src/3d/mesh.cpp +++ b/nel/src/3d/mesh.cpp @@ -30,6 +30,7 @@ #include "nel/3d/render_trav.h" #include "nel/3d/visual_collision_mesh.h" #include "nel/3d/meshvp_wind_tree.h" +#include "nel/3d/vertex_stream_manager.h" using namespace std; using namespace NLMISC; @@ -764,9 +765,38 @@ void CMeshGeom::renderSkin(CTransformShape *trans, float alphaMRM) // NB: the skeleton matrix has already been setuped by CSkeletonModel // NB: the normalize flag has already been setuped by CSkeletonModel + bool supportVertexStream = ((_VBuffer.getVertexFormat() & ~(CVertexBuffer::PaletteSkinFlag | CVertexBuffer::WeightFlag)) + == (CVertexBuffer::PositionFlag | CVertexBuffer::NormalFlag | CVertexBuffer::TexCoord0Flag)) + && (_VBuffer.getValueType(CVertexBuffer::TexCoord0) == CVertexBuffer::Float2) + && (_OriginalSkinNormals.size()) && (!_OriginalTGSpace.size()); + CVertexStreamManager *meshSkinManager = renderTrav->getMeshSkinManager(); + + if (supportVertexStream) + { + uint maxVertices = meshSkinManager->getMaxVertices(); + uint vertexSize = meshSkinManager->getVertexSize(); + nlassert(vertexSize == 32); + + if (_OriginalSkinVertices.size() <= maxVertices) + { + // apply the skinning + uint8 *dstVb = meshSkinManager->lock(); + applySkin(dstVb, skeleton); + meshSkinManager->unlock(_OriginalSkinVertices.size()); + } + else + { + supportVertexStream = false; + nlwarning("Unable to animate skinned model, too many vertices"); + } + } + else + { + nlwarning("Unable to animate skinned model, unsupported vertex format"); + } // apply the skinning: _VBuffer is modified. - applySkin(skeleton); + // applySkin(skeleton); // Setup meshVertexProgram @@ -786,7 +816,14 @@ void CMeshGeom::renderSkin(CTransformShape *trans, float alphaMRM) // Render the mesh. //=========== // active VB. - drv->activeVertexBuffer(_VBuffer); + if (supportVertexStream) + { + meshSkinManager->activate(); + } + else + { + drv->activeVertexBuffer(_VBuffer); + } // For all _MatrixBlocks @@ -816,6 +853,11 @@ void CMeshGeom::renderSkin(CTransformShape *trans, float alphaMRM) } } + if (supportVertexStream) + { + meshSkinManager->swapVBHard(); + } + // End VertexProgram effect if(useMeshVP) { @@ -1787,7 +1829,7 @@ void CMeshGeom::restoreOriginalSkinVertices() // *************************************************************************** -void CMeshGeom::applySkin(CSkeletonModel *skeleton) +void CMeshGeom::applySkin(void *dstVb, CSkeletonModel *skeleton) { // init. //=================== @@ -1802,10 +1844,12 @@ void CMeshGeom::applySkin(CSkeletonModel *skeleton) skinType= SkinWithNormal; else skinType= SkinWithTgSpace; + nlassert(skinType == SkinWithNormal); // Only support the streamable vertex buffer format // Get VB src/dst info/ptrs. uint numVertices= (uint)_OriginalSkinVertices.size(); - uint dstStride= _VBuffer.getVertexSize(); + static const uint dstStride = 32; // _VBuffer.getVertexSize(); + uint srcStride = _VBuffer.getVertexSize(); // Get dst TgSpace. uint tgSpaceStage = 0; if( skinType>= SkinWithTgSpace) @@ -1823,6 +1867,10 @@ void CMeshGeom::applySkin(CSkeletonModel *skeleton) CVertexBufferRead vba; _VBuffer.lock (vba); + uint8 *dstVbPos = (uint8 *)dstVb; + uint8 *dstVbNormal = dstVbPos + 12; + uint8 *dstVbUV = dstVbPos + 24; + // For all MatrixBlocks //=================== for(uint mb= 0; mb<_MatrixBlocks.size();mb++) @@ -1839,25 +1887,25 @@ void CMeshGeom::applySkin(CSkeletonModel *skeleton) CVector *srcVector= &_OriginalSkinVertices[0]; uint8 *srcPal= (uint8*)vba.getPaletteSkinPointer(0); uint8 *srcWgt= (uint8*)vba.getWeightPointer(0); - uint8 *dstVector= (uint8*)vba.getVertexCoordPointer(0); + uint8 *dstVector = dstVbPos; // (uint8 *)vba.getVertexCoordPointer(0); // Normal. CVector *srcNormal= NULL; uint8 *dstNormal= NULL; if(skinType>=SkinWithNormal) { srcNormal= &_OriginalSkinNormals[0]; - dstNormal= (uint8*)vba.getNormalCoordPointer(0); + dstNormal = dstVbNormal; // (uint8 *)vba.getNormalCoordPointer(0); } // TgSpace. CVector *srcTgSpace= NULL; uint8 *dstTgSpace= NULL; if(skinType>=SkinWithTgSpace) { + nlassert(false); srcTgSpace= &_OriginalTGSpace[0]; - dstTgSpace= (uint8*)vba.getTexCoordPointer(0, tgSpaceStage); + dstTgSpace = (uint8 *)vba.getTexCoordPointer(0, tgSpaceStage); } - // For all vertices that need to be computed. uint size= numVertices; for(;size>0;size--) @@ -1895,14 +1943,46 @@ void CMeshGeom::applySkin(CSkeletonModel *skeleton) srcNormal++; srcTgSpace++; // inc paletteSkin and dst (all whatever skin type used...) - srcPal+= dstStride; - srcWgt+= dstStride; + srcPal+= srcStride; + srcWgt+= srcStride; dstVector+= dstStride; dstNormal+= dstStride; dstTgSpace+= dstStride; } } + // Remaining vertices + { + uint8 *pFlag = &skinFlags[0]; + CVector *srcVector = &_OriginalSkinVertices[0]; + uint8 *dstVector = dstVbPos; + CVector *srcNormal = &_OriginalSkinNormals[0]; + uint8 *dstNormal = dstVbNormal; + uint8 *srcUV = (uint8 *)vba.getTexCoordPointer(0, 0); + uint8 *dstUV = dstVbUV; + uint srcStride = _VBuffer.getVertexSize(); + + for (uint i = 0; i < numVertices; ++i) + { + if (*pFlag != NL3D_SOFTSKIN_VCOMPUTED) + { + *(CVector *)dstVector = *srcVector; + *(CVector *)dstNormal = *srcNormal; + } + *(CVector2f *)dstUV = *(CVector2f *)srcUV; + + // inc flags. + pFlag++; + // inc src (all whatever skin type used...) + srcVector++; + srcNormal++; + srcUV += srcStride; + // inc paletteSkin and dst (all whatever skin type used...) + dstVector += dstStride; + dstNormal += dstStride; + dstUV += dstStride; + } + } // dirt _OriginalSkinRestored= false;