// SPDX-License-Identifier: MIT // Copyright 2023 Advanced Micro Devices, Inc. // Copyright 2017 Advanced Micro Devices, Inc. #include "lib/amdgpu/amd_mmd_shared.h" static bool is_uvd_enc_enable(amdgpu_device_handle device_handle) { int r; struct drm_amdgpu_info_hw_ip info = {}; r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_UVD_ENC, 0, &info); if (!info.available_rings) igt_info("\n\nThe ASIC NOT support UVD ENC, test skipped\n"); return (r == 0 && (info.available_rings ? true : false)); } static void amdgpu_uvd_enc_create(amdgpu_device_handle device_handle, struct uvd_enc_context *context) { context->enc.width = 160; context->enc.height = 128; context->uvd.num_resources = 0; alloc_resource(device_handle, &context->enc.session, 128 * 1024, AMDGPU_GEM_DOMAIN_GTT); context->uvd.resources[context->uvd.num_resources++] = context->enc.session.handle; context->uvd.resources[context->uvd.num_resources++] = context->uvd.ib_handle; } static void check_result(struct amdgpu_uvd_enc *enc) { uint64_t sum; uint32_t s = 175602; uint32_t *ptr, size; int j, r; r = amdgpu_bo_cpu_map(enc->fb.handle, (void **)&enc->fb.ptr); igt_assert_eq(r, 0); ptr = (uint32_t *)enc->fb.ptr; size = ptr[6]; r = amdgpu_bo_cpu_unmap(enc->fb.handle); igt_assert_eq(r, 0); r = amdgpu_bo_cpu_map(enc->bs.handle, (void **)&enc->bs.ptr); igt_assert_eq(r, 0); for (j = 0, sum = 0; j < size; ++j) sum += enc->bs.ptr[j]; igt_assert_eq(sum, s); r = amdgpu_bo_cpu_unmap(enc->bs.handle); igt_assert_eq(r, 0); } static void amdgpu_uvd_enc_session_init(amdgpu_device_handle device_handle, struct uvd_enc_context *context) { int len, r; len = 0; memcpy((context->uvd.ib_cpu + len), uve_session_info, sizeof(uve_session_info)); len += sizeof(uve_session_info) / 4; context->uvd.ib_cpu[len++] = context->enc.session.addr >> 32; context->uvd.ib_cpu[len++] = context->enc.session.addr; memcpy((context->uvd.ib_cpu + len), uve_task_info, sizeof(uve_task_info)); len += sizeof(uve_task_info) / 4; context->uvd.ib_cpu[len++] = 0x000000d8; context->uvd.ib_cpu[len++] = 0x00000000; context->uvd.ib_cpu[len++] = 0x00000000; memcpy((context->uvd.ib_cpu + len), uve_op_init, sizeof(uve_op_init)); len += sizeof(uve_op_init) / 4; memcpy((context->uvd.ib_cpu + len), uve_session_init, sizeof(uve_session_init)); len += sizeof(uve_session_init) / 4; memcpy((context->uvd.ib_cpu + len), uve_layer_ctrl, sizeof(uve_layer_ctrl)); len += sizeof(uve_layer_ctrl) / 4; memcpy((context->uvd.ib_cpu + len), uve_slice_ctrl, sizeof(uve_slice_ctrl)); len += sizeof(uve_slice_ctrl) / 4; memcpy((context->uvd.ib_cpu + len), uve_spec_misc, sizeof(uve_spec_misc)); len += sizeof(uve_spec_misc) / 4; memcpy((context->uvd.ib_cpu + len), uve_rc_session_init, sizeof(uve_rc_session_init)); len += sizeof(uve_rc_session_init) / 4; memcpy((context->uvd.ib_cpu + len), uve_deblocking_filter, sizeof(uve_deblocking_filter)); len += sizeof(uve_deblocking_filter) / 4; memcpy((context->uvd.ib_cpu + len), uve_quality_params, sizeof(uve_quality_params)); len += sizeof(uve_quality_params) / 4; memcpy((context->uvd.ib_cpu + len), uve_op_init_rc, sizeof(uve_op_init_rc)); len += sizeof(uve_op_init_rc) / 4; memcpy((context->uvd.ib_cpu + len), uve_op_init_rc_vbv_level, sizeof(uve_op_init_rc_vbv_level)); len += sizeof(uve_op_init_rc_vbv_level) / 4; r = submit(device_handle, &context->uvd, len, AMDGPU_HW_IP_UVD_ENC); igt_assert_eq(r, 0); } static void amdgpu_uvd_enc_encode(amdgpu_device_handle device_handle, struct uvd_enc_context *context) { int len, r, i; uint64_t luma_offset, chroma_offset; unsigned int luma_size; uint32_t vbuf_size, bs_size = 0x003f4800, cpb_size; unsigned int align = (context->uvd.family_id >= AMDGPU_FAMILY_AI) ? 256 : 16; vbuf_size = ALIGN(context->enc.width, align) * ALIGN(context->enc.height, 16) * 1.5; cpb_size = vbuf_size * 10; context->uvd.num_resources = 0; alloc_resource(device_handle, &context->enc.fb, 4096, AMDGPU_GEM_DOMAIN_VRAM); context->uvd.resources[context->uvd.num_resources++] = context->enc.fb.handle; alloc_resource(device_handle, &context->enc.bs, bs_size, AMDGPU_GEM_DOMAIN_VRAM); context->uvd.resources[context->uvd.num_resources++] = context->enc.bs.handle; alloc_resource(device_handle, &context->enc.vbuf, vbuf_size, AMDGPU_GEM_DOMAIN_VRAM); context->uvd.resources[context->uvd.num_resources++] = context->enc.vbuf.handle; alloc_resource(device_handle, &context->enc.cpb, cpb_size, AMDGPU_GEM_DOMAIN_VRAM); context->uvd.resources[context->uvd.num_resources++] = context->enc.cpb.handle; context->uvd.resources[context->uvd.num_resources++] = context->uvd.ib_handle; r = amdgpu_bo_cpu_map(context->enc.vbuf.handle, (void **)&context->enc.vbuf.ptr); igt_assert_eq(r, 0); memset(context->enc.vbuf.ptr, 0, vbuf_size); for (i = 0; i < context->enc.height; ++i) { memcpy(context->enc.vbuf.ptr, (frame + i * context->enc.width), context->enc.width); context->enc.vbuf.ptr += ALIGN(context->enc.width, align); } for (i = 0; i < context->enc.height / 2; ++i) { memcpy(context->enc.vbuf.ptr, ((frame + context->enc.height * context->enc.width) + i * context->enc.width), context->enc.width); context->enc.vbuf.ptr += ALIGN(context->enc.width, align); } r = amdgpu_bo_cpu_unmap(context->enc.vbuf.handle); igt_assert_eq(r, 0); len = 0; memcpy((context->uvd.ib_cpu + len), uve_session_info, sizeof(uve_session_info)); len += sizeof(uve_session_info) / 4; context->uvd.ib_cpu[len++] = context->enc.session.addr >> 32; context->uvd.ib_cpu[len++] = context->enc.session.addr; memcpy((context->uvd.ib_cpu + len), uve_task_info, sizeof(uve_task_info)); len += sizeof(uve_task_info) / 4; context->uvd.ib_cpu[len++] = 0x000005e0; context->uvd.ib_cpu[len++] = 0x00000001; context->uvd.ib_cpu[len++] = 0x00000001; memcpy((context->uvd.ib_cpu + len), uve_nalu_buffer_1, sizeof(uve_nalu_buffer_1)); len += sizeof(uve_nalu_buffer_1) / 4; memcpy((context->uvd.ib_cpu + len), uve_nalu_buffer_2, sizeof(uve_nalu_buffer_2)); len += sizeof(uve_nalu_buffer_2) / 4; memcpy((context->uvd.ib_cpu + len), uve_nalu_buffer_3, sizeof(uve_nalu_buffer_3)); len += sizeof(uve_nalu_buffer_3) / 4; memcpy((context->uvd.ib_cpu + len), uve_nalu_buffer_4, sizeof(uve_nalu_buffer_4)); len += sizeof(uve_nalu_buffer_4) / 4; memcpy((context->uvd.ib_cpu + len), uve_slice_header, sizeof(uve_slice_header)); len += sizeof(uve_slice_header) / 4; context->uvd.ib_cpu[len++] = 0x00000254; context->uvd.ib_cpu[len++] = 0x00000010; context->uvd.ib_cpu[len++] = context->enc.cpb.addr >> 32; context->uvd.ib_cpu[len++] = context->enc.cpb.addr; memcpy((context->uvd.ib_cpu + len), uve_ctx_buffer, sizeof(uve_ctx_buffer)); len += sizeof(uve_ctx_buffer) / 4; memcpy((context->uvd.ib_cpu + len), uve_bitstream_buffer, sizeof(uve_bitstream_buffer)); len += sizeof(uve_bitstream_buffer) / 4; context->uvd.ib_cpu[len++] = 0x00000000; context->uvd.ib_cpu[len++] = context->enc.bs.addr >> 32; context->uvd.ib_cpu[len++] = context->enc.bs.addr; context->uvd.ib_cpu[len++] = 0x003f4800; context->uvd.ib_cpu[len++] = 0x00000000; memcpy((context->uvd.ib_cpu + len), uve_feedback_buffer, sizeof(uve_feedback_buffer)); len += sizeof(uve_feedback_buffer) / 4; context->uvd.ib_cpu[len++] = context->enc.fb.addr >> 32; context->uvd.ib_cpu[len++] = context->enc.fb.addr; context->uvd.ib_cpu[len++] = 0x00000010; context->uvd.ib_cpu[len++] = 0x00000028; memcpy((context->uvd.ib_cpu + len), uve_feedback_buffer_additional, sizeof(uve_feedback_buffer_additional)); len += sizeof(uve_feedback_buffer_additional) / 4; memcpy((context->uvd.ib_cpu + len), uve_intra_refresh, sizeof(uve_intra_refresh)); len += sizeof(uve_intra_refresh) / 4; memcpy((context->uvd.ib_cpu + len), uve_layer_select, sizeof(uve_layer_select)); len += sizeof(uve_layer_select) / 4; memcpy((context->uvd.ib_cpu + len), uve_rc_layer_init, sizeof(uve_rc_layer_init)); len += sizeof(uve_rc_layer_init) / 4; memcpy((context->uvd.ib_cpu + len), uve_layer_select, sizeof(uve_layer_select)); len += sizeof(uve_layer_select) / 4; memcpy((context->uvd.ib_cpu + len), uve_rc_per_pic, sizeof(uve_rc_per_pic)); len += sizeof(uve_rc_per_pic) / 4; luma_size = ALIGN(context->enc.width, align) * ALIGN(context->enc.height, 16); luma_offset = context->enc.vbuf.addr; chroma_offset = luma_offset + luma_size; context->uvd.ib_cpu[len++] = 0x00000054; context->uvd.ib_cpu[len++] = 0x0000000c; context->uvd.ib_cpu[len++] = 0x00000002; context->uvd.ib_cpu[len++] = 0x003f4800; context->uvd.ib_cpu[len++] = luma_offset >> 32; context->uvd.ib_cpu[len++] = luma_offset; context->uvd.ib_cpu[len++] = chroma_offset >> 32; context->uvd.ib_cpu[len++] = chroma_offset; memcpy((context->uvd.ib_cpu + len), uve_encode_param, sizeof(uve_encode_param)); context->uvd.ib_cpu[len] = ALIGN(context->enc.width, align); context->uvd.ib_cpu[len + 1] = ALIGN(context->enc.width, align); len += sizeof(uve_encode_param) / 4; memcpy((context->uvd.ib_cpu + len), uve_op_speed_enc_mode, sizeof(uve_op_speed_enc_mode)); len += sizeof(uve_op_speed_enc_mode) / 4; memcpy((context->uvd.ib_cpu + len), uve_op_encode, sizeof(uve_op_encode)); len += sizeof(uve_op_encode) / 4; r = submit(device_handle, &context->uvd, len, AMDGPU_HW_IP_UVD_ENC); igt_assert_eq(r, 0); check_result(&context->enc); free_resource(&context->enc.fb); free_resource(&context->enc.bs); free_resource(&context->enc.vbuf); free_resource(&context->enc.cpb); } static void amdgpu_uvd_enc_destroy(amdgpu_device_handle device_handle, struct uvd_enc_context *context) { int len, r; context->uvd.num_resources = 0; context->uvd.resources[context->uvd.num_resources++] = context->uvd.ib_handle; len = 0; memcpy((context->uvd.ib_cpu + len), uve_session_info, sizeof(uve_session_info)); len += sizeof(uve_session_info) / 4; context->uvd.ib_cpu[len++] = context->enc.session.addr >> 32; context->uvd.ib_cpu[len++] = context->enc.session.addr; memcpy((context->uvd.ib_cpu + len), uve_task_info, sizeof(uve_task_info)); len += sizeof(uve_task_info) / 4; context->uvd.ib_cpu[len++] = 0xffffffff; context->uvd.ib_cpu[len++] = 0x00000002; context->uvd.ib_cpu[len++] = 0x00000000; memcpy((context->uvd.ib_cpu + len), uve_op_close, sizeof(uve_op_close)); len += sizeof(uve_op_close) / 4; r = submit(device_handle, &context->uvd, len, AMDGPU_HW_IP_UVD_ENC); igt_assert_eq(r, 0); free_resource(&context->enc.session); } static void amdgpu_uvd_enc_test(amdgpu_device_handle device, struct uvd_enc_context *context) { amdgpu_uvd_enc_create(device, context); amdgpu_uvd_enc_session_init(device, context); amdgpu_uvd_enc_encode(device, context); amdgpu_uvd_enc_destroy(device, context); } igt_main { amdgpu_device_handle device; struct uvd_enc_context context = {}; int fd = -1; igt_fixture { uint32_t major, minor; int err; fd = drm_open_driver(DRIVER_AMDGPU); err = amdgpu_device_initialize(fd, &major, &minor, &device); igt_require(err == 0); igt_info("Initialized amdgpu, driver version %d.%d\n", major, minor); memset(&context, 0, sizeof(context)); err = mmd_context_init(device, &context.uvd); igt_require(err == 0); igt_skip_on(!is_uvd_enc_enable(device)); } igt_describe("Test uvd session, encode, destroy"); igt_subtest("uvd_encoder") amdgpu_uvd_enc_test(device, &context); igt_fixture { mmd_context_clean(device, &context.uvd); amdgpu_device_deinitialize(device); drm_close_driver(fd); } }