diff options
| author | IronClawTrem <louie.nutman@gmail.com> | 2020-02-16 03:40:06 +0000 | 
|---|---|---|
| committer | IronClawTrem <louie.nutman@gmail.com> | 2020-02-16 03:40:06 +0000 | 
| commit | 425decdf7e9284d15aa726e3ae96b9942fb0e3ea (patch) | |
| tree | 6c0dd7edfefff1be7b9e75fe0b3a0a85fe1595f3 /src/renderergl2/tr_vbo.cpp | |
| parent | ccb0b2e4d6674a7a00c9bf491f08fc73b6898c54 (diff) | |
create tremded branch
Diffstat (limited to 'src/renderergl2/tr_vbo.cpp')
| -rw-r--r-- | src/renderergl2/tr_vbo.cpp | 945 | 
1 files changed, 945 insertions, 0 deletions
diff --git a/src/renderergl2/tr_vbo.cpp b/src/renderergl2/tr_vbo.cpp new file mode 100644 index 0000000..58836cd --- /dev/null +++ b/src/renderergl2/tr_vbo.cpp @@ -0,0 +1,945 @@ +/* +=========================================================================== +Copyright (C) 2007-2009 Robert Beckebans <trebor_7@users.sourceforge.net> +Copyright (C) 2015-2019 GrangerHub + +This file is part of Tremulous. + +Tremulous is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, +or (at your option) any later version. + +Tremulous is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Tremulous; if not, see <https://www.gnu.org/licenses/> + +=========================================================================== +*/ +// tr_vbo.c +#include "tr_local.h" + + +void R_VaoPackTangent(int16_t *out, vec4_t v) +{ +	out[0] = v[0] * 32767.0f + (v[0] > 0.0f ? 0.5f : -0.5f); +	out[1] = v[1] * 32767.0f + (v[1] > 0.0f ? 0.5f : -0.5f); +	out[2] = v[2] * 32767.0f + (v[2] > 0.0f ? 0.5f : -0.5f); +	out[3] = v[3] * 32767.0f + (v[3] > 0.0f ? 0.5f : -0.5f); +} + +void R_VaoPackNormal(int16_t *out, vec3_t v) +{ +	out[0] = v[0] * 32767.0f + (v[0] > 0.0f ? 0.5f : -0.5f); +	out[1] = v[1] * 32767.0f + (v[1] > 0.0f ? 0.5f : -0.5f); +	out[2] = v[2] * 32767.0f + (v[2] > 0.0f ? 0.5f : -0.5f); +	out[3] = 0; +} + +void R_VaoPackColor(uint16_t *out, vec4_t c) +{ +	out[0] = c[0] * 65535.0f + 0.5f; +	out[1] = c[1] * 65535.0f + 0.5f; +	out[2] = c[2] * 65535.0f + 0.5f; +	out[3] = c[3] * 65535.0f + 0.5f; +} + +void R_VaoUnpackTangent(vec4_t v, int16_t *pack) +{ +	v[0] = pack[0] / 32767.0f; +	v[1] = pack[1] / 32767.0f; +	v[2] = pack[2] / 32767.0f; +	v[3] = pack[3] / 32767.0f; +} + +void R_VaoUnpackNormal(vec3_t v, int16_t *pack) +{ +	v[0] = pack[0] / 32767.0f; +	v[1] = pack[1] / 32767.0f; +	v[2] = pack[2] / 32767.0f; +} + +void Vao_SetVertexPointers(vao_t *vao) +{ +	int attribIndex; + +	// set vertex pointers +	for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++) +	{ +		uint32_t attribBit = 1 << attribIndex; +		vaoAttrib_t *vAtb = &vao->attribs[attribIndex]; + +		if (vAtb->enabled) +		{ +			qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset)); +			if (glRefConfig.vertexArrayObject || !(glState.vertexAttribsEnabled & attribBit)) +				qglEnableVertexAttribArray(attribIndex); + +			if (!glRefConfig.vertexArrayObject || vao == tess.vao) +				glState.vertexAttribsEnabled |= attribBit; +		} +		else +		{ +			// don't disable vertex attribs when using vertex array objects +			// Vao_SetVertexPointers is only called during init when using VAOs, and vertex attribs start disabled anyway +			if (!glRefConfig.vertexArrayObject && (glState.vertexAttribsEnabled & attribBit)) +				qglDisableVertexAttribArray(attribIndex); + +			if (!glRefConfig.vertexArrayObject || vao == tess.vao) +				glState.vertexAttribsEnabled &= ~attribBit; +		} +	} +} + +/* +============ +R_CreateVao +============ +*/ +vao_t *R_CreateVao(const char *name, byte *vertexes, int vertexesSize, byte *indexes, int indexesSize, vaoUsage_t usage) +{ +	vao_t          *vao; +	int				glUsage; + +	switch (usage) +	{ +		case VAO_USAGE_STATIC: +			glUsage = GL_STATIC_DRAW; +			break; + +		case VAO_USAGE_DYNAMIC: +			glUsage = GL_DYNAMIC_DRAW; +			break; + +		default: +			Com_Error(ERR_FATAL, "bad vaoUsage_t given: %i", usage); +			return NULL; +	} + +	if(strlen(name) >= MAX_QPATH) +	{ +		ri.Error(ERR_DROP, "R_CreateVao: \"%s\" is too long", name); +	} + +	if ( tr.numVaos == MAX_VAOS ) { +		ri.Error( ERR_DROP, "R_CreateVao: MAX_VAOS hit"); +	} + +	R_IssuePendingRenderCommands(); + +	vao = tr.vaos[tr.numVaos] = (vao_t*)ri.Hunk_Alloc(sizeof(*vao), h_low); +	tr.numVaos++; + +	memset(vao, 0, sizeof(*vao)); + +	Q_strncpyz(vao->name, name, sizeof(vao->name)); + + +	if (glRefConfig.vertexArrayObject) +	{ +		qglGenVertexArrays(1, &vao->vao); +		qglBindVertexArray(vao->vao); +	} + + +	vao->vertexesSize = vertexesSize; + +	qglGenBuffers(1, &vao->vertexesVBO); + +	qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO); +	qglBufferData(GL_ARRAY_BUFFER, vertexesSize, vertexes, glUsage); + + +	vao->indexesSize = indexesSize; + +	qglGenBuffers(1, &vao->indexesIBO); + +	qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); +	qglBufferData(GL_ELEMENT_ARRAY_BUFFER, indexesSize, indexes, glUsage); + + +	glState.currentVao = vao; + +	GL_CheckErrors(); + +	return vao; +} + +/* +============ +R_CreateVao2 +============ +*/ +vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int numIndexes, glIndex_t *indexes) +{ +	vao_t          *vao; +	int             i; + +	byte           *data; +	int             dataSize; +	int             dataOfs; + +	int				glUsage = GL_STATIC_DRAW; + +	if(!numVertexes || !numIndexes) +		return NULL; + +	if(strlen(name) >= MAX_QPATH) +	{ +		ri.Error(ERR_DROP, "R_CreateVao2: \"%s\" is too long", name); +	} + +	if ( tr.numVaos == MAX_VAOS ) { +		ri.Error( ERR_DROP, "R_CreateVao2: MAX_VAOS hit"); +	} + +	R_IssuePendingRenderCommands(); + +	vao = tr.vaos[tr.numVaos] = (vao_t*)ri.Hunk_Alloc(sizeof(*vao), h_low); +	tr.numVaos++; + +	memset(vao, 0, sizeof(*vao)); + +	Q_strncpyz(vao->name, name, sizeof(vao->name)); + +	// since these vertex attributes are never altered, interleave them +	vao->attribs[ATTR_INDEX_POSITION      ].enabled = 1; +	vao->attribs[ATTR_INDEX_NORMAL        ].enabled = 1; +	vao->attribs[ATTR_INDEX_TANGENT       ].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; + +	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; + +	vao->attribs[ATTR_INDEX_POSITION      ].type = GL_FLOAT; +	vao->attribs[ATTR_INDEX_NORMAL        ].type = GL_SHORT; +	vao->attribs[ATTR_INDEX_TANGENT       ].type = GL_SHORT; +	vao->attribs[ATTR_INDEX_TEXCOORD      ].type = GL_FLOAT; +	vao->attribs[ATTR_INDEX_LIGHTCOORD    ].type = GL_FLOAT; +	vao->attribs[ATTR_INDEX_COLOR         ].type = GL_UNSIGNED_SHORT; +	vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT; + +	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_TRUE; +	vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; + +	vao->attribs[ATTR_INDEX_POSITION      ].offset = 0;        dataSize  = sizeof(verts[0].xyz); +	vao->attribs[ATTR_INDEX_NORMAL        ].offset = dataSize; dataSize += sizeof(verts[0].normal); +	vao->attribs[ATTR_INDEX_TANGENT       ].offset = dataSize; dataSize += sizeof(verts[0].tangent); +	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].color); +	vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(verts[0].lightdir); + +	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) +	{ +		qglGenVertexArrays(1, &vao->vao); +		qglBindVertexArray(vao->vao); +	} + + +	// create VBO +	dataSize *= numVertexes; +	data = (byte*)ri.Hunk_AllocateTempMemory(dataSize); +	dataOfs = 0; + +	for (i = 0; i < numVertexes; i++) +	{ +		// xyz +		memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz)); +		dataOfs += sizeof(verts[i].xyz); + +		// normal +		memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal)); +		dataOfs += sizeof(verts[i].normal); + +		// tangent +		memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent)); +		dataOfs += sizeof(verts[i].tangent); + +		// texcoords +		memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st)); +		dataOfs += sizeof(verts[i].st); + +		// lightmap texcoords +		memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap)); +		dataOfs += sizeof(verts[i].lightmap); + +		// colors +		memcpy(data + dataOfs, &verts[i].color, sizeof(verts[i].color)); +		dataOfs += sizeof(verts[i].color); + +		// light directions +		memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir)); +		dataOfs += sizeof(verts[i].lightdir); +	} + +	vao->vertexesSize = dataSize; + +	qglGenBuffers(1, &vao->vertexesVBO); + +	qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO); +	qglBufferData(GL_ARRAY_BUFFER, vao->vertexesSize, data, glUsage); + + +	// create IBO +	vao->indexesSize = numIndexes * sizeof(glIndex_t); + +	qglGenBuffers(1, &vao->indexesIBO); + +	qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); +	qglBufferData(GL_ELEMENT_ARRAY_BUFFER, vao->indexesSize, indexes, glUsage); + + +	Vao_SetVertexPointers(vao); + + +	glState.currentVao = vao; + +	GL_CheckErrors(); + +	ri.Hunk_FreeTempMemory(data); + +	return vao; +} + + +/* +============ +R_BindVao +============ +*/ +void R_BindVao(vao_t * vao) +{ +	if(!vao) +	{ +		//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((char*)va("--- R_BindVao( %s ) ---\n", vao->name)); +	} + +	if(glState.currentVao != vao) +	{ +		glState.currentVao = vao; + +		glState.vertexAttribsInterpolation = 0; +		glState.vertexAnimation = false; +		backEnd.pc.c_vaoBinds++; + +		if (glRefConfig.vertexArrayObject) +		{ +			qglBindVertexArray(vao->vao); + +			// Intel Graphics doesn't save GL_ELEMENT_ARRAY_BUFFER binding with VAO binding. +			if (glRefConfig.intelGraphics || vao == tess.vao) +				qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); + +			// tess VAO always has buffers bound +			if (vao == tess.vao) +				qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO); +		} +		else +		{ +			qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO); +			qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); + +			// tess VAO doesn't have vertex pointers set until data is uploaded +			if (vao != tess.vao) +				Vao_SetVertexPointers(vao); +		} +	} +} + +/* +============ +R_BindNullVao +============ +*/ +void R_BindNullVao(void) +{ +	GLimp_LogComment("--- R_BindNullVao ---\n"); + +	if(glState.currentVao) +	{ +		if (glRefConfig.vertexArrayObject) +		{ +			qglBindVertexArray(0); + +			// why you no save GL_ELEMENT_ARRAY_BUFFER binding, Intel? +			if (1) qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +		} +		else +		{ +			qglBindBuffer(GL_ARRAY_BUFFER, 0); +			qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +		} +		glState.currentVao = NULL; +	} + +	GL_CheckErrors(); +} + + +/* +============ +R_InitVaos +============ +*/ +void R_InitVaos(void) +{ +	int             vertexesSize, indexesSize; +	int             offset; + +	ri.Printf(PRINT_ALL, "------- R_InitVaos -------\n"); + +	tr.numVaos = 0; + +	vertexesSize  = sizeof(tess.xyz[0]); +	vertexesSize += sizeof(tess.normal[0]); +	vertexesSize += sizeof(tess.tangent[0]); +	vertexesSize += sizeof(tess.color[0]); +	vertexesSize += sizeof(tess.texCoords[0]); +	vertexesSize += sizeof(tess.lightCoords[0]); +	vertexesSize += sizeof(tess.lightdir[0]); +	vertexesSize *= SHADER_MAX_VERTEXES; + +	indexesSize = sizeof(tess.indexes[0]) * SHADER_MAX_INDEXES; + +	tess.vao = R_CreateVao("tessVertexArray_VAO", NULL, vertexesSize, NULL, indexesSize, VAO_USAGE_DYNAMIC); + +	offset = 0; + +	tess.vao->attribs[ATTR_INDEX_POSITION      ].enabled = 1; +	tess.vao->attribs[ATTR_INDEX_NORMAL        ].enabled = 1; +	tess.vao->attribs[ATTR_INDEX_TANGENT       ].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.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.vao->attribs[ATTR_INDEX_POSITION      ].type = GL_FLOAT; +	tess.vao->attribs[ATTR_INDEX_NORMAL        ].type = GL_SHORT; +	tess.vao->attribs[ATTR_INDEX_TANGENT       ].type = GL_SHORT; +	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_UNSIGNED_SHORT; +	tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT; + +	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_TRUE; +	tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; + +	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; +	tess.vao->attribs[ATTR_INDEX_TANGENT       ].offset = offset; offset += sizeof(tess.tangent[0])     * SHADER_MAX_VERTEXES; +	tess.vao->attribs[ATTR_INDEX_TEXCOORD      ].offset = offset; offset += sizeof(tess.texCoords[0])   * SHADER_MAX_VERTEXES; +	tess.vao->attribs[ATTR_INDEX_LIGHTCOORD    ].offset = offset; offset += sizeof(tess.lightCoords[0]) * SHADER_MAX_VERTEXES; +	tess.vao->attribs[ATTR_INDEX_COLOR         ].offset = offset; offset += sizeof(tess.color[0])       * SHADER_MAX_VERTEXES; +	tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = offset; + +	tess.vao->attribs[ATTR_INDEX_POSITION      ].stride = sizeof(tess.xyz[0]); +	tess.vao->attribs[ATTR_INDEX_NORMAL        ].stride = sizeof(tess.normal[0]); +	tess.vao->attribs[ATTR_INDEX_TANGENT       ].stride = sizeof(tess.tangent[0]); +	tess.vao->attribs[ATTR_INDEX_TEXCOORD      ].stride = sizeof(tess.texCoords[0]); +	tess.vao->attribs[ATTR_INDEX_LIGHTCOORD    ].stride = sizeof(tess.lightCoords[0]); +	tess.vao->attribs[ATTR_INDEX_COLOR         ].stride = sizeof(tess.color[0]); +	tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = sizeof(tess.lightdir[0]); + +	tess.attribPointers[ATTR_INDEX_POSITION]       = tess.xyz; +	tess.attribPointers[ATTR_INDEX_NORMAL]         = tess.normal; +	tess.attribPointers[ATTR_INDEX_TANGENT]        = tess.tangent; +	tess.attribPointers[ATTR_INDEX_TEXCOORD]       = tess.texCoords; +	tess.attribPointers[ATTR_INDEX_LIGHTCOORD]     = tess.lightCoords; +	tess.attribPointers[ATTR_INDEX_COLOR]          = tess.color; +	tess.attribPointers[ATTR_INDEX_LIGHTDIRECTION] = tess.lightdir; + +	Vao_SetVertexPointers(tess.vao); + +	R_BindNullVao(); + +	VaoCache_Init(); + +	GL_CheckErrors(); +} + +/* +============ +R_ShutdownVaos +============ +*/ +void R_ShutdownVaos(void) +{ +	int             i; +	vao_t          *vao; + +	ri.Printf(PRINT_ALL, "------- R_ShutdownVaos -------\n"); + +	R_BindNullVao(); + +	for(i = 0; i < tr.numVaos; i++) +	{ +		vao = tr.vaos[i]; + +		if(vao->vao) +			qglDeleteVertexArrays(1, &vao->vao); + +		if(vao->vertexesVBO) +		{ +			qglDeleteBuffers(1, &vao->vertexesVBO); +		} + +		if(vao->indexesIBO) +		{ +			qglDeleteBuffers(1, &vao->indexesIBO); +		} +	} + +	tr.numVaos = 0; +} + +/* +============ +R_VaoList_f +============ +*/ +void R_VaoList_f(void) +{ +	int             i; +	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.numVaos; i++) +	{ +		vao = tr.vaos[i]; + +		ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vao->vertexesSize / (1024 * 1024), +				  (vao->vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vao->name); + +		vertexesSize += vao->vertexesSize; +	} + +	for(i = 0; i < tr.numVaos; i++) +	{ +		vao = tr.vaos[i]; + +		ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vao->indexesSize / (1024 * 1024), +				  (vao->indexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vao->name); + +		indexesSize += vao->indexesSize; +	} + +	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, " %d.%02d MB total triangle indices memory\n", indexesSize / (1024 * 1024), +			  (indexesSize % (1024 * 1024)) * 100 / (1024 * 1024)); +} + + +/* +============== +RB_UpdateTessVao + +Adapted from Tess_UpdateVBOs from xreal + +Update the default VAO to replace the client side vertex arrays +============== +*/ +void RB_UpdateTessVao(unsigned int attribBits) +{ +	GLimp_LogComment("--- RB_UpdateTessVao ---\n"); + +	backEnd.pc.c_dynamicVaoDraws++; + +	// update the default VAO +	if(tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES && tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES) +	{ +		int attribIndex; +		int attribUpload; + +		R_BindVao(tess.vao); + +		// orphan old vertex buffer so we don't stall on it +		qglBufferData(GL_ARRAY_BUFFER, tess.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW); + +		// if nothing to set, set everything +		if(!(attribBits & ATTR_BITS)) +			attribBits = ATTR_BITS; + +		attribUpload = attribBits; + +		for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++) +		{ +			uint32_t attribBit = 1 << attribIndex; +			vaoAttrib_t *vAtb = &tess.vao->attribs[attribIndex]; + +			if (attribUpload & attribBit) +			{ +				// note: tess has a VBO where stride == size +				qglBufferSubData(GL_ARRAY_BUFFER, vAtb->offset, tess.numVertexes * vAtb->stride, tess.attribPointers[attribIndex]); +			} + +			if (attribBits & attribBit) +			{ +				if (!glRefConfig.vertexArrayObject) +					qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset)); + +				if (!(glState.vertexAttribsEnabled & attribBit)) +				{ +					qglEnableVertexAttribArray(attribIndex); +					glState.vertexAttribsEnabled |= attribBit; +				} +			} +			else +			{ +				if ((glState.vertexAttribsEnabled & attribBit)) +				{ +					qglDisableVertexAttribArray(attribIndex); +					glState.vertexAttribsEnabled &= ~attribBit; +				} +			} +		} + +		// orphan old index buffer so we don't stall on it +		qglBufferData(GL_ELEMENT_ARRAY_BUFFER, tess.vao->indexesSize, NULL, GL_DYNAMIC_DRAW); + +		qglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes); +	} +} + +typedef struct bufferCacheEntry_s +{ +	void *data; +	int size; +	int bufferOffset; +} +bufferCacheEntry_t; + +typedef struct queuedSurface_s +{ +	srfVert_t *vertexes; +	int numVerts; +	glIndex_t *indexes; +	int numIndexes; +} +queuedSurface_t; + +#define VAOCACHE_MAX_BUFFERED_SURFACES (1 << 16) +#define VAOCACHE_VERTEX_BUFFER_SIZE 12 * 1024 * 1024 +#define VAOCACHE_INDEX_BUFFER_SIZE 12 * 1024 * 1024 + +#define VAOCACHE_MAX_QUEUED_VERTEXES (1 << 16) +#define VAOCACHE_MAX_QUEUED_INDEXES (VAOCACHE_MAX_QUEUED_VERTEXES * 6 / 4) + +#define VAOCACHE_MAX_QUEUED_SURFACES 4096 + +static struct +{ +	vao_t *vao; +	bufferCacheEntry_t indexEntries[VAOCACHE_MAX_BUFFERED_SURFACES]; +	int indexChainLengths[VAOCACHE_MAX_BUFFERED_SURFACES]; +	int numIndexEntries; +	int vertexOffset; +	int indexOffset; + +	srfVert_t vertexes[VAOCACHE_MAX_QUEUED_VERTEXES]; +	int vertexCommitSize; + +	glIndex_t indexes[VAOCACHE_MAX_QUEUED_INDEXES]; +	int indexCommitSize; + +	queuedSurface_t surfaceQueue[VAOCACHE_MAX_QUEUED_SURFACES]; +	int numSurfacesQueued; +} +vc = { 0 }; + +void VaoCache_Commit(void) +{ +	bufferCacheEntry_t *entry1; +	queuedSurface_t *surf, *end = vc.surfaceQueue + vc.numSurfacesQueued; + +	R_BindVao(vc.vao); + +	// search entire cache for exact chain of indexes +	// FIXME: use faster search +	for (entry1 = vc.indexEntries; entry1 < vc.indexEntries + vc.numIndexEntries;) +	{ +		int chainLength = vc.indexChainLengths[entry1 - vc.indexEntries]; + +		if (chainLength == vc.numSurfacesQueued) +		{ +			bufferCacheEntry_t *entry2 = entry1; +			for (surf = vc.surfaceQueue; surf < end; surf++, entry2++) +			{ +				if (surf->indexes != entry2->data || (surf->numIndexes * sizeof(glIndex_t)) != entry2->size) +					break; +			} + +			if (surf == end) +				break; +		} + +		entry1 += chainLength; +	} + +	// if found, use that +	if (entry1 < vc.indexEntries + vc.numIndexEntries) +	{ +		tess.firstIndex = entry1->bufferOffset / sizeof(glIndex_t); +		//ri.Printf(PRINT_ALL, "firstIndex %d numIndexes %d\n", tess.firstIndex, tess.numIndexes); +		//ri.Printf(PRINT_ALL, "vc.numIndexEntries %d\n", vc.numIndexEntries); +	} +	// if not, rebuffer all the indexes but reuse any existing vertexes +	else +	{ +		srfVert_t *dstVertex = vc.vertexes; +		glIndex_t *dstIndex = vc.indexes; +		int *indexChainLength = vc.indexChainLengths + vc.numIndexEntries; + +		tess.firstIndex = vc.indexOffset / sizeof(glIndex_t); +		vc.vertexCommitSize = 0; +		vc.indexCommitSize = 0; +		for (surf = vc.surfaceQueue; surf < end; surf++) +		{ +			srfVert_t *srcVertex = surf->vertexes; +			glIndex_t *srcIndex = surf->indexes; +			int vertexesSize = surf->numVerts * sizeof(srfVert_t); +			int indexesSize = surf->numIndexes * sizeof(glIndex_t); +			int i, indexOffset = (vc.vertexOffset + vc.vertexCommitSize) / sizeof(srfVert_t); + +			for (i = 0; i < surf->numVerts; i++) +				*dstVertex++ = *srcVertex++; + +			vc.vertexCommitSize += vertexesSize; + +			entry1 = vc.indexEntries + vc.numIndexEntries; +			entry1->data = surf->indexes; +			entry1->size = indexesSize; +			entry1->bufferOffset = vc.indexOffset + vc.indexCommitSize; +			vc.numIndexEntries++; + +			*indexChainLength++ = ((surf == vc.surfaceQueue) ? vc.numSurfacesQueued : 0); + +			for (i = 0; i < surf->numIndexes; i++) +				*dstIndex++ = *srcIndex++ + indexOffset; + +			vc.indexCommitSize += indexesSize; +		} + +		//ri.Printf(PRINT_ALL, "committing %d to %d, %d to %d\n", vc.vertexCommitSize, vc.vertexOffset, vc.indexCommitSize, vc.indexOffset); + +		if (vc.vertexCommitSize) +		{ +			qglBindBuffer(GL_ARRAY_BUFFER, vc.vao->vertexesVBO); +			qglBufferSubData(GL_ARRAY_BUFFER, vc.vertexOffset, vc.vertexCommitSize, vc.vertexes); +			vc.vertexOffset += vc.vertexCommitSize; +		} + +		if (vc.indexCommitSize) +		{ +			qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesIBO); +			qglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, vc.indexOffset, vc.indexCommitSize, vc.indexes); +			vc.indexOffset += vc.indexCommitSize; +		} +	} +} + +void VaoCache_Init(void) +{ +	srfVert_t vert; +	int dataSize; + +	vc.vao = R_CreateVao("VaoCache", NULL, VAOCACHE_VERTEX_BUFFER_SIZE, NULL, VAOCACHE_INDEX_BUFFER_SIZE, VAO_USAGE_DYNAMIC); + +	vc.vao->attribs[ATTR_INDEX_POSITION].enabled       = 1; +	vc.vao->attribs[ATTR_INDEX_TEXCOORD].enabled       = 1; +	vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].enabled     = 1; +	vc.vao->attribs[ATTR_INDEX_NORMAL].enabled         = 1; +	vc.vao->attribs[ATTR_INDEX_TANGENT].enabled        = 1; +	vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].enabled = 1; +	vc.vao->attribs[ATTR_INDEX_COLOR].enabled          = 1; + +	vc.vao->attribs[ATTR_INDEX_POSITION].count       = 3; +	vc.vao->attribs[ATTR_INDEX_TEXCOORD].count       = 2; +	vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].count     = 2; +	vc.vao->attribs[ATTR_INDEX_NORMAL].count         = 4; +	vc.vao->attribs[ATTR_INDEX_TANGENT].count        = 4; +	vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4; +	vc.vao->attribs[ATTR_INDEX_COLOR].count          = 4; + +	vc.vao->attribs[ATTR_INDEX_POSITION].type             = GL_FLOAT; +	vc.vao->attribs[ATTR_INDEX_TEXCOORD].type             = GL_FLOAT; +	vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].type           = GL_FLOAT; +	vc.vao->attribs[ATTR_INDEX_NORMAL].type               = GL_SHORT; +	vc.vao->attribs[ATTR_INDEX_TANGENT].type              = GL_SHORT; +	vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type       = GL_SHORT; +	vc.vao->attribs[ATTR_INDEX_COLOR].type                = GL_UNSIGNED_SHORT; + +	vc.vao->attribs[ATTR_INDEX_POSITION].normalized       = GL_FALSE; +	vc.vao->attribs[ATTR_INDEX_TEXCOORD].normalized       = GL_FALSE; +	vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].normalized     = GL_FALSE; +	vc.vao->attribs[ATTR_INDEX_NORMAL].normalized         = GL_TRUE; +	vc.vao->attribs[ATTR_INDEX_TANGENT].normalized        = GL_TRUE; +	vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; +	vc.vao->attribs[ATTR_INDEX_COLOR].normalized          = GL_TRUE; + +	vc.vao->attribs[ATTR_INDEX_POSITION].offset       = 0;        dataSize  = sizeof(vert.xyz); +	vc.vao->attribs[ATTR_INDEX_TEXCOORD].offset       = dataSize; dataSize += sizeof(vert.st); +	vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].offset     = dataSize; dataSize += sizeof(vert.lightmap); +	vc.vao->attribs[ATTR_INDEX_NORMAL].offset         = dataSize; dataSize += sizeof(vert.normal); +	vc.vao->attribs[ATTR_INDEX_TANGENT].offset        = dataSize; dataSize += sizeof(vert.tangent); +	vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(vert.lightdir); +	vc.vao->attribs[ATTR_INDEX_COLOR].offset          = dataSize; dataSize += sizeof(vert.color); + +	vc.vao->attribs[ATTR_INDEX_POSITION].stride       = dataSize; +	vc.vao->attribs[ATTR_INDEX_TEXCOORD].stride       = dataSize; +	vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].stride     = dataSize; +	vc.vao->attribs[ATTR_INDEX_NORMAL].stride         = dataSize; +	vc.vao->attribs[ATTR_INDEX_TANGENT].stride        = dataSize; +	vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = dataSize; +	vc.vao->attribs[ATTR_INDEX_COLOR].stride          = dataSize; + +	Vao_SetVertexPointers(vc.vao); + +	vc.numIndexEntries = 0; +	vc.vertexOffset = 0; +	vc.indexOffset = 0; +	vc.vertexCommitSize = 0; +	vc.indexCommitSize = 0; +	vc.numSurfacesQueued = 0; +} + +void VaoCache_BindVao(void) +{ +	R_BindVao(vc.vao); +} + +void VaoCache_CheckAdd(bool *endSurface, bool *recycleVertexBuffer, bool *recycleIndexBuffer, int numVerts, int numIndexes) +{ +	int vertexesSize = sizeof(srfVert_t) * numVerts; +	int indexesSize = sizeof(glIndex_t) * numIndexes; + +	if (vc.vao->vertexesSize < vc.vertexOffset + vc.vertexCommitSize + vertexesSize) +	{ +		//ri.Printf(PRINT_ALL, "out of space in vertex cache: %d < %d + %d + %d\n", vc.vao->vertexesSize, vc.vertexOffset, vc.vertexCommitSize, vertexesSize); +		*recycleVertexBuffer = true; +		*recycleIndexBuffer = true; +		*endSurface = true; +	} + +	if (vc.vao->indexesSize < vc.indexOffset + vc.indexCommitSize + indexesSize) +	{ +		//ri.Printf(PRINT_ALL, "out of space in index cache\n"); +		*recycleIndexBuffer = true; +		*endSurface = true; +	} + +	if (vc.numIndexEntries + vc.numSurfacesQueued >= VAOCACHE_MAX_BUFFERED_SURFACES) +	{ +		//ri.Printf(PRINT_ALL, "out of surfaces in index cache\n"); +		*recycleIndexBuffer = true; +		*endSurface = true; +	} + +	if (vc.numSurfacesQueued == VAOCACHE_MAX_QUEUED_SURFACES) +	{ +		//ri.Printf(PRINT_ALL, "out of queued surfaces\n"); +		*endSurface = true; +	} + +	if (VAOCACHE_MAX_QUEUED_VERTEXES * sizeof(srfVert_t) < vc.vertexCommitSize + vertexesSize) +	{ +		//ri.Printf(PRINT_ALL, "out of queued vertexes\n"); +		*endSurface = true; +	} + +	if (VAOCACHE_MAX_QUEUED_INDEXES * sizeof(glIndex_t) < vc.indexCommitSize + indexesSize) +	{ +		//ri.Printf(PRINT_ALL, "out of queued indexes\n"); +		*endSurface = true; +	} +} + +void VaoCache_RecycleVertexBuffer(void) +{ +	qglBindBuffer(GL_ARRAY_BUFFER, vc.vao->vertexesVBO); +	qglBufferData(GL_ARRAY_BUFFER, vc.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW); +	vc.vertexOffset = 0; +} + +void VaoCache_RecycleIndexBuffer(void) +{ +	qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesIBO); +	qglBufferData(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesSize, NULL, GL_DYNAMIC_DRAW); +	vc.indexOffset = 0; +	vc.numIndexEntries = 0; +} + +void VaoCache_InitNewSurfaceSet(void) +{ +	vc.vertexCommitSize = 0; +	vc.indexCommitSize = 0; +	vc.numSurfacesQueued = 0; +} + +void VaoCache_AddSurface(srfVert_t *verts, int numVerts, glIndex_t *indexes, int numIndexes) +{ +	int vertexesSize = sizeof(srfVert_t) * numVerts; +	int indexesSize = sizeof(glIndex_t) * numIndexes; +	queuedSurface_t *queueEntry = vc.surfaceQueue + vc.numSurfacesQueued; +	queueEntry->vertexes = verts; +	queueEntry->numVerts = numVerts; +	queueEntry->indexes = indexes; +	queueEntry->numIndexes = numIndexes; +	vc.numSurfacesQueued++; + +	vc.vertexCommitSize += vertexesSize; +	vc.indexCommitSize += indexesSize; +}  | 
