-
-
Notifications
You must be signed in to change notification settings - Fork 188
[WIP] Implement DPMS get/setValue (Screen Off/On for KMS) #478
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
|
I used this example https://github.com/tomba/kmsxx/blob/master/utils/kmsblank.cpp#L77 |
|
Thanks for the contribution @DisDis ! I think providing support for DPMS & backlight is definitely useful, but a generic way to set KMS properties might be a bit too powerful. It's very easy to shoot yourself in the foot with that and it can easily conflict with flutter-pi's modesetting. Might be better to provide an abstraction specifically for DPMS (and/or backlight). Just a package where you can do something like: void main() async {
final dpms = await DPMS.getInstance(); // optionally allow passing the view id here, for multi-view
await dpms.setMode(PowerMode.on);
await Future.delayed(Duration(seconds: 5));
await dpms.setMode(PowerMode.standby);
// ...
}For backlight, one could implement a platform interface for: https://github.com/aaassseee/screen_brightness/ Weston has its own little sub-library to help with backlight: https://gitlab.freedesktop.org/wayland/weston/-/blob/main/libweston/backend-drm/libbacklight.c, that could just be added to the flutter-pi source tree under |
src/modesetting.c
Outdated
|
|
||
| #define DPMS_PROPERTY_NAME "DPMS" | ||
| #define DPMS_ERROR_PROPERTY_ID 0 | ||
| // FIXME: Is 0 error value? |
Check notice
Code scanning / CodeQL
FIXME comment
|
Hi @ardera. |
|
I have to apologize @DisDis , I just realized I reviewed this, but never submitted the review |
ardera
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some comments, and can you rebase on top of dev?
and move the logic into kms_req_builder and kms_window (window.c), maybe compositor
src/modesetting.c
Outdated
| uint32_t kms_drm_getDPMSPropertyId(struct drmdev *drmdev, uint32_t connector_id){ | ||
| ASSERT_NOT_NULL(drmdev); | ||
| ASSERT_NOT_NULL(drmdev->fd); | ||
| drmModeObjectProperties *props = drmModeObjectGetProperties(drmdev->fd, connector_id, DRM_MODE_OBJECT_CONNECTOR); | ||
| if (props == NULL){ | ||
| int ok = errno; | ||
| LOG_ERROR("Could not get connector properties. drmModeObjectGetProperties: %s\n", strerror(ok)); | ||
| return DPMS_ERROR_PROPERTY_ID; | ||
| } | ||
|
|
||
| uint32_t result_prop_id = DPMS_ERROR_PROPERTY_ID; | ||
| for (unsigned i = 0; i < props->count_props; ++i) { | ||
| uint32_t prop_id = props->props[i]; | ||
| drmModePropertyRes *drm_prop = drmModeGetProperty(drmdev->fd, prop_id); | ||
| if (drm_prop != NULL) { | ||
| if (streq(drm_prop->name, DPMS_PROPERTY_NAME)){ | ||
| result_prop_id = prop_id; | ||
| } | ||
| } | ||
| drmModeFreeProperty(drm_prop); | ||
| } | ||
|
|
||
| drmModeFreeObjectProperties(props); | ||
| return result_prop_id; | ||
| } | ||
|
|
||
| uint32_t kms_drm_getDPMSPropertyValue(struct drmdev *drmdev, uint32_t connector_id){ | ||
| ASSERT_NOT_NULL(drmdev); | ||
| ASSERT_NOT_NULL(drmdev->fd); | ||
| drmModeObjectProperties *props = drmModeObjectGetProperties(drmdev->fd, connector_id, DRM_MODE_OBJECT_CONNECTOR); | ||
| if (props == NULL){ | ||
| int ok = errno; | ||
| LOG_ERROR("Could not get connector properties. drmModeObjectGetProperties: %s\n", strerror(ok)); | ||
| return DPMS_ERROR_PROPERTY_ID; | ||
| } | ||
|
|
||
| uint32_t result_prop_value = DPMS_ERROR_PROPERTY_VALUE; | ||
| for (unsigned i = 0; i < props->count_props; ++i) { | ||
| uint32_t prop_id = props->props[i]; | ||
| drmModePropertyRes *drm_prop = drmModeGetProperty(drmdev->fd, prop_id); | ||
| if (drm_prop != NULL) { | ||
| if (streq(drm_prop->name, DPMS_PROPERTY_NAME)){ | ||
| result_prop_value = props->prop_values[i]; | ||
| } | ||
| } | ||
| drmModeFreeProperty(drm_prop); | ||
| } | ||
|
|
||
| drmModeFreeObjectProperties(props); | ||
| return result_prop_value; | ||
| } | ||
|
|
||
|
|
||
| uint64_t kms_dpms_getValue(struct drmdev *drmdev){ | ||
| ASSERT_NOT_NULL(drmdev); | ||
|
|
||
| struct drm_connector *connectors = drmdev->connectors; | ||
| size_t n_connectors = drmdev->n_connectors; | ||
| uint64_t result = DPMS_ERROR_PROPERTY_VALUE; | ||
|
|
||
| for (int i = 0; i < n_connectors; i++) { | ||
| if ( | ||
| connectors->variable_state.connection_state == kConnected_DrmConnectionState || | ||
| connectors->variable_state.connection_state == kUnknown_DrmConnectionState ){ | ||
| uint32_t property_id = kms_drm_getDPMSPropertyId(drmdev, connectors->id); | ||
| if (property_id != DPMS_ERROR_PROPERTY_ID){ | ||
| // Return only first value | ||
| result = kms_drm_getDPMSPropertyValue(drmdev, connectors->id); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
|
|
||
| void kms_dpms_setValue(struct drmdev *drmdev, uint64_t value){ | ||
| ASSERT_NOT_NULL(drmdev); | ||
|
|
||
| struct drm_connector *connectors = drmdev->connectors; | ||
| size_t n_connectors = drmdev->n_connectors; | ||
|
|
||
| for (int i = 0; i < n_connectors; i++) { | ||
| if ( | ||
| connectors->variable_state.connection_state == kConnected_DrmConnectionState || | ||
| connectors->variable_state.connection_state == kUnknown_DrmConnectionState ){ | ||
| uint32_t property_id = kms_drm_getDPMSPropertyId(drmdev, connectors->id); | ||
| if (property_id != DPMS_ERROR_PROPERTY_ID){ | ||
| drmModeObjectSetProperty(drmdev->fd, connectors->id, DRM_MODE_OBJECT_CONNECTOR, property_id, value); | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mhh, this basically circumvents all the modesetting code that's already there in modesetting.c.
What you could do is create a new constructor for kms_req_builder that just turns a display off:
int kms_req_builder_new_dpms_off(struct drmdev *drmdev, uint32_t crtc_id) {
/* ... */
}And make all other kms reqs implicity turn DPMS on. (Because there's no reason to build a frame if the display is off)
And then the DPMS logic goes in the window.c, maybe compositor.c
src/modesetting.c
Outdated
| #define DPMS_PROPERTY_NAME "DPMS" | ||
| #define DPMS_ERROR_PROPERTY_ID 0 | ||
| // FIXME: Is 0 error value? | ||
| #define DPMS_ERROR_PROPERTY_VALUE 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already being parsed by the modesetting code, e.g. the DPMS string definition is at:
Line 42 in 6365c91
| V("DPMS", dpms) \ |
The property id of the DPMS property for some given connector is contained in the struct drm_connector, e.g.:
uint32_t get_dpms_property_id(struct drmdev *drmdev, int connector_index) {
return drmdev->connectors[connector_index].ids.dpms;
}
src/modesetting.c
Outdated
| connectors->variable_state.connection_state == kUnknown_DrmConnectionState ){ | ||
| uint32_t property_id = kms_drm_getDPMSPropertyId(drmdev, connectors->id); | ||
| if (property_id != DPMS_ERROR_PROPERTY_ID){ | ||
| drmModeObjectSetProperty(drmdev->fd, connectors->id, DRM_MODE_OBJECT_CONNECTOR, property_id, value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unfortunately that API is a bit "deceitful", it'll actually blockingly commit a frame, so it can wait up to 16ms
I'll try to do it. |
If a device doesn't support rotation, there's really nothing we can do. So just try to apply rotation, but don't fail if it doesn't work. adds enforce_rotation property to struct kms_fb_layer, and makes egl_gbm_render_surface, vk_gbm_render_surface, dmabuf_surface specify false.
Thank you. 👍 I'm also here to assist if there's any problems |
|
@ardera |
|
so the thing that communicates with the dart side I would put in the plugins dir, something like this maybe: // 0 => off, 1 => on, negative value => errno-style error
int flutterpi_dpms_get() {
if (value == NULL) return -EINVAL;
return compositor_get_dpms(flutterpi->compositor);
}
// 0 => success, non-zero value => errno-style error
int flutterpi_dpms_set(bool value) {
return compositor_set_dpms(flutterpi->compositor, value);
}
void dpms_plugin_init(/*...*/) {
// ...
} |
f8f45d5 to
621138d
Compare
I'm not get. |
Roughly like this: add a field in struct kms_req_builder {
// ...
bool set_dpms_off;
}create a new method in drmModeAtomicAddProperty(
/* ... */
builder->connector->ids.dpms,
builder->is_dpms_off ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON
);then, in static int kms_window_set_dpms(struct window *window, bool dpms) {
if (!dpms) {
window->active = false;
struct kms_req_builder *b = drmdev_create_request_builder_dpms_off( /*...*/ );
struct kms_req *r = kms_req_builder_build(b);
return kms_req_commit_blocking(r, NULL);
} else {
window->active = true;
// present the last frame
if (window->composition != NULL) {
kms_window_push_composition_locked(window, window->composition);
}
}
}virtual here means it should be called via function pointer, like in and then call all that from |
|
@ardera I updated code. I don't yet understand how we'll enable dpms. I created |
I added kms drm property set function.
The code is dirty, but it works.
Any suggestions for improvement?
It allows turn off/on screen.
For my case I use HDMI-0.
kmsprint -pshow:
Screen ON:
Screen OFF:
Service:
static final KmsDrmService kmsDrmService = KmsDrmService();