mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-20 11:40:10 +01:00
st/egl_g3d: Add support for KMS native display.
The KMS native display implements the modeset interface using DRM modesetting. Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
This commit is contained in:
parent
2dcdf19ee3
commit
a68b51deb2
3 changed files with 1005 additions and 1 deletions
|
|
@ -1194,7 +1194,7 @@ esac
|
|||
AC_ARG_WITH([egl-displays],
|
||||
[AS_HELP_STRING([--with-egl-displays@<:@=DIRS...@:>@],
|
||||
[comma delimited native displays libEGL supports, e.g.
|
||||
"x11" @<:@default=auto@:>@])],
|
||||
"x11,kms" @<:@default=auto@:>@])],
|
||||
[with_egl_displays="$withval"],
|
||||
[with_egl_displays=yes])
|
||||
|
||||
|
|
|
|||
866
src/gallium/state_trackers/egl_g3d/kms/native_kms.c
Normal file
866
src/gallium/state_trackers/egl_g3d/kms/native_kms.c
Normal file
|
|
@ -0,0 +1,866 @@
|
|||
/*
|
||||
* Mesa 3-D graphics library
|
||||
* Version: 7.8
|
||||
*
|
||||
* Copyright (C) 2010 Chia-I Wu <olv@0xlab.org>
|
||||
*
|
||||
* 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
|
||||
* BRIAN PAUL 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "pipe/p_screen.h"
|
||||
#include "pipe/p_context.h"
|
||||
#include "util/u_debug.h"
|
||||
#include "util/u_memory.h"
|
||||
#include "egllog.h"
|
||||
|
||||
#include "native_kms.h"
|
||||
|
||||
static boolean
|
||||
kms_surface_validate(struct native_surface *nsurf,
|
||||
const enum native_attachment *natts,
|
||||
unsigned num_natts,
|
||||
struct pipe_texture **textures,
|
||||
int *width, int *height)
|
||||
{
|
||||
struct kms_surface *ksurf = kms_surface(nsurf);
|
||||
struct kms_display *kdpy = ksurf->kdpy;
|
||||
struct pipe_screen *screen = kdpy->base.screen;
|
||||
struct pipe_texture templ, *ptex;
|
||||
int i;
|
||||
|
||||
if (num_natts) {
|
||||
if (textures)
|
||||
memset(textures, 0, sizeof(*textures) * num_natts);
|
||||
|
||||
memset(&templ, 0, sizeof(templ));
|
||||
templ.target = PIPE_TEXTURE_2D;
|
||||
templ.last_level = 0;
|
||||
templ.width0 = ksurf->width;
|
||||
templ.height0 = ksurf->height;
|
||||
templ.depth0 = 1;
|
||||
templ.format = ksurf->color_format;
|
||||
templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
|
||||
if (ksurf->type == KMS_SURFACE_TYPE_SCANOUT)
|
||||
templ.tex_usage |= PIPE_TEXTURE_USAGE_PRIMARY;
|
||||
}
|
||||
|
||||
/* create textures */
|
||||
for (i = 0; i < num_natts; i++) {
|
||||
enum native_attachment natt = natts[i];
|
||||
|
||||
ptex = ksurf->textures[natt];
|
||||
if (!ptex) {
|
||||
ptex = screen->texture_create(screen, &templ);
|
||||
ksurf->textures[natt] = ptex;
|
||||
}
|
||||
|
||||
if (textures)
|
||||
pipe_texture_reference(&textures[i], ptex);
|
||||
}
|
||||
|
||||
if (width)
|
||||
*width = ksurf->width;
|
||||
if (height)
|
||||
*height = ksurf->height;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add textures as DRM framebuffers.
|
||||
*/
|
||||
static boolean
|
||||
kms_surface_init_framebuffers(struct native_surface *nsurf, boolean need_back)
|
||||
{
|
||||
struct kms_surface *ksurf = kms_surface(nsurf);
|
||||
struct kms_display *kdpy = ksurf->kdpy;
|
||||
int num_framebuffers = (need_back) ? 2 : 1;
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < num_framebuffers; i++) {
|
||||
struct kms_framebuffer *fb;
|
||||
enum native_attachment natt;
|
||||
unsigned int handle, stride;
|
||||
uint block_bits;
|
||||
|
||||
if (i == 0) {
|
||||
fb = &ksurf->front_fb;
|
||||
natt = NATIVE_ATTACHMENT_FRONT_LEFT;
|
||||
}
|
||||
else {
|
||||
fb = &ksurf->back_fb;
|
||||
natt = NATIVE_ATTACHMENT_BACK_LEFT;
|
||||
}
|
||||
|
||||
if (!fb->texture) {
|
||||
/* make sure the texture has been allocated */
|
||||
kms_surface_validate(&ksurf->base, &natt, 1, NULL, NULL, NULL);
|
||||
if (!ksurf->textures[natt])
|
||||
return FALSE;
|
||||
|
||||
pipe_texture_reference(&fb->texture, ksurf->textures[natt]);
|
||||
}
|
||||
|
||||
/* already initialized */
|
||||
if (fb->buffer_id)
|
||||
continue;
|
||||
|
||||
/* TODO detect the real value */
|
||||
fb->is_passive = TRUE;
|
||||
|
||||
if (!kdpy->api->local_handle_from_texture(kdpy->api,
|
||||
kdpy->base.screen, fb->texture, &stride, &handle))
|
||||
return FALSE;
|
||||
|
||||
block_bits = util_format_get_blocksizebits(ksurf->color_format);
|
||||
err = drmModeAddFB(kdpy->fd, ksurf->width, ksurf->height,
|
||||
block_bits, block_bits, stride, handle, &fb->buffer_id);
|
||||
if (err) {
|
||||
fb->buffer_id = 0;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static boolean
|
||||
kms_surface_flush_frontbuffer(struct native_surface *nsurf)
|
||||
{
|
||||
#ifdef DRM_MODE_FEATURE_DIRTYFB
|
||||
struct kms_surface *ksurf = kms_surface(nsurf);
|
||||
struct kms_display *kdpy = ksurf->kdpy;
|
||||
|
||||
/* pbuffer is private */
|
||||
if (ksurf->type == KMS_SURFACE_TYPE_PBUFFER)
|
||||
return TRUE;
|
||||
|
||||
if (ksurf->front_fb.is_passive)
|
||||
drmModeDirtyFB(kdpy->fd, ksurf->front_fb.buffer_id, NULL, 0);
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static boolean
|
||||
kms_surface_swap_buffers(struct native_surface *nsurf)
|
||||
{
|
||||
struct kms_surface *ksurf = kms_surface(nsurf);
|
||||
struct kms_crtc *kcrtc = &ksurf->current_crtc;
|
||||
struct kms_display *kdpy = ksurf->kdpy;
|
||||
struct kms_framebuffer tmp_fb;
|
||||
struct pipe_texture *tmp_texture;
|
||||
int err;
|
||||
|
||||
/* pbuffer is private */
|
||||
if (ksurf->type == KMS_SURFACE_TYPE_PBUFFER)
|
||||
return TRUE;
|
||||
|
||||
if (!ksurf->back_fb.buffer_id) {
|
||||
if (!kms_surface_init_framebuffers(&ksurf->base, TRUE))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ksurf->is_shown && kcrtc->crtc) {
|
||||
err = drmModeSetCrtc(kdpy->fd, kcrtc->crtc->crtc_id,
|
||||
ksurf->back_fb.buffer_id, kcrtc->crtc->x, kcrtc->crtc->y,
|
||||
kcrtc->connectors, kcrtc->num_connectors, &kcrtc->crtc->mode);
|
||||
if (err)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* swap the buffers */
|
||||
tmp_fb = ksurf->front_fb;
|
||||
ksurf->front_fb = ksurf->back_fb;
|
||||
ksurf->back_fb = tmp_fb;
|
||||
|
||||
tmp_texture = ksurf->textures[NATIVE_ATTACHMENT_FRONT_LEFT];
|
||||
ksurf->textures[NATIVE_ATTACHMENT_FRONT_LEFT] =
|
||||
ksurf->textures[NATIVE_ATTACHMENT_BACK_LEFT];
|
||||
ksurf->textures[NATIVE_ATTACHMENT_BACK_LEFT] = tmp_texture;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
kms_surface_wait(struct native_surface *nsurf)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
static void
|
||||
kms_surface_destroy(struct native_surface *nsurf)
|
||||
{
|
||||
struct kms_surface *ksurf = kms_surface(nsurf);
|
||||
int i;
|
||||
|
||||
if (ksurf->current_crtc.crtc)
|
||||
drmModeFreeCrtc(ksurf->current_crtc.crtc);
|
||||
|
||||
if (ksurf->front_fb.buffer_id)
|
||||
drmModeRmFB(ksurf->kdpy->fd, ksurf->front_fb.buffer_id);
|
||||
pipe_texture_reference(&ksurf->front_fb.texture, NULL);
|
||||
|
||||
if (ksurf->back_fb.buffer_id)
|
||||
drmModeRmFB(ksurf->kdpy->fd, ksurf->back_fb.buffer_id);
|
||||
pipe_texture_reference(&ksurf->back_fb.texture, NULL);
|
||||
|
||||
for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
|
||||
struct pipe_texture *ptex = ksurf->textures[i];
|
||||
pipe_texture_reference(&ptex, NULL);
|
||||
}
|
||||
|
||||
free(ksurf);
|
||||
}
|
||||
|
||||
static struct kms_surface *
|
||||
kms_display_create_surface(struct native_display *ndpy,
|
||||
enum kms_surface_type type,
|
||||
const struct native_config *nconf,
|
||||
uint width, uint height)
|
||||
{
|
||||
struct kms_display *kdpy = kms_display(ndpy);
|
||||
struct kms_config *kconf = kms_config(nconf);
|
||||
struct kms_surface *ksurf;
|
||||
|
||||
ksurf = CALLOC_STRUCT(kms_surface);
|
||||
if (!ksurf)
|
||||
return NULL;
|
||||
|
||||
ksurf->kdpy = kdpy;
|
||||
ksurf->type = type;
|
||||
ksurf->color_format = kconf->base.color_format;
|
||||
ksurf->width = width;
|
||||
ksurf->height = height;
|
||||
|
||||
ksurf->base.destroy = kms_surface_destroy;
|
||||
ksurf->base.swap_buffers = kms_surface_swap_buffers;
|
||||
ksurf->base.flush_frontbuffer = kms_surface_flush_frontbuffer;
|
||||
ksurf->base.validate = kms_surface_validate;
|
||||
ksurf->base.wait = kms_surface_wait;
|
||||
|
||||
return ksurf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose a CRTC that supports all given connectors.
|
||||
*/
|
||||
static uint32_t
|
||||
kms_display_choose_crtc(struct native_display *ndpy,
|
||||
uint32_t *connectors, int num_connectors)
|
||||
{
|
||||
struct kms_display *kdpy = kms_display(ndpy);
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < kdpy->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(kdpy->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(kdpy->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 >= kdpy->resources->count_crtcs) {
|
||||
_eglLog(_EGL_WARNING,
|
||||
"failed to find a CRTC that supports the given %d connectors",
|
||||
num_connectors);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return kdpy->resources->crtcs[idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember the original CRTC status and set the CRTC
|
||||
*/
|
||||
static boolean
|
||||
kms_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 kms_display *kdpy = kms_display(ndpy);
|
||||
struct kms_crtc *kcrtc = &kdpy->saved_crtcs[crtc_idx];
|
||||
uint32_t crtc_id;
|
||||
int err;
|
||||
|
||||
if (kcrtc->crtc) {
|
||||
crtc_id = kcrtc->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 = kms_display_choose_crtc(&kdpy->base,
|
||||
connectors, num_connectors);
|
||||
|
||||
/* save the original CRTC status */
|
||||
kcrtc->crtc = drmModeGetCrtc(kdpy->fd, crtc_id);
|
||||
if (!kcrtc->crtc)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < kdpy->num_connectors; i++) {
|
||||
struct kms_connector *kconn = &kdpy->connectors[i];
|
||||
drmModeConnectorPtr connector = kconn->connector;
|
||||
drmModeEncoderPtr encoder;
|
||||
|
||||
encoder = drmModeGetEncoder(kdpy->fd, connector->encoder_id);
|
||||
if (encoder) {
|
||||
if (encoder->crtc_id == crtc_id) {
|
||||
kcrtc->connectors[count++] = connector->connector_id;
|
||||
if (count >= Elements(kcrtc->connectors))
|
||||
break;
|
||||
}
|
||||
drmModeFreeEncoder(encoder);
|
||||
}
|
||||
}
|
||||
|
||||
kcrtc->num_connectors = count;
|
||||
}
|
||||
|
||||
err = drmModeSetCrtc(kdpy->fd, crtc_id, buffer_id, x, y,
|
||||
connectors, num_connectors, mode);
|
||||
if (err) {
|
||||
drmModeFreeCrtc(kcrtc->crtc);
|
||||
kcrtc->crtc = NULL;
|
||||
kcrtc->num_connectors = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static boolean
|
||||
kms_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 kms_display *kdpy = kms_display(ndpy);
|
||||
struct kms_surface *ksurf = kms_surface(nsurf);
|
||||
const struct kms_mode *kmode = kms_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 (ksurf) {
|
||||
if (!kms_surface_init_framebuffers(&ksurf->base, FALSE))
|
||||
return FALSE;
|
||||
|
||||
buffer_id = ksurf->front_fb.buffer_id;
|
||||
/* the mode argument of drmModeSetCrtc is not constified */
|
||||
mode_tmp = kmode->mode;
|
||||
mode = &mode_tmp;
|
||||
}
|
||||
else {
|
||||
/* disable the CRTC */
|
||||
buffer_id = 0;
|
||||
mode = NULL;
|
||||
num_nconns = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_nconns; i++) {
|
||||
struct kms_connector *kconn = kms_connector(nconns[i]);
|
||||
connector_ids[i] = kconn->connector->connector_id;
|
||||
}
|
||||
|
||||
if (!kms_display_set_crtc(&kdpy->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 (kdpy->shown_surfaces[crtc_idx])
|
||||
kdpy->shown_surfaces[crtc_idx]->is_shown = FALSE;
|
||||
kdpy->shown_surfaces[crtc_idx] = ksurf;
|
||||
|
||||
/* remember the settings for buffer swapping */
|
||||
if (ksurf) {
|
||||
uint32_t crtc_id = kdpy->saved_crtcs[crtc_idx].crtc->crtc_id;
|
||||
struct kms_crtc *kcrtc = &ksurf->current_crtc;
|
||||
|
||||
if (kcrtc->crtc)
|
||||
drmModeFreeCrtc(kcrtc->crtc);
|
||||
kcrtc->crtc = drmModeGetCrtc(kdpy->fd, crtc_id);
|
||||
|
||||
assert(num_nconns < Elements(kcrtc->connectors));
|
||||
memcpy(kcrtc->connectors, connector_ids,
|
||||
sizeof(*connector_ids) * num_nconns);
|
||||
kcrtc->num_connectors = num_nconns;
|
||||
|
||||
ksurf->is_shown = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const struct native_mode **
|
||||
kms_display_get_modes(struct native_display *ndpy,
|
||||
const struct native_connector *nconn,
|
||||
int *num_modes)
|
||||
{
|
||||
struct kms_display *kdpy = kms_display(ndpy);
|
||||
struct kms_connector *kconn = kms_connector(nconn);
|
||||
const struct native_mode **nmodes_return;
|
||||
int count, i;
|
||||
|
||||
/* delete old data */
|
||||
if (kconn->connector) {
|
||||
drmModeFreeConnector(kconn->connector);
|
||||
free(kconn->kms_modes);
|
||||
|
||||
kconn->connector = NULL;
|
||||
kconn->kms_modes = NULL;
|
||||
kconn->num_modes = 0;
|
||||
}
|
||||
|
||||
/* detect again */
|
||||
kconn->connector = drmModeGetConnector(kdpy->fd, kconn->connector_id);
|
||||
if (!kconn->connector)
|
||||
return NULL;
|
||||
|
||||
count = kconn->connector->count_modes;
|
||||
kconn->kms_modes = calloc(count, sizeof(*kconn->kms_modes));
|
||||
if (!kconn->kms_modes) {
|
||||
drmModeFreeConnector(kconn->connector);
|
||||
kconn->connector = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
struct kms_mode *kmode = &kconn->kms_modes[i];
|
||||
drmModeModeInfoPtr mode = &kconn->connector->modes[i];
|
||||
|
||||
kmode->mode = *mode;
|
||||
|
||||
kmode->base.desc = kmode->mode.name;
|
||||
kmode->base.width = kmode->mode.hdisplay;
|
||||
kmode->base.height = kmode->mode.vdisplay;
|
||||
kmode->base.refresh_rate = kmode->mode.vrefresh / 1000;
|
||||
}
|
||||
|
||||
nmodes_return = malloc(count * sizeof(*nmodes_return));
|
||||
if (nmodes_return) {
|
||||
for (i = 0; i < count; i++)
|
||||
nmodes_return[i] = &kconn->kms_modes[i].base;
|
||||
if (num_modes)
|
||||
*num_modes = count;
|
||||
}
|
||||
|
||||
return nmodes_return;
|
||||
}
|
||||
|
||||
static const struct native_connector **
|
||||
kms_display_get_connectors(struct native_display *ndpy, int *num_connectors,
|
||||
int *num_crtc)
|
||||
{
|
||||
struct kms_display *kdpy = kms_display(ndpy);
|
||||
const struct native_connector **connectors;
|
||||
int i;
|
||||
|
||||
if (!kdpy->connectors) {
|
||||
kdpy->connectors =
|
||||
calloc(kdpy->resources->count_connectors, sizeof(*kdpy->connectors));
|
||||
if (!kdpy->connectors)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < kdpy->resources->count_connectors; i++) {
|
||||
struct kms_connector *kconn = &kdpy->connectors[i];
|
||||
|
||||
kconn->connector_id = kdpy->resources->connectors[i];
|
||||
/* kconn->connector is allocated when the modes are asked */
|
||||
}
|
||||
|
||||
kdpy->num_connectors = kdpy->resources->count_connectors;
|
||||
}
|
||||
|
||||
connectors = malloc(kdpy->num_connectors * sizeof(*connectors));
|
||||
if (connectors) {
|
||||
for (i = 0; i < kdpy->num_connectors; i++)
|
||||
connectors[i] = &kdpy->connectors[i].base;
|
||||
if (num_connectors)
|
||||
*num_connectors = kdpy->num_connectors;
|
||||
}
|
||||
|
||||
if (num_crtc)
|
||||
*num_crtc = kdpy->resources->count_crtcs;
|
||||
|
||||
return connectors;
|
||||
}
|
||||
|
||||
static struct native_surface *
|
||||
kms_display_create_scanout_surface(struct native_display *ndpy,
|
||||
const struct native_config *nconf,
|
||||
uint width, uint height)
|
||||
{
|
||||
struct kms_surface *ksurf;
|
||||
|
||||
ksurf = kms_display_create_surface(ndpy,
|
||||
KMS_SURFACE_TYPE_SCANOUT, nconf, width, height);
|
||||
return &ksurf->base;
|
||||
}
|
||||
|
||||
static struct native_surface *
|
||||
kms_display_create_pbuffer_surface(struct native_display *ndpy,
|
||||
const struct native_config *nconf,
|
||||
uint width, uint height)
|
||||
{
|
||||
struct kms_surface *ksurf;
|
||||
|
||||
ksurf = kms_display_create_surface(ndpy,
|
||||
KMS_SURFACE_TYPE_PBUFFER, nconf, width, height);
|
||||
return &ksurf->base;
|
||||
}
|
||||
|
||||
static struct pipe_context *
|
||||
kms_display_create_context(struct native_display *ndpy, void *context_private)
|
||||
{
|
||||
struct kms_display *kdpy = kms_display(ndpy);
|
||||
struct pipe_context *pctx;
|
||||
|
||||
pctx = kdpy->api->create_context(kdpy->api, kdpy->base.screen);
|
||||
if (pctx)
|
||||
pctx->priv = context_private;
|
||||
return pctx;
|
||||
}
|
||||
|
||||
static boolean
|
||||
kms_display_is_format_supported(struct native_display *ndpy,
|
||||
enum pipe_format fmt, boolean is_color)
|
||||
{
|
||||
return ndpy->screen->is_format_supported(ndpy->screen,
|
||||
fmt, PIPE_TEXTURE_2D,
|
||||
(is_color) ? PIPE_TEXTURE_USAGE_RENDER_TARGET :
|
||||
PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0);
|
||||
}
|
||||
|
||||
static const struct native_config **
|
||||
kms_display_get_configs(struct native_display *ndpy, int *num_configs)
|
||||
{
|
||||
struct kms_display *kdpy = kms_display(ndpy);
|
||||
const struct native_config **configs;
|
||||
|
||||
/* first time */
|
||||
if (!kdpy->config) {
|
||||
struct native_config *nconf;
|
||||
enum pipe_format format;
|
||||
|
||||
kdpy->config = calloc(1, sizeof(*kdpy->config));
|
||||
if (!kdpy->config)
|
||||
return NULL;
|
||||
|
||||
nconf = &kdpy->config->base;
|
||||
|
||||
/* always double-buffered */
|
||||
nconf->mode.doubleBufferMode = TRUE;
|
||||
|
||||
format = PIPE_FORMAT_A8R8G8B8_UNORM;
|
||||
if (!kms_display_is_format_supported(&kdpy->base, format, TRUE)) {
|
||||
format = PIPE_FORMAT_B8G8R8A8_UNORM;
|
||||
if (!kms_display_is_format_supported(&kdpy->base, format, TRUE))
|
||||
format = PIPE_FORMAT_NONE;
|
||||
}
|
||||
if (format == PIPE_FORMAT_NONE)
|
||||
return NULL;
|
||||
|
||||
nconf->color_format = format;
|
||||
nconf->mode.redBits = 8;
|
||||
nconf->mode.greenBits = 8;
|
||||
nconf->mode.blueBits = 8;
|
||||
nconf->mode.alphaBits = 8;
|
||||
nconf->mode.rgbBits = 32;
|
||||
|
||||
format = PIPE_FORMAT_S8Z24_UNORM;
|
||||
if (!kms_display_is_format_supported(&kdpy->base, format, FALSE)) {
|
||||
format = PIPE_FORMAT_Z24S8_UNORM;
|
||||
if (!kms_display_is_format_supported(&kdpy->base, format, FALSE))
|
||||
format = PIPE_FORMAT_NONE;
|
||||
}
|
||||
if (format != PIPE_FORMAT_NONE) {
|
||||
nconf->depth_format = format;
|
||||
nconf->stencil_format = format;
|
||||
|
||||
nconf->mode.depthBits = 24;
|
||||
nconf->mode.stencilBits = 8;
|
||||
nconf->mode.haveDepthBuffer = TRUE;
|
||||
nconf->mode.haveStencilBuffer = TRUE;
|
||||
}
|
||||
|
||||
nconf->scanout_bit = TRUE;
|
||||
nconf->mode.drawableType = GLX_PBUFFER_BIT;
|
||||
nconf->mode.swapMethod = GLX_SWAP_EXCHANGE_OML;
|
||||
|
||||
nconf->mode.visualID = 0;
|
||||
nconf->mode.visualType = EGL_NONE;
|
||||
|
||||
nconf->mode.renderType = GLX_RGBA_BIT;
|
||||
nconf->mode.rgbMode = TRUE;
|
||||
nconf->mode.xRenderable = FALSE;
|
||||
}
|
||||
|
||||
configs = malloc(sizeof(*configs));
|
||||
if (configs) {
|
||||
configs[0] = &kdpy->config->base;
|
||||
if (num_configs)
|
||||
*num_configs = 1;
|
||||
}
|
||||
|
||||
return configs;
|
||||
}
|
||||
|
||||
static void
|
||||
kms_display_destroy(struct native_display *ndpy)
|
||||
{
|
||||
struct kms_display *kdpy = kms_display(ndpy);
|
||||
int i;
|
||||
|
||||
if (kdpy->config)
|
||||
free(kdpy->config);
|
||||
|
||||
if (kdpy->connectors) {
|
||||
for (i = 0; i < kdpy->num_connectors; i++) {
|
||||
struct kms_connector *kconn = &kdpy->connectors[i];
|
||||
if (kconn->connector) {
|
||||
drmModeFreeConnector(kconn->connector);
|
||||
free(kconn->kms_modes);
|
||||
}
|
||||
}
|
||||
free(kdpy->connectors);
|
||||
}
|
||||
|
||||
if (kdpy->shown_surfaces)
|
||||
free(kdpy->shown_surfaces);
|
||||
|
||||
if (kdpy->saved_crtcs) {
|
||||
for (i = 0; i < kdpy->resources->count_crtcs; i++) {
|
||||
struct kms_crtc *kcrtc = &kdpy->saved_crtcs[i];
|
||||
|
||||
if (kcrtc->crtc) {
|
||||
/* restore crtc */
|
||||
drmModeSetCrtc(kdpy->fd, kcrtc->crtc->crtc_id,
|
||||
kcrtc->crtc->buffer_id, kcrtc->crtc->x, kcrtc->crtc->y,
|
||||
kcrtc->connectors, kcrtc->num_connectors,
|
||||
&kcrtc->crtc->mode);
|
||||
|
||||
drmModeFreeCrtc(kcrtc->crtc);
|
||||
}
|
||||
}
|
||||
free(kdpy->saved_crtcs);
|
||||
}
|
||||
|
||||
if (kdpy->resources)
|
||||
drmModeFreeResources(kdpy->resources);
|
||||
|
||||
if (kdpy->base.screen)
|
||||
kdpy->base.screen->destroy(kdpy->base.screen);
|
||||
|
||||
if (kdpy->fd >= 0)
|
||||
drmClose(kdpy->fd);
|
||||
|
||||
if (kdpy->api)
|
||||
kdpy->api->destroy(kdpy->api);
|
||||
free(kdpy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize KMS and pipe screen.
|
||||
*/
|
||||
static boolean
|
||||
kms_display_init_screen(struct native_display *ndpy)
|
||||
{
|
||||
struct kms_display *kdpy = kms_display(ndpy);
|
||||
struct drm_create_screen_arg arg;
|
||||
int fd;
|
||||
|
||||
fd = drmOpen(kdpy->api->name, NULL);
|
||||
if (fd < 0) {
|
||||
_eglLog(_EGL_WARNING, "failed to open DRM device");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (drmSetMaster(fd)) {
|
||||
_eglLog(_EGL_WARNING, "failed to become DRM master");
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.mode = DRM_CREATE_NORMAL;
|
||||
kdpy->base.screen = kdpy->api->create_screen(kdpy->api, fd, &arg);
|
||||
if (!kdpy->base.screen) {
|
||||
_eglLog(_EGL_WARNING, "failed to create DRM screen");
|
||||
drmClose(fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
kdpy->fd = fd;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static struct native_display_modeset kms_display_modeset = {
|
||||
.get_connectors = kms_display_get_connectors,
|
||||
.get_modes = kms_display_get_modes,
|
||||
.create_scanout_surface = kms_display_create_scanout_surface,
|
||||
.program = kms_display_program
|
||||
};
|
||||
|
||||
static struct native_display *
|
||||
kms_create_display(EGLNativeDisplayType dpy, struct drm_api *api,
|
||||
native_flush_frontbuffer flush_frontbuffer)
|
||||
{
|
||||
struct kms_display *kdpy;
|
||||
|
||||
kdpy = CALLOC_STRUCT(kms_display);
|
||||
if (!kdpy)
|
||||
return NULL;
|
||||
|
||||
kdpy->api = api;
|
||||
if (!kdpy->api) {
|
||||
_eglLog(_EGL_WARNING, "failed to create DRM API");
|
||||
free(kdpy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kdpy->fd = -1;
|
||||
if (!kms_display_init_screen(&kdpy->base)) {
|
||||
kms_display_destroy(&kdpy->base);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* resources are fixed, unlike crtc, connector, or encoder */
|
||||
kdpy->resources = drmModeGetResources(kdpy->fd);
|
||||
if (!kdpy->resources) {
|
||||
kms_display_destroy(&kdpy->base);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kdpy->saved_crtcs =
|
||||
calloc(kdpy->resources->count_crtcs, sizeof(*kdpy->saved_crtcs));
|
||||
if (!kdpy->saved_crtcs) {
|
||||
kms_display_destroy(&kdpy->base);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kdpy->shown_surfaces =
|
||||
calloc(kdpy->resources->count_crtcs, sizeof(*kdpy->shown_surfaces));
|
||||
if (!kdpy->shown_surfaces) {
|
||||
kms_display_destroy(&kdpy->base);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kdpy->base.screen->flush_frontbuffer =
|
||||
(void (*)(struct pipe_screen *, struct pipe_surface *, void *))
|
||||
flush_frontbuffer;
|
||||
|
||||
kdpy->base.destroy = kms_display_destroy;
|
||||
kdpy->base.get_configs = kms_display_get_configs;
|
||||
kdpy->base.create_context = kms_display_create_context;
|
||||
kdpy->base.create_pbuffer_surface = kms_display_create_pbuffer_surface;
|
||||
|
||||
kdpy->base.modeset = &kms_display_modeset;
|
||||
|
||||
return &kdpy->base;
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_flush_frontbuffer(void *dummy, struct pipe_surface *surf,
|
||||
void *context_private)
|
||||
{
|
||||
_eglLog(_EGL_WARNING, "flush_frontbuffer is not supplied");
|
||||
}
|
||||
|
||||
/* the api is destroyed with the native display */
|
||||
static struct drm_api *drm_api;
|
||||
|
||||
const char *
|
||||
native_get_name(void)
|
||||
{
|
||||
static char kms_name[32];
|
||||
|
||||
if (!drm_api)
|
||||
drm_api = drm_api_create();
|
||||
|
||||
if (drm_api)
|
||||
snprintf(kms_name, sizeof(kms_name), "KMS/%s", drm_api->name);
|
||||
else
|
||||
snprintf(kms_name, sizeof(kms_name), "KMS");
|
||||
|
||||
return kms_name;
|
||||
}
|
||||
|
||||
struct native_display *
|
||||
native_create_display(EGLNativeDisplayType dpy,
|
||||
native_flush_frontbuffer flush_frontbuffer)
|
||||
{
|
||||
struct native_display *ndpy = NULL;
|
||||
|
||||
if (!drm_api)
|
||||
drm_api = drm_api_create();
|
||||
|
||||
if (!flush_frontbuffer)
|
||||
flush_frontbuffer = dummy_flush_frontbuffer;
|
||||
|
||||
if (drm_api)
|
||||
ndpy = kms_create_display(dpy, drm_api, flush_frontbuffer);
|
||||
|
||||
return ndpy;
|
||||
}
|
||||
138
src/gallium/state_trackers/egl_g3d/kms/native_kms.h
Normal file
138
src/gallium/state_trackers/egl_g3d/kms/native_kms.h
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Mesa 3-D graphics library
|
||||
* Version: 7.8
|
||||
*
|
||||
* Copyright (C) 2010 Chia-I Wu <olv@0xlab.org>
|
||||
*
|
||||
* 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
|
||||
* BRIAN PAUL 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.
|
||||
*/
|
||||
|
||||
#ifndef _NATIVE_KMS_H_
|
||||
#define _NATIVE_KMS_H_
|
||||
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include "pipe/p_compiler.h"
|
||||
#include "util/u_format.h"
|
||||
#include "pipe/p_state.h"
|
||||
#include "state_tracker/drm_api.h"
|
||||
|
||||
#include "common/native.h"
|
||||
|
||||
enum kms_surface_type {
|
||||
KMS_SURFACE_TYPE_PBUFFER,
|
||||
KMS_SURFACE_TYPE_SCANOUT
|
||||
};
|
||||
|
||||
struct kms_config;
|
||||
struct kms_connector;
|
||||
struct kms_mode;
|
||||
|
||||
struct kms_crtc {
|
||||
drmModeCrtcPtr crtc;
|
||||
uint32_t connectors[32];
|
||||
int num_connectors;
|
||||
};
|
||||
|
||||
struct kms_display {
|
||||
struct native_display base;
|
||||
|
||||
int fd;
|
||||
struct drm_api *api;
|
||||
drmModeResPtr resources;
|
||||
struct kms_config *config;
|
||||
|
||||
struct kms_connector *connectors;
|
||||
int num_connectors;
|
||||
|
||||
struct kms_surface **shown_surfaces;
|
||||
/* save the original settings of the CRTCs */
|
||||
struct kms_crtc *saved_crtcs;
|
||||
};
|
||||
|
||||
struct kms_framebuffer {
|
||||
struct pipe_texture *texture;
|
||||
boolean is_passive;
|
||||
|
||||
uint32_t buffer_id;
|
||||
};
|
||||
|
||||
struct kms_surface {
|
||||
struct native_surface base;
|
||||
enum kms_surface_type type;
|
||||
enum pipe_format color_format;
|
||||
struct kms_display *kdpy;
|
||||
int width, height;
|
||||
|
||||
struct pipe_texture *textures[NUM_NATIVE_ATTACHMENTS];
|
||||
struct kms_framebuffer front_fb, back_fb;
|
||||
|
||||
boolean is_shown;
|
||||
struct kms_crtc current_crtc;
|
||||
};
|
||||
|
||||
struct kms_config {
|
||||
struct native_config base;
|
||||
};
|
||||
|
||||
struct kms_connector {
|
||||
struct native_connector base;
|
||||
|
||||
uint32_t connector_id;
|
||||
drmModeConnectorPtr connector;
|
||||
struct kms_mode *kms_modes;
|
||||
int num_modes;
|
||||
};
|
||||
|
||||
struct kms_mode {
|
||||
struct native_mode base;
|
||||
drmModeModeInfo mode;
|
||||
};
|
||||
|
||||
static INLINE struct kms_display *
|
||||
kms_display(const struct native_display *ndpy)
|
||||
{
|
||||
return (struct kms_display *) ndpy;
|
||||
}
|
||||
|
||||
static INLINE struct kms_surface *
|
||||
kms_surface(const struct native_surface *nsurf)
|
||||
{
|
||||
return (struct kms_surface *) nsurf;
|
||||
}
|
||||
|
||||
static INLINE struct kms_config *
|
||||
kms_config(const struct native_config *nconf)
|
||||
{
|
||||
return (struct kms_config *) nconf;
|
||||
}
|
||||
|
||||
static INLINE struct kms_connector *
|
||||
kms_connector(const struct native_connector *nconn)
|
||||
{
|
||||
return (struct kms_connector *) nconn;
|
||||
}
|
||||
|
||||
static INLINE struct kms_mode *
|
||||
kms_mode(const struct native_mode *nmode)
|
||||
{
|
||||
return (struct kms_mode *) nmode;
|
||||
}
|
||||
|
||||
#endif /* _NATIVE_KMS_H_ */
|
||||
Loading…
Add table
Reference in a new issue