Commit 60022507 authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Chris Wilson
Browse files

sna: Support 10bpc gamma via the GAMMA_LUT crtc property



Probe the GAMMA_LUT/GAMMA_LUT_SIZE props and utilize them when
the running with > 8bpc.

v2: s/sna_crtc_id/__sna_crtc_id/ in DBG since we have a sna_crtc
v3: Fix the vg "bluered" typo (Mario)
    This time I even build tested with vg support

Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
Signed-off-by: Ville Syrjälä's avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-and-tested-by: Mario Kleiner's avatarMario Kleiner <mario.kleiner.de@gmail.com>
parent 539b15bd
......@@ -127,6 +127,7 @@ struct local_mode_obj_get_properties {
uint32_t obj_type;
uint32_t pad;
};
#define LOCAL_MODE_OBJECT_CRTC 0xcccccccc
#define LOCAL_MODE_OBJECT_PLANE 0xeeeeeeee
struct local_mode_set_plane {
......@@ -229,6 +230,11 @@ struct sna_crtc {
} primary;
struct list sprites;
struct drm_color_lut *gamma_lut;
uint64_t gamma_lut_prop;
uint64_t gamma_lut_blob;
uint32_t gamma_lut_size;
uint32_t mode_serial, flip_serial;
uint32_t last_seq, wrap_seq;
......@@ -317,6 +323,9 @@ static void __sna_output_dpms(xf86OutputPtr output, int dpms, int fixup);
static void sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc);
static bool sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc,
struct kgem_bo *bo, int x, int y);
static void sna_crtc_gamma_set(xf86CrtcPtr crtc,
CARD16 *red, CARD16 *green,
CARD16 *blue, int size);
static bool is_zaphod(ScrnInfoPtr scrn)
{
......@@ -3150,11 +3159,9 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
mode->VDisplay <= sna->mode.max_crtc_height);
#if HAS_GAMMA
drmModeCrtcSetGamma(sna->kgem.fd, __sna_crtc_id(sna_crtc),
crtc->gamma_size,
crtc->gamma_red,
crtc->gamma_green,
crtc->gamma_blue);
sna_crtc_gamma_set(crtc,
crtc->gamma_red, crtc->gamma_green,
crtc->gamma_blue, crtc->gamma_size);
#endif
saved_kmode = sna_crtc->kmode;
......@@ -3212,12 +3219,44 @@ void sna_mode_adjust_frame(struct sna *sna, int x, int y)
static void
sna_crtc_gamma_set(xf86CrtcPtr crtc,
CARD16 *red, CARD16 *green, CARD16 *blue, int size)
CARD16 *red, CARD16 *green, CARD16 *blue, int size)
{
assert(to_sna_crtc(crtc));
drmModeCrtcSetGamma(to_sna(crtc->scrn)->kgem.fd,
sna_crtc_id(crtc),
size, red, green, blue);
struct sna *sna = to_sna(crtc->scrn);
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
struct drm_color_lut *lut = sna_crtc->gamma_lut;
uint32_t blob_size = size * sizeof(lut[0]);
uint32_t blob_id;
int ret, i;
DBG(("%s: gamma_size %d\n", __FUNCTION__, size));
if (!lut) {
assert(size == 256);
drmModeCrtcSetGamma(to_sna(crtc->scrn)->kgem.fd,
sna_crtc_id(crtc),
size, red, green, blue);
return;
}
assert(size == sna_crtc->gamma_lut_size);
for (i = 0; i < size; i++) {
lut[i].red = red[i];
lut[i].green = green[i];
lut[i].blue = blue[i];
}
ret = drmModeCreatePropertyBlob(sna->kgem.fd, lut, blob_size, &blob_id);
if (ret)
return;
ret = drmModeObjectSetProperty(sna->kgem.fd,
sna_crtc->id, DRM_MODE_OBJECT_CRTC,
sna_crtc->gamma_lut_prop,
blob_id);
drmModeDestroyPropertyBlob(sna->kgem.fd, blob_id);
}
static void
......@@ -3229,6 +3268,8 @@ sna_crtc_destroy(xf86CrtcPtr crtc)
if (sna_crtc == NULL)
return;
free(sna_crtc->gamma_lut);
list_for_each_entry_safe(sprite, sn, &sna_crtc->sprites, link)
free(sprite);
......@@ -3663,6 +3704,55 @@ bool sna_has_sprite_format(struct sna *sna, uint32_t format)
return false;
}
inline static bool prop_is_gamma_lut(const struct drm_mode_get_property *prop)
{
return prop_has_type_and_name(prop, 4, "GAMMA_LUT");
}
inline static bool prop_is_gamma_lut_size(const struct drm_mode_get_property *prop)
{
return prop_has_type_and_name(prop, 1, "GAMMA_LUT_SIZE");
}
static void sna_crtc_parse_prop(struct sna *sna,
struct drm_mode_get_property *prop,
uint64_t value, void *data)
{
struct sna_crtc *crtc = data;
if (prop_is_gamma_lut(prop)) {
crtc->gamma_lut_prop = prop->prop_id;
crtc->gamma_lut_blob = value;
} else if (prop_is_gamma_lut_size(prop)) {
crtc->gamma_lut_size = value;
}
}
static void
sna_crtc_init__props(struct sna *sna, struct sna_crtc *crtc)
{
ScrnInfoPtr scrn = sna->scrn;
parse_props(sna, LOCAL_MODE_OBJECT_CRTC, crtc->id,
sna_crtc_parse_prop, crtc);
/* use high precision gamma LUT for > 8bpc */
/* X-Server < 1.20 mishandles > 256 slots / > 8 bpc color maps. */
if (scrn->rgbBits <= 8 ||
XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,20,0,0,0))
crtc->gamma_lut_size = 0;
if (crtc->gamma_lut_size) {
crtc->gamma_lut = calloc(max(crtc->gamma_lut_size, 256),
sizeof(crtc->gamma_lut[0]));
if (!crtc->gamma_lut)
crtc->gamma_lut_size = 0;
}
DBG(("%s: CRTC:%d, gamma_lut_size=%d\n", __FUNCTION__,
__sna_crtc_id(crtc), crtc->gamma_lut_size));
}
static void
sna_crtc_init__rotation(struct sna *sna, struct sna_crtc *crtc)
{
......@@ -3723,6 +3813,9 @@ sna_crtc_add(ScrnInfoPtr scrn, unsigned id)
list_init(&sna_crtc->sprites);
sna_crtc_init__rotation(sna, sna_crtc);
sna_crtc_init__props(sna, sna_crtc);
sna_crtc_find_planes(sna, sna_crtc);
DBG(("%s: CRTC:%d [pipe=%d], primary id=%x: supported-rotations=%x, current-rotation=%x\n",
......@@ -7274,36 +7367,110 @@ static void output_set_gamma(xf86OutputPtr output, xf86CrtcPtr crtc)
mon->mon_gamma_blue);
}
static bool
crtc_get_gamma_lut(xf86CrtcPtr crtc,
CARD16 *red, CARD16 *green, CARD16 *blue, int size)
{
struct sna *sna = to_sna(crtc->scrn);
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
struct drm_color_lut *lut = sna_crtc->gamma_lut;
struct drm_mode_get_blob blob;
int lut_size, i;
DBG(("%s: gamma_size %d\n", __FUNCTION__, size));
memset(&blob, 0, sizeof(blob));
blob.blob_id = sna_crtc->gamma_lut_blob;
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
return false;
lut_size = blob.length / sizeof(lut[0]);
if (lut_size == 0 ||
lut_size > max(sna_crtc->gamma_lut_size, 256))
return false;
blob.data = (uintptr_t)lut;
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
return false;
for (i = 0; i < size; i++) {
struct drm_color_lut *entry =
&lut[i * (lut_size - 1) / (size - 1)];
red[i] = entry->red;
green[i] = entry->green;
blue[i] = entry->blue;
}
return red[size - 1] &&
green[size - 1] &&
blue[size - 1];
}
static bool crtc_get_gamma_legacy(xf86CrtcPtr crtc,
CARD16 *red,
CARD16 *green,
CARD16 *blue,
int size)
{
struct sna *sna = to_sna(crtc->scrn);
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
struct drm_mode_crtc_lut lut = {
.crtc_id = __sna_crtc_id(sna_crtc),
.gamma_size = size,
.red = (uintptr_t)red,
.green = (uintptr_t)green,
.blue = (uintptr_t)blue,
};
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETGAMMA, &lut) != 0)
return false;
VG(VALGRIND_MAKE_MEM_DEFINED(red, size*sizeof(red[0])));
VG(VALGRIND_MAKE_MEM_DEFINED(green, size*sizeof(green[0])));
VG(VALGRIND_MAKE_MEM_DEFINED(blue, size*sizeof(blue[0])));
return red[size - 1] &&
green[size - 1] &&
blue[size - 1];
}
static void crtc_init_gamma(xf86CrtcPtr crtc)
{
struct sna *sna = to_sna(crtc->scrn);
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
uint16_t *gamma;
int size;
assert(sna_crtc);
size = sna_crtc->gamma_lut_size;
if (!size)
size = 256;
/* Initialize the gamma ramps */
gamma = NULL;
if (crtc->gamma_size == 256)
if (crtc->gamma_size == size)
gamma = crtc->gamma_red;
if (gamma == NULL)
gamma = malloc(3 * 256 * sizeof(uint16_t));
gamma = malloc(3 * size * sizeof(uint16_t));
if (gamma) {
struct sna *sna = to_sna(crtc->scrn);
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
struct drm_mode_crtc_lut lut;
bool gamma_set = false;
assert(sna_crtc);
lut.crtc_id = __sna_crtc_id(sna_crtc);
lut.gamma_size = 256;
lut.red = (uintptr_t)(gamma);
lut.green = (uintptr_t)(gamma + 256);
lut.blue = (uintptr_t)(gamma + 2 * 256);
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETGAMMA, &lut) == 0) {
VG(VALGRIND_MAKE_MEM_DEFINED(gamma, 3*256*sizeof(gamma[0])));
gamma_set =
gamma[256 - 1] &&
gamma[2*256 - 1] &&
gamma[3*256 - 1];
}
bool gamma_set;
uint16_t *red = gamma;
uint16_t *green = gamma + size;
uint16_t *blue = gamma + 2 * size;
if (sna_crtc->gamma_lut_size)
gamma_set = crtc_get_gamma_lut(crtc, red,
green, blue, size);
else
gamma_set = crtc_get_gamma_legacy(crtc, red,
green, blue, size);
DBG(("%s: CRTC:%d, pipe=%d: gamma set?=%d\n",
__FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
......@@ -7311,19 +7478,21 @@ static void crtc_init_gamma(xf86CrtcPtr crtc)
if (!gamma_set) {
int i;
for (i = 0; i < 256; i++) {
gamma[i] = i << 8;
gamma[256 + i] = i << 8;
gamma[2*256 + i] = i << 8;
for (i = 0; i < size; i++) {
uint16_t val = i * 0xffff / (size - 1);
red[i] = val;
green[i] = val;
blue[i] = val;
}
}
if (gamma != crtc->gamma_red) {
if (red != crtc->gamma_red) {
free(crtc->gamma_red);
crtc->gamma_red = gamma;
crtc->gamma_green = gamma + 256;
crtc->gamma_blue = gamma + 2*256;
crtc->gamma_size = 256;
crtc->gamma_red = red;
crtc->gamma_green = green;
crtc->gamma_blue = blue;
crtc->gamma_size = size;
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment