Hello,
I think i may have found a problem in Nvidia’s GLSL shader compiler on Windows.
In this GLSL snippet:
int val_i;
...
val_i = floatBitsToInt( -( intBitsToFloat( val_i ) ) );
the result of val_i contains the integer representation of the negated integer representation of the source argument instead of the expected negated float representation. It seems the compiler thinks the bit representation macros can be cancelled out without considering the negative modifier, ie that the following is occurring:
val_i = -( val_i );
The fix for this problem is to simply introduce a temporary:
float val_f = -( intBitsToFloat( val_i ) );
val_i = floatBitsToInt( val_f );
which then results in val_i containing the expected integer value of the negated float representation.
I’ve confirmed the behaviour with Nsight’s OGL shader debugging.
I’m not sure of this problem’s scope but it seems to occur when using the bit representation functions, scalar floats, (including from uniforms), and source argument modifiers, though of course the scope could be much wider. The problem doesn’t appear to occur on OSX, at least on:
OSX 10.9.5
NVIDIA GeForce GTX 780M OpenGL Engine
4.1 NVIDIA-8.26.28 310.40.55b01
I’ve added a repro case to the bottom of this post that shows the problem, (requires GLFW & GLEW), where the define FIX_OGL_COMPILER_PROBLEM can be used to control the problem.
System tested on:
Win7 Pro 64-bit (SP1), GeForce GTX 770, 344.65
GL_RENDERER: “GeForce GTX 770/PCIe/SSE2”
GL_VERSION: “4.4.0 NVIDIA 344.65”
Can anyone else reproduce this problem?
Thanks,
Andy Slater
Repro case:
nvidia_opengl_compiler_problem.c
//! uncomment to fix the OGL compiler problme
//#define FIX_OGL_COMPILER_PROBLEM
#if !( defined( __APPLE__ ) || defined( __linux__ ) )
#include <windows.h>
#endif
#if !defined( __APPLE__ )
#include <GL/glew.h>
#endif
#if( defined( __APPLE__ ) || defined( __linux__ ) )
#define GLFW_INCLUDE_GLCOREARB
#endif
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
#if( defined( __APPLE__ ) || defined( __linux__ ) )
#define outputf printf
#else
void outputf( const char *format, ... )
{
char charbuf[ 2048 ];
va_list argp;
va_start( argp, format );
vsprintf( charbuf, format, argp );
va_end( argp );
OutputDebugString( charbuf );
}
#endif
void flushGlErrors( const int showGlErrors )
{
GLenum err;
while(( err = glGetError() ) != GL_NO_ERROR )
{
if( showGlErrors )
{
outputf( "GL_ERROR = 0x%08x\n", err );
}
}
}
int main(void)
{
GLFWwindow* window;
float points[] = {
0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
};
GLuint vbo = 0;
GLuint vao = 0;
const char* vertex_shader =
"#version 150\n"
"in vec3 vp;\n"
"void main() {\n"
" gl_Position = vec4(vp, 1.0);\n"
"}\n";
const char* fragment_shader =
"#version 150\n"
"#extension GL_ARB_shader_bit_encoding : enable\n"
"out vec4 frag_colour;\n"
"void main() {\n"
" float val_f;\n"
" int val_i;\n"
" val_f = ( gl_FragCoord.x / 640.0 ) * -1.0f;\n"
" val_i = floatBitsToInt( val_f );\n"
#if !defined( FIX_OGL_COMPILER_PROBLEM )
" val_i = floatBitsToInt( ( intBitsToFloat( val_i ) ) * -1.0 );\n"
#else
" val_f = -( intBitsToFloat( val_i ) );\n"
" val_i = floatBitsToInt( val_f );\n"
#endif
" frag_colour = vec4( intBitsToFloat( val_i ), 0.0, 0.0, 1.0 );\n"
"}";
GLuint vs;
GLuint fs;
GLuint shader_programme;
if( !glfwInit() )
{
return -1;
}
#if defined( __APPLE__ ) && defined( GLFW_INCLUDE_GLCOREARB )
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if( !window )
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent( window );
#if !defined( __APPLE__ )
glewInit();
#endif
outputf( "Renderer: %s\n", glGetString( GL_RENDERER ) );
outputf( "OpenGL version supported %s\n", glGetString( GL_VERSION ) );
flushGlErrors( 0 );
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), points, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
// vertex shader
vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vertex_shader, NULL);
glCompileShader(vs);
{
GLint result = 0;
glGetShaderiv( vs, GL_COMPILE_STATUS, &result );
if( result != GL_TRUE )
{
outputf( "vertex shader compile failed\n" );
}
}
// fragment shader
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fragment_shader, NULL);
glCompileShader(fs);
{
GLint result = 0;
glGetShaderiv( fs, GL_COMPILE_STATUS, &result );
if( result != GL_TRUE )
{
outputf( "fragment shader compile failed\n" );
}
}
shader_programme = glCreateProgram();
glAttachShader(shader_programme, fs);
glAttachShader(shader_programme, vs);
glLinkProgram(shader_programme);
flushGlErrors( 1 );
glClearColor(0.0f, 0.0f, 0.5f, 0);
while( !glfwWindowShouldClose( window ) )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUseProgram(shader_programme);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}