Ok, here’s a simple little GLUT test program to illustrate how to draw a “bindless batch” (that is, draw it with NV_vertex_buffer_unified_memory from here). To build without bindless, comment out #define WITH_BINDLESS.
To keep it simple, I used the fixed-function pipe and legacy vertex attributes.
Anyway, here’s the code.
//------------------------------------------------------------------------------
// Bindless batches example:
//
// NOTE: To keep this as stupid-simple as possible, this demo pgm
// doesn't use shaders, and therefore doesn't use generic vertex
// attributes (since to do so would require assuming NVidia vertex
// attribute aliasing. Of course, bindless trivially supports both.
//
//------------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glut.h>
//------------------------------------------------------------------------
// Uncomment the following to build with NV bindless batches support
// (i.e. NV_vertex_buffer_unified_memory)
//------------------------------------------------------------------------
#define WITH_BINDLESS
GLuint Vbo_handle[3]; // Positions, Colors, Index list
#ifdef WITH_BINDLESS
GLuint64EXT Vbo_addr[3]; // Positions, Colors, Index list
GLuint Vbo_size[3]; // Positions, Colors, Index list
#endif
//-----------------------------------------------------------------------
void checkGLError( const char hdr[] )
{
int err = glGetError();
if( err )
{
fprintf(stderr, "ERROR %s: %s
", hdr, gluErrorString(err));
exit(1);
}
}
//-----------------------------------------------------------------------
void init()
{
static const GLfloat pos [] = { -1, -1,
-1, 1,
1, 1,
1, -1 };
static const GLfloat color[] = { 1,0,0,1,
1,0,0,1,
1,0,0,1,
1,0,0,1 };
static const GLushort index[] = { 0, 1, 2, 3 };
// Create and fill VBOs
glGenBuffers( 3, Vbo_handle );
GLenum gl_target = GL_ARRAY_BUFFER;
// Positions...
glBindBuffer( gl_target, Vbo_handle[0] );
glBufferData( gl_target, sizeof(pos) , pos , GL_STATIC_DRAW );
// Colors...
glBindBuffer( gl_target, Vbo_handle[1] );
glBufferData( gl_target, sizeof(color), color, GL_STATIC_DRAW );
// Index array...
gl_target = GL_ELEMENT_ARRAY_BUFFER;
glBindBuffer( gl_target, Vbo_handle[2] );
glBufferData( gl_target, sizeof(index), index, GL_STATIC_DRAW );
#ifdef WITH_BINDLESS
// Make them resident and query GPU addresses
for ( int i = 0; i < 3; i++ )
{
glBindBuffer( gl_target, Vbo_handle[i] );
glGetBufferParameterui64vNV( gl_target, GL_BUFFER_GPU_ADDRESS_NV,
&Vbo_addr[i] );
glMakeBufferResidentNV ( gl_target, GL_READ_ONLY );
}
Vbo_size[0] = sizeof(pos);
Vbo_size[1] = sizeof(color);
Vbo_size[2] = sizeof(index);
// Make draw calls use the GPU address VAO state, not the handle VAO state
glEnableClientState( GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV );
glEnableClientState( GL_ELEMENT_ARRAY_UNIFIED_NV );
#endif
}
//-----------------------------------------------------------------------
void reshape(int width, int height)
{
glViewport(0, 0, width, height);
}
//-----------------------------------------------------------------------
void display()
{
static float angle = 0.0;
// Clear screen
int err=0;
glClear( GL_COLOR_BUFFER_BIT );
// Load up PROJECTION and MODELVIEW
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2,2,-2,2,-2,2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(angle, 0,0,1);
angle += 0.01;
// Draw a quad
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
#ifdef WITH_BINDLESS
// "Bindless VBOs case
glVertexFormatNV ( 2, GL_FLOAT, 2*sizeof(GLfloat) );
glBufferAddressRangeNV( GL_VERTEX_ARRAY_ADDRESS_NV, 0,
Vbo_addr[0], Vbo_size[0]);
glColorFormatNV ( 4, GL_FLOAT, 4*sizeof(GLfloat) );
glBufferAddressRangeNV( GL_COLOR_ARRAY_ADDRESS_NV , 0,
Vbo_addr[1], Vbo_size[1]);
glBufferAddressRangeNV( GL_ELEMENT_ARRAY_ADDRESS_NV, 0,
Vbo_addr[2], Vbo_size[2] );
#else
// "Classic" VBOs case
glBindBuffer ( GL_ARRAY_BUFFER, Vbo_handle[0] );
glVertexPointer ( 2, GL_FLOAT, 2*sizeof(GLfloat), 0 );
glBindBuffer ( GL_ARRAY_BUFFER, Vbo_handle[1] );
glColorPointer ( 4, GL_FLOAT, 4*sizeof(GLfloat), 0 );
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, Vbo_handle[2] );
#endif
glDrawElements ( GL_QUADS, 4, GL_UNSIGNED_SHORT, 0 );
// Swap
glutSwapBuffers();
glutPostRedisplay();
checkGLError( "End of display()" );
}
//-----------------------------------------------------------------------
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
exit(0);
break;
}
}
int main (int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutCreateWindow(argv[0]);
glutKeyboardFunc(keyboard);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutReshapeWindow(400,400);
printf("GL_RENDERER = %s
",glGetString(GL_RENDERER));
glClearColor(0,0,0,0);
init();
glutMainLoop();
return 0;
}
If instead you wanted to use generic vertex attributes, in display() you’d just change the attribute setup to this:
glVertexAttribFormatNV( attrib_id, width, type, norm_fixed_pt, stride );
glBufferAddressRangeNV( GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, attrib_id, gpu_addr, gpu_size );
And of course use the generic enable (e.g. glEnableVertexAttribArray) instead of the legacy attribute enables.