• Android 12(S) 图像显示系统 - drm_hwcomposer 简析(下)



    必读:

    Android 12(S) 图像显示系统 - 开篇


     

     

    合成方式

    合成类型的定义:/hardware/interfaces/graphics/composer/2.1/IComposerClient.hal

        /** Possible composition types for a given layer. */
        /** 建议去看源码中的注释,可以理解每一个type的含义 */
        enum Composition : int32_t {
            INVALID = 0,
            CLIENT = 1, 
            DEVICE = 2,
            SOLID_COLOR = 3,
            CURSOR = 4,
            SIDEBAND = 5,
        };

     

    后端的设计逻辑

    有三个类定义

      1. Backend == 一个后端的实现,注册为"generic",主要是定义了ValidateDisplay方法,这个方法用来设置可见的HwcLayer应该采用什么合成方式

      2. BackendClient  ==  一个后端的实现,注册为"client",主要是定义了ValidateDisplay方法,它把所有HwcLayer都设置成立Client合成方式

      3. BackendManager == 后端的管理器,用来根据Device name从已注册的backend列表中选择一个,设置给HwcDisplay;GetBackendByName就是通过Device name来从available_backends_中选择一个匹配的Backend构造函数来构建后端对象。

     

    HWC 中如何为每一个Layer选择合成方式

    [drm-hwcomposer/hwc2_device/HwcDisplay.cpp]
    HWC2::Error HwcDisplay::ValidateDisplay(uint32_t *num_types,
                                            uint32_t *num_requests) {
        if (IsInHeadlessMode()) {
         *num_types = *num_requests = 0;
         return HWC2::Error::None;
      }
        return backend_->ValidateDisplay(this, num_types, num_requests); //调用backend的方法
    }

    去调用到后端的具体validate方法,我的平台就是走到Backend::ValidateDisplay

    [drm-hwcomposer/backend/Backend.cpp]
    HWC2::Error Backend::ValidateDisplay(HwcDisplay *display, uint32_t *num_types,
                                         uint32_t *num_requests) {
      *num_types = 0;
      *num_requests = 0;
      auto layers = display->GetOrderLayersByZPos(); // 按Z-order顺序排列的HwcLayer的集合
      int client_start = -1; // layers中,需要Client合成的layer的起始位置
      size_t client_size = 0; // layers中,需要Client合成的layer的个数
      if (display->ProcessClientFlatteningState(layers.size() <= 1)) {
        display->total_stats().frames_flattened_++;
        client_start = 0;
        client_size = layers.size();
        //设置合成类型,client_start到client_start+client_size之间的设置为Client,其它的设置为Device
        MarkValidated(layers, client_start, client_size);
      } else {
        std::tie(client_start, client_size) = GetClientLayers(display, layers);// 刷选哪些layer需要Client合成
        //设置合成类型,client_start到client_start+client_size之间的设置为Client,其它的设置为Device
        MarkValidated(layers, client_start, client_size);
        bool testing_needed = !(client_start == 0 && client_size == layers.size());
        AtomicCommitArgs a_args = {.test_only = true};
        if (testing_needed &&
            display->CreateComposition(a_args) != HWC2::Error::None) {
          ++display->total_stats().failed_kms_validate_;
          client_start = 0;
          client_size = layers.size();
          //设置合成类型,client_start到client_start+client_size之间的设置为Client,其它的设置为Device
          MarkValidated(layers, 0, client_size);
        }
      }
      *num_types = client_size;
      display->total_stats().gpu_pixops_ += CalcPixOps(layers, client_start,
                                                       client_size);
      display->total_stats().total_pixops_ += CalcPixOps(layers, 0, layers.size());
      return *num_types != 0 ? HWC2::Error::HasChanges : HWC2::Error::None;
    }
    折叠

    Backend中还有几个辅助方法,简单介绍下

    GetClientLayers:刷选出哪些layer需要Client合成,筛选是会经过两层考核 IsClientLayer & GetExtraClientRange

    IsClientLayer:判断指定的Layer是否要Client合成,有几个条件:1. HardwareSupportsLayerType硬件不支持的合成方式
                                                    2. IsHandleUsable buffer handle无法转为DRM要求的buffer object
                                                    3. color_transform_hint !=HAL_COLOR_TRANSFORM_IDENTITY
                                                    4. 需要scale or phase,但hwc强制GPU来处理

    GetExtraClientRange: 进一步筛选client layer, 当layer的数量多于hwc支持的planes时,需要留出一个给 client target

     

    合成显示

    PresentDisplay方法的作用就是把内容呈现到屏幕上去

    [drm-hwcomposer/hwc2_device/HwcDisplay.cpp]
    HWC2::Error HwcDisplay::PresentDisplay(int32_t *present_fence) {
      ...
      AtomicCommitArgs a_args{};
      ret = CreateComposition(a_args);// 调用
      ...
    }

    主要是去调用了CreateComposition这个方法

    [drm-hwcomposer/hwc2_device/HwcDisplay.cpp]
    HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
      if (IsInHeadlessMode()) { // 无头模式,不做处理,返回
        ALOGE("%s: Display is in headless mode, should never reach here", __func__);
        return HWC2::Error::None;
      }
      int PrevModeVsyncPeriodNs = static_cast<int>(
          1E9 / GetPipe().connector->Get()->GetActiveMode().v_refresh());
      auto mode_update_commited_ = false; // 是否需要更新/提交
      if (staged_mode_ && // staged_mode_ 当前所处的显示模式
          staged_mode_change_time_ <= ResourceManager::GetTimeMonotonicNs()) {
        client_layer_.SetLayerDisplayFrame( // 设置显示的位置大小
            (hwc_rect_t){.left = 0,
                         .top = 0,
                         .right = static_cast<int>(staged_mode_->h_display()),
                         .bottom = static_cast<int>(staged_mode_->v_display())});
        configs_.active_config_id = staged_mode_config_id_;
        a_args.display_mode = *staged_mode_;
        if (!a_args.test_only) {
          mode_update_commited_ = true;
        }
      }
      // order the layers by z-order
      bool use_client_layer = false; // 是否有GPU合成的图层
      uint32_t client_z_order = UINT32_MAX;
      std::map<uint32_t, HwcLayer *> z_map;
      for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
        switch (l.second.GetValidatedType()) {
          case HWC2::Composition::Device:
            z_map.emplace(std::make_pair(l.second.GetZOrder(), &l.second)); // z_map中是按照z-order排序的,Device合成的图层
            break;
          case HWC2::Composition::Client:
            // Place it at the z_order of the lowest client layer
            use_client_layer = true;
            client_z_order = std::min(client_z_order, l.second.GetZOrder()); // 找到GPU合成图层中最小的z-order
            break;
          default:
            continue;
        }
      }
      if (use_client_layer)
        z_map.emplace(std::make_pair(client_z_order, &client_layer_)); // GPU合成的Client图层加入z_map集合
      if (z_map.empty()) // 空集合,没有要合成的图层
        return HWC2::Error::BadLayer;
      std::vector<DrmHwcLayer> composition_layers;
      // now that they're ordered by z, add them to the composition
      for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
        DrmHwcLayer layer;
        l.second->PopulateDrmLayer(&layer); // 把HwcLayer转为DrmHwcLayer,主要是一些信息
        int ret = layer.ImportBuffer(GetPipe().device); // 1. 把buffer_handle_t转为drm buffer object  
                                                        // 2. 做drmPrimeFDToHandle处理
        if (ret) {
          ALOGE("Failed to import layer, ret=%d", ret);
          return HWC2::Error::NoResources;
        }
        composition_layers.emplace_back(std::move(layer));
      }
      /* Store plan to ensure shared planes won't be stolen by other display
       * in between of ValidateDisplay() and PresentDisplay() calls
       */
      current_plan_ = DrmKmsPlan::CreateDrmKmsPlan(GetPipe(), // 创建一个计划:合成显示
                                                   std::move(composition_layers));
      if (!current_plan_) {
        if (!a_args.test_only) {
          ALOGE("Failed to create DrmKmsPlan");
        }
        return HWC2::Error::BadConfig;
      }
      a_args.composition = current_plan_;
       // 提交/合成/显示到屏幕 == >DrmAtomicStateManager::ExecuteAtomicCommit
      int ret = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args); 
      if (ret) {
        if (!a_args.test_only)
          ALOGE("Failed to apply the frame composition ret=%d", ret);
        return HWC2::Error::BadParameter;
      }
      if (mode_update_commited_) {
        staged_mode_.reset();
        vsync_tracking_en_ = false;
        if (last_vsync_ts_ != 0) {
          hwc2_->SendVsyncPeriodTimingChangedEventToClient(
              handle_, last_vsync_ts_ + PrevModeVsyncPeriodNs);
        }
      }
      return HWC2::Error::None;
    }
    折叠

    上面出现了一个新的类型

    struct DrmHwcLayer {
      buffer_handle_t sf_handle = nullptr;
      hwc_drm_bo_t buffer_info{};
      std::shared_ptr<DrmFbIdHandle> fb_id_handle;
      int gralloc_buffer_usage = 0;
      DrmHwcTransform transform{};
      DrmHwcBlending blending = DrmHwcBlending::kNone;
      uint16_t alpha = UINT16_MAX;
      hwc_frect_t source_crop;
      hwc_rect_t display_frame;
      DrmHwcColorSpace color_space;
      DrmHwcSampleRange sample_range;
      UniqueFd acquire_fence;
      int ImportBuffer(DrmDevice *drm_device);
      bool IsProtected() const {
        return (gralloc_buffer_usage & GRALLOC_USAGE_PROTECTED) ==
               GRALLOC_USAGE_PROTECTED;
      }
    };

    ImportBuffer调用的流程:

    int DrmHwcLayer::ImportBuffer(DrmDevice *drm_device) {
      buffer_info = hwc_drm_bo_t{};
      int ret = BufferInfoGetter::GetInstance()->ConvertBoInfo(sf_handle,
                                                               &buffer_info);
      if (ret != 0) {
        ALOGE("Failed to convert buffer info %d", ret);
        return ret;
      }
      fb_id_handle = drm_device->GetDrmFbImporter().GetOrCreateFbId(&buffer_info);
      if (!fb_id_handle) {
        ALOGE("Failed to import buffer");
        return -EINVAL;
      }
      return 0;
    }

    进而调用到相关方法
    BufferInfoMapperMetadata::ConvertBoInfo
    DrmFbImporter::GetOrCreateFbId

     

    DrmAtomicStateManager::CommitFrame方法中应该是最终去显示内容的逻辑。

     

    看一下CommitFrame调用栈信息:

    PresentDisplay调用栈信息

    ValidateDisplay调用栈信息

     

  • 相关阅读:
    c语言从入门到实战——数组
    实战PyQt5:157-QChart图表之动态样条曲线
    关于我的家乡网页设计主题题材——梧州14页HTML+CSS网页
    基于STM32的烟雾浓度检测报警仿真设计(仿真+程序+讲解视频)
    一个C++读取XML的类
    登录认证,登录校验
    论文翻译:2021_A New Real-Time Noise Suppression Algorithm for Far-Field Speech Communication Based on Recurrent Neural Network
    【Linux】:文件系统
    【NLP】第10章 使用基于 BERT 的 Transformer 进行语义角色标记
    poj 1068 parencondings
  • 原文地址:https://www.cnblogs.com/roger-yu/p/16425521.html