/// <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");
        }