blob: 28342875f24694b54ecce032017675889ce23ef6 [file] [log] [blame]
/**********************************************************************
*
* Copyright (C) Imagination Technologies Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful but, except
* as otherwise stated in writing, without any warranty; without even the
* implied warranty of merchantability or fitness for a particular purpose.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* Imagination Technologies Ltd. <gpl-support@imgtec.com>
* Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
*
******************************************************************************/
#include "services_headers.h"
#include "buffer_manager.h"
#include "kernelbuffer.h"
#include "kerneldisplay.h"
#include "pvr_bridge_km.h"
#include "pdump_km.h"
#include "deviceid.h"
#include "lists.h"
PVRSRV_ERROR AllocateDeviceID(SYS_DATA *psSysData, IMG_UINT32 *pui32DevID);
PVRSRV_ERROR FreeDeviceID(SYS_DATA *psSysData, IMG_UINT32 ui32DevID);
#if defined(SUPPORT_MISR_IN_THREAD)
void OSVSyncMISR(IMG_HANDLE, IMG_BOOL);
#endif
#if defined(SUPPORT_CUSTOM_SWAP_OPERATIONS)
IMG_VOID PVRSRVFreeCommandCompletePacketKM(IMG_HANDLE hCmdCookie,
IMG_BOOL bScheduleMISR);
#endif
typedef struct PVRSRV_DC_SRV2DISP_KMJTABLE_TAG *PPVRSRV_DC_SRV2DISP_KMJTABLE;
typedef struct PVRSRV_DC_BUFFER_TAG
{
PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer;
struct PVRSRV_DISPLAYCLASS_INFO_TAG *psDCInfo;
struct PVRSRV_DC_SWAPCHAIN_TAG *psSwapChain;
} PVRSRV_DC_BUFFER;
typedef struct PVRSRV_DC_SWAPCHAIN_TAG
{
IMG_HANDLE hExtSwapChain;
IMG_UINT32 ui32SwapChainID;
IMG_UINT32 ui32RefCount;
IMG_UINT32 ui32Flags;
PVRSRV_QUEUE_INFO *psQueue;
PVRSRV_DC_BUFFER asBuffer[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS];
IMG_UINT32 ui32BufferCount;
PVRSRV_DC_BUFFER *psLastFlipBuffer;
IMG_UINT32 ui32MinSwapInterval;
IMG_UINT32 ui32MaxSwapInterval;
#if !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED)
PVRSRV_KERNEL_SYNC_INFO **ppsLastSyncInfos;
IMG_UINT32 ui32LastNumSyncInfos;
#endif
struct PVRSRV_DISPLAYCLASS_INFO_TAG *psDCInfo;
struct PVRSRV_DC_SWAPCHAIN_TAG *psNext;
} PVRSRV_DC_SWAPCHAIN;
typedef struct PVRSRV_DC_SWAPCHAIN_REF_TAG
{
struct PVRSRV_DC_SWAPCHAIN_TAG *psSwapChain;
IMG_HANDLE hResItem;
} PVRSRV_DC_SWAPCHAIN_REF;
typedef struct PVRSRV_DISPLAYCLASS_INFO_TAG
{
IMG_UINT32 ui32RefCount;
IMG_UINT32 ui32DeviceID;
IMG_HANDLE hExtDevice;
PPVRSRV_DC_SRV2DISP_KMJTABLE psFuncTable;
IMG_HANDLE hDevMemContext;
PVRSRV_DC_BUFFER sSystemBuffer;
struct PVRSRV_DC_SWAPCHAIN_TAG *psDCSwapChainShared;
} PVRSRV_DISPLAYCLASS_INFO;
typedef struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO_TAG
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PRESMAN_ITEM hResItem;
} PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO;
typedef struct PVRSRV_BC_SRV2BUFFER_KMJTABLE_TAG *PPVRSRV_BC_SRV2BUFFER_KMJTABLE;
typedef struct PVRSRV_BC_BUFFER_TAG
{
PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer;
struct PVRSRV_BUFFERCLASS_INFO_TAG *psBCInfo;
} PVRSRV_BC_BUFFER;
typedef struct PVRSRV_BUFFERCLASS_INFO_TAG
{
IMG_UINT32 ui32RefCount;
IMG_UINT32 ui32DeviceID;
IMG_HANDLE hExtDevice;
PPVRSRV_BC_SRV2BUFFER_KMJTABLE psFuncTable;
IMG_HANDLE hDevMemContext;
IMG_UINT32 ui32BufferCount;
PVRSRV_BC_BUFFER *psBuffer;
} PVRSRV_BUFFERCLASS_INFO;
typedef struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO_TAG
{
PVRSRV_BUFFERCLASS_INFO *psBCInfo;
IMG_HANDLE hResItem;
} PVRSRV_BUFFERCLASS_PERCONTEXT_INFO;
static PVRSRV_DISPLAYCLASS_INFO* DCDeviceHandleToDCInfo (IMG_HANDLE hDeviceKM)
{
PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo;
psDCPerContextInfo = (PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *)hDeviceKM;
return psDCPerContextInfo->psDCInfo;
}
static PVRSRV_BUFFERCLASS_INFO* BCDeviceHandleToBCInfo (IMG_HANDLE hDeviceKM)
{
PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo;
psBCPerContextInfo = (PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *)hDeviceKM;
return psBCPerContextInfo->psBCInfo;
}
static IMG_VOID PVRSRVEnumerateDCKM_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va)
{
IMG_UINT *pui32DevCount;
IMG_UINT32 **ppui32DevID;
PVRSRV_DEVICE_CLASS peDeviceClass;
pui32DevCount = va_arg(va, IMG_UINT*);
ppui32DevID = va_arg(va, IMG_UINT32**);
peDeviceClass = va_arg(va, PVRSRV_DEVICE_CLASS);
if ((psDeviceNode->sDevId.eDeviceClass == peDeviceClass)
&& (psDeviceNode->sDevId.eDeviceType == PVRSRV_DEVICE_TYPE_EXT))
{
(*pui32DevCount)++;
if(*ppui32DevID)
{
*(*ppui32DevID)++ = psDeviceNode->sDevId.ui32DeviceIndex;
}
}
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVEnumerateDCKM (PVRSRV_DEVICE_CLASS DeviceClass,
IMG_UINT32 *pui32DevCount,
IMG_UINT32 *pui32DevID )
{
IMG_UINT ui32DevCount = 0;
SYS_DATA *psSysData;
SysAcquireData(&psSysData);
List_PVRSRV_DEVICE_NODE_ForEach_va(psSysData->psDeviceNodeList,
&PVRSRVEnumerateDCKM_ForEachVaCb,
&ui32DevCount,
&pui32DevID,
DeviceClass);
if(pui32DevCount)
{
*pui32DevCount = ui32DevCount;
}
else if(pui32DevID == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVEnumerateDCKM: Invalid parameters"));
return (PVRSRV_ERROR_INVALID_PARAMS);
}
return PVRSRV_OK;
}
static
PVRSRV_ERROR PVRSRVRegisterDCDeviceKM (PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable,
IMG_UINT32 *pui32DeviceID)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo = IMG_NULL;
PVRSRV_DEVICE_NODE *psDeviceNode;
SYS_DATA *psSysData;
SysAcquireData(&psSysData);
if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP,
sizeof(*psDCInfo),
(IMG_VOID **)&psDCInfo, IMG_NULL,
"Display Class Info") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterDCDeviceKM: Failed psDCInfo alloc"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
OSMemSet (psDCInfo, 0, sizeof(*psDCInfo));
if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP,
sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE),
(IMG_VOID **)&psDCInfo->psFuncTable, IMG_NULL,
"Function table for SRVKM->DISPLAY") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterDCDeviceKM: Failed psFuncTable alloc"));
goto ErrorExit;
}
OSMemSet (psDCInfo->psFuncTable, 0, sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE));
*psDCInfo->psFuncTable = *psFuncTable;
if(OSAllocMem( PVRSRV_OS_NON_PAGEABLE_HEAP,
sizeof(PVRSRV_DEVICE_NODE),
(IMG_VOID **)&psDeviceNode, IMG_NULL,
"Device Node") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterDCDeviceKM: Failed psDeviceNode alloc"));
goto ErrorExit;
}
OSMemSet (psDeviceNode, 0, sizeof(PVRSRV_DEVICE_NODE));
psDeviceNode->pvDevice = (IMG_VOID*)psDCInfo;
psDeviceNode->ui32pvDeviceSize = sizeof(*psDCInfo);
psDeviceNode->ui32RefCount = 1;
psDeviceNode->sDevId.eDeviceType = PVRSRV_DEVICE_TYPE_EXT;
psDeviceNode->sDevId.eDeviceClass = PVRSRV_DEVICE_CLASS_DISPLAY;
psDeviceNode->psSysData = psSysData;
if (AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex) != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterBCDeviceKM: Failed to allocate Device ID"));
goto ErrorExit;
}
psDCInfo->ui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex;
if (pui32DeviceID)
{
*pui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex;
}
SysRegisterExternalDevice(psDeviceNode);
List_PVRSRV_DEVICE_NODE_Insert(&psSysData->psDeviceNodeList, psDeviceNode);
return PVRSRV_OK;
ErrorExit:
if(psDCInfo->psFuncTable)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE), psDCInfo->psFuncTable, IMG_NULL);
psDCInfo->psFuncTable = IMG_NULL;
}
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DISPLAYCLASS_INFO), psDCInfo, IMG_NULL);
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
static PVRSRV_ERROR PVRSRVRemoveDCDeviceKM(IMG_UINT32 ui32DevIndex)
{
SYS_DATA *psSysData;
PVRSRV_DEVICE_NODE *psDeviceNode;
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
SysAcquireData(&psSysData);
psDeviceNode = (PVRSRV_DEVICE_NODE*)
List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList,
&MatchDeviceKM_AnyVaCb,
ui32DevIndex,
IMG_FALSE,
PVRSRV_DEVICE_CLASS_DISPLAY);
if (!psDeviceNode)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRemoveDCDeviceKM: requested device %d not present", ui32DevIndex));
return PVRSRV_ERROR_NO_DEVICENODE_FOUND;
}
psDCInfo = (PVRSRV_DISPLAYCLASS_INFO*)psDeviceNode->pvDevice;
if(psDCInfo->ui32RefCount == 0)
{
List_PVRSRV_DEVICE_NODE_Remove(psDeviceNode);
SysRemoveExternalDevice(psDeviceNode);
PVR_ASSERT(psDCInfo->ui32RefCount == 0);
(IMG_VOID)FreeDeviceID(psSysData, ui32DevIndex);
(IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE), psDCInfo->psFuncTable, IMG_NULL);
psDCInfo->psFuncTable = IMG_NULL;
(IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DISPLAYCLASS_INFO), psDCInfo, IMG_NULL);
(IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL);
}
else
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRemoveDCDeviceKM: failed as %d Services DC API connections are still open", psDCInfo->ui32RefCount));
return PVRSRV_ERROR_UNABLE_TO_REMOVE_DEVICE;
}
return PVRSRV_OK;
}
static
PVRSRV_ERROR PVRSRVRegisterBCDeviceKM (PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTable,
IMG_UINT32 *pui32DeviceID)
{
PVRSRV_BUFFERCLASS_INFO *psBCInfo = IMG_NULL;
PVRSRV_DEVICE_NODE *psDeviceNode;
SYS_DATA *psSysData;
SysAcquireData(&psSysData);
if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP,
sizeof(*psBCInfo),
(IMG_VOID **)&psBCInfo, IMG_NULL,
"Buffer Class Info") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterBCDeviceKM: Failed psBCInfo alloc"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
OSMemSet (psBCInfo, 0, sizeof(*psBCInfo));
if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP,
sizeof(PVRSRV_BC_SRV2BUFFER_KMJTABLE),
(IMG_VOID **)&psBCInfo->psFuncTable, IMG_NULL,
"Function table for SRVKM->BUFFER") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterBCDeviceKM: Failed psFuncTable alloc"));
goto ErrorExit;
}
OSMemSet (psBCInfo->psFuncTable, 0, sizeof(PVRSRV_BC_SRV2BUFFER_KMJTABLE));
*psBCInfo->psFuncTable = *psFuncTable;
if(OSAllocMem( PVRSRV_OS_NON_PAGEABLE_HEAP,
sizeof(PVRSRV_DEVICE_NODE),
(IMG_VOID **)&psDeviceNode, IMG_NULL,
"Device Node") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterBCDeviceKM: Failed psDeviceNode alloc"));
goto ErrorExit;
}
OSMemSet (psDeviceNode, 0, sizeof(PVRSRV_DEVICE_NODE));
psDeviceNode->pvDevice = (IMG_VOID*)psBCInfo;
psDeviceNode->ui32pvDeviceSize = sizeof(*psBCInfo);
psDeviceNode->ui32RefCount = 1;
psDeviceNode->sDevId.eDeviceType = PVRSRV_DEVICE_TYPE_EXT;
psDeviceNode->sDevId.eDeviceClass = PVRSRV_DEVICE_CLASS_BUFFER;
psDeviceNode->psSysData = psSysData;
if (AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex) != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterBCDeviceKM: Failed to allocate Device ID"));
goto ErrorExit;
}
psBCInfo->ui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex;
if (pui32DeviceID)
{
*pui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex;
}
List_PVRSRV_DEVICE_NODE_Insert(&psSysData->psDeviceNodeList, psDeviceNode);
return PVRSRV_OK;
ErrorExit:
if(psBCInfo->psFuncTable)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PPVRSRV_BC_SRV2BUFFER_KMJTABLE), psBCInfo->psFuncTable, IMG_NULL);
psBCInfo->psFuncTable = IMG_NULL;
}
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BUFFERCLASS_INFO), psBCInfo, IMG_NULL);
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
static PVRSRV_ERROR PVRSRVRemoveBCDeviceKM(IMG_UINT32 ui32DevIndex)
{
SYS_DATA *psSysData;
PVRSRV_DEVICE_NODE *psDevNode;
PVRSRV_BUFFERCLASS_INFO *psBCInfo;
SysAcquireData(&psSysData);
psDevNode = (PVRSRV_DEVICE_NODE*)
List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList,
&MatchDeviceKM_AnyVaCb,
ui32DevIndex,
IMG_FALSE,
PVRSRV_DEVICE_CLASS_BUFFER);
if (!psDevNode)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRemoveBCDeviceKM: requested device %d not present", ui32DevIndex));
return PVRSRV_ERROR_NO_DEVICENODE_FOUND;
}
psBCInfo = (PVRSRV_BUFFERCLASS_INFO*)psDevNode->pvDevice;
if(psBCInfo->ui32RefCount == 0)
{
List_PVRSRV_DEVICE_NODE_Remove(psDevNode);
(IMG_VOID)FreeDeviceID(psSysData, ui32DevIndex);
(IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BC_SRV2BUFFER_KMJTABLE), psBCInfo->psFuncTable, IMG_NULL);
psBCInfo->psFuncTable = IMG_NULL;
(IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BUFFERCLASS_INFO), psBCInfo, IMG_NULL);
(IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), psDevNode, IMG_NULL);
}
else
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRemoveBCDeviceKM: failed as %d Services BC API connections are still open", psBCInfo->ui32RefCount));
return PVRSRV_ERROR_UNABLE_TO_REMOVE_DEVICE;
}
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVCloseDCDeviceKM (IMG_HANDLE hDeviceKM,
IMG_BOOL bResManCallback)
{
PVRSRV_ERROR eError;
PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo;
PVR_UNREFERENCED_PARAMETER(bResManCallback);
psDCPerContextInfo = (PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *)hDeviceKM;
eError = ResManFreeResByPtr(psDCPerContextInfo->hResItem, CLEANUP_WITH_POLL);
return eError;
}
static PVRSRV_ERROR CloseDCDeviceCallBack(IMG_PVOID pvParam,
IMG_UINT32 ui32Param,
IMG_BOOL bDummy)
{
PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo;
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVR_UNREFERENCED_PARAMETER(ui32Param);
PVR_UNREFERENCED_PARAMETER(bDummy);
psDCPerContextInfo = (PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *)pvParam;
psDCInfo = psDCPerContextInfo->psDCInfo;
if(psDCInfo->sSystemBuffer.sDeviceClassBuffer.ui32MemMapRefCount != 0)
{
PVR_DPF((PVR_DBG_MESSAGE,"CloseDCDeviceCallBack: system buffer (0x%p) still mapped (refcount = %d)",
&psDCInfo->sSystemBuffer.sDeviceClassBuffer,
psDCInfo->sSystemBuffer.sDeviceClassBuffer.ui32MemMapRefCount));
#if 0
return PVRSRV_ERROR_STILL_MAPPED;
#endif
}
psDCInfo->ui32RefCount--;
if(psDCInfo->ui32RefCount == 0)
{
psDCInfo->psFuncTable->pfnCloseDCDevice(psDCInfo->hExtDevice);
PVRSRVKernelSyncInfoDecRef(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL);
if (psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount == 0)
{
PVRSRVFreeSyncInfoKM(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo);
}
psDCInfo->hDevMemContext = IMG_NULL;
psDCInfo->hExtDevice = IMG_NULL;
}
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO), psDCPerContextInfo, IMG_NULL);
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVOpenDCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc,
IMG_UINT32 ui32DeviceID,
IMG_HANDLE hDevCookie,
IMG_HANDLE *phDeviceKM)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo;
PVRSRV_DEVICE_NODE *psDeviceNode;
SYS_DATA *psSysData;
PVRSRV_ERROR eError;
if(!phDeviceKM || !hDevCookie)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenDCDeviceKM: Invalid params"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
SysAcquireData(&psSysData);
psDeviceNode = (PVRSRV_DEVICE_NODE*)
List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList,
&MatchDeviceKM_AnyVaCb,
ui32DeviceID,
IMG_FALSE,
PVRSRV_DEVICE_CLASS_DISPLAY);
if (!psDeviceNode)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenDCDeviceKM: no devnode matching index %d", ui32DeviceID));
return PVRSRV_ERROR_NO_DEVICENODE_FOUND;
}
psDCInfo = (PVRSRV_DISPLAYCLASS_INFO*)psDeviceNode->pvDevice;
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(*psDCPerContextInfo),
(IMG_VOID **)&psDCPerContextInfo, IMG_NULL,
"Display Class per Context Info") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenDCDeviceKM: Failed psDCPerContextInfo alloc"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
OSMemSet(psDCPerContextInfo, 0, sizeof(*psDCPerContextInfo));
if(psDCInfo->ui32RefCount++ == 0)
{
psDeviceNode = (PVRSRV_DEVICE_NODE *)hDevCookie;
psDCInfo->hDevMemContext = (IMG_HANDLE)psDeviceNode->sDevMemoryInfo.pBMKernelContext;
eError = PVRSRVAllocSyncInfoKM(IMG_NULL,
(IMG_HANDLE)psDeviceNode->sDevMemoryInfo.pBMKernelContext,
&psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenDCDeviceKM: Failed sync info alloc"));
psDCInfo->ui32RefCount--;
return eError;
}
eError = psDCInfo->psFuncTable->pfnOpenDCDevice(ui32DeviceID,
&psDCInfo->hExtDevice,
(PVRSRV_SYNC_DATA*)psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenDCDeviceKM: Failed to open external DC device"));
psDCInfo->ui32RefCount--;
PVRSRVFreeSyncInfoKM(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo);
return eError;
}
psDCPerContextInfo->psDCInfo = psDCInfo;
eError = PVRSRVGetDCSystemBufferKM(psDCPerContextInfo, IMG_NULL);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenDCDeviceKM: Failed to get system buffer"));
psDCInfo->ui32RefCount--;
PVRSRVFreeSyncInfoKM(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo);
return eError;
}
PVRSRVKernelSyncInfoIncRef(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL);
psDCInfo->sSystemBuffer.sDeviceClassBuffer.ui32MemMapRefCount = 0;
}
else
{
psDCPerContextInfo->psDCInfo = psDCInfo;
}
psDCPerContextInfo->hResItem = ResManRegisterRes(psPerProc->hResManContext,
RESMAN_TYPE_DISPLAYCLASS_DEVICE,
psDCPerContextInfo,
0,
&CloseDCDeviceCallBack);
*phDeviceKM = (IMG_HANDLE)psDCPerContextInfo;
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVEnumDCFormatsKM (IMG_HANDLE hDeviceKM,
IMG_UINT32 *pui32Count,
DISPLAY_FORMAT *psFormat)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
if(!hDeviceKM || !pui32Count || !psFormat)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVEnumDCFormatsKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
return psDCInfo->psFuncTable->pfnEnumDCFormats(psDCInfo->hExtDevice, pui32Count, psFormat);
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVEnumDCDimsKM (IMG_HANDLE hDeviceKM,
DISPLAY_FORMAT *psFormat,
IMG_UINT32 *pui32Count,
DISPLAY_DIMS *psDim)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
if(!hDeviceKM || !pui32Count || !psFormat)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVEnumDCDimsKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
return psDCInfo->psFuncTable->pfnEnumDCDims(psDCInfo->hExtDevice, psFormat, pui32Count, psDim);
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVGetDCSystemBufferKM (IMG_HANDLE hDeviceKM,
IMG_HANDLE *phBuffer)
{
PVRSRV_ERROR eError;
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
IMG_HANDLE hExtBuffer;
if(!hDeviceKM)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetDCSystemBufferKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
eError = psDCInfo->psFuncTable->pfnGetDCSystemBuffer(psDCInfo->hExtDevice, &hExtBuffer);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetDCSystemBufferKM: Failed to get valid buffer handle from external driver"));
return eError;
}
psDCInfo->sSystemBuffer.sDeviceClassBuffer.pfnGetBufferAddr = psDCInfo->psFuncTable->pfnGetBufferAddr;
psDCInfo->sSystemBuffer.sDeviceClassBuffer.hDevMemContext = psDCInfo->hDevMemContext;
psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtDevice = psDCInfo->hExtDevice;
psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtBuffer = hExtBuffer;
psDCInfo->sSystemBuffer.psDCInfo = psDCInfo;
if (phBuffer)
{
*phBuffer = (IMG_HANDLE)&(psDCInfo->sSystemBuffer);
}
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVGetDCInfoKM (IMG_HANDLE hDeviceKM,
DISPLAY_INFO *psDisplayInfo)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVRSRV_ERROR eError;
if(!hDeviceKM || !psDisplayInfo)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetDCInfoKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
eError = psDCInfo->psFuncTable->pfnGetDCInfo(psDCInfo->hExtDevice, psDisplayInfo);
if (eError != PVRSRV_OK)
{
return eError;
}
if (psDisplayInfo->ui32MaxSwapChainBuffers > PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS)
{
psDisplayInfo->ui32MaxSwapChainBuffers = PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS;
}
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVDestroyDCSwapChainKM(IMG_HANDLE hSwapChainRef)
{
PVRSRV_ERROR eError;
PVRSRV_DC_SWAPCHAIN_REF *psSwapChainRef;
if(!hSwapChainRef)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVDestroyDCSwapChainKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psSwapChainRef = hSwapChainRef;
eError = ResManFreeResByPtr(psSwapChainRef->hResItem, CLEANUP_WITH_POLL);
return eError;
}
static PVRSRV_ERROR DestroyDCSwapChain(PVRSRV_DC_SWAPCHAIN *psSwapChain)
{
PVRSRV_ERROR eError;
PVRSRV_DISPLAYCLASS_INFO *psDCInfo = psSwapChain->psDCInfo;
IMG_UINT32 i;
if( psDCInfo->psDCSwapChainShared )
{
if( psDCInfo->psDCSwapChainShared == psSwapChain )
{
psDCInfo->psDCSwapChainShared = psSwapChain->psNext;
}
else
{
PVRSRV_DC_SWAPCHAIN *psCurrentSwapChain;
psCurrentSwapChain = psDCInfo->psDCSwapChainShared;
while( psCurrentSwapChain->psNext )
{
if( psCurrentSwapChain->psNext != psSwapChain )
{
psCurrentSwapChain = psCurrentSwapChain->psNext;
continue;
}
psCurrentSwapChain->psNext = psSwapChain->psNext;
break;
}
}
}
PVRSRVDestroyCommandQueueKM(psSwapChain->psQueue);
eError = psDCInfo->psFuncTable->pfnDestroyDCSwapChain(psDCInfo->hExtDevice,
psSwapChain->hExtSwapChain);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"DestroyDCSwapChainCallBack: Failed to destroy DC swap chain"));
return eError;
}
for(i=0; i<psSwapChain->ui32BufferCount; i++)
{
if(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo)
{
PVRSRVKernelSyncInfoDecRef(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL);
if (psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount == 0)
{
PVRSRVFreeSyncInfoKM(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo);
}
}
}
#if !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED)
if (psSwapChain->ppsLastSyncInfos)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_KERNEL_SYNC_INFO *) * psSwapChain->ui32LastNumSyncInfos,
psSwapChain->ppsLastSyncInfos, IMG_NULL);
}
#endif
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SWAPCHAIN), psSwapChain, IMG_NULL);
return eError;
}
static PVRSRV_ERROR DestroyDCSwapChainRefCallBack(IMG_PVOID pvParam,
IMG_UINT32 ui32Param,
IMG_BOOL bDummy)
{
PVRSRV_DC_SWAPCHAIN_REF *psSwapChainRef = (PVRSRV_DC_SWAPCHAIN_REF *) pvParam;
PVRSRV_ERROR eError = PVRSRV_OK;
IMG_UINT32 i;
PVR_UNREFERENCED_PARAMETER(ui32Param);
PVR_UNREFERENCED_PARAMETER(bDummy);
for (i = 0; i < psSwapChainRef->psSwapChain->ui32BufferCount; i++)
{
if (psSwapChainRef->psSwapChain->asBuffer[i].sDeviceClassBuffer.ui32MemMapRefCount != 0)
{
PVR_DPF((PVR_DBG_ERROR, "DestroyDCSwapChainRefCallBack: swapchain (0x%p) still mapped (ui32MemMapRefCount = %d)",
&psSwapChainRef->psSwapChain->asBuffer[i].sDeviceClassBuffer,
psSwapChainRef->psSwapChain->asBuffer[i].sDeviceClassBuffer.ui32MemMapRefCount));
#if 0
return PVRSRV_ERROR_STILL_MAPPED;
#endif
}
}
if(--psSwapChainRef->psSwapChain->ui32RefCount == 0)
{
eError = DestroyDCSwapChain(psSwapChainRef->psSwapChain);
}
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SWAPCHAIN_REF), psSwapChainRef, IMG_NULL);
return eError;
}
static PVRSRV_DC_SWAPCHAIN* PVRSRVFindSharedDCSwapChainKM(PVRSRV_DISPLAYCLASS_INFO *psDCInfo,
IMG_UINT32 ui32SwapChainID)
{
PVRSRV_DC_SWAPCHAIN *psCurrentSwapChain;
for(psCurrentSwapChain = psDCInfo->psDCSwapChainShared;
psCurrentSwapChain;
psCurrentSwapChain = psCurrentSwapChain->psNext)
{
if(psCurrentSwapChain->ui32SwapChainID == ui32SwapChainID)
return psCurrentSwapChain;
}
return IMG_NULL;
}
static PVRSRV_ERROR PVRSRVCreateDCSwapChainRefKM(PVRSRV_PER_PROCESS_DATA *psPerProc,
PVRSRV_DC_SWAPCHAIN *psSwapChain,
PVRSRV_DC_SWAPCHAIN_REF **ppsSwapChainRef)
{
PVRSRV_DC_SWAPCHAIN_REF *psSwapChainRef = IMG_NULL;
if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP,
sizeof(PVRSRV_DC_SWAPCHAIN_REF),
(IMG_VOID **)&psSwapChainRef, IMG_NULL,
"Display Class Swapchain Reference") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainRefKM: Failed psSwapChainRef alloc"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
OSMemSet (psSwapChainRef, 0, sizeof(PVRSRV_DC_SWAPCHAIN_REF));
psSwapChain->ui32RefCount++;
psSwapChainRef->psSwapChain = psSwapChain;
psSwapChainRef->hResItem = ResManRegisterRes(psPerProc->hResManContext,
RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN_REF,
psSwapChainRef,
0,
&DestroyDCSwapChainRefCallBack);
*ppsSwapChainRef = psSwapChainRef;
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVCreateDCSwapChainKM (PVRSRV_PER_PROCESS_DATA *psPerProc,
IMG_HANDLE hDeviceKM,
IMG_UINT32 ui32Flags,
DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib,
DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib,
IMG_UINT32 ui32BufferCount,
IMG_UINT32 ui32OEMFlags,
IMG_HANDLE *phSwapChainRef,
IMG_UINT32 *pui32SwapChainID)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVRSRV_DC_SWAPCHAIN *psSwapChain = IMG_NULL;
PVRSRV_DC_SWAPCHAIN_REF *psSwapChainRef = IMG_NULL;
PVRSRV_SYNC_DATA *apsSyncData[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS];
PVRSRV_QUEUE_INFO *psQueue = IMG_NULL;
PVRSRV_ERROR eError;
IMG_UINT32 i;
DISPLAY_INFO sDisplayInfo;
if(!hDeviceKM
|| !psDstSurfAttrib
|| !psSrcSurfAttrib
|| !phSwapChainRef
|| !pui32SwapChainID)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
if (ui32BufferCount > PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Too many buffers"));
return PVRSRV_ERROR_TOOMANYBUFFERS;
}
if (ui32BufferCount < 2)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Too few buffers"));
return PVRSRV_ERROR_TOO_FEW_BUFFERS;
}
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
if( ui32Flags & PVRSRV_CREATE_SWAPCHAIN_QUERY )
{
psSwapChain = PVRSRVFindSharedDCSwapChainKM(psDCInfo, *pui32SwapChainID );
if( psSwapChain )
{
eError = PVRSRVCreateDCSwapChainRefKM(psPerProc,
psSwapChain,
&psSwapChainRef);
if( eError != PVRSRV_OK )
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Couldn't create swap chain reference"));
return eError;
}
*phSwapChainRef = (IMG_HANDLE)psSwapChainRef;
return PVRSRV_OK;
}
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: No shared SwapChain found for query"));
return PVRSRV_ERROR_FLIP_CHAIN_EXISTS;
}
if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP,
sizeof(PVRSRV_DC_SWAPCHAIN),
(IMG_VOID **)&psSwapChain, IMG_NULL,
"Display Class Swapchain") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Failed psSwapChain alloc"));
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto ErrorExit;
}
OSMemSet (psSwapChain, 0, sizeof(PVRSRV_DC_SWAPCHAIN));
eError = PVRSRVCreateCommandQueueKM(1024, &psQueue);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Failed to create CmdQueue"));
goto ErrorExit;
}
psSwapChain->psQueue = psQueue;
for(i=0; i<ui32BufferCount; i++)
{
eError = PVRSRVAllocSyncInfoKM(IMG_NULL,
psDCInfo->hDevMemContext,
&psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Failed to alloc syninfo for psSwapChain"));
goto ErrorExit;
}
PVRSRVKernelSyncInfoIncRef(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL);
psSwapChain->asBuffer[i].sDeviceClassBuffer.pfnGetBufferAddr = psDCInfo->psFuncTable->pfnGetBufferAddr;
psSwapChain->asBuffer[i].sDeviceClassBuffer.hDevMemContext = psDCInfo->hDevMemContext;
psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtDevice = psDCInfo->hExtDevice;
psSwapChain->asBuffer[i].psDCInfo = psDCInfo;
psSwapChain->asBuffer[i].psSwapChain = psSwapChain;
apsSyncData[i] = (PVRSRV_SYNC_DATA*)psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM;
}
psSwapChain->ui32BufferCount = ui32BufferCount;
psSwapChain->psDCInfo = psDCInfo;
#if defined(PDUMP)
PDUMPCOMMENT("Allocate DC swap chain (SwapChainID == %u, BufferCount == %u)",
*pui32SwapChainID,
ui32BufferCount);
PDUMPCOMMENT(" Src surface dimensions == %u x %u",
psSrcSurfAttrib->sDims.ui32Width,
psSrcSurfAttrib->sDims.ui32Height);
PDUMPCOMMENT(" Dst surface dimensions == %u x %u",
psDstSurfAttrib->sDims.ui32Width,
psDstSurfAttrib->sDims.ui32Height);
#endif
eError = psDCInfo->psFuncTable->pfnGetDCInfo(psDCInfo->hExtDevice, &sDisplayInfo);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Failed to get DC info"));
return eError;
}
psSwapChain->ui32MinSwapInterval = sDisplayInfo.ui32MinSwapInterval;
psSwapChain->ui32MaxSwapInterval = sDisplayInfo.ui32MaxSwapInterval;
eError = psDCInfo->psFuncTable->pfnCreateDCSwapChain(psDCInfo->hExtDevice,
ui32Flags,
psDstSurfAttrib,
psSrcSurfAttrib,
ui32BufferCount,
apsSyncData,
ui32OEMFlags,
&psSwapChain->hExtSwapChain,
&psSwapChain->ui32SwapChainID);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Failed to create 3rd party SwapChain"));
PDUMPCOMMENT("Swapchain allocation failed.");
goto ErrorExit;
}
eError = PVRSRVCreateDCSwapChainRefKM(psPerProc,
psSwapChain,
&psSwapChainRef);
if( eError != PVRSRV_OK )
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Couldn't create swap chain reference"));
PDUMPCOMMENT("Swapchain allocation failed.");
goto ErrorExit;
}
psSwapChain->ui32RefCount = 1;
psSwapChain->ui32Flags = ui32Flags;
if( ui32Flags & PVRSRV_CREATE_SWAPCHAIN_SHARED )
{
if(! psDCInfo->psDCSwapChainShared )
{
psDCInfo->psDCSwapChainShared = psSwapChain;
}
else
{
PVRSRV_DC_SWAPCHAIN *psOldHead = psDCInfo->psDCSwapChainShared;
psDCInfo->psDCSwapChainShared = psSwapChain;
psSwapChain->psNext = psOldHead;
}
}
*pui32SwapChainID = psSwapChain->ui32SwapChainID;
*phSwapChainRef= (IMG_HANDLE)psSwapChainRef;
return eError;
ErrorExit:
for(i=0; i<ui32BufferCount; i++)
{
if(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo)
{
PVRSRVKernelSyncInfoDecRef(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL);
if (psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount == 0)
{
PVRSRVFreeSyncInfoKM(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo);
}
}
}
if(psQueue)
{
PVRSRVDestroyCommandQueueKM(psQueue);
}
if(psSwapChain)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SWAPCHAIN), psSwapChain, IMG_NULL);
}
return eError;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVSetDCDstRectKM(IMG_HANDLE hDeviceKM,
IMG_HANDLE hSwapChainRef,
IMG_RECT *psRect)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVRSRV_DC_SWAPCHAIN *psSwapChain;
if(!hDeviceKM || !hSwapChainRef)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSetDCDstRectKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
psSwapChain = ((PVRSRV_DC_SWAPCHAIN_REF*)hSwapChainRef)->psSwapChain;
return psDCInfo->psFuncTable->pfnSetDCDstRect(psDCInfo->hExtDevice,
psSwapChain->hExtSwapChain,
psRect);
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVSetDCSrcRectKM(IMG_HANDLE hDeviceKM,
IMG_HANDLE hSwapChainRef,
IMG_RECT *psRect)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVRSRV_DC_SWAPCHAIN *psSwapChain;
if(!hDeviceKM || !hSwapChainRef)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSetDCSrcRectKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
psSwapChain = ((PVRSRV_DC_SWAPCHAIN_REF*)hSwapChainRef)->psSwapChain;
return psDCInfo->psFuncTable->pfnSetDCSrcRect(psDCInfo->hExtDevice,
psSwapChain->hExtSwapChain,
psRect);
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVSetDCDstColourKeyKM(IMG_HANDLE hDeviceKM,
IMG_HANDLE hSwapChainRef,
IMG_UINT32 ui32CKColour)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVRSRV_DC_SWAPCHAIN *psSwapChain;
if(!hDeviceKM || !hSwapChainRef)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSetDCDstColourKeyKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
psSwapChain = ((PVRSRV_DC_SWAPCHAIN_REF*)hSwapChainRef)->psSwapChain;
return psDCInfo->psFuncTable->pfnSetDCDstColourKey(psDCInfo->hExtDevice,
psSwapChain->hExtSwapChain,
ui32CKColour);
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVSetDCSrcColourKeyKM(IMG_HANDLE hDeviceKM,
IMG_HANDLE hSwapChainRef,
IMG_UINT32 ui32CKColour)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVRSRV_DC_SWAPCHAIN *psSwapChain;
if(!hDeviceKM || !hSwapChainRef)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSetDCSrcColourKeyKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
psSwapChain = ((PVRSRV_DC_SWAPCHAIN_REF*)hSwapChainRef)->psSwapChain;
return psDCInfo->psFuncTable->pfnSetDCSrcColourKey(psDCInfo->hExtDevice,
psSwapChain->hExtSwapChain,
ui32CKColour);
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVGetDCBuffersKM(IMG_HANDLE hDeviceKM,
IMG_HANDLE hSwapChainRef,
IMG_UINT32 *pui32BufferCount,
IMG_HANDLE *phBuffer,
IMG_SYS_PHYADDR *psPhyAddr)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVRSRV_DC_SWAPCHAIN *psSwapChain;
IMG_HANDLE ahExtBuffer[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS];
PVRSRV_ERROR eError;
IMG_UINT32 i;
if(!hDeviceKM || !hSwapChainRef || !phBuffer || !psPhyAddr)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetDCBuffersKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
psSwapChain = ((PVRSRV_DC_SWAPCHAIN_REF*)hSwapChainRef)->psSwapChain;
eError = psDCInfo->psFuncTable->pfnGetDCBuffers(psDCInfo->hExtDevice,
psSwapChain->hExtSwapChain,
pui32BufferCount,
ahExtBuffer);
PVR_ASSERT(*pui32BufferCount <= PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS);
for(i=0; i<*pui32BufferCount; i++)
{
psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtBuffer = ahExtBuffer[i];
phBuffer[i] = (IMG_HANDLE)&psSwapChain->asBuffer[i];
}
#if defined(SUPPORT_GET_DC_BUFFERS_SYS_PHYADDRS)
for(i = 0; i < *pui32BufferCount; i++)
{
IMG_UINT32 ui32ByteSize, ui32TilingStride;
IMG_SYS_PHYADDR *pPhyAddr;
IMG_BOOL bIsContiguous;
IMG_HANDLE hOSMapInfo;
IMG_VOID *pvVAddr;
eError = psDCInfo->psFuncTable->pfnGetBufferAddr(psDCInfo->hExtDevice,
ahExtBuffer[i],
&pPhyAddr,
&ui32ByteSize,
&pvVAddr,
&hOSMapInfo,
&bIsContiguous,
&ui32TilingStride);
if(eError != PVRSRV_OK)
{
break;
}
psPhyAddr[i] = *pPhyAddr;
}
#endif
return eError;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVSwapToDCBufferKM(IMG_HANDLE hDeviceKM,
IMG_HANDLE hBuffer,
IMG_UINT32 ui32SwapInterval,
IMG_HANDLE hPrivateTag,
IMG_UINT32 ui32ClipRectCount,
IMG_RECT *psClipRect)
{
PVRSRV_ERROR eError;
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVRSRV_DC_BUFFER *psBuffer;
PVRSRV_QUEUE_INFO *psQueue;
DISPLAYCLASS_FLIP_COMMAND *psFlipCmd;
IMG_UINT32 i;
IMG_BOOL bAddReferenceToLast = IMG_TRUE;
IMG_UINT16 ui16SwapCommandID = DC_FLIP_COMMAND;
IMG_UINT32 ui32NumSrcSyncs = 1;
PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[2];
PVRSRV_COMMAND *psCommand;
SYS_DATA *psSysData;
if(!hDeviceKM || !hBuffer || !psClipRect)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBufferKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psBuffer = (PVRSRV_DC_BUFFER*)hBuffer;
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
if(ui32SwapInterval < psBuffer->psSwapChain->ui32MinSwapInterval ||
ui32SwapInterval > psBuffer->psSwapChain->ui32MaxSwapInterval)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBufferKM: Invalid swap interval. Requested %u, Allowed range %u-%u",
ui32SwapInterval, psBuffer->psSwapChain->ui32MinSwapInterval, psBuffer->psSwapChain->ui32MaxSwapInterval));
return PVRSRV_ERROR_INVALID_SWAPINTERVAL;
}
#if defined(SUPPORT_CUSTOM_SWAP_OPERATIONS)
if(psDCInfo->psFuncTable->pfnQuerySwapCommandID != IMG_NULL)
{
psDCInfo->psFuncTable->pfnQuerySwapCommandID(psDCInfo->hExtDevice,
psBuffer->psSwapChain->hExtSwapChain,
psBuffer->sDeviceClassBuffer.hExtBuffer,
hPrivateTag,
&ui16SwapCommandID,
&bAddReferenceToLast);
}
#endif
psQueue = psBuffer->psSwapChain->psQueue;
apsSrcSync[0] = psBuffer->sDeviceClassBuffer.psKernelSyncInfo;
if(bAddReferenceToLast && psBuffer->psSwapChain->psLastFlipBuffer &&
psBuffer != psBuffer->psSwapChain->psLastFlipBuffer)
{
apsSrcSync[1] = psBuffer->psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.psKernelSyncInfo;
ui32NumSrcSyncs++;
}
eError = PVRSRVInsertCommandKM (psQueue,
&psCommand,
psDCInfo->ui32DeviceID,
ui16SwapCommandID,
0,
IMG_NULL,
ui32NumSrcSyncs,
apsSrcSync,
sizeof(DISPLAYCLASS_FLIP_COMMAND) + (sizeof(IMG_RECT) * ui32ClipRectCount),
IMG_NULL,
IMG_NULL);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBufferKM: Failed to get space in queue"));
goto Exit;
}
psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)psCommand->pvData;
psFlipCmd->hExtDevice = psDCInfo->hExtDevice;
psFlipCmd->hExtSwapChain = psBuffer->psSwapChain->hExtSwapChain;
psFlipCmd->hExtBuffer = psBuffer->sDeviceClassBuffer.hExtBuffer;
psFlipCmd->hPrivateTag = hPrivateTag;
psFlipCmd->ui32ClipRectCount = ui32ClipRectCount;
psFlipCmd->psClipRect = (IMG_RECT*)((IMG_UINT8*)psFlipCmd + sizeof(DISPLAYCLASS_FLIP_COMMAND));
for(i=0; i<ui32ClipRectCount; i++)
{
psFlipCmd->psClipRect[i] = psClipRect[i];
}
psFlipCmd->ui32SwapInterval = ui32SwapInterval;
SysAcquireData(&psSysData);
{
if(psSysData->ePendingCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH)
{
OSFlushCPUCacheKM();
}
else if(psSysData->ePendingCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN)
{
OSCleanCPUCacheKM();
}
psSysData->ePendingCacheOpType = PVRSRV_MISC_INFO_CPUCACHEOP_NONE;
}
eError = PVRSRVSubmitCommandKM (psQueue, psCommand);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBufferKM: Failed to submit command"));
goto Exit;
}
eError = OSScheduleMISR(psSysData);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBufferKM: Failed to schedule MISR"));
goto Exit;
}
psBuffer->psSwapChain->psLastFlipBuffer = psBuffer;
Exit:
if(eError == PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE)
{
eError = PVRSRV_ERROR_RETRY;
}
return eError;
}
typedef struct _CALLBACK_DATA_
{
IMG_PVOID pvPrivData;
IMG_UINT32 ui32PrivDataLength;
IMG_PVOID ppvMemInfos;
IMG_UINT32 ui32NumMemInfos;
} CALLBACK_DATA;
static IMG_VOID FreePrivateData(IMG_HANDLE hCallbackData)
{
CALLBACK_DATA *psCallbackData = hCallbackData;
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, psCallbackData->ui32PrivDataLength,
psCallbackData->pvPrivData, IMG_NULL);
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(IMG_VOID *) * psCallbackData->ui32NumMemInfos,
psCallbackData->ppvMemInfos, IMG_NULL);
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(CALLBACK_DATA), hCallbackData, IMG_NULL);
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVSwapToDCBuffer2KM(IMG_HANDLE hDeviceKM,
IMG_HANDLE hSwapChain,
IMG_UINT32 ui32SwapInterval,
PVRSRV_KERNEL_MEM_INFO **ppsMemInfos,
PVRSRV_KERNEL_SYNC_INFO **ppsSyncInfos,
IMG_UINT32 ui32NumMemSyncInfos,
IMG_PVOID pvPrivData,
IMG_UINT32 ui32PrivDataLength)
{
PVRSRV_KERNEL_SYNC_INFO **ppsCompiledSyncInfos;
IMG_UINT32 i, ui32NumCompiledSyncInfos;
DISPLAYCLASS_FLIP_COMMAND2 *psFlipCmd;
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVRSRV_DC_SWAPCHAIN *psSwapChain;
PVRSRV_ERROR eError = PVRSRV_OK;
CALLBACK_DATA *psCallbackData;
PVRSRV_QUEUE_INFO *psQueue;
PVRSRV_COMMAND *psCommand;
IMG_PVOID *ppvMemInfos;
SYS_DATA *psSysData;
if(!hDeviceKM || !hSwapChain || !ppsMemInfos || !ppsSyncInfos || ui32NumMemSyncInfos < 1)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psSwapChain = ((PVRSRV_DC_SWAPCHAIN_REF*)hSwapChain)->psSwapChain;
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
if(ui32SwapInterval < psSwapChain->ui32MinSwapInterval ||
ui32SwapInterval > psSwapChain->ui32MaxSwapInterval)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Invalid swap interval. Requested %u, Allowed range %u-%u",
ui32SwapInterval, psSwapChain->ui32MinSwapInterval, psSwapChain->ui32MaxSwapInterval));
return PVRSRV_ERROR_INVALID_SWAPINTERVAL;
}
eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(CALLBACK_DATA),
(IMG_VOID **)&psCallbackData, IMG_NULL,
"PVRSRVSwapToDCBuffer2KM callback data");
if (eError != PVRSRV_OK)
{
return eError;
}
psCallbackData->pvPrivData = pvPrivData;
psCallbackData->ui32PrivDataLength = ui32PrivDataLength;
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(IMG_VOID *) * ui32NumMemSyncInfos,
(IMG_VOID **)&ppvMemInfos, IMG_NULL,
"Swap Command Meminfos") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to allocate space for meminfo list"));
psCallbackData->ppvMemInfos = IMG_NULL;
goto Exit;
}
for(i = 0; i < ui32NumMemSyncInfos; i++)
{
ppvMemInfos[i] = ppsMemInfos[i];
}
psCallbackData->ppvMemInfos = ppvMemInfos;
psCallbackData->ui32NumMemInfos = ui32NumMemSyncInfos;
psQueue = psSwapChain->psQueue;
#if !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED)
if(psSwapChain->ppsLastSyncInfos)
{
IMG_UINT32 ui32NumUniqueSyncInfos = psSwapChain->ui32LastNumSyncInfos;
IMG_UINT32 j;
for(j = 0; j < psSwapChain->ui32LastNumSyncInfos; j++)
{
for(i = 0; i < ui32NumMemSyncInfos; i++)
{
if(psSwapChain->ppsLastSyncInfos[j] == ppsSyncInfos[i])
{
psSwapChain->ppsLastSyncInfos[j] = IMG_NULL;
ui32NumUniqueSyncInfos--;
}
}
}
ui32NumCompiledSyncInfos = ui32NumMemSyncInfos + ui32NumUniqueSyncInfos;
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(PVRSRV_KERNEL_SYNC_INFO *) * ui32NumCompiledSyncInfos,
(IMG_VOID **)&ppsCompiledSyncInfos, IMG_NULL,
"Compiled syncinfos") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to allocate space for meminfo list"));
goto Exit;
}
OSMemCopy(ppsCompiledSyncInfos, ppsSyncInfos, sizeof(PVRSRV_KERNEL_SYNC_INFO *) * ui32NumMemSyncInfos);
for(j = 0, i = ui32NumMemSyncInfos; j < psSwapChain->ui32LastNumSyncInfos; j++)
{
if(psSwapChain->ppsLastSyncInfos[j])
{
ppsCompiledSyncInfos[i] = psSwapChain->ppsLastSyncInfos[j];
i++;
}
}
}
else
#endif
{
ppsCompiledSyncInfos = ppsSyncInfos;
ui32NumCompiledSyncInfos = ui32NumMemSyncInfos;
}
eError = PVRSRVInsertCommandKM (psQueue,
&psCommand,
psDCInfo->ui32DeviceID,
DC_FLIP_COMMAND,
0,
IMG_NULL,
ui32NumCompiledSyncInfos,
ppsCompiledSyncInfos,
sizeof(DISPLAYCLASS_FLIP_COMMAND2),
FreePrivateData,
psCallbackData);
if (ppsCompiledSyncInfos != ppsSyncInfos)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(PVRSRV_KERNEL_SYNC_INFO *) * ui32NumCompiledSyncInfos,
(IMG_VOID *)ppsCompiledSyncInfos,
IMG_NULL);
}
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to get space in queue"));
goto Exit;
}
psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND2*)psCommand->pvData;
psFlipCmd->hUnused = IMG_NULL;
psFlipCmd->hExtDevice = psDCInfo->hExtDevice;
psFlipCmd->hExtSwapChain = psSwapChain->hExtSwapChain;
psFlipCmd->ui32SwapInterval = ui32SwapInterval;
psFlipCmd->pvPrivData = pvPrivData;
psFlipCmd->ui32PrivDataLength = ui32PrivDataLength;
psFlipCmd->ppsMemInfos = (PDC_MEM_INFO *)ppvMemInfos;
psFlipCmd->ui32NumMemInfos = ui32NumMemSyncInfos;
SysAcquireData(&psSysData);
{
if(psSysData->ePendingCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH)
{
OSFlushCPUCacheKM();
}
else if(psSysData->ePendingCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN)
{
OSCleanCPUCacheKM();
}
psSysData->ePendingCacheOpType = PVRSRV_MISC_INFO_CPUCACHEOP_NONE;
}
eError = PVRSRVSubmitCommandKM (psQueue, psCommand);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to submit command"));
goto Exit;
}
psCallbackData = IMG_NULL;
eError = OSScheduleMISR(psSysData);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to schedule MISR"));
goto Exit;
}
#if !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED)
if (psSwapChain->ui32LastNumSyncInfos < ui32NumMemSyncInfos)
{
if (psSwapChain->ppsLastSyncInfos)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_KERNEL_SYNC_INFO *) * psSwapChain->ui32LastNumSyncInfos,
psSwapChain->ppsLastSyncInfos, IMG_NULL);
}
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(PVRSRV_KERNEL_SYNC_INFO *) * ui32NumMemSyncInfos,
(IMG_VOID **)&psSwapChain->ppsLastSyncInfos, IMG_NULL,
"Last syncinfos") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to allocate space for meminfo list"));
goto Exit;
}
}
psSwapChain->ui32LastNumSyncInfos = ui32NumMemSyncInfos;
for(i = 0; i < ui32NumMemSyncInfos; i++)
{
psSwapChain->ppsLastSyncInfos[i] = ppsSyncInfos[i];
}
#endif
Exit:
if (psCallbackData)
{
if(psCallbackData->ppvMemInfos)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(IMG_VOID *) * psCallbackData->ui32NumMemInfos,
psCallbackData->ppvMemInfos, IMG_NULL);
}
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(CALLBACK_DATA), psCallbackData, IMG_NULL);
}
if(eError == PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE)
{
eError = PVRSRV_ERROR_RETRY;
}
return eError;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVSwapToDCSystemKM(IMG_HANDLE hDeviceKM,
IMG_HANDLE hSwapChainRef)
{
PVRSRV_ERROR eError;
PVRSRV_QUEUE_INFO *psQueue;
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
PVRSRV_DC_SWAPCHAIN *psSwapChain;
PVRSRV_DC_SWAPCHAIN_REF *psSwapChainRef;
DISPLAYCLASS_FLIP_COMMAND *psFlipCmd;
IMG_UINT32 ui32NumSrcSyncs = 1;
PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[2];
PVRSRV_COMMAND *psCommand;
IMG_BOOL bAddReferenceToLast = IMG_TRUE;
IMG_UINT16 ui16SwapCommandID = DC_FLIP_COMMAND;
SYS_DATA *psSysData;
if(!hDeviceKM || !hSwapChainRef)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCSystemKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
psSwapChainRef = (PVRSRV_DC_SWAPCHAIN_REF*)hSwapChainRef;
psSwapChain = psSwapChainRef->psSwapChain;
psQueue = psSwapChain->psQueue;
#if defined(SUPPORT_CUSTOM_SWAP_OPERATIONS)
if(psDCInfo->psFuncTable->pfnQuerySwapCommandID != IMG_NULL)
{
psDCInfo->psFuncTable->pfnQuerySwapCommandID(psDCInfo->hExtDevice,
psSwapChain->hExtSwapChain,
psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtBuffer,
0,
&ui16SwapCommandID,
&bAddReferenceToLast);
}
#endif
apsSrcSync[0] = psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo;
if(bAddReferenceToLast && psSwapChain->psLastFlipBuffer)
{
if (apsSrcSync[0] != psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.psKernelSyncInfo)
{
apsSrcSync[1] = psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.psKernelSyncInfo;
ui32NumSrcSyncs++;
}
}
eError = PVRSRVInsertCommandKM (psQueue,
&psCommand,
psDCInfo->ui32DeviceID,
ui16SwapCommandID,
0,
IMG_NULL,
ui32NumSrcSyncs,
apsSrcSync,
sizeof(DISPLAYCLASS_FLIP_COMMAND),
IMG_NULL,
IMG_NULL);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCSystemKM: Failed to get space in queue"));
goto Exit;
}
psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)psCommand->pvData;
psFlipCmd->hExtDevice = psDCInfo->hExtDevice;
psFlipCmd->hExtSwapChain = psSwapChain->hExtSwapChain;
psFlipCmd->hExtBuffer = psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtBuffer;
psFlipCmd->hPrivateTag = IMG_NULL;
psFlipCmd->ui32ClipRectCount = 0;
psFlipCmd->ui32SwapInterval = 1;
eError = PVRSRVSubmitCommandKM (psQueue, psCommand);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCSystemKM: Failed to submit command"));
goto Exit;
}
SysAcquireData(&psSysData);
eError = OSScheduleMISR(psSysData);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCSystemKM: Failed to schedule MISR"));
goto Exit;
}
psSwapChain->psLastFlipBuffer = &psDCInfo->sSystemBuffer;
eError = PVRSRV_OK;
Exit:
if(eError == PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE)
{
eError = PVRSRV_ERROR_RETRY;
}
return eError;
}
static
PVRSRV_ERROR PVRSRVRegisterSystemISRHandler (PFN_ISR_HANDLER pfnISRHandler,
IMG_VOID *pvISRHandlerData,
IMG_UINT32 ui32ISRSourceMask,
IMG_UINT32 ui32DeviceID)
{
SYS_DATA *psSysData;
PVRSRV_DEVICE_NODE *psDevNode;
PVR_UNREFERENCED_PARAMETER(ui32ISRSourceMask);
SysAcquireData(&psSysData);
psDevNode = (PVRSRV_DEVICE_NODE*)
List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList,
&MatchDeviceKM_AnyVaCb,
ui32DeviceID,
IMG_TRUE);
if (psDevNode == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterSystemISRHandler: Failed to get psDevNode"));
PVR_DBG_BREAK;
return PVRSRV_ERROR_NO_DEVICENODE_FOUND;
}
psDevNode->pvISRData = (IMG_VOID*) pvISRHandlerData;
psDevNode->pfnDeviceISR = pfnISRHandler;
return PVRSRV_OK;
}
static
IMG_VOID PVRSRVSetDCState_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va)
{
PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
IMG_UINT32 ui32State;
ui32State = va_arg(va, IMG_UINT32);
if (psDeviceNode->sDevId.eDeviceClass == PVRSRV_DEVICE_CLASS_DISPLAY)
{
psDCInfo = (PVRSRV_DISPLAYCLASS_INFO *)psDeviceNode->pvDevice;
if (psDCInfo->psFuncTable->pfnSetDCState && psDCInfo->hExtDevice)
{
psDCInfo->psFuncTable->pfnSetDCState(psDCInfo->hExtDevice, ui32State);
}
}
}
IMG_VOID IMG_CALLCONV PVRSRVSetDCState(IMG_UINT32 ui32State)
{
SYS_DATA *psSysData;
SysAcquireData(&psSysData);
List_PVRSRV_DEVICE_NODE_ForEach_va(psSysData->psDeviceNodeList,
&PVRSRVSetDCState_ForEachVaCb,
ui32State);
}
static PVRSRV_ERROR
PVRSRVDCMemInfoGetCpuVAddr(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo,
IMG_CPU_VIRTADDR *pVAddr)
{
*pVAddr = psKernelMemInfo->pvLinAddrKM;
return PVRSRV_OK;
}
static PVRSRV_ERROR
PVRSRVDCMemInfoGetCpuPAddr(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo,
IMG_SIZE_T uByteOffset, IMG_CPU_PHYADDR *pPAddr)
{
*pPAddr = OSMemHandleToCpuPAddr(psKernelMemInfo->sMemBlk.hOSMemHandle, uByteOffset);
return PVRSRV_OK;
}
static PVRSRV_ERROR
PVRSRVDCMemInfoGetByteSize(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo,
IMG_SIZE_T *uByteSize)
{
*uByteSize = psKernelMemInfo->uAllocSize;
return PVRSRV_OK;
}
static IMG_BOOL
PVRSRVDCMemInfoIsPhysContig(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo)
{
return OSMemHandleIsPhysContig(psKernelMemInfo->sMemBlk.hOSMemHandle);
}
IMG_EXPORT
IMG_BOOL PVRGetDisplayClassJTable(PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable)
{
psJTable->ui32TableSize = sizeof(PVRSRV_DC_DISP2SRV_KMJTABLE);
psJTable->pfnPVRSRVRegisterDCDevice = &PVRSRVRegisterDCDeviceKM;
psJTable->pfnPVRSRVRemoveDCDevice = &PVRSRVRemoveDCDeviceKM;
psJTable->pfnPVRSRVOEMFunction = &SysOEMFunction;
psJTable->pfnPVRSRVRegisterCmdProcList = &PVRSRVRegisterCmdProcListKM;
psJTable->pfnPVRSRVRemoveCmdProcList = &PVRSRVRemoveCmdProcListKM;
#if defined(SUPPORT_MISR_IN_THREAD)
psJTable->pfnPVRSRVCmdComplete = &OSVSyncMISR;
#else
psJTable->pfnPVRSRVCmdComplete = &PVRSRVCommandCompleteKM;
#endif
psJTable->pfnPVRSRVRegisterSystemISRHandler = &PVRSRVRegisterSystemISRHandler;
psJTable->pfnPVRSRVRegisterPowerDevice = &PVRSRVRegisterPowerDevice;
#if defined(SUPPORT_CUSTOM_SWAP_OPERATIONS)
psJTable->pfnPVRSRVFreeCmdCompletePacket = &PVRSRVFreeCommandCompletePacketKM;
#endif
psJTable->pfnPVRSRVDCMemInfoGetCpuVAddr = &PVRSRVDCMemInfoGetCpuVAddr;
psJTable->pfnPVRSRVDCMemInfoGetCpuPAddr = &PVRSRVDCMemInfoGetCpuPAddr;
psJTable->pfnPVRSRVDCMemInfoGetByteSize = &PVRSRVDCMemInfoGetByteSize;
psJTable->pfnPVRSRVDCMemInfoIsPhysContig = &PVRSRVDCMemInfoIsPhysContig;
return IMG_TRUE;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVCloseBCDeviceKM (IMG_HANDLE hDeviceKM,
IMG_BOOL bResManCallback)
{
PVRSRV_ERROR eError;
PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo;
PVR_UNREFERENCED_PARAMETER(bResManCallback);
psBCPerContextInfo = (PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *)hDeviceKM;
eError = ResManFreeResByPtr(psBCPerContextInfo->hResItem, CLEANUP_WITH_POLL);
return eError;
}
static PVRSRV_ERROR CloseBCDeviceCallBack(IMG_PVOID pvParam,
IMG_UINT32 ui32Param,
IMG_BOOL bDummy)
{
PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo;
PVRSRV_BUFFERCLASS_INFO *psBCInfo;
IMG_UINT32 i;
PVR_UNREFERENCED_PARAMETER(ui32Param);
PVR_UNREFERENCED_PARAMETER(bDummy);
psBCPerContextInfo = (PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *)pvParam;
psBCInfo = psBCPerContextInfo->psBCInfo;
for (i = 0; i < psBCInfo->ui32BufferCount; i++)
{
if (psBCInfo->psBuffer[i].sDeviceClassBuffer.ui32MemMapRefCount != 0)
{
PVR_DPF((PVR_DBG_ERROR, "CloseBCDeviceCallBack: buffer %d (0x%p) still mapped (ui32MemMapRefCount = %d)",
i,
&psBCInfo->psBuffer[i].sDeviceClassBuffer,
psBCInfo->psBuffer[i].sDeviceClassBuffer.ui32MemMapRefCount));
return PVRSRV_ERROR_STILL_MAPPED;
}
}
psBCInfo->ui32RefCount--;
if(psBCInfo->ui32RefCount == 0)
{
psBCInfo->psFuncTable->pfnCloseBCDevice(psBCInfo->ui32DeviceID, psBCInfo->hExtDevice);
for(i=0; i<psBCInfo->ui32BufferCount; i++)
{
if(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo)
{
PVRSRVKernelSyncInfoDecRef(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL);
if (psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount == 0)
{
PVRSRVFreeSyncInfoKM(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo);
}
}
}
if(psBCInfo->psBuffer)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BC_BUFFER) * psBCInfo->ui32BufferCount, psBCInfo->psBuffer, IMG_NULL);
psBCInfo->psBuffer = IMG_NULL;
}
}
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BUFFERCLASS_PERCONTEXT_INFO), psBCPerContextInfo, IMG_NULL);
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVOpenBCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc,
IMG_UINT32 ui32DeviceID,
IMG_HANDLE hDevCookie,
IMG_HANDLE *phDeviceKM)
{
PVRSRV_BUFFERCLASS_INFO *psBCInfo;
PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo;
PVRSRV_DEVICE_NODE *psDeviceNode;
SYS_DATA *psSysData;
IMG_UINT32 i;
PVRSRV_ERROR eError;
if(!phDeviceKM || !hDevCookie)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenBCDeviceKM: Invalid params"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
SysAcquireData(&psSysData);
psDeviceNode = (PVRSRV_DEVICE_NODE*)
List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList,
&MatchDeviceKM_AnyVaCb,
ui32DeviceID,
IMG_FALSE,
PVRSRV_DEVICE_CLASS_BUFFER);
if (!psDeviceNode)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenBCDeviceKM: No devnode matching index %d", ui32DeviceID));
return PVRSRV_ERROR_NO_DEVICENODE_FOUND;
}
psBCInfo = (PVRSRV_BUFFERCLASS_INFO*)psDeviceNode->pvDevice;
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(*psBCPerContextInfo),
(IMG_VOID **)&psBCPerContextInfo, IMG_NULL,
"Buffer Class per Context Info") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenBCDeviceKM: Failed psBCPerContextInfo alloc"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
OSMemSet(psBCPerContextInfo, 0, sizeof(*psBCPerContextInfo));
if(psBCInfo->ui32RefCount++ == 0)
{
BUFFER_INFO sBufferInfo;
psDeviceNode = (PVRSRV_DEVICE_NODE *)hDevCookie;
psBCInfo->hDevMemContext = (IMG_HANDLE)psDeviceNode->sDevMemoryInfo.pBMKernelContext;
eError = psBCInfo->psFuncTable->pfnOpenBCDevice(ui32DeviceID, &psBCInfo->hExtDevice);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenBCDeviceKM: Failed to open external BC device"));
return eError;
}
eError = psBCInfo->psFuncTable->pfnGetBCInfo(psBCInfo->hExtDevice, &sBufferInfo);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenBCDeviceKM : Failed to get BC Info"));
return eError;
}
psBCInfo->ui32BufferCount = sBufferInfo.ui32BufferCount;
eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(PVRSRV_BC_BUFFER) * sBufferInfo.ui32BufferCount,
(IMG_VOID **)&psBCInfo->psBuffer,
IMG_NULL,
"Array of Buffer Class Buffer");
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenBCDeviceKM: Failed to allocate BC buffers"));
return eError;
}
OSMemSet (psBCInfo->psBuffer,
0,
sizeof(PVRSRV_BC_BUFFER) * sBufferInfo.ui32BufferCount);
for(i=0; i<psBCInfo->ui32BufferCount; i++)
{
eError = PVRSRVAllocSyncInfoKM(IMG_NULL,
psBCInfo->hDevMemContext,
&psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenBCDeviceKM: Failed sync info alloc"));
goto ErrorExit;
}
PVRSRVKernelSyncInfoIncRef(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL);
eError = psBCInfo->psFuncTable->pfnGetBCBuffer(psBCInfo->hExtDevice,
i,
psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->psSyncData,
&psBCInfo->psBuffer[i].sDeviceClassBuffer.hExtBuffer);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenBCDeviceKM: Failed to get BC buffers"));
goto ErrorExit;
}
psBCInfo->psBuffer[i].sDeviceClassBuffer.pfnGetBufferAddr = psBCInfo->psFuncTable->pfnGetBufferAddr;
psBCInfo->psBuffer[i].sDeviceClassBuffer.hDevMemContext = psBCInfo->hDevMemContext;
psBCInfo->psBuffer[i].sDeviceClassBuffer.hExtDevice = psBCInfo->hExtDevice;
psBCInfo->psBuffer[i].sDeviceClassBuffer.ui32MemMapRefCount = 0;
}
}
psBCPerContextInfo->psBCInfo = psBCInfo;
psBCPerContextInfo->hResItem = ResManRegisterRes(psPerProc->hResManContext,
RESMAN_TYPE_BUFFERCLASS_DEVICE,
psBCPerContextInfo,
0,
&CloseBCDeviceCallBack);
*phDeviceKM = (IMG_HANDLE)psBCPerContextInfo;
return PVRSRV_OK;
ErrorExit:
for(i=0; i<psBCInfo->ui32BufferCount; i++)
{
if(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo)
{
PVRSRVKernelSyncInfoDecRef(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL);
if (psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount == 0)
{
PVRSRVFreeSyncInfoKM(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo);
}
}
}
if(psBCInfo->psBuffer)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BC_BUFFER), psBCInfo->psBuffer, IMG_NULL);
psBCInfo->psBuffer = IMG_NULL;
}
return eError;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVGetBCInfoKM (IMG_HANDLE hDeviceKM,
BUFFER_INFO *psBufferInfo)
{
PVRSRV_BUFFERCLASS_INFO *psBCInfo;
PVRSRV_ERROR eError;
if(!hDeviceKM || !psBufferInfo)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetBCInfoKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psBCInfo = BCDeviceHandleToBCInfo(hDeviceKM);
eError = psBCInfo->psFuncTable->pfnGetBCInfo(psBCInfo->hExtDevice, psBufferInfo);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetBCInfoKM : Failed to get BC Info"));
return eError;
}
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVGetBCBufferKM (IMG_HANDLE hDeviceKM,
IMG_UINT32 ui32BufferIndex,
IMG_HANDLE *phBuffer)
{
PVRSRV_BUFFERCLASS_INFO *psBCInfo;
if(!hDeviceKM || !phBuffer)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetBCBufferKM: Invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psBCInfo = BCDeviceHandleToBCInfo(hDeviceKM);
if(ui32BufferIndex < psBCInfo->ui32BufferCount)
{
*phBuffer = (IMG_HANDLE)&psBCInfo->psBuffer[ui32BufferIndex];
}
else
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetBCBufferKM: Buffer index %d out of range (%d)", ui32BufferIndex,psBCInfo->ui32BufferCount));
return PVRSRV_ERROR_INVALID_PARAMS;
}
return PVRSRV_OK;
}
IMG_EXPORT
IMG_BOOL PVRGetBufferClassJTable(PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable)
{
psJTable->ui32TableSize = sizeof(PVRSRV_BC_BUFFER2SRV_KMJTABLE);
psJTable->pfnPVRSRVRegisterBCDevice = &PVRSRVRegisterBCDeviceKM;
psJTable->pfnPVRSRVScheduleDevices = &PVRSRVScheduleDevicesKM;
psJTable->pfnPVRSRVRemoveBCDevice = &PVRSRVRemoveBCDeviceKM;
return IMG_TRUE;
}