/* * Copyright (c) 2018-2019, 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 cm_ish_base.cpp //! \brief Contains Class CmISHBase definitions //! #include "cm_ish.h" #include "cm_kernel_ex.h" using namespace CMRT_UMD; CmISHBase::CmISHBase(): m_isSipKernelLoaded(false), m_sipKernel(nullptr), m_sipKernelSize(0), m_sipKernelOffset(0), m_osInterface(nullptr), m_resource(nullptr), m_lockedData(nullptr), m_size(0), m_offset(0), m_trackerProducer(nullptr), m_lastTrackerToken(nullptr), m_addedKernelCount(0) { } CmISHBase::~CmISHBase() { MOS_GFXRES_FREE_FLAGS resFreeFlags = {0}; resFreeFlags.AssumeNotInUse = 1; while (m_destroyedTrackers.size()) { MOS_RESOURCE *res = m_destroyedResources.back(); m_osInterface->pfnFreeResourceWithFlag(m_osInterface, res, resFreeFlags.Value); FrameTrackerToken *trackerToken = m_destroyedTrackers.back(); MOS_FreeMemory(res); MOS_Delete(trackerToken); m_destroyedResources.pop_back(); m_destroyedTrackers.pop_back(); } // delete current resource if (m_resource) { m_osInterface->pfnUnlockResource(m_osInterface, m_resource); m_osInterface->pfnFreeResourceWithFlag(m_osInterface, m_resource, resFreeFlags.Value); MOS_FreeMemory(m_resource); } if (m_lastTrackerToken) { MOS_Delete(m_lastTrackerToken); } if (m_sipKernel) { MOS_FreeMemory(m_sipKernel); } } MOS_STATUS CmISHBase::Initialize(CM_HAL_STATE *cmhal, FrameTrackerProducer *trackerProducer) { m_osInterface = cmhal->osInterface; m_trackerProducer = trackerProducer; ExpandHeapSize(m_initSize); if (!cmhal->midThreadPreemptionDisabled) { CM_CHK_MOSSTATUS_RETURN(CreateSipKernel(cmhal)); // generate sip kernel in m_sipKernel } return MOS_STATUS_SUCCESS; } MOS_STATUS CmISHBase::LoadKernels(CmKernelEx **kernels, int count) { uint32_t blockSizes[CM_MAX_KERNELS_PER_TASK]; uint32_t blockIdx = 0; uint32_t totalSize = 0; for (int i = 0; i < count; i++) { CmKernelEx *kernel = kernels[i]; // check if the kernel is in ish CmISHBase *rIsh = nullptr; int rIdx = -1; kernel->GetRecordedInfo(&rIsh, &rIdx); if (rIsh == this && rIdx >= 0 && rIdx < (int)m_addedKernelCount && m_addedKernels[rIdx] == kernel) { //printf("HFDebug: reUse kernel %p in ish, name %s\n", kernel, kernel->GetName()); continue; } auto ite = m_addedHashValues.find(kernel->GetHashValue()); if (ite != m_addedHashValues.end()) { continue; } //printf("HFDebug: add a new kernel %p in ish, name %s\n", kernel, kernel->GetName()); uint8_t *nkernel = nullptr; uint32_t size = 0; kernel->GetNativeKernel(&nkernel, &size); uint32_t temp = MOS_ALIGN_CEIL(size + m_kernelPadding, m_kernelAlign); blockSizes[blockIdx ++] = temp; totalSize += temp; } uint32_t neededSize = totalSize; if (!m_isSipKernelLoaded && m_sipKernelSize) { neededSize += MOS_ALIGN_CEIL(m_sipKernelSize + m_kernelPadding, m_kernelAlign); } if (m_offset + neededSize > m_size) { ExpandHeapSize(neededSize); } if (!m_isSipKernelLoaded && m_sipKernelSize) { uint32_t temp = MOS_ALIGN_CEIL(m_sipKernelSize + m_kernelPadding, m_kernelAlign); // Copy Cm Kernel Binary MOS_SecureMemcpy(m_lockedData + m_offset, m_size - m_offset, m_sipKernel, m_sipKernelSize); // Padding bytes dummy instructions after kernel binary to resolve page fault issue MOS_ZeroMemory(m_lockedData + m_offset + m_sipKernelSize, temp - m_sipKernelSize); m_sipKernelOffset = m_offset; m_offset += temp; m_isSipKernelLoaded = true; } for (int i = 0; i < count; i++) { CmKernelEx *kernel = kernels[i]; // check if the kernel is in ish CmISHBase *rIsh = nullptr; int rIdx = -1; kernel->GetRecordedInfo(&rIsh, &rIdx); if (rIsh == this && rIdx >= 0 && rIdx < (int)m_addedKernelCount && m_addedKernels[rIdx] == kernel) { continue; } auto ite = m_addedHashValues.find(kernel->GetHashValue()); if (ite != m_addedHashValues.end()) { uint32_t offset = ite->second; kernel->Recorded(this, -1, offset); continue; } // copy kernel binary uint8_t *nkernel = nullptr; uint32_t size = 0; kernel->GetNativeKernel(&nkernel, &size); uint32_t temp = MOS_ALIGN_CEIL(size + m_kernelPadding, m_kernelAlign); // Copy Cm Kernel Binary MOS_SecureMemcpy(m_lockedData + m_offset, m_size - m_offset, nkernel, size); // Padding bytes dummy instructions after kernel binary to resolve page fault issue MOS_ZeroMemory(m_lockedData + m_offset + size, temp - size); // record m_addedKernels.push_back(kernel); kernel->Recorded(this, (int)m_addedKernelCount, m_offset); m_addedHashValues[kernel->GetHashValue()] = m_offset; m_addedKernelCount ++; m_offset += temp; } return MOS_STATUS_SUCCESS; } MOS_STATUS CmISHBase::ExpandHeapSize(uint32_t extraSize) { uint32_t addSize = MOS_ALIGN_CEIL(extraSize, m_expandStep); // destroy the old resource if (m_resource) { m_destroyedResources.push_front(m_resource); } if(m_lastTrackerToken) { m_destroyedTrackers.push_front(m_lastTrackerToken); } // allocate new resource m_resource = (PMOS_RESOURCE)MOS_AllocAndZeroMemory(sizeof(MOS_RESOURCE)); CM_CHK_NULL_RETURN_MOSERROR(m_resource); MOS_ALLOC_GFXRES_PARAMS allocParams; MOS_ZeroMemory(&allocParams, sizeof(allocParams)); allocParams.Type = MOS_GFXRES_BUFFER; allocParams.TileType = MOS_TILE_LINEAR; allocParams.Format = Format_Buffer; allocParams.dwBytes = m_size + addSize; allocParams.pBufName = "ISHeap"; CM_CHK_MOSSTATUS_RETURN(m_osInterface->pfnAllocateResource(m_osInterface, &allocParams, m_resource)); CM_CHK_MOSSTATUS_RETURN(m_osInterface->pfnRegisterResource(m_osInterface, m_resource, true, true)); CM_CHK_MOSSTATUS_RETURN(m_osInterface->pfnSkipResourceSync(m_resource)); m_size += addSize; m_offset = 0; MOS_LOCK_PARAMS lockParams; MOS_ZeroMemory(&lockParams, sizeof(lockParams)); lockParams.WriteOnly = 1; lockParams.NoOverWrite = 1; lockParams.Uncached = 1; m_lockedData = (uint8_t*)m_osInterface->pfnLockResource(m_osInterface, m_resource, &lockParams); // one new tracker token with one new resource m_lastTrackerToken = MOS_New(FrameTrackerToken); m_lastTrackerToken->SetProducer(m_trackerProducer); // no kernel is in the new heap m_addedKernels.clear(); m_addedKernelCount = 0; m_addedHashValues.clear(); Refresh(); m_isSipKernelLoaded = false; return MOS_STATUS_SUCCESS; } MOS_STATUS CmISHBase::Refresh() { MOS_GFXRES_FREE_FLAGS resFreeFlags = {0}; resFreeFlags.AssumeNotInUse = 1; // goes from back to front to handle tracker overflow while (m_destroyedTrackers.size()) { FrameTrackerToken *trackerToken = m_destroyedTrackers.back(); if (!trackerToken->IsExpired()) { break; } MOS_RESOURCE *res = m_destroyedResources.back(); m_osInterface->pfnUnlockResource(m_osInterface, res); m_osInterface->pfnFreeResourceWithFlag(m_osInterface, res, resFreeFlags.Value); m_destroyedResources.pop_back(); m_destroyedTrackers.pop_back(); MOS_FreeMemory(res); MOS_Delete(trackerToken); } return MOS_STATUS_SUCCESS; } void CmISHBase::Clean() { m_offset = 0; m_addedKernels.clear(); m_addedKernelCount = 0; Refresh(); m_isSipKernelLoaded = false; }