| // 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; |
| |
| using fuchsia.hardware.display.types; |
| using fuchsia.images2; |
| using fuchsia.sysmem; |
| using zx; |
| |
| /// Maximum number of fences supported by |
| /// [`fuchsia.hardware.display/Coordinator.ApplyConfig2`]. |
| const APPLY_CONFIG_MAX_SIGNAL_FENCES uint64 = 32; |
| |
| /// Interface for accessing the display hardware. |
| /// |
| /// A display configuration can be separated into two parts: the layer layout and |
| /// the layer contents. The layout includes all parts of a configuration other |
| /// than the image handles. The active configuration is composed of the most |
| /// recently applied layout and an active image from each layer - see |
| /// SetLayerImage for details on how the active image is defined. Note the |
| /// requirement that each layer has an active image. Whenever a new active |
| /// configuration is available, it is immediately given to the hardware. This |
| /// allows the layout and each layer's contents to advance independently when |
| /// possible. |
| /// |
| /// Performing illegal actions on the interface will result in the interface |
| /// being closed. |
| closed protocol Coordinator { |
| // Event fired when displays are added or removed. This event will be fired |
| // when the callback is registered if there are any connected displays. |
| // |
| // A display change always invalidates the current configuration. When a |
| // client receives this event, they must either apply a new configuration |
| // or revalidate and reapply their current configuration. |
| strict -> OnDisplaysChanged(struct { |
| added vector<Info>:MAX; |
| removed vector<fuchsia.hardware.display.types.DisplayId>:MAX; |
| }); |
| |
| /// Imports a Buffer-Collection backed image. |
| /// |
| /// `image_metadata` must be compatible with the arguments passed to |
| /// [`fuchsia.hardware.display/Coordinator.SetBufferCollectionConstraints`] |
| /// on the `buffer_collection_id`. |
| /// |
| /// Returns `ZX_ERR_NOT_SUPPORTED` if the display hardware doesn't support |
| /// `image_config`. |
| /// Returns `ZX_ERR_ALREADY_EXISTS` if `image_id` was used in a successful |
| /// `ImportImage()` without a corresponding `ReleaseImage()`. |
| strict ImportImage(struct { |
| image_metadata fuchsia.hardware.display.types.ImageMetadata; |
| buffer_id BufferId; |
| image_id ImageId; |
| }) -> () error zx.Status; |
| |
| |
| /// Releases an imported image. |
| /// |
| /// `image_id` must be already imported by |
| /// [`fuchsia.hardware.display/Coordinator.ImportImage`]. |
| /// |
| /// The image must not be the capture target of an ongoing capture specified |
| /// in [`fuchsia.hardware.display/Coordinator.StartCapture`]. |
| /// |
| /// When an image is released, it is immediately removed from any pending |
| /// or active configurations, and any fences associated with the image are |
| /// dropped. The resources associated with the image will be released as |
| /// soon as the image is no longer in use. |
| // |
| // TODO(https://fxbug.dev/42080380): The precondition on capture image |
| // exists because capture images have different constraints on image reuse |
| // compared with non-capture images. We should have a unified design on |
| // image reuse for both capture and non-capture images. |
| strict ReleaseImage(struct { |
| image_id ImageId; |
| }); |
| |
| /// Imports an event into the driver and associates it with the given id. |
| /// |
| /// It is illegal for id to be equal to INVALID_DISP_ID, and it is undefined to |
| /// import one event with two different ids or to import two different events |
| /// with the same id (note that ids map well to koids). |
| /// |
| /// If a client is reusing events, they must clear the signal |
| /// before referencing the id again. |
| strict ImportEvent(resource struct { |
| event zx.Handle:EVENT; |
| id EventId; |
| }); |
| |
| /// Releases the event imported with the given id. |
| /// |
| /// If any images are currently using the given event, the event |
| /// will still be waited up or signaled as appropriate before its |
| /// resources are released. It is an error to reuse an ID while the |
| /// active config has references to it. |
| strict ReleaseEvent(struct { |
| id EventId; |
| }); |
| |
| // Creates a new layer. |
| // |
| // Layers are not associated with a particular display, but they can only be |
| // shown on at most one display at any given time. A layer is considered in |
| // use from the time it is passed to SetDisplayLayers until a subsequent |
| // configuration is applied which does not include the layer or until its |
| // display is removed. |
| strict CreateLayer() -> (struct { |
| layer_id LayerId; |
| }) error zx.Status; |
| |
| // Destroys the given layer. |
| // |
| // It is illegal to destroy a layer which does not exist or which is in use. |
| strict DestroyLayer(struct { |
| layer_id LayerId; |
| }); |
| |
| // Sets the display mode for the given display. |
| // |
| // It is illegal to pass a display mode which was not part of the display's Info. |
| strict SetDisplayMode(struct { |
| display_id fuchsia.hardware.display.types.DisplayId; |
| mode Mode; |
| }); |
| |
| // Set the color conversion applied to the display. The conversion is applied to |
| // to each pixel according to the formula: |
| // |
| // (coefficients * (pixel + preoffsets)) + postoffsets |
| // |
| // where pixel is a column vector consisting of the pixel's 3 components. |
| // |
| // `coefficients` is passed in row-major order. If the first entry of an array is NaN, the |
| // array is treated as the identity element for the relevant operation. |
| // Hardware that support color correction generally accept a limited range of coefficient |
| // values. Coefficients in the range of [-2, 2] inclusive will be accepted by most |
| // hardware. The hardware driver will clamp values that are outside its acceptable range. |
| // |
| // `preoffsets`, `postoffsets`: Clients are encourged to produce color correction values that |
| // do not depend on pre and post offsets since some hardware do not have support for that. |
| // For cases where pre and post offset values need to be used, the range should be limited to |
| // (-1, 1) exclusive as confirmed by CheckConfig API. Values outside this range will be |
| // rejected. |
| // |
| // Clients are encouraged to use the CheckConfig API to confirm support for correction and to |
| // validate their color correction input values. |
| // |
| // This a stateful call. Once color conversion values have been succesfully applied via a call |
| // to ApplyConfig() they will remain in place until changed and another ApplyConfig() call is |
| // successful. If SetDisplayColorConversion() is called and then the config is discarded, then |
| // the last successfully applied state is restored. |
| strict SetDisplayColorConversion(struct { |
| display_id fuchsia.hardware.display.types.DisplayId; |
| preoffsets array<float32, 3>; |
| coefficients array<float32, 9>; |
| postoffsets array<float32, 3>; |
| }); |
| |
| // Sets which layers are on a display. The list is in increasing z-order. |
| // |
| // It is illegal to use a layer on multiple displays concurrently. If a layer |
| // needs to be moved between displays, it must be removed from the first display's |
| // pending config before being added to the second display's pending config. It |
| // is also illegal to pass an invalid layer id. |
| strict SetDisplayLayers(struct { |
| display_id fuchsia.hardware.display.types.DisplayId; |
| layer_ids vector<LayerId>:MAX; |
| }); |
| |
| // Configures the layer as a primary layer with no image and the default |
| // config (no src_frame cropping, the identity transform, positioned in the |
| // top-left corner of the composed output, and no scaling). |
| // |
| // See the documentation on SetLayerImage for details on how this method |
| // affects the layer's contents. |
| // |
| // It is illegal to pass an invalid layer id. |
| strict SetLayerPrimaryConfig(struct { |
| layer_id LayerId; |
| image_metadata fuchsia.hardware.display.types.ImageMetadata; |
| }); |
| |
| // Sets the layer transform, scaling, and positioning. |
| // |
| // `src_frame` must be non-empty and must fit entirely within the source |
| // image. `dest_frame` must be non-empty and must fit entirely within the |
| // composed output. CheckConfig will return INVALID_CONFIG if any of these |
| // conditions is violated. |
| // |
| // Calling this on a non-primary layer or passing an invalid transform |
| // is illegal. |
| strict SetLayerPrimaryPosition(struct { |
| layer_id LayerId; |
| transform fuchsia.hardware.display.types.Transform; |
| src_frame fuchsia.hardware.display.types.Frame; |
| dest_frame fuchsia.hardware.display.types.Frame; |
| }); |
| |
| // Sets the alpha mode of the plane. |
| // |
| // If `mode` == DISABLED, the layer is opaque and `val` is ignored. |
| // |
| // If `mode` == PREMULTIPLIED or HW_MULTIPLY and `val` is NaN, the alpha |
| // used when blending is determined by the per-pixel alpha channel. |
| // |
| // If `mode` == PREMULTIPLIED or HW_MULTIPLY and `val` is not NaN, the |
| // alpha used when blending is the product of `val` and any per-pixel |
| // alpha. Additionally, if `mode` == PREMULTIPLIED, then the hardware |
| // premultiplies the color channel with `val` before blending. |
| // |
| // It is illegal to call this on a non-primary layer, to pass an |
| // invalid mode, or to pass a value of `val` which is not NaN or |
| // in the range [0, 1]. |
| strict SetLayerPrimaryAlpha(struct { |
| layer_id LayerId; |
| mode fuchsia.hardware.display.types.AlphaMode; |
| val float32; |
| }); |
| |
| // Configures the layer as a color layer with the given color in |
| // `pixel_format`. |
| // |
| // `color_bytes` vector is little-endian and of the exact size of one pixel |
| // in `pixel_format`. |
| // |
| // It is illegal to call this on an invalid layer or for the length of |
| // color_bytes to mismatch the size of the supplied format. |
| strict SetLayerColorConfig(struct { |
| layer_id LayerId; |
| pixel_format fuchsia.images2.PixelFormat; |
| color_bytes vector<uint8>:MAX; |
| }); |
| |
| // Sets the image for the layer. |
| // |
| // If wait_event_id corresponds to an imported event, the driver will |
| // wait for ZX_EVENT_SIGNALED on the object before presenting the image. |
| // |
| // If signal_event_id is valid, then the driver will signal the event with |
| // ZX_EVENT_SIGNALED when the image is no longer being presented. |
| // |
| // A layer's active image is the most recently applied image which either has |
| // no wait event or whose wait event has been signaled. Whenever a new image |
| // becomes active, any older images which never became active are dropped, and |
| // their signal events will be fired as soon as their wait events are |
| // signaled. The driver also does not have any concept like 'target vsync', |
| // meaning that if multiple images become active within one vsync period, then |
| // only the last image will actually be displayed. |
| // |
| // By default, the driver retains an active image until a new image becomes |
| // active. However, setting a layer's ImageConfig with SetLayerPrimaryConfig |
| // resets the layer's active and pending images, even if the new ImageConfig |
| // matches the old ImageConfig. |
| // |
| // An image cannot be used for multiple layers simultaneously, nor can an |
| // image be given back to the display coordinator while it is still in use. |
| // An image is considered in use when it is part of a pending configuration |
| // or from when its configuration is applied until its signal_event_id is |
| // signaled. |
| // |
| // It is illegal to call this with an invalid layer or image id, to |
| // call it on a color layer, or to call it with an image and layer whose |
| // ImageConfigs do not match. It is illegal to apply a configuration |
| // with an image layer that has no image (note that is is not illegal to |
| // validate such a configuration). It is illegal to reuse a wait event which |
| // another layer that has not been presented is waiting on. |
| strict SetLayerImage(struct { |
| layer_id LayerId; |
| image_id ImageId; |
| wait_event_id EventId; |
| signal_event_id EventId; |
| }); |
| |
| // Attempts to validate the current configuration. |
| // |
| // When CheckConfig is called, the driver will validate the pending |
| // configuration. If res is UNSUPPORTED_CONFIG, then ops will be |
| // non-empty. |
| // |
| // Most SetX operations require revalidating the configuration. The |
| // following operations do not require revalidation. |
| // * SetLayerImage() |
| // |
| // If discard is true, the pending changes will be discarded after validation. |
| strict CheckConfig(struct { |
| discard bool; |
| }) -> (struct { |
| res fuchsia.hardware.display.types.ConfigResult; |
| ops vector<ClientCompositionOp>:MAX; |
| }); |
| |
| // Applies any pending changes to the current configuration. This will |
| // not apply pending changes to layers which are not on any display. |
| // |
| // If the pending configuration cannot be applied, this call will silently |
| // fail, so the client should ensure its configuration is valid with |
| // CheckConfig. |
| strict ApplyConfig(); |
| |
| // TODO(https://fxbug.dev/42152065): This is a temporary solution to support old |
| // ApplyConfig() with new OnVsync() events. Remove this once the migration |
| // is done. |
| // |
| /// Gets the stamp provided with the latest configuration the client |
| /// submitted (by calling ApplyConfig()) and the display core driver |
| /// accepted; the display configuration may not have been rendered yet |
| /// because of pending image availability or pending layer changes. |
| /// If no configuration was applied before, returns `INVALID_CONFIG_STAMP_VALUE`. |
| strict GetLatestAppliedConfigStamp() -> (struct { |
| stamp fuchsia.hardware.display.types.ConfigStamp; |
| }); |
| |
| /// Applies any pending changes to the current configuration. This will |
| /// not apply pending changes to layers which are not on any display. |
| /// |
| /// For each event in `signal_fences`, once the pending configuration is |
| /// applied to and contents are displayed on all the displays connected to |
| /// the Coordinator, it will be signaled immediately. |
| /// |
| /// Arguments |
| /// |
| /// `signal_fences`: |
| /// Stores all fence events that will be signaled once the configuration |
| /// is applied. |
| /// |
| /// Error handling |
| /// |
| /// If the input is invalid, for example: |
| /// - `signal_fences` contains invalid events |
| /// or the pending configuration cannot be applied, this call will |
| /// silently fail, so the client should ensure its configuration is |
| /// valid with CheckConfig(). |
| // |
| // TODO(https://fxbug.dev/42072277): The current ApplyConfig2() API could cause delay |
| // when there are multiple displays with different refresh rates and vsync |
| // phases. In order to better support multiple displays, we should support |
| // fences to be signaled when configuration is applied to a subset of |
| // displays. |
| // |
| // TODO(https://fxbug.dev/42072361): `signal_fences` should be renamed. The field |
| // should be named to better indicate the timing and semantics when it is |
| // signaled by the display driver. |
| strict ApplyConfig2(resource struct { |
| signal_fences vector<zx.Handle:EVENT>:APPLY_CONFIG_MAX_SIGNAL_FENCES; |
| }); |
| |
| // Sets whether or not vsync events will be given to this client. Defaults |
| // to false. |
| strict EnableVsync(struct { |
| enable bool; |
| }); |
| |
| // This API is used by the client to acknowledge receipt of vsync messages. |
| // The cookie sent should match the cookie received via vsync message (OnVsync). |
| // A cookie can only be acknowledged once. Using invalid cookies, or previously |
| // acknowledged cookies will not be accepted by the driver. |
| strict AcknowledgeVsync(struct { |
| cookie uint64; |
| }); |
| |
| /// Event sent for every vsync. |
| /// |
| /// Arguments |
| /// |
| /// - `display_id` identifies the display on which the vsync occurred. |
| /// |
| /// - `timestamp` indicates the time the vsync occurred. |
| /// |
| /// - `applied_config_stamp` is the stamp of the latest configuration that |
| /// is *fully* applied to the display. For example, if a configuration |
| /// contains images that are still waiting to be ready, the configuration |
| /// will be only partially applied (without the pending image), and thus |
| /// the stamp of this configuration will not appear in Vsync messages |
| /// unless that image becomes ready and display coordinator reapplies |
| /// the configuration fully with the pending image. |
| /// |
| /// The `value` of the stamp MUST NOT be INVALID_CONFIG_STAMP_VALUE. |
| /// |
| /// - `cookie` is a unique number returned by the driver. |
| /// |
| /// Cookie is used to acknowledge the receipt of vsync events using |
| /// `AcknowledgeVsync` API. |
| /// |
| /// When cookie has a value of zero, no acknowledgement is required by the |
| /// client. A non-zero valued cookie requires immediate acknowledgement by |
| /// client. Failure to acknowledge vsync events will result in driver |
| /// suspending vsync event notification. All vsync messages containing a |
| /// non-zero cookie require acknowledgement regardless of whether client |
| /// has applied a (new) configuration or not (via ApplyConfig). |
| /// |
| /// If a client fails to acknowledge vsync messages, the driver will store |
| /// incoming hardware-generated vsyncs in a circular buffer and send them |
| /// to the client once it resumes acknowledgement. Due to limited size of |
| /// buffer, only the most recently received vsyncs will be stored and |
| /// older ones will be dropped. |
| strict -> OnVsync(resource struct { |
| display_id fuchsia.hardware.display.types.DisplayId; |
| timestamp uint64; |
| applied_config_stamp fuchsia.hardware.display.types.ConfigStamp; |
| cookie uint64; |
| }); |
| |
| /// Sets the visibility behavior of the virtcon. |
| /// |
| /// This must only be called from the Virtcon client. |
| strict SetVirtconMode(struct { |
| mode VirtconMode; |
| }); |
| |
| // Event fired when the client gains or loses ownership of the displays. |
| // |
| // New clients should assume they do not have ownership of the display |
| // until this event informs them otherwise. |
| strict -> OnClientOwnershipChange(struct { |
| has_ownership bool; |
| }); |
| |
| // Import a sysmem buffer collection token. `buffer_collection_id` must not |
| // already be in use. |
| strict ImportBufferCollection(resource struct { |
| buffer_collection_id BufferCollectionId; |
| buffer_collection_token client_end:fuchsia.sysmem.BufferCollectionToken; |
| }) -> () error zx.Status; |
| |
| // Release an imported buffer collection. |
| strict ReleaseBufferCollection(struct { |
| buffer_collection_id BufferCollectionId; |
| }); |
| |
| // Takes an imported buffer collection and sets the constraints |
| // on it so that it can be imported with a specific config. |
| // TODO(https://fxbug.dev/42166207): Update this API to better support |
| // optional fields. |
| strict SetBufferCollectionConstraints(struct { |
| buffer_collection_id BufferCollectionId; |
| buffer_usage fuchsia.hardware.display.types.ImageBufferUsage; |
| }) -> () error zx.Status; |
| |
| /// Returns true if Capture is supported on the platform. |
| strict IsCaptureSupported() -> (struct { |
| supported bool; |
| }) error zx.Status; |
| |
| /// Starts capture. Client must provide a valid signal_event_id and |
| /// image_id. signal_event_id must have been imported into the driver |
| /// using ImportEvent FIDL API. Image_id is the id from ImportImageForCapture. |
| /// The client will get notified once capture is complete via signal_event_id. |
| /// Returns ZX_ERR_NOT_SUPPORTED if coordinator does not support capture |
| strict StartCapture(struct { |
| signal_event_id EventId; |
| image_id ImageId; |
| }) -> () error zx.Status; |
| |
| /// Set the minimum value of rgb channels. Valid range [0 255] inclusive. Returns |
| /// ZX_ERR_NOT_SUPPORTED when the display hardware does not support this feature. |
| /// This API is meant to address backlight bleeding that may occur on some hardware |
| /// that have a specific type of panel and hardware assembly. The evolution of this |
| /// API is highly hardware and product dependant and therefore as products evolve, this |
| /// API may change or support for this API may become non-existent. Therefore, this |
| /// API should be used with caution. |
| /// |
| /// Unlike other calls in this API, SetMiniumRgb is applied immediately, and does not |
| /// wait for ApplyConfig(). It is, however, still stateful. |
| strict SetMinimumRgb(struct { |
| minimum_rgb uint8; |
| }) -> () error zx.Status; |
| |
| /// Power off/on the display panel. |
| /// |
| /// This function takes effect immediately. Clients don't need to call |
| /// `ApplyConfig()` to commit this command. |
| /// |
| /// Once a display is turned off, it will not deliver vsync events, which |
| /// may include the vsync event for the most recently applied config. |
| /// |
| /// Staged display control commands (e.g. SetDisplayLayer) will not be |
| /// affected. They are still applied to the display device when client calls |
| /// `ApplyConfig()`, but the contents will be shown on display panel only |
| /// after client powers on the display again. |
| /// |
| /// Newly added displays are turned on by default. |
| /// |
| /// Returns ZX_ERR_NOT_FOUND if `display_id` is invalid when Coordinator |
| /// handles this method. |
| /// Returns ZX_ERR_NOT_SUPPORTED if the display driver IC doesn't support |
| /// turning on/off displays. |
| strict SetDisplayPower(struct { |
| display_id fuchsia.hardware.display.types.DisplayId; |
| power_on bool; |
| }) -> () error zx.Status; |
| }; |