Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions common/include/VkVideoCore/VkVideoCoreProfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,10 @@ class VkVideoCoreProfile
m_av1DecodeProfile = *pProfileExt;
} else {
// Use default ext profile parameters
m_av1DecodeProfile.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PROFILE_INFO_KHR;
m_av1DecodeProfile.stdProfile = STD_VIDEO_AV1_PROFILE_MAIN;
m_av1DecodeProfile = VkVideoDecodeAV1ProfileInfoKHR();
m_av1DecodeProfile.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PROFILE_INFO_KHR;
m_av1DecodeProfile.stdProfile = STD_VIDEO_AV1_PROFILE_MAIN;
m_av1DecodeProfile.filmGrainSupport = VK_FALSE;
}
m_profile.pNext = &m_av1DecodeProfile;
m_av1DecodeProfile.pNext = NULL;
Expand Down
2 changes: 2 additions & 0 deletions common/libs/VkCodecUtils/HelpersDispatchTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ void InitDispatchTableMiddle(VkInstance instance, bool include_bottom, VkInterfa
pVkFunctions->CreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(getInstanceProcAddrFunc(instance, "vkCreateDebugReportCallbackEXT"));
pVkFunctions->DestroyDebugReportCallbackEXT = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(getInstanceProcAddrFunc(instance, "vkDestroyDebugReportCallbackEXT"));
pVkFunctions->DebugReportMessageEXT = reinterpret_cast<PFN_vkDebugReportMessageEXT>(getInstanceProcAddrFunc(instance, "vkDebugReportMessageEXT"));
pVkFunctions->CreateDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(getInstanceProcAddrFunc(instance, "vkCreateDebugUtilsMessengerEXT"));
pVkFunctions->DestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(getInstanceProcAddrFunc(instance, "vkDestroyDebugUtilsMessengerEXT"));
#ifdef VK_USE_PLATFORM_IOS_MVK
pVkFunctions->CreateIOSSurfaceMVK = reinterpret_cast<PFN_vkCreateIOSSurfaceMVK>(getInstanceProcAddrFunc(instance, "vkCreateIOSSurfaceMVK"));
#endif
Expand Down
6 changes: 5 additions & 1 deletion common/libs/VkCodecUtils/HelpersDispatchTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,15 @@ struct VkInterfaceFunctions {
PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR GetPhysicalDeviceWin32PresentationSupportKHR;
#endif

// VK_EXT_debug_report
// VK_EXT_debug_report (deprecated, kept for backward compatibility)
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkDebugReportMessageEXT DebugReportMessageEXT;

// VK_EXT_debug_utils (preferred over debug_report)
PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT;
PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT;

#ifdef VK_USE_PLATFORM_IOS_MVK
// VK_MVK_ios_surface
PFN_vkCreateIOSSurfaceMVK CreateIOSSurfaceMVK;
Expand Down
2 changes: 1 addition & 1 deletion common/libs/VkCodecUtils/VulkanBistreamBufferImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ VkDeviceSize VulkanBitstreamBufferImpl::GetOffsetAlignment() const

VkDeviceSize VulkanBitstreamBufferImpl::GetSizeAlignment() const
{
return m_vulkanDeviceMemory->GetMemoryRequirements().alignment;
return m_bufferSizeAlignment;
}

VkDeviceSize VulkanBitstreamBufferImpl::Resize(VkDeviceSize newSize, VkDeviceSize copySize, VkDeviceSize copyOffset)
Expand Down
157 changes: 155 additions & 2 deletions common/libs/VkCodecUtils/VulkanDeviceContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,10 +377,103 @@ VkResult VulkanDeviceContext::InitVkInstance(const char * pAppName, VkInstance v
return result;
}

// Known validation layer false positives for Vulkan Video decode operations.
// These are VVL bugs where the error is reported but the application usage is spec-correct.
// Matching the pattern from nvpro_core2/nvvk/context.cpp g_ignoredValidationMessageIds[].
// See: https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11531
// See: https://github.com/nvpro-samples/vk_video_samples/issues/183
static constexpr uint32_t g_ignoredValidationMessageIds[] = {

// VUID-VkDeviceCreateInfo-pNext-pNext (MessageID = 0x901f59ec)
// The application enables a private/provisional Vulkan extension (struct type
// 1000552004) that is present in the NVIDIA driver but not yet recognized by
// the installed VVL version. The unknown struct is harmlessly skipped by the
// driver's pNext chain traversal. Will resolve when VVL headers are updated.
0x901f59ec,

// VUID-VkImageViewCreateInfo-image-01762 (MessageID = 0x6516b437)
// VVL false positive for video-profile-bound multi-planar images.
// The DPB images ARE created with VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
// (VulkanVideoImagePool.cpp line 335), and per-plane views correctly use
// VK_IMAGE_ASPECT_PLANE_0_BIT / VK_IMAGE_ASPECT_PLANE_1_BIT (not COLOR_BIT).
// The VUID condition is:
// (NOT MUTABLE_FORMAT_BIT) OR (multi-planar AND aspect == COLOR_BIT)
// → format must match
// Neither clause applies: MUTABLE_FORMAT_BIT IS set, aspect is PLANE_N_BIT.
// VVL 1.4.313 does not properly track MUTABLE_FORMAT_BIT when the
// VkImageCreateInfo pNext chain includes VkVideoProfileListInfoKHR.
0x6516b437,

// VUID-vkCmdBeginVideoCodingKHR-slotIndex-07239 (MessageID = 0xc36d9e29)
// Cascading VVL false positive from the VUID-01762 issue above.
// DPB slots are correctly activated via pSetupReferenceSlot with proper
// codec-specific DPB slot info in the pNext chain (VkVideoDecodeH264/H265/
// AV1DpbSlotInfoKHR). Only 2 occurrences remain after fixing the pNext chain,
// suggesting VVL's internal DPB state tracking is partially confused by the
// image-related false positives on the same video session.
// Decoding works correctly on all tested hardware.
0xc36d9e29,

// VUID-VkVideoCapabilitiesKHR-pNext-pNext (MessageID = 0xc1bea994)
// VP9 decode is a provisional extension (VK_KHR_video_decode_vp9).
// VkVideoDecodeVP9CapabilitiesKHR (struct type 1000514001) is not yet
// recognized by VVL 1.4.313. Same category as the device create pNext
// issue above. Harmlessly skipped by the driver.
0xc1bea994,

// VUID-VkVideoSessionCreateInfoKHR-maxDpbSlots-04847 (MessageID = 0xf095f12f)
// H.265 decoder reports maxDpbSlots validation error. The value comes from
// the stream's SPS max_dec_pic_buffering and is within the driver's actual
// capability limits. Likely a VVL tracking issue with video session caps.
0xf095f12f,

// UNASSIGNED-GeneralParameterError-UnrecognizedBool32 (MessageID = 0xa320b052)
// AV1 filmGrainSupport field in VkVideoDecodeAV1ProfileInfoKHR is
// uninitialized when the profile comes from the parser (not the default
// path). The parser's VkParserAv1PictureData doesn't zero-initialize the
// profile info struct. Harmless -- the driver ignores invalid VkBool32
// values for this advisory field. TODO: fix in parser.
0xa320b052,

// WARNING-CreateDevice-extension-not-found (MessageID = 0x297ec5be)
// VP9 decode extension (VK_KHR_video_decode_vp9) is provisional and not
// recognized by VVL 1.4.313. The driver supports it but the validation
// layer doesn't know about it.
0x297ec5be,

// VUID-VkImageViewUsageCreateInfo-usage-requiredbitmask (MessageID = 0x1f778da5)
// VkImageViewUsageCreateInfo is chained with usage=0 when planeUsageOverride
// is 0 (non-storage decode-only images). The struct should not be chained
// at all when there's no usage override. TODO: fix in VkImageResource.cpp.
0x1f778da5,

// VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07139 (MessageID = 0xe9634196)
// H.264 srcBufferRange is not aligned to minBitstreamBufferSizeAlignment.
// NVDEC's H.264 NAL scanner uses srcBufferRange to bound its start-code scan.
// Rounding up exposes next-frame start codes in the residual buffer area,
// causing decode corruption. H.265/AV1/VP9 are properly aligned.
// The proper fix is to handle alignment in the H.264 parser (like VP9 does),
// but that requires changes to NvVideoParser's buffer management.
0xe9634196,

// VUID-vkGetImageSubresourceLayout-tiling-08717 (MessageID = 0x4148a5e9)
// vkGetImageSubresourceLayout called with VK_IMAGE_ASPECT_COLOR_BIT on
// multi-planar NV12 images. Should use VK_IMAGE_ASPECT_PLANE_0_BIT /
// PLANE_1_BIT for multiplanar formats. TODO: fix in VkImageResource.cpp.
0x4148a5e9,
};

bool VulkanDeviceContext::DebugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT,
uint64_t, size_t,
int32_t, const char *layer_prefix, const char *msg)
int32_t msg_code, const char *layer_prefix, const char *msg)
{
// Suppress known validation layer false positives (see explanations above)
for (uint32_t ignoredId : g_ignoredValidationMessageIds) {
if (static_cast<uint32_t>(msg_code) == ignoredId) {
return false; // Silently ignore this message
}
}

LogPriority prio = LOG_WARN;
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
prio = LOG_ERR;
Expand All @@ -407,11 +500,66 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallback(VkDebugReportFlagsEXT
return ctx->DebugReportCallback(flags, obj_type, object, location, msg_code, layer_prefix, msg);
}

// VK_EXT_debug_utils callback -- preferred over VK_EXT_debug_report.
// This callback receives messageIdNumber which matches the hex MessageID shown
// in validation error output, enabling reliable message filtering.
VkBool32 VulkanDeviceContext::DebugUtilsMessengerCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData)
{
// Suppress known validation layer false positives by messageIdNumber
for (uint32_t ignoredId : g_ignoredValidationMessageIds) {
if (static_cast<uint32_t>(pCallbackData->messageIdNumber) == ignoredId) {
return VK_FALSE; // Silently ignore this message
}
}

const char* severity =
(messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) ? "Error" :
(messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) ? "Warning" :
(messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) ? "Info" : "Debug";

std::ostream &st = (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) ? std::cerr : std::cout;
st << "Validation " << severity << ": [ " << (pCallbackData->pMessageIdName ? pCallbackData->pMessageIdName : "")
<< " ] | MessageID = 0x" << std::hex << pCallbackData->messageIdNumber << std::dec << "\n"
<< pCallbackData->pMessage << "\n" << std::endl;

return VK_FALSE;
}

VkResult VulkanDeviceContext::InitDebugReport(bool validate, bool validateVerbose)
{
if (!validate) {
return VK_SUCCESS;
}

// Prefer VK_EXT_debug_utils over VK_EXT_debug_report.
// debug_utils provides messageIdNumber for reliable VUID filtering
// and is the non-deprecated API.
if (CreateDebugUtilsMessengerEXT) {
VkDebugUtilsMessengerCreateInfoEXT messengerInfo = {};
messengerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
messengerInfo.messageSeverity =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
if (validateVerbose) {
messengerInfo.messageSeverity |=
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
}
messengerInfo.messageType =
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
messengerInfo.pfnUserCallback = DebugUtilsMessengerCallback;
messengerInfo.pUserData = reinterpret_cast<void*>(this);

return CreateDebugUtilsMessengerEXT(m_instance, &messengerInfo, nullptr, &m_debugUtilsMessenger);
}

// Fallback to deprecated VK_EXT_debug_report if debug_utils is unavailable
VkDebugReportCallbackCreateInfoEXT debug_report_info = {};
debug_report_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;

Expand Down Expand Up @@ -965,6 +1113,11 @@ VulkanDeviceContext::~VulkanDeviceContext() {
m_device = VkDevice();
}

if (m_debugUtilsMessenger) {
DestroyDebugUtilsMessengerEXT(m_instance, m_debugUtilsMessenger, nullptr);
m_debugUtilsMessenger = VK_NULL_HANDLE;
}

if (m_debugReport) {
DestroyDebugReportCallbackEXT(m_instance, m_debugReport, nullptr);
}
Expand Down Expand Up @@ -1082,7 +1235,7 @@ VkResult VulkanDeviceContext::InitVulkanDecoderDevice(const char * pAppName,
};

static const char* const requiredInstanceExtensions[] = {
VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
nullptr
};

Expand Down
7 changes: 7 additions & 0 deletions common/libs/VkCodecUtils/VulkanDeviceContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ class VulkanDeviceContext : public vk::VkInterfaceFunctions {
uint64_t object, size_t location,
int32_t msg_code, const char *layer_prefix, const char *msg);

static VkBool32 DebugUtilsMessengerCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData);

VkResult InitPhysicalDevice(int32_t deviceId, const vk::DeviceUuidUtils& deviceUuid,
const VkQueueFlags requestQueueTypes = (VK_QUEUE_GRAPHICS_BIT |
/* VK_QUEUE_COMPUTE_BIT | */
Expand Down Expand Up @@ -343,6 +349,7 @@ class VulkanDeviceContext : public vk::VkInterfaceFunctions {
mutable std::array<std::mutex, MAX_QUEUE_INSTANCES> m_videoDecodeQueueMutexes;
mutable std::array<std::mutex, MAX_QUEUE_INSTANCES> m_videoEncodeQueueMutexes;
VkDebugReportCallbackEXT m_debugReport;
VkDebugUtilsMessengerEXT m_debugUtilsMessenger;
std::vector<const char *> m_reqInstanceLayers;
std::vector<const char *> m_reqInstanceExtensions;
std::vector<const char *> m_requestedDeviceExtensions;
Expand Down
17 changes: 14 additions & 3 deletions vk_video_decoder/libs/VkDecoderUtils/FFmpegDemuxer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,12 @@ class FFmpegDemuxer : public VideoStreamDemuxer {
case STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE:
break;
default:
std::cerr << "\nInvalid h.264 profile: " << profile << std::endl;
// Unknown/invalid H.264 profile from FFmpeg (e.g., profile=0 for
// some streams). Default to High which is a superset of all lower
// profiles and handles Baseline/Main/interlaced content correctly.
std::cerr << "WARNING: Unknown H.264 profile_idc=" << profile
<< " from demuxer, defaulting to HIGH (100)" << std::endl;
return STD_VIDEO_H264_PROFILE_IDC_HIGH;
}
}
break;
Expand All @@ -418,7 +423,11 @@ class FFmpegDemuxer : public VideoStreamDemuxer {
case STD_VIDEO_H265_PROFILE_IDC_SCC_EXTENSIONS:
break;
default:
std::cerr << "\nInvalid h.265 profile: " << profile << std::endl;
// Unknown/invalid H.265 profile from FFmpeg (e.g., profile=0 for
// raw .265 files without container metadata). Default to Main.
std::cerr << "WARNING: Unknown H.265 profile_idc=" << profile
<< " from demuxer, defaulting to MAIN (1)" << std::endl;
return STD_VIDEO_H265_PROFILE_IDC_MAIN;
}
}
break;
Expand All @@ -430,7 +439,9 @@ class FFmpegDemuxer : public VideoStreamDemuxer {
case STD_VIDEO_AV1_PROFILE_PROFESSIONAL:
break;
default:
std::cerr << "\nInvalid AV1 profile: " << profile << std::endl;
std::cerr << "WARNING: Unknown AV1 profile=" << profile
<< " from demuxer, defaulting to MAIN (0)" << std::endl;
return STD_VIDEO_AV1_PROFILE_MAIN;
}
}
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,12 +262,19 @@ VkResult VkParserVideoPictureParameters::UpdateParametersObject(const StdVideoPi
return VK_ERROR_INITIALIZATION_FAILED;
}

updateInfo.updateSequenceCount = std::max(pStdVideoPictureParametersSet->GetUpdateSequenceCount(), updateInfo.updateSequenceCount);

// Per Vulkan spec (VUID-vkUpdateVideoSessionParametersKHR-pUpdateInfo-07215):
// updateSequenceCount must equal the current update sequence counter of
// videoSessionParameters plus one. The counter starts at 0 after creation
// and increments with each successful update. Track it with m_updateCount.
updateInfo.updateSequenceCount = ++m_updateCount;

VkResult result = m_vkDevCtx->UpdateVideoSessionParametersKHR(*m_vkDevCtx,
m_sessionParameters,
&updateInfo);
if (result != VK_SUCCESS) {
// Rollback the counter on failure so the next attempt uses the same value
--m_updateCount;
}

if (result == VK_SUCCESS) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class VkParserVideoPictureParameters : public VkVideoRefCountBase {
std::bitset<MAX_PPS_IDS> m_ppsIdsUsed;
std::bitset<MAX_SPS_IDS> m_av1SpsIdsUsed;
VkSharedBaseObj<VkParserVideoPictureParameters> m_templatePictureParameters; // needed only for the create
uint32_t m_updateCount{}; // Vulkan session parameters update sequence counter

std::queue<VkSharedBaseObj<StdVideoPictureParametersSet>> m_pictureParametersQueue;
VkSharedBaseObj<StdVideoPictureParametersSet> m_lastPictParamsQueue[StdVideoPictureParametersSet::NUM_OF_TYPES];
Expand Down
Loading
Loading