-
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: