From 00cf6e92425b187fd63432b4694fb817c9fa77fa Mon Sep 17 00:00:00 2001 From: Fedor Chelnokov Date: Thu, 3 Sep 2026 23:41:07 +0300 Subject: [PATCH] Take the desktop picker id through a flat varying, not gl_PrimitiveID The Ubuntu 26.04 UI test picked face -1090332440 out of a 512-face mesh. On desktop RenderMeshObject::renderPicker uses MeshDesktopPicker, whose fragment shader took the id from gl_PrimitiveID, and that is the one channel of the pick pixel that came back wrong - uniGeomId, a uniform in the neighbouring channel, was right. llvmpipe 21.1.8 / Mesa 26.0.8 is the only stack where it happens; 22.04 and 24.04 pass. The vertex shader already computes the id as uint(gl_VertexID) / primBucketSize for the corner-mode path, so pass that same value down a flat integer varying and read it instead. Emscripten keeps gl_PrimitiveID untouched behind #ifndef, and the varying is declared only in the mode that reads it so the lines pickers keep linking. --- source/MRViewer/MRGLStaticHolder.cpp | 16 +++++++++++++++- source/MRViewer/MRShaderBlocks.cpp | 10 +++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/source/MRViewer/MRGLStaticHolder.cpp b/source/MRViewer/MRGLStaticHolder.cpp index 26f3aac04f66..df82745c95c5 100644 --- a/source/MRViewer/MRGLStaticHolder.cpp +++ b/source/MRViewer/MRGLStaticHolder.cpp @@ -182,7 +182,14 @@ void GLStaticHolder::createShader_( ShaderType type ) out vec3 world_pos; out float primitiveIdf0; out float primitiveIdf1; - +)" +#ifndef __EMSCRIPTEN__ + // desktop GL has integer varyings, so the id needs no float round-trip + R"( + flat out uint primitiveIdFlat; +)" +#endif + R"( void main() { world_pos = vec3(model*vec4 (position, 1.0)); @@ -190,6 +197,13 @@ void GLStaticHolder::createShader_( ShaderType type ) uint primId = uint(gl_VertexID) / primBucketSize; primitiveIdf1 = float( uint( primId >> 20u ) ) + 0.5; primitiveIdf0 = float( primId % uint( 1u << 20u ) ) + 0.5; +)" +#ifndef __EMSCRIPTEN__ + R"( + primitiveIdFlat = primId; +)" +#endif + R"( gl_PointSize = pointSize; } )"; diff --git a/source/MRViewer/MRShaderBlocks.cpp b/source/MRViewer/MRShaderBlocks.cpp index f15cd093d208..2e182fa07fd0 100644 --- a/source/MRViewer/MRShaderBlocks.cpp +++ b/source/MRViewer/MRShaderBlocks.cpp @@ -22,11 +22,18 @@ std::string getPickerFragmentShader( bool points, bool cornerMode ) out highp uvec4 color; )"; + // outside corner mode the id arrives in a flat integer varying: gl_PrimitiveID came back + // as garbage under llvmpipe 21.1.8 / Mesa 26.0.8. Declared only where read, so the pickers + // that stay in corner mode keep linking against vertex shaders without it. const std::string primId = cornerMode ? R"( uint primitiveId = ( uint(primitiveIdf1) << 20u ) + uint(primitiveIdf0); )" : R"( - uint primitiveId = uint(gl_PrimitiveID); + uint primitiveId = primitiveIdFlat; +)"; + + const std::string idDecl = cornerMode ? "" : R"( + flat in uint primitiveIdFlat; )"; const std::string tail = R"( @@ -39,6 +46,7 @@ std::string getPickerFragmentShader( bool points, bool cornerMode ) return head + + idDecl + getShaderMainBeginBlock( false ) + ( points ? getFragmentShaderPointSizeBlock() : R"()" ) + getFragmentShaderClippingBlock() +