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