如何快速混合 RGBA 无符号字节颜色?

2024-02-18

我正在使用 c++ ,我想使用以下代码进行 alpha 混合。

#define CLAMPTOBYTE(color) \
    if ((color) & (~255)) { \
        color = (BYTE)((-(color)) >> 31); \
    } else { \
        color = (BYTE)(color); \
    }
#define GET_BYTE(accessPixel, x, y, scanline, bpp) \
    ((BYTE*)((accessPixel) + (y) * (scanline) + (x) * (bpp))) 

    for (int y = top ; y < bottom; ++y)
    {
        BYTE* resultByte = GET_BYTE(resultBits, left, y, stride, bytepp);
        BYTE* srcByte = GET_BYTE(srcBits, left, y, stride, bytepp);
        BYTE* srcByteTop = GET_BYTE(srcBitsTop, left, y, stride, bytepp);
        BYTE* maskCurrent = GET_GREY(maskSrc, left, y, width);
        int alpha = 0;
        int red = 0;
        int green = 0;
        int blue = 0;
        for (int x = left; x < right; ++x)
        {
            alpha = *maskCurrent;
            red = (srcByteTop[R] * alpha + srcByte[R] * (255 - alpha)) / 255;
            green = (srcByteTop[G] * alpha + srcByte[G] * (255 - alpha)) / 255;
            blue = (srcByteTop[B] * alpha + srcByte[B] * (255 - alpha)) / 255;
            CLAMPTOBYTE(red);
            CLAMPTOBYTE(green);
            CLAMPTOBYTE(blue);
            resultByte[R] = red;
            resultByte[G] = green;
            resultByte[B] = blue;
            srcByte += bytepp;
            srcByteTop += bytepp;
            resultByte += bytepp;
            ++maskCurrent;
        }
    }

但我发现它仍然很慢,合成两个 600 * 600 图像时大约需要 40 - 60 毫秒。 有什么方法可以将速度提高到16ms以下吗?

任何人都可以帮助我加快这段代码的速度吗?非常感谢!


Use SSE http://www2.units.it/~csia/calcolointensivo/tartaglia/intel/cce/intref_cls.pdf- 从第 131 页开始。

基本工作流程

  1. 从src加载4个像素(16个1字节数字)RGBA RGBA RGBA RGBA(流加载)

  2. 再加载 4 个要与 srcbytetop 混合的 RGBx RGBx RGBx RGBx

  3. 进行一些调整,使 1 中的 A 项填满每个槽,即

    xxxA xxxB xxxC xxxD -> AAAA BBBB CCCC DDDD

    在下面的解决方案中,我选择重新使用现有的“maskcurrent”数组,但将 alpha 集成到 1 的“A”字段中将需要更少的内存负载,因此速度更快。在这种情况下,混合可能是:并使用掩码选择 A、B、C、D。右移 8,或者使用原始,右移 16,或再次。

  4. 将以上内容添加到每个槽中均为 -255 的向量中

  5. 乘以 1 * 4(源与 255-alpha)和 2 * 3(结果与 alpha)。

    为此,您应该能够使用“乘法并丢弃底部 8 位”SSE2 指令。

  6. 将这两个(4 和 5)加在一起

  7. 将它们存储在其他地方(如果可能)或在您的目的地之上(如果必须)

这是您的起点:

    //Define your image with __declspec(align(16)) i.e char __declspec(align(16)) image[640*480]
    // so the first byte is aligned correctly for SIMD.
    // Stride must be a multiple of 16.

    for (int y = top ; y < bottom; ++y)
    {
        BYTE* resultByte = GET_BYTE(resultBits, left, y, stride, bytepp);
        BYTE* srcByte = GET_BYTE(srcBits, left, y, stride, bytepp);
        BYTE* srcByteTop = GET_BYTE(srcBitsTop, left, y, stride, bytepp);
        BYTE* maskCurrent = GET_GREY(maskSrc, left, y, width);
        for (int x = left; x < right; x += 4)
        {
            //If you can't align, use _mm_loadu_si128()
            // Step 1
            __mm128i src = _mm_load_si128(reinterpret_cast<__mm128i*>(srcByte)) 
            // Step 2
            __mm128i srcTop = _mm_load_si128(reinterpret_cast<__mm128i*>(srcByteTop)) 

            // Step 3
            // Fill the 4 positions for the first pixel with maskCurrent[0], etc
            // Could do better with shifts and so on, but this is clear
            __mm128i mask = _mm_set_epi8(maskCurrent[0],maskCurrent[0],maskCurrent[0],maskCurrent[0],
                                        maskCurrent[1],maskCurrent[1],maskCurrent[1],maskCurrent[1],
                                        maskCurrent[2],maskCurrent[2],maskCurrent[2],maskCurrent[2],
                                        maskCurrent[3],maskCurrent[3],maskCurrent[3],maskCurrent[3],
                                        ) 

            // step 4
            __mm128i maskInv = _mm_subs_epu8(_mm_set1_epu8(255), mask) 

            //Todo : Multiply, with saturate - find correct instructions for 4..6
            //note you can use Multiply and add _mm_madd_epi16

            alpha = *maskCurrent;
            red = (srcByteTop[R] * alpha + srcByte[R] * (255 - alpha)) / 255;
            green = (srcByteTop[G] * alpha + srcByte[G] * (255 - alpha)) / 255;
            blue = (srcByteTop[B] * alpha + srcByte[B] * (255 - alpha)) / 255;
            CLAMPTOBYTE(red);
            CLAMPTOBYTE(green);
            CLAMPTOBYTE(blue);
            resultByte[R] = red;
            resultByte[G] = green;
            resultByte[B] = blue;
            //----

            // Step 7 - store result.
            //Store aligned if output is aligned on 16 byte boundrary
            _mm_store_si128(reinterpret_cast<__mm128i*>(resultByte), result)
            //Slow version if you can't guarantee alignment
            //_mm_storeu_si128(reinterpret_cast<__mm128i*>(resultByte), result)

            //Move pointers forward 4 places
            srcByte += bytepp * 4;
            srcByteTop += bytepp * 4;
            resultByte += bytepp * 4;
            maskCurrent += 4;
        }
    }

要了解哪些 AMD 处理器将运行此代码(当前使用 SSE2 指令),请参阅维基百科的 AMD Turion 微处理器列表 http://en.wikipedia.org/wiki/List_of_AMD_Turion_microprocessors。您还可以查看 Wikipedia 上的其他处理器列表,但我的研究表明,大约 4 年前的 AMD cpu 都至少支持 SSE2。

您应该期望良好的 SSE2 实现的运行速度比当前代码快大约 8-16 倍。这是因为我们消除了循环中的分支,一次处理 4 个像素(或 12 个通道),并通过使用流指令提高缓存性能。作为 SSE 的替代方案,您可以通过消除用于饱和的 if 检查来使现有代码运行得更快。除此之外,我还需要对您的工作负载运行分析器。

当然,最好的解决方案是使用硬件支持(即在 DirectX 中对问题进行编码)并在显卡上完成。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何快速混合 RGBA 无符号字节颜色? 的相关文章

  • 自动映射器多对多 stackoverflowException

    我遇到以下映射的堆栈溢出 Mapper CreateMap
  • NDK 应用 onDestroy 清理 - 如何 DetachCurrentThread

    因此 如果我们连接 我们必须在完成后分离线程 对吗 JNIEnv get jni env JNIEnv res JAVA VM gt GetEnv void res JNI VERSION 1 6 Using cached JavaVM J
  • 将公历日期转换为儒略日期,然后再转换回来(随着时间)

    我正在编写一个程序 必须将当前的公历日期和时间转换为儒略日期 然后再转换回公历门 最终我需要添加能够添加年 月 日 小时 分钟和秒的功能 但我需要先解决这部分问题 现在我已经从公历日期转换为儒略日期 所以从逻辑上讲 我觉得我应该能够以某种方
  • 最新 .Net MongoDb.Driver 的连接问题

    我创建了一个 MongoLab 沙箱数据库 我与 MongoChef 连接 效果很好 我通过 Nuget 安装了 MongoDB Driver 2 2 2 我编写了一些简单的 C 演示代码 但就是无法使其工作 连接字符串是直接从 Mongo
  • Dapper 在执行时挂起

    我有一个 IDb连接 sql UPDATE 表名 SET json json lastupdate SYSDATE WHERE id id var param new DynamicParameters param Add json jso
  • 在没有 epsilon 的情况下可以将浮点数与 0.0 进行比较吗?

    我知道 要比较两个浮点值 需要使用一些 epsilon 精度 因为它们并不精确 但是 我想知道是否存在边缘情况 我不需要那个 epsilon 特别是 我想知道这样做是否总是安全的 double foo double x if x lt 0
  • 组合框下拉位置

    我有一个最大化的表单 其中包含 500px 的组合框控件 停靠在右上角 Width 尝试打开组合框后 列表的一半超出了屏幕 如何强制列表显示在表单中 棘手的问题 我找不到解决这个问题的好办法 只是一个解决方法 添加一个新类并粘贴如下所示的代
  • Visual Studio 中列表框的上移、下移按钮[重复]

    这个问题在这里已经有答案了 我正在尝试制作一个上移按钮和一个下移按钮 以移动 Microsoft Visual Studio 2012 中列表框中的选定项目 我已经在 WDF jquery winforms 和其他一些表单中看到了其他示例
  • 调用异步方法在视图模型的构造函数中加载数据有警告

    我的视图包含一个 ListView 它显示来自互联网的一些数据 我创建一个异步方法来加载数据并在我的视图模型的构造函数中调用该方法 它有一个警告提示我现在使用await关键字 还有其他解决方案可以在构造函数中异步加载数据吗 有几种可以应用的
  • 如何让XmlReader读取C#中的属性?

    我有一个 XML Stream 其中包含以下 XML 内容
  • 使用 Nexus 10 在 Android 4.3 上滚动时性能不佳

    我的应用程序有一个带有一些滚动的列表视图 在我测试过的所有手机 Nexus One Nexus 4 和 Galaxy S3 4 上都表现得非常好 以 60fps 滚动 但 Nexus 10 上的表现很糟糕 大概在 15fps 左右 我已经将
  • C#:自定义转换为值类型

    是否可以将自定义类转换为值类型 这是一个例子 var x new Foo var y int x Does not compile 是否有可能实现上述情况 我需要超载一些东西吗Foo 您将必须重载强制转换运算符 public class F
  • 如何同步nosql db(ravendb)中的更改

    我已经开始在 RavenDB 的示例上学习 NoSQL 我从一个最简单的模型开始 假设我们有由用户创建的主题 public class Topic public string Id get protected set public stri
  • 如何检测应用程序正在运行的 .NET 版本?

    我尝试使用Environment Version ToString 确定目标计算机上正在使用什么 NET 框架 但安装了 4 0 版本时 它说我正在使用 NET 2 0 如何检测目标计算机上正在运行的 NET Framework 版本 En
  • 卸载程序

    我正在尝试使用此代码卸载程序 但它似乎不起作用 我尝试过其他答案 但似乎也不起作用 有人可以帮助我吗 我正在尝试按给定名称 displayName 卸载该程序 例如 我给出 displayName Appname 那么此代码应该从我的计算机
  • Boost.asio和异步链,unique_ptr?

    我对异步编程不太熟悉 我有一个问题 我的问题如下 给出 boost asio 中 C 11 的 echo server 示例 http www boost org doc libs 1 60 0 doc html boost asio ex
  • 如何在 C 中创建最低有效位设置为 1 的掩码

    这个功能如何运作 最低有效 n 位设置为 1 的掩码 Example n 6 gt 0x2F n 17 gt 0x1FFFF 我根本不明白这些 尤其是 n 6 gt 0x2F 另外 什么是面膜 通常的方法是采取1 并将其左移n位 这会给你类
  • 使用 CodeDOM 将程序集添加到 BuildManager 会导致间歇性错误

    我正在使用 CodeDOM 在运行时创建内存中程序集 如下所示 public Assembly Compile CodeCompileUnit targetUnit string path Path GetDirectoryName new
  • 在windows + opengl中选择图形设备

    我知道如何使用 openGL 打开窗口 使用 Win32 或其他工具包 但是当系统有2块显卡时 如何选择要渲染的图形设备 我的编程语言是 C 我专注于 Windows 但任何示例都将受到欢迎 编辑 也许更好地解释我的问题是个好主意 以便添加
  • 实体框架代码首次日期字段创建

    我正在使用实体框架代码优先方法来创建我的数据库表 下面的代码 创建一个DATETIME数据库中的列 但我想创建一个DATE柱子 DataType DataType Date DisplayFormatAttribute ApplyForma

随机推荐

  • OPENGL混合功能——以分层的方式缓慢替换颜色

    我想做的是在亮红色 1 0 0 1 上添加带有 alpha 0 1 0 0 0 2 的深红色 对于第一层 它工作正常 结果是 0 9 0 0 1 然而 当红色值达到 0 5 时 它不能低于该值 第一层用以下等式进行演示 并且工作正常 glB
  • Javascript正则表达式多重匹配[重复]

    这个问题在这里已经有答案了 我正在尝试使用 javascript 在具有查询字符串参数的 url window location href 上执行正则表达式 但无法弄清楚如何执行此操作 就我而言 有一个查询字符串参数可以重复自身 例如 qu
  • ZF2 fileprg 与集合中的文件

    我无法得到fileprg用于处理集合中的文件的插件 我正在尝试使用上传多个文件FormCollections 但在 form gt getData 没有与我的收藏或文件相关的密钥 我用简单的方法测试了表单和 fileprgfile inpu
  • 在 HTML 省略号下划线

    我在用text overflow ellipsis剪切锚点内跨度内的文本 当我悬停时 省略号字符没有下划线 这会导致一个小间隙 有没有办法来解决这个问题 是的 你可以这样做 设置text decoration none而不是使用border
  • Ruby代码美化,将长指令拆分为多行

    我们如何编写以下语句以提高可读性 Promotion joins category where lft gt and rgt lt c lft c rgt joins shops where promotions per shops gt
  • 如何检查Dotnet事务是否回滚?

    如何检查 dotnet 交易是否已关闭 你的标题问的是一件事 你的问题问的是另一件事 所以 我同意你的标题 如果想知道事务是否回滚或者设置为仅回滚 可以查看 transaction WasRolledBack true if transac
  • SSRS:仅为当前登录的用户提取报告

    我需要能够根据登录人员提取报告 例如 在一组销售人员中 如果鲍勃进入此报告并单击 销售人员 下拉列表 我需要他只能将鲍勃视为可用的销售人员 而不是其他任何人 我通过使用解决了这个问题 User UserIDSSRS 中的函数并且运行良好 我
  • 如何在 Acrobat Javascript 中编写文本文件

    我正在使用 acrobat XI 我尝试过输出这样的文本文件 var cMyC abc var doc this createDataObject cName test txt cValue cMyC this exportDataObje
  • 在 Ruby 中初始化类对象变量

    例如我创建了一个类 class Result min 0 max 0 def initialize min max max min min max max max end end result Result new 1 10 result
  • 配置 LDAP 时出现 Berkeley DB 不匹配错误

    我正在配置 OPENLDAP 2 4 35 在 Redhat Linux 上 我已经安装了 Berkley DB 4 8 30 作为先决条件 我还检查了 OPENLDAP 的 README 文件中的版本兼容性 其中显示 SLAPD BDB
  • 在postgresql中将两个select语句添加到一个insert into语句中

    我通过以下方式制作了一个临时表 create temporary table return table p1 BIGINT p2 VARCHAR 45 p3 VARCHAR 45 p4 VARCHAR 45 p5 VARCHAR 45 p6
  • 确定插入符何时到达输入框的末尾

    我已经发现这个问题 https stackoverflow com questions 263743 how to get cursor position in textarea它提供了一种计算文本或输入框中插入符号的确切位置的解决方案 就
  • 如何在 Google colab 中循环播放音频

    我试图在 google colab 中循环运行音频 但它没有给 mi 任何输出 from gtts import gTTS from IPython display import Audio for voice in Aniket sach
  • 在 VR 中单击 inputField 时打开键盘(Oculus Quest 2 和 XRIT)

    我目前正在使用 Unity 为 oculus quest 2 开发一个小型应用程序 我创建了一个画布 在其中添加了一个按钮和一个输入字段 通过使用 XR 交互工具包 我可以使用两个控制器单击按钮或输入字段 但是 仍然无法在输入字段中输入任何
  • 如何在 Android 中使用双三次插值在画布上绘制和缩放位图?

    我想在画布上绘制比实际尺寸更大的位图 我可以使用 canvas drawBitmap bitmap null destRect null 但是 如果源图像比目标矩形小得多 那么质量就会很差 因为结果会像素化 如何使用双线性或双三次重采样绘制
  • 基于其他规则应用 CSS 规则 - RTL 特定样式

    推介会 我正在尝试建立一个可用于多种文化 具有不同阅读方向的网站 为此 我只需添加dir rtl 我的根 HTML 元素上的属性 我的问题是 我有一些特定于一个方向或另一个方向的 CSS 规则 大多数情况下是边距或填充 尝试使用属性选择器失
  • 编码 - codePointCount 和 length 之间的结果不同

    我发现了一个棘手的地方 但找不到任何答案为什么会发生这种情况 主要问题是字符串有多长 它是否包含一个或两个字符 Code public class App public static void main String args throws
  • 如何在 Travis CI 中使用 python-openbabel?

    我使用 Travis CI 作为毒理学绘图项目的一部分 对于这个项目 我需要 python openbabel 作为依赖项 因此 我已将 apt get 安装程序添加到 travis yml 文件中 如下所示 已删除注释 language
  • 在matlab中计算闭合曲线(或多边形)的曲率

    考虑以下几点 x 1 34 0 92 0 68 0 25 0 06 0 34 0 49 0 72 0 79 0 94 1 35 0 35 0 54 0 68 0 84 1 20 1 23 1 32 1 34 y 0 30 0 43 0 90
  • 如何快速混合 RGBA 无符号字节颜色?

    我正在使用 c 我想使用以下代码进行 alpha 混合 define CLAMPTOBYTE color if color 255 color BYTE color gt gt 31 else color BYTE color define