diff --git a/src/lib/ecore_drm2/Ecore_Drm2.h b/src/lib/ecore_drm2/Ecore_Drm2.h index 4dde788355..b3dc265df9 100644 --- a/src/lib/ecore_drm2/Ecore_Drm2.h +++ b/src/lib/ecore_drm2/Ecore_Drm2.h @@ -1,8 +1,6 @@ #ifndef _ECORE_DRM2_H # define _ECORE_DRM2_H -# include - # ifdef EAPI # undef EAPI # endif @@ -19,1207 +17,14 @@ # ifdef EFL_BETA_API_SUPPORT -typedef enum _Ecore_Drm2_Rotation -{ - ECORE_DRM2_ROTATION_NORMAL = 1, - ECORE_DRM2_ROTATION_90 = 2, - ECORE_DRM2_ROTATION_180 = 4, - ECORE_DRM2_ROTATION_270 = 8, - ECORE_DRM2_ROTATION_REFLECT_X = 16, - ECORE_DRM2_ROTATION_REFLECT_Y = 32 -} Ecore_Drm2_Rotation; - -typedef enum _Ecore_Drm2_Fb_Status -{ - ECORE_DRM2_FB_STATUS_SCANOUT_ON = 1, - ECORE_DRM2_FB_STATUS_SCANOUT_OFF = 2, - ECORE_DRM2_FB_STATUS_RELEASE = 4, - ECORE_DRM2_FB_STATUS_DELETED = 8, - ECORE_DRM2_FB_STATUS_PLANE_ASSIGN = 16, - ECORE_DRM2_FB_STATUS_PLANE_RELEASE = 32, -} Ecore_Drm2_Fb_Status; - -typedef enum _Ecore_Drm2_Relative_Mode -{ - ECORE_DRM2_RELATIVE_MODE_UNKNOWN, - ECORE_DRM2_RELATIVE_MODE_NONE, - ECORE_DRM2_RELATIVE_MODE_CLONE, - ECORE_DRM2_RELATIVE_MODE_TO_LEFT, - ECORE_DRM2_RELATIVE_MODE_TO_RIGHT, - ECORE_DRM2_RELATIVE_MODE_TO_ABOVE, - ECORE_DRM2_RELATIVE_MODE_TO_BELOW -} Ecore_Drm2_Relative_Mode; - /* opaque structure to represent a drm device */ typedef struct _Ecore_Drm2_Device Ecore_Drm2_Device; -/* opaque structure to represent a framebuffer object */ -typedef struct _Ecore_Drm2_Fb Ecore_Drm2_Fb; - -/* opaque structure to represent an output device */ -typedef struct _Ecore_Drm2_Output Ecore_Drm2_Output; - -/* opaque structure to represent an output mode */ -typedef struct _Ecore_Drm2_Output_Mode Ecore_Drm2_Output_Mode; - -/* opaque structure to represent a hardware plane */ -typedef struct _Ecore_Drm2_Plane Ecore_Drm2_Plane; - -/* structure to represent event for output changes */ -typedef struct _Ecore_Drm2_Event_Output_Changed -{ - unsigned int id; - int x, y, w, h; - int phys_width, phys_height; - unsigned int refresh, scale; - int subpixel, transform; - const char *make, *model, *name; - Eina_Bool connected : 1; - Eina_Bool enabled : 1; -} Ecore_Drm2_Event_Output_Changed; - -/* structure to represent event for session state changes */ -typedef struct _Ecore_Drm2_Event_Activate -{ - Eina_Bool active : 1; -} Ecore_Drm2_Event_Activate; - -/* structure to represent a drm event context */ -typedef struct _Ecore_Drm2_Context -{ - int version; - void (*vblank_handler)(int fd, unsigned int sequence, unsigned int tv_sec, - unsigned int tv_usec, void *user_data); - void (*page_flip_handler)(int fd, unsigned int sequence, unsigned int tv_sec, - unsigned int tv_usec, void *user_data); - void (*page_flip_handler2)(int fd, unsigned int sequence, unsigned int tv_sec, - unsigned int tv_usec, unsigned int crtc_id, void *user_data); -} Ecore_Drm2_Context; - -EAPI extern int ECORE_DRM2_EVENT_OUTPUT_CHANGED; -EAPI extern int ECORE_DRM2_EVENT_ACTIVATE; - -typedef void (*Ecore_Drm2_Release_Handler)(void *data, Ecore_Drm2_Fb *b); -typedef void (*Ecore_Drm2_Fb_Status_Handler)(Ecore_Drm2_Fb *b, Ecore_Drm2_Fb_Status status, void *data); - -/** - * @file - * @brief Ecore functions for dealing with drm, virtual terminals - * - * @defgroup Ecore_Drm2_Group Ecore_Drm2 - Drm Integration - * @ingroup Ecore - * - * Ecore_Drm2 provides a wrapper and functions for using libdrm - * - * @li @ref Ecore_Drm2_Init_Group - * @li @ref Ecore_Drm2_Device_Group - * @li @ref Ecore_Drm2_Output_Group - * @li @ref Ecore_Drm2_Fb_Group - * @li @ref Ecore_Drm2_Plane_Group - */ - -/** - * @defgroup Ecore_Drm2_Init_Group Drm library Init and Shutdown functions - * - * Functions that start and shutdown the Ecore_Drm2 library - */ - -/** - * Initialize the Ecore_Drm2 library - * - * @return The number of times the library has been initialized without - * being shut down. 0 is returned if an error occurs. - * - * @ingroup Ecore_Drm2_Init_Group - * @since 1.18 - */ +/* API functions */ EAPI int ecore_drm2_init(void); - -/** - * Shutdown the Ecore_Drm2 library - * - * @return The number of times the library has been initialized without - * being shutdown. 0 is returned if an error occurs. - * - * @ingroup Ecore_Drm2_Init_Group - * @since 1.18 - */ EAPI int ecore_drm2_shutdown(void); - -/** - * Read and process pending Drm events - * - * @param dev drm device - * @param drmctx - * - * @return 0 on success, -1 otherwise - * - * @note: Do not ever use this function in applications !!! - * This is a special-purpose API function and should not be used by - * application developers. - * - * @ingroup Ecore_Drm_Init_Group - * @since 1.19 - */ -EAPI int ecore_drm2_event_handle(Ecore_Drm2_Device *dev, Ecore_Drm2_Context *drmctx); - -/** - * @defgroup Ecore_Drm2_Device_Group Drm device functions - * - * Functions that deal with finding, opening, closing, or obtaining various - * information about a drm device - */ - -/** - * Try to open the Ecore_Drm2_Device for a given seat - * - * @param seat - * @param tty - * - * @return An Ecore_Drm2_Device or NULL on failure. - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ EAPI Ecore_Drm2_Device *ecore_drm2_device_open(const char *seat, unsigned int tty); - -/** - * Close an open Ecore_Drm2_Device - * - * @param device - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI void ecore_drm2_device_close(Ecore_Drm2_Device *device); - -/** - * Get the type of clock used by a given Ecore_Drm2_Device - * - * @param device - * - * @return The clockid_t used by this drm device - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI int ecore_drm2_device_clock_id_get(Ecore_Drm2_Device *device); - -/** - * Get the size of the cursor supported by a given Ecore_Drm2_Device - * - * @param device - * @param width - * @param height - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI void ecore_drm2_device_cursor_size_get(Ecore_Drm2_Device *device, int *width, int *height); - -/** - * Get the current pointer position - * - * @param device - * @param x - * @param y - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI void ecore_drm2_device_pointer_xy_get(Ecore_Drm2_Device *device, int *x, int *y); - -/** - * Warp the pointer position to given coordinates - * - * @param device - * @param x - * @param y - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI void ecore_drm2_device_pointer_warp(Ecore_Drm2_Device *device, int x, int y); - -/** - * Set a left handed mode for the given device - * - * @param device - * @param left - * - * @return EINA_TRUE on success, EINA_FALSE otherwise - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI Eina_Bool ecore_drm2_device_pointer_left_handed_set(Ecore_Drm2_Device *device, Eina_Bool left); - -/** - * Set which window is to be used for input events - * - * @param device - * @param window - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI void ecore_drm2_device_window_set(Ecore_Drm2_Device *device, unsigned int window); - -/** - * Set maximium position that pointer device is allowed to move - * - * @param device - * @param w - * @param h - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI void ecore_drm2_device_pointer_max_set(Ecore_Drm2_Device *device, int w, int h); - -/** - * Set pointer acceleration speed - * - * @param device - * @param speed - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.21 - */ -EAPI void ecore_drm2_device_pointer_accel_speed_set(Ecore_Drm2_Device *device, double speed); - -/** - * Set pointer acceleration profile - * - * @param device - * @param profile - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.21 - */ -EAPI void ecore_drm2_device_pointer_accel_profile_set(Ecore_Drm2_Device *device, uint32_t profile); - -/** - * Set pointer value rotation - * - * @param device - * @param rotation - * - * @return EINA_TRUE on success, EINA_FALSE otherwise - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.20 - */ -EAPI Eina_Bool ecore_drm2_device_pointer_rotation_set(Ecore_Drm2_Device *device, int rotation); - -/** - * Enable or disable pointer tap-to-click - * - * @param device - * @param enabled - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.22 - */ -EAPI void ecore_drm2_device_touch_tap_to_click_enabled_set(Ecore_Drm2_Device *device, Eina_Bool enabled); - -/** - * Set info to be used on keyboards - * - * @param device - * @param context - * @param keymap - * @param group - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.20 - */ -EAPI void ecore_drm2_device_keyboard_info_set(Ecore_Drm2_Device *device, void *context, void *keymap, int group); - -/** - * Set a group layout to be used on keyboards - * - * @param device - * @param group - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.20 - */ -EAPI void ecore_drm2_device_keyboard_group_set(Ecore_Drm2_Device *device, int group); - -/** - * Get the crtcs of a given device - * - * @param device - * @param num - * - * @return The crtcs of this given device or NULL on failure - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI unsigned int *ecore_drm2_device_crtcs_get(Ecore_Drm2_Device *device, int *num); - -/** - * Get the minimum and maximum screen size range - * - * @param device - * @param *minw - * @param *minh - * @param *maxw - * @param *maxh - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI void ecore_drm2_device_screen_size_range_get(Ecore_Drm2_Device *device, int *minw, int *minh, int *maxw, int *maxh); - -/** - * Calibrate any input devices for given screen size - * - * @param device - * @param w - * @param h - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI void ecore_drm2_device_calibrate(Ecore_Drm2_Device *device, int w, int h); - -/** - * Try to switch to a given virtual terminal - * - * @param device - * @param vt - * - * @return EINA_TRUE on success, EINA_FALSE otherwise - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 - */ -EAPI Eina_Bool ecore_drm2_device_vt_set(Ecore_Drm2_Device *device, int vt); - -/** - * Get if a given device prefers the use of shadow buffers - * - * @param device - * - * @return EINA_TRUE if preferred, EINA_FALSE otherwise - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.19 - */ -EAPI Eina_Bool ecore_drm2_device_prefer_shadow(Ecore_Drm2_Device *device); - -/** - * Get the default depth & bpp from a given device - * - * @param device - * @param depth - * @param bpp - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.25 - */ -EAPI void ecore_drm2_device_preferred_depth_get(Ecore_Drm2_Device *device, int *depth, int *bpp); - -/** - * @defgroup Ecore_Drm2_Output_Group Drm output functions - * - * Functions that deal with setup of outputs - */ - -/** - * Iterate drm resources and create outputs - * - * @param device - * - * @return EINA_TRUE on success, EINA_FALSE otherwise - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI Eina_Bool ecore_drm2_outputs_create(Ecore_Drm2_Device *device); - -/** - * Destroy any created outputs - * - * @param device - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI void ecore_drm2_outputs_destroy(Ecore_Drm2_Device *device); - -/** - * Get the list of outputs from a drm device - * - * @param device - * - * @return - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI const Eina_List *ecore_drm2_outputs_get(Ecore_Drm2_Device *device); - -/** - * Get the dpms level of a given output - * - * @param output - * - * @return Integer value representing the state of DPMS on a given output - * or -1 on error - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI int ecore_drm2_output_dpms_get(Ecore_Drm2_Output *output); - -/** - * Set the dpms level of a given output - * - * @param output - * @param level - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI void ecore_drm2_output_dpms_set(Ecore_Drm2_Output *output, int level); - -/** - * Get the edid of a given output - * - * @param output - * - * @return A string representing the edid - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI char *ecore_drm2_output_edid_get(Ecore_Drm2_Output *output); - -/** - * Get if a given output has a backlight - * - * @param output - * - * @return EINA_TRUE if this output has a backlight, EINA_FALSE otherwise - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI Eina_Bool ecore_drm2_output_backlight_get(Ecore_Drm2_Output *output); - -/** - * Find an output at the given position - * - * @param device - * @param x - * @param y - * - * @return An Ecore_Drm2_Output which exists at the given coordinates, or NULL on failure - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI Ecore_Drm2_Output *ecore_drm2_output_find(Ecore_Drm2_Device *device, int x, int y); - -/** - * Get the dpi of a given output - * - * @param output - * @param xdpi - * @param ydpi - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.19 - */ -EAPI void ecore_drm2_output_dpi_get(Ecore_Drm2_Output *output, int *xdpi, int *ydpi); - -/** - * Get the id of the crtc that an output is using - * - * @param output - * - * @return A valid crtc id or 0 on failure - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI unsigned int ecore_drm2_output_crtc_get(Ecore_Drm2_Output *output); - -/** - * Return the most recently set Ecore_Drm2_Fb for a given output - * - * This may be the currently scanned out buffer, a buffer currently being - * flipped to scanout, or a buffer that has been submit but may not - * actually ever hit scanout at all. - * - * @param output - * - * @return The latest Ecore_Drm2_Fb submit for this output, or NULL otherwise - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.19 - */ -EAPI Ecore_Drm2_Fb *ecore_drm2_output_latest_fb_get(Ecore_Drm2_Output *output); - -/** - * Get if a given output is marked as the primary output - * - * @param output - * - * @return EINA_TRUE if output is primary, EINA_FALSE otherwise - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI Eina_Bool ecore_drm2_output_primary_get(Ecore_Drm2_Output *output); - -/** - * Set a given output to be primary - * - * @param output - * @param primary - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI void ecore_drm2_output_primary_set(Ecore_Drm2_Output *output, Eina_Bool primary); - -/** - * Get if a given output is enabled - * - * @param output - * - * @return EINA_TRUE if enabled, EINA_FALSE otherwise. - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI Eina_Bool ecore_drm2_output_enabled_get(Ecore_Drm2_Output *output); - -/** - * Set if a given output is enabled - * - * @param output - * @param enabled - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI void ecore_drm2_output_enabled_set(Ecore_Drm2_Output *output, Eina_Bool enabled); - -/** - * Get the physical size of a given output - * - * This function will give the physical size (in mm) of an output - * - * @param output - * @param *w - * @param *h - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI void ecore_drm2_output_physical_size_get(Ecore_Drm2_Output *output, int *w, int *h); - -/** - * Get a list of the modes supported on a given output - * - * @param output - * - * @return An Eina_List of the modes supported for this output - * - * @note The returned list should not be freed - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI const Eina_List *ecore_drm2_output_modes_get(Ecore_Drm2_Output *output); - -/** - * Get information from an existing output mode - * - * @param mode - * @param w - * @param h - * @param refresh - * @param flags - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI void ecore_drm2_output_mode_info_get(Ecore_Drm2_Output_Mode *mode, int *w, int *h, unsigned int *refresh, unsigned int *flags); - -/** - * Set a given mode to be used on a given output - * - * @param output - * @param mode - * @param x - * @param y - * - * @return EINA_TRUE on success, EINA_FALSE otherwise - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI Eina_Bool ecore_drm2_output_mode_set(Ecore_Drm2_Output *output, Ecore_Drm2_Output_Mode *mode, int x, int y); - -/** - * Get the name of a given output - * - * @param output - * - * @return A string representing the output's name. Caller should free this return. - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI char *ecore_drm2_output_name_get(Ecore_Drm2_Output *output); - -/** - * Get the model of a given output - * - * @param output - * - * @return A string representing the output's model. Caller should free this return. - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI char *ecore_drm2_output_model_get(Ecore_Drm2_Output *output); - -/** - * Get if a given output is connected - * - * @param output - * - * @return EINA_TRUE if connected, EINA_FALSE otherwise - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI Eina_Bool ecore_drm2_output_connected_get(Ecore_Drm2_Output *output); - -/** - * Get if a given output is cloned - * - * @param output - * - * @return EINA_TRUE if cloned, EINA_FALSE otherwise. - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI Eina_Bool ecore_drm2_output_cloned_get(Ecore_Drm2_Output *output); - -/** - * Get the connector type of a given output - * - * @param output - * - * @return An unsigned integer representing the type of connector for this output - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI unsigned int ecore_drm2_output_connector_type_get(Ecore_Drm2_Output *output); - -/** - * Get the geometry and refresh rate for a given output - * - * @param output - * @param *x - * @param *y - * @param *w - * @param *h - * @param *refresh - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.21 - */ -EAPI void ecore_drm2_output_info_get(Ecore_Drm2_Output *output, int *x, int *y, int *w, int *h, unsigned int *refresh); - -/** - * Get if an output can be used on a given crtc - * - * This function will loop the possible crtcs of an encoder to determine if - * a given output can be assigned to a given crtc - * - * @param output - * @param crtc - * - * @return EINA_TRUE if the output can be assigned to given crtc, EINA_FALSE otherwise - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.18 - */ -EAPI Eina_Bool ecore_drm2_output_possible_crtc_get(Ecore_Drm2_Output *output, unsigned int crtc); - -/** - * Set the gamma level of an Ecore_Drm_Output - * - * This function will set the gamma of an Ecore_Drm2_Output - * - * @param output The Ecore_Drm2_Output to set the gamma level on - * @param size The gamma table size to set - * @param red The amount to scale the red channel - * @param green The amount to scale the green channel - * @param blue The amount to scale the blue channel - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.19 - */ -EAPI void ecore_drm2_output_gamma_set(Ecore_Drm2_Output *output, uint16_t size, uint16_t *red, uint16_t *green, uint16_t *blue); - -/** - * Get the supported rotations of a given output - * - * @param output - * - * @return An integer representing possible rotations, or -1 on failure - * - * @note This function will only return valid values if Atomic support - * is enabled as it requires hardware plane support. - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.19 - */ -EAPI int ecore_drm2_output_supported_rotations_get(Ecore_Drm2_Output *output); - -/** - * Set a rotation on a given output - * - * @param output - * @param rotation - * - * @return EINA_TRUE on success, EINA_FALSE otherwise - * - * @note This function will only work if Atomic support - * is enabled as it requires hardware plane support. - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.19 - */ -EAPI Eina_Bool ecore_drm2_output_rotation_set(Ecore_Drm2_Output *output, int rotation); - -/** - * Get current output rotation - * - * @param output - * - * @return An integer representing the output current rotation - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.22 - */ -EAPI int ecore_drm2_output_rotation_get(Ecore_Drm2_Output *output); - -/** - * Set the user data for the output's page flip handler - * - * @param o The output to update user data for - * @param data The new user data pointer - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.19 - */ -EAPI void ecore_drm2_output_user_data_set(Ecore_Drm2_Output *o, void *data); - -/** - * Get the user data for a given output - * - * @param output The output to get user data for - * - * @return The user data associated with given output - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.21 - */ -EAPI void *ecore_drm2_output_user_data_get(Ecore_Drm2_Output *output); - -/** - * Get the subpixel state of the output - * @param output the output - * @return The state value - * @ingroup Ecore_Drm2_Output_Group - * @since 1.20 - */ -EAPI unsigned int ecore_drm2_output_subpixel_get(const Ecore_Drm2_Output *output); - -/** - * Set the relative mode for an output - * - * @param output The output to set relative mode - * @param mode The relative mode to set - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.21 - */ -EAPI void ecore_drm2_output_relative_mode_set(Ecore_Drm2_Output *output, Ecore_Drm2_Relative_Mode mode); - -/** - * Get the relative mode of an output - * - * @param output The output to retrieve relative mode for - * - * @return The relative mode of a given output - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.21 - */ -EAPI Ecore_Drm2_Relative_Mode ecore_drm2_output_relative_mode_get(Ecore_Drm2_Output *output); - -/** - * Set which output a given output is relative to - * - * @param output The output for which to set relative - * @param relative The output for which the first output is relative to - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.21 - */ -EAPI void ecore_drm2_output_relative_to_set(Ecore_Drm2_Output *output, const char *relative); - -/** - * Get which output is relative to a given output - * - * @param output The output for which to retrieve relative - * - * @return The name of the output which is relative to the given output or NULL - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.21 - */ -EAPI const char *ecore_drm2_output_relative_to_get(Ecore_Drm2_Output *output); - -/** - * @defgroup Ecore_Drm2_Fb_Group Drm framebuffer functions - * - * Functions that deal with setup of framebuffers - */ - -/** - * Create a new framebuffer object - * - * @param dev - * @param width - * @param height - * @param depth - * @param bpp - * @param format - * - * @return A newly create framebuffer object, or NULL on failure - * - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.18 - */ -EAPI Ecore_Drm2_Fb *ecore_drm2_fb_create(Ecore_Drm2_Device *dev, int width, int height, int depth, int bpp, unsigned int format); - -EAPI Ecore_Drm2_Fb *ecore_drm2_fb_gbm_create(Ecore_Drm2_Device *dev, int width, int height, int depth, int bpp, unsigned int format, unsigned int handle, unsigned int stride, void *bo); - -/** - * Get a framebuffer's mmap'd data - * - * @param fb - * - * @return The mmap'd area of the framebuffer or NULL on failure - * - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.18 - */ -EAPI void *ecore_drm2_fb_data_get(Ecore_Drm2_Fb *fb); - -/** - * Get a framebuffer's size - * - * @param fb - * - * @return size of the framebuffers' mmap'd data or 0 on failure - * - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.18 - */ -EAPI unsigned int ecore_drm2_fb_size_get(Ecore_Drm2_Fb *fb); - -/** - * Get a framebuffer's stride - * - * @param fb - * - * @return stride of the framebuffer or 0 on failure - * - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.18 - */ -EAPI unsigned int ecore_drm2_fb_stride_get(Ecore_Drm2_Fb *fb); - -/** - * Mark regions of a framebuffer as dirty - * - * @param fb - * @param rects - * @param count - * - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.18 - */ -EAPI void ecore_drm2_fb_dirty(Ecore_Drm2_Fb *fb, Eina_Rectangle *rects, unsigned int count); - -/** - * Schedule a pageflip to the given Ecore_Drm2_Fb - * - * The caller is responsible for running a page flip handler - * and calling ecore_drm2_fb_flip_complete() when it completes. - * - * @param fb - * @param output - * - * @return The result of drmModePageFlip function call - * - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.18 - */ -EAPI int ecore_drm2_fb_flip(Ecore_Drm2_Fb *fb, Ecore_Drm2_Output *output); - -/** - * Must be called by a page flip handler when the flip completes. - * - * @param output - * - * @return Whether there's an undisplayed buffer still in the queue. - * - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.18 - */ -EAPI Eina_Bool ecore_drm2_fb_flip_complete(Ecore_Drm2_Output *output); - -/** - * Return the Ecore_Drm2_Fb's busy status - * - * @param fb - * - * @return The busy status - * - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.19 - */ -EAPI Eina_Bool ecore_drm2_fb_busy_get(Ecore_Drm2_Fb *fb); - -/** - * Try to force a framebuffer release for an output - * - * This tries to release the next or optionally pending, or current - * buffer from the output. If successful there will be a release callback - * to the registered handler, and the fb will no longer be flagged busy. - * - * Releasing buffers committed to scanout will potentially cause flicker, - * so this is only done when the panic flag is set. - * - * @param o The output to force release - * @param panic Try to release even buffers committed to scanout - * - * @return EINA_TRUE if a buffer was released - * - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.19 - */ -EAPI Eina_Bool ecore_drm2_fb_release(Ecore_Drm2_Output *o, Eina_Bool panic); - -/** - * Get the Framebuffer's gbm buffer object - * - * @param fb The framebuffer to query - * - * @return The gbm bo for the framebuffer - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.19 - */ -EAPI void *ecore_drm2_fb_bo_get(Ecore_Drm2_Fb *fb); - -/** - * Import a dmabuf object as a Framebuffer - * - * @param dev - * @param width - * @param height - * @param depth - * @param bpp - * @param format - * @param strides - * @param dmabuf_fd - * @param dmabuf_fd_count - * - * @return A newly created framebuffer object, or NULL on failure - * - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.20 - * - */ -EAPI Ecore_Drm2_Fb *ecore_drm2_fb_dmabuf_import(Ecore_Drm2_Device *dev, int width, int height, int depth, int bpp, unsigned int format, unsigned int strides[4], int dmabuf_fd[4], int dmabuf_fd_count); - -/** - * Discard a framebuffer object - * - * Decreases the refcount on a fb object. It will be destroyed when it's - * no longer attached to scanout or otherwise in use. - * - * @param fb - * - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.20 - */ -EAPI void ecore_drm2_fb_discard(Ecore_Drm2_Fb *fb); - -/** - * @defgroup Ecore_Drm2_Plane_Group Functions that deal with hardware planes - * - * Functions that deal with hardware plane manipulation - */ - -/** - * Find a hardware plane where a given Ecore_Drm2_Fb can go based on format and size - * - * @param output - * @param fb - * - * @return A newly allocated plane object, or NULL otherwise - * - * @ingroup Ecore_Drm2_Plane_Group - * @since 1.20 - */ -EAPI Ecore_Drm2_Plane *ecore_drm2_plane_assign(Ecore_Drm2_Output *output, Ecore_Drm2_Fb *fb, int x, int y); - -/** - * Remove a hardware plane from display - * - * @param plane - * - * @ingroup Ecore_Drm2_Plane_Group - * @since 1.20 - */ -EAPI void ecore_drm2_plane_release(Ecore_Drm2_Plane *plane); - -/** - * Set plane destination values - * - * @param plane - * @param x - * @param y - * @param w - * @param h - * - * @ingroup Ecore_Drm2_Plane_Group - * @since 1.20 - */ -EAPI void ecore_drm2_plane_destination_set(Ecore_Drm2_Plane *plane, int x, int y, int w, int h); - -/** - * Set plane frame buffer - * - * @param plane - * @param fb - * - * @return whether the plane state has been successfully changed or not - * - * @ingroup Ecore_Drm2_Plane_Group - * @since 1.20 - */ -EAPI Eina_Bool ecore_drm2_plane_fb_set(Ecore_Drm2_Plane *plane, Ecore_Drm2_Fb *fb); - -/** - * Register a callback for buffer status updates - * - * When a flip completes ecore_drm2 may release a buffer. Use this callback - * if you need to do bookkeeping or locking on buffer release. - * - * Additionally, an fb may be placed on scanout or removed from scanout by - * evas. When this happens a compositor needs to ensure the buffers aren't - * released back to a client while they're on scanout. - * - * @param fb The fb to register the callback on - * @param handler The function to handle the callback - * @param data The user data to pass to the callback - * @ingroup Ecore_Drm2_Fb_Group - * @since 1.20 - */ -EAPI void ecore_drm2_fb_status_handler_set(Ecore_Drm2_Fb *fb, Ecore_Drm2_Fb_Status_Handler handler, void *data); - -/** - * Get the time of the last vblank - * - * Query the display hardware for the time of a vblank, potentially blocking. - * - * If sequence is 0 the time of the last vblank will be immediately returned, - * if it's above zero that number of vblanks will pass before the function - * returns. - * - * @param output - * @param sequence - * @param sec - * @param usec - * - * @ingroup Ecore_Drm2_Output_Group - * @since 1.20 - */ -EAPI Eina_Bool ecore_drm2_output_blanktime_get(Ecore_Drm2_Output *output, int sequence, long *sec, long *usec); - -/** - * Get the fd of an Ecore_Drm2_Device - * - * Query the fd of the device. - * - * @param device - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.20 - */ -EAPI int ecore_drm2_device_fd_get(Ecore_Drm2_Device *device); - -/** - * Check if there's a pageflip in progress for an output - * - * Checks whether an output has submit a flip but not yet had - * a callback completion event for that flip yet. - * - * @param output - * @return Whether there's a flip in progress or not - * @ingroup Ecore_Drm2_Output_Group - * @since 1.20 - */ -EAPI Eina_Bool ecore_drm2_output_pending_get(Ecore_Drm2_Output *output); - -/** - * Set the background color of an output's crtc - * - * @param output - * @param r - * @param g - * @param b - * @param a - * - * @return EINA_TRUE on success, EINA_FALSE otherwise - * - * @note This requires support from the video driver in order to function - * - * @since 1.23 - */ -EAPI Eina_Bool ecore_drm2_output_background_color_set(Ecore_Drm2_Output *output, uint64_t r, uint64_t g, uint64_t b, uint64_t a); - -/** - * Check if vblank is supported by the current video driver - * - * @param dev - * - * @return EINA_TRUE if vblank is supported, EINA_FALSE otherwise - * - * @ingroup Ecore_Drm2_Device_Group - * @since 1.23 */ -EAPI Eina_Bool ecore_drm2_vblank_supported(Ecore_Drm2_Device *dev); +EAPI void ecore_drm2_device_close(Ecore_Drm2_Device *dev); # endif diff --git a/src/lib/ecore_drm2/ecore_drm2.c b/src/lib/ecore_drm2/ecore_drm2.c index a4ab72042d..d1eacfafe5 100644 --- a/src/lib/ecore_drm2/ecore_drm2.c +++ b/src/lib/ecore_drm2/ecore_drm2.c @@ -1,143 +1,11 @@ #include "ecore_drm2_private.h" +/* local variables */ static int _ecore_drm2_init_count = 0; -static void *drm_lib = NULL; +/* external variables */ int _ecore_drm2_log_dom = -1; -int (*sym_drmHandleEvent)(int fd, drmEventContext *evctx) = NULL; -void *(*sym_drmGetVersion)(int fd) = NULL; -void (*sym_drmFreeVersion)(void *drmver) = NULL; -void *(*sym_drmModeGetProperty)(int fd, uint32_t propertyId) = NULL; -void (*sym_drmModeFreeProperty)(drmModePropertyPtr ptr) = NULL; -void *(*sym_drmModeGetPropertyBlob)(int fd, uint32_t blob_id) = NULL; -void (*sym_drmModeFreePropertyBlob)(drmModePropertyBlobPtr ptr) = NULL; -int (*sym_drmModeDestroyPropertyBlob)(int fd, uint32_t id) = NULL; -int (*sym_drmIoctl)(int fd, unsigned long request, void *arg) = NULL; -void *(*sym_drmModeObjectGetProperties)(int fd, uint32_t object_id, uint32_t object_type) = NULL; -void (*sym_drmModeFreeObjectProperties)(drmModeObjectPropertiesPtr ptr) = NULL; -int (*sym_drmModeCreatePropertyBlob)(int fd, const void *data, size_t size, uint32_t *id) = NULL; -void *(*sym_drmModeAtomicAlloc)(void) = NULL; -void (*sym_drmModeAtomicFree)(drmModeAtomicReqPtr req) = NULL; -int (*sym_drmModeAtomicAddProperty)(drmModeAtomicReqPtr req, uint32_t object_id, uint32_t property_id, uint64_t value) = NULL; -int (*sym_drmModeAtomicCommit)(int fd, drmModeAtomicReqPtr req, uint32_t flags, void *user_data) = NULL; -void (*sym_drmModeAtomicSetCursor)(drmModeAtomicReqPtr req, int cursor) = NULL; -int (*sym_drmModeAtomicMerge)(drmModeAtomicReqPtr base, drmModeAtomicReqPtr augment); -void *(*sym_drmModeGetEncoder)(int fd, uint32_t encoder_id) = NULL; -void (*sym_drmModeFreeEncoder)(drmModeEncoderPtr ptr) = NULL; -void *(*sym_drmModeGetCrtc)(int fd, uint32_t crtcId) = NULL; -void (*sym_drmModeFreeCrtc)(drmModeCrtcPtr ptr) = NULL; -int (*sym_drmModeSetCrtc)(int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t *connectors, int count, drmModeModeInfoPtr mode) = NULL; -void *(*sym_drmModeGetResources)(int fd) = NULL; -void (*sym_drmModeFreeResources)(drmModeResPtr ptr) = NULL; -void *(*sym_drmModeGetConnector)(int fd, uint32_t connectorId) = NULL; -void (*sym_drmModeFreeConnector)(drmModeConnectorPtr ptr) = NULL; -int (*sym_drmModeConnectorSetProperty)(int fd, uint32_t connector_id, uint32_t property_id, uint64_t value) = NULL; -int (*sym_drmGetCap)(int fd, uint64_t capability, uint64_t *value) = NULL; -int (*sym_drmSetClientCap)(int fd, uint64_t capability, uint64_t value) = NULL; -void *(*sym_drmModeGetPlaneResources)(int fd) = NULL; -void (*sym_drmModeFreePlaneResources)(drmModePlaneResPtr ptr) = NULL; -void *(*sym_drmModeGetPlane)(int fd, uint32_t plane_id) = NULL; -void (*sym_drmModeFreePlane)(drmModePlanePtr ptr) = NULL; -int (*sym_drmModeAddFB)(int fd, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, uint32_t pitch, uint32_t bo_handle, uint32_t *buf_id) = NULL; -int (*sym_drmModeAddFB2)(int fd, uint32_t width, uint32_t height, uint32_t pixel_format, uint32_t bo_handles[4], uint32_t pitches[4], uint32_t offsets[4], uint32_t *buf_id, uint32_t flags) = NULL; -int (*sym_drmModeRmFB)(int fd, uint32_t bufferId) = NULL; -int (*sym_drmModePageFlip)(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data) = NULL; -int (*sym_drmModeDirtyFB)(int fd, uint32_t bufferId, drmModeClipPtr clips, uint32_t num_clips) = NULL; -int (*sym_drmModeCrtcSetGamma)(int fd, uint32_t crtc_id, uint32_t size, uint16_t *red, uint16_t *green, uint16_t *blue) = NULL; -int (*sym_drmPrimeFDToHandle)(int fd, int prime_fd, uint32_t *handle) = NULL; -int (*sym_drmWaitVBlank)(int fd, drmVBlank *vbl) = NULL; - -EAPI int ECORE_DRM2_EVENT_OUTPUT_CHANGED = -1; -EAPI int ECORE_DRM2_EVENT_ACTIVATE = -1; - -static Eina_Bool -_ecore_drm2_link(void) -{ - int i, fail; - const char *drm_libs[] = - { - "libdrm.so.2", - "libdrm.so.1", - "libdrm.so.0", - "libdrm.so", - NULL, - }; - -#define SYM(lib, xx) \ - do { \ - sym_ ## xx = dlsym(lib, #xx); \ - if (!(sym_ ## xx)) { \ - fail = 1; \ - } \ - } while (0) - - if (drm_lib) return EINA_TRUE; - - for (i = 0; drm_libs[i]; i++) - { - drm_lib = dlopen(drm_libs[i], RTLD_LOCAL | RTLD_LAZY); - if (!drm_lib) continue; - - fail = 0; - - SYM(drm_lib, drmIoctl); - /* SYM(drm_lib, drmClose); */ - SYM(drm_lib, drmWaitVBlank); - SYM(drm_lib, drmHandleEvent); - SYM(drm_lib, drmGetVersion); - SYM(drm_lib, drmFreeVersion); - SYM(drm_lib, drmModeGetProperty); - SYM(drm_lib, drmModeFreeProperty); - SYM(drm_lib, drmModeGetPropertyBlob); - SYM(drm_lib, drmModeFreePropertyBlob); - SYM(drm_lib, drmModeDestroyPropertyBlob); - SYM(drm_lib, drmModeObjectGetProperties); - SYM(drm_lib, drmModeFreeObjectProperties); - SYM(drm_lib, drmModeCreatePropertyBlob); - SYM(drm_lib, drmModeAtomicAlloc); - SYM(drm_lib, drmModeAtomicFree); - SYM(drm_lib, drmModeAtomicAddProperty); - SYM(drm_lib, drmModeAtomicCommit); - SYM(drm_lib, drmModeAtomicSetCursor); - SYM(drm_lib, drmModeAtomicMerge); - SYM(drm_lib, drmModeGetEncoder); - SYM(drm_lib, drmModeFreeEncoder); - SYM(drm_lib, drmModeGetCrtc); - SYM(drm_lib, drmModeFreeCrtc); - SYM(drm_lib, drmModeSetCrtc); - SYM(drm_lib, drmModeGetResources); - SYM(drm_lib, drmModeFreeResources); - SYM(drm_lib, drmModeGetConnector); - SYM(drm_lib, drmModeFreeConnector); - SYM(drm_lib, drmModeConnectorSetProperty); - SYM(drm_lib, drmGetCap); - SYM(drm_lib, drmSetClientCap); - SYM(drm_lib, drmModeGetPlaneResources); - SYM(drm_lib, drmModeFreePlaneResources); - SYM(drm_lib, drmModeGetPlane); - SYM(drm_lib, drmModeFreePlane); - SYM(drm_lib, drmModeAddFB); - SYM(drm_lib, drmModeAddFB2); - SYM(drm_lib, drmModeRmFB); - SYM(drm_lib, drmModePageFlip); - SYM(drm_lib, drmModeDirtyFB); - SYM(drm_lib, drmModeCrtcSetGamma); - SYM(drm_lib, drmPrimeFDToHandle); - - if (fail) - { - dlclose(drm_lib); - drm_lib = NULL; - } - else - break; - } - - if (!drm_lib) return EINA_FALSE; - return EINA_TRUE; -} - EAPI int ecore_drm2_init(void) { @@ -171,16 +39,8 @@ ecore_drm2_init(void) goto log_err; } - ECORE_DRM2_EVENT_OUTPUT_CHANGED = ecore_event_type_new(); - ECORE_DRM2_EVENT_ACTIVATE = ecore_event_type_new(); - - if (!_ecore_drm2_link()) goto link_err; - return _ecore_drm2_init_count; -link_err: - eina_log_domain_unregister(_ecore_drm2_log_dom); - _ecore_drm2_log_dom = -1; log_err: elput_shutdown(); elput_err: @@ -204,9 +64,6 @@ ecore_drm2_shutdown(void) if (--_ecore_drm2_init_count != 0) return _ecore_drm2_init_count; - ECORE_DRM2_EVENT_OUTPUT_CHANGED = -1; - ECORE_DRM2_EVENT_ACTIVATE = -1; - eina_log_domain_unregister(_ecore_drm2_log_dom); _ecore_drm2_log_dom = -1; @@ -217,18 +74,3 @@ ecore_drm2_shutdown(void) return _ecore_drm2_init_count; } - -EAPI int -ecore_drm2_event_handle(Ecore_Drm2_Device *dev, Ecore_Drm2_Context *drmctx) -{ - drmEventContext ctx; - - EINA_SAFETY_ON_NULL_RETURN_VAL(dev, -1); - - memset(&ctx, 0, sizeof(ctx)); - ctx.version = 2; - ctx.page_flip_handler = drmctx->page_flip_handler; - ctx.vblank_handler = drmctx->vblank_handler; - - return sym_drmHandleEvent(dev->fd, &ctx); -} diff --git a/src/lib/ecore_drm2/ecore_drm2_device.c b/src/lib/ecore_drm2/ecore_drm2_device.c deleted file mode 100644 index 77498d806e..0000000000 --- a/src/lib/ecore_drm2/ecore_drm2_device.c +++ /dev/null @@ -1,933 +0,0 @@ -#include "ecore_drm2_private.h" - -#ifndef DRM_CAP_DUMB_PREFERRED_DEPTH -# define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3 -#endif - -#ifndef DRM_CAP_DUMB_PREFER_SHADOW -# define DRM_CAP_DUMB_PREFER_SHADOW 0x4 -#endif - -#include - -Eina_Bool _ecore_drm2_use_atomic = EINA_TRUE; - -static Eina_Bool -_cb_session_active(void *data, int type EINA_UNUSED, void *event) -{ - Eina_List *l; - Ecore_Drm2_Device *device; - Ecore_Drm2_Output *output; - Elput_Event_Session_Active *ev; - Ecore_Drm2_Event_Activate *ea; - - ev = event; - device = data; - - if (ev->active) - EINA_LIST_FOREACH(device->outputs, l, output) - ecore_drm2_output_dpms_set(output, DRM_MODE_DPMS_ON); - - ea = calloc(1, sizeof(Ecore_Drm2_Event_Activate)); - if (!ea) return ECORE_CALLBACK_RENEW; - - ea->active = ev->active; - - ecore_event_add(ECORE_DRM2_EVENT_ACTIVATE, ea, NULL, NULL); - - return ECORE_CALLBACK_RENEW; -} - -static Eina_Bool -_cb_device_change(void *data, int type EINA_UNUSED, void *event) -{ - Elput_Event_Device_Change *ev = event; - Ecore_Drm2_Device *device = data; - - if (ev->type == ELPUT_DEVICE_ADDED) - { - Eina_List *l; - Ecore_Drm2_Output *output; - Eina_Stringshare *name; - - name = elput_device_output_name_get(ev->device); - if (!name) - { - output = eina_list_data_get(device->outputs); - if (output) - ecore_drm2_device_calibrate(device, - output->w, output->h); - } - else - { - EINA_LIST_FOREACH(device->outputs, l, output) - { - if (eina_streq(output->name, name)) - { - ecore_drm2_device_calibrate(device, - output->w, output->h); - break; - } - } - } - } - - return ECORE_CALLBACK_RENEW; -} - -static Eina_Bool -_drm2_device_modeset_capable(int fd) -{ - int ret = EINA_TRUE; - drmModeRes *res; - - res = sym_drmModeGetResources(fd); - if (!res) - return EINA_FALSE; - - if (res->count_crtcs <= 0 || - res->count_connectors <= 0 || - res->count_encoders <= 0) - ret = EINA_FALSE; - - sym_drmModeFreeResources(res); - - return ret; -} - -static const char * -_drm2_device_find(Elput_Manager *em, const char *seat) -{ - Eina_List *devs, *l; - const char *dev, *ret = NULL, *chosen_dev = NULL, *d = NULL; - Eina_Bool found = EINA_FALSE; - Eina_Bool modeset; - int fd; - - EINA_SAFETY_ON_NULL_RETURN_VAL(seat, NULL); - - d = getenv("ECORE_DRM2_CARD"); - if (d) - devs = eeze_udev_find_by_subsystem_sysname("drm", d); - else - devs = eeze_udev_find_by_subsystem_sysname("drm", "card[0-9]*"); - - if (!devs) return NULL; - - EINA_LIST_FOREACH(devs, l, dev) - { - const char *dpath, *dseat, *dparent; - - dpath = eeze_udev_syspath_get_devpath(dev); - if (!dpath) continue; - - dseat = eeze_udev_syspath_get_property(dev, "ID_SEAT"); - if (!dseat) dseat = eina_stringshare_add("seat0"); - - if (strcmp(seat, dseat)) - goto cont; - - fd = elput_manager_open(em, dpath, -1); - if (fd < 0) - goto cont; - modeset = _drm2_device_modeset_capable(fd); - elput_manager_close(em, fd); - if (!modeset) - goto cont; - - chosen_dev = dev; - - dparent = eeze_udev_syspath_get_parent_filtered(dev, "pci", NULL); - if (dparent) - { - const char *id; - - id = eeze_udev_syspath_get_sysattr(dparent, "boot_vga"); - if (id) - { - if (!strcmp(id, "1")) found = EINA_TRUE; - eina_stringshare_del(id); - } - - eina_stringshare_del(dparent); - } - -cont: - eina_stringshare_del(dpath); - eina_stringshare_del(dseat); - if (found) break; - } - - if (chosen_dev) - ret = eeze_udev_syspath_get_devpath(chosen_dev); - - EINA_LIST_FREE(devs, dev) - eina_stringshare_del(dev); - - return ret; -} - -# if 0 -static Eina_Bool -_drm2_atomic_usable(int fd) -{ - drmVersion *drmver; - Eina_Bool ret = EINA_FALSE; - - drmver = sym_drmGetVersion(fd); - if (!drmver) return EINA_FALSE; - - /* detect driver */ - if ((!strcmp(drmver->name, "i915")) && - (!strcmp(drmver->desc, "Intel Graphics"))) - { - FILE *fp; - - /* detect kernel version - * NB: In order for atomic modesetting to work properly for Intel, - * we need to be using a kernel >= 4.8.0 */ - - fp = fopen("/proc/sys/kernel/osrelease", "rb"); - if (fp) - { - char buff[512]; - int maj = 0, min = 0; - - if (fgets(buff, sizeof(buff), fp)) - { - if (sscanf(buff, "%i.%i.%*s", &maj, &min) == 2) - { - if ((maj >= 4) && (min >= 8)) - ret = EINA_TRUE; - } - } - fclose(fp); - } - } - - sym_drmFreeVersion(drmver); - - return ret; -} -# endif - -static void -_drm2_atomic_state_crtc_fill(Ecore_Drm2_Crtc_State *cstate, int fd) -{ - drmModeObjectPropertiesPtr oprops; - unsigned int i = 0; - - DBG("Atomic State Crtc Fill"); - - oprops = - sym_drmModeObjectGetProperties(fd, cstate->obj_id, DRM_MODE_OBJECT_CRTC); - if (!oprops) return; - - DBG("\tCrtc %d", cstate->obj_id); - - for (i = 0; i < oprops->count_props; i++) - { - drmModePropertyPtr prop; - - prop = sym_drmModeGetProperty(fd, oprops->props[i]); - if (!prop) continue; - - DBG("\t\tProperty: %s %d", prop->name, i); - - if (!strcmp(prop->name, "MODE_ID")) - { - drmModePropertyBlobPtr bp; - - cstate->mode.id = prop->prop_id; - cstate->mode.value = oprops->prop_values[i]; - DBG("\t\t\tValue: %d", cstate->mode.value); - - if (!cstate->mode.value) - { - cstate->mode.len = 0; - goto cont; - } - - bp = sym_drmModeGetPropertyBlob(fd, cstate->mode.value); - if (!bp) goto cont; - - if ((!cstate->mode.data) || - memcmp(cstate->mode.data, bp->data, bp->length) != 0) - { - cstate->mode.data = - eina_memdup(bp->data, bp->length, 1); - } - - cstate->mode.len = bp->length; - - if (cstate->mode.value != 0) - sym_drmModeCreatePropertyBlob(fd, bp->data, bp->length, - &cstate->mode.value); - - sym_drmModeFreePropertyBlob(bp); - } - else if (!strcmp(prop->name, "ACTIVE")) - { - cstate->active.id = prop->prop_id; - cstate->active.value = oprops->prop_values[i]; - DBG("\t\t\tValue: %lu", (long)cstate->active.value); - } - else if (!strcmp(prop->name, "BACKGROUND_COLOR")) - { - cstate->background.id = prop->prop_id; - cstate->background.value = oprops->prop_values[i]; - } -cont: - sym_drmModeFreeProperty(prop); - } - - sym_drmModeFreeObjectProperties(oprops); -} - -static void -_drm2_atomic_state_conn_fill(Ecore_Drm2_Connector_State *cstate, int fd) -{ - drmModeObjectPropertiesPtr oprops; - unsigned int i = 0; - - DBG("Atomic State Connector Fill"); - - oprops = - sym_drmModeObjectGetProperties(fd, cstate->obj_id, DRM_MODE_OBJECT_CONNECTOR); - if (!oprops) return; - - DBG("\tConnector: %d", cstate->obj_id); - - for (i = 0; i < oprops->count_props; i++) - { - drmModePropertyPtr prop; - - prop = sym_drmModeGetProperty(fd, oprops->props[i]); - if (!prop) continue; - - DBG("\t\tProperty: %s", prop->name); - - if (!strcmp(prop->name, "CRTC_ID")) - { - cstate->crtc.id = prop->prop_id; - cstate->crtc.value = oprops->prop_values[i]; - DBG("\t\t\tValue: %lu", (long)cstate->crtc.value); - } - else if (!strcmp(prop->name, "DPMS")) - { - cstate->dpms.id = prop->prop_id; - cstate->dpms.value = oprops->prop_values[i]; - DBG("\t\t\tValue: %lu", (long)cstate->dpms.value); - } - else if (!strcmp(prop->name, "EDID")) - { - drmModePropertyBlobPtr bp; - - cstate->edid.id = oprops->prop_values[i]; - if (!cstate->edid.id) - { - cstate->edid.len = 0; - goto cont; - } - - bp = sym_drmModeGetPropertyBlob(fd, cstate->edid.id); - if (!bp) goto cont; - - if ((!cstate->edid.data) || - memcmp(cstate->edid.data, bp->data, bp->length) != 0) - { - cstate->edid.data = - eina_memdup(bp->data, bp->length, 1); - } - - cstate->edid.len = bp->length; - - if (cstate->edid.id != 0) - sym_drmModeCreatePropertyBlob(fd, bp->data, bp->length, - &cstate->edid.id); - - sym_drmModeFreePropertyBlob(bp); - } - else if (!strcmp(prop->name, "aspect ratio")) - { - cstate->aspect.id = prop->prop_id; - cstate->aspect.value = oprops->prop_values[i]; - DBG("\t\t\tValue: %lu", (long)cstate->aspect.value); - } - else if (!strcmp(prop->name, "scaling mode")) - { - cstate->scaling.id = prop->prop_id; - cstate->scaling.value = oprops->prop_values[i]; - DBG("\t\t\tValue: %lu", (long)cstate->scaling.value); - } - -cont: - sym_drmModeFreeProperty(prop); - } - - sym_drmModeFreeObjectProperties(oprops); -} - -static void -_drm2_atomic_state_plane_fill(Ecore_Drm2_Plane_State *pstate, int fd) -{ - drmModeObjectPropertiesPtr oprops; - unsigned int i = 0; - int k = 0; - - DBG("Atomic State Plane Fill"); - - oprops = - sym_drmModeObjectGetProperties(fd, pstate->obj_id, DRM_MODE_OBJECT_PLANE); - if (!oprops) return; - - DBG("\tPlane: %d", pstate->obj_id); - - for (i = 0; i < oprops->count_props; i++) - { - drmModePropertyPtr prop; - - prop = sym_drmModeGetProperty(fd, oprops->props[i]); - if (!prop) continue; - - DBG("\t\tProperty: %s", prop->name); - - if (!strcmp(prop->name, "CRTC_ID")) - { - pstate->cid.id = prop->prop_id; - pstate->cid.value = oprops->prop_values[i]; - DBG("\t\t\tValue: %lu", (long)pstate->cid.value); - } - else if (!strcmp(prop->name, "FB_ID")) - { - pstate->fid.id = prop->prop_id; - pstate->fid.value = oprops->prop_values[i]; - DBG("\t\t\tValue: %lu", (long)pstate->fid.value); - } - else if (!strcmp(prop->name, "CRTC_X")) - { - pstate->cx.id = prop->prop_id; - pstate->cx.value = oprops->prop_values[i]; - } - else if (!strcmp(prop->name, "CRTC_Y")) - { - pstate->cy.id = prop->prop_id; - pstate->cy.value = oprops->prop_values[i]; - } - else if (!strcmp(prop->name, "CRTC_W")) - { - pstate->cw.id = prop->prop_id; - pstate->cw.value = oprops->prop_values[i]; - } - else if (!strcmp(prop->name, "CRTC_H")) - { - pstate->ch.id = prop->prop_id; - pstate->ch.value = oprops->prop_values[i]; - } - else if (!strcmp(prop->name, "SRC_X")) - { - pstate->sx.id = prop->prop_id; - pstate->sx.value = oprops->prop_values[i]; - } - else if (!strcmp(prop->name, "SRC_Y")) - { - pstate->sy.id = prop->prop_id; - pstate->sy.value = oprops->prop_values[i]; - } - else if (!strcmp(prop->name, "SRC_W")) - { - pstate->sw.id = prop->prop_id; - pstate->sw.value = oprops->prop_values[i]; - } - else if (!strcmp(prop->name, "SRC_H")) - { - pstate->sh.id = prop->prop_id; - pstate->sh.value = oprops->prop_values[i]; - } - else if (!strcmp(prop->name, "type")) - { - pstate->type.id = prop->prop_id; - pstate->type.value = oprops->prop_values[i]; - switch (pstate->type.value) - { - case DRM_PLANE_TYPE_OVERLAY: - DBG("\t\t\tOverlay Plane"); - break; - case DRM_PLANE_TYPE_PRIMARY: - DBG("\t\t\tPrimary Plane"); - break; - case DRM_PLANE_TYPE_CURSOR: - DBG("\t\t\tCursor Plane"); - break; - default: - DBG("\t\t\tValue: %lu", (long)pstate->type.value); - break; - } - } - else if (!strcmp(prop->name, "rotation")) - { - pstate->rotation.id = prop->prop_id; - pstate->rotation.value = oprops->prop_values[i]; - - for (k = 0; k < prop->count_enums; k++) - { - int r = -1; - - DBG("\t\t\tRotation: %s", prop->enums[k].name); - if (!strcmp(prop->enums[k].name, "rotate-0")) - r = ECORE_DRM2_ROTATION_NORMAL; - else if (!strcmp(prop->enums[k].name, "rotate-90")) - r = ECORE_DRM2_ROTATION_90; - else if (!strcmp(prop->enums[k].name, "rotate-180")) - r = ECORE_DRM2_ROTATION_180; - else if (!strcmp(prop->enums[k].name, "rotate-270")) - r = ECORE_DRM2_ROTATION_270; - else if (!strcmp(prop->enums[k].name, "reflect-x")) - r = ECORE_DRM2_ROTATION_REFLECT_X; - else if (!strcmp(prop->enums[k].name, "reflect-y")) - r = ECORE_DRM2_ROTATION_REFLECT_Y; - - if (r != -1) - { - pstate->supported_rotations |= r; - pstate->rotation_map[ffs(r)] = - 1ULL << prop->enums[k].value; - } - } - } - - sym_drmModeFreeProperty(prop); - } - - sym_drmModeFreeObjectProperties(oprops); -} - -static void -_drm2_atomic_state_fill(Ecore_Drm2_Atomic_State *state, int fd) -{ - int i = 0; - drmModeResPtr res; - drmModePlaneResPtr pres; - - res = sym_drmModeGetResources(fd); - if (!res) return; - - pres = sym_drmModeGetPlaneResources(fd); - if (!pres) goto err; - - state->crtcs = res->count_crtcs; - state->crtc_states = calloc(state->crtcs, sizeof(Ecore_Drm2_Crtc_State)); - if (state->crtc_states) - { - for (i = 0; i < state->crtcs; i++) - { - Ecore_Drm2_Crtc_State *cstate; - - cstate = &state->crtc_states[i]; - cstate->obj_id = res->crtcs[i]; - cstate->index = i; - - _drm2_atomic_state_crtc_fill(cstate, fd); - } - } - - state->conns = res->count_connectors; - state->conn_states = - calloc(state->conns, sizeof(Ecore_Drm2_Connector_State)); - if (state->conn_states) - { - for (i = 0; i < state->conns; i++) - { - Ecore_Drm2_Connector_State *cstate; - - cstate = &state->conn_states[i]; - cstate->obj_id = res->connectors[i]; - - _drm2_atomic_state_conn_fill(cstate, fd); - } - } - - state->planes = pres->count_planes; - state->plane_states = calloc(state->planes, sizeof(Ecore_Drm2_Plane_State)); - if (state->plane_states) - { - unsigned int f = 0; - - for (i = 0; i < state->planes; i++) - { - drmModePlanePtr plane; - Ecore_Drm2_Plane_State *pstate; - - plane = sym_drmModeGetPlane(fd, pres->planes[i]); - if (!plane) continue; - - pstate = &state->plane_states[i]; - pstate->obj_id = pres->planes[i]; - pstate->mask = plane->possible_crtcs; - pstate->num_formats = plane->count_formats; - - pstate->formats = calloc(plane->count_formats, sizeof(uint32_t)); - - for (f = 0; f < plane->count_formats; f++) - pstate->formats[f] = plane->formats[f]; - - sym_drmModeFreePlane(plane); - - _drm2_atomic_state_plane_fill(pstate, fd); - } - } - - sym_drmModeFreePlaneResources(pres); - -err: - sym_drmModeFreeResources(res); -} - -static void -_drm2_atomic_state_free(Ecore_Drm2_Atomic_State *state) -{ - free(state->plane_states); - free(state->conn_states); - free(state->crtc_states); - free(state); -} - -EAPI Ecore_Drm2_Device * -ecore_drm2_device_open(const char *seat, unsigned int tty) -{ - Ecore_Drm2_Device *device; - - device = calloc(1, sizeof(Ecore_Drm2_Device)); - if (!device) return NULL; - - device->em = elput_manager_connect(seat, tty); - if (!device->em) - { - ERR("Could not connect to input manager"); - goto man_err; - } - - device->path = _drm2_device_find(device->em, seat); - if (!device->path) - { - ERR("Could not find drm device on seat %s", seat); - goto path_err; - } - - device->fd = elput_manager_open(device->em, device->path, -1); - if (device->fd < 0) goto path_err; - - if (!elput_input_init(device->em)) - { - ERR("Could not initialize Elput Input"); - goto input_err; - } - - DBG("Device Path: %s", device->path); - DBG("Device Fd: %d", device->fd); - -# if 0 - /* check that this system can do atomic */ - _ecore_drm2_use_atomic = _drm2_atomic_usable(device->fd); -# endif - - if (getenv("ECORE_DRM2_ATOMIC_DISABLE")) - _ecore_drm2_use_atomic = EINA_FALSE; - - if (_ecore_drm2_use_atomic) - { - if (sym_drmSetClientCap(device->fd, - DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) - { - WRN("Could not enable Universal Plane support"); - _ecore_drm2_use_atomic = EINA_FALSE; - } - else - { - if (sym_drmSetClientCap(device->fd, DRM_CLIENT_CAP_ATOMIC, 1) < 0) - { - WRN("Could not enable Atomic Modesetting support"); - _ecore_drm2_use_atomic = EINA_FALSE; - } - } - } - - if (_ecore_drm2_use_atomic) - { - device->state = calloc(1, sizeof(Ecore_Drm2_Atomic_State)); - if (device->state) - _drm2_atomic_state_fill(device->state, device->fd); - } - - device->active_hdlr = - ecore_event_handler_add(ELPUT_EVENT_SESSION_ACTIVE, - _cb_session_active, device); - - device->device_change_hdlr = - ecore_event_handler_add(ELPUT_EVENT_DEVICE_CHANGE, - _cb_device_change, device); - - return device; - -input_err: - elput_manager_close(device->em, device->fd); -path_err: - elput_manager_disconnect(device->em); -man_err: - free(device); - return NULL; -} - -EAPI void -ecore_drm2_device_close(Ecore_Drm2_Device *device) -{ - EINA_SAFETY_ON_NULL_RETURN(device); - - elput_input_shutdown(device->em); - elput_manager_close(device->em, device->fd); - if (_ecore_drm2_use_atomic) - _drm2_atomic_state_free(device->state); - - ecore_event_handler_del(device->active_hdlr); - ecore_event_handler_del(device->device_change_hdlr); - eina_stringshare_del(device->path); - free(device); -} - -EAPI int -ecore_drm2_device_clock_id_get(Ecore_Drm2_Device *device) -{ - uint64_t caps; - int ret; - - EINA_SAFETY_ON_NULL_RETURN_VAL(device, -1); - - ret = sym_drmGetCap(device->fd, DRM_CAP_TIMESTAMP_MONOTONIC, &caps); - if ((ret == 0) && (caps == 1)) - return CLOCK_MONOTONIC; - else - return CLOCK_REALTIME; -} - -EAPI void -ecore_drm2_device_cursor_size_get(Ecore_Drm2_Device *device, int *width, int *height) -{ - uint64_t caps; - int ret; - - EINA_SAFETY_ON_NULL_RETURN(device); - - if (width) - { - *width = 64; - ret = sym_drmGetCap(device->fd, DRM_CAP_CURSOR_WIDTH, &caps); - if (ret == 0) - { - device->cursor.width = caps; - *width = caps; - } - } - if (height) - { - *height = 64; - ret = sym_drmGetCap(device->fd, DRM_CAP_CURSOR_HEIGHT, &caps); - if (ret == 0) - { - device->cursor.height = caps; - *height = caps; - } - } -} - -EAPI void -ecore_drm2_device_pointer_xy_get(Ecore_Drm2_Device *device, int *x, int *y) -{ - if (x) *x = 0; - if (y) *y = 0; - - EINA_SAFETY_ON_NULL_RETURN(device); - - elput_input_pointer_xy_get(device->em, NULL, x, y); -} - -EAPI void -ecore_drm2_device_pointer_warp(Ecore_Drm2_Device *device, int x, int y) -{ - EINA_SAFETY_ON_NULL_RETURN(device); - - elput_input_pointer_xy_set(device->em, NULL, x, y); -} - -EAPI Eina_Bool -ecore_drm2_device_pointer_left_handed_set(Ecore_Drm2_Device *device, Eina_Bool left) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(device, EINA_FALSE); - - return elput_input_pointer_left_handed_set(device->em, NULL, left); -} - -EAPI Eina_Bool -ecore_drm2_device_pointer_rotation_set(Ecore_Drm2_Device *device, int rotation) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(device, EINA_FALSE); - - return elput_input_pointer_rotation_set(device->em, rotation); -} - -EAPI void -ecore_drm2_device_pointer_accel_speed_set(Ecore_Drm2_Device *device, double speed) -{ - EINA_SAFETY_ON_NULL_RETURN(device); - - elput_input_pointer_accel_speed_set(device->em, NULL, speed); -} - -EAPI void -ecore_drm2_device_pointer_accel_profile_set(Ecore_Drm2_Device *device, uint32_t profile) -{ - EINA_SAFETY_ON_NULL_RETURN(device); - - elput_input_pointer_accel_profile_set(device->em, NULL, profile); -} - -EAPI void -ecore_drm2_device_touch_tap_to_click_enabled_set(Ecore_Drm2_Device *device, Eina_Bool enabled) -{ - EINA_SAFETY_ON_NULL_RETURN(device); - - elput_input_touch_tap_to_click_enabled_set(device->em, NULL, enabled); -} - -EAPI void -ecore_drm2_device_window_set(Ecore_Drm2_Device *device, unsigned int window) -{ - EINA_SAFETY_ON_NULL_RETURN(device); - EINA_SAFETY_ON_NULL_RETURN(device->em); - elput_manager_window_set(device->em, window); -} - -EAPI void -ecore_drm2_device_pointer_max_set(Ecore_Drm2_Device *device, int w, int h) -{ - EINA_SAFETY_ON_NULL_RETURN(device); - EINA_SAFETY_ON_NULL_RETURN(device->em); - - elput_input_pointer_max_set(device->em, w, h); -} - -EAPI void -ecore_drm2_device_keyboard_info_set(Ecore_Drm2_Device *device, void *context, void *keymap, int group) -{ - EINA_SAFETY_ON_NULL_RETURN(device); - - elput_input_keyboard_info_set(device->em, context, keymap, group); -} - -EAPI void -ecore_drm2_device_keyboard_group_set(Ecore_Drm2_Device *device, int group) -{ - EINA_SAFETY_ON_NULL_RETURN(device); - - elput_input_keyboard_group_set(device->em, group); -} - -EAPI unsigned int * -ecore_drm2_device_crtcs_get(Ecore_Drm2_Device *device, int *num) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(device, NULL); - - if (num) *num = device->num_crtcs; - return device->crtcs; -} - -EAPI void -ecore_drm2_device_screen_size_range_get(Ecore_Drm2_Device *device, int *minw, int *minh, int *maxw, int *maxh) -{ - if (minw) *minw = 0; - if (minh) *minh = 0; - if (maxw) *maxw = 0; - if (maxh) *maxh = 0; - - EINA_SAFETY_ON_NULL_RETURN(device); - - if (minw) *minw = device->min.width; - if (minh) *minh = device->min.height; - if (maxw) *maxw = device->max.width; - if (maxh) *maxh = device->max.height; -} - -EAPI void -ecore_drm2_device_calibrate(Ecore_Drm2_Device *device, int w, int h) -{ - EINA_SAFETY_ON_NULL_RETURN(device); - - elput_input_devices_calibrate(device->em, w, h); -} - -EAPI Eina_Bool -ecore_drm2_device_vt_set(Ecore_Drm2_Device *device, int vt) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(device, EINA_FALSE); - - return elput_manager_vt_set(device->em, vt); -} - -EAPI Eina_Bool -ecore_drm2_device_prefer_shadow(Ecore_Drm2_Device *device) -{ - uint64_t caps; - int ret; - - EINA_SAFETY_ON_NULL_RETURN_VAL(device, EINA_FALSE); - - ret = sym_drmGetCap(device->fd, DRM_CAP_DUMB_PREFER_SHADOW, &caps); - if ((ret == 0) && (caps == 1)) - return EINA_TRUE; - else - return EINA_FALSE; -} - -EAPI void -ecore_drm2_device_preferred_depth_get(Ecore_Drm2_Device *device, int *depth, int *bpp) -{ - uint64_t caps; - int ret; - - EINA_SAFETY_ON_NULL_RETURN(device); - - ret = sym_drmGetCap(device->fd, DRM_CAP_DUMB_PREFERRED_DEPTH, &caps); - if (ret == 0) - { - if (depth) *depth = caps; - if (bpp) *bpp = caps; - } -} - -EAPI int -ecore_drm2_device_fd_get(Ecore_Drm2_Device *device) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(device, -1); - - return device->fd; -} - -EAPI Eina_Bool -ecore_drm2_vblank_supported(Ecore_Drm2_Device *dev) -{ - drmVBlank tmp; - int ret = 0; - - EINA_SAFETY_ON_NULL_RETURN_VAL(dev, EINA_FALSE); - - memset(&tmp, 0, sizeof(drmVBlank)); - tmp.request.type = DRM_VBLANK_RELATIVE; - - ret = sym_drmWaitVBlank(dev->fd, &tmp); - - if (ret != 0) return EINA_FALSE; - return EINA_TRUE; -} - -/* prevent crashing with old apps compiled against these functions */ -EAPI void ecore_drm2_device_keyboard_cached_context_set(){}; -EAPI void ecore_drm2_device_keyboard_cached_keymap_set(){}; diff --git a/src/lib/ecore_drm2/ecore_drm2_fb.c b/src/lib/ecore_drm2/ecore_drm2_fb.c deleted file mode 100644 index e2ef2e8a2f..0000000000 --- a/src/lib/ecore_drm2/ecore_drm2_fb.c +++ /dev/null @@ -1,799 +0,0 @@ -#include "ecore_drm2_private.h" - -#define FLIP_TIMEOUT 1.0 - -static Eina_Bool -_fb2_create(Ecore_Drm2_Fb *fb) -{ - uint32_t offsets[4] = { 0 }; - int r; - - r = sym_drmModeAddFB2(fb->fd, fb->w, fb->h, fb->format, fb->handles, - fb->strides, offsets, &fb->id, 0); - - if (r) - return EINA_FALSE; - - return EINA_TRUE; -} - -EAPI Ecore_Drm2_Fb * -ecore_drm2_fb_create(Ecore_Drm2_Device *dev, int width, int height, int depth, int bpp, unsigned int format) -{ - Ecore_Drm2_Fb *fb; - struct drm_mode_create_dumb carg; - struct drm_mode_destroy_dumb darg; - struct drm_mode_map_dumb marg; - int ret; - - EINA_SAFETY_ON_NULL_RETURN_VAL(dev, NULL); - - fb = calloc(1, sizeof(Ecore_Drm2_Fb)); - if (!fb) return NULL; - - fb->fd = dev->fd; - fb->w = width; - fb->h = height; - fb->bpp = bpp; - fb->depth = depth; - fb->format = format; - fb->ref = 1; - - memset(&carg, 0, sizeof(struct drm_mode_create_dumb)); - carg.bpp = bpp; - carg.width = width; - carg.height = height; - - ret = sym_drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg); - if (ret) goto err; - - fb->handles[0] = carg.handle; - fb->sizes[0] = carg.size; - fb->strides[0] = carg.pitch; - - if (!_fb2_create(fb)) - { - ret = - sym_drmModeAddFB(dev->fd, width, height, depth, bpp, - fb->strides[0], fb->handles[0], &fb->id); - if (ret) - { - ERR("Could not add framebuffer: %m"); - goto add_err; - } - } - - memset(&marg, 0, sizeof(struct drm_mode_map_dumb)); - marg.handle = fb->handles[0]; - ret = sym_drmIoctl(dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &marg); - if (ret) - { - ERR("Could not map framebuffer: %m"); - goto map_err; - } - - fb->mmap = mmap(NULL, fb->sizes[0], PROT_WRITE, MAP_SHARED, dev->fd, marg.offset); - if (fb->mmap == MAP_FAILED) - { - ERR("Could not mmap framebuffer memory: %m"); - goto map_err; - } - - return fb; - -map_err: - sym_drmModeRmFB(dev->fd, fb->id); -add_err: - memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb)); - darg.handle = fb->handles[0]; - sym_drmIoctl(dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg); -err: - free(fb); - return NULL; -} - -EAPI Ecore_Drm2_Fb * -ecore_drm2_fb_gbm_create(Ecore_Drm2_Device *dev, int width, int height, int depth, int bpp, unsigned int format, unsigned int handle, unsigned int stride, void *bo) -{ - Ecore_Drm2_Fb *fb; - - EINA_SAFETY_ON_NULL_RETURN_VAL(dev, NULL); - - fb = calloc(1, sizeof(Ecore_Drm2_Fb)); - if (!fb) return NULL; - - fb->gbm = EINA_TRUE; - fb->gbm_bo = bo; - - fb->fd = dev->fd; - fb->w = width; - fb->h = height; - fb->bpp = bpp; - fb->depth = depth; - fb->format = format; - fb->strides[0] = stride; - fb->sizes[0] = fb->strides[0] * fb->h; - fb->handles[0] = handle; - fb->ref = 1; - - if (!_fb2_create(fb)) - { - if (sym_drmModeAddFB(dev->fd, width, height, depth, bpp, - fb->strides[0], fb->handles[0], &fb->id)) - { - ERR("Could not add framebuffer: %m"); - goto err; - } - } - return fb; - -err: - free(fb); - return NULL; -} - -static void -_ecore_drm2_fb_destroy(Ecore_Drm2_Fb *fb) -{ - EINA_SAFETY_ON_NULL_RETURN(fb); - - if (!fb->dead) WRN("Destroying an fb that hasn't been discarded"); - - if (fb->scanout_count) - WRN("Destroyed fb on scanout %d times.", fb->scanout_count); - - if (fb->mmap) munmap(fb->mmap, fb->sizes[0]); - - if (fb->id) sym_drmModeRmFB(fb->fd, fb->id); - - if (!fb->gbm && !fb->dmabuf) - { - struct drm_mode_destroy_dumb darg; - - memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb)); - darg.handle = fb->handles[0]; - sym_drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg); - } - - free(fb); -} - -void -_ecore_drm2_fb_ref(Ecore_Drm2_Fb *fb) -{ - fb->ref++; -} - -void -_ecore_drm2_fb_deref(Ecore_Drm2_Fb *fb) -{ - fb->ref--; - if (fb->ref) return; - - if (fb->status_handler) - fb->status_handler(fb, ECORE_DRM2_FB_STATUS_DELETED, fb->status_data); - - _ecore_drm2_fb_destroy(fb); -} - -EAPI void -ecore_drm2_fb_discard(Ecore_Drm2_Fb *fb) -{ - EINA_SAFETY_ON_NULL_RETURN(fb); - EINA_SAFETY_ON_TRUE_RETURN(fb->ref < 1); - - fb->dead = EINA_TRUE; - _ecore_drm2_fb_deref(fb); -} - -EAPI void * -ecore_drm2_fb_data_get(Ecore_Drm2_Fb *fb) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(fb, NULL); - EINA_SAFETY_ON_TRUE_RETURN_VAL(fb->dead, NULL); - return fb->mmap; -} - -EAPI unsigned int -ecore_drm2_fb_size_get(Ecore_Drm2_Fb *fb) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(fb, 0); - EINA_SAFETY_ON_TRUE_RETURN_VAL(fb->dead, 0); - return fb->sizes[0]; -} - -EAPI unsigned int -ecore_drm2_fb_stride_get(Ecore_Drm2_Fb *fb) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(fb, 0); - EINA_SAFETY_ON_TRUE_RETURN_VAL(fb->dead, 0); - - return fb->strides[0]; -} - -EAPI void -ecore_drm2_fb_dirty(Ecore_Drm2_Fb *fb, Eina_Rectangle *rects, unsigned int count) -{ - EINA_SAFETY_ON_NULL_RETURN(fb); - EINA_SAFETY_ON_NULL_RETURN(rects); - EINA_SAFETY_ON_TRUE_RETURN(fb->dead); - -#ifdef DRM_MODE_FEATURE_DIRTYFB - drmModeClip *clip; - unsigned int i = 0; - int ret; - - clip = alloca(count * sizeof(drmModeClip)); - for (i = 0; i < count; i++) - { - clip[i].x1 = rects[i].x; - clip[i].y1 = rects[i].y; - clip[i].x2 = rects[i].w; - clip[i].y2 = rects[i].h; - } - - ret = sym_drmModeDirtyFB(fb->fd, fb->id, clip, count); - if ((ret) && (ret == -EINVAL)) - WRN("Could not mark framebuffer as dirty: %m"); -#endif -} - -/* perhaps output is no longer a necessary parameter for this function */ -void -_ecore_drm2_fb_buffer_release(Ecore_Drm2_Output *output EINA_UNUSED, Ecore_Drm2_Output_State *s) -{ - Ecore_Drm2_Fb *fb = s->fb; - - if (fb->status_handler) - fb->status_handler(fb, ECORE_DRM2_FB_STATUS_RELEASE, fb->status_data); - - _ecore_drm2_fb_deref(fb); - s->fb = NULL; - if (_ecore_drm2_use_atomic) - { - if (s->atomic_req) - sym_drmModeAtomicFree(s->atomic_req); - s->atomic_req = NULL; - } -} - -static void -_cb_mainloop_async_timer_del(void *data) -{ - Ecore_Drm2_Output *output = data; - - ecore_timer_del(output->flip_timeout); - output->flip_timeout = NULL; -} - -EAPI Eina_Bool -ecore_drm2_fb_flip_complete(Ecore_Drm2_Output *output) -{ - Eina_Bool plane_scanout; - Ecore_Drm2_Fb *fb; - - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - - if (output->flip_timeout) - { - // XXX: output ref++ - ecore_main_loop_thread_safe_call_async - (_cb_mainloop_async_timer_del, output); - } - if (!output->pending.fb) fprintf(stderr, "XXX--XXX eeeeek pending fb is NULL so current would become null ----------------------------------\n"); - if (output->current.fb && (output->current.fb != output->pending.fb)) - _ecore_drm2_fb_buffer_release(output, &output->current); - - output->current.fb = output->pending.fb; - output->pending.fb = NULL; - - if (_ecore_drm2_use_atomic) - { - Eina_List *l, *ll; - Ecore_Drm2_Plane *plane; - - output->current.atomic_req = output->pending.atomic_req; - output->pending.atomic_req = NULL; - - EINA_LIST_FOREACH_SAFE(output->planes, l, ll, plane) - { - fb = plane->fb; - plane_scanout = plane->scanout; - if (!plane->dead) - { - /* First time this plane is scanned out */ - if (!plane->scanout) - fb->scanout_count++; - - plane->scanout = EINA_TRUE; - if (fb->status_handler && (fb->scanout_count == 1) && - (plane_scanout != plane->scanout)) - fb->status_handler(fb, ECORE_DRM2_FB_STATUS_SCANOUT_ON, - fb->status_data); - continue; - } - output->planes = eina_list_remove_list(output->planes, l); - free(plane); - if (!plane_scanout) continue; - - fb->scanout_count--; - if (fb->status_handler && (fb->scanout_count == 0)) - fb->status_handler(fb, ECORE_DRM2_FB_STATUS_SCANOUT_OFF, - fb->status_data); - } - } - - EINA_LIST_FREE(output->fbs, fb) - _ecore_drm2_fb_deref(fb); - output->fbs = NULL; - - return !!output->next.fb; -} - -Eina_Bool -_fb_atomic_flip_test(Ecore_Drm2_Output *output) -{ - int ret = 0; - Eina_List *l; - Ecore_Drm2_Crtc_State *cstate; - Ecore_Drm2_Plane_State *pstate; - Ecore_Drm2_Plane *plane; - drmModeAtomicReq *req = NULL; - uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_ATOMIC_ALLOW_MODESET | - DRM_MODE_ATOMIC_TEST_ONLY; - - if (!_ecore_drm2_use_atomic) return EINA_FALSE; - - req = sym_drmModeAtomicAlloc(); - if (!req) return EINA_FALSE; - - sym_drmModeAtomicSetCursor(req, 0); - - cstate = output->crtc_state; - - ret = - sym_drmModeAtomicAddProperty(req, cstate->obj_id, cstate->mode.id, - cstate->mode.value); - if (ret < 0) goto err; - - ret = - sym_drmModeAtomicAddProperty(req, cstate->obj_id, cstate->active.id, - cstate->active.value); - if (ret < 0) goto err; - - if (cstate->background.id) - { - ret = - sym_drmModeAtomicAddProperty(req, cstate->obj_id, - cstate->background.id, - cstate->background.value); - if (ret < 0) goto err; - } - - EINA_LIST_FOREACH(output->planes, l, plane) - { - pstate = plane->state; - - if (!pstate->in_use) - { - pstate->cid.value = 0; - pstate->fid.value = 0; - pstate->sw.value = 0; - pstate->sh.value = 0; - pstate->cx.value = 0; - pstate->cy.value = 0; - pstate->cw.value = 0; - pstate->ch.value = 0; - } - - ret = - sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->cid.id, pstate->cid.value); - if (ret < 0) goto err; - - ret = - sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->fid.id, pstate->fid.value); - if (ret < 0) goto err; - - ret = - sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->sx.id, pstate->sx.value); - if (ret < 0) goto err; - - ret = - sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->sy.id, pstate->sy.value); - if (ret < 0) goto err; - - ret = - sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->sw.id, pstate->sw.value); - if (ret < 0) goto err; - - ret = - sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->sh.id, pstate->sh.value); - if (ret < 0) goto err; - - ret = - sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->cx.id, pstate->cx.value); - if (ret < 0) goto err; - - ret = - sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->cy.id, pstate->cy.value); - if (ret < 0) goto err; - - ret = - sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->cw.id, pstate->cw.value); - if (ret < 0) goto err; - - ret = - sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->ch.id, pstate->ch.value); - if (ret < 0) goto err; - -#if 0 - /* XXX: Disable hardware plane rotation for now as this has broken - * recently. The break happens because of an invalid argument, - * ie: the value being sent from pstate->rotation_map ends up being - * incorrect for some reason. I suspect the breakage to be from - * kernel drivers (linux 4.20.0) but have not confirmed that version */ - if ((pstate->rotation.id) && - (pstate->type.value == DRM_PLANE_TYPE_PRIMARY)) - { - DBG("Plane %d Atomic Rotation: %lu", - pstate->obj_id, pstate->rotation.value); - ret = - sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->rotation.id, - pstate->rotation_map[pstate->rotation.value]); - if (ret < 0) goto err; - } -#endif - } - - ret = - sym_drmModeAtomicCommit(output->fd, req, flags, output); - if (ret < 0) goto err; - - /* clear any previous request */ - if (output->prep.atomic_req) - sym_drmModeAtomicFree(output->prep.atomic_req); - - output->prep.atomic_req = req; - return EINA_TRUE; - -err: - DBG("Failed Atomic Test: %m"); - sym_drmModeAtomicFree(req); - - return EINA_FALSE; -} - -static int _fb_atomic_flip(Ecore_Drm2_Output *output); -static int _fb_flip(Ecore_Drm2_Output *output); - -static Eina_Bool -_cb_flip_timeout(void *data) -{ - Ecore_Drm2_Output *output = data; - - output->flip_timeout = NULL; - ERR("flip event callback timout %0.2fsec - try again", FLIP_TIMEOUT); - if (_ecore_drm2_use_atomic) _fb_atomic_flip(output); - else _fb_flip(output); - return EINA_FALSE; -} - -static void -_cb_mainloop_async_timer_reset(void *data) -{ - Ecore_Drm2_Output *output = data; - if (output->flip_timeout) ecore_timer_del(output->flip_timeout); - output->flip_timeout = ecore_timer_add(FLIP_TIMEOUT, _cb_flip_timeout, output); -} - -static int -_fb_atomic_flip(Ecore_Drm2_Output *output) -{ - int res = 0; - uint32_t flags = - DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT | - DRM_MODE_ATOMIC_ALLOW_MODESET; - - if (!_ecore_drm2_use_atomic) return -1; - - /* If we have no req yet, we're flipping to current state. - * rebuild the current state in the prep state */ - if (!output->prep.atomic_req) _fb_atomic_flip_test(output); - - /* Still no req is a bad situation */ - EINA_SAFETY_ON_NULL_RETURN_VAL(output->prep.atomic_req, -1); - - // sometimes we get a EBUSY ... so try again a few times. - int i; - for (i = 0; i < 10; i++) - { - res = - sym_drmModeAtomicCommit(output->fd, output->prep.atomic_req, flags, - output); - if (res == 0) break; - else ERR("DRM atomic commit failed - retry #%i", i + 1); - usleep(100); - } - - if (res < 0) - { - ERR("Failed Atomic Commit: %m"); - return -1; - } - else - { - // XXX: output ref++ - ecore_main_loop_thread_safe_call_async - (_cb_mainloop_async_timer_reset, output); - } - - return 0; -} - -static int -_fb_flip(Ecore_Drm2_Output *output) -{ - Ecore_Drm2_Fb *fb; - Eina_Bool repeat; - int count = 0; - int ret = 0; - - fb = output->prep.fb; - if (!fb) - { - fb = output->pending.fb; - ERR("Trying to flip NULL fb - fallback to pending fb"); - } - if (!fb) - { - ERR("Pending fb is also NULL, give up flipping"); - return ret; - } - - if ((!output->current.fb) || - (output->current.fb->strides[0] != fb->strides[0])) - { - ret = - sym_drmModeSetCrtc(fb->fd, output->crtc_id, fb->id, - 0, 0, &output->conn_id, 1, - &output->current_mode->info); - if (ret) - { - ERR("Failed to set Mode %dx%d for Output %s: %m", - output->current_mode->width, output->current_mode->height, - output->name); - return ret; - } - - if (output->current.fb) - _ecore_drm2_fb_buffer_release(output, &output->current); - output->current.fb = fb; - _ecore_drm2_fb_ref(output->current.fb); - output->next.fb = NULL; - /* We used to return here, but now that the ticker is fixed this - * can leave us hanging waiting for a tick to happen forever. - * Instead, we now fall through to the flip path to make sure - * even this first set can cause a flip callback. - */ - } - - do - { - static Eina_Bool bugged_about_bug = EINA_FALSE; - repeat = EINA_FALSE; - ret = sym_drmModePageFlip(fb->fd, output->crtc_id, fb->id, - DRM_MODE_PAGE_FLIP_EVENT, output); - /* Some drivers (RPI - looking at you) are broken and produce - * flip events before they are ready for another flip, so be - * a little robust in the face of badness and try a few times - * until we can flip or we give up (100 tries with a yield - * between each try). We can't expect everyone to run the - * latest bleeding edge kernel IF a workaround is possible - * in userspace, so do this. - * We only report this as an ERR once since if it will - * generate a huge amount of spam otherwise. */ - if ((ret < 0) && (errno == EBUSY)) - { - repeat = EINA_TRUE; - if (count == 0 && !bugged_about_bug) - { - ERR("Pageflip fail - EBUSY from drmModePageFlip - " - "This is either a kernel bug or an EFL one."); - bugged_about_bug = EINA_TRUE; - } - count++; - if (count > 500) - { - ERR("Pageflip EBUSY for %i tries - give up", count); - break; - } - usleep(100); - } - else - { - // XXX: output ref++ - ecore_main_loop_thread_safe_call_async - (_cb_mainloop_async_timer_reset, output); - } - } - while (repeat); - - if ((ret == 0) && (count > 0)) - DBG("Pageflip finally succeeded after %i tries due to EBUSY", count); - - if ((ret < 0) && (errno != EBUSY)) - { - ERR("Pageflip Failed for Crtc %u on Connector %u: %m", - output->crtc_id, output->conn_id); - return ret; - } - else if (ret < 0) - { - output->next.fb = fb; - _ecore_drm2_fb_ref(output->next.fb); - } - - return 0; -} - -EAPI int -ecore_drm2_fb_flip(Ecore_Drm2_Fb *fb, Ecore_Drm2_Output *output) -{ - int ret = -1; - - EINA_SAFETY_ON_NULL_RETURN_VAL(output, -1); - EINA_SAFETY_ON_NULL_RETURN_VAL(output->current_mode, -1); - - if (!output->enabled) return -1; - - if (fb) _ecore_drm2_fb_ref(fb); - - if (output->pending.fb) - { - if (output->next.fb) - _ecore_drm2_fb_buffer_release(output, &output->next); - output->next.fb = fb; - return 0; - } - if (!fb) - { - fb = output->next.fb; - output->next.fb = NULL; - } - - /* So we can generate a tick by flipping to the current fb */ - if (!fb) fb = output->current.fb; - - if (output->next.fb) - _ecore_drm2_fb_buffer_release(output, &output->next); - - /* If we don't have an fb to set by now, BAIL! */ - if (!fb) return -1; - - output->prep.fb = fb; - - if (_ecore_drm2_use_atomic) - ret = _fb_atomic_flip(output); - else - ret = _fb_flip(output); - - if (ret) - { - if (output->prep.fb != output->current.fb) - _ecore_drm2_fb_buffer_release(output, &output->prep); - return ret; - } - output->pending.fb = output->prep.fb; - output->prep.fb = NULL; - - if (_ecore_drm2_use_atomic) - { - output->pending.atomic_req = output->prep.atomic_req; - output->prep.atomic_req = NULL; - } - - return 0; -} - -EAPI Eina_Bool -ecore_drm2_fb_busy_get(Ecore_Drm2_Fb *fb) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE); - EINA_SAFETY_ON_TRUE_RETURN_VAL(fb->dead, EINA_FALSE); - - return !!(fb->ref - 1); -} - -EAPI Eina_Bool -ecore_drm2_fb_release(Ecore_Drm2_Output *o, Eina_Bool panic) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(o, EINA_FALSE); - - if (o->next.fb) - { - _ecore_drm2_fb_buffer_release(o, &o->next); - return EINA_TRUE; - } - if (!panic) return EINA_FALSE; - - /* This has been demoted to DBG from WRN because we - * call this function to reclaim all buffers on a - * surface resize. - */ - DBG("Buffer release request when no next buffer"); - /* If we have to release these we're going to see tearing. - * Try to reclaim in decreasing order of visual awfulness - */ - if (o->current.fb) - { - _ecore_drm2_fb_buffer_release(o, &o->current); - return EINA_TRUE; - } - - if (o->pending.fb) - { - _ecore_drm2_fb_buffer_release(o, &o->pending); - return EINA_TRUE; - } - - return EINA_FALSE; -} - -EAPI void * -ecore_drm2_fb_bo_get(Ecore_Drm2_Fb *fb) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(fb, NULL); - EINA_SAFETY_ON_TRUE_RETURN_VAL(fb->dead, NULL); - - return fb->gbm_bo; -} - -EAPI Ecore_Drm2_Fb * -ecore_drm2_fb_dmabuf_import(Ecore_Drm2_Device *dev, int width, int height, int depth, int bpp, unsigned int format, unsigned int strides[4], int dmabuf_fd[4], int dmabuf_fd_count) -{ - int i; - Ecore_Drm2_Fb *fb; - - EINA_SAFETY_ON_NULL_RETURN_VAL(dev, NULL); - - fb = calloc(1, sizeof(Ecore_Drm2_Fb)); - if (!fb) return NULL; - - for (i = 0; i < dmabuf_fd_count; i++) - if (sym_drmPrimeFDToHandle(dev->fd, dmabuf_fd[i], &fb->handles[i])) - goto fail; - - fb->dmabuf = EINA_TRUE; - fb->fd = dev->fd; - fb->w = width; - fb->h = height; - fb->bpp = bpp; - fb->depth = depth; - fb->format = format; - fb->ref = 1; - - memcpy(&fb->strides, strides, sizeof(fb->strides)); - if (_fb2_create(fb)) return fb; - -fail: - free(fb); - return NULL; -} - -EAPI void -ecore_drm2_fb_status_handler_set(Ecore_Drm2_Fb *fb, Ecore_Drm2_Fb_Status_Handler handler, void *data) -{ - fb->status_handler = handler; - fb->status_data = data; -} diff --git a/src/lib/ecore_drm2/ecore_drm2_outputs.c b/src/lib/ecore_drm2/ecore_drm2_outputs.c deleted file mode 100644 index 77123c948a..0000000000 --- a/src/lib/ecore_drm2/ecore_drm2_outputs.c +++ /dev/null @@ -1,1766 +0,0 @@ -#include "ecore_drm2_private.h" - -#define INSIDE(x, y, xx, yy, ww, hh) \ - (((x) < ((xx) + (ww))) && ((y) < ((yy) + (hh))) && \ - ((x) >= (xx)) && ((y) >= (yy))) - -#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe -#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc -#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff -#define EDID_OFFSET_DATA_BLOCKS 0x36 -#define EDID_OFFSET_LAST_BLOCK 0x6c -#define EDID_OFFSET_PNPID 0x08 -#define EDID_OFFSET_SERIAL 0x0c - -static const char *conn_types[] = -{ - "None", "VGA", "DVI-I", "DVI-D", "DVI-A", - "Composite", "S-Video", "LVDS", "Component", "DIN", - "DisplayPort", "HDMI-A", "HDMI-B", "TV", "eDP", "Virtual", "DSI", -}; - -static void -_output_debug(Ecore_Drm2_Output *output, const drmModeConnector *conn) -{ - Eina_List *l; - Ecore_Drm2_Output_Mode *omode; - Ecore_Drm2_Plane_State *pstate; - - DBG("Created New Output At %d,%d", output->x, output->y); - DBG("\tCrtc Pos: %d %d", output->ocrtc->x, output->ocrtc->y); - DBG("\tCrtc: %d", output->crtc_id); - DBG("\tConn: %d", output->conn_id); - DBG("\tName: %s", output->name); - DBG("\tMake: %s", output->make); - DBG("\tModel: %s", output->model); - DBG("\tSerial: %s", output->serial); - DBG("\tCloned: %d", output->cloned); - DBG("\tPrimary: %d", output->primary); - DBG("\tConnected: %d", output->connected); - DBG("\tEnabled: %d", output->enabled); - - if (output->backlight.path) - { - DBG("\tBacklight"); - switch (output->backlight.type) - { - case ECORE_DRM2_BACKLIGHT_RAW: - DBG("\t\tType: Raw"); - break; - case ECORE_DRM2_BACKLIGHT_PLATFORM: - DBG("\t\tType: Platform"); - break; - case ECORE_DRM2_BACKLIGHT_FIRMWARE: - DBG("\t\tType: Firmware"); - break; - } - DBG("\t\tPath: %s", output->backlight.path); - } - - EINA_LIST_FOREACH(output->plane_states, l, pstate) - DBG("\tPossible Plane: %d", pstate->obj_id); - - EINA_LIST_FOREACH(output->modes, l, omode) - { - DBG("\tAdded Mode: %dx%d@%d%s%s%s", - omode->width, omode->height, omode->refresh, - (omode->flags & DRM_MODE_TYPE_PREFERRED) ? ", preferred" : "", - (omode->flags & DRM_MODE_TYPE_DEFAULT) ? ", current" : "", - (conn->count_modes == 0) ? ", built-in" : ""); - } -} - -static void -_cb_output_event_free(void *data EINA_UNUSED, void *event) -{ - Ecore_Drm2_Event_Output_Changed *ev; - - ev = event; - eina_stringshare_del(ev->make); - eina_stringshare_del(ev->model); - eina_stringshare_del(ev->name); - free(ev); -} - -static void -_output_event_send(Ecore_Drm2_Output *output) -{ - Ecore_Drm2_Event_Output_Changed *ev; - - ev = calloc(1, sizeof(Ecore_Drm2_Event_Output_Changed)); - if (!ev) return; - - ev->id = output->crtc_id; - - ev->x = output->x; - ev->y = output->y; - if (output->current_mode) - { - ev->w = output->current_mode->width; - ev->h = output->current_mode->height; - ev->refresh = output->current_mode->refresh; - } - else - { - ev->w = output->ocrtc->width; - ev->h = output->ocrtc->height; - ev->refresh = 0; - } - - ev->phys_width = output->pw; - ev->phys_height = output->ph; - - ev->scale = output->scale; - ev->subpixel = output->subpixel; - ev->transform = output->transform; - ev->connected = output->connected; - ev->enabled = output->enabled; - - ev->name = eina_stringshare_ref(output->name); - ev->make = eina_stringshare_ref(output->make); - ev->model = eina_stringshare_ref(output->model); - - ecore_event_add(ECORE_DRM2_EVENT_OUTPUT_CHANGED, ev, - _cb_output_event_free, NULL); -} - -static void -_output_edid_parse_string(const uint8_t *data, char text[]) -{ - int i = 0, rep = 0; - - strncpy(text, (const char *)data, 12); - - for (; text[i] != '\0'; i++) - { - if ((text[i] == '\n') || (text[i] == '\r')) - { - text[i] = '\0'; - break; - } - } - - for (i = 0; text[i] != '\0'; i++) - { - if (!isprint(text[i])) - { - text[i] = '-'; - rep++; - } - } - - if (rep > 4) text[0] = '\0'; -} - -static int -_output_edid_parse(Ecore_Drm2_Output *output, const uint8_t *data, size_t len) -{ - int i = 0; - uint32_t serial; - - if (len < 128) return -1; - if ((data[0] != 0x00) || (data[1] != 0xff)) return -1; - - output->edid.pnp[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1; - output->edid.pnp[1] = - 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + - ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1; - output->edid.pnp[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1; - output->edid.pnp[3] = '\0'; - - serial = (uint32_t) data[EDID_OFFSET_SERIAL + 0]; - serial += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100; - serial += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000; - serial += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000; - if (serial > 0) - sprintf(output->edid.serial, "%lu", (unsigned long)serial); - - for (i = EDID_OFFSET_DATA_BLOCKS; i <= EDID_OFFSET_LAST_BLOCK; i += 18) - { - if (data[i] != 0) continue; - if (data[i + 2] != 0) continue; - - if (data[i + 3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) - _output_edid_parse_string(&data[i + 5], output->edid.monitor); - else if (data[i + 3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) - _output_edid_parse_string(&data[i + 5], output->edid.serial); - else if (data[i + 3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) - _output_edid_parse_string(&data[i + 5], output->edid.eisa); - } - - return 0; -} - -static void -_output_edid_atomic_find(Ecore_Drm2_Output *output) -{ - Ecore_Drm2_Connector_State *cstate; - int ret = 0; - - cstate = output->conn_state; - - ret = _output_edid_parse(output, cstate->edid.data, cstate->edid.len); - if (!ret) - { - if (output->edid.pnp[0] != '\0') - eina_stringshare_replace(&output->make, output->edid.pnp); - if (output->edid.monitor[0] != '\0') - eina_stringshare_replace(&output->model, output->edid.monitor); - if (output->edid.serial[0] != '\0') - eina_stringshare_replace(&output->serial, output->edid.serial); - } -} - -static void -_output_edid_find(Ecore_Drm2_Output *output, const drmModeConnector *conn) -{ - drmModePropertyBlobPtr blob = NULL; - drmModePropertyPtr prop; - int i = 0, ret = 0; - - for (; i < conn->count_props && !blob; i++) - { - if (!(prop = sym_drmModeGetProperty(output->fd, conn->props[i]))) - continue; - if ((prop->flags & DRM_MODE_PROP_BLOB) && - (!strcmp(prop->name, "EDID"))) - { - blob = sym_drmModeGetPropertyBlob(output->fd, conn->prop_values[i]); - } - sym_drmModeFreeProperty(prop); - if (blob) break; - } - - if (!blob) return; - - output->edid.blob = eina_memdup(blob->data, blob->length, 1); - - ret = _output_edid_parse(output, blob->data, blob->length); - if (!ret) - { - if (output->edid.pnp[0] != '\0') - eina_stringshare_replace(&output->make, output->edid.pnp); - if (output->edid.monitor[0] != '\0') - eina_stringshare_replace(&output->model, output->edid.monitor); - if (output->edid.serial[0] != '\0') - eina_stringshare_replace(&output->serial, output->edid.serial); - } - - sym_drmModeFreePropertyBlob(blob); -} - -static int -_output_crtc_find(const drmModeRes *res, const drmModeConnector *conn, int fd) -{ - drmModeEncoder *enc; - uint32_t crtc; - int i = 0, j = 0; - - /* Skip all disconnected connectors... - * - * When a connector is disconnected it still has an encoder id - * which messes up our output selection code later. When we support - * multi-head properly and hotplug becomes a real thing we'll - * need to revisit this hack (and the crtc assignment code as well) - */ - if (conn->connection != DRM_MODE_CONNECTED) return -1; - - for (j = 0; j < conn->count_encoders; j++) - { - enc = sym_drmModeGetEncoder(fd, conn->encoders[j]); - if (!enc) continue; - - crtc = enc->crtc_id; - sym_drmModeFreeEncoder(enc); - - for (i = 0; i < res->count_crtcs; i++) - if (crtc == res->crtcs[i]) - return i; - } - - return -1; -} - -static char * -_output_name_get(const drmModeConnector *conn) -{ - char name[DRM_CONNECTOR_NAME_LEN]; - const char *type = NULL; - - if (conn->connector_type < EINA_C_ARRAY_LENGTH(conn_types)) - type = conn_types[conn->connector_type]; - else - type = "UNKNOWN"; - - snprintf(name, sizeof(name), "%s-%d", type, conn->connector_type_id); - return strdup(name); -} - -static Ecore_Drm2_Output_Mode * -_output_mode_add(Ecore_Drm2_Output *output, const drmModeModeInfo *info) -{ - Ecore_Drm2_Output_Mode *mode; - uint64_t refresh; - - EINA_SAFETY_ON_NULL_RETURN_VAL(info, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL((info->htotal > 0), NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL((info->vtotal > 0), NULL); - - mode = calloc(1, sizeof(Ecore_Drm2_Output_Mode)); - if (!mode) return NULL; - - mode->flags = 0; - mode->width = info->hdisplay; - mode->height = info->vdisplay; - - refresh = (info->clock * 1000LL / info->htotal + info->vtotal / 2) / - info->vtotal; - - if (info->flags & DRM_MODE_FLAG_INTERLACE) - refresh *= 2; - if (info->flags & DRM_MODE_FLAG_DBLSCAN) - refresh /= 2; - if (info->vscan > 1) - refresh /= info->vscan; - - mode->refresh = refresh; - mode->info = *info; - - if (info->type & DRM_MODE_TYPE_PREFERRED) - mode->flags |= DRM_MODE_TYPE_PREFERRED; - - output->modes = eina_list_append(output->modes, mode); - - return mode; -} - -static void -_output_modes_create(Ecore_Drm2_Device *dev, Ecore_Drm2_Output *output, const drmModeConnector *conn) -{ - int i = 0; - drmModeCrtc *crtc; - drmModeEncoder *enc; - drmModeModeInfo crtc_mode; - Ecore_Drm2_Output_Mode *omode; - Ecore_Drm2_Output_Mode *current = NULL, *preferred = NULL, *best = NULL; - Eina_List *l = NULL; - - memset(&crtc_mode, 0, sizeof(crtc_mode)); - - enc = sym_drmModeGetEncoder(dev->fd, conn->encoder_id); - if (enc) - { - crtc = sym_drmModeGetCrtc(dev->fd, enc->crtc_id); - sym_drmModeFreeEncoder(enc); - if (!crtc) return; - if (crtc->mode_valid) crtc_mode = crtc->mode; - sym_drmModeFreeCrtc(crtc); - } - - for (i = 0; i < conn->count_modes; i++) - { - omode = _output_mode_add(output, &conn->modes[i]); - if (!omode) continue; - } - - EINA_LIST_REVERSE_FOREACH(output->modes, l, omode) - { - if (!memcmp(&crtc_mode, &omode->info, sizeof(crtc_mode))) - current = omode; - if (omode->flags & DRM_MODE_TYPE_PREFERRED) - preferred = omode; - best = omode; - } - - if ((!current) && (crtc_mode.clock != 0)) - { - current = _output_mode_add(output, &crtc_mode); - if (!current) goto err; - } - - if (current) output->current_mode = current; - else if (preferred) output->current_mode = preferred; - else if (best) output->current_mode = best; - - if (!output->current_mode) goto err; - - output->current_mode->flags |= DRM_MODE_TYPE_DEFAULT; - - return; - -err: - EINA_LIST_FREE(output->modes, omode) - free(omode); -} - -static drmModePropertyPtr -_output_dpms_property_get(int fd, const drmModeConnector *conn) -{ - drmModePropertyPtr prop; - int i = 0; - - for (; i < conn->count_props; i++) - { - prop = sym_drmModeGetProperty(fd, conn->props[i]); - if (!prop) continue; - - if (!strcmp(prop->name, "DPMS")) return prop; - - sym_drmModeFreeProperty(prop); - } - - return NULL; -} - -static double -_output_backlight_value_get(Ecore_Drm2_Output *output, const char *attr) -{ - const char *b = NULL; - double ret = 0.0; - - if ((!output) || (!output->backlight.path)) return 0.0; - - b = eeze_udev_syspath_get_sysattr(output->backlight.path, attr); - if (!b) return 0.0; - - ret = strtod(b, NULL); - if (ret < 0) ret = 0.0; - - return ret; -} - -static void -_output_backlight_init(Ecore_Drm2_Output *output, unsigned int conn_type) -{ - Eina_List *devs, *l; - const char *dev, *t; - Eina_Bool found = EINA_FALSE; - Ecore_Drm2_Backlight_Type type = 0; - - devs = eeze_udev_find_by_filter("backlight", NULL, NULL); - - EINA_LIST_FOREACH(devs, l, dev) - { - t = eeze_udev_syspath_get_sysattr(dev, "type"); - if (!t) continue; - - if (!strcmp(t, "raw")) - type = ECORE_DRM2_BACKLIGHT_RAW; - else if (!strcmp(t, "platform")) - type = ECORE_DRM2_BACKLIGHT_PLATFORM; - else if (!strcmp(t, "firmware")) - type = ECORE_DRM2_BACKLIGHT_FIRMWARE; - - if ((conn_type == DRM_MODE_CONNECTOR_LVDS) || - (conn_type == DRM_MODE_CONNECTOR_eDP) || - (type == ECORE_DRM2_BACKLIGHT_RAW)) - found = EINA_TRUE; - - eina_stringshare_del(t); - if (found) break; - } - - if (found) - { - output->backlight.type = type; - output->backlight.path = eina_stringshare_add(dev); - output->backlight.max = - _output_backlight_value_get(output, "max_brightness"); - output->backlight.value = - _output_backlight_value_get(output, "brightness"); - } - - EINA_LIST_FREE(devs, dev) - eina_stringshare_del(dev); -} - -static void -_output_scale_init(Ecore_Drm2_Output *output, Ecore_Drm2_Transform transform, unsigned int scale) -{ - output->transform = transform; - - if ((output->enabled) && (output->current_mode)) - { - switch (transform) - { - case ECORE_DRM2_TRANSFORM_90: - case ECORE_DRM2_TRANSFORM_270: - case ECORE_DRM2_TRANSFORM_FLIPPED_90: - case ECORE_DRM2_TRANSFORM_FLIPPED_270: - output->w = output->current_mode->height; - output->h = output->current_mode->width; - break; - case ECORE_DRM2_TRANSFORM_NORMAL: - case ECORE_DRM2_TRANSFORM_180: - case ECORE_DRM2_TRANSFORM_FLIPPED: - case ECORE_DRM2_TRANSFORM_FLIPPED_180: - output->w = output->current_mode->width; - output->h = output->current_mode->height; - break; - default: - break; - } - } - - output->scale = scale; - output->w /= scale; - output->h /= scale; -} - -static void -_output_matrix_rotate_xy(Eina_Matrix3 *matrix, double x, double y) -{ - Eina_Matrix4 tmp, m; - - eina_matrix4_identity(&tmp); - eina_matrix4_values_set(&tmp, x, y, 0, 0, -y, x, 0, 0, - 0, 0, 1, 0, 0, 0, 0, 1); - - eina_matrix3_matrix4_to(&m, matrix); - eina_matrix4_multiply(&m, &m, &tmp); - eina_matrix4_matrix3_to(matrix, &m); -} - -static void -_output_matrix_update(Ecore_Drm2_Output *output) -{ - Eina_Matrix3 m3; - - eina_matrix4_identity(&output->matrix); - eina_matrix4_matrix3_to(&m3, &output->matrix); - eina_matrix3_translate(&m3, -output->x, -output->y); - - switch (output->transform) - { - case ECORE_DRM2_TRANSFORM_FLIPPED: - case ECORE_DRM2_TRANSFORM_FLIPPED_90: - case ECORE_DRM2_TRANSFORM_FLIPPED_180: - case ECORE_DRM2_TRANSFORM_FLIPPED_270: - eina_matrix3_translate(&m3, -output->w, 0); - break; - default: - break; - } - - switch (output->transform) - { - case ECORE_DRM2_TRANSFORM_NORMAL: - case ECORE_DRM2_TRANSFORM_FLIPPED: - default: - break; - case ECORE_DRM2_TRANSFORM_90: - case ECORE_DRM2_TRANSFORM_FLIPPED_90: - eina_matrix3_translate(&m3, 0, -output->h); - _output_matrix_rotate_xy(&m3, 0, 1); - break; - case ECORE_DRM2_TRANSFORM_180: - case ECORE_DRM2_TRANSFORM_FLIPPED_180: - eina_matrix3_translate(&m3, -output->w, -output->h); - _output_matrix_rotate_xy(&m3, -1, 0); - break; - case ECORE_DRM2_TRANSFORM_270: - case ECORE_DRM2_TRANSFORM_FLIPPED_270: - eina_matrix3_translate(&m3, -output->w, 0); - _output_matrix_rotate_xy(&m3, 0, -1); - break; - } - - if (output->scale != 1) - eina_matrix3_scale(&m3, output->scale, output->scale); - - eina_matrix3_matrix4_to(&output->matrix, &m3); - eina_matrix4_inverse(&output->inverse, &output->matrix); -} - -static Ecore_Drm2_Crtc_State * -_atomic_state_crtc_duplicate(Ecore_Drm2_Crtc_State *state) -{ - Ecore_Drm2_Crtc_State *cstate; - - cstate = calloc(1, sizeof(Ecore_Drm2_Crtc_State)); - if (!cstate) return NULL; - - memcpy(cstate, state, sizeof(Ecore_Drm2_Crtc_State)); - - return cstate; -} - -static Ecore_Drm2_Crtc_State * -_output_crtc_state_get(Ecore_Drm2_Atomic_State *state, unsigned int id) -{ - Ecore_Drm2_Crtc_State *cstate; - int i = 0; - - for (; i < state->crtcs; i++) - { - cstate = &state->crtc_states[i]; - if (cstate->obj_id != id) continue; - return _atomic_state_crtc_duplicate(cstate); - } - - return NULL; -} - -static Ecore_Drm2_Connector_State * -_atomic_state_conn_duplicate(Ecore_Drm2_Connector_State *state) -{ - Ecore_Drm2_Connector_State *cstate; - - cstate = calloc(1, sizeof(Ecore_Drm2_Connector_State)); - if (!cstate) return NULL; - - memcpy(cstate, state, sizeof(Ecore_Drm2_Connector_State)); - - return cstate; -} - -static Ecore_Drm2_Connector_State * -_output_conn_state_get(Ecore_Drm2_Atomic_State *state, unsigned int id) -{ - Ecore_Drm2_Connector_State *cstate; - int i = 0; - - for (; i < state->conns; i++) - { - cstate = &state->conn_states[i]; - if (cstate->obj_id != id) continue; - return _atomic_state_conn_duplicate(cstate); - } - - return NULL; -} - -static Ecore_Drm2_Plane_State * -_atomic_state_plane_duplicate(Ecore_Drm2_Plane_State *state) -{ - Ecore_Drm2_Plane_State *pstate; - - pstate = calloc(1, sizeof(Ecore_Drm2_Plane_State)); - if (!pstate) return NULL; - - memcpy(pstate, state, sizeof(Ecore_Drm2_Plane_State)); - - return pstate; -} - -static Eina_List * -_output_plane_states_get(Ecore_Drm2_Atomic_State *state, unsigned int crtc_id, int index) -{ - Eina_List *states = NULL; - Ecore_Drm2_Plane_State *pstate; - - int i = 0; - - for (; i < state->planes; i++) - { - pstate = &state->plane_states[i]; - if (pstate->cid.value == crtc_id) - { - states = - eina_list_append(states, _atomic_state_plane_duplicate(pstate)); - } - else if (pstate->mask & (1ULL << index)) - { - states = - eina_list_append(states, _atomic_state_plane_duplicate(pstate)); - } - } - - return states; -} - -static Eina_Bool -_output_create(Ecore_Drm2_Device *dev, const drmModeRes *res, const drmModeConnector *conn, int x, int y, int *w, Eina_Bool cloned) -{ - Ecore_Drm2_Output *output; - int i = 0; - char *name = NULL; - - if (w) *w = 0; - - i = _output_crtc_find(res, conn, dev->fd); - if (i < 0) return EINA_FALSE; - - output = calloc(1, sizeof(Ecore_Drm2_Output)); - if (!output) return EINA_FALSE; - - output->fd = dev->fd; - output->x = x; - output->y = y; - output->cloned = cloned; - output->pw = conn->mmWidth; - output->ph = conn->mmHeight; - - switch (conn->subpixel) - { - case DRM_MODE_SUBPIXEL_UNKNOWN: - output->subpixel = 0; // WL_OUTPUT_SUBPIXEL_UNKNOWN - break; - case DRM_MODE_SUBPIXEL_NONE: - output->subpixel = 1; // WL_OUTPUT_SUBPIXEL_NONE - break; - case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB: - output->subpixel = 2; // WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB - break; - case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR: - output->subpixel = 3; // WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR - break; - case DRM_MODE_SUBPIXEL_VERTICAL_RGB: - output->subpixel = 4; // WL_OUTPUT_SUBPIXEL_VERTICAL_RGB - break; - case DRM_MODE_SUBPIXEL_VERTICAL_BGR: - output->subpixel = 5; // WL_OUTPUT_SUBPIXEL_VERTICAL_BGR - break; - default: - output->subpixel = 0; - break; - } - - name = _output_name_get(conn); - output->name = eina_stringshare_add(name); - output->make = eina_stringshare_add("unknown"); - output->model = eina_stringshare_add("unknown"); - output->serial = eina_stringshare_add("unknown"); - free(name); - - output->pipe = i; - output->crtc_id = res->crtcs[i]; - output->conn_id = conn->connector_id; - output->conn_type = conn->connector_type; - - output->connected = (conn->connection == DRM_MODE_CONNECTED); - - output->ocrtc = sym_drmModeGetCrtc(dev->fd, output->crtc_id); - - if (_ecore_drm2_use_atomic) - { - output->crtc_state = - _output_crtc_state_get(dev->state, output->crtc_id); - output->conn_state = - _output_conn_state_get(dev->state, output->conn_id); - output->plane_states = - _output_plane_states_get(dev->state, output->crtc_id, output->pipe); - } - - output->dpms = _output_dpms_property_get(dev->fd, conn); - - _output_backlight_init(output, conn->connector_type); - - output->gamma = output->ocrtc->gamma_size; - - _output_modes_create(dev, output, conn); - - if (_ecore_drm2_use_atomic) - _output_edid_atomic_find(output); - else - _output_edid_find(output, conn); - - if (output->connected) output->enabled = EINA_TRUE; - - _output_scale_init(output, ECORE_DRM2_TRANSFORM_NORMAL, 1); - _output_matrix_update(output); - - if (!eina_list_count(dev->outputs)) - output->primary = EINA_TRUE; - else - { - /* temporarily disable other outputs which are not primary */ - output->connected = EINA_FALSE; - output->enabled = EINA_FALSE; - } - - dev->outputs = eina_list_append(dev->outputs, output); - - _output_debug(output, conn); - - if ((output->enabled) && (output->current_mode)) - { - if (w) *w = output->current_mode->width; - } - - return EINA_TRUE; -} - -static Ecore_Drm2_Output * -_output_find_by_con(Ecore_Drm2_Device *dev, uint32_t id) -{ - Ecore_Drm2_Output *output; - Eina_List *l; - - EINA_LIST_FOREACH(dev->outputs, l, output) - if (output->conn_id == id) return output; - - return NULL; -} - -static void -_outputs_update(Ecore_Drm2_Device *dev) -{ - Ecore_Drm2_Output *output; - Eina_List *l, *ll; - drmModeRes *res; - drmModeConnector *conn; - uint32_t *connected; - int i = 0, x = 0, y = 0; - - res = sym_drmModeGetResources(dev->fd); - if (!res) return; - - connected = calloc(res->count_connectors, sizeof(uint32_t)); - if (!connected) - { - sym_drmModeFreeResources(res); - return; - } - - for (i = 0; i < res->count_connectors; i++) - { - conn = sym_drmModeGetConnector(dev->fd, res->connectors[i]); - if (!conn) continue; - - if (conn->connection != DRM_MODE_CONNECTED) goto next; - - connected[i] = res->connectors[i]; - if (!_output_find_by_con(dev, res->connectors[i])) - { - if (dev->outputs) - { - Ecore_Drm2_Output *last; - - last = eina_list_last_data_get(dev->outputs); - if (last) x = last->x + last->current_mode->width; - else x = 0; - } - else - x = 0; - - if (!_output_create(dev, res, conn, x, y, NULL, EINA_TRUE)) - goto next; - } - -next: - sym_drmModeFreeConnector(conn); - } - - sym_drmModeFreeResources(res); - - EINA_LIST_FOREACH_SAFE(dev->outputs, l, ll, output) - { - Eina_Bool disconnected = EINA_TRUE; - - for (i = 0; i < res->count_connectors; i++) - if (connected[i] == output->conn_id) - { - disconnected = EINA_FALSE; - break; - } - - if (disconnected) - { - output->connected = EINA_FALSE; - output->enabled = EINA_FALSE; - } - else - { - output->connected = EINA_TRUE; - output->enabled = EINA_TRUE; - } - - _output_event_send(output); - } - free(connected); -} - -static void -_cb_output_event(const char *device EINA_UNUSED, Eeze_Udev_Event event EINA_UNUSED, void *data, Eeze_Udev_Watch *watch EINA_UNUSED) -{ - Ecore_Drm2_Device *dev; - - dev = data; - _outputs_update(dev); -} - -static void -_output_destroy(Ecore_Drm2_Device *dev EINA_UNUSED, Ecore_Drm2_Output *output) -{ - Ecore_Drm2_Output_Mode *mode; - Ecore_Drm2_Plane *plane; - Ecore_Drm2_Plane_State *pstate; - - if (_ecore_drm2_use_atomic) - { - if (output->prep.atomic_req) - sym_drmModeAtomicFree(output->prep.atomic_req); - - EINA_LIST_FREE(output->plane_states, pstate) - free(pstate); - - EINA_LIST_FREE(output->planes, plane) - free(plane); - - free(output->conn_state); - free(output->crtc_state); - } - - EINA_LIST_FREE(output->modes, mode) - { - if (mode->id) - sym_drmModeDestroyPropertyBlob(output->fd, mode->id); - free(mode); - } - - eina_stringshare_del(output->backlight.path); - eina_stringshare_del(output->name); - eina_stringshare_del(output->make); - eina_stringshare_del(output->model); - eina_stringshare_del(output->serial); - eina_stringshare_del(output->relative.to); - - if (output->flip_timeout) ecore_timer_del(output->flip_timeout); - - sym_drmModeFreeProperty(output->dpms); - free(output->edid.blob); - - free(output); -} - -/* this function is used to indicate if we are in a multi-gpu situation - * and need to calculate vblank sync with high crtc mask */ -static unsigned int -_output_vblank_pipe(Ecore_Drm2_Output *output) -{ - if (output->pipe > 1) - return ((output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) & - DRM_VBLANK_HIGH_CRTC_MASK); - else if (output->pipe > 0) - return DRM_VBLANK_SECONDARY; - else - return 0; -} - -EAPI Eina_Bool -ecore_drm2_outputs_create(Ecore_Drm2_Device *device) -{ - drmModeConnector *conn; - drmModeRes *res; - int i = 0, x = 0, y = 0, w = 0; - int events = 0; - - EINA_SAFETY_ON_NULL_RETURN_VAL(device, EINA_FALSE); - EINA_SAFETY_ON_TRUE_RETURN_VAL((device->fd < 0), EINA_FALSE); - - res = sym_drmModeGetResources(device->fd); - if (!res) return EINA_FALSE; - - device->crtcs = calloc(res->count_crtcs, sizeof(uint32_t)); - if (!device->crtcs) goto err; - - device->min.width = res->min_width; - device->min.height = res->min_height; - device->max.width = res->max_width; - device->max.height = res->max_height; - - device->num_crtcs = res->count_crtcs; - memcpy(device->crtcs, res->crtcs, sizeof(uint32_t) * res->count_crtcs); - - for (i = 0; i < res->count_connectors; i++) - { - conn = sym_drmModeGetConnector(device->fd, res->connectors[i]); - if (!conn) continue; - - if (!_output_create(device, res, conn, x, y, &w, EINA_FALSE)) - goto next; - - x += w; - -next: - sym_drmModeFreeConnector(conn); - } - - if (eina_list_count(device->outputs) < 1) goto err; - - sym_drmModeFreeResources(res); - - events = (EEZE_UDEV_EVENT_ADD | EEZE_UDEV_EVENT_REMOVE | - EEZE_UDEV_EVENT_CHANGE); - - device->watch = - eeze_udev_watch_add(EEZE_UDEV_TYPE_DRM, events, _cb_output_event, device); - - return EINA_TRUE; - -err: - sym_drmModeFreeResources(res); - return EINA_FALSE; -} - -EAPI void -ecore_drm2_outputs_destroy(Ecore_Drm2_Device *device) -{ - Ecore_Drm2_Output *output; - - EINA_SAFETY_ON_NULL_RETURN(device); - - EINA_LIST_FREE(device->outputs, output) - _output_destroy(device, output); -} - -EAPI const Eina_List * -ecore_drm2_outputs_get(Ecore_Drm2_Device *device) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(device, NULL); - return device->outputs; -} - -EAPI int -ecore_drm2_output_dpms_get(Ecore_Drm2_Output *output) -{ - drmModeObjectProperties *props; - drmModePropertyRes *prop; - int val = -1; - unsigned int i; - - EINA_SAFETY_ON_NULL_RETURN_VAL(output, -1); - - props = - sym_drmModeObjectGetProperties(output->fd, output->conn_id, - DRM_MODE_OBJECT_CONNECTOR); - if (!props) return -1; - - for (i = 0; i < props->count_props; i++) - { - prop = sym_drmModeGetProperty(output->fd, props->props[i]); - if (!prop) continue; - - if (!strcmp(prop->name, "DPMS")) - val = props->prop_values[i]; - - sym_drmModeFreeProperty(prop); - } - - sym_drmModeFreeObjectProperties(props); - - return val; -} - -EAPI void -ecore_drm2_output_dpms_set(Ecore_Drm2_Output *output, int level) -{ - EINA_SAFETY_ON_NULL_RETURN(output); - EINA_SAFETY_ON_TRUE_RETURN(!output->enabled); - - sym_drmModeConnectorSetProperty(output->fd, output->conn_id, - output->dpms->prop_id, level); - - if (level == 0) /* DPMS on */ - ecore_drm2_fb_flip(NULL, output); -} - -EAPI char * -ecore_drm2_output_edid_get(Ecore_Drm2_Output *output) -{ - char *edid_str = NULL; - unsigned char *blob; - unsigned char fallback_blob[128]; - - EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL); - - if (_ecore_drm2_use_atomic) - blob = output->conn_state->edid.data; - else - { - EINA_SAFETY_ON_NULL_RETURN_VAL(output->edid.blob, NULL); - blob = output->edid.blob; - } - if (!blob) - { - memset(fallback_blob, 0, sizeof(fallback_blob)); - blob = fallback_blob; - } - - edid_str = malloc((128 * 2) + 1); - if (edid_str) - { - unsigned int k, kk; - const char *hexch = "0123456789abcdef"; - - for (kk = 0, k = 0; k < 128; k++) - { - edid_str[kk] = hexch[(blob[k] >> 4) & 0xf]; - edid_str[kk + 1] = hexch[blob[k] & 0xf]; - kk += 2; - } - edid_str[kk] = 0; - } - - return edid_str; -} - -EAPI Eina_Bool -ecore_drm2_output_backlight_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - return (output->backlight.path != NULL); -} - -EAPI Ecore_Drm2_Output * -ecore_drm2_output_find(Ecore_Drm2_Device *device, int x, int y) -{ - Eina_List *l; - Ecore_Drm2_Output *output; - - EINA_SAFETY_ON_NULL_RETURN_VAL(device, NULL); - - EINA_LIST_FOREACH(device->outputs, l, output) - { - int ox, oy, ow, oh; - - if (!output->enabled) continue; - - ox = output->x; - oy = output->y; - ow = output->current_mode->width; - oh = output->current_mode->height; - - if (INSIDE(x, y, ox, oy, ow, oh)) - return output; - } - - return NULL; -} - -EAPI void -ecore_drm2_output_dpi_get(Ecore_Drm2_Output *output, int *xdpi, int *ydpi) -{ - EINA_SAFETY_ON_NULL_RETURN(output); - EINA_SAFETY_ON_TRUE_RETURN(!output->enabled); - - if (xdpi) - *xdpi = ((25.4 * (output->current_mode->width)) / output->pw); - - if (ydpi) - *ydpi = ((25.4 * (output->current_mode->height)) / output->ph); -} - -EAPI unsigned int -ecore_drm2_output_crtc_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0); - return output->crtc_id; -} - -EAPI Ecore_Drm2_Fb * -ecore_drm2_output_latest_fb_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL); - if (output->pending.fb) return output->pending.fb; - if (output->current.fb) return output->current.fb; - return output->next.fb; -} - -EAPI Eina_Bool -ecore_drm2_output_primary_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - return output->primary; -} - -EAPI void -ecore_drm2_output_primary_set(Ecore_Drm2_Output *output, Eina_Bool primary) -{ - EINA_SAFETY_ON_NULL_RETURN(output); - output->primary = primary; -} - -EAPI Eina_Bool -ecore_drm2_output_enabled_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - return output->enabled; -} - -EAPI void -ecore_drm2_output_enabled_set(Ecore_Drm2_Output *output, Eina_Bool enabled) -{ - EINA_SAFETY_ON_NULL_RETURN(output); - - if (!output->connected) return; - if (output->enabled == enabled) return; - - if (enabled) - { - output->enabled = enabled; - ecore_drm2_output_dpms_set(output, DRM_MODE_DPMS_ON); - } - else - { - if (_ecore_drm2_use_atomic) - ecore_drm2_fb_flip(NULL, output); - - ecore_drm2_output_dpms_set(output, DRM_MODE_DPMS_OFF); - output->enabled = enabled; - - if (output->current.fb) - _ecore_drm2_fb_buffer_release(output, &output->current); - - if (output->next.fb) - _ecore_drm2_fb_buffer_release(output, &output->next); - - if (output->pending.fb) - _ecore_drm2_fb_buffer_release(output, &output->pending); - } - - _output_event_send(output); -} - -EAPI void -ecore_drm2_output_physical_size_get(Ecore_Drm2_Output *output, int *w, int *h) -{ - if (w) *w = 0; - if (h) *h = 0; - - EINA_SAFETY_ON_NULL_RETURN(output); - - if (w) *w = output->pw; - if (h) *h = output->ph; -} - -EAPI const Eina_List * -ecore_drm2_output_modes_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL); - return output->modes; -} - -EAPI void -ecore_drm2_output_mode_info_get(Ecore_Drm2_Output_Mode *mode, int *w, int *h, unsigned int *refresh, unsigned int *flags) -{ - if (w) *w = 0; - if (h) *h = 0; - if (refresh) *refresh = 0; - if (flags) *flags = 0; - - EINA_SAFETY_ON_NULL_RETURN(mode); - - if (w) *w = mode->width; - if (h) *h = mode->height; - if (refresh) *refresh = mode->refresh; - if (flags) *flags = mode->flags; -} - -static Eina_Bool -_output_mode_atomic_set(Ecore_Drm2_Output *output, Ecore_Drm2_Output_Mode *mode) -{ - Ecore_Drm2_Crtc_State *cstate; - drmModeAtomicReq *req = NULL; - int ret = 0; - - cstate = output->crtc_state; - - if (mode) - { - if (mode->id) - sym_drmModeDestroyPropertyBlob(output->fd, mode->id); - - ret = - sym_drmModeCreatePropertyBlob(output->fd, &mode->info, - sizeof(drmModeModeInfo), &mode->id); - if (ret < 0) - { - ERR("Failed to create Mode Property Blob"); - return EINA_FALSE; - } - } - - req = sym_drmModeAtomicAlloc(); - if (!req) return EINA_FALSE; - - sym_drmModeAtomicSetCursor(req, 0); - - if (mode) - { - cstate->active.value = 1; - cstate->mode.value = mode->id; - } - else - cstate->active.value = 0; - - ret = sym_drmModeAtomicAddProperty(req, cstate->obj_id, cstate->mode.id, - cstate->mode.value); - if (ret < 0) - { - ERR("Could not add atomic property"); - ret = EINA_FALSE; - goto err; - } - - ret = sym_drmModeAtomicAddProperty(req, cstate->obj_id, - cstate->active.id, cstate->active.value); - if (ret < 0) - { - ERR("Could not add atomic property"); - ret = EINA_FALSE; - goto err; - } - - if (cstate->background.id) - { - ret = - sym_drmModeAtomicAddProperty(req, cstate->obj_id, - cstate->background.id, - cstate->background.value); - if (ret < 0) - { - ERR("Could not add atomic property"); - ret = EINA_FALSE; - goto err; - } - } - - ret = sym_drmModeAtomicCommit(output->fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, - output); - if (ret < 0) - { - ERR("Failed to commit atomic Mode: %m"); - ret = EINA_FALSE; - goto err; - } - else - ret = EINA_TRUE; - -err: - sym_drmModeAtomicFree(req); - return ret; -} - -EAPI Eina_Bool -ecore_drm2_output_mode_set(Ecore_Drm2_Output *output, Ecore_Drm2_Output_Mode *mode, int x, int y) -{ - Eina_Bool ret = EINA_TRUE; - - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - EINA_SAFETY_ON_TRUE_RETURN_VAL((output->fd < 0), EINA_FALSE); - - output->x = x; - output->y = y; - output->current_mode = mode; - - if (_ecore_drm2_use_atomic) - ret = _output_mode_atomic_set(output, mode); - else - { - if (mode) - { - unsigned int buffer = 0; - - if (output->current.fb) - buffer = output->current.fb->id; - else if (output->next.fb) - buffer = output->next.fb->id; - else - buffer = output->ocrtc->buffer_id; - - if (sym_drmModeSetCrtc(output->fd, output->crtc_id, buffer, 0, 0, - &output->conn_id, 1, &mode->info) < 0) - { - ERR("Failed to set Mode %dx%d for Output %s: %m", - mode->width, mode->height, output->name); - ret = EINA_FALSE; - } - } - else - { - if (sym_drmModeSetCrtc(output->fd, output->crtc_id, 0, - 0, 0, 0, 0, NULL) < 0) - { - ERR("Failed to turn off Output %s: %m", output->name); - ret = EINA_FALSE; - } - } - } - - return ret; -} - -EAPI char * -ecore_drm2_output_name_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(output->name, NULL); - return strdup(output->name); -} - -EAPI char * -ecore_drm2_output_model_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(output->model, NULL); - return strdup(output->model); -} - -EAPI Eina_Bool -ecore_drm2_output_connected_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - return output->connected; -} - -EAPI Eina_Bool -ecore_drm2_output_cloned_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - return (output->cloned || - output->relative.mode == ECORE_DRM2_RELATIVE_MODE_CLONE); -} - -EAPI unsigned int -ecore_drm2_output_connector_type_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0); - return output->conn_type; -} - -EAPI Eina_Bool -ecore_drm2_output_possible_crtc_get(Ecore_Drm2_Output *output, unsigned int crtc) -{ - drmModeRes *res; - drmModeConnector *conn; - drmModeEncoder *enc; - int i = 0, j = 0, k = 0; - unsigned int p = 0; - Eina_Bool ret = EINA_FALSE; - - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - EINA_SAFETY_ON_TRUE_RETURN_VAL((output->fd < 0), EINA_FALSE); - - res = sym_drmModeGetResources(output->fd); - if (!res) return EINA_FALSE; - - for (; i < res->count_connectors; i++) - { - conn = sym_drmModeGetConnector(output->fd, res->connectors[i]); - if (!conn) continue; - - for (j = 0; j < conn->count_encoders; j++) - { - enc = sym_drmModeGetEncoder(output->fd, conn->encoders[j]); - if (!enc) continue; - - if (enc->crtc_id != crtc) goto next; - - p = enc->possible_crtcs; - - for (k = 0; k < res->count_crtcs; k++) - { - if (res->crtcs[k] != output->crtc_id) continue; - - if (p & (1ULL << k)) - { - ret = EINA_TRUE; - break; - } - } - -next: - sym_drmModeFreeEncoder(enc); - if (ret) break; - } - - sym_drmModeFreeConnector(conn); - if (ret) break; - } - - sym_drmModeFreeResources(res); - - return ret; -} - -EAPI void -ecore_drm2_output_user_data_set(Ecore_Drm2_Output *o, void *data) -{ - EINA_SAFETY_ON_NULL_RETURN(o); - - o->user_data = data; -} - -EAPI void * -ecore_drm2_output_user_data_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL); - return output->user_data; -} - -EAPI void -ecore_drm2_output_gamma_set(Ecore_Drm2_Output *output, uint16_t size, uint16_t *red, uint16_t *green, uint16_t *blue) -{ - EINA_SAFETY_ON_NULL_RETURN(output); - EINA_SAFETY_ON_TRUE_RETURN(output->fd < 0); - - if (output->gamma != size) return; - - if (sym_drmModeCrtcSetGamma(output->fd, output->crtc_id, size, - red, green, blue) < 0) - ERR("Failed to set gamma for Output %s: %m", output->name); -} - -EAPI int -ecore_drm2_output_supported_rotations_get(Ecore_Drm2_Output *output) -{ - int ret = -1; - - EINA_SAFETY_ON_NULL_RETURN_VAL(output, -1); - - if (_ecore_drm2_use_atomic) - { - Ecore_Drm2_Plane_State *pstate; - Eina_List *l; - - EINA_LIST_FOREACH(output->plane_states, l, pstate) - { - if (pstate->type.value != DRM_PLANE_TYPE_PRIMARY) continue; - ret = pstate->supported_rotations; - break; - } - } - else - return (ECORE_DRM2_ROTATION_NORMAL | ECORE_DRM2_ROTATION_90 | - ECORE_DRM2_ROTATION_180 | ECORE_DRM2_ROTATION_270); - - return ret; -} - -EAPI Eina_Bool -ecore_drm2_output_rotation_set(Ecore_Drm2_Output *output, int rotation) -{ - Eina_Bool ret = EINA_TRUE; - - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - - output->rotation = rotation; - -#if 0 - /* XXX: Disable hardware plane rotation for now as this has broken - * recently. The break happens because of an invalid argument, - * ie: the value being sent from pstate->rotation_map ends up being - * incorrect for some reason. I suspect the breakage to be from - * kernel drivers (linux 4.20.0) but have not confirmed that version */ - if (_ecore_drm2_use_atomic) - { - Eina_List *l; - Ecore_Drm2_Plane_State *pstate = NULL; - drmModeAtomicReq *req = NULL; - int res = 0; - uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK | - DRM_MODE_ATOMIC_ALLOW_MODESET; - - EINA_LIST_FOREACH(output->plane_states, l, pstate) - { - if (pstate->type.value != DRM_PLANE_TYPE_PRIMARY) continue; - - if ((pstate->supported_rotations & rotation) == 0) - { - WRN("Unsupported rotation"); - return EINA_FALSE; - } - - req = sym_drmModeAtomicAlloc(); - if (!req) return EINA_FALSE; - - sym_drmModeAtomicSetCursor(req, 0); - - res = sym_drmModeAtomicAddProperty(req, pstate->obj_id, - pstate->rotation.id, rotation); - if (res < 0) goto err; - - res = sym_drmModeAtomicCommit(output->fd, req, flags, output); - if (res < 0) - goto err; - else - { - ret = EINA_TRUE; - pstate->rotation.value = rotation; - } - } - -err: - sym_drmModeAtomicFree(req); - } -#endif - - return ret; -} - -EAPI int -ecore_drm2_output_rotation_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, -1); - return output->rotation; -} - -EAPI unsigned int -ecore_drm2_output_subpixel_get(const Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0); - return output->subpixel; -} - -static void -_blank_fallback_handler(int fd EINA_UNUSED, unsigned int frame EINA_UNUSED, unsigned int sec, unsigned int usec, void *data EINA_UNUSED) -{ - Ecore_Drm2_Output *output; - - output = data; - output->fallback_usec = usec; - output->fallback_sec = sec; -} - -static int -_blanktime_fallback(Ecore_Drm2_Output *output, int sequence, long *sec, long *usec) -{ - drmEventContext ctx; - int ret; - - /* Too lazy to loop for > 1, and don't want to block for < 1 */ - if (sequence != 1) return -1; - - /* If we got here with a flip waiting to complete we can do nothing. */ - if (output->pending.fb) return -1; - - if (!output->current.fb) return -1; - - memset(&ctx, 0, sizeof(ctx)); - ctx.version = 2; - ctx.page_flip_handler = _blank_fallback_handler; - ctx.vblank_handler = NULL; - - ret = sym_drmModePageFlip(output->current.fb->fd, output->crtc_id, - output->current.fb->id, DRM_MODE_PAGE_FLIP_EVENT, - output); - if (ret < 0) return -1; - do - { - ret = sym_drmHandleEvent(output->current.fb->fd, &ctx); - } while (ret != 0 && errno == EAGAIN); - if (ret < 0) return -1; - - *sec = output->fallback_sec; - *usec = output->fallback_usec; - return 0; -} - -EAPI Eina_Bool -ecore_drm2_output_blanktime_get(Ecore_Drm2_Output *output, int sequence, long *sec, long *usec) -{ - drmVBlank v; - int ret; - Eina_Bool success; - - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(sec, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(usec, EINA_FALSE); - - memset(&v, 0, sizeof(v)); - v.request.type = DRM_VBLANK_RELATIVE; - v.request.type |= _output_vblank_pipe(output); - v.request.sequence = sequence; - ret = sym_drmWaitVBlank(output->fd, &v); - success = (ret == 0) && (v.reply.tval_sec > 0 || v.reply.tval_usec > 0); - if (!success) - { - ret = _blanktime_fallback(output, sequence, sec, usec); - if (ret) return EINA_FALSE; - return EINA_TRUE; - } - - *sec = v.reply.tval_sec; - *usec = v.reply.tval_usec; - return EINA_TRUE; -} - -EAPI void -ecore_drm2_output_info_get(Ecore_Drm2_Output *output, int *x, int *y, int *w, int *h, unsigned int *refresh) -{ - if (x) *x = 0; - if (y) *y = 0; - if (w) *w = 0; - if (h) *h = 0; - if (refresh) *refresh = 0; - - EINA_SAFETY_ON_NULL_RETURN(output); - EINA_SAFETY_ON_TRUE_RETURN(!output->current_mode); - - switch (output->rotation) - { - case ECORE_DRM2_ROTATION_90: - case ECORE_DRM2_ROTATION_270: - if (w) *w = output->current_mode->height; - if (h) *h = output->current_mode->width; - break; - case ECORE_DRM2_ROTATION_NORMAL: - case ECORE_DRM2_ROTATION_180: - default: - if (w) *w = output->current_mode->width; - if (h) *h = output->current_mode->height; - break; - } - - if (refresh) *refresh = output->current_mode->refresh; - if (x) *x = output->x; - if (y) *y = output->y; -} - -EAPI Eina_Bool -ecore_drm2_output_pending_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - - if (output->pending.fb) return EINA_TRUE; - - return EINA_FALSE; -} - -EAPI void -ecore_drm2_output_relative_mode_set(Ecore_Drm2_Output *output, Ecore_Drm2_Relative_Mode mode) -{ - EINA_SAFETY_ON_NULL_RETURN(output); - output->relative.mode = mode; -} - -EAPI Ecore_Drm2_Relative_Mode -ecore_drm2_output_relative_mode_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, ECORE_DRM2_RELATIVE_MODE_UNKNOWN); - return output->relative.mode; -} - -EAPI void -ecore_drm2_output_relative_to_set(Ecore_Drm2_Output *output, const char *relative) -{ - EINA_SAFETY_ON_NULL_RETURN(output); - eina_stringshare_replace(&output->relative.to, relative); -} - -EAPI const char * -ecore_drm2_output_relative_to_get(Ecore_Drm2_Output *output) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL); - return output->relative.to; -} - -EAPI Eina_Bool -ecore_drm2_output_background_color_set(Ecore_Drm2_Output *output, uint64_t r, uint64_t g, uint64_t b, uint64_t a) -{ - Ecore_Drm2_Crtc_State *cstate; - - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(output->crtc_state, EINA_FALSE); - - cstate = output->crtc_state; - if (cstate->background.id) - { - cstate->background.value = (a << 48 | b << 32 | g << 16 | r); - return _fb_atomic_flip_test(output); - } - - return EINA_FALSE; -} diff --git a/src/lib/ecore_drm2/ecore_drm2_plane.c b/src/lib/ecore_drm2/ecore_drm2_plane.c deleted file mode 100644 index 6dfa0bcb85..0000000000 --- a/src/lib/ecore_drm2/ecore_drm2_plane.c +++ /dev/null @@ -1,203 +0,0 @@ -#include "ecore_drm2_private.h" - -static Eina_Bool -_plane_format_supported(Ecore_Drm2_Plane_State *pstate, uint32_t format) -{ - Eina_Bool ret = EINA_FALSE; - unsigned int i = 0; - - for (; i < pstate->num_formats; i++) - { - if (pstate->formats[i] == format) - { - ret = EINA_TRUE; - break; - } - } - - return ret; -} - -static void -_plane_cursor_size_get(int fd, int *width, int *height) -{ - uint64_t caps; - int ret; - - if (width) - { - *width = 64; - ret = sym_drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &caps); - if (ret == 0) *width = caps; - } - if (height) - { - *height = 64; - ret = sym_drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &caps); - if (ret == 0) *height = caps; - } -} - -EAPI Ecore_Drm2_Plane * -ecore_drm2_plane_assign(Ecore_Drm2_Output *output, Ecore_Drm2_Fb *fb, int x, int y) -{ - Eina_List *l; - Ecore_Drm2_Plane *plane; - Ecore_Drm2_Plane_State *pstate; - - if (!_ecore_drm2_use_atomic) return NULL; - - /* use algo based on format, size, etc to find a plane this FB can go in */ - EINA_LIST_FOREACH(output->plane_states, l, pstate) - { - if (pstate->in_use) - continue; - - /* test if this plane supports the given format */ - if (!_plane_format_supported(pstate, fb->format)) - continue; - - if (pstate->type.value == DRM_PLANE_TYPE_CURSOR) - { - int cw, ch; - - _plane_cursor_size_get(output->fd, &cw, &ch); - - /* check that this fb can fit in cursor plane */ - if ((fb->w != cw) || (fb->h != ch)) - continue; - - /* if we reach here, this FB can go on the cursor plane */ - goto out; - } - else if (pstate->type.value == DRM_PLANE_TYPE_OVERLAY) - { - /* there are no size checks for an overlay plane */ - goto out; - } - else if (pstate->type.value == DRM_PLANE_TYPE_PRIMARY) - { - if ((fb->w > output->current_mode->width) || - (fb->h > output->current_mode->height)) - continue; - - /* if we reach here, this FB can go on the primary plane */ - goto out; - } - } - - return NULL; - -out: - /* create plane */ - plane = calloc(1, sizeof(Ecore_Drm2_Plane)); - if (!plane) return NULL; - - pstate->in_use = EINA_TRUE; - pstate->cid.value = output->crtc_id; - pstate->fid.value = fb->id; - plane->fb = fb; - - pstate->sx.value = 0; - pstate->sy.value = 0; - pstate->sw.value = fb->w << 16; - pstate->sh.value = fb->h << 16; - - pstate->cx.value = x; - pstate->cy.value = y; - pstate->cw.value = fb->w; - pstate->ch.value = fb->h; - - plane->state = pstate; - plane->type = pstate->type.value; - plane->output = output; - - output->planes = eina_list_append(output->planes, plane); - - if (!_fb_atomic_flip_test(output)) - { - output->planes = eina_list_remove(output->planes, plane); - plane->state->in_use = EINA_FALSE; - free(plane); - - return NULL; - } - - _ecore_drm2_fb_ref(fb); - DBG("FB %d assigned to Plane %d", fb->id, pstate->obj_id); - - if (fb->status_handler) - fb->status_handler(fb, - ECORE_DRM2_FB_STATUS_PLANE_ASSIGN, - fb->status_data); - return plane; -} - -EAPI void -ecore_drm2_plane_release(Ecore_Drm2_Plane *plane) -{ - Ecore_Drm2_Fb *fb; - - EINA_SAFETY_ON_NULL_RETURN(plane); - EINA_SAFETY_ON_TRUE_RETURN(plane->dead); - - fb = plane->fb; - - plane->output->fbs = - eina_list_append(plane->output->fbs, fb); - - plane->dead = EINA_TRUE; - plane->state->in_use = EINA_FALSE; - _fb_atomic_flip_test(plane->output); - - if (fb->status_handler) - fb->status_handler(fb, - ECORE_DRM2_FB_STATUS_PLANE_RELEASE, - fb->status_data); -} - -EAPI void -ecore_drm2_plane_destination_set(Ecore_Drm2_Plane *plane, int x, int y, int w, int h) -{ - EINA_SAFETY_ON_NULL_RETURN(plane); - EINA_SAFETY_ON_TRUE_RETURN(plane->dead); - - plane->state->cx.value = x; - plane->state->cy.value = y; - plane->state->cw.value = w; - plane->state->ch.value = h; - - _fb_atomic_flip_test(plane->output); -} - -EAPI Eina_Bool -ecore_drm2_plane_fb_set(Ecore_Drm2_Plane *plane, Ecore_Drm2_Fb *fb) -{ - uint32_t fallback_id; - - EINA_SAFETY_ON_NULL_RETURN_VAL(plane, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE); - EINA_SAFETY_ON_TRUE_RETURN_VAL(plane->dead, EINA_FALSE); - - fallback_id = plane->state->fid.value; - plane->state->fid.value = fb->id; - - /* Update plane state based on fb */ - plane->state->sw.value = fb->w << 16; - plane->state->sh.value = fb->h << 16; - plane->state->cw.value = fb->w; - plane->state->ch.value = fb->h; - - if (_fb_atomic_flip_test(plane->output)) - { - _ecore_drm2_fb_ref(fb); - - plane->output->fbs = - eina_list_append(plane->output->fbs, plane->fb); - - plane->fb = fb; - return EINA_TRUE; - } - plane->state->fid.value = fallback_id; - return EINA_FALSE; -} diff --git a/src/lib/ecore_drm2/ecore_drm2_private.h b/src/lib/ecore_drm2/ecore_drm2_private.h index 56c9fe8a99..271bb1ff99 100644 --- a/src/lib/ecore_drm2/ecore_drm2_private.h +++ b/src/lib/ecore_drm2/ecore_drm2_private.h @@ -5,30 +5,31 @@ # include "config.h" # endif -# include "Ecore.h" -# include "ecore_private.h" -# include "Eeze.h" -# include "Elput.h" -# include - +/* include system headers */ # include # include # include # include # include - # include # include +/* include drm headers */ # include # include # include # include # include -#ifndef DRM2_NODEFS +/* include needed EFL headers */ +# include "Ecore.h" +# include "ecore_private.h" +# include "Eeze.h" +# include "Elput.h" +# include + +/* define necessary vars/macros for ecore_drm2 log domain */ extern int _ecore_drm2_log_dom; -extern Eina_Bool _ecore_drm2_use_atomic; # ifdef ECORE_DRM2_DEFAULT_LOG_COLOR # undef ECORE_DRM2_DEFAULT_LOG_COLOR @@ -59,298 +60,5 @@ extern Eina_Bool _ecore_drm2_use_atomic; # undef CRIT # endif # define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_drm2_log_dom, __VA_ARGS__) -#endif - -typedef struct _Ecore_Drm2_Atomic_State Ecore_Drm2_Atomic_State; - -typedef struct _Ecore_Drm2_Atomic_Blob -{ - uint32_t id, value; - size_t len; - void *data; -} Ecore_Drm2_Atomic_Blob; - -typedef struct _Ecore_Drm2_Atomic_Property -{ - uint32_t id; - uint64_t value; -} Ecore_Drm2_Atomic_Property; - -typedef struct _Ecore_Drm2_Connector_State -{ - uint32_t obj_id; - Ecore_Drm2_Atomic_Property crtc; - Ecore_Drm2_Atomic_Property dpms; - Ecore_Drm2_Atomic_Property aspect; - Ecore_Drm2_Atomic_Property scaling; - Ecore_Drm2_Atomic_Blob edid; -} Ecore_Drm2_Connector_State; - -typedef struct _Ecore_Drm2_Crtc_State -{ - uint32_t obj_id; - int index; - Ecore_Drm2_Atomic_Property active; - Ecore_Drm2_Atomic_Property background; - Ecore_Drm2_Atomic_Blob mode; -} Ecore_Drm2_Crtc_State; - -typedef struct _Ecore_Drm2_Plane_State -{ - uint32_t obj_id, mask; - Ecore_Drm2_Atomic_Property type; - Ecore_Drm2_Atomic_Property cid, fid; - Ecore_Drm2_Atomic_Property sx, sy, sw, sh; - Ecore_Drm2_Atomic_Property cx, cy, cw, ch; - Ecore_Drm2_Atomic_Property rotation; - - /* these are not part of an atomic state, but we store these here - * so that we do not have to refetch properties when iterating planes */ - uint32_t rotation_map[6]; - uint32_t supported_rotations; - - uint32_t num_formats; - uint32_t *formats; - - Eina_Bool in_use; -} Ecore_Drm2_Plane_State; - -struct _Ecore_Drm2_Atomic_State -{ - int crtcs, conns, planes; - Ecore_Drm2_Crtc_State *crtc_states; - Ecore_Drm2_Connector_State *conn_states; - Ecore_Drm2_Plane_State *plane_states; -}; - -# ifndef DRM_CAP_CURSOR_WIDTH -# define DRM_CAP_CURSOR_WIDTH 0x8 -# endif - -# ifndef DRM_CAP_CURSOR_HEIGHT -# define DRM_CAP_CURSOR_HEIGHT 0x9 -# endif - -typedef enum _Ecore_Drm2_Backlight_Type -{ - ECORE_DRM2_BACKLIGHT_RAW, - ECORE_DRM2_BACKLIGHT_PLATFORM, - ECORE_DRM2_BACKLIGHT_FIRMWARE -} Ecore_Drm2_Backlight_Type; - -typedef enum _Ecore_Drm2_Transform -{ - ECORE_DRM2_TRANSFORM_NORMAL, - ECORE_DRM2_TRANSFORM_90, - ECORE_DRM2_TRANSFORM_180, - ECORE_DRM2_TRANSFORM_270, - ECORE_DRM2_TRANSFORM_FLIPPED, - ECORE_DRM2_TRANSFORM_FLIPPED_90, - ECORE_DRM2_TRANSFORM_FLIPPED_180, - ECORE_DRM2_TRANSFORM_FLIPPED_270 -} Ecore_Drm2_Transform; - -struct _Ecore_Drm2_Fb -{ - int fd; - int w, h; - int depth, bpp; - short ref; - int scanout_count; - uint32_t id, handles[4]; - uint32_t strides[4], sizes[4]; - uint32_t format; - - void *gbm_bo; - void *mmap; - - Ecore_Drm2_Fb_Status_Handler status_handler; - void *status_data; - - Eina_Bool gbm : 1; - Eina_Bool dmabuf : 1; - Eina_Bool dead : 1; -}; - -struct _Ecore_Drm2_Plane -{ - int type; - Ecore_Drm2_Plane_State *state; - Ecore_Drm2_Output *output; - Ecore_Drm2_Fb *fb; - Eina_Bool dead; - Eina_Bool scanout; -}; - -struct _Ecore_Drm2_Output_Mode -{ - uint32_t id; - uint32_t flags; - int32_t width, height; - uint32_t refresh; - drmModeModeInfo info; -}; - -/* A half step - we still keep an fb for the canvas - * and an atomic_req for all atomic state (including - * the canvas fb). - * The non atomic code only uses the canvas fb. - */ -typedef struct _Ecore_Drm2_Output_State -{ - Ecore_Drm2_Fb *fb; - drmModeAtomicReq *atomic_req; -} Ecore_Drm2_Output_State; - -struct _Ecore_Drm2_Output -{ - Eina_Stringshare *name; - Eina_Stringshare *make, *model, *serial; - - int fd; - int pipe; - int x, y, w, h, pw, ph; - int rotation; - - long fallback_sec, fallback_usec; - - uint32_t subpixel; - uint32_t crtc_id, conn_id, conn_type; - uint32_t scale; - uint16_t gamma; - - struct - { - char eisa[13]; - char monitor[13]; - char pnp[5]; - char serial[13]; - unsigned char *blob; // unused when doing atomic - } edid; - - struct - { - const char *path; - double value, max; - Ecore_Drm2_Backlight_Type type; - } backlight; - - struct - { - const char *to; - Ecore_Drm2_Relative_Mode mode; - } relative; - - drmModeCrtcPtr ocrtc; - - /* prep is for state we're preparing and have never - * attempted to commit */ - Ecore_Drm2_Output_State prep; - - Ecore_Drm2_Output_State current, next, pending; - - Eina_Matrix4 matrix, inverse; - Ecore_Drm2_Transform transform; - - /* unused when doing atomic */ - drmModePropertyPtr dpms; - - Ecore_Timer *flip_timeout; - - Ecore_Drm2_Output_Mode *current_mode; - Eina_List *modes; - - void *user_data; - - Ecore_Drm2_Crtc_State *crtc_state; - Ecore_Drm2_Connector_State *conn_state; - - Eina_List *plane_states; - Eina_List *planes; - Eina_List *fbs; - - Eina_Bool connected : 1; - Eina_Bool primary : 1; - Eina_Bool cloned : 1; - Eina_Bool enabled : 1; -}; - -struct _Ecore_Drm2_Device -{ - Elput_Manager *em; - - int fd; - const char *path; - - int num_crtcs; - uint32_t *crtcs; - - struct - { - uint32_t width, height; - } min, max; - - struct - { - int width, height; - } cursor; - - Eeze_Udev_Watch *watch; - Ecore_Event_Handler *active_hdlr; - Ecore_Event_Handler *device_change_hdlr; - - Ecore_Drm2_Atomic_State *state; - - Eina_List *outputs; -}; - -Eina_Bool _fb_atomic_flip_test(Ecore_Drm2_Output *output); -void _ecore_drm2_fb_ref(Ecore_Drm2_Fb *); -void _ecore_drm2_fb_deref(Ecore_Drm2_Fb *); -void _ecore_drm2_fb_buffer_release(Ecore_Drm2_Output *output, Ecore_Drm2_Output_State *s); - -/* extern int (*sym_drmClose)(int fd); */ -extern int (*sym_drmWaitVBlank)(int fd, drmVBlank *vbl); -extern int (*sym_drmHandleEvent)(int fd, drmEventContext *evctx); -extern void *(*sym_drmGetVersion)(int fd); -extern void (*sym_drmFreeVersion)(void *drmver); -extern void *(*sym_drmModeGetProperty)(int fd, uint32_t propertyId); -extern void (*sym_drmModeFreeProperty)(drmModePropertyPtr ptr); -extern void *(*sym_drmModeGetPropertyBlob)(int fd, uint32_t blob_id); -extern void (*sym_drmModeFreePropertyBlob)(drmModePropertyBlobPtr ptr); -extern int (*sym_drmModeDestroyPropertyBlob)(int fd, uint32_t id); -extern int (*sym_drmIoctl)(int fd, unsigned long request, void *arg); -extern void *(*sym_drmModeObjectGetProperties)(int fd, uint32_t object_id, uint32_t object_type); -extern void (*sym_drmModeFreeObjectProperties)(drmModeObjectPropertiesPtr ptr); -extern int (*sym_drmModeCreatePropertyBlob)(int fd, const void *data, size_t size, uint32_t *id); -extern void *(*sym_drmModeAtomicAlloc)(void); -extern void (*sym_drmModeAtomicFree)(drmModeAtomicReqPtr req); -extern int (*sym_drmModeAtomicAddProperty)(drmModeAtomicReqPtr req, uint32_t object_id, uint32_t property_id, uint64_t value); -extern int (*sym_drmModeAtomicCommit)(int fd, drmModeAtomicReqPtr req, uint32_t flags, void *user_data); -extern void (*sym_drmModeAtomicSetCursor)(drmModeAtomicReqPtr req, int cursor); -extern int (*sym_drmModeAtomicMerge)(drmModeAtomicReqPtr base, drmModeAtomicReqPtr augment); -extern void *(*sym_drmModeGetEncoder)(int fd, uint32_t encoder_id); -extern void (*sym_drmModeFreeEncoder)(drmModeEncoderPtr ptr); -extern void *(*sym_drmModeGetCrtc)(int fd, uint32_t crtcId); -extern void (*sym_drmModeFreeCrtc)(drmModeCrtcPtr ptr); -extern int (*sym_drmModeSetCrtc)(int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t *connectors, int count, drmModeModeInfoPtr mode); -extern void *(*sym_drmModeGetResources)(int fd); -extern void (*sym_drmModeFreeResources)(drmModeResPtr ptr); -extern void *(*sym_drmModeGetConnector)(int fd, uint32_t connectorId); -extern void (*sym_drmModeFreeConnector)(drmModeConnectorPtr ptr); -extern int (*sym_drmModeConnectorSetProperty)(int fd, uint32_t connector_id, uint32_t property_id, uint64_t value); -extern int (*sym_drmGetCap)(int fd, uint64_t capability, uint64_t *value); -extern int (*sym_drmSetClientCap)(int fd, uint64_t capability, uint64_t value); -extern void *(*sym_drmModeGetPlaneResources)(int fd); -extern void (*sym_drmModeFreePlaneResources)(drmModePlaneResPtr ptr); -extern void *(*sym_drmModeGetPlane)(int fd, uint32_t plane_id); -extern void (*sym_drmModeFreePlane)(drmModePlanePtr ptr); -extern int (*sym_drmModeAddFB)(int fd, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, uint32_t pitch, uint32_t bo_handle, uint32_t *buf_id); -extern int (*sym_drmModeAddFB2)(int fd, uint32_t width, uint32_t height, uint32_t pixel_format, uint32_t bo_handles[4], uint32_t pitches[4], uint32_t offsets[4], uint32_t *buf_id, uint32_t flags); -extern int (*sym_drmModeRmFB)(int fd, uint32_t bufferId); -extern int (*sym_drmModePageFlip)(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data); -extern int (*sym_drmModeDirtyFB)(int fd, uint32_t bufferId, drmModeClipPtr clips, uint32_t num_clips); -extern int (*sym_drmModeCrtcSetGamma)(int fd, uint32_t crtc_id, uint32_t size, uint16_t *red, uint16_t *green, uint16_t *blue); -extern int (*sym_drmPrimeFDToHandle)(int fd, int prime_fd, uint32_t *handle); #endif diff --git a/src/lib/ecore_drm2/meson.build b/src/lib/ecore_drm2/meson.build index 212dd366c7..4eb9dfe912 100644 --- a/src/lib/ecore_drm2/meson.build +++ b/src/lib/ecore_drm2/meson.build @@ -7,10 +7,6 @@ ecore_drm2_header_src = [ ] ecore_drm2_src = files([ - 'ecore_drm2_plane.c', - 'ecore_drm2_fb.c', - 'ecore_drm2_outputs.c', - 'ecore_drm2_device.c', 'ecore_drm2.c', 'ecore_drm2_private.h' ])