打印
[STM32F7]

STM32F7 DAM2D alpha像素混合

[复制链接]
653|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
alpha像素混合可以在一个图层上面显示另外一张带透明的图片



//ICO解码所需的填充接口-会执行像素混合
void ICO_FillPoint_CallBack(GRAM_HANDLE* pHandle, u16 OffsetX, u16 OffsetY, void* pSourceImage, u16 SourceWidth, u16 SourceHeight)
{
    static u32 offset;
        static DMA2D_PixelMixing_Parm mMixingParm;                //混合所需参数
       
       
        offset = (u32)pHandle->Width * OffsetY + OffsetX;
        offset *= pHandle->PixelByteSize;
        //=====参数初始化======
        //公共配置
        mMixingParm.ImageWidth                                =        SourceWidth;                                                //待传输的像素图像宽度,单位像素
        mMixingParm.ImageHeight                                =        SourceHeight;                                                //待传输的像素图像高度,单位像素
        //输入的背景配置
        mMixingParm.InBackImageAddr                        =        pHandle->GRAM_Addr + offset;                //输入的背景图像开始地址(通过地址控制开始的X,Y坐标)
        mMixingParm.InBackImageOffsetX                =        pHandle->Width - SourceWidth;                //输入的背景图像跳过的X坐标值
        mMixingParm.InBackAlpha                                =        0xFF;                                                                //输入的背景图像的固定Alpha值,是否使用根据InBackAlphaMode配置决定
        mMixingParm.InBackColorMode                        =        pHandle->ColorMode;                                        //输入的背景图像的颜色模式
        mMixingParm.InBackAlphaMode                        =        DMA2D_ALPHA_NULL;                                        //输入的背景图像Alpha模式
        //输入的前景配置
        mMixingParm.InForeImageAddr                        =        (u32)pSourceImage;                                        //输入的前景图像开始地址(通过地址控制开始的X,Y坐标)
        mMixingParm.InForeImageOffsetX                =        0x00;                                                                //输入的前景图像跳过的X坐标值
        mMixingParm.InForeAlpha                                =        0xFF;                                                                //输入的前景图像的固定Alpha值,是否使用根据InForeAlphaMode配置决定
        mMixingParm.InForeColorMode                        =        DMA2D_COLOR_ARGB8888;                                //输入的前景图像的颜色模式
        mMixingParm.InForeAlphaMode                        =        DMA2D_ALPHA_NULL;                                        //输入的前景图像Alpha模式
        //输出配置
        mMixingParm.OutImageAddr                        =        pHandle->GRAM_Addr + offset;                //输出的图像开始地址(通过地址控制开始的X,Y坐标)
        mMixingParm.OutImageOffsetX                        =        pHandle->Width - SourceWidth;                //输出的图像跳过的X坐标值
        mMixingParm.OutColorMode                        =        pHandle->ColorMode;                                        //输出的图像的颜色模式
       
        DMA2D_WaitTransferComplete(5);                                        //需要等待上一次传输完成-不等待可能会出现乱点
        DMA2D_FillImage_PixelMixing(&mMixingParm);                //DMA2D进行矩形图形填充(会执行像素格式转换与Alpha混合)
}
上面这个是ICO解码的数据填充函数,输入的数据是ARGB格式,带透明信息,原本屏幕已经显示了一张底图,然后这个接口会自动对底图与新图进行Alpha混合,实现2个图片带透明度的叠加.

DMA2D_FillImage_PixelMixing()函数有硬件的,也提供一个对应的软件实现版本.


使用特权

评论回复
沙发
八层楼|  楼主 | 2021-8-1 16:53 | 只看该作者
先上STM32F7的硬件DMA2D像素混合代码


/*************************************************************************************************************************
* 函数                        :        void DMA2D_WaitTransferComplete(u32 TimeOutMs)
* 功能                        :        等待DMA2D传输完成
* 参数                        :        TimeOutMs:超时时间
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2019-10-30
* 最后修改时间         :         2019-10-30
* 说明                        :        超时后会取消传输
                                        2020-03-13:修改为通过传输启动状态来判断传输结束,由于传输结束,终止,出错后会自动清除启动位,如果没有启动,也不存在超时,比较灵活
*************************************************************************************************************************/
void DMA2D_WaitTransferComplete(u32 TimeOutMs)
{
        u32 timeout = 0;
       
        //while((DMA2D->ISR & (1<<1)) == 0)        //等待传输完成
        while(DMA2D->CR & BIT0)                                //等待传输结束
        {
                timeout++;
                SYS_DelayMS(1);                                        //延时1ms
                if(timeout > TimeOutMs)
                {
                        DMA2D_Abort();                                //终止传输
                        break;                                                //超时退出
                }
        }  
        DMA2D->IFCR |= 1<<1;                                //清除传输完成标志        
}

/*************************************************************************************************************************
* 函数                        :        void DMA2D_FillImage_PixelMixing(DMA2D_PixelMixing_Parm *pParm)
* 功能                        :        DMA2D进行矩形图形填充(会执行像素格式转换与Alpha混合)
* 参数                        :        pParm:所需的参数,见DMA2D_PixelMixing_Parm
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2020-03-13
* 最后修改时间         :         2020-03-13
* 说明                        :        用于填充图形,不会等待是否传输成功,需要调用DMA2D_WaitTransferComplete()等待传输结束
*************************************************************************************************************************/
void DMA2D_FillImage_PixelMixing(DMA2D_PixelMixing_Parm *pParm)
{
       
        SYS_DeviceClockEnable(DEV_DMA2D, TRUE);                                                //使能DMA2D时钟

        DMA2D->CR = 1<<2;                                                                                        //配置寄存器先复位-停止传输
        //传输模式设置
        DMA2D->CR = DMA2D_MODE_MEM_MIXED<<16;                                                //存储器到存储器模式-激活像素混合
        //背景图像设置
        DMA2D->BGPFCCR = ((u32)pParm->InBackAlpha&0XFF) << 24;                //设置固定Alpha值
        DMA2D->BGPFCCR |= (pParm->InBackAlphaMode & 0x03) << 16;        //Alpha 模式 (Alpha mode)
        DMA2D->BGPFCCR |= (pParm->InBackColorMode & 0x0f) << 0;                //颜色模式
        DMA2D->BGOR = pParm->InBackImageOffsetX;                                        //背DD景层偏移寄存器
        DMA2D->BGMAR = pParm->InBackImageAddr;                                                //背景层存储器地址寄存器
        //前景图像设置
        DMA2D->FGPFCCR = ((u32)pParm->InForeAlpha&0XFF) << 24;                //设置固定Alpha值
        DMA2D->FGPFCCR |= (pParm->InForeAlphaMode & 0x03) << 16;        //Alpha 模式 (Alpha mode)
        DMA2D->FGPFCCR |= (pParm->InForeColorMode & 0x0f) << 0;                //颜色模式
        DMA2D->FGOR = pParm->InForeImageOffsetX;                                        //前景层偏移寄存器
        DMA2D->FGMAR = pParm->InForeImageAddr;                                                //前景层存储器地址寄存器
        //输出设置
        DMA2D->OPFCCR = pParm->OutColorMode & 0x07;                                        //输出颜色模式
        DMA2D->OMAR = pParm->OutImageAddr;                                                        //输出存储器地址
        DMA2D->OOR = pParm->OutImageOffsetX;                                                //输出偏移寄存器
        //公共配置
        DMA2D->NLR = pParm->ImageWidth;                                                                //待传输的像素图像宽度,单位像素
        DMA2D->NLR <<= 16;
        DMA2D->NLR |= pParm->ImageHeight;                                                        //待传输的像素图像高度,单位像素

        DMA2D_Start();                                                                                                //开始传输
}


使用特权

评论回复
板凳
八层楼|  楼主 | 2021-8-1 16:53 | 只看该作者

/*************************************************************************************************************
* 文件名                :        dma2d.H
* 功能                        :        STM32F7 DMA2D驱动
* 作者                        :        cp1300@139.com
* 创建时间                :        2019-10-29
* 最后修改时间        :        2019-10-29
* 详细:                       
*************************************************************************************************************/       
#ifndef __DMA2D_H_
#define        __DMA2D_H_          
#include "system.h"


typedef enum
{
        DMA2D_MODE_MEM                =         0,                //存储器到存储器(仅限 FG前景色 获取)
        DMA2D_MODE_MEM_PFC        =        1,                //存储器到存储器并执行 PFC(仅限 FG PFC 激活时的 FG 获取)
        DMA2D_MODE_MEM_MIXED=        2,                //存储器到存储器并执行混合(执行 PFC 和混合时的 FG 和 BG 获取)
        DMA2D_MODE_REG                =        3,                //寄存器到存储器(无 FG 和 BG,仅输出阶段激活)
}DMA2D_MODE;

//颜色模式
typedef enum
{
        DMA2D_COLOR_ARGB8888         = 0,
        DMA2D_COLOR_RGB888                 = 1,
        DMA2D_COLOR_RGB565                 = 2,
        /*DMA2D_COLOR_ARGB1555         = 3,
        DMA2D_COLOR_ARGB4444         = 4,
        DMA2D_COLOR_L8                         = 5,        //8 位 Luminance
        DMA2D_COLOR_AL44                 = 6,        //4 位 Alpha,4 位 Luminance
        DMA2D_COLOR_AL88                 = 7,        //8 位 Alpha,8 位 Luminance
        DMA2D_COLOR_L4                         = 8,        //4 位 Luminance
        DMA2D_COLOR_A8                         = 9,        //8 位 Alpha
        DMA2D_COLOR_A4                         = 10,        //4 位 Alpha*/
}DMA2D_COLOR_MODE;


//Alpha 模式
typedef enum
{
        DMA2D_ALPHA_NULL        =        0,//不修改层图像的 alpha 通道值
        DMA2D_ALPHA_REPLACE        =        1,//原始层图像的 alpha 通道值替换为 ALPHA[7: 0]
        DMA2D_ALPHA_PRODUCT        =        2,//原始层图像的 alpha 通道值替换为 ALPHA[7: 0] 与原始 alpha 通道值的乘积
}DMA2D_ALPHA_MODE;

//像素混合模式下DMA图形填充所需参数
typedef struct
{
        //公共配置
        u16 ImageWidth;                                                //待传输的像素图像宽度,单位像素
        u16 ImageHeight;                                        //待传输的像素图像高度,单位像素
        //输入的背景配置
        u32 InBackImageAddr;                                //输入的背景图像开始地址(通过地址控制开始的X,Y坐标)
        u32 InBackImageOffsetX;                                //输入的背景图像跳过的X坐标值
        u32 InBackAlpha;                                        //输入的背景图像的固定Alpha值,是否使用根据InBackAlphaMode配置决定
        DMA2D_COLOR_MODE InBackColorMode;        //输入的背景图像的颜色模式
        DMA2D_ALPHA_MODE InBackAlphaMode;        //输入的背景图像Alpha模式
        //输入的前景配置
        u32 InForeImageAddr;                                //输入的前景图像开始地址(通过地址控制开始的X,Y坐标)
        u32 InForeImageOffsetX;                                //输入的前景图像跳过的X坐标值
        u32 InForeAlpha;                                        //输入的前景图像的固定Alpha值,是否使用根据InForeAlphaMode配置决定
        DMA2D_COLOR_MODE InForeColorMode;        //输入的前景图像的颜色模式
        DMA2D_ALPHA_MODE InForeAlphaMode;        //输入的前景图像Alpha模式
        //输出配置
        u32 OutImageAddr;                                        //输出的图像开始地址(通过地址控制开始的X,Y坐标)
        u32 OutImageOffsetX;                                //输出的图像跳过的X坐标值
        DMA2D_COLOR_MODE OutColorMode;                //输出的图像的颜色模式
}DMA2D_PixelMixing_Parm;



__inline void DMA2D_Abort(void) {DMA2D->CR |= BIT2;}                //终止传输
__inline void DMA2D_Suspend(void) {DMA2D->CR |= BIT1;}                //挂起传输
__inline void DMA2D_Start(void) {DMA2D->CR |= BIT0;}                //开始传输


void DMA2D_WaitTransferComplete(u32 TimeOutMs);                                                                                                                                                        //等待DMA2D传输完成

void DMA2D_FillImage_PixelMixing(DMA2D_PixelMixing_Parm *pParm);        //DMA2D进行矩形图形填充(会执行像素格式转换与Alpha混合)

#endif //__DMA2D_H_


使用特权

评论回复
地板
八层楼|  楼主 | 2021-8-1 16:54 | 只看该作者
下面是C语言软件实现的alpha混合,功能与使用完全一致

//RGB888 转 RGB565
#ifndef RGB565
#define RGB565(color) ((((color) >> 19) & 0x1f) << 11) \
                                            |((((color) >> 10) & 0x3f) << 5) \
                                            |(((color) >> 3) & 0x1f)
#endif //RGB565


//RGB565转RGB888
#ifndef RGB888
#define RGB888(color) ((((color) >> 8) & 0xF8) << 16) \
                                            |((((color) >> 3) & 0xFC) << 8) \
                                            |(((color) << 3) & 0xFC)
#endif //RGB888


//RGB888转ARGB8888
#ifndef RGB888toARGB
#define RGB888toARGB(color) (color|0xFF000000)
#endif //RGB888toARGB


//ARGB 格式数据定义
typedef struct
{
    u8 mB;
    u8 mG;
    u8 mR;
    u8 mA;
}ARGB_DATA_TYPE;

//获取一个像素的数据长度
static u8 DMA2D_GetPidexByteSize(DMA2D_COLOR_MODE ColorMode)
{
    switch (ColorMode)
    {
        case DMA2D_COLOR_ARGB8888: return 4;
        case DMA2D_COLOR_RGB888: return 3;
        default: return 2;
    }
}

//转换一个像素为ARGB格式
static u32 __inline DMA2D_ConvPidexToARGB(u32 Color, DMA2D_COLOR_MODE ColorMode)
{
    switch (ColorMode)
    {
        case DMA2D_COLOR_ARGB8888:  //输入像素为ARGB8888,不用转换
        {
            return Color;
        }
        case DMA2D_COLOR_RGB888:    //输入像素为RGB888,加上alpha通道数据
        {
            return RGB888toARGB(Color);
        }
        default:  //输入像素为RGB565
        {
            return RGB888toARGB(RGB888(Color));
        }
    }
}


//处理一个像素的Alpha设置
static void __inline DMA2D_PidexAlphaModeHandle(u32 *pColor, u8 Alpha, DMA2D_ALPHA_MODE AlphaMode)
{
    u16 temp;
    ARGB_DATA_TYPE* pPidex = (ARGB_DATA_TYPE*)pColor;

    switch (AlphaMode)
    {
        case DMA2D_ALPHA_REPLACE ://原始前景层图像的 alpha 通道值替换为 ALPHA[7: 0]
        {
            pPidex->mA = Alpha;
        }break;
        case DMA2D_ALPHA_PRODUCT ://原始前景层图像的 alpha 通道值替换为 ALPHA[7: 0] 与原始 alpha 通道值的乘积
        {
            temp = Alpha;
            temp *= pPidex->mA;
            pPidex->mA = temp / 255;
        }break;
        default: break;//不修改前景层图像的 alpha 通道值      
    }
}

//进行2个像素混合,必须是ARGB888格式
static void __inline DMA2D_PixelMixing(ARGB_DATA_TYPE* pInBackPidex, ARGB_DATA_TYPE* pInForePidex, ARGB_DATA_TYPE* pOutPidex)
{
    ARGB_DATA_TYPE tempARGB;
    //先计算底层(背景默认为黑色)-底层有个黑色幕布,如果背景层的Alpha不是255,会先进行计算
    if (pInBackPidex->mA < 255)
    {
        tempARGB.mR = ((u32)(pInBackPidex->mA) * pInBackPidex->mR) / 255;
        tempARGB.mG = ((u32)(pInBackPidex->mA) * pInBackPidex->mG) / 255;
        tempARGB.mB = ((u32)(pInBackPidex->mA) * pInBackPidex->mB) / 255;
    }
    else
    {
        memcpy(&tempARGB, pInBackPidex, 4);         //不用计算混合,直接使用背景层
    }

    //背景层与前景层混合
    pOutPidex->mR = (((u32)(pInForePidex->mA) * pInForePidex->mR) + (u32)(255 - pInForePidex->mA) * tempARGB.mR) / 255;
    pOutPidex->mG = (((u32)(pInForePidex->mA) * pInForePidex->mG) + (u32)(255 - pInForePidex->mA) * tempARGB.mG) / 255;
    pOutPidex->mB = (((u32)(pInForePidex->mA) * pInForePidex->mB) + (u32)(255 - pInForePidex->mA) * tempARGB.mB) / 255;
    pOutPidex->mA = 0xFF;   //混合后的最终图像不需要Alpha了,因为屏幕显示只需要RGB即可
}

//将ARGB8888数据格式转换为输出所需格式
static u32 __inline DMA2D_ARGBtOConvPidex(u32 Color, DMA2D_COLOR_MODE ColorMode)
{
    switch (ColorMode)
    {
        case DMA2D_COLOR_ARGB8888:  //输出像素为ARGB8888,不用转换
        {
            return Color;
        }
        case DMA2D_COLOR_RGB888:    //输出像素为RGB888,去掉alpha通道数据
        {
            return Color & 0x00FFFFFF;
        }
        default:  //输出像素为RGB565
        {
            return RGB565(Color);
        }
    }
}

/*************************************************************************************************************************
* 函数                        :        void DMA2D_FillImage_PixelMixing(DMA2D_PixelMixing_Parm *pParm)
* 功能                        :        DMA2D进行矩形图形填充(会执行像素格式转换与Alpha混合)
* 参数                        :        pParm:所需的参数,见DMA2D_PixelMixing_Parm
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2020-03-14
* 最后修改时间         :         2020-03-14
* 说明                        :        用于填充图形,实现STM32F7的 DMA2D像素混合功能
*************************************************************************************************************************/
void DMA2D_FillImage_PixelMixing(DMA2D_PixelMixing_Parm* pParm)
{
    u32 x, y;
    //像素点缓冲区
    u32 InBackPidex;                //输入的背景像素
    u32 InForePidex;                //输入的前景像素
    u32 OutPidex;                   //输出的像素
    //像素点指针-用于alpha混合
    ARGB_DATA_TYPE* pInBackPidex;   //输入的背景像素ARGB格式指针
    ARGB_DATA_TYPE* pInForePidex;   //输入的前景像素ARGB格式指针
    ARGB_DATA_TYPE* pOutPidex;      //输出的像素ARGB格式指针
    //像素大小-单位字节
    u8 InBackPidexSize;                //输入的背景像素
    u8 InForePidexSize;                //输入的前景像素
    u8 OutPidexSize;                   //输出的像素
    //当前处理的像素位置指针-字节指针
    u8* pInBackPidexBytePoint;         //输入的背景像素处理位置指针
    u8* pInForePidexBytePoint;         //输入的前景像素处理位置指针
    u8* pOutPidexBytePoint;            //输出的像素字节指针

    //像素指针初始化
    pInBackPidex = (ARGB_DATA_TYPE*)&InBackPidex;   //输入的背景像素
    pInForePidex = (ARGB_DATA_TYPE*)&InForePidex;   //输入的前景像素
    pOutPidex = (ARGB_DATA_TYPE*)&OutPidex;         //输出的像素
    //像素大小初始化
    InBackPidexSize = DMA2D_GetPidexByteSize(pParm->InBackColorMode);                //输入的背景像素
    InForePidexSize = DMA2D_GetPidexByteSize(pParm->InForeColorMode);                //输入的前景像素
    OutPidexSize = DMA2D_GetPidexByteSize(pParm->OutColorMode);                      //输出的像素
    //像素处理位置指针初始化
    pInBackPidexBytePoint = (u8*)pParm->InBackImageAddr;                             //输入的背景像素处理位置指针
    pInForePidexBytePoint = (u8*)pParm->InForeImageAddr;                             //输入的前景像素处理位置指针
    pOutPidexBytePoint = (u8*)pParm->OutImageAddr;                                   //输出的像素字节指针

    for (y = 0; y < pParm->ImageHeight; y++)
    {
        for (x = 0; x < pParm->ImageWidth; x++)
        {
            //像素数据初始化为0
            InBackPidex = 0; InForePidex = 0; OutPidex = 0;
            //读取一个背景像素,转换为ARGB格式
            memcpy(&InBackPidex, pInBackPidexBytePoint, InBackPidexSize);                           //读取一个输入的背景像素
            InBackPidex = DMA2D_ConvPidexToARGB(InBackPidex, pParm->InBackColorMode);               //转换为ARGB
            DMA2D_PidexAlphaModeHandle(&InBackPidex, pParm->InBackAlpha, pParm->InBackAlphaMode);   //处理一个像素的Alpha设置
            pInBackPidexBytePoint += InBackPidexSize;                                               //指针跳到下一个像素
            //读取一个前景像素,转换为ARGB格式
            memcpy(&InForePidex, pInForePidexBytePoint, InForePidexSize);                           //读取一个输入的前景像素
            InForePidex = DMA2D_ConvPidexToARGB(InForePidex, pParm->InForeColorMode);               //转换为ARGB
            DMA2D_PidexAlphaModeHandle(&InForePidex, pParm->InForeAlpha, pParm->InForeAlphaMode);   //处理一个像素的Alpha设置
            pInForePidexBytePoint += InForePidexSize;                                               //指针跳到下一个像素
            //Alpha混合
            DMA2D_PixelMixing(pInBackPidex, pInForePidex, pOutPidex);                               //进行2个像素混合,必须是ARGB888格式
            //输出像素转换
            OutPidex = DMA2D_ARGBtOConvPidex(OutPidex, pParm->OutColorMode);                        //将ARGB8888数据格式转换为输出所需格式
            //拷贝最终数据到输出缓冲区中
            memcpy(pOutPidexBytePoint, &OutPidex, OutPidexSize);
            pOutPidexBytePoint += OutPidexSize;                                                     //指针跳到下一个像素
        }
        //一行处理完了,需要跳过一些X值
        pInBackPidexBytePoint += pParm->InBackImageOffsetX * InBackPidexSize;
        pInForePidexBytePoint += pParm->InForeImageOffsetX * InForePidexSize;
        pOutPidexBytePoint += pParm->OutImageOffsetX * OutPidexSize;
    }

}


使用特权

评论回复
5
八层楼|  楼主 | 2021-8-1 16:55 | 只看该作者
测试时,背景图片与后面的ICO透明图标都在一个图层上面显示

BMP_Show("C:\\system\\BL01.bmp", pLTDC_Layer1_GRAM_HANDLE, 0, 0, 0, 0, &pErrorStr);

ICO_Show("C:\\256x256.ico", pLTDC_Layer1_GRAM_HANDLE, 1, 1, 256, 256, &pErrorStr);

2个图片都是显示在LTDC_Layer1上,下面是开发板效果

这个是PC端,使用win32调用软件接口,效果与F7硬件DMA2D效果完全一致.


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

83

主题

3896

帖子

2

粉丝