📄 queue.c
字号:
/*!****************************************************************************
@File services_um/common/queue.c
@Title user side command queue functions
@Author Imagination Technologies
@date 08/09/2003
@Copyright Copyright 2003-2004 by Imagination Technologies Limited.
All rights reserved. No part of this software, either
material or conceptual may be copied or distributed,
transmitted, transcribed, stored in a retrieval system
or translated into any human or computer language in any
form by any means, electronic, mechanical, manual or
other-wise, or disclosed to third parties without the
express written permission of Imagination Technologies
Limited, Unit 8, HomePark Industrial Estate,
King's Langley, Hertfordshire, WD4 8LZ, U.K.
@Platform generic
@Description user side command queue functions
@DoxygenVer
******************************************************************************/
/******************************************************************************
Modifications :-
$Log: queue.c $
*****************************************************************************/
#ifndef QUEUE_C
#define QUEUE_C
#include "img_defs.h"
#include "services.h"
#include "pvr3dif.h"
#if defined(PVR_KERNEL)
#include "hostfunc.h"
#else
#include "hostfunc_um.h"
#endif
#include "syscommon.h"
#include "sharedutils.h"
#include "mbx1defs.h"
#include "mbx13ddef.h"
#include "pvr_debug.h"
#include <stdlib.h>
/*!
@page SyncOverview Synchronisation overview
Services provide a synchronisation interface that allows drivers to issue
asynchronous commands to drive hardware that is shared between multiple
processes, using multiple hardware components, with a minimal processing overhead.
In systems with user/kernel divides, commands are typically submitted by
user space driver code, and executed as soon as possible (within interupt service routines typically)
without requiring expensive mode transitions.
Since the commands are executed asynchronously, and yet are only executed when
all previous commands that might conflict in their use of buffers have completed,
there is no need to poll for completion of commands etc.
*/
PVRSRV_ERROR GetFreeHWContextID (PVRSRV_DEV_INFO *psDevInfo,
PVRSRV_HW_INFO *psHWInfo,
IMG_UINT32 *puiRetID);
/*!
* Macro to return space in given command queue
*/
#define GET_SPACE_IN_HWQ(psQueue) \
(((psQueue->ui32ReadOffset - psQueue->ui32WriteOffset) \
+ (psQueue->ui32QueueSize - 1)) & (psQueue->ui32QueueSize - 1))
/*!
* Macro to Write Offset in given command queue
*/
#define UPDATE_QUEUE_WOFF(psQueue, ui32Size) \
psQueue->ui32WriteOffset = (psQueue->ui32WriteOffset + ui32Size) \
& (psQueue->ui32QueueSize - 1);
/*****************************************************************************
User-only functions
*****************************************************************************/
/*!
****************************************************************************
@Function : PVRSRVGetNextWriteOp
@Description : Gets the next operation to wait for in a sync object
@Input : psSyncInfo - pointer to sync information struct
@Input : bIsReadOp - Is this a read or write op
@Return : Next op value
*****************************************************************************/
IMG_EXPORT
IMG_UINT32 PVRSRVGetNextWriteOp(PVRSRV_SYNC_INFO *psSyncInfo, IMG_BOOL bIsReadOp)
{
IMG_UINT32 ui32NextOp;
if(bIsReadOp)
{
ui32NextOp = psSyncInfo->ui32NextWriteOp;
}
else
{
/* Doesnt this need to be atomic??? - yes*/
ui32NextOp = psSyncInfo->ui32NextWriteOp++;
}
return ui32NextOp;
}
/*!
*****************************************************************************
@Function : PVRSRVGetReadOpsPending
@Description : Gets the number of pending read ops
@Input : psSyncInfo - pointer to sync information struct
@Input : bIsReadOp - Is this a read or write op
@Return : Next op value
*****************************************************************************/
IMG_EXPORT
IMG_UINT32 PVRSRVGetReadOpsPending(PVRSRV_SYNC_INFO *psSyncInfo, IMG_BOOL bIsReadOp)
{
IMG_UINT32 ui32ReadOps;
if(bIsReadOp)
{
ui32ReadOps = psSyncInfo->ui32ReadOpsPending++;
}
else
{
ui32ReadOps = psSyncInfo->ui32ReadOpsPending;
psSyncInfo->ui32ReadOpsPending = 0;
}
return ui32ReadOps;
}
/*!
*****************************************************************************
@Function : PVRSRVReleaseQueue
@Description : Free the queue access member
@Input : psQueue - pointer to queue information struct
@Return : None
*****************************************************************************/
IMG_EXPORT
PVRSRV_ERROR PVRSRVReleaseQueue(PVRSRV_QUEUE_INFO *psQueue)
{
return HostUnlockResource(&psQueue->hAccess);
}
/*!
*****************************************************************************
@Function : PVRSRVGetQueueSpace
@Description : Waits for queue access rights and checks for available space in
queue for task param structure
@Input : psQueue - pointer to queue information struct
@Input : ui32ParamSize - size of task data structure
@Return : 0 if not enough space, else pointer to param start addr in queue on success
*****************************************************************************/
IMG_EXPORT
IMG_VOID * PVRSRVGetQueueSpace(PVRSRV_QUEUE_INFO *psQueue, IMG_UINT32 ui32ParamSize)
{
IMG_VOID *pvRetVal;
IMG_BOOL bTimeout;
IMG_BOOL bStart;
IMG_UINT32 uiStart;
if (ui32ParamSize > PVRSRV_MAX_CMD_SIZE)
{
PVR_DPF((PVR_DBG_WARNING,"PVRSRVGetQueueSpace: max command size is %d bytes", PVRSRV_MAX_CMD_SIZE));
return NULL;
}
bTimeout = IMG_TRUE;
bStart = IMG_FALSE;
uiStart = 0;
do
{
if(HostLockResource (&psQueue->hAccess, IMG_FALSE)==PVRSRV_OK)
{
if (GET_SPACE_IN_HWQ(psQueue) > ui32ParamSize)
{
bTimeout = IMG_FALSE;
break;
}
/* Not enough space in the queue, so release the mutex for a bit and try again*/
if(HostUnlockResource (&psQueue->hAccess) != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"HostUnlockResource: failed to unlock resource"));
}
}
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)
{
/* failure */
if(HostUnlockResource (&psQueue->hAccess) != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"HostUnlockResource: failed to unlock resource"));
}
pvRetVal = IMG_NULL;
}
else
{
pvRetVal = (IMG_VOID *)(psQueue->ui32WriteOffset + (IMG_UINT32)psQueue->pvLinQueueUM);
}
return pvRetVal;
}
/*!
*****************************************************************************
@Function : PVRSRVUpdateQueue
@Description : Updates the Queue Write pointer to take into account the new
params added to the Queue
@Input : psQueue - pointer to queue information struct
@Input : ui32ParamSize - size of task data structure
@Return : None
*****************************************************************************/
IMG_EXPORT
IMG_VOID PVRSRVUpdateQueue( PVRSRV_QUEUE_INFO *psQueue,
IMG_UINT32 ui32ParamSize)
{
UPDATE_QUEUE_WOFF(psQueue, ui32ParamSize)
SysKickCmdProc (psQueue->pui32KickerAddr);
}
/*!
****************************************************************************
@Function : QueueRender
@Description : Inserts a render command into a Q
@Input psQueue - pointer to queue information struct
@Input psTARenderInfo - pointer to the render info
@Input psBGObjInfo - pointer to the info needed to complete the background object
@Input bExternalDepthBuffer - has an external Z buffer been allocated
@Input psDstSync - Destination sync structure
@Input ui32NumSrcSyncs - How many sources are we synchronising with
@Input apsSrcSync[] - Pointers to the SyncInfos within the source MEM_INFOs
@Input ui32NumRegs - number of 3D registers
@Input psRegs - array of register (address:value) pairs
@Return : PVRSRV_ERROR_INVALID_PARAMS if too many SRCs
*****************************************************************************/
IMG_EXPORT
PVRSRV_ERROR PVRSRVQueueRender (PVRSRV_QUEUE_INFO *psQueue,
PVRSRV_TARENDERINFO *psTARenderInfo,
PVRSRV_BGOBJ_INFO *psBGObjInfo,
IMG_BOOL bExternalDepthBuffer,
PVRSRV_SYNC_INFO *psDstSync,
IMG_UINT32 ui32NumSrcSyncs,
PVRSRV_SYNC_INFO *apsSrcSync[],
IMG_UINT32 ui32NumRegs,
PVRSRV_HWREG *psRegs)
{
PVRSRV_RENDER_CMD_INFO *psRenderCmd;
IMG_UINT32 ui32CommandSize;
PVRSRV_SRCSYNC_INFO *psSrcSyncInfo;
PVRSRV_HWREG *psRegData;
IMG_UINT32 i;
if (ui32NumSrcSyncs > PVRSRV_MAX_RENDER_SRC)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
ui32CommandSize = sizeof(PVRSRV_RENDER_CMD_INFO) + (ui32NumRegs * sizeof(PVRSRV_HWREG)) - sizeof(IMG_UINT32) +
(sizeof(PVRSRV_SRCSYNC_INFO) * ui32NumSrcSyncs);
/*
round to 4byte units
*/
ui32CommandSize = (ui32CommandSize+3) & ~3L;
psRenderCmd = (PVRSRV_RENDER_CMD_INFO *) PVRSRVGetQueueSpace(psQueue, ui32CommandSize);
if(!psRenderCmd)
{
PVR_DPF((PVR_DBG_ERROR,"Couldn't get space in queue"));
return PVRSRV_ERROR_TIMEOUT;
}
psRenderCmd->sCmdInfo.ui32CommandID = PVRSRV_CMD_ID_RENDER;
psRenderCmd->sCmdInfo.ui32Size = ui32CommandSize;
psRenderCmd->ui32TexFormatStride = psBGObjInfo->ui32TexFormatStride;
psRenderCmd->ui32TexAddrStride = psBGObjInfo->ui32TexAddrStride;
psRenderCmd->bExternalDepthBuffer = bExternalDepthBuffer;
psRenderCmd->ui32CurrentRenderData = psTARenderInfo->psSharedData->ui32CurrentRenderData;
psRenderCmd->psTARenderInfo = psTARenderInfo->psTARenderInfoKM;
psRenderCmd->ui32DstNextWriteOpVal = PVRSRVGetNextWriteOp(psDstSync, IMG_FALSE);
psRenderCmd->ui32DstReadOpsPending = PVRSRVGetReadOpsPending(psDstSync, IMG_FALSE);
psRenderCmd->psDstSyncInfoKM = psDstSync->psKernSyncInfo;
psSrcSyncInfo = (PVRSRV_SRCSYNC_INFO *)&psRenderCmd->aui32Data[0];
for(i = 0; i < ui32NumSrcSyncs; i++)
{
psSrcSyncInfo[i].ui32NextWriteOpVal = PVRSRVGetNextWriteOp(apsSrcSync[i], IMG_TRUE);
PVRSRVGetReadOpsPending(apsSrcSync[i], IMG_TRUE);
psSrcSyncInfo[i].psSyncInfoKM = apsSrcSync[i]->psKernSyncInfo;
}
psRenderCmd->ui32NumSrcSyncInfos = ui32NumSrcSyncs;
psRegData = (PVRSRV_HWREG *)&psSrcSyncInfo[i];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -