diff --git a/code/renderercommon/qgl.h b/code/renderercommon/qgl.h index fbe063f6..252e0bb2 100644 --- a/code/renderercommon/qgl.h +++ b/code/renderercommon/qgl.h @@ -726,6 +726,17 @@ extern void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs); #define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F #endif +// GL_ARB_vertex_array_object +extern void (APIENTRY * qglBindVertexArrayARB)(GLuint array); +extern void (APIENTRY * qglDeleteVertexArraysARB)(GLsizei n, const GLuint *arrays); +extern void (APIENTRY * qglGenVertexArraysARB)(GLsizei n, GLuint *arrays); +extern GLboolean (APIENTRY * qglIsVertexArrayARB)(GLuint array); +#ifndef GL_ARB_vertex_array_object +#define GL_ARB_vertex_array_object +#define GL_VERTEX_ARRAY_BINDING_ARB 0x85B5 +#endif + + #if defined(WIN32) // WGL_ARB_create_context #ifndef WGL_ARB_create_context diff --git a/code/renderergl2/tr_animation.c b/code/renderergl2/tr_animation.c index 3c49e146..7153556d 100644 --- a/code/renderergl2/tr_animation.c +++ b/code/renderergl2/tr_animation.c @@ -412,7 +412,7 @@ void RB_MDRSurfaceAnim( mdrSurface_t *surface ) tess.xyz[baseVertex + j][1] = tempVert[1]; tess.xyz[baseVertex + j][2] = tempVert[2]; - tess.normal[baseVertex + j] = R_VboPackNormal(tempNormal); + tess.normal[baseVertex + j] = R_VaoPackNormal(tempNormal); tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; diff --git a/code/renderergl2/tr_bsp.c b/code/renderergl2/tr_bsp.c index e14fb939..cf4ddca0 100644 --- a/code/renderergl2/tr_bsp.c +++ b/code/renderergl2/tr_bsp.c @@ -1844,10 +1844,10 @@ static void CopyVert(const srfVert_t * in, srfVert_t * out) /* =============== -R_CreateWorldVBOs +R_CreateWorldVaos =============== */ -static void R_CreateWorldVBOs(void) +static void R_CreateWorldVaos(void) { int i, j, k; @@ -1861,8 +1861,7 @@ static void R_CreateWorldVBOs(void) msurface_t *surface, **firstSurf, **lastSurf, **currSurf; msurface_t **surfacesSorted; - VBO_t *vbo; - IBO_t *ibo; + vao_t *vao; int maxVboSize = 4 * 1024 * 1024; @@ -1978,7 +1977,7 @@ static void R_CreateWorldVBOs(void) { int currVboSize; - // Find range of surfaces to place in a vbo/ibo by: + // Find range of surfaces to place in a VAO by: // - Collecting a number of surfaces which fit under maxVboSize, or // - All the surfaces with a single shader which go over maxVboSize currVboSize = 0; @@ -2017,7 +2016,7 @@ static void R_CreateWorldVBOs(void) numSurfaces++; } - ri.Printf(PRINT_ALL, "...calculating world VBO %d ( %i verts %i tris )\n", k, numVerts, numIndexes / 3); + ri.Printf(PRINT_ALL, "...calculating world VAO %d ( %i verts %i tris )\n", k, numVerts, numIndexes / 3); // create arrays verts = ri.Hunk_AllocateTempMemory(numVerts * sizeof(srfVert_t)); @@ -2050,16 +2049,14 @@ static void R_CreateWorldVBOs(void) } } - vbo = R_CreateVBO2(va("staticBspModel%i_VBO", k), numVerts, verts); - ibo = R_CreateIBO2(va("staticBspModel%i_IBO", k), numIndexes, indexes); + vao = R_CreateVao2(va("staticBspModel%i_VAO", k), numVerts, verts, numIndexes, indexes); - // point bsp surfaces to VBO + // point bsp surfaces to VAO for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) { srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - bspSurf->vbo = vbo; - bspSurf->ibo = ibo; + bspSurf->vao = vao; } ri.Hunk_FreeTempMemory(indexes); @@ -2123,7 +2120,7 @@ static void R_CreateWorldVBOs(void) mergedSurf = s_worldData.mergedSurfaces; for(firstSurf = lastSurf = surfacesSorted; firstSurf < surfacesSorted + numSortedSurfaces; firstSurf = lastSurf) { - srfBspSurface_t *bspSurf, *vboSurf; + srfBspSurface_t *bspSurf, *vaoSurf; for ( lastSurf++ ; lastSurf < surfacesSorted + numSortedSurfaces; lastSurf++) { @@ -2147,35 +2144,34 @@ static void R_CreateWorldVBOs(void) bspSurf = (srfBspSurface_t *)(*firstSurf)->data; - vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low); - memset(vboSurf, 0, sizeof(*vboSurf)); - vboSurf->surfaceType = SF_VBO_MESH; + vaoSurf = ri.Hunk_Alloc(sizeof(*vaoSurf), h_low); + memset(vaoSurf, 0, sizeof(*vaoSurf)); + vaoSurf->surfaceType = SF_VAO_MESH; - vboSurf->vbo = bspSurf->vbo; - vboSurf->ibo = bspSurf->ibo; + vaoSurf->vao = bspSurf->vao; - vboSurf->firstIndex = bspSurf->firstIndex; - vboSurf->minIndex = bspSurf->minIndex; - vboSurf->maxIndex = bspSurf->maxIndex; + vaoSurf->firstIndex = bspSurf->firstIndex; + vaoSurf->minIndex = bspSurf->minIndex; + vaoSurf->maxIndex = bspSurf->maxIndex; - ClearBounds(vboSurf->cullBounds[0], vboSurf->cullBounds[1]); + ClearBounds(vaoSurf->cullBounds[0], vaoSurf->cullBounds[1]); for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) { srfBspSurface_t *currBspSurf = (srfBspSurface_t *)(*currSurf)->data; - vboSurf->numVerts += currBspSurf->numVerts; - vboSurf->numIndexes += currBspSurf->numIndexes; - vboSurf->minIndex = MIN(vboSurf->minIndex, currBspSurf->minIndex); - vboSurf->maxIndex = MAX(vboSurf->maxIndex, currBspSurf->maxIndex); - AddPointToBounds((*currSurf)->cullinfo.bounds[0], vboSurf->cullBounds[0], vboSurf->cullBounds[1]); - AddPointToBounds((*currSurf)->cullinfo.bounds[1], vboSurf->cullBounds[0], vboSurf->cullBounds[1]); + vaoSurf->numVerts += currBspSurf->numVerts; + vaoSurf->numIndexes += currBspSurf->numIndexes; + vaoSurf->minIndex = MIN(vaoSurf->minIndex, currBspSurf->minIndex); + vaoSurf->maxIndex = MAX(vaoSurf->maxIndex, currBspSurf->maxIndex); + AddPointToBounds((*currSurf)->cullinfo.bounds[0], vaoSurf->cullBounds[0], vaoSurf->cullBounds[1]); + AddPointToBounds((*currSurf)->cullinfo.bounds[1], vaoSurf->cullBounds[0], vaoSurf->cullBounds[1]); } - VectorCopy(vboSurf->cullBounds[0], mergedSurf->cullinfo.bounds[0]); - VectorCopy(vboSurf->cullBounds[1], mergedSurf->cullinfo.bounds[1]); + VectorCopy(vaoSurf->cullBounds[0], mergedSurf->cullinfo.bounds[0]); + VectorCopy(vaoSurf->cullBounds[1], mergedSurf->cullinfo.bounds[1]); mergedSurf->cullinfo.type = CULLINFO_BOX; - mergedSurf->data = (surfaceType_t *)vboSurf; + mergedSurf->data = (surfaceType_t *)vaoSurf; mergedSurf->fogIndex = (*firstSurf)->fogIndex; mergedSurf->cubemapIndex = (*firstSurf)->cubemapIndex; mergedSurf->shader = (*firstSurf)->shader; @@ -2206,7 +2202,7 @@ static void R_CreateWorldVBOs(void) ri.Free(surfacesSorted); endTime = ri.Milliseconds(); - ri.Printf(PRINT_ALL, "world VBOs calculation time = %5.2f seconds\n", (endTime - startTime) / 1000.0); + ri.Printf(PRINT_ALL, "world VAOs calculation time = %5.2f seconds\n", (endTime - startTime) / 1000.0); } /* @@ -2270,7 +2266,7 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { // Two passes, allocate surfaces first, then load them full of data - // This ensures surfaces are close together to reduce L2 cache misses when using VBOs, + // This ensures surfaces are close together to reduce L2 cache misses when using VAOs, // which don't actually use the verts and indexes in = (void *)(fileBase + surfs->fileofs); out = s_worldData.surfaces; @@ -2393,7 +2389,7 @@ static void R_LoadSubmodels( lump_t *l ) { if(i == 0) { - // Add this for limiting VBO surface creation + // Add this for limiting VAO surface creation s_worldData.numWorldSurfaces = out->numSurfaces; } } @@ -3402,17 +3398,16 @@ void RE_LoadWorldMap( const char *name ) { } } - // create static VBOS from the world - R_CreateWorldVBOs(); + // create static VAOS from the world + R_CreateWorldVaos(); s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker; // only set tr.world now that we know the entire level has loaded properly tr.world = &s_worldData; - // make sure the VBO glState entries are safe - R_BindNullVBO(); - R_BindNullIBO(); + // make sure the VAO glState entry is safe + R_BindNullVao(); // Render all cubemaps if (r_cubeMapping->integer && tr.numCubemaps) diff --git a/code/renderergl2/tr_cmds.c b/code/renderergl2/tr_cmds.c index 139a3430..34c490ee 100644 --- a/code/renderergl2/tr_cmds.c +++ b/code/renderergl2/tr_cmds.c @@ -66,8 +66,8 @@ void R_PerformanceCounters( void ) { } else if (r_speeds->integer == 7 ) { - ri.Printf( PRINT_ALL, "VBO draws: static %i dynamic %i\nMultidraws: %i merged %i\n", - backEnd.pc.c_staticVboDraws, backEnd.pc.c_dynamicVboDraws, backEnd.pc.c_multidraws, backEnd.pc.c_multidrawsMerged ); + ri.Printf( PRINT_ALL, "VAO draws: static %i dynamic %i\nMultidraws: %i merged %i\n", + backEnd.pc.c_staticVaoDraws, backEnd.pc.c_dynamicVaoDraws, backEnd.pc.c_multidraws, backEnd.pc.c_multidrawsMerged ); ri.Printf( PRINT_ALL, "GLSL binds: %i draws: gen %i light %i fog %i dlight %i\n", backEnd.pc.c_glslShaderBinds, backEnd.pc.c_genericDraws, backEnd.pc.c_lightallDraws, backEnd.pc.c_fogDraws, backEnd.pc.c_dlightDraws); } diff --git a/code/renderergl2/tr_extensions.c b/code/renderergl2/tr_extensions.c index bcf76df2..bc8bb756 100644 --- a/code/renderergl2/tr_extensions.c +++ b/code/renderergl2/tr_extensions.c @@ -178,6 +178,12 @@ void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei sa // GL_ARB_draw_buffers void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs); +// GL_ARB_vertex_array_object +void (APIENTRY * qglBindVertexArrayARB)(GLuint array); +void (APIENTRY * qglDeleteVertexArraysARB)(GLsizei n, const GLuint *arrays); +void (APIENTRY * qglGenVertexArraysARB)(GLsizei n, GLuint *arrays); +GLboolean (APIENTRY * qglIsVertexArrayARB)(GLuint array); + static qboolean GLimp_HaveExtension(const char *ext) { const char *ptr = Q_stristr( glConfig.extensions_string, ext ); @@ -682,4 +688,25 @@ void GLimp_InitExtraExtensions() // use float lightmaps? glRefConfig.floatLightmap = (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer && r_hdr->integer); + + // GL_ARB_vertex_array_object + extension = "GL_ARB_vertex_array_object"; + glRefConfig.vertexArrayObject = qfalse; + if( GLimp_HaveExtension( extension ) ) + { + qglBindVertexArrayARB = (void *) SDL_GL_GetProcAddress("glBindVertexArray"); + qglDeleteVertexArraysARB = (void *) SDL_GL_GetProcAddress("glDeleteVertexArrays"); + qglGenVertexArraysARB = (void *) SDL_GL_GetProcAddress("glGenVertexArrays"); + qglIsVertexArrayARB = (void *) SDL_GL_GetProcAddress("glIsVertexArray"); + + if (r_arb_vertex_array_object->integer) + glRefConfig.vertexArrayObject = qtrue; + + ri.Printf(PRINT_ALL, result[glRefConfig.vertexArrayObject ? 1 : 0], extension); + } + else + { + ri.Printf(PRINT_ALL, result[2], extension); + } + } diff --git a/code/renderergl2/tr_glsl.c b/code/renderergl2/tr_glsl.c index 6e8934ed..d41fb1ff 100644 --- a/code/renderergl2/tr_glsl.c +++ b/code/renderergl2/tr_glsl.c @@ -1487,50 +1487,40 @@ void GLSL_BindNullProgram(void) void GLSL_VertexAttribsState(uint32_t stateBits) { - uint32_t diff = stateBits ^ glState.vertexAttribsState; - - if (diff) + int attribIndex; + for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++) { - int attribIndex; - for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++) + uint32_t attribBit = 1 << attribIndex; + if (stateBits & attribBit) { - uint32_t attribBit = 1 << attribIndex; - if(diff & attribBit) - { - if (stateBits & attribBit) - { - qglEnableVertexAttribArrayARB(attribIndex); - } - else - { - qglDisableVertexAttribArrayARB(attribIndex); - } - } + qglEnableVertexAttribArrayARB(attribIndex); + } + else + { + qglDisableVertexAttribArrayARB(attribIndex); } } GLSL_VertexAttribPointers(stateBits); - - glState.vertexAttribsState = stateBits; } void GLSL_VertexAttribPointers(uint32_t attribBits) { int newFrame, oldFrame; - VBO_t *vbo = glState.currentVBO; + vao_t *vao = glState.currentVao; int attribIndex; uint32_t extraOffsets[ATTR_INDEX_COUNT]; - if(!vbo) + if(!vao) { - ri.Error(ERR_FATAL, "GL_VertexAttribPointers: no VBO bound"); + ri.Error(ERR_FATAL, "GL_VertexAttribPointers: no VAO bound"); return; } // don't just call LogComment, or we will get a call to va() every frame! if(r_logFile->integer) { - GLimp_LogComment(va("--- GL_VertexAttribPointers( %s ) ---\n", vbo->name)); + GLimp_LogComment(va("--- GL_VertexAttribPointers( %s ) ---\n", vao->name)); } for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++) @@ -1541,13 +1531,18 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) newFrame = glState.vertexAttribsNewFrame; if (glState.vertexAnimation) { - glState.vertexAttribPointersSet &= ~(ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TANGENT | ATTR_TANGENT2); - extraOffsets[ATTR_INDEX_POSITION] = newFrame * vbo->size_xyz; - extraOffsets[ATTR_INDEX_POSITION2] = oldFrame * vbo->size_xyz; - extraOffsets[ATTR_INDEX_NORMAL] = newFrame * vbo->size_normal; - extraOffsets[ATTR_INDEX_NORMAL2] = oldFrame * vbo->size_normal; - extraOffsets[ATTR_INDEX_TANGENT] = newFrame * vbo->size_normal; - extraOffsets[ATTR_INDEX_TANGENT2] = oldFrame * vbo->size_normal; + extraOffsets[ATTR_INDEX_POSITION] = newFrame * vao->size_xyz; + extraOffsets[ATTR_INDEX_POSITION2] = oldFrame * vao->size_xyz; + extraOffsets[ATTR_INDEX_NORMAL] = newFrame * vao->size_normal; + extraOffsets[ATTR_INDEX_NORMAL2] = oldFrame * vao->size_normal; + extraOffsets[ATTR_INDEX_TANGENT] = newFrame * vao->size_normal; + extraOffsets[ATTR_INDEX_TANGENT2] = oldFrame * vao->size_normal; + } + + // this may not be bound if we're using VAOs + if (glRefConfig.vertexArrayObject) + { + qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); } for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++) @@ -1555,13 +1550,12 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) uint32_t attribBit = 1 << attribIndex; vaoAttrib_t *vAtb; - if (!(attribBits & attribBit) || (glState.vertexAttribPointersSet & attribBit)) + if (!(attribBits & attribBit)) continue; - vAtb = &vbo->attribs[attribIndex]; + vAtb = &vao->attribs[attribIndex]; qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + extraOffsets[attribIndex])); - glState.vertexAttribPointersSet |= attribBit; } } diff --git a/code/renderergl2/tr_init.c b/code/renderergl2/tr_init.c index 8cff86ec..e3ddc75a 100644 --- a/code/renderergl2/tr_init.c +++ b/code/renderergl2/tr_init.c @@ -104,6 +104,7 @@ cvar_t *r_arb_half_float_pixel; cvar_t *r_ext_framebuffer_multisample; cvar_t *r_arb_seamless_cube_map; cvar_t *r_arb_vertex_type_2_10_10_10_rev; +cvar_t *r_arb_vertex_array_object; cvar_t *r_mergeMultidraws; cvar_t *r_mergeLeafSurfaces; @@ -944,15 +945,12 @@ void GL_SetDefaultState( void ) // glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE; - glState.vertexAttribsState = 0; - glState.vertexAttribPointersSet = 0; glState.currentProgram = 0; qglUseProgramObjectARB(0); qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - glState.currentVBO = NULL; - glState.currentIBO = NULL; + glState.currentVao = NULL; qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglDepthMask( GL_TRUE ); @@ -1136,6 +1134,7 @@ void R_Register( void ) r_ext_framebuffer_multisample = ri.Cvar_Get( "r_ext_framebuffer_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH); r_arb_seamless_cube_map = ri.Cvar_Get( "r_arb_seamless_cube_map", "0", CVAR_ARCHIVE | CVAR_LATCH); r_arb_vertex_type_2_10_10_10_rev = ri.Cvar_Get( "r_arb_vertex_type_2_10_10_10_rev", "1", CVAR_ARCHIVE | CVAR_LATCH); + r_arb_vertex_array_object = ri.Cvar_Get( "r_arb_vertex_array_object", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", "0", CVAR_ARCHIVE | CVAR_LATCH ); @@ -1442,7 +1441,7 @@ void R_Init( void ) { GLSL_InitGPUShaders(); - R_InitVBOs(); + R_InitVaos(); R_InitShaders(); @@ -1492,7 +1491,7 @@ void RE_Shutdown( qboolean destroyWindow ) { if (glRefConfig.framebufferObject) FBO_Shutdown(); R_DeleteTextures(); - R_ShutdownVBOs(); + R_ShutdownVaos(); GLSL_ShutdownGPUShaders(); } diff --git a/code/renderergl2/tr_light.c b/code/renderergl2/tr_light.c index 3d1d1f24..e95fecd0 100644 --- a/code/renderergl2/tr_light.c +++ b/code/renderergl2/tr_light.c @@ -99,7 +99,7 @@ void R_DlightBmodel( bmodel_t *bmodel ) { case SF_FACE: case SF_GRID: case SF_TRIANGLES: - case SF_VBO_MESH: + case SF_VAO_MESH: ((srfBspSurface_t *)surf->data)->dlightBits = mask; break; diff --git a/code/renderergl2/tr_local.h b/code/renderergl2/tr_local.h index a9d1043c..d2d6cb08 100644 --- a/code/renderergl2/tr_local.h +++ b/code/renderergl2/tr_local.h @@ -49,8 +49,7 @@ typedef unsigned int glIndex_t; #define MAX_FBOS 64 #define MAX_VISCOUNTS 5 -#define MAX_VBOS 4096 -#define MAX_IBOS 4096 +#define MAX_VAOS 4096 #define MAX_CALC_PSHADOWS 64 #define MAX_DRAWN_PSHADOWS 16 // do not increase past 32, because bit flags are used on surfaces @@ -101,9 +100,9 @@ typedef struct { typedef enum { - VBO_USAGE_STATIC, - VBO_USAGE_DYNAMIC -} vboUsage_t; + VAO_USAGE_STATIC, + VAO_USAGE_DYNAMIC +} vaoUsage_t; typedef struct vaoAttrib_s { @@ -116,26 +115,22 @@ typedef struct vaoAttrib_s } vaoAttrib_t; -typedef struct VBO_s +typedef struct vao_s { char name[MAX_QPATH]; + uint32_t vao; + uint32_t vertexesVBO; int vertexesSize; // amount of memory data allocated for all vertices in bytes vaoAttrib_t attribs[VAO_MAX_ATTRIBS]; uint32_t size_xyz; uint32_t size_normal; -} VBO_t; -typedef struct IBO_s -{ - char name[MAX_QPATH]; - - uint32_t indexesVBO; + uint32_t indexesIBO; int indexesSize; // amount of memory data allocated for all triangles in bytes -// uint32_t ofsIndexes; -} IBO_t; +} vao_t; //=============================================================================== @@ -859,8 +854,8 @@ typedef enum { SF_FLARE, SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity SF_DISPLAY_LIST, - SF_VBO_MESH, - SF_VBO_MDVMESH, + SF_VAO_MESH, + SF_VAO_MDVMESH, SF_NUM_SURFACE_TYPES, SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int ) @@ -923,7 +918,7 @@ typedef struct #define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0, 0}} #endif -// srfBspSurface_t covers SF_GRID, SF_TRIANGLES, SF_POLY, and SF_VBO_MESH +// srfBspSurface_t covers SF_GRID, SF_TRIANGLES, SF_POLY, and SF_VAO_MESH typedef struct srfBspSurface_s { surfaceType_t surfaceType; @@ -953,8 +948,7 @@ typedef struct srfBspSurface_s glIndex_t maxIndex; // static render data - VBO_t *vbo; - IBO_t *ibo; + vao_t *vao; // SF_GRID specific variables after here @@ -1016,7 +1010,7 @@ typedef struct srfIQModel_s { int first_triangle, num_triangles; } srfIQModel_t; -typedef struct srfVBOMDVMesh_s +typedef struct srfVaoMdvMesh_s { surfaceType_t surfaceType; @@ -1030,9 +1024,8 @@ typedef struct srfVBOMDVMesh_s glIndex_t maxIndex; // static render data - VBO_t *vbo; - IBO_t *ibo; -} srfVBOMDVMesh_t; + vao_t *vao; +} srfVaoMdvMesh_t; extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *); @@ -1256,8 +1249,8 @@ typedef struct mdvModel_s int numSurfaces; mdvSurface_t *surfaces; - int numVBOSurfaces; - srfVBOMDVMesh_t *vboSurfaces; + int numVaoSurfaces; + srfVaoMdvMesh_t *vaoSurfaces; int numSkins; } mdvModel_t; @@ -1370,16 +1363,13 @@ typedef struct { int texEnv[2]; int faceCulling; unsigned long glStateBits; - uint32_t vertexAttribsState; - uint32_t vertexAttribPointersSet; uint32_t vertexAttribsNewFrame; uint32_t vertexAttribsOldFrame; float vertexAttribsInterpolation; qboolean vertexAnimation; shaderProgram_t *currentProgram; FBO_t *currentFBO; - VBO_t *currentVBO; - IBO_t *currentIBO; + vao_t *currentVao; mat4_t modelview; mat4_t projection; mat4_t modelviewProjection; @@ -1428,6 +1418,7 @@ typedef struct { GLenum packedNormalDataType; qboolean floatLightmap; + qboolean vertexArrayObject; } glRefConfig_t; @@ -1436,13 +1427,12 @@ typedef struct { int c_surfBatches; float c_overDraw; - int c_vboVertexBuffers; - int c_vboIndexBuffers; - int c_vboVertexes; - int c_vboIndexes; + int c_vaoBinds; + int c_vaoVertexes; + int c_vaoIndexes; - int c_staticVboDraws; - int c_dynamicVboDraws; + int c_staticVaoDraws; + int c_dynamicVaoDraws; int c_multidraws; int c_multidrawsMerged; @@ -1643,11 +1633,8 @@ typedef struct { int numFBOs; FBO_t *fbos[MAX_FBOS]; - int numVBOs; - VBO_t *vbos[MAX_VBOS]; - - int numIBOs; - IBO_t *ibos[MAX_IBOS]; + int numVaos; + vao_t *vaos[MAX_VAOS]; // shader indexes from other modules will be looked up in tr.shaders[] // shader indexes from drawsurfs will be looked up in sortedShaders[] @@ -1729,6 +1716,7 @@ extern cvar_t *r_arb_half_float_pixel; extern cvar_t *r_ext_framebuffer_multisample; extern cvar_t *r_arb_seamless_cube_map; extern cvar_t *r_arb_vertex_type_2_10_10_10_rev; +extern cvar_t *r_arb_vertex_array_object; extern cvar_t *r_nobind; // turns off binding to appropriate textures extern cvar_t *r_singleShader; // make most world faces use default shader @@ -2032,9 +2020,8 @@ typedef struct shaderCommands_s //int vertexDlightBits[SHADER_MAX_VERTEXES] QALIGN(16); void *attribPointers[ATTR_INDEX_COUNT]; - VBO_t *vbo; - IBO_t *ibo; - qboolean useInternalVBO; + vao_t *vao; + qboolean useInternalVao; stageVars_t svars QALIGN(16); @@ -2074,7 +2061,7 @@ void RB_EndSurface(void); void RB_CheckOverflow( int verts, int indexes ); #define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);} -void R_DrawElementsVBO( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ); +void R_DrawElementsVao( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ); void RB_StageIteratorGeneric( void ); void RB_StageIteratorSky( void ); void RB_StageIteratorVertexLitTexture( void ); @@ -2194,28 +2181,24 @@ VERTEX BUFFER OBJECTS ============================================================ */ -uint32_t R_VboPackTangent(vec4_t v); -uint32_t R_VboPackNormal(vec3_t v); -void R_VboUnpackTangent(vec4_t v, uint32_t b); -void R_VboUnpackNormal(vec3_t v, uint32_t b); +uint32_t R_VaoPackTangent(vec4_t v); +uint32_t R_VaoPackNormal(vec3_t v); +void R_VaoUnpackTangent(vec4_t v, uint32_t b); +void R_VaoUnpackNormal(vec3_t v, uint32_t b); -VBO_t *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, vboUsage_t usage); -VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vertexes); +vao_t *R_CreateVao(const char *name, byte *vertexes, int vertexesSize, byte *indexes, int indexesSize, vaoUsage_t usage); +vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int numIndexes, glIndex_t *inIndexes); -IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, vboUsage_t usage); -IBO_t *R_CreateIBO2(const char *name, int numIndexes, glIndex_t * inIndexes); +void R_BindVao(vao_t *vao); +void R_BindNullVao(void); -void R_BindVBO(VBO_t * vbo); -void R_BindNullVBO(void); +void Vao_SetVertexPointers(vao_t *vao); -void R_BindIBO(IBO_t * ibo); -void R_BindNullIBO(void); +void R_InitVaos(void); +void R_ShutdownVaos(void); +void R_VaoList_f(void); -void R_InitVBOs(void); -void R_ShutdownVBOs(void); -void R_VBOList_f(void); - -void RB_UpdateTessVbo(unsigned int attribBits); +void RB_UpdateTessVao(unsigned int attribBits); /* diff --git a/code/renderergl2/tr_main.c b/code/renderergl2/tr_main.c index cc9c6cb8..a476586d 100644 --- a/code/renderergl2/tr_main.c +++ b/code/renderergl2/tr_main.c @@ -1575,7 +1575,7 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128 shortest = len; } - R_VboUnpackNormal(tNormal, tess.normal[tess.indexes[i]]); + R_VaoUnpackNormal(tNormal, tess.normal[tess.indexes[i]]); if ( DotProduct( normal, tNormal ) >= 0 ) { diff --git a/code/renderergl2/tr_mesh.c b/code/renderergl2/tr_mesh.c index 618958be..0d6844a4 100644 --- a/code/renderergl2/tr_mesh.c +++ b/code/renderergl2/tr_mesh.c @@ -388,9 +388,9 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { // don't add third_person objects if not viewing through a portal if(!personalModel) { - srfVBOMDVMesh_t *vboSurface = &model->vboSurfaces[i]; + srfVaoMdvMesh_t *vaoSurface = &model->vaoSurfaces[i]; - R_AddDrawSurf((void *)vboSurface, shader, fogNum, qfalse, qfalse, cubemapIndex ); + R_AddDrawSurf((void *)vaoSurface, shader, fogNum, qfalse, qfalse, cubemapIndex ); } surface++; diff --git a/code/renderergl2/tr_model.c b/code/renderergl2/tr_model.c index a9405809..eac94fe2 100644 --- a/code/renderergl2/tr_model.c +++ b/code/renderergl2/tr_model.c @@ -656,14 +656,14 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, } { - srfVBOMDVMesh_t *vboSurf; + srfVaoMdvMesh_t *vaoSurf; - mdvModel->numVBOSurfaces = mdvModel->numSurfaces; - mdvModel->vboSurfaces = ri.Hunk_Alloc(sizeof(*mdvModel->vboSurfaces) * mdvModel->numSurfaces, h_low); + mdvModel->numVaoSurfaces = mdvModel->numSurfaces; + mdvModel->vaoSurfaces = ri.Hunk_Alloc(sizeof(*mdvModel->vaoSurfaces) * mdvModel->numSurfaces, h_low); - vboSurf = mdvModel->vboSurfaces; + vaoSurf = mdvModel->vaoSurfaces; surf = mdvModel->surfaces; - for (i = 0; i < mdvModel->numSurfaces; i++, vboSurf++, surf++) + for (i = 0; i < mdvModel->numSurfaces; i++, vaoSurf++, surf++) { vec3_t *verts; vec2_t *texcoords; @@ -713,13 +713,13 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, VectorCopy(v->xyz, verts[j]); - normals[j] = R_VboPackNormal(v->normal); + normals[j] = R_VaoPackNormal(v->normal); #ifdef USE_VERT_TANGENT_SPACE CrossProduct(v->normal, v->tangent, nxt); VectorCopy(v->tangent, tangent); tangent[3] = (DotProduct(nxt, v->bitangent) < 0.0f) ? -1.0f : 1.0f; - tangents[j] = R_VboPackTangent(tangent); + tangents[j] = R_VaoPackTangent(tangent); #endif } @@ -729,76 +729,76 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, texcoords[j][1] = st->st[1]; } - vboSurf->surfaceType = SF_VBO_MDVMESH; - vboSurf->mdvModel = mdvModel; - vboSurf->mdvSurface = surf; - vboSurf->numIndexes = surf->numIndexes; - vboSurf->numVerts = surf->numVerts; + vaoSurf->surfaceType = SF_VAO_MDVMESH; + vaoSurf->mdvModel = mdvModel; + vaoSurf->mdvSurface = surf; + vaoSurf->numIndexes = surf->numIndexes; + vaoSurf->numVerts = surf->numVerts; - vboSurf->minIndex = 0; - vboSurf->maxIndex = surf->numVerts; + vaoSurf->minIndex = 0; + vaoSurf->maxIndex = surf->numVerts; - vboSurf->vbo = R_CreateVBO(va("staticMD3Mesh_VBO '%s'", surf->name), data, dataSize, VBO_USAGE_STATIC); + vaoSurf->vao = R_CreateVao(va("staticMD3Mesh_VAO '%s'", surf->name), data, dataSize, (byte *)surf->indexes, surf->numIndexes * sizeof(*surf->indexes), VAO_USAGE_STATIC); - vboSurf->vbo->attribs[ATTR_INDEX_POSITION ].enabled = 1; - vboSurf->vbo->attribs[ATTR_INDEX_POSITION2 ].enabled = 1; - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL ].enabled = 1; - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL2 ].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_POSITION ].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2 ].enabled = 1; #ifdef USE_VERT_TANGENT_SPACE - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT ].enabled = 1; - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT2 ].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ].enabled = 1; #endif - vboSurf->vbo->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1; - vboSurf->vbo->attribs[ATTR_INDEX_POSITION ].count = 3; - vboSurf->vbo->attribs[ATTR_INDEX_POSITION2 ].count = 3; - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL ].count = 4; - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL2 ].count = 4; - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT ].count = 4; - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT2 ].count = 4; - vboSurf->vbo->attribs[ATTR_INDEX_TEXCOORD ].count = 2; + vaoSurf->vao->attribs[ATTR_INDEX_POSITION ].count = 3; + vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].count = 3; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].count = 4; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2 ].count = 4; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ].count = 4; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD ].count = 2; - vboSurf->vbo->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT; - vboSurf->vbo->attribs[ATTR_INDEX_POSITION2 ].type = GL_FLOAT; - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL2 ].type = glRefConfig.packedNormalDataType; - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT2 ].type = glRefConfig.packedNormalDataType; - vboSurf->vbo->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT; + vaoSurf->vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT; + vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].type = GL_FLOAT; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2 ].type = glRefConfig.packedNormalDataType; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ].type = glRefConfig.packedNormalDataType; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT; - vboSurf->vbo->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE; - vboSurf->vbo->attribs[ATTR_INDEX_POSITION2 ].normalized = GL_FALSE; - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL2 ].normalized = GL_TRUE; - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT2 ].normalized = GL_TRUE; - vboSurf->vbo->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE; + vaoSurf->vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE; + vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].normalized = GL_FALSE; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2 ].normalized = GL_TRUE; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ].normalized = GL_TRUE; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE; - vboSurf->vbo->attribs[ATTR_INDEX_POSITION ].offset = ofs_xyz; - vboSurf->vbo->attribs[ATTR_INDEX_POSITION ].stride = sizeof(*verts); - vboSurf->vbo->attribs[ATTR_INDEX_POSITION2 ].offset = ofs_xyz; - vboSurf->vbo->attribs[ATTR_INDEX_POSITION2 ].stride = sizeof(*verts); + vaoSurf->vao->attribs[ATTR_INDEX_POSITION ].offset = ofs_xyz; + vaoSurf->vao->attribs[ATTR_INDEX_POSITION ].stride = sizeof(*verts); + vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].offset = ofs_xyz; + vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].stride = sizeof(*verts); - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL ].offset = ofs_normal; - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL ].stride = sizeof(*normals); - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL2 ].offset = ofs_normal; - vboSurf->vbo->attribs[ATTR_INDEX_NORMAL2 ].stride = sizeof(*normals); + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].offset = ofs_normal; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].stride = sizeof(*normals); + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2 ].offset = ofs_normal; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2 ].stride = sizeof(*normals); #ifdef USE_VERT_TANGENT_SPACE - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT ].offset = ofs_tangent; - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT ].stride = sizeof(*tangents); - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT2 ].offset = ofs_tangent; - vboSurf->vbo->attribs[ATTR_INDEX_TANGENT2 ].stride = sizeof(*tangents); + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].offset = ofs_tangent; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].stride = sizeof(*tangents); + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ].offset = ofs_tangent; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ].stride = sizeof(*tangents); #endif - vboSurf->vbo->attribs[ATTR_INDEX_TEXCOORD ].offset = ofs_st; - vboSurf->vbo->attribs[ATTR_INDEX_TEXCOORD ].stride = sizeof(*st); + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD ].offset = ofs_st; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD ].stride = sizeof(*st); - vboSurf->vbo->size_xyz = sizeof(*verts) * surf->numVerts; - vboSurf->vbo->size_normal = sizeof(*normals) * surf->numVerts; + vaoSurf->vao->size_xyz = sizeof(*verts) * surf->numVerts; + vaoSurf->vao->size_normal = sizeof(*normals) * surf->numVerts; + + Vao_SetVertexPointers(vaoSurf->vao); ri.Free(data); - - vboSurf->ibo = R_CreateIBO2(va("staticMD3Mesh_IBO %s", surf->name), surf->numIndexes, surf->indexes); } } diff --git a/code/renderergl2/tr_model_iqm.c b/code/renderergl2/tr_model_iqm.c index e47171e7..f0b2b388 100644 --- a/code/renderergl2/tr_model_iqm.c +++ b/code/renderergl2/tr_model_iqm.c @@ -1130,7 +1130,7 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { normal[1] = DotProduct(&nrmMat[3], &data->normals[3*vtx]); normal[2] = DotProduct(&nrmMat[6], &data->normals[3*vtx]); - *outNormal = R_VboPackNormal(normal); + *outNormal = R_VaoPackNormal(normal); #ifdef USE_VERT_TANGENT_SPACE tangent[0] = DotProduct(&nrmMat[0], &data->tangents[4*vtx]); @@ -1138,7 +1138,7 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { tangent[2] = DotProduct(&nrmMat[6], &data->tangents[4*vtx]); tangent[3] = data->tangents[4*vtx+3]; - *outTangent++ = R_VboPackTangent(tangent); + *outTangent++ = R_VaoPackTangent(tangent); #endif } diff --git a/code/renderergl2/tr_shade.c b/code/renderergl2/tr_shade.c index 79a1778d..f22310f8 100644 --- a/code/renderergl2/tr_shade.c +++ b/code/renderergl2/tr_shade.c @@ -41,7 +41,7 @@ R_DrawElements ================== */ -void R_DrawElementsVBO( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ) +void R_DrawElementsVao( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ) { if (glRefConfig.drawRangeElements) qglDrawRangeElementsEXT(GL_TRIANGLES, minIndex, maxIndex, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t))); @@ -51,7 +51,7 @@ void R_DrawElementsVBO( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex } -static void R_DrawMultiElementsVBO( int multiDrawPrimitives, glIndex_t *multiDrawMinIndex, glIndex_t *multiDrawMaxIndex, +static void R_DrawMultiElementsVao( int multiDrawPrimitives, glIndex_t *multiDrawMinIndex, glIndex_t *multiDrawMaxIndex, GLsizei *multiDrawNumIndexes, glIndex_t **multiDrawFirstIndex) { if (glRefConfig.multiDrawArrays) @@ -154,11 +154,11 @@ static void DrawTris (shaderCommands_t *input) { if (input->multiDrawPrimitives) { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); + R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); + R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); } } @@ -202,7 +202,7 @@ void RB_BeginSurface( shader_t *shader, int fogNum, int cubemapIndex ) { tess.xstages = state->stages; tess.numPasses = state->numUnfoggedPasses; tess.currentStageIteratorFunc = state->optimalStageIteratorFunc; - tess.useInternalVBO = qtrue; + tess.useInternalVao = qtrue; tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) { @@ -429,11 +429,11 @@ static void ProjectDlightTexture( void ) { if (tess.multiDrawPrimitives) { shaderCommands_t *input = &tess; - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); + R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); + R_DrawElementsVao(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); } backEnd.pc.c_totalIndexes += tess.numIndexes; @@ -873,11 +873,11 @@ static void ForwardDlight( void ) { if (input->multiDrawPrimitives) { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); + R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); + R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); } backEnd.pc.c_totalIndexes += tess.numIndexes; @@ -949,11 +949,11 @@ static void ProjectPshadowVBOGLSL( void ) { if (input->multiDrawPrimitives) { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); + R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); + R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); } backEnd.pc.c_totalIndexes += tess.numIndexes; @@ -1032,11 +1032,11 @@ static void RB_FogPass( void ) { if (tess.multiDrawPrimitives) { shaderCommands_t *input = &tess; - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); + R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); + R_DrawElementsVao(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); } } @@ -1398,11 +1398,11 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) // if (input->multiDrawPrimitives) { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); + R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); + R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); } // allow skipping out to show just lightmaps during development @@ -1462,11 +1462,11 @@ static void RB_RenderShadowmap( shaderCommands_t *input ) if (input->multiDrawPrimitives) { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); + R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); + R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); } } } @@ -1489,20 +1489,20 @@ void RB_StageIteratorGeneric( void ) return; } - if (tess.useInternalVBO) + if (tess.useInternalVao) { RB_DeformTessGeometry(); } vertexAttribs = RB_CalcShaderVertexAttribs( input ); - if (tess.useInternalVBO) + if (tess.useInternalVao) { - RB_UpdateTessVbo(vertexAttribs); + RB_UpdateTessVao(vertexAttribs); } else { - backEnd.pc.c_staticVboDraws++; + backEnd.pc.c_staticVaoDraws++; } // @@ -1543,7 +1543,10 @@ void RB_StageIteratorGeneric( void ) // // Set vertex attribs and pointers // - GLSL_VertexAttribsState(vertexAttribs); + if (tess.useInternalVao) + GLSL_VertexAttribsState(vertexAttribs); + else if (glState.vertexAnimation) + GLSL_VertexAttribPointers(vertexAttribs & (ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TANGENT | ATTR_TANGENT2)); // // render depth if in depthfill mode diff --git a/code/renderergl2/tr_shade_calc.c b/code/renderergl2/tr_shade_calc.c index 0a0cbff0..c5cc651e 100644 --- a/code/renderergl2/tr_shade_calc.c +++ b/code/renderergl2/tr_shade_calc.c @@ -125,7 +125,7 @@ void RB_CalcDeformVertexes( deformStage_t *ds ) for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) { - R_VboUnpackNormal(offset, *normal); + R_VaoUnpackNormal(offset, *normal); xyz[0] += offset[0] * scale; xyz[1] += offset[1] * scale; @@ -145,7 +145,7 @@ void RB_CalcDeformVertexes( deformStage_t *ds ) ds->deformationWave.phase + off, ds->deformationWave.frequency ); - R_VboUnpackNormal(offset, *normal); + R_VaoUnpackNormal(offset, *normal); xyz[0] += offset[0] * scale; xyz[1] += offset[1] * scale; @@ -170,7 +170,7 @@ void RB_CalcDeformNormals( deformStage_t *ds ) { for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) { vec3_t fNormal; - R_VboUnpackNormal(fNormal, *normal); + R_VaoUnpackNormal(fNormal, *normal); scale = 0.98f; scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, @@ -189,7 +189,7 @@ void RB_CalcDeformNormals( deformStage_t *ds ) { VectorNormalizeFast( fNormal ); - *normal = R_VboPackNormal(fNormal); + *normal = R_VaoPackNormal(fNormal); } } @@ -213,7 +213,7 @@ void RB_CalcBulgeVertexes( deformStage_t *ds ) { float scale; vec3_t fNormal; - R_VboUnpackNormal(fNormal, *normal); + R_VaoUnpackNormal(fNormal, *normal); off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now ); @@ -277,7 +277,7 @@ void DeformText( const char *text ) { height[1] = 0; height[2] = -1; - R_VboUnpackNormal(fNormal, tess.normal[0]); + R_VaoUnpackNormal(fNormal, tess.normal[0]); CrossProduct( fNormal, height, width ); // find the midpoint of the box diff --git a/code/renderergl2/tr_sky.c b/code/renderergl2/tr_sky.c index 1d9a97c5..ec7425eb 100644 --- a/code/renderergl2/tr_sky.c +++ b/code/renderergl2/tr_sky.c @@ -421,7 +421,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max tess.maxIndex = tess.numVertexes; // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function - RB_UpdateTessVbo(ATTR_POSITION | ATTR_TEXCOORD); + RB_UpdateTessVao(ATTR_POSITION | ATTR_TEXCOORD); /* { shaderProgram_t *sp = &tr.textureColorShader; @@ -466,7 +466,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector); } - R_DrawElementsVBO(tess.numIndexes - tess.firstIndex, tess.firstIndex, tess.minIndex, tess.maxIndex); + R_DrawElementsVao(tess.numIndexes - tess.firstIndex, tess.firstIndex, tess.minIndex, tess.maxIndex); //qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(glIndex_t))); diff --git a/code/renderergl2/tr_surface.c b/code/renderergl2/tr_surface.c index 38c4814f..8a2027a9 100644 --- a/code/renderergl2/tr_surface.c +++ b/code/renderergl2/tr_surface.c @@ -66,19 +66,18 @@ void RB_CheckOverflow( int verts, int indexes ) { RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex ); } -void RB_CheckVBOandIBO(VBO_t *vbo, IBO_t *ibo) +void RB_CheckVao(vao_t *vao) { - if (!(vbo == glState.currentVBO && ibo == glState.currentIBO) || tess.multiDrawPrimitives >= MAX_MULTIDRAW_PRIMITIVES) + if (vao != glState.currentVao || tess.multiDrawPrimitives >= MAX_MULTIDRAW_PRIMITIVES) { RB_EndSurface(); RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); - R_BindVBO(vbo); - R_BindIBO(ibo); + R_BindVao(vao); } - if (vbo != tess.vbo && ibo != tess.ibo) - tess.useInternalVBO = qfalse; + if (vao != tess.vao) + tess.useInternalVao = qfalse; } @@ -127,7 +126,7 @@ void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], tess.normal[ndx] = tess.normal[ndx+1] = tess.normal[ndx+2] = - tess.normal[ndx+3] = R_VboPackNormal(normal); + tess.normal[ndx+3] = R_VaoPackNormal(normal); // standard square texture coordinates VectorSet2(tess.texCoords[ndx ][0], s1, t1); @@ -203,11 +202,11 @@ void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4]) tess.minIndex = 0; tess.maxIndex = 3; - RB_UpdateTessVbo(ATTR_POSITION | ATTR_TEXCOORD); + RB_UpdateTessVao(ATTR_POSITION | ATTR_TEXCOORD); GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); + R_DrawElementsVao(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); tess.numIndexes = 0; tess.numVertexes = 0; @@ -325,7 +324,7 @@ static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIn glIndex_t *outIndex; float *color; - RB_CheckVBOandIBO(tess.vbo, tess.ibo); + RB_CheckVao(tess.vao); RB_CHECKOVERFLOW( numVerts, numIndexes ); @@ -349,7 +348,7 @@ static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIn dv = verts; normal = &tess.normal[ tess.numVertexes ]; for ( i = 0 ; i < numVerts ; i++, dv++, normal++ ) - *normal = R_VboPackNormal(dv->normal); + *normal = R_VaoPackNormal(dv->normal); } #ifdef USE_VERT_TANGENT_SPACE @@ -358,7 +357,7 @@ static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIn dv = verts; tangent = &tess.tangent[ tess.numVertexes ]; for ( i = 0 ; i < numVerts ; i++, dv++, tangent++ ) - *tangent = R_VboPackTangent(dv->tangent); + *tangent = R_VaoPackTangent(dv->tangent); } #endif @@ -391,7 +390,7 @@ static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIn dv = verts; lightdir = &tess.lightdir[ tess.numVertexes ]; for ( i = 0 ; i < numVerts ; i++, dv++, lightdir++ ) - *lightdir = R_VboPackNormal(dv->lightdir); + *lightdir = R_VaoPackNormal(dv->lightdir); } #if 0 // nothing even uses vertex dlightbits @@ -406,12 +405,12 @@ static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIn tess.numVertexes += numVerts; } -static qboolean RB_SurfaceVbo(VBO_t *vbo, IBO_t *ibo, int numVerts, int numIndexes, int firstIndex, int minIndex, int maxIndex, int dlightBits, int pshadowBits, qboolean shaderCheck) +static qboolean RB_SurfaceVao(vao_t *vao, int numVerts, int numIndexes, int firstIndex, int minIndex, int maxIndex, int dlightBits, int pshadowBits, qboolean shaderCheck) { int i, mergeForward, mergeBack; GLvoid *firstIndexOffset, *lastIndexOffset; - if (!vbo || !ibo) + if (!vao) { return qfalse; } @@ -421,7 +420,7 @@ static qboolean RB_SurfaceVbo(VBO_t *vbo, IBO_t *ibo, int numVerts, int numIndex return qfalse; } - RB_CheckVBOandIBO(vbo, ibo); + RB_CheckVao(vao); tess.dlightBits |= dlightBits; tess.pshadowBits |= pshadowBits; @@ -515,7 +514,7 @@ RB_SurfaceTriangles ============= */ static void RB_SurfaceTriangles( srfBspSurface_t *srf ) { - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, + if( RB_SurfaceVao (srf->vao, srf->numVerts, srf->numIndexes, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) { return; @@ -601,7 +600,7 @@ static void RB_SurfaceBeam( void ) tess.maxIndex = tess.numVertexes; // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function - RB_UpdateTessVbo(ATTR_POSITION); + RB_UpdateTessVao(ATTR_POSITION); GLSL_VertexAttribsState(ATTR_POSITION); GLSL_BindProgram(sp); @@ -610,7 +609,7 @@ static void RB_SurfaceBeam( void ) GLSL_SetUniformVec4(sp, UNIFORM_COLOR, colorRed); - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); + R_DrawElementsVao(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); tess.numIndexes = 0; tess.numVertexes = 0; @@ -1150,7 +1149,7 @@ static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp) VectorCopy(newVerts->xyz, outXyz); VectorCopy(newVerts->normal, normal); - *outNormal = R_VboPackNormal(normal); + *outNormal = R_VaoPackNormal(normal); newVerts++; outXyz += 4; @@ -1175,7 +1174,7 @@ static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp) VectorLerp(newVerts->normal, oldVerts->normal, backlerp, normal); VectorNormalize(normal); - *outNormal = R_VboPackNormal(normal); + *outNormal = R_VaoPackNormal(normal); newVerts++; oldVerts++; @@ -1250,7 +1249,7 @@ RB_SurfaceFace ============== */ static void RB_SurfaceFace( srfBspSurface_t *srf ) { - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, + if( RB_SurfaceVao (srf->vao, srf->numVerts, srf->numIndexes, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) { return; @@ -1320,7 +1319,7 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) { int pshadowBits; //int *vDlightBits; - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, + if( RB_SurfaceVao (srf->vao, srf->numVerts, srf->numIndexes, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) { return; @@ -1413,13 +1412,13 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) { if ( tess.shader->vertexAttribs & ATTR_NORMAL ) { - *normal++ = R_VboPackNormal(dv->normal); + *normal++ = R_VaoPackNormal(dv->normal); } #ifdef USE_VERT_TANGENT_SPACE if ( tess.shader->vertexAttribs & ATTR_TANGENT ) { - *tangent++ = R_VboPackTangent(dv->tangent); + *tangent++ = R_VaoPackTangent(dv->tangent); } #endif if ( tess.shader->vertexAttribs & ATTR_TEXCOORD ) @@ -1442,7 +1441,7 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) { if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION ) { - *lightdir++ = R_VboPackNormal(dv->lightdir); + *lightdir++ = R_VaoPackNormal(dv->lightdir); } //*vDlightBits++ = dlightBits; @@ -1567,31 +1566,30 @@ static void RB_SurfaceFlare(srfFlare_t *surf) RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal); } -static void RB_SurfaceVBOMesh(srfBspSurface_t * srf) +static void RB_SurfaceVaoMesh(srfBspSurface_t * srf) { - RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, srf->firstIndex, + RB_SurfaceVao (srf->vao, srf->numVerts, srf->numIndexes, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qfalse ); } -void RB_SurfaceVBOMDVMesh(srfVBOMDVMesh_t * surface) +void RB_SurfaceVaoMdvMesh(srfVaoMdvMesh_t * surface) { //mdvModel_t *mdvModel; //mdvSurface_t *mdvSurface; refEntity_t *refEnt; - GLimp_LogComment("--- RB_SurfaceVBOMDVMesh ---\n"); + GLimp_LogComment("--- RB_SurfaceVaoMdvMesh ---\n"); - if(!surface->vbo || !surface->ibo) + if(!surface->vao) return; - //RB_CheckVBOandIBO(surface->vbo, surface->ibo); + //RB_CheckVao(surface->vao); RB_EndSurface(); RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); - R_BindVBO(surface->vbo); - R_BindIBO(surface->ibo); + R_BindVao(surface->vao); - tess.useInternalVBO = qfalse; + tess.useInternalVao = qfalse; tess.numIndexes += surface->numIndexes; tess.numVertexes += surface->numVerts; @@ -1645,6 +1643,6 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY (void(*)(void*))RB_SurfaceDisplayList, // SF_DISPLAY_LIST - (void(*)(void*))RB_SurfaceVBOMesh, // SF_VBO_MESH, - (void(*)(void*))RB_SurfaceVBOMDVMesh, // SF_VBO_MDVMESH + (void(*)(void*))RB_SurfaceVaoMesh, // SF_VAO_MESH, + (void(*)(void*))RB_SurfaceVaoMdvMesh, // SF_VAO_MDVMESH }; diff --git a/code/renderergl2/tr_vbo.c b/code/renderergl2/tr_vbo.c index cb140921..31659f96 100644 --- a/code/renderergl2/tr_vbo.c +++ b/code/renderergl2/tr_vbo.c @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" -uint32_t R_VboPackTangent(vec4_t v) +uint32_t R_VaoPackTangent(vec4_t v) { if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) { @@ -41,7 +41,7 @@ uint32_t R_VboPackTangent(vec4_t v) } } -uint32_t R_VboPackNormal(vec3_t v) +uint32_t R_VaoPackNormal(vec3_t v) { if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) { @@ -57,7 +57,7 @@ uint32_t R_VboPackNormal(vec3_t v) } } -void R_VboUnpackTangent(vec4_t v, uint32_t b) +void R_VaoUnpackTangent(vec4_t v, uint32_t b) { if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) { @@ -75,7 +75,7 @@ void R_VboUnpackTangent(vec4_t v, uint32_t b) } } -void R_VboUnpackNormal(vec3_t v, uint32_t b) +void R_VaoUnpackNormal(vec3_t v, uint32_t b) { if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) { @@ -91,73 +91,113 @@ void R_VboUnpackNormal(vec3_t v, uint32_t b) } } + +void Vao_SetVertexPointers(vao_t *vao) +{ + int i; + + // set vertex pointers + for (i = 0; i < ATTR_INDEX_COUNT; i++) + { + if (vao->attribs[i].enabled) + { + qglVertexAttribPointerARB((GLuint)i, + (GLint)vao->attribs[i].count, + (GLenum)vao->attribs[i].type, + (GLboolean)vao->attribs[i].normalized, + (GLsizei)vao->attribs[i].stride, + BUFFER_OFFSET(vao->attribs[i].offset)); + qglEnableVertexAttribArrayARB(i); + } + else + { + qglDisableVertexAttribArrayARB(i); + } + } +} + /* ============ -R_CreateVBO +R_CreateVao ============ */ -VBO_t *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, vboUsage_t usage) +vao_t *R_CreateVao(const char *name, byte *vertexes, int vertexesSize, byte *indexes, int indexesSize, vaoUsage_t usage) { - VBO_t *vbo; + vao_t *vao; int glUsage; switch (usage) { - case VBO_USAGE_STATIC: + case VAO_USAGE_STATIC: glUsage = GL_STATIC_DRAW_ARB; break; - case VBO_USAGE_DYNAMIC: + case VAO_USAGE_DYNAMIC: glUsage = GL_DYNAMIC_DRAW_ARB; break; default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); + Com_Error(ERR_FATAL, "bad vaoUsage_t given: %i", usage); return NULL; } if(strlen(name) >= MAX_QPATH) { - ri.Error(ERR_DROP, "R_CreateVBO: \"%s\" is too long", name); + ri.Error(ERR_DROP, "R_CreateVao: \"%s\" is too long", name); } - if ( tr.numVBOs == MAX_VBOS ) { - ri.Error( ERR_DROP, "R_CreateVBO: MAX_VBOS hit"); + if ( tr.numVaos == MAX_VAOS ) { + ri.Error( ERR_DROP, "R_CreateVao: MAX_VAOS hit"); } R_IssuePendingRenderCommands(); - vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); - tr.numVBOs++; + vao = tr.vaos[tr.numVaos] = ri.Hunk_Alloc(sizeof(*vao), h_low); + tr.numVaos++; - memset(vbo, 0, sizeof(*vbo)); + memset(vao, 0, sizeof(*vao)); - Q_strncpyz(vbo->name, name, sizeof(vbo->name)); + Q_strncpyz(vao->name, name, sizeof(vao->name)); - vbo->vertexesSize = vertexesSize; - qglGenBuffersARB(1, &vbo->vertexesVBO); + if (glRefConfig.vertexArrayObject) + { + qglGenVertexArraysARB(1, &vao->vao); + qglBindVertexArrayARB(vao->vao); + } - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); + + vao->vertexesSize = vertexesSize; + + qglGenBuffersARB(1, &vao->vertexesVBO); + + qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexesSize, vertexes, glUsage); - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glState.currentVBO = NULL; + vao->indexesSize = indexesSize; + + qglGenBuffersARB(1, &vao->indexesIBO); + + qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesIBO); + qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); + + + glState.currentVao = vao; GL_CheckErrors(); - return vbo; + return vao; } /* ============ -R_CreateVBO2 +R_CreateVao2 ============ */ -VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * verts) +vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int numIndexes, glIndex_t *indexes) { - VBO_t *vbo; + vao_t *vao; int i; byte *data; @@ -166,79 +206,87 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert int glUsage = GL_STATIC_DRAW_ARB; - if(!numVertexes) + if(!numVertexes || !numIndexes) return NULL; if(strlen(name) >= MAX_QPATH) { - ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long", name); + ri.Error(ERR_DROP, "R_CreateVao2: \"%s\" is too long", name); } - if ( tr.numVBOs == MAX_VBOS ) { - ri.Error( ERR_DROP, "R_CreateVBO2: MAX_VBOS hit"); + if ( tr.numVaos == MAX_VAOS ) { + ri.Error( ERR_DROP, "R_CreateVao2: MAX_VAOS hit"); } R_IssuePendingRenderCommands(); - vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); - tr.numVBOs++; + vao = tr.vaos[tr.numVaos] = ri.Hunk_Alloc(sizeof(*vao), h_low); + tr.numVaos++; - memset(vbo, 0, sizeof(*vbo)); + memset(vao, 0, sizeof(*vao)); - Q_strncpyz(vbo->name, name, sizeof(vbo->name)); + Q_strncpyz(vao->name, name, sizeof(vao->name)); // since these vertex attributes are never altered, interleave them - vbo->attribs[ATTR_INDEX_POSITION ].enabled = 1; - vbo->attribs[ATTR_INDEX_NORMAL ].enabled = 1; + vao->attribs[ATTR_INDEX_POSITION ].enabled = 1; + vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1; #ifdef USE_VERT_TANGENT_SPACE - vbo->attribs[ATTR_INDEX_TANGENT ].enabled = 1; + vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1; #endif - vbo->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1; - vbo->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1; - vbo->attribs[ATTR_INDEX_COLOR ].enabled = 1; - vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].enabled = 1; + vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1; + vao->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1; + vao->attribs[ATTR_INDEX_COLOR ].enabled = 1; + vao->attribs[ATTR_INDEX_LIGHTDIRECTION].enabled = 1; - vbo->attribs[ATTR_INDEX_POSITION ].count = 3; - vbo->attribs[ATTR_INDEX_NORMAL ].count = 4; - vbo->attribs[ATTR_INDEX_TANGENT ].count = 4; - vbo->attribs[ATTR_INDEX_TEXCOORD ].count = 2; - vbo->attribs[ATTR_INDEX_LIGHTCOORD ].count = 2; - vbo->attribs[ATTR_INDEX_COLOR ].count = 4; - vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4; + vao->attribs[ATTR_INDEX_POSITION ].count = 3; + vao->attribs[ATTR_INDEX_NORMAL ].count = 4; + vao->attribs[ATTR_INDEX_TANGENT ].count = 4; + vao->attribs[ATTR_INDEX_TEXCOORD ].count = 2; + vao->attribs[ATTR_INDEX_LIGHTCOORD ].count = 2; + vao->attribs[ATTR_INDEX_COLOR ].count = 4; + vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4; - vbo->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT; - vbo->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; - vbo->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; - vbo->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT; - vbo->attribs[ATTR_INDEX_LIGHTCOORD ].type = GL_FLOAT; - vbo->attribs[ATTR_INDEX_COLOR ].type = GL_FLOAT; - vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].type = glRefConfig.packedNormalDataType; + vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT; + vao->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; + vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; + vao->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT; + vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = GL_FLOAT; + vao->attribs[ATTR_INDEX_COLOR ].type = GL_FLOAT; + vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = glRefConfig.packedNormalDataType; - vbo->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE; - vbo->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; - vbo->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; - vbo->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE; - vbo->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE; - vbo->attribs[ATTR_INDEX_COLOR ].normalized = GL_FALSE; - vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; + vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE; + vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; + vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; + vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE; + vao->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE; + vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_FALSE; + vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; - vbo->attribs[ATTR_INDEX_POSITION ].offset = 0; dataSize = sizeof(verts[0].xyz); - vbo->attribs[ATTR_INDEX_NORMAL ].offset = dataSize; dataSize += sizeof(uint32_t); + vao->attribs[ATTR_INDEX_POSITION ].offset = 0; dataSize = sizeof(verts[0].xyz); + vao->attribs[ATTR_INDEX_NORMAL ].offset = dataSize; dataSize += sizeof(uint32_t); #ifdef USE_VERT_TANGENT_SPACE - vbo->attribs[ATTR_INDEX_TANGENT ].offset = dataSize; dataSize += sizeof(uint32_t); + vao->attribs[ATTR_INDEX_TANGENT ].offset = dataSize; dataSize += sizeof(uint32_t); #endif - vbo->attribs[ATTR_INDEX_TEXCOORD ].offset = dataSize; dataSize += sizeof(verts[0].st); - vbo->attribs[ATTR_INDEX_LIGHTCOORD ].offset = dataSize; dataSize += sizeof(verts[0].lightmap); - vbo->attribs[ATTR_INDEX_COLOR ].offset = dataSize; dataSize += sizeof(verts[0].vertexColors); - vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(uint32_t); + vao->attribs[ATTR_INDEX_TEXCOORD ].offset = dataSize; dataSize += sizeof(verts[0].st); + vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = dataSize; dataSize += sizeof(verts[0].lightmap); + vao->attribs[ATTR_INDEX_COLOR ].offset = dataSize; dataSize += sizeof(verts[0].vertexColors); + vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(uint32_t); + + vao->attribs[ATTR_INDEX_POSITION ].stride = dataSize; + vao->attribs[ATTR_INDEX_NORMAL ].stride = dataSize; + vao->attribs[ATTR_INDEX_TANGENT ].stride = dataSize; + vao->attribs[ATTR_INDEX_TEXCOORD ].stride = dataSize; + vao->attribs[ATTR_INDEX_LIGHTCOORD ].stride = dataSize; + vao->attribs[ATTR_INDEX_COLOR ].stride = dataSize; + vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = dataSize; + + + if (glRefConfig.vertexArrayObject) + { + qglGenVertexArraysARB(1, &vao->vao); + qglBindVertexArrayARB(vao->vao); + } - vbo->attribs[ATTR_INDEX_POSITION ].stride = dataSize; - vbo->attribs[ATTR_INDEX_NORMAL ].stride = dataSize; - vbo->attribs[ATTR_INDEX_TANGENT ].stride = dataSize; - vbo->attribs[ATTR_INDEX_TEXCOORD ].stride = dataSize; - vbo->attribs[ATTR_INDEX_LIGHTCOORD ].stride = dataSize; - vbo->attribs[ATTR_INDEX_COLOR ].stride = dataSize; - vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = dataSize; // create VBO dataSize *= numVertexes; @@ -255,13 +303,13 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert // normal p = (uint32_t *)(data + dataOfs); - *p = R_VboPackNormal(verts[i].normal); + *p = R_VaoPackNormal(verts[i].normal); dataOfs += sizeof(uint32_t); #ifdef USE_VERT_TANGENT_SPACE // tangent p = (uint32_t *)(data + dataOfs); - *p = R_VboPackTangent(verts[i].tangent); + *p = R_VaoPackTangent(verts[i].tangent); dataOfs += sizeof(uint32_t); #endif @@ -279,334 +327,205 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert // feed vertex light directions p = (uint32_t *)(data + dataOfs); - *p = R_VboPackNormal(verts[i].lightdir); + *p = R_VaoPackNormal(verts[i].lightdir); dataOfs += sizeof(uint32_t); } - vbo->vertexesSize = dataSize; + vao->vertexesSize = dataSize; - qglGenBuffersARB(1, &vbo->vertexesVBO); + qglGenBuffersARB(1, &vao->vertexesVBO); - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, glUsage); + qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); + qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vao->vertexesSize, data, glUsage); - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glState.currentVBO = NULL; + // create IBO + vao->indexesSize = numIndexes * sizeof(glIndex_t); + + qglGenBuffersARB(1, &vao->indexesIBO); + + qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesIBO); + qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesSize, indexes, glUsage); + + + Vao_SetVertexPointers(vao); + + + glState.currentVao = vao; GL_CheckErrors(); ri.Hunk_FreeTempMemory(data); - return vbo; + return vao; } /* ============ -R_CreateIBO +R_BindVao ============ */ -IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, vboUsage_t usage) +void R_BindVao(vao_t * vao) { - IBO_t *ibo; - int glUsage; - - switch (usage) + if(!vao) { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateIBO: \"%s\" is too long", name); - } - - if ( tr.numIBOs == MAX_IBOS ) { - ri.Error( ERR_DROP, "R_CreateIBO: MAX_IBOS hit"); - } - - R_IssuePendingRenderCommands(); - - ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); - tr.numIBOs++; - - Q_strncpyz(ibo->name, name, sizeof(ibo->name)); - - ibo->indexesSize = indexesSize; - - qglGenBuffersARB(1, &ibo->indexesVBO); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - - glState.currentIBO = NULL; - - GL_CheckErrors(); - - return ibo; -} - -/* -============ -R_CreateIBO2 -============ -*/ -IBO_t *R_CreateIBO2(const char *name, int numIndexes, glIndex_t * inIndexes) -{ - IBO_t *ibo; - int i; - - glIndex_t *indexes; - int indexesSize; - - int glUsage = GL_STATIC_DRAW_ARB; - - if(!numIndexes) - return NULL; - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateIBO2: \"%s\" is too long", name); - } - - if ( tr.numIBOs == MAX_IBOS ) { - ri.Error( ERR_DROP, "R_CreateIBO2: MAX_IBOS hit"); - } - - R_IssuePendingRenderCommands(); - - ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); - tr.numIBOs++; - - Q_strncpyz(ibo->name, name, sizeof(ibo->name)); - - indexesSize = numIndexes * sizeof(glIndex_t); - indexes = ri.Hunk_AllocateTempMemory(indexesSize); - - for(i = 0; i < numIndexes; i++) - { - indexes[i] = inIndexes[i]; - } - - ibo->indexesSize = indexesSize; - - qglGenBuffersARB(1, &ibo->indexesVBO); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - - glState.currentIBO = NULL; - - GL_CheckErrors(); - - ri.Hunk_FreeTempMemory(indexes); - - return ibo; -} - -/* -============ -R_BindVBO -============ -*/ -void R_BindVBO(VBO_t * vbo) -{ - if(!vbo) - { - //R_BindNullVBO(); - ri.Error(ERR_DROP, "R_BindNullVBO: NULL vbo"); + //R_BindNullVao(); + ri.Error(ERR_DROP, "R_BindVao: NULL vao"); return; } if(r_logFile->integer) { // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- R_BindVBO( %s ) ---\n", vbo->name)); + GLimp_LogComment(va("--- R_BindVao( %s ) ---\n", vao->name)); } - if(glState.currentVBO != vbo) + if(glState.currentVao != vao) { - glState.currentVBO = vbo; - glState.vertexAttribPointersSet = 0; + glState.currentVao = vao; glState.vertexAttribsInterpolation = 0; glState.vertexAttribsOldFrame = 0; glState.vertexAttribsNewFrame = 0; glState.vertexAnimation = qfalse; + backEnd.pc.c_vaoBinds++; - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); + if (glRefConfig.vertexArrayObject) + { + qglBindVertexArrayARB(vao->vao); - backEnd.pc.c_vboVertexBuffers++; + // why you no save GL_ELEMENT_ARRAY_BUFFER binding, Intel? + if (1) + qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); + } + else + { + qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); + qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesIBO); + + if (vao != tess.vao) + Vao_SetVertexPointers(vao); + } } } /* ============ -R_BindNullVBO +R_BindNullVao ============ */ -void R_BindNullVBO(void) +void R_BindNullVao(void) { - GLimp_LogComment("--- R_BindNullVBO ---\n"); + GLimp_LogComment("--- R_BindNullVao ---\n"); - if(glState.currentVBO) + if(glState.currentVao) { - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glState.currentVBO = NULL; + if (glRefConfig.vertexArrayObject) + { + qglBindVertexArrayARB(0); + + // why you no save GL_ELEMENT_ARRAY_BUFFER binding, Intel? + if (1) qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + } + else + { + qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + } + glState.currentVao = NULL; } GL_CheckErrors(); } -/* -============ -R_BindIBO -============ -*/ -void R_BindIBO(IBO_t * ibo) -{ - if(!ibo) - { - //R_BindNullIBO(); - ri.Error(ERR_DROP, "R_BindIBO: NULL ibo"); - return; - } - - if(r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- R_BindIBO( %s ) ---\n", ibo->name)); - } - - if(glState.currentIBO != ibo) - { - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - - glState.currentIBO = ibo; - - backEnd.pc.c_vboIndexBuffers++; - } -} /* ============ -R_BindNullIBO +R_InitVaos ============ */ -void R_BindNullIBO(void) +void R_InitVaos(void) { - GLimp_LogComment("--- R_BindNullIBO ---\n"); - - if(glState.currentIBO) - { - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - glState.currentIBO = NULL; - glState.vertexAttribPointersSet = 0; - } -} - -/* -============ -R_InitVBOs -============ -*/ -void R_InitVBOs(void) -{ - int dataSize; + int vertexesSize, indexesSize; int offset; - ri.Printf(PRINT_ALL, "------- R_InitVBOs -------\n"); + ri.Printf(PRINT_ALL, "------- R_InitVaos -------\n"); - tr.numVBOs = 0; - tr.numIBOs = 0; + tr.numVaos = 0; - dataSize = sizeof(tess.xyz[0]); - dataSize += sizeof(tess.normal[0]); + vertexesSize = sizeof(tess.xyz[0]); + vertexesSize += sizeof(tess.normal[0]); #ifdef USE_VERT_TANGENT_SPACE - dataSize += sizeof(tess.tangent[0]); + vertexesSize += sizeof(tess.tangent[0]); #endif - dataSize += sizeof(tess.vertexColors[0]); - dataSize += sizeof(tess.texCoords[0][0]) * 2; - dataSize += sizeof(tess.lightdir[0]); - dataSize *= SHADER_MAX_VERTEXES; + vertexesSize += sizeof(tess.vertexColors[0]); + vertexesSize += sizeof(tess.texCoords[0][0]) * 2; + vertexesSize += sizeof(tess.lightdir[0]); + vertexesSize *= SHADER_MAX_VERTEXES; - tess.vbo = R_CreateVBO("tessVertexArray_VBO", NULL, dataSize, VBO_USAGE_DYNAMIC); + indexesSize = sizeof(tess.indexes[0]) * SHADER_MAX_INDEXES; + + tess.vao = R_CreateVao("tessVertexArray_VAO", NULL, vertexesSize, NULL, indexesSize, VAO_USAGE_DYNAMIC); offset = 0; - tess.vbo->attribs[ATTR_INDEX_POSITION ].enabled = 1; - tess.vbo->attribs[ATTR_INDEX_NORMAL ].enabled = 1; + tess.vao->attribs[ATTR_INDEX_POSITION ].enabled = 1; + tess.vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1; #ifdef USE_VERT_TANGENT_SPACE - tess.vbo->attribs[ATTR_INDEX_TANGENT ].enabled = 1; + tess.vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1; #endif - tess.vbo->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1; - tess.vbo->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1; - tess.vbo->attribs[ATTR_INDEX_COLOR ].enabled = 1; - tess.vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].enabled = 1; + tess.vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1; + tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1; + tess.vao->attribs[ATTR_INDEX_COLOR ].enabled = 1; + tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].enabled = 1; - tess.vbo->attribs[ATTR_INDEX_POSITION ].count = 3; - tess.vbo->attribs[ATTR_INDEX_NORMAL ].count = 4; - tess.vbo->attribs[ATTR_INDEX_TANGENT ].count = 4; - tess.vbo->attribs[ATTR_INDEX_TEXCOORD ].count = 2; - tess.vbo->attribs[ATTR_INDEX_LIGHTCOORD ].count = 2; - tess.vbo->attribs[ATTR_INDEX_COLOR ].count = 4; - tess.vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4; + tess.vao->attribs[ATTR_INDEX_POSITION ].count = 3; + tess.vao->attribs[ATTR_INDEX_NORMAL ].count = 4; + tess.vao->attribs[ATTR_INDEX_TANGENT ].count = 4; + tess.vao->attribs[ATTR_INDEX_TEXCOORD ].count = 2; + tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].count = 2; + tess.vao->attribs[ATTR_INDEX_COLOR ].count = 4; + tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4; - tess.vbo->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT; - tess.vbo->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; - tess.vbo->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; - tess.vbo->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT; - tess.vbo->attribs[ATTR_INDEX_LIGHTCOORD ].type = GL_FLOAT; - tess.vbo->attribs[ATTR_INDEX_COLOR ].type = GL_FLOAT; - tess.vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].type = glRefConfig.packedNormalDataType; + tess.vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT; + tess.vao->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; + tess.vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; + tess.vao->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT; + tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = GL_FLOAT; + tess.vao->attribs[ATTR_INDEX_COLOR ].type = GL_FLOAT; + tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = glRefConfig.packedNormalDataType; - tess.vbo->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE; - tess.vbo->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; - tess.vbo->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; - tess.vbo->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE; - tess.vbo->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE; - tess.vbo->attribs[ATTR_INDEX_COLOR ].normalized = GL_FALSE; - tess.vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; + tess.vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE; + tess.vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; + tess.vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; + tess.vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE; + tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE; + tess.vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_FALSE; + tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; - tess.vbo->attribs[ATTR_INDEX_POSITION ].offset = offset; offset += sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES; - tess.vbo->attribs[ATTR_INDEX_NORMAL ].offset = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES; + tess.vao->attribs[ATTR_INDEX_POSITION ].offset = offset; offset += sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES; + tess.vao->attribs[ATTR_INDEX_NORMAL ].offset = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES; #ifdef USE_VERT_TANGENT_SPACE - tess.vbo->attribs[ATTR_INDEX_TANGENT ].offset = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES; + tess.vao->attribs[ATTR_INDEX_TANGENT ].offset = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES; #endif // these next two are actually interleaved - tess.vbo->attribs[ATTR_INDEX_TEXCOORD ].offset = offset; - tess.vbo->attribs[ATTR_INDEX_LIGHTCOORD ].offset = offset + sizeof(tess.texCoords[0][0]); + tess.vao->attribs[ATTR_INDEX_TEXCOORD ].offset = offset; + tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = offset + sizeof(tess.texCoords[0][0]); offset += sizeof(tess.texCoords[0][0]) * 2 * SHADER_MAX_VERTEXES; - tess.vbo->attribs[ATTR_INDEX_COLOR ].offset = offset; offset += sizeof(tess.vertexColors[0]) * SHADER_MAX_VERTEXES; - tess.vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = offset; + tess.vao->attribs[ATTR_INDEX_COLOR ].offset = offset; offset += sizeof(tess.vertexColors[0]) * SHADER_MAX_VERTEXES; + tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = offset; - tess.vbo->attribs[ATTR_INDEX_POSITION ].stride = sizeof(tess.xyz[0]); - tess.vbo->attribs[ATTR_INDEX_NORMAL ].stride = sizeof(tess.normal[0]); + tess.vao->attribs[ATTR_INDEX_POSITION ].stride = sizeof(tess.xyz[0]); + tess.vao->attribs[ATTR_INDEX_NORMAL ].stride = sizeof(tess.normal[0]); #ifdef USE_VERT_TANGENT_SPACE - tess.vbo->attribs[ATTR_INDEX_TANGENT ].stride = sizeof(tess.tangent[0]); + tess.vao->attribs[ATTR_INDEX_TANGENT ].stride = sizeof(tess.tangent[0]); #endif - tess.vbo->attribs[ATTR_INDEX_COLOR ].stride = sizeof(tess.vertexColors[0]); - tess.vbo->attribs[ATTR_INDEX_TEXCOORD ].stride = sizeof(tess.texCoords[0][0]) * 2; - tess.vbo->attribs[ATTR_INDEX_LIGHTCOORD ].stride = sizeof(tess.texCoords[0][0]) * 2; - tess.vbo->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = sizeof(tess.lightdir[0]); - - dataSize = sizeof(tess.indexes[0]) * SHADER_MAX_INDEXES; + tess.vao->attribs[ATTR_INDEX_COLOR ].stride = sizeof(tess.vertexColors[0]); + tess.vao->attribs[ATTR_INDEX_TEXCOORD ].stride = sizeof(tess.texCoords[0][0]) * 2; + tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].stride = sizeof(tess.texCoords[0][0]) * 2; + tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = sizeof(tess.lightdir[0]); tess.attribPointers[ATTR_INDEX_POSITION] = tess.xyz; tess.attribPointers[ATTR_INDEX_TEXCOORD] = tess.texCoords; @@ -617,100 +536,86 @@ void R_InitVBOs(void) tess.attribPointers[ATTR_INDEX_COLOR] = tess.vertexColors; tess.attribPointers[ATTR_INDEX_LIGHTDIRECTION] = tess.lightdir; - tess.ibo = R_CreateIBO("tessVertexArray_IBO", NULL, dataSize, VBO_USAGE_DYNAMIC); + Vao_SetVertexPointers(tess.vao); - R_BindNullVBO(); - R_BindNullIBO(); + R_BindNullVao(); GL_CheckErrors(); } /* ============ -R_ShutdownVBOs +R_ShutdownVaos ============ */ -void R_ShutdownVBOs(void) +void R_ShutdownVaos(void) { int i; - VBO_t *vbo; - IBO_t *ibo; + vao_t *vao; - ri.Printf(PRINT_ALL, "------- R_ShutdownVBOs -------\n"); + ri.Printf(PRINT_ALL, "------- R_ShutdownVaos -------\n"); - R_BindNullVBO(); - R_BindNullIBO(); + R_BindNullVao(); - - for(i = 0; i < tr.numVBOs; i++) + for(i = 0; i < tr.numVaos; i++) { - vbo = tr.vbos[i]; + vao = tr.vaos[i]; - if(vbo->vertexesVBO) + if(vao->vao) + qglDeleteVertexArraysARB(1, &vao->vao); + + if(vao->vertexesVBO) { - qglDeleteBuffersARB(1, &vbo->vertexesVBO); + qglDeleteBuffersARB(1, &vao->vertexesVBO); } - //ri.Free(vbo); - } - - for(i = 0; i < tr.numIBOs; i++) - { - ibo = tr.ibos[i]; - - if(ibo->indexesVBO) + if(vao->indexesIBO) { - qglDeleteBuffersARB(1, &ibo->indexesVBO); + qglDeleteBuffersARB(1, &vao->indexesIBO); } - - //ri.Free(ibo); } - tr.numVBOs = 0; - tr.numIBOs = 0; + tr.numVaos = 0; } /* ============ -R_VBOList_f +R_VaoList_f ============ */ -void R_VBOList_f(void) +void R_VaoList_f(void) { int i; - VBO_t *vbo; - IBO_t *ibo; + vao_t *vao; int vertexesSize = 0; int indexesSize = 0; ri.Printf(PRINT_ALL, " size name\n"); ri.Printf(PRINT_ALL, "----------------------------------------------------------\n"); - for(i = 0; i < tr.numVBOs; i++) + for(i = 0; i < tr.numVaos; i++) { - vbo = tr.vbos[i]; + vao = tr.vaos[i]; - ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vbo->vertexesSize / (1024 * 1024), - (vbo->vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vbo->name); + ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vao->vertexesSize / (1024 * 1024), + (vao->vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vao->name); - vertexesSize += vbo->vertexesSize; + vertexesSize += vao->vertexesSize; } - for(i = 0; i < tr.numIBOs; i++) + for(i = 0; i < tr.numVaos; i++) { - ibo = tr.ibos[i]; + vao = tr.vaos[i]; - ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", ibo->indexesSize / (1024 * 1024), - (ibo->indexesSize % (1024 * 1024)) * 100 / (1024 * 1024), ibo->name); + ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vao->indexesSize / (1024 * 1024), + (vao->indexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vao->name); - indexesSize += ibo->indexesSize; + indexesSize += vao->indexesSize; } - ri.Printf(PRINT_ALL, " %i total VBOs\n", tr.numVBOs); + ri.Printf(PRINT_ALL, " %i total VAOs\n", tr.numVaos); ri.Printf(PRINT_ALL, " %d.%02d MB total vertices memory\n", vertexesSize / (1024 * 1024), (vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024)); - - ri.Printf(PRINT_ALL, " %i total IBOs\n", tr.numIBOs); ri.Printf(PRINT_ALL, " %d.%02d MB total triangle indices memory\n", indexesSize / (1024 * 1024), (indexesSize % (1024 * 1024)) * 100 / (1024 * 1024)); } @@ -718,28 +623,35 @@ void R_VBOList_f(void) /* ============== -RB_UpdateTessVbo +RB_UpdateTessVao Adapted from Tess_UpdateVBOs from xreal -Update the default VBO to replace the client side vertex arrays +Update the default VAO to replace the client side vertex arrays ============== */ -void RB_UpdateTessVbo(unsigned int attribBits) +void RB_UpdateTessVao(unsigned int attribBits) { - GLimp_LogComment("--- RB_UpdateTessVbo ---\n"); + GLimp_LogComment("--- RB_UpdateTessVao ---\n"); - backEnd.pc.c_dynamicVboDraws++; + backEnd.pc.c_dynamicVaoDraws++; - // update the default VBO - if(tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES) + // update the default VAO + if(tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES && tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES) { int attribIndex; - R_BindVBO(tess.vbo); + R_BindVao(tess.vao); - // orphan old buffer so we don't stall on it - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->vertexesSize, NULL, GL_DYNAMIC_DRAW_ARB); + // these may not be bound if we're using VAOs + if (glRefConfig.vertexArrayObject) + { + qglBindBufferARB(GL_ARRAY_BUFFER_ARB, tess.vao->vertexesVBO); + qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.vao->indexesIBO); + } + + // orphan old vertex buffer so we don't stall on it + qglBufferDataARB(GL_ARRAY_BUFFER_ARB, tess.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW_ARB); // if nothing to set, set everything if(!(attribBits & ATTR_BITS)) @@ -757,21 +669,15 @@ void RB_UpdateTessVbo(unsigned int attribBits) { if (attribBits & (1 << attribIndex)) { - vaoAttrib_t *vAtb = &tess.vbo->attribs[attribIndex]; + vaoAttrib_t *vAtb = &tess.vao->attribs[attribIndex]; - // note: tess is a VBO where stride == size + // note: tess has a VBO where stride == size qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, vAtb->offset, tess.numVertexes * vAtb->stride, tess.attribPointers[attribIndex]); } } - } - // update the default IBO - if(tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES) - { - R_BindIBO(tess.ibo); - - // orphan old buffer so we don't stall on it - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.ibo->indexesSize, NULL, GL_DYNAMIC_DRAW_ARB); + // orphan old index buffer so we don't stall on it + qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.vao->indexesSize, NULL, GL_DYNAMIC_DRAW_ARB); qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes); } diff --git a/code/renderergl2/tr_world.c b/code/renderergl2/tr_world.c index 8bd6fae9..98b1c811 100644 --- a/code/renderergl2/tr_world.c +++ b/code/renderergl2/tr_world.c @@ -213,7 +213,7 @@ static int R_DlightSurface( msurface_t *surf, int dlightBits ) { case SF_FACE: case SF_GRID: case SF_TRIANGLES: - case SF_VBO_MESH: + case SF_VAO_MESH: ((srfBspSurface_t *)surf->data)->dlightBits = dlightBits; break; @@ -299,7 +299,7 @@ static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) { case SF_FACE: case SF_GRID: case SF_TRIANGLES: - case SF_VBO_MESH: + case SF_VAO_MESH: ((srfBspSurface_t *)surf->data)->pshadowBits = pshadowBits; break;