Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 10 of 10

Thread: Sharing an uniform buffer across a block array.

  1. #1
    Super Moderator Frequent Contributor Groovounet's Avatar
    Join Date
    Jul 2004
    Posts
    934

    Sharing an uniform buffer across a block array.

    Hi,

    I was trying to use a single uniform buffer across a block array.
    For this I used glBindBufferRange instead of glBindBufferBase to bind the buffer and in this experiment I expected it will use the offset and range parameters.

    Unfortunately, I can't make it work on nVidia drivers. (AMD doesn't support block arrays yet).

    So, is such feature supposed to be an OpenGL 4.0 feature?

    I haven't find any clue against it but, nothing confirming it explicitly either:
    As least glBindBufferRange can be used on uniform buffer.
    http://www.opengl.org/sdk/docs/man4/...ufferRange.xml

  2. #2
    Senior Member OpenGL Guru
    Join Date
    May 2009
    Posts
    4,948

    Re: Sharing an uniform buffer across a block array.

    I was trying to use a single uniform buffer across a block array.
    I'm not sure what it is that you're trying to accomplish.

    Each element of a block array is a separate UBO binding point. As long as you bind different regions of the buffer to those different binding points, you should be fine.

    Unfortunately, I can't make it work on nVidia drivers.
    What happens?

  3. #3
    Super Moderator Frequent Contributor Groovounet's Avatar
    Join Date
    Jul 2004
    Posts
    934

    Re: Sharing an uniform buffer across a block array.

    That's what I was trying to accomplish.

    I have an invalid operation error on the second glBindBufferRange call...

  4. #4
    Senior Member OpenGL Guru
    Join Date
    May 2009
    Posts
    4,948

    Re: Sharing an uniform buffer across a block array.

    I have an invalid operation error on the second glBindBufferRange call...
    Do you have the alignment for your data correct? Are you sure that you are not binding beyond the end of the buffer object?

  5. #5
    Super Moderator Frequent Contributor Groovounet's Avatar
    Join Date
    Jul 2004
    Posts
    934

    Re: Sharing an uniform buffer across a block array.

    Yes I am pretty sure not to bind beyond the buffer object.

    What are the restriction on the alignment? For my experiment it was 64 bytes alignment so it should be not problem here.

  6. #6
    Senior Member OpenGL Guru
    Join Date
    May 2009
    Posts
    4,948

    Re: Sharing an uniform buffer across a block array.

    Are you sure you're getting GL_INVALID_OPERATION? Because the only reason glBindBufferRange should return that is if you have passed a buffer object name that doesn't exist.

  7. #7
    Super Moderator Frequent Contributor Groovounet's Avatar
    Join Date
    Jul 2004
    Posts
    934

    Re: Sharing an uniform buffer across a block array.

    My mistake Alfonse, the error is "invalid value" actually.

    I just made a basic sample code out of it to show the problem and I guess it's a bug then:

    Code :
    //**********************************
    // OpenGL Uniform Buffer Shared
    // 23/08/2010 - 23/08/2010
    //**********************************
    // Christophe Riccio
    // [email]g.truc.creation@gmail.com[/email]
    //**********************************
    // G-Truc Creation
    // [url]www.g-truc.net[/url]
    //**********************************
     
    #include <glf/glf.hpp>
     
    namespace
    {
    	std::string const SAMPLE_NAME = "OpenGL Uniform Buffer Shared";
    	std::string const VERTEX_SHADER_SOURCE(glf::DATA_DIRECTORY + "400/uniform-buffer.vert");
    	std::string const FRAGMENT_SHADER_SOURCE(glf::DATA_DIRECTORY + "400/uniform-buffer.frag");
    	int const SAMPLE_SIZE_WIDTH = 640;
    	int const SAMPLE_SIZE_HEIGHT = 480;
    	int const SAMPLE_MAJOR_VERSION = 4;
    	int const SAMPLE_MINOR_VERSION = 0;
     
    	glf::window Window(glm::ivec2(SAMPLE_SIZE_WIDTH, SAMPLE_SIZE_HEIGHT));
     
    	GLsizei const VertexCount = 4;
    	GLsizeiptr const PositionSize = VertexCount * sizeof(glm::vec2);
    	glm::vec2 const PositionData[VertexCount] =
    	{
    		glm::vec2(-1.0f,-1.0f),
    		glm::vec2( 1.0f,-1.0f),
    		glm::vec2( 1.0f, 1.0f),
    		glm::vec2(-1.0f, 1.0f)
    	};
     
    	GLsizei const ElementCount = 6;
    	GLsizeiptr const ElementSize = ElementCount * sizeof(GLushort);
    	GLushort const ElementData[ElementCount] =
    	{
    		0, 1, 2, 
    		2, 3, 0
    	};
     
    	GLuint const Instances = 2;
     
    	GLuint ProgramName = 0;
    	GLuint ElementBufferName = 0;
    	GLuint ArrayBufferName = 0;
    	GLuint VertexArrayName = 0;
    	GLuint TransformBufferName = 0;
    	GLuint MaterialBufferName = 0;
    	GLint UniformTransform[Instances] = {0, 0};
    	GLint UniformMaterial = 0;
     
    }//namespace
     
    bool initProgram()
    {
    	bool Validated = true;
     
    	// Create program
    	if(Validated)
    	{
    		GLuint VertexShaderName = glf::createShader(GL_VERTEX_SHADER, VERTEX_SHADER_SOURCE);
    		GLuint FragmentShaderName = glf::createShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE);
     
    		ProgramName = glCreateProgram();
    		glAttachShader(ProgramName, VertexShaderName);
    		glAttachShader(ProgramName, FragmentShaderName);
    		glDeleteShader(VertexShaderName);
    		glDeleteShader(FragmentShaderName);
     
    		glLinkProgram(ProgramName);
    		Validated = glf::checkProgram(ProgramName);
    	}
     
    	// Get variables locations
    	if(Validated)
    	{
    		UniformMaterial = glGetUniformBlockIndex(ProgramName, "material");
    		UniformTransform[0] = glGetUniformBlockIndex(ProgramName, "transform[0]");
    		UniformTransform[1] = glGetUniformBlockIndex(ProgramName, "transform[1]");
    	}
     
    	return Validated &amp;&amp; glf::checkError("initProgram");
    }
     
    bool initVertexArray()
    {
    	// Build a vertex array object
    	glGenVertexArrays(1, &amp;VertexArrayName);
        glBindVertexArray(VertexArrayName);
    		glBindBuffer(GL_ARRAY_BUFFER, ArrayBufferName);
    		glVertexAttribPointer(glf::semantic::attr::POSITION, 2, GL_FLOAT, GL_FALSE, 0, 0);
     
    		glEnableVertexAttribArray(glf::semantic::attr::POSITION);
    	glBindVertexArray(0);
     
    	return glf::checkError("initVertexArray");
    }
     
    bool initArrayBuffer()
    {
    	// Generate a buffer object
    	glGenBuffers(1, &amp;ElementBufferName);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ElementBufferName);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, ElementSize, ElementData, GL_STATIC_DRAW);
    	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
     
    	glGenBuffers(1, &amp;ArrayBufferName);
        glBindBuffer(GL_ARRAY_BUFFER, ArrayBufferName);
        glBufferData(GL_ARRAY_BUFFER, PositionSize, PositionData, GL_STATIC_DRAW);
    	glBindBuffer(GL_ARRAY_BUFFER, 0);
     
    	return glf::checkError("initArrayBuffer");
    }
     
    bool initUniformBuffer()
    {
    	GLint UniformBlockSize = 0;
     
    	glGenBuffers(1, &amp;TransformBufferName);
    	glBindBuffer(GL_UNIFORM_BUFFER, TransformBufferName);
     
    	glGetActiveUniformBlockiv(
    		ProgramName, 
    		UniformTransform[0],
    		GL_UNIFORM_BLOCK_DATA_SIZE,
    		&amp;UniformBlockSize);
     
    	glBufferData(GL_UNIFORM_BUFFER, UniformBlockSize * Instances, 0, GL_DYNAMIC_DRAW);
     
    	// Attach the buffer to UBO binding point glf::semantic::uniform::TRANSFORMn
    	glBindBufferRange(GL_UNIFORM_BUFFER, glf::semantic::uniform::TRANSFORM0, TransformBufferName, 0 * sizeof(glm::mat4), sizeof(glm::mat4));
    	glBindBufferRange(GL_UNIFORM_BUFFER, glf::semantic::uniform::TRANSFORM1, TransformBufferName, 1 * sizeof(glm::mat4), sizeof(glm::mat4));
     
    	{
    		glm::vec4 Diffuse(1.0f, 0.5f, 0.0f, 1.0f);
     
    		glGetActiveUniformBlockiv(
    			ProgramName, 
    			UniformMaterial,
    			GL_UNIFORM_BLOCK_DATA_SIZE,
    			&amp;UniformBlockSize);
     
    		glGenBuffers(1, &amp;MaterialBufferName);
    		glBindBuffer(GL_UNIFORM_BUFFER, MaterialBufferName);
    		glBufferData(GL_UNIFORM_BUFFER, UniformBlockSize, &amp;Diffuse[0], GL_DYNAMIC_DRAW);
    		glBindBuffer(GL_UNIFORM_BUFFER, 0);
     
    		// Attach the buffer to UBO binding point glf::semantic::uniform::MATERIAL
    		glBindBufferBase(GL_UNIFORM_BUFFER, glf::semantic::uniform::MATERIAL, MaterialBufferName);
    	}
     
    	return glf::checkError("initUniformBuffer");
    }
     
    bool begin()
    {
    	GLint MajorVersion = 0;
    	GLint MinorVersion = 0;
    	glGetIntegerv(GL_MAJOR_VERSION, &amp;MajorVersion);
    	glGetIntegerv(GL_MINOR_VERSION, &amp;MinorVersion);
    	bool Validated = glf::version(MajorVersion, MinorVersion) >= glf::version(SAMPLE_MAJOR_VERSION, SAMPLE_MINOR_VERSION);
     
    	if(Validated)
    		Validated = initProgram();
    	if(Validated)
    		Validated = initArrayBuffer();
    	if(Validated)
    		Validated = initVertexArray();
    	if(Validated)
    		Validated = initUniformBuffer();
     
    	return Validated &amp;&amp; glf::checkError("begin");
    }
     
    bool end()
    {
    	glDeleteVertexArrays(1, &amp;VertexArrayName);
    	glDeleteBuffers(1, &amp;ArrayBufferName);
    	glDeleteBuffers(1, &amp;ElementBufferName);
    	glDeleteBuffers(1, &amp;TransformBufferName);
    	glDeleteBuffers(1, &amp;MaterialBufferName);
    	glDeleteProgram(ProgramName);
     
    	return glf::checkError("end");
    }
     
    void display()
    {
    	glBindBuffer(GL_UNIFORM_BUFFER, TransformBufferName);
    	glBufferData(GL_UNIFORM_BUFFER, sizeof(glm::mat4) * Instances, NULL, GL_DYNAMIC_DRAW);
     
    	{
    		// Compute the MVP (Model View Projection matrix)
    		glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
    		glm::mat4 ViewTranslate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Window.TranlationCurrent.y));
    		glm::mat4 ViewRotateX = glm::rotate(ViewTranslate, Window.RotationCurrent.y, glm::vec3(1.f, 0.f, 0.f));
    		glm::mat4 View = glm::rotate(ViewRotateX, Window.RotationCurrent.x, glm::vec3(0.f, 1.f, 0.f));
    		glm::mat4 Model = glm::mat4(1.0f);
    		glm::mat4 MVP = Projection * View * Model;
     
    		glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(MVP), &amp;MVP[0][0]);
    	}
     
    	{
    		// Compute the MVP (Model View Projection matrix)
    		glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
    		glm::mat4 ViewTranslate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Window.TranlationCurrent.y));
    		glm::mat4 ViewRotateX = glm::rotate(ViewTranslate, Window.RotationCurrent.y, glm::vec3(1.f, 0.f, 0.f));
    		glm::mat4 View = glm::rotate(ViewRotateX, Window.RotationCurrent.x + 90.f, glm::vec3(0.f, 1.f, 0.f));
    		glm::mat4 Model = glm::mat4(1.0f);
    		glm::mat4 MVP = Projection * View * Model;
     
    		glBufferSubData(GL_UNIFORM_BUFFER, sizeof(MVP), sizeof(MVP), &amp;MVP[0][0]);
    	}
    	glBindBuffer(GL_UNIFORM_BUFFER, 0);
     
    	// Set the display viewport
    	glViewport(0, 0, Window.Size.x, Window.Size.y);
     
    	// Clear color buffer with black
    	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    	glClear(GL_COLOR_BUFFER_BIT);
     
    	// Bind program
    	glUseProgram(ProgramName);
    	glUniformBlockBinding(ProgramName, UniformTransform[0], glf::semantic::uniform::TRANSFORM0);
    	glUniformBlockBinding(ProgramName, UniformTransform[1], glf::semantic::uniform::TRANSFORM1);
    	glUniformBlockBinding(ProgramName, UniformMaterial, glf::semantic::uniform::MATERIAL);
     
    	// Bind vertex array & draw 
    	glBindVertexArray(VertexArrayName);
    	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ElementBufferName);
     
    	glDrawElementsInstancedBaseVertex(GL_TRIANGLES, ElementCount, GL_UNSIGNED_SHORT, NULL, Instances, 0);
     
    	glf::checkError("display");
    	glf::swapBuffers();
    }
     
    int main(int argc, char* argv[])
    {
    	if(glf::run(
    		argc, argv,
    		glm::ivec2(::SAMPLE_SIZE_WIDTH, ::SAMPLE_SIZE_HEIGHT), 
    		::SAMPLE_MAJOR_VERSION, 
    		::SAMPLE_MINOR_VERSION))
    		return 0;
    	return 1;
    }

  8. #8
    Super Moderator Frequent Contributor Groovounet's Avatar
    Join Date
    Jul 2004
    Posts
    934

    Re: Sharing an uniform buffer across a block array.

    I just made more tests about a single uniform buffer shared across 2 blocks and I have the same error.

    1 block from the vertex shader, 1 block from the fragment shader. Do you know if it is a limitation?

    By the way I have this error both on nVidia and AMD.

  9. #9
    Advanced Member Frequent Contributor
    Join Date
    Apr 2009
    Posts
    578

    Re: Sharing an uniform buffer across a block array.

    Likely me being paranoid, but just to check: if you bind 2 different buffer objects to two different indices, everything is then ok?

    On another wonkiness check, this is more like out of curiosity: what happens if you use glBindBufferBase (yes one loses the offset) for two different indices and same buffer object?

    Odd though... I cannot see any thing in the 3.3 or 4.1 spec that says the same buffer object cannot be used the way you are.. but if both NVIDIA and ATI have the same behavior, makes me suspicious that I missed something in the spec.

  10. #10
    Senior Member OpenGL Guru
    Join Date
    May 2009
    Posts
    4,948

    Re: Sharing an uniform buffer across a block array.

    but if both NVIDIA and ATI have the same behavior, makes me suspicious that I missed something in the spec.
    They don't have the same behavior. NVIDIA drivers are having a problem with binding the same buffer object to multiple buffer object binding points that are buffer arrays. ATI drivers don't yet support buffer arrays at all. This has the same effect as the NVIDIA issue, but it's not the same problem.

    I'd suggest sending a bug report off to NIVIDA.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •