Clean up resources when plane is reassigned
This commit is contained in:
parent
2f8b5c4448
commit
aedfa27d3a
|
@ -173,6 +173,56 @@ void wlr_drm_renderer_free(struct wlr_drm_renderer *renderer) {
|
|||
gbm_device_destroy(renderer->gbm);
|
||||
}
|
||||
|
||||
static bool wlr_drm_plane_renderer_init(struct wlr_drm_renderer *renderer,
|
||||
struct wlr_drm_plane *plane, uint32_t width, uint32_t height) {
|
||||
if (plane->width == width && plane->height == height) {
|
||||
return true;
|
||||
}
|
||||
|
||||
plane->width = width;
|
||||
plane->height = height;
|
||||
|
||||
plane->gbm = gbm_surface_create(renderer->gbm, width, height,
|
||||
GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
|
||||
if (!plane->gbm) {
|
||||
wlr_log_errno(L_ERROR, "Failed to create GBM surface for plane");
|
||||
return false;
|
||||
}
|
||||
|
||||
plane->egl = wlr_egl_create_surface(&renderer->egl, plane->gbm);
|
||||
if (plane->egl == EGL_NO_SURFACE) {
|
||||
wlr_log(L_ERROR, "Failed to create EGL surface for plane");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void wlr_drm_plane_renderer_free(struct wlr_drm_renderer *renderer,
|
||||
struct wlr_drm_plane *plane) {
|
||||
if (!renderer || !plane)
|
||||
return;
|
||||
|
||||
wlr_log(L_DEBUG, "%s called", __func__);
|
||||
|
||||
if (plane->front)
|
||||
gbm_surface_release_buffer(plane->gbm, plane->front);
|
||||
if (plane->back)
|
||||
gbm_surface_release_buffer(plane->gbm, plane->back);
|
||||
|
||||
if (plane->egl)
|
||||
eglDestroySurface(renderer->egl.display, plane->egl);
|
||||
if (plane->gbm)
|
||||
gbm_surface_destroy(plane->gbm);
|
||||
|
||||
plane->width = 0;
|
||||
plane->height = 0;
|
||||
plane->egl = EGL_NO_SURFACE;
|
||||
plane->gbm = NULL;
|
||||
plane->front = NULL;
|
||||
plane->back = NULL;
|
||||
}
|
||||
|
||||
static void free_fb(struct gbm_bo *bo, void *data) {
|
||||
uint32_t id = (uintptr_t)data;
|
||||
|
||||
|
@ -258,40 +308,6 @@ void wlr_drm_output_start_renderer(struct wlr_output_state *output) {
|
|||
output->pageflip_pending = true;
|
||||
}
|
||||
|
||||
static bool plane_init_renderer(struct wlr_drm_renderer *renderer,
|
||||
struct wlr_drm_plane *plane, struct wlr_output_mode *mode) {
|
||||
plane->width = mode->width;
|
||||
plane->height = mode->height;
|
||||
|
||||
plane->gbm = gbm_surface_create(renderer->gbm, mode->width,
|
||||
mode->height, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
|
||||
if (!plane->gbm) {
|
||||
wlr_log_errno(L_ERROR, "Failed to create GBM surface for plane");
|
||||
return false;
|
||||
}
|
||||
|
||||
plane->egl = wlr_egl_create_surface(&renderer->egl, plane->gbm);
|
||||
if (plane->egl == EGL_NO_SURFACE) {
|
||||
wlr_log(L_ERROR, "Failed to create EGL surface for plane");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int find_id(const void *item, const void *cmp_to) {
|
||||
const struct wlr_output_state *output = item;
|
||||
const uint32_t *id = cmp_to;
|
||||
|
||||
if (output->connector < *id) {
|
||||
return -1;
|
||||
} else if (output->connector > *id) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void wlr_drm_output_enable(struct wlr_output_state *output, bool enable) {
|
||||
struct wlr_backend_state *state =
|
||||
wl_container_of(output->renderer, state, renderer);
|
||||
|
@ -303,11 +319,7 @@ static void wlr_drm_output_enable(struct wlr_output_state *output, bool enable)
|
|||
drmModeConnectorSetProperty(state->fd, output->connector, output->props.dpms,
|
||||
DRM_MODE_DPMS_ON);
|
||||
|
||||
// Start rendering loop again by drawing a black frame
|
||||
wlr_drm_output_make_current(output);
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
wlr_drm_output_swap_buffers(output);
|
||||
wlr_drm_output_start_renderer(output);
|
||||
} else {
|
||||
drmModeConnectorSetProperty(state->fd, output->connector, output->props.dpms,
|
||||
DRM_MODE_DPMS_OFF);
|
||||
|
@ -343,13 +355,19 @@ static void realloc_planes(struct wlr_backend_state *drm, const uint32_t *crtc_i
|
|||
continue;
|
||||
|
||||
struct wlr_drm_crtc *c = &drm->crtcs[i];
|
||||
c->planes[type] = &drm->type_planes[type][crtc_res[i]];
|
||||
struct wlr_drm_plane **old = &c->planes[type];
|
||||
struct wlr_drm_plane *new = &drm->type_planes[type][crtc_res[i]];
|
||||
|
||||
if (*old != new) {
|
||||
wlr_drm_plane_renderer_free(&drm->renderer, *old);
|
||||
wlr_drm_plane_renderer_free(&drm->renderer, new);
|
||||
*old = new;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void realloc_crtcs(struct wlr_backend_state *drm, struct wlr_output_state *output) {
|
||||
bool handled[drm->outputs->length];
|
||||
uint32_t crtc[drm->num_crtcs];
|
||||
uint32_t crtc_res[drm->num_crtcs];
|
||||
uint32_t possible_crtc[drm->outputs->length];
|
||||
|
@ -359,18 +377,15 @@ static void realloc_crtcs(struct wlr_backend_state *drm, struct wlr_output_state
|
|||
}
|
||||
|
||||
memset(possible_crtc, 0, sizeof(possible_crtc));
|
||||
memset(handled, 0, sizeof(handled));
|
||||
|
||||
size_t index;
|
||||
for (size_t i = 0; i < drm->outputs->length; ++i) {
|
||||
struct wlr_output_state *o = drm->outputs->items[i];
|
||||
if (o == output) {
|
||||
if (o == output)
|
||||
index = i;
|
||||
}
|
||||
|
||||
if (o->state != WLR_DRM_OUTPUT_CONNECTED) {
|
||||
if (o->state != WLR_DRM_OUTPUT_CONNECTED)
|
||||
continue;
|
||||
}
|
||||
|
||||
possible_crtc[i] = o->possible_crtc;
|
||||
crtc[o->crtc - drm->crtcs] = i;
|
||||
|
@ -379,14 +394,22 @@ static void realloc_crtcs(struct wlr_backend_state *drm, struct wlr_output_state
|
|||
possible_crtc[index] = output->possible_crtc;
|
||||
match_obj(drm->outputs->length, possible_crtc, drm->num_crtcs, crtc, crtc_res);
|
||||
|
||||
realloc_planes(drm, crtc_res);
|
||||
|
||||
bool matched = false;
|
||||
for (size_t i = 0; i < drm->num_crtcs; ++i) {
|
||||
if (crtc_res[i] == UNMATCHED) {
|
||||
continue;
|
||||
// We don't want any of the current monitors to be deactivated.
|
||||
if (crtc[i] != UNMATCHED && crtc_res[i] == UNMATCHED)
|
||||
return;
|
||||
if (crtc_res[i] == index)
|
||||
matched = true;
|
||||
}
|
||||
|
||||
handled[crtc_res[i]] = true;
|
||||
// There is no point doing anything if this monitor doesn't get activated
|
||||
if (!matched)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < drm->num_crtcs; ++i) {
|
||||
if (crtc_res[i] == UNMATCHED)
|
||||
continue;
|
||||
|
||||
if (crtc_res[i] != crtc[i]) {
|
||||
struct wlr_output_state *o = drm->outputs->items[crtc_res[i]];
|
||||
|
@ -394,11 +417,7 @@ static void realloc_crtcs(struct wlr_backend_state *drm, struct wlr_output_state
|
|||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < drm->outputs->length; ++i) {
|
||||
if (!handled[i]) {
|
||||
wlr_drm_output_cleanup(drm->outputs->items[i], false);
|
||||
}
|
||||
}
|
||||
realloc_planes(drm, crtc_res);
|
||||
}
|
||||
|
||||
static bool wlr_drm_output_set_mode(struct wlr_output_state *output,
|
||||
|
@ -450,12 +469,24 @@ static bool wlr_drm_output_set_mode(struct wlr_output_state *output,
|
|||
output->base->current_mode = mode;
|
||||
wl_signal_emit(&output->base->events.resolution, output->base);
|
||||
|
||||
if (!plane_init_renderer(&drm->renderer, output->crtc->primary, mode)) {
|
||||
// Since realloc_crtcs can deallocate planes on OTHER outputs,
|
||||
// we actually need to reinitalise all of them
|
||||
for (size_t i = 0; i < drm->outputs->length; ++i) {
|
||||
struct wlr_output_state *output = drm->outputs->items[i];
|
||||
struct wlr_output_mode *mode = output->base->current_mode;
|
||||
struct wlr_drm_crtc *crtc = output->crtc;
|
||||
|
||||
if (output->state != WLR_DRM_OUTPUT_CONNECTED)
|
||||
continue;
|
||||
|
||||
if (!wlr_drm_plane_renderer_init(&drm->renderer, crtc->primary,
|
||||
mode->width, mode->height)) {
|
||||
wlr_log(L_ERROR, "Failed to initalise renderer for plane");
|
||||
goto error_enc;
|
||||
}
|
||||
|
||||
wlr_drm_output_start_renderer(output);
|
||||
}
|
||||
|
||||
drmModeFreeEncoder(enc);
|
||||
drmModeFreeConnector(conn);
|
||||
|
@ -566,6 +597,19 @@ static struct wlr_output_impl output_impl = {
|
|||
.swap_buffers = wlr_drm_output_swap_buffers,
|
||||
};
|
||||
|
||||
static int find_id(const void *item, const void *cmp_to) {
|
||||
const struct wlr_output_state *output = item;
|
||||
const uint32_t *id = cmp_to;
|
||||
|
||||
if (output->connector < *id) {
|
||||
return -1;
|
||||
} else if (output->connector > *id) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const int32_t subpixel_map[] = {
|
||||
[DRM_MODE_SUBPIXEL_UNKNOWN] = WL_OUTPUT_SUBPIXEL_UNKNOWN,
|
||||
[DRM_MODE_SUBPIXEL_HORIZONTAL_RGB] = WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB,
|
||||
|
@ -742,6 +786,10 @@ void wlr_drm_output_cleanup(struct wlr_output_state *output, bool restore) {
|
|||
restore = false;
|
||||
}
|
||||
|
||||
wlr_drm_plane_renderer_free(renderer, output->crtc->overlay);
|
||||
wlr_drm_plane_renderer_free(renderer, output->crtc->primary);
|
||||
wlr_drm_plane_renderer_free(renderer, output->crtc->cursor);
|
||||
|
||||
output->crtc = NULL;
|
||||
output->possible_crtc = 0;
|
||||
/* Fallthrough */
|
||||
|
|
|
@ -148,7 +148,6 @@ struct wlr_output_state {
|
|||
uint32_t cursor_width, cursor_height;
|
||||
|
||||
bool pageflip_pending;
|
||||
bool cleanup;
|
||||
};
|
||||
|
||||
bool wlr_drm_check_features(struct wlr_backend_state *drm);
|
||||
|
|
|
@ -206,7 +206,7 @@ bool wlr_output_set_cursor(struct wlr_output *output,
|
|||
output->cursor.texture = wlr_render_surface_init(output->cursor.renderer);
|
||||
}
|
||||
|
||||
wlr_surface_attach_pixels(output->cursor.texture, WL_SHM_FORMAT_ABGR8888,
|
||||
wlr_surface_attach_pixels(output->cursor.texture, WL_SHM_FORMAT_ARGB8888,
|
||||
stride, width, height, buf);
|
||||
|
||||
return true;
|
||||
|
|
Loading…
Reference in New Issue