(glslang) Cleanups

This commit is contained in:
libretroadmin 2024-05-23 18:18:11 +02:00
parent bdff6a146b
commit 5454b570e7
2 changed files with 170 additions and 135 deletions

View File

@ -305,7 +305,7 @@ static spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
static spv::Decoration TranslatePrecisionDecoration(glslang::TPrecisionQualifier glslangPrecision)
{
switch (glslangPrecision) {
case glslang::EpqLow: return spv::DecorationRelaxedPrecision;
case glslang::EpqLow:
case glslang::EpqMedium: return spv::DecorationRelaxedPrecision;
default: break;
}
@ -321,11 +321,14 @@ static spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
// Translate glslang type to SPIR-V block decorations.
static spv::Decoration TranslateBlockDecoration(const glslang::TType& type, bool useStorageBuffer)
{
if (type.getBasicType() == glslang::EbtBlock) {
if (type.getBasicType() == glslang::EbtBlock)
{
switch (type.getQualifier().storage) {
case glslang::EvqUniform: return spv::DecorationBlock;
case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock;
case glslang::EvqVaryingIn: return spv::DecorationBlock;
case glslang::EvqBuffer:
if (!useStorageBuffer) return spv::DecorationBufferBlock;
/* fallthrough */
case glslang::EvqUniform:
case glslang::EvqVaryingIn:
case glslang::EvqVaryingOut: return spv::DecorationBlock;
default:
break;
@ -355,7 +358,8 @@ void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector
// Translate glslang type to SPIR-V layout decorations.
spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::TLayoutMatrix matrixLayout)
{
if (type.isMatrix()) {
if (type.isMatrix())
{
switch (matrixLayout) {
case glslang::ElmRowMajor:
return spv::DecorationRowMajor;
@ -363,12 +367,14 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::T
return spv::DecorationColMajor;
default:
// opaque layouts don't need a majorness
return spv::DecorationMax;
break;
}
} else {
}
else
{
switch (type.getBasicType()) {
default:
return spv::DecorationMax;
break;
case glslang::EbtBlock:
switch (type.getQualifier().storage) {
case glslang::EvqUniform:
@ -376,16 +382,17 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::T
switch (type.getQualifier().layoutPacking) {
case glslang::ElpShared: return spv::DecorationGLSLShared;
case glslang::ElpPacked: return spv::DecorationGLSLPacked;
default:
return spv::DecorationMax;
default: break;
}
break;
case glslang::EvqVaryingIn:
case glslang::EvqVaryingOut:
default:
return spv::DecorationMax;
break;
}
}
}
return spv::DecorationMax;
}
// Translate glslang type to SPIR-V interpolation decorations.
@ -419,11 +426,12 @@ spv::Decoration TGlslangToSpvTraverser::TranslateAuxiliaryStorageDecoration(cons
return spv::DecorationPatch;
else if (qualifier.centroid)
return spv::DecorationCentroid;
else if (qualifier.sample) {
else if (qualifier.sample)
{
builder.addCapability(spv::CapabilitySampleRateShading);
return spv::DecorationSample;
} else
return spv::DecorationMax;
}
return spv::DecorationMax;
}
// If glslang type is invariant, return SPIR-V invariant decoration.

View File

@ -113,11 +113,6 @@ class FloatProxy {
// Returns the raw data.
uint_type data() const { return data_; }
// Returns true if the value represents any type of NaN.
bool isNan() { return FloatProxyTraits<T>::isNan(getAsFloat()); }
// Returns true if the value represents any type of infinity.
bool isInfinity() { return std::isinf(getAsFloat()); }
// Returns the maximum normal value.
static FloatProxy<T> max() {
return FloatProxy<T>(std::numeric_limits<float>::max());
@ -324,13 +319,14 @@ class HexFloat {
// If the number was normalized, returns the unbiased exponent.
// If the number was denormal, normalize the exponent first.
const int_type getUnbiasedNormalizedExponent() const {
if ((getBits() & ~sign_mask) == 0) { // special case if everything is 0
if ((getBits() & ~sign_mask) == 0) // special case if everything is 0
return 0;
}
int_type exp = getUnbiasedExponent();
if (exp == min_exponent) { // We are in denorm land.
if (exp == min_exponent)
{ // We are in denorm land.
uint_type significand_bits = getSignificandBits();
while ((significand_bits & (first_exponent_bit >> 1)) == 0) {
while ((significand_bits & (first_exponent_bit >> 1)) == 0)
{
significand_bits = static_cast<uint_type>(significand_bits << 1);
exp = static_cast<int_type>(exp - 1);
}
@ -340,12 +336,12 @@ class HexFloat {
}
// Returns the signficand after it has been normalized.
const uint_type getNormalizedSignificand() const {
const uint_type getNormalizedSignificand() const
{
int_type unbiased_exponent = getUnbiasedNormalizedExponent();
uint_type significand = getSignificandBits();
for (int_type i = unbiased_exponent; i <= min_exponent; ++i) {
for (int_type i = unbiased_exponent; i <= min_exponent; ++i)
significand = static_cast<uint_type>(significand << 1);
}
significand &= fraction_encode_mask;
return significand;
}
@ -390,9 +386,8 @@ class HexFloat {
}
uint_type new_value = 0;
if (negative) {
if (negative)
new_value = static_cast<uint_type>(new_value | sign_mask);
}
exponent = static_cast<int_type>(exponent + exponent_bias);
// put it all together
@ -410,7 +405,8 @@ class HexFloat {
// All significands and to_increment are assumed to be within the bounds
// for a valid significand.
static uint_type incrementSignificand(uint_type significand,
uint_type to_increment, bool* carry) {
uint_type to_increment, bool* carry)
{
significand = static_cast<uint_type>(significand + to_increment);
*carry = false;
if (significand & first_exponent_bit) {
@ -431,18 +427,16 @@ class HexFloat {
template <typename int_type>
uint_type negatable_left_shift(int_type N, uint_type val)
{
if(N >= 0)
if (N >= 0)
return val << N;
return val >> -N;
}
template <typename int_type>
uint_type negatable_right_shift(int_type N, uint_type val)
{
if(N >= 0)
if (N >= 0)
return val >> N;
return val << -N;
}
@ -485,15 +479,15 @@ class HexFloat {
// If every non-representable bit is 0, then we don't have any casting to
// do.
if ((significand & throwaway_mask) == 0) {
if ((significand & throwaway_mask) == 0)
return static_cast<other_uint_type>(
negatable_right_shift(num_throwaway_bits, significand));
}
bool round_away_from_zero = false;
// We actually have to narrow the significand here, so we have to follow the
// rounding rules.
switch (dir) {
switch (dir)
{
case kRoundToZero:
break;
case kRoundToPositiveInfinity:
@ -504,17 +498,18 @@ class HexFloat {
break;
case kRoundToNearestEven:
// Have to round down, round bit is 0
if ((first_rounded_bit & significand) == 0) {
if ((first_rounded_bit & significand) == 0)
break;
}
if (((significand & throwaway_mask) & ~first_rounded_bit) != 0) {
if (((significand & throwaway_mask) & ~first_rounded_bit) != 0)
{
// If any subsequent bit of the rounded portion is non-0 then we round
// up.
round_away_from_zero = true;
break;
}
// We are exactly half-way between 2 numbers, pick even.
if ((significand & last_significant_bit) != 0) {
if ((significand & last_significant_bit) != 0)
{
// 1 for our last bit, round up.
round_away_from_zero = true;
break;
@ -522,14 +517,12 @@ class HexFloat {
break;
}
if (round_away_from_zero) {
if (round_away_from_zero)
return static_cast<other_uint_type>(
negatable_right_shift(num_throwaway_bits, incrementSignificand(
significand, last_significant_bit, carry_bit)));
} else {
return static_cast<other_uint_type>(
negatable_right_shift(num_throwaway_bits, significand));
}
return static_cast<other_uint_type>(
negatable_right_shift(num_throwaway_bits, significand));
}
// Casts this value to another HexFloat. If the cast is widening,
@ -542,10 +535,10 @@ class HexFloat {
void castTo(other_T& other, round_direction round_dir) {
other = other_T(static_cast<typename other_T::native_type>(0));
bool negate = isNegative();
if (getUnsignedBits() == 0) {
if (negate) {
if (getUnsignedBits() == 0)
{
if (negate)
other.set_value(-other.value());
}
return;
}
uint_type significand = getSignificandBits();
@ -656,9 +649,11 @@ std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
// If we are denorm, then start shifting, and decreasing the exponent until
// our leading bit is 1.
if (is_denorm) {
while ((fraction & HF::fraction_top_bit) == 0) {
fraction = static_cast<uint_type>(fraction << 1);
if (is_denorm)
{
while ((fraction & HF::fraction_top_bit) == 0)
{
fraction = static_cast<uint_type>(fraction << 1);
int_exponent = static_cast<int_type>(int_exponent - 1);
}
// Since this is denormalized, we have to consume the leading 1 since it
@ -680,12 +675,11 @@ std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
const auto saved_fill = os.fill();
os << sign << "0x" << (is_zero ? '0' : '1');
if (fraction_nibbles) {
// Make sure to keep the leading 0s in place, since this is the fractional
// part.
// Make sure to keep the leading 0s in place, since this is the fractional
// part.
if (fraction_nibbles)
os << "." << std::setw(static_cast<int>(fraction_nibbles))
<< std::setfill('0') << std::hex << fraction;
}
os << "p" << std::dec << (int_exponent >= 0 ? "+" : "") << int_exponent;
os.flags(saved_flags);
@ -699,10 +693,13 @@ std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
// on the stream and set the value to the zero value for its type.
template <typename T, typename Traits>
inline bool RejectParseDueToLeadingSign(std::istream& is, bool negate_value,
HexFloat<T, Traits>& value) {
if (negate_value) {
HexFloat<T, Traits>& value)
{
if (negate_value)
{
auto next_char = is.peek();
if (next_char == '-' || next_char == '+') {
if (next_char == '-' || next_char == '+')
{
// Fail the parse. Emulate standard behaviour by setting the value to
// the zero value, and set the fail bit on the stream.
value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type(0));
@ -725,21 +722,23 @@ inline bool RejectParseDueToLeadingSign(std::istream& is, bool negate_value,
// In particular, the Microsoft C++ runtime appears to be out of spec.
template <typename T, typename Traits>
inline std::istream& ParseNormalFloat(std::istream& is, bool negate_value,
HexFloat<T, Traits>& value) {
if (RejectParseDueToLeadingSign(is, negate_value, value)) {
return is;
}
HexFloat<T, Traits>& value)
{
T val;
if (RejectParseDueToLeadingSign(is, negate_value, value))
return is;
is >> val;
if (negate_value) {
if (negate_value)
val = -val;
}
value.set_value(val);
// In the failure case, map -0.0 to 0.0.
if (is.fail() && value.getUnsignedBits() == 0u) {
if (is.fail() && value.getUnsignedBits() == 0u)
value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type(0));
}
if (val.isInfinity()) {
// Does the value represents any type of infinity?
if (std::isinf(val.getAsFloat()))
{
// Fail the parse. Emulate standard behaviour by setting the value to
// the closest normal value, and set the fail bit on the stream.
value.set_value((value.isNegative() | negate_value) ? T::lowest()
@ -776,7 +775,8 @@ ParseNormalFloat<FloatProxy<Float16>, HexFloatTraits<FloatProxy<Float16>>>(
// Overflow on 16-bit behaves the same as for 32- and 64-bit: set the
// fail bit and set the lowest or highest value.
if (Float16::isInfinity(value.value().getAsFloat())) {
if (Float16::isInfinity(value.value().getAsFloat()))
{
value.set_value(value.isNegative() ? Float16(0xfbff) : Float16(0x7bff));
is.setstate(std::ios_base::failbit);
}
@ -803,45 +803,47 @@ ParseNormalFloat<FloatProxy<Float16>, HexFloatTraits<FloatProxy<Float16>>>(
// 0x1p+129 (+inf)
// -0x1p+129 (-inf)
template <typename T, typename Traits>
std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
using HF = HexFloat<T, Traits>;
std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value)
{
using HF = HexFloat<T, Traits>;
using uint_type = typename HF::uint_type;
using int_type = typename HF::int_type;
using int_type = typename HF::int_type;
value.set_value(static_cast<typename HF::native_type>(0.f));
if (is.flags() & std::ios::skipws) {
if (is.flags() & std::ios::skipws)
{
// If the user wants to skip whitespace , then we should obey that.
while (std::isspace(is.peek())) {
while (std::isspace(is.peek()))
is.get();
}
}
auto next_char = is.peek();
bool negate_value = false;
if (next_char != '-' && next_char != '0') {
if (next_char != '-' && next_char != '0')
return ParseNormalFloat(is, negate_value, value);
}
if (next_char == '-') {
if (next_char == '-')
{
negate_value = true;
is.get();
next_char = is.peek();
}
if (next_char == '0') {
if (next_char == '0')
{
is.get(); // We may have to unget this.
auto maybe_hex_start = is.peek();
if (maybe_hex_start != 'x' && maybe_hex_start != 'X') {
if (maybe_hex_start != 'x' && maybe_hex_start != 'X')
{
is.unget();
return ParseNormalFloat(is, negate_value, value);
} else {
is.get(); // Throw away the 'x';
}
} else {
return ParseNormalFloat(is, negate_value, value);
is.get(); // Throw away the 'x';
}
else
return ParseNormalFloat(is, negate_value, value);
// This "looks" like a hex-float so treat it as one.
bool seen_p = false;
@ -852,29 +854,32 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
int_type exponent = HF::exponent_bias;
// Strip off leading zeros so we don't have to special-case them later.
while ((next_char = is.peek()) == '0') {
while ((next_char = is.peek()) == '0')
is.get();
}
bool is_denorm =
true; // Assume denorm "representation" until we hear otherwise.
// NB: This does not mean the value is actually denorm,
// it just means that it was written 0.
// Assume denorm "representation" until we hear otherwise.
// NB: This does not mean the value is actually denorm,
// it just means that it was written 0.
bool is_denorm = true;
bool bits_written = false; // Stays false until we write a bit.
while (!seen_p && !seen_dot) {
while (!seen_p && !seen_dot)
{
// Handle characters that are left of the fractional part.
if (next_char == '.') {
if (next_char == '.')
seen_dot = true;
} else if (next_char == 'p') {
else if (next_char == 'p')
seen_p = true;
} else if (::isxdigit(next_char)) {
else if (::isxdigit(next_char))
{
// We know this is not denormalized since we have stripped all leading
// zeroes and we are not a ".".
is_denorm = false;
int number = get_nibble_from_character(next_char);
for (int i = 0; i < 4; ++i, number <<= 1) {
for (int i = 0; i < 4; ++i, number <<= 1)
{
uint_type write_bit = (number & 0x8) ? 0x1 : 0x0;
if (bits_written) {
if (bits_written)
{
// If we are here the bits represented belong in the fractional
// part of the float, and we have to adjust the exponent accordingly.
fraction = static_cast<uint_type>(
@ -885,7 +890,9 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
}
bits_written |= write_bit != 0;
}
} else {
}
else
{
// We have not found our exponent yet, so we have to fail.
is.setstate(std::ios::failbit);
return is;
@ -894,28 +901,32 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
next_char = is.peek();
}
bits_written = false;
while (seen_dot && !seen_p) {
while (seen_dot && !seen_p)
{
// Handle only fractional parts now.
if (next_char == 'p') {
if (next_char == 'p')
seen_p = true;
} else if (::isxdigit(next_char)) {
else if (::isxdigit(next_char))
{
int number = get_nibble_from_character(next_char);
for (int i = 0; i < 4; ++i, number <<= 1) {
for (int i = 0; i < 4; ++i, number <<= 1)
{
uint_type write_bit = (number & 0x8) ? 0x01 : 0x00;
bits_written |= write_bit != 0;
if (is_denorm && !bits_written) {
// Handle modifying the exponent here this way we can handle
// an arbitrary number of hex values without overflowing our
// integer.
// Handle modifying the exponent here this way we can handle
// an arbitrary number of hex values without overflowing our
// integer.
if (is_denorm && !bits_written)
exponent = static_cast<int_type>(exponent - 1);
} else {
else
fraction = static_cast<uint_type>(
fraction |
static_cast<uint_type>(
write_bit << (HF::top_bit_left_shift - fraction_index++)));
}
}
} else {
}
else
{
// We still have not found our 'p' exponent yet, so this is not a valid
// hex-float.
is.setstate(std::ios::failbit);
@ -928,22 +939,28 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
bool seen_sign = false;
int8_t exponent_sign = 1;
int_type written_exponent = 0;
while (true) {
if ((next_char == '-' || next_char == '+')) {
if (seen_sign) {
for (;;)
{
if ((next_char == '-' || next_char == '+'))
{
if (seen_sign)
{
is.setstate(std::ios::failbit);
return is;
}
seen_sign = true;
seen_sign = true;
exponent_sign = (next_char == '-') ? -1 : 1;
} else if (::isdigit(next_char)) {
}
else if (::isdigit(next_char))
{
// Hex-floats express their exponent as decimal.
written_exponent = static_cast<int_type>(written_exponent * 10);
written_exponent =
static_cast<int_type>(written_exponent + (next_char - '0'));
} else {
break;
}
else
break;
is.get();
next_char = is.peek();
}
@ -952,14 +969,16 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
exponent = static_cast<int_type>(exponent + written_exponent);
bool is_zero = is_denorm && (fraction == 0);
if (is_denorm && !is_zero) {
if (is_denorm && !is_zero)
{
fraction = static_cast<uint_type>(fraction << 1);
exponent = static_cast<int_type>(exponent - 1);
} else if (is_zero) {
exponent = 0;
}
else if (is_zero)
exponent = 0;
if (exponent <= 0 && !is_zero) {
if (exponent <= 0 && !is_zero)
{
fraction = static_cast<uint_type>(fraction >> 1);
fraction |= static_cast<uint_type>(1) << HF::top_bit_left_shift;
}
@ -970,12 +989,14 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
SetBits<uint_type, 0, HF::num_exponent_bits>::get;
// Handle actual denorm numbers
while (exponent < 0 && !is_zero) {
while (exponent < 0 && !is_zero)
{
fraction = static_cast<uint_type>(fraction >> 1);
exponent = static_cast<int_type>(exponent + 1);
fraction &= HF::fraction_encode_mask;
if (fraction == 0) {
if (fraction == 0)
{
// We have underflowed our fraction. We should clamp to zero.
is_zero = true;
exponent = 0;
@ -983,7 +1004,8 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
}
// We have overflowed so we should be inf/-inf.
if (exponent > max_exponent) {
if (exponent > max_exponent)
{
exponent = max_exponent;
fraction = 0;
}
@ -1008,26 +1030,31 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
// enough digits to fully reproduce the value. Other values (subnormal,
// NaN, and infinity) are printed as a hex float.
template <typename T>
std::ostream& operator<<(std::ostream& os, const FloatProxy<T>& value) {
std::ostream& operator<<(std::ostream& os, const FloatProxy<T>& value)
{
auto float_val = value.getAsFloat();
switch (std::fpclassify(float_val)) {
case FP_ZERO:
case FP_NORMAL: {
auto saved_precision = os.precision();
os.precision(std::numeric_limits<T>::digits10);
os << float_val;
os.precision(saved_precision);
} break;
default:
os << HexFloat<FloatProxy<T>>(value);
break;
switch (std::fpclassify(float_val))
{
case FP_ZERO:
case FP_NORMAL:
{
auto saved_precision = os.precision();
os.precision(std::numeric_limits<T>::digits10);
os << float_val;
os.precision(saved_precision);
}
break;
default:
os << HexFloat<FloatProxy<T>>(value);
break;
}
return os;
}
template <>
inline std::ostream& operator<<<Float16>(std::ostream& os,
const FloatProxy<Float16>& value) {
const FloatProxy<Float16>& value)
{
os << HexFloat<FloatProxy<Float16>>(value);
return os;
}