| // Copyright 2023 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.engine; |
| |
| using fuchsia.hardware.display.types; |
| using fuchsia.hardware.i2cimpl; |
| using fuchsia.images2; |
| using fuchsia.sysmem; |
| using fuchsia.sysmem2; |
| using zx; |
| |
| type ColorConversion = strict bits : 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; |
| }; |
| |
| /// Constants for display_config's mode_flags field |
| type ModeFlag = strict bits : uint32 { |
| VSYNC_POSITIVE = 0x1; |
| HSYNC_POSITIVE = 0x2; |
| INTERLACED = 0x4; |
| ALTERNATING_VBLANK = 0x8; |
| DOUBLE_CLOCKED = 0x10; |
| }; |
| |
| /// The video parameters which specify the display mode. |
| /// TODO(https://fxbug.dev/42085013): Replace this type with something more similar |
| /// to //src/graphics/display/lib/api-types-cpp/display-timing.h. |
| type DisplayMode = struct { |
| pixel_clock_hz int64; |
| 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; |
| flags ModeFlag; |
| }; |
| |
| 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>; |
| |
| layer vector<fuchsia.hardware.display.types.Layer>:MAX; |
| }; |
| |
| // An E-EDID can contain up to 256 data blocks, each of which contains 128 |
| // bytes. So it can contain up to 256 * 128 = 32768 bytes of data. |
| const MAX_COUNT_EDID_BYTES uint32 = 32768; |
| |
| const MAX_COUNT_DISPLAY_PIXEL_FORMATS uint32 = fuchsia.sysmem2.MAX_COUNT_PIXEL_FORMAT_AND_MODIFIERS; |
| |
| const MAX_COUNT_DISPLAY_INFO_PREFERRED_MODES uint32 = 4; |
| |
| // TODO(https://fxbug.dev/42150719): Convert RawDisplayInfo to a table, for |
| // extensibility. The comments about empty vectors will mention members not |
| // being present, instead. |
| |
| /// Collects the information reported by the engine hardware about a display. |
| /// |
| /// The data representation closely matches the formats used by display engine |
| /// hardware. The display coordinator is responsible for parsing these formats |
| /// and converting the information into forms that are more suitable for |
| /// higher-level software. |
| type RawDisplayInfo = resource struct { |
| display_id uint64; |
| |
| /// Operational modes known to be supported by the display. |
| /// |
| /// When this vector is not empty, the display modes here take precedence |
| /// over the modes retrieved from `edid_bytes` and from `eddc_client`. The |
| /// modes are ordered by suitability. The first mode is most preferred. The |
| /// display modes here may overlap with the modes encoded in the display's |
| /// E-EDID. |
| /// |
| /// Drivers for internal (embedded) displays typically report the display's |
| /// only supported operational mode in this member. Drivers that support |
| /// seamless display handoff from a bootloader report the display's initial |
| /// mode in this member. |
| preferred_modes vector<DisplayMode>:MAX_COUNT_DISPLAY_INFO_PREFERRED_MODES; |
| |
| /// Display capabilities, encoded using the E-EDID standard. |
| /// |
| /// E-EDID (Enhanced Extended Display Identification Data) is a VESA |
| /// standard that describes display capabilities as a series of 128-byte |
| /// data blocks. |
| /// |
| /// When this vector is not empty and contains valid E-EDID information, it |
| /// is used as the definitive description of the display's capabilities. In |
| /// this case, the `eddc_client` connection is not used to read E-EDID |
| /// information. |
| /// |
| /// Drivers for external (connected) displays use this member to report the |
| /// display's E-EDID, when it is exposed in a non-standard manner. |
| edid_bytes vector<uint8>:MAX_COUNT_EDID_BYTES; |
| |
| /// Connection to the display's implementation of the E-DDC standard. |
| /// |
| /// E-DDC (Enhanced Display Data Channel) is a VESA standard that describes |
| /// exposing display information over an I2C bus. The information is encoded |
| /// using the VESA E-EDID or DisplayID standards. Displays that offer an |
| /// E-DDC connection may also support DDC/CI (DDC Command Interface) over |
| /// the connection. |
| /// |
| /// When this client is valid, the E-DDC connection may be used to retrieve |
| /// the display's E-EDID information, and may be used to issue DDC/CI |
| /// commands. |
| eddc_client client_end:fuchsia.hardware.i2cimpl.Device; |
| |
| /// A list of pixel formats supported by the display. |
| /// |
| /// The pixel formats modes are ordered by suitability. The first format is |
| /// most preferred. |
| pixel_formats vector<fuchsia.images2.PixelFormat>:MAX_COUNT_DISPLAY_PIXEL_FORMATS; |
| }; |
| |
| /// This protocol is `open` while under development. |
| /// TODO(b/316631158): We should make it `closed` once the API is stabilized. |
| @discoverable |
| @transport("Driver") |
| open protocol Engine { |
| /// Import a sysmem buffer collection token. |
| /// |
| /// Returns ZX_ERR_ALREADY_EXISTS if `collection_id` is in use. |
| flexible ImportBufferCollection(resource struct { |
| buffer_collection_id BufferCollectionId; |
| |
| collection_token client_end:fuchsia.sysmem.BufferCollectionToken; |
| }) -> () error zx.Status; |
| |
| /// Release an imported buffer collection. |
| /// |
| /// Returns ZX_ERR_NOT_FOUND if `collection_id` isn't successfully imported. |
| flexible ReleaseBufferCollection(struct { |
| collection_id uint64; |
| }) -> () error zx.Status; |
| |
| /// Imports an image from a imported BufferCollection into the driver and |
| /// returns its unique ID. |
| /// |
| /// 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. |
| flexible ImportImage(struct { |
| // TODO(https://fxbug.dev/329163718): Some of the information in |
| // `image_metadata` was negotiated by sysmem. The display coordinator or |
| // engine drivers should read that information directly from sysmem. |
| image_metadata fuchsia.hardware.display.types.ImageMetadata; |
| buffer_id BufferId; |
| }) -> (struct { |
| image_id ImageId; |
| }) error 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. |
| /// |
| /// If display capture is not supported, returns ZX_ERR_NOT_SUPPORTED. |
| /// |
| /// 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. |
| flexible ImportImageForCapture(struct { |
| buffer_id BufferId; |
| }) -> (struct { |
| capture_image_id ImageId; |
| }) error zx.Status; |
| |
| /// Releases any driver state associated with the given image. The client |
| /// is expected to not release any images passed to `apply_config` |
| /// until a vsync occurs with a more recent image. |
| flexible ReleaseImage(struct { |
| image_id ImageId; |
| }) -> (); |
| |
| /// 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. |
| /// |
| /// `config_check_result` should be set to a CONFIG_DISPLAY_* error if the |
| /// combination of display modes is not supported. |
| /// |
| /// `client_composition_opcodes` are per-layer client operations |
| /// to make the layer configuration supported by the display hardware. If |
| /// the `config_check_result` is not `CONFIG_CHECK_RESULT_OK`, the values of |
| /// `client_composition_opcodes` are undefined and should be ignored by the |
| /// client. |
| /// |
| /// `client_composition_opcodes` is an array with one element for each |
| /// layer in |
| /// each display_config element. The elements map to layers following a |
| /// DFS traversal of a tree where the first-level children are the |
| /// `display_config` elements, and the second-level children are each |
| /// `DisplayConfig`'s layers. |
| /// |
| /// The element ordering matches flattening the array obtained by mapping |
| /// each display_config element to its `DisplayConfig.layers` value: |
| /// [ display 0 layer 0, display 0 layer 1, ..., |
| /// display 1 layer 0, display 1 layer 1, ..., |
| /// display (N-1) layer 0, ..., display (N-1) layer (M-1) ]. |
| flexible CheckConfiguration(struct { |
| display_config vector<DisplayConfig>:MAX; |
| }) -> (struct { |
| config_check_result fuchsia.hardware.display.types.ConfigResult; |
| client_composition_opcodes |
| vector<fuchsia.hardware.display.types.ClientCompositionOpcode>:MAX; |
| }); |
| |
| /// Applies the configuration. |
| /// |
| /// All configurations passed to this function must 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 `CheckConfiguration`, 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 turning them off. In |
| /// either case, the driver must drop all references to old images and |
| /// invoke the vsync callback after doing so. |
| flexible ApplyConfiguration(struct { |
| display_config vector<DisplayConfig>:MAX; |
| |
| /// Identifies the configuration to be applied. Must be a valid value. |
| /// Must be strictly increasing across calls. |
| config_stamp fuchsia.hardware.display.types.ConfigStamp; |
| }) -> (); |
| |
| /// 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. |
| flexible SetBufferCollectionConstraints(struct { |
| usage fuchsia.hardware.display.types.ImageBufferUsage; |
| buffer_collection_id BufferCollectionId; |
| }) -> () error 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. |
| flexible SetDisplayPower(struct { |
| display_id uint64; |
| power_on bool; |
| }) -> () error zx.Status; |
| |
| /// Set the minimum value of RGB channels. |
| /// |
| /// Returns ZX_ERR_NOT_SUPPORTED if RGB clamping is not supported. |
| /// |
| /// This method is provisional and is only for some display engines. |
| /// Most display drivers willreturn ZX_ERR_NOT_SUPPORTED. |
| // |
| // TODO(https://fxbug.dev/328903017): This is a provisional method meant |
| // to address a hardware issue where RGB channels need to get clamped in |
| // order to reduce backlight bleeding. Revise this method when stabilizing |
| // the Engine protocol API. |
| flexible SetMinimumRgb(struct { |
| /// Must be >= 0 and <= 255. |
| minimum_rgb uint8; |
| }) -> () error zx.Status; |
| |
| /// Returns true iff the display Engine supports capturing the pixels |
| /// on the display device. |
| flexible IsCaptureSupported() -> (struct { |
| is_supported bool; |
| }); |
| |
| /// Starts capture into the resource mapped by `capture_image_id `(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. |
| flexible StartCapture(struct { |
| capture_image_id ImageId; |
| }) -> () error zx.Status; |
| |
| /// Releases resources allocated by `capture_image_id`. |
| /// 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. |
| flexible ReleaseCapture(struct { |
| capture_image_id ImageId; |
| }) -> () error zx.Status; |
| |
| /// Returns true if display capture is supported and the previous capture is |
| /// completed. False otherwise. |
| flexible IsCaptureCompleted() -> (struct { |
| is_capture_completed bool; |
| }); |
| |
| /// Triggered when a previous display capture triggered by [`StartCapture`] |
| /// is completed. |
| /// |
| /// The display Engine emits an [`OnCaptureComplete`] event only if |
| /// [`IsCaptureSupported`] returns `true`. |
| flexible -> OnCaptureComplete(); |
| |
| /// Emitted when a display is connected. |
| /// |
| /// Display Engine drivers must emit this event for all displays connected |
| /// prior to initialization. |
| flexible -> OnDisplayAdded(resource struct { |
| display_info RawDisplayInfo; |
| }); |
| |
| /// Emitted when a display is removed. |
| /// |
| /// `display_id` must be a valid display ID that occurred in a previous |
| /// `OnDisplayAdded()` event. |
| /// |
| /// Display Engine drivers must have finished accessing all images which |
| /// were on the removed display before emitting the `OnDisplayRemoved()` |
| /// event. |
| flexible -> OnDisplayRemoved(struct { |
| display_id uint64; |
| }); |
| |
| /// 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 emit this event as close as possible to the start of |
| /// every display's VSync period, even if the display has no images |
| /// displayed. |
| flexible -> OnDisplayVsync(struct { |
| display_id uint64; |
| timestamp zx.Time; |
| config_stamp box<fuchsia.hardware.display.types.ConfigStamp>; |
| }); |
| |
| // A noop method with a response from the server that should be used |
| // by clients who optionally use this library to determine availability. |
| flexible IsAvailable() -> (); |
| }; |
| |
| service Service { |
| engine client_end:Engine; |
| }; |