我应该使用统一变量来减少矩阵乘法的数量吗?

Posted

技术标签:

【中文标题】我应该使用统一变量来减少矩阵乘法的数量吗?【英文标题】:Should I use uniform variable to reduce the amount of matrix multiplication? 【发布时间】:2015-07-08 15:33:09 【问题描述】:

我刚刚写了一个程序来旋转一个对象。它只是使用空闲函数更新变量 theta。该变量用于创建旋转矩阵..然后我这样做..

gl_Position = rx * ry * rz * vPosition;

rxryrz(矩阵)对于同一帧中的每个点都是相同的......但是它正在被对象中的每个点相乘......我应该使用一个统一变量mat4 存储rx* ry * rz 的相乘值并将其传递给着色器?...或者让着色器处理每个点的乘法?.....哪个更快?...

【问题讨论】:

问题“哪个更快?”只能通过您的仔细分析来回答。在您 (a) 确定这是您的应用程序的瓶颈并且 (b) 确定哪种方法实际上更快之前,您应该选择更简单且更具可读性的方法。 只是想知道矩阵乘法是否比在 cpu 和 gpu 之间传输数据成本更高...... 我还要补充一点,编译器会在大多数情况下为您解决这种问题。就像循环展开和尾递归优化一样。就像 RedRobotHood 说的分析你的代码,看看它是否是一个瓶颈。 @Rob 这不是编译器会为您解决的问题。它需要更改代码以将单个矩阵数据作为统一传递,而不是传递三个。 @MuertoExcobito 但优化器可能会发现rx * ry * rz 的结果仅取决于制服并创建一个“预着色器”,它将在 CPU 上执行一次,然后将结果作为制服传递。不过取决于驱动程序。 【参考方案1】:

虽然分析对于衡量您的应用程序如何响应优化至关重要,但通常需要将串联矩阵传递给顶点着色器。这有两个原因:

    从 CPU 到 GPU 的数据量减少了。如果rxryrz 都是 4x4 矩阵,并且它们的乘积(比如 rx_ry_rz = rx * ry * rz)也是一个 4x4 矩阵,那么您将少传输 2 个 4x4 矩阵(128 字节)作为统一矩阵每次更新。如果您使用此着色器以 60hz 每帧渲染 1000 个对象,并随每个对象进行统一更新,则每秒可节省 7MB 以上的带宽。也许不是特别重要,但每一点都有帮助,特别是如果带宽是您的瓶颈。

    减少了顶点阶段必须做的工作量(假设顶点数量不小)。通常顶点阶段不是瓶颈,但是,许多驱动程序在阶段之间的着色器核心分配中实现负载平衡,因此减少顶点阶段的工作可以在像素阶段带来好处(例如)。同样,分析将使您更好地了解这是否/如何提高性能。

缺点是增加了乘以矩阵的 CPU 时间。如果您的应用程序的瓶颈是 CPU 执行,那么这样做可能会减慢您的应用程序,因为它需要 CPU 完成比以前更多的工作。

【讨论】:

rx,ry 和 rz 也是在我的代码中的着色器上计算的......现在只有 theta 作为统一变量传递......谢谢你的回复:) 在这种情况下,好处 #1 并不真正适用,因为您实际上会传递更多具有完整矩阵而不是 3 个 theta 值的数据。而且 - 你可以通过投票和/或接受来感谢我:)。【参考方案2】:

我不会指望这种重复的乘法被优化掉,除非你确信它确实发生在你关心的所有平台上。为此:

一个选项是基准测试,但可能很难很好地隔离此操作以可靠地测量可能的差异。 我相信有些供应商提供的开发工具可以让您查看已编译着色器的汇编代码。我认为这是让您了解在这种情况下您的 GLSL 代码究竟发生了什么的唯一可靠方法。

这是一个更大主题的非常典型的例子。至少在我个人看来,您所拥有的是一个使用 OpenGL 效率低下的代码示例。对顶点着色器中的每个顶点进行相同的计算(至少在概念上是为每个顶点执行的)不是您应该做的事情。

实际上,针对 API 使用效率低下的驱动程序优化是基于它们提供的优势进行的。如果一个高知名度的应用程序/游戏使用某些不良模式(其中许多确实如此!),并且它们被确定为对性能有负面影响,则驱动程序会被优化以解决它们,并且仍然提供最佳性能。如果应用程序/游戏通常用于基准测试,则尤其如此。具有讽刺意味的是,这些优化可能会损害那些被认为不太重要的编写良好的软件的性能。

因此,如果曾经有一个重要的应用/游戏与您正在做的事情相同(在这种情况下似乎很有可能),那么很可能许多驱动程序将包含优化以有效地处理它。

不过,我不会依赖它。原因既有哲学性的,也有实践性的:

    如果我在开发应用程序,我觉得编写高效的代码是我的工作。我不想编写糟糕的代码,并希望其他人碰巧优化他们的代码以弥补它。 您不能指望应用程序将运行的所有平台都包含这些类型的优化。特别是因为应用代码的生命周期可能很长,而这些平台甚至可能还不存在。 即使优化到位,它们也很可能不是免费的。您可能会触发驱动程序代码,最终消耗的资源比您的代码自己提供组合矩阵所需的资源更多。

【讨论】:

以上是关于我应该使用统一变量来减少矩阵乘法的数量吗?的主要内容,如果未能解决你的问题,请参考以下文章

一种计算矩阵乘法的快速算法

使用 valgrind 进行平铺矩阵乘法的 C++ 性能分析

MCM(矩阵链乘法)

OpenGL矩阵乘法C++

GLM的向量矩阵乘法行为?

使用三种不同方法的矩阵乘法会给出不同的结果,具体取决于值的数量