123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676 |
- /*
- * Mesa 3-D graphics library
- * Version: 7.9
- *
- * Copyright (C) 2010 LunarG Inc.
- * Copyright (C) 2011 VMware Inc. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Chia-I Wu <olv@lunarg.com>
- * Thomas Hellstrom <thellstrom@vmware.com>
- */
-
- #include "util/u_memory.h"
- #include "util/u_inlines.h"
- #include "egllog.h"
-
- #include "native_drm.h"
-
- static boolean
- drm_surface_validate(struct native_surface *nsurf, uint attachment_mask,
- unsigned int *seq_num, struct pipe_resource **textures,
- int *width, int *height)
- {
- struct drm_surface *drmsurf = drm_surface(nsurf);
-
- if (!resource_surface_add_resources(drmsurf->rsurf, attachment_mask))
- return FALSE;
- if (textures)
- resource_surface_get_resources(drmsurf->rsurf, textures, attachment_mask);
-
- if (seq_num)
- *seq_num = drmsurf->sequence_number;
- if (width)
- *width = drmsurf->width;
- if (height)
- *height = drmsurf->height;
-
- return TRUE;
- }
-
- /**
- * Add textures as DRM framebuffers.
- */
- static boolean
- drm_surface_init_framebuffers(struct native_surface *nsurf, boolean need_back)
- {
- struct drm_surface *drmsurf = drm_surface(nsurf);
- struct drm_display *drmdpy = drmsurf->drmdpy;
- int num_framebuffers = (need_back) ? 2 : 1;
- int i, err;
-
- for (i = 0; i < num_framebuffers; i++) {
- struct drm_framebuffer *fb;
- enum native_attachment natt;
- struct winsys_handle whandle;
- uint block_bits;
-
- if (i == 0) {
- fb = &drmsurf->front_fb;
- natt = NATIVE_ATTACHMENT_FRONT_LEFT;
- }
- else {
- fb = &drmsurf->back_fb;
- natt = NATIVE_ATTACHMENT_BACK_LEFT;
- }
-
- if (!fb->texture) {
- /* make sure the texture has been allocated */
- resource_surface_add_resources(drmsurf->rsurf, 1 << natt);
- fb->texture =
- resource_surface_get_single_resource(drmsurf->rsurf, natt);
- if (!fb->texture)
- return FALSE;
- }
-
- /* already initialized */
- if (fb->buffer_id)
- continue;
-
- /* TODO detect the real value */
- fb->is_passive = TRUE;
-
- memset(&whandle, 0, sizeof(whandle));
- whandle.type = DRM_API_HANDLE_TYPE_KMS;
-
- if (!drmdpy->base.screen->resource_get_handle(drmdpy->base.screen,
- fb->texture, &whandle))
- return FALSE;
-
- block_bits = util_format_get_blocksizebits(drmsurf->color_format);
- err = drmModeAddFB(drmdpy->fd, drmsurf->width, drmsurf->height,
- block_bits, block_bits, whandle.stride, whandle.handle,
- &fb->buffer_id);
- if (err) {
- fb->buffer_id = 0;
- return FALSE;
- }
- }
-
- return TRUE;
- }
-
- static boolean
- drm_surface_flush_frontbuffer(struct native_surface *nsurf)
- {
- #ifdef DRM_MODE_FEATURE_DIRTYFB
- struct drm_surface *drmsurf = drm_surface(nsurf);
- struct drm_display *drmdpy = drmsurf->drmdpy;
-
- if (drmsurf->front_fb.is_passive)
- drmModeDirtyFB(drmdpy->fd, drmsurf->front_fb.buffer_id, NULL, 0);
- #endif
-
- return TRUE;
- }
-
- static boolean
- drm_surface_copy_swap(struct native_surface *nsurf)
- {
- struct drm_surface *drmsurf = drm_surface(nsurf);
- struct drm_display *drmdpy = drmsurf->drmdpy;
-
- (void) resource_surface_throttle(drmsurf->rsurf);
- if (!resource_surface_copy_swap(drmsurf->rsurf, &drmdpy->base))
- return FALSE;
-
- (void) resource_surface_flush(drmsurf->rsurf, &drmdpy->base);
- if (!drm_surface_flush_frontbuffer(nsurf))
- return FALSE;
-
- drmsurf->sequence_number++;
-
- return TRUE;
- }
-
- static boolean
- drm_surface_swap_buffers(struct native_surface *nsurf)
- {
- struct drm_surface *drmsurf = drm_surface(nsurf);
- struct drm_crtc *drmcrtc = &drmsurf->current_crtc;
- struct drm_display *drmdpy = drmsurf->drmdpy;
- struct drm_framebuffer tmp_fb;
- int err;
-
- if (!drmsurf->have_pageflip)
- return drm_surface_copy_swap(nsurf);
-
- if (!drmsurf->back_fb.buffer_id) {
- if (!drm_surface_init_framebuffers(&drmsurf->base, TRUE))
- return FALSE;
- }
-
- if (drmsurf->is_shown && drmcrtc->crtc) {
- err = drmModePageFlip(drmdpy->fd, drmcrtc->crtc->crtc_id,
- drmsurf->back_fb.buffer_id, 0, NULL);
- if (err) {
- drmsurf->have_pageflip = FALSE;
- return drm_surface_copy_swap(nsurf);
- }
- }
-
- /* swap the buffers */
- tmp_fb = drmsurf->front_fb;
- drmsurf->front_fb = drmsurf->back_fb;
- drmsurf->back_fb = tmp_fb;
-
- resource_surface_swap_buffers(drmsurf->rsurf,
- NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, FALSE);
- /* the front/back textures are swapped */
- drmsurf->sequence_number++;
- drmdpy->event_handler->invalid_surface(&drmdpy->base,
- &drmsurf->base, drmsurf->sequence_number);
-
- return TRUE;
- }
-
- static boolean
- drm_surface_present(struct native_surface *nsurf,
- enum native_attachment natt,
- boolean preserve,
- uint swap_interval)
- {
- boolean ret;
-
- if (swap_interval)
- return FALSE;
-
- switch (natt) {
- case NATIVE_ATTACHMENT_FRONT_LEFT:
- ret = drm_surface_flush_frontbuffer(nsurf);
- break;
- case NATIVE_ATTACHMENT_BACK_LEFT:
- if (preserve)
- ret = drm_surface_copy_swap(nsurf);
- else
- ret = drm_surface_swap_buffers(nsurf);
- break;
- default:
- ret = FALSE;
- break;
- }
-
- return ret;
- }
-
- static void
- drm_surface_wait(struct native_surface *nsurf)
- {
- struct drm_surface *drmsurf = drm_surface(nsurf);
-
- resource_surface_wait(drmsurf->rsurf);
- }
-
- static void
- drm_surface_destroy(struct native_surface *nsurf)
- {
- struct drm_surface *drmsurf = drm_surface(nsurf);
-
- resource_surface_wait(drmsurf->rsurf);
- if (drmsurf->current_crtc.crtc)
- drmModeFreeCrtc(drmsurf->current_crtc.crtc);
-
- if (drmsurf->front_fb.buffer_id)
- drmModeRmFB(drmsurf->drmdpy->fd, drmsurf->front_fb.buffer_id);
- pipe_resource_reference(&drmsurf->front_fb.texture, NULL);
-
- if (drmsurf->back_fb.buffer_id)
- drmModeRmFB(drmsurf->drmdpy->fd, drmsurf->back_fb.buffer_id);
- pipe_resource_reference(&drmsurf->back_fb.texture, NULL);
-
- resource_surface_destroy(drmsurf->rsurf);
- FREE(drmsurf);
- }
-
- static struct drm_surface *
- drm_display_create_surface(struct native_display *ndpy,
- const struct native_config *nconf,
- uint width, uint height)
- {
- struct drm_display *drmdpy = drm_display(ndpy);
- struct drm_config *drmconf = drm_config(nconf);
- struct drm_surface *drmsurf;
-
- drmsurf = CALLOC_STRUCT(drm_surface);
- if (!drmsurf)
- return NULL;
-
- drmsurf->drmdpy = drmdpy;
- drmsurf->color_format = drmconf->base.color_format;
- drmsurf->width = width;
- drmsurf->height = height;
- drmsurf->have_pageflip = TRUE;
-
- drmsurf->rsurf = resource_surface_create(drmdpy->base.screen,
- drmsurf->color_format,
- PIPE_BIND_RENDER_TARGET |
- PIPE_BIND_SAMPLER_VIEW |
- PIPE_BIND_DISPLAY_TARGET |
- PIPE_BIND_SCANOUT);
- if (!drmsurf->rsurf) {
- FREE(drmsurf);
- return NULL;
- }
-
- resource_surface_set_size(drmsurf->rsurf, drmsurf->width, drmsurf->height);
-
- drmsurf->base.destroy = drm_surface_destroy;
- drmsurf->base.present = drm_surface_present;
- drmsurf->base.validate = drm_surface_validate;
- drmsurf->base.wait = drm_surface_wait;
-
- return drmsurf;
- }
-
- /**
- * Choose a CRTC that supports all given connectors.
- */
- static uint32_t
- drm_display_choose_crtc(struct native_display *ndpy,
- uint32_t *connectors, int num_connectors)
- {
- struct drm_display *drmdpy = drm_display(ndpy);
- int idx;
-
- for (idx = 0; idx < drmdpy->resources->count_crtcs; idx++) {
- boolean found_crtc = TRUE;
- int i, j;
-
- for (i = 0; i < num_connectors; i++) {
- drmModeConnectorPtr connector;
- int encoder_idx = -1;
-
- connector = drmModeGetConnector(drmdpy->fd, connectors[i]);
- if (!connector) {
- found_crtc = FALSE;
- break;
- }
-
- /* find an encoder the CRTC supports */
- for (j = 0; j < connector->count_encoders; j++) {
- drmModeEncoderPtr encoder =
- drmModeGetEncoder(drmdpy->fd, connector->encoders[j]);
- if (encoder->possible_crtcs & (1 << idx)) {
- encoder_idx = j;
- break;
- }
- drmModeFreeEncoder(encoder);
- }
-
- drmModeFreeConnector(connector);
- if (encoder_idx < 0) {
- found_crtc = FALSE;
- break;
- }
- }
-
- if (found_crtc)
- break;
- }
-
- if (idx >= drmdpy->resources->count_crtcs) {
- _eglLog(_EGL_WARNING,
- "failed to find a CRTC that supports the given %d connectors",
- num_connectors);
- return 0;
- }
-
- return drmdpy->resources->crtcs[idx];
- }
-
- /**
- * Remember the original CRTC status and set the CRTC
- */
- static boolean
- drm_display_set_crtc(struct native_display *ndpy, int crtc_idx,
- uint32_t buffer_id, uint32_t x, uint32_t y,
- uint32_t *connectors, int num_connectors,
- drmModeModeInfoPtr mode)
- {
- struct drm_display *drmdpy = drm_display(ndpy);
- struct drm_crtc *drmcrtc = &drmdpy->saved_crtcs[crtc_idx];
- uint32_t crtc_id;
- int err;
-
- if (drmcrtc->crtc) {
- crtc_id = drmcrtc->crtc->crtc_id;
- }
- else {
- int count = 0, i;
-
- /*
- * Choose the CRTC once. It could be more dynamic, but let's keep it
- * simple for now.
- */
- crtc_id = drm_display_choose_crtc(&drmdpy->base,
- connectors, num_connectors);
-
- /* save the original CRTC status */
- drmcrtc->crtc = drmModeGetCrtc(drmdpy->fd, crtc_id);
- if (!drmcrtc->crtc)
- return FALSE;
-
- for (i = 0; i < drmdpy->num_connectors; i++) {
- struct drm_connector *drmconn = &drmdpy->connectors[i];
- drmModeConnectorPtr connector = drmconn->connector;
- drmModeEncoderPtr encoder;
-
- encoder = drmModeGetEncoder(drmdpy->fd, connector->encoder_id);
- if (encoder) {
- if (encoder->crtc_id == crtc_id) {
- drmcrtc->connectors[count++] = connector->connector_id;
- if (count >= Elements(drmcrtc->connectors))
- break;
- }
- drmModeFreeEncoder(encoder);
- }
- }
-
- drmcrtc->num_connectors = count;
- }
-
- err = drmModeSetCrtc(drmdpy->fd, crtc_id, buffer_id, x, y,
- connectors, num_connectors, mode);
- if (err) {
- drmModeFreeCrtc(drmcrtc->crtc);
- drmcrtc->crtc = NULL;
- drmcrtc->num_connectors = 0;
-
- return FALSE;
- }
-
- return TRUE;
- }
-
- static boolean
- drm_display_program(struct native_display *ndpy, int crtc_idx,
- struct native_surface *nsurf, uint x, uint y,
- const struct native_connector **nconns, int num_nconns,
- const struct native_mode *nmode)
- {
- struct drm_display *drmdpy = drm_display(ndpy);
- struct drm_surface *drmsurf = drm_surface(nsurf);
- const struct drm_mode *drmmode = drm_mode(nmode);
- uint32_t connector_ids[32];
- uint32_t buffer_id;
- drmModeModeInfo mode_tmp, *mode;
- int i;
-
- if (num_nconns > Elements(connector_ids)) {
- _eglLog(_EGL_WARNING, "too many connectors (%d)", num_nconns);
- num_nconns = Elements(connector_ids);
- }
-
- if (drmsurf) {
- if (!drm_surface_init_framebuffers(&drmsurf->base, FALSE))
- return FALSE;
-
- buffer_id = drmsurf->front_fb.buffer_id;
- /* the mode argument of drmModeSetCrtc is not constified */
- mode_tmp = drmmode->mode;
- mode = &mode_tmp;
- }
- else {
- /* disable the CRTC */
- buffer_id = 0;
- mode = NULL;
- num_nconns = 0;
- }
-
- for (i = 0; i < num_nconns; i++) {
- struct drm_connector *drmconn = drm_connector(nconns[i]);
- connector_ids[i] = drmconn->connector->connector_id;
- }
-
- if (!drm_display_set_crtc(&drmdpy->base, crtc_idx, buffer_id, x, y,
- connector_ids, num_nconns, mode)) {
- _eglLog(_EGL_WARNING, "failed to set CRTC %d", crtc_idx);
-
- return FALSE;
- }
-
- if (drmdpy->shown_surfaces[crtc_idx])
- drmdpy->shown_surfaces[crtc_idx]->is_shown = FALSE;
- drmdpy->shown_surfaces[crtc_idx] = drmsurf;
-
- /* remember the settings for buffer swapping */
- if (drmsurf) {
- uint32_t crtc_id = drmdpy->saved_crtcs[crtc_idx].crtc->crtc_id;
- struct drm_crtc *drmcrtc = &drmsurf->current_crtc;
-
- if (drmcrtc->crtc)
- drmModeFreeCrtc(drmcrtc->crtc);
- drmcrtc->crtc = drmModeGetCrtc(drmdpy->fd, crtc_id);
-
- assert(num_nconns < Elements(drmcrtc->connectors));
- memcpy(drmcrtc->connectors, connector_ids,
- sizeof(*connector_ids) * num_nconns);
- drmcrtc->num_connectors = num_nconns;
-
- drmsurf->is_shown = TRUE;
- }
-
- return TRUE;
- }
-
- static const struct native_mode **
- drm_display_get_modes(struct native_display *ndpy,
- const struct native_connector *nconn,
- int *num_modes)
- {
- struct drm_display *drmdpy = drm_display(ndpy);
- struct drm_connector *drmconn = drm_connector(nconn);
- const struct native_mode **nmodes_return;
- int count, i;
-
- /* delete old data */
- if (drmconn->connector) {
- drmModeFreeConnector(drmconn->connector);
- FREE(drmconn->drm_modes);
-
- drmconn->connector = NULL;
- drmconn->drm_modes = NULL;
- drmconn->num_modes = 0;
- }
-
- /* detect again */
- drmconn->connector = drmModeGetConnector(drmdpy->fd, drmconn->connector_id);
- if (!drmconn->connector)
- return NULL;
-
- count = drmconn->connector->count_modes;
- drmconn->drm_modes = CALLOC(count, sizeof(*drmconn->drm_modes));
- if (!drmconn->drm_modes) {
- drmModeFreeConnector(drmconn->connector);
- drmconn->connector = NULL;
-
- return NULL;
- }
-
- for (i = 0; i < count; i++) {
- struct drm_mode *drmmode = &drmconn->drm_modes[i];
- drmModeModeInfoPtr mode = &drmconn->connector->modes[i];
-
- drmmode->mode = *mode;
-
- drmmode->base.desc = drmmode->mode.name;
- drmmode->base.width = drmmode->mode.hdisplay;
- drmmode->base.height = drmmode->mode.vdisplay;
- drmmode->base.refresh_rate = drmmode->mode.vrefresh;
- /* not all kernels have vrefresh = refresh_rate * 1000 */
- if (drmmode->base.refresh_rate < 1000)
- drmmode->base.refresh_rate *= 1000;
- }
-
- nmodes_return = MALLOC(count * sizeof(*nmodes_return));
- if (nmodes_return) {
- for (i = 0; i < count; i++)
- nmodes_return[i] = &drmconn->drm_modes[i].base;
- if (num_modes)
- *num_modes = count;
- }
-
- return nmodes_return;
- }
-
- static const struct native_connector **
- drm_display_get_connectors(struct native_display *ndpy, int *num_connectors,
- int *num_crtc)
- {
- struct drm_display *drmdpy = drm_display(ndpy);
- const struct native_connector **connectors;
- int i;
-
- if (!drmdpy->connectors) {
- drmdpy->connectors =
- CALLOC(drmdpy->resources->count_connectors, sizeof(*drmdpy->connectors));
- if (!drmdpy->connectors)
- return NULL;
-
- for (i = 0; i < drmdpy->resources->count_connectors; i++) {
- struct drm_connector *drmconn = &drmdpy->connectors[i];
-
- drmconn->connector_id = drmdpy->resources->connectors[i];
- /* drmconn->connector is allocated when the modes are asked */
- }
-
- drmdpy->num_connectors = drmdpy->resources->count_connectors;
- }
-
- connectors = MALLOC(drmdpy->num_connectors * sizeof(*connectors));
- if (connectors) {
- for (i = 0; i < drmdpy->num_connectors; i++)
- connectors[i] = &drmdpy->connectors[i].base;
- if (num_connectors)
- *num_connectors = drmdpy->num_connectors;
- }
-
- if (num_crtc)
- *num_crtc = drmdpy->resources->count_crtcs;
-
- return connectors;
- }
-
- static struct native_surface *
- drm_display_create_scanout_surface(struct native_display *ndpy,
- const struct native_config *nconf,
- uint width, uint height)
- {
- struct drm_surface *drmsurf;
-
- drmsurf = drm_display_create_surface(ndpy, nconf, width, height);
- return &drmsurf->base;
- }
-
- static struct native_display_modeset drm_display_modeset = {
- .get_connectors = drm_display_get_connectors,
- .get_modes = drm_display_get_modes,
- .create_scanout_surface = drm_display_create_scanout_surface,
- .program = drm_display_program
- };
-
- void
- drm_display_fini_modeset(struct native_display *ndpy)
- {
- struct drm_display *drmdpy = drm_display(ndpy);
- int i;
-
- if (drmdpy->connectors) {
- for (i = 0; i < drmdpy->num_connectors; i++) {
- struct drm_connector *drmconn = &drmdpy->connectors[i];
- if (drmconn->connector) {
- drmModeFreeConnector(drmconn->connector);
- FREE(drmconn->drm_modes);
- }
- }
- FREE(drmdpy->connectors);
- }
-
- if (drmdpy->shown_surfaces) {
- FREE(drmdpy->shown_surfaces);
- drmdpy->shown_surfaces = NULL;
- }
-
- if (drmdpy->saved_crtcs) {
- for (i = 0; i < drmdpy->resources->count_crtcs; i++) {
- struct drm_crtc *drmcrtc = &drmdpy->saved_crtcs[i];
-
- if (drmcrtc->crtc) {
- /* restore crtc */
- drmModeSetCrtc(drmdpy->fd, drmcrtc->crtc->crtc_id,
- drmcrtc->crtc->buffer_id, drmcrtc->crtc->x, drmcrtc->crtc->y,
- drmcrtc->connectors, drmcrtc->num_connectors,
- &drmcrtc->crtc->mode);
-
- drmModeFreeCrtc(drmcrtc->crtc);
- }
- }
- FREE(drmdpy->saved_crtcs);
- }
-
- if (drmdpy->resources) {
- drmModeFreeResources(drmdpy->resources);
- drmdpy->resources = NULL;
- }
-
- drmdpy->base.modeset = NULL;
- }
-
- boolean
- drm_display_init_modeset(struct native_display *ndpy)
- {
- struct drm_display *drmdpy = drm_display(ndpy);
-
- /* resources are fixed, unlike crtc, connector, or encoder */
- drmdpy->resources = drmModeGetResources(drmdpy->fd);
- if (!drmdpy->resources) {
- _eglLog(_EGL_DEBUG, "Failed to get KMS resources. Disable modeset.");
- return FALSE;
- }
-
- drmdpy->saved_crtcs =
- CALLOC(drmdpy->resources->count_crtcs, sizeof(*drmdpy->saved_crtcs));
- if (!drmdpy->saved_crtcs) {
- drm_display_fini_modeset(&drmdpy->base);
- return FALSE;
- }
-
- drmdpy->shown_surfaces =
- CALLOC(drmdpy->resources->count_crtcs, sizeof(*drmdpy->shown_surfaces));
- if (!drmdpy->shown_surfaces) {
- drm_display_fini_modeset(&drmdpy->base);
- return FALSE;
- }
-
- drmdpy->base.modeset = &drm_display_modeset;
-
- return TRUE;
- }
|