GLSL implicit int to float error yielded at "float to float"…? - casting

The following line in my fragment-shader…
gl_FragColor.r = curPosition.x;
raises warning C7011: implicit cast from "int" to "float" but curPosition is defined as vec3 (so it is a float) and gl_FragColor.r is … well … a float. so… what's the problem?

Related

Clang-Tidy Narrowing Conversion from uint8_t to float

I'm getting a clang-tidy warning that reads narrowing conversion from 'int' to 'float' when I convert from a uint8_t to a float, which to my understanding is not a narrowing conversion since float can represent every integer that a uint8_t can.
Code example:
uint8_t testVar = 8;
float test2 = 2.0f * testVar;
clang-tidy flags the second line of that with the warning cppcoreguidelines-narrowing-conversions: narrowing conversion from 'int' to 'float'. In my IDE, the squiggle shows up under the testVar.
According to the reference, this warning should be flagged if we convert from an integer to a narrower floating-point (e.g. uint64_t to float), but to the best of my knowledge, float is not narrower than uint8_t.
Am I fundamentally misunderstanding these data types, or is something else going on here?
I'm on LLVM version 11.0.0 if that matters.

conversion from 'double' to 'float' requires a narrowing conversion

I have the following lines of code:
std::vector<float> qualities = { 0.5, 0.6, 0.7, 0.8 };
std::vector<float> percentages = { 0.15, 0.16, 0.17, 0.18 };
I get the error mentioned in the title for each element.
Why is that?
You get the message because a constant of the form (e.g.) 0.5 is a double, and assigning a double to a float is a narrowing conversion.
To fix this, append f to each of your constants, e.g. 0.5f.
conversion from 'double' to 'float' requires a narrowing conversion
I get the error mentioned in the title for each element. Why is that?
Because you are constructing a vector of floats using double literals. Such conversion is narrowing.
That said, such conversions are allowed in this context and the example is well-formed and should compile. I suspect that you've used some compiler options to ask the compiler to not compile some well-formed programs.
You can write a float literal by appending f to a double literal.

Data type float

While declaring a variable of type float, is it necessary to write f towards the end of the value? For example, float amount = .01 and float amount = 0.01f, here what does the f mean and how does it make any difference?Also, what is the role of #include library file here.
It's not necessary: the compiler will make an appropriate numerical conversion for you.
0.01f is a literal of float type, whereas 0.01 is a double type.
Occasionally you need to descriminate explicitly especially when working with templates or overloaded functions:
void foo(const float&){
// Pay me a bonus
}
void foo(const double&){
// Reformat my disk
}
int main(){
foo(1.f);
}
Finally, if you're leading towards using a float over a double, then do read through this: Is using double faster than float?
It depends on how you define your variable. When specifying the type float in the definition, adding a trailing f is not necessary:
float amount = 0.1; /* This is fine, compiler knows the type of amount. */
Adding a superfluous literal here (float amount = 0.1f;) might even be considered bad practice, as you repeat the type information, resulting in more edits when the type is changed.
In the context of type deduction though, you have to give the f literal:
auto amount = 0.1f; /* Without the literal, compiler deduces double. */
There are more subtle contexts in which type deduction occurs, e.g.
std::vector<float> vecOfFloats;
/* ... */
std::accumulate(vecOfFloats.cbegin(), vecOfFloats.cend(), 0.1f);
Here, the third argument is used to deduce the type on which std::accumulate operates. If you just call it like std::accumulate(..., 0.1);, a double to float conversion takes place for every element in vecOfFloats.
.01 is a double literal. There is an implicit conversion to float in the initialisation
float amount = .01;
.01f is a float literal. There is no conversion in the initialisation
float amount = .01f;
That depends...
You can do for example:
1)
float f = 3.14f;
In this case the literal 3.14 is explicitly given as a float... so everything is ok
2)
float f = 3.14;
In this case 3.14 is actually a double, but the variable f is declared as a float...so when compiling, the number will be casted to a float with the loss precision consequences of that case...
You could since c++11
auto f = 3.14;
Or auto f{3,14};
In both cases the compiler takes exactly the type of the literal...(both are doubles)

GLSL(330) modulo returns unexpected value

I am currently working with GLSL 330 and came across some odd behavior of the mod() function.
Im working under windows 8 with a Radeon HD 6470M. I can not recreate this behavior on my desktop PC which uses windows 7 and a GeForce GTX 260.
Here is my test code:
float testvalf = -126;
vec2 testval = vec2(-126, -126);
float modtest1 = mod(testvalf, 63.0); //returns 63
float modtest2 = mod(testval.x, 63.0); //returns 63
float modtest3 = mod(-126, 63.0); //returns 0
Edit:
Here are some more test results done after IceCools suggestion below.
int y = 63;
int inttestval = -126;
ivec2 intvectest(-126, -126);
float floattestval = -125.9;
float modtest4 = mod(inttestval, 63); //returns 63
float modtest5 = mod(intvectest, 63); //returns vec2(63.0, 63.0)
float modtest6 = mod(intvectest.x, 63); //returns 63
float modtest7 = mod(floor(floattestval), 63); //returns 63
float modtest8 = mod(inttestval, y); //returns 63
float modtest9 = mod(-126, y); //returns 63
I updated my drivers and tested again, same results. Once again not reproducable on the desktop.
According to the GLSL docs on mod the possible parameter combinations are (GenType, float) and (GenType, GenType) (no double, since we're < 4.0). Also the return type is forced to float but that shouldn't matter for this problem.
I don't know that if you did it on intention but -126 is an int not a float, and the code might not be doing what you expect.
By the way about the modulo:
Notice that 2 different functions are called:
The first two line:
float mod(float, float);
The last line:
int mod(int, float);
If I'm right mod is calculated like:
genType mod(genType x, float y){
return x - y*floor(x/y);
}
Now note, that if x/y evaluates -2.0 it will return 0, but if it evaluates as -2.00000001 then 63.0 will be returned. That difference is not impossible between int/float and float/float division.
So the reason is might be just the fact that you are using ints and floats mixed.
I think I have found the answer.
One thing I've been wrong about is that mangsl's keyword for genType doesn't mean a generic type, like in a c++ template.
GenType is shorthand for float, vec2, vec3, and vec4 (see link - ctrl+f genType).
Btw genType naming is like:
genType - floats
genDType - doubles
genIType - ints
genBType - bools
Which means that genType mod(genType, float) implies that there is no function like int mod(int, float).
All the code above have been calling float mod(float, float) (thankfully there is implicit typecast for function parameters, so mod(int, int) works too, but actually mod(float, float) is called).
Just as a proof:
int x = mod(-126, 63);
Doesn't compile: error C7011: implicit cast from "float" to "int"
It only doesn't work because it returns float, so it works like this:
float x = mod(-126, 63);
Therefore float mod(float, float) is called.
So we are back at the original problem:
float division is inaccurate
int to float cast is inaccurate
It shouldn't be a problem on most GPU, as floats are considered equal if the difference between them is less than 10^-5 (it may vary with hardware, but this is the case for my GPU). So floor(-2.0000001) is -2. Highp floats are far more accurate than this.
Therefore either you are not using highp floats (precision highp float; should fix it then) or your GPU has stricter limit for float equality, or some of the functions are returning less accurate value.
If all else fails try:
#extension BlackMagic : enable
Maybe some driver setting is forcing default float precision to be mediump.
If this happens, all your defined variables will be mediump, however, numbers typed in the code will still remain highp.
Consider this code:
precision mediump float;
float x = 0.4121551, y = 0.4121552;
x == y; // true
0.4121551 == 0.4121552; // false, as highp they still differ.
So that mod(-126,63.0) could be still precise enough to return the correct value, as its working with high precision floats, however if you give a variable (like at all the other cases), which will only be mediump, the function won't have enough precision to calculate the correct value, and as you look at your tests, this is what's happening:
All the functions that take at least one variable are not precise enough
The only function call that takes 2 typed numbers return the correct value.

Fragment shader for unsigned integer textures

I am using following shader for unsigned integer textures to read a data:
Fragment shader:
Code :
#version 150
out uvec4 fragColor;
uniform uint factor;
void main()
{
uint temp=factor;
temp=temp/2;
fragColor = uvec4(temp,temp,temp,temp);
}
But i am getting error on driver A:
"Compile failed.
ERROR: 0:7: '/' : Wrong operand types. No operation '/' exists that takes a left-hand operand of type 'uint' and a right operand of type 'const int' (and there is no acceptable conversion)
ERROR: 1 compilation errors. No code generated."
on driver B it runs perfectly. Is driver A is buggy or my shader is wrong? if wrong, how can i achieve the same result?
Try this:
temp = temp / uint(2);
GLSL does not allow implicit conversions between signed and unsigned ints, so both operands of a binary operand must be the same. Use:
temp = temp / 2u;
to use an unsigned int constant.