DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

VertexCache.cpp (10654B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 #include "tr_local.h"
     33 
     34 idVertexCache vertexCache;
     35 
     36 idCVar r_showVertexCache( "r_showVertexCache", "0", CVAR_RENDERER | CVAR_BOOL, "Print stats about the vertex cache every frame" );
     37 idCVar r_showVertexCacheTimings( "r_showVertexCache", "0", CVAR_RENDERER | CVAR_BOOL, "Print stats about the vertex cache every frame" );
     38 
     39 
     40 /*
     41 ==============
     42 ClearGeoBufferSet
     43 ==============
     44 */
     45 static void ClearGeoBufferSet( geoBufferSet_t &gbs ) {
     46 	gbs.indexMemUsed.SetValue( 0 );
     47 	gbs.vertexMemUsed.SetValue( 0 );
     48 	gbs.jointMemUsed.SetValue( 0 );
     49 	gbs.allocations = 0;
     50 }
     51 
     52 /*
     53 ==============
     54 MapGeoBufferSet
     55 ==============
     56 */
     57 static void MapGeoBufferSet( geoBufferSet_t &gbs ) {
     58 	if ( gbs.mappedVertexBase == NULL ) {
     59 		gbs.mappedVertexBase = (byte *)gbs.vertexBuffer.MapBuffer( BM_WRITE );
     60 	}
     61 	if ( gbs.mappedIndexBase == NULL ) {
     62 		gbs.mappedIndexBase = (byte *)gbs.indexBuffer.MapBuffer( BM_WRITE );
     63 	}
     64 	if ( gbs.mappedJointBase == NULL && gbs.jointBuffer.GetAllocedSize() != 0 ) {
     65 		gbs.mappedJointBase = (byte *)gbs.jointBuffer.MapBuffer( BM_WRITE );
     66 	}
     67 }
     68 
     69 /*
     70 ==============
     71 UnmapGeoBufferSet
     72 ==============
     73 */
     74 static void UnmapGeoBufferSet( geoBufferSet_t &gbs ) {
     75 	if ( gbs.mappedVertexBase != NULL ) {
     76 		gbs.vertexBuffer.UnmapBuffer();
     77 		gbs.mappedVertexBase = NULL;
     78 	}
     79 	if ( gbs.mappedIndexBase != NULL ) {
     80 		gbs.indexBuffer.UnmapBuffer();
     81 		gbs.mappedIndexBase = NULL;
     82 	}
     83 	if ( gbs.mappedJointBase != NULL ) {
     84 		gbs.jointBuffer.UnmapBuffer();
     85 		gbs.mappedJointBase = NULL;
     86 	}
     87 }
     88 
     89 /*
     90 ==============
     91 AllocGeoBufferSet
     92 ==============
     93 */
     94 static void AllocGeoBufferSet( geoBufferSet_t &gbs, const int vertexBytes, const int indexBytes, const int jointBytes ) {
     95 	gbs.vertexBuffer.AllocBufferObject( NULL, vertexBytes );
     96 	gbs.indexBuffer.AllocBufferObject( NULL, indexBytes );
     97 	if ( jointBytes != 0 ) {
     98 		gbs.jointBuffer.AllocBufferObject( NULL, jointBytes / sizeof( idJointMat ) );
     99 	}
    100 	ClearGeoBufferSet( gbs );
    101 }
    102 
    103 /*
    104 ==============
    105 idVertexCache::Init
    106 ==============
    107 */
    108 void idVertexCache::Init( bool restart ) {
    109 	currentFrame = 0;
    110 	listNum = 0;
    111 
    112 	mostUsedVertex = 0;
    113 	mostUsedIndex = 0;
    114 	mostUsedJoint = 0;
    115 
    116 	for ( int i = 0; i < VERTCACHE_NUM_FRAMES; i++ ) {
    117 		AllocGeoBufferSet( frameData[i], VERTCACHE_VERTEX_MEMORY_PER_FRAME, VERTCACHE_INDEX_MEMORY_PER_FRAME, VERTCACHE_JOINT_MEMORY_PER_FRAME );
    118 	}
    119 	AllocGeoBufferSet( staticData, STATIC_VERTEX_MEMORY, STATIC_INDEX_MEMORY, 0 );
    120 
    121 	MapGeoBufferSet( frameData[listNum] );
    122 }
    123 
    124 /*
    125 ==============
    126 idVertexCache::Shutdown
    127 ==============
    128 */
    129 void idVertexCache::Shutdown() {
    130 	for ( int i = 0; i < VERTCACHE_NUM_FRAMES; i++ ) {
    131 		frameData[i].vertexBuffer.FreeBufferObject();
    132 		frameData[i].indexBuffer.FreeBufferObject();
    133 		frameData[i].jointBuffer.FreeBufferObject();
    134 	}
    135 }
    136 
    137 /*
    138 ==============
    139 idVertexCache::PurgeAll
    140 ==============
    141 */
    142 void idVertexCache::PurgeAll() {
    143 	Shutdown();
    144 	Init( true );
    145 }
    146 
    147 /*
    148 ==============
    149 idVertexCache::FreeStaticData
    150 
    151 call on loading a new map
    152 ==============
    153 */
    154 void idVertexCache::FreeStaticData() {
    155 	ClearGeoBufferSet( staticData );
    156 	mostUsedVertex = 0;
    157 	mostUsedIndex = 0;
    158 	mostUsedJoint = 0;
    159 }
    160 
    161 /*
    162 ==============
    163 idVertexCache::ActuallyAlloc
    164 ==============
    165 */
    166 vertCacheHandle_t idVertexCache::ActuallyAlloc( geoBufferSet_t & vcs, const void * data, int bytes, cacheType_t type ) {
    167 	if ( bytes == 0 ) {
    168 		return (vertCacheHandle_t)0;
    169 	}
    170 
    171 	assert( ( ((UINT_PTR)(data)) & 15 ) == 0 );
    172 	assert( ( bytes & 15 ) == 0 );
    173 
    174 	// thread safe interlocked adds
    175 	byte ** base = NULL;
    176 	int	endPos = 0;
    177 	if ( type == CACHE_INDEX ) {
    178 		base = &vcs.mappedIndexBase;
    179 		endPos = vcs.indexMemUsed.Add( bytes );
    180 		if ( endPos > vcs.indexBuffer.GetAllocedSize() ) {
    181 			idLib::Error( "Out of index cache" );
    182 		}
    183 	} else if ( type == CACHE_VERTEX ) {
    184 		base = &vcs.mappedVertexBase;
    185 		endPos = vcs.vertexMemUsed.Add( bytes );
    186 		if ( endPos > vcs.vertexBuffer.GetAllocedSize() ) {
    187 			idLib::Error( "Out of vertex cache" );
    188 		}
    189 	} else if ( type == CACHE_JOINT ) {
    190 		base = &vcs.mappedJointBase;
    191 		endPos = vcs.jointMemUsed.Add( bytes );
    192 		if ( endPos > vcs.jointBuffer.GetAllocedSize() ) {
    193 			idLib::Error( "Out of joint buffer cache" );
    194 		}
    195 	} else {
    196 		assert( false );
    197 	}
    198 
    199 	vcs.allocations++;
    200 
    201 	int offset = endPos - bytes;
    202 
    203 	// Actually perform the data transfer
    204 	if ( data != NULL ) {
    205 		MapGeoBufferSet( vcs );
    206 		CopyBuffer( *base + offset, (const byte *)data, bytes );
    207 	}
    208 
    209 	vertCacheHandle_t handle =	( (uint64)(currentFrame & VERTCACHE_FRAME_MASK ) << VERTCACHE_FRAME_SHIFT ) |
    210 								( (uint64)(offset & VERTCACHE_OFFSET_MASK ) << VERTCACHE_OFFSET_SHIFT ) |
    211 								( (uint64)(bytes & VERTCACHE_SIZE_MASK ) << VERTCACHE_SIZE_SHIFT );
    212 	if ( &vcs == &staticData ) {
    213 		handle |= VERTCACHE_STATIC;
    214 	}
    215 	return handle;
    216 }
    217 
    218 /*
    219 ==============
    220 idVertexCache::GetVertexBuffer
    221 ==============
    222 */
    223 bool idVertexCache::GetVertexBuffer( vertCacheHandle_t handle, idVertexBuffer * vb ) {
    224 	const int isStatic = handle & VERTCACHE_STATIC;
    225 	const uint64 size = (int)( handle >> VERTCACHE_SIZE_SHIFT ) & VERTCACHE_SIZE_MASK;
    226 	const uint64 offset = (int)( handle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
    227 	const uint64 frameNum = (int)( handle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
    228 	if ( isStatic ) {
    229 		vb->Reference( staticData.vertexBuffer, offset, size );
    230 		return true;
    231 	}
    232 	if ( frameNum != ( ( currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) {
    233 		return false;
    234 	}
    235 	vb->Reference( frameData[drawListNum].vertexBuffer, offset, size );
    236 	return true;
    237 }
    238 
    239 /*
    240 ==============
    241 idVertexCache::GetIndexBuffer
    242 ==============
    243 */
    244 bool idVertexCache::GetIndexBuffer( vertCacheHandle_t handle, idIndexBuffer * ib ) {
    245 	const int isStatic = handle & VERTCACHE_STATIC;
    246 	const uint64 size = (int)( handle >> VERTCACHE_SIZE_SHIFT ) & VERTCACHE_SIZE_MASK;
    247 	const uint64 offset = (int)( handle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
    248 	const uint64 frameNum = (int)( handle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
    249 	if ( isStatic ) {
    250 		ib->Reference( staticData.indexBuffer, offset, size );
    251 		return true;
    252 	}
    253 	if ( frameNum != ( ( currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) {
    254 		return false;
    255 	}
    256 	ib->Reference( frameData[drawListNum].indexBuffer, offset, size );
    257 	return true;
    258 }
    259 
    260 /*
    261 ==============
    262 idVertexCache::GetJointBuffer
    263 ==============
    264 */
    265 bool idVertexCache::GetJointBuffer( vertCacheHandle_t handle, idJointBuffer * jb ) {
    266 	const int isStatic = handle & VERTCACHE_STATIC;
    267 	const uint64 numBytes = (int)( handle >> VERTCACHE_SIZE_SHIFT ) & VERTCACHE_SIZE_MASK;
    268 	const uint64 jointOffset = (int)( handle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
    269 	const uint64 frameNum = (int)( handle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
    270 	const uint64 numJoints = numBytes / sizeof( idJointMat );
    271 	if ( isStatic ) {
    272 		jb->Reference( staticData.jointBuffer, jointOffset, numJoints );
    273 		return true;
    274 	}
    275 	if ( frameNum != ( ( currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) {
    276 		return false;
    277 	}
    278 	jb->Reference( frameData[drawListNum].jointBuffer, jointOffset, numJoints );
    279 	return true;
    280 }
    281 
    282 /*
    283 ==============
    284 idVertexCache::BeginBackEnd
    285 ==============
    286 */
    287 void idVertexCache::BeginBackEnd() {
    288 	mostUsedVertex = Max( mostUsedVertex, frameData[listNum].vertexMemUsed.GetValue() );
    289 	mostUsedIndex = Max( mostUsedIndex, frameData[listNum].indexMemUsed.GetValue() );
    290 	mostUsedJoint = Max( mostUsedJoint, frameData[listNum].jointMemUsed.GetValue() );
    291 
    292 	if ( r_showVertexCache.GetBool() ) {
    293 		idLib::Printf( "%08d: %d allocations, %dkB vertex, %dkB index, %kB joint : %dkB vertex, %dkB index, %kB joint\n", 
    294 			currentFrame, frameData[listNum].allocations,
    295 			frameData[listNum].vertexMemUsed.GetValue() / 1024,
    296 			frameData[listNum].indexMemUsed.GetValue() / 1024,
    297 			frameData[listNum].jointMemUsed.GetValue() / 1024,
    298 			mostUsedVertex / 1024,
    299 			mostUsedIndex / 1024,
    300 			mostUsedJoint / 1024 );
    301 	}
    302 
    303 	// unmap the current frame so the GPU can read it
    304 	const int startUnmap = Sys_Milliseconds();
    305 	UnmapGeoBufferSet( frameData[listNum] );
    306 	UnmapGeoBufferSet( staticData );
    307 	const int endUnmap = Sys_Milliseconds();
    308 	if ( endUnmap - startUnmap > 1 ) {
    309 		idLib::PrintfIf( r_showVertexCacheTimings.GetBool(), "idVertexCache::unmap took %i msec\n", endUnmap - startUnmap );
    310 	}
    311 	drawListNum = listNum;
    312 
    313 	// prepare the next frame for writing to by the CPU
    314 	currentFrame++;
    315 
    316 	listNum = currentFrame % VERTCACHE_NUM_FRAMES;
    317 	const int startMap = Sys_Milliseconds();
    318 	MapGeoBufferSet( frameData[listNum] );
    319 	const int endMap = Sys_Milliseconds();
    320 	if ( endMap - startMap > 1 ) {
    321 		idLib::PrintfIf( r_showVertexCacheTimings.GetBool(), "idVertexCache::map took %i msec\n", endMap - startMap );
    322 	}
    323 
    324 	ClearGeoBufferSet( frameData[listNum] );
    325 
    326 
    327 #if 0
    328 	const int startBind = Sys_Milliseconds();
    329 	qglBindBufferARB( GL_ARRAY_BUFFER_ARB, (GLuint)frameData[drawListNum].vertexBuffer.GetAPIObject() );
    330 	qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, (GLuint)frameData[drawListNum].indexBuffer.GetAPIObject() );
    331 	const int endBind = Sys_Milliseconds();
    332 	if ( endBind - startBind > 1 ) {
    333 		idLib::Printf( "idVertexCache::bind took %i msec\n", endBind - startBind );
    334 	}
    335 #endif
    336 
    337 }
    338