Skip to content

Skinned Mesh Shader Optimizations and C++ changes to support - #6256

Open
naitro2010 wants to merge 8 commits into
secondlife:developfrom
naitro2010:feature-skinned-mesh-shader-optimizations
Open

naitro2010 wants to merge 8 commits into
secondlife:developfrom
naitro2010:feature-skinned-mesh-shader-optimizations

Conversation

@naitro2010

Copy link
Copy Markdown

Description

This PR moves some processing that used to run on the GPU for every skinned vertex into a precomputed step on the CPU to hopefully improve frame rates with lots of visible avatars.

Here is the linked issue: #6255


Checklist

Please ensure the following before requesting review:

  • [Y] I have provided a clear title and detailed description for this pull request.
  • [Y] If useful, I have included media such as screenshots and video to show off my changes.
  • [Y] The PR is linked to a relevant issue with sufficient context.
  • [M] I have tested the changes locally and verified they work as intended. (I cherrypicked the changes from a local branch with my other modifications to Alchemy Viewer. They work on Alchemy Viewer with my local build.)
  • [?] All new and existing tests pass.
  • [?] Code follows the project's style guidelines.
  • [?] Documentation has been updated if needed.
  • [Y] Any dependent changes have been merged and published in downstream modules
  • [Y] I have reviewed the contributing guidelines.

Additional Notes

This is my first time creating a pull request for Second Life.
Please let me know if I can do anything to improve the next pull requests I make or if there are any code quality issues that I can fix.
I mostly wrote these changes to improve the frame rate for my new version of the viewer with Stereo 3D Virtual Reality rendering that I've been working on but I think they might help with normal rendering too.
I don't have a large number of different GPUs to test on so I'm leaving this pull request as a draft until more people are able to test it on their hardware.

@github-actions github-actions Bot added the c/cpp label Sep 3, 2026
@github-actions

github-actions Bot commented Sep 3, 2026 •

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@naitro2010

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

@akleshchev
akleshchev requested a review from Geenz September 3, 2026 15:31
@naitro2010

Copy link
Copy Markdown
Author

Is there a way to make a release build for this pull request with GitHub actions that I can download and test? I've only tested with a local build so far.

Thanks :)

@akleshchev

akleshchev commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Is there a way to make a release build for this pull request with GitHub actions that I can download and test?

There is a full, downloadable build at the bottom?

@naitro2010

Copy link
Copy Markdown
Author

I just merged the latest changes from develop because the newer LLSD parsing integration test failed to pass.

@naitro2010

Copy link
Copy Markdown
Author

Apparently GitHub is having internal server errors when downloading dependencies now 😢

@akleshchev

akleshchev commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

@naitro2010 there is a green checkbox near the commit, click it, it will show a list of 'checks', that's the build, open any OS specifc one and go to summary.

Artifacts are at the bottom of the summary. https://github.com/secondlife/viewer/actions/runs/34837962086

@naitro2010

Copy link
Copy Markdown
Author

@akleshchev Thanks :)

I'll test with the release build on Windows now.

@akleshchev

Copy link
Copy Markdown
Contributor

Note that it's ReleaseOS, not Release, but the difference should be negligible for shaders.

@naitro2010

Copy link
Copy Markdown
Author

I just tested and it seems like avatar and skinned mesh rendering works on Windows without any issues.
I'm not sure how to profile for A/B testing though.
I think I did see a way to record and replay a connection in the Advanced or Developer menu but I'm not sure how to use it or if it will work for profiling the same scene multiple times.

@akleshchev

Copy link
Copy Markdown
Contributor

Basically you moved some repeating math from gpu to make it one-time on cpu?

Sadly shaders are not in my wheelhouse and I have no idea how to test skinning either.

@naitro2010
naitro2010 marked this pull request as ready for review September 17, 2026 08:47
@akleshchev

Copy link
Copy Markdown
Contributor

@Geenz Please take a look.

@cosmic-linden cosmic-linden left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just starting to review this.

As a general note, math calculations done in C++ in lieu of a shader should be done via glm when possible, but I'm not yet sure if that's applicable here.

Have you tried running Develop > Render Tests > Frame Profile and checking the log for objectSkinV run time? Intuitively, I would think this could make an impact assuming the code is correct (as avatars can have many vertices), but it could be interesting to know.

index = max(index, vec4( 0.0));

w *= 1.0/(w.x+w.y+w.z+w.w);
vec4 w = fract(weight4)*2.0;

@cosmic-linden cosmic-linden Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand why this factor of two is multiplied here. Looks like a new factor of 0.5 is applied in LLFace::getGeometryVolume and Primitive::upload which this is trying to compensate for. See also pbrmetallicroughnessV.glsl, which is another shader which makes use of weight4.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for reviewing my changes. :)

I think the scaling I added in primitive.cpp might be a bug.

weight4 in getGLTFTransform is using a different format for the actual weights.
objectSkinV uses the integer portion for the index and the fractional portion for the weight.
getGLTFTransform splits the two into joints and weights.
It is a bit confusing to have the same input used in two different shaders with different data formats.

Reverting the changes in primitive.cpp seemed to work with normal meshes. I'm going to test with a GLTF PBR mesh next.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just reverted the changes to primitive.cpp and everything seems to still work ok with a local build.
Please let me know if everything else looks good and when another ReleaseOS build is ready.
Thanks :)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the factor of 0.5 is for floating point precision with weights close to 1.0 on the GPU in case it rounds up. I don't know if it is needed on most GPUs though.

@cosmic-linden cosmic-linden Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in case it rounds up

Why would it round up? And why would that fix only be relevant to certain GPUs?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could round up if the precision on the GPU is different than fp32 and the weight is really close to 1.0.
There might be some other cases where it could also have rounding errors accumulate.
If it works without the scaling factor on all CPUs and GPUs it probably isn't needed.
I have run into issues with floating point precision before which is why I added the scaling factor for the fractional portion.

It might be better to have the joints be integers like in pbrmetallicroughnessV.glsl instead of using the integer portion of the floating point weights. It would also make it so the scaling is no longer potentially required.

I'll make two local builds and use the Frame Profiler to compare.

Thanks :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the GPU precision is lower than on CPU, I doubt a factor of two would fix it. Based on what I'm reading, floating point precision on the GPU can differ by multiple digits. And even if it only differed by one digit, I don't think your factor of two workaround is going to address that (best case, it will decrement the floating-point exponent and have no impact on precision at all). I think it would be best to not include that alleged workaround unless we have a bug report which it fixes.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tested with normalization to 1.0 and it caused the skinned mesh to explode.
I just updated the C++ code to normalize to 0.9999 instead of 1.0 for the fractional portion and everything worked ok without the extra scaling factor in the shader.
I'm going to try to do some A/B testing now and see what the frame profiler says.
Thanks :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants