blob: d0066c4f0b7e70d04171dfbfb32b92c6da74bf1f [file] [log] [blame] [edit]
// 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.math;
using fuchsia.sysmem2;
using zx;
/// Provides updates from a `Coordinator` to one of its clients.
///
/// This protocol solely consists of one-way methods.
open protocol CoordinatorListener {
/// Called when the set of connected displays changes.
///
/// Also used to communicate the set of connected displays to a newly
/// connected client.
///
/// After this method is called, all applied and draft configurations may no
/// longer be valid. The client must validate and apply a new configuration,
/// by calling [`Coordinator.CheckConfig`] and [`Coordinator.ApplyConfig`].
///
/// `added` and `removed` must not be both empty.
strict OnDisplaysChanged(struct {
added vector<Info>:MAX;
removed vector<fuchsia.hardware.display.types.DisplayId>:MAX;
});
/// Called on every display Vertical Synchronization (Vsync).
///
/// Clients must acknowledge VSync events via the method
/// [`Coordinator.AcknowledgeVsync`]. The coordinator may throttle a client
/// that accumulates a certain number of unacknowledged VSync cookies.
/// Throttled clients do not receive VSync events.
///
/// After a the client catches up on acknowledging cookies, the coordinator
/// will unthrottle it (resume sending VSync events). Throttled clients may
/// miss some VSync events, as the coordinator is allowed to drop VSync
/// event information for throttled clients.
///
/// When dropping VSync event information for throttled clients, the
/// coordinator should prioritize retaining the information for newer
/// events. In other words, the oldest unreported events should be dropped
/// first.
strict OnVsync(struct {
/// The display associated with the VSync event.
display_id fuchsia.hardware.display.types.DisplayId;
/// The time when the VSync occurred.
///
/// The accurrancy of this timestamp depends on the display hardware.
timestamp zx.Time;
/// Identifies the lastest configuration fully applied to the display.
///
/// Guaranteed to be a valid value.
///
/// If a configuration contains images that are still waiting to be
/// ready, that configuration will be only partially applied (without
/// the waiting image). That configuration's stamp will not be reported
/// here.
applied_config_stamp ConfigStamp;
/// Used to acknowledge the receipt of VSync events.
///
/// A value of zero means no acknowledgement is required by the
/// client.
///
/// Each non-zero cookie must be acknowledged immediately, via a call to
/// [`Coordinator.AcknowledgeVsync`]. Cookies must be acknowledged even
/// if the client does not change the display's configuration.
cookie VsyncAckCookie;
});
/// Called when the corresponding `Coordinator` client gains or loses
/// ownership of the displays.
///
/// A `Coordinator` client's active config is displayed iff it holds the
/// ownership of the displays.
///
/// A new `Coordinator` client should assume they do not have ownership
/// of the displays until this method informs them otherwise.
strict OnClientOwnershipChange(struct {
has_ownership bool;
});
};
/// Constrains the use of `Coordinator.SetLayerImage2`; see documentation there.
const MAX_WAITING_IMAGES_PER_LAYER uint32 = 10;
/// 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. The channel closure epitaph will return one of 4 values:
/// - ZX_ERR_INVALID_ARGS: for trivially-verifiable client errors, such as providing an ID for a
/// nonexistent image/layer/event, or a non-monotonically-increasing config stamp to
/// ApplyConfig, etc.
/// - ZX_ERR_BAD_STATE: indicates that the client has violated other API invariants, such as reusing
/// an event that hasn't been signaled yet.
/// - ZX_ERR_NO_MEMORY: memory could not be allocated to satisfy the requested operation.
/// - ZX_ERR_INTERNAL: catch-all used for any error that is not listed above.
closed protocol Coordinator {
/// 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()`.
/// Returns `ZX_ERR_INVALID_ARGS` for a variety of reasons, such as:
/// - `image_id` is invalid
/// - `buffer_id` does not refer to an already-imported buffer collection
/// - `image_metadata.dimensions` have negative width/height, or exceed maximums
/// Returns `ZX_ERR_NO_MEMORY` if memory cannot be allocated for managing the image
/// Additionally, this method delegates internally to `fuchsia.hardware.display.engine/Engine`,
/// and will forward errors received from `ImportImage()` and `ImportImageForCapture()`.
// TODO(https://fxbug.dev/391698891): it's undesirable to expose this implementation dependency
// on `fuchsia.hardware.display.engine/Engine`.
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 draft
/// 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 mode for a display.
strict SetDisplayMode(struct {
/// The display whose mode is changed.
///
/// The call is ignored if the display ID does not belong to a display
/// known by the Coordinator. This can happen if a client issues a call
/// to [`Coordinator.SetDisplayMode`] before it receives a notification
/// that the display was removed.
display_id fuchsia.hardware.display.types.DisplayId;
/// The new mode for the display.
///
/// Must be one of the [`Info.modes`] entries for the display.
mode fuchsia.hardware.display.types.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 {
/// The display whose color coefficients are set.
///
/// The call is ignored if the display ID does not belong to a display
/// known by the Coordinator. This can happen if a client issues a call
/// to [`Coordinator.SetDisplayColorConversion`] before it receives a
/// notification that the display was removed.
display_id fuchsia.hardware.display.types.DisplayId;
preoffsets array<float32, 3>;
coefficients array<float32, 9>;
postoffsets array<float32, 3>;
});
/// Assigns a list of layers to be composited on a display.
strict SetDisplayLayers(struct {
/// The display that will show the result of compositing the layers.
///
/// The call is ignored if the display ID does not belong to a display
/// known by the Coordinator. This can happen if a client issues a call
/// to [`Coordinator.SetDisplayLayers`] before it receives a
/// notification that the display was removed.
display_id fuchsia.hardware.display.types.DisplayId;
// The layers to be composited on the display.
//
// The layers are listed in increasing Z-order.
//
// The list must not be empty, and each ID must be valid.
//
// Each layer ID must not be composited on any another display. Moving a
// layer between displays is accomplished by first removing the layer
// from its current display, via a call to
// [`Coordinator.SetDisplayLayers`] that does not include the layer's
// ID.
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.
///
/// CheckConfig() will return INVALID_CONFIG if any of the configuration
/// validity conditions specified here is violated.
///
/// Calling this on a non-primary layer or passing an invalid transform is
/// illegal.
strict SetLayerPrimaryPosition(struct {
layer_id LayerId;
/// Applied to the input image pixels specified by `image_source`.
///
/// `display_destination` must account for image dimensions changes
/// caused by rotations. For example, rotating a 600x300 pixel image by
/// 90 degrees would specify 300x600 pixel dimensions in
/// `display_destination`.
image_source_transformation fuchsia.hardware.display.types.CoordinateTransformation;
/// The associated image region whose pixels are drawn by the layer.
///
/// The rectangle uses the Vulkan coordinate space. The origin is at the
/// image's top-left corner. The X axis points to the right, and the Y
/// axis points downwards.
///
/// A valid layer definition requires a valid non-empty image source
/// rectangle that is entirely contained within the image.
///
/// Hardware image cropping is requested implicitly, when the source
/// region's dimensions differ from the image's dimensions. Some display
/// hardware may not support cropping.
image_source fuchsia.math.RectU;
/// The display image (composited output) region occupied by the layer.
///
/// The rectangle uses the Vulkan coordinate space. The origin is at the
/// display's top-left corner. The X axis points to the right, and the Y
/// axis points downwards.
///
/// A valid layer definition requires a valid non-empty display
/// destination rectangle that is entirely contained within the display.
///
/// Hardware image scaling is requested implicitly, when the output
/// region's dimensions differ from the dimensions of `image_source`.
/// Some display hardware may not support scaling. All display hardware
/// has limitations in scaling support.
display_destination fuchsia.math.RectU;
});
/// 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 solid color fill layer.
///
/// It is illegal to call this on an invalid layer.
strict SetLayerColorConfig(struct {
layer_id LayerId;
color fuchsia.hardware.display.types.Color;
});
/// Sets the image for the layer's draft configuration.
///
/// If wait_event_id corresponds to an imported event, the driver will
/// wait for ZX_EVENT_SIGNALED on the object before presenting the image.
///
/// A layer's applied image is the most recently applied image which either has
/// no wait event or whose wait event has been signaled. Whenever a new image
/// is applied, any older images which never got applied 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 are applied within one vsync period, then
/// only the last image will actually be displayed.
///
/// By default, the driver retains an applied image until a new image is
/// applied. However, setting a layer's ImageConfig with SetLayerPrimaryConfig
/// resets the layer's applied and waiting 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 draft configuration
/// or from when its configuration is applied until it is replaced by a
/// subsequent configuration that is *displayed* (not merely applied).
///
/// 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.
///
/// Each layer can track a maximum of `MAX_WAITING_IMAGES_PER_LAYER` waiting images.
/// An image becomes "waiting" when it is the most recent image set to a layer that appears in
/// a config that is applied via `ApplyConfig()` or similar. To avoid exceeding the maximum,
/// the client can infer that the image is no longer waiting by:
/// - noting the config stamp when the config containing the layer/image is applied
/// - watching for that same (or later) config stamp to be returned by
/// `CoordinatorListener.OnVsync()`.
strict SetLayerImage2(struct {
layer_id LayerId;
image_id ImageId;
wait_event_id EventId;
});
/// Validates the draft configuration.
///
/// Validation entails checking that the draft configuration can be used
/// by the system's display hardware.
///
/// Most SetX operations require verifying the draft configuration. The
/// following operations do not require revalidation.
/// * SetLayerImage2()
///
strict CheckConfig() -> (struct {
res fuchsia.hardware.display.types.ConfigResult;
});
/// Discard all draft configuration changes.
strict DiscardConfig();
// TODO(https://fxbug.dev/42152065): Deprecated; use ApplyConfig3() instead.
// 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 draft layer changes.
/// If no configuration was applied before, returns `INVALID_CONFIG_STAMP_VALUE`.
strict GetLatestAppliedConfigStamp() -> (struct {
stamp ConfigStamp;
});
/// Applies any draft changes to the current configuration. This will
/// not apply draft changes to layers which are not on any display.
///
/// If the draft configuration cannot be applied, this call will silently
/// fail, so the client should ensure its configuration is valid by
/// calling [`Coordinator.CheckConfig`].
strict ApplyConfig3(resource table {
/// Required. Must be valid and strictly monotonically-increasing.
1: stamp ConfigStamp;
});
/// Configures the client's preferences for VSync event delivery.
///
/// VSync event delivery is disabled by default. Clients interested in
/// receiving VSync events must explicitly enable their delivery.
strict SetVsyncEventDelivery(struct {
/// If false, the client will not receive `OnVsync` messages.
vsync_delivery_enabled bool;
});
/// Acknowledges the receipt of one `OnVsync` message.
strict AcknowledgeVsync(struct {
/// The cookie received in the most recent `OnVsync` message.
///
/// Must not be zero. Zero cookies do not require acknowledgement.
///
/// Each cookie must be acknowledged exactly once. Cookies must
/// be acknowledged in the order of their receipt.
cookie uint64;
});
/// Sets the visibility behavior of the virtcon.
///
/// This must only be called from the Virtcon client.
strict SetVirtconMode(struct {
mode VirtconMode;
});
/// 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.sysmem2.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 call takes effect immediately. Clients don't need to call
/// [`Coordinator.ApplyConfig`].
///
/// Fails with ZX_ERR_NOT_FOUND if `display_id` does not belong to a display
/// known by the Coordinator. This can happen if a client issues a call to
/// [`Coordinator.SetDisplayPower`] before it receives a notification that
/// the display was removed.
///
/// Fails with ZX_ERR_NOT_SUPPORTED if the display drivers or the hardware
/// don't support displays on and off.
strict SetDisplayPower(struct {
display_id fuchsia.hardware.display.types.DisplayId;
/// True powers on the display, false powers it off.
///
/// Once a display is turned off, the hardware will not generate new
/// VSync events. However, the client should be prepared to handle VSync
/// events generated before the [`Coordinator.SetDisplayPower`] call
/// reaches the hardware.
///
/// Calls that impact draft configurations, such as
/// [`Coordinator.SetDisplayLayers`], still work while the display is
/// powered off.
///
/// [`Coordinator.ApplyConfig`] also works while the display is powered
/// off. When the display is powered back on on, it will show the
/// latest applied configuration.
///
/// Newly added displays are powered on.
power_on bool;
}) -> () error zx.Status;
};