| 1150 | } |
| 1151 | |
| 1152 | void Submit(const AVFrame* frame) { |
| 1153 | if (pending_submission_) |
| 1154 | throw std::runtime_error("Direct Vulkan compositor submission called while previous frame is still pending"); |
| 1155 | if (software_input_) |
| 1156 | throw std::runtime_error("Composite(AVFrame) called on software-input compositor"); |
| 1157 | auto* vk_frame = reinterpret_cast<AVVkFrame*>(frame->data[0]); |
| 1158 | if (!vk_frame) |
| 1159 | throw std::runtime_error("Missing AVVkFrame on direct Vulkan frame"); |
| 1160 | DebugLog("direct compositor: begin frame"); |
| 1161 | |
| 1162 | std::array<VkImageView, 3> video_views{}; |
| 1163 | if (frames_context_->sw_format == AV_PIX_FMT_NV12) { |
| 1164 | DebugLog("direct compositor: create NV12 views"); |
| 1165 | DebugLog("direct compositor: img0=" + std::to_string(reinterpret_cast<uintptr_t>(vk_frame->img[0])) + |
| 1166 | " img1=" + std::to_string(reinterpret_cast<uintptr_t>(vk_frame->img[1])) + |
| 1167 | " fmt0=" + std::to_string(static_cast<int>(vulkan_frames_context_->format[0])) + |
| 1168 | " fmt1=" + std::to_string(static_cast<int>(vulkan_frames_context_->format[1]))); |
| 1169 | video_views[0] = CreatePlaneView(vk_frame->img[0], VK_FORMAT_R8_UNORM, VK_IMAGE_ASPECT_PLANE_0_BIT); |
| 1170 | video_views[1] = CreatePlaneView(vk_frame->img[0], VK_FORMAT_R8G8_UNORM, VK_IMAGE_ASPECT_PLANE_1_BIT); |
| 1171 | video_views[2] = CreatePlaneView(vk_frame->img[0], VK_FORMAT_R8G8_UNORM, VK_IMAGE_ASPECT_PLANE_1_BIT); |
| 1172 | } else { |
| 1173 | DebugLog("direct compositor: create planar views"); |
| 1174 | for (int i = 0; i < 3; ++i) |
| 1175 | video_views[i] = CreatePlaneView(vk_frame->img[i], vulkan_frames_context_->format[i], VK_IMAGE_ASPECT_COLOR_BIT); |
| 1176 | } |
| 1177 | |
| 1178 | UpdateDescriptorSet(video_views); |
| 1179 | DebugLog("direct compositor: descriptor set updated"); |
| 1180 | const std::array<VkImageLayout, 3> wait_layouts = { |
| 1181 | vk_frame->layout[0], |
| 1182 | vk_frame->layout[1], |
| 1183 | frames_context_->sw_format == AV_PIX_FMT_NV12 ? vk_frame->layout[1] : vk_frame->layout[2] |
| 1184 | }; |
| 1185 | |
| 1186 | VkCommandBufferAllocateInfo alloc_info{}; |
| 1187 | alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; |
| 1188 | alloc_info.commandPool = command_pool_; |
| 1189 | alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
| 1190 | alloc_info.commandBufferCount = 1; |
| 1191 | |
| 1192 | VkCommandBuffer command_buffer = VK_NULL_HANDLE; |
| 1193 | CheckVk(vkAllocateCommandBuffers(device_, &alloc_info, &command_buffer), "vkAllocateCommandBuffers"); |
| 1194 | DebugLog("direct compositor: command buffer allocated"); |
| 1195 | |
| 1196 | VkCommandBufferBeginInfo begin_info{}; |
| 1197 | begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
| 1198 | begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
| 1199 | CheckVk(vkBeginCommandBuffer(command_buffer, &begin_info), "vkBeginCommandBuffer"); |
| 1200 | DebugLog("direct compositor: command buffer begin"); |
| 1201 | |
| 1202 | const int plane_count = frames_context_->sw_format == AV_PIX_FMT_NV12 ? 1 : 3; |
| 1203 | std::array<VkImageMemoryBarrier, 3> video_barriers{}; |
| 1204 | for (int i = 0; i < plane_count; ++i) { |
| 1205 | video_barriers[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
| 1206 | video_barriers[i].srcAccessMask = static_cast<VkAccessFlags>(vk_frame->access[i]); |
| 1207 | video_barriers[i].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; |
| 1208 | video_barriers[i].oldLayout = wait_layouts[i]; |
| 1209 | video_barriers[i].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
no test coverage detected