0

I am relatively new to vulkan. I am having this weird issue, where say I write a very small floating point to an FBO, it gets rounded to 0. For example, say I write outFrag = vec4(1.0e-39,0,0,1); this gets stored as (0,0,0,1). I've found this issue when I run the code on an Nvidia GPU (1060), but it works fine on an Intel integrated GPU. (The image format I am using the for the FBO is VK_FORMAT_R32G32B32A32_SFLOAT).

On the other hand, if I write the same value to a float buffer, it gets written correctly! I am not sure if there is any specific property I need to set to fix this.

(For context, I need to write integers into the the float FBO, and I cannot use an int FBO since I need Blend enabled. So I am trying to use intBitsToFloat() which results in very small float values depending on the integer.)

EDIT: The alternative is to use Logic operations on a integer frame buffer with VK_LOGIC_OP_COPY. However, when I tried this, I get no output at all. (actually simply enabling blend with the integer FBO gives a validation error, but I get the required output -- this might simply be the drivers not being strict, but I would ideally not want to use something which might break my code in the future).

Any help is much appreciated.

  • 2
    "*I cannot use an int FBO since I need Blend enabled*" How do you expect floating-point blending on integer values to produce a meaningful result? – Nicol Bolas Aug 26 '22 at 13:19
  • *I am trying to use intBitsToFloat() which results in very small float values depending on the integer.* I find it very unlikely you want a bitcast instead of a conversion cast. I'm also guessing that these values are ending up in the denormal range, which your GPU won't preserve. – vandench Aug 26 '22 at 21:07
  • @NicolBolas Well, In my case all I simply set the blend operation to overwrite the existing value with the new value... so, I am not actually doing any alpha blending per se. The alternative was to use logic operations (VkLogicOp) on an int frame buffer with COPY as the operation. but that does not seem to work at all. Which is why I went to using float and using conversion from int bits to float. – Harish Doraiswamy Aug 27 '22 at 11:24
  • @vandench using regular casting has other problems with precision when integer values are large. I am at a loss at what the work around would be. VkLogicalOp would be the ideal way to do this. But, when I enable it in the device features, and set the operation to VK_LOGIC_OP_COPY, I get no validation errors, but nothing is being written to the framebuffer either :( – Harish Doraiswamy Aug 27 '22 at 11:47
  • "*In my case all I simply set the blend operation to overwrite the existing value with the new value...*" Why use a blend operation at all? Just don't enable blending for that buffer and use integers. – Nicol Bolas Aug 27 '22 at 13:19
  • @NicolBolas Not enabling blend does not update the framebuffer at all. It simply remains with the cleared value. – Harish Doraiswamy Aug 27 '22 at 14:51

1 Answers1

0

1.0e-39 is small enough that it belongs to a special category of floating-point values: "subnormal" or "denormal" values. If you look at https://float.exposed/0x000ae398 you can see that its "exponent" is 0, which is what makes it subnormal. Vulkan implementations are allowed to treat these numbers as if they were zero, and it's particularly likely that they will do so for blending for the sake of performance.

You might have some luck with using floatBitsToInt() to bitcast the value to an integer, and then writing it out to an integer framebuffer.

With that said, there's no guarantee that an implementation will let you create denormal float values at all. There is a "float controls" extension that lets this be controlled, but I'm not sure if it's possible to use that from GLSL.

Andrea
  • 19,134
  • 4
  • 43
  • 65