71#define FRUC_NB_SLOTS 2
162#define OFFSET(x) offsetof(FRUCVulkanContext, x)
163#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
166 {
"fps",
"A string describing the desired output frame rate",
168 {
"perf",
"Optical flow performance level (quality versus speed)",
170 VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV, VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_FAST_NV,
171 FLAGS, .unit =
"perf" },
173 { .i64 = VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV }, 0, 0,
FLAGS, .unit =
"perf" },
175 { .i64 = VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MEDIUM_NV }, 0, 0,
FLAGS, .unit =
"perf" },
177 { .i64 = VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_FAST_NV }, 0, 0,
FLAGS, .unit =
"perf" },
178 {
"grid",
"Optical flow output grid size in pixels (coarser is faster)",
181 { .i64 = 0 }, 0, 0,
FLAGS, .unit =
"grid" },
196 VkOpticalFlowImageFormatInfoNV info = {
197 .sType = VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV,
200 VkOpticalFlowImageFormatPropertiesNV *props;
201 VkFormat result = VK_FORMAT_UNDEFINED;
204 vk->GetPhysicalDeviceOpticalFlowImageFormatsNV(vkctx->
hwctx->
phys_dev, &info,
207 return VK_FORMAT_UNDEFINED;
209 props =
av_calloc(count,
sizeof(*props));
211 return VK_FORMAT_UNDEFINED;
212 for (uint32_t
i = 0;
i < count;
i++)
213 props[
i].sType = VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_PROPERTIES_NV;
215 vk->GetPhysicalDeviceOpticalFlowImageFormatsNV(vkctx->
hwctx->
phys_dev, &info,
218 result = props[0].format;
219 for (uint32_t
i = 0;
i < count;
i++) {
222 if (props[
i].
format == preferred) {
234 VkOpticalFlowUsageFlagsNV of_usage, VkImageUsageFlags
usage,
235 VkImageCreateFlags create_flags)
243 VkOpticalFlowImageFormatInfoNV of_info = {
244 .sType = VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV,
247 VkImageViewCreateInfo view_info = {
248 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
249 .viewType = VK_IMAGE_VIEW_TYPE_2D,
252 .subresourceRange = {
253 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
264 VK_IMAGE_TILING_OPTIMAL,
usage, create_flags,
269 view_info.image = *
img;
270 ret = vk->CreateImageView(hwctx->
act_dev, &view_info, hwctx->
alloc, view);
271 if (ret != VK_SUCCESS) {
297 VkImage imgs[4] = {
fs->gray_img[0],
fs->gray_img[1],
298 fs->flow_img[0],
fs->flow_img[1] };
300 for (
int i = 0;
i < 4;
i++) {
301 bar[nb_bar++] = (VkImageMemoryBarrier2) {
302 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
303 .srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
305 .dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
306 .dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT,
307 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
308 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
309 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
310 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
312 .subresourceRange = {
313 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
321 vk->CmdPipelineBarrier2(exec->
buf, &(VkDependencyInfo) {
322 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
323 .pImageMemoryBarriers = bar,
324 .imageMemoryBarrierCount = nb_bar,
344 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
345 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
346 case VK_FORMAT_B8G8R8_UNORM:
347 case VK_FORMAT_B8G8R8A8_UNORM:
350 return c->offset / ((
c->depth + 7) / 8);
360 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
363 return c->offset / ((
c->depth + 7) / 8);
382 (
desc->log2_chroma_w ||
desc->log2_chroma_h)) {
384 "supported\n",
desc->name);
394 "shader representation\n",
desc->name);
411 mask = vkctx->ownership_props[
from].optimalImageTransferToQueueFamilies;
412 return !!(
mask & (1U <<
to));
422 VkOpticalFlowGridSizeFlagsNV grids;
439 static const float bt709[3] = { 0.2126f, 0.7152f, 0.0722f };
441 memset(
s->luma_weights, 0,
sizeof(
s->luma_weights));
449 for (
int c = 0;
c < 3;
c++)
450 s->luma_weights[
desc->comp[
c].plane][0] = bt709[
c];
453 s->luma_weights[0][0] = 1.0f;
455 }
else if (
desc->nb_components > 1) {
459 for (
int c = 0;
c < 3;
c++)
468 s->luma_weights[0][0] = 1.0f;
481 for (
int p = 0; p <
s->gray_planes; p++) {
485 if (vkfmts[p] != VK_FORMAT_R16_UNORM)
488 for (
int c = 0;
c <
desc->nb_components;
c++) {
489 if (
desc->comp[
c].plane == p) {
497 if (
comp->shift +
comp->depth == 16)
500 scale = 65535.0f / (((1U <<
comp->depth) - 1U) <<
comp->shift);
501 for (
int c = 0;
c < 4;
c++)
502 s->luma_weights[p][
c] *=
scale;
508 "VK_NV_optical_flow extension\n");
516 const VkPhysicalDeviceOpticalFlowFeaturesNV *of;
518 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV);
519 if (!of || !of->opticalFlow) {
521 "opticalFlow feature enabled\n");
531 "VK_KHR_maintenance9 extension\n");
536 const VkPhysicalDeviceMaintenance9FeaturesKHR *m9;
538 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_9_FEATURES_KHR);
539 if (!m9 || !m9->maintenance9) {
541 "maintenance9 feature enabled\n");
561 if (
s->qf_of->idx !=
s->qf->idx &&
565 "families cannot exchange optimally tiled images without explicit "
566 "queue family ownership transfers\n",
s->qf->idx,
s->qf_of->idx);
583 VkSemaphoreTypeCreateInfo sem_type_info = {
584 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
585 .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
588 VkSemaphoreCreateInfo sem_info = {
589 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
590 .pNext = &sem_type_info,
592 if (vk->CreateSemaphore(vkctx->
hwctx->
act_dev, &sem_info,
593 vkctx->
hwctx->
alloc, &
s->sem_gray) != VK_SUCCESS ||
595 vkctx->
hwctx->
alloc, &
s->sem_flow) != VK_SUCCESS ||
597 vkctx->
hwctx->
alloc, &
s->sem_interp) != VK_SUCCESS) {
606 if (
s->input_format != VK_FORMAT_R8_UNORM) {
613 VK_FORMAT_R16G16_S10_5_NV);
614 if (
s->flow_format != VK_FORMAT_R16G16_S10_5_NV) {
616 "unavailable (got %d)\n",
s->flow_format);
620 static const struct {
622 VkOpticalFlowGridSizeFlagsNV
bit;
624 { 1, VK_OPTICAL_FLOW_GRID_SIZE_1X1_BIT_NV },
625 { 2, VK_OPTICAL_FLOW_GRID_SIZE_2X2_BIT_NV },
626 { 4, VK_OPTICAL_FLOW_GRID_SIZE_4X4_BIT_NV },
627 { 8, VK_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_NV },
631 if (
s->opt_grid_size) {
633 VkOpticalFlowGridSizeFlagsNV want = 0;
635 if (grid_map[
i].
size ==
s->opt_grid_size)
636 want = grid_map[
i].bit;
637 if (!want || !(grids & want)) {
639 "supported by the device (supported mask 0x%x)\n",
640 s->opt_grid_size, grids);
643 s->grid_size =
s->opt_grid_size;
649 if (grids & grid_map[
i].
bit) {
650 s->grid_size = grid_map[
i].size;
651 s->grid_bit = grid_map[
i].bit;
661 s->flow_width = (
s->width +
s->grid_size - 1) /
s->grid_size;
662 s->flow_height = (
s->height +
s->grid_size - 1) /
s->grid_size;
664 av_log(avctx,
AV_LOG_INFO,
"optical flow: perf %d, grid %d, flow %dx%d, bidir=%d, "
665 "min %dx%d max %dx%d\n",
s->perf_level,
s->grid_size,
s->flow_width,
s->flow_height,
673 if ((uint32_t)
s->width < ofp->minWidth || (uint32_t)
s->width > ofp->maxWidth ||
674 (uint32_t)
s->height < ofp->minHeight || (uint32_t)
s->height > ofp->maxHeight) {
676 "device optical flow engine supports (%ux%u to %ux%u)\n",
678 ofp->minWidth, ofp->minHeight, ofp->maxWidth, ofp->maxHeight);
685 "bidirectional flow, which this filter requires\n");
695 s->input_format,
s->width,
s->height,
696 VK_OPTICAL_FLOW_USAGE_INPUT_BIT_NV,
697 VK_IMAGE_USAGE_STORAGE_BIT, 0));
699 s->input_format,
s->width,
s->height,
700 VK_OPTICAL_FLOW_USAGE_INPUT_BIT_NV,
701 VK_IMAGE_USAGE_STORAGE_BIT, 0));
708 s->flow_format,
s->flow_width,
s->flow_height,
709 VK_OPTICAL_FLOW_USAGE_OUTPUT_BIT_NV,
710 VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT));
712 s->flow_format,
s->flow_width,
s->flow_height,
713 VK_OPTICAL_FLOW_USAGE_OUTPUT_BIT_NV,
714 VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT));
716 for (
int i = 0;
i < 2;
i++) {
717 VkImageViewCreateInfo view_info = {
718 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
719 .image =
fs->flow_img[
i],
720 .viewType = VK_IMAGE_VIEW_TYPE_2D,
721 .format = VK_FORMAT_R16G16_SINT,
723 .subresourceRange = {
724 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
729 if (vk->CreateImageView(vkctx->
hwctx->
act_dev, &view_info,
730 vkctx->
hwctx->
alloc, &
fs->flow_sint_view[
i]) != VK_SUCCESS) {
736 ret = vk->CreateOpticalFlowSessionNV(vkctx->
hwctx->
act_dev,
737 &(VkOpticalFlowSessionCreateInfoNV) {
738 .sType = VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_INFO_NV,
741 .imageFormat = s->input_format,
742 .flowVectorFormat = s->flow_format,
743 .outputGridSize = s->grid_bit,
744 .performanceLevel = s->perf_level,
745 .flags = VK_OPTICAL_FLOW_SESSION_CREATE_BOTH_DIRECTIONS_BIT_NV,
747 if (ret != VK_SUCCESS) {
753 static const VkOpticalFlowSessionBindingPointNV binding_points[] = {
754 VK_OPTICAL_FLOW_SESSION_BINDING_POINT_INPUT_NV,
755 VK_OPTICAL_FLOW_SESSION_BINDING_POINT_REFERENCE_NV,
756 VK_OPTICAL_FLOW_SESSION_BINDING_POINT_FLOW_VECTOR_NV,
757 VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_FLOW_VECTOR_NV,
759 const VkImageView binding_views[] = {
760 fs->gray_view[0],
fs->gray_view[1],
761 fs->flow_view[0],
fs->flow_view[1],
764 ret = vk->BindOpticalFlowSessionImageNV(vkctx->
hwctx->
act_dev,
fs->session,
765 binding_points[
i], binding_views[
i], VK_IMAGE_LAYOUT_GENERAL);
766 if (ret != VK_SUCCESS) {
778 (uint32_t []) { 32, 32, 1 }, 0);
780 VK_SHADER_STAGE_COMPUTE_BIT);
784 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
786 .elems =
s->gray_planes,
787 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
791 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
793 .elems =
s->gray_planes,
794 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
798 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
800 .mem_quali =
"writeonly",
803 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
815 (uint32_t []) { 32, 32, 1 }, 0);
817 VK_SHADER_STAGE_COMPUTE_BIT);
821 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
824 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
828 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
831 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
835 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
836 .mem_quali =
"writeonly",
839 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
842 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
844 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
848 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
850 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
866 VkPipelineStageFlags2 src_stage, VkAccessFlags2 src_access,
867 VkPipelineStageFlags2 dst_stage, VkAccessFlags2 dst_access)
869 *bar = (VkImageMemoryBarrier2) {
870 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
871 .srcStageMask = src_stage,
872 .srcAccessMask = src_access,
873 .dstStageMask = dst_stage,
874 .dstAccessMask = dst_access,
875 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
876 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
877 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
878 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
880 .subresourceRange = {
881 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
917 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
918 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
920 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
921 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
927 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
934 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
936 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
940 for (
int p = 0; p <
s->gray_planes; p++) {
942 f0_views[p], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
945 f1_views[p], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
949 fs->gray_view[0], VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE);
951 fs->gray_view[1], VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE);
959 VK_SHADER_STAGE_COMPUTE_BIT, 0,
965 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
966 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
967 VK_ACCESS_SHADER_READ_BIT,
968 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
969 VK_QUEUE_FAMILY_IGNORED);
971 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
972 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
973 VK_ACCESS_SHADER_READ_BIT,
974 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
975 VK_QUEUE_FAMILY_IGNORED);
977 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 0,
978 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT);
980 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 0,
981 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT);
983 vk->CmdPipelineBarrier2(exec->
buf, &(VkDependencyInfo) {
984 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
985 .pImageMemoryBarriers = img_bar,
986 .imageMemoryBarrierCount = nb_img_bar,
989 vk->CmdDispatch(exec->
buf,
990 FFALIGN(
s->width,
s->grayscale.lg_size[0]) /
s->grayscale.lg_size[0],
991 FFALIGN(
s->height,
s->grayscale.lg_size[1]) /
s->grayscale.lg_size[1],
1006 VK_PIPELINE_STAGE_2_OPTICAL_FLOW_BIT_NV);
1011 VK_PIPELINE_STAGE_2_OPTICAL_FLOW_BIT_NV);
1017 VK_PIPELINE_STAGE_2_OPTICAL_FLOW_BIT_NV);
1019 VK_PIPELINE_STAGE_2_OPTICAL_FLOW_BIT_NV);
1023 vk->CmdOpticalFlowExecuteNV(exec->
buf,
fs->session,
1024 &(VkOpticalFlowExecuteInfoNV) {
1025 .sType = VK_STRUCTURE_TYPE_OPTICAL_FLOW_EXECUTE_INFO_NV,
1044 int plane, uint32_t *
w, uint32_t *
h)
1086 if (!
s->flow_valid) {
1103 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
1108 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
1110 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
1112 fs->interp_done =
s->interp_value;
1115 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
1116 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
1118 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
1119 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
1121 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
1122 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
1129 0, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
1132 0, 1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
1135 0, 2, VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE);
1137 fs->flow_sint_view[0], VK_IMAGE_LAYOUT_GENERAL,
s->flow_sampler);
1139 fs->flow_sint_view[1], VK_IMAGE_LAYOUT_GENERAL,
s->flow_sampler);
1143 VK_SHADER_STAGE_COMPUTE_BIT, 0,
sizeof(pd), &pd);
1147 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
1148 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
1149 VK_ACCESS_SHADER_WRITE_BIT,
1150 VK_IMAGE_LAYOUT_GENERAL,
1151 VK_QUEUE_FAMILY_IGNORED);
1153 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
1154 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
1155 VK_ACCESS_SHADER_READ_BIT,
1156 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
1157 VK_QUEUE_FAMILY_IGNORED);
1159 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
1160 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
1161 VK_ACCESS_SHADER_READ_BIT,
1162 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
1163 VK_QUEUE_FAMILY_IGNORED);
1165 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 0,
1166 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT);
1168 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 0,
1169 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT);
1171 vk->CmdPipelineBarrier2(exec->
buf, &(VkDependencyInfo) {
1172 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
1173 .pImageMemoryBarriers = img_bar,
1174 .imageMemoryBarrierCount = nb_img_bar,
1177 vk->CmdDispatch(exec->
buf,
1178 FFALIGN(
s->width,
s->interpolate.lg_size[0]) /
s->interpolate.lg_size[0],
1179 FFALIGN(
s->height,
s->interpolate.lg_size[1]) /
s->interpolate.lg_size[1],
1213 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
1214 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT));
1216 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
1217 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT));
1220 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
1221 VK_PIPELINE_STAGE_2_COPY_BIT,
1222 VK_ACCESS_2_TRANSFER_READ_BIT,
1223 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1224 VK_QUEUE_FAMILY_IGNORED);
1226 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
1227 VK_PIPELINE_STAGE_2_COPY_BIT,
1228 VK_ACCESS_2_TRANSFER_WRITE_BIT,
1229 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1230 VK_QUEUE_FAMILY_IGNORED);
1232 vk->CmdPipelineBarrier2(exec->
buf, &(VkDependencyInfo) {
1233 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
1234 .pImageMemoryBarriers = img_bar,
1235 .imageMemoryBarrierCount = nb_img_bar,
1238 for (
int i = 0;
i < nb_planes;
i++) {
1241 VkImageCopy region = {
1244 .extent = {
w,
h, 1 },
1246 vk->CmdCopyImage(exec->
buf,
1247 src_vk->
img[
FFMIN(
i, src_nb_images - 1)],
1248 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1249 out_vk->
img[
FFMIN(
i, out_nb_images - 1)],
1250 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1294 if (!
s->f0 && !
s->flush)
1300 if (work_pts >=
s->pts1 && !
s->flush)
1312 if (work_pts >=
s->pts1 +
s->delta &&
s->flush)
1315 interpolate8 =
av_rescale(work_pts -
s->pts0, 256,
s->delta);
1316 if (interpolate8 >= 256) {
1320 }
else if (interpolate8 <= 0) {
1325 float t = (
float)(work_pts -
s->pts0) / (
float)
s->delta;
1342 s->work->pts = work_pts;
1383 if (
s->f1 &&
pts ==
s->pts1) {
1395 s->delta =
s->pts1 -
s->pts0;
1400 s->start_pts =
s->pts1;
1406 s->start_pts =
s->pts1;
1442 double var_values[
VARS_NB], res;
1449 "config_output() input time base:%u/%u (%f)\n",
1450 ctx->inputs[0]->time_base.num,
ctx->inputs[0]->time_base.den,
1461 s->dest_frame_rate =
av_d2q(res, INT_MAX);
1462 if (
s->dest_frame_rate.num <= 0 ||
s->dest_frame_rate.den <= 0) {
1464 "Invalid output frame rate '%s' (must evaluate to a positive value)\n",
1465 s->requested_frame_rate);
1471 exact =
av_reduce(&
s->dest_time_base.num, &
s->dest_time_base.den,
1473 (
int64_t)
s->srce_time_base.den *
s->dest_frame_rate.den ),
1474 (
int64_t)
s->srce_time_base.den *
s->dest_frame_rate.num, INT_MAX);
1482 if (!
s->dest_time_base.num || !
s->dest_time_base.den) {
1483 exact =
av_reduce(&
s->dest_time_base.num, &
s->dest_time_base.den,
1484 s->dest_frame_rate.den,
s->dest_frame_rate.num, INT_MAX);
1488 "time base:%u/%u -> %u/%u exact:%d\n",
1489 s->srce_time_base.num,
s->srce_time_base.den,
1490 s->dest_time_base.num,
s->dest_time_base.den, exact);
1503 "config_output() output time base:%u/%u (%f) w:%d h:%d\n",
1506 outlink->
w, outlink->
h);
1544 vk->DestroyOpticalFlowSessionNV(vkctx->
hwctx->
act_dev,
fs->session,
1546 for (
int i = 0;
i < 2;
i++) {
1547 if (
fs->gray_view[
i])
1550 if (
fs->flow_view[
i])
1552 if (
fs->flow_sint_view[
i])
1563 if (
s->flow_sampler)
1589 .p.name =
"fruc_vulkan",
1590 .p.description =
NULL_IF_CONFIG_SMALL(
"Frame rate up-conversion using the Vulkan NV optical flow extension"),
1591 .p.priv_class = &fruc_vulkan_class,
static int config_input(AVFilterLink *inlink)
static const char *const format[]
const FFFilter ff_vf_fruc_vulkan
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
#define i(width, name, range_min, range_max)
#define bit(string, value)
#define fs(width, name, subs,...)
#define AV_CEIL_RSHIFT(a, b)
int(* init)(AVBSFContext *ctx)
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
int av_expr_parse_and_eval(double *d, const char *s, const char *const *const_names, const double *const_values, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), void *opaque, int log_offset, void *log_ctx)
Parse and evaluate an expression.
simple arithmetic expression evaluator
#define AV_NUM_DATA_POINTERS
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
@ AV_OPT_TYPE_INT
Underlying C type is int.
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
#define AVFILTER_FLAG_HWDEVICE
The filter can create hardware frames using AVFilterContext.hw_device_ctx.
#define AVERROR_EXTERNAL
Generic error in an external library.
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
#define AV_FRAME_FLAG_INTERLACED
A flag to mark frames whose content is interlaced.
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
#define AV_LOG_WARNING
Something somehow does not look correct.
#define AV_LOG_VERBOSE
Detailed information.
#define AV_LOG_INFO
Standard information.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
Reduce a fraction.
AVRational av_d2q(double d, int max)
Convert a double precision floating point number to a rational.
static double av_q2d(AVRational a)
Convert an AVRational to a double.
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
int64_t av_gcd(int64_t a, int64_t b)
Compute the greatest common divisor of two integer operands.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
#define AV_NOPTS_VALUE
Undefined timestamp value.
const VkFormat * av_vkfmt_from_pixfmt(enum AVPixelFormat p)
Returns the optimal per-plane Vulkan format for a given sw_format, one for each plane.
static void scale(int *out, const int *in, const int w, const int h, const int shift)
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
static int config_output(AVBitStreamFilterLink *outlink)
#define FILTER_INPUTS(array)
#define FILTER_OUTPUTS(array)
#define FF_FILTER_FORWARD_WANTED(outlink, inlink)
Forward the frame_wanted_out flag from an output link to an input link.
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
#define FFERROR_NOT_READY
Filters implementation helper functions and internal structures.
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
static FilterLink * ff_filter_link(AVFilterLink *link)
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
#define AVFILTER_DEFINE_CLASS(fname)
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
void ff_vk_shader_update_img_array(FFVulkanContext *s, FFVkExecContext *e, FFVulkanShader *shd, AVFrame *f, VkImageView *views, int set, int binding, VkImageLayout layout, VkSampler sampler)
Update a descriptor in a buffer with an image array.
int ff_vk_shader_load(FFVulkanShader *shd, VkPipelineStageFlags stage, VkSpecializationInfo *spec, uint32_t wg_size[3], uint32_t required_subgroup_size)
Initialize a shader object.
void ff_vk_shader_add_descriptor_set(FFVulkanContext *s, FFVulkanShader *shd, const FFVulkanDescriptorSetBinding *desc, int nb, int singular)
Add descriptor to a shader.
void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool)
VkImageAspectFlags ff_vk_aspect_flag(AVFrame *f, int p)
Get the aspect flag for a plane from an image.
int ff_vk_exec_pool_init(FFVulkanContext *s, AVVulkanDeviceQueueFamily *qf, FFVkExecPool *pool, int nb_contexts, int nb_queries, VkQueryType query_type, int query_64bit, const void *query_create_pnext)
Allocates/frees an execution pool.
void ff_vk_image_free(FFVulkanContext *s, VkImage *img, VkDeviceMemory *mem)
Free an image created by ff_vk_image_create(); all GPU use must have completed.
void ff_vk_exec_wait(FFVulkanContext *s, FFVkExecContext *e)
int ff_vk_image_create(FFVulkanContext *s, VkImage *img, VkDeviceMemory *mem, int width, int height, VkFormat format, int nb_layers, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, void *create_pnext)
Memory/buffer/image allocation helpers.
int ff_vk_shader_add_push_const(FFVulkanShader *shd, int offset, int size, VkShaderStageFlagBits stage)
Add/update push constants for execution.
int ff_vk_shader_update_img(FFVulkanContext *s, FFVkExecContext *e, FFVulkanShader *shd, int set, int bind, int offs, VkImageView view, VkImageLayout layout, VkSampler sampler)
Sets an image descriptor for specified shader and binding.
void ff_vk_uninit(FFVulkanContext *s)
Frees main context.
const char * ff_vk_ret2str(VkResult res)
Converts Vulkan return values to strings.
const VkComponentMapping ff_comp_identity_map
void ff_vk_frame_barrier(FFVulkanContext *s, FFVkExecContext *e, AVFrame *pic, VkImageMemoryBarrier2 *bar, int *nb_bar, VkPipelineStageFlags2 src_stage, VkPipelineStageFlags2 dst_stage, VkAccessFlagBits2 new_access, VkImageLayout new_layout, uint32_t new_qf)
int ff_vk_exec_start(FFVulkanContext *s, FFVkExecContext *e)
Start/submit/wait an execution.
int ff_vk_create_imageviews(FFVulkanContext *s, FFVkExecContext *e, VkImageView views[AV_NUM_DATA_POINTERS], AVFrame *f, enum FFVkShaderRepFormat rep_fmt)
Create an imageview and add it as a dependency to an execution.
void ff_vk_shader_free(FFVulkanContext *s, FFVulkanShader *shd)
Free a shader.
int ff_vk_shader_register_exec(FFVulkanContext *s, FFVkExecPool *pool, FFVulkanShader *shd)
Register a shader with an exec pool.
int ff_vk_init_sampler(FFVulkanContext *s, VkSampler *sampler, int unnorm_coords, VkFilter filt)
Create a sampler.
FFVkExecContext * ff_vk_exec_get(FFVulkanContext *s, FFVkExecPool *pool)
Retrieve an execution pool.
int ff_vk_exec_submit(FFVulkanContext *s, FFVkExecContext *e)
void ff_vk_exec_bind_shader(FFVulkanContext *s, FFVkExecContext *e, const FFVulkanShader *shd)
Bind a shader.
AVVulkanDeviceQueueFamily * ff_vk_qf_find(FFVulkanContext *s, VkQueueFlagBits dev_family, VkVideoCodecOperationFlagBitsKHR vid_ops)
Chooses an appropriate QF.
void ff_vk_exec_add_dep_signal_sem(FFVulkanContext *s, FFVkExecContext *e, VkSemaphore sem, uint64_t val, VkPipelineStageFlagBits2 stage)
void ff_vk_exec_discard(FFVulkanContext *s, FFVkExecContext *e)
int ff_vk_shader_link(FFVulkanContext *s, FFVulkanShader *shd, const char *spirv, size_t spirv_len, const char *entrypoint)
Link a shader into an executable.
int ff_vk_exec_add_dep_frame(FFVulkanContext *s, FFVkExecContext *e, AVFrame *f, VkPipelineStageFlagBits2 wait_stage, VkPipelineStageFlagBits2 signal_stage)
void ff_vk_shader_update_push_const(FFVulkanContext *s, FFVkExecContext *e, FFVulkanShader *shd, VkShaderStageFlagBits stage, int offset, size_t size, void *src)
Update push constant in a shader.
void ff_vk_exec_add_dep_wait_sem(FFVulkanContext *s, FFVkExecContext *e, VkSemaphore sem, uint64_t val, VkPipelineStageFlagBits2 stage)
static const struct @257111027162314367033347246032313251342043035002 planes[]
static const uint16_t mask[17]
void * av_calloc(size_t nmemb, size_t size)
Memory handling functions.
static const char *const var_names[]
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
#define AV_PIX_FMT_FLAG_RGB
The pixel format contains RGB-like data (as opposed to YUV/grayscale).
#define AV_PIX_FMT_FLAG_FLOAT
The pixel format contains IEEE-754 floating point values.
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
#define AV_PIX_FMT_FLAG_BAYER
The pixel format is following a Bayer pattern.
AVPixelFormat
Pixel format.
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
#define FF_ARRAY_ELEMS(a)
void * priv
private data for use by the filter
A link between two filters.
int w
agreed upon image width
int h
agreed upon image height
AVFilterContext * src
source filter
AVRational time_base
Define the time base used by the PTS of the frames/samples which will pass through this link.
AVFilterContext * dst
dest filter
A filter pad used for either input or output.
This structure describes decoded (raw) audio or video data.
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Rational number (pair of numerator and denominator).
VkImage img[AV_NUM_DATA_POINTERS]
Vulkan images to which the memory is bound to.
Main Vulkan context, allocated as AVHWDeviceContext.hwctx.
VkPhysicalDevice phys_dev
Physical device.
const VkAllocationCallbacks * alloc
Custom memory allocator, else NULL.
VkDevice act_dev
Active device.
VkPhysicalDeviceFeatures2 device_features
This structure should be set to the set of features that present and enabled during device creation.
FFVulkanExtensions extensions
VkPhysicalDeviceOpticalFlowPropertiesNV optical_flow_props
AVVulkanDeviceContext * hwctx
enum AVPixelFormat output_format
VkDeviceMemory gray_mem[2]
VkImageView flow_view[2]
native (SFIXED5) view, bound to the OF session
VkImage gray_img[2]
grayscale inputs (INPUT, REFERENCE)
VkImage flow_img[2]
[0] forward, [1] backward
VkImageView flow_sint_view[2]
R16G16_SINT reinterpret view for sampling.
VkOpticalFlowSessionNV session
VkDeviceMemory flow_mem[2]
VkSampler flow_sampler
nearest sampler for the flow vectors
FFVulkanShader interpolate
char * requested_frame_rate
output fps as an expression
int opt_grid_size
requested grid in pixels (0 = finest)
int gray_planes
number of input planes the grayscale pass samples
int64_t pts1
current frame pts in dest_time_base
FRUCFlowSlot slots[FRUC_NB_SLOTS]
FFVkExecPool e_of
optical flow execution pool
int perf_level
VkOpticalFlowPerformanceLevelNV.
int flow_valid
flow computed for current (f0, f1) pair
VkSemaphore sem_flow
optical flow -> interpolation (compute)
VkSampler sampler
linear sampler for the video planes
FFVkExecPool e
compute execution pool
AVRational srce_time_base
timebase of source
int64_t pts0
last frame pts in dest_time_base
AVVulkanDeviceQueueFamily * qf_of
optical flow queue family
AVRational dest_time_base
timebase of destination
VkSemaphore sem_gray
grayscale (compute) -> optical flow
VkFormat input_format
grayscale input format
float luma_weights[4][4]
RGB->Y weights for the grayscale pass.
AVVulkanDeviceQueueFamily * qf
compute queue family
uint64_t gen
source pair generation (sem_gray/sem_flow value)
int flush
1 if the filter is being flushed
VkFormat flow_format
flow vector format
uint64_t interp_value
monotonic interpolation counter (sem_interp value)
AVFrame * f1
current frame
int64_t start_pts
pts of the first output frame
AVRational dest_frame_rate
output frames per second
int64_t delta
pts1 to pts0 delta
VkOpticalFlowGridSizeFlagsNV grid_bit
VkSemaphore sem_interp
interpolation reads -> next pair optical flow
int64_t n
output frame counter
Link properties exposed to filter code, but not external callers.
AVRational frame_rate
Frame rate of the stream on the link, or 1/0 if unknown or variable.
float luma_weights[4][4]
per-plane RGB->Y weights (dotted with each plane's texel)
int32_t planes
number of input planes sampled per frame
float plane_size[4][2]
visible texel extent of each plane
float luma_weights[4][4]
per-plane RGB->Y weights, matching the grayscale pass
static int packed_luma_channel(const AVPixFmtDescriptor *desc, VkFormat vkfmt)
const unsigned int ff_fruc_interpolate_comp_spv_len
static const AVOption fruc_vulkan_options[]
static int process_work_frame(AVFilterContext *ctx)
static void plane_wh(const AVPixFmtDescriptor *desc, int width, int height, int plane, uint32_t *w, uint32_t *h)
static int compute_flow(AVFilterContext *avctx)
const unsigned int ff_fruc_grayscale_comp_spv_len
static const AVFilterPad fruc_vulkan_outputs[]
static int config_input(AVFilterLink *inlink)
static int init_image_layouts(FRUCVulkanContext *s)
static int packed_rgb_channel(const AVPixFmtDescriptor *desc, VkFormat vkfmt, int comp)
static VkFormat pick_of_format(FRUCVulkanContext *s, VkOpticalFlowUsageFlagsNV usage, VkFormat preferred)
const unsigned char ff_fruc_grayscale_comp_spv_data[]
const unsigned char ff_fruc_interpolate_comp_spv_data[]
static int copy_frame(AVFilterContext *avctx, AVFrame *out, AVFrame *src)
static int create_of_image(FRUCVulkanContext *s, VkImage *img, VkDeviceMemory *mem, VkImageView *view, VkFormat format, int width, int height, VkOpticalFlowUsageFlagsNV of_usage, VkImageUsageFlags usage, VkImageCreateFlags create_flags)
static const AVFilterPad fruc_vulkan_inputs[]
static av_cold int check_sw_format(AVFilterContext *avctx, enum AVPixelFormat sw_format)
static int interpolate_frame(AVFilterContext *avctx, AVFrame *out, float t)
static int activate(AVFilterContext *ctx)
static av_cold void uninit(AVFilterContext *avctx)
static int passthrough_frame(AVFilterContext *ctx, AVFrame **work, AVFrame *src)
static av_cold int init_filter(AVFilterContext *avctx)
static int config_output(AVFilterLink *outlink)
static void of_image_barrier(VkImageMemoryBarrier2 *bar, VkImage img, VkPipelineStageFlags2 src_stage, VkAccessFlags2 src_access, VkPipelineStageFlags2 dst_stage, VkAccessFlags2 dst_access)
static int qf_transfer_preserves(FFVulkanContext *vkctx, uint32_t from, uint32_t to)
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
#define FF_VK_DEFAULT_EXEC_CONTEXTS
static const void * ff_vk_find_struct(const void *chain, VkStructureType stype)
static int ff_vk_count_images(AVVkFrame *f)
int ff_vk_filter_config_input(AVFilterLink *inlink)
int ff_vk_filter_config_output(AVFilterLink *outlink)
int ff_vk_filter_init(AVFilterContext *avctx)
General lavfi IO functions.
#define FF_VK_EXT_OPTICAL_FLOW
#define FF_VK_EXT_MAINTENANCE_9