From: Maaz Mombasawala Add execution buffer related tests in vmwgfx, includes execution buffer submit and syncs, mob creation and execution buffer stress test. Signed-off-by: Zack Rusin Signed-off-by: Maaz Mombasawala Reviewed-by: Martin Krastev --- tests/vmwgfx/meson.build | 3 +- tests/vmwgfx/vmw_execution_buffer.c | 313 ++++++++++++++++++++++++++++ 2 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 tests/vmwgfx/vmw_execution_buffer.c diff --git a/tests/vmwgfx/meson.build b/tests/vmwgfx/meson.build index e2e5a86b..ce2969db 100644 --- a/tests/vmwgfx/meson.build +++ b/tests/vmwgfx/meson.build @@ -1,6 +1,7 @@ vmwgfx_progs = [ - 'vmw_tri' + 'vmw_tri', + 'vmw_execution_buffer' ] vmwgfx_deps = test_deps diff --git a/tests/vmwgfx/vmw_execution_buffer.c b/tests/vmwgfx/vmw_execution_buffer.c new file mode 100644 index 00000000..42322514 --- /dev/null +++ b/tests/vmwgfx/vmw_execution_buffer.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/********************************************************** + * Copyright 2021-2022 VMware, Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + **********************************************************/ + +#include "igt_vmwgfx.h" + +#include + +struct { + bool stress_test; +} options; + +static struct option long_options[] = { + { "stress-test", 0, 0, 's' }, + { NULL, 0, 0, 0 }, +}; + +IGT_TEST_DESCRIPTION("Test basic command buffer processing."); + +static int parse_options(int opt, int opt_index, void *data) +{ + switch (opt) { + case 's': + options.stress_test = 1; + igt_info("stress-test mode\n"); + break; + default: + return IGT_OPT_HANDLER_ERROR; + } + return IGT_OPT_HANDLER_SUCCESS; +} + +static void check_mob_create_map(int fd) +{ + struct vmw_mob *mob_obj; + uint32 size = 4096; + + /* create a new mob */ + mob_obj = vmw_ioctl_mob_create(fd, size); + /* takes the created mob and maps it */ + vmw_ioctl_mob_map(fd, mob_obj); + /* test that mapping is successful */ + igt_assert_neq(mob_obj->map_count, 0); + + vmw_ioctl_mob_unmap(mob_obj); + vmw_ioctl_mob_close_handle(fd, mob_obj); +} + +static void check_buffer_create(int fd) +{ + struct vmw_surface *buffer_obj; + struct vmw_mob *mob_obj; + uint32 size = 4096; + + mob_obj = vmw_ioctl_mob_create(fd, size); + /* creates a buffer from mob */ + buffer_obj = vmw_ioctl_buffer_create(fd, 0, size, mob_obj); + /* checks that the buffer is allocated */ + igt_assert_eq(buffer_obj->base.backup_size, size); + + vmw_ioctl_surface_unref(fd, buffer_obj); + vmw_ioctl_mob_close_handle(fd, mob_obj); +} + +static void check_execbuf_submit_fence(int fd, int32 cid) +{ + struct vmw_execbuf *command_buffer; + struct drm_vmw_fence_rep cmd_fence = { 0 }; + const uint32 buffer_size = 128; + + struct vmw_mob *mob; + struct vmw_surface *src_buffer; + struct vmw_surface *dst_buffer1, *dst_buffer2, *dst_buffer3; + + uint32_t total_size = 0; + SVGA3dCmdDXBufferCopy copyCmd = { 0 }; + uint32_t total_cmd_len = sizeof(SVGA3dCmdHeader) + sizeof(copyCmd); + + SVGA3dCmdReadbackGBSurface cmd; + struct vmw_mob fake_mob = { 0 }; + char *readback; + + char *data; + int i; + + mob = vmw_ioctl_mob_create(fd, buffer_size); + + data = vmw_ioctl_mob_map(fd, mob); + for (i = 0; i < buffer_size; ++i) + data[i] = i; + vmw_ioctl_mob_unmap(mob); + + src_buffer = vmw_ioctl_buffer_create( + fd, SVGA3D_SURFACE_BIND_SHADER_RESOURCE, buffer_size, mob); + dst_buffer1 = vmw_ioctl_buffer_create( + fd, SVGA3D_SURFACE_BIND_SHADER_RESOURCE, buffer_size, NULL); + dst_buffer2 = vmw_ioctl_buffer_create( + fd, SVGA3D_SURFACE_BIND_SHADER_RESOURCE, buffer_size, NULL); + dst_buffer3 = vmw_ioctl_buffer_create( + fd, SVGA3D_SURFACE_BIND_SHADER_RESOURCE, buffer_size, NULL); + /* Create command buffer */ + command_buffer = vmw_execbuf_create(fd, cid); + igt_assert(command_buffer != NULL); + + copyCmd.src = src_buffer->base.handle; + copyCmd.dest = dst_buffer1->base.handle; + copyCmd.width = buffer_size; + copyCmd.srcX = 0; + copyCmd.destX = 0; + vmw_execbuf_append(command_buffer, SVGA_3D_CMD_DX_BUFFER_COPY, ©Cmd, + sizeof(copyCmd), NULL, 0); + total_size += total_cmd_len; + igt_assert_eq(command_buffer->offset, total_size); + igt_assert(command_buffer->offset < command_buffer->buffer_size); + + for (i = 0; i < 4096; ++i) { + copyCmd.src = dst_buffer1->base.handle; + copyCmd.dest = dst_buffer2->base.handle; + vmw_execbuf_append(command_buffer, SVGA_3D_CMD_DX_BUFFER_COPY, + ©Cmd, sizeof(copyCmd), NULL, 0); + total_size += total_cmd_len; + } + + copyCmd.src = dst_buffer2->base.handle; + copyCmd.dest = dst_buffer3->base.handle; + vmw_execbuf_append(command_buffer, SVGA_3D_CMD_DX_BUFFER_COPY, ©Cmd, + sizeof(copyCmd), NULL, 0); + total_size += total_cmd_len; + + igt_assert_eq(command_buffer->offset, total_size); + igt_assert(command_buffer->offset < command_buffer->buffer_size); + + vmw_execbuf_submit(command_buffer, &cmd_fence); + vmw_ioctl_fence_finish(fd, &cmd_fence); + + cmd.sid = dst_buffer1->base.handle; + vmw_execbuf_append(command_buffer, SVGA_3D_CMD_READBACK_GB_SURFACE, + &cmd, sizeof(cmd), NULL, 0); + vmw_execbuf_submit(command_buffer, &cmd_fence); + vmw_ioctl_fence_finish(fd, &cmd_fence); + + fake_mob.size = dst_buffer1->base.buffer_size; + fake_mob.handle = dst_buffer1->base.buffer_handle; + fake_mob.map_handle = dst_buffer1->base.buffer_map_handle; + readback = vmw_ioctl_mob_map(fd, &fake_mob); + for (i = 0; i < buffer_size; i++) { + int val = readback[i]; + + igt_assert_eq(i, val); + } + vmw_ioctl_mob_unmap(&fake_mob); + + vmw_ioctl_surface_unref(fd, src_buffer); + vmw_ioctl_surface_unref(fd, dst_buffer1); + vmw_ioctl_surface_unref(fd, dst_buffer2); + vmw_ioctl_surface_unref(fd, dst_buffer3); + vmw_execbuf_destroy(command_buffer); + vmw_ioctl_mob_close_handle(fd, mob); +} + +static int32 vmw_ioctl_command2(int drm_fd, int32_t cid, void *commands, + uint32_t size, struct drm_vmw_fence_rep *fence) +{ + struct drm_vmw_execbuf_arg arg = { 0 }; + int ret; + const int argsize = sizeof(arg); + + memset(&arg, 0, sizeof(arg)); + + arg.fence_rep = (unsigned long)fence; + arg.commands = (unsigned long)commands; + arg.command_size = size; + arg.throttle_us = 0; /* deprecated */ + arg.version = DRM_VMW_EXECBUF_VERSION; + arg.context_handle = cid; + + do { + ret = drmCommandWrite(drm_fd, DRM_VMW_EXECBUF, &arg, argsize); + if (ret == -EBUSY) + usleep(1000); + } while (ret == -ERESTART || ret == -EBUSY); + if (ret) + return 1; + return 0; +} + +static _Atomic(int32_t) context_id; +static const uint32_t max_tries = 100000; + +static void *create_contexts(void *data) +{ + int fd = (uintptr_t)data; + uint32_t i; + + for (i = 0; i < max_tries; ++i) { + int32_t cid = vmw_ioctl_context_create(fd); + + atomic_store(&context_id, cid); + + vmw_ioctl_context_destroy(fd, cid); + } + return 0; +} + +static void *submit_queries(void *data) +{ + int fd = (uintptr_t)data; + uint32_t i; + + for (i = 0; i < max_tries; ++i) { + struct vmw_execbuf *cmd_buf; + SVGA3dCmdDXDefineQuery cmd = { + .queryId = 0, + .type = SVGA3D_QUERYTYPE_TIMESTAMP, + .flags = 0, + }; + int32_t cid = atomic_load(&context_id); + + cmd_buf = vmw_execbuf_create(fd, cid); + + vmw_execbuf_append(cmd_buf, SVGA_3D_CMD_DX_DEFINE_QUERY, &cmd, + sizeof(cmd), NULL, 0); + + vmw_ioctl_command2(fd, cid, cmd_buf->buffer, cmd_buf->offset, + NULL); + cmd_buf->offset = 0; + vmw_execbuf_destroy(cmd_buf); + } + return 0; +} + +static void execbuf_stress_test(int fd) +{ + pthread_t threads[2]; + void *status; + int ret; + + ret = pthread_create(&threads[0], NULL, create_contexts, + (void *)(uintptr_t)fd); + igt_assert_eq(ret, 0); + ret = pthread_create(&threads[1], NULL, submit_queries, + (void *)(uintptr_t)fd); + igt_assert_eq(ret, 0); + + pthread_join(threads[0], &status); + pthread_join(threads[1], &status); +} + +igt_main_args("st:", long_options, NULL, parse_options, NULL) +{ + int fd; + int32 cid; + + igt_fixture + { + fd = drm_open_driver_render(DRIVER_VMWGFX); + cid = vmw_ioctl_context_create(fd); + } + + igt_describe("Test creation/mapping of a basic mob."); + igt_subtest("mob-create-map") + { + check_mob_create_map(fd); + } + + igt_describe("Test creation of a buffer surface from mob."); + igt_subtest("buffer-create") + { + check_buffer_create(fd); + } + + igt_describe("Test basic fencing on command buffers."); + igt_subtest("execution-buffer-submit-sync") + { + check_execbuf_submit_fence(fd, cid); + } + + if (options.stress_test) { + igt_describe("Stress test synching cmd-buffers between threads."); + igt_subtest("execution-buffer-stress-test") + { + execbuf_stress_test(fd); + } + } + + igt_fixture + { + vmw_ioctl_context_destroy(fd, cid); + close(fd); + } +} -- 2.39.2