/* * Copyright (C) 2018-2021 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "opencl/source/mem_obj/mem_obj.h" #include "shared/source/command_stream/command_stream_receiver.h" #include "shared/source/gmm_helper/gmm.h" #include "shared/source/gmm_helper/resource_info.h" #include "shared/source/helpers/aligned_memory.h" #include "shared/source/helpers/bit_helpers.h" #include "shared/source/helpers/get_info.h" #include "shared/source/memory_manager/deferred_deleter.h" #include "shared/source/memory_manager/internal_allocation_storage.h" #include "shared/source/memory_manager/memory_manager.h" #include "shared/source/os_interface/os_context.h" #include "opencl/source/cl_device/cl_device.h" #include "opencl/source/command_queue/command_queue.h" #include "opencl/source/context/context.h" #include "opencl/source/helpers/get_info_status_mapper.h" #include namespace NEO { MemObj::MemObj(Context *context, cl_mem_object_type memObjectType, const MemoryProperties &memoryProperties, cl_mem_flags flags, cl_mem_flags_intel flagsIntel, size_t size, void *memoryStorage, void *hostPtr, MultiGraphicsAllocation multiGraphicsAllocation, bool zeroCopy, bool isHostPtrSVM, bool isObjectRedescribed) : context(context), memObjectType(memObjectType), memoryProperties(memoryProperties), flags(flags), flagsIntel(flagsIntel), size(size), memoryStorage(memoryStorage), hostPtr(hostPtr), isZeroCopy(zeroCopy), isHostPtrSVM(isHostPtrSVM), isObjectRedescribed(isObjectRedescribed), multiGraphicsAllocation(std::move(multiGraphicsAllocation)), mapAllocations(static_cast(this->multiGraphicsAllocation.getGraphicsAllocations().size() - 1)) { if (context) { context->incRefInternal(); memoryManager = context->getMemoryManager(); auto device = context->getDevice(0); executionEnvironment = device->getExecutionEnvironment(); } } MemObj::~MemObj() { if (!context) { return; } bool needWait = false; if (allocatedMapPtr != nullptr) { needWait = true; } if (mapOperationsHandler.size() > 0 && !getCpuAddressForMapping()) { needWait = true; } if (!destructorCallbacks.empty()) { needWait = true; } if (!isObjectRedescribed) { if (peekSharingHandler()) { peekSharingHandler()->releaseReusedGraphicsAllocation(); } for (auto graphicsAllocation : multiGraphicsAllocation.getGraphicsAllocations()) { auto rootDeviceIndex = graphicsAllocation ? graphicsAllocation->getRootDeviceIndex() : 0; bool doAsyncDestructions = DebugManager.flags.EnableAsyncDestroyAllocations.get(); if (graphicsAllocation && !associatedMemObject && !isHostPtrSVM && graphicsAllocation->peekReuseCount() == 0) { memoryManager->removeAllocationFromHostPtrManager(graphicsAllocation); if (!doAsyncDestructions) { needWait = true; } if (needWait && graphicsAllocation->isUsed()) { memoryManager->waitForEnginesCompletion(*graphicsAllocation); } destroyGraphicsAllocation(graphicsAllocation, doAsyncDestructions); graphicsAllocation = nullptr; } if (!associatedMemObject) { releaseMapAllocation(rootDeviceIndex, doAsyncDestructions); } if (mcsAllocation) { destroyGraphicsAllocation(mcsAllocation, false); } if (graphicsAllocation && associatedMemObject) { if (associatedMemObject->getGraphicsAllocation(graphicsAllocation->getRootDeviceIndex()) != graphicsAllocation) { destroyGraphicsAllocation(graphicsAllocation, false); } associatedMemObject->decRefInternal(); } } if (!associatedMemObject) { releaseAllocatedMapPtr(); } } destructorCallbacks.invoke(this); context->decRefInternal(); } cl_int MemObj::getMemObjectInfo(cl_mem_info paramName, size_t paramValueSize, void *paramValue, size_t *paramValueSizeRet) { cl_int retVal; size_t srcParamSize = GetInfo::invalidSourceSize; void *srcParam = nullptr; cl_bool usesSVMPointer; cl_uint refCnt = 0; cl_uint mapCount = 0; cl_mem clAssociatedMemObject = static_cast(this->associatedMemObject); cl_context ctx = nullptr; uint64_t internalHandle = 0llu; auto allocation = getMultiGraphicsAllocation().getDefaultGraphicsAllocation(); Gmm *gmm; cl_bool usesCompression; switch (paramName) { case CL_MEM_TYPE: srcParamSize = sizeof(memObjectType); srcParam = &memObjectType; break; case CL_MEM_FLAGS: srcParamSize = sizeof(flags); srcParam = &flags; break; case CL_MEM_SIZE: srcParamSize = sizeof(size); srcParam = &size; break; case CL_MEM_HOST_PTR: srcParamSize = sizeof(hostPtr); srcParam = &hostPtr; break; case CL_MEM_CONTEXT: srcParamSize = sizeof(context); ctx = context; srcParam = &ctx; break; case CL_MEM_USES_SVM_POINTER: usesSVMPointer = isHostPtrSVM && isValueSet(flags, CL_MEM_USE_HOST_PTR); srcParamSize = sizeof(cl_bool); srcParam = &usesSVMPointer; break; case CL_MEM_OFFSET: srcParamSize = sizeof(offset); srcParam = &offset; break; case CL_MEM_ASSOCIATED_MEMOBJECT: srcParamSize = sizeof(clAssociatedMemObject); srcParam = &clAssociatedMemObject; break; case CL_MEM_MAP_COUNT: srcParamSize = sizeof(mapCount); mapCount = static_cast(mapOperationsHandler.size()); srcParam = &mapCount; break; case CL_MEM_REFERENCE_COUNT: refCnt = static_cast(this->getReference()); srcParamSize = sizeof(refCnt); srcParam = &refCnt; break; case CL_MEM_ALLOCATION_HANDLE_INTEL: internalHandle = multiGraphicsAllocation.getDefaultGraphicsAllocation()->peekInternalHandle(this->memoryManager); srcParamSize = sizeof(internalHandle); srcParam = &internalHandle; break; case CL_MEM_USES_COMPRESSION_INTEL: gmm = allocation->getDefaultGmm(); if (gmm != nullptr) { usesCompression = gmm->isCompressionEnabled; } else { usesCompression = allocation->getAllocationType() == GraphicsAllocation::AllocationType::BUFFER_COMPRESSED; } srcParam = &usesCompression; srcParamSize = sizeof(cl_bool); break; case CL_MEM_PROPERTIES: srcParamSize = propertiesVector.size() * sizeof(cl_mem_properties); srcParam = propertiesVector.data(); break; default: getOsSpecificMemObjectInfo(paramName, &srcParamSize, &srcParam); break; } auto getInfoStatus = GetInfo::getInfo(paramValue, paramValueSize, srcParam, srcParamSize); retVal = changeGetInfoStatusToCLResultType(getInfoStatus); GetInfo::setParamValueReturnSize(paramValueSizeRet, srcParamSize, getInfoStatus); return retVal; } cl_int MemObj::setDestructorCallback(void(CL_CALLBACK *funcNotify)(cl_mem, void *), void *userData) { std::unique_lock theLock(mtx); destructorCallbacks.add(funcNotify, userData); return CL_SUCCESS; } void *MemObj::getCpuAddress() const { return memoryStorage; } void *MemObj::getHostPtr() const { return hostPtr; } size_t MemObj::getSize() const { return size; } void MemObj::setAllocatedMapPtr(void *allocatedMapPtr) { this->allocatedMapPtr = allocatedMapPtr; } bool MemObj::isMemObjZeroCopy() const { return isZeroCopy; } bool MemObj::isMemObjWithHostPtrSVM() const { return isHostPtrSVM; } bool MemObj::isMemObjUncacheable() const { return isValueSet(flagsIntel, CL_MEM_LOCALLY_UNCACHED_RESOURCE); } bool MemObj::isMemObjUncacheableForSurfaceState() const { return isAnyBitSet(flagsIntel, CL_MEM_LOCALLY_UNCACHED_SURFACE_STATE_RESOURCE | CL_MEM_LOCALLY_UNCACHED_RESOURCE); } GraphicsAllocation *MemObj::getGraphicsAllocation(uint32_t rootDeviceIndex) const { return multiGraphicsAllocation.getGraphicsAllocation(rootDeviceIndex); } void MemObj::checkUsageAndReleaseOldAllocation(uint32_t rootDeviceIndex) { auto graphicsAllocation = getGraphicsAllocation(rootDeviceIndex); if (graphicsAllocation != nullptr && (peekSharingHandler() == nullptr || graphicsAllocation->peekReuseCount() == 0)) { memoryManager->checkGpuUsageAndDestroyGraphicsAllocations(graphicsAllocation); } } void MemObj::resetGraphicsAllocation(GraphicsAllocation *newGraphicsAllocation) { TakeOwnershipWrapper lock(*this); checkUsageAndReleaseOldAllocation(newGraphicsAllocation->getRootDeviceIndex()); multiGraphicsAllocation.addAllocation(newGraphicsAllocation); } void MemObj::removeGraphicsAllocation(uint32_t rootDeviceIndex) { TakeOwnershipWrapper lock(*this); checkUsageAndReleaseOldAllocation(rootDeviceIndex); multiGraphicsAllocation.removeAllocation(rootDeviceIndex); } bool MemObj::readMemObjFlagsInvalid() { return isValueSet(flags, CL_MEM_HOST_WRITE_ONLY) || isValueSet(flags, CL_MEM_HOST_NO_ACCESS); } bool MemObj::writeMemObjFlagsInvalid() { return isValueSet(flags, CL_MEM_HOST_READ_ONLY) || isValueSet(flags, CL_MEM_HOST_NO_ACCESS); } bool MemObj::mapMemObjFlagsInvalid(cl_map_flags mapFlags) { return (writeMemObjFlagsInvalid() && (mapFlags & CL_MAP_WRITE)) || (readMemObjFlagsInvalid() && (mapFlags & CL_MAP_READ)); } void MemObj::setHostPtrMinSize(size_t size) { hostPtrMinSize = size; } void *MemObj::getCpuAddressForMapping() { void *ptrToReturn = nullptr; if (isValueSet(flags, CL_MEM_USE_HOST_PTR)) { ptrToReturn = this->hostPtr; } else { ptrToReturn = this->memoryStorage; } return ptrToReturn; } void *MemObj::getCpuAddressForMemoryTransfer() { void *ptrToReturn = nullptr; if (isValueSet(flags, CL_MEM_USE_HOST_PTR) && this->isMemObjZeroCopy()) { ptrToReturn = this->hostPtr; } else { ptrToReturn = this->memoryStorage; } return ptrToReturn; } void MemObj::releaseAllocatedMapPtr() { if (allocatedMapPtr) { DEBUG_BREAK_IF(isValueSet(flags, CL_MEM_USE_HOST_PTR)); memoryManager->freeSystemMemory(allocatedMapPtr); } allocatedMapPtr = nullptr; } void MemObj::releaseMapAllocation(uint32_t rootDeviceIndex, bool asyncDestroy) { auto mapAllocation = mapAllocations.getGraphicsAllocation(rootDeviceIndex); if (mapAllocation && !isHostPtrSVM) { if (asyncDestroy && !isValueSet(flags, CL_MEM_USE_HOST_PTR)) { destroyGraphicsAllocation(mapAllocation, true); } else { if (mapAllocation->isUsed()) { memoryManager->waitForEnginesCompletion(*mapAllocation); } destroyGraphicsAllocation(mapAllocation, false); } } } void MemObj::destroyGraphicsAllocation(GraphicsAllocation *allocation, bool asyncDestroy) { if (asyncDestroy) { memoryManager->checkGpuUsageAndDestroyGraphicsAllocations(allocation); } else { memoryManager->freeGraphicsMemory(allocation); } } bool MemObj::checkIfMemoryTransferIsRequired(size_t offsetInMemObject, size_t offsetInHostPtr, const void *hostPtr, cl_command_type cmdType) { auto bufferStorage = ptrOffset(this->getCpuAddressForMemoryTransfer(), offsetInMemObject); auto hostStorage = ptrOffset(hostPtr, offsetInHostPtr); auto isMemTransferNeeded = !((bufferStorage == hostStorage) && (cmdType == CL_COMMAND_WRITE_BUFFER || cmdType == CL_COMMAND_READ_BUFFER || cmdType == CL_COMMAND_WRITE_BUFFER_RECT || cmdType == CL_COMMAND_READ_BUFFER_RECT || cmdType == CL_COMMAND_WRITE_IMAGE || cmdType == CL_COMMAND_READ_IMAGE)); return isMemTransferNeeded; } void *MemObj::getBasePtrForMap(uint32_t rootDeviceIndex) { if (associatedMemObject) { return associatedMemObject->getBasePtrForMap(rootDeviceIndex); } if (getFlags() & CL_MEM_USE_HOST_PTR) { return getHostPtr(); } else { TakeOwnershipWrapper memObjOwnership(*this); if (getMapAllocation(rootDeviceIndex)) { return getMapAllocation(rootDeviceIndex)->getUnderlyingBuffer(); } else { auto memory = getAllocatedMapPtr(); if (!memory) { memory = memoryManager->allocateSystemMemory(getSize(), MemoryConstants::pageSize); setAllocatedMapPtr(memory); } AllocationProperties properties{rootDeviceIndex, false, // allocateMemory getSize(), GraphicsAllocation::AllocationType::MAP_ALLOCATION, false, //isMultiStorageAllocation context->getDeviceBitfieldForAllocation(rootDeviceIndex)}; auto allocation = memoryManager->allocateGraphicsMemoryWithProperties(properties, memory); setMapAllocation(allocation); return getAllocatedMapPtr(); } } } bool MemObj::addMappedPtr(void *ptr, size_t ptrLength, cl_map_flags &mapFlags, MemObjSizeArray &size, MemObjOffsetArray &offset, uint32_t mipLevel) { return mapOperationsHandler.add(ptr, ptrLength, mapFlags, size, offset, mipLevel); } bool MemObj::isTiledAllocation() const { auto graphicsAllocation = multiGraphicsAllocation.getDefaultGraphicsAllocation(); auto gmm = graphicsAllocation->getDefaultGmm(); return gmm && (gmm->gmmResourceInfo->getTileModeSurfaceState() != 0); } bool MemObj::mappingOnCpuAllowed() const { auto graphicsAllocation = multiGraphicsAllocation.getDefaultGraphicsAllocation(); return !isTiledAllocation() && !peekSharingHandler() && !isMipMapped(this) && !DebugManager.flags.DisableZeroCopyForBuffers.get() && !(graphicsAllocation->getDefaultGmm() && graphicsAllocation->getDefaultGmm()->isCompressionEnabled) && MemoryPool::isSystemMemoryPool(graphicsAllocation->getMemoryPool()); } void MemObj::storeProperties(const cl_mem_properties *properties) { if (properties) { for (size_t i = 0; properties[i] != 0; i += 2) { propertiesVector.push_back(properties[i]); propertiesVector.push_back(properties[i + 1]); } propertiesVector.push_back(0); } } void MemObj::cleanAllGraphicsAllocations(Context &context, MemoryManager &memoryManager, AllocationInfoType &allocationInfo, bool isParentObject) { if (!isParentObject) { for (auto &index : context.getRootDeviceIndices()) { if (allocationInfo[index].memory) { memoryManager.removeAllocationFromHostPtrManager(allocationInfo[index].memory); memoryManager.freeGraphicsMemory(allocationInfo[index].memory); } } } } } // namespace NEO