/* * Copyright (c) 2014-2018, Intel Corporation * * 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. * * 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. 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. */ //! \file mhw_vebox.cpp //! \brief MHW interface for constructing commands for the VEBOX //! \details Impelements the functionalities common across all platforms for MHW_VEBOX //! #include "mhw_utilities.h" #include "mhw_vebox.h" #include "hal_oca_interface.h" void MhwVeboxInterface::RefreshVeboxSync() { PMHW_VEBOX_HEAP pVeboxHeap; PMHW_VEBOX_HEAP_STATE pCurInstance; PMOS_INTERFACE pOsInterface; uint32_t dwCurrentTag; int32_t i; int32_t iInstanceInUse; MOS_NULL_RENDERING_FLAGS NullRenderingFlags; MHW_FUNCTION_ENTER; if (m_veboxHeap == nullptr || m_osInterface == nullptr ) { MHW_ASSERTMESSAGE("RefreshVeboxSync failed due to m_veboxHeap or m_osInterface is invalid "); return; } iInstanceInUse = 0; // Vebox Heap will always be locked by driver pVeboxHeap = m_veboxHeap; pOsInterface = m_osInterface; // Most recent tag if (pOsInterface->bEnableKmdMediaFrameTracking) { dwCurrentTag = pOsInterface->pfnGetGpuStatusSyncTag(pOsInterface, MOS_GPU_CONTEXT_VEBOX); } else { dwCurrentTag = pVeboxHeap->pSync[0]; } pVeboxHeap->dwSyncTag = dwCurrentTag - 1; NullRenderingFlags = m_osInterface->pfnGetNullHWRenderFlags( m_osInterface); // Refresh VeboxHeap states pCurInstance = pVeboxHeap->pStates; for (i = m_veboxSettings.uiNumInstances; i > 0; i--, pCurInstance++) { if (!pCurInstance->bBusy) continue; // The condition below is valid when sync tag wraps from 2^32-1 to 0 if (((int32_t)(dwCurrentTag - pCurInstance->dwSyncTag) >= 0) || NullRenderingFlags.VPGobal || NullRenderingFlags.VPDnDi) { pCurInstance->bBusy = false; } else { iInstanceInUse++; } } // Save number of instance in use m_veboxHeapInUse = iInstanceInUse; } MOS_STATUS MhwVeboxInterface::AssignVeboxState() { uint32_t dwWaitMs, dwWaitTag; MOS_STATUS eStatus = MOS_STATUS_SUCCESS; PMOS_INTERFACE pOsInterface; PMHW_VEBOX_HEAP_STATE pVeboxCurState; PMHW_VEBOX_HEAP pVeboxHeap; uint32_t uiOffset; MHW_FUNCTION_ENTER; MHW_CHK_NULL(m_veboxHeap); MHW_CHK_NULL(m_osInterface); pVeboxHeap = m_veboxHeap; pVeboxCurState = &m_veboxHeap->pStates[pVeboxHeap->uiNextState]; pOsInterface = m_osInterface; // Refresh sync tag for all vebox heap instance RefreshVeboxSync(); // Check validity of current vebox heap instance // The code below is unlikely to be executed - unless all Vebox states are in use // If this ever happens, please consider increasing the number of media states MHW_CHK_NULL(pVeboxCurState); if (pVeboxCurState->bBusy) { // Get current vebox instance sync tag dwWaitTag = pVeboxCurState->dwSyncTag; // Wait for Batch Buffer complete event OR timeout for (dwWaitMs = MHW_TIMEOUT_MS_DEFAULT; dwWaitMs > 0; dwWaitMs--) { uint32_t dwCurrentTag; MHW_CHK_STATUS(pOsInterface->pfnWaitForBBCompleteNotifyEvent( pOsInterface, MOS_GPU_CONTEXT_VEBOX, MHW_EVENT_TIMEOUT_MS)); if (pOsInterface->bEnableKmdMediaFrameTracking) { dwCurrentTag = pOsInterface->pfnGetGpuStatusSyncTag(pOsInterface, MOS_GPU_CONTEXT_VEBOX); } else { dwCurrentTag = pVeboxHeap->pSync[0]; } // Mark current instance status as availabe. Wait if this sync tag came back from GPU if ((int32_t)(dwCurrentTag - dwWaitTag) >= 0) { pVeboxCurState->bBusy = false; break; } } // Timeout if (dwWaitMs == 0) { MHW_ASSERTMESSAGE("Timeout on waiting for free Vebox Heap."); eStatus = MOS_STATUS_UNKNOWN; goto finish; } } // Prepare syncTag for GPU write back if (pOsInterface->bEnableKmdMediaFrameTracking) { pVeboxCurState->dwSyncTag = pOsInterface->pfnGetGpuStatusTag(pOsInterface, MOS_GPU_CONTEXT_VEBOX); } else { pVeboxCurState->dwSyncTag = pVeboxHeap->dwNextTag; } // Assign current state and increase next state pVeboxHeap->uiCurState = pVeboxHeap->uiNextState; pVeboxHeap->uiNextState = (pVeboxHeap->uiNextState + 1) % (m_veboxSettings.uiNumInstances); //Clean the memory of current veboxheap to avoid the history states uiOffset = pVeboxHeap->uiCurState * pVeboxHeap->uiInstanceSize; MOS_ZeroMemory(pVeboxHeap->pLockedDriverResourceMem + uiOffset, pVeboxHeap->uiInstanceSize); finish: return eStatus; } MOS_STATUS MhwVeboxInterface::UpdateVeboxSync() { PMHW_VEBOX_HEAP pVeboxHeap; MOS_STATUS eStatus = MOS_STATUS_SUCCESS; PMOS_INTERFACE pOsInterface; MHW_FUNCTION_ENTER; MHW_CHK_NULL(m_veboxHeap); MHW_CHK_NULL(m_osInterface); pVeboxHeap = m_veboxHeap; pOsInterface = m_osInterface; // If KMD frame tracking is on, the dwSyncTag has been set to gpu status tag // in Mhw_VeboxInterface_AssignVeboxState(). dwNextTag is not used anymore. if (!pOsInterface->bEnableKmdMediaFrameTracking) { pVeboxHeap->pStates[pVeboxHeap->uiCurState].dwSyncTag = pVeboxHeap->dwNextTag++; } pVeboxHeap->pStates[pVeboxHeap->uiCurState].bBusy = true; finish: return eStatus; } MOS_STATUS MhwVeboxInterface::GetVeboxHeapInfo( const MHW_VEBOX_HEAP **ppVeboxHeap) { MOS_STATUS eStatus = MOS_STATUS_SUCCESS; MHW_FUNCTION_ENTER; MHW_CHK_NULL(ppVeboxHeap); *ppVeboxHeap = (const MHW_VEBOX_HEAP *)m_veboxHeap; finish: return eStatus; } MOS_STATUS MhwVeboxInterface::CreateHeap( ) { MOS_STATUS eStatus; uint8_t *pMem; uint32_t uiSize; uint32_t uiOffset; MOS_ALLOC_GFXRES_PARAMS AllocParams; MOS_LOCK_PARAMS LockFlags; MEDIA_FEATURE_TABLE *skuTable = nullptr; MHW_FUNCTION_ENTER; MHW_CHK_NULL(m_osInterface); MHW_CHK_NULL(m_osInterface->pfnGetSkuTable); skuTable = m_osInterface->pfnGetSkuTable(m_osInterface); MHW_CHK_NULL(skuTable); eStatus = MOS_STATUS_SUCCESS; uiSize = sizeof(MHW_VEBOX_HEAP); uiSize += m_veboxSettings.uiNumInstances * sizeof(MHW_VEBOX_HEAP_STATE); // Allocate memory for VEBOX pMem = (uint8_t*)MOS_AllocAndZeroMemory(uiSize); MHW_CHK_NULL(pMem); m_veboxHeap = (PMHW_VEBOX_HEAP)pMem; m_veboxHeap->pStates = (PMHW_VEBOX_HEAP_STATE)(pMem + sizeof(MHW_VEBOX_HEAP)); // Assign offsets and sizes uiOffset = 0; m_veboxHeap->uiDndiStateOffset = uiOffset; uiOffset += m_veboxSettings.uiDndiStateSize; m_veboxHeap->uiIecpStateOffset = uiOffset; uiOffset += m_veboxSettings.uiIecpStateSize; m_veboxHeap->uiGamutStateOffset = uiOffset; uiOffset += m_veboxSettings.uiGamutStateSize; m_veboxHeap->uiVertexTableOffset = uiOffset; uiOffset += m_veboxSettings.uiVertexTableSize; m_veboxHeap->uiCapturePipeStateOffset = uiOffset; uiOffset += m_veboxSettings.uiCapturePipeStateSize; m_veboxHeap->uiGammaCorrectionStateOffset = uiOffset; uiOffset += m_veboxSettings.uiGammaCorrectionStateSize; m_veboxHeap->uiHdrStateOffset = uiOffset; uiOffset += m_veboxSettings.uiHdrStateSize; m_veboxHeap->uiInstanceSize = uiOffset; // Appending VeboxHeap sync data after all vebox heap instances m_veboxHeap->uiOffsetSync = m_veboxHeap->uiInstanceSize * m_veboxSettings.uiNumInstances; // Allocate GPU memory uiSize = m_veboxHeap->uiInstanceSize * m_veboxSettings.uiNumInstances + m_veboxSettings.uiSyncSize; // for using vdbox copy, the size have to be cache line aligned MOS_ALIGN_CEIL(uiSize, MHW_CACHELINE_SIZE); m_veboxHeap->uiStateHeapSize = uiSize; MOS_ZeroMemory(&AllocParams, sizeof(MOS_ALLOC_GFXRES_PARAMS)); AllocParams.Type = MOS_GFXRES_BUFFER; AllocParams.TileType = MOS_TILE_LINEAR; AllocParams.Format = Format_Buffer; AllocParams.dwBytes = uiSize; AllocParams.pBufName = "VphalVeboxHeap"; AllocParams.ResUsageType = MOS_HW_RESOURCE_USAGE_VP_INTERNAL_READ_WRITE_FF; if (MEDIA_IS_SKU(skuTable, FtrLimitedLMemBar)) { AllocParams.dwMemType = MOS_MEMPOOL_SYSTEMMEMORY; } MHW_CHK_STATUS(m_osInterface->pfnAllocateResource( m_osInterface, &AllocParams, &m_veboxHeap->DriverResource)); if (MEDIA_IS_SKU(skuTable, FtrLimitedLMemBar)) { // Use device memory for vebox heap kernel resource, as no cpu access on it. AllocParams.dwMemType = MOS_MEMPOOL_DEVICEMEMORY; } AllocParams.Flags.bNotLockable = 1; MHW_CHK_STATUS(m_osInterface->pfnAllocateResource( m_osInterface, &AllocParams, &m_veboxHeap->KernelResource)); // Lock the driver resource MOS_ZeroMemory(&LockFlags, sizeof(MOS_LOCK_PARAMS)); LockFlags.NoOverWrite = 1; m_veboxHeap->pLockedDriverResourceMem = (uint8_t*)m_osInterface->pfnLockResource( m_osInterface, &m_veboxHeap->DriverResource, &LockFlags); MHW_CHK_NULL(m_veboxHeap->pLockedDriverResourceMem); // Initialize VeboxHeap controls that depend on mapping m_veboxHeap->pSync = (uint32_t*) (m_veboxHeap->pLockedDriverResourceMem + m_veboxHeap->uiOffsetSync); finish: if (eStatus != MOS_STATUS_SUCCESS) { DestroyHeap(); } return eStatus; } MOS_STATUS MhwVeboxInterface::DestroyHeap() { PMOS_INTERFACE pOsInterface; MOS_STATUS eStatus = MOS_STATUS_SUCCESS; MHW_FUNCTION_ENTER; MHW_CHK_NULL(m_osInterface); pOsInterface = m_osInterface; if (m_veboxHeap) { if (!Mos_ResourceIsNull(&m_veboxHeap->DriverResource)) { if (m_veboxHeap->pLockedDriverResourceMem) { pOsInterface->pfnUnlockResource( pOsInterface, &m_veboxHeap->DriverResource); } pOsInterface->pfnFreeResource( pOsInterface, &m_veboxHeap->DriverResource); } if (!Mos_ResourceIsNull(&m_veboxHeap->KernelResource)) { pOsInterface->pfnFreeResource( pOsInterface, &m_veboxHeap->KernelResource); } MOS_FreeMemory(m_veboxHeap); m_veboxHeap = nullptr; } finish: return eStatus; } MhwVeboxInterface::MhwVeboxInterface(PMOS_INTERFACE pOsInterface) { MHW_FUNCTION_ENTER; MOS_ZeroMemory(&m_veboxSettings, sizeof(m_veboxSettings)); pfnAddResourceToCmd = nullptr; if (pOsInterface == nullptr) { MHW_ASSERTMESSAGE("Invalid input pointers provided"); return; } m_osInterface = pOsInterface; if (m_osInterface->bUsesGfxAddress) { pfnAddResourceToCmd = Mhw_AddResourceToCmd_GfxAddress; } else //PatchList { pfnAddResourceToCmd = Mhw_AddResourceToCmd_PatchList; } } void MhwVeboxInterface::TraceIndirectStateInfo(MOS_COMMAND_BUFFER &cmdBuffer, MOS_CONTEXT &mosContext, bool isCmBuffer, bool useVeboxHeapKernelResource) { if (isCmBuffer) { char ocaLog[] = "Vebox indirect state use CmBuffer"; HalOcaInterface::TraceMessage(cmdBuffer, (MOS_CONTEXT_HANDLE)&mosContext, ocaLog, sizeof(ocaLog)); } else { if (useVeboxHeapKernelResource) { char ocaLog[] = "Vebox indirect state use KernelResource"; HalOcaInterface::TraceMessage(cmdBuffer, (MOS_CONTEXT_HANDLE)&mosContext, ocaLog, sizeof(ocaLog)); } else { char ocaLog[] = "Vebox indirect state use DriverResource"; HalOcaInterface::TraceMessage(cmdBuffer, (MOS_CONTEXT_HANDLE)&mosContext, ocaLog, sizeof(ocaLog)); } } }