/// <summary> /// /// </summary> public GLESHardwareBufferManagerBase() { _scratchBufferPool = new byte[ScratchPoolSize]; unsafe { _scratchBufferPoolPtr = Memory.PinObject(_scratchBufferPool); GLESScratchBufferAlloc *ptrAlloc = (GLESScratchBufferAlloc *)_scratchBufferPoolPtr; ptrAlloc->Size = ScratchPoolSize - sizeof(GLESScratchBufferAlloc); ptrAlloc->Free = 1; } }
/// <summary> /// Allocator method to allow us to use a pool of memory as a scratch /// area for hardware buffers. This is because glMapBuffer is incredibly /// inefficient, seemingly no matter what options we give it. So for the /// period of lock/unlock, we will instead allocate a section of a local /// memory pool, and use glBufferSubDataARB / glGetBufferSubDataARB /// instead. /// </summary> /// <param name="size"></param> /// <returns></returns> public IntPtr AllocateScratch(int size) { unsafe { LogManager.Instance.Write("Allocate Scratch : " + size.ToString()); // simple forward link search based on alloc sizes // not that fast but the list should never get that long since not many // locks at once (hopefully) lock ( _scratchLock ) { // Alignment - round up the size to 32 bits // control blocks are 32 bits too so this packs nicely if (size % 4 != 0) { size += 4 - (size % 4); } int bufferPos = 0; byte *dataPtr = (byte *)_scratchBufferPoolPtr; while (bufferPos < ScratchPoolSize) { LogManager.Instance.Write("Bufferpos " + bufferPos); GLESScratchBufferAlloc *pNext = (GLESScratchBufferAlloc *)(dataPtr + bufferPos); // Big enough? if (pNext->Free != 0 && pNext->Size >= size) { LogManager.Instance.Write("Was big enough!"); // split? And enough space for control block if (pNext->Size > size + sizeof(GLESScratchBufferAlloc)) { LogManager.Instance.Write("Split! " + pNext->Size.ToString()); int offset = sizeof(GLESScratchBufferAlloc) + size; GLESScratchBufferAlloc *pSplitAlloc = (GLESScratchBufferAlloc *)(dataPtr + bufferPos + offset); pSplitAlloc->Free = 1; // split size is remainder minus new control block pSplitAlloc->Size = pNext->Size - size - sizeof(GLESScratchBufferAlloc); // New size of current pNext->Size = size; } // allocate and return pNext->Free = 0; // return pointer just after this control block (++ will do that for us) return((IntPtr)(++pNext)); } bufferPos += sizeof(GLESScratchBufferAlloc) + pNext->Size; } //end while return(IntPtr.Zero); } //end lock } //end unsafe }
/// <summary> /// /// </summary> /// <param name="ptr"></param> public void DeallocateScratch(IntPtr ptr) { unsafe { lock ( _scratchLock ) { // Simple linear search dealloc int bufferPos = 0; GLESScratchBufferAlloc *pLast = (GLESScratchBufferAlloc *)IntPtr.Zero; byte *dataPtr = (byte *)_scratchBufferPoolPtr; GLESScratchBufferAlloc *pToDelete = (GLESScratchBufferAlloc *)ptr; while (bufferPos < ScratchPoolSize) { GLESScratchBufferAlloc *pCurrent = (GLESScratchBufferAlloc *)(dataPtr + bufferPos); // Pointers match? if ((dataPtr + bufferPos + sizeof(GLESScratchBufferAlloc)) == pToDelete) { // dealloc pCurrent->Free = 1; // merge with previous if (pLast != (GLESScratchBufferAlloc *)IntPtr.Zero && pLast->Free != 0) { // adjust buffer pos bufferPos -= (pLast->Size + sizeof(GLESScratchBufferAlloc)); // merge free space pLast->Size += pCurrent->Size + sizeof(GLESScratchBufferAlloc); pCurrent = pLast; } // merge with next int offset = bufferPos + pCurrent->Size + sizeof(GLESScratchBufferAlloc); if (offset < ScratchPoolSize) { GLESScratchBufferAlloc *pNext = (GLESScratchBufferAlloc *)(dataPtr + offset); if (pNext->Free != 0) { pCurrent->Size += pNext->Size + sizeof(GLESScratchBufferAlloc); } } //done return; } bufferPos += sizeof(GLESScratchBufferAlloc) + pCurrent->Size; pLast = pCurrent; } //end while } //end lock } //end unsafe // Should never get here unless there's a corruption Utilities.Contract.Requires(false, "Memory deallocation error"); }