@@ -1833,6 +1833,10 @@ UR_APIEXPORT ur_result_t UR_APICALL urMemBufferCreateWithNativeHandle(
18331833 UR_CALL (
18341834 Buffer->getZeHandle (ZeHandleDst, ur_mem_handle_t_::write_only, Device));
18351835
1836+ // Indicate that this buffer has the device buffer mapped to a native buffer
1837+ // and track the native pointer such that the memory is synced later at
1838+ // memory free.
1839+ Buffer->DeviceMappedHostNativePtr = Ptr;
18361840 // zeCommandListAppendMemoryCopy must not be called from simultaneous
18371841 // threads with the same command list handle, so we need exclusive lock.
18381842 std::scoped_lock<ur_mutex> Lock (Context->ImmediateCommandListMutex );
@@ -2169,6 +2173,17 @@ ur_result_t _ur_buffer::free() {
21692173 ? Plt->ContextsMutex
21702174 : UrContext->Mutex );
21712175
2176+ // If this memory was allocated as a proxy device buffer, then we must
2177+ // copy the final memory contents back to the original native pointer
2178+ // before releasing the buffer memory.
2179+ if (DeviceMappedHostNativePtr != nullptr ) {
2180+ // zeCommandListAppendMemoryCopy must not be called from simultaneous
2181+ // threads with the same command list handle, so we need exclusive lock.
2182+ std::scoped_lock<ur_mutex> Lock (UrContext->ImmediateCommandListMutex );
2183+ ZE2UR_CALL (zeCommandListAppendMemoryCopy,
2184+ (UrContext->ZeCommandListInit , DeviceMappedHostNativePtr,
2185+ ZeHandle, Size, nullptr , 0 , nullptr ));
2186+ }
21722187 UR_CALL (USMFreeHelper (reinterpret_cast <ur_context_handle_t >(UrContext),
21732188 ZeHandle));
21742189 break ;
0 commit comments