blob: 091f9dcc94ea5629365cd5471dfb155e2e6bff3f [file] [log] [blame]
/*
* 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, &params);
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, &params);
create_info.videoSessionParametersTemplate = params;
m_errorMonitor->SetDesiredError("VUID-VkVideoSessionParametersCreateInfoKHR-videoSession-10278");
vk::CreateVideoSessionParametersKHR(device(), &create_info, nullptr, &params2);
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, &params);
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, &params);
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();
}