| // SPDX-License-Identifier: MIT |
| /* |
| * Copyright © 2022 Intel Corporation |
| */ |
| |
| #include "igt.h" |
| #include "igt_vgem.h" |
| #include "sw_sync.h" |
| #include "dmabuf_sync_file.h" |
| |
| IGT_TEST_DESCRIPTION("Tests for sync_file support in dma-buf"); |
| |
| /** |
| * TEST: dmabuf_sync_file |
| * Category: Core |
| * Mega feature: General Core features |
| * Sub-category: dmabuf |
| * Description: Tests for sync_file support in dma-buf |
| * Functionality: dmabuf test |
| * |
| * SUBTEST: export-basic |
| * SUBTEST: export-before-signal |
| * SUBTEST: export-multiwait |
| * SUBTEST: export-wait-after-attach |
| * SUBTEST: import-basic |
| * SUBTEST: import-multiple-read-only |
| * SUBTEST: import-multiple-read-write |
| * |
| */ |
| |
| static void test_export_basic(int fd) |
| { |
| struct vgem_bo bo; |
| int dmabuf; |
| uint32_t fence; |
| |
| igt_require(has_dmabuf_export_sync_file(fd)); |
| |
| bo.width = 1; |
| bo.height = 1; |
| bo.bpp = 32; |
| vgem_create(fd, &bo); |
| |
| dmabuf = prime_handle_to_fd(fd, bo.handle); |
| |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| |
| fence = vgem_fence_attach(fd, &bo, 0); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| |
| vgem_fence_signal(fd, fence); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| |
| fence = vgem_fence_attach(fd, &bo, VGEM_FENCE_WRITE); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| |
| vgem_fence_signal(fd, fence); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| |
| close(dmabuf); |
| gem_close(fd, bo.handle); |
| } |
| |
| static void test_export_before_signal(int fd) |
| { |
| struct vgem_bo bo; |
| int dmabuf, read_fd, write_fd; |
| uint32_t fence; |
| |
| igt_require(has_dmabuf_export_sync_file(fd)); |
| |
| bo.width = 1; |
| bo.height = 1; |
| bo.bpp = 32; |
| vgem_create(fd, &bo); |
| |
| dmabuf = prime_handle_to_fd(fd, bo.handle); |
| |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| |
| fence = vgem_fence_attach(fd, &bo, 0); |
| |
| read_fd = dmabuf_export_sync_file(dmabuf, DMA_BUF_SYNC_READ); |
| write_fd = dmabuf_export_sync_file(dmabuf, DMA_BUF_SYNC_WRITE); |
| |
| igt_assert(!sync_file_busy(read_fd)); |
| igt_assert(sync_file_busy(write_fd)); |
| |
| vgem_fence_signal(fd, fence); |
| |
| igt_assert(!sync_file_busy(read_fd)); |
| igt_assert(!sync_file_busy(write_fd)); |
| |
| close(read_fd); |
| close(write_fd); |
| |
| fence = vgem_fence_attach(fd, &bo, VGEM_FENCE_WRITE); |
| |
| read_fd = dmabuf_export_sync_file(dmabuf, DMA_BUF_SYNC_READ); |
| write_fd = dmabuf_export_sync_file(dmabuf, DMA_BUF_SYNC_WRITE); |
| |
| igt_assert(sync_file_busy(read_fd)); |
| igt_assert(sync_file_busy(write_fd)); |
| |
| vgem_fence_signal(fd, fence); |
| |
| igt_assert(!sync_file_busy(read_fd)); |
| igt_assert(!sync_file_busy(write_fd)); |
| |
| close(read_fd); |
| close(write_fd); |
| |
| close(dmabuf); |
| gem_close(fd, bo.handle); |
| } |
| |
| static void test_export_multiwait(int fd) |
| { |
| struct vgem_bo bo; |
| int dmabuf, sync_file; |
| uint32_t fence1, fence2, fence3; |
| |
| igt_require(has_dmabuf_export_sync_file(fd)); |
| |
| bo.width = 1; |
| bo.height = 1; |
| bo.bpp = 32; |
| vgem_create(fd, &bo); |
| |
| dmabuf = prime_handle_to_fd(fd, bo.handle); |
| |
| fence1 = vgem_fence_attach(fd, &bo, 0); |
| fence2 = vgem_fence_attach(fd, &bo, 0); |
| |
| sync_file = dmabuf_export_sync_file(dmabuf, DMA_BUF_SYNC_WRITE); |
| |
| fence3 = vgem_fence_attach(fd, &bo, 0); |
| |
| igt_assert(sync_file_busy(sync_file)); |
| |
| vgem_fence_signal(fd, fence1); |
| |
| igt_assert(sync_file_busy(sync_file)); |
| |
| vgem_fence_signal(fd, fence2); |
| |
| igt_assert(!sync_file_busy(sync_file)); |
| |
| vgem_fence_signal(fd, fence3); |
| |
| close(sync_file); |
| close(dmabuf); |
| gem_close(fd, bo.handle); |
| } |
| |
| static void test_export_wait_after_attach(int fd) |
| { |
| struct vgem_bo bo; |
| int dmabuf, read_sync_file, write_sync_file; |
| uint32_t fence1, fence2; |
| |
| igt_require(has_dmabuf_export_sync_file(fd)); |
| |
| bo.width = 1; |
| bo.height = 1; |
| bo.bpp = 32; |
| vgem_create(fd, &bo); |
| |
| dmabuf = prime_handle_to_fd(fd, bo.handle); |
| |
| read_sync_file = dmabuf_export_sync_file(dmabuf, DMA_BUF_SYNC_READ); |
| write_sync_file = dmabuf_export_sync_file(dmabuf, DMA_BUF_SYNC_WRITE); |
| |
| fence1 = vgem_fence_attach(fd, &bo, VGEM_FENCE_WRITE); |
| |
| igt_assert(!sync_file_busy(read_sync_file)); |
| igt_assert(!sync_file_busy(write_sync_file)); |
| close(read_sync_file); |
| close(write_sync_file); |
| |
| /* These wait on fence1 */ |
| read_sync_file = dmabuf_export_sync_file(dmabuf, DMA_BUF_SYNC_READ); |
| write_sync_file = dmabuf_export_sync_file(dmabuf, DMA_BUF_SYNC_WRITE); |
| |
| igt_assert(sync_file_busy(read_sync_file)); |
| igt_assert(sync_file_busy(write_sync_file)); |
| |
| vgem_fence_signal(fd, fence1); |
| fence2 = vgem_fence_attach(fd, &bo, VGEM_FENCE_WRITE); |
| |
| /* fence1 has signaled */ |
| igt_assert(!sync_file_busy(read_sync_file)); |
| igt_assert(!sync_file_busy(write_sync_file)); |
| |
| /* fence2 has not */ |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| |
| vgem_fence_signal(fd, fence2); |
| close(read_sync_file); |
| close(write_sync_file); |
| |
| close(dmabuf); |
| gem_close(fd, bo.handle); |
| } |
| |
| static void test_import_basic(int fd) |
| { |
| struct vgem_bo bo; |
| int dmabuf, timeline; |
| |
| igt_require_sw_sync(); |
| igt_require(has_dmabuf_import_sync_file(fd)); |
| |
| bo.width = 1; |
| bo.height = 1; |
| bo.bpp = 32; |
| vgem_create(fd, &bo); |
| |
| dmabuf = prime_handle_to_fd(fd, bo.handle); |
| |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| |
| timeline = sw_sync_timeline_create(); |
| |
| dmabuf_import_timeline_fence(dmabuf, DMA_BUF_SYNC_READ, timeline, 1); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| |
| sw_sync_timeline_inc(timeline, 1); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| |
| dmabuf_import_timeline_fence(dmabuf, DMA_BUF_SYNC_WRITE, timeline, 2); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| |
| sw_sync_timeline_inc(timeline, 1); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| |
| dmabuf_import_timeline_fence(dmabuf, DMA_BUF_SYNC_RW, timeline, 3); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| |
| sw_sync_timeline_inc(timeline, 1); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!dmabuf_sync_file_busy(dmabuf, DMA_BUF_SYNC_RW)); |
| } |
| |
| static void test_import_multiple(int fd, bool write) |
| { |
| struct vgem_bo bo; |
| int i, dmabuf, read_sync_file, write_sync_file; |
| int write_timeline = -1, read_timelines[32]; |
| |
| igt_require_sw_sync(); |
| igt_require(has_dmabuf_import_sync_file(fd)); |
| |
| bo.width = 1; |
| bo.height = 1; |
| bo.bpp = 32; |
| vgem_create(fd, &bo); |
| |
| dmabuf = prime_handle_to_fd(fd, bo.handle); |
| |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| |
| for (i = 0; i < ARRAY_SIZE(read_timelines); i++) { |
| read_timelines[i] = sw_sync_timeline_create(); |
| dmabuf_import_timeline_fence(dmabuf, DMA_BUF_SYNC_READ, |
| read_timelines[i], 1); |
| } |
| |
| if (write) { |
| write_timeline = sw_sync_timeline_create(); |
| dmabuf_import_timeline_fence(dmabuf, DMA_BUF_SYNC_WRITE, |
| write_timeline, 1); |
| } |
| |
| read_sync_file = dmabuf_export_sync_file(dmabuf, DMA_BUF_SYNC_READ); |
| write_sync_file = dmabuf_export_sync_file(dmabuf, DMA_BUF_SYNC_WRITE); |
| |
| for (i = ARRAY_SIZE(read_timelines) - 1; i >= 0; i--) { |
| igt_assert_eq(dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ), write); |
| igt_assert_eq(sync_file_busy(read_sync_file), write); |
| igt_assert(dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(sync_file_busy(write_sync_file)); |
| |
| sw_sync_timeline_inc(read_timelines[i], 1); |
| } |
| |
| igt_assert_eq(dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ), write); |
| igt_assert_eq(sync_file_busy(read_sync_file), write); |
| igt_assert_eq(dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE), write); |
| igt_assert_eq(sync_file_busy(write_sync_file), write); |
| |
| if (write) |
| sw_sync_timeline_inc(write_timeline, 1); |
| |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_READ)); |
| igt_assert(!sync_file_busy(read_sync_file)); |
| igt_assert(!dmabuf_busy(dmabuf, DMA_BUF_SYNC_WRITE)); |
| igt_assert(!sync_file_busy(write_sync_file)); |
| } |
| |
| igt_main |
| { |
| int fd; |
| |
| igt_fixture { |
| fd = drm_open_driver(DRIVER_VGEM); |
| } |
| |
| igt_describe("Sanity test for exporting a sync_file from a dma-buf."); |
| igt_subtest("export-basic") |
| test_export_basic(fd); |
| |
| igt_describe("Test exporting a sync_file from a dma-buf before " |
| "signaling any of its fences."); |
| igt_subtest("export-before-signal") |
| test_export_before_signal(fd); |
| |
| igt_describe("Test exporting a sync_file from a dma-buf with multiple " |
| "fences on it."); |
| igt_subtest("export-multiwait") |
| test_export_multiwait(fd); |
| |
| igt_describe("Test exporting a sync_file from a dma-buf then adding " |
| "fences to the dma-buf before we wait. The sync_file " |
| "should snapshot the current set of fences and not wait " |
| "for any fences added after it was exported."); |
| igt_subtest("export-wait-after-attach") |
| test_export_wait_after_attach(fd); |
| |
| igt_describe("Sanity test for importing a sync_file into a dma-buf."); |
| igt_subtest("import-basic") |
| test_import_basic(fd); |
| |
| igt_describe("Test importing multiple read-only fences into a dma-buf. " |
| "They should all block any write operations but not other " |
| "read operations."); |
| igt_subtest("import-multiple-read-only") |
| test_import_multiple(fd, false); |
| |
| igt_describe("Test importing multiple read-write fences into a " |
| "dma-buf. They should all block any read or write " |
| "operations."); |
| igt_subtest("import-multiple-read-write") |
| test_import_multiple(fd, true); |
| |
| igt_fixture |
| drm_close_driver(fd); |
| } |