幻想森林

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 6073|回复: 11

[通用编程] mmx 的32位alpha 混合一直弄不好啊。。

[复制链接]

550

主题

9116

帖子

214748万

积分

超级版主

如同神一般的存在,腿神!拖后腿的神~~

Rank: 8Rank: 8

积分
2147483647
发表于 2012-10-12 14:33:58 | 显示全部楼层 |阅读模式
是这样

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[esi], 0x00FFFFFF    ; 如果alpha为0,则跳过混合部分
            jna            BLEND_END

            movd        mm0, [edi]            ; 把目的像素值移入mm0寄存器的低32位
            movd        mm1, [esi]            ; 把源像素值移入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            ; 饱和加到原图象=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        [edi], 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指令将寄存器清空
    }
}
我就是你们的神,庶民们,追随我吧!跟着我一起拖后腿!
回复

使用道具 举报

550

主题

9116

帖子

214748万

积分

超级版主

如同神一般的存在,腿神!拖后腿的神~~

Rank: 8Rank: 8

积分
2147483647
 楼主| 发表于 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自己试了在这个代码里面添汇编指令,总是失败,求教
我就是你们的神,庶民们,追随我吧!跟着我一起拖后腿!
回复 支持 反对

使用道具 举报

550

主题

9116

帖子

214748万

积分

超级版主

如同神一般的存在,腿神!拖后腿的神~~

Rank: 8Rank: 8

积分
2147483647
 楼主| 发表于 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[esi], 0x00FFFFFF; 如果alpha为0,则跳过混合部分
            jna            BLEND_END
;后边是添加的代码
            mov            eax, blendalpha        ; 获取blend alpha
            mov            edx, dword ptr[esi]
            shr            edx, 24                ; edx 获取源像素 alpha
            imul        eax, edx
            mov            edx, 0
            idiv        ff ;下边说的就是这句
            shl            eax, 24
            mov            edx, eax
            mov            eax, dword ptr[esi]
            and            eax, 0x00ffffff
            or            eax, edx ;添加完毕
;添加完毕
            movd        mm0, [edi]            ; 把目的像素值移入mm0寄存器的低32位
            ;movd        mm1, [esi]            ; 把源像素值移入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了吧?。。想不通了。。总之解决了,剩下的就是附加题了
我就是你们的神,庶民们,追随我吧!跟着我一起拖后腿!
回复 支持 反对

使用道具 举报

0

主题

16

帖子

128

积分

③业余

积分
128
QQ
发表于 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

效果见这张图:

如果你用过D3D,就应该知道这个色调调节就是顶点颜色所实现的效果.
回复 支持 反对

使用道具 举报

0

主题

16

帖子

128

积分

③业余

积分
128
QQ
发表于 2012-10-13 11:04:13 | 显示全部楼层
寄存器不够用的话,就用栈吧,我写的一个支持缩放+色调调节+亮度调节的alpha混合函数,仅push了两个寄存器
但很多情况下,只要算法足够精当,都会够用
回复 支持 反对

使用道具 举报

550

主题

9116

帖子

214748万

积分

超级版主

如同神一般的存在,腿神!拖后腿的神~~

Rank: 8Rank: 8

积分
2147483647
 楼主| 发表于 2012-10-13 18:03:13 | 显示全部楼层
idiv那一句,我写成 idiv edx 会出错哇,调试会出现整数溢出。。。要不,我也不用申请变量哇。。。

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

我看楼上的就是用位移代替 除法,反正255 和 256 差不多是吧?
我就是你们的神,庶民们,追随我吧!跟着我一起拖后腿!
回复 支持 反对

使用道具 举报

0

主题

16

帖子

128

积分

③业余

积分
128
QQ
发表于 2012-10-13 21:15:38 | 显示全部楼层
引用第5楼secondsen于2012-10-13 18:03发表的 :
idiv那一句,我写成 idiv edx 会出错哇,调试会出现整数溢出。。。要不,我也不用申请变量哇。。。

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

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


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

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

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

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

使用道具 举报

550

主题

9116

帖子

214748万

积分

超级版主

如同神一般的存在,腿神!拖后腿的神~~

Rank: 8Rank: 8

积分
2147483647
 楼主| 发表于 2012-10-13 21:25:04 | 显示全部楼层
因为是这样,所以是这样哇。。。我是按照这个来的 http://www.cnblogs.com/del/archive/2010/04/15/1712950.html

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

其实alpha一通百通,色调也是一样,我都已经成功了,只是不知道idiv是什么毛病,也不知道我上面自己瞎想的对不对。。。OTZ
我就是你们的神,庶民们,追随我吧!跟着我一起拖后腿!
回复 支持 反对

使用道具 举报

0

主题

16

帖子

128

积分

③业余

积分
128
QQ
发表于 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


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

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

使用道具 举报

550

主题

9116

帖子

214748万

积分

超级版主

如同神一般的存在,腿神!拖后腿的神~~

Rank: 8Rank: 8

积分
2147483647
 楼主| 发表于 2012-10-15 08:30:21 | 显示全部楼层
不是edx:eax合起来是被除数么
我就是你们的神,庶民们,追随我吧!跟着我一起拖后腿!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|幻想森林

GMT+8, 2024-3-29 04:29 , Processed in 0.025049 second(s), 22 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表