帮助我改进更多 SSE2 代码

2024-06-25

我正在寻找一些帮助来改进 core2 cpu 上的双线性缩放 sse2 代码

在我的 Atom N270 和 i7 上,此代码比 mmx 代码快大约 2 倍。但在 core2 cpu 下它只等于 mmx 代码。

代码如下

void ConversionProcess::convert_SSE2(BBitmap *from, BBitmap *to)
{
    uint32 fromBPR, toBPR, fromBPRDIV4, x, y, yr, xr;

    ULLint start = rdtsc();
    ULLint stop;
    if (from && to) {
        uint32 width, height;
        width = from->Bounds().IntegerWidth() + 1;
        height = from->Bounds().IntegerHeight() + 1;

        uint32 toWidth, toHeight;
        toWidth = to->Bounds().IntegerWidth() + 1;
        toHeight = to->Bounds().IntegerHeight() + 1;

        fromBPR = from->BytesPerRow();
        fromBPRDIV4 = fromBPR >> 2;
        toBPR = to->BytesPerRow();

        uint32 x_ratio = ((width-1) << 7) / toWidth ;
        uint32 y_ratio = ((height-1) << 7) / toHeight ;

        uint8* toPtr = (uint8*)to->Bits();
        uint8* fromPtr1 = (uint8*)from->Bits();
        uint8* fromPtr2 = (uint8*)from->Bits() + fromBPR;

        struct FilterInfo {
            uint16 one_minus_diff;      // one minus diff
            uint16 diff;                // diff value used to calculate the weights used to average the pixels
            uint16 one_minus_diff_rep;  // one minus diff repeated
            uint16 diff_rep;            // diff value used to calculate the weights used to average the pixels repeated
        };

        FilterInfo *xWeights = (FilterInfo *)memalign(16, toWidth * 8);
        FilterInfo *yWeights = (FilterInfo *)memalign(16, toHeight * 8);
        uint32 *xIndexes = (uint32 *)memalign(16, (toWidth+2) * 4);     // will overread by 2 index
        uint32 *yIndexes = (uint32 *)memalign(16, toHeight * 4);

        x = 0;
        for (uint32 j=0;j < toWidth;j++) {
            xr = x >> 7;
            xWeights[j].diff = x - (xr << 7);
            xWeights[j].one_minus_diff = 127 - xWeights[j].diff;
            xWeights[j].one_minus_diff_rep = xWeights[j].one_minus_diff;
            xWeights[j].diff_rep = xWeights[j].diff;
            xIndexes[j] = xr << 2;

            x += x_ratio;
        }

        y = 0;
        for (uint32 j=0;j < toHeight; j++) {
            yr = y >> 7;
            yWeights[j].diff = y - (yr << 7);
            yWeights[j].one_minus_diff = 127 - yWeights[j].diff;
            yIndexes[j] = (yr * fromBPR);
            y += y_ratio;

        }

        for (uint32 i=0;i < toHeight; i++) {
            _ScaleSSE2X2(toPtr, fromPtr1 + yIndexes[i], fromPtr2 + yIndexes[i], xIndexes, xWeights, &yWeights[i], toWidth);
            toPtr += toBPR; 
        }

        free(xWeights);
        free(yWeights);
        free(xIndexes);
        free(yIndexes);

        stop = rdtsc() - start;
        if (stop < timeTaken) {
            timeTaken = stop;
        }
    }
}

;
; Copyright (C) 2011 David McPaul
;
; All rights reserved. Distributed under the terms of the MIT License.
;

; A rather unoptimised bilinear scaler

%macro  cglobal 1
    global  _%1
    %define %1 _%1
    align 16
%1:
%endmacro

SECTION .data align=16

RGB_AND db  0xff
        db  0x00
        db  0x00
        db  0x00
        db  0xff
        db  0x00
        db  0x00
        db  0x00
        db  0xff
        db  0x00
        db  0x00
        db  0x00
        db  0xff
        db  0x00
        db  0x00
        db  0x00

; void  _ScaleSSE2X2(void *toPtr, void *fromPtr1, void *fromPtr2, void* xIndexPtr, void *xWeightPtr, void *yWeightPtr, uint32 length);

length      equ ebp+32
yWeightPtr  equ ebp+28
xWeightPtr  equ ebp+24
xIndexPtr   equ ebp+20
fromPtr2    equ ebp+16
fromPtr1    equ ebp+12
toPtr       equ ebp+8

SECTION .text align=16
cglobal ScaleSSE2X2
; reserve registers. eax, ecx, edx automatically available
    push ebp
    mov ebp, esp
    push ebx    ; yWeights, xIndexPtr
    push edi    ; scratch
    push esi    ; fromPtr3

    mov esi, [fromPtr1]
    mov edx, [fromPtr2]
    mov eax, [xWeightPtr]
    mov ebx, [yWeightPtr]
    mov ecx, [length]

; calculate y weights and cache
    movd xmm7, [ebx]                ; get 1-yDiff and yDiff
    pshuflw xmm7, xmm7, 01010000b   ; 1-yDiff, 1-yDiff, yDiff, yDiff
    pshufd xmm7, xmm7, 01000100b    ; duplicate

    mov ebx, [xIndexPtr]

    push ebp                        ; reuse frame ptr for toPtr
    mov ebp, [toPtr]                ; Cannot use parameter refs anymore

    shr ecx,1

    ; calculate first index
    mov edi, [ebx]                  ; index

    align 16
REPEATLOOPX2:

    ; load first and second set of weights into xmm3
    movdqa xmm3, [eax]              ; get 1-xDiff, xDiff, 1-xDiff, xDiff
    pmullw xmm3, xmm7               ; calculate F1, F2, F3, F4 (2)
    add eax, 16

    ; load first set of source pixels
    movq xmm0, [esi+edi]            ; xmm0 = fromPtr1 + index | fromPtr1 + index + 4
    movq xmm1, [edx+edi]            ; xmm1 = fromPtr2 + index | fromPtr2 + index + 4
    punpcklqdq xmm0, xmm1           ; combine all 4 pixels into xmm0

    sub edi, [ebx+4]                ; if the x index is the same then skip the second load
    jz SKIP

    ; calculate second index
    mov edi, [ebx+4]                ; index

    ; load second set of source pixels
    movq xmm4, [esi+edi]            ; xmm4 = fromPtr1 + index | fromPtr1 + index + 4
    movq xmm5, [edx+edi]            ; xmm5 = fromPtr2 + index | fromPtr2 + index + 4
    punpcklqdq xmm4, xmm5           ; combine all 4 pixels into xmm4

    movdqa xmm1, xmm0               ; copy to xmm1, xmm2
    pshufd xmm2, xmm0, 0xE4 
    movdqa xmm5, xmm4               ; copy to xmm1, xmm2
    pshufd xmm6, xmm4, 0xE4 

    jmp NEXT
align 16
SKIP:
    movdqa xmm1, xmm0               ; copy to xmm1, xmm2
    pshufd xmm2, xmm0, 0xE4 
    movdqa xmm4, xmm0               ; copy first pixel set xmm0 to second pixel set xmm4
    pshufd xmm5, xmm4, 0xE4         ; copy to xmm4, xmm6
    movdqa xmm6, xmm4               
NEXT:
;   prefetchnta [edx+edi+16]

    add ebx, 8

; calculate dest rgb values using color = a * F1 + b * F2 + c * F3 + d * F4

; extract b from both sets of pixels and combine into a single reg
    pand xmm0, [RGB_AND]            ; clear all but r values leaving b000
    pand xmm4, [RGB_AND]            ; clear all but r values leaving b000
    packssdw xmm0, xmm4             ; pack down to 16 bit values

    movdqa xmm4, [RGB_AND]          ; xmm4 is now free
    pmaddwd xmm0, xmm3              ; multiply and add to get temp1 = a * F1 + b * F2, temp2 = c * F3 + d * F4

; extract g
    psrld xmm1, 8                   ; rotate g to low bytes
    pand xmm1, xmm4                 ; extract g values g000
    psrld xmm5, 8                   ; rotate g to low bytes
    pand xmm5, xmm4                 ; extract g values g000
    packssdw xmm1, xmm5             ; pack down to 16 bit values

    pmaddwd xmm1, xmm3              ; multiply and add

; extract r
    psrld xmm2, 16                  ; rotate b to low bytes
    pand xmm2, xmm4                 ; extract b values b000
    psrld xmm6, 16                  ; rotate b to low bytes
    pand xmm6, xmm4                 ; extract b values b000
    packssdw xmm2, xmm6             ; pack down to 16 bit values

    pmaddwd xmm2, xmm3              ; multiply and add

;   Add temp1 and temp2 leaving us with rrrr xxxx rrrr xxxx
    psrld xmm0, 14                  ; scale back to range
    pshufd xmm3, xmm0, 00110001b    ; extract temp2
    paddd xmm0, xmm3                ; add back to temp1

    psrld xmm1, 14                  ; scale back to range
    pshufd xmm3, xmm1, 00110001b
    paddd xmm1, xmm3                ; add

    psrld xmm2, 14                  ; scale back to range
    pshufd xmm3, xmm2, 00110001b
    paddd xmm2, xmm3                ; add

;   recombine into 2 rgba values

    pslld xmm1, 8
    por xmm0, xmm1
    pslld xmm2, 16
    por xmm0, xmm2
    pshufd xmm0, xmm0, 00001000b    ; shuffle down

    movq [ebp], xmm0                ; output 32bit * 2
    add ebp, 8

    mov edi, [ebx]                  ; index

    sub ecx, 1
    jnz REPEATLOOPX2

; Cleanup

    pop ebp
    pop esi
    pop edi
    pop ebx
    mov esp, ebp
    pop ebp
    ret

两个建议:

  • 在 Core 2 上一个不错的分析器下的测试工具中运行此代码(例如Zoom http://rotateright.com)查看热点和依赖/其他摊位在哪里

  • 使用内在函数重新编写 SIMD 代码,然后让编译器处理寄存器分配、指令调度和其他优化 - 一个像 ICC 甚至 gcc 这样的不错的编译器将比您的手工编码汇编做得更好。此外,您还可以针对不同的 x86 CPU 系列重新定位,而无需重新编写代码。

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

帮助我改进更多 SSE2 代码 的相关文章

随机推荐

  • 为什么在 sqlalchemy 中使用 sqlite 取消绑定会话方法?

    复制错误的代码 from sqlalchemy import create engine Table Column Integer from sqlalchemy ext declarative import declarative bas
  • 从流中读取对象时出现 Java ClassNotFoundException

    从 ObjectInputStream 读取对象时出现 ClassNotFoundException 正在发送的对象是读取代码所引用的 WorkUnit 的子类 接收端似乎在抱怨 因为它不知道具体的实现 当我只引用对象的超类 接收端的 Wo
  • Python 3:展平嵌套字典和字典内的列表

    我正在处理复杂的嵌套字典和列表数据结构 我需要展平数据并将所有嵌套项目提升至 0 级 请参阅下面的示例以了解更多信息 a 1 b 2 c c1 c11 1 c12 2 c13 3 c21 1 c22 2 c23 3 d1 d11 1 d12
  • 如何从 Android Studio 同时在所有连接的设备或模拟器中运行 Android 应用程序?

    如何从 Android Studio 同时在所有连接的设备或模拟器中运行 Android 应用程序 我们能够在 Eclipse 中同时在所有连接的设备或模拟器中运行 Android 应用程序 但是在 Android Studio 中如何呢
  • GDI 已加速。有谁知道这是什么时候发生的?

    概述这个问题的背景 在工作中我们使用 Dell Precision 工作站 我目前的电脑是 NVidia Quadro FX1700 我的团队正在开发实时数据采集系统的图形组件 因此 我们总是留意图形操作是否不会占用太多 CPU 时间 为了
  • 如何用 df 中的字符替换 NA [重复]

    这个问题在这里已经有答案了 我希望在 df 中将所有 NA 替换为 Not Found 我有这个 df A B 1 NA 2 NA 3 NA 我怎样才能得到那个 A B 1 Not Found 2 Not Found 3 Not Found
  • 是否使用了分配提示?

    我正在读书为什么 C 分配器中没有重新分配功能 https stackoverflow com q 3105001 961353 and 是否可以在运行时在堆上创建一个数组 然后在需要时分配更多空间 https stackoverflow
  • 是否可以在 mailto url 中添加新行?

    我正在尝试打开电子邮件客户端mailto来自我的反应本机应用程序的网址 用于打开客户端的代码片段 const body my email nbody Linking openURL mailto email protected cdn cg
  • 不同浏览器中的HTML输入字段高度不同

    现在的情况 在一个简单的网站上 我有一个具有固定高度的输入控件 其中有一个具有特定字体大小的文本 我希望该文本在输入字段的中间垂直对齐 但即使我使用了重置CSS 链接here https github com necolas normali
  • 单链表的时间复杂度

    我正在研究数据结构 单链表 该网站称单链表的插入和删除时间复杂度为O 1 我错过了什么吗 网站链接 http bigocheatsheet com 我用 C 做这个 而且我只有一个root pointer 如果我想插入到最后 那么我必须一直
  • 在 Eclipse 中调试 Android NDK C/C++ 代码 - 未命中断点

    我下载了适用于 Linux 的 Android SDK Bundle 和 Android NDK 安装了ADT 我安装了CDT 我创建了一个 Android 项目并添加了本机支持 jni 然后我用java代码编写了本机函数 并用c 代码导出
  • C语言中如何计算执行时间?

    如何计算以下代码中的执行时间 include
  • MySqlDataReader GetBytes 缓冲区问题...

    我发现 MySqlDataReader GetBytes 实现有一个奇怪的怪癖 只是想知道这是否众所周知 因为我似乎在网上找不到任何有关它的文章 如果您按照以下代码示例进行操作数据库读取器 http msdn microsoft com e
  • SQL - 选择具有最大值的所有行

    我有这个 SQL 查询 SELECT id COUNT AS price FROM SELECT FROM rt WHERE somecondition AS st JOIN tt ON st id tt id GROUP BY id 现在
  • 如何检测 Facebook Messenger 的气泡何时打开?

    Facebook 使用一项服务在 Android 上推送 Messenger bubble 如下所示 http www piwai info chatheads basics http www piwai info chatheads ba
  • 仅在应用程序升级时升级行

    如果我只想在用户升级应用程序时更新数据库行一次 那么您会在数据库处理程序类的 OnUpgrade 方法中执行此操作 还是会在基于 SharedPreferences 的应用程序类中将其作为 asyncTask 执行 谢谢 应用程序中数据库更
  • Laravel:在刀片页面中使用 asset 方法有什么好处?

    在一些 Laravel 示例中 我看到资产被这样调用 与这样做相比 使用该方法有什么优点 如果您选择后者 则当您访问任何包含正斜杠的 URL 时 这些 URL 将不起作用 例如 不使用asset如果您在主页上 则看起来工作正常 但如果您在
  • 如何更改 Maven 日志记录级别以仅显示警告和错误?

    我想阻止 Maven 显示信息消息 我只想看到警告和错误 如果有 我怎样才能实现这一点 最好是通过更改调用 Maven 的命令行 回答你的问题 我做了一个小调查 因为我也对解决方案感兴趣 Maven 命令行详细选项 根据http books
  • http:多余的response.WriteHeader调用

    我有一个HandleFunc 如果成功的话 我希望 显然 能够 sent a 200回复 在回复中写一条信息性消息 但是以下代码片段 在快乐路径中执行 if fullRun w Write byte successMsg w WriteHe
  • 帮助我改进更多 SSE2 代码

    我正在寻找一些帮助来改进 core2 cpu 上的双线性缩放 sse2 代码 在我的 Atom N270 和 i7 上 此代码比 mmx 代码快大约 2 倍 但在 core2 cpu 下它只等于 mmx 代码 代码如下 void Conve