| /* 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; |
| } |