Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

error message using floatToIntBits

Discussion in 'Shaders' started by iko79, May 16, 2014.

  1. iko79

    iko79

    Joined:
    Jan 21, 2013
    Posts:
    45
    Hi,

    I don't get it. Why does the following shaderlab code not work?

    Code (csharp):
    1. Shader "Custom/testShader" {
    2. //http://docs.unity3d.com/Documentation/Components/SL-Properties.html
    3.     Properties {
    4.     }
    5.    
    6.     CGINCLUDE
    7. // Upgrade NOTE: excluded shader from DX11 and Xbox360; has structs without semantics (struct v2f members color)
    8. #pragma exclude_renderers xbox360 ps3 gles flash
    9. //http://docs.unity3d.com/Documentation/Components/SL-ShaderPrograms.html#target
    10. #pragma target 3.0
    11.  
    12.     #include "UnityCG.cginc"
    13.  
    14.     float   _input;
    15.  
    16.     uniform sampler2D _MainTex;
    17.  
    18.     struct v2f {
    19.         float4 vertPos : POSITION;
    20.         float2 uv : TEXCOORD0;
    21.     };
    22.  
    23.     struct PixelOutput
    24.     {
    25.         int4 col : COLOR0;
    26.     };
    27.  
    28.     v2f vert( appdata_base v ) {
    29.  
    30.         v2f o;
    31.  
    32.         o.vertPos = mul( UNITY_MATRIX_MVP, v.vertex );
    33.         o.uv = MultiplyUV( UNITY_MATRIX_TEXTURE0, v.texcoord );
    34.  
    35.         return o;
    36.     }
    37.    
    38.     PixelOutput frag(v2f i) : COLOR {
    39.  
    40.         PixelOutput o;
    41.  
    42.         int inputI = floatToIntBits( _input );
    43.         o.col = int4(
    44.             ( inputI  0xff000000 ) >> 24,
    45.             ( inputI  0x00ff0000 ) >> 16,
    46.             ( inputI  0x0000ff00 ) >> 8,
    47.             ( inputI  0x000000ff ) );
    48.  
    49.         return o;
    50.     }
    51.  
    52.     ENDCG
    53.    
    54. Subshader {
    55.  Pass {
    56.  //http://docs.unity3d.ru/Components/SL-Pass.html
    57.       ZTest LEqual
    58.       Cull Back
    59.       ZWrite On
    60.       Blend SrcAlpha OneMinusSrcAlpha
    61.       Fog { Mode off }
    62.  
    63.       CGPROGRAM
    64.       #pragma fragmentoption ARB_precision_hint_fastest
    65.       #pragma vertex vert
    66.       #pragma fragment frag
    67.       ENDCG
    68.   }
    69. }
    70.  
    71. Fallback off   
    72. }
    What I get reported in Unity is the following:

    Shader warning in 'Custom/testShader': Program 'frag', implicit cast from "float4" to "float2" at line 32
    Shader error in 'Custom/testShader': Program 'frag', unable to find compatible overloaded function "floatToIntBits(float)" at line 41

    When I remove floatToIntBits there is no error. I cannot see where I'm trying to implicitly cast from float4 to float2 here. Can anybody help me?

    Cheers,
    iko
     
    Last edited: May 21, 2014
  2. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    Are you in DX11 mode? I don't think SM3 supports bitwise operators, such as the bitwise AND.
     
  3. iko79

    iko79

    Joined:
    Jan 21, 2013
    Posts:
    45
    You mean the checkbox "Use Direct3D 11" in the player settings? It was not checked, but it doesn't make a big difference when I check it... I'm now using
    Code (csharp):
    1. #pragma only_renderers d3d11
    instead of exclude_renderers and
    Code (csharp):
    1. #pragma target 4.0
    I'm still getting the following warning (along with a shader that's not working, thus resulting in a magenta frame):

    Shader warning in 'Custom/testShader': Program 'vert', undeclared identifier 'floatToIntBits' (compiling for d3d11) at line 38

    Do I have to add an additional include file? Note that it says "Program 'vert'" now, which is completely weird.
     
  4. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    In the current version of Unity, error reporting is a bit odd.

    It looks like only Cg has floatToIntBits, and DX10/11 code is compiled using the HLSL compiler. You could try using casting the value directly.
     
  5. iko79

    iko79

    Joined:
    Jan 21, 2013
    Posts:
    45
    Thanks for your help, RC-1290. I'm really confused about Shaderlab syntax and available functions. I always thought everything between CGINCLUDE and ENDCG would be Cg.

    Well, casting is not what I'm trying to do. I have to preserve the IEEE 754 binary value of the float so I can use it in C# later on.

    Any idea how I could use the Cg compiler instead?

    Edit:
    Oh, and by the way, in my initial post I forgot about shifting the masked values since I was only worried about the floatToIntBits function. The code wouldn't work like this of course -- I corrected this.
     
    Last edited: May 21, 2014
  6. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    Shaderlab is essentially Unitys' syntax that needs to be parsed/compiled to actual CG code, everything between the CGINCLUDE/PROGRAM and ENDCG is likely shader code they can "simple copy paste".

    The basic case is that Unity compiles with the CG Compiler, but as RC-1290's link provided, there are some exceptions for DX11 (and xbox360) that compile with the HLSL compiler.

    I guess the same is done for GLSL when you explicitly state it needs to compile for GLSL.
     
  7. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    Actually, I misread the requirements for floatToIntBits. You need quite specific Nvidia hardware. And I don't think you can easily compile for that profile specifically from Unity.

    I don't think I understand what you're trying to do. If you're trying to read the data back to C# later on, you're going to lose a lot of data anyway, because the only standard way of getting data back from the GPU is to read ARGB32 texture data, which would only be 8 bits per channel. And bit shifting isn't supported in standard Cg.

    Perhaps you would be better off writing a Compute Shader instead. They give you more direct controls over input and output, and they allow you to use bitwise operators.
     
  8. iko79

    iko79

    Joined:
    Jan 21, 2013
    Posts:
    45
    Thank you guys. First I didn't realize RC-1290 was posting links, thanks Rld_

    Since it seems like d3d9 isn't enough and d3d11 uses hlsl it seems to me that Cg will not work anyway, so now I tried the according HLSL function asint(). Now it compiles, nonetheless I'm still struggling getting what I want (see below) since it still does not work for whatever reason.

    @shift operators: Well, at least it compiles without error or warning. But wth -- whether or not I have to adhere to Cg syntax and what Unity does with my shader code is a bit of a mystery anyways.

    @what I'm trying to do: I somehow have to get float values from frame buffer to C#. Since reading from a RenderTarget only seems to be possible via Texture2D.ReadPixels and there are no floating point formats for Texture2Ds, I had the idea of trying this (actually pretty simple) workaround of using four 32bit ARGB render buffers, each of which holding a float value in form of four (meaningless) color channels. So, I want to store the float's IEEE 754 binary value (32bits) in the ARGB render target (32bits, 8bit per channel) so when I read it in C# code (from a 32bit texture), and interprete it as (note: not "cast it to") a float value I should end up with the float value I initially had in the shader. Should be straight forward, but turns out it isn't. For some more context, the even bigger picture of this is: I have to read HDR rendered color buffers to RAM and Unity wouldn't let me. This is where I ended up.

    Cheers,
    iko
     
  9. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    There is actually a recent blog post about how Unity compiles your shaders, and how it will change in an upcoming version of Unity.
    If you're in DX11 mode, on a machine that supports it, the shader code between the CG tags (CGINCLUDE or CGPROGRAM and ENDCG) will be compiled by the HLSL compiler, and you have to follow its rules. In many cases it's identical to Cg though.

    In most other cases, it'll use the Cg compiler. The things it supports depends on the profiles it's trying to compile for. As far as I know, you can't specify the profiles that should be compiled for directly, but you can influence it with things like
    #pragma target
    #pragma only_renderers
    #pragma exclude_renderers
    #pragma glsl



    This is what ComputeBuffers are useful for, when using Compute Shaders. You can pretty much get and set arrays of float values.

    Keep in mind that with most graphics cards data has to travel a relatively long distance if it moves between the video memory, and system memory, so it can take a while to complete (precious milliseconds, it might wait until it doesn't have to do anything else).
     
  10. iko79

    iko79

    Joined:
    Jan 21, 2013
    Posts:
    45
    Thanks, RC-1290.

    I'm fiddling aroud with compute shaders a bit. I can find very little documentation and examples though, so I'm already stuck again. For starters I'm just trying to write to a buffer and reading it back to RAM again. Any ideas what's wrong with this code?

    Shader code:
    Code (CSharp):
    1. #pragma kernel CSMain
    2.  
    3. RWStructuredBuffer<float4>    result;
    4.  
    5. [numthreads(32,32,1)]
    6. void CSMain (uint3 id : SV_DispatchThreadID)
    7. {
    8.     result[id.xy] = float4(0, 0.25, 0.5, 1);
    9. }
    C# code:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. using System;
    4. using System.Collections;
    5.  
    6. public class framegrabber : MonoBehaviour
    7. {
    8. public ComputeShader computeShader = null;
    9.  
    10. ComputeBuffer computeBuffer = null;
    11. float[] data = null;
    12.  
    13. int csId = 0;
    14.  
    15. void Start()
    16. {
    17. if( !SystemInfo.supportsComputeShaders )
    18. Debug.LogError( "compute shaders not supported" );
    19.  
    20. this.csId = this.computeShader.FindKernel( "CSMain" );
    21.  
    22. this.data = new float[1024 * 1024 * 4];
    23. this.computeBuffer = new ComputeBuffer( this.data.Length / 4, 4 * sizeof( float ) );
    24. this.computeBuffer.SetData( this.data );
    25. this.computeShader.SetBuffer( this.csId, "result", this.computeBuffer );
    26. }
    27.  
    28. void OnRenderImage(RenderTexture src, RenderTexture dst)
    29. {
    30. Graphics.Blit( src, dst );
    31.  
    32. this.computeShader.Dispatch( this.csId, 32, 32, 1 );
    33. this.computeBuffer.GetData( this.data );
    34.  
    35. Debug.Log( "col[0,0] = " + data[0] + " / " + data[1] + " / " + data[2] + " / " + data[3] );
    36. Debug.Log( "col[1,0] = " + data[4] + " / " + data[5] + " / " + data[6] + " / " + data[7] );
    37. }
    38. }
    It causes my display driver to crash, most of the time. When it doesn't, it prints "col[0,0] = 0 / 0 / 0 / 0" and "col[1,0] = 0 / 0 / 0 / 0" instead of the value I would actually write in the shader.

    Thanks!
     
  11. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    Does it also crash when you dispatch the compute shader once? Perhaps you call it in response to a button instead of "OnRenderImage"(and not right after Graphics.Blit)?

    Also, in all cases where I've supplied data to a float4 buffer, I've used an array of Vector4, not an array of 4 times as many floats. While I don't know why it wouldn't accept an array of 4 times as many floats, I also haven't tested it yet (I just remember ComputeBuffers being a bit picky when it comes to the structs they will write to successfully).
     
  12. iko79

    iko79

    Joined:
    Jan 21, 2013
    Posts:
    45
    Thanks for your reply.

    It also crashes if I dispatch once, and also it doesn't matter where I do it (Update, OnRenderImage, OnPostRender). I also tried changing data types to Vector4, no success. The funny thing is, when I add the definitions of these two symbols to my shader, the driver doesn't crash, although they're not accessed or referenced in any way:

    Code (CSharp):
    1. Texture2D<float4>    texture;
    2. SamplerState        samplerTexture;
    Still, it won't work in the end, since I only get zeroes when I read back the data.
     
  13. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    Only getting back zeroes? Perhaps the stride and length aren't correct.
    When you use Vector4, don't forget that the array lenght is the same as the buffer length, in stead of the divided by 4 you're using there.
     
  14. iko79

    iko79

    Joined:
    Jan 21, 2013
    Posts:
    45
    Not sure, I assume the stride is meant to be specified in bytes, the documentation doesn't tell. The initialization code now is as follows:

    Code (CSharp):
    1.         this.data = new Vector4[1024 * 1024];
    2.         this.computeBuffer = new ComputeBuffer( this.data.Length, System.Runtime.InteropServices.Marshal.SizeOf( typeof( Vector4 ) ), ComputeBufferType.Default );
    3.         this.computeBuffer.SetData( this.data );
    4.         this.computeShader.SetBuffer( this.csId, "result", this.computeBuffer );
    and, as before, I read back like this:

    Code (CSharp):
    1.             this.computeBuffer.GetData( this.data );
    Anything looking suspicious?
     
  15. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    That is correct. I submitted that as a documentation bug about a year ago, but it hasn't been updated yet. it seems to be a standard term for people with a background in C or C++. For Vector4, I use a hardcoded 16.

    Hmmm... I guess you could try using a smaller buffer (and thus smaller dispatch size). I tend to see significant slowdowns when my texture sizes reach a magical threshold.

    The code is similar to the code I use. Except that I don't write to the buffer that I read from, and that I Release the buffer after reading from it.
     
  16. iko79

    iko79

    Joined:
    Jan 21, 2013
    Posts:
    45
    Thanks RC-1290,

    I recently made it work, seems like I'm not supposed to index using a 2D-value:

    Code (CSharp):
    1. #pragma kernel CSMain
    2.  
    3. #define threadsInBlockX    32
    4. #define threadsInBlockY    32
    5.  
    6. uint stride;
    7.  
    8. Texture2D<float4>   inTexture;
    9.  
    10. RWStructuredBuffer<float4>    result;
    11.  
    12. [numthreads(threadsInBlockX, threadsInBlockY, 1)]
    13. void CSMain( uint3 dtid : SV_DispatchThreadID )
    14. {
    15.     float4 val = inTexture[dtid.xy];
    16.  
    17.     result[dtid.x + dtid.y * stride] = val;
    18. }
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. using System;
    4. using System.Collections;
    5.  
    6. public class framegrabber : MonoBehaviour
    7. {
    8.     int textureWidth = 1440;
    9.     int textureHeight = 1440;
    10.  
    11.     public ComputeShader    computeShader    =    null;
    12.  
    13.     ComputeBuffer    computeBuffer = null;
    14.     Vector4[,]        data = null;
    15.  
    16.     int csId = 0;
    17.  
    18.     // Use this for initialization
    19.     void Start()
    20.     {
    21.         if( !SystemInfo.supportsComputeShaders )
    22.             Debug.LogError( "compute shaders not supported" );
    23.  
    24.         this.csId = this.computeShader.FindKernel( "CSMain" );
    25.  
    26.         this.data = new Vector4[this.textureWidth, this.textureHeight];
    27.  
    28.         this.computeBuffer = new ComputeBuffer( this.data.Length, System.Runtime.InteropServices.Marshal.SizeOf( typeof( Vector4 ) ), ComputeBufferType.Default );
    29.         this.computeBuffer.SetData( this.data );
    30.  
    31.         this.computeShader.SetInt( "stride", this.textureWidth );
    32.         this.computeShader.SetBuffer( this.csId, "result", this.computeBuffer );
    33.     }
    34.  
    35.     void OnRenderImage( RenderTexture src, RenderTexture dst )
    36.     {
    37.         RenderTexture rtTemp = RenderTexture.GetTemporary( this.textureWidth, this.textureHeight, 0, RenderTextureFormat.ARGBFloat );
    38.  
    39.         try
    40.         {
    41.             Graphics.Blit( src, rtTemp );
    42.             Graphics.Blit( rtTemp, dst );
    43.  
    44.             this.computeShader.SetTexture( this.csId, "inTexture", rtTemp );
    45.             this.computeShader.Dispatch( this.csId, this.textureWidth / 32, this.textureHeight / 32, 1 );
    46.         }
    47.         catch( Exception e )
    48.         {
    49.             Debug.Log( "caught exception " + e.Message );
    50.         }
    51.         finally
    52.         {
    53.             RenderTexture.ReleaseTemporary( rtTemp );
    54.         }
    55.  
    56.         this.computeBuffer.GetData( this.data );
    57.         Debug.Log( "col[1,1] = " + data[1,1] );
    58.     }
    59. }
    Seemed like I was writing outside of allocated memory.

    Still not sure how to use a two dimensional buffer, I'm still failing on that one.

    Boy, this was a tough one, given the actually incredible simple task. Some samples and better documentation surely wouldn't hurt. What's also misleading is the names of the arguments of ComputeShader.Dispatch: threadsX, threadsY, threadsZ -- it should actually be blocksX, blocksY and blocksZ, shouldn't it? I was a bit confused about what the point of specifying the threads dimension would be, when after all it is specified in the shader itself.
     
  17. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    For Surface Waves simulation calculations I'm using a 2D index without problems. But I only use it for texture data.

    For the experimental buoyancy in Surface waves, I work entirely with data in a single dimension, so I calculate a single index value, which works:
    Code (hlsl):
    1. int flatIndex = threadId.y * (numThreadsX * groupCountX) + threadId.x;// assuming the z direction is 1 for both groupsize and dispatch group count
    If you output using a vector, it should automatically calculate the index (and that definitely works with textures). But I think I started using a flat index to simplify setting the Compute Buffer data, not necessarily because of problems with the automatic indexing (or at least, I usually make notes about such problems, and I can't find any about any such issue).

    (Please note: I'm not saying this is best practice. Perhaps you could simply use a single dimension of threads and threadgroups, I don't know if using multiple dimensions is actually faster. Perhaps you could simply use the SV_DispatchThreadId to calculate the flat index. Etc. I wrote the code in rush to enter the DX11 competition.)

    The best documentation I could find about it a year ago was on MSDN, and even still I had to look at the image several times before I understood what was going on.

    But yeah, the numthreads attribute in the compute shader sets the size of a single threadgroup.
    Code (hlsl):
    1. [numthreads(32,32,1)]// 32 * 32 * 1 = 1024 threads per group
    Whereas the values passed to dispatch(see the MSDN documentation again, this time for dispatch), set the number of threadgroups that will be created.
    Code (csharp):
    1. simulationShader.Dispatch(kernelIndex, threadGroupsX, threadGroupsY, threadGroupsZ);
    So to get the total number of threads that will be created, you need to multiply those values together, similar to what I do for the flat index calculation above.