📄 ra.c
字号:
RETURNS: span marker boundary tag
</function>
-----------------------------------------------------------------------------*/
static BT *
_BuildSpanMarker (RA_ARENA *pArena, IMG_UINTPTR_T base)
{
BT *pBT;
PVR_ASSERT (pArena != IMG_NULL);
PVR_ASSERT (pArena->pState != IMG_NULL);
pBT = POOL_Alloc (pArena->pState->pBTPool);
if (pBT != IMG_NULL)
{
pBT->type = btt_span;
pBT->base = base;
};
return pBT;
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: _BuildBT
PURPOSE: Construct a boundary tag for a free segment.
PARAMETERS: In: pArena -
In: base - the base of the resource segment.
In: uSize - the extent of the resouce segment.
RETURNS: boundary tag
</function>
-----------------------------------------------------------------------------*/
static BT *
_BuildBT (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
BT *pBT;
PVR_ASSERT (pArena!=IMG_NULL);
PVR_ASSERT (pArena->pState!=IMG_NULL);
pBT = POOL_Alloc (pArena->pState->pBTPool);
if (pBT!=IMG_NULL)
{
pBT->type = btt_free;
pBT->base = base;
pBT->uSize = uSize;
}
return pBT;
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: _InsertResource
PURPOSE: Add a free resource segment to an arena.
PARAMETERS: In: pArena - the arena.
In: base - the base of the resource segment.
In: uSize - the extent of the resource segment.
RETURNS: IMG_FALSE failed
IMG_TRUE success
</function>
-----------------------------------------------------------------------------*/
static IMG_BOOL
_InsertResource (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
BT *pBT;
PVR_ASSERT (pArena!=IMG_NULL);
pBT = _BuildBT (pArena, base, uSize);
if (pBT == IMG_NULL)
return IMG_FALSE;
_SegmentListInsert (pArena, pBT);
_FreeListInsert (pArena, pBT);
#ifdef RA_STATS
pArena->sStatistics.uTotalResourceCount+=uSize;
pArena->sStatistics.uFreeResourceCount+=uSize;
pArena->sStatistics.uSpanCount++;
#endif
return IMG_TRUE;
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: _InsertResourceSpan
PURPOSE: Add a free resource span to an arena, complete with span markers.
PARAMETERS: In: pArena - the arena.
In: base - the base of the resource segment.
In: uSize - the extent of the resource segment.
RETURNS: the boundary tag representing the free resource segment,
or IMG_NULL on failure.
</function>
-----------------------------------------------------------------------------*/
static BT *
_InsertResourceSpan (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
BT *pSpanStart;
BT *pSpanEnd;
BT *pBT;
PVR_ASSERT (pArena != IMG_NULL);
PVR_ASSERT (pArena->pState != IMG_NULL);
PVR_DPF ((PVR_DBG_MESSAGE,
"ra:_InsertResourceSpan (arena='%s', base=0x%x, size=0x%x)",
pArena->name, base, uSize));
pSpanStart = _BuildSpanMarker (pArena, base);
if (pSpanStart == IMG_NULL) goto fail_start;
pSpanEnd = _BuildSpanMarker (pArena, base + uSize);
if (pSpanEnd == IMG_NULL) goto fail_end;
pBT = _BuildBT (pArena, base, uSize);
if (pBT == IMG_NULL) goto fail_bt;
_SegmentListInsert (pArena, pSpanStart);
_SegmentListInsertAfter (pArena, pSpanStart, pBT);
_FreeListInsert (pArena, pBT);
_SegmentListInsertAfter (pArena, pBT, pSpanEnd);
#ifdef RA_STATS
pArena->sStatistics.uTotalResourceCount+=uSize;
/* pArena->sStatistics.uFreeResourceCount+=uSize;
This has got to be wrong as uFreeResourceCount ends
up larger than uTotalResourceCount by uTotalResourceCount
- allocated memory
*/
#endif
return pBT;
fail_bt:
POOL_Free (pArena->pState->pBTPool, pSpanEnd);
fail_end:
POOL_Free (pArena->pState->pBTPool, pSpanStart);
fail_start:
return IMG_NULL;
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: _FreeBT
PURPOSE: Free a boundary tag taking care of the segment list and the
boundary tag free table.
PARAMETERS: In: pArena - the arena.
In: pBT - the boundary tag to free.
RETURNS: None
</function>
------------------------------------------------------------------------------*/
static void
_FreeBT (RA_ARENA *pArena, BT *pBT)
{
BT *pNeighbour;
PVR_ASSERT (pArena!=IMG_NULL);
PVR_ASSERT (pArena->pState!=IMG_NULL);
PVR_ASSERT (pBT!=IMG_NULL);
#ifdef RA_STATS
pArena->sStatistics.uLiveSegmentCount--;
pArena->sStatistics.uFreeSegmentCount++;
pArena->sStatistics.uFreeResourceCount+=pBT->uSize;
#endif
/* try and coalesce with left neighbour */
pNeighbour = pBT->pPrevSegment;
if (pNeighbour!=IMG_NULL
&& pNeighbour->type == btt_free
&& pNeighbour->base + pNeighbour->uSize == pBT->base)
{
_FreeListRemove (pArena, pNeighbour);
_SegmentListRemove (pArena, pNeighbour);
pBT->base = pNeighbour->base;
pBT->uSize += pNeighbour->uSize;
POOL_Free (pArena->pState->pBTPool, pNeighbour);
#ifdef RA_STATS
pArena->sStatistics.uFreeSegmentCount--;
#endif
}
/* try to coalesce with right neighbour */
pNeighbour = pBT->pNextSegment;
if (pNeighbour!=IMG_NULL
&& pNeighbour->type == btt_free
&& pBT->base + pBT->uSize == pNeighbour->base)
{
_FreeListRemove (pArena, pNeighbour);
_SegmentListRemove (pArena, pNeighbour);
pBT->uSize += pNeighbour->uSize;
POOL_Free (pArena->pState->pBTPool, pNeighbour);
#ifdef RA_STATS
pArena->sStatistics.uFreeSegmentCount--;
#endif
}
if (pBT->pNextSegment!=IMG_NULL && pBT->pNextSegment->type == btt_span
&& pBT->pPrevSegment!=IMG_NULL && pBT->pPrevSegment->type == btt_span)
{
BT *next = pBT->pNextSegment;
BT *prev = pBT->pPrevSegment;
_SegmentListRemove (pArena, next);
_SegmentListRemove (pArena, prev);
_SegmentListRemove (pArena, pBT);
pArena->pImportFree (pArena->pImportHandle, pBT->base, pBT->pRef);
#ifdef RA_STATS
pArena->sStatistics.uSpanCount--;
pArena->sStatistics.uExportCount++;
pArena->sStatistics.uFreeSegmentCount--;
pArena->sStatistics.uFreeResourceCount-=pBT->uSize;
pArena->sStatistics.uTotalResourceCount-=pBT->uSize;
#endif
POOL_Free (pArena->pState->pBTPool, next);
POOL_Free (pArena->pState->pBTPool, prev);
POOL_Free (pArena->pState->pBTPool, pBT);
}
else
_FreeListInsert (pArena, pBT);
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: _AttemptAllocAligned
PURPOSE: Attempt an allocation from an arena.
PARAMETERS: In: pArena - the arena.
In: uSize - the requested allocation size.
Out: pRef - the user references associated with the allocated
segment.
In: flags - allocation flags
In: uAlignment - required uAlignment, or 0
In: uAlignmentOffset
Out: base - allocated resource base
RETURNS: IMG_FALSE failure
IMG_TRUE success
</function>
-----------------------------------------------------------------------------*/
static IMG_BOOL
_AttemptAllocAligned (RA_ARENA *pArena,
IMG_SIZE_T uSize,
void **pRef,
IMG_UINT32 uFlags,
IMG_UINT32 uAlignment,
IMG_UINT32 uAlignmentOffset,
IMG_UINTPTR_T *base)
{
IMG_UINT32 uIndex;
PVR_ASSERT (pArena!=IMG_NULL);
UNREFERENCED_PARAMETER (uFlags);
if (uAlignment>1)
uAlignmentOffset %= uAlignment;
/* search for a near fit free boundary tag, start looking at the
log2 free table for our required size and work on up the
table. */
uIndex = log2 (uSize);
#if 0
/* If the size required is exactly 2**n then use the n bucket, because
we know that every free block in that bucket is larger than 2**n,
otherwise start at then next bucket up. */
if (1u<<uIndex < uSize)
uIndex++;
#endif
while (uIndex < FREE_TABLE_LIMIT && pArena->aHeadFree[uIndex]==IMG_NULL)
uIndex++;
while (uIndex < FREE_TABLE_LIMIT)
{
if (pArena->aHeadFree[uIndex]!=IMG_NULL)
{
/* we have a cached free boundary tag */
BT *pBT;
pBT = pArena->aHeadFree [uIndex];
while (pBT!=IMG_NULL)
{
IMG_UINTPTR_T aligned_base;
if (uAlignment>1)
aligned_base = (pBT->base + uAlignmentOffset + uAlignment - 1) / uAlignment * uAlignment - uAlignmentOffset;
else
aligned_base = pBT->base;
PVR_DPF ((PVR_DBG_MESSAGE,
"..ra:_AttemptAllocAligned () pBT-base=0x%x "
"pBT-size=0x%x alignedbase=0x%x size=0x%x",
pBT->base, pBT->uSize, aligned_base, uSize));
if (pBT->base + pBT->uSize >= aligned_base + uSize)
{
_FreeListRemove (pArena, pBT);
PVR_ASSERT (pBT->type == btt_free);
#ifdef RA_STATS
pArena->sStatistics.uLiveSegmentCount++;
pArena->sStatistics.uFreeSegmentCount--;
pArena->sStatistics.uFreeResourceCount-=pBT->uSize;
#endif
/* with uAlignment we might need to discard the front of this segment */
if (aligned_base > pBT->base)
{
BT *pNeighbour;
pNeighbour = _SegmentSplit (pArena, pBT, aligned_base-pBT->base);
/* partition the buffer, create a new boundary tag */
if (pNeighbour==IMG_NULL)
return IMG_FALSE;
_FreeListInsert (pArena, pBT);
#ifdef RA_STATS
pArena->sStatistics.uFreeSegmentCount++;
pArena->sStatistics.uFreeResourceCount+=pBT->uSize;
#endif
pBT = pNeighbour;
}
/* the segment might be too big, if so, discard the back of the segment */
if (pBT->uSize > uSize)
{
BT *pNeighbour;
pNeighbour = _SegmentSplit (pArena, pBT, uSize);
/* partition the buffer, create a new boundary tag */
if (pNeighbour==IMG_NULL)
return IMG_FALSE;
_FreeListInsert (pArena, pNeighbour);
#ifdef RA_STATS
pArena->sStatistics.uFreeSegmentCount++;
pArena->sStatistics.uFreeResourceCount+=pNeighbour->uSize;
#endif
}
pBT->type = btt_live;
if (!HASH_Insert (pArena->pSegmentHash, pBT->base, (IMG_UINTPTR_T) pBT))
{
_FreeBT (pArena, pBT);
return IMG_FALSE;
}
if (pRef!=IMG_NULL)
*pRef = pBT->pRef;
*base = pBT->base;
return IMG_TRUE;
}
pBT = pBT->pNextFree;
}
}
uIndex++;
}
return IMG_FALSE;
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: RA_Initialise
PURPOSE: To initialise the ra module. Must be called before any
other ra API function.
PARAMETERS: In: pHashState - HASH state pointer (from HASH_Initialise)
Out: ppState - Receives the ra state pointer.
RETURNS: IMG_FALSE - Failure
IMG_TRUE - Success
</function>
-----------------------------------------------------------------------------*/
IMG_BOOL
RA_Initialise (HASH_STATE *pHashState, RA_STATE **ppState)
{
RA_STATE *pState;
PVR_DPF ((PVR_DBG_MESSAGE, "RA_Initialise()"));
PVR_ASSERT (pHashState!=IMG_NULL);
PVR_ASSERT (ppState!=IMG_NULL);
HostAllocMem (PVRSRV_HOST_PAGEABLE_HEAP,
sizeof (*pState),
(IMG_VOID **)&pState, 0);
if (pState == IMG_NULL) goto fail_alloc;
pState->pHashState = pHashState;
pState->pArenaPool = POOL_Create ("img-arena", sizeof (RA_ARENA));
if (pState->pArenaPool == IMG_NULL) goto fail_arena;
pState->pBTPool = POOL_Create ("img-bt", sizeof (BT));
if (pState->pBTPool == IMG_NULL) goto fail_bt;
*ppState = pState;
return IMG_TRUE;
fail_bt:
POOL_Delete (pState->pArenaPool);
fail_arena:
HostPageableByteFree (pState);
fail_alloc:
return IMG_FALSE;
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: RA_Finalise
PURPOSE: To finalise the ra module.
PARAMETERS: pState - pointer to ra state
RETURNS: None
</function>
-----------------------------------------------------------------------------*/
void
RA_Finalise (RA_STATE *pState)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -