blob: 5d1c695765e498ec2cd507b3b07dce39f15e7024 [file] [log] [blame]
// 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;
};