diff --git a/CMakeLists.txt b/CMakeLists.txt index 686243d1..7264d983 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ include(CMakeDependentOption) option(OPENCL_SDK_BUILD_UTILITY_LIBRARIES "Build utility libraries" ON) cmake_dependent_option(OPENCL_SDK_BUILD_SAMPLES "Build sample code" ON OPENCL_SDK_BUILD_UTILITY_LIBRARIES OFF) cmake_dependent_option(OPENCL_SDK_BUILD_OPENGL_SAMPLES "Build OpenCL-OpenGL interop sample code" ON OPENCL_SDK_BUILD_SAMPLES OFF) +cmake_dependent_option(OPENCL_SDK_BUILD_VULKAN_SAMPLES "Build OpenCL-Vulkan interop sample code" ON OPENCL_SDK_BUILD_SAMPLES OFF) cmake_dependent_option(OPENCL_SDK_TEST_SAMPLES "Add CTest to samples (where applicable)" ON OPENCL_SDK_BUILD_SAMPLES OFF) option(OPENCL_SDK_BUILD_CLINFO "Build clinfo utility" ON) diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index 24383896..06145cb8 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -41,7 +41,7 @@ set(BUILD_SHARED_LIBS OFF CACHE BOOL "Global flag to cause add_library() to crea # Fetch dependencies if(OPENCL_SDK_BUILD_SAMPLES) - foreach(DEP IN ITEMS cargs TCLAP Stb Vulkan) + foreach(DEP IN ITEMS cargs TCLAP Stb) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/Dependencies/${DEP}") include(${DEP}) endforeach() @@ -52,6 +52,11 @@ if(OPENCL_SDK_BUILD_SAMPLES) include(${DEP}) endforeach() endif(OPENCL_SDK_BUILD_OPENGL_SAMPLES) + + if(OPENCL_SDK_BUILD_VULKAN_SAMPLES) + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/Dependencies/Vulkan") + include(Vulkan) + endif(OPENCL_SDK_BUILD_VULKAN_SAMPLES) endif(OPENCL_SDK_BUILD_SAMPLES) if(OPENCL_SDK_BUILD_CLINFO) diff --git a/samples/extensions/khr/CMakeLists.txt b/samples/extensions/khr/CMakeLists.txt index 4bf194d7..efc6d747 100644 --- a/samples/extensions/khr/CMakeLists.txt +++ b/samples/extensions/khr/CMakeLists.txt @@ -12,9 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_subdirectory(externalmemory) add_subdirectory(histogram) if(OPENCL_SDK_BUILD_OPENGL_SAMPLES) add_subdirectory(conway) add_subdirectory(nbody) endif() +if(OPENCL_SDK_BUILD_VULKAN_SAMPLES) + add_subdirectory(externalmemory) +endif() diff --git a/samples/extensions/khr/externalmemory/main.c b/samples/extensions/khr/externalmemory/main.c index c49ff2c6..b7698fc6 100644 --- a/samples/extensions/khr/externalmemory/main.c +++ b/samples/extensions/khr/externalmemory/main.c @@ -430,7 +430,6 @@ int main(int argc, char* argv[]) buffer_info.size = sizeof(cl_float) * length; buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - ; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VkBuffer vk_buf_x, vk_buf_y; @@ -485,6 +484,35 @@ int main(int argc, char* argv[]) memcpy(vk_arr_x, arr_x, sizeof(cl_float) * length); memcpy(vk_arr_y, arr_y, sizeof(cl_float) * length); +#ifdef _WIN32 + // Get Vulkan external memory file descriptors for accessing external memory + // with OpenCL. + VkMemoryGetWin32HandleInfoKHR handle_info_x = { 0 }; + handle_info_x.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + handle_info_x.pNext = NULL; + handle_info_x.memory = vk_buf_x_memory; + handle_info_x.handleType = vk_external_memory_handle_type; + HANDLE handle_x; + + VkMemoryGetWin32HandleInfoKHR handle_info_y = { 0 }; + handle_info_y.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + handle_info_y.pNext = NULL; + handle_info_y.memory = vk_buf_y_memory; + handle_info_y.handleType = vk_external_memory_handle_type; + HANDLE handle_y; + + // We need to get the pointer to the + // vkGetMemoryFdKHR/vkGetMemoryWin32HandleKHR function because it's from + // extension VK_KHR_external_memory_fd. This Vulkan function exports a POSIX + // file descriptor/Windows handle referencing the payload of a Vulkan device + // memory object. + PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32Handle; + *(PFN_vkGetMemoryWin32HandleKHR*)&vkGetMemoryWin32Handle = + (PFN_vkGetMemoryWin32HandleKHR)vkGetDeviceProcAddr( + vk_device, "vkGetMemoryWin32HandleKHR"); + VK_CHECK(vkGetMemoryWin32Handle(vk_device, &handle_info_x, &handle_x)); + VK_CHECK(vkGetMemoryWin32Handle(vk_device, &handle_info_y, &handle_y)); +#else // Get Vulkan external memory file descriptors for accessing external memory // with OpenCL. VkMemoryGetFdInfoKHR fd_info_x = { 0 }; @@ -501,19 +529,28 @@ int main(int argc, char* argv[]) fd_info_y.handleType = vk_external_memory_handle_type; int fd_y; - // We need to get the pointer to the vkGetMemoryFdKHR function because it's - // from extension VK_KHR_external_memory_fd. - PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR = + // We need to get the pointer to the + // vkGetMemoryFdKHR/vkGetMemoryWin32HandleKHR function because it's from + // extension VK_KHR_external_memory_fd. This Vulkan function exports a POSIX + // file descriptor/Windows handle referencing the payload of a Vulkan device + // memory object. + PFN_vkGetMemoryFdKHR vkGetMemoryFd; + *(PFN_vkGetMemoryFdKHR*)&vkGetMemoryFd = (PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr(vk_device, "vkGetMemoryFdKHR"); + VK_CHECK(vkGetMemoryFd(vk_device, &fd_info_x, &fd_x)); + VK_CHECK(vkGetMemoryFd(vk_device, &fd_info_y, &fd_y)); +#endif - VK_CHECK(vkGetMemoryFdKHR(vk_device, &fd_info_x, &fd_x)); - VK_CHECK(vkGetMemoryFdKHR(vk_device, &fd_info_y, &fd_y)); // Create OpenCL buffers from Vulkan external memory file descriptors. cl_mem_properties ext_mem_props_x[] = { (cl_mem_properties)CL_EXTERNAL_MEMORY_HANDLE_OPAQUE_FD_KHR, +#ifdef _WIN32 + (cl_mem_properties)handle_x, +#else (cl_mem_properties)fd_x, +#endif (cl_mem_properties)CL_DEVICE_HANDLE_LIST_KHR, (cl_mem_properties)(uintptr_t)cl_device, CL_DEVICE_HANDLE_LIST_END_KHR, @@ -521,7 +558,11 @@ int main(int argc, char* argv[]) }; cl_mem_properties ext_mem_props_y[] = { (cl_mem_properties)CL_EXTERNAL_MEMORY_HANDLE_OPAQUE_FD_KHR, +#ifdef _WIN32 + (cl_mem_properties)handle_y, +#else (cl_mem_properties)fd_y, +#endif (cl_mem_properties)CL_DEVICE_HANDLE_LIST_KHR, (cl_mem_properties)(uintptr_t)cl_device, CL_DEVICE_HANDLE_LIST_END_KHR, @@ -552,6 +593,16 @@ int main(int argc, char* argv[]) OCLERROR_RET(clSetKernelArg(saxpy, 2, sizeof(cl_mem), &cl_buf_y), error, clbufy); + // Acquire OpenCL memory objects created from Vulkan external memory + // handles. + cl_mem cl_mem_objects[] = { cl_buf_x, cl_buf_y }; + clEnqueueAcquireExternalMemObjectsKHR_fn + clEnqueueAcquireExternalMemObjects = + (clEnqueueAcquireExternalMemObjectsKHR_fn) + clGetExtensionFunctionAddressForPlatform( + cl_platform, "clEnqueueAcquireExternalMemObjectsKHR"); + clEnqueueAcquireExternalMemObjects(queue, 2, cl_mem_objects, 0, NULL, NULL); + // Launch kernel. if (diag_opts.verbose) { @@ -570,6 +621,15 @@ int main(int argc, char* argv[]) cl_ulong dev_time; TIMER_DIFFERENCE(dev_time, dev_start, dev_end) + // Release OpenCL memory objects created from Vulkan external memory + // handles. + clEnqueueReleaseExternalMemObjectsKHR_fn + clEnqueueReleaseExternalMemObjects = + (clEnqueueReleaseExternalMemObjectsKHR_fn) + clGetExtensionFunctionAddressForPlatform( + cl_platform, "clEnqueueReleaseExternalMemObjectsKHR"); + clEnqueueReleaseExternalMemObjects(queue, 2, cl_mem_objects, 0, NULL, NULL); + // Concurrently calculate reference saxpy. if (diag_opts.verbose) { diff --git a/samples/extensions/khr/externalmemory/main.cpp b/samples/extensions/khr/externalmemory/main.cpp index e4026c23..c82d8994 100644 --- a/samples/extensions/khr/externalmemory/main.cpp +++ b/samples/extensions/khr/externalmemory/main.cpp @@ -349,7 +349,6 @@ int main(int argc, char* argv[]) buffer_info.size = sizeof(cl_float) * length; buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - ; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VkBuffer vk_buf_x, vk_buf_y; @@ -404,6 +403,37 @@ int main(int argc, char* argv[]) memcpy(vk_arr_x, arr_x.data(), sizeof(cl_float) * length); memcpy(vk_arr_y, arr_y.data(), sizeof(cl_float) * length); +#ifdef _WIN32 + // Get Vulkan external memory file descriptors for accessing external + // memory with OpenCL. + VkMemoryGetWin32HandleInfoKHR handle_info_x{}; + handle_info_x.sType = + VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + handle_info_x.pNext = nullptr; + handle_info_x.memory = vk_buf_x_memory; + handle_info_x.handleType = vk_external_memory_handle_type; + HANDLE handle_x; + + VkMemoryGetWin32HandleInfoKHR handle_info_y{}; + handle_info_y.sType = + VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + handle_info_y.pNext = nullptr; + handle_info_y.memory = vk_buf_y_memory; + handle_info_y.handleType = vk_external_memory_handle_type; + HANDLE handle_y; + + // We need to get the pointer to the + // vkGetMemoryFdKHR/vkGetMemoryWin32HandleKHR function because it's from + // the extension VK_KHR_external_memory_fd. This Vulkan function exports + // a POSIX file descriptor/Windows handle referencing the payload of a + // Vulkan device memory object. + PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32Handle; + *(PFN_vkGetMemoryWin32HandleKHR*)&vkGetMemoryWin32Handle = + (PFN_vkGetMemoryWin32HandleKHR)vkGetDeviceProcAddr( + vk_device, "vkGetMemoryWin32HandleKHR"); + VK_CHECK(vkGetMemoryWin32Handle(vk_device, &handle_info_x, &handle_x)); + VK_CHECK(vkGetMemoryWin32Handle(vk_device, &handle_info_y, &handle_y)); +#else // Get Vulkan external memory file descriptors for accessing external // memory with OpenCL. VkMemoryGetFdInfoKHR fd_info_x{}; @@ -420,19 +450,27 @@ int main(int argc, char* argv[]) fd_info_y.handleType = vk_external_memory_handle_type; int fd_y; - // We need to get the pointer to the vkGetMemoryFdKHR function because - // it's from extension VK_KHR_external_memory_fd. - PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR = + // We need to get the pointer to the + // vkGetMemoryFdKHR/vkGetMemoryWin32HandleKHR function because it's from + // extension VK_KHR_external_memory_fd. This Vulkan function exports a + // POSIX file descriptor/Windows handle referencing the payload of a + // Vulkan device memory object. + PFN_vkGetMemoryFdKHR vkGetMemoryFd; + *(PFN_vkGetMemoryFdKHR*)&vkGetMemoryFd = (PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr(vk_device, "vkGetMemoryFdKHR"); - - VK_CHECK(vkGetMemoryFdKHR(vk_device, &fd_info_x, &fd_x)); - VK_CHECK(vkGetMemoryFdKHR(vk_device, &fd_info_y, &fd_y)); + VK_CHECK(vkGetMemoryFd(vk_device, &fd_info_x, &fd_x)); + VK_CHECK(vkGetMemoryFd(vk_device, &fd_info_y, &fd_y)); +#endif // Create OpenCL buffers from Vulkan external memory file descriptors. std::vector ext_mem_props_x = { (cl_mem_properties)CL_EXTERNAL_MEMORY_HANDLE_OPAQUE_FD_KHR, +#ifdef _WIN32 + (cl_mem_properties)handle_x, +#else (cl_mem_properties)fd_x, +#endif (cl_mem_properties)CL_DEVICE_HANDLE_LIST_KHR, (cl_mem_properties)cl_device(), CL_DEVICE_HANDLE_LIST_END_KHR, @@ -440,7 +478,11 @@ int main(int argc, char* argv[]) }; std::vector ext_mem_props_y = { (cl_mem_properties)CL_EXTERNAL_MEMORY_HANDLE_OPAQUE_FD_KHR, +#ifdef _WIN32 + (cl_mem_properties)handle_y, +#else (cl_mem_properties)fd_y, +#endif (cl_mem_properties)CL_DEVICE_HANDLE_LIST_KHR, (cl_mem_properties)cl_device(), CL_DEVICE_HANDLE_LIST_END_KHR, @@ -457,6 +499,18 @@ int main(int argc, char* argv[]) 0 }; cl::CommandQueue queue{ cl_context, cl_device, *queue_props }; + // Acquire OpenCL memory objects created from Vulkan external memory + // handles. + std::vector cl_mem_objects = { cl_buf_x(), cl_buf_y() }; + clEnqueueAcquireExternalMemObjectsKHR_fn + clEnqueueAcquireExternalMemObjects = + (clEnqueueAcquireExternalMemObjectsKHR_fn) + clGetExtensionFunctionAddressForPlatform( + cl_platform(), "clEnqueueAcquireExternalMemObjectsKHR"); + clEnqueueAcquireExternalMemObjects( + queue(), static_cast(cl_mem_objects.size()), + cl_mem_objects.data(), 0, nullptr, nullptr); + // Launch kernel. if (diag_opts.verbose) { @@ -472,6 +526,17 @@ int main(int argc, char* argv[]) cl::WaitForEvents(kernel_run); auto dev_end = std::chrono::high_resolution_clock::now(); + // Release OpenCL memory objects created from Vulkan external memory + // handles. + clEnqueueReleaseExternalMemObjectsKHR_fn + clEnqueueReleaseExternalMemObjects = + (clEnqueueReleaseExternalMemObjectsKHR_fn) + clGetExtensionFunctionAddressForPlatform( + cl_platform(), "clEnqueueReleaseExternalMemObjectsKHR"); + clEnqueueReleaseExternalMemObjects( + queue(), static_cast(cl_mem_objects.size()), + cl_mem_objects.data(), 0, nullptr, nullptr); + // Concurrently calculate reference saxpy. if (diag_opts.verbose) { diff --git a/samples/extensions/khr/externalmemory/vulkan_utils.h b/samples/extensions/khr/externalmemory/vulkan_utils.h index 2b718564..130bc45e 100644 --- a/samples/extensions/khr/externalmemory/vulkan_utils.h +++ b/samples/extensions/khr/externalmemory/vulkan_utils.h @@ -224,24 +224,24 @@ find_suitable_device(VkInstance instance, // Query OpenCL devices available. cl_int error = CL_SUCCESS; bool candidate_found = false; - cl_uint cl_platform_count = 0; + cl_uint platform_count = 0; struct device_candidate found_candidate = {0}; - OCLERROR_RET(clGetPlatformIDs(0, NULL, &cl_platform_count), error, ret); + OCLERROR_RET(clGetPlatformIDs(0, NULL, &platform_count), error, ret); cl_platform_id* platforms = - (cl_platform_id*)malloc(cl_platform_count * sizeof(cl_platform_id)); - OCLERROR_RET(clGetPlatformIDs(cl_platform_count, platforms, NULL), error, + (cl_platform_id*)malloc(platform_count * sizeof(cl_platform_id)); + OCLERROR_RET(clGetPlatformIDs(platform_count, platforms, NULL), error, platforms); size_t cl_device_count = 0; const char* uuid_khronos_extension[] = { CL_KHR_DEVICE_UUID_EXTENSION_NAME }; - for (cl_uint cl_platform_id = 0; cl_platform_id < cl_platform_count; - ++cl_platform_id) + for (cl_uint platform_id = 0; platform_id < platform_count; + ++platform_id) { cl_uint cl_platform_devices_count = 0; - OCLERROR_RET(clGetDeviceIDs(platforms[cl_platform_id], + OCLERROR_RET(clGetDeviceIDs(platforms[platform_id], CL_DEVICE_TYPE_ALL, 0, NULL, &cl_platform_devices_count), error, platforms); @@ -250,7 +250,7 @@ find_suitable_device(VkInstance instance, { cl_device_id device; OCLERROR_PAR(device = cl_util_get_device( - cl_platform_id, device_id, CL_DEVICE_TYPE_ALL, &error), error, platforms); + platform_id, device_id, CL_DEVICE_TYPE_ALL, &error), error, platforms); cl_device_count += check_khronos_extensions(device, uuid_khronos_extension, 1); } @@ -264,11 +264,11 @@ find_suitable_device(VkInstance instance, (struct cl_device_candidate*)malloc( cl_device_count * sizeof(struct cl_device_candidate)); cl_device_count = 0; - for (cl_uint cl_platform_id = 0; cl_platform_id < cl_platform_count; - ++cl_platform_id) + for (cl_uint platform_id = 0; platform_id < platform_count; + ++platform_id) { cl_uint cl_platform_devices_count = 0; - OCLERROR_RET(clGetDeviceIDs(platforms[cl_platform_id], + OCLERROR_RET(clGetDeviceIDs(platforms[platform_id], CL_DEVICE_TYPE_ALL, 0, NULL, &cl_platform_devices_count), error, candidates); @@ -278,7 +278,7 @@ find_suitable_device(VkInstance instance, ++cl_candidate_id, ++cl_device_count) { cl_device_id device = cl_util_get_device( - cl_platform_id, cl_candidate_id, CL_DEVICE_TYPE_ALL, &error); + platform_id, cl_candidate_id, CL_DEVICE_TYPE_ALL, &error); if (check_khronos_extensions(device, uuid_khronos_extension, 1)) { cl_uchar vk_candidate_uuid[CL_UUID_SIZE_KHR];