gfxGLCircularVolatileBuffer.h
Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h
Classes:
class
Detailed Description
1 2#ifndef GL_CIRCULAR_VOLATILE_BUFFER_H 3#define GL_CIRCULAR_VOLATILE_BUFFER_H 4 5#include "gfx/gl/gfxGLDevice.h" 6#include "gfx/gl/gfxGLUtils.h" 7 8class GLFenceRange 9{ 10public: 11 GLFenceRange() : mStart(0), mEnd(0), mSync(0) 12 { 13 14 } 15 16 ~GLFenceRange() 17 { 18 //the order of creation/destruction of static variables is indetermined... depends on detail of the build 19 //looks like for some reason on windows + sdl + opengl the order make invalid / wrong the process TODO: Refactor -LAR 20 //AssertFatal( mSync == 0, ""); 21 } 22 23 void init(U32 start, U32 end) 24 { 25 PROFILE_SCOPE(GFXGLQueryFence_issue); 26 mStart = start; 27 mEnd = end; 28 mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 29 } 30 31 bool checkOverlap(U32 start, U32 end) 32 { 33 if( mStart < end && start < mEnd ) 34 return true; 35 36 return false; 37 } 38 39 void wait() 40 { 41 PROFILE_SCOPE(GFXGLQueryFence_block); 42 GLbitfield waitFlags = 0; 43 GLuint64 waitDuration = 0; 44 while( 1 ) 45 { 46 GLenum waitRet = glClientWaitSync( mSync, waitFlags, waitDuration ); 47 if( waitRet == GL_ALREADY_SIGNALED || waitRet == GL_CONDITION_SATISFIED ) 48 { 49 break; 50 } 51 52 if( waitRet == GL_WAIT_FAILED ) 53 { 54 AssertFatal(0, "GLSync failed."); 55 break; 56 } 57 58 waitFlags = GL_SYNC_FLUSH_COMMANDS_BIT; 59 waitDuration = scOneSecondInNanoSeconds; 60 } 61 62 glDeleteSync(mSync); 63 mSync = 0; 64 } 65 66 void swap( GLFenceRange &r ) 67 { 68 GLFenceRange temp; 69 temp = *this; 70 *this = r; 71 r = temp; 72 } 73 74protected: 75 U32 mStart, mEnd; 76 GLsync mSync; 77 static const GLuint64 scOneSecondInNanoSeconds = 1000000000; 78 79 GLFenceRange( const GLFenceRange &); 80 GLFenceRange& operator=(const GLFenceRange &r) 81 { 82 mStart = r.mStart; 83 mEnd = r.mEnd; 84 mSync = r.mSync; 85 return *this; 86 } 87}; 88 89class GLOrderedFenceRangeManager 90{ 91public: 92 93 ~GLOrderedFenceRangeManager( ) 94 { 95 //the order of creation/destruction of static variables is indetermined... depends on detail of the build 96 //looks like for some reason on windows + sdl + opengl the order make invalid / wrong the process TODO: Refactor -LAR 97 //waitAllRanges( ); 98 } 99 100 void protectOrderedRange( U32 start, U32 end ) 101 { 102 mFenceRanges.increment(); 103 GLFenceRange &range = mFenceRanges.last(); 104 range.init( start, end ); 105 } 106 107 void waitFirstRange( U32 start, U32 end ) 108 { 109 if( !mFenceRanges.size() || !mFenceRanges[0].checkOverlap( start, end ) ) 110 return; 111 112 mFenceRanges[0].wait(); 113 mFenceRanges.pop_front(); 114 } 115 116 void waitOverlapRanges( U32 start, U32 end ) 117 { 118 for( U32 i = 0; i < mFenceRanges.size(); ++i ) 119 { 120 if( !mFenceRanges[i].checkOverlap( start, end ) ) 121 continue; 122 123 mFenceRanges[i].wait(); 124 mFenceRanges.erase(i); 125 } 126 } 127 128 void waitAllRanges() 129 { 130 for( int i = 0; i < mFenceRanges.size(); ++i ) 131 mFenceRanges[i].wait(); 132 133 mFenceRanges.clear(); 134 } 135 136protected: 137 Vector<GLFenceRange> mFenceRanges; 138}; 139 140class GLCircularVolatileBuffer 141{ 142public: 143 GLCircularVolatileBuffer(GLuint binding) 144 : mBinding(binding), mBufferName(0), mBufferPtr(NULL), mBufferSize(0), mBufferFreePos(0), mCurrectUsedRangeStart(0) 145 { 146 init(); 147 } 148 149 ~GLCircularVolatileBuffer() 150 { 151 glDeleteBuffers(1, &mBufferName); 152 } 153 154 void init() 155 { 156 glGenBuffers(1, &mBufferName); 157 158 PRESERVE_BUFFER( mBinding ); 159 glBindBuffer(mBinding, mBufferName); 160 161 const U32 cSizeInMB = 10; 162 mBufferSize = (cSizeInMB << 20); 163 164 if( GFXGL->mCapabilities.bufferStorage ) 165 { 166 const GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT; 167 glBufferStorage(mBinding, mBufferSize, NULL, flags); 168 mBufferPtr = glMapBufferRange(mBinding, 0, mBufferSize, flags); 169 } 170 else 171 { 172 glBufferData(mBinding, mBufferSize, NULL, GL_DYNAMIC_DRAW); 173 } 174 } 175 176 struct 177 { 178 U32 mOffset, mSize; 179 }_getBufferData; 180 181 void lock(const U32 size, U32 offsetAlign, U32 &outOffset, void* &outPtr) 182 { 183 if( !size ) 184 { 185 AssertFatal(0, ""); 186 outOffset = 0; 187 outPtr = NULL; 188 } 189 190 mLockManager.waitFirstRange( mBufferFreePos, (mBufferFreePos + size)-1 ); 191 192 if( mBufferFreePos + size > mBufferSize ) 193 { 194 mUsedRanges.push_back( UsedRange( mBufferFreePos, mBufferSize-1 ) ); 195 mBufferFreePos = 0; 196 } 197 198 // force offset buffer align 199 if( offsetAlign ) 200 mBufferFreePos = ( (mBufferFreePos/offsetAlign) + 1 ) * offsetAlign; 201 202 outOffset = mBufferFreePos; 203 204 if( GFXGL->mCapabilities.bufferStorage ) 205 { 206 outPtr = (U8*)(mBufferPtr) + mBufferFreePos; 207 } 208 else if( GFXGL->glUseMap() ) 209 { 210 PRESERVE_BUFFER( mBinding ); 211 glBindBuffer(mBinding, mBufferName); 212 213 const GLbitfield access = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT; 214 outPtr = glMapBufferRange(mBinding, outOffset, size, access); 215 } 216 else 217 { 218 _getBufferData.mOffset = outOffset; 219 _getBufferData.mSize = size; 220 221 outPtr = mFrameAllocator.lock( size ); 222 } 223 224 //set new buffer pos 225 mBufferFreePos = mBufferFreePos + size; 226 227 //align 4bytes 228 mBufferFreePos = ( (mBufferFreePos/4) + 1 ) * 4; 229 } 230 231 void unlock() 232 { 233 if( GFXGL->mCapabilities.bufferStorage ) 234 { 235 return; 236 } 237 else if( GFXGL->glUseMap() ) 238 { 239 PRESERVE_BUFFER( mBinding ); 240 glBindBuffer(mBinding, mBufferName); 241 242 glUnmapBuffer(mBinding); 243 } 244 else 245 { 246 PRESERVE_BUFFER( mBinding ); 247 glBindBuffer(mBinding, mBufferName); 248 249 glBufferSubData( mBinding, _getBufferData.mOffset, _getBufferData.mSize, mFrameAllocator.getlockedPtr() ); 250 251 _getBufferData.mOffset = 0; 252 _getBufferData.mSize = 0; 253 254 mFrameAllocator.unlock(); 255 } 256 257 } 258 259 U32 getHandle() const { return mBufferName; } 260 261 void protectUsedRange() 262 { 263 for( int i = 0; i < mUsedRanges.size(); ++i ) 264 { 265 mLockManager.protectOrderedRange( mUsedRanges[i].start, mUsedRanges[i].end ); 266 } 267 mUsedRanges.clear(); 268 269 if( mCurrectUsedRangeStart < mBufferFreePos ) 270 { 271 mLockManager.protectOrderedRange( mCurrectUsedRangeStart, mBufferFreePos-1 ); 272 mCurrectUsedRangeStart = mBufferFreePos; 273 } 274 } 275 276protected: 277 278 GLuint mBinding; 279 GLuint mBufferName; 280 void *mBufferPtr; 281 U32 mBufferSize; 282 U32 mBufferFreePos; 283 U32 mCurrectUsedRangeStart; 284 285 GLOrderedFenceRangeManager mLockManager; 286 FrameAllocatorLockableHelper mFrameAllocator; 287 288 struct UsedRange 289 { 290 UsedRange(U32 _start = 0, U32 _end = 0) 291 : start(_start), end(_end) 292 { 293 294 } 295 U32 start, end; 296 }; 297 Vector<UsedRange> mUsedRanges; 298}; 299 300 301#endif 302
