-
| SummaryQuerying location of uniforms returns  Steps to reproduce
 
 CommentsAll my extension methods for my shader first query location with  I tried to pack those uniforms into  So I made method that doesn't query location and I set  | 
Beta Was this translation helpful? Give feedback.
Replies: 10 comments
-
| So as example, my extension methods for setting uniforms are as follows: public enum OGLShaderUniformRequirementPolicy
{
  /// <summary>
  /// Uniform is always required. Error out if missing.
  /// </summary>
  REQUIRED,
  /// <summary>
  /// Uniform can be skipped if missing. Don't error out.
  /// </summary>
  OPTIONAL
}
    
public static (int Ok, ExecutionErrorReport Err) GetUniformLocation(this OGLShader me, string uniform_name, OGLShaderUniformRequirementPolicy requirement_policy)
{
    try
    {
       // Context is just a property to GL variable stored in OGLShader.
        var location = me.Context.GetUniformLocation(me.ID, uniform_name);
        var errCode = me.Context.GetError();
        if (errCode != GLEnum.NoError)
            return (location, new() { ErrorMessage = $"*** GetUniformLocation() failed with error: {errCode}", ErrorType = ExecutionErrorType.Exit });
        
        if (requirement_policy == OGLShaderUniformRequirementPolicy.OPTIONAL) return (location, new());
        else
        {
            return location.Equals((int)GLEnum.InvalidIndex)
                ? (location, new() { ErrorMessage = $"*** {uniform_name} uniform not found on shader {me.ID}", ErrorType = ExecutionErrorType.Exit })
                : (location, new());
        }
    }
    catch (Exception e)
    { return ((int)GLEnum.InvalidIndex, new() { ErrorMessage = e.Message, ErrorType = ExecutionErrorType.Exception }); }
}
public unsafe static ExecutionErrorReport SetUniform(this OGLShader me, string uniform_name, float value)
{
    try
    {
        var (location, err) = me.GetUniformLocation(uniform_name, OGLShaderUniformRequirementPolicy.REQUIRED);
        if (err.ErrorType != ExecutionErrorType.None) return err;
        me.Context.Uniform1(location, value);
        var errCode = me.Context.GetError();
        return errCode != GLEnum.NoError
            ? new() { ErrorMessage = $"*** Uniform1() failed with error: {errCode}", ErrorType = ExecutionErrorType.Exit }
            : new();
    }
    catch (Exception e)
    { return new() { ErrorMessage = e.Message, ErrorType = ExecutionErrorType.Exception }; }
}
public unsafe static ExecutionErrorReport SetNearPlane(this OGLShader me, float value)
    => me.SetUniform(OGLShaderUniformNames.NEAR_PLANE, value);
public unsafe static ExecutionErrorReport SetFarPlane(this OGLShader me, float value)
    => me.SetUniform(OGLShaderUniformNames.FAR_PLANE, value);
public unsafe static ExecutionErrorReport SetClippingPlanes(this OGLShader me, float near, float far)
{
    var err = me.SetNearPlane(near);
    if (err.ErrorType != ExecutionErrorType.None) return err;
    return me.SetFarPlane(far);
}For now all methods use OGLShaderUniformRequirementPolicy::REQUIRED, so they error out if location is  And this fails only for those two uniforms,  public unsafe static ExecutionErrorReport SetUniform(this OGLShader me, int uniform_location, float value)
{
    try
    {
        me.Context.Uniform1(uniform_location, value);
        var errCode = me.Context.GetError();
        return errCode != GLEnum.NoError
            ? new() { ErrorMessage = $"*** Uniform1() failed with error: {errCode}", ErrorType = ExecutionErrorType.Exit }
            : new();
    }
    catch (Exception e)
    { return new() { ErrorMessage = e.Message, ErrorType = ExecutionErrorType.Exception }; }
}will work and uniforms are changing in shader. | 
Beta Was this translation helpful? Give feedback.
-
| The pipeline layout of OGL should be fixed in the code rather than obtained through querying. This approach is also in line with the modern programming style of graphic libraries. | 
Beta Was this translation helpful? Give feedback.
-
| I'm building engine at this point, so not many standarized things there yet. Just adding viewport gizmos. So what, GetUniformLocation() is deprecated in Core and it can return wrong value? | 
Beta Was this translation helpful? Give feedback.
-
| 
 I have encountered similar issues with shaders compiled using OGL 4.6 + SPV on Intel and AMD GPUs, where querying would indeed return -1. | 
Beta Was this translation helpful? Give feedback.
-
| Have you tried to check the output of something like this: gl.GetProgram(program, GLEnum.ActiveUniforms, out var activeUniforms);
for (var i = 0; i < activeUniforms; i++)
{
    var name = GetActiveUniform(program, (uint)i, out var size, out var type);
    Console.WriteLine($"Uniform {i} - Name: {name} - Size: {size} - Type: {type}");
} | 
Beta Was this translation helpful? Give feedback.
-
| On Intel iGPU prints: If I force RTX 3050, it prints:  | 
Beta Was this translation helpful? Give feedback.
-
| Interesting... Perhaps try adjusting the previous code:     Console.WriteLine($"Uniform {i} - Name: {name} - Size: {size} - Type: {type} - Location: {gl.GetUniformLocation(program, name)}");To see whether there's a noticeable gap in the location indices. Also make sure you're checking the compile/link status, and retrieving the info logs in any case. There may be more info therein. Note you can also use  | 
Beta Was this translation helpful? Give feedback.
-
| Intel iGPU: RTX 3050: As for the  | 
Beta Was this translation helpful? Give feedback.
-
| Ah yeah my bad, forgot about that. It seems like 3 and 4 are being kept free. Have you tried with other names just in case it's a weird driver quirk? Assuming that there was no extra info in the link/compile logs, I also recommend using RenderDoc to see if you can see what RenderDoc recognises the shader as. Failing all of that, I recommend reporting this to NVIDIA and finding a workaround e.g. using a uniform block or SSBO instead. There is ample evidence here that this is not a Silk.NET issue. | 
Beta Was this translation helpful? Give feedback.
-
| I found the problem. It seems that NVidia is optimizing out so hard, that even despite that this function: vec2
ComputeDepth(vec3 position, float near_plane, float far_plane, mat4 view, mat4 projection) 
{
    // Raw depth value of the fragment position in clip space.
    vec4 clipSpacePosition = projection * view * vec4(position.xyz, 1.0);
    float depth = (clipSpacePosition.z / clipSpacePosition.w);
    // Linear depth of the fragment position in view space.
    float shiftedDepth = depth * 2.0 - 1.0; // Put back between -1 and 1.
    float linearDepth = (2.0 * near_plane * far_plane) / (far_plane + near_plane - shiftedDepth * (far_plane - near_plane)); // Get linear value between 0.01 and 100.
    linearDepth = linearDepth / far_plane; // Normalize.
                    
    return vec2(depth, linearDepth); 
}is using      // Linear depth of the fragment position in view space.
   float shiftedDepth = depth * 2.0 - 1.0; // Put back between -1 and 1.
   float linearDepth = (2.0 * near_plane * far_plane) / (far_plane + near_plane - shiftedDepth * (far_plane - near_plane)); // Get linear value between 0.01 and 100.
   linearDepth = linearDepth / far_plane; // Normalize.doesn't exists on NVidia. And this is the only part that is using those uniforms. The moment I use  | 
Beta Was this translation helpful? Give feedback.
I found the problem. It seems that NVidia is optimizing out so hard, that even despite that this function: