/*************************************************************************/ /*! @File @Title Device class services functions @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved @Description Kernel services functions for device class devices @License Dual MIT/GPLv2 The contents of this file are subject to the MIT license as set out below. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Alternatively, the contents of this file may be used under the terms of the GNU General Public License Version 2 ("GPL") in which case the provisions of GPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of GPL, and not to allow others to use your version of this file under the terms of the MIT license, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by GPL as set out in the file called "GPL-COPYING" included in this distribution. If you do not delete the provisions above, a recipient may use your version of this file under the terms of either the MIT license or GPL. This License is also included in this distribution in the file called "MIT-COPYING". EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ #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" #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE) #include "pvr_sync_common.h" #endif PVRSRV_ERROR AllocateDeviceID(SYS_DATA *psSysData, IMG_UINT32 *pui32DevID); PVRSRV_ERROR FreeDeviceID(SYS_DATA *psSysData, IMG_UINT32 ui32DevID); /*********************************************************************** Local Display Class Structures ************************************************************************/ typedef struct PVRSRV_DC_SRV2DISP_KMJTABLE_TAG *PPVRSRV_DC_SRV2DISP_KMJTABLE; /* Display Class Buffer Info */ typedef struct PVRSRV_DC_BUFFER_TAG { /* BC/DC common details - THIS MUST BE THE FIRST MEMBER */ PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer; struct PVRSRV_DISPLAYCLASS_INFO_TAG *psDCInfo; struct PVRSRV_DC_SWAPCHAIN_TAG *psSwapChain; } PVRSRV_DC_BUFFER; /* Display Device Class kernel swapchain information structure */ 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 /* !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) */ struct PVRSRV_DISPLAYCLASS_INFO_TAG *psDCInfo; struct PVRSRV_DC_SWAPCHAIN_TAG *psNext; } PVRSRV_DC_SWAPCHAIN; /* Display Device Class kernel swapchain referecne structure */ typedef struct PVRSRV_DC_SWAPCHAIN_REF_TAG { struct PVRSRV_DC_SWAPCHAIN_TAG *psSwapChain; IMG_HANDLE hResItem; } PVRSRV_DC_SWAPCHAIN_REF; /* Display Device Class kernel services information structure */ 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; /* Per-context Display Device Class kernel services information structure */ typedef struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO_TAG { PVRSRV_DISPLAYCLASS_INFO *psDCInfo; PRESMAN_ITEM hResItem; } PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO; /*********************************************************************** Local Buffer Class Structures ************************************************************************/ typedef struct PVRSRV_BC_SRV2BUFFER_KMJTABLE_TAG *PPVRSRV_BC_SRV2BUFFER_KMJTABLE; /* Buffer Class Buffer Info */ typedef struct PVRSRV_BC_BUFFER_TAG { /* BC/DC common details - THIS MUST BE THE FIRST MEMBER */ PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer; struct PVRSRV_BUFFERCLASS_INFO_TAG *psBCInfo; } PVRSRV_BC_BUFFER; /* Buffer Device Class kernel services information structure */ typedef struct PVRSRV_BUFFERCLASS_INFO_TAG { IMG_UINT32 ui32RefCount; IMG_UINT32 ui32DeviceID; IMG_HANDLE hExtDevice; PPVRSRV_BC_SRV2BUFFER_KMJTABLE psFuncTable; IMG_HANDLE hDevMemContext; /* buffer info returned from 3rd party driver */ IMG_UINT32 ui32BufferCount; PVRSRV_BC_BUFFER *psBuffer; } PVRSRV_BUFFERCLASS_INFO; /* Per-context Buffer Device Class kernel services information structure */ typedef struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO_TAG { PVRSRV_BUFFERCLASS_INFO *psBCInfo; IMG_HANDLE hResItem; } PVRSRV_BUFFERCLASS_PERCONTEXT_INFO; /*! ****************************************************************************** @Function DCDeviceHandleToDCInfo @Description Convert a client-visible 3rd party device class handle to an internal PVRSRV_DISPLAYCLASS_INFO pointer. @Input hDeviceKM - handle to display class device, returned from OpenDCDevice @Return success: pointer to PVRSRV_DISPLAYCLASS_INFO failure: IMG_NULL ******************************************************************************/ static PVRSRV_DISPLAYCLASS_INFO* DCDeviceHandleToDCInfo (IMG_HANDLE hDeviceKM) { PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; psDCPerContextInfo = (PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *)hDeviceKM; return psDCPerContextInfo->psDCInfo; } /*! ****************************************************************************** @Function BCDeviceHandleToBCInfo @Description Convert a client-visible 3rd party buffer class handle to an internal PVRSRV_BUFFERCLASS_INFO pointer. @Input hDeviceKM - handle to buffer class device, returned from OpenBCDevice @Return success: pointer to PVRSRV_BUFFERCLASS_INFO failure: IMG_NULL ******************************************************************************/ static PVRSRV_BUFFERCLASS_INFO* BCDeviceHandleToBCInfo (IMG_HANDLE hDeviceKM) { PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; psBCPerContextInfo = (PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *)hDeviceKM; return psBCPerContextInfo->psBCInfo; } /*! ****************************************************************************** @Function PVRSRVEnumerateDCKM_ForEachVaCb @Description Enumerates the device node (if is of the same class as given). @Input psDeviceNode - The device node to be enumerated va - variable arguments list, with: pui32DevCount - The device count pointer (to be increased) ppui32DevID - The pointer to the device IDs pointer (to be updated and increased) peDeviceClass - The pointer to the device class of the psDeviceNode's to be enumerated. ******************************************************************************/ 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; } } } /*! ****************************************************************************** @Function PVRSRVEnumerateDCKM @Description Enumerates devices available in a given class. On first call, pass valid ptr for pui32DevCount and IMG_NULL for pui32DevID, On second call, pass same ptr for pui32DevCount and client allocated ptr for pui32DevID device id list @Input hServices - handle for services connection @Input ui32DevClass - device class identifier @Output pui32DevCount - number of devices available in class @Output pui32DevID - list of device ids in the device class @Return success: handle to matching display class device failure: IMG_NULL ******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVEnumerateDCKM (PVRSRV_DEVICE_CLASS DeviceClass, IMG_UINT32 *pui32DevCount, IMG_UINT32 *pui32DevID ) { /*PVRSRV_DEVICE_NODE *psDeviceNode;*/ IMG_UINT ui32DevCount = 0; SYS_DATA *psSysData; SysAcquireData(&psSysData); /* search devonode list for devices in specified class and return the device ids */ 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; } /*! ****************************************************************************** @Function PVRSRVRegisterDCDeviceKM @Description registers an external device with the system @Input psFuncTable : device function table @Output pui32DeviceID : unique device key (for case of multiple identical devices) @Return PVRSRV_ERROR : ******************************************************************************/ static PVRSRV_ERROR PVRSRVRegisterDCDeviceKM (PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable, IMG_UINT32 *pui32DeviceID) { PVRSRV_DISPLAYCLASS_INFO *psDCInfo = IMG_NULL; PVRSRV_DEVICE_NODE *psDeviceNode = IMG_NULL; SYS_DATA *psSysData; /* IN: - name of client side ext. device driver library for subsequent loading - predefined list of callbacks into kernel ext. device driver (based on class type) FUNCTION TASKS: - allocate display device class info structure - hang ext.device kernel callbacks on this structure (pfnKSwapToSystem) OUT: - DEVICE_ID - pass back devinfo? no Q&A: - DEVICE_ID passed in or allocated - assume allocate */ SysAcquireData(&psSysData); /* If we got this far we're doing dynamic enumeration or first time static registration */ /* Allocate device control block */ 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)); /* setup the display device information structure */ 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)); /* copy the jump table */ *psDCInfo->psFuncTable = *psFuncTable; /* Allocate device node */ 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; /* allocate a unique device id */ 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; } /* Register the device with the system */ SysRegisterExternalDevice(psDeviceNode); /* and finally insert the device into the dev-list */ 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); /*not nulling pointer, out of scope*/ if(psDeviceNode) { OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL); } return PVRSRV_ERROR_OUT_OF_MEMORY; } /*! ****************************************************************************** @Function PVRSRVRemoveDCDeviceKM @Description Removes external device from services system record @Input ui32DeviceIndex : unique device key (for case of multiple identical devices) @Return PVRSRV_ERROR : ******************************************************************************/ static PVRSRV_ERROR PVRSRVRemoveDCDeviceKM(IMG_UINT32 ui32DevIndex) { SYS_DATA *psSysData; PVRSRV_DEVICE_NODE *psDeviceNode; PVRSRV_DISPLAYCLASS_INFO *psDCInfo; SysAcquireData(&psSysData); /*search the node matching the devindex and display class*/ psDeviceNode = (PVRSRV_DEVICE_NODE*) List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, &MatchDeviceKM_AnyVaCb, ui32DevIndex, IMG_FALSE, PVRSRV_DEVICE_CLASS_DISPLAY); if (!psDeviceNode) { /*device not found*/ PVR_DPF((PVR_DBG_ERROR,"PVRSRVRemoveDCDeviceKM: requested device %d not present", ui32DevIndex)); return PVRSRV_ERROR_NO_DEVICENODE_FOUND; } /* setup DCInfo ptr */ psDCInfo = (PVRSRV_DISPLAYCLASS_INFO*)psDeviceNode->pvDevice; /* The device can only be removed if there are no open connections in the Services interface */ if(psDCInfo->ui32RefCount == 0) { /* Remove from the device list. */ List_PVRSRV_DEVICE_NODE_Remove(psDeviceNode); /* Unregister the device with the system */ SysRemoveExternalDevice(psDeviceNode); /* OK found a device with a matching devindex remove registration information */ 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); /*not nulling original pointer, overwritten*/ (IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL); /*not nulling pointer, out of scope*/ } 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; } /*! ****************************************************************************** @Function PVRSRVRegisterBCDeviceKM @Description registers an external device with the system @Input psFuncTable : device function table @Input ui32DeviceIndex : unique device key (for case of multiple identical devices) @Return PVRSRV_ERROR : ******************************************************************************/ static PVRSRV_ERROR PVRSRVRegisterBCDeviceKM (PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTable, IMG_UINT32 *pui32DeviceID) { PVRSRV_BUFFERCLASS_INFO *psBCInfo = IMG_NULL; PVRSRV_DEVICE_NODE *psDeviceNode = IMG_NULL; SYS_DATA *psSysData; /* IN: - name of client side ext. device driver library for subsequent loading - predefined list of callbacks into kernel ext. device driver (based on class type) FUNCTION TASKS: - allocate buffer device class info structure OUT: - DEVICE_ID - pass back devinfo? no Q&A: - DEVICE_ID passed in or allocated - assume allcoate */ SysAcquireData(&psSysData); /* If we got this far we're doing dynamic enumeration or first time static registration */ /* Allocate device control block */ 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)); /* setup the buffer device information structure */ 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)); /* copy the jump table */ *psBCInfo->psFuncTable = *psFuncTable; /* Allocate device node */ 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; /* allocate a unique device id */ 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; } /* and finally insert the device into the dev-list */ List_PVRSRV_DEVICE_NODE_Insert(&psSysData->psDeviceNodeList, psDeviceNode); return PVRSRV_OK; ErrorExit: if(psBCInfo->psFuncTable) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BC_SRV2BUFFER_KMJTABLE), psBCInfo->psFuncTable, IMG_NULL); psBCInfo->psFuncTable = IMG_NULL; } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BUFFERCLASS_INFO), psBCInfo, IMG_NULL); /*not nulling shared pointer, wasn't allocated to this point*/ if(psDeviceNode) { OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL); } return PVRSRV_ERROR_OUT_OF_MEMORY; } /*! ****************************************************************************** @Function PVRSRVRemoveBCDeviceKM @Description Removes external device from services system record @Input ui32DeviceIndex : unique device key (for case of multiple identical devices) @Return PVRSRV_ERROR : ******************************************************************************/ static PVRSRV_ERROR PVRSRVRemoveBCDeviceKM(IMG_UINT32 ui32DevIndex) { SYS_DATA *psSysData; PVRSRV_DEVICE_NODE *psDevNode; PVRSRV_BUFFERCLASS_INFO *psBCInfo; SysAcquireData(&psSysData); /*search the device node with the devindex and buffer class*/ 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; } /* set-up devnode ptr */ /* psDevNode = *(ppsDevNode); */ /* setup BCInfo ptr */ psBCInfo = (PVRSRV_BUFFERCLASS_INFO*)psDevNode->pvDevice; /* The device can only be removed if there are no open connections in the Services interface */ if(psBCInfo->ui32RefCount == 0) { /* Remove from the device list. */ List_PVRSRV_DEVICE_NODE_Remove(psDevNode); /* OK found a device with a matching devindex remove registration information */ (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); /*not nulling pointer, copy on stack*/ (IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), psDevNode, IMG_NULL); /*not nulling pointer, out of scope*/ } 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; } /*! ****************************************************************************** @Function PVRSRVCloseDCDeviceKM @Description Closes a connection to the Display Class device @Input hDeviceKM : device handle @Return PVRSRV_ERROR : ******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVCloseDCDeviceKM (IMG_HANDLE hDeviceKM) { PVRSRV_ERROR eError; PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; psDCPerContextInfo = (PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *)hDeviceKM; /* Remove the item from the resman list and trigger the callback. */ 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)); } psDCInfo->ui32RefCount--; if(psDCInfo->ui32RefCount == 0) { /* close the external device */ psDCInfo->psFuncTable->pfnCloseDCDevice(psDCInfo->hExtDevice); PVRSRVKernelSyncInfoDecRef(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); psDCInfo->hDevMemContext = IMG_NULL; psDCInfo->hExtDevice = IMG_NULL; } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO), psDCPerContextInfo, IMG_NULL); /*not nulling pointer, copy on stack*/ return PVRSRV_OK; } /*! ****************************************************************************** @Function PVRSRVOpenDCDeviceKM @Description Opens a connection to the Display Class device, associating the connection with a Device Memory Context for a services managed device @Input psPerProc : Per-process data @Input ui32DeviceID : unique device index @Input hDevCookie : devcookie used to derive the Device Memory Context into BC surfaces will be mapped into @Outut phDeviceKM : handle to the DC device @Return PVRSRV_ERROR : ******************************************************************************/ 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); /* find the matching devicenode */ 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; /* Allocate the per-context DC Info before calling the external device, to make error handling easier. */ 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; /* store the device kernel context to map into */ psDCInfo->hDevMemContext = (IMG_HANDLE)psDeviceNode->sDevMemoryInfo.pBMKernelContext; /* create a syncinfo for the device's system surface */ 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")); goto ErrorExit; } /* open the external device */ 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")); goto ErrorExitSyncInfo; } psDCPerContextInfo->psDCInfo = psDCInfo; eError = PVRSRVGetDCSystemBufferKM(psDCPerContextInfo, IMG_NULL); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenDCDeviceKM: Failed to get system buffer")); goto ErrorExitCloseDevice; } psDCInfo->sSystemBuffer.sDeviceClassBuffer.ui32MemMapRefCount = 0; } else { psDCPerContextInfo->psDCInfo = psDCInfo; } psDCPerContextInfo->hResItem = ResManRegisterRes(psPerProc->hResManContext, RESMAN_TYPE_DISPLAYCLASS_DEVICE, psDCPerContextInfo, 0, &CloseDCDeviceCallBack); /* return a reference to the DCPerContextInfo */ *phDeviceKM = (IMG_HANDLE)psDCPerContextInfo; return PVRSRV_OK; ErrorExitCloseDevice: psDCInfo->psFuncTable->pfnCloseDCDevice(psDCInfo->hExtDevice); ErrorExitSyncInfo: PVRSRVKernelSyncInfoDecRef(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); ErrorExit: OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO), psDCPerContextInfo, IMG_NULL); psDCInfo->ui32RefCount = 0; return eError; } /*! ****************************************************************************** @Function PVRSRVEnumDCFormatsKM @Description Enumerates the devices pixel formats @Input hDeviceKM : device handle @Output pui32Count : number of pixel formats @Output psFormat : format list @Return PVRSRV_ERROR : ******************************************************************************/ 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); /* call into the display device driver to get info */ return psDCInfo->psFuncTable->pfnEnumDCFormats(psDCInfo->hExtDevice, pui32Count, psFormat); } /*! ****************************************************************************** @Function PVRSRVEnumDCDimsKM @Description Enumerates the devices mode dimensions for a given pixel format @Input hDeviceKM : device handle @Input psFormat : pixel format @Output pui32Count : number of dimensions @Output psDim : dimensions list @Return PVRSRV_ERROR : ******************************************************************************/ 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) // psDim==NULL to query number of dims { PVR_DPF((PVR_DBG_ERROR,"PVRSRVEnumDCDimsKM: Invalid parameters")); return PVRSRV_ERROR_INVALID_PARAMS; } psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); /* call into the display device driver to get info */ return psDCInfo->psFuncTable->pfnEnumDCDims(psDCInfo->hExtDevice, psFormat, pui32Count, psDim); } /*! ****************************************************************************** @Function PVRSRVGetDCSystemBufferKM @Description Get the primary surface and optionally return its buffer handle @Input hDeviceKM : device handle @Output phBuffer : Optional buffer handle @Return PVRSRV_ERROR : ******************************************************************************/ 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); /* call into the display device driver to get info */ 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; } /* save the new info */ 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; /* return handle */ if (phBuffer) { *phBuffer = (IMG_HANDLE)&(psDCInfo->sSystemBuffer); } return PVRSRV_OK; } /****************************************************************************** @Function PVRSRVGetDCInfoKM @Description Gets Display Class device Info @Input hDeviceKM : device handle @Output psDisplayInfo @Return PVRSRV_ERROR : ******************************************************************************/ 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); /* call into the display device driver to get info */ 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; /* Update shared swapchains list */ 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; } } } /* Destroy command queue before swapchain - it may use the swapchain when commands are flushed. */ PVRSRVDestroyCommandQueueKM(psSwapChain->psQueue); /* call into the display device driver to destroy a swapchain */ 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; } /* free the resources */ for(i=0; iui32BufferCount; i++) { if(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo) { PVRSRVKernelSyncInfoDecRef(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); } } #if !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) if (psSwapChain->ppsLastSyncInfos) { for (i = 0; i < psSwapChain->ui32LastNumSyncInfos; i++) { if (psSwapChain->ppsLastSyncInfos[i]) { PVRSRVKernelSyncInfoDecRef(psSwapChain->ppsLastSyncInfos[i], IMG_NULL); psSwapChain->ppsLastSyncInfos[i] = IMG_NULL; } } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_KERNEL_SYNC_INFO *) * psSwapChain->ui32LastNumSyncInfos, psSwapChain->ppsLastSyncInfos, IMG_NULL); } #endif /* !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SWAPCHAIN), psSwapChain, IMG_NULL); /*not nulling pointer, copy on stack*/ 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(--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; /* Allocate swapchain reference structre*/ 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)); /* Bump refcount */ psSwapChain->ui32RefCount++; /* Create reference resource */ psSwapChainRef->psSwapChain = psSwapChain; psSwapChainRef->hResItem = ResManRegisterRes(psPerProc->hResManContext, RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN_REF, psSwapChainRef, 0, &DestroyDCSwapChainRefCallBack); if (psSwapChainRef->hResItem == IMG_NULL) { PVR_DPF ((PVR_DBG_ERROR, "PVRSRVCreateDCSwapChainRefKM: ResManRegisterRes failed")); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SWAPCHAIN_REF), psSwapChainRef, IMG_NULL); return PVRSRV_ERROR_INVALID_PARAMS; } *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 #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE) ,IMG_INT32 i32TimelineFd #endif ) { 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; } OSMemSet (apsSyncData, 0, sizeof(PVRSRV_SYNC_DATA *) * PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS); if (ui32BufferCount > PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Too many buffers")); return PVRSRV_ERROR_TOOMANYBUFFERS; } psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); if( ui32Flags & PVRSRV_CREATE_SWAPCHAIN_QUERY ) { /* Query - use pui32SwapChainID as input */ psSwapChain = PVRSRVFindSharedDCSwapChainKM(psDCInfo, *pui32SwapChainID ); if( psSwapChain ) { /* Create new reference */ 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; } /* Allocate swapchain control structure for srvkm */ 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)); /* Create a command queue for the swapchain */ eError = PVRSRVCreateCommandQueueKM(1024, &psQueue); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Failed to create CmdQueue")); goto ErrorExit; } #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE) psQueue->i32TimelineFd = i32TimelineFd; #endif /* store the Queue */ psSwapChain->psQueue = psQueue; /* Create a Sync Object for each surface in the swapchain */ for(i=0; ihDevMemContext, &psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDCSwapChainKM: Failed to alloc syninfo for psSwapChain")); goto ErrorExit; } /* setup common device class info */ psSwapChain->asBuffer[i].sDeviceClassBuffer.pfnGetBufferAddr = psDCInfo->psFuncTable->pfnGetBufferAddr; psSwapChain->asBuffer[i].sDeviceClassBuffer.hDevMemContext = psDCInfo->hDevMemContext; psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtDevice = psDCInfo->hExtDevice; /* save off useful ptrs */ psSwapChain->asBuffer[i].psDCInfo = psDCInfo; psSwapChain->asBuffer[i].psSwapChain = psSwapChain; /* syncinfos must be passed as array of syncdata ptrs to the 3rd party driver */ 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; /* call into the display device driver to create a swapchain */ 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; } /* Create new reference */ 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; /* Save pointer in DC structure if it's shared struct */ 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; } } /* We create swapchain - pui32SwapChainID is output */ *pui32SwapChainID = psSwapChain->ui32SwapChainID; /* return the swapchain reference handle */ *phSwapChainRef= (IMG_HANDLE)psSwapChainRef; return eError; ErrorExit: for(i=0; iasBuffer[i].sDeviceClassBuffer.psKernelSyncInfo) { PVRSRVKernelSyncInfoDecRef(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); } } if(psQueue) { PVRSRVDestroyCommandQueueKM(psQueue); } if(psSwapChain) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SWAPCHAIN), psSwapChain, IMG_NULL); /*not nulling pointer, out of scope*/ } 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; /* call into the display device driver to get info */ eError = psDCInfo->psFuncTable->pfnGetDCBuffers(psDCInfo->hExtDevice, psSwapChain->hExtSwapChain, pui32BufferCount, ahExtBuffer); PVR_ASSERT(*pui32BufferCount <= PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS); /* populate the srvkm's buffer structure with the 3rd party buffer handles and return the services buffer handles */ for(i=0; i<*pui32BufferCount; i++) { psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtBuffer = ahExtBuffer[i]; phBuffer[i] = (IMG_HANDLE)&psSwapChain->asBuffer[i]; } 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); /* Validate swap interval against limits */ 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; } /* get the queue from the buffer structure */ psQueue = psBuffer->psSwapChain->psQueue; /* specify the syncs */ apsSrcSync[0] = psBuffer->sDeviceClassBuffer.psKernelSyncInfo; if(bAddReferenceToLast && psBuffer->psSwapChain->psLastFlipBuffer && psBuffer != psBuffer->psSwapChain->psLastFlipBuffer) { apsSrcSync[1] = psBuffer->psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.psKernelSyncInfo; ui32NumSrcSyncs++; } /* insert the command (header) */ eError = PVRSRVInsertCommandKM (psQueue, &psCommand, psDCInfo->ui32DeviceID, ui16SwapCommandID, 0, IMG_NULL, ui32NumSrcSyncs, apsSrcSync, sizeof(DISPLAYCLASS_FLIP_COMMAND) + (sizeof(IMG_RECT) * ui32ClipRectCount), IMG_NULL, IMG_NULL, IMG_NULL); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBufferKM: Failed to get space in queue")); goto Exit; } /* setup the flip command */ psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)psCommand->pvData; /* Ext Device Handle */ psFlipCmd->hExtDevice = psDCInfo->hExtDevice; /* Ext SwapChain Handle */ psFlipCmd->hExtSwapChain = psBuffer->psSwapChain->hExtSwapChain; /* Ext Buffer Handle (Buffer to Flip to) */ psFlipCmd->hExtBuffer = psBuffer->sDeviceClassBuffer.hExtBuffer; /* private tag */ psFlipCmd->hPrivateTag = hPrivateTag; /* setup the clip rects */ psFlipCmd->ui32ClipRectCount = ui32ClipRectCount; /* cliprect memory appends the command structure */ psFlipCmd->psClipRect = (IMG_RECT*)((IMG_UINT8*)psFlipCmd + sizeof(DISPLAYCLASS_FLIP_COMMAND)); // PRQA S 3305 /* copy the clip rects */ for(i=0; ipsClipRect[i] = psClipRect[i]; } /* number of vsyncs between successive flips */ psFlipCmd->ui32SwapInterval = ui32SwapInterval; SysAcquireData(&psSysData); /* Because we might be composing just software surfaces, without * any SGX renders since the last frame, we won't necessarily * have cleaned/flushed the CPU caches before the buffers need * to be displayed. * * Doing so now is safe because InsertCommand bumped ROP2 on the * affected buffers (preventing more SW renders starting) but the * display won't start to process the buffers until SubmitCommand. */ { 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; } /* submit the command */ eError = PVRSRVSubmitCommandKM (psQueue, psCommand); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBufferKM: Failed to submit command")); goto Exit; } /* Schedule an MISR to process it */ eError = OSScheduleMISR(psSysData); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBufferKM: Failed to schedule MISR")); goto Exit; } /* update the last flip buffer */ 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; if(psCallbackData->ui32PrivDataLength) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP | PVRSRV_SWAP_BUFFER_ALLOCATION, psCallbackData->ui32PrivDataLength, psCallbackData->pvPrivData, IMG_NULL); } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP | PVRSRV_SWAP_BUFFER_ALLOCATION, sizeof(IMG_VOID *) * psCallbackData->ui32NumMemInfos, psCallbackData->ppvMemInfos, IMG_NULL); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP | PVRSRV_SWAP_BUFFER_ALLOCATION, 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, IMG_HANDLE *phFence) { IMG_UINT32 ui32NumSyncInfos = ui32NumMemSyncInfos; IMG_UINT32 ui32NumMemInfos = ui32NumMemSyncInfos; PVRSRV_KERNEL_SYNC_INFO **ppsCompiledSyncInfos; IMG_UINT32 i, ui32NumCompiledSyncInfos; DISPLAYCLASS_FLIP_COMMAND2 *psFlipCmd; PVRSRV_DISPLAYCLASS_INFO *psDCInfo; PVRSRV_DC_SWAPCHAIN *psSwapChain; CALLBACK_DATA *psCallbackData; PVRSRV_QUEUE_INFO *psQueue; PVRSRV_COMMAND *psCommand; IMG_PVOID *ppvMemInfos; PVRSRV_ERROR eError; SYS_DATA *psSysData; #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) struct sync_fence *apsFence[SGX_MAX_SRC_SYNCS_TA] = {}; #elif defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE) struct fence *apsFence[SGX_MAX_SRC_SYNCS_TA] = {}; #endif /* defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) */ 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); /* Validate swap interval against limits */ 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 | PVRSRV_SWAP_BUFFER_ALLOCATION, 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 | PVRSRV_SWAP_BUFFER_ALLOCATION, sizeof(void *) * ui32NumMemInfos, (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 < ui32NumMemInfos; i++) { ppvMemInfos[i] = ppsMemInfos[i]; } psCallbackData->ppvMemInfos = ppvMemInfos; psCallbackData->ui32NumMemInfos = ui32NumMemInfos; #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE) eError = PVRSyncFencesToSyncInfos(ppsSyncInfos, &ui32NumSyncInfos, apsFence); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: PVRSyncFencesToSyncInfos failed")); goto Exit; } #endif /* defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) */ /* get the queue from the buffer structure */ psQueue = psSwapChain->psQueue; #if !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) if(psSwapChain->ppsLastSyncInfos) { IMG_UINT32 ui32NumUniqueSyncInfos = psSwapChain->ui32LastNumSyncInfos; IMG_BOOL *abUnique; IMG_UINT32 j; if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(IMG_BOOL) * psSwapChain->ui32LastNumSyncInfos, (IMG_VOID **)&abUnique, IMG_NULL, "Unique booleans") != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to allocate space for unique booleans")); goto Exit; } for(j = 0; j < psSwapChain->ui32LastNumSyncInfos; j++) { abUnique[j] = IMG_TRUE; for(i = 0; i < ui32NumSyncInfos; i++) { PVR_ASSERT(psSwapChain->ppsLastSyncInfos[j]); PVR_ASSERT(ppsSyncInfos[i]); if(psSwapChain->ppsLastSyncInfos[j] == ppsSyncInfos[i]) { abUnique[j] = IMG_FALSE; ui32NumUniqueSyncInfos--; break; } } } ui32NumCompiledSyncInfos = ui32NumSyncInfos + 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")); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(IMG_BOOL) * psSwapChain->ui32LastNumSyncInfos, (IMG_VOID *)abUnique, IMG_NULL); #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) for(i = 0; i < SGX_MAX_SRC_SYNCS_TA && apsFence[i]; i++) sync_fence_put(apsFence[i]); #elif defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE) for(i = 0; i < SGX_MAX_SRC_SYNCS_TA && apsFence[i]; i++) fence_put(apsFence[i]); #endif goto Exit; } OSMemCopy(ppsCompiledSyncInfos, ppsSyncInfos, sizeof(PVRSRV_KERNEL_SYNC_INFO *) * ui32NumSyncInfos); for(j = 0, i = ui32NumSyncInfos; j < psSwapChain->ui32LastNumSyncInfos; j++) { if(abUnique[j]) { ppsCompiledSyncInfos[i] = psSwapChain->ppsLastSyncInfos[j]; i++; } } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(IMG_BOOL) * psSwapChain->ui32LastNumSyncInfos, (IMG_VOID *)abUnique, IMG_NULL); } else #endif /* !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) */ { IMG_UINT32 j, ui32Missing = 0; /* Older synchronization schemes would just pass down the syncinfos * hanging off of the meminfos. So we would expect identical lists. * However, newer drivers may send down additional synchronization * i.e. for TQ fence operations. In such a case we need to allocate * more space for the compiled syncinfos to ensure everything is * ROP2 synchronized. */ for(i = 0; i < ui32NumMemInfos; i++) { for(j = 0; j < ui32NumSyncInfos; j++) { if(ppsSyncInfos[j] == ppsMemInfos[i]->psKernelSyncInfo) break; } if(j == ui32NumSyncInfos) ui32Missing++; } if(ui32Missing) { IMG_UINT32 k; ui32NumCompiledSyncInfos = ui32NumSyncInfos + ui32Missing; 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")); #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) for(i = 0; i < SGX_MAX_SRC_SYNCS_TA && apsFence[i]; i++) sync_fence_put(apsFence[i]); #elif defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE) for(i = 0; i < SGX_MAX_SRC_SYNCS_TA && apsFence[i]; i++) fence_put(apsFence[i]); #endif goto Exit; } for(i = 0; i < ui32NumSyncInfos; i++) { ppsCompiledSyncInfos[i] = ppsSyncInfos[i]; } k = i; for(i = 0; i < ui32NumMemInfos; i++) { for(j = 0; j < ui32NumSyncInfos; j++) { if(ppsSyncInfos[j] == ppsMemInfos[i]->psKernelSyncInfo) break; } if(j == ui32NumSyncInfos) { /* Insert the unique one */ PVR_ASSERT(k < ui32NumCompiledSyncInfos); ppsCompiledSyncInfos[k] = ppsMemInfos[i]->psKernelSyncInfo; k++; } } PVR_ASSERT(k == ui32NumCompiledSyncInfos); /* As a further complication, if we have multiple displays, we * might see the same layer/meminfo submitted twice. This is * valid, as the layer might be needed by two separate pipes, * but we should not use the meminfo's synchronization twice * because this will deadlock the queue processor. * * For now, work over the meminfo end of the compiled syncs * list and collapse any duplicates. We can assume the fence * sync part of the array has already been de-duplicated. */ k = ui32NumSyncInfos; for(i = ui32NumSyncInfos; i < ui32NumCompiledSyncInfos; i++) { /* Compare the i'th entry with all that follow */ for(j = i + 1; j < ui32NumCompiledSyncInfos; j++) { if(ppsCompiledSyncInfos[i] == ppsCompiledSyncInfos[j]) break; } if(j == ui32NumCompiledSyncInfos) { /* No duplicate found. Use this entry */ ppsCompiledSyncInfos[k] = ppsCompiledSyncInfos[i]; k++; } } ui32NumCompiledSyncInfos = k; } else { ppsCompiledSyncInfos = ppsSyncInfos; ui32NumCompiledSyncInfos = ui32NumSyncInfos; } } /* insert the command (header) */ eError = PVRSRVInsertCommandKM (psQueue, &psCommand, psDCInfo->ui32DeviceID, DC_FLIP_COMMAND, 0, IMG_NULL, ui32NumCompiledSyncInfos, ppsCompiledSyncInfos, sizeof(DISPLAYCLASS_FLIP_COMMAND2), FreePrivateData, psCallbackData, phFence); #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) /* InsertCommand bumped the refcount on the raw sync objects, so we * can put the fences now. Even if the fences are deleted, the syncs * will persist. */ for(i = 0; i < SGX_MAX_SRC_SYNCS_TA && apsFence[i]; i++) sync_fence_put(apsFence[i]); #elif defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE) for(i = 0; i < SGX_MAX_SRC_SYNCS_TA && apsFence[i]; i++) fence_put(apsFence[i]); #endif 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; } /* setup the flip command */ psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND2*)psCommand->pvData; /* Ext Device Handle */ psFlipCmd->hExtDevice = psDCInfo->hExtDevice; /* Ext SwapChain Handle */ psFlipCmd->hExtSwapChain = psSwapChain->hExtSwapChain; /* number of vsyncs between successive flips */ psFlipCmd->ui32SwapInterval = ui32SwapInterval; /* Opaque private data, if supplied */ psFlipCmd->pvPrivData = pvPrivData; psFlipCmd->ui32PrivDataLength = ui32PrivDataLength; psFlipCmd->ppsMemInfos = (PDC_MEM_INFO *)ppvMemInfos; psFlipCmd->ui32NumMemInfos = ui32NumMemInfos; /* Even though this is "unused", we have to initialize it, * as the display controller might NULL-test it. */ psFlipCmd->hUnused = IMG_NULL; SysAcquireData(&psSysData); /* Because we might be composing just software surfaces, without * any SGX renders since the last frame, we won't necessarily * have cleaned/flushed the CPU caches before the buffers need * to be displayed. * * Doing so now is safe because InsertCommand bumped ROP2 on the * affected buffers (preventing more SW renders starting) but the * display won't start to process the buffers until SubmitCommand. */ { 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; } /* submit the command */ PVRSRVSubmitCommandKM (psQueue, psCommand); /* The command has been submitted and so psCallbackData will be freed by the callback */ psCallbackData = IMG_NULL; /* Schedule an MISR to process it */ OSScheduleMISR(psSysData); #if !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) /* Reallocate the syncinfo list if it was too small */ if (psSwapChain->ui32LastNumSyncInfos < ui32NumSyncInfos) { if (psSwapChain->ppsLastSyncInfos) { for (i = 0; i < psSwapChain->ui32LastNumSyncInfos; i++) { if (psSwapChain->ppsLastSyncInfos[i]) { PVRSRVKernelSyncInfoDecRef(psSwapChain->ppsLastSyncInfos[i], IMG_NULL); psSwapChain->ppsLastSyncInfos[i] = IMG_NULL; } } 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 *) * ui32NumSyncInfos, (IMG_VOID **)&psSwapChain->ppsLastSyncInfos, IMG_NULL, "Last syncinfos") != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to allocate space for meminfo list")); #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) sync_fence_put(*phFence); *phFence = IMG_NULL; #elif defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE) fence_put(*phFence); *phFence = IMG_NULL; #endif goto Exit; } } for (i = 0; i < psSwapChain->ui32LastNumSyncInfos; i++) { if (psSwapChain->ppsLastSyncInfos[i]) { PVRSRVKernelSyncInfoDecRef(psSwapChain->ppsLastSyncInfos[i], IMG_NULL); psSwapChain->ppsLastSyncInfos[i] = IMG_NULL; } } psSwapChain->ui32LastNumSyncInfos = ui32NumSyncInfos; for(i = 0; i < ui32NumSyncInfos; i++) { psSwapChain->ppsLastSyncInfos[i] = ppsSyncInfos[i]; PVRSRVKernelSyncInfoIncRef(psSwapChain->ppsLastSyncInfos[i], IMG_NULL); } #endif /* !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) */ Exit: if (psCallbackData) { if(psCallbackData->ppvMemInfos) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP | PVRSRV_SWAP_BUFFER_ALLOCATION, sizeof(IMG_VOID *) * psCallbackData->ui32NumMemInfos, psCallbackData->ppvMemInfos, IMG_NULL); } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP | PVRSRV_SWAP_BUFFER_ALLOCATION, 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; /* If more than 1 reference to the swapchain exists then ignore any request to swap to the system buffer */ if (psSwapChain->ui32RefCount > 1) { return PVRSRV_OK; } /* get the queue from the buffer structure */ psQueue = psSwapChain->psQueue; /* specify the syncs */ apsSrcSync[0] = psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo; if(bAddReferenceToLast && psSwapChain->psLastFlipBuffer) { /* Make sure we don't make a double dependency on the same server */ if (apsSrcSync[0] != psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.psKernelSyncInfo) { apsSrcSync[1] = psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.psKernelSyncInfo; ui32NumSrcSyncs++; } } /* insert the command (header) */ eError = PVRSRVInsertCommandKM (psQueue, &psCommand, psDCInfo->ui32DeviceID, ui16SwapCommandID, 0, IMG_NULL, ui32NumSrcSyncs, apsSrcSync, sizeof(DISPLAYCLASS_FLIP_COMMAND), IMG_NULL, IMG_NULL, IMG_NULL); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCSystemKM: Failed to get space in queue")); goto Exit; } /* setup the flip command */ psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)psCommand->pvData; /* Ext Device Handle */ psFlipCmd->hExtDevice = psDCInfo->hExtDevice; /* Ext SwapChain Handle */ psFlipCmd->hExtSwapChain = psSwapChain->hExtSwapChain; /* Ext Buffer Handle (Buffer to Flip to) */ psFlipCmd->hExtBuffer = psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtBuffer; /* private tag */ psFlipCmd->hPrivateTag = IMG_NULL; /* setup the clip rects */ psFlipCmd->ui32ClipRectCount = 0; psFlipCmd->ui32SwapInterval = 1; /* submit the command */ eError = PVRSRVSubmitCommandKM (psQueue, psCommand); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCSystemKM: Failed to submit command")); goto Exit; } /* Schedule an MISR to process it */ SysAcquireData(&psSysData); eError = OSScheduleMISR(psSysData); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCSystemKM: Failed to schedule MISR")); goto Exit; } /* update the last flip buffer */ psSwapChain->psLastFlipBuffer = &psDCInfo->sSystemBuffer; eError = PVRSRV_OK; Exit: if(eError == PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE) { eError = PVRSRV_ERROR_RETRY; } return eError; } /*! ****************************************************************************** @Function PVRSRVRegisterSystemISRHandler @Description registers an external ISR to be called of the back of a system ISR @Input ppfnISRHandler : ISR pointer @Input hISRHandlerData : Callback data @Input ui32ISRSourceMask : ISR Mask @Input ui32DeviceID : unique device key @Return PVRSRV_ERROR : ******************************************************************************/ 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); /* Find Dev Node (just using the device id, ignore the class) */ 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; } /* set up data before enabling the ISR */ psDevNode->pvISRData = (IMG_VOID*) pvISRHandlerData; /* enable the ISR */ psDevNode->pfnDeviceISR = pfnISRHandler; return PVRSRV_OK; } /*! ****************************************************************************** @Function PVRSRVSetDCState_ForEachVaCb @Description If the device node is a display, calls its set state function. @Input psDeviceNode - the device node va - variable argument list with: ui32State - the state to be set. ******************************************************************************/ 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); } } } /*! ****************************************************************************** @Function PVRSRVSetDCState @Description Calls the display driver(s) to put them into the specified state. @Input ui32State: new DC state - one of DC_STATE_* ******************************************************************************/ IMG_VOID IMG_CALLCONV PVRSRVSetDCState(IMG_UINT32 ui32State) { /* PVRSRV_DISPLAYCLASS_INFO *psDCInfo; PVRSRV_DEVICE_NODE *psDeviceNode; */ 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); } /*! ****************************************************************************** @Function PVRGetDisplayClassJTable @Description Sets up function table for 3rd party Display Class Device to call through @Input psJTable : pointer to function pointer table memory @Return PVRSRV_ERROR : ******************************************************************************/ 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; psJTable->pfnPVRSRVCmdComplete = &PVRSRVCommandCompleteKM; psJTable->pfnPVRSRVRegisterSystemISRHandler = &PVRSRVRegisterSystemISRHandler; psJTable->pfnPVRSRVRegisterPowerDevice = &PVRSRVRegisterPowerDevice; psJTable->pfnPVRSRVDCMemInfoGetCpuVAddr = &PVRSRVDCMemInfoGetCpuVAddr; psJTable->pfnPVRSRVDCMemInfoGetCpuPAddr = &PVRSRVDCMemInfoGetCpuPAddr; psJTable->pfnPVRSRVDCMemInfoGetByteSize = &PVRSRVDCMemInfoGetByteSize; psJTable->pfnPVRSRVDCMemInfoIsPhysContig = &PVRSRVDCMemInfoIsPhysContig; return IMG_TRUE; } /****************************************************************************** @Function PVRSRVCloseBCDeviceKM @Description Closes a connection to the Buffer Class device @Input hDeviceKM : device handle @Return PVRSRV_ERROR : ******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVCloseBCDeviceKM (IMG_HANDLE hDeviceKM) { PVRSRV_ERROR eError; PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; psBCPerContextInfo = (PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *)hDeviceKM; /* Remove the item from the resman list and trigger the callback. */ 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) { /* close the external device */ psBCInfo->psFuncTable->pfnCloseBCDevice(psBCInfo->ui32DeviceID, psBCInfo->hExtDevice); /* free syncinfos */ for(i=0; iui32BufferCount; i++) { if(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo) { PVRSRVKernelSyncInfoDecRef(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); } } /* free buffers */ 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); /*not nulling pointer, copy on stack*/ return PVRSRV_OK; } /*! ****************************************************************************** @Function PVRSRVOpenBCDeviceKM @Description Opens a connection to the Buffer Class device, associating the connection with a Device Memory Context for a services managed device @Input psPerProc : Per-process data @Input ui32DeviceID : unique device index @Input hDevCookie : devcookie used to derive the Device Memory Context into BC surfaces will be mapped into @Outut phDeviceKM : handle to the DC device @Return PVRSRV_ERROR : ******************************************************************************/ 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); /* find the matching devicenode */ 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; /* FoundDevice: */ /* Allocate the per-context BC Info before calling the external device, to make error handling easier. */ 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; /* store the device kernel context to map into */ psBCInfo->hDevMemContext = (IMG_HANDLE)psDeviceNode->sDevMemoryInfo.pBMKernelContext; /* open the external device */ eError = psBCInfo->psFuncTable->pfnOpenBCDevice(ui32DeviceID, &psBCInfo->hExtDevice); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenBCDeviceKM: Failed to open external BC device")); goto ErrorExit; } /* get information about the buffers */ eError = psBCInfo->psFuncTable->pfnGetBCInfo(psBCInfo->hExtDevice, &sBufferInfo); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenBCDeviceKM : Failed to get BC Info")); goto ErrorExitCloseDevice; } /* interpret and store info */ psBCInfo->ui32BufferCount = sBufferInfo.ui32BufferCount; /* allocate BC buffers */ 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")); goto ErrorExitCloseDevice; } OSMemSet (psBCInfo->psBuffer, 0, sizeof(PVRSRV_BC_BUFFER) * sBufferInfo.ui32BufferCount); for(i=0; iui32BufferCount; i++) { /* create a syncinfo for the device's system surface */ 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 ErrorExitBuffers; } /* get the buffers from the buffer class drivers by index, passing-in the syncdata objects */ 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 ErrorExitBuffers; } /* setup common device class info */ 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); /* return a reference to the BCPerContextInfo */ *phDeviceKM = (IMG_HANDLE)psBCPerContextInfo; return PVRSRV_OK; ErrorExitBuffers: /* free syncinfos */ for(i=0; iui32BufferCount; i++) { if(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo) { PVRSRVKernelSyncInfoDecRef(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); } } /* free buffers */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BC_BUFFER), psBCInfo->psBuffer, IMG_NULL); psBCInfo->psBuffer = IMG_NULL; ErrorExitCloseDevice: psBCInfo->psFuncTable->pfnCloseBCDevice(psBCInfo->ui32DeviceID, psBCInfo->hExtDevice); ErrorExit: OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BUFFERCLASS_PERCONTEXT_INFO), psBCPerContextInfo, IMG_NULL); psBCInfo->ui32RefCount = 0; return eError; } /****************************************************************************** @Function PVRSRVGetBCInfoKM @Description Gets Buffer Class device Info @Input hDeviceKM : device handle @Output psBufferInfo @Return PVRSRV_ERROR : ******************************************************************************/ 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; } /****************************************************************************** @Function PVRSRVGetBCBufferKM @Description Gets Buffer Class Buffer Handle @Input hDeviceKM : device handle @Output psBufferInfo @Return PVRSRV_ERROR : ******************************************************************************/ 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; } /*! ****************************************************************************** @Function PVRGetBufferClassJTable @Description Sets up function table for 3rd party Buffer Class Device to call through @Input psJTable : pointer to function pointer table memory @Return PVRSRV_ERROR : ******************************************************************************/ 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; } /****************************************************************************** End of file (deviceclass.c) ******************************************************************************/