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 = 0; 179 U32 mSize = 0; 180 }_getBufferData; 181 182 void lock(const U32 size, U32 offsetAlign, U32 &outOffset, void* &outPtr) 183 { 184 if( !size ) 185 { 186 AssertFatal(0, ""); 187 outOffset = 0; 188 outPtr = NULL; 189 } 190 191 mLockManager.waitFirstRange( mBufferFreePos, (mBufferFreePos + size)-1 ); 192 193 if( mBufferFreePos + size > mBufferSize ) 194 { 195 mUsedRanges.push_back( UsedRange( mBufferFreePos, mBufferSize-1 ) ); 196 mBufferFreePos = 0; 197 } 198 199 // force offset buffer align 200 if( offsetAlign ) 201 mBufferFreePos = ( (mBufferFreePos/offsetAlign) + 1 ) * offsetAlign; 202 203 outOffset = mBufferFreePos; 204 205 if( GFXGL->mCapabilities.bufferStorage ) 206 { 207 outPtr = (U8*)(mBufferPtr) + mBufferFreePos; 208 } 209 else if( GFXGL->glUseMap() ) 210 { 211 PRESERVE_BUFFER( mBinding ); 212 glBindBuffer(mBinding, mBufferName); 213 214 const GLbitfield access = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT; 215 outPtr = glMapBufferRange(mBinding, outOffset, size, access); 216 } 217 else 218 { 219 _getBufferData.mOffset = outOffset; 220 _getBufferData.mSize = size; 221 222 outPtr = mFrameAllocator.lock( size ); 223 } 224 225 //set new buffer pos 226 mBufferFreePos = mBufferFreePos + size; 227 228 //align 4bytes 229 mBufferFreePos = ( (mBufferFreePos/4) + 1 ) * 4; 230 } 231 232 void unlock() 233 { 234 if( GFXGL->mCapabilities.bufferStorage ) 235 { 236 return; 237 } 238 else if( GFXGL->glUseMap() ) 239 { 240 PRESERVE_BUFFER( mBinding ); 241 glBindBuffer(mBinding, mBufferName); 242 243 glUnmapBuffer(mBinding); 244 } 245 else 246 { 247 PRESERVE_BUFFER( mBinding ); 248 glBindBuffer(mBinding, mBufferName); 249 250 glBufferSubData( mBinding, _getBufferData.mOffset, _getBufferData.mSize, mFrameAllocator.getlockedPtr() ); 251 252 _getBufferData.mOffset = 0; 253 _getBufferData.mSize = 0; 254 255 mFrameAllocator.unlock(); 256 } 257 258 } 259 260 U32 getHandle() const { return mBufferName; } 261 262 void protectUsedRange() 263 { 264 for( int i = 0; i < mUsedRanges.size(); ++i ) 265 { 266 mLockManager.protectOrderedRange( mUsedRanges[i].start, mUsedRanges[i].end ); 267 } 268 mUsedRanges.clear(); 269 270 if( mCurrectUsedRangeStart < mBufferFreePos ) 271 { 272 mLockManager.protectOrderedRange( mCurrectUsedRangeStart, mBufferFreePos-1 ); 273 mCurrectUsedRangeStart = mBufferFreePos; 274 } 275 } 276 277protected: 278 279 GLuint mBinding; 280 GLuint mBufferName; 281 void *mBufferPtr; 282 U32 mBufferSize; 283 U32 mBufferFreePos; 284 U32 mCurrectUsedRangeStart; 285 286 GLOrderedFenceRangeManager mLockManager; 287 FrameAllocatorLockableHelper mFrameAllocator; 288 289 struct UsedRange 290 { 291 UsedRange(U32 _start = 0, U32 _end = 0) 292 : start(_start), end(_end) 293 { 294 295 } 296 U32 start, end; 297 }; 298 Vector<UsedRange> mUsedRanges; 299}; 300 301 302#endif 303