【Android SDM660源码分析】- 03 - UEFI XBL GraphicsOutput BMP图片显示流程

  • 1. GraphicsOutput.h
  • 2. 显示驱动初化 DisplayDxe.c
    • 2.1 获得所有支持的屏 Display_ABL_Initialize()
      • 2.1.1 解析屏列表,并配置全局变量 CheckTargetPanelSupport()
    • 2.2 显示屏初始化 MDPInit()
    • 2.3 上电 MDPPower()
    • 2.4 解析XML,生成字符串发送给ABL中 MDPDetect(MDP_DISPLAY_PRIMARY, &sDetectParams, 0x0)
    • 2.5 配置屏幕显示模式 DisplayDxeSelectMode()
    • 2.6 使能主屏显示prop属性MDPSetProperty()
    • 2.7 注册显示相关的服务 InstallMultipleProtocolInterfaces()
  • 3. 显示图片函数分析 DisplayDxe_Blt

系列文章:

  1. 《【Android SDM660开机流程】- UEFI XBL 代码流程分析》
  2. 《【Android SDM660源码分析】- 01 - 如何创建 UEFI XBL Protocol DXE_DRIVER 驱动及UEFI_APPLICATION 应用程序》
  3. 《【Android SDM660源码分析】- 02 - UEFI XBL QcomChargerApp充电流程代码分析》
  4. 《【Android SDM660源码分析】- 03 - UEFI XBL GraphicsOutput BMP图片显示流程》
  5. 《【Android SDM660源码分析】- 04 - UEFI ABL LinuxLoader 代码分析》

在前面充电流程中,我们看到了显示BMP图片这一块,本文来分析下BMP图片的显示流程。

显示图片的驱动GUUID为 gEfiGraphicsOutputProtocolGuid ,它定义在

# amss/BOOT.XF.1.4/boot_images/MdePkg/MdePkg.dec## Include/Protocol/GraphicsOutput.hgEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }}# amss/BOOT.XF.1.4/boot_images/MdePkg/Include/Protocol/GraphicsOutput.h
#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \{ \0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } \}
typedef struct _EFI_GRAPHICS_OUTPUT_PROTOCOL EFI_GRAPHICS_OUTPUT_PROTOCOL;

其对应的模块为:amss/BOOT.XF.1.4/boot_images/QcomPkg/Drivers/DisplayDxe

# amss/BOOT.XF.1.4/boot_images/QcomPkg/Sdm660Pkg/LA/Sdm660Pkg.fdf# Display/MDP DXE driverINF QcomPkg/Drivers/DisplayDxe/DisplayDxe.inf# amss/BOOT.XF.1.4/boot_images/QcomPkg/Sdm660Pkg/LA/Sdm660Pkg_Core.dsc# Display DXE DriverQcomPkg/Drivers/DisplayDxe/DisplayDxe.inf# amss/BOOT.XF.1.4/boot_images/QcomPkg/Sdm660Pkg/LA/Apriori.fdf.incINF QcomPkg/Drivers/DisplayDxe/DisplayDxe.inf

1. GraphicsOutput.h

gEfiGraphicsOutputProtocolGuid所对应的结构体为:_EFI_GRAPHICS_OUTPUT_PROTOCOL

# amss/BOOT.XF.1.4/boot_images/MdePkg/Include/Protocol/GraphicsOutput.hstruct _EFI_GRAPHICS_OUTPUT_PROTOCOL {EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE  QueryMode;EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE    SetMode;EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT         Blt;/// Pointer to EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE data.EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE        *Mode;
};
extern EFI_GUID gEfiGraphicsOutputProtocolGuid;

2. 显示驱动初化 DisplayDxe.c

DisplayDxe/DisplayDxe.inf 中我们可以知道,入口函数为:DisplayDxeInitialize
其主要工作流程为:

  1. 注册回调函数,当退出UEFI是,会调用 DisplayDxeExitBootServicesEvent 函数,释放相关的资源
  2. 创建回调函数,当需要显示是,发送这个时间,就会调用 UIActiveEventCallBack,给屏幕上电。
  3. 创建回调函数,收到这个事件是,会调用回调函数UIIdleEventCallBack,给屏幕下电,关闭显示
  4. 初始化ABL上下文,获得所有支持的屏
  5. 显示屏初始化
  6. 如果配置了MDP_DISPLAY_PRIMARY,则上电,检测屏幕是否存在,配置屏幕显示模式,使能主屏显示prop属性
  7. 如果配置了MDP_DISPLAY_EXTERNAL ,同样开始上电检测、配置屏幕显示模式
  8. 初始化显示 pix format 相关信息
  9. 注册显示屏相关的GUUID 服务
# amss/BOOT.XF.1.4/boot_images/QcomPkg/Drivers/DisplayDxe/DisplayDxe.cEFI_STATUS EFIAPI DisplayDxeInitialize(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
{// 1. 注册回调函数,当退出UEFI是,会调用 DisplayDxeExitBootServicesEvent 函数,释放相关的资源/* Register for an ExitBootServicesEvent */gBS->CreateEvent(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, DisplayDxeExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);/* Register for BlockIoRefreshEvent */gBS->CreateEventEx(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, BlockIoCallback, NULL, &gBlockIoRefreshGuid, &gBlockIoRefreshEvt);// 2. 创建回调函数,当需要显示是,发送这个时间,就会调用 UIActiveEventCallBack,给屏幕上电。/* Create and Register for UI_Active Event*/gBS->CreateEventEx(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, UIActiveEventCallBack, NULL, &UIActiveEventGuid, &gModeInfo.UIActiveEvent);// 3. 创建回调函数,收到这个事件是,会调用回调函数UIIdleEventCallBack,给屏幕下电,关闭显示/* Create and Register for UI_Idle Event*/gBS->CreateEventEx(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, UIIdleEventCallBack, NULL, &UIIdleEventGuid, &gModeInfo.UIIdleEvent);// 4. 初始化ABL上下文,获得所有支持的屏// Initialize Apps BootLoader (ABL) interface// It checks for panel override, if any, set by ABL and sets up parameters which will be used by MDPInitMDPSetProperty(MDP_DISPLAY_PRIMARY, MDP_DISPLAY_PROPERTY_ABL_INTERFACE_INIT, NULL);==========>Display_ABL_Initialize();// 5. 显示屏初始化// Initialize the MDP MDPInit(&sInitParam, 0x0);//// Main Display ////// 6. 如果配置了MDP_DISPLAY_PRIMARY// If the primary is supported initialize itif (TRUE == sInitParam.aSupportedDisplays[MDP_DISPLAY_PRIMARY]){// 6.1 上电MDPPower(MDP_DISPLAY_PRIMARY, &sPowerParams, 0x0);// 6.2 检测默认配置的屏幕是否存在// Default reporting of primary displayif (MDP_STATUS_OK != MDPDetect(MDP_DISPLAY_PRIMARY, &sDetectParams, 0x0)){eStatus = EFI_DEVICE_ERROR;}else if (TRUE == sDetectParams.bDisplayDetected){ // 6.3 配置屏幕显示模式eStatus = DisplayDxeSelectMode(MDP_DISPLAY_PRIMARY, &sDetectParams);// 6.4 使能主屏显示prop属性 Set the primary display to on MDPSetProperty(MDP_DISPLAY_PRIMARY, MDP_DISPLAY_PROPERTY_POWER_STATE, &sDisplayProp)}}}    // 7. 拓展屏初始化,如果存在 MDP_DISPLAY_EXTERNAL 对应的屏幕,则开始上电检测、配置模式//// External Display ////// If the external is supported initialize it,if ((EFI_SUCCESS == eStatus) && (TRUE == sInitParam.aSupportedDisplays[MDP_DISPLAY_EXTERNAL])){MDPPower(MDP_DISPLAY_EXTERNAL, &sPowerParams, 0x0);// Default reporting of External displayif ((MDP_STATUS_OK != MDPDetect(MDP_DISPLAY_EXTERNAL, &sDetectParams, 0x0)) || (FALSE == sDetectParams.bDisplayDetected)){// External display not detected, turn off and continue onsPowerParams.bPowerOn = FALSE;if (MDP_STATUS_OK != MDPPower(MDP_DISPLAY_EXTERNAL, &sPowerParams, 0x0)){DEBUG ((EFI_D_INFO, "DisplayDxe: External panel power up failed!\n"));   }}else{eStatus = DisplayDxeSelectMode(MDP_DISPLAY_EXTERNAL,&sDetectParams);// Set the external display to on if (MDP_STATUS_OK != MDPSetProperty(MDP_DISPLAY_EXTERNAL, MDP_DISPLAY_PROPERTY_POWER_STATE, &sDisplayProp)){eStatus = EFI_DEVICE_ERROR; }}}}// If we not have detected a valid mode on both primary and external display report errorif ((0 == gModeInfo.uNumModes[MDP_DISPLAY_PRIMARY]) && (0 == gModeInfo.uNumModes[MDP_DISPLAY_EXTERNAL])){eStatus = EFI_DEVICE_ERROR;}else{// 8. 初始化显示format相关信息。// Default at some dummy modegModeInfo.sCurrentModeInfo.Version                       = GRAPHICS_OUTPUT_PROTOCOL_REVISION;gModeInfo.sCurrentModeInfo.PixelFormat                   = DISPLAYDXE_DEFAULT_PIXEL_FORMAT;gModeInfo.sCurrentModeInfo.HorizontalResolution          = 0;gModeInfo.sCurrentModeInfo.VerticalResolution            = 0;gModeInfo.sCurrentModeInfo.PixelInformation.RedMask      = DISPLAYDXE_RED_MASK;gModeInfo.sCurrentModeInfo.PixelInformation.GreenMask    = DISPLAYDXE_GREEN_MASK;gModeInfo.sCurrentModeInfo.PixelInformation.BlueMask     = DISPLAYDXE_BLUE_MASK;gModeInfo.sCurrentModeInfo.PixelInformation.ReservedMask = DISPLAYDXE_ALPHA_MASK;gModeInfo.sCurrentModeInfo.PixelsPerScanLine             = 0;// Setup the protocol information, set the current mode to an invalid mode forcing a set modegModeInfo.sProtocolInfo.MaxMode    = 1;gModeInfo.sProtocolInfo.Mode       = (UINT32)-1;gModeInfo.sProtocolInfo.SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);gModeInfo.sProtocolInfo.Info       = &gModeInfo.sCurrentModeInfo;// 9. 注册显示屏相关的GUUID 服务// Install display protocols only if panel is detected.// Make a new handle with EFI Graphics ProtocolgBS->InstallMultipleProtocolInterfaces (&hUEFIDisplayHandle, &gEfiDevicePathProtocolGuid, &DisplayDevicePath,&sOutputGUID,&gDisplayDxeOutputProtocol,&gQcomDisplayPwrCtrlProtocolGuid,&gDisplayPwrCtrlProtocolImplementation,&gEfiDisplayPowerStateProtocolGuid,&gDisplayPwrProtocolImplementation,&gQcomDisplayABLProtocolGuid,&gQcomDisplayABLProtocolImplementation,NULL);return eStatus;
}

2.1 获得所有支持的屏 Display_ABL_Initialize()

  1. 获得全局变量 Display_ABLContextType gsABLContext
  2. 清空结构体 gsABLContext
  3. 获取所有支持的 display panels 列表
  4. 检查 ABL中是否有配置覆盖
# amss/BOOT.XF.1.4/boot_images/QcomPkg/Library/MDPLib/DisplayABLInterface.c
void Display_ABL_Initialize(void)
{ // 1. 获得全局变量 Display_ABLContextType gsABLContextDisplay_ABLContextType *pABLContext = GET_ABL_CONTEXT();MDP_OSAL_DELAYMS(100);// 2. 清空结构体 gsABLContextMDP_OSAL_MEMZERO(pABLContext, sizeof(Display_ABLContextType));// 3. 获取所有支持的 display panels 列表/* get list of supported panels & build DT info array */CheckTargetPanelSupport();// 4. 检查 ABL中是否有配置覆盖 /* Check panel override */CheckPanelOverride();
}
2.1.1 解析屏列表,并配置全局变量 CheckTargetPanelSupport()
  1. 获取gPanelList数组,保存在psPanelDTInfo中,
    从头文件#include "MDPPlatformLib.h"可以看出,调用的是 /MDPPlatformLibBoot/MDPPlatformLib.c 中的代码
  2. 解析屏幕列表
  3. 使用 QcomTokenSpace GUID 配置全局变量: DisplaySupportedPanelCount
  4. 使用 QcomTokenSpace GUID 配置全局变量: DisplaySupportedPanelList
# amss/BOOT.XF.1.4/boot_images/QcomPkg/Library/MDPLib/DisplayABLInterface.c
/****************************************************************************
*   Helper function to query Platform Lib for a list of supported panels and
*   set boot service variables to inform ABL
****************************************************************************/
static void CheckTargetPanelSupport()
{MDPPlatformParams       sPlatformParams;// 1. 获取gPanelList数组,保存在psPanelDTInfo中,从头文件#include "MDPPlatformLib.h"可以看出,调用的是 /MDPPlatformLibBoot/MDPPlatformLib.c 中的代码MDPPlatformConfigure(MDP_DISPLAY_PRIMARY, MDPPLATFORM_CONFIG_GETPANELDTINFO, &sPlatformParams);========>  pPlatformParams->psPanelDTInfo = (PanelInfoType*)&gPanelList;<========// CHAR8 *pPanels     = pABLContext->pSupportedPanels;CHAR8 *szSeparator = ",";uint32 uPanelCount = 0;PanelInfoType *psPanelDTInfo = sPlatformParams.psPanelDTInfo;/* The received panel list is sorted by panel IDs Go through the panel mapping to lookup names. */while (MDPPLATFORM_PANEL_NONE != psPanelDTInfo[uPanelCount].ePanel){if (0 < uPanelCount)LocalAsciiStrnCat(pPanels, PANEL_LIST_STR_LEN_MAX, szSeparator);  /* separator *//* append it to string */LocalAsciiStrnCat(pPanels, PANEL_LIST_STR_LEN_MAX, (CHAR8*)psPanelDTInfo[uPanelCount].name);uPanelCount++;}/* Save Panel DT info to ABL Context */pABLContext->pDTInfoArray = psPanelDTInfo;// 2. 使用 QcomTokenSpace GUID 配置全局变量: DisplaySupportedPanelCounteStatus = MDP_SetBootServiceVariable(DISPVAR_SUPPORTED_PANEL_COUNT, &uPanelCount, sizeof(uPanelCount), 0);// 3. 使用 QcomTokenSpace GUID 配置全局变量: DisplaySupportedPanelListeStatus = MDP_SetBootServiceVariable(DISPVAR_SUPPORTED_PANEL_LIST, pPanels, AsciiStrSize(pPanels), 0);
}

在gPanelList 中保存了当前所支持的所有屏信息列表,从gPanelList 中可以解析出屏相关的配置信息,如下所示:

# amss/BOOT.XF.1.4/boot_images/QcomPkg/Sdm660Pkg/Library/MDPPlatformLib/MDPPlatformLib.c
/* DT info for panels*/
const PanelInfoType gPanelList[] =
{/*Supported Panels*/  /* Truly HX8399 fhd video */PANEL_CREATE_ENTRY("hx8399_truly_fhd_video",     MDPPLATFORM_PANEL_HX8399_TRULY_FHD_VIDEO,      "qcom,mdss_dsi_hx8399_truly_fhd_video",        DISP_INTF_DSI, Truly_HX8399_FHD_video_xmldata,        DISP_TOPOLOGY_CONFIG_0,    PLL_OVERRIDE_NONE, DISP_MODE_SINGLE_DSI,                              DISP_MODE_SINGLE_DSI,                            DISP_MODE_SINGLE_DSI), 省略一大部分屏信息 /*Skip mode only panels, SW render in UEFI*//*Sharp 2k video*/PANEL_CREATE_ENTRY("nt35597_wqxga_dualdsi_video", MDPPLATFORM_PANEL_NT35597_WQHD_DUALDSI_VIDEO,   "qcom,mdss_dsi_nt35597_wqxga_video",     DISP_INTF_DSI, NULL,                                  DISP_TOPOLOGY_CONFIG_NONE, PLL_OVERRIDE_NONE, DISP_MODE_DUAL_DSI   | DISP_MODE_SKIP_BOOTLOADER,  DISP_MODE_DUAL_DSI   | DISP_MODE_SKIP_BOOTLOADER,     DISP_MODE_DUAL_DSI   | DISP_MODE_SKIP_BOOTLOADER),
};

2.2 显示屏初始化 MDPInit()

  1. 分配 DSI 和 I2C 相关的缓存内存资源
  2. 检查是否配置了bSWRender 软件渲染,
  3. 如果没有配置,则获取平台信息,是硬件初始化
  4. 检查再ABL中是否有对屏幕配置覆盖,或者是否支持 硬件屏幕,判断条见为 gPanelList 数组内容是否为空
  5. 初始化 MDP HAL,配置 MMU
  6. 如果不支持硬件屏幕,或者屏幕检测失败,则配置为软件渲染
# amss/BOOT.XF.1.4/boot_images/QcomPkg/Library/MDPLib/MDPLib.c
/* This function will perform the basic initialization and detection of the MDP core */
MDP_Status  MDPInit(MDP_InitParamsType *pMDPInitParams, uint32 uFlags)
{// 1. 分配 DSI 和 I2C 相关的缓存内存资源gpDSIInitSequenceBuffer = (uint8*)MDP_OSAL_CALLOC(MDP_DSI_COMMAND_BUFFER_SIZE);gpDSITermSequenceBuffer = (uint8*)MDP_OSAL_CALLOC(MDP_DSI_COMMAND_BUFFER_SIZE);gpDSIDscPpsBuffer = (uint8*)MDP_OSAL_CALLOC(MDP_DSI_DSC_PPS_TOTAL_PACKET_SIZE);gpI2CInitSequenceBuffer = (uint8*)MDP_OSAL_CALLOC(MDP_I2C_COMMAND_BUFFER_SIZE);gpI2CTermSequenceBuffer = (uint8*)MDP_OSAL_CALLOC(MDP_I2C_COMMAND_BUFFER_SIZE);// 2. 检查是否配置了bSWRender 软件渲染,MDPPlatformConfigure(MDP_DISPLAY_PRIMARY, MDPPLATFORM_CONFIG_SW_RENDERER, &sPlatformParams);// 3. 如果没有配置,则获取平台信息,是硬件初始化// Start hardware initialization, fall back to SW renderer in this path if key hardware functions failif (FALSE == bSWRender){//Get the platform Chip ID and catch in gsMDPHwPrivateInfoif (MDP_STATUS_OK == (eStatus = MDPPlatformConfigure(MDP_DISPLAY_PRIMARY, MDPPLATFORM_CONFIG_GETPLATFORMINFO, &sPlatformParams))){psMDPHwPrivateInfo->sEFIChipSetId     = sPlatformParams.sPlatformInfo.sEFIChipSetId;psMDPHwPrivateInfo->sEFIChipSetFamily = sPlatformParams.sPlatformInfo.sEFIChipSetFamily;psMDPHwPrivateInfo->eEFIPlatformInfo  = sPlatformParams.sPlatformInfo.sEFIPlatformType.platform;}// 4. 检查再ABL中是否有对屏幕配置覆盖,或者是否支持 硬件屏幕,判断条见为 gPanelList 数组内容是否为空// Hardware pathDisplay_ABL_CheckPanelSkip();//Set MDSS base addressMDPPlatformSetMdssBase(sPlatformParams.sPlatformInfo.sEFIChipSetFamily);// 5. 初始化 MDP HAL,配置 MMUHAL_MDP_Init(NULL, DEAFAULT_MDP_INIT_FLAGS)// Initialize the HW private info MDPInitHwPrivateInfo(psMDPHwPrivateInfo);HAL_MDP_TrafficCtrl_Init(NULL, 0);// Hardware detected// - Setup based on the hardware configuration              // Populate the input parameterspMDPInitParams->uMDPVersionMajor    = psMDPHwPrivateInfo->sMDPVersionInfo.uMajorVersion;pMDPInitParams->uMDPVersionMinor    = psMDPHwPrivateInfo->sMDPVersionInfo.uMinorVersion;pMDPInitParams->uMDPVersionRevision = psMDPHwPrivateInfo->sMDPVersionInfo.uReleaseVersion;//For continuous splash feature, since frame buffer memory is shared between UEFI//and kernel, the MMU context need to be updated to enable sharingMDP_SetupMMUSIDs(pMDPInitParams->uMDPVersionMajor,pMDPInitParams->uMDPVersionMinor);// Find the supported displays MDP_OSAL_MEMZERO(&pMDPInitParams->aSupportedDisplays, sizeof(pMDPInitParams->aSupportedDisplays));pMDPInitParams->aSupportedDisplays[MDP_DISPLAY_PRIMARY]  = TRUE;pMDPInitParams->aSupportedDisplays[MDP_DISPLAY_EXTERNAL] = FALSE;// Check the external display configuration.if (ExtDisp_SupportedByPlatform(&sExtDispAttr)){gDisplayInfo[MDP_DISPLAY_EXTERNAL].ePhysConnect          = sExtDispAttr.ePhysConnect;                pMDPInitParams->aSupportedDisplays[MDP_DISPLAY_EXTERNAL] = TRUE;}// If DISABLEDISPLAY variable is set, then disable primary display// Note: Make sure to check if external display is supported before proceedingif(TRUE == pMDPInitParams->aSupportedDisplays[MDP_DISPLAY_EXTERNAL]){if(TRUE == MDPPlatformGetDisableDisplay()){// DISABLEDISPLAY variable is set. Disable primary displaypMDPInitParams->aSupportedDisplays[MDP_DISPLAY_PRIMARY]  = FALSE;}}}// 6. 如果不支持硬件屏幕,或者屏幕检测失败,则配置为软件渲染// Platform is configured for SW renderer, or hardware detection failedif (TRUE == bSWRender){// Populate the input parameterspMDPInitParams->uMDPVersionMajor    = 0;pMDPInitParams->uMDPVersionMinor    = 0;pMDPInitParams->uMDPVersionRevision = 0;// Fix the supported displays to just primaryMDP_OSAL_MEMZERO(&pMDPInitParams->aSupportedDisplays, sizeof(pMDPInitParams->aSupportedDisplays));pMDPInitParams->aSupportedDisplays[MDP_DISPLAY_PRIMARY]  = TRUE;pMDPInitParams->aSupportedDisplays[MDP_DISPLAY_EXTERNAL] = FALSE;// Tell platform layer we are in SW render mode to by pass any hardware configurationMDP_OSAL_MEMZERO(&sPlatformParams, sizeof(MDPPlatformParams));sPlatformParams.sPlatformInfo.bSWRenderOverrride = TRUE;MDPPlatformConfigure(MDP_DISPLAY_PRIMARY, MDPPLATFORM_CONFIG_SW_RENDERER, &sPlatformParams);        }return eStatus;
}

2.3 上电 MDPPower()

MDPPower() 中的逻辑比较简单,根据pMDPPowerParams->bPowerOn 来决定是上电还是下电。

MDP_Status  MDPPower(MDP_Display_IDType eDisplayId, MDP_PowerParamsType *pMDPPowerParams, uint32 uFlags)
{Display_ABL_CheckPanelSkip();if (TRUE == pMDPPowerParams->bPowerOn){// Power up the respective displaysMDPPlatformConfigure(eDisplayId, MDPPLATFORM_CONFIG_POWERUP, NULL);}else if (FALSE == pMDPPowerParams->bPowerOn){// Power down the respective displaysMDPPlatformConfigure(eDisplayId, MDPPLATFORM_CONFIG_POWERDOWN, NULL);}MDP_LOG_FUNC_EXIT("MDPPower()");    return eStatus;
}

2.4 解析XML,生成字符串发送给ABL中 MDPDetect(MDP_DISPLAY_PRIMARY, &sDetectParams, 0x0)

  1. 获取到屏幕的 xml 信息,解析 xml
  2. 配置屏相关的参数
  3. 更新屏幕信息到 ABL 中
    拼接字符串,示例如: 0:dsi:0:qcom,mdss_dsi_nt35597_wqxga_video:dsi:1:qcom,mdss_dsi_nt35597_wqxga_video:config0
    将字符串 通过 QcomTokenSpace GUID 保存起来,供 ABL 中使用
# amss/BOOT.XF.1.4/boot_images/QcomPkg/Library/MDPLib/MDPLib.c
MDP_Status  MDPDetect(MDP_Display_IDType eDisplayId, MDP_DetectParamType *pMDPDetectParams, uint32 uFlags )
{// Handle each displayswitch (eDisplayId){case MDP_DISPLAY_PRIMARY:{MDPDetectPanel(eDisplayId, pDisplayInfo);=================>// 1. 获取到屏幕的 xml 信息,解析 xmlMDPPlatformConfigure(eDisplayId, MDPPLATFORM_CONFIG_GETPANELCONFIG, &sPlatformParams);XML_Parser(sPlatformParams.sPlatformPanel.pPanelXMLConfig, sPlatformParams.sPlatformPanel.uConfigSize, sXmlTagsList, XML_TAGSLIST_LENGTH);<==================pMDPDetectParams->bDisplayDetected          = pDisplayInfo->bDetected;pMDPDetectParams->uSupportedModes           = 1; // Only 1 mode is supportedpMDPDetectParams->aModeList[0].bInterlaced  = FALSE;pMDPDetectParams->aModeList[0].uModeIndex   = 0;pMDPDetectParams->aModeList[0].uWidth       = pDisplayInfo->uDisplayWidth;pMDPDetectParams->aModeList[0].uHeight      = pDisplayInfo->uDisplayHeight;eSelectedPanel                              = pDisplayInfo->eSelectedPanel;switch (pDisplayInfo->ePhysConnect){case MDP_DISPLAY_CONNECT_PRIMARY_DSI_VIDEO:case MDP_DISPLAY_CONNECT_PRIMARY_DSI_CMD:case MDP_DISPLAY_CONNECT_SECONDARY_DSI_VIDEO:case MDP_DISPLAY_CONNECT_SECONDARY_DSI_CMD:                pMDPDetectParams->aModeList[0].uRefreshRate = pDisplayInfo->uAttrs.sDsi.uRefreshRate;/* If DSC is enable setup MDP structures for DSC */// 2. 配置屏相关的参数MDPSetupDSCProperty(pDisplayInfo);break;}case MDP_DISPLAY_EXTERNAL:{MDPDetectExtPlugin(pDisplayInfo);// DP detected pDisplayInfo->bDetected            = TRUE;pDisplayInfo->uNumInterfaces       = MDP_INTERFACE_SINGLE;MDPDetectParams->bDisplayDetected = TRUE;// Enumerate all modesfor (i=0;i<MDP_DISPLAY_MAX_MODES;i++){MDP_OSAL_MEMZERO(&sMode, sizeof(MDP_Panel_AttrType));if (MDP_STATUS_OK == ExtDisp_GetModeInfo(i, &sMode)){pMDPDetectParams->aModeList[i].uModeIndex   = i;pMDPDetectParams->aModeList[i].uWidth       = sMode.uDisplayWidth;pMDPDetectParams->aModeList[i].uHeight      = sMode.uDisplayHeight;pMDPDetectParams->aModeList[i].uRefreshRate = sMode.uRefreshRate;                      pMDPDetectParams->aModeList[i].bInterlaced  = FALSE; pMDPDetectParams->uSupportedModes++;}}}}break;}}// 3. 更新屏幕信息到 ABL 中//Update ABL with selected panel infoDisplay_ABL_SetPanelConfiguration(eSelectedPanel);===========>// 3.1 拼接字符串,示例如: 0:dsi:0:qcom,mdss_dsi_nt35597_wqxga_video:dsi:1:qcom,mdss_dsi_nt35597_wqxga_video:config0UpdatePanelConfiguration(eSelected, pConfigStr);// 3.2 将字符串 通过 QcomTokenSpace GUID 保存起来,供 ABL 中使用MDP_SetBootServiceVariable(DISPVAR_PANEL_CONFIGURATION, pConfigStr, AsciiStrLen(pConfigStr)+1, 0)<===========MDP_LOG_FUNC_EXIT("MDPDetect()");    return eStatus;
}

2.5 配置屏幕显示模式 DisplayDxeSelectMode()

这个函数没啥好看,就是配置显示模式,最大16种。
每种显示模式对应着不同的分辨率,刷新率等。

# amss\BOOT.XF.1.4\boot_images\QcomPkg\Drivers\DisplayDxe\DisplayDxe.c
/** DisplayDxeSelectModeDisplay DXE Local function to select the mode out of supported modes **/
static EFI_STATUS DisplayDxeSelectMode(MDP_Display_IDType eDisplayId, MDP_DetectParamType  *pDisplayModes)
{// Handle each displayswitch (eDisplayId){//For Primary only 1 mode is supported, case MDP_DISPLAY_PRIMARY:gModeInfo.uSelectedModeIndex[eDisplayId] = 0 ;break;// Select the largest mode out of the list of supported modes available on the external monitorcase MDP_DISPLAY_EXTERNAL:{MDP_ModeInfo *pMaxMode = &pDisplayModes->aModeList[0];//Auto Select the largest mode// We loop through the list to find the largest mode for (uI = 1; uI < pDisplayModes->uSupportedModes; uI++){// Largest Modeif ((pMaxMode->uWidth < pDisplayModes->aModeList[uI].uWidth) &&(pMaxMode->uHeight < pDisplayModes->aModeList[uI].uHeight)){pMaxMode = &pDisplayModes->aModeList[uI];uLargestModeIndex = uI;}}gModeInfo.uSelectedModeIndex[eDisplayId] = uLargestModeIndex;}else           {uint32 uWidth  = uExtModePCD & 0xFFFF;uint32 uHeight = (uExtModePCD>>16) & 0xFFFF;gModeInfo.uSelectedModeIndex[eDisplayId] = MDP_DISPLAY_MAX_MODES;// We loop through the list to find the match for (uI = 0; uI < pDisplayModes->uSupportedModes; uI++){if ((uWidth  ==  pDisplayModes->aModeList[uI].uWidth) &&(uHeight ==  pDisplayModes->aModeList[uI].uHeight)){gModeInfo.uSelectedModeIndex[eDisplayId] = uI;break;}}if (MDP_DISPLAY_MAX_MODES == gModeInfo.uSelectedModeIndex[eDisplayId]){gModeInfo.uSelectedModeIndex[eDisplayId] = 0;DEBUG((EFI_D_INFO, "DisplayDxe: Failed to override the External panel mode!\n"));}}}break;}if (EFI_SUCCESS == Status){MDP_PropertiesParamType               sDisplayProp;      UINT32                                uResLimitIndex     = (PcdGet32(PcdFrameBufMaxRes) < DISPLAY_FB_RES_MAX)?PcdGet32(PcdFrameBufMaxRes):0;EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *pMode              = &gModeInfo.sModeList[eDisplayId][0];UINT32                                uSelectedModeIndex = gModeInfo.uSelectedModeIndex[eDisplayId];// Set the Selected Mode index //(MDPlib checks if it needs dual pipe and for external monitor also sets the active timing information for this mode MDP_OSAL_MEMZERO(&sDisplayProp, sizeof(MDP_PropertiesParamType));sDisplayProp.sModeParams.uModeIndex = uSelectedModeIndex;MDPSetProperty(eDisplayId, MDP_DISPLAY_PROPERTY_MODE_INFO, &sDisplayProp);// Update global Mode InformationpMode->Version                              = GRAPHICS_OUTPUT_PROTOCOL_REVISION;pMode->PixelFormat                          = DISPLAYDXE_DEFAULT_PIXEL_FORMAT;pMode->HorizontalResolution                 = pDisplayModes->aModeList[uSelectedModeIndex].uWidth;pMode->VerticalResolution                   = pDisplayModes->aModeList[uSelectedModeIndex].uHeight;// Limit the frame buffer allocation as specified by PcdFrameBufMaxRes, frame buffer will be letterboxed in to the larger resolution panelif ((pDisplayModes->aModeList[uSelectedModeIndex].uWidth * pDisplayModes->aModeList[uSelectedModeIndex].uHeight) >(gFBResLimit[uResLimitIndex].uWidth * gFBResLimit[uResLimitIndex].uHeight)){// Portrait mode panel if (pDisplayModes->aModeList[uSelectedModeIndex].uHeight > pDisplayModes->aModeList[uSelectedModeIndex].uWidth){// Clamp the width to Max height and height to Max Width to maintain the portrait aspect ratio pMode->HorizontalResolution  = gFBResLimit[uResLimitIndex].uHeight;  pMode->VerticalResolution    = gFBResLimit[uResLimitIndex].uWidth;}// Landscape mode panelelse{pMode->HorizontalResolution = gFBResLimit[uResLimitIndex].uWidth;pMode->VerticalResolution   = gFBResLimit[uResLimitIndex].uHeight;}DEBUG ((EFI_D_INFO, "DisplayDxe: Frame buffer allocation limited to %dix%d\n", pMode->HorizontalResolution, pMode->VerticalResolution));            }pMode->PixelInformation.RedMask             = DISPLAYDXE_RED_MASK;pMode->PixelInformation.GreenMask           = DISPLAYDXE_GREEN_MASK;pMode->PixelInformation.BlueMask            = DISPLAYDXE_BLUE_MASK;pMode->PixelInformation.ReservedMask        = DISPLAYDXE_ALPHA_MASK;pMode->PixelsPerScanLine                    = pMode->HorizontalResolution;gModeInfo.uNumModes[eDisplayId]++;}}return Status;
}

2.6 使能主屏显示prop属性MDPSetProperty()

MDPSetProperty(MDP_DISPLAY_PRIMARY, MDP_DISPLAY_PROPERTY_POWER_STATE, &sDisplayProp)

传入的sDisplayProp ,其结构体为:

/* * MDPProperty Parameters*/
typedef union
{uint32                uBacklightLevel;           /* MDP_DISPLAY_PROPERTY_BACKLIGHT */bool32                bDisplayPwrState;          /* MDP_DISPLAY_PROPERTY_POWER_STATE */bool32                bDisplayDetected;          /* MDP_DISPLAY_PROPERTY_DETECTION_INFO */ MDP_SetModeParamType  sModeParams;               /* MDP_DISPLAY_PROPERTY_MODE_INFO */
} MDP_PropertiesParamType;

包含了 背光等级,电源开关,模式索引等信息。

我们来进函数看下,本次传入的是 MDP_DISPLAY_PROPERTY_POWER_STATE,
可以看出,就是执行了 pDisplayInfo->bDisplayPwrState = pMDPPropertiesParams->bDisplayPwrState; 这句话。

MDP_Status  MDPSetProperty(MDP_Display_IDType eDisplayId, MDP_Display_Property eProperty, MDP_PropertiesParamType *pMDPPropertiesParams)
{MDP_Panel_AttrType  *pDisplayInfo = MDP_GET_DISPLAYINFO(eDisplayId);switch (eProperty){case MDP_DISPLAY_PROPERTY_BACKLIGHT:{MDPPlatformParams  sPlatformParams;// Setup any other display parametersMDP_OSAL_MEMZERO(&sPlatformParams, sizeof(MDPPlatformParams));sPlatformParams.sBacklightConfig.bEnable                        = TRUE;sPlatformParams.sBacklightConfig.eBacklightType                 = pDisplayInfo->eBacklightType;sPlatformParams.sBacklightConfig.uBacklightCntrl.eBacklightCtrl = pDisplayInfo->uBacklightCntrl.eBacklightCtrl;sPlatformParams.sBacklightConfig.uLevel                         = pMDPPropertiesParams->uBacklightLevel;if (MDP_STATUS_OK == (eStatus = MDPPlatformConfigure(eDisplayId, MDPPLATFORM_CONFIG_SETBACKLIGHT, &sPlatformParams))){// Cache current backlight levelpDisplayInfo->uBacklightLevel = pMDPPropertiesParams->uBacklightLevel;}}break;case MDP_DISPLAY_PROPERTY_FIRMWAREENV:{eStatus = MDP_SaveFirmwareEnvironmentVariable(eDisplayId);}break;  case MDP_DISPLAY_PROPERTY_MODE_INFO:{MDP_HwPrivateInfo *psMDPHwPrivateInfo = MDP_GETPRIVATEINFO();uint32             ModeIndex          =  pMDPPropertiesParams->sModeParams.uModeIndex;// External monitor supports more than one mode , store the mode info for the selected mode// For primary only one mode is supported and this information is populated at the detect timeswitch (eDisplayId){case MDP_DISPLAY_EXTERNAL:eStatus = ExtDisp_GetModeInfo(ModeIndex, pDisplayInfo);break;default:break;   }// Check if we need Dual pipe for this panelif ((NULL != psMDPHwPrivateInfo->pDeviceCaps) &&(pDisplayInfo->uDisplayWidth > psMDPHwPrivateInfo->pDeviceCaps->pResolutionCaps->uMaxLayerWidthPx)){pDisplayInfo->uNumMixers = MDP_DUALPIPE_NUM_MIXERS;}}break;case MDP_DISPLAY_PROPERTY_POWER_STATE:{/* Cache the current display power state information */pDisplayInfo->bDisplayPwrState  =  pMDPPropertiesParams->bDisplayPwrState;break;}case MDP_DISPLAY_PROPERTY_ABL_INTERFACE_INIT:{/* Initialize ABL context which will be used to create panel configuration string for ABL later */Display_ABL_Initialize();break;}}return eStatus;
}

2.7 注册显示相关的服务 InstallMultipleProtocolInterfaces()

在代码中,同时注册了好多个GUUID,接下来,我们一个个来看看:

gBS->InstallMultipleProtocolInterfaces (&hUEFIDisplayHandle, &gEfiDevicePathProtocolGuid,             &DisplayDevicePath,&sOutputGUID,                            &gDisplayDxeOutputProtocol,&gQcomDisplayPwrCtrlProtocolGuid,        &gDisplayPwrCtrlProtocolImplementation,&gEfiDisplayPowerStateProtocolGuid,      &gDisplayPwrProtocolImplementation,&gQcomDisplayABLProtocolGuid,            &gQcomDisplayABLProtocolImplementation,NULL);
  1. gEfiDevicePathProtocolGuid 对应 DisplayDevicePath
# amss/BOOT.XF.1.4/boot_images/MdePkg/Include/Protocol/DevicePath.h
// Device Path protocol
#define EFI_DEVICE_PATH_PROTOCOL_GUID \{ \0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} \}/* DisplayDXE Device path */
static EFI_DISPLAY_DEVICE_PATH DisplayDevicePath =
{{{HARDWARE_DEVICE_PATH,HW_VENDOR_DP,{(UINT8) (sizeof (VENDOR_DEVICE_PATH)),(UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)}},EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID},{ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {sizeof (EFI_DEVICE_PATH_PROTOCOL), 0}}
};
  1. sOutputGUID 对应 gDisplayDxeOutputProtocol
# amss/BOOT.XF.1.4/boot_images/MdePkg/Include/Protocol/GraphicsOutput.h
#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \{ \0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } \}# amss/BOOT.XF.1.4/boot_images/QcomPkg/Drivers/DisplayDxe/DisplayDxe.c
/* Function table pointer to the supported protocol functions */
static EFI_GRAPHICS_OUTPUT_PROTOCOL gDisplayDxeOutputProtocol = {&DisplayDxe_QueryMode,&DisplayDxe_SetMode,&DisplayDxe_Blt,&gModeInfo.sProtocolInfo
};
  1. gQcomDisplayPwrCtrlProtocolGuid 对应 gDisplayPwrCtrlProtocolImplementation,用于显示的电源控制
# amss/BOOT.XF.1.4/boot_images/QcomPkg/Drivers/DisplayDxe/DisplayPwrCtrlProtocol.c
/**Display power UEFI Protocol implementation*/
EFI_QCOM_DISPLAY_PWR_CTRL_PROTOCOL gDisplayPwrCtrlProtocolImplementation =
{DISPLAY_PWR_CTRL_REVISION,EFI_DisplayPanelPowerControl,EFI_DisplayPanelPowerStatus,EFI_DisplayBackLightBrightnessLevelControl,EFI_DisplayBackLightBrightnessLevelStatus,
};
  1. gEfiDisplayPowerStateProtocolGuid 对应 gDisplayPwrProtocolImplementation,用于获取电源状态
# amss/BOOT.XF.1.4/boot_images/QcomPkg/Drivers/DisplayDxe/DisplayPwrProtocol.c
/**Display power UEFI Protocol implementation*/
EFI_DISPLAY_POWER_PROTOCOL gDisplayPwrProtocolImplementation =
{EFI_DISPLAY_POWER_PROTOCOL_REVISION,EFI_DisplayPowerSetDisplayPowerState,EFI_DisplayPowerGetDisplayPowerState
};
  1. gQcomDisplayABLProtocolGuid 对应 gQcomDisplayABLProtocolImplementation
# amss/BOOT.XF.1.4/boot_images/QcomPkg/Library/MDPLib/DisplayABLInterface.c
EFI_QCOM_DISPLAY_ABL_PROTOCOL  gQcomDisplayABLProtocolImplementation =
{DISPLAY_ABL_REVISION,Display_ABL_SetProperty,Display_ABL_GetProperty,Display_ABL_RenderLogo,   //NOTE: Adding this to have same EFI_QCOM_DISPLAY_UTILS_PROTOCOL protocol APIs as on ABL side. Display_ABL_SetMode,      //NOTE: Adding this to have same EFI_QCOM_DISPLAY_UTILS_PROTOCOL protocol APIs as on ABL side. Display_ABL_SetVariable,Display_ABL_GetVariable
};

好,显示驱动实发始化差不多主就这些,对于调试驱动来说,需要配置如下

3. 显示图片函数分析 DisplayDxe_Blt

先来看下传入的参数:

  • This: 调用的模式驱动指针
  • BltBuffer:图片buffer 地址
  • BltOperation : 显示模式,如:EfiBltVideoFill填充,EfiBltVideoToBltBuffer,EfiBltBufferToVideo,EfiBltVideoToVideo
    本次传入的是 EfiBltBufferToVideo,意思是将图片做为video方式显示。
  • SourceX,SourceY: 源 buffer 的 x,y 坐标
  • DestinationX,DestinationY : 目标 buffer的x,y坐标
  • Width, Height 宽高
  • Delta : 一行的大小,值为 width x rgb(3byte)

DisplayDxe_Blt 函数的主要作用就是拷贝图片数据到 framebuffer中,数据为RGB格式,这样就能直接显示出来了。

  1. pSrcBuffer 指向图片buffer,pDstBuffer指向 framebuffer的地址。
  2. 数据从pSrcBuffer 拷贝到pDstBuffer中,宽、高、字节/每像素 赋值
  3. 拷贝图片数据
# amss\BOOT.XF.1.4\boot_images\QcomPkg\Drivers\DisplayDxe\DisplayDxe.c
/**Display DXE Protocol Blt function@param  This         Protocol instance pointer.@param  BltBuffer    Buffer containing data to blit into video buffer. Thisbuffer has a size of Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)@param  BltOperation Operation to perform on BlitBuffer and video memory@param  SourceX      X coordinate of source for the BltBuffer.@param  SourceY      Y coordinate of source for the BltBuffer.@param  DestinationX X coordinate of destination for the BltBuffer.@param  DestinationY Y coordinate of destination for the BltBuffer.@param  Width        Width of rectangle in BltBuffer in pixels.@param  Height       Hight of rectangle in BltBuffer in pixels.@param  Delta        OPTIONAL@retval EFI_SUCCESS           The Blt operation completed.@retval EFI_INVALID_PARAMETER BltOperation is not valid or source/destination parameters are invalid@retval EFI_DEVICE_ERROR      A hardware error occured writting to the video buffer.**/
EFI_STATUS
DisplayDxe_Blt (IN  EFI_GRAPHICS_OUTPUT_PROTOCOL            *This,IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer,IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,IN  UINTN                                   SourceX,IN  UINTN                                   SourceY,IN  UINTN                                   DestinationX,IN  UINTN                                   DestinationY,IN  UINTN                                   Width,IN  UINTN                                   Height,IN  UINTN                                   Delta)
{case EfiBltBufferToVideo:{// 1. pSrcBuffer 指向图片buffer,pDstBuffer指向 framebuffer的地址。UINT8 *pSrcBuffer = (UINT8*)BltBuffer;UINT8 *pDstBuffer = (UINT8*)DISPLAYDXE_PHYSICALADDRESS32(gModeInfo.sProtocolInfo.FrameBufferBase);UINTN SrcStride, DstStride, CopyWidth, CopyHeight;// 2. 数据从pSrcBuffer 拷贝到pDstBuffer中,宽、高、字节/每像素 赋值CopyWidth  = Width;CopyHeight = Height;/* Video buffer stride in bytes, consider padding as well */DstStride = gModeInfo.sCurrentModeInfo.PixelsPerScanLine * DISPLAYDXE_DEFAULT_BYTES_PER_PIXEL;/* Src buffer stride in bytes. Delta is valid when X or Y is not 0 */SrcStride = Width * DISPLAYDXE_DEFAULT_BYTES_PER_PIXEL;// 3. 拷贝图片数据DisplayDxeBltInternal (pSrcBuffer,pDstBuffer,SourceX, SourceY, CopyWidth,  CopyHeight,SrcStride,DestinationX, DestinationY,DstStride,DISPLAYDXE_DEFAULT_BYTES_PER_PIXEL);/* If display frame buffer is cached, need to call cache maintenance function */FlushStaleLines(pDstBuffer + (DstStride * DestinationY), (DstStride * CopyHeight));eStatus = EFI_SUCCESS;}break;case EfiBltVideoToBltBuffer:{  UINT8 *pDstBuffer = (UINT8*)BltBuffer;UINT8 *pSrcBuffer = (UINT8*)DISPLAYDXE_PHYSICALADDRESS32(gModeInfo.sProtocolInfo.FrameBufferBase);UINTN SrcStride, DstStride, CopyWidth, CopyHeight;CopyWidth  = Width;CopyHeight = Height;/* Video buffer stride in bytes, consider padding as well */SrcStride = gModeInfo.sCurrentModeInfo.PixelsPerScanLine * DISPLAYDXE_DEFAULT_BYTES_PER_PIXEL;/* Buffer stride in bytes. Delta is valid when X or Y is not 0 */DstStride = Width * DISPLAYDXE_DEFAULT_BYTES_PER_PIXEL;DisplayDxeBltInternal (pSrcBuffer,pDstBuffer,SourceX, SourceY, CopyWidth, CopyHeight,SrcStride,DestinationX,DestinationY,DstStride,DISPLAYDXE_DEFAULT_BYTES_PER_PIXEL);eStatus = EFI_SUCCESS;}break; }    }return eStatus;
}

从 DisplayDxeBltInternal() 中可以看出,它主要作用就是拷贝数据,很好理解

static void DisplayDxeBltInternal (UINT8   *pSrc,UINT8   *pDst,UINTN    uSrcX,UINTN    uSrcY,UINTN    uSrcWidth,UINTN    uSrcHeight,UINTN    uSrcStride,UINTN    uDstX,UINTN    uDstY,UINTN    uDstStride,UINTN    uBytesPerPixel)
{UINT32 uI = 0;UINT32 uSrcWidthBytes = uSrcWidth * uBytesPerPixel;  /* move src pointer to start of src rectangle */pSrc += (uSrcY * uSrcStride) + (uSrcX * uBytesPerPixel);/* move dest pointer to start of dest rectangle */pDst += (uDstY * uDstStride) + (uDstX * uBytesPerPixel); /* Blit Operation **  We use MDP_OSAL_MEMCPY which invokes Neon memcpy (kr_memcpy.asm) *  This memcpy supports overlapped src and dst buffers but copying may not be optimal in the overlap case */  for (uI = 0; uI < uSrcHeight; ++uI){MDP_OSAL_MEMCPY((void*)pDst, (void*)pSrc, uSrcWidthBytes);pDst += uDstStride;pSrc += uSrcStride;}
}

【Android SDM660源码分析】- 03 - UEFI XBL GraphicsOutput BMP图片显示流程相关推荐

  1. 【Android SDM660源码分析】- 02 - UEFI XBL QcomChargerApp充电流程代码分析

    [Android SDM660源码分析]- 02 - UEFI XBL QcomChargerApp充电流程代码分析 一.加载 UEFI 默认应用程序 1.1 LaunchDefaultBDSApps ...

  2. 【Android SDM660源码分析】- 01 - 如何创建 UEFI XBL Protocol DXE_DRIVER 驱动及UEFI_APPLICATION 应用程序

    [Android SDM660源码分析]- 01 - 如何创建 UEFI XBL Protocol DXE_DRIVER 驱动及UEFI_APPLICATION 应用程序 一.创建DXE_DRIVER ...

  3. 【Android SDM660源码分析】- 04 - UEFI ABL LinuxLoader 代码分析

    [Android SDM660源码分析]- 04 - UEFI ABL LinuxLoader 代码分析 1. LinuxLoader.c 系列文章: <[Android SDM660开机流程] ...

  4. Android HandlerThread 源码分析

    HandlerThread 简介: 我们知道Thread线程是一次性消费品,当Thread线程执行完一个耗时的任务之后,线程就会被自动销毁了.如果此时我们又有一 个耗时任务需要执行,我们不得不重新创建 ...

  5. Android ADB 源码分析(三)

    前言 之前分析的两篇文章 Android Adb 源码分析(一) 嵌入式Linux:Android root破解原理(二) 写完之后,都没有写到相关的实现代码,这篇文章写下ADB的通信流程的一些细节 ...

  6. Android 音频源码分析——AndroidRecord录音(一)

    Android 音频源码分析--AndroidRecord录音(一) Android 音频源码分析--AndroidRecord录音(二) Android 音频源码分析--AndroidRecord音 ...

  7. Android框架源码分析——从设计模式角度看 Retrofit 核心源码

    Android框架源码分析--从设计模式角度看 Retrofit 核心源码 Retrofit中用到了许多常见的设计模式:代理模式.外观模式.构建者模式等.我们将从这三种设计模式入手,分析 Retrof ...

  8. 人人网官方Android客户端源码分析(1)

    ContentProvider是不同应用程序之间进行数据交换的标准API,ContentProvider以某种Uri的形式对外提供数据,允许其他应用访问或修改数据;其他应用程序使用ContentRes ...

  9. 【SA8295P 源码分析】08 - XBL Loader 加载 SMSS、XBL Config、SHRM、CDT 、DDR、APDP、RamDump、OEM_MISC、AOP、QSEE过程分析

    [SA8295P 源码分析]08 - XBL Loader 加载 SMSS.XBL Config.SHRM.CDT .DDR.APDP.RamDump.OEM_MISC.AOP.QSEE Dev Co ...

最新文章

  1. LINQ to Entities 不识别方法“System.String ToString()”,因此该方法无法转换为存储表达式。...
  2. 释疑のSAP库位的创建
  3. java不用抽象类实现多态_原来你是这样的JAVA[03]-继承、多态、抽象类
  4. 讲oracle个阶段书籍6,经典图书推荐系列-之六
  5. CSS3 box-reflect 属性
  6. Css 特殊或不常用属性
  7. 单链表实现约瑟夫环(JosephCircle)(C语言)
  8. python selenium使用JS新建标签(new tab)与切换标签
  9. 苹果今年预计生产8000万部iPhone 12,多还是少?
  10. 分布式消息中间件之kafka设计思想及基本介绍(一)
  11. Starling 动画功能
  12. [转]oracle分页用两层循环还是三层循环?
  13. 手机号码正则_中国大陆手机号码的正则表达式总结ChinaMobilePhoneNumberRegex
  14. (十二)幸福之家 - 1
  15. 献给那些没有自信的人。
  16. 9ku音乐网音乐爬取,仅供交流~~
  17. 【论文笔记】CS会议论文书写注意点
  18. fuchsia学习_下载编译遇到问题和demo运行
  19. C# CheckBox/CheckedListBox 复选框/复选框列表
  20. J: Participate in E-sports [大数牛顿迭代判断是否是平方数]

热门文章

  1. 我的世界java边境之地_我的世界边境之地是否存在 我的世界边境之地大揭秘
  2. 达芬奇密码 第五十九章
  3. Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++ Build Tools“(已解决)
  4. uni-app 接入高德地图案例
  5. 商务英语基础: 口语 | Essential Business English: Speaking
  6. 助力武汉抗击疫情,湖北科研资料共享
  7. 后端框架的学习----mybatis框架(7、使用注解开发)
  8. 图书馆馆藏书籍管理功能
  9. 更新Android版GPS定位源代码
  10. Nginx安装及详细配置