// constructor for memory page with segmented type
        public H1GpuMemoryAllocInfo(H1GpuMemoryBlock newBlock)
        {
            m_MemoryBlockRef = newBlock;

            H1GpuMemoryPage page = m_MemoryBlockRef.MemoryPage;

            // this constructor should trigger by segmented type only
            if (page.PageType != H1GpuMemoryPageType.Segmented)
            {
                throw new InvalidOperationException("Invalid parameter for this constructor!");
            }

            // set appropriate properties with memory chunk
            H1GpuMemoryChunk chunk = page.Owner;

            SetProperties(chunk);
        }
        public H1GpuMemoryBlock Allocate(Int32 size)
        {
            // calculate number of blocks we need to allocate
            Int32 numSegments = -1;

            numSegments = (size + m_PageSegmentSize) / m_PageSegmentSize;

            // if available memory blocks are not initialized yet, update them
            if (m_AvailableMemoryBlocks[0] == null)
            {
                UpdateAvailableMemoryBlocks();
            }

            // among available memory blocks, find the best fit block
            Int32 minEvaluatedValue = Int32.MaxValue;
            Int32 minEvaluatedIndex = -1;

            Int32 currIndex = 0;

            foreach (H1GpuMemoryBlock memoryBlock in m_AvailableMemoryBlocks)
            {
                Int32 evaluatedValue = memoryBlock.Counts - numSegments;
                if (evaluatedValue > 0 && minEvaluatedValue > evaluatedValue)
                {
                    // update the values
                    minEvaluatedIndex = currIndex;
                    minEvaluatedValue = evaluatedValue;
                }

                currIndex++;
            }

            // there is no available memory for this page
            if (minEvaluatedIndex == -1)
            {
                return(null);
            }

            H1GpuMemoryBlock newBlock = m_AvailableMemoryBlocks[minEvaluatedIndex];

            // update available memory blocks
            UpdateAvailableMemoryBlocks();

            return(newBlock);
        }
        public void Deallocate(H1GpuMemoryBlock block)
        {
            // apply alloc bits as deallocated
            Int32 startIndex = block.Start;
            Int32 counts     = block.Counts;

            for (Int32 index = startIndex; index < counts; ++index)
            {
                // reset alloc bit as deallocated (free space)
                m_AllocBits.Set(index, false);
            }

            // invalidate memory block
            block.Invalidate();

            // update available memory blocks
            UpdateAvailableMemoryBlocks();
        }
        protected H1GpuMemoryAllocInfo AllocateWithSegmented(Int32 size)
        {
            if (m_Pages.Count == 0)
            {
                CreateNewPageSegmented();
            }

            // allocate memory
            H1GpuMemoryBlock newBlock = m_AvailablePage.Allocate(size);

            // not enough memory we need to make new page
            if (newBlock == null)
            {
                // create new page and allocate newly assigned available page
                CreateNewPageSegmented();
                newBlock = m_AvailablePage.Allocate(size);
            }

            // update available memory page
            UpdateAvailableMemoryPageSegmented();

            return(new H1GpuMemoryAllocInfo(newBlock));
        }
        protected void UpdateAvailableMemoryBlocks()
        {
            Boolean isContiguous           = false;
            Int32   contiguousAllocBitsNum = 0;
            List <H1GpuMemoryBlock> allAvailableMemoryBlocksInPage = new List <H1GpuMemoryBlock>();

            // find all available memory blocks
            Int32 startIndex = 0;
            Int32 currIndex  = 0;

            foreach (Boolean allocBit in m_AllocBits)
            {
                if (allocBit == false && isContiguous == false)
                {
                    isContiguous           = true;
                    startIndex             = currIndex;
                    contiguousAllocBitsNum = 1;
                }

                else if (allocBit == true && isContiguous == true)
                {
                    // if previously contiguous segments exists
                    if (contiguousAllocBitsNum > 0)
                    {
                        // add available memory block
                        H1GpuMemoryBlock newBlock = new H1GpuMemoryBlock(this, startIndex, contiguousAllocBitsNum);
                        allAvailableMemoryBlocksInPage.Add(newBlock);
                    }

                    // reset tracking temp values
                    isContiguous           = false;
                    contiguousAllocBitsNum = 0;
                }

                else if (allocBit == false && isContiguous == true)
                {
                    contiguousAllocBitsNum++;
                }

                else // allocBit == true && isContiguous == false
                {
                    // do nothing
                }

                // update index
                currIndex++;
            }

            // sort allAvailableMemoryBlocksInPage by memory segment counts
            allAvailableMemoryBlocksInPage.OrderBy(x => x.Counts);

            // extract largest three memory blocks
            // zero out the m_AvailableMemoryBlocks
            Array.Clear(m_AvailableMemoryBlocks, 0, m_AvailableMemoryBlocks.Count());
            // reuse currIndex variable
            currIndex = 0;
            foreach (H1GpuMemoryBlock block in allAvailableMemoryBlocksInPage)
            {
                if (currIndex > 3)
                {
                    break;
                }

                m_AvailableMemoryBlocks[currIndex] = block;
            }
        }