backend/drm: implement wlr_backend_impl.{test,commit}

This commit is contained in:
Simon Ser 2024-02-16 15:55:40 +01:00 committed by Kenny Levinsen
parent d41b5efc65
commit 52e01a9c8b
3 changed files with 85 additions and 2 deletions

View File

@ -75,15 +75,29 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
return drm->fd;
}
static uint32_t drm_backend_get_buffer_caps(struct wlr_backend *backend) {
static uint32_t backend_get_buffer_caps(struct wlr_backend *backend) {
return WLR_BUFFER_CAP_DMABUF;
}
static bool backend_test(struct wlr_backend *backend,
const struct wlr_backend_output_state *states, size_t states_len) {
struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
return commit_drm_device(drm, states, states_len, true);
}
static bool backend_commit(struct wlr_backend *backend,
const struct wlr_backend_output_state *states, size_t states_len) {
struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
return commit_drm_device(drm, states, states_len, false);
}
static const struct wlr_backend_impl backend_impl = {
.start = backend_start,
.destroy = backend_destroy,
.get_drm_fd = backend_get_drm_fd,
.get_buffer_caps = drm_backend_get_buffer_caps,
.get_buffer_caps = backend_get_buffer_caps,
.test = backend_test,
.commit = backend_commit,
};
bool wlr_backend_is_drm(struct wlr_backend *b) {

View File

@ -1870,6 +1870,73 @@ void restore_drm_device(struct wlr_drm_backend *drm) {
}
}
bool commit_drm_device(struct wlr_drm_backend *drm,
const struct wlr_backend_output_state *output_states, size_t output_states_len,
bool test_only) {
if (!drm->session->active) {
return false;
}
struct wlr_drm_connector_state *conn_states = calloc(output_states_len, sizeof(conn_states[0]));
if (conn_states == NULL) {
return false;
}
bool ok = false;
bool modeset = false;
size_t conn_states_len = 0;
for (size_t i = 0; i < output_states_len; i++) {
const struct wlr_backend_output_state *output_state = &output_states[i];
struct wlr_output *output = output_state->output;
if (!output->enabled && !output_pending_enabled(output, &output_state->base)) {
// KMS rejects commits which disable already-disabled connectors
// and have the DRM_MODE_PAGE_FLIP_EVENT flag
continue;
}
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
if (output_pending_enabled(output, &output_state->base) && !drm_connector_alloc_crtc(conn)) {
wlr_drm_conn_log(conn, WLR_DEBUG,
"No CRTC available for this connector");
goto out;
}
struct wlr_drm_connector_state *conn_state = &conn_states[conn_states_len];
drm_connector_state_init(conn_state, conn, &output_state->base);
conn_states_len++;
if (!drm_connector_prepare(conn_state, test_only)) {
goto out;
}
if (output_state->base.tearing_page_flip) {
wlr_log(WLR_DEBUG, "Tearing not supported for DRM device-wide commits");
goto out;
}
modeset |= output_state->base.allow_reconfiguration;
}
uint32_t flags = 0;
if (!test_only) {
flags |= DRM_MODE_PAGE_FLIP_EVENT;
}
struct wlr_drm_device_state dev_state = {
.modeset = modeset,
.connectors = conn_states,
.connectors_len = conn_states_len,
};
ok = drm_commit(drm, &dev_state, flags, test_only);
out:
for (size_t i = 0; i < conn_states_len; i++) {
drm_connector_state_finish(&conn_states[i]);
}
free(conn_states);
return ok;
}
static int mhz_to_nsec(int mhz) {
return 1000000000000LL / mhz;
}

View File

@ -206,6 +206,8 @@ void finish_drm_resources(struct wlr_drm_backend *drm);
void scan_drm_connectors(struct wlr_drm_backend *state,
struct wlr_device_hotplug_event *event);
void scan_drm_leases(struct wlr_drm_backend *drm);
bool commit_drm_device(struct wlr_drm_backend *drm,
const struct wlr_backend_output_state *states, size_t states_len, bool test_only);
void restore_drm_device(struct wlr_drm_backend *drm);
int handle_drm_event(int fd, uint32_t mask, void *data);
void destroy_drm_connector(struct wlr_drm_connector *conn);