8155平台multi-display(多屏显示)原理与配置

一,APP层

提供如下三种方法可以启动或者创建第二屏幕的显示。

1,APP创建时候设置displayid

应用层可以在activity创建的时候,调用setLaunchDisplayId(int) 来设置启动展示的id。

Display[] displays = displayManager.getDisplays();
Display targetDisplay = null;
for (Display display : displays) {
    if(xxxxx) {
        targetDisplay = display;
        break;
    }
    break;
}

@override
protected void onCreate(Bundle saveInstanceState) {
    super.onCreate(saveInstanceState);
    setContentView(XXXXX);
    setLaunchDisplayId(targetDisplay);
}

2, 在第二屏幕启动某个Activity

    public static Display getSecondDisplayId(Context context){
        DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
        Display[] displays = displayManager.getDisplays();
//        Display[] arrayOfDisplay = displayManager.getDisplays(DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC);
        return displays[1];
    }

        ActivityOptions options = ActivityOptions.makeBasic();
        options.setLaunchDisplayId(DisplayUtils.getSecondDisplayId(context).getDisplayId());
        Intent intent = new Intent(context,CommonOptionDialog.class);
        context.startActivity(intent,options.toBundle());

 3, 通过创建第二屏Context方法,获取第二屏windowManager

public class DisplayUtils {
    private Context mContext;
    private DisplayManager mDisplayManager;

    private ArrayList<Display> mAllDisplays = new ArrayList<>();

    public DisplayUtils(Context context) {
        mContext = context;
        mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
    }

    public ArrayList<String> getCurrentDisplays() {
        mAllDisplays.clear();
        ArrayList<String> allDisplays = new ArrayList<String>();
        Display[] displays = mDisplayManager.getDisplays();
        for (Display display : displays) {
            mAllDisplays.add(display);
            allDisplays.add("Display " + display.getDisplayId() + " : " + display.getName());
        }
        return allDisplays;
    }

    //获取第二屏context
    public Context getDisplayContext(int checked) {
        int displayId = mAllDisplays.get(checked-1).getDisplayId();
        if (displayId != DEFAULT_DISPLAY) {
            Log.d("wangchong", "getDisplayContext not DEFAULT_DISPLAY, displayId = " + displayId);
            return mContext.createDisplayContext(mAllDisplays.get(checked-1));
        }
        Log.d("wangchong", "getDisplayContext DEFAULT_DISPLAY");
        return mContext;
    }
}

未不同的屏幕创建不同的windowmanager代理 

windowManager2 = displayUtils.getDisplayContext(2).getSystemService(WindowManager.class);

 toast弹框选择屏幕参考

Display display = getDisplay(1);//获取ivi proup层屏幕的显示数据
displaycontext = getApplicationContext().createDisplayContext(display);//通过createDisplayContext创建displaycontex,通过displaycontext设置屏幕id
mToast = CustomToast.makeText(displaycontext, message,Toast.LENGTH_SHORT, 0, 0); //使用displaycontext创建toast

AlertDialog选择屏幕参考

Display display = getDisplay(1);//获取ivi proup层屏幕的显示数据
displaycontext = getApplicationContext().createDisplayContext(display);//通过createDisplayContext创建displaycontex,通过displaycontext设置屏幕id
AlertDialog = new AlertDialog(mContext,type);

二, DisplayManagerService

Android 中 对display 操作时, 从APP, DisplayManagerService, SurfaceFlinger到HWC通信都需要用到display id, 但是, 实际上,每个模块的display id 并不一致, 他们之间有一定的对应关系。

DisplayID

DisplayManagerService用于管理display 使用的id, 也是app 能够通过Display.getDisplayId() 得到的ID。

在android S之前的版本,该ID 是按display 加载的顺序确定的, 每加载一个display, id依次增一。 代码 :rameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java#assignDisplayIdLocked。

在Android S版本,DeviceStateToLayoutMap#loadLayoutsFromConfig函数加载固定displayId方案中的xml。

在启动DMS服务的阶段加载DisplayDeviceRepository,通知LogicalDisplayMapper display事件。然后调用onDisplayDeviceEventLocked。发生事件类型为DISPLAY_DEVICE_EVENT_ADDED的时机,对于LocalDisplayDevice有两处:

  1. DMS对象创建完成后,执行onStart(),注册LocalDisplayAdapter,从surfaceflinger获取所有的display,然后依次通知LogicalDisplayMapper有DISPLAY_DEVICE_EVENT_ADDED。
  2. 收到来自surfaceflinger的onHotplug事件,有display接入时,通知LogicalDisplayMapper有DISPLAY_DEVICE_EVENT_ADDED。

对于每一个INTERNAL屏(内置display)会分配两次displayId,最终会保留createDisplayLocked时分配的displayId,这样就实现Android S版本上内置display分配的displayId为固定值。具体逻辑在函数LogicalDisplayMapper#applyLayoutLocked中实现。


PhysicalDisplayID

SurfaceFlinger 中管理display 使用的ID, DisplayManagerService与SurfaceFlinger通信借助该ID。surfaceflinger中根据 mPhysicalDisplayId 找到HWC::Display, 通过HWC::Display中的mid 与hwc 通信, 其中的mId 为HWC给出, 即为下面的client_id. 

android\frameworks\native\libs\ui\include\ui\DisplayId.h


client_id

HWC中定义的ID, 会传递给SurfaceFlinger,  与SurfaceFlinger 通信使用该ID。HWC按照可支持的display 数量和类型的定义:hardware/qcom/display/sdm/libs/hwc2/hwc_session.cpp中HWCSession::InitSupportedDisplaySlots看map_info.client_id赋值。 client_id 与 surfaceflinger 中HWC::Display中的mId 相同。 hwc_session中根据该client_id通过hwc_display_[client_id]找到相应的 HWCDisplay, 该HWCDisplay中记录了sdm_id, 对应底层的display id。 

android\hardware\qcom\display\sdm\libs\hwc2\hwc_session.cpp# InitSupportedDisplaySlots


sdm_id

display driver传递给HWC的ID。

代码

android\hardware\qcom\display\sdm\libs\hwc2\hwc_session.cpp# CreatePrimaryDisplay

android\hardware\qcom\display\sdm\libs\core\drm\hw_info_drm.cpp# GetDisplaysStatus

android\vendor\qcom\proprietary\display\sde-drm\drm_connector.cpp

sdm_id就是resource中的connector。

inux的DRM架构,DRM是linux内核中负责与显卡交互的管理架构

drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);

整体过程:

三, surfaceflinger

 WindowManagerService  服务端,与绘制无关,控制窗口的状态、属性,如大小,位置等;

WindowManagerService  管理View 内容端绘制申请 SurfaceMeasureLayout Draw 过程。当为activity申请好了surface之后,每个进程就可以跟surfaceflinger通信了。

SurfaceFlinger 是一个独立的Service, 它接收所有Window的Surface作为输入,根据ZOrder, 透明度,大小,位置等参数,计算出每个Surface在最终合成图像中的位置,然后交由HWComposer或OpenGL生成最终的显示Buffer, 然后显示到显示设备上。

架构图:

数据流图

 整体数据流程

 四,HAL层 - HWC

hwc(hardware composer)是芯片厂商对android compoer的实现。高通的HWC架构如下:

五,驱动层 DRM 

略。

六,openWFD软件架构

display驱动加载过程

七,display 配置

 Display 驱动xml配置基础介绍

QNX/workspace/modules/bsp/apps/qnx_ap/boards/display/adp_star_sda8155/config/qcdisplaycfg_ADP_STAR_LA_MULTI_DISP_P03_TI_MST.xml

Display 驱动xml配置QNX display id 

Display 驱动xml配置基础(android display id 

Display 驱动screen config配置基础

八,硬件架构参考

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值