光追渲染器开发记录:基础渲染架构线程池泛型单例

光追渲染器开发记录:基础渲染架构线程池泛型单例,第1张

目录

程序的主入口:

构建BVH:

渲染循环:

核心功能:

多线程加速:

泛型单例:

消息队列:

线程池:

学习资料:


 

上一篇记录:

光追渲染器开发记录:开发环境配置Cmake+Vcpkg进行集成_This is MX的博客-CSDN博客https://blog.csdn.net/m0_56399931/article/details/123835101前记:个人水平有限,如果有改进的建议欢迎提出-------------------------------------------博主:mx

  程序的主入口:

渲染器目前主入口长这样:

后续添加修改内容肯定会进行更改。


 

我们的主入口主要做了以下几件事:

· 构建场景

· 初始化渲染器

· 建立空间切分

· 侦听输入

· 渲染tick

构建BVH:

截取了核心的一部分:

这里我采用games101里面的递归构建方法,核心就是:获取到最大的轴,根据那个轴进行排序切分递归构建。


 

渲染循环:

先看图:

核心功能:

渲染循环主要做两个事情:

· Path Tracing 获取屏幕的每个像素颜色

· PostProcess后处理

 

这一部分肯定需要进行多线程加速。


多线程加速:

为了使用多线程加速

这里多线程,采用了单例的线程池。


泛型单例:

这个比较简单,就是采用的懒汉版单理模式,然后c++11是要求编译器保证内部静态变量的线程安全性,所以这个单例也是线程安全的,并且泛型能够适配多种类。


消息队列:

这个核心是把消息队列适配多种任务,并且需要是线程安全的,所以我做的是把原生的std::queue进行改造,对齐进行加锁,保证在调用的时候不会错误。


线程池:

这个其实就比较难。


主要是工作线程和消息封装这两个部分。


工作线程:

首先我们使用一个封装的工作线程来调用消息队列里面的消息,他会在线程池运行的时候,不断获取消息队列的任务进行执行,如果消息队列里面没有任务了,就会阻塞当前线程,直到有任务被唤醒。


消息封装:

我们封装的函数应该做到以下两点:

  • 接收任何参数的任何函数。


    (普通函数,Lambda,成员函数……)

  • 立即返回任务结束的结果,避免阻塞主线程。




 

这里我们涉及几个知识:

· typename... Args:这个是C++11引入的可变模版参数(variadic templates)

 

· decltype:decltype(表达式)能够根据表达式推断出类型

 

· 尾返回类型(trailing return type):例如这样的来自动推断返回类型:

template
auto add2(T x, U y) -> decltype(x+y){
return x + y;
}

 

· std::future :提供了一种用于访问异步 *** 作结果的机制。


我们可以使用std::future的wait()方法来设置屏障,阻塞线程,实现线程同步。


并最终使用std::future的get()方法来获得执行结果。


 

· std::function :它是一种通用、多态的函数封装,它的实例可以对任何可以调用的目标实体进行存储、复制和调用 *** 作,它也是对 C++中现有的可调用实体的一种类型安全的包裹(相对来说,函数指针的调用不是类型安全的),简而言之,std::function 就是函数的容器。


 

· std::bind :它可以将函数f和参数args绑定起来,留下一部分在真正调用时确定(当然,你也可以直接指定全部参数,在调用时不再指定。


)。


这个特性其实很适合做回调函数。


 

· std::forward:这个主要涉及万能引用、完美转发以及引用折叠。


· · 完美转发:

指的是函数模板可以将自己的参数“完美”地转发给内部调用的其它函数。


· · 万能引用(universal reference)

只有在发生类型推导的时候 “&&” 才代表 universal reference

如果用来初始化universal reference的表达式是一个左值,那么universal reference就变成lvalue reference。


如果用来初始化universal reference的表达式是一个右值,那么universal reference就变成rvalue reference。


· · 引用折叠

引用折叠只有两条规则:

一个 rvalue reference to an rvalue reference 会变成 (“折叠为”) 一个 rvalue reference.

所有其他种类的"引用的引用"(i.e., 组合当中含有lvalue reference) 都会折叠为 lvalue reference.

 

了解了这些之后我们再来看这个消息的封装:

核心其实是:自动推断出返回的future,用这个future来进行结果的获取。


函数体是主要先绑定参数,然后将其封装成一个void()类型的函数方便调用,然后将其提交到任务队列,并唤醒一个线程。


 

这里提一下我们的消息队列也将每日任务统一的封装成了std::function,对于返回值呢我们通过std::future来获取。


学习资料:

games101 光追渲染器

1.基于C++11实现线程池 - 知乎

2.C++中的单例模式_bob62856的博客-CSDN博客_c++ 单例模式

 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/564685.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-06
下一篇 2022-04-06

发表评论

登录后才能评论

评论列表(0条)

保存