| // Copyright 2018 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. |
| library fuchsia.hardware.display.controller; |
| |
| using fuchsia.hardware.audiotypes; |
| using fuchsia.hardware.i2cimpl; |
| using zx; |
| |
| type ImageType = strict enum : uint32 { |
| /// The image is linear and VMO backed. |
| SIMPLE = 0; |
| |
| // Intentionally left some gap between SIMPLE and CAPTURE. |
| |
| /// The image is used for capture |
| CAPTURE = 10; |
| }; |
| |
| /// A structure containing information about an image. |
| type Image = struct { |
| /// The width and height of the image in pixels. |
| width uint32; |
| height uint32; |
| |
| /// The type conveys information about what is providing the pixel data. If this is not |
| /// IMAGE_TYPE_SIMPLE, it is up to the driver and buffer producer to agree on the meaning |
| /// of the value through some mechanism outside the scope of this API. |
| type uint32; |
| |
| /// A driver-defined handle to the image. Each handle must be unique. |
| handle uint64; |
| }; |
| |
| const INVALID_DISPLAY_ID uint32 = 0; |
| const INVALID_ID uint32 = 0; |
| |
| /// Indicates that a ConfigStamp is invalid. |
| const INVALID_CONFIG_STAMP_VALUE uint64 = 0; |
| |
| /// A unique stamp representing a unique set of display configuration. |
| /// The value is always strictly increasing in chronological order. |
| type ConfigStamp = struct { |
| /// For valid configurations, the value should not be equal to |
| /// `INVALID_CONFIG_STAMP_VALUE`. |
| value uint64; |
| }; |
| |
| /// A fallback structure to convey display information without an edid. |
| type DisplayParams = struct { |
| width uint32; |
| height uint32; |
| refresh_rate_e2 uint32; |
| }; |
| |
| /// Info about valid cursor configurations. |
| type CursorInfo = struct { |
| /// The width and height of the cursor configuration, in pixels. |
| width uint32; |
| height uint32; |
| |
| /// Pixel format type of the cursor buffer. |
| format FuchsiaImages2PixelFormatEnumValue; |
| }; |
| |
| type Panel = strict resource union { |
| // The i2c bus to use to read this display's edid. |
| 1: i2c client_end:fuchsia.hardware.i2cimpl.I2cImpl; |
| /// The display's parameters if an edid is not present. |
| 2: params DisplayParams; |
| }; |
| |
| /// A structure containing information a connected display. |
| type AddedDisplayArgs = resource struct { |
| display_id uint64; |
| |
| /// A flag indicating whether or not the display has a valid edid. |
| /// |
| /// If true, the device should provide a fuchsia.hardware.i2cimpl.I2cImpl client in the `Panel` |
| /// union. Note that the i2c device will be called from the on_displays_changed callback, so |
| /// care should be taken to avoid deadlocks or double-locking. |
| /// |
| /// If no edid is present, then the meaning of display_config's mode structure is |
| /// undefined, and drivers should ignore it in check_configuration and apply_configuration. |
| edid_present bool; |
| panel Panel; |
| |
| /// A list of pixel formats supported by the display. The first entry is the |
| /// preferred pixel format. |
| pixel_format vector<FuchsiaImages2PixelFormatEnumValue>:MAX; |
| |
| /// A list of cursor configurations most likely to be accepted by the driver. Can |
| /// be null if cursor_count is 0. |
| /// |
| /// The driver may reject some of these configurations in some circumstances, and |
| /// it may accept other configurations, but at least one of these configurations |
| /// should be valid at most times. |
| cursor_info vector<CursorInfo>:MAX; |
| }; |
| |
| /// Out parameters will be populated before on_displays_changed returns. |
| type AddedDisplayInfo = struct { |
| is_hdmi_out bool; |
| is_standard_srgb_out bool; |
| |
| audio_format_count uint32; |
| |
| /// All strings are null-terminated. |manufacturer_id| is guaranteed to have |
| /// length 3, all other strings may be empty. |
| manufacturer_id string:4; |
| /// non-null |
| manufacturer_name string:MAX; |
| /// null-terminated |
| monitor_name string:14; |
| /// null-terminated |
| monitor_serial string:14; |
| |
| // physical horizontal size in millimeters |
| horizontal_size_mm uint32; |
| // physical vertical size in millimeters |
| vertical_size_mm uint32; |
| }; |
| |
| /// The client will not make any `ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL` calls into the device |
| /// during these callbacks. |
| @transport("Banjo") |
| @banjo_layout("ddk-interface") |
| closed protocol DisplayControllerInterface { |
| /// Callbacks which are invoked when displays are added or removed. |added_display_list| and |
| /// |removed_display_list| point to arrays of the display ids which were added and removed. If |
| /// |added_display_count| or |removed_display_count| is 0, the corresponding array can be NULL. |
| /// |
| /// The driver must be done accessing any images which were on the removed displays. |
| /// |
| /// The driver should call this function when the callback is registered if any displays |
| /// are present. |
| strict OnDisplaysChanged(resource struct { |
| added_display vector<AddedDisplayArgs>:MAX; |
| removed_display vector<uint64>:MAX; |
| }) -> (struct { |
| display_info vector<AddedDisplayInfo>:MAX; |
| }); |
| |
| /// Events which are invoked when display vsync occurs. |
| /// |
| /// Arguments |
| /// - |timestamp| |
| /// The ZX_CLOCK_MONOTONIC timestamp at which the vsync occurred. |
| /// - |config_stamp| |
| /// The config stamp of the latest configuration that is currently |
| /// fully applied to all the layers of the display with `display_id`. |
| /// If none of the configurations are currently fully applied to |
| /// this display, a null value will be passed to the driver. |
| /// Note that an `ApplyConfiguration()` call may contain multiple |
| /// configurations with a certain `config_stamp`; Only the application |
| /// status of the configuration with ID `display_id` is related. |
| /// |
| /// The driver must call this function for all vsync events, even if the |
| /// display has no images displayed. |
| strict OnDisplayVsync(struct { |
| display_id uint64; |
| timestamp zx.Time; |
| config_stamp box<ConfigStamp>; |
| }) -> (); |
| |
| strict GetAudioFormat(struct { |
| display_id uint64; |
| fmt_idx uint32; |
| }) -> (struct { |
| s zx.Status; |
| fmt fuchsia.hardware.audiotypes.AudioTypesAudioStreamFormatRange; |
| }); |
| }; |
| |
| @transport("Banjo") |
| @banjo_layout("ddk-interface") |
| closed protocol DisplayCaptureInterface { |
| strict OnCaptureComplete() -> (); |
| }; |
| |
| type Alpha = strict enum : uint8 { |
| DISABLE = 0; |
| PREMULTIPLIED = 1; |
| HW_MULTIPLY = 2; |
| }; |
| |
| /// Rotations are applied counter-clockwise, and are applied before reflections. |
| type FrameTransform = strict enum : uint32 { |
| IDENTITY = 0; |
| REFLECT_X = 1; |
| REFLECT_Y = 2; |
| ROT_90 = 3; |
| ROT_180 = 4; |
| ROT_270 = 5; |
| ROT_90_REFLECT_X = 6; |
| ROT_90_REFLECT_Y = 7; |
| }; |
| |
| type Frame = struct { |
| /// (|x_pos|, |y_pos|) specifies the position of the upper-left corner |
| /// of the frame. |
| x_pos uint32; |
| y_pos uint32; |
| width uint32; |
| height uint32; |
| }; |
| |
| type PrimaryLayer = struct { |
| image Image; |
| |
| /// An ALPHA_* constant. |
| /// |
| /// If |alpha_mode| == `ALPHA_DISABLED`, the layer is opaque and alpha_layer_val is ignored. |
| /// |
| /// If |alpha_mode| == `PREMULTIPLIED` or `HW_MULTIPLY` and |alpha_layer_val| is NaN, the alpha |
| /// used when blending is determined by the per-pixel alpha channel. |
| /// |
| /// If |alpha_mode| == `PREMULTIPLIED` or `HW_MULTIPLY` and |alpha_layer_val| is not NaN, the |
| /// alpha used when blending is the product of alpha_layer_val and any per-pixel alpha. |
| /// Additionally, if alpha_mode == PREMULTIPLIED, then the hardware must premultiply the color |
| /// channel with alpha_layer_val before blending. |
| /// |
| /// If alpha_layer_val is not NaN, it will be in the range [0, 1]. |
| alpha_mode Alpha; |
| alpha_layer_val float32; |
| |
| transform_mode FrameTransform; |
| |
| /// The source frame, where (0,0) is the top-left corner of the image. The |
| /// client guarantees that src_frame lies entirely within the image. |
| src_frame Frame; |
| |
| /// The destination frame, where (0,0) is the top-left corner of the |
| /// composed output. The client guarantees that dest_frame lies entirely |
| /// within the composed output. |
| dest_frame Frame; |
| }; |
| |
| type CursorLayer = struct { |
| image Image; |
| |
| /// The position of the top-left corner of the cursor's image. When being |
| /// applied to a display, the cursor is guaranteed to have at least one |
| /// pixel of overlap with the display. |
| x_pos int32; |
| y_pos int32; |
| }; |
| |
| type ColorLayer = struct { |
| /// The format of `color` bytes. |
| format FuchsiaImages2PixelFormatEnumValue; |
| |
| /// The color to use for the layer. The color is little-endian, and is |
| /// guaranteed to be of the exact size of one pixel in `format`. |
| color vector<uint8>:MAX; |
| }; |
| |
| /// Types of layers. |
| type LayerType = strict enum : uint32 { |
| PRIMARY = 0; |
| CURSOR = 1; |
| COLOR = 2; |
| }; |
| |
| type LayerConfig = strict union { |
| 1: primary PrimaryLayer; |
| 2: cursor CursorLayer; |
| 3: color ColorLayer; |
| }; |
| |
| type Layer = struct { |
| type LayerType; |
| /// z_index of the layer. See |check_configuration| and |apply_configuration|. |
| z_index uint32; |
| cfg LayerConfig; |
| }; |
| |
| /// constants for display_config's mode_flags field |
| type ModeFlag = strict enum : uint32 { |
| VSYNC_POSITIVE = 0x1; |
| HSYNC_POSITIVE = 0x2; |
| INTERLACED = 0x4; |
| ALTERNATING_VBLANK = 0x8; |
| DOUBLE_CLOCKED = 0x10; |
| }; |
| |
| /// The video parameters which specify the display mode. |
| type DisplayMode = struct { |
| pixel_clock_10khz uint32; |
| h_addressable uint32; |
| h_front_porch uint32; |
| h_sync_pulse uint32; |
| h_blanking uint32; |
| v_addressable uint32; |
| v_front_porch uint32; |
| v_sync_pulse uint32; |
| v_blanking uint32; |
| /// A bitmask of MODE_FLAG_* values |
| flags uint32; |
| }; |
| |
| type ColorConversion = strict enum : uint32 { |
| /// If set, use the 0 vector for the color conversion preoffset |
| PREOFFSET = 0x1; |
| /// If set, use the identity matrix for the color conversion coefficients |
| COEFFICIENTS = 0x2; |
| /// If set, use the 0 vector for the color conversion postoffset |
| POSTOFFSET = 0x4; |
| }; |
| |
| type DisplayConfig = struct { |
| /// the display id to which the configuration applies |
| display_id uint64; |
| |
| mode DisplayMode; |
| |
| /// Bitmask of flags defined in the ColorConversion enum. |
| cc_flags uint32; |
| /// Color conversion is applied to each pixel according to the formula: |
| /// |
| /// (cc_coefficients * (pixel + cc_preoffsets)) + cc_postoffsets |
| /// |
| /// where pixel is a column vector consisting of the pixel's 3 components. |
| cc_preoffsets array<float32, 3>; |
| cc_coefficients array<array<float32, 3>, 3>; |
| cc_postoffsets array<float32, 3>; |
| |
| @mutable |
| @out_of_line_contents |
| layer vector<Layer>:MAX; |
| }; |
| |
| type ConfigCheckResult = strict enum : uint32 { |
| /// The display mode configuration is valid. Note that this is distinct from |
| /// whether or not the layer configuration is valid. |
| OK = 0; |
| /// Error indicating that the hardware cannot simultaneously support the |
| /// requested number of displays. |
| TOO_MANY = 1; |
| /// Error indicating that the hardware cannot simultaneously support the given |
| /// set of display modes. To support a mode, the display must be able to display |
| /// a single layer with width and height equal to the requested mode and the |
| /// preferred pixel format. |
| UNSUPPORTED_MODES = 2; |
| }; |
| |
| type Client = strict enum : uint32 { |
| /// The client should convert the corresponding layer to a primary layer. |
| USE_PRIMARY = 0x1; |
| /// The client should compose all layers with MERGE_BASE and MERGE_SRC into a new, |
| /// single primary layer at the MERGE_BASE layer's z-order. The driver must accept |
| /// a fullscreen layer with the default pixel format, but may accept other layer |
| /// parameters. |
| /// |
| /// MERGE_BASE should only be set on one layer per display. If it is set on multiple |
| /// layers, the client will arbitrarily pick one and change the rest to MERGE_SRC. |
| MERGE_BASE = 0x2; |
| MERGE_SRC = 0x4; |
| /// The client should pre-scale the image so that src_frame's dimensions are equal |
| /// to dest_frame's dimensions. |
| FRAME_SCALE = 0x8; |
| /// The client should pre-clip the image so that src_frame's dimensions are equal to |
| /// the image's dimensions. |
| SRC_FRAME = 0x10; |
| /// The client should pre-apply the transformation so TRANSFORM_IDENTITY can be used. |
| TRANSFORM = 0x20; |
| /// The client should apply the color conversion. |
| COLOR_CONVERSION = 0x40; |
| /// The client should apply the alpha transformation itself. |
| ALPHA = 0x80; |
| }; |
| |
| /// The client guarantees that check_configuration and apply_configuration are always |
| /// made from a single thread. The client makes no other threading guarantees. |
| @transport("Banjo") |
| @banjo_layout("ddk-protocol") |
| closed protocol DisplayControllerImpl { |
| /// The function will only be called once, and it will be called before any other |
| /// functions are called. |
| strict SetDisplayControllerInterface(resource struct { |
| intf client_end:DisplayControllerInterface; |
| }) -> (); |
| |
| /// Initialize the display capture interface. Must be called only once |
| /// before importing resources for capture and starting display capture. |
| /// |
| /// Returns ZX_ERR_NOT_SUPPORTED if display capture is not supported. |
| strict SetDisplayCaptureInterface(resource struct { |
| intf client_end:DisplayCaptureInterface; |
| }) -> (struct { |
| s zx.Status; |
| }); |
| |
| /// Import a sysmem buffer collection token. |
| /// |
| /// Returns ZX_ERR_ALREADY_EXISTS if `collection_id` is in use. |
| strict ImportBufferCollection(resource struct { |
| collection_id uint64; |
| // TODO(fxbug.dev/89649): This is a client end channel of FIDL protocol |
| // fuchsia.sysmem.BufferCollectionToken. The raw channel needs to be |
| // replaced with FIDL client end once banjo to FIDL migration finishes. |
| collection_token zx.Handle:CHANNEL; |
| }) -> (struct { |
| s zx.Status; |
| }); |
| |
| /// Release an imported buffer collection. |
| /// |
| /// Returns ZX_ERR_NOT_FOUND if `collection_id` isn't successfully imported. |
| strict ReleaseBufferCollection(struct { |
| collection_id uint64; |
| }) -> (struct { |
| s zx.Status; |
| }); |
| |
| /// Imports an image from a imported BufferCollection into the driver. |
| /// |
| /// Sets `image->handle` iff the image is imported successfully. |
| /// |
| /// Returns ZX_OK if the image is imported succesfully. |
| /// Returns ZX_ERR_NOT_FOUND if `collection_id` is not imported yet. |
| /// Returns ZX_ERR_SHOULD_WAIT if the buffer collection is not already |
| /// allocated. |
| strict ImportImage(struct { |
| @in_out |
| image Image; |
| collection_id uint64; |
| index uint32; |
| }) -> (struct { |
| s zx.Status; |
| }); |
| |
| /// Import BufferCollection backed VMO pointed to by `index`. |
| /// Importing the VMO usually involves pinning the VMO and updating display |
| /// controller hardware registers with the physical address of the VMO to be |
| /// used for capture. Returns out_capture_handle which maps to the allocated |
| /// resource. |
| /// |
| /// If display capture is not supported, returns ZX_ERR_NOT_SUPPORTED and |
| /// the value of `capture_handle` will be undefined. |
| /// |
| /// Returns ZX_ERR_NOT_FOUND if `collection_id` is not imported yet. |
| /// Returns ZX_ERR_SHOULD_WAIT if the buffer collection is not already |
| /// allocated. |
| strict ImportImageForCapture(struct { |
| collection_id uint64; |
| index uint32; |
| }) -> (struct { |
| s zx.Status; |
| capture_handle uint64; |
| }); |
| |
| /// Releases any driver state associated with the given image. The client guarantees that |
| /// any images passed to apply_config will not be released until a vsync occurs with a |
| /// more recent image. |
| strict ReleaseImage(struct { |
| @in_out |
| image Image; |
| }) -> (); |
| |
| /// Validates the given configuration. |
| /// |
| /// The configuration may not include all displays. Omitted displays should be treated as |
| /// whichever of off or displaying a blank screen results in a more permissive validation. |
| /// |
| /// All displays in a configuration will have at least one layer. The layers will be |
| /// arranged in increasing z-order, and their z_index fields will be set consecutively. |
| /// |
| /// Whether or not the driver can accept the configuration cannot depend on the |
| /// particular image handles, as it must always be possible to present a new image in |
| /// place of another image with a matching configuration. It also cannot depend on the |
| /// cursor position, as that can be updated without another call to check_configuration. |
| /// |
| /// display_cfg_result should be set to a CONFIG_DISPLAY_* error if the combination of |
| /// display modes is not supported. |
| /// |
| /// layer_cfg_result points to an array of arrays. The primary length is display_count, the |
| /// secondary lengths are the corresponding display_cfg's layer_count. If display_cfg_result |
| /// is CONFIG_CHECK_RESULT_OK, any errors in layer configuration should be returned as a CLIENT* |
| /// flag in the corresponding layer_cfg_result entry. |
| /// |
| /// The driver must not retain references to the configuration after this function returns. |
| /// TODO: Fix me... |
| strict CheckConfiguration(struct { |
| @inner_pointer |
| display_config vector<DisplayConfig>:MAX; |
| }) -> (struct { |
| display_cfg_result ConfigCheckResult; |
| @callee_allocated |
| layer_cfg_result vector<uint32>:MAX; |
| }); |
| |
| /// Applies the configuration. |
| /// |
| /// All configurations passed to this function will be derived from configurations which |
| /// have been successfully validated, with the only differences either being omitted layers |
| /// or different image handles. To account for any layers which are not present, the driver |
| /// must use the z_index values of the present layers to configure them as if the whole |
| /// configuration was present. |
| /// |
| /// Unlike with check_configuration, displays included in the configuration are not |
| /// guaranteed to include any layers. Both omitted displays and displays with no layers |
| /// can either be turned off or set to display a blank screen, but for displays with no |
| /// layers there is a strong preference to display a blank screen instead of turn them off. |
| /// In either case, the driver must drop all references to old images and invoke the vsync |
| /// callback after doing so. |
| /// |
| /// The driver must not retain references to the configuration after this function returns. |
| strict ApplyConfiguration(struct { |
| @inner_pointer |
| display_config vector<DisplayConfig>:MAX; |
| |
| /// Identifies the configuration to be applied. Must be a valid value. |
| /// Must be strictly increasing across calls. |
| config_stamp ConfigStamp; |
| }) -> (); |
| |
| /// Set ELD for one display. |
| /// |
| /// This method is called independently from the CheckConfiguration and ApplyConfiguration |
| /// methods. The display_id may be unconfigured at the time this method is called. |
| /// raw_eld is the ELD raw data formatted according to the HDA specification version 1.0a |
| /// section 7.3.3.34.1. |
| /// https://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/high-definition-audio-specification.pdf |
| /// The driver must not retain references to the ELD after this function returns. |
| strict SetEld(struct { |
| display_id uint64; |
| raw_eld vector<uint8>:MAX; |
| }) -> (); |
| |
| // Connects the handle to the sysmem service. |
| strict GetSysmemConnection(resource struct { |
| sysmem_handle zx.Handle:CHANNEL; |
| }) -> (struct { |
| s zx.Status; |
| }); |
| |
| /// Set sysmem buffer collection contraints needed to ensure an image can be |
| /// imported with `config` on the imported BufferCollecition with |
| /// `collection_id`. |
| /// |
| /// Returns ZX_ERR_NOT_FOUND if `collection_id` is not imported yet. |
| strict SetBufferCollectionConstraints(struct { |
| config Image; |
| collection_id uint64; |
| }) -> (struct { |
| s zx.Status; |
| }); |
| |
| // Power off/on the display panel. Newly added displays are turned on by default. |
| // |
| // Displays that are turned off will not deliver VSync events. |
| // This may include the vsync event for the most recently applied |
| // config. |
| strict SetDisplayPower(struct { |
| display_id uint64; |
| power_on bool; |
| }) -> (struct { |
| s zx.Status; |
| }); |
| |
| /// Starts capture into the resource mapped by capture_handle (non-blocking) |
| /// Only one active capture is allowed at a time. |
| /// A valid image must be displayed during capture. Otherwise unexpected hardware |
| /// behavior might occur. |
| /// Drivers should not leave display hardware in this unexpected state. |
| /// Drivers are expected to stop and/or abort capture if no valid |
| /// image is being displayed. |
| /// |
| /// Returns ZX_ERR_NOT_SUPPORTED if display capture feature is not |
| /// supported. |
| strict StartCapture(struct { |
| capture_handle uint64; |
| }) -> (struct { |
| s zx.Status; |
| }); |
| |
| /// Releases resources allocated by capture_handle. |
| /// Releasing resources from an active capture is not allowed and will cause |
| /// unexpected behavior. |
| /// |
| /// Returns ZX_ERR_NOT_SUPPORTED if display capture feature is not |
| /// supported. |
| strict ReleaseCapture(struct { |
| capture_handle uint64; |
| }) -> (struct { |
| s zx.Status; |
| }); |
| |
| /// Returns true if display capture is supported and the previous capture is |
| /// completed. False otherwise. |
| strict IsCaptureCompleted() -> (struct { |
| b bool; |
| }); |
| }; |