渲染优化 lock unlock

本文探讨了在GPU资源管理中,锁操作(Lock和Unlock)对并发计算效率的影响,通过实例展示了不当使用锁操作可能导致的CPU等待GPU的情况,以及在OpenGL下的一种资源管理策略,并分析了其实际应用效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

昨天参加了公司组织的nvdia的培训,讲了一些关于D3D的优化和可能的瓶颈所在,具体的条目就不说了,这里说一些关于资源的Lock和Unlock,以及我在GL下的测试。

 

老师讲到向Draw*这类函数是将其指令放入指令队列,带填满后或者强制刷新时交给显卡去画,也就是说它并不是即时的,而像对资源的Lock和Unlock确是即时的操作,而且cpu和gpu是并行计算的,当lock的资源正是当前gpu正在使用的资源会导致lock堵塞直到gpu使用完后才返回,也就是说不当的使用lock会造成cpu等待gpu的情形。当然D3D的lock函数有一个标记用来告诉lock是否立即返回,使用这个标记后lock会立即返回,并且拿到资源地址,此时cpu如果向该地址写入新的数据,但gpu也正在使用之,则将出现不可预知的效果。比如lock下一个文理并填入新的数据,此时gpu正使用该纹理进行渲染,则使用该纹理渲染出来东西的纹理将是乱的。

 

我用OpenGL并且一直使用这么一种方式来管理顶点Buffer和索引Buffer(见下面的描述),但从没考虑过上面的提到的lock造成的堵塞,当然我用的是OpenGL,但我想Lock这个机制应该是驱动或者显卡那一级的事情,D3D和GL都应该存Lock的问题。

 

我这里所谓的管理顶点Buffer和索引Buffer的方式是这样的。考虑这么一种情况,当场景中那些粒子也好,动画也好,比较多的时候,我们要每个都给他们在显卡上单独分配顶点缓冲和索引缓冲,毕竟他们的数据是不同的,而且每贞都有变化,即便是使用同一个动画的角色,在同一时刻也不一定在播放同一贞,这带来一个问题,当场景中此类对象很多时将占用很多的显村,且很难控制量,毕竟在引擎这个层面无法知道游戏中到底需要摆放多少个角色,显卡到底有多少空间可供分配等等。我采用的方式是在引擎启动之初就再显卡上分配一个65535个顶点缓冲和65535个索引缓冲,所有需要动态更新顶点Buffer和索引Buffer都填入该缓冲内,并在填充完毕后调用渲染方法。伪代码如下

 

for (int indexMesh = 0; indexMesh < 100; indexMesh++)

{

            vertex *pv = lock(); // 从共享Buffer中获得

            {

                   for (int indexVertex = 0; indexVertex < 1024; indexVertex++)

                  {

                             pv[indexVertex] = position;

                            // ...

                  }

            }

            unlock(pv);

 

            Render();

}

 

如果按照之前提到的Lock会被阻塞和数据交叉的问题,那么这么做将会出现效率下降,更严重的是会出现数据混乱的问题,或者画的是最后一次填充的数据。

 

但是在实际使用和测试中发现这并没有任何问题,首先说一下效率,lock和unlock只消耗0.025毫秒(当然这个和我提交的数据量关系),渲染几乎没有消耗(一共渲染10万左右个面,显卡是nv8600gt)。而数据也没有出现任何混乱。我没有A卡,没办法进行相关测试。

 

莫非Lock,unLock这个真的是D3D9才有的问题?

 

 

### 使用 libvlc 实现软件渲染 为了实现软件渲染,可以利用 `libvlc` 提供的功能来控制视频解码和显示方式。具体来说,在初始化 `libvlc` 时可以通过配置选项禁用硬件加速并强制使用软件解码。 #### 初始化 libvlc 并设置参数 当调用 `libvlc_new()` 函数创建一个新的 LibVLC 实例时,传递特定命令行参数以确保只采用软件路径处理多媒体流: ```c // 创建新的LibVLC实例,并指定不使用硬件加速 libvlc_instance_t *instance; char const *const vlc_args[] = { "--avcodec-hw=none", // 关闭AVCodec中的硬件加速功能 }; int argc = sizeof(vlc_args) / sizeof(*vlc_args); instance = libvlc_new(argc, vlc_args); if (!instance){ fprintf(stderr,"无法创建libvlc实例\n"); } ``` 上述代码片段展示了如何通过设置 `"--avcodec-hw=none"` 参数来关闭 AVCodec 的硬件加速支持[^1]。 #### 设置媒体播放器属性 接着定义一个用于管理音频/视频文件或流的媒体对象,并关联至媒体播放器组件上: ```c // 加载本地文件或其他资源URL作为输入源 libvlc_media_player_t* mp = libvlc_media_player_new(instance); // 如果是网络直播流,则需指明其地址;对于本地文件则提供绝对路径即可 libvlc_media_t* media = libvlc_media_new_location (instance, "rtsp://example.com/stream"); // 将Media附加给MediaPlayer libvlc_media_player_set_media(mp,media); ``` 此时已经准备好了一个仅依赖 CPU 进行图像帧缓冲区更新的基础框架。 #### 获取原始像素数据 如果希望进一步定制化图形界面或者对接其他第三方库的话,还可以借助回调机制捕获每一帧未经压缩过的 RGB/BGR 数据以便后续操作: ```c void (*lock)(void **planes, void *); void (*unlock)(void **planes, void *); void (*display)(void *, void *); struct custom_video_callbacks{ unsigned char* buffer; /* Buffer containing the raw video frame */ }; static void lock_callback(void **picture, void *data) { struct custom_video_callbacks *p_cb=(struct custom_video_callbacks *) data; p_cb->buffer=*picture; } static void unlock_callback(void **picture,void *data) { // Nothing special here... } static void display_callback(void *data,void *) { struct custom_video_callbacks *cb_data=(struct custom_video_callbacks*)data; // Process cb_data->buffer which contains current frame's pixel information. printf("Processing new video frame...\n"); } /* Register our own set of callbacks instead of default ones */ libvlc_video_set_callbacks(mp, &custom_video_callbacks::lock, &custom_video_callbacks::unlock, &custom_video_callbacks::display, NULL,&custom_video_callbacks()); ``` 这段示例说明了怎样注册自定义函数去拦截来自底层驱动程序传输过来的画面信息,从而允许应用程序层面对这些二进制位图做任意变换后再呈现出来[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值