From: "Leo (Sunpeng) Li" <sunpeng.li@xxxxxxx> This change adds a few functions in preparation of enabling CRTC color managment via the randr interface. The driver-private CRTC object now contains a list of properties, mirroring the driver-private output object. The lifecycle of the CRTC properties will also mirror the output. Since color managment properties are all DRM blobs, we'll expose the ability to change the blob ID. The user can create blobs via libdrm (which can be done without ownership of DRM master), then set the ID via xrandr. The user will then have to ensure proper cleanup by subsequently releasing the blob. Signed-off-by: Leo (Sunpeng) Li <sunpeng.li at amd.com> --- src/drmmode_display.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/drmmode_display.h | 17 ++-- 2 files changed, 264 insertions(+), 7 deletions(-) diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 85970d1..23f9ad3 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -1301,6 +1301,25 @@ static Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) return TRUE; } +static void drmmode_crtc_destroy(xf86CrtcPtr crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + int i; + + /* Free property list */ + for (i = 0; i < drmmode_crtc->num_props; i++) { + drmModeFreeProperty(drmmode_crtc->props[i].mode_prop); + free(drmmode_crtc->props[i].atoms); + } + free(drmmode_crtc->props); + + drmModeFreeCrtc(drmmode_crtc->mode_crtc); + + free(drmmode_crtc); + crtc->driver_private = NULL; +} + + static xf86CrtcFuncsRec drmmode_crtc_funcs = { .dpms = drmmode_crtc_dpms, .set_mode_major = drmmode_set_mode_major, @@ -1604,6 +1623,18 @@ static void drmmode_output_dpms(xf86OutputPtr output, int mode) } } +static Bool drmmode_crtc_property_ignore(drmModePropertyPtr prop) +{ + if (!prop) + return TRUE; + /* Ignore CRTC gamma lut sizes */ + if (!strcmp(prop->name, "GAMMA_LUT_SIZE") || + !strcmp(prop->name, "DEGAMMA_LUT_SIZE")) + return TRUE; + + return FALSE; +} + static Bool drmmode_property_ignore(drmModePropertyPtr prop) { if (!prop) @@ -1618,6 +1649,163 @@ static Bool drmmode_property_ignore(drmModePropertyPtr prop) return FALSE; } +/** +* Configure and change the given output property through randr. Currently +* ignores DRM_MODE_PROP_ENU property types. Used as part of create_resources. +* +* Return: 0 on success, X-defined error codes on failure. +*/ +static int __rr_configure_and_change_property(xf86OutputPtr output, + drmmode_prop_ptr pmode_prop) +{ + drmModePropertyPtr mode_prop = pmode_prop->mode_prop; + Bool is_immutable = mode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? + TRUE : FALSE; + int err; + + if (mode_prop->flags & DRM_MODE_PROP_BLOB) { + INT32 blob_id = pmode_prop->value; + INT32 range[2]; + + range[0] = 0; + range[1] = 0x7fffffff; /* Max signed 32-bit integer */ + + pmode_prop->num_atoms = 1; + pmode_prop->atoms = calloc(pmode_prop->num_atoms, sizeof(Atom)); + if (!pmode_prop->atoms) + return -1; + + pmode_prop->atoms[0] = MakeAtom(mode_prop->name, + strlen(mode_prop->name), + TRUE); + err = RRConfigureOutputProperty(output->randr_output, + pmode_prop->atoms[0], + FALSE, TRUE, + is_immutable, 2, range); + if (err) + goto rrconfig_error; + + err = RRChangeOutputProperty(output->randr_output, + pmode_prop->atoms[0], + XA_INTEGER, 32, + PropModeReplace, 1, &blob_id, + FALSE, TRUE); + if (err) + goto rrchange_error; + } + else if (mode_prop->flags & DRM_MODE_PROP_RANGE) { + INT32 range[2]; + INT32 value = pmode_prop->value; + + pmode_prop->num_atoms = 1; + pmode_prop->atoms = calloc(pmode_prop->num_atoms, sizeof(Atom)); + if (!pmode_prop->atoms) + return -1; + pmode_prop->atoms[0] = MakeAtom(mode_prop->name, + strlen(mode_prop->name), + TRUE); + range[0] = mode_prop->values[0]; + range[1] = mode_prop->values[1]; + + err = RRConfigureOutputProperty(output->randr_output, + pmode_prop->atoms[0], + FALSE, TRUE, + is_immutable, 2, range); + if (err) + goto rrconfig_error; + + err = RRChangeOutputProperty(output->randr_output, + pmode_prop->atoms[0], + XA_INTEGER, 32, + PropModeReplace, 1, &value, + FALSE, TRUE); + if (err) + goto rrchange_error; + } + + return 0; + +rrconfig_error: + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "Configuring property %s failed with %d\n", + mode_prop->name, err); + return err; + +rrchange_error: + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "Changing property %s failed with %d\n", + mode_prop->name, err); + return err; + +} + +static void drmmode_crtc_create_resources(xf86CrtcPtr crtc, + xf86OutputPtr output) +{ + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); + int i, j; + + /* 'p' prefix for driver private objects */ + drmmode_crtc_private_ptr pmode_crtc = crtc->driver_private; + drmModeCrtcPtr mode_crtc = pmode_crtc->mode_crtc; + + drmmode_prop_ptr pmode_prop; + drmModePropertyPtr mode_prop; + + /* Get list of DRM CRTC properties, and their values */ + drmModeObjectPropertiesPtr mode_props; + mode_props = drmModeObjectGetProperties(pAMDGPUEnt->fd, + mode_crtc->crtc_id, + DRM_MODE_OBJECT_CRTC); + if (!mode_props) + goto err_allocs; + + /* Allocate, then populate the driver-private CRTC property list */ + pmode_crtc->props = calloc(mode_props->count_props + 1, + sizeof(drmmode_prop_rec)); + if (!pmode_crtc->props) + goto err_allocs; + + pmode_crtc->num_props = 0; + + /* Filter through drm crtc properties for relevant ones, and save + * them */ + for (i = 0, j = 0; i < mode_props->count_props; i++) { + mode_prop = drmModeGetProperty(pAMDGPUEnt->fd, + mode_props->props[i]); + if (!mode_prop) + goto err_allocs; + + if (drmmode_crtc_property_ignore(mode_prop)) { + drmModeFreeProperty(mode_prop); + continue; + } + + pmode_crtc->num_props++; + pmode_prop = &pmode_crtc->props[j]; + pmode_prop->mode_prop = mode_prop; + pmode_prop->value = mode_props->prop_values[i]; + + j++; + } + + /* Finally, configure and set the properties */ + for (i = 0; i < pmode_crtc->num_props; i++) { + pmode_prop = &pmode_crtc->props[i]; + __rr_configure_and_change_property(output, pmode_prop); + } + + drmModeFreeObjectProperties(mode_props); + return; + +err_allocs: + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "Memory error creating resources for CRTC %d\n", + mode_crtc->crtc_id); + drmModeFreeObjectProperties(mode_props); + return; +} + static void drmmode_output_create_resources(xf86OutputPtr output) { AMDGPUInfoPtr info = AMDGPUPTR(output->scrn); @@ -1747,6 +1935,72 @@ static void drmmode_output_create_resources(xf86OutputPtr output) } } +/** +* Set a CRTC property. +* +* Return 0 on success, -errno on failure. +* A >0 return value implies the given property was not found on the CRTC. +*/ +static int drmmode_crtc_set_property(xf86CrtcPtr crtc, Atom property, + RRPropertyValuePtr value) +{ + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); + drmmode_crtc_private_ptr pmode_crtc = crtc->driver_private; + drmmode_prop_ptr p = NULL; + int i; + + for (i = 0; i < pmode_crtc->num_props; i++) { + p = &pmode_crtc->props[i]; + + if (p->atoms[0] == property) + break; + } + if (i == pmode_crtc->num_props) /* Property not found in CRTC. */ + return 1; + + if (p->mode_prop->flags & DRM_MODE_PROP_BLOB) { + uint32_t blob_id; + int ret; + + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + return -EINVAL; + + blob_id = *(uint32_t *) value->data; + + ret = drmModeObjectSetProperty(pAMDGPUEnt->fd, + pmode_crtc->mode_crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, + p->mode_prop->prop_id, + (uint64_t)blob_id); + if (ret) + return ret; + + return 0; + } + if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { + uint32_t val; + int ret; + + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + return -EINVAL; + val = *(uint32_t *) value->data; + + ret = drmModeObjectSetProperty(pAMDGPUEnt->fd, + pmode_crtc->mode_crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, + p->mode_prop->prop_id, + (uint64_t) val); + if (ret) + return ret; + return 0; + } + + /* No property set. */ + return 1; +} + static Bool drmmode_output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value) diff --git a/src/drmmode_display.h b/src/drmmode_display.h index 2aa5672..fcadce3 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -74,6 +74,13 @@ struct drmmode_scanout { }; typedef struct { + drmModePropertyPtr mode_prop; + uint64_t value; + 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; drmModeCrtcPtr mode_crtc; int hw_id; @@ -109,14 +116,10 @@ typedef struct { unsigned present_vblank_msc; Bool present_flip_expected; #endif -} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; -typedef struct { - drmModePropertyPtr mode_prop; - uint64_t value; - 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; + int num_props; + drmmode_prop_ptr props; +} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; typedef struct { drmmode_ptr drmmode; -- 2.7.4