typedef enum {
TDM_DISPLAY_CAPABILITY_PP = (1 << 0), /**< if hardware supports pp operation */
TDM_DISPLAY_CAPABILITY_CAPTURE = (1 << 1), /**< if hardware supports capture operation */
+ TDM_DISPLAY_CAPABILITY_HWC = (1 << 2), /**< if hardware supports hwc operation */
} tdm_display_capability;
/**
tdm_output_create_capture(tdm_output *output, tdm_error *error);
/**
+ * @brief Creates a new window on the given display.
+ * @param[in] output A output object
+ * @param[out] error #TDM_ERROR_NONE if success. Otherwise, error value.
+ * @return A created window object
+ */
+tdm_hwc_window *
+tdm_output_create_hwc_window(tdm_output *output, tdm_error *error);
+
+/**
+ * @brief Destroys the given window.
+ * @param[in] output A output object
+ * @param[in] window the pointer of the window to destroy
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_output_destroy_hwc_window(tdm_output *output, tdm_hwc_window *hwc_window);
+
+/**
+ * @brief Set the client(relative to the TDM) target buffer
+ * @details Sets the buffer which will receive the output of client composition.
+ * Window marked as TDM_COMPOSITION_CLIENT or TDM_COMPOSITION_DEVICE_CANDIDATE
+ * will be composited into this buffer prior to the call to tdm_output_commit(),
+ * and windows not marked as TDM_COMPOSITION_CLIENT and
+ * TDM_COMPOSITION_DEVICE_CANDIDATE should be composited with this buffer by the
+ * device.
+ *
+ * The buffer handle provided may be null if no windows are being composited by
+ * the client. This must not result in an error (unless an invalid display
+ * handle is also provided).
+ *
+ * The damage parameter describes a surface damage region as defined in the
+ * description of tdm_hwc_window_set_surface_damage().
+ *
+ * Will be called before tdm_output_commit() if any of the layers are marked as
+ * TDM_COMPOSITION_CLIENT or TDM_COMPOSITION_DEVICE_CANDIDATE. If no layers are
+ * so marked, then it is not necessary to call this function. It is not necessary
+ * to call tdm_output_validate() after changing the target through this function.
+ * @param[in] output A output object
+ * @param[in] target The new target buffer
+ * @param[in] damage The surface damage region
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_output_set_client_target_buffer(tdm_output *output, tbm_surface_h target,
+ tdm_hwc_region damage);
+
+/**
+ * @brief Validate the output
+ * @details Instructs the device to inspect all of the layer state and
+ * determine if there are any composition type changes necessary before
+ * presenting the output. Permitted changes are described in the definition
+ * of tdm_hwc_window_composition_t above.
+ * @param[in] output A output object
+ * @param[out] num_types The number of composition type changes required by
+ * the device; if greater than 0, the client must either set and validate new
+ * types, or call tdm_output_accept_changes() to accept the changes returned by
+ * tdm_output_get_changed_composition_types(); must be the same as the number of
+ * changes returned by tdm_output_get_changed_composition_types (see the
+ * declaration of that function for more information); pointer will be non-NULL
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_output_validate(tdm_output *output, uint32_t *num_types);
+
+/**
+ * @brief Get changed composition types
+ * @details Retrieves the windows for which the device requires a different
+ * composition type than had been set prior to the last call to tdm_output_validate().
+ * The client will either update its state with these types and call
+ * tdm_output_accept_changes, or will set new types and attempt to validate the
+ * display again.
+ * windows and types may be NULL to retrieve the number of elements which
+ * will be returned. The number of elements returned must be the same as the
+ * value returned in num_types from the last call to tdm_output_validate().
+ * @param[in] output A output object
+ * @param[out] num_elements If windows or types were NULL, the number of layers
+ * and types which would have been returned; if both were non-NULL, the
+ * number of elements returned in layers and types, which must not exceed
+ * the value stored in num_elements prior to the call; pointer will be
+ * non-NULL
+ * @param[in] output A output object
+ * @param[out] windows An array of windows
+ * @param[out] composition_types An array of composition types, each corresponding
+ * to an element of windows
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_output_get_changed_composition_types(tdm_output *output,uint32_t *num_elements,
+ tdm_hwc_window **hwc_window,
+ tdm_hwc_window_composition_t *composition_types);
+
+/**
+ * @brief Accepts the changes required by the device
+ * @details Accepts the changes required by the device from the previous
+ * tdm_output_validate() call (which may be queried using
+ * tdm_output_get_chaged_composition_types()) and revalidates the display. This
+ * function is equivalent to requesting the changed types from
+ * tdm_output_get_chaged_composition_types(), setting those types on the
+ * corresponding windows, and then calling tdm_output_validate again.
+ * After this call it must be valid to present this display. Calling this after
+ * tdm_output_validate() returns 0 changes must succeed with TDM_ERROR_NONE, but
+ * should have no other effect.
+ * @param[in] output A output object
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_output_accept_changes(tdm_output *output);
+
+/**
+ * @brief Get a target surface queue
+ * @details Surfaces from target surface queue will receive the output of
+ * client composition. Window marked as TDM_COMPOSITION_CLIENT or
+ * TDM_COMPOSITION_DEVICE_CANDIDATE will be composited into this surfaces
+ * prior to the call to tdm_output_commit().
+ * @param[in] output A output object
+ * @param[out] error #TDM_ERROR_NONE if success. Otherwise, error value.
+ * @return A surface queue
+ */
+tbm_surface_queue_h
+tdm_output_get_target_surface_queue(tdm_output *output, tdm_error *error);
+
+/**
* @brief Get the capabilities of a layer object.
* @param[in] layer A layer object
* @param[out] capabilities The capabilities of a layer object
tdm_layer_get_buffer_flags(tdm_layer *layer, unsigned int *flags);
/**
+ * @brief Get a tbm surface queue for the window object
+ * @details These surfaces are used to composite by hardware a client content in
+ * the nocomp mode.
+ * @param[in] hwc_window A window object
+ * @param[out] error #TDM_ERROR_NONE if success. Otherwise, error value.
+ * @return A tbm surface queue
+ */
+tbm_surface_queue_h
+tdm_hwc_window_get_tbm_surface_queue(tdm_hwc_window *hwc_window, tdm_error *error);
+
+/**
+ * @brief Sets the desired Z order of the given window. A window with
+ * a greater Z value occludes a window with a lesser Z value.
+ * @param[in] hwc_window A window object
+ * @param[in] z the new Z order
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_hwc_window_set_zpos(tdm_hwc_window *hwc_window, uint32_t zpos);
+
+/**
+ * @brief Sets the desired composition type of the given window.
+ * @details During tdm_output_validate(), the device may request changes to
+ * the composition types of any of the layers as described in the definition
+ * of tdm_hwc_window_composition_t above.
+ * @param[in] hwc_window A window object
+ * @param[in] composition_type The new composition type
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_hwc_window_set_composition_type(tdm_hwc_window *hwc_window,
+ tdm_hwc_window_composition_t composition_type);
+
+/**
+ * @brief Set the surface damage
+ * @details Provides the region of the source buffer which has been modified
+ * since the last frame. This region does not need to be validated before
+ * calling tdm_output_commit().
+ * Once set through this function, the damage region remains the same until a
+ * subsequent call to this function.
+ * If damage.num_rects > 0, then it may be assumed that any portion of the source
+ * buffer not covered by one of the rects has not been modified this frame. If
+ * damage.num_rects == 0, then the whole source buffer must be treated as if it
+ * has been modified.
+ * If the layer's contents are not modified relative to the prior frame, damage
+ * will contain exactly one empty rect([0, 0, 0, 0]).
+ * The damage rects are relative to the pre-transformed buffer, and their origin
+ * is the top-left corner. They will not exceed the dimensions of the latched
+ * buffer.
+ * @param[in] hwc_window A window object
+ * @param[in] damage The new surface damage region
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_hwc_window_set_surface_damage(tdm_hwc_window *hwc_window, tdm_hwc_region damage);
+
+/**
+ * @brief Set the information to a window object
+ * @details The information will be applied when the output object of a window
+ * object is committed.
+ * @param[in] hwc_window A window object
+ * @param[in] info The information
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info);
+
+/**
+ * @brief Set a TBM buffer to a window object
+ * @details A TBM buffer will be applied when the output object of a layer
+ * object is committed.
+ * @param[in] hwc_window A layer object
+ * @param[in] buffer A TDM buffer
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer);
+
+/**
* @brief Destroy a pp object
* @param[in] pp A pp object
* @see tdm_display_create_pp
tdm_error (*output_set_dpms_handler)(tdm_output *output,
tdm_output_dpms_handler func,
void *user_data);
- void (*reserved2)(void);
- void (*reserved3)(void);
- void (*reserved4)(void);
- void (*reserved5)(void);
- void (*reserved6)(void);
- void (*reserved7)(void);
- void (*reserved8)(void);
+ /**
+ * @brief Creates a new window on the given display.
+ * @param[in] output A output object
+ * @param[out] error #TDM_ERROR_NONE if success. Otherwise, error value.
+ * @return A created window object
+ */
+ tdm_hwc_window *(*output_create_hwc_window)(tdm_output *output, tdm_error *error);
+
+ /**
+ * @brief Destroys the given window.
+ * @param[in] output A output object
+ * @param[in] window the pointer of the window to destroy
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+ tdm_error (*output_destroy_hwc_window)(tdm_output *output, tdm_hwc_window *hwc_window);
+
+ /**
+ * @brief Set the client(relative to the TDM) target buffer
+ * @details Sets the buffer which will receive the output of client composition.
+ * Window marked as TDM_COMPOSITION_CLIENT or TDM_COMPOSITION_DEVICE_CANDIDATE
+ * will be composited into this buffer prior to the call to output_commit(),
+ * and windows not marked as TDM_COMPOSITION_CLIENT and
+ * TDM_COMPOSITION_DEVICE_CANDIDATE should be composited with this buffer by the
+ * device.
+ *
+ * The buffer handle provided may be null if no windows are being composited by
+ * the client. This must not result in an error (unless an invalid display
+ * handle is also provided).
+ *
+ * The damage parameter describes a surface damage region as defined in the
+ * description of hwc_window_set_surface_damage().
+ *
+ * Will be called before output_commit() if any of the layers are marked as
+ * TDM_COMPOSITION_CLIENT or TDM_COMPOSITION_DEVICE_CANDIDATE. If no layers are
+ * so marked, then it is not necessary to call this function. It is not necessary
+ * to call output_validate() after changing the target through this function.
+ * @param[in] output A output object
+ * @param[in] target The new target buffer
+ * @param[in] damage The surface damage region
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+ tdm_error (*output_set_client_target_buffer)(tdm_output *output, tbm_surface_h target,
+ tdm_hwc_region damage);
+
+ /**
+ * @brief Validate the output
+ * @details Instructs the device to inspect all of the layer state and
+ * determine if there are any composition type changes necessary before
+ * presenting the output. Permitted changes are described in the definition
+ * of tdm_composition_t above.
+ * @param[in] output A output object
+ * @param[out] num_types The number of composition type changes required by
+ * the device; if greater than 0, the client must either set and validate new
+ * types, or call output_accept_changes() to accept the changes returned by
+ * output_get_changed_composition_types(); must be the same as the number of
+ * changes returned by output_get_changed_composition_types (see the
+ * declaration of that function for more information); pointer will be non-NULL
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+ tdm_error (*output_validate)(tdm_output *output, uint32_t *num_types);
+
+ /**
+ * @brief Get changed composition types
+ * @details Retrieves the windows for which the device requires a different
+ * composition type than had been set prior to the last call to output_validate().
+ * The client will either update its state with these types and call
+ * output_accept_changes, or will set new types and attempt to validate the
+ * display again.
+ * layers and types may be NULL to retrieve the number of elements which
+ * will be returned. The number of elements returned must be the same as the
+ * value returned in num_types from the last call to output_validate().
+ * @param[in] output A output object
+ * @param[out] num_elements If windows or types were NULL, the number of layers
+ * and types which would have been returned; if both were non-NULL, the
+ * number of elements returned in layers and types, which must not exceed
+ * the value stored in num_elements prior to the call; pointer will be
+ * non-NULL
+ * @param[out] windows An array of windows
+ * @param[out] composition_types An array of composition types, each
+ * corresponding to an element of windows
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+ tdm_error (*output_get_changed_composition_types)(tdm_output *output,
+ uint32_t *num_elements,
+ tdm_hwc_window **hwc_window,
+ tdm_hwc_window_composition_t *composition_types);
+ /**
+ * @brief Accepts the changes required by the device
+ * @details Accepts the changes required by the device from the previous
+ * output_validate() call (which may be queried using
+ * output_get_chaged_composition_types()) and revalidates the display. This
+ * function is equivalent to requesting the changed types from
+ * output_get_chaged_composition_types(), setting those types on the
+ * corresponding windows, and then calling output_validate again.
+ * After this call it must be valid to present this display. Calling this after
+ * output_validate() returns 0 changes must succeed with TDM_ERROR_NONE, but
+ * should have no other effect.
+ * @param[in] output A output object
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+ tdm_error (*output_accept_changes)(tdm_output *output);
+
+ /**
+ * @brief Get a target surface queue
+ * @param[in] output A output object
+ * @param[out] error #TDM_ERROR_NONE if success. Otherwise, error value.
+ * @return A surface queue
+ */
+ tbm_surface_queue_h (*output_get_target_surface_queue)(tdm_output *output,
+ tdm_error *error);
} tdm_func_output;
/**
} tdm_func_layer;
/**
+ * @brief The window functions for a backend module.
+ */
+typedef struct _tdm_func_window {
+ /**
+ * @brief Get a tbm surface queue for the window object
+ * @param[in] hwc_window A window object
+ * @param[out] error #TDM_ERROR_NONE if success. Otherwise, error value.
+ * @return A tbm surface queue
+ */
+ tbm_surface_queue_h (*hwc_window_get_tbm_surface_queue)(tdm_hwc_window *hwc_window,
+ tdm_error *error);
+
+ /**
+ * @brief Sets the desired Z order (height) of the given window. A window with
+ * a greater Z value occludes a window with a lesser Z value.
+ * @param[in] hwc_window A window object
+ * @param[in] z the new Z order
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+ tdm_error (*hwc_window_set_zpos)(tdm_hwc_window *hwc_window, uint32_t zpos);
+
+ /**
+ * @brief Sets the desired composition type of the given window.
+ * @details During output_validate(), the device may request changes to
+ * the composition types of any of the layers as described in the definition
+ * of tdm_hwc_window_composition_t above.
+ * @param[in] hwc_window A window object
+ * @param[in] composition_type The new composition type
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+ tdm_error (*hwc_window_set_composition_type)(tdm_hwc_window *hwc_window,
+ tdm_hwc_window_composition_t composition_type);
+
+ /**
+ * @brief Set the surface damage
+ * @details Provides the region of the source buffer which has been modified
+ * since the last frame. This region does not need to be validated before
+ * calling output_commit().
+ * Once set through this function, the damage region remains the same until a
+ * subsequent call to this function.
+ * If damage.num_rects > 0, then it may be assumed that any portion of the source
+ * buffer not covered by one of the rects has not been modified this frame. If
+ * damage.num_rects == 0, then the whole source buffer must be treated as if it
+ * has been modified.
+ * If the layer's contents are not modified relative to the prior frame, damage
+ * will contain exactly one empty rect([0, 0, 0, 0]).
+ * The damage rects are relative to the pre-transformed buffer, and their origin
+ * is the top-left corner. They will not exceed the dimensions of the latched
+ * buffer.
+ * @param[in] hwc_window A window object
+ * @param[in] damage The new surface damage region
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+ tdm_error (*hwc_window_set_surface_damage)(tdm_hwc_window *hwc_window,
+ tdm_hwc_region damage);
+
+ /**
+ * @brief Set the information to a window object
+ * @details The information will be applied when the output object
+ * of a layer object is committed.
+ * @param[in] hwc_window A window object
+ * @param[in] info The geometry information
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+ tdm_error (*hwc_window_set_info)(tdm_hwc_window *hwc_window,
+ tdm_hwc_window_info *info);
+
+ /**
+ * @brief Set a TDM buffer to a window object
+ * @details A TDM buffer will be applied when the output object
+ * of a layer object is committed.
+ * @param[in] hwc_window A layer object
+ * @param[in] buffer A TDM buffer
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+ tdm_error (*hwc_window_set_buffer)(tdm_hwc_window *hwc_window,
+ tbm_surface_h buffer);
+} tdm_func_hwc_window;
+
+/**
* @brief The pp functions for a backend module.
*/
typedef struct _tdm_func_pp {
tdm_backend_register_func_layer(tdm_display *dpy, tdm_func_layer *func_layer);
/**
+ * @brief Register the backend hwc_window functions to a display
+ * @param[in] dpy A display object
+ * @param[in] func_hwc_window hwc_window functions
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ * @see tdm_backend_register_func_display, tdm_backend_register_func_output
+ * @remarks
+ * A backend module @b SHOULD set the backend hwc_window functions at least.
+ */
+tdm_error
+tdm_backend_register_func_hwc_window(tdm_display *dpy, tdm_func_hwc_window *func_hwc_window);
+
+/**
* @brief Register the backend pp functions to a display
* @param[in] dpy A display object
* @param[in] func_pp pp functions
unsigned int h;
} tdm_pos;
+typedef struct _tdm_hwc_region {
+ unsigned int num_rects;
+ tdm_pos const *rects;
+} tdm_hwc_region;
+
/**
* @brief The tdm value type enumeration
*/
} tdm_info_layer;
/**
+ * @brief The hwc window info structure
+ */
+typedef struct _tdm_hwc_window_info {
+ tdm_info_config src_config;
+ tdm_pos dst_pos;
+ tdm_transform transform;
+} tdm_hwc_window_info;
+
+/**
* @brief The pp info structre
*/
typedef struct _tdm_info_pp {
} tdm_info_capture;
/**
+ * @brief Possible composition types for a given window
+ */
+typedef enum {
+ /** The client will composite this window into the client target window
+ *
+ * User can choose this type for window to avoid a hardware composition for
+ * this window.
+ *
+ * The device must not request any composition type changes for windows of
+ * this type.
+ */
+ TDM_COMPOSITION_CLIENT = 0,
+
+ /** Set by the client before tdm_output_validate().
+ *
+ * Upon tdm_output_validate(), the device may request a change from this type to
+ * TDM_COMPOSITION_DEVICE or TDM_COMPOSITION_CLIENT. */
+ TDM_COMPOSITION_DEVICE_CANDIDATE = 2,
+
+ /** Set by the HWC after tdm_output_validate().
+ *
+ * The device will handle the composition of this window through a hardware
+ * overlay or other similar means.
+ *
+ * Upon tdm_output_validate(), the device may request a change from this type to
+ * TDM_COMPOSITION_CLIENT or TDM_COMPOSITION_DEVICE_CANDIDATE. */
+ TDM_COMPOSITION_DEVICE = 1,
+
+ /** Similar to DEVICE, but the position of this layer may also be set
+ * asynchronously through layer_set_cursor_position. If this functionality is not
+ * supported on a layer that the client sets to TDM_COMPOSITION_CURSOR, the
+ * device must request that the composition type of that layer is changed to
+ * TDM_COMPOSITION_CLIENT upon the next call to tdm_output_validate().
+ *
+ * Upon tdm_output_validate(), the device may request a change from this type to
+ * either TDM_COMPOSITION_DEVICE or TDM_COMPOSITION_CLIENT. Changing to
+ * TDM_COMPOSITION_DEVICE will prevent the use of layer_set_cursor_position but
+ * still permit the device to composite the layer. */
+ TDM_COMPOSITION_CURSOR = 3,
+
+ /** The device will handle the composition of this layer through a hardware
+ * overlay or other similar means.
+ *
+ * Upon tdm_output_validate(), the device may request a change from this type to
+ * either TDM_COMPOSITION_DEVICE or TDM_COMPOSITION_CLIENT, but it is
+ * unlikely that content will display correctly in these cases. */
+ TDM_COMPOSITION_VIDEO = 4,
+} tdm_hwc_window_composition_t;
+
+/**
* @brief The tdm display object
*/
typedef void tdm_display;
typedef void tdm_layer;
/**
+ * @brief The tdm window object
+ */
+typedef void tdm_hwc_window;
+
+/**
* @brief The tdm capture object
*/
typedef void tdm_capture;
tdm_display.c \
tdm_output.c \
tdm_layer.c \
+ tdm_hwc_window.c \
tdm_pp.c \
tdm_capture.c \
tdm_monitor_server.c \
private_output->index = pipe;
LIST_INITHEAD(&private_output->layer_list);
+ LIST_INITHEAD(&private_output->hwc_window_list);
LIST_INITHEAD(&private_output->capture_list);
LIST_INITHEAD(&private_output->vblank_handler_list);
LIST_INITHEAD(&private_output->output_commit_handler_list);
tdm_display_enable_commit_per_vblank(private_display, enable);
}
+ str = getenv("TDM_HWC");
+ if (str) {
+ char *end;
+ int enable = strtol(str, &end, 10);
+ private_display->hwc_enable = enable;
+ }
+
if (pthread_mutex_init(&private_display->lock, NULL)) {
ret = TDM_ERROR_OPERATION_FAILED;
TDM_ERR("mutex init failed: %m");
if (ret != TDM_ERROR_NONE)
goto failed_load;
+ if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_HWC))
+ private_display->hwc_enable = 0;
+
stamp2 = tdm_helper_get_time();
TDM_DBG("loading backend time: %.3f ms", (stamp2 - stamp1) * 1000.0);
stamp1 = stamp2;
}
EXTERN tdm_error
+tdm_backend_register_func_hwc_window(tdm_display *dpy, tdm_func_hwc_window *func_hwc_window)
+{
+ tdm_backend_module *module;
+
+ TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
+
+ BACKEND_FUNC_ENTRY();
+
+ TDM_RETURN_VAL_IF_FAIL(func_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ module = private_display->module_data;
+ if (_check_abi_version(module, 1, 1) < 0)
+ return TDM_ERROR_BAD_MODULE;
+
+ private_display->capabilities |= TDM_DISPLAY_CAPABILITY_HWC;
+ private_display->func_hwc_window = *func_hwc_window;
+
+ return TDM_ERROR_NONE;
+}
+
+EXTERN tdm_error
tdm_backend_register_func_pp(tdm_display *dpy, tdm_func_pp *func_pp)
{
TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
--- /dev/null
+/**************************************************************************
+ *
+ * libtdm
+ *
+ * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+ *
+ * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
+ * JinYoung Jeon <jy0.jeon@samsung.com>,
+ * Taeheon Kim <th908.kim@samsung.com>,
+ * YoungJun Cho <yj44.cho@samsung.com>,
+ * SooChan Lim <sc1.lim@samsung.com>,
+ * Boram Park <sc1.lim@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm.h"
+#include "tdm_backend.h"
+#include "tdm_private.h"
+#include "tdm_helper.h"
+
+#define COUNT_MAX 10
+
+#define HWC_WINDOW_FUNC_ENTRY() \
+ tdm_private_display *private_display; \
+ tdm_private_output *private_output; \
+ tdm_private_hwc_window *private_hwc_window; \
+ tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
+ TDM_RETURN_VAL_IF_FAIL(hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER); \
+ private_hwc_window = (tdm_private_hwc_window*)hwc_window; \
+ private_output = private_hwc_window->private_output; \
+ private_display = private_output->private_display
+
+#define HWC_WINDOW_FUNC_ENTRY_ERROR() \
+ tdm_private_display *private_display; \
+ tdm_private_output *private_output; \
+ tdm_private_hwc_window *private_hwc_window; \
+ tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
+ TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \
+ private_hwc_window = (tdm_private_hwc_window*)hwc_window; \
+ private_output = private_hwc_window->private_output; \
+ private_display = private_output->private_display
+
+#define HWC_WINDOW_FUNC_ENTRY_VOID_RETURN() \
+ tdm_private_display *private_display; \
+ tdm_private_output *private_output; \
+ tdm_private_hwc_window *private_hwc_window; \
+ tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
+ TDM_RETURN_IF_FAIL(hwc_window != NULL); \
+ private_hwc_window = (tdm_private_hwc_window*)hwc_window; \
+ private_output = private_hwc_window->private_output; \
+ private_display = private_output->private_display
+
+tbm_surface_queue_h
+tdm_hwc_window_get_tbm_surface_queue(tdm_hwc_window *hwc_window, tdm_error *error)
+{
+ tdm_func_hwc_window *func_hwc_window = NULL;
+ tbm_surface_queue_h queue = NULL;
+
+ HWC_WINDOW_FUNC_ENTRY_ERROR();
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ func_hwc_window = &private_display->func_hwc_window;
+
+ if (!func_hwc_window->hwc_window_get_tbm_surface_queue) {
+ _pthread_mutex_unlock(&private_display->lock);
+ TDM_ERR("not implemented!!");
+ *error = TDM_ERROR_NOT_IMPLEMENTED;
+ return NULL;
+ }
+
+ queue = func_hwc_window->hwc_window_get_tbm_surface_queue(private_hwc_window->hwc_window_backend, error);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return queue;
+}
+
+EXTERN tdm_error
+tdm_hwc_window_set_zpos(tdm_hwc_window *hwc_window, uint32_t zpos)
+{
+ tdm_func_hwc_window *func_hwc_window = NULL;
+
+ HWC_WINDOW_FUNC_ENTRY();
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ func_hwc_window = &private_display->func_hwc_window;
+
+ if (!func_hwc_window->hwc_window_set_zpos) {
+ _pthread_mutex_unlock(&private_display->lock);
+ TDM_ERR("not implemented!!");
+ return TDM_ERROR_NOT_IMPLEMENTED;
+ }
+
+ ret = func_hwc_window->hwc_window_set_zpos(private_hwc_window->hwc_window_backend, zpos);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return ret;
+}
+
+EXTERN tdm_error
+tdm_hwc_window_set_composition_type(tdm_hwc_window *hwc_window,
+ tdm_hwc_window_composition_t composition_type)
+{
+ tdm_func_hwc_window *func_hwc_window = NULL;
+
+ HWC_WINDOW_FUNC_ENTRY();
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ func_hwc_window = &private_display->func_hwc_window;
+
+ if (!func_hwc_window->hwc_window_set_composition_type) {
+ _pthread_mutex_unlock(&private_display->lock);
+ TDM_ERR("not implemented!!");
+ return TDM_ERROR_NOT_IMPLEMENTED;
+ }
+
+ ret = func_hwc_window->hwc_window_set_composition_type(private_hwc_window->hwc_window_backend, composition_type);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return ret;
+}
+
+EXTERN tdm_error
+tdm_hwc_window_set_surface_damage(tdm_hwc_window *hwc_window, tdm_hwc_region damage)
+{
+ tdm_func_hwc_window *func_hwc_window = NULL;
+
+ HWC_WINDOW_FUNC_ENTRY();
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ func_hwc_window = &private_display->func_hwc_window;
+
+ if (!func_hwc_window->hwc_window_set_surface_damage) {
+ _pthread_mutex_unlock(&private_display->lock);
+ TDM_ERR("not implemented!!");
+ return TDM_ERROR_NOT_IMPLEMENTED;
+ }
+
+ ret = func_hwc_window->hwc_window_set_surface_damage(private_hwc_window->hwc_window_backend, damage);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return ret;
+}
+
+
+EXTERN tdm_error
+tdm_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info)
+{
+ tdm_func_hwc_window *func_hwc_window = NULL;
+ char fmtstr[128];
+
+ HWC_WINDOW_FUNC_ENTRY();
+
+ TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ func_hwc_window = &private_display->func_hwc_window;
+
+ if (!func_hwc_window->hwc_window_set_info) {
+ _pthread_mutex_unlock(&private_display->lock);
+ TDM_ERR("not implemented!!");
+ return TDM_ERROR_NOT_IMPLEMENTED;
+ }
+
+ if (info->src_config.format)
+ snprintf(fmtstr, 128, "%c%c%c%c", FOURCC_STR(info->src_config.format));
+ else
+ snprintf(fmtstr, 128, "NONE");
+
+ TDM_INFO("hwc_window(%p) info: src(%dx%d %d,%d %dx%d %s) dst(%d,%d %dx%d) trans(%d)",
+ private_hwc_window, info->src_config.size.h, info->src_config.size.v,
+ info->src_config.pos.x, info->src_config.pos.y,
+ info->src_config.pos.w, info->src_config.pos.h,
+ fmtstr,
+ info->dst_pos.x, info->dst_pos.y,
+ info->dst_pos.w, info->dst_pos.h,
+ info->transform);
+
+ ret = func_hwc_window->hwc_window_set_info(private_hwc_window->hwc_window_backend, info);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return ret;
+}
+
+EXTERN tdm_error
+tdm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer)
+{
+ tdm_func_hwc_window *func_hwc_window;
+
+ HWC_WINDOW_FUNC_ENTRY();
+
+ _pthread_mutex_lock(&private_display->lock);
+
+
+ func_hwc_window = &private_display->func_hwc_window;
+
+ if (!func_hwc_window->hwc_window_set_buffer) {
+ _pthread_mutex_unlock(&private_display->lock);
+ TDM_ERR("not implemented!!");
+ return TDM_ERROR_NOT_IMPLEMENTED;
+ }
+
+ ret = func_hwc_window->hwc_window_set_buffer(private_hwc_window->hwc_window_backend, buffer);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return ret;
+}
+
+INTERN tdm_hwc_window *
+tdm_hwc_window_create_internal(tdm_private_output *private_output,
+ tdm_error *error)
+{
+ tdm_private_display *private_display = private_output->private_display;
+ tdm_func_output *func_output = &private_display->func_output;
+ tdm_private_hwc_window *private_hwc_window = NULL;
+ tdm_hwc_window *hwc_window_backend = NULL;
+ tdm_error ret = TDM_ERROR_NONE;
+
+ TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
+
+ hwc_window_backend = func_output->output_create_hwc_window(
+ private_output->output_backend, &ret);
+ if (ret != TDM_ERROR_NONE) {
+ if (error)
+ *error = ret;
+ return NULL;
+ }
+
+ private_hwc_window = calloc(1, sizeof(tdm_private_capture));
+ if (!private_hwc_window) {
+ TDM_ERR("failed: alloc memory");
+ func_output->output_destroy_hwc_window(private_output->output_backend, hwc_window_backend);
+ if (error)
+ *error = TDM_ERROR_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+ LIST_ADD(&private_hwc_window->link, &private_output->hwc_window_list);
+
+ private_hwc_window->private_display = private_display;
+ private_hwc_window->private_output = private_output;
+ private_hwc_window->hwc_window_backend = hwc_window_backend;
+
+ TDM_DBG("hwc_window(%p) create", private_hwc_window);
+
+ if (error)
+ *error = TDM_ERROR_NONE;
+
+ return private_hwc_window;
+}
+
+INTERN tdm_error
+tdm_hwc_window_destroy_internal(tdm_private_hwc_window * private_hwc_window)
+{
+ tdm_private_display *private_display;
+ tdm_private_output *private_output;
+ tdm_func_output *func_output;
+
+ TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
+
+ if (!private_hwc_window)
+ return TDM_ERROR_OPERATION_FAILED;
+
+ private_display = private_hwc_window->private_display;
+ private_output = private_hwc_window->private_output;
+
+ LIST_DEL(&private_hwc_window->link);
+
+ func_output = &private_display->func_output;
+ func_output->output_destroy_hwc_window(private_output->output_backend, private_hwc_window->hwc_window_backend);
+
+ free(private_hwc_window);
+ return TDM_ERROR_NONE;
+}
private_output = (tdm_private_output*)output; \
private_display = private_output->private_display
+
+static tdm_private_hwc_window *
+_tdm_output_find_private_hwc_window(tdm_private_output *private_output,
+ tdm_hwc_window *hwc_window_backend)
+{
+ tdm_private_hwc_window *private_hwc_window = NULL;
+
+ LIST_FOR_EACH_ENTRY(private_hwc_window, &private_output->hwc_window_list, link) {
+ if (private_hwc_window->hwc_window_backend == hwc_window_backend)
+ return private_hwc_window;
+ }
+
+ return NULL;
+}
+
EXTERN tdm_error
tdm_output_get_model_info(tdm_output *output, const char **maker,
const char **model, const char **name)
_pthread_mutex_lock(&private_display->lock);
+ if (private_display->hwc_enable) {
+ *count = 0;
+ return TDM_ERROR_NONE;
+ }
+
*count = 0;
LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link)
(*count)++;
if (error)
*error = TDM_ERROR_NONE;
+ if (private_display->hwc_enable) {
+ *error = TDM_ERROR_INVALID_PARAMETER;
+ return NULL;
+ }
+
LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
if (private_layer->index == index) {
_pthread_mutex_unlock(&private_display->lock);
return capture;
}
+EXTERN tdm_hwc_window *
+tdm_output_create_hwc_window(tdm_output *output, tdm_error *error)
+{
+ tdm_hwc_window *hwc_window = NULL;
+
+ OUTPUT_FUNC_ENTRY_ERROR();
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_display->hwc_enable, TDM_ERROR_BAD_REQUEST, NULL);
+
+ hwc_window = (tdm_hwc_window *)tdm_hwc_window_create_internal(private_output, error);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return hwc_window;
+}
+
+EXTERN tdm_error
+tdm_output_destroy_hwc_window(tdm_output *output, tdm_hwc_window *hwc_window)
+{
+ OUTPUT_FUNC_ENTRY();
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ ret = tdm_hwc_window_destroy_internal(hwc_window);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return ret;
+}
+
+EXTERN tdm_error
+tdm_output_validate(tdm_output *output, uint32_t *num_types)
+{
+ tdm_func_output *func_output = NULL;
+
+ OUTPUT_FUNC_ENTRY();
+
+ TDM_RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ func_output = &private_display->func_output;
+
+ if (!func_output->output_validate) {
+ _pthread_mutex_unlock(&private_display->lock);
+ TDM_ERR("not implemented!!");
+ return TDM_ERROR_NOT_IMPLEMENTED;
+ }
+
+ ret = func_output->output_validate(private_output->output_backend, num_types);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return ret;
+}
+
+EXTERN tdm_error
+tdm_output_get_changed_composition_types(tdm_output *output,
+ uint32_t *num_elements,
+ tdm_hwc_window **hwc_window,
+ tdm_hwc_window_composition_t *composition_types)
+{
+ tdm_func_output *func_output = NULL;
+ tdm_private_hwc_window * private_hwc_window = NULL;
+ int i = 0;
+
+ OUTPUT_FUNC_ENTRY();
+
+ TDM_RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ func_output = &private_display->func_output;
+
+ if (!func_output->output_get_changed_composition_types) {
+ _pthread_mutex_unlock(&private_display->lock);
+ TDM_ERR("not implemented!!");
+ return TDM_ERROR_NOT_IMPLEMENTED;
+ }
+
+ ret = func_output->output_get_changed_composition_types(private_output->output_backend,
+ num_elements, hwc_window, composition_types);
+ TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+
+ if (hwc_window == NULL || composition_types == NULL)
+ return TDM_ERROR_NONE;
+
+ for (i = 0; i < *num_elements; i++) {
+
+ private_hwc_window = _tdm_output_find_private_hwc_window(private_output, hwc_window[i]);
+
+ if (private_hwc_window == NULL) {
+ TDM_ERR("failed! This should never happen!");
+ func_output->output_destroy_hwc_window(private_output->output_backend, hwc_window[i]);
+ free(hwc_window);
+ free(composition_types);
+ num_elements = 0;
+ hwc_window = NULL;
+ composition_types = NULL;
+ _pthread_mutex_unlock(&private_display->lock);
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ hwc_window[i] = (tdm_hwc_window*)private_hwc_window;
+ }
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return ret;
+}
+
+tdm_error
+tdm_output_accept_changes(tdm_output *output)
+{
+ tdm_func_output *func_output = NULL;
+
+ OUTPUT_FUNC_ENTRY();
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ func_output = &private_display->func_output;
+
+ if (!func_output->output_validate) {
+ _pthread_mutex_unlock(&private_display->lock);
+ TDM_ERR("not implemented!!");
+ return TDM_ERROR_NOT_IMPLEMENTED;
+ }
+
+ ret = func_output->output_accept_changes(private_output->output_backend);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return ret;
+}
+
+tbm_surface_queue_h
+tdm_output_get_target_surface_queue(tdm_output *output, tdm_error *error)
+{
+ tdm_func_output *func_output = NULL;
+ tbm_surface_queue_h queue = NULL;
+
+ OUTPUT_FUNC_ENTRY_ERROR();
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ func_output = &private_display->func_output;
+
+ if (!func_output->output_get_target_surface_queue) {
+ _pthread_mutex_unlock(&private_display->lock);
+ TDM_ERR("not implemented!!");
+ return NULL;
+ }
+
+ queue = func_output->output_get_target_surface_queue(private_output->output_backend, error);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return queue;
+}
+
+EXTERN tdm_error
+tdm_output_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer,
+ tdm_hwc_region damage)
+{
+ tdm_func_output *func_output = NULL;
+
+ OUTPUT_FUNC_ENTRY();
+
+ _pthread_mutex_lock(&private_display->lock);
+
+
+ func_output = &private_display->func_output;
+
+ if (!func_output->output_set_client_target_buffer) {
+ _pthread_mutex_unlock(&private_display->lock);
+ TDM_ERR("not implemented!!");
+ return TDM_ERROR_NOT_IMPLEMENTED;
+ }
+
+ ret = func_output->output_set_client_target_buffer(private_output->output_backend, buffer, damage);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return ret;
+}
+
INTERN void
tdm_output_call_change_handler_internal(tdm_private_output *private_output,
struct list_head *change_handler_list,
typedef struct _tdm_private_display tdm_private_display;
typedef struct _tdm_private_output tdm_private_output;
typedef struct _tdm_private_layer tdm_private_layer;
+typedef struct _tdm_private_hwc_window tdm_private_hwc_window;
typedef struct _tdm_private_pp tdm_private_pp;
typedef struct _tdm_private_capture tdm_private_capture;
typedef struct _tdm_private_loop tdm_private_loop;
tdm_func_display func_display;
tdm_func_output func_output;
tdm_func_layer func_layer;
+ tdm_func_hwc_window func_hwc_window;
tdm_func_pp func_pp;
tdm_func_capture func_capture;
int commit_per_vblank;
tdm_commit_type commit_type;
+ int hwc_enable;
+
int print_fps;
};
int regist_dpms_cb;
struct list_head layer_list;
+ struct list_head hwc_window_list;
struct list_head capture_list;
struct list_head vblank_handler_list;
struct list_head output_commit_handler_list;
unsigned int fps_count;
};
+struct _tdm_private_hwc_window {
+ struct list_head link;
+
+ int index;
+
+ tdm_private_display *private_display;
+ tdm_private_output *private_output;
+
+ tdm_hwc_window *hwc_window_backend;
+};
+
+
struct _tdm_private_pp {
struct list_head link;
void
tdm_pp_destroy_internal(tdm_private_pp *private_pp);
+tdm_hwc_window *
+tdm_hwc_window_create_internal(tdm_private_output *private_output, tdm_error *error);
+tdm_error
+tdm_hwc_window_destroy_internal(tdm_private_hwc_window * private_hwc_window);
+
tdm_private_capture *
tdm_capture_create_output_internal(tdm_private_output *private_output,
tdm_error *error);