如何編寫顯示驅動程式庫

決定推出新版面。在深入探討程式設計之前 請回答以下問題,確保自己擁有一切所需:

  • 我如何瞭解裝置和其暫存器的運作方式?

    • 這通常稱為「作業理論」。製造商經常提供 含有登錄定義的資料工作表,但這些參考資料可能不會說明 裝置的實際使用方式
  • 是否有類似董事會的驅動程式庫?

    • 在可行情況下,您可以重構該程式碼並 修訂驅動程式庫的繫結規則。
  • 裝置是否有固定的螢幕?

    • 部分顯示控制器和麵板 (輸出螢幕) 是緊密耦合。 如果是新開發板的案例,請 顯示器驅動程式庫程式中的 GPIO、I2C 和其他控制項。

必要條件

本指南假設您熟悉一或多個驅動程式庫開發程序 以及作業系統同時假設您已熟悉 Fuchsia DDK-TL

程式語言

新驅動程式必須以 C++ 編寫。已規劃支援 Rust,但效能仍相當高 實驗功能。

已安裝適當授權的驅動程式庫 若是使用 C 語言,則可直接攜碼轉移至 Fuchsia,而非 在 C++ 中實作新版本。請洽詢 graphics-dev@fuchsia.dev 再做出決定

開始使用

如果是沒有 ACPI 或 PCI 匯流排的平台,請改造圖板 驅動程式是第一步。本指南假設 現在可以使用 Jamboard 驅動程式庫,且顯示驅動程式庫的名稱為 fancy。所有代碼 新驅動程式庫的 src/graphics/display/drivers/fancy-display/ 上線。

首先請建立以下項目:

將驅動程式庫新增至建構作業

  1. 在名為 BUILD.gn 的檔案中建立建構方案
# Copyright 2021 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import("//build/bind/bind.gni")
import("//build/drivers.gni")

driver_bind_rules("fancy-display-bind") {
  rules = "meta/fancy-display.bind"
  bind_output = "fancy-display.bindbc"
  tests = "meta/bind_tests.json"
  deps = [
    "//src/devices/bind/board_maker_company.platform",
  ]
}

# Factored out so that it can be used in tests.
source_set("common") {
  public_deps = [
    ":fancy-display-bind",
  ]
  sources = [
    "fancy-display.cc",
  ]
}

fuchsia_driver("fancy-display") {
  sources = []
  deps = [
    ":common",
    "//src/devices/lib/driver",
  ]
}
  1. //src/graphics/display/drivers/fancy-display 新增為 測試產品所使用的 Jamboard。舉例來說,如果您的裝置 Khadas VIM3 開發板的一部分,請將 //boards/vim3.gni 值 您的驅動程式庫新增至 _common_bootfs_deps 清單。

選擇要駕駛的裝置

現在您已擁有建構方案,可以接著建立 bind 驅動程式管理器判斷驅動程式庫身分。 可與裝置搭配使用

  1. src/graphics/display/drivers/fancy-display 中建立 meta/fancy-display.bind:
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

using fuchsia.pci;

fuchsia.BIND_PROTOCOL == fuchsia.pci.BIND_PROTOCOL.DEVICE;
fuchsia.BIND_PCI_VID == fuchsia.pci.BIND_PCI_VID.PLANK_HW_INC;
accept fuchsia.BIND_PCI_DID {
  // Fancy
  0x0100,
  // Fancy+ series
  0x0120,
  0x0121,
}

對於電腦裝置,intel-螢幕繫結規則就是一個很好的例子。適用對象 固定硬體 SoC,請參閱 Amlogic 顯示規則

極簡驅動程式庫

最後,新增簡單的骨架驅動程式庫 時間。之後,您可以使用規格書 執行特定工作

src/graphics/display/drivers/fancy-display 中建立 fancy-display.cc

#include <ddktl/device.h>
#include <fuchsia/hardware/display/controller/cpp/banjo.h>

namespace fancy_display {

class Device;
using DeviceType = ddk::Device<Device>

// A Device exposes a single display controller for use by the display
// coordinator driver in src/graphics/display/drivers/coordinator.
//
// This object is constructed once for each device that matches this
// driver's bind rules.
class Device : public DeviceType {
 public:
  explicit Device(zx_device_t* parent) : DeviceType(parent) {}

  // If Bind() returns an error, the driver won't claim the device.
  zx_status_t Bind() { return ZX_OK };

  // Functionality needed by the common display driver core.
  void DisplayEngineRegisterDisplayEngineListener(
      const display_engine_listener_protocol* interface) {}

  zx_status_t DisplayEngineImportBufferCollection(
      uint64_t collection_id, zx::channel collection_token) {
    return ZX_ERR_NOT_SUPPORTED;
  }

  zx_status_t DisplayEngineReleaseBufferCollection(
      uint64_t collection_id) {
    return ZX_ERR_NOT_SUPPORTED;
  }

  zx_status_t DisplayEngineImportImage(const image_metadata_t* image_metadata,
                                               uint64_t collection_id, uint32_t index,
                                               uint64_t* out_image_handle) {
    return ZX_ERR_NOT_SUPPORTED;
  }

  void DisplayEngineReleaseImage(image_t* image) {}

  config_check_result_t DisplayEngineCheckConfiguration(
      const display_config_t** display_configs, size_t display_count,
      client_composition_opcode_t* out_client_composition_opcodes_list, size_t client_composition_opcodes_count,
      size_t* out_client_composition_opcodes_actual);

  void DisplayEngineApplyConfiguration(
      const display_config_t** display_config, size_t display_count) {}

  zx_status_t DisplayEngineSetBufferCollectionConstraints(
      const image_buffer_usage_t* usage, uint64_t collection_id) {
    return ZX_ERR_NOT_SUPPORTED;
  }

};

}  // namespace fancy_display

// Main bind function called from dev manager.
zx_status_t fancy_display_bind(void* ctx, zx_device_t* parent) {
    fbl::AllocChecker alloc_checker;
    auto dev = fbl::make_unique_checked<fancy_display::Device>(
        &alloc_checker, parent);
    if (!alloc_checker.check()) {
        return ZX_ERR_NO_MEMORY;
    }
    auto status = dev->Bind();
    if (status == ZX_OK) {
      // The driver/device manager now owns this memory.
      [[maybe_unused]] auto ptr = dev.release();
    }
    return status;
}

// zx_driver_ops_t is the ABI between driver modules and the device manager.
// This lambda is used so that drivers can be rebuilt without compiler
// warnings if/when new fields are added to the struct.
static zx_driver_ops_t fancy_display_ops = [](){
    zx_driver_ops_t ops;
    ops.version = DRIVER_OPS_VERSION;
    ops.bind = fancy_display_bind;
    return ops;
}();

// ZIRCON_DRIVER marks the compiled driver as compatible with the zircon
// 0.1 driver ABI.
ZIRCON_DRIVER(fancy_display, fancy_display_ops, "zircon", "0.1");

顯示卡驅動程式必須實作 DisplayEngine 「通訊協定」,可公開硬體層並導入 vsync 通知。「顯示協調器」驅動程式庫多工 與顯示器驅動程式庫程式上的所有裝置專用驅動程式相互通訊 堆疊用戶端,也就是系統合成器和 Virtcon。

導入訣竅

驅動程式可決定將設定傳遞至 ApplyConfiguration 的時機和方式 就會生效。為了避免撕裂,駕駛人應 會在 vsync 後立即套用新設定。

大多數裝置會在 vsync 事件中產生中斷情形。您可以輕鬆建構 確保即時 Vsync 通知為產生單獨的執行緒,僅適用於 運作中斷即使沒有顯示任何圖片,駕駛人還是必須 為每個 vsync 呼叫 OnDisplayVsync

支援系統啟動載入程式的控制器

如果開機時螢幕處於啟用狀態,例如:表示已開啟的面板 隨後就能在驅動程式中快速取得基本功能。已讀 系統啟動載入程式記錄和/或來源:

  • Framebuffer 的實際位址
  • 用來編寫該位址的程式
  • 圖片的像素尺寸,例如800x600
  • 圖片的像素格式,例如RGB888、NV12 或 BGRA8888

然後︰

  1. 修改驅動程式庫,回報包含格式限制的顯示畫面。
  2. 記錄 image->handle 中任何匯入映像檔的實體位址。
  3. 呼叫 ApplyConfig 後,請將暫存器重新編寫程式。

如果您不知道如何觀察 Vsync,可以使用 以 60Hz 呼叫 OnDisplayVsync

啟動「黑暗」的控制器

要開啟顯示控制器,並沒有一套方法。 基本的系統啟動載入程式驅動程式庫。在多數情況下,規劃藍圖為:

  1. 為裝置充電。
  2. 初始化時鐘。
  3. 「探索」附加顯示畫面。
  4. 針對相容模式編寫 PHY。
  5. 避免撕裂的程式版面配置 (Framebuffer Addr 等)。
  6. Sysmem 整合。