[PATCH 1/3] kms: Don't hardcode the output properties [PATCH 2/3] kms: Implement output->get_property when RandR1.3 is available. [PATCH 3/3] kms: Add TV-out support src/drmmode_display.c | 403 ++++++++++++++++++++++++++++++++----------------- 1 files changed, 261 insertions(+), 142 deletions(-)
Francisco Jerez
2009-Aug-12 00:18 UTC
[Nouveau] [PATCH 1/3] kms: Don't hardcode the output properties
Replicate any properties the kernel exposes. Mostly taken from the intel DDX. --- src/drmmode_display.c | 303 ++++++++++++++++++++++++------------------------- 1 files changed, 151 insertions(+), 152 deletions(-) diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 3f04be1..805dc5b 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -58,11 +58,22 @@ typedef struct { } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; typedef struct { + drmModePropertyPtr mode_prop; + int index; /* Index within the kernel-side property arrays for + * this connector. */ + int num_atoms; /* if range prop, num_atoms == 1; if enum prop, + * num_atoms == num_enums + 1 */ + Atom *atoms; +} drmmode_prop_rec, *drmmode_prop_ptr; + +typedef struct { drmmode_ptr drmmode; int output_id; drmModeConnectorPtr mode_output; drmModeEncoderPtr mode_encoder; drmModePropertyBlobPtr edid_blob; + int num_props; + drmmode_prop_ptr props; } drmmode_output_private_rec, *drmmode_output_private_ptr; static void drmmode_output_dpms(xf86OutputPtr output, int mode); @@ -613,9 +624,14 @@ static void drmmode_output_destroy(xf86OutputPtr output) { drmmode_output_private_ptr drmmode_output = output->driver_private; + int i; if (drmmode_output->edid_blob) drmModeFreePropertyBlob(drmmode_output->edid_blob); + for (i = 0; i < drmmode_output->num_props; i++) { + drmModeFreeProperty(drmmode_output->props[i].mode_prop); + xfree(drmmode_output->props[i].atoms); + } drmModeFreeConnector(drmmode_output->mode_output); xfree(drmmode_output); output->driver_private = NULL; @@ -652,140 +668,110 @@ drmmode_output_dpms(xf86OutputPtr output, int mode) mode_id, mode); } -/* - * Several scaling modes exist, let the user choose. - */ -struct drmmode_enum { - char *name; - int value; -}; - -static struct drmmode_enum scaling_mode[] = { - { "non-gpu", DRM_MODE_SCALE_NON_GPU }, - { "fullscreen", DRM_MODE_SCALE_FULLSCREEN }, - { "aspect", DRM_MODE_SCALE_ASPECT }, - { "noscale", DRM_MODE_SCALE_NO_SCALE }, - { NULL, -1 /* invalid */ } -}; -static Atom scaling_mode_atom; - -static struct drmmode_enum dithering_mode[] = { - { "off", DRM_MODE_DITHERING_OFF }, - { "on", DRM_MODE_DITHERING_ON }, - { NULL, -1 /* invalid */ } -}; -static Atom dithering_atom; - -static int -drmmode_enum_lookup_value(struct drmmode_enum *ptr, char *name, int size) { - if (size == 0) - size = strlen(name); - - while (ptr->name) { - if (!strcmp(name, ptr->name)) - return ptr->value; - ptr++; - } - - return -1; -} - -static char * -drmmode_enum_lookup_name(struct drmmode_enum *ptr, int value) +static Bool +drmmode_property_ignore(drmModePropertyPtr prop) { - while (ptr->name) { - if (ptr->value == value) - return ptr->name; - ptr++; - } + if (!prop) + return TRUE; + /* ignore blob prop */ + if (prop->flags & DRM_MODE_PROP_BLOB) + return TRUE; + /* ignore standard property */ + if (!strcmp(prop->name, "EDID") || + !strcmp(prop->name, "DPMS")) + return TRUE; - return NULL; + return FALSE; } -drmModePropertyPtr -drmmode_output_property_find(xf86OutputPtr output, uint32_t type, - const char *name) +static void +drmmode_output_create_resources(xf86OutputPtr output) { drmmode_output_private_ptr drmmode_output = output->driver_private; - drmModeConnectorPtr koutput = drmmode_output->mode_output; + drmModeConnectorPtr mode_output = drmmode_output->mode_output; drmmode_ptr drmmode = drmmode_output->drmmode; - drmModePropertyPtr props; - int i; + drmModePropertyPtr drmmode_prop; + uint32_t value; + int i, j, err; - for (i = 0; i < koutput->count_props; i++) { - props = drmModeGetProperty(drmmode->fd, koutput->props[i]); + drmmode_output->props = xcalloc(mode_output->count_props, sizeof(drmmode_prop_rec)); + if (!drmmode_output->props) + return; - if (!props || !(props->flags & type)) + drmmode_output->num_props = 0; + for (i = 0, j = 0; i < mode_output->count_props; i++) { + drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); + if (drmmode_property_ignore(drmmode_prop)) { + drmModeFreeProperty(drmmode_prop); continue; - - if (!strcmp(props->name, name)) - return props; - } - - return NULL; -} - -static const char * -drmmode_output_property_string(xf86OutputPtr output, struct drmmode_enum *ptr, - const char *prop) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - drmModeConnectorPtr koutput = drmmode_output->mode_output; - drmModePropertyPtr props; - const char *name; - int i; - - props = drmmode_output_property_find(output, DRM_MODE_PROP_ENUM, prop); - if (!props) - return "unknown_prop"; - - for (i = 0; i < koutput->count_props; i++) { - if (koutput->props[i] == props->prop_id) - break; - } - - if (koutput->props[i] != props->prop_id) - return "unknown_output_prop"; - - name = drmmode_enum_lookup_name(ptr, koutput->prop_values[i]); - return name ? name : "unknown_enum"; -} - -static void -drmmode_output_create_resources(xf86OutputPtr output) -{ - ScrnInfoPtr pScrn = output->scrn; - const char *name; - int ret; - - scaling_mode_atom = MakeAtom("SCALING_MODE", 12, TRUE); - dithering_atom = MakeAtom("DITHERING", 9, TRUE); - - ret = RRConfigureOutputProperty(output->randr_output, scaling_mode_atom, - FALSE, FALSE, FALSE, 0, NULL); - if (ret) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Error creating SCALING_MODE property: %d\n", ret); + } + drmmode_output->props[j].mode_prop = drmmode_prop; + drmmode_output->props[j].index = i; + drmmode_output->num_props++; + j++; } - name = drmmode_output_property_string(output, scaling_mode, - "scaling mode"); - RRChangeOutputProperty(output->randr_output, scaling_mode_atom, - XA_STRING, 8, PropModeReplace, strlen(name), - (char *)name, FALSE, FALSE); - - ret = RRConfigureOutputProperty(output->randr_output, dithering_atom, - FALSE, FALSE, FALSE, 0, NULL); - if (ret) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Error creating DITHERING property: %d\n", ret); + for (i = 0; i < drmmode_output->num_props; i++) { + drmmode_prop_ptr p = &drmmode_output->props[i]; + drmmode_prop = p->mode_prop; + + value = drmmode_output->mode_output->prop_values[p->index]; + + if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { + INT32 range[2]; + + p->num_atoms = 1; + p->atoms = xcalloc(p->num_atoms, sizeof(Atom)); + if (!p->atoms) + continue; + p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); + range[0] = drmmode_prop->values[0]; + range[1] = drmmode_prop->values[1]; + err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], + FALSE, TRUE, + drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, + 2, range); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + err = RRChangeOutputProperty(output->randr_output, p->atoms[0], + XA_INTEGER, 32, PropModeReplace, 1, + &value, FALSE, FALSE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { + p->num_atoms = drmmode_prop->count_enums + 1; + p->atoms = xcalloc(p->num_atoms, sizeof(Atom)); + if (!p->atoms) + continue; + p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); + for (j = 1; j <= drmmode_prop->count_enums; j++) { + struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; + p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); + } + err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], + FALSE, FALSE, + drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, + p->num_atoms - 1, (INT32 *)&p->atoms[1]); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + for (j = 0; j < drmmode_prop->count_enums; j++) + if (drmmode_prop->enums[j].value == value) + break; + /* there's always a matching value */ + err = RRChangeOutputProperty(output->randr_output, p->atoms[0], + XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } } - - name = drmmode_output_property_string(output, dithering_mode, - "dithering"); - RRChangeOutputProperty(output->randr_output, dithering_atom, - XA_STRING, 8, PropModeReplace, strlen(name), - (char *)name, FALSE, FALSE); } static Bool @@ -794,47 +780,60 @@ drmmode_output_set_property(xf86OutputPtr output, Atom property, { drmmode_output_private_ptr drmmode_output = output->driver_private; drmmode_ptr drmmode = drmmode_output->drmmode; - drmModePropertyPtr props; - int mode, ret = 0; + int i, ret; - if (property == scaling_mode_atom) { - if (value->type != XA_STRING || value->format != 8) - return FALSE; + for (i = 0; i < drmmode_output->num_props; i++) { + drmmode_prop_ptr p = &drmmode_output->props[i]; - mode = drmmode_enum_lookup_value(scaling_mode, value->data, - value->size); - if (mode == -1) - return FALSE; + if (p->atoms[0] != property) + continue; - props = drmmode_output_property_find(output, DRM_MODE_PROP_ENUM, - "scaling mode"); - if (!props) - return FALSE; + if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { + uint32_t val; - ret = drmModeConnectorSetProperty(drmmode->fd, - drmmode_output->output_id, - props->prop_id, mode); - } else - if (property == dithering_atom) { - if (value->type != XA_STRING || value->format != 8) - return FALSE; + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + return FALSE; + val = *(uint32_t *)value->data; - mode = drmmode_enum_lookup_value(dithering_mode, value->data, - value->size); - if (mode == -1) - return FALSE; + ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, + p->mode_prop->prop_id, (uint64_t)val); - props = drmmode_output_property_find(output, DRM_MODE_PROP_ENUM, - "dithering"); - if (!props) - return FALSE; + if (ret) + return FALSE; + + return TRUE; - ret = drmModeConnectorSetProperty(drmmode->fd, - drmmode_output->output_id, - props->prop_id, mode); + } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { + Atom atom; + const char *name; + int j; + + if (value->type != XA_ATOM || value->format != 32 || value->size != 1) + return FALSE; + memcpy(&atom, value->data, 4); + name = NameForAtom(atom); + + /* search for matching name string, then set its value down */ + for (j = 0; j < p->mode_prop->count_enums; j++) { + if (!strcmp(p->mode_prop->enums[j].name, name)) { + ret = drmModeConnectorSetProperty(drmmode->fd, + drmmode_output->output_id, + p->mode_prop->prop_id, + p->mode_prop->enums[j].value); + + if (ret) + return FALSE; + + return TRUE; + } + } + + return FALSE; + } } - return ret == 0; + return TRUE; } static const xf86OutputFuncsRec drmmode_output_funcs = { -- 1.6.3.3
Francisco Jerez
2009-Aug-12 00:18 UTC
[Nouveau] [PATCH 2/3] kms: Implement output->get_property when RandR1.3 is available.
This allows getting updated values when the kernel is modifying them behind our back. --- src/drmmode_display.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 53 insertions(+), 0 deletions(-) diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 805dc5b..9b61da8 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -836,6 +836,56 @@ drmmode_output_set_property(xf86OutputPtr output, Atom property, return TRUE; } +#ifdef RANDR_13_INTERFACE +static Bool +drmmode_output_get_property(xf86OutputPtr output, Atom property) +{ + + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmmode_ptr drmmode = drmmode_output->drmmode; + uint32_t value; + int err, i; + + drmModeFreeConnector(drmmode_output->mode_output); + + drmmode_output->mode_output + drmModeGetConnector(drmmode->fd, drmmode_output->output_id); + + for (i = 0; i < drmmode_output->num_props; i++) { + drmmode_prop_ptr p = &drmmode_output->props[i]; + if (p->atoms[0] != property) + continue; + + value = drmmode_output->mode_output->prop_values[p->index]; + + if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { + err = RRChangeOutputProperty(output->randr_output, + property, XA_INTEGER, 32, + PropModeReplace, 1, &value, + FALSE, FALSE); + + return !err; + } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { + int j; + + /* search for matching name string, then set its value down */ + for (j = 0; j < p->mode_prop->count_enums; j++) { + if (p->mode_prop->enums[j].value == value) + break; + } + + err = RRChangeOutputProperty(output->randr_output, property, + XA_ATOM, 32, PropModeReplace, 1, + &p->atoms[j+1], FALSE, FALSE); + + return !err; + } + } + + return FALSE; +} +#endif + static const xf86OutputFuncsRec drmmode_output_funcs = { .create_resources = drmmode_output_create_resources, .dpms = drmmode_output_dpms, @@ -853,6 +903,9 @@ static const xf86OutputFuncsRec drmmode_output_funcs = { .get_modes = drmmode_output_get_modes, .set_property = drmmode_output_set_property, +#ifdef RANDR_13_INTERFACE + .get_property = drmmode_output_get_property, +#endif .destroy = drmmode_output_destroy }; -- 1.6.3.3
--- src/drmmode_display.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 9b61da8..daa3f53 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -571,8 +571,16 @@ drmmode_output_detect(xf86OutputPtr output) } static Bool -drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) +drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode) { + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmModeConnectorPtr koutput = drmmode_output->mode_output; + + if (koutput->connector_type == DRM_MODE_CONNECTOR_TV + && mode->type & M_T_DEFAULT) + /* Default modes are harmful here. */ + return MODE_BAD; + return MODE_OK; } @@ -778,8 +786,10 @@ static Bool drmmode_output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value) { + ScrnInfoPtr pScrn = output->scrn; drmmode_output_private_ptr drmmode_output = output->driver_private; drmmode_ptr drmmode = drmmode_output->drmmode; + const char* property_name = NameForAtom(property); int i, ret; for (i = 0; i < drmmode_output->num_props; i++) { @@ -802,7 +812,7 @@ drmmode_output_set_property(xf86OutputPtr output, Atom property, if (ret) return FALSE; - return TRUE; + goto out; } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { Atom atom; @@ -825,7 +835,7 @@ drmmode_output_set_property(xf86OutputPtr output, Atom property, if (ret) return FALSE; - return TRUE; + goto out; } } @@ -833,6 +843,62 @@ drmmode_output_set_property(xf86OutputPtr output, Atom property, } } +out: + /* The following properties are evil because they often + * render the current CRTC mode invalid. + */ + + if (!strcmp(property_name, "mode") + || !strcmp(property_name, "scale")) { + xf86CrtcPtr crtc = output->crtc; + drmmode_crtc_private_ptr drmmode_crtc; + DisplayModePtr mode, + mode_same = NULL, + mode_preferred = NULL; + + drmModeFreeConnector(drmmode_output->mode_output); + drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, + drmmode_output->output_id); + + if (!drmmode_output->mode_output || !pScrn->vtSema + || !crtc || !crtc->enabled) + return TRUE; + + drmmode_crtc = crtc->driver_private; + + xf86ProbeOutputModes(pScrn, 0, 0); + xf86SetScrnInfoModes(pScrn); + + /* Look for a mode with the same dimensions, otherwise + * use the preferred one. */ + + for (mode = output->probed_modes; mode; + mode = mode->next) { + if (crtc->mode.HDisplay == mode->HDisplay + && crtc->mode.VDisplay == mode->VDisplay) + mode_same = mode; + + if (mode->type & M_T_PREFERRED) + mode_preferred = mode; + } + + if (mode_same) + mode = mode_same; + else if (mode_preferred) + mode = mode_preferred; + + /* Disable the CRTC first to ensure a full modeset is performed. */ + drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + 0, 0, 0, NULL, 0, NULL); + + if(mode) + drmmode_set_mode_major(crtc, mode, crtc->rotation, crtc->x, crtc->y); + + if (output->randr_output->modes) + xf86RandR12TellChanged(pScrn->pScreen); + + } + return TRUE; } @@ -922,13 +988,14 @@ const char *output_names[] = { "None", "DVI-D", "DVI-A", "Composite", - "TV", + "SVIDEO", "LVDS", "CTV", "DIN", "DP", "HDMI", "HDMI", + "TV", }; -- 1.6.3.3
--- src/drmmode_display.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 9b61da8..f2fe0e8 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -571,8 +571,12 @@ drmmode_output_detect(xf86OutputPtr output) } static Bool -drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) +drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode) { + if (mode->type & M_T_DEFAULT) + /* Default modes are harmful here. */ + return MODE_BAD; + return MODE_OK; } @@ -922,13 +926,14 @@ const char *output_names[] = { "None", "DVI-D", "DVI-A", "Composite", - "TV", + "SVIDEO", "LVDS", "CTV", "DIN", "DP", "HDMI", "HDMI", + "TV", }; -- 1.6.3.3
Possibly Parallel Threads
- [PATCH 1/2] nouveau/mode: split out create_ranged_atom
- [PATCH] drmmode: Add backlight support
- [PATCH] drmmode: update logic for dynamic connectors, paths, and tiles
- [PATCH 2/2] nouveau: add libbacklight and randr property support.
- [PATCH] drmmode: update logic for dynamic connectors, paths, and tiles