Jump to content

  • Log In with Google      Sign In   
  • Create Account

Rarosu

Member Since 16 Jun 2010
Offline Last Active Apr 25 2016 03:02 PM

#5252747 Only the last instance is rendered

Posted by Rarosu on 17 September 2015 - 02:38 PM

Thanks for the reply, GlassKnife, I'll edit the original post with the code.

 

I have reduced the issue to where I know there is something going on with the uniform bindings. I have tried making a separate program, VBO and VAO for the second instance and the same problem occurs. When I make a separate uniform buffer object however and fill it with the same data, it works. That is, the difference between:

glUseProgram(program);
glBindVertexArray(vao);

// Instance is rendered.
uniform_buffer_data.offset = 1.3f;
glBindBufferBase(GL_UNIFORM_BUFFER, UNIFORM_BINDING, uniform_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformBuffer), &uniform_buffer_data);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

// This instance is also rendered.
ubo_data2.offset = -0.4f;
glBindBufferBase(GL_UNIFORM_BUFFER, UNIFORM_BINDING, ubo2);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformBuffer), &ubo_data2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

And this:

glUseProgram(program);
glBindVertexArray(vao);

// This instance is no longer visible.
uniform_buffer_data.offset = 1.3f;
glBindBufferBase(GL_UNIFORM_BUFFER, UNIFORM_BINDING, uniform_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformBuffer), &uniform_buffer_data);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

// And only this one is rendered.
uniform_buffer_data.offset = -0.4f;
glBindBufferBase(GL_UNIFORM_BUFFER, UNIFORM_BINDING, uniform_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformBuffer), &uniform_buffer_data);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

As for checking the state, I am not sure what to look for in this scenario. I tried apitrace at your suggestion (which seems awesome) and the state looks fine to me; as I would expect it.




#5252727 Only the last instance is rendered

Posted by Rarosu on 17 September 2015 - 01:14 PM

Hello GameDev!

 

I am porting an OpenGL 4.4 application to OpenGL 3.1 to get it to run on my Intel HD Graphics 3000 card (on my laptop). So far, things have been going well, but I ran into a problem when rendering more than one instance using the same vertex buffer (just changing the uniform buffer between the draw calls). When I do this, only the last instance is rendered. The non-ported code did not exhibit this problem and I just cannot see what I might have done to cause it to fail.

 

I have managed to isolate the bug in a minimal sample: http://pastebin.com/87DQhdrS

#include <SDL2/SDL.h>
#include <GL/gl3w.h>
#include <iostream>
#include <string>

const int OPENGL_MAJOR = 3;
const int OPENGL_MINOR = 1;
const int UNIFORM_BINDING = 1;

const char* VERTEX_SOURCE =
	"#version 140                                    \n"
	"                                                \n"
	"in vec2 in_position;                            \n"
	"                                                \n"
	"layout(std140) uniform UniformBuffer            \n"
	"{                                               \n"
	"    vec4 offset;                                \n"
	"};                                              \n"
	"                                                \n"
	"void main()                                     \n"
	"{                                               \n"
	"    gl_Position = vec4(in_position, 0.0f, 1.0f);\n"
	"    gl_Position.x += offset.x;                  \n"
	"}                                               \n";

const char* FRAGMENT_SOURCE =
	"#version 140                                    \n"
	"                                                \n"
	"out vec4 out_color;                             \n"
	"                                                \n"
	"void main()                                     \n"
	"{                                               \n"
	"    out_color = vec4(1.0f, 1.0f, 1.0f, 1.0f);   \n"
	"}                                               \n";

struct UniformBuffer
{
	float offset[4];
};

SDL_Window* window = nullptr;
SDL_GLContext glcontext = nullptr;
unsigned int viewport_width = 800;
unsigned int viewport_height = 600;
bool running = true;
GLuint vertexShader = 0;
GLuint fragmentShader = 0;
GLuint program = 0;
GLuint position_vbo = 0;
GLuint vao = 0;
UniformBuffer uniform_buffer_data;
GLuint uniform_buffer = 0;

void initialize();
void loadResources();
GLuint compileShader(const char* source, GLuint type);
void linkProgram(GLuint program);
void run();
void handleEvents();
void render();

int main(int argc, char* argv[])
{
	initialize();
	loadResources();
	run();

	return 0;
}

void initialize()
{
	if (SDL_Init(0) != 0)
	{
		throw std::runtime_error("Failed to initialize SDL");
	}

	window = SDL_CreateWindow("gl3", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, viewport_width, viewport_height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
	if (window == nullptr)
	{
		throw std::runtime_error("Failed to create SDL window");
	}

	SDL_GLcontextFlag flags = SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG;
#ifndef NDEBUG
	flags = (SDL_GLcontextFlag)(flags | SDL_GL_CONTEXT_DEBUG_FLAG);
#endif
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, OPENGL_MAJOR);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, OPENGL_MINOR);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, flags);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32);
	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);

	glcontext = SDL_GL_CreateContext(window);
	if (glcontext == nullptr)
	{
		throw std::runtime_error("Failed to create OpenGL context");
	}

	if (gl3wInit() != 0)
	{
		throw std::runtime_error(std::string("Failed to initialize gl3w"));
	}

	if (gl3wIsSupported(OPENGL_MAJOR, OPENGL_MINOR) != 1)
	{
		throw std::runtime_error("OpenGL version not supported");
	}

	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glViewport(0, 0, viewport_width, viewport_height);

	SDL_GL_SetSwapInterval(1);
}

void loadResources()
{
	// VBOs.
	float positions[] = { -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f };

	glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);

	glGenBuffers(1, &position_vbo);
	glBindBuffer(GL_ARRAY_BUFFER, position_vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, positions, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);

	// Shaders.
	vertexShader = compileShader(VERTEX_SOURCE, GL_VERTEX_SHADER);
	fragmentShader = compileShader(FRAGMENT_SOURCE, GL_FRAGMENT_SHADER);

	program = glCreateProgram();
	glAttachShader(program, vertexShader);
	glAttachShader(program, fragmentShader);
	linkProgram(program);

	glUniformBlockBinding(program, glGetUniformBlockIndex(program, "UniformBuffer"), UNIFORM_BINDING);

	// UBOs.
	uniform_buffer_data.offset[0] = 0.0f;
	uniform_buffer_data.offset[1] = 0.0f;
	uniform_buffer_data.offset[2] = 0.0f;
	uniform_buffer_data.offset[3] = 0.0f;

	glGenBuffers(1, &uniform_buffer);
	glBindBufferBase(GL_UNIFORM_BUFFER, UNIFORM_BINDING, uniform_buffer);
	glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformBuffer) * sizeof(float), &uniform_buffer_data, GL_DYNAMIC_DRAW);
}

GLuint compileShader(const char* source, GLuint type)
{
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &source, nullptr);
	glCompileShader(shader);

	GLint status;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
	if (status != GL_TRUE)
	{
		GLint logSize;
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logSize);

		std::string log;
		if (logSize > 0)
		{
			int written;
			log.resize(logSize);
			glGetShaderInfoLog(shader, logSize, &written, &log[0]);
		}

		throw std::runtime_error("Failed to compile shader: " + log);
	}

	return shader;
}

void linkProgram(GLuint program)
{
	glLinkProgram(program);

	GLint status;
	glGetProgramiv(program, GL_LINK_STATUS, &status);
	if (status != GL_TRUE)
	{
		GLint logSize;
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logSize);

		std::string log;
		if (logSize > 0)
		{
			int written;
			log.resize(logSize);
			glGetProgramInfoLog(program, logSize, &written, &log[0]);
		}

		throw std::runtime_error("Failed to link program: " + log);
	}
}

void run()
{
	while (running)
	{
		handleEvents();
		render();
	}
}

void handleEvents()
{
	SDL_Event event;
	while (SDL_PollEvent(&event))
	{
		switch (event.type)
		{
			case SDL_QUIT:
			{
				running = false;
			} break;

			case SDL_WINDOWEVENT:
			{
				switch (event.window.event)
				{
					case SDL_WINDOWEVENT_RESIZED:
					{
						viewport_width = event.window.data1;
						viewport_height = event.window.data2;

						glViewport(0, 0, viewport_width, viewport_height);
					} break;
				}
			} break;
		}
	}
}

void render()
{
	glClear(GL_COLOR_BUFFER_BIT);

	glUseProgram(program);
	glBindVertexArray(vao);

	uniform_buffer_data.offset[0] = 1.3f;
	glBindBufferBase(GL_UNIFORM_BUFFER, UNIFORM_BINDING, uniform_buffer);
	glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformBuffer) * sizeof(float), &uniform_buffer_data);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	uniform_buffer_data.offset[0] = -0.4f;
	glBindBufferBase(GL_UNIFORM_BUFFER, UNIFORM_BINDING, uniform_buffer);
	glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformBuffer) * sizeof(float), &uniform_buffer_data);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	SDL_GL_SwapWindow(window);
}

I am using SDL2 and GL3W and I am working in Visual Studio 2013 on Windows 10. The biggest change when I ported was that I no longer could specify the uniform binding point in the shader, but had to use glUniformBlockBinding instead. Anyone familiar with this version of OpenGL who could tell me if I am doing something stupid?

 

Cheers!

- Rarosu




PARTNERS