📄 resources.c
字号:
static PVRSRV_ERROR IMG_CALLCONV ResetContext (PVRSRV_DEV_INFO *psDevInfo,
PVRSRV_TARENDERINFO *psTARenderInfo,
PVRSRV_HW_INFO *psHWInfo)
{
DEVICE3D *ps3D = &psDevInfo->sDeviceSpecific.s3D;
PVRSRV_ERROR eError = PVRSRV_OK;
PVRSRV_HWREG sRegs[2];
PVR3DIF_SHAREDDATA *psSharedData = psTARenderInfo->psSharedData;
IMG_UINT32 ui32HWContextID;
IMG_BOOL bTimeout;
IMG_BOOL bStart;
IMG_UINT32 uiStart;
/* wait for a set of region headers to become free */
bTimeout = IMG_TRUE;
bStart = IMG_FALSE;
uiStart = 0;
do
{
if (psSharedData->aui32ContextStatus[0] == PVR3DIF_3DCTL_FREE)
{
psSharedData->aui32ContextStatus[0] = PVR3DIF_3DCTL_PREPARING;
psSharedData->ui32CurrentRenderData = 0;
bTimeout = IMG_FALSE;
break;
}
if (psSharedData->aui32ContextStatus[1] == PVR3DIF_3DCTL_FREE)
{
psSharedData->aui32ContextStatus[1] = PVR3DIF_3DCTL_PREPARING;
psSharedData->ui32CurrentRenderData = 1;
bTimeout = IMG_FALSE;
break;
}
/* If the 3D is already in progress, no need to kick the ISR */
if(ps3D->b3DIdle && ps3D->b2DIdle)
{
SysKickCmdProc (psHWInfo->pui32KickerAddr);
}
/* We may relinquish if more than one 3D app is running */
if(ps3D->ui32ParamBufferRefCount > 1)
{
HostReleaseThreadQuanta();
}
if (bStart == IMG_FALSE)
{
bStart = IMG_TRUE;
uiStart = HostClockus();
}
HostWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
} while ((HostClockus() - uiStart) < MAX_HW_TIME_US);
if (bTimeout == IMG_TRUE)
{
PVR_DPF((PVR_DBG_ERROR, "ResetContext: failed to get free region header set"));
return PVRSRV_ERROR_GENERIC;
}
eError = GetFreeHWContextID(psDevInfo, psHWInfo, &ui32HWContextID);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "ResetContext: Failed to get free HW context ID"));
return eError;
}
/*
store off record of what HWContextID we're using
*/
psSharedData->aui32HWContextID[psSharedData->ui32CurrentRenderData] = ui32HWContextID;
/* update the TA context id */
sRegs[0].ui32RegAddr = MBX1_TAGLOBREG_RENDER_ID;
sRegs[0].ui32RegVal = ui32HWContextID;
/* Write to context-reset register to kick-off the reset */
sRegs[1].ui32RegAddr = MBX1_TAGLOBREG_CONTEXT_RESET;
sRegs[1].ui32RegVal = 1;
PDUMPREG(psTARenderInfo->psPDContext, PDUMPTAGS_REG_MBX, MBX1_GLOBREG_INT_CLEAR, MBX1_INT_TA_CONTEXT);
WriteHWRegs(psHWInfo->pvRegsBase, 2, sRegs);
PDUMPREGARRAY(psTARenderInfo->psPDContext, PDUMPTAGS_REG_MBX, sRegs, 2);
/*
If we've changed render target since the last
TA pass, reset the tail pointers
n.b. we only actually need to do this if the render target dimensions change
This doesn't work so I now just test for context changes. below is the original test:
if((ps3D->ui32LastTilesX != psSharedData->ui32TilesX)
&& (ps3D->ui32LastTilesY != psSharedData->ui32TilesY))
*/
if(ps3D->ui32Last3DCtlID != psSharedData->ui32UniqueID)
{
HostMemSet( psTARenderInfo->pvTailPtrs,
0,
psSharedData->ui32TailPtrSize);
}
/* Wait for the TA to finish resetting the HW-context */
if(PollForValue ((volatile IMG_UINT32 *)&ps3D->bTAContextInterrupt,
IMG_TRUE,
0xFFFFFFFF,
MAX_HW_TIME_US/WAIT_TRY_COUNT,
WAIT_TRY_COUNT) != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "ResetContext: Failed to reset"));
eError = PVRSRV_ERROR_TIMEOUT;
}
/* reset bTAContextInterrupt boolean */
ps3D->bTAContextInterrupt = IMG_FALSE;
/*
context reset represents the start of a new scene so
clear the scene invalidate flag in case a context on
another process blew up
*/
psSharedData->bSceneInvalidated = IMG_FALSE;
PDUMPPOL(psTARenderInfo->psPDContext, PDUMPTAGS_REG_MBX, MBX1_TAGLOBREG_INTSTATUS, MBX1_INT_TA_CONTEXT, MBX1_INT_TA_CONTEXT, 0, 10, 1000);
PDUMPREG(psTARenderInfo->psPDContext, PDUMPTAGS_REG_MBX, MBX1_GLOBREG_INT_CLEAR, MBX1_INT_TA_CONTEXT);
return eError;
}
/*!
******************************************************************************
@Function PVRSRVAcquireTA
@Description
USER MODE FUNCTION
Acquire the TA. If the TA is not available, this function will block until available.
This should not require a kernel transition to services if the OS has mechanisms for
cheap user mutexes.
@Input psDevInfo : UM devinfo
@Input psTARenderInfo : TA and 3D render info
@Input psHWInfo : HW Info structure
@Input bFirstTAInScene : first time to acquire TA in a scene
@Input bBlock : block until TA is available or return failure
@Output *pbHasContextSwitched : Pointer to boolean showing if TA context has
changed since this function was last called.
If TRUE, driver must resubmit all TA/VGP state
n.b. It's the responsibility of the driver to setup all TA registers. It needs
to do this at the start of each scene and whenever *pbHasContextSwitched
is TRUE upon acquiring the TA.
@Return PVRSRV_ERROR
******************************************************************************/
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVAcquireTA (PVRSRV_DEV_INFO *psDevInfo,
PVRSRV_TARENDERINFO *psTARenderInfo,
PVRSRV_HW_INFO *psHWInfo,
IMG_BOOL bFirstTAInScene,
IMG_BOOL bBlock,
IMG_BOOL *pbHasContextSwitched)
{
DEVICE3D *ps3D = &psDevInfo->sDeviceSpecific.s3D;
PVR3DIF_SHAREDDATA *psSharedData = psTARenderInfo->psSharedData;
PVRSRV_ERROR eError;
/* Current psRenderCtl acquires the TA */
eError = HostLockResource(&ps3D->hTAResource, bBlock);
if (eError != PVRSRV_OK)
{
return eError;
}
/* if another process blew up mid-scene we need to wait for a new scene */
if (psSharedData->bSceneInvalidated)
{
if (bFirstTAInScene)
{
*pbHasContextSwitched = IMG_TRUE;
}
else
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVAcquireTA: current scene is invalidated, wait for new scene"));
eError = HostUnlockResource(&ps3D->hTAResource);
if (eError != PVRSRV_OK)
{
return eError;
}
return PVRSRV_ERROR_SCENE_INVALID;
}
}
else
{
/* assume context will not switch */
*pbHasContextSwitched = IMG_FALSE;
}
/* is the last psTARenderData to acquire the TA different ? */
if (ps3D->ui32Last3DCtlID != psSharedData->ui32UniqueID)
{
/* is the last psTARenderData MidScene ? */
if (ps3D->bLastContextMidScene)
{
StopTA (psDevInfo, psHWInfo, IMG_FALSE, IMG_FALSE, psTARenderInfo);
StoreContext (psDevInfo, psHWInfo, psTARenderInfo);
}
else
{
eError = PollForValue ((volatile IMG_UINT32 *)&ps3D->bTAIdle,
IMG_TRUE,
0xFFFFFFFF,
MAX_HW_TIME_US/WAIT_TRY_COUNT,
WAIT_TRY_COUNT);
if (eError != PVRSRV_OK)
{
goto ErrorHandler;
}
PDUMPPOL(psTARenderInfo->psPDContext, PDUMPTAGS_REG_MBX, MBX1_TAGLOBREG_INTSTATUS, MBX1_INT_TA_COMPLETE, MBX1_INT_TA_COMPLETE, 0, 10, 1000);
PDUMPREG(psTARenderInfo->psPDContext, PDUMPTAGS_REG_MBX, MBX1_GLOBREG_INT_CLEAR, MBX1_INT_TA_COMPLETE);
#ifdef DYNAMIC_3DCLOCKGATING
/* Ungate the TA */
eError = SysCoreEnable(psDevInfo, DEV_CGCORE_MBX_TA, bBlock);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVAcquireTA: failed to ungate 3d"));
goto ErrorHandler;
}
#endif
}
/* is the new psTARenderData MidScene ? */
if (bFirstTAInScene)
{
eError = ResetContext(psDevInfo, psTARenderInfo, psHWInfo);
}
else
{
eError = LoadContext(psDevInfo, psTARenderInfo, psHWInfo);
}
if (eError != PVRSRV_OK)
{
goto ErrorHandler;
}
/* signal that context has switched */
*pbHasContextSwitched = IMG_TRUE;
}
else if (bFirstTAInScene)
{
/* TA may still be finishing off last scene */
eError = PollForValue ((volatile IMG_UINT32 *)&ps3D->bTAIdle,
IMG_TRUE,
0xFFFFFFFF,
MAX_HW_TIME_US/WAIT_TRY_COUNT,
WAIT_TRY_COUNT);
if (eError != PVRSRV_OK)
{
goto ErrorHandler;
}
PDUMPPOL(psTARenderInfo->psPDContext, PDUMPTAGS_REG_MBX, MBX1_TAGLOBREG_INTSTATUS, MBX1_INT_TA_COMPLETE, MBX1_INT_TA_COMPLETE, 0, 10, 1000);
PDUMPREG(psTARenderInfo->psPDContext, PDUMPTAGS_REG_MBX, MBX1_GLOBREG_INT_CLEAR, MBX1_INT_TA_COMPLETE);
#ifdef DYNAMIC_3DCLOCKGATING
/* Ungate the TA */
eError = SysCoreEnable(psDevInfo, DEV_CGCORE_MBX_TA, bBlock);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVAcquireTA: failed to ungate 3d"));
goto ErrorHandler;
}
#endif
eError = ResetContext(psDevInfo, psTARenderInfo, psHWInfo);
if (eError != PVRSRV_OK)
{
goto ErrorHandler;
}
}
/*
save the last render data
*/
ps3D->LastEVMContextDevVAddr = psSharedData->EVMContextDevVAddr;
ps3D->LastTAContextDevVAddr = psSharedData->TAContextDevVAddr;
ps3D->ui32Last3DCtlID = psSharedData->ui32UniqueID;
ps3D->ui32LastTilesX = psSharedData->ui32TilesX;
ps3D->ui32LastTilesY = psSharedData->ui32TilesY;
/*
TA complete handler needs to know what we've been working on
*/
ps3D->psCurrentTARenderInfoKM = psTARenderInfo->psTARenderInfoKM;
ps3D->psCurrentTARenderInfoUM = psTARenderInfo;
/*
if we're about use the TA we are technically midscene
*/
ps3D->bLastContextMidScene = IMG_TRUE;
/*
mark TA as busy
*/
ps3D->bTAIdle = IMG_FALSE;
return eError;
ErrorHandler:
if(HostUnlockResource(&ps3D->hTAResource) != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"HostUnlockResource: failed to unlock resource"));
}
return eError;
}
/*!
******************************************************************************
@Function PVRSRVReleaseTA
@Description
USER MODE FUNCTION
Releases the TA. This will not require a kernel transition to services if
the DevInfo contains user mappings to a Mutex Access word for TA
(to ensure single user access).
@Input psDevInfo : UM devinfo
@Input bSceneTerminated
@Return PVRSRV_ERROR : NO_ERROR or RESOURCE_NOT_LOCKED
******************************************************************************/
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVReleaseTA(PVRSRV_DEV_INFO *psDevInfo, IMG_BOOL bSceneTerminated)
{
DEVICE3D *ps3D = &psDevInfo->sDeviceSpecific.s3D;
PVRSRV_ERROR eError;
/* Release the TA resource */
eError = HostUnlockResource(&ps3D->hTAResource);
if(bSceneTerminated)
{
/* we've sent all the data for the current scene */
ps3D->bLastContextMidScene = IMG_FALSE;
}
/* Only try to release thread if more than 1 3d app has attached to param buffer */
if(ps3D->ui32ParamBufferRefCount > 1)
{
/* @todo FIXME: need something like
if(Time Elapsed > X timeslices) OR if(prims processed)
{
HostReleaseThreadQuanta();
}
*/
/* give thread quanta to another thread of same priority */
HostReleaseThreadQuanta();
}
return eError;
}
/*!
******************************************************************************
@Function PVRSRVAcquire3DFifoSpace
@Description
USER AND KERNEL MODE FUNCTION
Attempts to acquire space in the SlavePort FIFO. Called from
display driver, 3D driver and ISRs
This provides flow control for the slaveports.
On return, the number of bytes that can be written is returned in pui32BytesObtained.
@Input psDevInfo : UM devdata
@Input psHWInfo : HW Info
@Output *pui32BytesObtained : free bytes in FIFO
@Return PVRSRV_ERROR :
******************************************************************************/
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVAcquire3DFifoSpace (PVRSRV_DEV_INFO *psDevInfo,
PVRSRV_HW_INFO *psHWInfo,
IMG_UINT32 *pui32BytesObtained)
{
PVRSRV_ERROR eError;
DEVICE3D *ps3D = &psDevInfo->sDeviceSpecific.s3D;
PVRSRV_MUTEX_HANDLE *phMutex = &ps3D->hMutexTAFifoSpace;
IMG_UINT32 ui32ReserveBytes;
IMG_UINT32 ui32FifoBytes;
eError = HostAcquireMutex (phMutex, IMG_TRUE);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVAcquire3DFifoSpace: failed to acquire the FIFO resource"));
return eError;
}
#ifdef DEBUG
/* check appropriate resources have previously been acquired */
if (HostIsResourceLocked(&ps3D->hTAResource) == IMG_FALSE)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVAcquire3DFifoSpace: TA is not locked"));
eError = PVRSRV_ERROR_GENERIC;
goto ErrorHandler; /* we need to release FIFO mutex */
}
#endif
/* check for stream errors */
if (ps3D->bTAStreamErrorInterrupt)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVAcquire3DFifoSpace: got stream error"));
PVRSRVDiscardTAScene ( psDevInfo,
(PVRSRV_TARENDERINFO*)psDevInfo->sDeviceSpecific.s3D.psCurrentTARenderInfoUM,
psHWInfo,
IMG_TRUE);
eError = PVRSRV_ERROR_STREAM_ERROR;
goto ErrorHandler; /* we need to release FIFO mutex */
}
/* set up temporary for reserve2d */
ui32ReserveBytes = ps3D->ui32BytesReserved2d;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -