diff --git a/level_zero/core/source/cmdlist/cmdlist_hw.inl b/level_zero/core/source/cmdlist/cmdlist_hw.inl index 44090f265e..3fa5adb2f8 100644 --- a/level_zero/core/source/cmdlist/cmdlist_hw.inl +++ b/level_zero/core/source/cmdlist/cmdlist_hw.inl @@ -536,6 +536,17 @@ ze_result_t CommandListCoreFamily::appendImageCopyFromMemory(ze_i auto slicePitch = image->getImageInfo().imgDesc.imageType == NEO::ImageType::Image1DArray ? 1 : pDstRegion->height * rowPitch; + DriverHandleImp *driverHandle = static_cast(device->getDriverHandle()); + if (driverHandle->isRemoteImageNeeded(image, device)) { + L0::Image *peerImage = nullptr; + + ze_result_t ret = driverHandle->getPeerImage(device, image, &peerImage); + if (ret != ZE_RESULT_SUCCESS) { + return ret; + } + image = peerImage; + } + if (isCopyOnly()) { return appendCopyImageBlit(allocationStruct.alloc, image->getAllocation(), {0, 0, 0}, {pDstRegion->originX, pDstRegion->originY, pDstRegion->originZ}, rowPitch, slicePitch, @@ -569,7 +580,7 @@ ze_result_t CommandListCoreFamily::appendImageCopyFromMemory(ze_i builtinKernel->setArgBufferWithAlloc(0u, allocationStruct.alignedAllocationPtr, allocationStruct.alloc); - builtinKernel->setArgRedescribedImage(1u, hDstImage); + builtinKernel->setArgRedescribedImage(1u, image->toHandle()); builtinKernel->setArgumentValue(2u, sizeof(size_t), &allocationStruct.offset); uint32_t origin[] = { @@ -668,6 +679,17 @@ ze_result_t CommandListCoreFamily::appendImageCopyToMemory(void * auto slicePitch = (image->getImageInfo().imgDesc.imageType == NEO::ImageType::Image1DArray ? 1 : pSrcRegion->height) * rowPitch; + DriverHandleImp *driverHandle = static_cast(device->getDriverHandle()); + if (driverHandle->isRemoteImageNeeded(image, device)) { + L0::Image *peerImage = nullptr; + + ze_result_t ret = driverHandle->getPeerImage(device, image, &peerImage); + if (ret != ZE_RESULT_SUCCESS) { + return ret; + } + image = peerImage; + } + if (isCopyOnly()) { return appendCopyImageBlit(image->getAllocation(), allocationStruct.alloc, {pSrcRegion->originX, pSrcRegion->originY, pSrcRegion->originZ}, {0, 0, 0}, rowPitch, slicePitch, @@ -700,7 +722,7 @@ ze_result_t CommandListCoreFamily::appendImageCopyToMemory(void * break; } - builtinKernel->setArgRedescribedImage(0u, hSrcImage); + builtinKernel->setArgRedescribedImage(0u, image->toHandle()); builtinKernel->setArgBufferWithAlloc(1u, allocationStruct.alignedAllocationPtr, allocationStruct.alloc); @@ -812,6 +834,27 @@ ze_result_t CommandListCoreFamily::appendImageCopyRegion(ze_image event = Event::fromHandle(hEvent); } + DriverHandleImp *driverHandle = static_cast(device->getDriverHandle()); + if (driverHandle->isRemoteImageNeeded(dstImage, device)) { + L0::Image *peerImage = nullptr; + + ze_result_t ret = driverHandle->getPeerImage(device, dstImage, &peerImage); + if (ret != ZE_RESULT_SUCCESS) { + return ret; + } + dstImage = peerImage; + } + + if (driverHandle->isRemoteImageNeeded(srcImage, device)) { + L0::Image *peerImage = nullptr; + + ze_result_t ret = driverHandle->getPeerImage(device, srcImage, &peerImage); + if (ret != ZE_RESULT_SUCCESS) { + return ret; + } + srcImage = peerImage; + } + if (isCopyOnly()) { auto bytesPerPixel = static_cast(srcImage->getImageInfo().surfaceFormat->ImageElementSizeInBytes); @@ -863,8 +906,8 @@ ze_result_t CommandListCoreFamily::appendImageCopyRegion(ze_image ze_group_count_t kernelArgs{srcRegion.width / groupSizeX, srcRegion.height / groupSizeY, srcRegion.depth / groupSizeZ}; - kernel->setArgRedescribedImage(0, hSrcImage); - kernel->setArgRedescribedImage(1, hDstImage); + kernel->setArgRedescribedImage(0, srcImage->toHandle()); + kernel->setArgRedescribedImage(1, dstImage->toHandle()); kernel->setArgumentValue(2, sizeof(srcOffset), &srcOffset); kernel->setArgumentValue(3, sizeof(dstOffset), &dstOffset); diff --git a/level_zero/core/source/device/device_imp.h b/level_zero/core/source/device/device_imp.h index c94b1256fe..759b2de43d 100644 --- a/level_zero/core/source/device/device_imp.h +++ b/level_zero/core/source/device/device_imp.h @@ -133,6 +133,8 @@ struct DeviceImp : public Device { NEO::SVMAllocsManager::MapBasedAllocationTracker peerAllocations; NEO::SpinLock peerAllocationsMutex; + std::unordered_map peerImageAllocations; + NEO::SpinLock peerImageAllocationsMutex; std::map memAdviseSharedAllocations; std::unique_ptr allocationsForReuse; std::unique_ptr driverInfo; diff --git a/level_zero/core/source/driver/driver_handle_imp.cpp b/level_zero/core/source/driver/driver_handle_imp.cpp index 30f9e1bbf8..7a4b098c88 100644 --- a/level_zero/core/source/driver/driver_handle_imp.cpp +++ b/level_zero/core/source/driver/driver_handle_imp.cpp @@ -26,6 +26,7 @@ #include "level_zero/core/source/driver/driver_imp.h" #include "level_zero/core/source/driver/host_pointer_manager.h" #include "level_zero/core/source/fabric/fabric.h" +#include "level_zero/core/source/image/image.h" #include "driver_version_l0.h" @@ -558,6 +559,47 @@ void *DriverHandleImp::importFdHandles(NEO::Device *neoDevice, ze_ipc_memory_fla return reinterpret_cast(alloc->getGpuAddress()); } +bool DriverHandleImp::isRemoteImageNeeded(Image *image, Device *device) { + return (image->getAllocation()->getRootDeviceIndex() != device->getRootDeviceIndex()); +} + +ze_result_t DriverHandleImp::getPeerImage(Device *device, Image *image, Image **peerImage) { + DeviceImp *deviceImp = static_cast(device); + auto imageAllocPtr = reinterpret_cast(image->getAllocation()->getGpuAddress()); + + std::unique_lock lock(deviceImp->peerImageAllocationsMutex); + + if (deviceImp->peerImageAllocations.find(imageAllocPtr) != deviceImp->peerImageAllocations.end()) { + *peerImage = deviceImp->peerImageAllocations[imageAllocPtr]; + } else { + uint64_t handle = 0; + + int ret = image->getAllocation()->peekInternalHandle(this->getMemoryManager(), handle); + if (ret < 0) { + return ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + ze_image_desc_t desc = image->getImageDesc(); + ze_external_memory_import_fd_t externalMemoryImportDesc = {}; + + externalMemoryImportDesc.stype = ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMPORT_FD; + externalMemoryImportDesc.fd = static_cast(handle); + externalMemoryImportDesc.flags = ZE_EXTERNAL_MEMORY_TYPE_FLAG_DMA_BUF; + externalMemoryImportDesc.pNext = nullptr; + desc.pNext = &externalMemoryImportDesc; + + auto productFamily = device->getNEODevice()->getHardwareInfo().platform.eProductFamily; + ze_result_t result = Image::create(productFamily, device, &desc, peerImage); + + if (result != ZE_RESULT_SUCCESS) { + return result; + } + deviceImp->peerImageAllocations.insert(std::make_pair(imageAllocPtr, *peerImage)); + } + + return ZE_RESULT_SUCCESS; +} + NEO::GraphicsAllocation *DriverHandleImp::getPeerAllocation(Device *device, NEO::SvmAllocationData *allocData, void *basePtr, diff --git a/level_zero/core/source/driver/driver_handle_imp.h b/level_zero/core/source/driver/driver_handle_imp.h index 3b2b121f6e..87d04da503 100644 --- a/level_zero/core/source/driver/driver_handle_imp.h +++ b/level_zero/core/source/driver/driver_handle_imp.h @@ -21,6 +21,7 @@ namespace L0 { class HostPointerManager; struct FabricVertex; struct FabricEdge; +struct Image; struct DriverHandleImp : public DriverHandle { ~DriverHandleImp() override; @@ -70,6 +71,7 @@ struct DriverHandleImp : public DriverHandle { size_t size, uint32_t rootDeviceIndex, uintptr_t *gpuAddress) override; + ze_result_t getPeerImage(Device *device, L0::Image *image, L0::Image **peerImage); NEO::GraphicsAllocation *getPeerAllocation(Device *device, NEO::SvmAllocationData *allocData, void *basePtr, @@ -79,6 +81,7 @@ struct DriverHandleImp : public DriverHandle { void createHostPointerManager(); void sortNeoDevices(std::vector> &neoDevices); + bool isRemoteImageNeeded(Image *image, Device *device); bool isRemoteResourceNeeded(void *ptr, NEO::GraphicsAllocation *alloc, NEO::SvmAllocationData *allocData, diff --git a/level_zero/core/source/image/image.h b/level_zero/core/source/image/image.h index 6dca1ab8b7..57581ea057 100644 --- a/level_zero/core/source/image/image.h +++ b/level_zero/core/source/image/image.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2022 Intel Corporation + * Copyright (C) 2020-2023 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -28,6 +28,7 @@ struct Image : _ze_image_handle_t { virtual ~Image() = default; virtual ze_result_t destroy() = 0; + virtual ze_result_t destroyPeerImages(const void *ptr, Device *device) = 0; static ze_result_t create(uint32_t productFamily, Device *device, const ze_image_desc_t *desc, Image **pImage); diff --git a/level_zero/core/source/image/image_imp.cpp b/level_zero/core/source/image/image_imp.cpp index 870514364e..01673146de 100644 --- a/level_zero/core/source/image/image_imp.cpp +++ b/level_zero/core/source/image/image_imp.cpp @@ -12,6 +12,8 @@ #include "shared/source/memory_manager/memory_manager.h" #include "level_zero/core/source/device/device.h" +#include "level_zero/core/source/device/device_imp.h" +#include "level_zero/core/source/driver/driver_handle_imp.h" #include "igfxfmid.h" @@ -26,10 +28,32 @@ ImageImp::~ImageImp() { } ze_result_t ImageImp::destroy() { + if (this->getAllocation() && this->device) { + auto imageAllocPtr = reinterpret_cast(this->getAllocation()->getGpuAddress()); + DriverHandleImp *driverHandle = static_cast(this->device->getDriverHandle()); + + for (auto peerDevice : driverHandle->devices) { + this->destroyPeerImages(imageAllocPtr, peerDevice); + } + } + delete this; return ZE_RESULT_SUCCESS; } +ze_result_t ImageImp::destroyPeerImages(const void *ptr, Device *device) { + DeviceImp *deviceImp = static_cast(device); + + std::unique_lock lock(deviceImp->peerImageAllocationsMutex); + + if (deviceImp->peerImageAllocations.find(ptr) != deviceImp->peerImageAllocations.end()) { + delete deviceImp->peerImageAllocations[ptr]; + deviceImp->peerImageAllocations.erase(ptr); + } + + return ZE_RESULT_SUCCESS; +} + ze_result_t ImageImp::createView(Device *device, const ze_image_desc_t *desc, ze_image_handle_t *pImage) { auto productFamily = device->getNEODevice()->getHardwareInfo().platform.eProductFamily; diff --git a/level_zero/core/source/image/image_imp.h b/level_zero/core/source/image/image_imp.h index 48df3153fe..55426e5ade 100644 --- a/level_zero/core/source/image/image_imp.h +++ b/level_zero/core/source/image/image_imp.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 Intel Corporation + * Copyright (C) 2020-2023 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -15,6 +15,7 @@ namespace L0 { struct ImageImp : public Image { ze_result_t destroy() override; + ze_result_t destroyPeerImages(const void *ptr, Device *device) override; virtual ze_result_t initialize(Device *device, const ze_image_desc_t *desc) = 0; diff --git a/level_zero/core/test/unit_tests/sources/memory/test_memory.cpp b/level_zero/core/test/unit_tests/sources/memory/test_memory.cpp index 2d204f4b05..fee1d4b1ed 100644 --- a/level_zero/core/test/unit_tests/sources/memory/test_memory.cpp +++ b/level_zero/core/test/unit_tests/sources/memory/test_memory.cpp @@ -4946,5 +4946,316 @@ TEST_F(MemAllocMultiSubDeviceTestsEnabledImplicitScaling, GivenImplicitScalingDi EXPECT_EQ(res, ZE_RESULT_ERROR_OUT_OF_DEVICE_MEMORY); } +class ExportImportMockGraphicsAllocation : public NEO::MemoryAllocation { + public: + ExportImportMockGraphicsAllocation() : NEO::MemoryAllocation(0, AllocationType::BUFFER, nullptr, 0u, 0, MemoryPool::MemoryNull, MemoryManager::maxOsContextCount, 0llu) {} + + int peekInternalHandle(NEO::MemoryManager *memoryManager, uint64_t &handle) override { + return -1; + } +}; + +class MockSharedHandleMemoryManager : public MockMemoryManager { + public: + using MockMemoryManager::MockMemoryManager; + + GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation, bool reuseSharedAllocation) override { + if (failOnCreateGraphicsAllocationFromSharedHandle) { + return nullptr; + } + + return MockMemoryManager::createGraphicsAllocationFromSharedHandle(handle, properties, requireSpecificBitness, isHostIpcAllocation, reuseSharedAllocation); + } + + GraphicsAllocation *allocateGraphicsMemoryWithProperties(const AllocationProperties &properties) override { + if (failPeekInternalHandle) { + return new ExportImportMockGraphicsAllocation(); + } + return MockMemoryManager::allocateGraphicsMemoryWithProperties(properties); + } + + bool failOnCreateGraphicsAllocationFromSharedHandle = false; + bool failPeekInternalHandle = false; +}; + +struct MultipleDevicePeerImageTest : public ::testing::Test { + void SetUp() override { + DebugManagerStateRestore restorer; + + DebugManager.flags.CreateMultipleSubDevices.set(numSubDevices); + VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); + + std::vector> devices; + NEO::ExecutionEnvironment *executionEnvironment = new NEO::ExecutionEnvironment(); + executionEnvironment->prepareRootDeviceEnvironments(numRootDevices); + for (auto i = 0u; i < executionEnvironment->rootDeviceEnvironments.size(); i++) { + executionEnvironment->rootDeviceEnvironments[i]->setHwInfoAndInitHelpers(NEO::defaultHwInfo.get()); + executionEnvironment->rootDeviceEnvironments[i]->initGmm(); + } + + auto &gfxCoreHelper = executionEnvironment->rootDeviceEnvironments[0]->getHelper(); + bool enableLocalMemory = gfxCoreHelper.getEnableLocalMemory(*defaultHwInfo); + bool aubUsage = (testMode == TestMode::AubTests) || (testMode == TestMode::AubTestsWithTbx); + deviceFactoryMemoryManager = new MockSharedHandleMemoryManager(false, enableLocalMemory, aubUsage, *executionEnvironment); + executionEnvironment->memoryManager.reset(deviceFactoryMemoryManager); + deviceFactory = std::make_unique(numRootDevices, numSubDevices, *executionEnvironment); + + for (auto i = 0u; i < executionEnvironment->rootDeviceEnvironments.size(); i++) { + devices.push_back(std::unique_ptr(deviceFactory->rootDevices[i])); + } + driverHandle = std::make_unique(); + driverHandle->initialize(std::move(devices)); + + context = std::make_unique(driverHandle.get()); + EXPECT_NE(context, nullptr); + for (auto i = 0u; i < numRootDevices; i++) { + auto device = driverHandle->devices[i]; + context->getDevices().insert(std::make_pair(device->getRootDeviceIndex(), device->toHandle())); + auto neoDevice = device->getNEODevice(); + context->rootDeviceIndices.push_back(neoDevice->getRootDeviceIndex()); + context->deviceBitfields.insert({neoDevice->getRootDeviceIndex(), neoDevice->getDeviceBitfield()}); + } + context->rootDeviceIndices.remove_duplicates(); + } + + void TearDown() override {} + + NEO::MemoryManager *deviceFactoryMemoryManager = nullptr; + + NEO::SVMAllocsManager *prevSvmAllocsManager = nullptr; + NEO::SVMAllocsManager *currSvmAllocsManager = nullptr; + std::unique_ptr driverHandle; + + std::unique_ptr deviceFactory; + std::unique_ptr context; + + const uint32_t numRootDevices = 2u; + const uint32_t numSubDevices = 2u; +}; + +using ImageSupport = IsWithinProducts; + +HWTEST2_F(MultipleDevicePeerImageTest, + whenisRemoteImageNeededIsCalledWithDifferentCombinationsOfInputsThenExpectedOutputIsReturned, + ImageSupport) { + L0::Device *device0 = driverHandle->devices[0]; + L0::Device *device1 = driverHandle->devices[1]; + + ze_image_desc_t zeDesc = {}; + zeDesc.stype = ZE_STRUCTURE_TYPE_IMAGE_DESC; + zeDesc.arraylevels = 1u; + zeDesc.depth = 1u; + zeDesc.height = 1u; + zeDesc.width = 1u; + zeDesc.miplevels = 1u; + zeDesc.type = ZE_IMAGE_TYPE_2DARRAY; + zeDesc.flags = ZE_IMAGE_FLAG_BIAS_UNCACHED; + + zeDesc.format = {ZE_IMAGE_FORMAT_LAYOUT_32, + ZE_IMAGE_FORMAT_TYPE_UINT, + ZE_IMAGE_FORMAT_SWIZZLE_R, + ZE_IMAGE_FORMAT_SWIZZLE_G, + ZE_IMAGE_FORMAT_SWIZZLE_B, + ZE_IMAGE_FORMAT_SWIZZLE_A}; + + L0::Image *image0; + auto result = Image::create(productFamily, device0, &zeDesc, &image0); + EXPECT_EQ(result, ZE_RESULT_SUCCESS); + + L0::Image *image1; + result = Image::create(productFamily, device1, &zeDesc, &image1); + EXPECT_EQ(result, ZE_RESULT_SUCCESS); + + bool isNeeded = driverHandle->isRemoteImageNeeded(image0, device0); + EXPECT_FALSE(isNeeded); + + isNeeded = driverHandle->isRemoteImageNeeded(image1, device0); + EXPECT_TRUE(isNeeded); + + isNeeded = driverHandle->isRemoteImageNeeded(image0, device1); + EXPECT_TRUE(isNeeded); + + isNeeded = driverHandle->isRemoteImageNeeded(image1, device1); + EXPECT_FALSE(isNeeded); + + result = image0->destroy(); + ASSERT_EQ(result, ZE_RESULT_SUCCESS); + result = image1->destroy(); + ASSERT_EQ(result, ZE_RESULT_SUCCESS); +} + +HWTEST2_F(MultipleDevicePeerImageTest, + givenRemoteImageAllocationsPassedToAppendImageCopyCallsUsingDevice0ThenSuccessIsReturned, + ImageSupport) { + const ze_command_queue_desc_t queueDesc = {}; + L0::Device *device0 = driverHandle->devices[0]; + L0::Device *device1 = driverHandle->devices[1]; + void *srcPtr = reinterpret_cast(0x1234); + void *dstPtr = reinterpret_cast(0x2345); + + ze_image_desc_t desc = {}; + desc.stype = ZE_STRUCTURE_TYPE_IMAGE_DESC; + desc.type = ZE_IMAGE_TYPE_3D; + desc.format.layout = ZE_IMAGE_FORMAT_LAYOUT_8_8_8_8; + desc.format.type = ZE_IMAGE_FORMAT_TYPE_UINT; + desc.width = 11; + desc.height = 13; + desc.depth = 17; + + desc.format.x = ZE_IMAGE_FORMAT_SWIZZLE_A; + desc.format.y = ZE_IMAGE_FORMAT_SWIZZLE_0; + desc.format.z = ZE_IMAGE_FORMAT_SWIZZLE_1; + desc.format.w = ZE_IMAGE_FORMAT_SWIZZLE_X; + + L0::Image *image0Src; + L0::Image *image0Dst; + auto result = Image::create(productFamily, device0, &desc, &image0Src); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + result = Image::create(productFamily, device0, &desc, &image0Dst); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + L0::Image *image1Src; + L0::Image *image1Dst; + result = Image::create(productFamily, device1, &desc, &image1Src); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + result = Image::create(productFamily, device1, &desc, &image1Dst); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + device0->getNEODevice()->getRootDeviceEnvironment().getMutableHardwareInfo()->capabilityTable.blitterOperationsSupported = true; + ze_result_t returnValue; + std::unique_ptr commandList0(CommandList::createImmediate(productFamily, + device0, + &queueDesc, + false, + NEO::EngineGroupType::Copy, + returnValue)); + ASSERT_NE(nullptr, commandList0); + + result = commandList0->appendImageCopy(image0Dst->toHandle(), image1Src->toHandle(), nullptr, 0, nullptr, false); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + result = commandList0->appendImageCopy(image1Dst->toHandle(), image0Src->toHandle(), nullptr, 0, nullptr, false); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + result = commandList0->appendImageCopyFromMemory(image1Dst->toHandle(), srcPtr, nullptr, nullptr, 0, nullptr, false); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + result = commandList0->appendImageCopyToMemory(dstPtr, image1Src->toHandle(), nullptr, nullptr, 0, nullptr, false); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + result = image0Src->destroy(); + ASSERT_EQ(result, ZE_RESULT_SUCCESS); + result = image0Dst->destroy(); + ASSERT_EQ(result, ZE_RESULT_SUCCESS); + + result = image1Src->destroy(); + ASSERT_EQ(result, ZE_RESULT_SUCCESS); + result = image1Dst->destroy(); + ASSERT_EQ(result, ZE_RESULT_SUCCESS); +} + +HWTEST2_F(MultipleDevicePeerImageTest, + givenRemoteImageAllocationsPassedToAppendImageCopyCallsUsingDevice0WithFailingSharedHandleAllocationsThenErrorIsReturned, + ImageSupport) { + MockSharedHandleMemoryManager *fixtureMemoryManager = static_cast(deviceFactoryMemoryManager); + fixtureMemoryManager->failOnCreateGraphicsAllocationFromSharedHandle = true; + + L0::Device *device0 = driverHandle->devices[0]; + L0::Device *device1 = driverHandle->devices[1]; + void *srcPtr = reinterpret_cast(0x1234); + void *dstPtr = reinterpret_cast(0x2345); + + ze_image_desc_t desc = {}; + desc.stype = ZE_STRUCTURE_TYPE_IMAGE_DESC; + desc.type = ZE_IMAGE_TYPE_3D; + desc.format.layout = ZE_IMAGE_FORMAT_LAYOUT_8_8_8_8; + desc.format.type = ZE_IMAGE_FORMAT_TYPE_UINT; + desc.width = 11; + desc.height = 13; + desc.depth = 17; + + desc.format.x = ZE_IMAGE_FORMAT_SWIZZLE_A; + desc.format.y = ZE_IMAGE_FORMAT_SWIZZLE_0; + desc.format.z = ZE_IMAGE_FORMAT_SWIZZLE_1; + desc.format.w = ZE_IMAGE_FORMAT_SWIZZLE_X; + + L0::Image *image0Src; + L0::Image *image0Dst; + auto result = Image::create(productFamily, device0, &desc, &image0Src); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + result = Image::create(productFamily, device0, &desc, &image0Dst); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + L0::Image *image1Src; + L0::Image *image1Dst; + result = Image::create(productFamily, device1, &desc, &image1Src); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + result = Image::create(productFamily, device1, &desc, &image1Dst); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + device0->getNEODevice()->getRootDeviceEnvironment().getMutableHardwareInfo()->capabilityTable.blitterOperationsSupported = true; + const ze_command_queue_desc_t queueDesc = {}; + ze_result_t returnValue; + std::unique_ptr commandList0(CommandList::createImmediate(productFamily, + device0, + &queueDesc, + false, + NEO::EngineGroupType::Copy, + returnValue)); + ASSERT_NE(nullptr, commandList0); + + result = commandList0->appendImageCopy(image0Dst->toHandle(), image1Src->toHandle(), nullptr, 0, nullptr, false); + EXPECT_NE(ZE_RESULT_SUCCESS, result); + result = commandList0->appendImageCopy(image1Dst->toHandle(), image0Src->toHandle(), nullptr, 0, nullptr, false); + EXPECT_NE(ZE_RESULT_SUCCESS, result); + result = commandList0->appendImageCopyFromMemory(image1Dst->toHandle(), srcPtr, nullptr, nullptr, 0, nullptr, false); + EXPECT_NE(ZE_RESULT_SUCCESS, result); + result = commandList0->appendImageCopyToMemory(dstPtr, image1Src->toHandle(), nullptr, nullptr, 0, nullptr, false); + EXPECT_NE(ZE_RESULT_SUCCESS, result); + + result = image0Src->destroy(); + ASSERT_EQ(result, ZE_RESULT_SUCCESS); + result = image0Dst->destroy(); + ASSERT_EQ(result, ZE_RESULT_SUCCESS); + + result = image1Src->destroy(); + ASSERT_EQ(result, ZE_RESULT_SUCCESS); + result = image1Dst->destroy(); + ASSERT_EQ(result, ZE_RESULT_SUCCESS); +} + +HWTEST2_F(MultipleDevicePeerImageTest, + givenPeekInternalHandleFailsThenGetPeerImageReturnsNullptr, + ImageSupport) { + MockSharedHandleMemoryManager *fixtureMemoryManager = static_cast(deviceFactoryMemoryManager); + fixtureMemoryManager->failPeekInternalHandle = true; + + L0::Device *device0 = driverHandle->devices[0]; + L0::Device *device1 = driverHandle->devices[1]; + + ze_image_desc_t desc = {}; + desc.stype = ZE_STRUCTURE_TYPE_IMAGE_DESC; + desc.type = ZE_IMAGE_TYPE_3D; + desc.format.layout = ZE_IMAGE_FORMAT_LAYOUT_8_8_8_8; + desc.format.type = ZE_IMAGE_FORMAT_TYPE_UINT; + desc.width = 11; + desc.height = 13; + desc.depth = 17; + + desc.format.x = ZE_IMAGE_FORMAT_SWIZZLE_A; + desc.format.y = ZE_IMAGE_FORMAT_SWIZZLE_0; + desc.format.z = ZE_IMAGE_FORMAT_SWIZZLE_1; + desc.format.w = ZE_IMAGE_FORMAT_SWIZZLE_X; + + L0::Image *image; + auto result = Image::create(productFamily, device1, &desc, &image); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + L0::Image *peerImage = nullptr; + result = driverHandle->getPeerImage(device0, image, &peerImage); + EXPECT_NE(result, ZE_RESULT_SUCCESS); + EXPECT_EQ(peerImage, nullptr); + + result = image->destroy(); + ASSERT_EQ(result, ZE_RESULT_SUCCESS); +} + } // namespace ult } // namespace L0