123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- #ifndef GL_CIRCULAR_VOLATILE_BUFFER_H
- #define GL_CIRCULAR_VOLATILE_BUFFER_H
- #include "gfx/gl/gfxGLDevice.h"
- #include "gfx/gl/gfxGLUtils.h"
- class GLFenceRange
- {
- public:
- GLFenceRange() : mStart(0), mEnd(0), mSync(0)
- {
-
- }
- ~GLFenceRange()
- {
- //the order of creation/destruction of static variables is indetermined... depends on detail of the build
- //looks like for some reason on windows + sdl + opengl the order make invalid / wrong the process TODO: Refactor -LAR
- //AssertFatal( mSync == 0, "");
- }
- void init(U32 start, U32 end)
- {
- PROFILE_SCOPE(GFXGLQueryFence_issue);
- mStart = start;
- mEnd = end;
- mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- }
- bool checkOverlap(U32 start, U32 end)
- {
- if( mStart < end && start < mEnd )
- return true;
- return false;
- }
- void wait()
- {
- PROFILE_SCOPE(GFXGLQueryFence_block);
- GLbitfield waitFlags = 0;
- GLuint64 waitDuration = 0;
- while( 1 )
- {
- GLenum waitRet = glClientWaitSync( mSync, waitFlags, waitDuration );
- if( waitRet == GL_ALREADY_SIGNALED || waitRet == GL_CONDITION_SATISFIED )
- {
- break;
- }
- if( waitRet == GL_WAIT_FAILED )
- {
- AssertFatal(0, "GLSync failed.");
- break;
- }
-
- waitFlags = GL_SYNC_FLUSH_COMMANDS_BIT;
- waitDuration = scOneSecondInNanoSeconds;
- }
- glDeleteSync(mSync);
- mSync = 0;
- }
- void swap( GLFenceRange &r )
- {
- GLFenceRange temp;
- temp = *this;
- *this = r;
- r = temp;
- }
- protected:
- U32 mStart, mEnd;
- GLsync mSync;
- static const GLuint64 scOneSecondInNanoSeconds = 1000000000;
- GLFenceRange( const GLFenceRange &);
- GLFenceRange& operator=(const GLFenceRange &r)
- {
- mStart = r.mStart;
- mEnd = r.mEnd;
- mSync = r.mSync;
- return *this;
- }
- };
- class GLOrderedFenceRangeManager
- {
- public:
- ~GLOrderedFenceRangeManager( )
- {
- //the order of creation/destruction of static variables is indetermined... depends on detail of the build
- //looks like for some reason on windows + sdl + opengl the order make invalid / wrong the process TODO: Refactor -LAR
- //waitAllRanges( );
- }
- void protectOrderedRange( U32 start, U32 end )
- {
- mFenceRanges.increment();
- GLFenceRange &range = mFenceRanges.last();
- range.init( start, end );
- }
- void waitFirstRange( U32 start, U32 end )
- {
- if( !mFenceRanges.size() || !mFenceRanges[0].checkOverlap( start, end ) )
- return;
-
- mFenceRanges[0].wait();
- mFenceRanges.pop_front();
- }
- void waitOverlapRanges( U32 start, U32 end )
- {
- for( U32 i = 0; i < mFenceRanges.size(); ++i )
- {
- if( !mFenceRanges[i].checkOverlap( start, end ) )
- continue;
-
- mFenceRanges[i].wait();
- mFenceRanges.erase(i);
- }
- }
- void waitAllRanges()
- {
- for( int i = 0; i < mFenceRanges.size(); ++i )
- mFenceRanges[i].wait();
- mFenceRanges.clear();
- }
- protected:
- Vector<GLFenceRange> mFenceRanges;
- };
- class GLCircularVolatileBuffer
- {
- public:
- GLCircularVolatileBuffer(GLuint binding)
- : mBinding(binding), mBufferName(0), mBufferPtr(NULL), mBufferSize(0), mBufferFreePos(0), mCurrectUsedRangeStart(0)
- {
- init();
- }
- ~GLCircularVolatileBuffer()
- {
- glDeleteBuffers(1, &mBufferName);
- }
- void init()
- {
- glGenBuffers(1, &mBufferName);
- PRESERVE_BUFFER( mBinding );
- glBindBuffer(mBinding, mBufferName);
-
- const U32 cSizeInMB = 10;
- mBufferSize = (cSizeInMB << 20);
- if( GFXGL->mCapabilities.bufferStorage )
- {
- const GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
- glBufferStorage(mBinding, mBufferSize, NULL, flags);
- mBufferPtr = glMapBufferRange(mBinding, 0, mBufferSize, flags);
- }
- else
- {
- glBufferData(mBinding, mBufferSize, NULL, GL_DYNAMIC_DRAW);
- }
- }
- struct
- {
- U32 mOffset = 0;
- U32 mSize = 0;
- }_getBufferData;
- void lock(const U32 size, U32 offsetAlign, U32 &outOffset, void* &outPtr)
- {
- if( !size )
- {
- AssertFatal(0, "");
- outOffset = 0;
- outPtr = NULL;
- }
- mLockManager.waitFirstRange( mBufferFreePos, (mBufferFreePos + size)-1 );
- if( mBufferFreePos + size > mBufferSize )
- {
- mUsedRanges.push_back( UsedRange( mBufferFreePos, mBufferSize-1 ) );
- mBufferFreePos = 0;
- }
- // force offset buffer align
- if( offsetAlign )
- mBufferFreePos = ( (mBufferFreePos/offsetAlign) + 1 ) * offsetAlign;
- outOffset = mBufferFreePos;
- if( GFXGL->mCapabilities.bufferStorage )
- {
- outPtr = (U8*)(mBufferPtr) + mBufferFreePos;
- }
- else if( GFXGL->glUseMap() )
- {
- PRESERVE_BUFFER( mBinding );
- glBindBuffer(mBinding, mBufferName);
- const GLbitfield access = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
- outPtr = glMapBufferRange(mBinding, outOffset, size, access);
- }
- else
- {
- _getBufferData.mOffset = outOffset;
- _getBufferData.mSize = size;
- outPtr = mFrameAllocator.lock( size );
- }
- //set new buffer pos
- mBufferFreePos = mBufferFreePos + size;
- //align 4bytes
- mBufferFreePos = ( (mBufferFreePos/4) + 1 ) * 4;
- }
- void unlock()
- {
- if( GFXGL->mCapabilities.bufferStorage )
- {
- return;
- }
- else if( GFXGL->glUseMap() )
- {
- PRESERVE_BUFFER( mBinding );
- glBindBuffer(mBinding, mBufferName);
- glUnmapBuffer(mBinding);
- }
- else
- {
- PRESERVE_BUFFER( mBinding );
- glBindBuffer(mBinding, mBufferName);
- glBufferSubData( mBinding, _getBufferData.mOffset, _getBufferData.mSize, mFrameAllocator.getlockedPtr() );
- _getBufferData.mOffset = 0;
- _getBufferData.mSize = 0;
- mFrameAllocator.unlock();
- }
-
- }
- U32 getHandle() const { return mBufferName; }
- void protectUsedRange()
- {
- for( int i = 0; i < mUsedRanges.size(); ++i )
- {
- mLockManager.protectOrderedRange( mUsedRanges[i].start, mUsedRanges[i].end );
- }
- mUsedRanges.clear();
- if( mCurrectUsedRangeStart < mBufferFreePos )
- {
- mLockManager.protectOrderedRange( mCurrectUsedRangeStart, mBufferFreePos-1 );
- mCurrectUsedRangeStart = mBufferFreePos;
- }
- }
- protected:
- GLuint mBinding;
- GLuint mBufferName;
- void *mBufferPtr;
- U32 mBufferSize;
- U32 mBufferFreePos;
- U32 mCurrectUsedRangeStart;
- GLOrderedFenceRangeManager mLockManager;
- FrameAllocatorLockableHelper mFrameAllocator;
- struct UsedRange
- {
- UsedRange(U32 _start = 0, U32 _end = 0)
- : start(_start), end(_end)
- {
- }
- U32 start, end;
- };
- Vector<UsedRange> mUsedRanges;
- };
- #endif
|