blob: 679ff84cd78d103964173602a3c9c66e5645eaa5 [file] [log] [blame]
/* Copyright (c) 2022-2023 The Khronos Group Inc.
* Copyright (c) 2022-2023 RasterGrid Kft.
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <assert.h>
#include <vector>
#include <vulkan/vk_enum_string_helper.h>
#include "generated/chassis.h"
#include "core_validation.h"
// Flags validation error if the associated call is made inside a video coding block.
// The apiName routine should ONLY be called outside a video coding block.
bool CoreChecks::InsideVideoCodingScope(const CMD_BUFFER_STATE &cb_state, const Location &loc, const char *vuid) const {
bool inside = false;
if (cb_state.bound_video_session) {
inside = LogError(vuid, cb_state.commandBuffer(), loc, "It is invalid to issue this call inside a video coding block.");
}
return inside;
}
// Flags validation error if the associated call is made outside a video coding block.
// The apiName routine should ONLY be called inside a video coding block.
bool CoreChecks::OutsideVideoCodingScope(const CMD_BUFFER_STATE &cb_state, const Location &loc, const char *vuid) const {
bool outside = false;
if (!cb_state.bound_video_session) {
outside = LogError(vuid, cb_state.commandBuffer(), loc, "This call must be issued inside a video coding block.");
}
return outside;
}
std::vector<VkVideoFormatPropertiesKHR> CoreChecks::GetVideoFormatProperties(VkImageUsageFlags image_usage,
const VkVideoProfileListInfoKHR *profile_list) const {
VkPhysicalDeviceVideoFormatInfoKHR format_info = vku::InitStructHelper();
format_info.imageUsage = image_usage;
format_info.pNext = profile_list;
uint32_t format_count = 0;
DispatchGetPhysicalDeviceVideoFormatPropertiesKHR(physical_device, &format_info, &format_count, nullptr);
std::vector<VkVideoFormatPropertiesKHR> format_props(format_count, vku::InitStruct<VkVideoFormatPropertiesKHR>());
DispatchGetPhysicalDeviceVideoFormatPropertiesKHR(physical_device, &format_info, &format_count, format_props.data());
return format_props;
}
std::vector<VkVideoFormatPropertiesKHR> CoreChecks::GetVideoFormatProperties(VkImageUsageFlags image_usage,
const VkVideoProfileInfoKHR *profile) const {
VkVideoProfileListInfoKHR profile_list = vku::InitStructHelper();
profile_list.profileCount = 1;
profile_list.pProfiles = profile;
return GetVideoFormatProperties(image_usage, &profile_list);
}
bool CoreChecks::IsVideoFormatSupported(VkFormat format, VkImageUsageFlags image_usage,
const VkVideoProfileInfoKHR *profile) const {
auto format_props_list = GetVideoFormatProperties(image_usage, profile);
for (const auto &format_props : format_props_list) {
if (format_props.format == format) return true;
}
return false;
}
bool CoreChecks::ValidateVideoPictureResource(const VideoPictureResource &picture_resource, VkCommandBuffer cmdbuf,
const VIDEO_SESSION_STATE &vs_state, const char *api_name, const char *where,
const char *coded_offset_vuid, const char *coded_extent_vuid) const {
bool skip = false;
const auto &profile_caps = vs_state.profile->GetCapabilities();
if (coded_offset_vuid) {
VkOffset2D offset_granularity{0, 0};
if (vs_state.GetCodecOp() == VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR &&
vs_state.GetH264PictureLayout() == VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_SEPARATE_PLANES_BIT_KHR) {
offset_granularity = profile_caps.decode_h264.fieldOffsetGranularity;
}
if (!IsIntegerMultipleOf(picture_resource.coded_offset, offset_granularity)) {
LogObjectList objlist(cmdbuf);
objlist.add(vs_state.videoSession());
skip |= LogError(objlist, coded_offset_vuid,
"%s(): codedOffset (%u,%u) is not an integer multiple of the codedOffsetGranularity (%u,%u).%s",
api_name, picture_resource.coded_offset.x, picture_resource.coded_offset.y, offset_granularity.x,
offset_granularity.y, where);
}
}
if (coded_extent_vuid &&
!IsBetweenInclusive(picture_resource.coded_extent, profile_caps.base.minCodedExtent, vs_state.create_info.maxCodedExtent)) {
LogObjectList objlist(cmdbuf);
objlist.add(vs_state.videoSession());
skip |= LogError(objlist, coded_extent_vuid,
"%s(): codedExtent (%u,%u) is outside of the range (%u,%u)-(%u,%u) supported by %s.%s", api_name,
picture_resource.coded_extent.width, picture_resource.coded_extent.height,
profile_caps.base.minCodedExtent.width, profile_caps.base.minCodedExtent.height,
vs_state.create_info.maxCodedExtent.width, vs_state.create_info.maxCodedExtent.height,
FormatHandle(vs_state).c_str(), where);
}
if (picture_resource.base_array_layer >= picture_resource.image_view_state->create_info.subresourceRange.layerCount) {
LogObjectList objlist(cmdbuf);
objlist.add(vs_state.videoSession());
objlist.add(picture_resource.image_view_state->Handle());
objlist.add(picture_resource.image_state->Handle());
skip |= LogError(objlist, "VUID-VkVideoPictureResourceInfoKHR-baseArrayLayer-07175",
"%s(): baseArrayLayer (%u) is greater than or equal to the layerCount (%u) "
"the %s specified in imageViewBinding was created with.%s",
api_name, picture_resource.base_array_layer,
picture_resource.image_view_state->create_info.subresourceRange.layerCount,
FormatHandle(picture_resource.image_view_state->Handle()).c_str(), where);
}
return skip;
}
template bool CoreChecks::ValidateVideoProfileInfo<VkDevice>(const VkVideoProfileInfoKHR *profile, const VkDevice object,
const char *api_name, const char *where) const;
template bool CoreChecks::ValidateVideoProfileInfo<VkPhysicalDevice>(const VkVideoProfileInfoKHR *profile,
const VkPhysicalDevice object, const char *api_name,
const char *where) const;
template <typename T1>
bool CoreChecks::ValidateVideoProfileInfo(const VkVideoProfileInfoKHR *profile, const T1 object, const char *api_name,
const char *where) const {
bool skip = false;
const char *profile_pnext_msg = "%s(): missing %s from the pNext chain of %s";
if (GetBitSetCount(profile->chromaSubsampling) != 1) {
skip |= LogError(object, "VUID-VkVideoProfileInfoKHR-chromaSubsampling-07013",
"%s(): chromaSubsampling in %s must have a single bit set", api_name, where);
}
if (GetBitSetCount(profile->lumaBitDepth) != 1) {
skip |= LogError(object, "VUID-VkVideoProfileInfoKHR-lumaBitDepth-07014",
"%s(): lumaBitDepth in %s must have a single bit set", api_name, where);
}
if (profile->chromaSubsampling != VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR) {
if (GetBitSetCount(profile->chromaBitDepth) != 1) {
skip |= LogError(object, "VUID-VkVideoProfileInfoKHR-chromaSubsampling-07015",
"%s(): chromaBitDepth in %s must have a single bit set", api_name, where);
}
}
switch (profile->videoCodecOperation) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR: {
const auto decode_h264 = vku::FindStructInPNextChain<VkVideoDecodeH264ProfileInfoKHR>(profile->pNext);
if (decode_h264 == nullptr) {
skip |= LogError(object, "VUID-VkVideoProfileInfoKHR-videoCodecOperation-07179", profile_pnext_msg, api_name,
"VkVideoDecodeH264ProfileInfoKHR", where);
}
break;
}
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR: {
const auto decode_h265 = vku::FindStructInPNextChain<VkVideoDecodeH265ProfileInfoKHR>(profile->pNext);
if (decode_h265 == nullptr) {
skip |= LogError(object, "VUID-VkVideoProfileInfoKHR-videoCodecOperation-07180", profile_pnext_msg, api_name,
"VkVideoDecodeH265ProfileInfoKHR", where);
}
break;
}
default:
assert(false);
skip = true;
break;
}
return skip;
}
template bool CoreChecks::ValidateVideoProfileListInfo<VkDevice>(
const VkVideoProfileListInfoKHR *profile_list, const VkDevice object, const char *api_name, bool expect_decode_profile,
const char *missing_decode_profile_msg_code, bool expect_encode_profile, const char *missing_encode_profile_msg_code) const;
template bool CoreChecks::ValidateVideoProfileListInfo<VkPhysicalDevice>(
const VkVideoProfileListInfoKHR *profile_list, const VkPhysicalDevice object, const char *api_name, bool expect_decode_profile,
const char *missing_decode_profile_msg_code, bool expect_encode_profile, const char *missing_encode_profile_msg_code) const;
template <typename T1>
bool CoreChecks::ValidateVideoProfileListInfo(const VkVideoProfileListInfoKHR *profile_list, const T1 object, const char *api_name,
bool expect_decode_profile, const char *missing_decode_profile_msg_code,
bool expect_encode_profile, const char *missing_encode_profile_msg_code) const {
bool skip = false;
bool has_decode_profile = false;
bool has_encode_profile = false;
if (profile_list) {
char where[64];
for (uint32_t i = 0; i < profile_list->profileCount; ++i) {
snprintf(where, sizeof(where), "VkVideoProfileListInfoKHR::pProfiles[%u]", i);
skip |= ValidateVideoProfileInfo(&profile_list->pProfiles[i], object, api_name, where);
switch (profile_list->pProfiles[i].videoCodecOperation) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
if (has_decode_profile) {
skip |= LogError(object, "VUID-VkVideoProfileListInfoKHR-pProfiles-06813",
"%s(): the video profile list contains more than one profile with decode "
"codec operation",
api_name);
}
has_decode_profile = true;
break;
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_EXT:
case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_EXT:
has_encode_profile = true;
break;
default:
assert(false);
skip = true;
break;
}
}
}
if (expect_decode_profile && !has_decode_profile) {
skip |= LogError(device, missing_decode_profile_msg_code,
"%s(): the video profile list contains no profile with decode codec operation", api_name);
}
if (expect_encode_profile && !has_encode_profile) {
skip |= LogError(device, missing_encode_profile_msg_code,
"%s(): the video profile list contains no profile with encode codec operation", api_name);
}
return skip;
}
bool CoreChecks::ValidateDecodeH264ParametersAddInfo(const VkVideoDecodeH264SessionParametersAddInfoKHR *add_info, VkDevice device,
const char *api_name, const char *where,
const VkVideoDecodeH264SessionParametersCreateInfoKHR *create_info,
const VIDEO_SESSION_PARAMETERS_STATE *template_state) const {
bool skip = false;
vvl::unordered_set<VIDEO_SESSION_PARAMETERS_STATE::ParameterKey> keys;
auto template_data = template_state ? template_state->Lock() : VIDEO_SESSION_PARAMETERS_STATE::ReadOnlyAccessor();
if (add_info) {
// Verify SPS key uniqueness
for (uint32_t i = 0; i < add_info->stdSPSCount; ++i) {
auto key = VIDEO_SESSION_PARAMETERS_STATE::GetH264SPSKey(add_info->pStdSPSs[i]);
if (!keys.emplace(key).second) {
skip |= LogError(device, "VUID-VkVideoDecodeH264SessionParametersAddInfoKHR-None-04825",
"%s(): H.264 SPS keys are not unique in %s", api_name, where);
break;
}
}
}
if (create_info) {
// Verify SPS capacity
if (template_data) {
for (const auto &it : template_data->h264.sps) {
keys.emplace(it.first);
}
}
if (keys.size() > create_info->maxStdSPSCount) {
skip |= LogError(device, "VUID-VkVideoSessionParametersCreateInfoKHR-videoSession-07204",
"%s(): number of H.264 SPS entries to add (%zu) is larger than "
"VkVideoDecodeH264SessionParametersCreateInfoKHR::maxStdSPSCount (%u)",
api_name, keys.size(), create_info->maxStdSPSCount);
}
}
keys.clear();
if (add_info) {
// Verify PPS key uniqueness
for (uint32_t i = 0; i < add_info->stdPPSCount; ++i) {
auto key = VIDEO_SESSION_PARAMETERS_STATE::GetH264PPSKey(add_info->pStdPPSs[i]);
if (!keys.emplace(key).second) {
skip |= LogError(device, "VUID-VkVideoDecodeH264SessionParametersAddInfoKHR-None-04826",
"%s(): H.264 PPS keys are not unique in %s", api_name, where);
break;
}
}
}
if (create_info) {
// Verify PPS capacity
if (template_data) {
for (const auto &it : template_data->h264.pps) {
keys.emplace(it.first);
}
}
if (keys.size() > create_info->maxStdPPSCount) {
skip |= LogError(device, "VUID-VkVideoSessionParametersCreateInfoKHR-videoSession-07205",
"%s(): number of H.264 PPS entries to add (%zu) is larger than "
"VkVideoDecodeH264SessionParametersCreateInfoKHR::maxStdPPSCount (%u)",
api_name, keys.size(), create_info->maxStdPPSCount);
}
}
return skip;
}
bool CoreChecks::ValidateDecodeH265ParametersAddInfo(const VkVideoDecodeH265SessionParametersAddInfoKHR *add_info, VkDevice device,
const char *api_name, const char *where,
const VkVideoDecodeH265SessionParametersCreateInfoKHR *create_info,
const VIDEO_SESSION_PARAMETERS_STATE *template_state) const {
bool skip = false;
vvl::unordered_set<VIDEO_SESSION_PARAMETERS_STATE::ParameterKey> keys;
auto template_data = template_state ? template_state->Lock() : VIDEO_SESSION_PARAMETERS_STATE::ReadOnlyAccessor();
if (add_info) {
// Verify VPS key uniqueness
for (uint32_t i = 0; i < add_info->stdVPSCount; ++i) {
auto key = VIDEO_SESSION_PARAMETERS_STATE::GetH265VPSKey(add_info->pStdVPSs[i]);
if (!keys.emplace(key).second) {
skip |= LogError(device, "VUID-VkVideoDecodeH265SessionParametersAddInfoKHR-None-04833",
"%s(): H.265 VPS keys are not unique in %s", api_name, where);
break;
}
}
}
if (create_info) {
// Verify VPS capacity
if (template_data) {
for (const auto &it : template_data->h265.vps) {
keys.emplace(it.first);
}
}
if (keys.size() > create_info->maxStdVPSCount) {
skip |= LogError(device, "VUID-VkVideoSessionParametersCreateInfoKHR-videoSession-07207",
"%s(): number of H.265 VPS entries to add (%zu) is larger than "
"VkVideoDecodeH265SessionParametersCreateInfoKHR::maxStdVPSCount (%u)",
api_name, keys.size(), create_info->maxStdVPSCount);
}
}
keys.clear();
if (add_info) {
// Verify SPS key uniqueness
for (uint32_t i = 0; i < add_info->stdSPSCount; ++i) {
auto key = VIDEO_SESSION_PARAMETERS_STATE::GetH265SPSKey(add_info->pStdSPSs[i]);
if (!keys.emplace(key).second) {
skip |= LogError(device, "VUID-VkVideoDecodeH265SessionParametersAddInfoKHR-None-04834",
"%s(): H.265 SPS keys are not unique in %s", api_name, where);
break;
}
}
}
if (create_info) {
// Verify SPS capacity
if (template_data) {
for (const auto &it : template_data->h265.sps) {
keys.emplace(it.first);
}
}
if (keys.size() > create_info->maxStdSPSCount) {
skip |= LogError(device, "VUID-VkVideoSessionParametersCreateInfoKHR-videoSession-07208",
"%s(): number of H.265 SPS entries to add (%zu) is larger than "
"VkVideoDecodeH265SessionParametersCreateInfoKHR::maxStdSPSCount (%u)",
api_name, keys.size(), create_info->maxStdSPSCount);
}
}
keys.clear();
if (add_info) {
// Verify PPS key uniqueness
for (uint32_t i = 0; i < add_info->stdPPSCount; ++i) {
auto key = VIDEO_SESSION_PARAMETERS_STATE::GetH265PPSKey(add_info->pStdPPSs[i]);
if (!keys.emplace(key).second) {
skip |= LogError(device, "VUID-VkVideoDecodeH265SessionParametersAddInfoKHR-None-04835",
"%s(): H.265 PPS keys are not unique in %s", api_name, where);
break;
}
}
}
if (create_info) {
// Verify PPS capacity
if (template_data) {
for (const auto &it : template_data->h265.pps) {
keys.emplace(it.first);
}
}
if (keys.size() > create_info->maxStdPPSCount) {
skip |= LogError(device, "VUID-VkVideoSessionParametersCreateInfoKHR-videoSession-07209",
"%s(): number of H.265 PPS entries to add (%zu) is larger than "
"VkVideoDecodeH265SessionParametersCreateInfoKHR::maxStdPPSCount (%u)",
api_name, keys.size(), create_info->maxStdPPSCount);
}
}
return skip;
}
bool CoreChecks::ValidateVideoDecodeInfoH264(const CMD_BUFFER_STATE &cb_state, const VkVideoDecodeInfoKHR &decode_info) const {
bool skip = false;
const char *pnext_msg = "%s(): missing %s from the pNext chain of %s";
const auto &vs_state = *cb_state.bound_video_session;
const auto &vsp_state = *cb_state.bound_video_session_parameters;
const auto session_params = vsp_state.Lock();
bool interlaced_frame_support =
(vs_state.profile->GetH264PictureLayout() != VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_KHR);
auto picture_info = vku::FindStructInPNextChain<VkVideoDecodeH264PictureInfoKHR>(decode_info.pNext);
if (picture_info) {
auto std_picture_info = picture_info->pStdPictureInfo;
if (!interlaced_frame_support && std_picture_info->flags.field_pic_flag) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(vs_state.videoSession());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-None-07258",
"vkCmdDecodeVideoKHR(): decode output picture is a field but the bound video session "
"%s was not created with interlaced frame support",
FormatHandle(vs_state).c_str());
}
for (uint32_t i = 0; i < picture_info->sliceCount; ++i) {
if (picture_info->pSliceOffsets[i] >= decode_info.srcBufferRange) {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-pSliceOffsets-07153",
"vkCmdDecodeVideoKHR(): VkVideoDecodeH264PictureInfoKHR::pSliceOffsets[%u] "
"(%u) is greater than or equal to pDecodeInfo->srcBufferRange (%" PRIu64 ")",
i, picture_info->pSliceOffsets[i], decode_info.srcBufferRange);
}
}
if (session_params.GetH264SPS(std_picture_info->seq_parameter_set_id) == nullptr) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(vsp_state.videoSessionParameters());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-StdVideoH264SequenceParameterSet-07154",
"vkCmdDecodeVideoKHR(): no H.264 SPS with seq_parameter_set_id = %u "
"exists in the bound video session parameters object %s",
std_picture_info->seq_parameter_set_id, FormatHandle(vsp_state).c_str());
}
if (session_params.GetH264PPS(std_picture_info->seq_parameter_set_id, std_picture_info->pic_parameter_set_id) == nullptr) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(vsp_state.videoSessionParameters());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-StdVideoH264PictureParameterSet-07155",
"vkCmdDecodeVideoKHR(): no H.264 PPS with seq_parameter_set_id = %u "
"and pic_parameter_set_id = %u exists in the bound video session parameters object %s",
std_picture_info->seq_parameter_set_id, std_picture_info->pic_parameter_set_id,
FormatHandle(vsp_state).c_str());
}
} else {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-pNext-07152", pnext_msg, "vkCmdDecodeVideoKHR()",
"VkVideoDecodeH264PictureInfoKHR", "pDecodeInfo");
}
if (decode_info.pSetupReferenceSlot) {
auto dpb_slot_info = vku::FindStructInPNextChain<VkVideoDecodeH264DpbSlotInfoKHR>(decode_info.pSetupReferenceSlot->pNext);
if (dpb_slot_info) {
VideoPictureID picture_id(*vs_state.profile, *decode_info.pSetupReferenceSlot);
if (!interlaced_frame_support && !picture_id.IsFrame()) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(vs_state.videoSession());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07259",
"vkCmdDecodeVideoKHR(): reconstructed picture is a field but the bound "
"video session %s was not created with interlaced frame support",
FormatHandle(vs_state).c_str());
}
if (picture_info) {
bool dst_is_field = (picture_info->pStdPictureInfo->flags.field_pic_flag != 0);
bool dst_is_bottom_field = (picture_info->pStdPictureInfo->flags.bottom_field_flag != 0);
if (!dst_is_field && !picture_id.IsFrame()) {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07261",
"vkCmdDecodeVideoKHR(): decode output picture is a frame but the "
"reconstructed picture is not a frame");
}
if (dst_is_field && !dst_is_bottom_field && !picture_id.IsTopField()) {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07262",
"vkCmdDecodeVideoKHR(): decode output picture is a top field but the "
"reconstructed picture is not a top field");
}
if (dst_is_field && dst_is_bottom_field && !picture_id.IsBottomField()) {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07263",
"vkCmdDecodeVideoKHR(): decode output picture is a bottom field but the "
"reconstructed picture is not a bottom field");
}
}
} else {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07156", pnext_msg,
"vkCmdDecodeVideoKHR()", "VkVideoDecodeH264DpbSlotInfoKHR", "pDecodeInfo->pSetupReferenceSlot");
}
}
for (uint32_t i = 0; i < decode_info.referenceSlotCount; ++i) {
auto dpb_slot_info = vku::FindStructInPNextChain<VkVideoDecodeH264DpbSlotInfoKHR>(decode_info.pReferenceSlots[i].pNext);
if (dpb_slot_info) {
VideoPictureID picture_id(*vs_state.profile, decode_info.pReferenceSlots[i]);
if (!interlaced_frame_support && !picture_id.IsFrame()) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(vs_state.videoSession());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07260",
"vkCmdDecodeVideoKHR(): reference picture specified in "
"pDecodeInfo->pReferneceSlots[%u] is a field but the bound "
"video session %s was not created with interlaced frame support",
i, FormatHandle(vs_state).c_str());
}
} else {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-pNext-07157",
"vkCmdDecodeVideoKHR(): missing VkVideoDecodeH264DpbSlotInfoKHR from the "
"pNext chain of pDecodeInfo->pReferenceSlots[%u]",
i);
}
}
return skip;
}
bool CoreChecks::ValidateVideoDecodeInfoH265(const CMD_BUFFER_STATE &cb_state, const VkVideoDecodeInfoKHR &decode_info) const {
bool skip = false;
const char *pnext_msg = "%s(): missing %s from the pNext chain of %s";
const auto &vsp_state = *cb_state.bound_video_session_parameters;
const auto session_params = vsp_state.Lock();
auto picture_info = vku::FindStructInPNextChain<VkVideoDecodeH265PictureInfoKHR>(decode_info.pNext);
if (picture_info) {
auto std_picture_info = picture_info->pStdPictureInfo;
for (uint32_t i = 0; i < picture_info->sliceSegmentCount; ++i) {
if (picture_info->pSliceSegmentOffsets[i] >= decode_info.srcBufferRange) {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-pSliceSegmentOffsets-07159",
"vkCmdDecodeVideoKHR(): VkVideoDecodeH265PictureInfoKHR::pSliceSegmentOffsets[%u] "
"(%u) is greater than or equal to pDecodeInfo->srcBufferRange (%" PRIu64 ")",
i, picture_info->pSliceSegmentOffsets[i], decode_info.srcBufferRange);
}
}
if (session_params.GetH265VPS(std_picture_info->sps_video_parameter_set_id) == nullptr) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(vsp_state.videoSessionParameters());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-StdVideoH265VideoParameterSet-07160",
"vkCmdDecodeVideoKHR(): no H.265 VPS with sps_video_parameter_set_id = %u "
"exists in the bound video session parameters object %s",
std_picture_info->sps_video_parameter_set_id, FormatHandle(vsp_state).c_str());
}
if (session_params.GetH265SPS(std_picture_info->sps_video_parameter_set_id, std_picture_info->pps_seq_parameter_set_id) ==
nullptr) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(vsp_state.videoSessionParameters());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-StdVideoH265SequenceParameterSet-07161",
"vkCmdDecodeVideoKHR(): no H.265 SPS with sps_video_parameter_set_id = %u "
"and pps_seq_parameter_set_id = %u exists in the bound video session "
"parameters object %s",
std_picture_info->sps_video_parameter_set_id, std_picture_info->pps_seq_parameter_set_id,
FormatHandle(vsp_state).c_str());
}
if (session_params.GetH265PPS(std_picture_info->sps_video_parameter_set_id, std_picture_info->pps_seq_parameter_set_id,
std_picture_info->pps_pic_parameter_set_id) == nullptr) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(vsp_state.videoSessionParameters());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-StdVideoH265PictureParameterSet-07162",
"vkCmdDecodeVideoKHR(): no H.265 SPS with sps_video_parameter_set_id = %u, "
"pps_seq_parameter_set_id = %u, and pps_pic_parameter_set_id = %u exists in "
"the bound video session parameters object %s",
std_picture_info->sps_video_parameter_set_id, std_picture_info->pps_seq_parameter_set_id,
std_picture_info->pps_pic_parameter_set_id, FormatHandle(vsp_state).c_str());
}
} else {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-pNext-07158", pnext_msg, "vkCmdDecodeVideoKHR()",
"VkVideoDecodeH265PictureInfoKHR", "pDecodeInfo");
}
if (decode_info.pSetupReferenceSlot) {
auto dpb_slot_info = vku::FindStructInPNextChain<VkVideoDecodeH265DpbSlotInfoKHR>(decode_info.pSetupReferenceSlot->pNext);
if (!dpb_slot_info) {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07163", pnext_msg,
"vkCmdDecodeVideoKHR()", "VkVideoDecodeH265DpbSlotInfoKHR", "pDecodeInfo->pSetupReferenceSlot");
}
}
for (uint32_t i = 0; i < decode_info.referenceSlotCount; ++i) {
auto dpb_slot_info = vku::FindStructInPNextChain<VkVideoDecodeH265DpbSlotInfoKHR>(decode_info.pReferenceSlots[i].pNext);
if (!dpb_slot_info) {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-pNext-07164",
"vkCmdDecodeVideoKHR(): missing VkVideoDecodeH265DpbSlotInfoKHR from the "
"pNext chain of pDecodeInfo->pReferenceSlots[%u]",
i);
}
}
return skip;
}
bool CoreChecks::ValidateActiveReferencePictureCount(const CMD_BUFFER_STATE &cb_state,
const VkVideoDecodeInfoKHR &decode_info) const {
bool skip = false;
const auto &vs_state = *cb_state.bound_video_session;
uint32_t active_reference_picture_count = decode_info.referenceSlotCount;
if (vs_state.GetCodecOp() == VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR) {
for (uint32_t i = 0; i < decode_info.referenceSlotCount; ++i) {
auto dpb_slot_info = vku::FindStructInPNextChain<VkVideoDecodeH264DpbSlotInfoKHR>(decode_info.pReferenceSlots[i].pNext);
if (!dpb_slot_info) continue;
auto std_reference_info = dpb_slot_info->pStdReferenceInfo;
if (!std_reference_info) continue;
if (std_reference_info->flags.top_field_flag && std_reference_info->flags.bottom_field_flag) {
++active_reference_picture_count;
}
}
}
if (active_reference_picture_count > vs_state.create_info.maxActiveReferencePictures) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(vs_state.videoSession());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-activeReferencePictureCount-07150",
"vkCmdDecodeVideoKHR(): more active reference pictures (%u) were specified than "
"the maxActiveReferencePictures (%u) the bound video session %s was created with",
active_reference_picture_count, vs_state.create_info.maxActiveReferencePictures,
FormatHandle(vs_state).c_str());
}
return skip;
}
bool CoreChecks::ValidateReferencePictureUseCount(const CMD_BUFFER_STATE &cb_state, const VkVideoDecodeInfoKHR &decode_info) const {
bool skip = false;
const auto &vs_state = *cb_state.bound_video_session;
std::vector<uint32_t> dpb_frame_use_count(vs_state.create_info.maxDpbSlots, 0);
bool interlaced_frame_support = false;
std::vector<uint32_t> dpb_top_field_use_count;
std::vector<uint32_t> dpb_bottom_field_use_count;
if (vs_state.GetCodecOp() == VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR) {
if (vs_state.profile->GetH264PictureLayout() != VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_KHR) {
interlaced_frame_support = true;
dpb_top_field_use_count.resize(vs_state.create_info.maxDpbSlots, 0);
dpb_bottom_field_use_count.resize(vs_state.create_info.maxDpbSlots, 0);
}
}
// Collect use count for each DPB across the elements pReferenceSlots and pSetupReferenceSlot
for (uint32_t i = 0; i <= decode_info.referenceSlotCount; ++i) {
const VkVideoReferenceSlotInfoKHR *slot =
(i == decode_info.referenceSlotCount) ? decode_info.pSetupReferenceSlot : &decode_info.pReferenceSlots[i];
if (slot == nullptr) continue;
if (slot->slotIndex < 0 || (uint32_t)slot->slotIndex >= vs_state.create_info.maxDpbSlots) continue;
++dpb_frame_use_count[slot->slotIndex];
if (!interlaced_frame_support) continue;
if (vs_state.GetCodecOp() == VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR) {
auto dpb_slot_info = vku::FindStructInPNextChain<VkVideoDecodeH264DpbSlotInfoKHR>(slot->pNext);
if (!dpb_slot_info) continue;
auto std_reference_info = dpb_slot_info->pStdReferenceInfo;
if (!std_reference_info) continue;
if (std_reference_info->flags.top_field_flag || std_reference_info->flags.bottom_field_flag) {
--dpb_frame_use_count[slot->slotIndex];
}
if (std_reference_info->flags.top_field_flag) {
++dpb_top_field_use_count[slot->slotIndex];
}
if (std_reference_info->flags.bottom_field_flag) {
++dpb_bottom_field_use_count[slot->slotIndex];
}
}
}
for (uint32_t i = 0; i < vs_state.create_info.maxDpbSlots; ++i) {
if (dpb_frame_use_count[i] > 1) {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-dpbFrameUseCount-07176",
"vkCmdDecodeVideoKHR(): frame in DPB slot %u is referred to multiple times across "
"pDecodeInfo->pSetupReferenceSlot and the elements of pDecodeInfo->pReferenceSlots",
i);
}
if (interlaced_frame_support) {
if (dpb_top_field_use_count[i] > 1) {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-dpbTopFieldUseCount-07177",
"vkCmdDecodeVideoKHR(): top field in DPB slot %u is referred to multiple "
"times across pDecodeInfo->pSetupReferenceSlot and the elements of "
"pDecodeInfo->pReferenceSlots",
i);
}
if (dpb_bottom_field_use_count[i] > 1) {
skip |= LogError(cb_state.commandBuffer(), "VUID-vkCmdDecodeVideoKHR-dpbBottomFieldUseCount-07178",
"vkCmdDecodeVideoKHR(): bottom field in DPB slot %u is referred to multiple "
"times across pDecodeInfo->pSetupReferenceSlot and the elements of "
"pDecodeInfo->pReferenceSlots",
i);
}
}
}
return skip;
}
bool CoreChecks::PreCallValidateGetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice,
const VkVideoProfileInfoKHR *pVideoProfile,
VkVideoCapabilitiesKHR *pCapabilities,
const ErrorObject &error_obj) const {
bool skip = false;
skip |= ValidateVideoProfileInfo(pVideoProfile, device, "vkGetPhysicalDeviceVideoCapabilitiesKHR", "pVideoProfile");
const char *caps_pnext_msg = "vkGetPhysicalDeviceVideoCapabilitiesKHR(): Missing %s from the pNext chain of pCapabilities";
bool is_decode = false;
switch (pVideoProfile->videoCodecOperation) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
is_decode = true;
if (!vku::FindStructInPNextChain<VkVideoDecodeH264CapabilitiesKHR>(pCapabilities->pNext)) {
skip |= LogError(physicalDevice, "VUID-vkGetPhysicalDeviceVideoCapabilitiesKHR-pVideoProfile-07184", caps_pnext_msg,
"VkVideoDecodeH264CapabilitiesKHR");
}
break;
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
is_decode = true;
if (!vku::FindStructInPNextChain<VkVideoDecodeH265CapabilitiesKHR>(pCapabilities->pNext)) {
skip |= LogError(physicalDevice, "VUID-vkGetPhysicalDeviceVideoCapabilitiesKHR-pVideoProfile-07185", caps_pnext_msg,
"VkVideoDecodeH265CapabilitiesKHR");
}
break;
default:
break;
}
if (is_decode && !vku::FindStructInPNextChain<VkVideoDecodeCapabilitiesKHR>(pCapabilities->pNext)) {
skip |= LogError(physicalDevice, "VUID-vkGetPhysicalDeviceVideoCapabilitiesKHR-pVideoProfile-07183", caps_pnext_msg,
"VkVideoDecodeCapabilitiesKHR");
}
return skip;
}
bool CoreChecks::PreCallValidateGetPhysicalDeviceVideoFormatPropertiesKHR(
VkPhysicalDevice physicalDevice, const VkPhysicalDeviceVideoFormatInfoKHR *pVideoFormatInfo,
uint32_t *pVideoFormatPropertyCount, VkVideoFormatPropertiesKHR *pVideoFormatProperties, const ErrorObject &error_obj) const {
bool skip = false;
const auto *video_profiles = vku::FindStructInPNextChain<VkVideoProfileListInfoKHR>(pVideoFormatInfo->pNext);
if (video_profiles && video_profiles->profileCount != 0) {
skip |= ValidateVideoProfileListInfo(video_profiles, physicalDevice, "vkGetPhysicalDeviceVideoFormatPropertiesKHR", false,
nullptr, false, nullptr);
} else {
const char *msg = video_profiles ? "no VkVideoProfileListInfoKHR structure found in the pNext chain of pVideoFormatInfo"
: "profileCount is zero in the VkVideoProfileListInfoKHR structure included in the "
"pNext chain of pVideoFormatInfo";
skip |= LogError(physicalDevice, "VUID-vkGetPhysicalDeviceVideoFormatPropertiesKHR-pNext-06812",
"vkGetPhysicalDeviceVideoFormatPropertiesKHR(): %s", msg);
}
return skip;
}
bool CoreChecks::PreCallValidateCreateVideoSessionKHR(VkDevice device, const VkVideoSessionCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkVideoSessionKHR *pVideoSession,
const ErrorObject &error_obj) const {
bool skip = false;
skip |= ValidateVideoProfileInfo(pCreateInfo->pVideoProfile, device, "vkCreateVideoSessionKHR", "pCreateInfo->pVideoProfile");
VideoProfileDesc profile_desc(this, pCreateInfo->pVideoProfile);
const auto &profile_caps = profile_desc.GetCapabilities();
if (profile_caps.supported) {
if (pCreateInfo->flags & VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR) {
const char *error_msg = nullptr;
if (enabled_features.core11.protectedMemory == VK_FALSE) {
error_msg = "the protectedMemory feature is not enabled";
} else if ((profile_caps.base.flags & VK_VIDEO_CAPABILITY_PROTECTED_CONTENT_BIT_KHR) == 0) {
error_msg = "protected content is not supported for the video profile";
}
if (error_msg != nullptr) {
skip |= LogError(device, "VUID-VkVideoSessionCreateInfoKHR-protectedMemory-07189",
"vkCreateVideoSessionKHR(): VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR "
"was specified but %s",
error_msg);
}
}
if (!IsBetweenInclusive(pCreateInfo->maxCodedExtent, profile_caps.base.minCodedExtent, profile_caps.base.maxCodedExtent)) {
skip |= LogError(device, "VUID-VkVideoSessionCreateInfoKHR-maxCodedExtent-04851",
"vkCreateVideoSessionKHR(): pCreateInfo->maxCodedExtent (%u,%u) is outside of the "
"range (%u,%u)-(%u,%u) supported by the video profile",
pCreateInfo->maxCodedExtent.width, pCreateInfo->maxCodedExtent.height,
profile_caps.base.minCodedExtent.width, profile_caps.base.minCodedExtent.height,
profile_caps.base.maxCodedExtent.width, profile_caps.base.maxCodedExtent.height);
}
if (pCreateInfo->maxDpbSlots > profile_caps.base.maxDpbSlots) {
skip |= LogError(device, "VUID-VkVideoSessionCreateInfoKHR-maxDpbSlots-04847",
"vkCreateVideoSessionKHR(): pCreateInfo->maxDpbSlots (%u) is greater than the "
"maxDpbSlots (%u) supported by the video profile",
pCreateInfo->maxDpbSlots, profile_caps.base.maxDpbSlots);
}
if (pCreateInfo->maxActiveReferencePictures > profile_caps.base.maxActiveReferencePictures) {
skip |= LogError(device, "VUID-VkVideoSessionCreateInfoKHR-maxActiveReferencePictures-04849",
"vkCreateVideoSessionKHR(): pCreateInfo->maxActiveReferencePictures (%u) is greater "
"than the maxActiveReferencePictures (%u) supported by the video profile",
pCreateInfo->maxActiveReferencePictures, profile_caps.base.maxActiveReferencePictures);
}
if ((pCreateInfo->maxDpbSlots == 0 && pCreateInfo->maxActiveReferencePictures != 0) ||
(pCreateInfo->maxDpbSlots != 0 && pCreateInfo->maxActiveReferencePictures == 0)) {
skip |= LogError(device, "VUID-VkVideoSessionCreateInfoKHR-maxDpbSlots-04850",
"vkCreateVideoSessionKHR(): if either pCreateInfo->maxDpbSlots (%u) or "
"pCreateInfo->maxActiveReferencePictures (%u) is zero then both must be zero",
pCreateInfo->maxDpbSlots, pCreateInfo->maxActiveReferencePictures);
}
if (profile_desc.GetProfile().is_decode && pCreateInfo->maxActiveReferencePictures > 0 &&
!IsVideoFormatSupported(pCreateInfo->referencePictureFormat, VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR,
pCreateInfo->pVideoProfile)) {
skip |= LogError(device, "VUID-VkVideoSessionCreateInfoKHR-referencePictureFormat-04852",
"vkCreateVideoSessionKHR(): pCreateInfo->referencePictureFormat (%s) is not a supported "
"decode DPB format for the video profile specified in pCreateInfo->pVideoProfile",
string_VkFormat(pCreateInfo->referencePictureFormat));
}
if (profile_desc.GetProfile().is_decode &&
!IsVideoFormatSupported(pCreateInfo->pictureFormat, VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR,
pCreateInfo->pVideoProfile)) {
skip |= LogError(device, "VUID-VkVideoSessionCreateInfoKHR-pictureFormat-04853",
"vkCreateVideoSessionKHR(): pCreateInfo->pictureFormat (%s) is not a supported "
"decode output format for the video profile specified in pCreateInfo->pVideoProfile",
string_VkFormat(pCreateInfo->pictureFormat));
}
if (strncmp(pCreateInfo->pStdHeaderVersion->extensionName, profile_caps.base.stdHeaderVersion.extensionName,
VK_MAX_EXTENSION_NAME_SIZE)) {
skip |= LogError(device, "VUID-VkVideoSessionCreateInfoKHR-pStdHeaderVersion-07190",
"vkCreateVideoSessionKHR(): unsupported Video Std header name '%.*s' specified in "
"pCreateInfo->pStdHeaderVersion->extensionName, expected '%.*s'",
VK_MAX_EXTENSION_NAME_SIZE, pCreateInfo->pStdHeaderVersion->extensionName, VK_MAX_EXTENSION_NAME_SIZE,
profile_caps.base.stdHeaderVersion.extensionName);
}
if (pCreateInfo->pStdHeaderVersion->specVersion > profile_caps.base.stdHeaderVersion.specVersion) {
skip |= LogError(device, "VUID-VkVideoSessionCreateInfoKHR-pStdHeaderVersion-07191",
"vkCreateVideoSessionKHR(): Video Std header version (0x%08x) specified in "
"pCreateInfo->pStdHeaderVersion->specVersion is larger than the supported version (0x%08x)",
pCreateInfo->pStdHeaderVersion->specVersion, profile_caps.base.stdHeaderVersion.specVersion);
}
} else {
skip |= LogError(device, "VUID-VkVideoSessionCreateInfoKHR-pVideoProfile-04845",
"vkCreateVideoSessionKHR(): the video profile specified in pCreateInfo->pVideoProfile "
"is not supported");
}
return skip;
}
bool CoreChecks::PreCallValidateDestroyVideoSessionKHR(VkDevice device, VkVideoSessionKHR videoSession,
const VkAllocationCallbacks *pAllocator,
const ErrorObject &error_obj) const {
auto video_session_state = Get<VIDEO_SESSION_STATE>(videoSession);
bool skip = false;
if (video_session_state) {
skip |= ValidateObjectNotInUse(video_session_state.get(), error_obj.location,
"VUID-vkDestroyVideoSessionKHR-videoSession-07192");
}
return skip;
}
bool CoreChecks::PreCallValidateBindVideoSessionMemoryKHR(VkDevice device, VkVideoSessionKHR videoSession,
uint32_t bindSessionMemoryInfoCount,
const VkBindVideoSessionMemoryInfoKHR *pBindSessionMemoryInfos,
const ErrorObject &error_obj) const {
bool skip = false;
auto vs_state = Get<VIDEO_SESSION_STATE>(videoSession);
assert(vs_state);
if (pBindSessionMemoryInfos) {
{
vvl::unordered_set<uint32_t> memory_bind_indices;
for (uint32_t i = 0; i < bindSessionMemoryInfoCount; ++i) {
uint32_t mem_bind_index = pBindSessionMemoryInfos[i].memoryBindIndex;
if (memory_bind_indices.find(mem_bind_index) != memory_bind_indices.end()) {
skip |= LogError(videoSession, "VUID-vkBindVideoSessionMemoryKHR-memoryBindIndex-07196",
"vkBindVideoSessionMemoryKHR(): memoryBindIndex values in pBindSessionMemoryInfos "
"array are not unique");
break;
}
memory_bind_indices.emplace(mem_bind_index);
}
}
for (uint32_t i = 0; i < bindSessionMemoryInfoCount; ++i) {
const auto &bind_info = pBindSessionMemoryInfos[i];
const auto &mem_binding_info = vs_state->GetMemoryBindingInfo(bind_info.memoryBindIndex);
if (mem_binding_info != nullptr) {
auto mem_state = Get<DEVICE_MEMORY_STATE>(bind_info.memory);
if (mem_state) {
if (((1 << mem_state->alloc_info.memoryTypeIndex) & mem_binding_info->requirements.memoryTypeBits) == 0) {
LogObjectList objlist(videoSession);
objlist.add(mem_state->Handle());
skip |= LogError(objlist, "VUID-vkBindVideoSessionMemoryKHR-pBindSessionMemoryInfos-07198",
"vkBindVideoSessionMemoryKHR(): memoryTypeBits (0x%x) for memory binding "
"with index %u of %s are not compatible with the memory type index (%u) of "
"%s specified in pBindSessionMemoryInfos[%u].memory",
mem_binding_info->requirements.memoryTypeBits, bind_info.memoryBindIndex,
FormatHandle(videoSession).c_str(), mem_state->alloc_info.memoryTypeIndex,
FormatHandle(*mem_state).c_str(), i);
}
if (bind_info.memoryOffset >= mem_state->alloc_info.allocationSize) {
LogObjectList objlist(videoSession);
objlist.add(mem_state->Handle());
skip |= LogError(objlist, "VUID-VkBindVideoSessionMemoryInfoKHR-memoryOffset-07201",
"vkBindVideoSessionMemoryKHR(): pBindSessionMemoryInfos[%u].memoryOffset (%" PRIuLEAST64
") must be less than the size (%" PRIuLEAST64 ") of %s",
i, bind_info.memoryOffset, mem_state->alloc_info.allocationSize,
FormatHandle(*mem_state).c_str());
} else if (bind_info.memoryOffset + bind_info.memorySize > mem_state->alloc_info.allocationSize) {
LogObjectList objlist(videoSession);
objlist.add(mem_state->Handle());
skip |= LogError(
objlist, "VUID-VkBindVideoSessionMemoryInfoKHR-memorySize-07202",
"vkBindVideoSessionMemoryKHR(): memoryOffset (%" PRIuLEAST64 ") + memory size (%" PRIuLEAST64
") specified in pBindSessionMemoryInfos[%u] must be less than or equal to the size (%" PRIuLEAST64
") of %s",
bind_info.memoryOffset, bind_info.memorySize, i, mem_state->alloc_info.allocationSize,
FormatHandle(*mem_state).c_str());
}
}
if (SafeModulo(bind_info.memoryOffset, mem_binding_info->requirements.alignment) != 0) {
skip |= LogError(videoSession, "VUID-vkBindVideoSessionMemoryKHR-pBindSessionMemoryInfos-07199",
"vkBindVideoSessionMemoryKHR(): pBindSessionMemoryInfos[%u].memoryOffset is %" PRIuLEAST64
" but must be an integer multiple of the alignment value %" PRIuLEAST64
" for the memory binding index %u of %s",
i, bind_info.memoryOffset, mem_binding_info->requirements.alignment, bind_info.memoryBindIndex,
FormatHandle(videoSession).c_str());
}
if (bind_info.memorySize != mem_binding_info->requirements.size) {
skip |= LogError(videoSession, "VUID-vkBindVideoSessionMemoryKHR-pBindSessionMemoryInfos-07200",
"vkBindVideoSessionMemoryKHR(): pBindSessionMemoryInfos[%u].memorySize (%" PRIuLEAST64
") does not equal the required size (%" PRIuLEAST64 ") for the memory binding index %u of %s",
i, bind_info.memorySize, mem_binding_info->requirements.size, bind_info.memoryBindIndex,
FormatHandle(videoSession).c_str());
}
if (mem_binding_info->bound) {
skip |= LogError(videoSession, "VUID-vkBindVideoSessionMemoryKHR-videoSession-07195",
"vkBindVideoSessionMemoryKHR(): memory binding with index %u of %s is already "
"bound but was specified in pBindSessionMemoryInfos[%u].memoryBindIndex",
bind_info.memoryBindIndex, FormatHandle(videoSession).c_str(), i);
}
} else {
skip |= LogError(videoSession, "VUID-vkBindVideoSessionMemoryKHR-pBindSessionMemoryInfos-07197",
"vkBindVideoSessionMemoryKHR(): %s does not have a memory binding corresponding "
"to the memoryBindIndex specified in pBindSessionMemoryInfos[%u]",
FormatHandle(videoSession).c_str(), i);
}
}
}
return skip;
}
bool CoreChecks::PreCallValidateCreateVideoSessionParametersKHR(VkDevice device,
const VkVideoSessionParametersCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkVideoSessionParametersKHR *pVideoSessionParameters,
const ErrorObject &error_obj) const {
bool skip = false;
std::shared_ptr<const VIDEO_SESSION_PARAMETERS_STATE> template_state;
if (pCreateInfo->videoSessionParametersTemplate != VK_NULL_HANDLE) {
template_state = Get<VIDEO_SESSION_PARAMETERS_STATE>(pCreateInfo->videoSessionParametersTemplate);
if (template_state->vs_state->videoSession() != pCreateInfo->videoSession) {
LogObjectList objlist(device);
objlist.add(pCreateInfo->videoSessionParametersTemplate);
objlist.add(pCreateInfo->videoSession);
skip |= LogError(objlist, "VUID-VkVideoSessionParametersCreateInfoKHR-videoSessionParametersTemplate-04855",
"vkCreateVideoSessionParametersKHR(): template %s was not created against the same %s",
FormatHandle(pCreateInfo->videoSessionParametersTemplate).c_str(),
FormatHandle(pCreateInfo->videoSession).c_str());
}
}
auto vs_state = Get<VIDEO_SESSION_STATE>(pCreateInfo->videoSession);
assert(vs_state);
const char *pnext_chain_msg = "vkCreateVideoSessionParametersKHR(): missing %s from pCreateInfo pNext chain";
switch (vs_state->GetCodecOp()) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR: {
auto codec_info = vku::FindStructInPNextChain<VkVideoDecodeH264SessionParametersCreateInfoKHR>(pCreateInfo->pNext);
if (codec_info) {
skip |= ValidateDecodeH264ParametersAddInfo(
codec_info->pParametersAddInfo, device, "vkCreateVideoSessionParametersKHR",
"VkVideoDecodeH264SessionParametersCreateInfoKHR::pParametersAddInfo", codec_info, template_state.get());
} else {
skip |= LogError(device, "VUID-VkVideoSessionParametersCreateInfoKHR-videoSession-07203", pnext_chain_msg,
"VkVideoDecodeH264SessionParametersCreateInfoKHR");
}
break;
}
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR: {
auto codec_info = vku::FindStructInPNextChain<VkVideoDecodeH265SessionParametersCreateInfoKHR>(pCreateInfo->pNext);
if (codec_info) {
skip |= ValidateDecodeH265ParametersAddInfo(
codec_info->pParametersAddInfo, device, "vkCreateVideoSessionParametersKHR",
"VkVideoDecodeH265SessionParametersCreateInfoKHR::pParametersAddInfo", codec_info, template_state.get());
} else {
skip |= LogError(device, "VUID-VkVideoSessionParametersCreateInfoKHR-videoSession-07206", pnext_chain_msg,
"VkVideoDecodeH265SessionParametersCreateInfoKHR");
}
break;
}
default:
break;
}
return skip;
}
bool CoreChecks::PreCallValidateUpdateVideoSessionParametersKHR(VkDevice device, VkVideoSessionParametersKHR videoSessionParameters,
const VkVideoSessionParametersUpdateInfoKHR *pUpdateInfo,
const ErrorObject &error_obj) const {
bool skip = false;
auto vsp_state = Get<VIDEO_SESSION_PARAMETERS_STATE>(videoSessionParameters);
assert(vsp_state);
auto vsp_data = vsp_state->Lock();
if (pUpdateInfo->updateSequenceCount != vsp_data->update_sequence_counter + 1) {
skip |= LogError(device, "VUID-vkUpdateVideoSessionParametersKHR-pUpdateInfo-07215",
"vkUpdateVideoSessionParametersKHR(): incorrect updateSequenceCount");
}
switch (vsp_state->GetCodecOp()) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR: {
auto add_info = vku::FindStructInPNextChain<VkVideoDecodeH264SessionParametersAddInfoKHR>(pUpdateInfo->pNext);
if (add_info) {
skip |= ValidateDecodeH264ParametersAddInfo(add_info, device, "vkUpdateVideoSessionParametersKHR",
"VkVideoDecodeH264SessionParametersAddInfoKHR");
for (uint32_t i = 0; i < add_info->stdSPSCount; ++i) {
if (vsp_data.GetH264SPS(add_info->pStdSPSs[i].seq_parameter_set_id)) {
skip |=
LogError(videoSessionParameters, "VUID-vkUpdateVideoSessionParametersKHR-videoSessionParameters-07216",
"vkUpdateVideoSessionParametersKHR(): H.264 SPS with key "
"(SPS ID = %u) already exists in %s",
add_info->pStdSPSs[i].seq_parameter_set_id, FormatHandle(videoSessionParameters).c_str());
}
}
if (add_info->stdSPSCount + vsp_data->h264.sps.size() > vsp_data->h264.spsCapacity) {
skip |= LogError(videoSessionParameters, "VUID-vkUpdateVideoSessionParametersKHR-videoSessionParameters-07217",
"vkUpdateVideoSessionParametersKHR(): number of H.264 SPS entries to add "
"(%u) plus the already used capacity (%zu) is greater than the maximum H.264 "
"SPS capacity (%u) the %s was created with",
add_info->stdSPSCount, vsp_data->h264.sps.size(), vsp_data->h264.spsCapacity,
FormatHandle(videoSessionParameters).c_str());
}
for (uint32_t i = 0; i < add_info->stdPPSCount; ++i) {
if (vsp_data.GetH264PPS(add_info->pStdPPSs[i].seq_parameter_set_id,
add_info->pStdPPSs[i].pic_parameter_set_id)) {
skip |=
LogError(videoSessionParameters, "VUID-vkUpdateVideoSessionParametersKHR-videoSessionParameters-07218",
"vkUpdateVideoSessionParametersKHR(): H.264 PPS with key "
"(SPS ID = %u, PPS ID = %u) already exists in %s",
add_info->pStdPPSs[i].seq_parameter_set_id, add_info->pStdPPSs[i].pic_parameter_set_id,
FormatHandle(videoSessionParameters).c_str());
}
}
if (add_info->stdPPSCount + vsp_data->h264.pps.size() > vsp_data->h264.ppsCapacity) {
skip |= LogError(videoSessionParameters, "VUID-vkUpdateVideoSessionParametersKHR-videoSessionParameters-07219",
"vkUpdateVideoSessionParametersKHR(): number of H.264 PPS entries to add "
"(%u) plus the already used capacity (%zu) is greater than the maximum H.264 "
"PPS capacity (%u) the %s was created with",
add_info->stdPPSCount, vsp_data->h264.pps.size(), vsp_data->h264.ppsCapacity,
FormatHandle(videoSessionParameters).c_str());
}
}
break;
}
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR: {
auto add_info = vku::FindStructInPNextChain<VkVideoDecodeH265SessionParametersAddInfoKHR>(pUpdateInfo->pNext);
if (add_info) {
skip |= ValidateDecodeH265ParametersAddInfo(add_info, device, "vkUpdateVideoSessionParametersKHR",
"VkVideoDecodeH265SessionParametersAddInfoKHR");
for (uint32_t i = 0; i < add_info->stdVPSCount; ++i) {
if (vsp_data.GetH265VPS(add_info->pStdVPSs[i].vps_video_parameter_set_id)) {
skip |= LogError(
videoSessionParameters, "VUID-vkUpdateVideoSessionParametersKHR-videoSessionParameters-07220",
"vkUpdateVideoSessionParametersKHR(): H.265 VPS with key "
"(VPS ID = %u) already exists in %s",
add_info->pStdVPSs[i].vps_video_parameter_set_id, FormatHandle(videoSessionParameters).c_str());
}
}
if (add_info->stdVPSCount + vsp_data->h265.vps.size() > vsp_data->h265.vpsCapacity) {
skip |= LogError(videoSessionParameters, "VUID-vkUpdateVideoSessionParametersKHR-videoSessionParameters-07221",
"vkUpdateVideoSessionParametersKHR(): number of H.265 VPS entries to add "
"(%u) plus the already used capacity (%zu) is greater than the maximum H.265 "
"VPS capacity (%u) the %s was created with",
add_info->stdVPSCount, vsp_data->h265.vps.size(), vsp_data->h265.vpsCapacity,
FormatHandle(videoSessionParameters).c_str());
}
for (uint32_t i = 0; i < add_info->stdSPSCount; ++i) {
if (vsp_data.GetH265SPS(add_info->pStdSPSs[i].sps_video_parameter_set_id,
add_info->pStdSPSs[i].sps_seq_parameter_set_id)) {
skip |=
LogError(videoSessionParameters, "VUID-vkUpdateVideoSessionParametersKHR-videoSessionParameters-07222",
"vkUpdateVideoSessionParametersKHR(): H.265 SPS with key "
"(VPS ID = %u, SPS ID = %u) already exists in %s",
add_info->pStdSPSs[i].sps_video_parameter_set_id,
add_info->pStdSPSs[i].sps_seq_parameter_set_id, FormatHandle(videoSessionParameters).c_str());
}
}
if (add_info->stdSPSCount + vsp_data->h265.sps.size() > vsp_data->h265.spsCapacity) {
skip |= LogError(videoSessionParameters, "VUID-vkUpdateVideoSessionParametersKHR-videoSessionParameters-07223",
"vkUpdateVideoSessionParametersKHR(): number of H.265 SPS entries to add "
"(%u) plus the already used capacity (%zu) is greater than the maximum H.265 "
"SPS capacity (%u) the %s was created with",
add_info->stdSPSCount, vsp_data->h265.sps.size(), vsp_data->h265.spsCapacity,
FormatHandle(videoSessionParameters).c_str());
}
for (uint32_t i = 0; i < add_info->stdPPSCount; ++i) {
if (vsp_data.GetH265PPS(add_info->pStdPPSs[i].sps_video_parameter_set_id,
add_info->pStdPPSs[i].pps_seq_parameter_set_id,
add_info->pStdPPSs[i].pps_pic_parameter_set_id)) {
skip |= LogError(
videoSessionParameters, "VUID-vkUpdateVideoSessionParametersKHR-videoSessionParameters-07224",
"vkUpdateVideoSessionParametersKHR(): H.265 PPS with key "
"(VPS ID = %u, SPS ID = %u, PPS ID = %u) already exists in %s",
add_info->pStdPPSs[i].sps_video_parameter_set_id, add_info->pStdPPSs[i].pps_seq_parameter_set_id,
add_info->pStdPPSs[i].pps_pic_parameter_set_id, FormatHandle(videoSessionParameters).c_str());
}
}
if (add_info->stdPPSCount + vsp_data->h265.pps.size() > vsp_data->h265.ppsCapacity) {
skip |= LogError(videoSessionParameters, "VUID-vkUpdateVideoSessionParametersKHR-videoSessionParameters-07225",
"vkUpdateVideoSessionParametersKHR(): number of H.265 PPS entries to add "
"(%u) plus the already used capacity (%zu) is greater than the maximum H.265 "
"PPS capacity (%u) the %s was created with",
add_info->stdPPSCount, vsp_data->h265.pps.size(), vsp_data->h265.ppsCapacity,
FormatHandle(videoSessionParameters).c_str());
}
}
break;
}
default:
break;
}
return skip;
}
bool CoreChecks::PreCallValidateDestroyVideoSessionParametersKHR(VkDevice device,
VkVideoSessionParametersKHR videoSessionParameters,
const VkAllocationCallbacks *pAllocator,
const ErrorObject &error_obj) const {
auto video_session_parameters_state = Get<VIDEO_SESSION_PARAMETERS_STATE>(videoSessionParameters);
bool skip = false;
if (video_session_parameters_state) {
skip |= ValidateObjectNotInUse(video_session_parameters_state.get(), error_obj.location,
"VUID-vkDestroyVideoSessionParametersKHR-videoSessionParameters-07212");
}
return skip;
}
bool CoreChecks::PreCallValidateCmdBeginVideoCodingKHR(VkCommandBuffer commandBuffer, const VkVideoBeginCodingInfoKHR *pBeginInfo,
const ErrorObject &error_obj) const {
bool skip = false;
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
if (!cb_state) return false;
if (cb_state->activeQueries.size() > 0) {
skip |= LogError(commandBuffer, "VUID-vkCmdBeginVideoCodingKHR-None-07232",
"vkCmdBeginVideoCodingKHR(): %s has active queries", FormatHandle(commandBuffer).c_str());
}
auto vs_state = Get<VIDEO_SESSION_STATE>(pBeginInfo->videoSession);
assert(vs_state);
auto vsp_state = Get<VIDEO_SESSION_PARAMETERS_STATE>(pBeginInfo->videoSessionParameters);
auto qf_ext_props = queue_family_ext_props[cb_state->command_pool->queueFamilyIndex];
if ((qf_ext_props.video_props.videoCodecOperations & vs_state->GetCodecOp()) == 0) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSession);
objlist.add(cb_state->command_pool->Handle());
skip |= LogError(objlist, "VUID-vkCmdBeginVideoCodingKHR-commandBuffer-07231",
"vkCmdBeginVideoCodingKHR(): %s does not support video codec operation %s "
"that %s specified in pBeginInfo->videoSession was created with",
FormatHandle(cb_state->command_pool->Handle()).c_str(),
string_VkVideoCodecOperationFlagBitsKHR(vs_state->GetCodecOp()),
FormatHandle(pBeginInfo->videoSession).c_str());
}
if (vs_state->GetUnboundMemoryBindingCount() > 0) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSession);
skip |= LogError(objlist, "VUID-VkVideoBeginCodingInfoKHR-videoSession-07237",
"vkCmdBeginVideoCodingKHR(): %s has %u unbound memory binding indices",
FormatHandle(pBeginInfo->videoSession).c_str(), vs_state->GetUnboundMemoryBindingCount());
}
// if driver supports protectedNoFault the operation is valid, just has undefined values
if ((!phys_dev_props_core11.protectedNoFault) && (cb_state->unprotected == true) &&
((vs_state->create_info.flags & VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR) != 0)) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSession);
skip |= LogError(objlist, "VUID-vkCmdBeginVideoCodingKHR-commandBuffer-07233",
"vkCmdBeginVideoCodingKHR(): %s is unprotected while %s was created with "
"VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR",
FormatHandle(commandBuffer).c_str(), FormatHandle(pBeginInfo->videoSession).c_str());
}
// if driver supports protectedNoFault the operation is valid, just has undefined values
if ((!phys_dev_props_core11.protectedNoFault) && (cb_state->unprotected == false) &&
((vs_state->create_info.flags & VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR) == 0)) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSession);
skip |= LogError(objlist, "VUID-vkCmdBeginVideoCodingKHR-commandBuffer-07234",
"vkCmdBeginVideoCodingKHR(): %s is protected while %s was created without "
"VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR",
FormatHandle(commandBuffer).c_str(), FormatHandle(pBeginInfo->videoSession).c_str());
}
if (pBeginInfo->pReferenceSlots) {
VideoPictureResources unique_resources{};
bool resources_unique = true;
bool has_separate_images = false;
const IMAGE_STATE *last_dpb_image = nullptr;
char where[64];
for (uint32_t i = 0; i < pBeginInfo->referenceSlotCount; ++i) {
const auto &slot = pBeginInfo->pReferenceSlots[i];
if (slot.slotIndex >= 0 && (uint32_t)slot.slotIndex >= vs_state->create_info.maxDpbSlots) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSession);
skip |= LogError(objlist, "VUID-VkVideoBeginCodingInfoKHR-slotIndex-04856",
"vkCmdBeginVideoCodingKHR(): pBeginInfo->pReferenceSlots[%u].slotIndex (%d) "
"is greater than the maxDpbSlots %s was created with",
i, slot.slotIndex, FormatHandle(pBeginInfo->videoSession).c_str());
}
if (slot.pPictureResource != nullptr) {
snprintf(where, sizeof(where), " Image referenced in pBeginInfo->pReferenceSlots[%u]", i);
auto reference_resource = VideoPictureResource(this, *slot.pPictureResource);
skip |= ValidateVideoPictureResource(reference_resource, commandBuffer, *vs_state, "vkCmdBeginVideoCodingKHR()",
where, "VUID-VkVideoBeginCodingInfoKHR-pPictureResource-07242",
"VUID-VkVideoBeginCodingInfoKHR-pPictureResource-07243");
if (reference_resource) {
if (!unique_resources.emplace(reference_resource).second) {
resources_unique = false;
}
if (last_dpb_image != nullptr && last_dpb_image != reference_resource.image_state.get()) {
has_separate_images = true;
}
skip |= ValidateProtectedImage(*cb_state, *reference_resource.image_state, error_obj.location,
"VUID-vkCmdBeginVideoCodingKHR-commandBuffer-07235", where);
skip |= ValidateUnprotectedImage(*cb_state, *reference_resource.image_state, error_obj.location,
"VUID-vkCmdBeginVideoCodingKHR-commandBuffer-07236", where);
const auto &supported_profiles = reference_resource.image_state->supported_video_profiles;
if (supported_profiles.find(vs_state->profile) == supported_profiles.end()) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSession);
objlist.add(reference_resource.image_view_state->image_view());
objlist.add(reference_resource.image_state->image());
skip |= LogError(objlist, "VUID-VkVideoBeginCodingInfoKHR-pPictureResource-07240",
"vkCmdBeginVideoCodingKHR(): pBeginInfo->pReferenceSlots[%u]."
"imageViewBinding (%s created from %s) is not compatible with the "
"video profile %s was created with",
i, FormatHandle(reference_resource.image_view_state->image_view()).c_str(),
FormatHandle(reference_resource.image_state->image()).c_str(),
FormatHandle(pBeginInfo->videoSession).c_str());
}
if (reference_resource.image_view_state->create_info.format != vs_state->create_info.referencePictureFormat) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSession);
objlist.add(reference_resource.image_view_state->image_view());
objlist.add(reference_resource.image_state->image());
skip |= LogError(objlist, "VUID-VkVideoBeginCodingInfoKHR-pPictureResource-07241",
"vkCmdBeginVideoCodingKHR(): pBeginInfo->pReferenceSlots[%u]."
"imageViewBinding (%s created from %s) format (%s) does not match "
"the referencePictureFormat (%s) %s was created with",
i, FormatHandle(reference_resource.image_view_state->image_view()).c_str(),
FormatHandle(reference_resource.image_state->image()).c_str(),
string_VkFormat(reference_resource.image_view_state->create_info.format),
string_VkFormat(vs_state->create_info.referencePictureFormat),
FormatHandle(pBeginInfo->videoSession).c_str());
}
auto supported_usage = reference_resource.image_view_state->inherited_usage;
if ((supported_usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) == 0) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSession);
objlist.add(reference_resource.image_view_state->image_view());
objlist.add(reference_resource.image_state->image());
skip |= LogError(objlist, "VUID-VkVideoBeginCodingInfoKHR-slotIndex-07245",
"vkCmdBeginVideoCodingKHR(): pBeginInfo->pReferenceSlots[%u].imageViewBinding "
"(%s created from %s) was not created with VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR "
"thus it cannot be used as a reference picture with %s that was created with a "
"decode operation",
i, FormatHandle(reference_resource.image_view_state->image_view()).c_str(),
FormatHandle(reference_resource.image_state->image()).c_str(),
FormatHandle(pBeginInfo->videoSession).c_str());
}
last_dpb_image = reference_resource.image_state.get();
}
}
}
if (!resources_unique) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSession);
skip |= LogError(objlist, "VUID-VkVideoBeginCodingInfoKHR-pPictureResource-07238",
"vkCmdBeginVideoCodingKHR(): more than one element of pBeginInfo->pReferenceSlots "
"refers to the same video picture resource");
}
auto supported_cap_flags = vs_state->profile->GetCapabilities().base.flags;
if ((supported_cap_flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR) == 0 && has_separate_images) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSession);
skip |= LogError(objlist, "VUID-VkVideoBeginCodingInfoKHR-flags-07244",
"vkCmdBeginVideoCodingKHR(): not all elements of pBeginInfo->pReferenceSlots refer "
"to the same image and the video profile %s was created with does not support "
"VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR",
FormatHandle(pBeginInfo->videoSession).c_str());
}
}
if (vsp_state && vsp_state->vs_state->videoSession() != vs_state->videoSession()) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSessionParameters);
objlist.add(pBeginInfo->videoSession);
skip |= LogError(objlist, "VUID-VkVideoBeginCodingInfoKHR-videoSessionParameters-04857",
"vkCmdBeginVideoCodingKHR(): %s was not created for %s",
FormatHandle(pBeginInfo->videoSessionParameters).c_str(), FormatHandle(pBeginInfo->videoSession).c_str());
}
const char *codec_op_requires_params_vuid = nullptr;
switch (vs_state->GetCodecOp()) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
codec_op_requires_params_vuid = "VUID-VkVideoBeginCodingInfoKHR-videoSession-07247";
break;
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
codec_op_requires_params_vuid = "VUID-VkVideoBeginCodingInfoKHR-videoSession-07248";
break;
default:
break;
}
if ((codec_op_requires_params_vuid != nullptr) && (vsp_state == nullptr)) {
LogObjectList objlist(commandBuffer);
objlist.add(pBeginInfo->videoSession);
skip |= LogError(objlist, codec_op_requires_params_vuid,
"vkCmdBeginVideoCodingKHR(): %s was created with %s but no video session parameters object was "
"specified in pBeginInfo->videoSessionParameters",
FormatHandle(pBeginInfo->videoSession).c_str(),
string_VkVideoCodecOperationFlagBitsKHR(vs_state->GetCodecOp()));
}
skip |= ValidateCmd(*cb_state, error_obj.location);
return skip;
}
bool CoreChecks::PreCallValidateCmdEndVideoCodingKHR(VkCommandBuffer commandBuffer, const VkVideoEndCodingInfoKHR *pEndCodingInfo,
const ErrorObject &error_obj) const {
bool skip = false;
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
if (!cb_state) return false;
if (cb_state->activeQueries.size() > 0) {
skip |= LogError(commandBuffer, "VUID-vkCmdEndVideoCodingKHR-None-07251", "vkCmdEndVideoCodingKHR(): %s has active queries",
FormatHandle(commandBuffer).c_str());
}
skip |= ValidateCmd(*cb_state, error_obj.location);
return skip;
}
bool CoreChecks::PreCallValidateCmdControlVideoCodingKHR(VkCommandBuffer commandBuffer,
const VkVideoCodingControlInfoKHR *pCodingControlInfo,
const ErrorObject &error_obj) const {
bool skip = false;
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
if (!cb_state) return false;
skip |= ValidateCmd(*cb_state, error_obj.location);
return skip;
}
bool CoreChecks::PreCallValidateCmdDecodeVideoKHR(VkCommandBuffer commandBuffer, const VkVideoDecodeInfoKHR *pDecodeInfo,
const ErrorObject &error_obj) const {
bool skip = false;
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
if (!cb_state) return false;
const auto vs_state = cb_state->bound_video_session.get();
if (!vs_state) return false;
const auto &bound_resources = cb_state->bound_video_picture_resources;
bool hit_error = false;
const auto &profile_caps = vs_state->profile->GetCapabilities();
auto buffer_state = Get<BUFFER_STATE>(pDecodeInfo->srcBuffer);
if (buffer_state) {
const char *where = " Buffer referenced in pDecodeInfo->srcBuffer";
skip |= ValidateProtectedBuffer(*cb_state, *buffer_state, error_obj.location,
"VUID-vkCmdDecodeVideoKHR-commandBuffer-07136", where);
skip |= ValidateUnprotectedBuffer(*cb_state, *buffer_state, error_obj.location,
"VUID-vkCmdDecodeVideoKHR-commandBuffer-07137", where);
}
if ((buffer_state->usage & VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR) == 0) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
objlist.add(pDecodeInfo->srcBuffer);
skip |= LogError(objlist, "VUID-VkVideoDecodeInfoKHR-srcBuffer-07165",
"vkCmdDecodeVideoKHR(): pDecodeInfo->srcBuffer (%s) was not created with "
"VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR",
FormatHandle(pDecodeInfo->srcBuffer).c_str());
}
const auto &src_supported_profiles = buffer_state->supported_video_profiles;
if (src_supported_profiles.find(vs_state->profile) == src_supported_profiles.end()) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
objlist.add(pDecodeInfo->srcBuffer);
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07135",
"vkCmdDecodeVideoKHR(): pDecodeInfo->srcBuffer (%s) is not compatible "
"with the video profile %s was created with",
FormatHandle(pDecodeInfo->srcBuffer).c_str(), FormatHandle(vs_state->videoSession()).c_str());
}
if (pDecodeInfo->srcBufferOffset >= buffer_state->createInfo.size) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
objlist.add(pDecodeInfo->srcBuffer);
skip |= LogError(objlist, "VUID-VkVideoDecodeInfoKHR-srcBufferOffset-07166",
"vkCmdDecodeVideoKHR(): pDecodeInfo->srcBufferOffset (%" PRIu64 ") must be less than the size (%" PRIu64
") of pDecodeInfo->srcBuffer (%s)",
pDecodeInfo->srcBufferOffset, buffer_state->createInfo.size, FormatHandle(pDecodeInfo->srcBuffer).c_str());
}
if (!IsIntegerMultipleOf(pDecodeInfo->srcBufferOffset, profile_caps.base.minBitstreamBufferOffsetAlignment)) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07138",
"vkCmdDecodeVideoKHR(): pDecodeInfo->srcBufferOffset (%" PRIu64
") is not an integer multiple of the minBitstreamBufferOffsetAlignment (%" PRIu64
") required by the video profile %s was created with",
pDecodeInfo->srcBufferOffset, profile_caps.base.minBitstreamBufferOffsetAlignment,
FormatHandle(vs_state->videoSession()).c_str());
}
if (pDecodeInfo->srcBufferOffset + pDecodeInfo->srcBufferRange > buffer_state->createInfo.size) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
objlist.add(pDecodeInfo->srcBuffer);
skip |=
LogError(objlist, "VUID-VkVideoDecodeInfoKHR-srcBufferRange-07167",
"vkCmdDecodeVideoKHR(): pDecodeInfo->srcBufferOffset (%" PRIu64 ") plus pDecodeInfo->srcBufferRange (%" PRIu64
") must be less than or equal to the size (%" PRIu64 ") of pDecodeInfo->srcBuffer (%s)",
pDecodeInfo->srcBufferOffset, pDecodeInfo->srcBufferRange, buffer_state->createInfo.size,
FormatHandle(pDecodeInfo->srcBuffer).c_str());
}
if (!IsIntegerMultipleOf(pDecodeInfo->srcBufferRange, profile_caps.base.minBitstreamBufferSizeAlignment)) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07139",
"vkCmdDecodeVideoKHR(): pDecodeInfo->srcBufferRange (%" PRIu64
") is not an integer multiple of the minBitstreamBufferSizeAlignment (%" PRIu64
") required by the video profile %s was created with",
pDecodeInfo->srcBufferRange, profile_caps.base.minBitstreamBufferSizeAlignment,
FormatHandle(vs_state->videoSession()).c_str());
}
VideoPictureResource setup_resource;
if (pDecodeInfo->pSetupReferenceSlot) {
if (pDecodeInfo->pSetupReferenceSlot->slotIndex < 0) {
skip |= LogError(commandBuffer, "VUID-VkVideoDecodeInfoKHR-pSetupReferenceSlot-07168",
"vkCmdDecodeVideoKHR(): pBeginInfo->pSetupReferenceSlot->slotIndex (%d) "
"must not be negative",
pDecodeInfo->pSetupReferenceSlot->slotIndex);
} else if ((uint32_t)pDecodeInfo->pSetupReferenceSlot->slotIndex >= vs_state->create_info.maxDpbSlots) {
skip |= LogError(commandBuffer, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07170",
"vkCmdDecodeVideoKHR(): pBeginInfo->pSetupReferenceSlot->slotIndex (%d) "
"must be smaller than the maxDpbSlots (%u) the bound video session %s "
"was created with",
pDecodeInfo->pSetupReferenceSlot->slotIndex, vs_state->create_info.maxDpbSlots,
FormatHandle(vs_state->videoSession()).c_str());
}
if (pDecodeInfo->pSetupReferenceSlot->pPictureResource != nullptr) {
setup_resource = VideoPictureResource(this, *pDecodeInfo->pSetupReferenceSlot->pPictureResource);
if (setup_resource) {
skip |= ValidateVideoPictureResource(setup_resource, commandBuffer, *vs_state, "vkCmdDecodeVideoKHR()",
" Image referenced in pDecodeInfo->pSetupReferenceSlot",
"VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07173");
if (bound_resources.find(setup_resource) == bound_resources.end()) {
skip |= LogError(commandBuffer, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07149",
"vkCmdDecodeVideoKHR(): the video picture resource specified in "
"pDecodeInfo->pSetupReferenceSlot->pPictureResource is not one of the "
"bound video picture resources");
}
skip |= VerifyImageLayout(*cb_state, *setup_resource.image_state, setup_resource.range,
VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR, error_obj.location,
"VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07254", &hit_error);
}
} else {
skip |= LogError(commandBuffer, "VUID-VkVideoDecodeInfoKHR-pSetupReferenceSlot-07169",
"vkCmdDecodeVideoKHR(): pBeginInfo->pSetupReferenceSlot->pPictureResource "
"must not be NULL");
}
}
auto dst_resource = VideoPictureResource(this, pDecodeInfo->dstPictureResource);
skip |= ValidateVideoPictureResource(
dst_resource, commandBuffer, *vs_state, "vkCmdDecodeVideoKHR()", " Image referenced in pDecodeInfo->dstPictureResource",
"VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07144", "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07145");
if (dst_resource) {
const char *where = " Image referenced in pDecodeInfo->dstPictureResource";
skip |= ValidateProtectedImage(*cb_state, *dst_resource.image_state, error_obj.location,
"VUID-vkCmdDecodeVideoKHR-commandBuffer-07147", where);
skip |= ValidateUnprotectedImage(*cb_state, *dst_resource.image_state, error_obj.location,
"VUID-vkCmdDecodeVideoKHR-commandBuffer-07148", where);
const auto &dst_supported_profiles = dst_resource.image_state->supported_video_profiles;
if (dst_supported_profiles.find(vs_state->profile) == dst_supported_profiles.end()) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
objlist.add(dst_resource.image_view_state->image_view());
objlist.add(dst_resource.image_state->image());
skip |=
LogError(objlist, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07142",
"vkCmdDecodeVideoKHR(): pDecodeInfo->dstPictureResource.imageViewBinding "
"(%s created from %s) is not compatible with the video profile the bound "
"video session %s was created with",
FormatHandle(pDecodeInfo->dstPictureResource.imageViewBinding).c_str(),
FormatHandle(dst_resource.image_state->image()).c_str(), FormatHandle(vs_state->videoSession()).c_str());
}
if (dst_resource.image_view_state->create_info.format != vs_state->create_info.pictureFormat) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
objlist.add(dst_resource.image_view_state->image_view());
objlist.add(dst_resource.image_state->image());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07143",
"vkCmdDecodeVideoKHR(): pDecodeInfo->dstPictureResource.imageViewBinding "
"(%s created from %s) format (%s) does not match the pictureFormat (%s) "
"the bound video session %s was created with",
FormatHandle(dst_resource.image_view_state->image_view()).c_str(),
FormatHandle(dst_resource.image_state->image()).c_str(),
string_VkFormat(dst_resource.image_view_state->create_info.format),
string_VkFormat(vs_state->create_info.pictureFormat), FormatHandle(vs_state->videoSession()).c_str());
}
auto supported_usage = dst_resource.image_view_state->inherited_usage;
if ((supported_usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR) == 0) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
objlist.add(dst_resource.image_view_state->image_view());
objlist.add(dst_resource.image_state->image());
skip |=
LogError(objlist, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07146",
"vkCmdDecodeVideoKHR(): pDecodeInfo->dstPictureResource.imageViewBinding "
"(%s created from %s) was not created with VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR "
"thus it cannot be used as a decode output picture with the bound video session %s "
"that was created with a decode operation",
FormatHandle(dst_resource.image_view_state->image_view()).c_str(),
FormatHandle(dst_resource.image_state->image()).c_str(), FormatHandle(vs_state->videoSession()).c_str());
}
bool dst_same_as_setup = (setup_resource == dst_resource);
VkImageLayout expected_layout =
dst_same_as_setup ? VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR : VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR;
const char *vuid =
dst_same_as_setup ? "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07253" : "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07252";
skip |= VerifyImageLayout(*cb_state, *dst_resource.image_state, dst_resource.range, expected_layout, error_obj.location,
vuid, &hit_error);
if (setup_resource) {
if ((profile_caps.decode.flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR) == 0 &&
dst_same_as_setup) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07140",
"vkCmdDecodeVideoKHR(): the video profile %s was created with does not support "
"VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR but "
"pDecodeInfo->dstPictureResource and "
"pDecodeInfo->pSetupReferenceSlot->pPictureResource match",
FormatHandle(vs_state->videoSession()).c_str());
}
if ((profile_caps.decode.flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR) == 0 &&
!dst_same_as_setup) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07141",
"vkCmdDecodeVideoKHR(): the video profile %s was created with does not support "
"VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR but "
"pDecodeInfo->dstPictureResource and pSetupReferenceSlot->pPictureResource "
"do not match",
FormatHandle(vs_state->videoSession()).c_str());
}
}
}
if (pDecodeInfo->pReferenceSlots) {
VideoPictureResources unique_resources{};
bool resources_unique = true;
char where[64];
skip |= ValidateActiveReferencePictureCount(*cb_state, *pDecodeInfo);
skip |= ValidateReferencePictureUseCount(*cb_state, *pDecodeInfo);
for (uint32_t i = 0; i < pDecodeInfo->referenceSlotCount; ++i) {
if (pDecodeInfo->pReferenceSlots[i].slotIndex < 0) {
skip |= LogError(commandBuffer, "VUID-VkVideoDecodeInfoKHR-slotIndex-07171",
"vkCmdDecodeVideoKHR(): pDecodeInfo->pReferenceSlots[%u].slotIndex (%d) "
"must not be negative",
i, pDecodeInfo->pReferenceSlots[i].slotIndex);
} else if ((uint32_t)pDecodeInfo->pReferenceSlots[i].slotIndex >= vs_state->create_info.maxDpbSlots) {
LogObjectList objlist(commandBuffer);
objlist.add(vs_state->videoSession());
skip |= LogError(objlist, "VUID-vkCmdDecodeVideoKHR-slotIndex-07256",
"vkCmdDecodeVideoKHR(): pDecodeInfo->pReferenceSlots[%u].slotIndex (%d) "
"must be smaller than the maxDpbSlots (%u) the bound video session %s "
"was created with",
i, pDecodeInfo->pReferenceSlots[i].slotIndex, vs_state->create_info.maxDpbSlots,
FormatHandle(vs_state->videoSession()).c_str());
}
if (pDecodeInfo->pReferenceSlots[i].pPictureResource != nullptr) {
auto reference_resource = VideoPictureResource(this, *pDecodeInfo->pReferenceSlots[i].pPictureResource);
if (reference_resource) {
if (!unique_resources.emplace(reference_resource).second) {
resources_unique = false;
}
const auto &it = bound_resources.find(reference_resource);
if (it == bound_resources.end()) {
skip |= LogError(commandBuffer, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07151",
"vkCmdDecodeVideoKHR(): the video picture resource specified in "
"pDecodeInfo->pReferenceSlots[%u].pPictureResource is not one of the "
"bound video picture resources",
i);
} else if (pDecodeInfo->pReferenceSlots[i].slotIndex >= 0 &&
pDecodeInfo->pReferenceSlots[i].slotIndex != it->second) {
skip |= LogError(commandBuffer, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07151",
"vkCmdDecodeVideoKHR(): the bound video picture resource specified in "
"pDecodeInfo->pReferenceSlots[%u].pPictureResource is not currently "
"associated with the DPB slot index specifed in "
"pDecodeInfo->pReferenceSlots[%u].slotIndex (%d)",
i, i, pDecodeInfo->pReferenceSlots[i].slotIndex);
}
snprintf(where, sizeof(where), " Image referenced in pDecodeInfo->pReferenceSlots[%u]", i);
skip |= ValidateVideoPictureResource(reference_resource, commandBuffer, *vs_state, "vkCmdDecodeVideoKHR()",
where, "VUID-vkCmdDecodeVideoKHR-codedOffset-07257");
skip |= VerifyImageLayout(*cb_state, *reference_resource.image_state, reference_resource.range,
VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR, error_obj.location,
"VUID-vkCmdDecodeVideoKHR-pPictureResource-07255", &hit_error);
}
} else {
skip |= LogError(commandBuffer, "VUID-VkVideoDecodeInfoKHR-pPictureResource-07172",
"vkCmdDecodeVideoKHR(): pDecodeInfo->pReferenceSlots[%u].pPictureResource "
"must not be NULL",
i);
}
}
if (!resources_unique) {
skip |= LogError(commandBuffer, "VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07264",
"vkCmdDecodeVideoKHR(): more than one element of pDecodeInfo->pReferenceSlots "
"refers to the same video picture resource");
}
}
for (const auto &query : cb_state->activeQueries) {
uint32_t op_count = vs_state->GetVideoDecodeOperationCount(pDecodeInfo);
if (query.active_query_index + op_count > query.last_activatable_query_index + 1) {
auto query_pool_state = Get<QUERY_POOL_STATE>(query.pool);
skip |= LogError(commandBuffer, "VUID-vkCmdDecodeVideoKHR-opCount-07134",
"vkCmdDecodeVideoKHR(): not enough activatable queries for query type %s "
"with opCount %u, active query index %u, and last activatable query index %u",
string_VkQueryType(query_pool_state->createInfo.queryType), op_count, query.active_query_index,
query.last_activatable_query_index);
}
}
switch (vs_state->GetCodecOp()) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
skip |= ValidateVideoDecodeInfoH264(*cb_state, *pDecodeInfo);
break;
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
skip |= ValidateVideoDecodeInfoH265(*cb_state, *pDecodeInfo);
break;
default:
break;
}
skip |= ValidateCmd(*cb_state, error_obj.location);
return skip;
}