22 #include "config_components.h"
27 #if CONFIG_H264_VULKAN_HWACCEL
30 #if CONFIG_HEVC_VULKAN_HWACCEL
33 #if CONFIG_AV1_VULKAN_HWACCEL
38 #if CONFIG_H264_VULKAN_HWACCEL
41 #if CONFIG_HEVC_VULKAN_HWACCEL
44 #if CONFIG_AV1_VULKAN_HWACCEL
60 const VkVideoProfileListInfoKHR *profile_list;
62 VkStructureType profile_struct_type =
69 VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
73 for (
int i = 0;
i < profile_list->profileCount;
i++)
75 return &profile_list->pProfiles[
i];
99 VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR, 0,
164 if (
ctx->common.layered_dpb && alloc_dpb) {
167 }
else if (alloc_dpb) {
178 dpb_hwfc->format[0], !is_current);
185 if (!alloc_dpb || is_current) {
192 hwfc->format[0], !is_current);
206 const uint8_t *
data,
size_t size,
int add_startcode,
207 uint32_t *nb_slices,
const uint32_t **
offsets)
212 static const uint8_t startcode_prefix[3] = { 0x0, 0x0, 0x1 };
213 const size_t startcode_len = add_startcode ?
sizeof(startcode_prefix) : 0;
214 const int nb = *nb_slices;
220 ctx->caps.minBitstreamBufferSizeAlignment;
221 new_size =
FFALIGN(new_size,
ctx->caps.minBitstreamBufferSizeAlignment);
224 (nb + 1)*
sizeof(slice_off));
232 if (!vkbuf || vkbuf->
size < new_size) {
238 size_t buf_size =
FFMAX(new_size, 1024*1024);
242 buf_size = 2 <<
av_log2(buf_size);
245 VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR,
246 ctx->s.hwfc->create_pnext, buf_size,
247 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
265 memcpy(slices + vp->
slices_size, startcode_prefix, startcode_len);
282 VkVideoBeginCodingInfoKHR decode_start = {
283 .sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR,
284 .videoSession =
ctx->common.session,
285 .videoSessionParameters =
ctx->empty_session_params,
287 VkVideoCodingControlInfoKHR decode_ctrl = {
288 .sType = VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR,
289 .
flags = VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR,
292 .sType = VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR,
295 VkCommandBuffer cmd_buf;
301 vk->CmdBeginVideoCodingKHR(cmd_buf, &decode_start);
302 vk->CmdControlVideoCodingKHR(cmd_buf, &decode_ctrl);
303 vk->CmdEndVideoCodingKHR(cmd_buf, &
decode_end);
318 VkCommandBuffer cmd_buf;
329 const int layered_dpb =
ctx->common.layered_dpb;
331 VkVideoSessionParametersKHR *par = (VkVideoSessionParametersKHR *)dec->
session_params->
data;
332 VkVideoBeginCodingInfoKHR decode_start = {
333 .sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR,
334 .videoSession =
ctx->common.session,
335 .videoSessionParameters = *par,
336 .referenceSlotCount = vp->
decode_info.referenceSlotCount,
337 .pReferenceSlots = vp->
decode_info.pReferenceSlots,
340 .sType = VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR,
343 VkImageMemoryBarrier2 img_bar[37];
346 ctx->caps.minBitstreamBufferSizeAlignment);
351 VkVideoReferenceSlotInfoKHR *cur_vk_ref;
352 cur_vk_ref = (
void *)&decode_start.pReferenceSlots[decode_start.referenceSlotCount];
354 cur_vk_ref[0].slotIndex = -1;
355 decode_start.referenceSlotCount++;
360 VK_QUERY_RESULT_WAIT_BIT);
361 if (
ret != VK_NOT_READY &&
ret != VK_SUCCESS) {
368 result[0] != VK_QUERY_RESULT_STATUS_COMPLETE_KHR ?
370 "Result of previous frame decoding: %u\n",
result[0]);
376 if (!(sd_buf->
flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
377 VkMappedMemoryRange flush_buf = {
378 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
379 .memory = sd_buf->
mem,
382 ctx->s.props.properties.limits.nonCoherentAtomSize),
385 ret = vk->FlushMappedMemoryRanges(
ctx->s.hwctx->act_dev, 1, &flush_buf);
386 if (
ret != VK_SUCCESS) {
415 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
416 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR);
426 img_bar[nb_img_bar] = (VkImageMemoryBarrier2) {
427 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
429 .srcStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
430 .dstStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
431 .srcAccessMask = VK_ACCESS_2_NONE,
432 .dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
433 .oldLayout = vkf->
layout[0],
434 .newLayout = (layered_dpb || vp->
dpb_frame) ?
435 VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR :
436 VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
438 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
439 .image = vkf->
img[0],
440 .subresourceRange = (VkImageSubresourceRange) {
447 &img_bar[nb_img_bar], &nb_img_bar);
452 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
453 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR);
467 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
468 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR);
483 img_bar[nb_img_bar] = (VkImageMemoryBarrier2) {
484 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
486 .srcStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
487 .dstStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
488 .srcAccessMask = VK_ACCESS_2_NONE,
489 .dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR |
490 VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
491 .oldLayout = rvkf->
layout[0],
492 .newLayout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
494 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
495 .image = rvkf->
img[0],
496 .subresourceRange = (VkImageSubresourceRange) {
503 &img_bar[nb_img_bar], &nb_img_bar);
510 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
511 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR);
517 vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
518 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
519 .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
520 .pImageMemoryBarriers = img_bar,
521 .imageMemoryBarrierCount = nb_img_bar,
525 vk->CmdBeginVideoCodingKHR(cmd_buf, &decode_start);
537 vk->CmdEndVideoCodingKHR(cmd_buf, &
decode_end);
547 VkSemaphoreWaitInfo
sem_wait = (VkSemaphoreWaitInfo) {
548 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
549 .pSemaphores = &vp->
sem,
584 if (
ctx->empty_session_params)
585 vk->DestroyVideoSessionParametersKHR(
s->hwctx->act_dev,
586 ctx->empty_session_params,
620 VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME);
639 VkVideoDecodeH264CapabilitiesKHR *h264_caps,
640 VkVideoDecodeH265CapabilitiesKHR *h265_caps,
641 VkVideoDecodeAV1CapabilitiesKHR *av1_caps,
642 VkVideoCapabilitiesKHR *caps,
643 VkVideoDecodeCapabilitiesKHR *dec_caps,
646 VkVideoDecodeUsageInfoKHR *
usage = &prof->
usage;
648 VkVideoProfileListInfoKHR *profile_list = &prof->
profile_list;
650 VkVideoDecodeH264ProfileInfoKHR *h264_profile = &prof->
h264_profile;
651 VkVideoDecodeH265ProfileInfoKHR *h265_profile = &prof->
h265_profile;
652 VkVideoDecodeAV1ProfileInfoKHR *av1_profile = &prof->
av1_profile;
659 dec_caps->pNext = h264_caps;
660 usage->pNext = h264_profile;
661 h264_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR;
670 VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_KHR :
671 VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_INTERLEAVED_LINES_BIT_KHR;
673 dec_caps->pNext = h265_caps;
674 usage->pNext = h265_profile;
675 h265_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR;
676 h265_profile->stdProfileIdc = cur_profile;
678 dec_caps->pNext = av1_caps;
679 usage->pNext = av1_profile;
680 av1_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PROFILE_INFO_KHR;
681 av1_profile->stdProfile = cur_profile;
685 usage->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_USAGE_INFO_KHR;
686 usage->videoUsageHints = VK_VIDEO_DECODE_USAGE_DEFAULT_KHR;
688 profile->sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR;
695 profile_list->sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR;
696 profile_list->profileCount = 1;
697 profile_list->pProfiles =
profile;
700 caps->sType = VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR;
701 caps->pNext = dec_caps;
702 dec_caps->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_CAPABILITIES_KHR;
705 return vk->GetPhysicalDeviceVideoCapabilitiesKHR(hwctx->
phys_dev,
profile,
715 int max_level, base_profile, cur_profile;
728 VkVideoCapabilitiesKHR *caps = &
ctx->caps;
729 VkVideoDecodeCapabilitiesKHR *dec_caps = &
ctx->dec_caps;
731 VkVideoDecodeH264CapabilitiesKHR h264_caps = {
732 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_KHR,
734 VkVideoDecodeH265CapabilitiesKHR h265_caps = {
735 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_KHR,
737 VkVideoDecodeAV1CapabilitiesKHR av1_caps = {
738 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_CAPABILITIES_KHR,
741 VkPhysicalDeviceVideoFormatInfoKHR fmt_info = {
742 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR,
745 VkVideoFormatPropertiesKHR *ret_info;
746 uint32_t nb_out_fmts = 0;
767 if (
ret == VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR &&
769 avctx->
profile != base_profile) {
771 "again with profile %s\n",
775 cur_profile = base_profile;
785 if (
ret == VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR) {
787 "%s profile \"%s\" not supported!\n",
791 }
else if (
ret == VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR) {
793 "format (%s) not supported!\n",
796 }
else if (
ret == VK_ERROR_FEATURE_NOT_PRESENT ||
797 ret == VK_ERROR_FORMAT_NOT_SUPPORTED) {
799 }
else if (
ret != VK_SUCCESS) {
812 max_level, avctx->
level);
814 caps->minCodedExtent.width, caps->maxCodedExtent.width);
816 caps->minCodedExtent.height, caps->maxCodedExtent.height);
818 caps->pictureAccessGranularity.width);
820 caps->pictureAccessGranularity.height);
822 caps->minBitstreamBufferOffsetAlignment);
824 caps->minBitstreamBufferSizeAlignment);
828 caps->maxActiveReferencePictures);
830 caps->stdHeaderVersion.extensionName,
832 av_log(avctx,
AV_LOG_VERBOSE,
" Codec header version: %i.%i.%i (driver), %i.%i.%i (compiled)\n",
833 CODEC_VER(caps->stdHeaderVersion.specVersion),
836 dec_caps->flags ?
"" :
838 dec_caps->flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR ?
839 " reuse_dst_dpb" :
"",
840 dec_caps->flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR ?
841 " dedicated_dpb" :
"");
845 caps->flags & VK_VIDEO_CAPABILITY_PROTECTED_CONTENT_BIT_KHR ?
847 caps->flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR ?
848 " separate_references" :
"");
851 if (avctx->
coded_width < caps->minCodedExtent.width ||
858 avctx->
level > max_level)
862 if (!(dec_caps->flags & (VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR |
863 VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR))) {
865 "VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR nor "
866 "VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR are set!\n");
868 }
else if ((dec_caps->flags & (VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR |
869 VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR) ==
870 VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR) &&
871 !(caps->flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR)) {
872 av_log(avctx,
AV_LOG_ERROR,
"Cannot initialize Vulkan decoding session, buggy driver: "
873 "VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR set "
874 "but VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR is unset!\n");
878 dec->
dedicated_dpb = !(dec_caps->flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR);
880 !(caps->flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR);
883 fmt_info.imageUsage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR;
885 fmt_info.imageUsage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR |
886 VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR |
887 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
888 VK_IMAGE_USAGE_SAMPLED_BIT;
892 fmt_info.imageUsage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
896 ret = vk->GetPhysicalDeviceVideoFormatPropertiesKHR(hwctx->
phys_dev,
899 if (
ret == VK_ERROR_FORMAT_NOT_SUPPORTED ||
900 (!nb_out_fmts &&
ret == VK_SUCCESS)) {
902 }
else if (
ret != VK_SUCCESS) {
908 ret_info =
av_mallocz(
sizeof(*ret_info)*nb_out_fmts);
912 for (
int i = 0;
i < nb_out_fmts;
i++)
913 ret_info[
i].sType = VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR;
915 ret = vk->GetPhysicalDeviceVideoFormatPropertiesKHR(hwctx->
phys_dev,
917 &nb_out_fmts, ret_info);
918 if (
ret == VK_ERROR_FORMAT_NOT_SUPPORTED ||
919 (!nb_out_fmts &&
ret == VK_SUCCESS)) {
922 }
else if (
ret != VK_SUCCESS) {
931 *vk_fmt = best_vkfmt = VK_FORMAT_UNDEFINED;
934 av_log(avctx,
AV_LOG_DEBUG,
"Choosing best pixel format for decoding from %i:\n", nb_out_fmts);
935 for (
int i = 0;
i < nb_out_fmts;
i++) {
943 if (
tmp == best_format)
944 best_vkfmt = ret_info[
i].format;
954 av_log(avctx,
AV_LOG_ERROR,
"No valid/compatible pixel format found for decoding!\n");
962 *vk_fmt = best_vkfmt;
977 int err, dedicated_dpb;
996 prof, &dedicated_dpb);
1009 hwfc->format[0] = vkfmt;
1010 hwfc->create_pnext = &prof->profile_list;
1011 hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
1012 hwfc->usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1013 VK_IMAGE_USAGE_SAMPLED_BIT |
1014 VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR;
1016 if (!dec->dedicated_dpb)
1017 hwfc->usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR;
1019 ctx = dec->shared_ctx;
1022 hwfc->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
1031 VkVideoSessionParametersKHR *par = (VkVideoSessionParametersKHR *)
data;
1032 vk->DestroyVideoSessionParametersKHR(
ctx->s.hwctx->act_dev, *par,
1033 ctx->s.hwctx->alloc);
1038 const VkVideoSessionParametersCreateInfoKHR *session_params_create)
1040 VkVideoSessionParametersKHR *par =
av_malloc(
sizeof(*par));
1048 ret = vk->CreateVideoSessionParametersKHR(
ctx->s.hwctx->act_dev, session_params_create,
1049 ctx->s.hwctx->alloc, par);
1050 if (
ret != VK_SUCCESS) {
1051 av_log(logctx,
AV_LOG_ERROR,
"Unable to create Vulkan video session parameters: %s!\n",
1089 const VkVideoProfileInfoKHR *
profile;
1091 const VkPhysicalDeviceDriverProperties *driver_props;
1093 VkVideoDecodeH264SessionParametersCreateInfoKHR h264_params = {
1094 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR,
1096 VkVideoDecodeH265SessionParametersCreateInfoKHR h265_params = {
1097 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR,
1099 StdVideoAV1SequenceHeader av1_empty_seq = { 0 };
1100 VkVideoDecodeAV1SessionParametersCreateInfoKHR av1_params = {
1101 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR,
1102 .pStdSequenceHeader = &av1_empty_seq,
1104 VkVideoSessionParametersCreateInfoKHR session_params_create = {
1105 .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR,
1111 VkVideoSessionCreateInfoKHR session_create = {
1112 .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR,
1137 VK_QUEUE_VIDEO_DECODE_BIT_KHR,
1146 if (
s->query_props[
ctx->qf.queue_family].queryResultStatusSupport)
1149 session_create.flags = 0x0;
1150 session_create.queueFamilyIndex =
ctx->qf.queue_family;
1151 session_create.maxCodedExtent =
ctx->caps.maxCodedExtent;
1152 session_create.maxDpbSlots =
ctx->caps.maxDpbSlots;
1153 session_create.maxActiveReferencePictures =
ctx->caps.maxActiveReferencePictures;
1154 session_create.pictureFormat =
s->hwfc->format[0];
1155 session_create.referencePictureFormat = session_create.pictureFormat;
1156 session_create.pStdHeaderVersion = &vk_desc->
ext_props;
1157 session_create.pVideoProfile =
profile;
1164 nb_q, VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR, 0,
1179 if (!
ctx->common.dpb_hwfc_ref) {
1192 VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
1193 dpb_hwfc->
format[0] =
s->hwfc->format[0];
1194 dpb_hwfc->
tiling = VK_IMAGE_TILING_OPTIMAL;
1195 dpb_hwfc->
usage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR |
1196 VK_IMAGE_USAGE_SAMPLED_BIT;
1198 if (
ctx->common.layered_dpb)
1205 if (
ctx->common.layered_dpb) {
1207 if (!
ctx->common.layered_frame) {
1213 &
ctx->common.layered_view,
1214 &
ctx->common.layered_aspect,
1216 s->hwfc->format[0], 1);
1222 session_params_create.videoSession =
ctx->common.session;
1223 ret = vk->CreateVideoSessionParametersKHR(
s->hwctx->act_dev, &session_params_create,
1224 s->hwctx->alloc, &
ctx->empty_session_params);
1225 if (
ret != VK_SUCCESS) {
1226 av_log(avctx,
AV_LOG_ERROR,
"Unable to create empty Vulkan video session parameters: %s!\n",
1232 if (driver_props->driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY &&
1233 driver_props->conformanceVersion.major == 1 &&
1234 driver_props->conformanceVersion.minor == 3 &&
1235 driver_props->conformanceVersion.subminor == 8 &&
1236 driver_props->conformanceVersion.patch < 3)