I was decompiling a game’s shaders using RenderDoc and stumbled upon something that has me scratching my head. There’s a segment of code that completely perplexes me, especially line 60. Here’s the relevant part:
“`
57: mul [precise(xyz)] r8.xyz, r5.yzxy, r6.zxyz
58: add [precise(xyz)] r7.xyz, r7.xyzx, -r8.xyzx
59: ishl [precise(x)] r0.x, r4.z, l(23)
60: iadd [precise(x)] r0.x, r0.x, l(-20769187434139310000000000000000000.000000)
61: mov [precise(xz)] r4.xz, r2.zzwz
62: and [precise(xyz)] r2.xyz, r4.xyzx, l(0x0000ffff, 0x0000ffff, 0x0000ffff, 0)
63: utof [precise(xyz)] r2.xyz, r2.xyzx
“`
Line 60 really throws me off because it’s using `iadd` (which is supposed to be for integers) alongside this massive float value, which obviously doesn’t fit as an integer. At first glance, I was convinced that this couldn’t be right. Digging a bit deeper, I checked the bytecode and found `f8800000`, which when interpreted as a float, does match the large number.
What confuses me the most is that lines 59 and 62 seem to handle non-float values correctly, so why on earth is line 60 reading this massive value as a float in the first place? Is there something I’m missing about how these values are being defined?
When I think about converting this to HLSL, I wonder if I need to apply something like `asint()` or `asuint()`, but even then, the number with the negative sign complicates things. I’ve tried various combinations, but the value stored in `r0.x` keeps showing up as something like `4.16914E+09`. It leaves me with heaps of questions—should I just be leaving it alone, or could the way it’s processed be causing unwanted NaNs and INFs in later calculations?
I’d love to hear your thoughts on this! Have you encountered anything similar in shader code? How did you approach it? Any insights or suggestions would be greatly appreciated!
Wow, that shader code segment is definitely a head-scratcher, especially line 60! It seems really strange to use
iadd
with such a massive float value.From my understanding,
iadd
is intended for integer addition, while the number you found, which fits as a float, implies some type of conversion is happening under the hood. It’s like the shader is taking a float representation of that large number but then treating it as an integer for the operation.Considering the value you found in the bytecode (
f8800000
), it would actually represent a very different number if interpreted as an integer. It’s likely that the large negative value is just a way to introduce a specific adjustment in your calculations without worrying about what type of data it originally was.For converting to HLSL, you might need to consider the
asint()
operation or maybe something likeasuint()
dependent on how that shader expects data. The sign is tricky because you’re working with a float and an integer in one go. If you end up with a float like4.16914E+09
, it’s hinting at something possibly going wrong. NaNs and INFs can definitely pop up with mismanaged types or unexpected value ranges.Maybe it’s worth leaving that line as-is unless you see it breaking something downstream. Debugging shader code feels like a dark tunnel sometimes, and sometimes those oddities are just how things are designed to work. If you figure it out, I’d love to hear how!
What you’re seeing in line 60 is most likely an artifact caused by incorrect interpretation of shader constants when decompiling shader bytecode. Shader assembly languages like the one RenderDoc displays sometimes represent constants in a misleading way, particularly if it misinterprets a floating-point bit pattern as a literal float. This typically occurs when a hexadecimal constant originally intended as an integer or bit-pattern constant is mistakenly decoded as a float. Indeed, the instruction
iadd
should strictly handle integers, which strongly suggests that the huge float value you see is actually a misrepresentation. This often happens because the underlying shader bytecode uses the same 32-bit storage for float and integer constants, and the decompiler chooses a floating representation incorrectly.To resolve this in your HLSL conversion, you most likely want to reinterpret the literal constant as a properly typed integer. Given your mention of a bytecode constant
f8800000
, it’s highly likely intended to be viewed through bitwise reinterpretation (asint()
orasuint()
) rather than a straight float value. Thus, converting it correctly would look something liker0.x = iadd(r0.x, asint(0xf8800000));
. Using bitwise reinterpretation ensures stability and correctness in later computations, preventing potential NaNs or INF values that could arise from inappropriate float-to-int mismatches. If examined closely, shaders often do precisely such bit-level manipulations, particularly for encoding data or special sentinel values, so explicitly reinterpreting the constant value as an integer is the safest approach here.