SVT-AV1编码器中实现WPP依赖管理核心调度

assign_enc_dec_segments 函数。这个函数是 SVT-AV1 编码器中实现波前并行处理(WPP)分段依赖管理的核心调度器之一。

//函数功能:分配编码解码段任务

//返回值Bool

//True 成功分配了一个段给当前线程,调用者应该处理这个段

//False 当前没有可立即处理的段,调用这个应该跳出循环或者进行其他操作

参数:

//segmentPtr: 指向EncDecSegments 结构的指针,包含整个图像分段的状态,依赖关系等信息

//segmentInOutIndex 输入输出参数,输入时可能是旧的段索引,输出时,如果分配成功,被设置为分配段的索引。

//taskPtr 指向EncDecTasks结构体的指针,包含任务的具体信息

srmFifoPtr 指向一个FIFO队列指针,用于在需要时向其他现线程反馈新的任务。

static Bool assign_enc_dec_segments(EncDecSegments *segmentPtr, uint16_t *segmentInOutIndex, EncDecTasks *taskPtr, EbFifo *srmFifoPtr)

{

//初始化标志位,表示是否成功分配了段以供继续处理

Bool continue_processing_flag = FALSE;

//当前段所在的行索引

uint32_t row_segment_index = 0;

//当前正在处理或者检查的段索引

uint32_t segment_index;

//当前段的右邻居 段索引

uint32_t right_segment_index;

//当前段的左下邻居段索引,在WPP依赖中非常重要

uint32_t bottom_left_segment_index;

//反馈行索引,初始化为-1表示暂无反馈需要返送

//如果不为-1 ,则表示需要向指定行反馈一个任务

int16_t feedback_row_index = -1;

//标志位,表示在当前函数调用中是否已经为当前线程自身分配了一个段

//用于防止一次调用分配多个段给同一个线程

uint32_t self_assigned = FALSE;

//根据输入任务的任务类型 input_type 进行不同的处理

switch (taskPtr->input_type)

{

//case 1 任务来自MDC, Mode Decision Configuration 过程输入

case ENCDEC_TASKS_MDC_INPUT:

//整个图像的MDC过程已经完成,提供了完整的画面信息

//因此不需要复杂的逻辑来清除输入依赖

//重置所有编码解码段的行状态:遍历每一行分段

for (uint32_t row_index = 0; row_index < segmentPtr->segment_row_count; ++row_index) {

//将美航的当前处理段索引重置为该行的起始段索引

segmentPtr->row_array[row_index].current_seg_index = segmentPtr->row_array[row_index].starting_seg_index;

}

//立即从第0行的第0个段开始处理

*segmentInOutIndex = segmentPtr->row_array[0].current_seg_index;//分配段索引

taskPtr->input_type = ENCDEC_TASKS_CONTINUE;//将任务类型标记为 继续 以便后续处理

//递增第0行的当前段索引,为下一次分配做准备

++segmentPtr->row_array[0].current_seg_index;

//设置标志位TRUE,表示成功分配了段,调用者应继续处理此段

continue_processing_flag = TRUE;

break; //跳出siwtch

//case 2:任务指定了要处理的编码解码行ENCDEC_INPUT

case ENCDEC_TASKS_ENCDEC_INPUT:

//立即从指定行enc_dec_segment_row 的当前段开始处理

*segmentInOutIndex = segmentPtr->row_array[taskPtr->enc_dec_segment_row].current_seg_index;

taskPtr->input_type = ENCDEC_TASKS_CONTINUE;//将任务类型标记为继续

//递增指定行的当前段索引

++segmentPtr->row_array[taskPtr->enc_dec_segment_row].current_seg_index;

//设置标志位为True,表示成功分配了段

continue_processing_flag = TRUE;

break;

//任务类型是继续COnitnue,表示一个段已经完成处理,需要检查并更新依赖关系,可能分配下一个段。

case ENCDEC_TASKS_CONTINUE:

//获取刚刚处理完的段索引

segment_index = *segmentInOutIndex;

//计算这个段所在的行索引 将一维段索引映射到二维的行索引

tow_segment_index = segment_idnex / segmentPtr->segment_band_count;

//计算当前段的右邻居段索引 同一行,下一个段

right_segment_index = segment_idnex + 1;

//计算当前段的左下邻居段索引,相对左下位置,这是WPP依赖的关键

bottom_left_segment_index = segment_idnex + segmentPtr->segment_band_count;

//检查并处理右邻居段的依赖

//首先检查右邻居是否存在,当前段索引是否小雨当前行的结束段索引

if (segment_index < segmentPtr->row_array[row_segment_index].assignment_mutex) {

//递减右邻居段的依赖计数器,每个段初始时间能有依赖,例如依赖于左上和上方的段

--segmentPtr->dep_map.dependency_map[right_segment_index];

//检查右邻居段的依赖计数器是否降为0, 意味着它所依赖的所有段都已经处理完成

if (segmentPtr->dep_map.dependency_map[right_segment_index] == 0) {

//依赖已满足,可以将右邻居段分配给当前线程处理

*segmentInOutIndex = segmentPtr->row_array[row_segment_index].current_seg_index;

//递增该行的当前段索引,为下次分配准备

++segmentPtr->row_array[row_segment_index].current_seg_index;

//标记当前线程已经为自己分配了一个段

self_assigned = TRUE;

//设置标志位,表示有段需要处理

continue_processing_flag = TRUE;

}

//释放当前的互斥锁

svt_release_mutex(segmentPtr->row_array[row_segment_index].assignment_mutex);

}

//检查并处理左下邻居段的依赖

//检查左下邻居是否存在1 当前行不是最后一行,2 左下邻居段索引在该下一行的有效范围内

if (row_segment_index < segmentPtr->segment_row_count - 1 && bottom_left_segment_index >= segmentPtr->row_array[row_segment_index + 1].starting_seg_index) {

//获取下一行的互斥锁,以安全的修改该行的共享依赖状态

svt_block_on_mutex(segmentPtr->row_array[row_segment_index + 1].assignment_mutex);

//递减左下邻居段的依赖计数器是是否降为0

if (segmentPtr->dep_map.dependency[bottom_left_segment_index] == 0) {

//如果当前线程在检查右邻居时已经在自身分配了一个段

if (self_assigned == TRUE)

//则无法同时处理左下段,记录需要反馈的行索引 下一行

//稍后将创建一个新任务放入队列,让其他线程处理这个就绪的段

feedback_row_index = (int16_t)row_segment_index + 1;

else {

*segmentInOutIndex = segmentPtr->row_array[row_segment_index + 1].current_seg_index;

++segmentPtr->row_array[row_segment_index + 1].current_seg_index;

continue_processing_flag = TRUE;

}

}

//释放下一行的互斥锁

svtt_release_mutex(segmentPtr->row_array[row_segment_index + 1].assignment_mutex);

}

//如果之前发现左下段就绪但是自身无法处理,因为已经分配了右段,则需要反馈任务

if (feedback_row_index > 0) {

EbObjectWrapper *wrapper_ptr;

//从FIFO队列中获取一个空的任务包装器对象

svt_get_empty_object(srmFifoPtr, &wrapper_ptr);

//获取包装器中的任务对象

EncDecTasks *feedback_task = (EncDecTasks*)wrapper_ptr->object_ptr;

//设置任务类型为ENCDEC_INPUT,并指定需要处理的行

feedback_task->input_type = ENCDEC_TASKS_ENCDEC_INPUT;

feedback_task->enc_dec_segment_row = feedback_row_index; //设置需要处理的行索引

//负值必要的上下文信息

feedback_task->pcs_wrapper = taskPtr->pcs_wrapper;

feedback_task->file_group_index = taskPtr->tile_group_index;

//将填充好的任务对象发布到FIFO队列中,等待其他工作线程获取并处理

svt_post_full_object(wrapper_ptr);

}

break;//跳出switch

}

default: break;

}

//返回标志位,告知调用者是否分配了段以供处理

return continue_processing_flag;

}

1 依赖管理,此函数的核心是管理图像分段间的空间依赖关系,在视频编码中,处理一个编码块通常需要上方,左上方和右上方的块信息。

assign_enc_dec_segments 通过一个依赖映射表dependency_map 来跟踪每个分段对其前置分段的依赖。当一个分段处理完成是,会递减其右邻居和左下邻居的依赖计数。 只有当依赖计数降为0时,该分段被认为就绪,可以背分配处理。

2 实现波前并行处理:这个函数时SVT-AV1 实现Wavefront Parallel Processing 的关键。WPP允许编码器在处理第N行的几个块之后,可以开始处理第N+1行,不必等待整行N处理完毕,这极大的提高了多核CPU的利用率和编码并行度。函数中bottom_left_segment_index检查和反馈机制正是为了实现这种波浪式的推进。

3 任务调度与负载均衡:函数作为一个调度器,动态地将就绪的分配给工作现场,痛殴互斥锁,保护共享状态current_seg_index。确保了多线程环境下的正确性。当某个现场完成分段后,会立即尝试获取下一个就绪的分段,有助于保持所有CPU核心的繁忙状态。

4 通信与同步:函数通过FIFO队列进行现场间的通信。当一个现场发现自己触发了另一个分段就绪,但是又无法立即处理时

self_assigned == TRUE的情况,会创建一个新的任务并放入队列,通知其他工作线程有新的工作可用,这是一种高效的工作窃取Work Stealing和协同机制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/95840.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/95840.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

直接让前端请求代理到自己的本地服务器,告别CV报文到自己的API工具,解放双手

直接使用前端直接调用本地服务器&#xff0c;在自己的浏览器搜索插件proxyVerse&#xff0c;类似的插件应该还有一些&#xff0c;可以选择自己喜欢的这类插件可以将浏览器请求&#xff0c;直接转发到本地服务器&#xff0c;这样在本地调试的时候&#xff0c;不需要前端项目&…

Golang Goroutine 与 Channel:构建高效并发程序的基石

在当今这个多核处理器日益普及的时代&#xff0c;利用并发来提升程序的性能和响应能力已经成为软件开发的必然趋势。而Go语言&#xff0c;作为一门为并发而生的语言&#xff0c;其设计哲学中将“并发”置于核心地位。其中&#xff0c;Goroutines 和 Channels 是Go实现并发编程的…

17 C 语言宏进阶必看:从宏替换避坑到宏函数用法,不定参数模拟实现一次搞定

预处理详解1. 预定义符号//C语⾔设置了⼀些预定义符号&#xff0c;可以直接使⽤&#xff0c;预定义符号也是在预处理期间处理的。 __FILE__ //进⾏编译的源⽂件--预处理阶段被替换成指向文件名字符串的指针--char* 类型的变量 __LINE__ //⽂件当前的⾏号 --预处理阶段替换成使用…

深入剖析 HarmonyOS ArkUI 声明式开发:状态管理艺术与最佳实践

好的&#xff0c;请看这篇关于 HarmonyOS ArkUI 声明式开发范式与状态管理的技术文章。 深入剖析 HarmonyOS ArkUI 声明式开发&#xff1a;状态管理艺术与最佳实践 引言 随着 HarmonyOS 4、5 的广泛应用以及面向未来的 HarmonyOS NEXT&#xff08;API 12&#xff09;的发布&…

Qwen-Code安装教程

一、概述Qwen Code 是一个强大的基于命令行、面向开发者的 AI 工作流工具&#xff0c;改编自 Gemini CLI&#xff0c;专门针对 Qwen3-Coder 模型进行了优化。它专门为代码理解、代码重构、自动化工作流、Git 操作等场景设计&#xff0c;让你的开发工作变得更高效、更智能。它既…

老师傅一分钟精准判断电池好坏!就靠这个神器!

在汽车维修与保养领域&#xff0c;蓄电池状态的准确判断一直是技术人员面临的重要挑战。传统的电压测量方法只能反映表面现象&#xff0c;无法深入评估蓄电池的实际健康状态。Midtronics MDX-P300蓄电池及电气系统测试仪作为专业级诊断设备&#xff0c;通过电导测试技术和多系统…

Axure笔记

Axure介绍 快速原型的软件 应用场景&#xff1a;拉投资、给项目团队、销售演示、项目投标、内部收集反馈、教学 软件安装与汉化 汉化&#xff1a;复制lang文件夹和三个dll 软件的基础功能 基本布局&#xff1a;菜单栏、工具栏、页面和摘要、元件和母版、画布、样式交互和说明设…

Pytorch Yolov11 OBB 旋转框检测+window部署+推理封装 留贴记录

Pytorch Yolov11 OBB 旋转框检测window部署推理封装 留贴记录 上一章写了下【Pytorch Yolov11目标检测window部署推理封装 留贴记录】&#xff0c;这一章开一下YOLOV11 OBB旋转框检测相关的全流程&#xff0c;有些和上一章重复的地方我会简写&#xff0c;要两篇结合着看&#x…

《Keil 开发避坑指南:STM32 头文件加载异常与 RTE 配置问题全解决》

《Keil 开发避坑指南&#xff1a;STM32 头文件加载异常与 RTE 配置问题全解决》文章提纲一、引言• 简述 Keil 在 STM32 开发中的核心地位&#xff0c;指出头文件加载和 RTE&#xff08;运行时环境&#xff09;配置是新手常遇且关键的问题&#xff0c;说明本文旨在为开发者提…

TortoiseGit 2.4.0.0 64位安装教程(附详细步骤和Git配置 附安装包)

本教程详细讲解 ​TortoiseGit 2.4.0.0 64位版本​ 的完整安装步骤&#xff0c;包括如何运行 ​TortoiseGit-2.4.0.0-64bit.msi​ 安装包、设置安装路径、关联 Git 环境&#xff0c;以及安装后的基本配置方法&#xff0c;适合 Windows 用户快速上手 Git 图形化管理工具。 一、…

大数据毕业设计选题推荐-基于大数据的高级大豆农业数据分析与可视化系统-Hadoop-Spark-数据可视化-BigData

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…

学习机器学习能看哪些书籍

关注B站可以观看更多实战教学视频&#xff1a;hallo128的个人空间 在机器学习与深度学习的知识海洋中&#xff0c;选择合适的书籍往往是入门和进阶的关键。以下四本经典著作各具特色&#xff0c;覆盖了从基础理论到实践应用的多个维度&#xff0c;无论你是初学者还是有一定基础…

Unity通过Object学习原型模式

原型模式简述 依据现有的实例生成新的实例 Object的实例化方法 Object.Instantiate 克隆 original 对象并返回克隆对象 Unity中的实例&#xff1a;预制体或场景中的游戏对象 示例 方法1&#xff1a;手动创建对象并添加组件 方法2&#xff1a;使用实例化方法&#xff0c;实…

【踩坑记录】Unity 项目中 PlasticSCM 掩蔽列表引发的 文件缺失问题排查与解决

问题描述&#xff1a; Plastic SCM 签入时&#xff0c;弹窗提示“项xxx在该工作区中不存在” Unity 项目中 PlasticSCM 掩蔽列表引发的 文件缺失问题排查与解决 文章目录Unity 项目中 PlasticSCM 掩蔽列表引发的 文件缺失问题排查与解决一、前言二、Unity 与 .meta 文件机制1. …

Redis实战-附近的人实现的解决方案

1.GEO数据结构1.1实现附近的人的数据结构Redis提供的专用的数据结构来实现附近的人的操作&#xff0c;这也是企业的主流解决方案&#xff0c;建议使用这种解决方案。GEO就是Redis提供的地理坐标计算的一个数据结构&#xff0c;可以很方便的计算出来两个地点的地理坐标&#xff…

HTML第七课:发展史

HTML第七课&#xff1a;发展史发展史快速学习平台发展史 示例 HTML 发展史 前端三件套&#xff1a;html 、css、javascript(Js) HTML 发展史 HTML 1.0&#xff08;1993 年&#xff09; 蒂姆伯纳斯 - 李&#xff08;Tim Berners - Lee&#xff09;发明了万维网&#xff0c;同…

中国生成式引擎优化(GEO)市场分析:领先企业格局与未来趋势分析

一、GEO市场变革中国生成式引擎优化&#xff08;Generative Engine Optimization, GEO&#xff09;市场正经历一场深刻的变革&#xff0c;其核心在于生成式人工智能&#xff08;Generative AI&#xff09;对传统搜索引擎和数字营销模式的颠覆性影响。传统搜索引擎以“提供链接”…

好看的背景颜色 uniapp+小程序

<view class"bg-decoration"><view class"circle-1"></view><view class"circle-2"></view><view class"circle-3"></view> </view>/* 背景装饰 */.container{background: linear-gr…

《驾驭云原生复杂性:隐性Bug的全链路防御体系构建》

容器、服务网格、动态配置等抽象层为系统赋予了弹性与效率,但也像深海中的暗礁,将技术风险隐藏在标准化的接口之下。那些困扰开发者的隐性Bug,往往并非源于底层技术的缺陷,而是对抽象层运行逻辑的理解偏差、配置与业务特性的错配,或是多组件交互时的协同失效。它们以“偶发…

vosk语音识别实战

一、简介 Vosk 是一个由 Alpha Cephei 团队开发的开源离线语音识别&#xff08;ASR&#xff09;工具包。它的核心优势在于完全离线运行和轻量级&#xff0c;使其非常适合在资源受限的环境、注重隐私的场景或需要低延迟的应用中使用。 二、核心特点 离线运行 (Offline) 这是…