diff --git a/src/amd/vulkan/radv_video.c b/src/amd/vulkan/radv_video.c index c75fb834465..a7dbe5ac9a3 100644 --- a/src/amd/vulkan/radv_video.c +++ b/src/amd/vulkan/radv_video.c @@ -53,6 +53,18 @@ radv_check_vcn_fw_version(const struct radv_physical_device *pdev, uint32_t dec, pdev->info.vcn_fw_revision >= rev); } +static bool +radv_enable_tier3(struct radv_physical_device *pdev, VkVideoCodecOperationFlagBitsKHR operation) +{ + if (pdev->info.vcn_ip_version < VCN_5_0_0) + return false; + + if (operation == VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR) + return radv_check_vcn_fw_version(pdev, 9, 9, 14); + + return true; +} + static bool radv_enable_tier2(struct radv_physical_device *pdev) { @@ -182,7 +194,7 @@ radv_vcn_sq_start(struct radv_cmd_buffer *cmd_buffer) { struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); - radeon_check_space(device->ws, cmd_buffer->cs, 256); + radeon_check_space(device->ws, cmd_buffer->cs, 512); radv_vcn_sq_header(cmd_buffer->cs, &cmd_buffer->video.sq, RADEON_VCN_ENGINE_TYPE_DECODE, false); rvcn_decode_ib_package_t *ib_header = (rvcn_decode_ib_package_t *)&(cmd_buffer->cs->buf[cmd_buffer->cs->cdw]); ib_header->package_size = sizeof(struct rvcn_decode_buffer_s) + sizeof(struct rvcn_decode_ib_package_s); @@ -492,21 +504,30 @@ radv_CreateVideoSessionKHR(VkDevice _device, const VkVideoSessionCreateInfoKHR * switch (vid->vk.op) { case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR: vid->stream_type = RDECODE_CODEC_H264_PERF; - if (radv_enable_tier2(pdev)) + if (radv_enable_tier3(pdev, vid->vk.op)) + vid->dpb_type = DPB_DYNAMIC_TIER_3; + else if (radv_enable_tier2(pdev)) vid->dpb_type = DPB_DYNAMIC_TIER_2; break; case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR: vid->stream_type = RDECODE_CODEC_H265; - if (radv_enable_tier2(pdev)) + if (radv_enable_tier3(pdev, vid->vk.op)) + vid->dpb_type = DPB_DYNAMIC_TIER_3; + else if (radv_enable_tier2(pdev)) vid->dpb_type = DPB_DYNAMIC_TIER_2; break; case VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR: vid->stream_type = RDECODE_CODEC_AV1; - vid->dpb_type = DPB_DYNAMIC_TIER_2; + if (radv_enable_tier3(pdev, vid->vk.op) && vid->vk.av1.profile != STD_VIDEO_AV1_PROFILE_PROFESSIONAL) + vid->dpb_type = DPB_DYNAMIC_TIER_3; + else + vid->dpb_type = DPB_DYNAMIC_TIER_2; break; case VK_VIDEO_CODEC_OPERATION_DECODE_VP9_BIT_KHR: vid->stream_type = RDECODE_CODEC_VP9; - if (pdev->info.vcn_ip_version >= VCN_3_0_0) + if (radv_enable_tier3(pdev, vid->vk.op)) + vid->dpb_type = DPB_DYNAMIC_TIER_3; + else if (pdev->info.vcn_ip_version >= VCN_3_0_0) vid->dpb_type = DPB_DYNAMIC_TIER_2; else vid->dpb_type = DPB_DYNAMIC_TIER_1; @@ -705,8 +726,11 @@ radv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, cons if (!is_encode) { dec_caps = (struct VkVideoDecodeCapabilitiesKHR *)vk_find_struct(pCapabilities->pNext, VIDEO_DECODE_CAPABILITIES_KHR); - if (dec_caps) + if (dec_caps) { dec_caps->flags = VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR; + if (radv_enable_tier3(pdev, pVideoProfile->videoCodecOperation)) + dec_caps->flags |= VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR; + } pCapabilities->minBitstreamBufferOffsetAlignment = 128; pCapabilities->minBitstreamBufferSizeAlignment = 128; } else { @@ -817,9 +841,13 @@ radv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, cons (!have_12bit || pVideoProfile->lumaBitDepth != VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR)) return VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR; + if (av1_profile->stdProfile == STD_VIDEO_AV1_PROFILE_PROFESSIONAL) + dec_caps->flags &= ~VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR; + pCapabilities->maxDpbSlots = RADV_VIDEO_AV1_MAX_DPB_SLOTS; pCapabilities->maxActiveReferencePictures = RADV_VIDEO_AV1_MAX_NUM_REF_FRAME; pCapabilities->flags |= VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR; + ext->maxLevel = STD_VIDEO_AV1_LEVEL_6_1; /* For VCN3/4, the only h/w currently with AV1 decode support */ strcpy(pCapabilities->stdHeaderVersion.extensionName, VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME); pCapabilities->stdHeaderVersion.specVersion = VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION; @@ -1053,8 +1081,8 @@ radv_GetPhysicalDeviceVideoFormatPropertiesKHR(VkPhysicalDevice physicalDevice, !pdev->video_encode_enabled) return VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR; - /* radv requires separate allocates for DPB and decode video. */ - if ((pVideoFormatInfo->imageUsage & + /* VCN < 5 requires separate allocates for DPB and decode video. */ + if (pdev->info.vcn_ip_version < VCN_5_0_0 && (pVideoFormatInfo->imageUsage & (VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR | VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)) == (VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR | VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)) return VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR; @@ -1459,7 +1487,7 @@ get_h264_msg(struct radv_video_session *vid, struct radv_video_session_params *p result.sps_info_flags |= sps->flags.mb_adaptive_frame_field_flag << 1; result.sps_info_flags |= sps->flags.frame_mbs_only_flag << 2; result.sps_info_flags |= sps->flags.delta_pic_order_always_zero_flag << 3; - if (vid->dpb_type != DPB_DYNAMIC_TIER_2) + if (vid->dpb_type < DPB_DYNAMIC_TIER_2) result.sps_info_flags |= 1 << RDECODE_SPS_INFO_H264_EXTENSION_SUPPORT_FLAG_SHIFT; result.bit_depth_luma_minus8 = sps->bit_depth_luma_minus8; @@ -2275,6 +2303,27 @@ get_av1_msg(struct radv_device *device, struct radv_video_session *vid, struct r return result; } +static void +fill_ref_buffer(rvcn_dec_ref_buffer_t *ref, struct radv_image *img, uint32_t slice, uint32_t index) +{ + uint64_t y_addr = img->bindings[0].addr + img->planes[0].surface.u.gfx9.surf_offset + + slice * img->planes[0].surface.u.gfx9.surf_slice_size; + uint64_t uv_addr = img->bindings[0].addr + img->planes[1].surface.u.gfx9.surf_offset + + slice * img->planes[1].surface.u.gfx9.surf_slice_size; + + memset(ref, 0, sizeof(*ref)); + ref->index = index; + ref->y_pitch = img->planes[0].surface.u.gfx9.surf_pitch; + ref->y_aligned_height = img->planes[0].surface.u.gfx9.surf_height; + ref->y_aligned_size = img->planes[0].surface.u.gfx9.surf_slice_size; + ref->y_ref_buffer_address_hi = y_addr >> 32; + ref->y_ref_buffer_address_lo = y_addr; + ref->uv_pitch = img->planes[1].surface.u.gfx9.surf_pitch; + ref->uv_aligned_height = img->planes[1].surface.u.gfx9.surf_height; + ref->uv_aligned_size = img->planes[1].surface.u.gfx9.surf_slice_size; + ref->uv_ref_buffer_address_hi = uv_addr >> 32; + ref->uv_ref_buffer_address_lo = uv_addr; +} static bool rvcn_dec_message_decode(struct radv_cmd_buffer *cmd_buffer, struct radv_video_session *vid, @@ -2297,6 +2346,15 @@ rvcn_dec_message_decode(struct radv_cmd_buffer *cmd_buffer, struct radv_video_se struct radv_image_plane *chroma = &img->planes[1]; bool use_intra_only_allocation_for_dpb = false; + if (vid->dpb_type == DPB_DYNAMIC_TIER_3) { + VkImageUsageFlags coincide = + VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR | VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR; + if (luma->surface.is_linear || (img->vk.usage & coincide) != coincide) + vid->dpb_type = DPB_DYNAMIC_TIER_2; + else + assert(!luma->surface.is_linear); + } + header = ptr; sizes += sizeof(rvcn_dec_message_header_t); @@ -2468,6 +2526,16 @@ rvcn_dec_message_decode(struct radv_cmd_buffer *cmd_buffer, struct radv_video_se decode->hw_ctxt_size = vid->ctx.size; + uint64_t addr; + if (use_intra_only_allocation_for_dpb) { + addr = radv_buffer_get_va(vid->intra_only_dpb.mem->bo) + vid->intra_only_dpb.offset; + radv_cs_add_buffer(device->ws, cmd_buffer->cs, vid->intra_only_dpb.mem->bo); + } else { + addr = dpb->bindings[0].addr; + radv_cs_add_buffer(device->ws, cmd_buffer->cs, dpb->bindings[0].bo); + addr += dpb_array_idx * (dpb->planes[0].surface.u.gfx9.surf_slice_size + dpb->planes[1].surface.u.gfx9.surf_slice_size); + } + if (vid->dpb_type == DPB_DYNAMIC_TIER_1) { decode->decode_flags |= (RDECODE_FLAGS_USE_DYNAMIC_DPB_MASK | RDECODE_FLAGS_USE_PAL_MASK); @@ -2480,64 +2548,106 @@ rvcn_dec_message_decode(struct radv_cmd_buffer *cmd_buffer, struct radv_video_se dynamic_dpb->dpbChromaAlignedHeight = dpb->planes[1].surface.u.gfx9.surf_height; dynamic_dpb->dpbChromaAlignedSize = dpb->planes[1].surface.u.gfx9.surf_slice_size; dynamic_dpb->dpbReserved0[0] = vid->db_alignment; - } + } else if (vid->dpb_type == DPB_DYNAMIC_TIER_2) { + decode->decode_flags = RDECODE_FLAGS_USE_DYNAMIC_DPB_MASK; - if (vid->dpb_type != DPB_DYNAMIC_TIER_2) - return true; + dynamic_dpb_t2->dpbCurrLo = addr; + dynamic_dpb_t2->dpbCurrHi = addr >> 32; - uint64_t addr; - - if (use_intra_only_allocation_for_dpb) { - addr = radv_buffer_get_va(vid->intra_only_dpb.mem->bo) + vid->intra_only_dpb.offset; - radv_cs_add_buffer(device->ws, cmd_buffer->cs, vid->intra_only_dpb.mem->bo); - } else { - addr = dpb->bindings[0].addr; - radv_cs_add_buffer(device->ws, cmd_buffer->cs, dpb->bindings[0].bo); - addr += dpb_array_idx * (dpb->planes[0].surface.u.gfx9.surf_slice_size + dpb->planes[1].surface.u.gfx9.surf_slice_size); - } - - dynamic_dpb_t2->dpbCurrLo = addr; - dynamic_dpb_t2->dpbCurrHi = addr >> 32; - - if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR) { - /* The following loop will fill in the references for the current frame, - * this ensures all DPB addresses are "valid" (pointing at the current - * decode target), so that the firmware doesn't evict things it should not. - * It will not perform any actual writes to these dummy slots. - */ - for (int i = 0; i < STD_VIDEO_AV1_NUM_REF_FRAMES; i++) { - dynamic_dpb_t2->dpbAddrHi[i] = addr; - dynamic_dpb_t2->dpbAddrLo[i] = addr >> 32; + if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR) { + /* The following loop will fill in the references for the current frame, + * this ensures all DPB addresses are "valid" (pointing at the current + * decode target), so that the firmware doesn't evict things it should not. + * It will not perform any actual writes to these dummy slots. + */ + for (int i = 0; i < STD_VIDEO_AV1_NUM_REF_FRAMES; i++) { + dynamic_dpb_t2->dpbAddrHi[i] = addr; + dynamic_dpb_t2->dpbAddrLo[i] = addr >> 32; + } } + + for (int i = 0; i < frame_info->referenceSlotCount; i++) { + struct radv_image_view *f_dpb_iv = + radv_image_view_from_handle(frame_info->pReferenceSlots[i].pPictureResource->imageViewBinding); + assert(f_dpb_iv != NULL); + struct radv_image *dpb_img = f_dpb_iv->image; + int f_dpb_array_idx = frame_info->pReferenceSlots[i].pPictureResource->baseArrayLayer + f_dpb_iv->vk.base_array_layer; + + radv_cs_add_buffer(device->ws, cmd_buffer->cs, dpb_img->bindings[0].bo); + addr = dpb_img->bindings[0].addr; + addr += f_dpb_array_idx * (dpb_img->planes[0].surface.u.gfx9.surf_slice_size + dpb_img->planes[1].surface.u.gfx9.surf_slice_size); + dynamic_dpb_t2->dpbAddrLo[i] = addr; + dynamic_dpb_t2->dpbAddrHi[i] = addr >> 32; + + ++dynamic_dpb_t2->dpbArraySize; + } + + dynamic_dpb_t2->dpbConfigFlags = 0; + + dynamic_dpb_t2->dpbLumaPitch = dpb->planes[0].surface.u.gfx9.surf_pitch; + dynamic_dpb_t2->dpbLumaAlignedHeight = dpb->planes[0].surface.u.gfx9.surf_height; + dynamic_dpb_t2->dpbLumaAlignedSize = dpb->planes[0].surface.u.gfx9.surf_slice_size; + + dynamic_dpb_t2->dpbChromaPitch = dpb->planes[1].surface.u.gfx9.surf_pitch; + dynamic_dpb_t2->dpbChromaAlignedHeight = dpb->planes[1].surface.u.gfx9.surf_height; + dynamic_dpb_t2->dpbChromaAlignedSize = dpb->planes[1].surface.u.gfx9.surf_slice_size; + } else if (vid->dpb_type == DPB_DYNAMIC_TIER_3) { + decode->decode_flags = RDECODE_FLAGS_UNIFIED_DT_MASK; + + bool add_setup_slot = false; + uint32_t num_bufs = frame_info->referenceSlotCount; + + if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR) { + num_bufs = STD_VIDEO_AV1_NUM_REF_FRAMES; + /* Film grain is applied to decode target only. */ + if (frame_info->pSetupReferenceSlot && (img != dpb || dt_array_idx != dpb_array_idx)) { + add_setup_slot = true; + num_bufs++; + } + } + + uint32_t size = sizeof(rvcn_dec_ref_buffers_header_t) + sizeof(rvcn_dec_ref_buffer_t) * num_bufs; + rvcn_decode_ib_package_t *ib_header = (rvcn_decode_ib_package_t *)&(cmd_buffer->cs->buf[cmd_buffer->cs->cdw]); + + ib_header->package_size = size + sizeof(struct rvcn_decode_ib_package_s); + cmd_buffer->cs->cdw++; + ib_header->package_type = RDECODE_IB_PARAM_DYNAMIC_REFLIST_BUFFER; + cmd_buffer->cs->cdw++; + + rvcn_dec_ref_buffers_header_t *refs = (rvcn_dec_ref_buffers_header_t *)&(cmd_buffer->cs->buf[cmd_buffer->cs->cdw]); + cmd_buffer->cs->cdw += size / 4; + refs->size = size; + refs->num_bufs = 0; + + uint16_t used_slots = 1 << (vid->vk.max_dpb_slots ? frame_info->pSetupReferenceSlot->slotIndex : 0); + + for (int i = 0; i < frame_info->referenceSlotCount; i++) { + struct radv_image_view *f_dpb_iv = + radv_image_view_from_handle(frame_info->pReferenceSlots[i].pPictureResource->imageViewBinding); + assert(f_dpb_iv != NULL); + struct radv_image *dpb_img = f_dpb_iv->image; + uint32_t f_dpb_array_idx = frame_info->pReferenceSlots[i].pPictureResource->baseArrayLayer + f_dpb_iv->vk.base_array_layer; + fill_ref_buffer(&refs->pBufs[refs->num_bufs++], dpb_img, f_dpb_array_idx, frame_info->pReferenceSlots[i].slotIndex); + radv_cs_add_buffer(device->ws, cmd_buffer->cs, dpb_img->bindings[0].bo); + used_slots |= 1 << frame_info->pReferenceSlots[i].slotIndex; + } + + if (add_setup_slot) + fill_ref_buffer(&refs->pBufs[refs->num_bufs++], dpb, dpb_array_idx, frame_info->pSetupReferenceSlot->slotIndex); + + if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR) { + for (int j = 0; j < STD_VIDEO_AV1_NUM_REF_FRAMES + 1; j++) { + if ((used_slots & (1 << j)) == 0) { + fill_ref_buffer(&refs->pBufs[refs->num_bufs++], dpb, dpb_array_idx, j); + used_slots |= 1 << j; + } + } + } + + assert(refs->num_bufs == num_bufs); + cmd_buffer->video.decode_buffer->valid_buf_flag |= RDECODE_CMDBUF_FLAGS_MSG_BUFFER; } - for (int i = 0; i < frame_info->referenceSlotCount; i++) { - struct radv_image_view *f_dpb_iv = - radv_image_view_from_handle(frame_info->pReferenceSlots[i].pPictureResource->imageViewBinding); - assert(f_dpb_iv != NULL); - struct radv_image *dpb_img = f_dpb_iv->image; - int f_dpb_array_idx = frame_info->pReferenceSlots[i].pPictureResource->baseArrayLayer + f_dpb_iv->vk.base_array_layer; - - radv_cs_add_buffer(device->ws, cmd_buffer->cs, dpb_img->bindings[0].bo); - addr = dpb_img->bindings[0].addr; - addr += f_dpb_array_idx * (dpb_img->planes[0].surface.u.gfx9.surf_slice_size + dpb_img->planes[1].surface.u.gfx9.surf_slice_size); - dynamic_dpb_t2->dpbAddrLo[i] = addr; - dynamic_dpb_t2->dpbAddrHi[i] = addr >> 32; - - ++dynamic_dpb_t2->dpbArraySize; - } - - decode->decode_flags = 1; - dynamic_dpb_t2->dpbConfigFlags = 0; - - dynamic_dpb_t2->dpbLumaPitch = dpb->planes[0].surface.u.gfx9.surf_pitch; - dynamic_dpb_t2->dpbLumaAlignedHeight = dpb->planes[0].surface.u.gfx9.surf_height; - dynamic_dpb_t2->dpbLumaAlignedSize = dpb->planes[0].surface.u.gfx9.surf_slice_size; - - dynamic_dpb_t2->dpbChromaPitch = dpb->planes[1].surface.u.gfx9.surf_pitch; - dynamic_dpb_t2->dpbChromaAlignedHeight = dpb->planes[1].surface.u.gfx9.surf_height; - dynamic_dpb_t2->dpbChromaAlignedSize = dpb->planes[1].surface.u.gfx9.surf_slice_size; - return true; } @@ -3174,7 +3284,7 @@ radv_vcn_decode_video(struct radv_cmd_buffer *cmd_buffer, const VkVideoDecodeInf radv_buffer_get_va(vid->sessionctx.mem->bo) + vid->sessionctx.offset); send_cmd(cmd_buffer, RDECODE_CMD_MSG_BUFFER, msg_bo, radv_buffer_get_va(msg_bo) + out_offset); - if (vid->dpb_type != DPB_DYNAMIC_TIER_2) { + if (vid->dpb_type < DPB_DYNAMIC_TIER_2) { if (vid->vk.max_dpb_slots == 0) { uint64_t addr = radv_buffer_get_va(vid->intra_only_dpb.mem->bo) + vid->intra_only_dpb.offset; send_cmd(cmd_buffer, RDECODE_CMD_DPB_BUFFER, vid->intra_only_dpb.mem->bo, addr); diff --git a/src/amd/vulkan/radv_video.h b/src/amd/vulkan/radv_video.h index 63e7c0f52fb..dfc5979d0de 100644 --- a/src/amd/vulkan/radv_video.h +++ b/src/amd/vulkan/radv_video.h @@ -43,7 +43,7 @@ struct radv_video_session { uint32_t stream_handle; unsigned stream_type; bool encode; - enum { DPB_MAX_RES = 0, DPB_DYNAMIC_TIER_1, DPB_DYNAMIC_TIER_2 } dpb_type; + enum { DPB_MAX_RES = 0, DPB_DYNAMIC_TIER_1, DPB_DYNAMIC_TIER_2, DPB_DYNAMIC_TIER_3 } dpb_type; unsigned db_alignment; struct radv_vid_mem sessionctx;