diff --git a/0001-Fix-encoding-decoding-of-string-literals-for-big-end.patch b/0001-Fix-encoding-decoding-of-string-literals-for-big-end.patch new file mode 100644 index 0000000..8fb1fc8 --- /dev/null +++ b/0001-Fix-encoding-decoding-of-string-literals-for-big-end.patch @@ -0,0 +1,192 @@ +From d19aa4a7fc68fe4472cca981a717f9181bc63723 Mon Sep 17 00:00:00 2001 +From: Marius Hillenbrand +Date: Tue, 19 Oct 2021 18:09:52 +0200 +Subject: [PATCH 1/3] Fix encoding/decoding of string literals for big-endian + systems + +Per SPIR-V spec, a string literal's UTF-8 octets are encoded packed into +words with little-endian convention. Explicitly perform that encoding +instead of assuming that the host system is little-endian. + +Note that this change requires corresponding fixes in SPIRV-Tools. + +Fixes #202 +--- + src/3rdparty/glslang/SPIRV/SPVRemapper.cpp | 18 ++++++--- + src/3rdparty/glslang/SPIRV/disassemble.cpp | 47 ++++++++++++++-------- + src/3rdparty/glslang/SPIRV/spvIR.h | 22 +++++----- + 3 files changed, 52 insertions(+), 35 deletions(-) + +diff --git a/src/3rdparty/glslang/SPIRV/SPVRemapper.cpp b/src/3rdparty/glslang/SPIRV/SPVRemapper.cpp +index 56d7f43..3d09c89 100644 +--- a/src/3rdparty/glslang/SPIRV/SPVRemapper.cpp ++++ b/src/3rdparty/glslang/SPIRV/SPVRemapper.cpp +@@ -297,15 +297,21 @@ namespace spv { + std::string spirvbin_t::literalString(unsigned word) const + { + std::string literal; ++ const spirword_t * pos = spv.data() + word; + + literal.reserve(16); + +- const char* bytes = reinterpret_cast(spv.data() + word); +- +- while (bytes && *bytes) +- literal += *bytes++; +- +- return literal; ++ do { ++ spirword_t word = *pos; ++ for (int i = 0; i < 4; i++) { ++ char c = word & 0xff; ++ if (c == '\0') ++ return literal; ++ literal += c; ++ word >>= 8; ++ } ++ pos++; ++ } while (true); + } + + void spirvbin_t::applyMap() +diff --git a/src/3rdparty/glslang/SPIRV/disassemble.cpp b/src/3rdparty/glslang/SPIRV/disassemble.cpp +index 73c988c..74dd605 100644 +--- a/src/3rdparty/glslang/SPIRV/disassemble.cpp ++++ b/src/3rdparty/glslang/SPIRV/disassemble.cpp +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + #include "disassemble.h" + #include "doc.h" +@@ -100,6 +101,7 @@ protected: + void outputMask(OperandClass operandClass, unsigned mask); + void disassembleImmediates(int numOperands); + void disassembleIds(int numOperands); ++ std::pair decodeString(); + int disassembleString(); + void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands); + +@@ -290,31 +292,44 @@ void SpirvStream::disassembleIds(int numOperands) + } + } + +-// return the number of operands consumed by the string +-int SpirvStream::disassembleString() ++// decode string from words at current position (non-consuming) ++std::pair SpirvStream::decodeString() + { +- int startWord = word; +- +- out << " \""; +- +- const char* wordString; ++ std::string res; ++ int wordPos = word; ++ char c; + bool done = false; ++ + do { +- unsigned int content = stream[word]; +- wordString = (const char*)&content; ++ unsigned int content = stream[wordPos]; + for (int charCount = 0; charCount < 4; ++charCount) { +- if (*wordString == 0) { ++ c = content & 0xff; ++ content >>= 8; ++ if (c == '\0') { + done = true; + break; + } +- out << *(wordString++); ++ res += c; + } +- ++word; +- } while (! done); ++ ++wordPos; ++ } while(! done); ++ ++ return std::make_pair(wordPos - word, res); ++} ++ ++// return the number of operands consumed by the string ++int SpirvStream::disassembleString() ++{ ++ out << " \""; + ++ std::pair decoderes = decodeString(); ++ ++ out << decoderes.second; + out << "\""; + +- return word - startWord; ++ word += decoderes.first; ++ ++ return decoderes.first; + } + + void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands) +@@ -331,7 +346,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, + nextNestedControl = 0; + } + } else if (opCode == OpExtInstImport) { +- idDescriptor[resultId] = (const char*)(&stream[word]); ++ idDescriptor[resultId] = decodeString().second; + } + else { + if (resultId != 0 && idDescriptor[resultId].size() == 0) { +@@ -428,7 +443,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, + --numOperands; + // Get names for printing "(XXX)" for readability, *after* this id + if (opCode == OpName) +- idDescriptor[stream[word - 1]] = (const char*)(&stream[word]); ++ idDescriptor[stream[word - 1]] = decodeString().second; + break; + case OperandVariableIds: + disassembleIds(numOperands); +diff --git a/src/3rdparty/glslang/SPIRV/spvIR.h b/src/3rdparty/glslang/SPIRV/spvIR.h +index 486e80d..5249a5b 100755 +--- a/src/3rdparty/glslang/SPIRV/spvIR.h ++++ b/src/3rdparty/glslang/SPIRV/spvIR.h +@@ -111,27 +111,23 @@ public: + + void addStringOperand(const char* str) + { +- unsigned int word; +- char* wordString = (char*)&word; +- char* wordPtr = wordString; +- int charCount = 0; ++ unsigned int word = 0; ++ unsigned int shiftAmount = 0; + char c; ++ + do { + c = *(str++); +- *(wordPtr++) = c; +- ++charCount; +- if (charCount == 4) { ++ word |= ((unsigned int)c) << shiftAmount; ++ shiftAmount += 8; ++ if (shiftAmount == 32) { + addImmediateOperand(word); +- wordPtr = wordString; +- charCount = 0; ++ word = 0; ++ shiftAmount = 0; + } + } while (c != 0); + + // deal with partial last word +- if (charCount > 0) { +- // pad with 0s +- for (; charCount < 4; ++charCount) +- *(wordPtr++) = 0; ++ if (shiftAmount > 0) { + addImmediateOperand(word); + } + } +-- +2.34.1 + diff --git a/0002-TIntermediate-promoteConstantUnion-fix-conversion-to.patch b/0002-TIntermediate-promoteConstantUnion-fix-conversion-to.patch new file mode 100644 index 0000000..cbae162 --- /dev/null +++ b/0002-TIntermediate-promoteConstantUnion-fix-conversion-to.patch @@ -0,0 +1,33 @@ +From 75e3ed99c61b1d201498b5a7fbb6498f902344e0 Mon Sep 17 00:00:00 2001 +From: Marius Hillenbrand +Date: Wed, 10 Nov 2021 18:10:58 +0100 +Subject: [PATCH 2/3] TIntermediate::promoteConstantUnion(): fix conversion to + int8 + +The signedness of type char is implementation-defined in C++. The +conversion to (signed) int8 currently uses a cast to char, which is +undefined for negative values when the type char is implemented as +unsigned. Thus, fix to cast to "signed char", which has the intended +semantic on all implementations. + +Fixes #2807 +--- + .../glslang/glslang/MachineIndependent/Intermediate.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp b/src/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp +index 84b4c55..89538ea 100644 +--- a/src/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp ++++ b/src/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp +@@ -3867,7 +3867,7 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC + case EbtFloat16: PROMOTE(setDConst, double, Get); break; \ + case EbtFloat: PROMOTE(setDConst, double, Get); break; \ + case EbtDouble: PROMOTE(setDConst, double, Get); break; \ +- case EbtInt8: PROMOTE(setI8Const, char, Get); break; \ ++ case EbtInt8: PROMOTE(setI8Const, signed char, Get); break; \ + case EbtInt16: PROMOTE(setI16Const, short, Get); break; \ + case EbtInt: PROMOTE(setIConst, int, Get); break; \ + case EbtInt64: PROMOTE(setI64Const, long long, Get); break; \ +-- +2.34.1 + diff --git a/0003-Use-intermOut.cpp-s-IsNan-and-IsInfinity-for-parse-t.patch b/0003-Use-intermOut.cpp-s-IsNan-and-IsInfinity-for-parse-t.patch new file mode 100644 index 0000000..6d3d76b --- /dev/null +++ b/0003-Use-intermOut.cpp-s-IsNan-and-IsInfinity-for-parse-t.patch @@ -0,0 +1,177 @@ +From 1c28979226b8bb5a61bcbfa9b2c1963072bc7df4 Mon Sep 17 00:00:00 2001 +From: Marius Hillenbrand +Date: Tue, 9 Nov 2021 16:31:22 +0100 +Subject: [PATCH 3/3] Use intermOut.cpp's IsNan and IsInfinity for parse-time + constant folding (updated) + +There were two implementations of isInf() and isNan(), in Constant.cpp +and in intermOut.cpp. The former only works on little-endian systems, +the latter is a wrapper for library functions and works regardless of +endianness. Move the second version into Common.h and adopt it in both +places. Thereby avoid the duplication and fix for big-endian systems. + +A previous commit with the same intent and purpose had missed a required +header for builds on Windows. + +On s390x, this fixes the test case +Glsl/CompileToAstTest.FromFile/constFold_frag. + +Fixes #2802 +--- + src/3rdparty/glslang/glslang/Include/Common.h | 34 +++++++++++++++++++ + .../glslang/MachineIndependent/Constant.cpp | 33 ++---------------- + .../glslang/MachineIndependent/intermOut.cpp | 31 ----------------- + 3 files changed, 36 insertions(+), 62 deletions(-) + +diff --git a/src/3rdparty/glslang/glslang/Include/Common.h b/src/3rdparty/glslang/glslang/Include/Common.h +index 115f6f7..5b2dae6 100644 +--- a/src/3rdparty/glslang/glslang/Include/Common.h ++++ b/src/3rdparty/glslang/glslang/Include/Common.h +@@ -39,6 +39,11 @@ + + #include + #include ++#ifdef _MSC_VER ++#include ++#else ++#include ++#endif + #include + #include + #include +@@ -288,6 +293,35 @@ template bool IsMultipleOfPow2(T number, int powerOf2) + return ! (number & (powerOf2 - 1)); + } + ++inline bool IsInfinity(double x) { ++#ifdef _MSC_VER ++ switch (_fpclass(x)) { ++ case _FPCLASS_NINF: ++ case _FPCLASS_PINF: ++ return true; ++ default: ++ return false; ++ } ++#else ++ return std::isinf(x); ++#endif ++} ++ ++inline bool IsNan(double x) { ++#ifdef _MSC_VER ++ switch (_fpclass(x)) { ++ case _FPCLASS_SNAN: ++ case _FPCLASS_QNAN: ++ return true; ++ default: ++ return false; ++ } ++#else ++ return std::isnan(x); ++#endif ++} ++ ++ + } // end namespace glslang + } // namespace QtShaderTools + +diff --git a/src/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp b/src/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp +index 23c511e..1b23d68 100644 +--- a/src/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp ++++ b/src/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp +@@ -46,35 +46,6 @@ namespace { + using namespace QtShaderTools; + using namespace glslang; + +-typedef union { +- double d; +- int i[2]; +-} DoubleIntUnion; +- +-// Some helper functions +- +-bool isNan(double x) +-{ +- DoubleIntUnion u; +- // tough to find a platform independent library function, do it directly +- u.d = x; +- int bitPatternL = u.i[0]; +- int bitPatternH = u.i[1]; +- return (bitPatternH & 0x7ff80000) == 0x7ff80000 && +- ((bitPatternH & 0xFFFFF) != 0 || bitPatternL != 0); +-} +- +-bool isInf(double x) +-{ +- DoubleIntUnion u; +- // tough to find a platform independent library function, do it directly +- u.d = x; +- int bitPatternL = u.i[0]; +- int bitPatternH = u.i[1]; +- return (bitPatternH & 0x7ff00000) == 0x7ff00000 && +- (bitPatternH & 0xFFFFF) == 0 && bitPatternL == 0; +-} +- + const double pi = 3.1415926535897932384626433832795; + + } // end anonymous namespace +@@ -664,12 +635,12 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) + + case EOpIsNan: + { +- newConstArray[i].setBConst(isNan(unionArray[i].getDConst())); ++ newConstArray[i].setBConst(IsNan(unionArray[i].getDConst())); + break; + } + case EOpIsInf: + { +- newConstArray[i].setBConst(isInf(unionArray[i].getDConst())); ++ newConstArray[i].setBConst(IsInfinity(unionArray[i].getDConst())); + break; + } + +diff --git a/src/3rdparty/glslang/glslang/MachineIndependent/intermOut.cpp b/src/3rdparty/glslang/glslang/MachineIndependent/intermOut.cpp +index e07cdfe..9478fd5 100644 +--- a/src/3rdparty/glslang/glslang/MachineIndependent/intermOut.cpp ++++ b/src/3rdparty/glslang/glslang/MachineIndependent/intermOut.cpp +@@ -48,37 +48,6 @@ + #endif + #include + +-namespace { +- +-bool IsInfinity(double x) { +-#ifdef _MSC_VER +- switch (_fpclass(x)) { +- case _FPCLASS_NINF: +- case _FPCLASS_PINF: +- return true; +- default: +- return false; +- } +-#else +- return std::isinf(x); +-#endif +-} +- +-bool IsNan(double x) { +-#ifdef _MSC_VER +- switch (_fpclass(x)) { +- case _FPCLASS_SNAN: +- case _FPCLASS_QNAN: +- return true; +- default: +- return false; +- } +-#else +- return std::isnan(x); +-#endif +-} +- +-} + + namespace QtShaderTools { + +-- +2.34.1 + diff --git a/qt6-shadertools.changes b/qt6-shadertools.changes index 9547497..e15af95 100644 --- a/qt6-shadertools.changes +++ b/qt6-shadertools.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Fri Dec 10 19:52:26 UTC 2021 - Christophe Giboudeaux + +- Add patches to fix endianness issues on big endian platforms: + * 0001-Fix-encoding-decoding-of-string-literals-for-big-end.patch + * 0002-TIntermediate-promoteConstantUnion-fix-conversion-to.patch + * 0003-Use-intermOut.cpp-s-IsNan-and-IsInfinity-for-parse-t.patch + ------------------------------------------------------------------- Wed Dec 1 10:06:27 UTC 2021 - Christophe Giboudeaux diff --git a/qt6-shadertools.spec b/qt6-shadertools.spec index e815dd9..7e007bd 100644 --- a/qt6-shadertools.spec +++ b/qt6-shadertools.spec @@ -34,6 +34,10 @@ License: GPL-3.0-or-later URL: https://www.qt.io Source: https://download.qt.io/official_releases/qt/%{short_version}/%{real_version}%{tar_suffix}/submodules/%{tar_name}-%{real_version}%{tar_suffix}.tar.xz Source99: qt6-shadertools-rpmlintrc +# PATCH-FIX-UPSTREAM Fix endianness issues on big endian platforms +Patch0: 0001-Fix-encoding-decoding-of-string-literals-for-big-end.patch +Patch1: 0002-TIntermediate-promoteConstantUnion-fix-conversion-to.patch +Patch2: 0003-Use-intermOut.cpp-s-IsNan-and-IsInfinity-for-parse-t.patch BuildRequires: qt6-gui-private-devel BuildRequires: cmake(Qt6Core) BuildRequires: cmake(Qt6Gui)