Okay here’s a minimal code.
The bug is present on my platform
/// /////////////////////////////////////////////////////////////
/// \author Jonathan DUPUY
/// \date 16.02.2011
/// \version 1.0
///
/// \sample Testing Uniform Array
/// /////////////////////////////////////////////////////////////
#define GL3_PROTOTYPES 1
#include <GL/gl3.h>
#define __gl_h_
#include <GL/freeglut.h>
#include <stdint.h>
#include <string>
#include <vector>
#include <cmath>
#include <cstring>
#include <unistd.h>
#include <sstream>
#include <algorithm>
#include <iomanip>
#include <iostream>
#ifdef _WIN32
#include <windows.h>
#include <winbase.h>
#else
#include <sys/time.h>
#endif
#define UTILS_BUFFER_OFFSET(i) ((char*)NULL+(i))
/////////////////////////////////////////////////////////////
// Variables
/////////////////////////////////////////////////////////////
namespace
{
// window attribs
namespace window
{
int32_t width = 800;
int32_t height = 500;
const int32_t gl_major = 3;
const int32_t gl_minor = 3;
const char* name = "Driver test";
}
// OpenGL variables
namespace gl
{
// buffer objects
namespace buffer
{
enum
{
VERTEX_QUAD,
UNIFORM_PARAMS,
MAX
};
}
// vertex array objects
namespace varray
{
enum
{
QUAD = 0,
MAX
};
}
// programs
namespace program
{
enum
{
SUM = 0,
MAX
};
}
GLuint buffers[buffer::MAX];
GLuint varrays[varray::MAX];
GLuint programs[program::MAX];
}
// scene params
namespace scene
{
}
// gerstner simulation variables
namespace color
{
namespace param
{
enum
{
FIRST = 0,
SECOND,
THIRD,
FOURTH,
MAX
};
}
typedef struct _ShaderParameters
{
float red; ///< width of the simulated plane
float green; ///< depth of the simulated plane
float blue; ///< wave vector x
float alpha; ///< wave vector y
char __reserved[16]; ///< round size to 32 bytes
} Params;
Params params[param::MAX];
}
}
/////////////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////////////
bool onInit();
void onShutdown();
void onRender();
void onResize(int32_t w, int32_t h);
void onKeyboard(uint8_t k, int32_t x, int32_t y);
void onSpecialKey(int32_t k, int32_t x, int32_t y);
void onMouseButton(int32_t button, int32_t state, int32_t x, int32_t y);
void onMouseMotion(int32_t x, int32_t y);
void onMousePassiveMotion(int32_t x, int32_t y);
void onIdle();
/////////////////////////////////////////////////////////////
// Main
/////////////////////////////////////////////////////////////
int main(int argc, char *argv[])
{
// create a GL context
glutInit(&argc, argv);
glutInitContextVersion(window::gl_major, window::gl_minor);
glutInitContextProfile(GLUT_COMPATIBILITY_PROFILE); // can't go to core profile here because of tw
// glutInitContextFlags (GLUT_FORWARD_COMPATIBLE | GLUT_DEBUG);
// configure glut
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(window::width , window::height);
glutInitWindowPosition(32, 32);
glutCreateWindow(window::name);
glutReshapeFunc(onResize);
glutDisplayFunc(onRender);
glutKeyboardFunc(onKeyboard);
glutSpecialFunc(onSpecialKey);
glutMouseFunc(onMouseButton);
glutMotionFunc(onMouseMotion);
glutPassiveMotionFunc(onMousePassiveMotion);
glutIdleFunc(onIdle);
glutCloseFunc(onShutdown);
// try running the app and clean if necessary
if(onInit())
glutMainLoop();
else
onShutdown();
return 0;
}
/////////////////////////////////////////////////////////////
// Helper functions
/////////////////////////////////////////////////////////////
// get time in seconds
double time()
{
#ifdef _WIN32
__int64 time;
__int64 cpuFrequency;
QueryPerformanceCounter((LARGE_INTEGER*) &time);
QueryPerformanceFrequency((LARGE_INTEGER*) &cpuFrequency);
return time / double(cpuFrequency);
#else
static double t0 = 0;
timeval tv;
gettimeofday(&tv, NULL);
if (!t0)
{
t0 = tv.tv_sec; // don't care about useconds here
}
return double(tv.tv_sec-t0) + double(tv.tv_usec) / 1e6;
#endif
}
void print_uniform_block_info(GLuint prog, GLint block_index, std::string const &indent = std::string())
{
// Fetch uniform block name:
GLint name_length;
glGetActiveUniformBlockiv(prog, block_index, GL_UNIFORM_BLOCK_NAME_LENGTH, &name_length);
std::string block_name(name_length, 0);
glGetActiveUniformBlockName(prog, block_index, name_length, NULL, &block_name[0]);
// Fetch info on each active uniform:
GLint active_uniforms = 0;
glGetActiveUniformBlockiv(prog, block_index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &active_uniforms);
std::vector<GLuint> uniform_indices(active_uniforms, 0);
glGetActiveUniformBlockiv(prog, block_index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, reinterpret_cast<GLint*>(&uniform_indices[0]));
std::vector<GLint> name_lengths(uniform_indices.size(), 0);
glGetActiveUniformsiv(prog, uniform_indices.size(), &uniform_indices[0], GL_UNIFORM_NAME_LENGTH, &name_lengths[0]);
std::vector<GLint> offsets(uniform_indices.size(), 0);
glGetActiveUniformsiv(prog, uniform_indices.size(), &uniform_indices[0], GL_UNIFORM_OFFSET, &offsets[0]);
std::vector<GLint> types(uniform_indices.size(), 0);
glGetActiveUniformsiv(prog, uniform_indices.size(), &uniform_indices[0], GL_UNIFORM_TYPE, &types[0]);
std::vector<GLint> sizes(uniform_indices.size(), 0);
glGetActiveUniformsiv(prog, uniform_indices.size(), &uniform_indices[0], GL_UNIFORM_SIZE, &sizes[0]);
std::vector<GLint> strides(uniform_indices.size(), 0);
glGetActiveUniformsiv(prog, uniform_indices.size(), &uniform_indices[0], GL_UNIFORM_ARRAY_STRIDE, &strides[0]);
// Build a string detailing each uniform in the block:
std::vector<std::string> uniform_details;
uniform_details.reserve(uniform_indices.size());
for(std::size_t i = 0; i < uniform_indices.size(); ++i)
{
GLuint const uniform_index = uniform_indices[i];
std::string name(name_lengths[i], 0);
glGetActiveUniformName(prog, uniform_index, name_lengths[i], NULL, &name[0]);
std::ostringstream details;
details << std::setfill('0') << std::setw(4) << offsets[i] << ": " << std::setfill(' ') << std::setw(5) << types[i] << " " << name;
if(sizes[i] > 1)
{
details << "[" << sizes[i] << "]";
}
details << "
";
uniform_details.push_back(details.str());
}
// Sort uniform detail string alphabetically. (Since the detail strings
// start with the uniform's byte offset, this will order the uniforms in
// the order they are laid out in memory:
std::sort(uniform_details.begin(), uniform_details.end());
// Output details:
std::cout << indent << "Uniform block \"" << block_name << "\":
";
for(auto detail = uniform_details.begin(); detail != uniform_details.end(); ++detail)
{
std::cout << indent << " " << *detail;
}
}
GLvoid printShaderLog(GLuint shader)
{
GLint infologLength = 0;
GLint charsWritten = 0;
GLchar *infoLog;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength);
if (infologLength > 0)
{
infoLog = (GLchar *)malloc(infologLength);
glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog);
std::cout << infoLog << "
";
free(infoLog);
}
}
/////////////////////////////////////////////////////////////
// Call back impl
/////////////////////////////////////////////////////////////
// Init
bool onInit()
{
// ---------------------
// init GL
glGenBuffers(gl::buffer::MAX, gl::buffers);
glGenVertexArrays(gl::varray::MAX, gl::varrays);
for(uint8_t i = 0; i < gl::program::MAX; ++i)
gl::programs[i] = glCreateProgram();
// vertex buffer to draw 4 quads
std::vector<float> quad_vertices;
for(uint8_t i = 0; i < 4u; ++i)
{
quad_vertices.push_back(-1.0f); // ll
quad_vertices.push_back(-1.0f);
quad_vertices.push_back( 1.0f); // ur
quad_vertices.push_back( 1.0f);
quad_vertices.push_back(-1.0f); // ul
quad_vertices.push_back( 1.0f);
quad_vertices.push_back(-1.0f); // ll
quad_vertices.push_back(-1.0f);
quad_vertices.push_back( 1.0f); // lr
quad_vertices.push_back(-1.0f);
quad_vertices.push_back( 1.0f); // ur
quad_vertices.push_back( 1.0f);
}
// param buffer
color::params[0].red = 0.1f;
color::params[0].green = 0.0f;
color::params[0].blue = 0.0f;
color::params[0].alpha = 0.0f;
color::params[1].red = 0.0f;
color::params[1].green = 0.25f;
color::params[1].blue = 0.75f;
color::params[1].alpha = 0.0f;
color::params[2].red = 0.0f;
color::params[2].green = 0.75f;
color::params[2].blue = 0.25f;
color::params[2].alpha = 0.0f;
color::params[3].red = 0.9f;
color::params[3].green = 0.0f;
color::params[3].blue = 0.0f;
color::params[3].alpha = 0.0f; // quad should be white
glBindBuffer(GL_ARRAY_BUFFER, gl::buffers[gl::buffer::VERTEX_QUAD]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*quad_vertices.size(), &quad_vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_UNIFORM_BUFFER, gl::buffers[gl::buffer::UNIFORM_PARAMS]);
glBufferData(GL_UNIFORM_BUFFER, sizeof(color::Params)*color::param::MAX, &(color::params[0].red), GL_STREAM_COPY);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glBindBufferBase( GL_UNIFORM_BUFFER,
gl::buffer::UNIFORM_PARAMS,
gl::buffers[gl::buffer::UNIFORM_PARAMS]);
// vertex arrays
glBindVertexArray(gl::varrays[gl::varray::QUAD]);
glBindBuffer(GL_ARRAY_BUFFER, gl::buffers[gl::buffer::VERTEX_QUAD]);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, UTILS_BUFFER_OFFSET(0));
glBindVertexArray(0);
// programs
const GLchar* vshader_src[] =
{
"#version 330 core
",
"layout(location=0) in vec2 vsin_pos;
",
"flat out int vsout_id;
",
"void main()
",
"{
",
" vsout_id = gl_VertexID/6;
",
" gl_Position = vec4(vsin_pos, 0.0, 1.0);
",
"}
"
};
const GLchar* fshader_src[] =
{
"#version 330 core
",
"struct Parameter
",
"{
",
" vec2 rg;
",
" vec2 ba;
",
" vec4 reserved;
",
"};
",
"layout(std140) uniform Params
",
"{
",
" Parameter cst_params[4];
"
"};
",
"flat in int vsout_id;
",
"out vec4 fsout_color;
",
"void main()
",
"{
",
" int ID = vsout_id;
",
" fsout_color = vec4(cst_params[ID].rg, cst_params[ID].ba);
",
" vec4 tmp = cst_params[ID].reserved;
",
"}
"
};
GLuint vshader_sum = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vshader_sum, 8, vshader_src, NULL);
glCompileShader(vshader_sum);
printShaderLog(vshader_sum);
GLuint fshader_sum = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fshader_sum, 18, fshader_src, NULL);
glCompileShader(fshader_sum);
GLint length = 0;
// glGetShaderiv(fshader_sum, GL_SHADER_SOURCE_LENGTH, &length);
GLchar buffer[512];
glGetShaderSource(fshader_sum, 512, &length, buffer);
std::cout << "source :
" << buffer << "
";
printShaderLog(fshader_sum);
glAttachShader(gl::programs[gl::program::SUM], vshader_sum);
glAttachShader(gl::programs[gl::program::SUM], fshader_sum);
glLinkProgram(gl::programs[gl::program::SUM]);
glUseProgram(gl::programs[gl::program::SUM]);
glUniformBlockBinding( gl::programs[gl::program::SUM],
glGetUniformBlockIndex(gl::programs[gl::program::SUM], "Params"),
gl::buffer::UNIFORM_PARAMS );
print_uniform_block_info(gl::programs[gl::program::SUM], glGetUniformBlockIndex(gl::programs[gl::program::SUM], "Params"));
glUseProgram(0);
glDeleteShader(vshader_sum);
glDeleteShader(fshader_sum);
glClearColor(0.0f,0.0f,0.0f,0.0f);
glEnable(GL_DEPTH_TEST);
glViewport(0,0,window::width, window::height);
// check errors
int error = glGetError();
std::cout << "gl error : " << error << "
";
if(error)
return false;
return true;
}
/////////////////////////////////////////////////////////////
// Shutdown
void onShutdown()
{
glDeleteBuffers(gl::buffer::MAX, gl::buffers);
glDeleteVertexArrays(gl::varray::MAX, gl::varrays);
for(uint8_t i = 0; i < gl::program::MAX; ++i)
glDeleteProgram(gl::programs[i]);
// make sure we're done
glFinish();
}
/////////////////////////////////////////////////////////////
// Render
void onRender()
{
// time
double t = time();
// updload colors
// glBindBuffer(GL_UNIFORM_BUFFER, gl::buffers[gl::buffer::UNIFORM_PARAMS]);
// gerstner::Params* params = (gerstner::Params*) glMapBufferRange( GL_UNIFORM_BUFFER,
// 0,
// sizeof(gerstner::Params) * gerstner::param::MAX,
// GL_MAP_WRITE_BIT |
// GL_MAP_UNSYNCHRONIZED_BIT |
// GL_MAP_INVALIDATE_RANGE_BIT);
// std::memcpy(params, &(gerstner::params[0].x0max), sizeof(gerstner::Params) * gerstner::param::MAX);
// glUnmapBuffer(GL_UNIFORM_BUFFER);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquation(GL_FUNC_ADD);
// draw 4 fulls screen quads
glUseProgram(gl::programs[gl::program::SUM]);
glBindVertexArray(gl::varrays[gl::varray::QUAD]);
glDrawArrays( GL_TRIANGLES,
0,
24 );
glBindVertexArray(0);
glUseProgram(0);
glutSwapBuffers();
}
/////////////////////////////////////////////////////////////
// Resize
void onResize(int32_t w, int32_t h)
{
window::width = w;
window::height = h;
glViewport(0,0,w,h);
}
/////////////////////////////////////////////////////////////
// Keyboard
void onKeyboard(uint8_t k, int32_t x, int32_t y)
{
// handle esc key
switch(k)
{
case 27:
onShutdown();
exit(0);
break;
}
}
/////////////////////////////////////////////////////////////
// Special keys
void onSpecialKey(int32_t k, int32_t x, int32_t y)
{
}
/////////////////////////////////////////////////////////////
// Passive mouse
void onMousePassiveMotion(int32_t x, int32_t y)
{
}
/////////////////////////////////////////////////////////////
// Button event
void onMouseButton(int32_t button, int32_t state, int32_t x, int32_t y)
{
}
/////////////////////////////////////////////////////////////
// Mouse active motion
void onMouseMotion(int32_t x, int32_t y)
{
}
/////////////////////////////////////////////////////////////
// idle
void onIdle()
{
// sleep
#ifdef _WIN32
Sleep(1);
#else
usleep(1000);
#endif
onRender();
}
Makefile :
BIN = sample
CPP = g++
LDD = g++
CPPFLAGS = -ansi -pedantic -std=c++0x -I ./
LDDFLAGS = -lm -lGL -lglut
FILES_SRC = $(wildcard *.cpp)
FILES_OBJ = $(FILES_SRC:%.cpp=%.o)
FILES_DEP = $(FILES_SRC:%.cpp=%.d)
default: $(BIN)
all: $(BIN)
$(BIN): $(FILES_OBJ)
$(LDD) -o $@ $^ $(LDDFLAGS)
$(DIR_OBJ)/%.o: $(DIR_SRC)/%.c
$(CPP) $(CPPFLAGS) -o $@ -c $<
$(DIR_DEP)/%.d: $(DIR_SRC)/%.c
$(CPP) $(CPPFLAGS) -MM -MD -o $@ $<
-include $(FILES_DEP)
# regles de nettoyage
.PHONY: clean distclean
clean :
rm -rf $(FILES_OBJ) $(FILES_DEP)
distclean:
rm -f $(BIN)
(You will need to provide the GL/gl3.h)
The bug is still present : buffer[0] and buffer[3] seem to be read, the others are ignored ?! (and I’m not even mapping the buffer anymore)
EDIT Not working on catalyst 11.2 either