Hello,
we observe inconsistent behavior with glDrawArrays on AMD Hardware (Nvidia and Intel provide the correct result). Similar to the thread https://www.opengl.org/discussion_boards/showthread.php/200523-Vertex-shader-stops-passing-values-on-AMD-Hardware we are rendering 3-component colors with the type GL_UNSIGNED_BYTE. The problem is not restricted to drawing points, we also observe the same problem when rendering GL_TRIANGLES. The glDrawArrays call uses a non-zero offset (i.e. the first parameter in glDrawArrays(mode, first, count) is non zero). When rendering with such an offset, we observe flickering and/or that the last color in the color VBO is incorrectly black.
The problem only occurs with the following setup:
GL_VENDOR = ATI Technologies Inc.
GL_VERSION = 3.2.13521 Core Profile Context 24.20.11016.4
GL_RENDERER = Radeon ™ RX 480 Graphics
A simple test-program outputs the following images. The lower-left pixel is black in the failing case.
Correct vs Incorrect
[ATTACH=CONFIG]1870[/ATTACH] [ATTACH=CONFIG]1871[/ATTACH]
We have found two alternatives to avoid the problem:
[ol]
[li]Using glMultiDrawArrays which are OpenGL 1.4[/li][li]Using 4-component colors[/li][/ol]
The following simple test-program was used to narrow down the problem:
//------------------------------------------------------------------------------
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
//------------------------------------------------------------------------------
static void error_callback(int, const char* description)
{
fprintf(stderr, "Error: %s
", description);
}
//------------------------------------------------------------------------------
static void key_callback(GLFWwindow* window, int key, int, int action, int)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
//------------------------------------------------------------------------------
/*
* Based on:
* https://www.glfw.org/docs/latest/quick.html
* https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_03
*
* Same bug see also:
* https://www.opengl.org/discussion_boards/showthread.php/200523-Vertex-shader-stops-passing-values-on-AMD-Hardware?p=1290870#post1290870
*/
int main(int argc, char **argv)
{
GLFWwindow * window;
glfwSetErrorCallback(error_callback);
if (!glfwInit())
{
exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(640, 480, "Rendering Test", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetKeyCallback(window, key_callback);
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glewExperimental = GL_TRUE; // necessary on intel and nvidia
if (glewInit() != GLEW_OK)
{
exit(EXIT_FAILURE);
}
std::cout << "GL_VENDOR = " << glGetString(GL_VENDOR) << std::endl;
std::cout << "GL_VERSION = " << glGetString(GL_VERSION) << std::endl;
std::cout << "GL_RENDERER = " << glGetString(GL_RENDERER) << std::endl;
/*
* Loading shaders and geometry
*/
static const char* vertex_shader_text =
"#version 150 core
"
"in vec2 position;
"
"in vec3 color;
"
"out vec3 pass_color;
"
"void main()
"
"{
"
" gl_Position = vec4(position, 0.0, 1.0);
"
" pass_color = color;
"
"}
";
static const char* fragment_shader_text =
"#version 150 core
"
"in vec3 pass_color;
"
"out vec4 out_color;
"
"void main()
"
"{
"
" out_color = vec4(pass_color, 1.0);
"
"}
";
float vertices[] = {
0.0f, 0.0f,
0.0f, 0.5f,
0.5f, -0.5f,
-0.5f, -0.5f
};
/*
* The AMD driver bug does not occur if we use the same data type
* in the color array (GL_FLOAT) as in the vertex-position array.
*
* The problem also does not occur when using 4-component colors,
* this may be a hint that something related to data-structure
* alignment may be the cause of the error.
*/
GLubyte colors[] =
{
255, 255, 255, //255,
255, 0, 0, //255,
0, 255, 0, //255,
0, 0, 255 //255
};
GLuint vbo_position;
glGenBuffers(1, &vbo_position);
GLuint vbo_color;
glGenBuffers(1, &vbo_color);
glBindBuffer(GL_ARRAY_BUFFER, vbo_position);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vbo_color);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
GLuint vao;
glGenVertexArrays(1, &vao);
/*
* Shader initialization
*/
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertex_shader_text, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragment_shader_text, NULL);
glCompileShader(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
/*
* Get uniforms
*/
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
/*
* VBO setup
*/
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo_position);
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_color);
glEnableVertexAttribArray(colAttrib);
/*
* Only fails if we use GL_UNSIGNED_BYTE and 3 component colors.
*/
glVertexAttribPointer(colAttrib, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glBindVertexArray(0);
while (!glfwWindowShouldClose(window))
{
int width, height;
glfwGetFramebufferSize(window, &width, &height);
float ratio = width / (float)height;
glViewport(0, 0, width, height);
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glPointSize(10.0f);
glBindVertexArray(vao);
/*
* Change flag to show the non-failing case
*/
bool failing_case = true;
if (failing_case)
{
glDrawArrays(GL_POINTS, 1, 3); //GL_POINTS //GL_TRIANGLES
}
else
{
const GLint starts[] = { 1 };
const GLsizei sizes[] = { 3 };
glMultiDrawArrays(GL_POINTS, starts, sizes, 1);
}
glBindVertexArray(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteProgram(shaderProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
glDeleteBuffers(1, &vbo_position);
glDeleteBuffers(1, &vbo_color);
glDeleteVertexArrays(1, &vao);
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
//------------------------------------------------------------------------------
Best,
Matthias
edit1: Added glewExperimental = GL_TRUE; to glew initialization in the test program to run the code on intel/nvidia and removed redundant VAO bind/unbind.