[Fix] (Tessellation): compare the default patch levels by bit pattern, so a NaN level stops re-linking the program on every draw

This commit is contained in:
Swung0x48
2026-08-27 03:18:13 -04:00
parent e3163233a5
commit 2635fe84b6
2 changed files with 19 additions and 2 deletions
@@ -220,8 +220,13 @@ namespace MobileGL {
// BumpVersions(), not just ++m_version, for the same reason SetPatchVertices does it:
// these levels are compiled INTO the synthesized pass-through tessellation control
// stage on both backends, so changing one makes an already-built program stale.
//
// The redundant-write guard compares BIT PATTERNS, not floats: glPatchParameterfv
// accepts NaN, and a float compare would let a re-set of the identical NaN tuple fall
// through and bump the pipeline-state version - invalidating DirectVulkan's pipeline
// memo and DirectGLES's render-state span - on every single call.
void RenderState::SetPatchDefaultOuterLevel(const FloatVec4& levels) {
if (m_parameters.PatchDefaultOuterLevel == levels) return;
if (BitwiseEqual(m_parameters.PatchDefaultOuterLevel, levels)) return;
m_parameters.PatchDefaultOuterLevel = levels;
BumpVersions();
@@ -232,7 +237,7 @@ namespace MobileGL {
}
void RenderState::SetPatchDefaultInnerLevel(const FloatVec2& levels) {
if (m_parameters.PatchDefaultInnerLevel == levels) return;
if (BitwiseEqual(m_parameters.PatchDefaultInnerLevel, levels)) return;
m_parameters.PatchDefaultInnerLevel = levels;
BumpVersions();
+12
View File
@@ -10,6 +10,8 @@
#include <Includes.h>
#include <cstring>
namespace MobileGL {
template <typename Derived, typename T, SizeT N>
struct VecBase {
@@ -84,6 +86,16 @@ namespace MobileGL {
}
};
// Bit-pattern equality, for a vector used as a cache or staleness KEY rather than as a
// number. IEEE `==` - which operator== above is - says a NaN never equals itself, so a single
// NaN component makes every comparison answer "changed" and whatever the key guards is
// rebuilt on every use, forever. Two zeros of opposite sign compare unequal here, which only
// ever costs one extra rebuild.
template <typename Derived, typename T, SizeT N>
Bool BitwiseEqual(const VecBase<Derived, T, N>& a, const VecBase<Derived, T, N>& b) {
return std::memcmp(a.data.data(), b.data.data(), sizeof(T) * N) == 0;
}
template <typename T>
struct Vec2 : public VecBase<Vec2<T>, T, 2> {
using Base = VecBase<Vec2<T>, T, 2>;