我正在尝试用基于Vulkan的C ++编写渲染引擎。 Vulkan是用C语言编写的,因此它有一些有趣的约定。
我在Vulkan应用程序的教程/代码片段中看到的反复出现的模式是,大多数代码都在一个非常大的类中。 (现在我的vulkan课程已经大约2000行)。但是为了制作一个合适的渲染引擎,我需要将代码划分到一定程度。
上述有趣的一点是它有一个叫做逻辑设备的东西,它是对显卡的抽象参考。
它可以在任何地方使用,以下列方式创建和分配:
我该如何处理这个问题?服务定位器和单身人员被许多人认为是可怕的解决方案(我可以理解),所以这似乎是我宁愿避免的。
是否有设计模式可以解决这个问题?
答案 0 :(得分:4)
逻辑设备是实际依赖项。
它具有状态,并且其状态需要可用于使用硬件。
您可以将它用作操作的参数,存储在几乎所有类中的值,全局或monadic-esque" final"参数,其中每个操作只返回仍需要设备运行的东西。您可以用返回(指针/引用)它的函数替换它(指针/引用)。
考虑纯OOP是否是您想要做的; vulkan和渲染更多的是关于操作而不是操作的东西。我想混合一些函数式编程模式,这使得类似monad的选择更合理。
对缓冲区/数据进行撰写操作。这些返回操作也包含缓冲区和数据。组合操作指定哪些参数是新输入,哪些参数是下一步消耗的参数。这样做你可以(在编译时)设置一个类型安全的工作图表,而不需要运行任何东西。
结果组合操作将有一个设置(你可以绑定逻辑设备和你可以做的任何事情"早期"在你需要准备昂贵的缓冲区之前)和执行阶段(你在哪里)给它提供昂贵的缓冲区并生成输出。)
或者作为另一种方法,从c++2a找到一个带有协程支持的编译器,并在程序上将其写为异步。
答案 1 :(得分:0)
Vulkan是一个OOP API。它不是基于类的,因为它是C99而不是C ++。使用官方Vulkan-Hpp可以很容易地解决这个问题。您可以将其作为半职级LunarG Vulkan SDK的一部分vulkan.hpp
使用。
使用情况与vulkan.h
不同:您可能有Device
实例的成员指针/引用,或者每个对象都有VkDevice
个句柄成员需要它。某些更高级别的对象将处理逻辑设备的生命周期(例如您的RenderingEngine类等)。差异几乎只是美学:你会使用device->command(...)
而不是vkCommand(device, ...)
。 vulkan.hpp
似乎没有通过构造函数/析构函数使用正确的RAII,这是一种耻辱。
或者,引擎的用户可以管理设备。虽然与OpenGL不同,但这并没有多大用处。如果用户也希望使用Vulkan,则可以创建自己的VkInstance
和VkDevice
。
我在Vulkan应用程序的教程/代码片段中看到的反复出现的模式是,大多数代码都是在一个非常大的类中。
这并不是特别针对Vulkan的。如果你考虑一下,几乎所有的C ++应用程序都是一个大的类来做所有事情(唯一的区别在于程序员难以从它委托给其他类实例)。