| /* |
| * Copyright (c) 2022-2025 The Khronos Group Inc. |
| * Copyright (c) 2022-2025 RasterGrid Kft. |
| * Modifications Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| */ |
| |
| #include "../framework/video_objects.h" |
| |
| class NegativeVideoEncodeAV1 : public VkVideoLayerTest {}; |
| |
| TEST_F(NegativeVideoEncodeAV1, ProfileMissingCodecInfo) { |
| TEST_DESCRIPTION("Test missing codec-specific structure in profile definition"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VkVideoProfileInfoKHR profile = *config.Profile(); |
| profile.pNext = nullptr; |
| |
| // Missing codec-specific info for AV1 encode profile |
| m_errorMonitor->SetDesiredError("VUID-VkVideoProfileInfoKHR-videoCodecOperation-10262"); |
| vk::GetPhysicalDeviceVideoCapabilitiesKHR(Gpu(), &profile, config.Caps()); |
| m_errorMonitor->VerifyFound(); |
| |
| // For encode this VU is also relevant for quality level property queries |
| auto quality_level_info = vku::InitStruct<VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR>(); |
| quality_level_info.pVideoProfile = &profile; |
| |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR-pVideoProfile-08259"); |
| m_errorMonitor->SetDesiredError("VUID-VkVideoProfileInfoKHR-videoCodecOperation-10262"); |
| vk::GetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR(Gpu(), &quality_level_info, config.EncodeQualityLevelProps()); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, CapabilityQueryMissingChain) { |
| TEST_DESCRIPTION("vkGetPhysicalDeviceVideoCapabilitiesKHR - missing return structures in chain"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| auto caps = vku::InitStruct<VkVideoCapabilitiesKHR>(); |
| auto encode_caps = vku::InitStruct<VkVideoEncodeCapabilitiesKHR>(); |
| auto encode_av1_caps = vku::InitStruct<VkVideoEncodeAV1CapabilitiesKHR>(); |
| |
| // Missing encode caps struct for encode profile |
| m_errorMonitor->SetDesiredError("VUID-vkGetPhysicalDeviceVideoCapabilitiesKHR-pVideoProfile-07186"); |
| caps.pNext = &encode_av1_caps; |
| vk::GetPhysicalDeviceVideoCapabilitiesKHR(Gpu(), config.Profile(), &caps); |
| m_errorMonitor->VerifyFound(); |
| |
| // Missing AV1 encode caps struct for AV1 encode profile |
| m_errorMonitor->SetDesiredError("VUID-vkGetPhysicalDeviceVideoCapabilitiesKHR-pVideoProfile-10263"); |
| caps.pNext = &encode_caps; |
| vk::GetPhysicalDeviceVideoCapabilitiesKHR(Gpu(), config.Profile(), &caps); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, QualityLevelPropsMissingChain) { |
| TEST_DESCRIPTION("vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR - missing return structures in chain"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| auto quality_level_info = vku::InitStruct<VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR>(); |
| auto quality_level_props = vku::InitStruct<VkVideoEncodeQualityLevelPropertiesKHR>(); |
| |
| quality_level_info.pVideoProfile = config.Profile(); |
| |
| // Missing codec-specific output structure for AV1 encode profile |
| m_errorMonitor->SetDesiredError("VUID-vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR-pQualityLevelInfo-10305"); |
| vk::GetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR(Gpu(), &quality_level_info, &quality_level_props); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, CreateSessionVideoEncodeAV1NotEnabled) { |
| TEST_DESCRIPTION("vkCreateVideoSession - AV1 encode is specified but videoEncodeAV1 was not enabled"); |
| |
| ForceDisableFeature(vkt::Feature::videoEncodeAV1); |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VkVideoSessionKHR session; |
| VkVideoSessionCreateInfoKHR create_info = *config.SessionCreateInfo(); |
| create_info.pVideoProfile = config.Profile(); |
| create_info.pStdHeaderVersion = config.StdVersion(); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoSessionCreateInfoKHR-pVideoProfile-10269"); |
| vk::CreateVideoSessionKHR(device(), &create_info, nullptr, &session); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, CreateSessionInvalidMaxLevel) { |
| TEST_DESCRIPTION("vkCreateVideoSessionKHR - invalid AV1 maxLevel for encode session"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VkVideoSessionKHR session; |
| VkVideoSessionCreateInfoKHR create_info = *config.SessionCreateInfo(); |
| create_info.pVideoProfile = config.Profile(); |
| create_info.pStdHeaderVersion = config.StdVersion(); |
| |
| auto av1_create_info = vku::InitStruct<VkVideoEncodeAV1SessionCreateInfoKHR>(); |
| av1_create_info.pNext = create_info.pNext; |
| create_info.pNext = &av1_create_info; |
| |
| auto unsupported_level = static_cast<int32_t>(config.EncodeCapsAV1()->maxLevel) + 1; |
| av1_create_info.maxLevel = static_cast<StdVideoAV1Level>(unsupported_level); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoSessionCreateInfoKHR-pVideoProfile-10270"); |
| vk::CreateVideoSessionKHR(device(), &create_info, nullptr, &session); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, CreateSessionParamsMissingCodecInfo) { |
| TEST_DESCRIPTION("vkCreateVideoSessionParametersKHR - missing codec-specific chained structure"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VideoContext context(m_device, config); |
| |
| VkVideoSessionParametersKHR params; |
| VkVideoSessionParametersCreateInfoKHR create_info = *config.SessionParamsCreateInfo(); |
| auto other_codec_info = vku::InitStruct<VkVideoEncodeH264SessionParametersCreateInfoKHR>(); |
| other_codec_info.maxStdSPSCount = 1; |
| other_codec_info.maxStdPPSCount = 1; |
| create_info.pNext = &other_codec_info; |
| create_info.videoSession = context.Session(); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoSessionParametersCreateInfoKHR-videoSession-10279"); |
| vk::CreateVideoSessionParametersKHR(device(), &create_info, nullptr, ¶ms); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, CreateSessionParamsTemplateNotAllowed) { |
| TEST_DESCRIPTION("vkCreateVideoSessionParametersKHR - AV1 encode does not allow using parameters templates"); |
| |
| RETURN_IF_SKIP(Init()); |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VideoContext context(DeviceObj(), config); |
| |
| StdVideoAV1SequenceHeader seq_header{}; |
| auto av1_ci = vku::InitStruct<VkVideoEncodeAV1SessionParametersCreateInfoKHR>(); |
| av1_ci.pStdSequenceHeader = &seq_header; |
| |
| VkVideoSessionParametersKHR params, params2; |
| VkVideoSessionParametersCreateInfoKHR create_info = *config.SessionParamsCreateInfo(); |
| create_info.pNext = &av1_ci; |
| create_info.videoSession = context.Session(); |
| |
| vk::CreateVideoSessionParametersKHR(device(), &create_info, nullptr, ¶ms); |
| |
| create_info.videoSessionParametersTemplate = params; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoSessionParametersCreateInfoKHR-videoSession-10278"); |
| vk::CreateVideoSessionParametersKHR(device(), &create_info, nullptr, ¶ms2); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::DestroyVideoSessionParametersKHR(device(), params, nullptr); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, CreateSessionParamsFilmGrain) { |
| TEST_DESCRIPTION("vkCreateVideoSessionParametersKHR - encoding with film grain is not support"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VideoContext context(m_device, config); |
| |
| auto av1_seq_header = config.CreateAV1SequenceHeader(); |
| av1_seq_header.flags.film_grain_params_present = 1; |
| |
| auto av1_ci = vku::InitStruct<VkVideoEncodeAV1SessionParametersCreateInfoKHR>(); |
| av1_ci.pStdSequenceHeader = &av1_seq_header; |
| |
| VkVideoSessionParametersCreateInfoKHR create_info = *config.SessionParamsCreateInfo(); |
| create_info.pNext = &av1_ci; |
| create_info.videoSession = context.Session(); |
| |
| VkVideoSessionParametersKHR params; |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeAV1SessionParametersCreateInfoKHR-pStdSequenceHeader-10288"); |
| vk::CreateVideoSessionParametersKHR(device(), &create_info, nullptr, ¶ms); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, CreateSessionParamsTooManyOperatingPoints) { |
| TEST_DESCRIPTION("vkCreateVideoSessionParametersKHR - too many operating points"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VideoContext context(m_device, config); |
| |
| auto av1_seq_header = config.CreateAV1SequenceHeader(); |
| av1_seq_header.flags.reduced_still_picture_header = 0; |
| std::vector<StdVideoEncodeAV1OperatingPointInfo> av1_op_points(config.EncodeCapsAV1()->maxOperatingPoints + 1); |
| |
| auto av1_ci = vku::InitStruct<VkVideoEncodeAV1SessionParametersCreateInfoKHR>(); |
| av1_ci.pStdSequenceHeader = &av1_seq_header; |
| av1_ci.stdOperatingPointCount = static_cast<uint32_t>(av1_op_points.size()); |
| av1_ci.pStdOperatingPoints = av1_op_points.data(); |
| |
| VkVideoSessionParametersCreateInfoKHR create_info = *config.SessionParamsCreateInfo(); |
| create_info.pNext = &av1_ci; |
| create_info.videoSession = context.Session(); |
| |
| VkVideoSessionParametersKHR params; |
| m_errorMonitor->SetDesiredError("VUID-VkVideoSessionParametersCreateInfoKHR-videoSession-10280"); |
| vk::CreateVideoSessionParametersKHR(device(), &create_info, nullptr, ¶ms); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, UpdateSessionParams) { |
| TEST_DESCRIPTION("vkUpdateVideoSessionParametersKHR - not supported for AV1 encode"); |
| |
| RETURN_IF_SKIP(Init()); |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VideoContext context(DeviceObj(), config); |
| |
| auto update_info = vku::InitStruct<VkVideoSessionParametersUpdateInfoKHR>(); |
| update_info.updateSequenceCount = 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkUpdateVideoSessionParametersKHR-videoSessionParameters-10281"); |
| vk::UpdateVideoSessionParametersKHR(device(), context.SessionParams(), &update_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, BeginCodingRequiresSessionParams) { |
| TEST_DESCRIPTION("vkCmdBeginVideoCodingKHR - AV1 encode requires session parameters"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| VkVideoBeginCodingInfoKHR begin_info = context.Begin(); |
| begin_info.videoSessionParameters = VK_NULL_HANDLE; |
| |
| cb.Begin(); |
| m_errorMonitor->SetDesiredError("VUID-VkVideoBeginCodingInfoKHR-videoSession-10283"); |
| cb.BeginVideoCoding(begin_info); |
| m_errorMonitor->VerifyFound(); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, BeginCodingMissingGopRemainingFrames) { |
| TEST_DESCRIPTION("vkCmdBeginCodingKHR - Encode AV1 useGopRemainingFrames missing when required"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsWithRateControl(GetConfigsEncodeAV1()), [](const VideoConfig& config) { |
| return config.EncodeCapsAV1()->requiresGopRemainingFrames == VK_TRUE; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires an AV1 encode profile with rate control and requiresGopRemainingFrames == VK_TRUE"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| auto gop_remaining_frames_info = vku::InitStruct<VkVideoEncodeAV1GopRemainingFrameInfoKHR>(); |
| |
| auto rc_layer = vku::InitStruct<VkVideoEncodeRateControlLayerInfoKHR>(); |
| rc_layer.averageBitrate = 32000; |
| rc_layer.maxBitrate = 32000; |
| rc_layer.frameRateNumerator = 15; |
| rc_layer.frameRateDenominator = 1; |
| |
| auto rc_info_av1 = vku::InitStruct<VkVideoEncodeAV1RateControlInfoKHR>(); |
| rc_info_av1.flags = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REGULAR_GOP_BIT_KHR; |
| rc_info_av1.gopFrameCount = 15; |
| |
| auto rc_info = vku::InitStruct<VkVideoEncodeRateControlInfoKHR>(&rc_info_av1); |
| rc_info.rateControlMode = config.GetAnySupportedRateControlMode(); |
| rc_info.layerCount = 1; |
| rc_info.pLayers = &rc_layer; |
| rc_info.virtualBufferSizeInMs = 1000; |
| rc_info.initialVirtualBufferSizeInMs = 0; |
| |
| VkVideoBeginCodingInfoKHR begin_info = context.Begin(); |
| begin_info.pNext = &rc_info; |
| |
| cb.Begin(); |
| |
| // Test with VkVideoEncodeAV1GopRemainingFrameInfoKHR missing from pNext chain |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBeginVideoCodingKHR-pBeginInfo-10282"); |
| cb.BeginVideoCoding(begin_info); |
| m_errorMonitor->VerifyFound(); |
| |
| // Test with useGopRemainingFrames set to VK_FALSE |
| gop_remaining_frames_info.useGopRemainingFrames = VK_FALSE; |
| gop_remaining_frames_info.pNext = begin_info.pNext; |
| begin_info.pNext = &gop_remaining_frames_info; |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBeginVideoCodingKHR-pBeginInfo-10282"); |
| cb.BeginVideoCoding(begin_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, RateControlConstantQIndexNonZero) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - constantQIndex must be zero for AV1 if rate control mode is not DISABLED"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithRateControl(GetConfigsEncodeAV1())); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with rate control"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| auto rc_info = VideoEncodeRateControlInfo(config).SetAnyMode(); |
| rc_info.AddLayer(VideoEncodeRateControlLayerInfo(config)); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin()); |
| cb.ControlVideoCoding(context.Control().RateControl(rc_info)); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(); |
| encode_info.CodecInfo().encode_av1.picture_info.constantQIndex = 1; |
| |
| if (config.EncodeCapsAV1()->maxQIndex < 1) { |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-constantQIndex-10321"); |
| } |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-constantQIndex-10320"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, RateControlConstantQIndexNotInCapRange) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - constantQIndex must be within AV1 minQIndex/maxQIndex caps"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Find an AV1 encode config with a non-zero minQIndex, if possible |
| VideoConfig config = GetConfig( |
| FilterConfigs(GetConfigsWithRateControl(GetConfigsEncodeAV1(), VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR), |
| [](const VideoConfig& config) { return config.EncodeCapsAV1()->minQIndex > 0; })); |
| // If couldn't find any config with a non-zero minQIndex, settle with any config that supports DISABLED rate control |
| if (!config) { |
| config = GetConfig(GetConfigsWithRateControl(GetConfigsEncodeAV1(), VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR)); |
| } |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with DISABLED rate control"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| auto rc_info = VideoEncodeRateControlInfo(config); |
| rc_info->rateControlMode = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR; |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin()); |
| cb.ControlVideoCoding(context.Control().RateControl(rc_info)); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(); |
| |
| if (config.EncodeCapsAV1()->minQIndex > 0) { |
| encode_info.CodecInfo().encode_av1.picture_info.constantQIndex = config.EncodeCapsAV1()->minQIndex - 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-constantQIndex-10321"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| encode_info.CodecInfo().encode_av1.picture_info.constantQIndex = config.EncodeCapsAV1()->maxQIndex + 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-constantQIndex-10321"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, RateControlLayerCountMismatch) { |
| TEST_DESCRIPTION( |
| "vkCmdBegin/ControlVideoCodingKHR - when using more than one rate control layer " |
| "the layer count must match the AV1 temporal layer count"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithMultiLayerRateControl(GetConfigsEncodeAV1())); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with multi-layer rate control"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| auto rc_info = VideoEncodeRateControlInfo(config, true).SetAnyMode(); |
| rc_info.AddLayer(VideoEncodeRateControlLayerInfo(config)); |
| rc_info.AddLayer(VideoEncodeRateControlLayerInfo(config)); |
| |
| cb.Begin(); |
| |
| rc_info.CodecInfo().encode_av1.temporalLayerCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeRateControlInfoKHR-videoCodecOperation-10351"); |
| cb.BeginVideoCoding(context.Begin().RateControl(rc_info)); |
| m_errorMonitor->VerifyFound(); |
| |
| if (config.EncodeCapsAV1()->maxTemporalLayerCount > 2) { |
| rc_info.CodecInfo().encode_av1.temporalLayerCount = 3; |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeRateControlInfoKHR-videoCodecOperation-10351"); |
| cb.BeginVideoCoding(context.Begin().RateControl(rc_info)); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| cb.BeginVideoCoding(context.Begin()); |
| |
| rc_info.CodecInfo().encode_av1.temporalLayerCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeRateControlInfoKHR-videoCodecOperation-10351"); |
| cb.ControlVideoCoding(context.Control().RateControl(rc_info)); |
| m_errorMonitor->VerifyFound(); |
| |
| if (config.EncodeCapsAV1()->maxTemporalLayerCount > 2) { |
| rc_info.CodecInfo().encode_av1.temporalLayerCount = 3; |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeRateControlInfoKHR-videoCodecOperation-10351"); |
| cb.ControlVideoCoding(context.Control().RateControl(rc_info)); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, RateControlTemporalLayerCount) { |
| TEST_DESCRIPTION("vkCmdBegin/ControlVideoCodingKHR - temporalLayerCount is greater than maxTemporalLayerCount"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithRateControl(GetConfigsEncodeAV1())); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with rate control"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| auto rc_info = VideoEncodeRateControlInfo(config, true).SetAnyMode(); |
| rc_info.AddLayer(VideoEncodeRateControlLayerInfo(config)); |
| rc_info.CodecInfo().encode_av1.temporalLayerCount = config.EncodeCapsAV1()->maxTemporalLayerCount + 1; |
| |
| cb.Begin(); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeAV1RateControlInfoKHR-temporalLayerCount-10299"); |
| cb.BeginVideoCoding(context.Begin().RateControl(rc_info)); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.BeginVideoCoding(context.Begin()); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeAV1RateControlInfoKHR-temporalLayerCount-10299"); |
| cb.ControlVideoCoding(context.Control().RateControl(rc_info)); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, RateControlInvalidCodecInfo) { |
| TEST_DESCRIPTION("vkCmdBegin/ControlVideoCodingKHR - invalid AV1 rate control info"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithRateControl(GetConfigsEncodeAV1())); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with rate control"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| auto rc_info = VideoEncodeRateControlInfo(config, true).SetAnyMode(); |
| rc_info.AddLayer(VideoEncodeRateControlLayerInfo(config)); |
| const char* vuid = nullptr; |
| |
| VideoEncodeRateControlTestUtils rc_test_utils(this, context); |
| |
| // Reference pattern without regular GOP flag |
| vuid = "VUID-VkVideoEncodeAV1RateControlInfoKHR-flags-10294"; |
| |
| rc_info.CodecInfo().encode_av1.gopFrameCount = 8; |
| |
| rc_info.CodecInfo().encode_av1.flags = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_KHR; |
| rc_test_utils.TestRateControlInfo(rc_info, vuid); |
| |
| rc_info.CodecInfo().encode_av1.flags |= VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REGULAR_GOP_BIT_KHR; |
| rc_test_utils.TestRateControlInfo(rc_info); |
| |
| rc_info.CodecInfo().encode_av1.flags = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REFERENCE_PATTERN_DYADIC_BIT_KHR; |
| rc_test_utils.TestRateControlInfo(rc_info, vuid); |
| |
| rc_info.CodecInfo().encode_av1.flags |= VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REGULAR_GOP_BIT_KHR; |
| rc_test_utils.TestRateControlInfo(rc_info); |
| |
| // Conflicting reference pattern flags |
| vuid = "VUID-VkVideoEncodeAV1RateControlInfoKHR-flags-10295"; |
| |
| rc_info.CodecInfo().encode_av1.flags = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REGULAR_GOP_BIT_KHR | |
| VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_KHR | |
| VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REFERENCE_PATTERN_DYADIC_BIT_KHR; |
| rc_test_utils.TestRateControlInfo(rc_info, vuid); |
| |
| // Regular GOP flag requires non-zero GOP size |
| vuid = "VUID-VkVideoEncodeAV1RateControlInfoKHR-flags-10296"; |
| |
| rc_info.CodecInfo().encode_av1.flags = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REGULAR_GOP_BIT_KHR; |
| rc_test_utils.TestRateControlInfo(rc_info); |
| |
| rc_info.CodecInfo().encode_av1.gopFrameCount = 0; |
| rc_test_utils.TestRateControlInfo(rc_info, vuid); |
| |
| // Invalid key frame period |
| vuid = "VUID-VkVideoEncodeAV1RateControlInfoKHR-keyFramePeriod-10297"; |
| |
| rc_info.CodecInfo().encode_av1.gopFrameCount = 8; |
| rc_test_utils.TestRateControlInfo(rc_info); |
| |
| rc_info.CodecInfo().encode_av1.keyFramePeriod = 4; |
| rc_test_utils.TestRateControlInfo(rc_info, vuid); |
| |
| rc_info.CodecInfo().encode_av1.keyFramePeriod = 8; |
| rc_test_utils.TestRateControlInfo(rc_info); |
| |
| rc_info.CodecInfo().encode_av1.gopFrameCount = 9; |
| rc_test_utils.TestRateControlInfo(rc_info, vuid); |
| |
| rc_info.CodecInfo().encode_av1.gopFrameCount = 1; |
| rc_test_utils.TestRateControlInfo(rc_info); |
| |
| rc_info.CodecInfo().encode_av1.keyFramePeriod = 0; |
| rc_test_utils.TestRateControlInfo(rc_info); |
| |
| // Invalid consecutive bipredictive frame count |
| vuid = "VUID-VkVideoEncodeAV1RateControlInfoKHR-consecutiveBipredictiveFrameCount-10298"; |
| |
| rc_info.CodecInfo().encode_av1.gopFrameCount = 4; |
| rc_test_utils.TestRateControlInfo(rc_info); |
| |
| rc_info.CodecInfo().encode_av1.consecutiveBipredictiveFrameCount = 4; |
| rc_test_utils.TestRateControlInfo(rc_info, vuid); |
| |
| rc_info.CodecInfo().encode_av1.consecutiveBipredictiveFrameCount = 3; |
| rc_test_utils.TestRateControlInfo(rc_info); |
| |
| rc_info.CodecInfo().encode_av1.gopFrameCount = 1; |
| rc_test_utils.TestRateControlInfo(rc_info, vuid); |
| |
| rc_info.CodecInfo().encode_av1.consecutiveBipredictiveFrameCount = 0; |
| rc_test_utils.TestRateControlInfo(rc_info); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, RateControlQIndexRange) { |
| TEST_DESCRIPTION("vkCmdBegin/ControlVideoCodingKHR - AV1 rate control layer quantizer index out of bounds"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Find an AV1 encode config with a non-zero minQIndex, if possible |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsWithRateControl(GetConfigsEncodeAV1()), |
| [](const VideoConfig& config) { return config.EncodeCapsAV1()->minQIndex > 0; })); |
| // If couldn't find any config with a non-zero minQIndex, settle with any config that supports DISABLED rate control |
| if (!config) { |
| config = GetConfig(GetConfigsWithRateControl(GetConfigsEncodeAV1())); |
| } |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with rate control"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| VideoEncodeRateControlTestUtils rc_test_utils(this, context); |
| |
| const char* expected_min_qi_vuid = "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMinQIndex-10300"; |
| const char* allowed_min_qi_vuid = "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMinQIndex-10301"; |
| |
| if (config.EncodeCapsAV1()->minQIndex > 0) { |
| // minQIndex.intraQIndex not in supported range |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.minQIndex.intraQIndex -= 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_min_qi_vuid, {allowed_min_qi_vuid}); |
| } |
| |
| // minQIndex.predictiveQIndex not in supported range |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.minQIndex.predictiveQIndex -= 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_min_qi_vuid, {allowed_min_qi_vuid}); |
| } |
| |
| // minQIndex.bipredictiveQIndex not in supported range |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.minQIndex.bipredictiveQIndex -= 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_min_qi_vuid, {allowed_min_qi_vuid}); |
| } |
| } |
| |
| // out of bounds minQIndex should be ignored if useMinQIndex is not set |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.useMinQIndex = VK_FALSE; |
| rc_layer.CodecInfo().encode_av1.minQIndex.intraQIndex -= 1; |
| rc_layer.CodecInfo().encode_av1.minQIndex.predictiveQIndex -= 1; |
| rc_layer.CodecInfo().encode_av1.minQIndex.bipredictiveQIndex -= 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer); |
| } |
| |
| const char* expected_max_qi_vuid = "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMaxQIndex-10302"; |
| const char* allowed_max_qi_vuid = "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMaxQIndex-10303"; |
| |
| // maxQIndex.intraQIndex not in supported range |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.maxQIndex.intraQIndex += 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_max_qi_vuid, {allowed_max_qi_vuid}); |
| } |
| |
| // maxQIndex.predictiveQIndex not in supported range |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.maxQIndex.predictiveQIndex += 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_max_qi_vuid, {allowed_max_qi_vuid}); |
| } |
| |
| // maxQIndex.bipredictiveQIndex not in supported range |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.maxQIndex.bipredictiveQIndex += 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_max_qi_vuid, {allowed_max_qi_vuid}); |
| } |
| |
| // out of bounds maxQIndex should be ignored if useMaxQIndex is not set |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.useMaxQIndex = VK_FALSE; |
| rc_layer.CodecInfo().encode_av1.maxQIndex.intraQIndex += 1; |
| rc_layer.CodecInfo().encode_av1.maxQIndex.predictiveQIndex += 1; |
| rc_layer.CodecInfo().encode_av1.maxQIndex.bipredictiveQIndex += 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer); |
| } |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, RateControlPerRcGroupQIndex) { |
| TEST_DESCRIPTION("vkCmdBegin/ControlVideoCodingKHR - AV1 per rate control group min/max quantizer index depends on capability"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsWithRateControl(GetConfigsEncodeAV1()), [](const VideoConfig& config) { |
| return (config.EncodeCapsAV1()->flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_PER_RATE_CONTROL_GROUP_MIN_MAX_Q_INDEX_BIT_KHR) == 0; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode without per rate control group min/max quantizer index support"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| VideoEncodeRateControlTestUtils rc_test_utils(this, context); |
| |
| const char* expected_min_qi_vuid = "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMinQIndex-10301"; |
| const char* allowed_min_qi_vuid = "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMinQIndex-10300"; |
| |
| // minQIndex.intraQIndex does not match the other quantizer index values |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.minQIndex.intraQIndex += 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_min_qi_vuid, {allowed_min_qi_vuid}); |
| } |
| |
| // minQIndex.predictiveQIndex does not match the other quantizer index values |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.minQIndex.predictiveQIndex += 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_min_qi_vuid, {allowed_min_qi_vuid}); |
| } |
| |
| // minQIndex.bipredictiveQIndex does not match the other quantizer index values |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.minQIndex.bipredictiveQIndex += 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_min_qi_vuid, {allowed_min_qi_vuid}); |
| } |
| |
| // non-matching quantizer index values in minQIndex should be ignored if useMinQIndex is not set |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.useMinQIndex = VK_FALSE; |
| rc_layer.CodecInfo().encode_av1.minQIndex.predictiveQIndex += 1; |
| rc_layer.CodecInfo().encode_av1.minQIndex.bipredictiveQIndex += 2; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer); |
| } |
| |
| const char* expected_max_qi_vuid = "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMaxQIndex-10303"; |
| const char* allowed_max_qi_vuid = "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMaxQIndex-10302"; |
| |
| // maxQIndex.intraQIndex does not match the other quantizer index values |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.maxQIndex.intraQIndex -= 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_max_qi_vuid, {allowed_max_qi_vuid}); |
| } |
| |
| // maxQIndex.predictiveQIndex does not match the other quantizer index values |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.maxQIndex.predictiveQIndex -= 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_max_qi_vuid, {allowed_max_qi_vuid}); |
| } |
| |
| // maxQIndex.bipredictiveQIndex does not match the other quantizer index values |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.maxQIndex.bipredictiveQIndex -= 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_max_qi_vuid, {allowed_max_qi_vuid}); |
| } |
| |
| // non-matching quantizer index values in maxQIndex should be ignored if useMaxQIndex is not set |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.useMaxQIndex = VK_FALSE; |
| rc_layer.CodecInfo().encode_av1.maxQIndex.predictiveQIndex -= 1; |
| rc_layer.CodecInfo().encode_av1.maxQIndex.bipredictiveQIndex -= 2; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer); |
| } |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, RateControlMinQIndexGreaterThanMaxQIndex) { |
| TEST_DESCRIPTION("vkCmdBegin/ControlVideoCodingKHR - AV1 rate control layer minQIndex > maxQIndex"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithRateControl(GetConfigsEncodeAV1())); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with rate control"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| VideoEncodeRateControlTestUtils rc_test_utils(this, context); |
| |
| const char* expected_vuid = "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMinQIndex-10304"; |
| std::vector<const char*> allowed_vuids = { |
| "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMaxQIndex-10302", |
| "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMinQIndex-10301", |
| "VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMaxQIndex-10303", |
| }; |
| |
| // minQIndex.intraQIndex > maxQIndex.intraQIndex |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.minQIndex.intraQIndex = rc_layer.CodecInfo().encode_av1.maxQIndex.intraQIndex; |
| rc_layer.CodecInfo().encode_av1.maxQIndex.intraQIndex -= 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_vuid, allowed_vuids); |
| } |
| |
| // minQIndex.predictiveQIndex > maxQIndex.predictiveQIndex |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.minQIndex.predictiveQIndex = rc_layer.CodecInfo().encode_av1.maxQIndex.predictiveQIndex; |
| rc_layer.CodecInfo().encode_av1.maxQIndex.predictiveQIndex -= 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_vuid, allowed_vuids); |
| } |
| |
| // minQIndex.bipredictiveQIndex > maxQIndex.bipredictiveQIndex |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.minQIndex.bipredictiveQIndex = rc_layer.CodecInfo().encode_av1.maxQIndex.bipredictiveQIndex; |
| rc_layer.CodecInfo().encode_av1.maxQIndex.bipredictiveQIndex -= 1; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer, expected_vuid, allowed_vuids); |
| } |
| |
| // minQIndex can be equal to maxQIndex |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| rc_layer.CodecInfo().encode_av1.minQIndex.intraQIndex = rc_layer.CodecInfo().encode_av1.maxQIndex.intraQIndex; |
| rc_layer.CodecInfo().encode_av1.minQIndex.predictiveQIndex = rc_layer.CodecInfo().encode_av1.maxQIndex.predictiveQIndex; |
| rc_layer.CodecInfo().encode_av1.minQIndex.bipredictiveQIndex = rc_layer.CodecInfo().encode_av1.maxQIndex.bipredictiveQIndex; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer); |
| } |
| |
| // minQIndex can be larger than maxQIndex if useMinQIndex or useMaxQIndex is not set |
| { |
| auto rc_layer = rc_test_utils.CreateRateControlLayerWithMinMaxQIndex(); |
| std::swap(rc_layer.CodecInfo().encode_av1.minQIndex, rc_layer.CodecInfo().encode_av1.maxQIndex); |
| |
| rc_layer.CodecInfo().encode_av1.useMinQIndex = VK_FALSE; |
| rc_layer.CodecInfo().encode_av1.useMaxQIndex = VK_TRUE; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer); |
| |
| rc_layer.CodecInfo().encode_av1.useMinQIndex = VK_TRUE; |
| rc_layer.CodecInfo().encode_av1.useMaxQIndex = VK_FALSE; |
| rc_test_utils.TestRateControlLayerInfo(rc_layer); |
| } |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, RateControlStateMismatch) { |
| TEST_DESCRIPTION("vkCmdBeginVideoCodingKHR - AV1 rate control state specified does not match current configuration"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Try to find a config that supports both CBR and VBR |
| VkVideoEncodeRateControlModeFlagsKHR rc_modes = |
| VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR | VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR; |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [rc_modes](const VideoConfig& config) { |
| return (config.EncodeCaps()->rateControlModes & rc_modes) == rc_modes; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires an AV1 encode profile that supports both CBR and VBR rate control modes"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| const bool include_codec_info = true; |
| |
| auto rc_info = VideoEncodeRateControlInfo(config, include_codec_info); |
| rc_info->rateControlMode = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR; |
| rc_info->virtualBufferSizeInMs = 3000; |
| rc_info->initialVirtualBufferSizeInMs = 1000; |
| |
| rc_info.CodecInfo().encode_av1.flags = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REGULAR_GOP_BIT_KHR; |
| rc_info.CodecInfo().encode_av1.gopFrameCount = 15; |
| rc_info.CodecInfo().encode_av1.keyFramePeriod = 60; |
| rc_info.CodecInfo().encode_av1.consecutiveBipredictiveFrameCount = 2; |
| rc_info.CodecInfo().encode_av1.temporalLayerCount = config.EncodeCaps()->maxRateControlLayers; |
| |
| for (uint32_t i = 0; i < config.EncodeCaps()->maxRateControlLayers; ++i) { |
| auto rc_layer = VideoEncodeRateControlLayerInfo(config, include_codec_info); |
| |
| rc_layer->averageBitrate = 32000 / (i + 1); |
| rc_layer->maxBitrate = 48000 / (i + 1); |
| rc_layer->frameRateNumerator = 30; |
| rc_layer->frameRateDenominator = i + 1; |
| |
| rc_layer.CodecInfo().encode_av1.useMinQIndex = VK_TRUE; |
| rc_layer.CodecInfo().encode_av1.minQIndex.intraQIndex = config.ClampAV1QIndex(0 + i); |
| rc_layer.CodecInfo().encode_av1.minQIndex.predictiveQIndex = config.ClampAV1QIndex(5 + i); |
| rc_layer.CodecInfo().encode_av1.minQIndex.bipredictiveQIndex = config.ClampAV1QIndex(10 + i); |
| |
| if ((config.EncodeCapsAV1()->flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_PER_RATE_CONTROL_GROUP_MIN_MAX_Q_INDEX_BIT_KHR) == 0) { |
| rc_layer.CodecInfo().encode_av1.minQIndex.predictiveQIndex = rc_layer.CodecInfo().encode_av1.minQIndex.intraQIndex; |
| rc_layer.CodecInfo().encode_av1.minQIndex.bipredictiveQIndex = rc_layer.CodecInfo().encode_av1.minQIndex.intraQIndex; |
| } |
| |
| rc_layer.CodecInfo().encode_av1.useMaxFrameSize = VK_TRUE; |
| rc_layer.CodecInfo().encode_av1.maxFrameSize.intraFrameSize = 30000 / (i + 1); |
| rc_layer.CodecInfo().encode_av1.maxFrameSize.predictiveFrameSize = 20000 / (i + 1); |
| rc_layer.CodecInfo().encode_av1.maxFrameSize.bipredictiveFrameSize = 10000 / (i + 1); |
| |
| rc_info.AddLayer(rc_layer); |
| } |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin()); |
| cb.ControlVideoCoding(context.Control().Reset().RateControl(rc_info)); |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| |
| context.Queue().Submit(cb); |
| m_device->Wait(); |
| |
| VideoEncodeRateControlTestUtils rc_test_utils(this, context); |
| |
| // flags mismatch |
| VkVideoEncodeAV1RateControlFlagsKHR flags = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_TEMPORAL_LAYER_PATTERN_DYADIC_BIT_KHR; |
| std::swap(rc_info.CodecInfo().encode_av1.flags, flags); |
| rc_test_utils.TestRateControlStateMismatch(rc_info); |
| std::swap(rc_info.CodecInfo().encode_av1.flags, flags); |
| |
| // gopFrameCount mismatch |
| uint32_t gop_frame_count = 12; |
| std::swap(rc_info.CodecInfo().encode_av1.gopFrameCount, gop_frame_count); |
| rc_test_utils.TestRateControlStateMismatch(rc_info); |
| std::swap(rc_info.CodecInfo().encode_av1.gopFrameCount, gop_frame_count); |
| |
| // keyFramePeriod mismatch |
| uint32_t key_frame_period = 30; |
| std::swap(rc_info.CodecInfo().encode_av1.keyFramePeriod, key_frame_period); |
| rc_test_utils.TestRateControlStateMismatch(rc_info); |
| std::swap(rc_info.CodecInfo().encode_av1.keyFramePeriod, key_frame_period); |
| |
| // consecutiveBipredictiveFrameCount mismatch |
| uint32_t cons_b_frames = 4; |
| std::swap(rc_info.CodecInfo().encode_av1.consecutiveBipredictiveFrameCount, cons_b_frames); |
| rc_test_utils.TestRateControlStateMismatch(rc_info); |
| std::swap(rc_info.CodecInfo().encode_av1.consecutiveBipredictiveFrameCount, cons_b_frames); |
| |
| // Layer useMinQIndex mismatch |
| rc_info.Layer(0).CodecInfo().encode_av1.useMinQIndex = VK_FALSE; |
| rc_test_utils.TestRateControlStateMismatch(rc_info); |
| rc_info.Layer(0).CodecInfo().encode_av1.useMinQIndex = VK_TRUE; |
| |
| // Layer minQIndex.bipredictiveQIndex mismatch |
| rc_info.Layer(0).CodecInfo().encode_av1.minQIndex.bipredictiveQIndex -= 1; |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMinQIndex-10300"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMinQIndex-10301"); |
| rc_test_utils.TestRateControlStateMismatch(rc_info); |
| rc_info.Layer(0).CodecInfo().encode_av1.minQIndex.bipredictiveQIndex += 1; |
| |
| // Layer useMaxQIndex mismatch |
| rc_info.Layer(0).CodecInfo().encode_av1.useMaxQIndex = VK_TRUE; |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMaxQIndex-10302"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMaxQIndex-10303"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMinQIndex-10304"); |
| rc_test_utils.TestRateControlStateMismatch(rc_info); |
| rc_info.Layer(0).CodecInfo().encode_av1.useMaxQIndex = VK_FALSE; |
| |
| // Layer maxQIndex.predictiveQIndex mismatch |
| rc_info.Layer(0).CodecInfo().encode_av1.maxQIndex.predictiveQIndex += 1; |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMinQIndex-10301"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1RateControlLayerInfoKHR-useMaxQIndex-10303"); |
| rc_test_utils.TestRateControlStateMismatch(rc_info); |
| rc_info.Layer(0).CodecInfo().encode_av1.maxQIndex.predictiveQIndex -= 1; |
| |
| // Layer useMaxFrameSize mismatch |
| rc_info.Layer(0).CodecInfo().encode_av1.useMaxFrameSize = VK_FALSE; |
| rc_test_utils.TestRateControlStateMismatch(rc_info); |
| rc_info.Layer(0).CodecInfo().encode_av1.useMaxFrameSize = VK_TRUE; |
| |
| // Layer maxFrameSize.intraFrameSize mismatch |
| uint32_t max_frame_i_size = 12345; |
| std::swap(rc_info.Layer(0).CodecInfo().encode_av1.maxFrameSize.intraFrameSize, max_frame_i_size); |
| rc_test_utils.TestRateControlStateMismatch(rc_info); |
| std::swap(rc_info.Layer(0).CodecInfo().encode_av1.maxFrameSize.intraFrameSize, max_frame_i_size); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeCapsPrimaryRefCdfOnly) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - using AV1 primary reference for CDF-only is not supported"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithDpbSlots( |
| GetConfigsWithReferences(FilterConfigs(GetConfigsEncodeAV1(), |
| [](const VideoConfig& config) { |
| return (config.EncodeCapsAV1()->flags & |
| VK_VIDEO_ENCODE_AV1_CAPABILITY_PRIMARY_REFERENCE_CDF_ONLY_BIT_KHR) == 0; |
| })), |
| 2)); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support without CDF-only primary reference support"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = 2; |
| config.SessionCreateInfo()->maxActiveReferencePictures = 1; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(0, 0).AddResource(1, 1)); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.primaryReferenceCdfOnly = VK_TRUE; |
| |
| // This may trigger other, prediction mode specific cap VUs, because we do not respect the need |
| // to use one or two of the supported reference names corresponding to the used prediction mode |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-predictionMode-10329"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-predictionMode-10331"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-predictionMode-10333"); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeAV1PictureInfoKHR-flags-10289"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeCapsGenObuExtHeader) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - generating AV1 OBU extension header is not supported"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [](const VideoConfig& config) { |
| return (config.EncodeCapsAV1()->flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_GENERATE_OBU_EXTENSION_HEADER_BIT_KHR) == 0; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support without OBU extension header generation support"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin()); |
| |
| StdVideoEncodeAV1ExtensionHeader av1_obu_ext_header{}; |
| VideoEncodeInfo encode_info = context.EncodeFrame(); |
| encode_info.CodecInfo().encode_av1.picture_info.generateObuExtensionHeader = VK_TRUE; |
| encode_info.CodecInfo().encode_av1.std_picture_info.pExtensionHeader = &av1_obu_ext_header; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeAV1PictureInfoKHR-flags-10292"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeCapsFrameSizeOverride) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - AV1 frame size override is not supported"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [](const VideoConfig& config) { |
| return ((config.Caps()->minCodedExtent.width < config.Caps()->maxCodedExtent.width) || |
| (config.Caps()->minCodedExtent.height < config.Caps()->maxCodedExtent.height)) && |
| (config.EncodeCapsAV1()->flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_FRAME_SIZE_OVERRIDE_BIT_KHR) == 0; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with no frame size override support"; |
| } |
| |
| config.UpdateMaxCodedExtent(config.Caps()->maxCodedExtent); |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin()); |
| |
| // Cannot set frame_size_override_flag |
| auto encode_info = context.EncodeFrame(); |
| encode_info.CodecInfo().encode_av1.std_picture_info.flags.frame_size_override_flag = 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-flags-10322"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| encode_info.CodecInfo().encode_av1.std_picture_info.flags.frame_size_override_flag = 0; |
| |
| // Cannot use smaller coded width |
| encode_info->srcPictureResource.codedExtent.width -= 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-flags-10323"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| encode_info->srcPictureResource.codedExtent.width += 1; |
| |
| // Cannot use smaller coded height |
| encode_info->srcPictureResource.codedExtent.height -= 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-flags-10324"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| encode_info->srcPictureResource.codedExtent.height += 1; |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeCapsMotionVectorScaling) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - AV1 motion vector scaling is not supported"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithDpbSlots( |
| GetConfigsWithReferences(FilterConfigs( |
| GetConfigsEncodeAV1(), |
| [](const VideoConfig& config) { |
| return ((config.Caps()->minCodedExtent.width < config.Caps()->maxCodedExtent.width) || |
| (config.Caps()->minCodedExtent.height < config.Caps()->maxCodedExtent.height)) && |
| (config.EncodeCapsAV1()->flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_MOTION_VECTOR_SCALING_BIT_KHR) == 0; |
| })), |
| 2)); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with references but no motion vector scaling support"; |
| } |
| |
| config.UpdateMaxCodedExtent(config.Caps()->maxCodedExtent); |
| |
| config.SessionCreateInfo()->maxDpbSlots = 2; |
| config.SessionCreateInfo()->maxActiveReferencePictures = 1; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| // We will use a setup where the encoded picture has an extent of maxCodedExtent |
| // but the reference frame has an extent of minCodedExtent |
| auto patched_resource = context.Dpb()->Picture(1); |
| patched_resource.codedExtent = config.Caps()->minCodedExtent; |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(0, 0).AddResource(1, patched_resource)); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-flags-10325"); |
| cb.EncodeVideo(context.EncodeFrame(0).AddReferenceFrame(1, &patched_resource)); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeCapsMaxTiles) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - TileCols and TileRows must be between (0,0) and maxTiles"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin()); |
| |
| StdVideoAV1TileInfo tile_info{}; |
| VideoEncodeInfo encode_info = context.EncodeFrame(); |
| encode_info.CodecInfo().encode_av1.std_picture_info.pTileInfo = &tile_info; |
| |
| // TileCols > 0 is not satisfied |
| { |
| tile_info.TileCols = 0; |
| tile_info.TileRows = 1; |
| |
| // We may violate tile size limits here but that's okay |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10347"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10348"); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pTileInfo-10343"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // TileRows > 0 is not satisfied |
| { |
| tile_info.TileCols = 1; |
| tile_info.TileRows = 0; |
| |
| // We may violate tile size limits here but that's okay |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10347"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10348"); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pTileInfo-10344"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // TileCols <= maxTiles.width is not satisfied |
| { |
| tile_info.TileCols = static_cast<uint8_t>(config.EncodeCapsAV1()->maxTiles.width + 1); |
| tile_info.TileRows = 1; |
| |
| // We may violate tile size limits here but that's okay |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10347"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10348"); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pTileInfo-10345"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // TileRows <= maxTiles.height is not satisfied |
| { |
| tile_info.TileCols = 1; |
| tile_info.TileRows = static_cast<uint8_t>(config.EncodeCapsAV1()->maxTiles.height + 1); |
| |
| // We may violate tile size limits here but that's okay |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10347"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10348"); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pTileInfo-10346"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeCapsMinMaxTileSize) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - ceil(codedExtent / (TileCols,TileRows)) must be between minTileSize and maxTileSize"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| auto configs = GetConfigsEncodeAV1(); |
| if (configs.empty()) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| StdVideoAV1TileInfo tile_info{}; |
| |
| auto test_encode = [&](const VideoConfig& config, const char* expected_tile_size_vuid) { |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin()); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(); |
| encode_info.CodecInfo().encode_av1.std_picture_info.pTileInfo = &tile_info; |
| |
| m_errorMonitor->SetDesiredError(expected_tile_size_vuid); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| }; |
| |
| // Test a case that triggers ceil(codedExtent.width / TileCols) < minTileSize.width |
| { |
| // Find the config with the largest supported minimum tile width |
| uint32_t max_min_tile_width = 0; |
| VideoConfig config; |
| for (auto& cfg : configs) { |
| if (cfg.EncodeCapsAV1()->minTileSize.width > max_min_tile_width) { |
| max_min_tile_width = cfg.EncodeCapsAV1()->minTileSize.width; |
| config = cfg; |
| } |
| } |
| |
| // Use the smallest possible coded extent |
| const VkExtent2D coded_extent = config.Caps()->minCodedExtent; |
| config.UpdateMaxCodedExtent(coded_extent); |
| |
| // Use more tile columns than what would be the maximum to have a tile width >= minTileSize.width |
| tile_info.TileCols = static_cast<uint8_t>(coded_extent.width / config.EncodeCapsAV1()->minTileSize.width + 1); |
| tile_info.TileRows = static_cast<uint8_t>(coded_extent.height / config.EncodeCapsAV1()->minTileSize.height); |
| |
| // We may violate some tile count VUIDs here but that is fine |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10345"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10346"); |
| |
| test_encode(config, "VUID-vkCmdEncodeVideoKHR-pTileInfo-10347"); |
| } |
| |
| // Test a case that triggers ceil(codedExtent.height / TileRows) < minTileSize.height |
| { |
| // Find the config with the largest supported minimum tile height |
| uint32_t max_min_tile_height = 0; |
| VideoConfig config; |
| for (auto& cfg : configs) { |
| if (cfg.EncodeCapsAV1()->minTileSize.height > max_min_tile_height) { |
| max_min_tile_height = cfg.EncodeCapsAV1()->minTileSize.height; |
| config = cfg; |
| } |
| } |
| |
| // Use the smallest possible coded extent |
| const VkExtent2D coded_extent = config.Caps()->minCodedExtent; |
| config.UpdateMaxCodedExtent(coded_extent); |
| |
| // Use more tile rows than what would be the maximum to have a tile height >= minTileSize.height |
| tile_info.TileCols = static_cast<uint8_t>(coded_extent.width / config.EncodeCapsAV1()->minTileSize.width); |
| tile_info.TileRows = static_cast<uint8_t>(coded_extent.height / config.EncodeCapsAV1()->minTileSize.height + 1); |
| |
| // We may violate some tile count VUIDs here but that is fine |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10345"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-pTileInfo-10346"); |
| |
| test_encode(config, "VUID-vkCmdEncodeVideoKHR-pTileInfo-10348"); |
| } |
| |
| // Test a case that triggers ceil(codedExtent.width / TileCols) > maxTileSize.width |
| { |
| // Find the config with the smallest supported maximum tile width |
| uint32_t min_max_tile_width = UINT32_MAX; |
| VideoConfig config; |
| for (auto& cfg : configs) { |
| if (cfg.EncodeCapsAV1()->maxTileSize.width < min_max_tile_width) { |
| min_max_tile_width = cfg.EncodeCapsAV1()->maxTileSize.width; |
| config = cfg; |
| } |
| } |
| |
| // Use the largest possible coded extent |
| const VkExtent2D coded_extent = config.Caps()->maxCodedExtent; |
| config.UpdateMaxCodedExtent(coded_extent); |
| |
| // Use less tile columns than what would be the minimum to have a tile width <= maxTileSize.width |
| tile_info.TileCols = static_cast<uint8_t>( |
| (coded_extent.width + config.EncodeCapsAV1()->maxTileSize.width - 1) / config.EncodeCapsAV1()->maxTileSize.width - 1); |
| tile_info.TileRows = static_cast<uint8_t>((coded_extent.height + config.EncodeCapsAV1()->maxTileSize.height - 1) / |
| config.EncodeCapsAV1()->maxTileSize.height); |
| |
| // We can only test this if the determined TileCols is not zero |
| if (tile_info.TileCols > 0) { |
| test_encode(config, "VUID-vkCmdEncodeVideoKHR-pTileInfo-10347"); |
| } |
| } |
| |
| // Test a case that triggers ceil(codedExtent.height / TileRows) > maxTileSize.height |
| { |
| // Find the config with the smallest supported maximum tile height |
| uint32_t min_max_tile_height = UINT32_MAX; |
| VideoConfig config; |
| for (auto& cfg : configs) { |
| if (cfg.EncodeCapsAV1()->maxTileSize.height < min_max_tile_height) { |
| min_max_tile_height = cfg.EncodeCapsAV1()->maxTileSize.height; |
| config = cfg; |
| } |
| } |
| |
| // Use the largest possible coded extent |
| const VkExtent2D coded_extent = config.Caps()->maxCodedExtent; |
| config.UpdateMaxCodedExtent(coded_extent); |
| |
| // Use less tile rows than what would be the minimum to have a tile height <= maxTileSize.height |
| tile_info.TileCols = static_cast<uint8_t>((coded_extent.width + config.EncodeCapsAV1()->maxTileSize.width - 1) / |
| config.EncodeCapsAV1()->maxTileSize.width); |
| tile_info.TileRows = static_cast<uint8_t>((coded_extent.height + config.EncodeCapsAV1()->maxTileSize.height - 1) / |
| config.EncodeCapsAV1()->maxTileSize.height - |
| 1); |
| |
| // We can only test this if the determined TileRows is not zero |
| if (tile_info.TileRows > 0) { |
| test_encode(config, "VUID-vkCmdEncodeVideoKHR-pTileInfo-10348"); |
| } |
| } |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidCodecInfo) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - invalid/missing AV1 codec-specific information"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithDpbSlots(GetConfigsWithReferences(GetConfigsEncodeAV1()), 2)); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with reference pictures and 2 DPB slots"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = 2; |
| config.SessionCreateInfo()->maxActiveReferencePictures = 1; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(0, 0).AddResource(-1, 1)); |
| |
| // Missing AV1 picture info |
| { |
| auto encode_info = context.EncodeFrame(0); |
| encode_info->pNext = nullptr; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pNext-10317"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // INTRA_ONLY prediction mode used with AV1 frame type other than KEY_FRAME or INTRA_ONLY_FRAME |
| { |
| auto encode_info = context.EncodeFrame(1).AddReferenceFrame(0); |
| |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_INTRA_ONLY_KHR; |
| encode_info.CodecInfo().encode_av1.std_picture_info.frame_type = STD_VIDEO_AV1_FRAME_TYPE_INTER; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10326"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Non-INTRA_ONLY prediction mode used with AV1 frame type KEY_FRAME or INTRA_ONLY_FRAME |
| { |
| auto encode_info = context.EncodeFrame(1).AddReferenceFrame(0); |
| |
| encode_info.CodecInfo().encode_av1.std_picture_info.frame_type = STD_VIDEO_AV1_FRAME_TYPE_INTRA_ONLY; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pStdPictureInfo-10327"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| encode_info.CodecInfo().encode_av1.std_picture_info.frame_type = STD_VIDEO_AV1_FRAME_TYPE_KEY; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pStdPictureInfo-10327"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Missing AV1 setup reference info |
| { |
| auto slot = vku::InitStruct<VkVideoReferenceSlotInfoKHR>(); |
| slot.pNext = nullptr; |
| slot.slotIndex = 0; |
| slot.pPictureResource = &context.Dpb()->Picture(0); |
| |
| auto encode_info = context.EncodeFrame(0); |
| encode_info->pSetupReferenceSlot = &slot; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pEncodeInfo-10318"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Missing AV1 reference info |
| { |
| auto slot = vku::InitStruct<VkVideoReferenceSlotInfoKHR>(); |
| slot.pNext = nullptr; |
| slot.slotIndex = 0; |
| slot.pPictureResource = &context.Dpb()->Picture(0); |
| |
| auto encode_info = context.EncodeFrame(1).AddReferenceFrame(0); |
| encode_info->referenceSlotCount = 1; |
| encode_info->pReferenceSlots = &slot; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pNext-10319"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Missing reference in referenceNameSlotIndices to reference slot |
| { |
| auto encode_info = context.EncodeFrame(1).AddReferenceFrame(0); |
| |
| for (uint32_t i = 0; i < VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR; ++i) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } |
| |
| // This will also trigger the VU related to primary_ref_frame DPB slot index |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1PictureInfoKHR-pStdPictureInfo-10291"); |
| |
| // This may trigger other, prediction mode specific cap VUs, because we do not respect the need |
| // to use one or two of the supported reference names corresponding to the used prediction mode |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-predictionMode-10329"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-predictionMode-10331"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-predictionMode-10333"); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-slotIndex-10335"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Missing reference slot for DPB slot index referred to by referenceNameSlotIndices |
| { |
| auto encode_info = context.EncodeFrame(1).AddReferenceFrame(0); |
| encode_info->referenceSlotCount = 0; |
| encode_info->pReferenceSlots = nullptr; |
| |
| for (uint32_t i = 0; i < VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR; ++i) { |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-referenceNameSlotIndices-10334"); |
| } |
| |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // AV1 segmentation is not supported but segmentation_enabled is not zero |
| { |
| auto encode_info = context.EncodeFrame(0); |
| encode_info.CodecInfo().encode_av1.std_picture_info.flags.segmentation_enabled = 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pStdPictureInfo-10349"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // AV1 segmentation is not supported but pSegmentation is not NULL |
| { |
| StdVideoAV1Segmentation segmentation_info{}; |
| auto encode_info = context.EncodeFrame(0); |
| encode_info.CodecInfo().encode_av1.std_picture_info.pSegmentation = &segmentation_info; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pStdPictureInfo-10350"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidCodecInfoPrimaryRefCdfOnly) { |
| TEST_DESCRIPTION( |
| "vkCmdEncodeVideoKHR - invalid/missing AV1 codec-specific information " |
| "when primary reference is used only as CDF reference"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithDpbSlots( |
| GetConfigsWithReferences(FilterConfigs(GetConfigsEncodeAV1(), |
| [](const VideoConfig& config) { |
| return (config.EncodeCapsAV1()->flags & |
| VK_VIDEO_ENCODE_AV1_CAPABILITY_PRIMARY_REFERENCE_CDF_ONLY_BIT_KHR) != 0; |
| })), |
| 2)); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with reference pictures, 2 DPB slots, " |
| "and CDF-only primary reference support"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = 2; |
| config.SessionCreateInfo()->maxActiveReferencePictures = 1; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(0, 0).AddResource(1, 1)); |
| |
| // Invalid primary_ref_frame |
| { |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.primaryReferenceCdfOnly = VK_TRUE; |
| encode_info.CodecInfo().encode_av1.std_picture_info.primary_ref_frame = VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeAV1PictureInfoKHR-primaryReferenceCdfOnly-10290"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Invalid primary reference DPB slot index |
| { |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.primaryReferenceCdfOnly = VK_TRUE; |
| const uint8_t primary_ref_frame = encode_info.CodecInfo().encode_av1.std_picture_info.primary_ref_frame; |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[primary_ref_frame] = -1; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeAV1PictureInfoKHR-pStdPictureInfo-10291"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidPrimaryRefFrameDpbSlotIndex) { |
| TEST_DESCRIPTION( |
| "vkCmdEncodeVideoKHR - AV1 primary_ref_frame specifies a valid reference name with no associated DPB slot index"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithDpbSlots(GetConfigsWithReferences(GetConfigsEncodeAV1()), 2)); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with reference pictures and 2 DPB slots"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = 2; |
| config.SessionCreateInfo()->maxActiveReferencePictures = 1; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(0, 0).AddResource(1, 1)); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| const uint8_t primary_ref_frame = encode_info.CodecInfo().encode_av1.std_picture_info.primary_ref_frame; |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[primary_ref_frame] = -1; |
| |
| // This may trigger other, prediction mode specific cap VUs, because we do not respect the need |
| // to use one or two of the supported reference names corresponding to the used prediction mode |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-predictionMode-10329"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-predictionMode-10331"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdEncodeVideoKHR-predictionMode-10333"); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeAV1PictureInfoKHR-pStdPictureInfo-10291"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidCodecInfoGenObuExtHeader) { |
| TEST_DESCRIPTION( |
| "vkCmdEncodeVideoKHR - invalid/missing AV1 codec-specific information " |
| "when OBU extension header generation is requested"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [](const VideoConfig& config) { |
| return (config.EncodeCapsAV1()->flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_GENERATE_OBU_EXTENSION_HEADER_BIT_KHR) != 0; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with OBU extension header generation support"; |
| } |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin()); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(); |
| encode_info.CodecInfo().encode_av1.picture_info.generateObuExtensionHeader = VK_TRUE; |
| encode_info.CodecInfo().encode_av1.std_picture_info.pExtensionHeader = nullptr; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkVideoEncodeAV1PictureInfoKHR-generateObuExtensionHeader-10293"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeSingleReferenceNotSupported) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - AV1 single reference prediction mode not supported"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Single reference prediction requires at least one active reference picture |
| const uint32_t min_ref_count = 1; |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [&](const VideoConfig& config) { |
| return config.Caps()->maxDpbSlots > min_ref_count && config.Caps()->maxActiveReferencePictures >= min_ref_count && |
| config.EncodeCapsAV1()->maxSingleReferenceCount == 0; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with no single reference prediction mode support"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = min_ref_count + 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = min_ref_count; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(-1, 0).AddResource(1, 1)); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_SINGLE_REFERENCE_KHR; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-maxSingleReferenceCount-10328"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidSingleReference) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - Unsupported AV1 single reference name"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Single reference prediction requires at least one active reference picture |
| const uint32_t min_ref_count = 1; |
| |
| // We need to find an unsupported AV1 reference name |
| const uint32_t ref_name_mask = 0x7F; |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [&](const VideoConfig& config) { |
| return config.Caps()->maxDpbSlots > min_ref_count && config.Caps()->maxActiveReferencePictures >= min_ref_count && |
| config.EncodeCapsAV1()->maxSingleReferenceCount > 0 && |
| (config.EncodeCapsAV1()->singleReferenceNameMask & ref_name_mask) != ref_name_mask; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with single reference prediction mode support"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = min_ref_count + 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = min_ref_count; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(-1, 0).AddResource(1, 1)); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_SINGLE_REFERENCE_KHR; |
| |
| // Clear all supported reference name indices, leaving only the unsupported ones on |
| for (uint32_t i = 0; i < VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR; ++i) { |
| if ((config.EncodeCapsAV1()->singleReferenceNameMask & (1 << i)) != 0) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } |
| } |
| |
| // This may trigger the VU related to primary_ref_frame DPB slot index |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1PictureInfoKHR-pStdPictureInfo-10291"); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10329"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidSingleReferenceCdfOnly) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - Unsupported CDF-only AV1 single reference name"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Single reference prediction requires at least one active reference picture |
| // The CDF-only reference can also refer to the same reference slot, only the reference name has to differ |
| const uint32_t min_ref_count = 1; |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [&](const VideoConfig& config) { |
| return config.Caps()->maxDpbSlots > min_ref_count && config.Caps()->maxActiveReferencePictures >= min_ref_count && |
| config.EncodeCapsAV1()->maxSingleReferenceCount > 0 && |
| (config.EncodeCapsAV1()->flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_PRIMARY_REFERENCE_CDF_ONLY_BIT_KHR) != 0; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with single reference prediction mode " |
| "and CDF-only primary reference support"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = min_ref_count + 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = min_ref_count; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(-1, 0).AddResource(1, 1)); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_SINGLE_REFERENCE_KHR; |
| |
| // Clear all supported reference name indices, leaving only the unsupported ones on |
| uint8_t supported_ref_idx = 0; |
| for (uint8_t i = 0; i < VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR; ++i) { |
| if ((config.EncodeCapsAV1()->singleReferenceNameMask & (1 << i)) != 0) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } else { |
| // Remember one of the supported reference names as we will use that as CDF-only reference |
| supported_ref_idx = i; |
| } |
| } |
| |
| // Use the supported reference name as CDF-only reference |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[supported_ref_idx] = 1; |
| encode_info.CodecInfo().encode_av1.picture_info.primaryReferenceCdfOnly = VK_TRUE; |
| encode_info.CodecInfo().encode_av1.std_picture_info.primary_ref_frame = supported_ref_idx; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10329"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeUnidirectionalCompoundNotSupported) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - AV1 unidirectional compound prediction mode not supported"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Unidirectional compound prediction requires at least one active reference picture |
| // No need for two pictures as both reference names can point to the same picture |
| const uint32_t min_ref_count = 1; |
| |
| // We need to find an unsupported AV1 reference name |
| // NOTE: Unidirectional compound prediction does not support ALTREF2_FRAME in any combination |
| const uint32_t ref_name_mask = 0x5F; |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [&](const VideoConfig& config) { |
| return config.Caps()->maxDpbSlots > min_ref_count && config.Caps()->maxActiveReferencePictures >= min_ref_count && |
| config.EncodeCapsAV1()->maxUnidirectionalCompoundReferenceCount == 0 && |
| (config.EncodeCapsAV1()->unidirectionalCompoundReferenceNameMask & ref_name_mask) != ref_name_mask; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with no unidirectional compound prediction mode support"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = min_ref_count + 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = min_ref_count; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(-1, 0).AddResource(1, 1)); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = |
| VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_UNIDIRECTIONAL_COMPOUND_KHR; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-maxUnidirectionalCompoundReferenceCount-10330"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidUnidirectionalCompound) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - Unsupported AV1 unidirectional compound reference names"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Unidirectional compound prediction requires at least one active reference picture |
| // No need for two pictures as both reference names can point to the same picture |
| const uint32_t min_ref_count = 1; |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [&](const VideoConfig& config) { |
| return config.Caps()->maxDpbSlots > min_ref_count && config.Caps()->maxActiveReferencePictures >= min_ref_count && |
| config.EncodeCapsAV1()->maxUnidirectionalCompoundReferenceCount > 0; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with unidirectional compound prediction mode support"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = min_ref_count + 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = min_ref_count; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(-1, 0).AddResource(1, 1)); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = |
| VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_UNIDIRECTIONAL_COMPOUND_KHR; |
| |
| // Unidirectional compound supports the following combinations |
| // (0,1) - LAST_FRAME + LAST2_FRAME |
| // (0,2) - LAST_FRAME + LAST3_FRAME |
| // (0,3) - LAST_FRAME + GOLDEN_FRAME |
| // (4,6) - BWDREF_FRAME + ALTREF_FRAME |
| // Test with cases that fail these conditions in some way |
| std::vector<uint32_t> clear_masks = { |
| 0x11, // No LAST_FRAME or BWDREF_FRAME |
| 0x41, // No LAST_FRAME or ALTREF_FRAME |
| 0x1E, // No LAST2_FRAME, LAST3_FRAME, GOLDEN_FRAME, or BWDREF_FRAME |
| 0x4E, // No LAST2_FRAME, LAST3_FRAME, GOLDEN_FRAME, or ALTREF_FRAME |
| }; |
| for (auto clear_mask : clear_masks) { |
| for (uint32_t i = 0; i < VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR; ++i) { |
| if ((clear_mask & (1 << i)) != 0) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } |
| } |
| |
| // This may trigger the VU related to primary_ref_frame DPB slot index |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1PictureInfoKHR-pStdPictureInfo-10291"); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10331"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidUnidirectionalCompoundCdfOnly) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - Unsupported CDF-only AV1 unidirectional compound reference names"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Unidirectional compound prediction requires at least one active reference picture |
| // No need for two pictures as both reference names can point to the same picture |
| // The CDF-only reference can also refer to the same reference slot, only the reference name has to differ |
| const uint32_t min_ref_count = 1; |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [&](const VideoConfig& config) { |
| return config.Caps()->maxDpbSlots > min_ref_count && config.Caps()->maxActiveReferencePictures >= min_ref_count && |
| config.EncodeCapsAV1()->maxUnidirectionalCompoundReferenceCount > 0 && |
| (config.EncodeCapsAV1()->flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_PRIMARY_REFERENCE_CDF_ONLY_BIT_KHR) != 0; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with unidirectional compound prediction mode " |
| "and CDF-only primary reference support"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = min_ref_count + 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = min_ref_count; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(-1, 0).AddResource(1, 1)); |
| |
| // Unidirectional compound supports the following combinations |
| // (0,1) - LAST_FRAME + LAST2_FRAME |
| // (0,2) - LAST_FRAME + LAST3_FRAME |
| // (0,3) - LAST_FRAME + GOLDEN_FRAME |
| // (4,6) - BWDREF_FRAME + ALTREF_FRAME |
| |
| const uint8_t last_frame_idx = STD_VIDEO_AV1_REFERENCE_NAME_LAST_FRAME - 1; |
| const std::array<uint8_t, 3> last_frame_pair_indices = {STD_VIDEO_AV1_REFERENCE_NAME_LAST2_FRAME - 1, |
| STD_VIDEO_AV1_REFERENCE_NAME_LAST3_FRAME - 1, |
| STD_VIDEO_AV1_REFERENCE_NAME_GOLDEN_FRAME - 1}; |
| const uint8_t bwdref_frame_idx = STD_VIDEO_AV1_REFERENCE_NAME_BWDREF_FRAME - 1; |
| const uint8_t altref_frame_idx = STD_VIDEO_AV1_REFERENCE_NAME_ALTREF_FRAME - 1; |
| |
| if ((config.EncodeCapsAV1()->unidirectionalCompoundReferenceNameMask & (1 << last_frame_idx)) != 0) { |
| // If LAST_FRAME is supported, we clear all group 2 reference names and set it as CDF-only reference, |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = |
| VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_UNIDIRECTIONAL_COMPOUND_KHR; |
| |
| for (uint8_t i = bwdref_frame_idx; i < VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR; ++i) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[last_frame_idx] = 1; |
| encode_info.CodecInfo().encode_av1.picture_info.primaryReferenceCdfOnly = VK_TRUE; |
| encode_info.CodecInfo().encode_av1.std_picture_info.primary_ref_frame = last_frame_idx; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10331"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| // then we clear all except LAST_FRAME and enable one of its pairs (if supported) as CDF-only reference |
| for (uint8_t i = last_frame_idx + 1; i < VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR; ++i) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } |
| |
| for (auto other_frame_idx : last_frame_pair_indices) { |
| if ((config.EncodeCapsAV1()->unidirectionalCompoundReferenceNameMask & (1 << other_frame_idx)) != 0) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[other_frame_idx] = 1; |
| encode_info.CodecInfo().encode_av1.picture_info.primaryReferenceCdfOnly = VK_TRUE; |
| encode_info.CodecInfo().encode_av1.std_picture_info.primary_ref_frame = other_frame_idx; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10331"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[other_frame_idx] = -1; |
| } |
| } |
| } |
| |
| if ((config.EncodeCapsAV1()->unidirectionalCompoundReferenceNameMask & (1 << bwdref_frame_idx)) != 0) { |
| // If BWDREF_FRAME is supported, we clear all group 1 reference names and set it as CDF-only reference |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = |
| VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_UNIDIRECTIONAL_COMPOUND_KHR; |
| |
| for (uint8_t i = last_frame_idx; i < bwdref_frame_idx; ++i) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[bwdref_frame_idx] = 1; |
| encode_info.CodecInfo().encode_av1.picture_info.primaryReferenceCdfOnly = VK_TRUE; |
| encode_info.CodecInfo().encode_av1.std_picture_info.primary_ref_frame = bwdref_frame_idx; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10331"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| if ((config.EncodeCapsAV1()->unidirectionalCompoundReferenceNameMask & (1 << altref_frame_idx)) != 0) { |
| // If ALTREF_FRAME is supported, we clear all group 1 reference names and set it as CDF-only reference |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = |
| VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_UNIDIRECTIONAL_COMPOUND_KHR; |
| |
| for (uint8_t i = last_frame_idx; i < bwdref_frame_idx; ++i) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[altref_frame_idx] = 1; |
| encode_info.CodecInfo().encode_av1.picture_info.primaryReferenceCdfOnly = VK_TRUE; |
| encode_info.CodecInfo().encode_av1.std_picture_info.primary_ref_frame = altref_frame_idx; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10331"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeBidirectionalCompoundNotSupported) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - AV1 bidirectional compound prediction mode not supported"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Bidirectional compound prediction requires at least one active reference picture |
| // No need for two pictures as both reference names can point to the same picture |
| const uint32_t min_ref_count = 1; |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [&](const VideoConfig& config) { |
| return config.Caps()->maxDpbSlots > min_ref_count && config.Caps()->maxActiveReferencePictures >= min_ref_count && |
| config.EncodeCapsAV1()->maxBidirectionalCompoundReferenceCount == 0; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with no bidirectional compound prediction mode support"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = min_ref_count + 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = min_ref_count; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(-1, 0).AddResource(1, 1)); |
| |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_BIDIRECTIONAL_COMPOUND_KHR; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-maxBidirectionalCompoundReferenceCount-10332"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidBidirectionalCompound) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - Unsupported AV1 bidirectional compound reference names"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Bidirectional compound prediction requires at least one active reference picture |
| // No need for two pictures as both reference names can point to the same picture |
| const uint32_t min_ref_count = 1; |
| |
| // We need to find an unsupported AV1 reference name |
| const uint32_t ref_name_mask = 0x7F; |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [&](const VideoConfig& config) { |
| return config.Caps()->maxDpbSlots > min_ref_count && config.Caps()->maxActiveReferencePictures >= min_ref_count && |
| config.EncodeCapsAV1()->maxBidirectionalCompoundReferenceCount > 0 && |
| (config.EncodeCapsAV1()->bidirectionalCompoundReferenceNameMask & ref_name_mask) != ref_name_mask; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with bidirectional compound prediction mode support"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = min_ref_count + 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = min_ref_count; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(-1, 0).AddResource(1, 1)); |
| |
| const uint32_t bwdref_frame_idx = STD_VIDEO_AV1_REFERENCE_NAME_BWDREF_FRAME - 1; |
| |
| // Clear all supported reference name indices from group 1 |
| { |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = |
| VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_BIDIRECTIONAL_COMPOUND_KHR; |
| |
| for (uint32_t i = 0; i < bwdref_frame_idx; ++i) { |
| if ((config.EncodeCapsAV1()->bidirectionalCompoundReferenceNameMask & (1 << i)) != 0) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } |
| } |
| |
| // This may trigger the VU related to primary_ref_frame DPB slot index |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1PictureInfoKHR-pStdPictureInfo-10291"); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10333"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Clear all supported reference name indices from group 2 |
| { |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = |
| VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_BIDIRECTIONAL_COMPOUND_KHR; |
| |
| for (uint32_t i = bwdref_frame_idx; i < VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR; ++i) { |
| if ((config.EncodeCapsAV1()->bidirectionalCompoundReferenceNameMask & (1 << i)) != 0) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } |
| } |
| |
| // This may trigger the VU related to primary_ref_frame DPB slot index |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkVideoEncodeAV1PictureInfoKHR-pStdPictureInfo-10291"); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10333"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidBidirectionalCompoundCdfOnly) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - Unsupported CDF-only AV1 bidirectional compound reference names"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| // Bidirectional compound prediction requires at least one active reference picture |
| // No need for two pictures as both reference names can point to the same picture |
| // The CDF-only reference can also refer to the same reference slot, only the reference name has to differ |
| const uint32_t min_ref_count = 1; |
| |
| VideoConfig config = GetConfig(FilterConfigs(GetConfigsEncodeAV1(), [&](const VideoConfig& config) { |
| return config.Caps()->maxDpbSlots > min_ref_count && config.Caps()->maxActiveReferencePictures >= min_ref_count && |
| config.EncodeCapsAV1()->maxBidirectionalCompoundReferenceCount > 0 && |
| (config.EncodeCapsAV1()->flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_PRIMARY_REFERENCE_CDF_ONLY_BIT_KHR) != 0; |
| })); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with bidirectional compound prediction mode " |
| "and CDF-only primary reference support"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = min_ref_count + 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = min_ref_count; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(-1, 0).AddResource(1, 1)); |
| |
| const uint8_t bwdref_frame_idx = STD_VIDEO_AV1_REFERENCE_NAME_BWDREF_FRAME - 1; |
| |
| // Clear all supported reference name indices from group 1 |
| { |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = |
| VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_BIDIRECTIONAL_COMPOUND_KHR; |
| |
| uint8_t supported_group1_ref_idx = 0; |
| for (uint8_t i = 0; i < bwdref_frame_idx; ++i) { |
| if ((config.EncodeCapsAV1()->bidirectionalCompoundReferenceNameMask & (1 << i)) != 0) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } else { |
| // Remember one of the supported group 1 reference names as we will use that as CDF-only reference |
| supported_group1_ref_idx = i; |
| } |
| } |
| |
| // Use the supported group 1 reference name as CDF-only reference |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[supported_group1_ref_idx] = 1; |
| encode_info.CodecInfo().encode_av1.picture_info.primaryReferenceCdfOnly = VK_TRUE; |
| encode_info.CodecInfo().encode_av1.std_picture_info.primary_ref_frame = supported_group1_ref_idx; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10333"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Clear all supported reference name indices from group 2 |
| { |
| VideoEncodeInfo encode_info = context.EncodeFrame(0).AddReferenceFrame(1); |
| encode_info.CodecInfo().encode_av1.picture_info.predictionMode = |
| VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_BIDIRECTIONAL_COMPOUND_KHR; |
| |
| uint8_t supported_group2_ref_idx = 0; |
| for (uint8_t i = bwdref_frame_idx; i < VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR; ++i) { |
| if ((config.EncodeCapsAV1()->bidirectionalCompoundReferenceNameMask & (1 << i)) != 0) { |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[i] = -1; |
| } else { |
| // Remember one of the supported group 2 reference names as we will use that as CDF-only reference |
| supported_group2_ref_idx = i; |
| } |
| } |
| |
| // Use the supported group 2 reference name as CDF-only reference |
| encode_info.CodecInfo().encode_av1.picture_info.referenceNameSlotIndices[supported_group2_ref_idx] = 1; |
| encode_info.CodecInfo().encode_av1.picture_info.primaryReferenceCdfOnly = VK_TRUE; |
| encode_info.CodecInfo().encode_av1.std_picture_info.primary_ref_frame = supported_group2_ref_idx; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-predictionMode-10333"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeObuExtHeaderPictureSetupMismatch) { |
| TEST_DESCRIPTION( |
| "vkCmdEncodeVideoKHR - AV1 OBU extension header must be specified for both or neither of picture and setup info"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithDpbSlots(GetConfigsWithReferences(GetConfigsEncodeAV1()))); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with DPB slots"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = 1; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(0, 0)); |
| |
| // Picture info has AV1 OBU extension header info but the setup reference info does not |
| { |
| StdVideoEncodeAV1ExtensionHeader av1_obu_ext_header{}; |
| auto encode_info = context.EncodeFrame(0); |
| encode_info.CodecInfo().encode_av1.std_picture_info.pExtensionHeader = &av1_obu_ext_header; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pEncodeInfo-10338"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Setup reference info has AV1 OBU extension header info but the picture info does not |
| { |
| StdVideoEncodeAV1ExtensionHeader av1_obu_ext_header{}; |
| auto encode_info = context.EncodeFrame(0); |
| encode_info.CodecInfo().encode_av1.std_setup_reference_info.pExtensionHeader = &av1_obu_ext_header; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pEncodeInfo-10338"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidTemporalId) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - AV1 temporal ID exceeds maxTemporalLayerCount"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithDpbSlots(GetConfigsWithReferences(GetConfigsEncodeAV1()), 2)); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with reference pictures and 2 DPB slots"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = 2; |
| config.SessionCreateInfo()->maxActiveReferencePictures = 1; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(0, 0).AddResource(-1, 1)); |
| |
| // Picture temporal_id >= maxTemporalLayerCount |
| { |
| StdVideoEncodeAV1ExtensionHeader av1_obu_ext_header{}; |
| auto encode_info = context.EncodeFrame(0); |
| encode_info.CodecInfo().encode_av1.std_picture_info.pExtensionHeader = &av1_obu_ext_header; |
| encode_info.CodecInfo().encode_av1.std_setup_reference_info.pExtensionHeader = &av1_obu_ext_header; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pExtensionHeader-10336"); |
| av1_obu_ext_header.temporal_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxTemporalLayerCount + 1); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pExtensionHeader-10336"); |
| av1_obu_ext_header.temporal_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxTemporalLayerCount); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| av1_obu_ext_header.temporal_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxTemporalLayerCount - 1); |
| cb.EncodeVideo(encode_info); |
| } |
| |
| // Reference temporal_id >= maxTemporalLayerCount |
| { |
| StdVideoEncodeAV1ExtensionHeader av1_obu_ext_header{}; |
| auto encode_info = context.EncodeFrame(1).AddReferenceFrame(0); |
| encode_info.CodecInfo().encode_av1.std_reference_info[0].pExtensionHeader = &av1_obu_ext_header; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pExtensionHeader-10341"); |
| av1_obu_ext_header.temporal_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxTemporalLayerCount + 1); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pExtensionHeader-10341"); |
| av1_obu_ext_header.temporal_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxTemporalLayerCount); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| av1_obu_ext_header.temporal_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxTemporalLayerCount - 1); |
| cb.EncodeVideo(encode_info); |
| } |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodePictureSetupTemporalIdMismatch) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - temporal_id mismatch between picture and setup info"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithDpbSlots(GetConfigsWithReferences(FilterConfigs( |
| GetConfigsEncodeAV1(), [](const VideoConfig& config) { return config.EncodeCapsAV1()->maxTemporalLayerCount > 1; })))); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with DPB slots and multiple temporal layers"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = 1; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(0, 0)); |
| |
| StdVideoEncodeAV1ExtensionHeader picture_av1_obu_ext_header{}; |
| StdVideoEncodeAV1ExtensionHeader setup_av1_obu_ext_header{}; |
| auto encode_info = context.EncodeFrame(0); |
| encode_info.CodecInfo().encode_av1.std_picture_info.pExtensionHeader = &picture_av1_obu_ext_header; |
| encode_info.CodecInfo().encode_av1.std_setup_reference_info.pExtensionHeader = &setup_av1_obu_ext_header; |
| |
| picture_av1_obu_ext_header.temporal_id = 0; |
| setup_av1_obu_ext_header.temporal_id = 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pEncodeInfo-10339"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodeInvalidSpatialId) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - AV1 spatial ID exceeds maxSpatialLayerCount"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithDpbSlots(GetConfigsWithReferences(GetConfigsEncodeAV1()), 2)); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with reference pictures and 2 DPB slots"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = 2; |
| config.SessionCreateInfo()->maxActiveReferencePictures = 1; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(0, 0).AddResource(-1, 1)); |
| |
| // Picture spatial_id >= maxSpatialLayerCount |
| { |
| StdVideoEncodeAV1ExtensionHeader av1_obu_ext_header{}; |
| auto encode_info = context.EncodeFrame(0); |
| encode_info.CodecInfo().encode_av1.std_picture_info.pExtensionHeader = &av1_obu_ext_header; |
| encode_info.CodecInfo().encode_av1.std_setup_reference_info.pExtensionHeader = &av1_obu_ext_header; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pExtensionHeader-10337"); |
| av1_obu_ext_header.spatial_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxSpatialLayerCount + 1); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pExtensionHeader-10337"); |
| av1_obu_ext_header.spatial_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxSpatialLayerCount); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| av1_obu_ext_header.spatial_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxSpatialLayerCount - 1); |
| cb.EncodeVideo(encode_info); |
| } |
| |
| // Reference spatial_id >= maxSpatialLayerCount |
| { |
| StdVideoEncodeAV1ExtensionHeader av1_obu_ext_header{}; |
| auto encode_info = context.EncodeFrame(1).AddReferenceFrame(0); |
| encode_info.CodecInfo().encode_av1.std_reference_info[0].pExtensionHeader = &av1_obu_ext_header; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pExtensionHeader-10342"); |
| av1_obu_ext_header.spatial_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxSpatialLayerCount + 1); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pExtensionHeader-10342"); |
| av1_obu_ext_header.spatial_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxSpatialLayerCount); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| av1_obu_ext_header.spatial_id = static_cast<uint8_t>(config.EncodeCapsAV1()->maxSpatialLayerCount - 1); |
| cb.EncodeVideo(encode_info); |
| } |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, EncodePictureSetupSpatialIdMismatch) { |
| TEST_DESCRIPTION("vkCmdEncodeVideoKHR - spatial_id mismatch between picture and setup info"); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfig(GetConfigsWithDpbSlots(GetConfigsWithReferences(FilterConfigs( |
| GetConfigsEncodeAV1(), [](const VideoConfig& config) { return config.EncodeCapsAV1()->maxSpatialLayerCount > 1; })))); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support with DPB slots and multiple spatial layers"; |
| } |
| |
| config.SessionCreateInfo()->maxDpbSlots = 1; |
| config.SessionCreateInfo()->maxActiveReferencePictures = 1; |
| |
| VideoContext context(m_device, config); |
| context.CreateAndBindSessionMemory(); |
| context.CreateResources(); |
| |
| vkt::CommandBuffer& cb = context.CmdBuffer(); |
| |
| cb.Begin(); |
| cb.BeginVideoCoding(context.Begin().AddResource(0, 0)); |
| |
| StdVideoEncodeAV1ExtensionHeader picture_av1_obu_ext_header{}; |
| StdVideoEncodeAV1ExtensionHeader setup_av1_obu_ext_header{}; |
| auto encode_info = context.EncodeFrame(0); |
| encode_info.CodecInfo().encode_av1.std_picture_info.pExtensionHeader = &picture_av1_obu_ext_header; |
| encode_info.CodecInfo().encode_av1.std_setup_reference_info.pExtensionHeader = &setup_av1_obu_ext_header; |
| |
| picture_av1_obu_ext_header.spatial_id = 0; |
| setup_av1_obu_ext_header.spatial_id = 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdEncodeVideoKHR-pEncodeInfo-10340"); |
| cb.EncodeVideo(encode_info); |
| m_errorMonitor->VerifyFound(); |
| |
| cb.EndVideoCoding(context.End()); |
| cb.End(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, CreateBufferVideoEncodeAV1NotEnabled) { |
| TEST_DESCRIPTION("vkCreateBuffer - AV1 encode is specified but videoEncodeAV1 was not enabled"); |
| |
| ForceDisableFeature(vkt::Feature::videoEncodeAV1); |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VkBuffer buffer = VK_NULL_HANDLE; |
| VkBufferCreateInfo buffer_ci = vku::InitStructHelper(); |
| buffer_ci.usage = VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR; |
| buffer_ci.size = 2048; |
| |
| VkVideoProfileListInfoKHR video_profiles = vku::InitStructHelper(); |
| video_profiles.profileCount = 1; |
| video_profiles.pProfiles = config.Profile(); |
| buffer_ci.pNext = &video_profiles; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkBufferCreateInfo-pNext-10249"); |
| vk::CreateBuffer(device(), &buffer_ci, nullptr, &buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, CreateImageVideoEncodeAV1NotEnabled) { |
| TEST_DESCRIPTION("vkCreateImage - AV1 encode is specified but videoEncodeAV1 was not enabled"); |
| |
| ForceDisableFeature(vkt::Feature::videoEncodeAV1); |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| VkImage image = VK_NULL_HANDLE; |
| VkImageCreateInfo image_ci = vku::InitStructHelper(); |
| image_ci.imageType = config.PictureFormatProps()->imageType; |
| image_ci.format = config.PictureFormatProps()->format; |
| image_ci.extent = {config.MaxCodedExtent().width, config.MaxCodedExtent().height, 1}; |
| image_ci.mipLevels = 1; |
| image_ci.arrayLayers = 1; |
| image_ci.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_ci.tiling = config.PictureFormatProps()->imageTiling; |
| image_ci.usage = config.PictureFormatProps()->imageUsageFlags; |
| image_ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| |
| VkVideoProfileListInfoKHR video_profiles = vku::InitStructHelper(); |
| video_profiles.profileCount = 1; |
| video_profiles.pProfiles = config.Profile(); |
| image_ci.pNext = &video_profiles; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkImageCreateInfo-pNext-10250"); |
| vk::CreateImage(device(), &image_ci, nullptr, &image); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeVideoEncodeAV1, CreateQueryPoolVideoEncodeAV1NotEnabled) { |
| TEST_DESCRIPTION("vkCreateQueryPool - AV1 encode is specified but videoEncodeAV1 was not enabled"); |
| |
| ForceDisableFeature(vkt::Feature::videoEncodeAV1); |
| RETURN_IF_SKIP(Init()); |
| |
| VideoConfig config = GetConfigEncodeAV1(); |
| if (!config) { |
| GTEST_SKIP() << "Test requires AV1 encode support"; |
| } |
| |
| auto encode_feedback_info = vku::InitStruct<VkQueryPoolVideoEncodeFeedbackCreateInfoKHR>(config.Profile()); |
| encode_feedback_info.encodeFeedbackFlags = VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BYTES_WRITTEN_BIT_KHR; |
| |
| VkQueryPool query_pool = VK_NULL_HANDLE; |
| auto create_info = vku::InitStruct<VkQueryPoolCreateInfo>(&encode_feedback_info); |
| create_info.queryType = VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR; |
| create_info.queryCount = 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkQueryPoolCreateInfo-pNext-10248"); |
| vk::CreateQueryPool(device(), &create_info, nullptr, &query_pool); |
| m_errorMonitor->VerifyFound(); |
| } |