secondsen 发表于 2012-10-12 14:33:58

mmx 的32位alpha 混合一直弄不好啊。。

是这样

void Widget_HTC_Weather::AlphaBlend32(UINT* pDstBmp, UINT* pSrcBmp, int bit_w, int bit_h, int rc_x, int rc_y, int rc_w, int rc_h, int x, int y, int sw, int sh, int blendalpha)
{
    // rect尺寸为0或负
    if (rc_w <= 0) return;
    if (rc_h <= 0) return;
    // 越界
    if (x >= sw) return;
    if (y >= sh) return;
    if (rc_w + rc_x - 1 < 0) return;
    if (rc_h + rc_y - 1 < 0) return;
    if (x < 0)
    {
      rc_x -= x;
      rc_w += x;
      x = 0;
    }
    if (y < 0)
    {
      rc_y -= y;
      rc_h += y;
      y = 0;
    }
    if (rc_x >= bit_w) return;
    if (rc_y >= bit_h) return;
    // 修正边界
    if (rc_x < 0)
    {
      rc_w += rc_x;
      rc_x = 0;
    }
    if (rc_y < 0)
    {
      rc_h += rc_y;
      rc_y = 0;
    }
    if (rc_x + rc_w > bit_w) rc_w = bit_w - rc_x;
    if (rc_y + rc_h > bit_h) rc_h = bit_h - rc_y;
    if (x + rc_w > sw) rc_w = sw - x;
    if (y + rc_h > sh) rc_h = sh - y;
    const int nextLineOffset_src = (bit_w - rc_w) * 4;    // 混合完一行像素后,通过加上该值,便可直接定位到下行起始像素
    const int nextLineOffset_dst = (sw - rc_w) * 4;

    pDstBmp += y * sw + x;
    pSrcBmp += rc_y * bit_w + rc_x;
    UINT** pptmp = &pDstBmp;

    __asm
    {
      mov            edi, pDstBmp      ; 目的像素
            mov            esi, pSrcBmp      ; 源像素
            xor            ebx, ebx            ; 已混合的高度
            mov            ecx, rc_w            ; 要混合的宽度

BLEND_BEGIN:
      cmp            dword ptr, 0x00FFFFFF    ; 如果alpha为0,则跳过混合部分
            jna            BLEND_END

            movd      mm0,             ; 把目的像素值移入mm0寄存器的低32位
            movd      mm1,             ; 把源像素值移入mm1寄存器的低32位

            ; Core Begin
            pxor      mm2, mm2            ; 把MM2清0
            punpcklbw    mm0, mm2            ; src:8 bit到16 bit以容纳结果,32bit expand to 64 bit
            punpcklbw    mm1, mm2            ; dst:8 bit到16 bit以容纳结果.32bit expand to 64 bit
            movq      mm3, mm1            ; 因为要用dst的Alpha值
            punpckhwd    mm3, mm3            ; 高字移动到双字
            punpckhdq    mm3, mm3            ; 双字移动到四字,现在有八个像素的Alpha了!
            movq      mm4, mm0            ; mm4 = dst
            movq      mm5, mm1            ; mm5 = src
            psubusw      mm4, mm1            ; dst-src,饱和减,小于0为0
            psubusw      mm5, mm0            ; src-dst,饱和减,小于0为0
            pmullw      mm4, mm3            ; Alpha * (src-dst)
            pmullw      mm5, mm3            ; Alpha * (dst-src)
            psrlw      mm4, 8                ; 除以256,now mm4 get the result,(src-dst)<0 部分
            psrlw      mm5, 8                ; 除以256,now mm5 get the result,(dst-src)>0 部分
            paddusw      mm0, mm5            ; 饱和加到原图象:D=Alpha*(O-S)+S,(src-dst)<0 部分
            psubusw      mm0, mm4            ; 饱和加到原图象D=S-Alpha*(S-O),(dst-src)>0 部分
            packuswb    mm0, mm0            ; 紧缩到低32bit
            ; Core End

            movd      , mm0            ; 混合结果写进目的像素

BLEND_END:
      add            edi, 4
            add            esi, 4
            ;loop      BLEND_BEGIN                ; 循环
            dec            ecx
            cmp            ecx, 0                ; rc_w <= 0 跳出循环
            jg            BLEND_BEGIN

            add            esi, nextLineOffset_src    ; 加上偏移量,使定位到下行起始处
            add            edi, nextLineOffset_dst

            inc            ebx
            mov            ecx, rc_w

            cmp            ebx, rc_h                ; 若ebx小于rc_h,则转移到上面继续混合
            jb            BLEND_BEGIN

            EMMS                              ; 因为从mm0到mm7,这些寄存器是“借用”浮点寄存器的低64位,所以每次在用完MMX指令后一定要用EMMS指令将寄存器清空
    }
}

secondsen 发表于 2012-10-12 14:41:16

UINT* pDstBmp 目标地址
UINT* pSrcBmp 源地址
int bit_w 源位图的尺寸
int bit_h
int rc_x 矩形尺寸(源位图,中的一个矩形区域混合到Dst上)
int rc_y
int rc_w
int rc_h
int x, 混合到目标位图的位置
int y,
int sw, 目标位图的尺寸
int sh,
int blendalpha 透明度

现在是 int blendalpha 透明度 这个参数没有用上,一切都正常,我想加上这个参数比如 blendalpha = 100
源位图选取的矩形在混合的时候透明度会 *100/255自己试了在这个代码里面添汇编指令,总是失败,求教

secondsen 发表于 2012-10-12 17:44:24

竟然又自己捣鼓出来了!!!不过还是有疑问哇


    const int ff = 0xff;//这一句是添加的

    __asm
    {
        mov            edi, pDstBmp        ; 目的像素
            mov            esi, pSrcBmp        ; 源像素
            xor            ebx, ebx            ; 已混合的高度
            mov            ecx, rc_w            ; 要混合的宽度

BLEND_BEGIN:
        cmp            dword ptr, 0x00FFFFFF; 如果alpha为0,则跳过混合部分
            jna            BLEND_END
;后边是添加的代码
            mov            eax, blendalpha        ; 获取blend alpha
            mov            edx, dword ptr
            shr            edx, 24                ; edx 获取源像素 alpha
            imul        eax, edx
            mov            edx, 0
            idiv        ff ;下边说的就是这句
            shl            eax, 24
            mov            edx, eax
            mov            eax, dword ptr
            and            eax, 0x00ffffff
            or            eax, edx ;添加完毕
;添加完毕
            movd        mm0,             ; 把目的像素值移入mm0寄存器的低32位
            ;movd        mm1,             ; 把源像素值移入mm1寄存器的低32位
            movd            mm1, eax   ;这一句替换上一句

那么,问题来了。。。问题描述在这里
添加的一大串中
            idiv        ff
ff是我前面定义的 const int 局部变量

我起初
mov edx, 0xff
idiv edx
结果 编译过了,调试的时候 0xC0000095 整数溢出,断点断在 函数调用的地方,但是 idiv 这一句屏蔽掉,一点问题都没有。

这里问题1
我就郁闷了。。。
那么 原因 是不是 这样的?
edx:eax 是被除数 除edx 高位32位得 1低是32位XXXX  这个高位的1 就是溢出的东西?

问题2
那么我不想要多定义 const int ff 这个局部变量怎么办的
双层循环已经占用了ebx ecx,mmx 占用了 ebi esi 那么只剩下 eax edx了吧?。。想不通了。。总之解决了,剩下的就是附加题了

weiwuyuan 发表于 2012-10-13 10:46:50

你想调整整个图像的alpha?
如果是这样的,我感觉你的方式有点不对,至少是不好,
在我的实现里面,图像有以下几种效果:
1:缩放
2:调节色调
3:调节亮度

其中,调节色调就能解决你的需求,
调节色调就是对源像素按给出的比例进行缩放:
比如源像素是0xFFFFFFFF,给出的比例是:0xFFFFFF64,那么结果就是0xFFFFFF64,即100/255.0f*255=100
如果源像素是0xC8FFFFFF,给出的比例是:0x64FFFFFF,那么结果就是0x4EFFFF,即100/255.0f*200=78

效果见这张图:
http://img.my.csdn.net/uploads/201209/15/1347677430_4954.jpg
如果你用过D3D,就应该知道这个色调调节就是顶点颜色所实现的效果.

weiwuyuan 发表于 2012-10-13 11:04:13

寄存器不够用的话,就用栈吧,我写的一个支持缩放+色调调节+亮度调节的alpha混合函数,仅push了两个寄存器
但很多情况下,只要算法足够精当,都会够用

secondsen 发表于 2012-10-13 18:03:13

idiv那一句,我写成 idiv edx 会出错哇,调试会出现整数溢出。。。要不,我也不用申请变量哇。。。

我就是想 给选择的矩形部分加一个透明度 再 混合到 dst上。原图不变,也不是整个图都变透明,只是选的那部分(要进行混合的)

我看楼上的就是用位移代替 除法,反正255 和 256 差不多是吧?

weiwuyuan 发表于 2012-10-13 21:15:38

引用第5楼secondsen于2012-10-13 18:03发表的 :
idiv那一句,我写成 idiv edx 会出错哇,调试会出现整数溢出。。。要不,我也不用申请变量哇。。。

我就是想 给选择的矩形部分加一个透明度 再 混合到 dst上。原图不变,也不是整个图都变透明,只是选的那部分(要进行混合的)

我看楼上的就是用位移代替 除法,反正255 和 256 差不多是吧? http://www.rpgchina.net/images/back.gif


我写的那代码有问题,让我删了,
可以用除以256来代替除以255,这个损失是可以接受的,要不然除法指令会慢一些.

你是说,你渲染一个图片的时候,你想调整图片某块区域的透明度? 而不是整个图片的透明度?
这个功能我倒是没做过,
如果你只调整alpha的话,单独写一个函数就行.

关于idiv
这个指令我没用过,查了一下,是有符号除法,你为什么不用div呢? 这个是无符号除,因为颜色分量都是无符号的.

还有:
你居然可以这么写: imul      eax, edx
因为我用mul都是这样的: mulebx , 即被乘数是eax, 乘数是ebx,结果低32位放到eax上,高32位放到edx上,
你这个居然能用两个寄存器.
另外,你的代码我没看出有什么问题.

secondsen 发表于 2012-10-13 21:25:04

因为是这样,所以是这样哇。。。我是按照这个来的 http://www.cnblogs.com/del/archive/2010/04/15/1712950.html

用有符号的的指令,因为无符号的指令编译过不去,不知道什么毛病

其实alpha一通百通,色调也是一样,我都已经成功了,只是不知道idiv是什么毛病,也不知道我上面自己瞎想的对不对。。。OTZ

weiwuyuan 发表于 2012-10-13 21:30:37

引用第7楼secondsen于2012-10-13 21:25发表的 :
因为是这样,所以是这样哇。。。我是按照这个来的 http://www.cnblogs.com/del/archive/2010/04/15/1712950.html

用有符号的的指令,因为无符号的指令编译过不去,不知道什么毛病

其实alpha一通百通,色调也是一样,我都已经成功了,只是不知道idiv是什么毛病,也不知道我上面自己瞎想的对不对。。。OTZ http://www.rpgchina.net/images/back.gif


div编译不了?
那就奇怪了,我是从16位汇编学过来的,我一直使用mul和div,而没用过imul和idiv, 也没出现什么编译不了的问题.
你的写法和我的是一样的.

另外,你不应该除以edx,因为你是在做32位除法,你的edx总是0,被除数都在eax上

secondsen 发表于 2012-10-15 08:30:21

不是edx:eax合起来是被除数么
页: [1] 2
查看完整版本: mmx 的32位alpha 混合一直弄不好啊。。