1 /*
2  * Copyright © 2013 Red Hat
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *      Dave Airlie <airlied@redhat.com>
25  *
26  * some code is derived from the xf86-video-ati radeon driver, mainly
27  * the calculations.
28  */
29 
30 /** @file glamor_xv.c
31  *
32  * Xv acceleration implementation
33  */
34 
35 #ifdef HAVE_DIX_CONFIG_H
36 #include <dix-config.h>
37 #endif
38 
39 #include "glamor_priv.h"
40 #include "glamor_transform.h"
41 #include "glamor_transfer.h"
42 
43 #include <X11/extensions/Xv.h>
44 #include "../hw/xfree86/common/fourcc.h"
45 /* Reference color space transform data */
46 typedef struct tagREF_TRANSFORM {
47     float RefLuma;
48     float RefRCb;
49     float RefRCr;
50     float RefGCb;
51     float RefGCr;
52     float RefBCb;
53     float RefBCr;
54 } REF_TRANSFORM;
55 
56 #define RTFSaturation(a)   (1.0 + ((a)*1.0)/1000.0)
57 #define RTFBrightness(a)   (((a)*1.0)/2000.0)
58 #define RTFIntensity(a)   (((a)*1.0)/2000.0)
59 #define RTFContrast(a)   (1.0 + ((a)*1.0)/1000.0)
60 #define RTFHue(a)   (((a)*3.1416)/1000.0)
61 
62 static const glamor_facet glamor_facet_xv_planar = {
63     .name = "xv_planar",
64 
65     .version = 120,
66 
67     .source_name = "v_texcoord0",
68     .vs_vars = ("attribute vec2 position;\n"
69                 "attribute vec2 v_texcoord0;\n"
70                 "varying vec2 tcs;\n"),
71     .vs_exec = (GLAMOR_POS(gl_Position, position)
72                 "        tcs = v_texcoord0;\n"),
73 
74     .fs_vars = ("uniform sampler2D y_sampler;\n"
75                 "uniform sampler2D u_sampler;\n"
76                 "uniform sampler2D v_sampler;\n"
77                 "uniform vec4 offsetyco;\n"
78                 "uniform vec4 ucogamma;\n"
79                 "uniform vec4 vco;\n"
80                 "varying vec2 tcs;\n"),
81     .fs_exec = (
82                 "        float sample;\n"
83                 "        vec4 temp1;\n"
84                 "        sample = texture2D(y_sampler, tcs).w;\n"
85                 "        temp1.xyz = offsetyco.www * vec3(sample) + offsetyco.xyz;\n"
86                 "        sample = texture2D(u_sampler, tcs).w;\n"
87                 "        temp1.xyz = ucogamma.xyz * vec3(sample) + temp1.xyz;\n"
88                 "        sample = texture2D(v_sampler, tcs).w;\n"
89                 "        temp1.xyz = clamp(vco.xyz * vec3(sample) + temp1.xyz, 0.0, 1.0);\n"
90                 "        temp1.w = 1.0;\n"
91                 "        gl_FragColor = temp1;\n"
92                 ),
93 };
94 
95 #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
96 
97 XvAttributeRec glamor_xv_attributes[] = {
98     {XvSettable | XvGettable, -1000, 1000, (char *)"XV_BRIGHTNESS"},
99     {XvSettable | XvGettable, -1000, 1000, (char *)"XV_CONTRAST"},
100     {XvSettable | XvGettable, -1000, 1000, (char *)"XV_SATURATION"},
101     {XvSettable | XvGettable, -1000, 1000, (char *)"XV_HUE"},
102     {XvSettable | XvGettable, 0, 1, (char *)"XV_COLORSPACE"},
103     {0, 0, 0, NULL}
104 };
105 int glamor_xv_num_attributes = ARRAY_SIZE(glamor_xv_attributes) - 1;
106 
107 Atom glamorBrightness, glamorContrast, glamorSaturation, glamorHue,
108     glamorColorspace, glamorGamma;
109 
110 XvImageRec glamor_xv_images[] = {
111     XVIMAGE_YV12,
112     XVIMAGE_I420,
113 };
114 int glamor_xv_num_images = ARRAY_SIZE(glamor_xv_images);
115 
116 static void
glamor_init_xv_shader(ScreenPtr screen)117 glamor_init_xv_shader(ScreenPtr screen)
118 {
119     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
120     GLint sampler_loc;
121 
122     glamor_build_program(screen,
123                          &glamor_priv->xv_prog,
124                          &glamor_facet_xv_planar, NULL, NULL, NULL);
125 
126     glUseProgram(glamor_priv->xv_prog.prog);
127     sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "y_sampler");
128     glUniform1i(sampler_loc, 0);
129     sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "u_sampler");
130     glUniform1i(sampler_loc, 1);
131     sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "v_sampler");
132     glUniform1i(sampler_loc, 2);
133 
134 }
135 
136 #define ClipValue(v,min,max) ((v) < (min) ? (min) : (v) > (max) ? (max) : (v))
137 
138 void
glamor_xv_stop_video(glamor_port_private * port_priv)139 glamor_xv_stop_video(glamor_port_private *port_priv)
140 {
141 }
142 
143 static void
glamor_xv_free_port_data(glamor_port_private * port_priv)144 glamor_xv_free_port_data(glamor_port_private *port_priv)
145 {
146     int i;
147 
148     for (i = 0; i < 3; i++) {
149         if (port_priv->src_pix[i]) {
150             glamor_destroy_pixmap(port_priv->src_pix[i]);
151             port_priv->src_pix[i] = NULL;
152         }
153     }
154     RegionUninit(&port_priv->clip);
155     RegionNull(&port_priv->clip);
156 }
157 
158 int
glamor_xv_set_port_attribute(glamor_port_private * port_priv,Atom attribute,INT32 value)159 glamor_xv_set_port_attribute(glamor_port_private *port_priv,
160                              Atom attribute, INT32 value)
161 {
162     if (attribute == glamorBrightness)
163         port_priv->brightness = ClipValue(value, -1000, 1000);
164     else if (attribute == glamorHue)
165         port_priv->hue = ClipValue(value, -1000, 1000);
166     else if (attribute == glamorContrast)
167         port_priv->contrast = ClipValue(value, -1000, 1000);
168     else if (attribute == glamorSaturation)
169         port_priv->saturation = ClipValue(value, -1000, 1000);
170     else if (attribute == glamorGamma)
171         port_priv->gamma = ClipValue(value, 100, 10000);
172     else if (attribute == glamorColorspace)
173         port_priv->transform_index = ClipValue(value, 0, 1);
174     else
175         return BadMatch;
176     return Success;
177 }
178 
179 int
glamor_xv_get_port_attribute(glamor_port_private * port_priv,Atom attribute,INT32 * value)180 glamor_xv_get_port_attribute(glamor_port_private *port_priv,
181                              Atom attribute, INT32 *value)
182 {
183     if (attribute == glamorBrightness)
184         *value = port_priv->brightness;
185     else if (attribute == glamorHue)
186         *value = port_priv->hue;
187     else if (attribute == glamorContrast)
188         *value = port_priv->contrast;
189     else if (attribute == glamorSaturation)
190         *value = port_priv->saturation;
191     else if (attribute == glamorGamma)
192         *value = port_priv->gamma;
193     else if (attribute == glamorColorspace)
194         *value = port_priv->transform_index;
195     else
196         return BadMatch;
197 
198     return Success;
199 }
200 
201 int
glamor_xv_query_image_attributes(int id,unsigned short * w,unsigned short * h,int * pitches,int * offsets)202 glamor_xv_query_image_attributes(int id,
203                                  unsigned short *w, unsigned short *h,
204                                  int *pitches, int *offsets)
205 {
206     int size = 0, tmp;
207 
208     if (offsets)
209         offsets[0] = 0;
210     switch (id) {
211     case FOURCC_YV12:
212     case FOURCC_I420:
213         *w = ALIGN(*w, 2);
214         *h = ALIGN(*h, 2);
215         size = ALIGN(*w, 4);
216         if (pitches)
217             pitches[0] = size;
218         size *= *h;
219         if (offsets)
220             offsets[1] = size;
221         tmp = ALIGN(*w >> 1, 4);
222         if (pitches)
223             pitches[1] = pitches[2] = tmp;
224         tmp *= (*h >> 1);
225         size += tmp;
226         if (offsets)
227             offsets[2] = size;
228         size += tmp;
229         break;
230     }
231     return size;
232 }
233 
234 /* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces
235    note the difference to the parameters used in overlay are due
236    to 10bit vs. float calcs */
237 static REF_TRANSFORM trans[2] = {
238     {1.1643, 0.0, 1.5960, -0.3918, -0.8129, 2.0172, 0.0},       /* BT.601 */
239     {1.1643, 0.0, 1.7927, -0.2132, -0.5329, 2.1124, 0.0}        /* BT.709 */
240 };
241 
242 void
glamor_xv_render(glamor_port_private * port_priv)243 glamor_xv_render(glamor_port_private *port_priv)
244 {
245     ScreenPtr screen = port_priv->pPixmap->drawable.pScreen;
246     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
247     PixmapPtr pixmap = port_priv->pPixmap;
248     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
249     glamor_pixmap_private *src_pixmap_priv[3];
250     BoxPtr box = REGION_RECTS(&port_priv->clip);
251     int nBox = REGION_NUM_RECTS(&port_priv->clip);
252     GLfloat src_xscale[3], src_yscale[3];
253     int i;
254     const float Loff = -0.0627;
255     const float Coff = -0.502;
256     float uvcosf, uvsinf;
257     float yco;
258     float uco[3], vco[3], off[3];
259     float bright, cont, gamma;
260     int ref = port_priv->transform_index;
261     GLint uloc;
262     GLfloat *v;
263     char *vbo_offset;
264     int dst_box_index;
265 
266     if (!glamor_priv->xv_prog.prog)
267         glamor_init_xv_shader(screen);
268 
269     cont = RTFContrast(port_priv->contrast);
270     bright = RTFBrightness(port_priv->brightness);
271     gamma = (float) port_priv->gamma / 1000.0;
272     uvcosf = RTFSaturation(port_priv->saturation) * cos(RTFHue(port_priv->hue));
273     uvsinf = RTFSaturation(port_priv->saturation) * sin(RTFHue(port_priv->hue));
274 /* overlay video also does pre-gamma contrast/sat adjust, should we? */
275 
276     yco = trans[ref].RefLuma * cont;
277     uco[0] = -trans[ref].RefRCr * uvsinf;
278     uco[1] = trans[ref].RefGCb * uvcosf - trans[ref].RefGCr * uvsinf;
279     uco[2] = trans[ref].RefBCb * uvcosf;
280     vco[0] = trans[ref].RefRCr * uvcosf;
281     vco[1] = trans[ref].RefGCb * uvsinf + trans[ref].RefGCr * uvcosf;
282     vco[2] = trans[ref].RefBCb * uvsinf;
283     off[0] = Loff * yco + Coff * (uco[0] + vco[0]) + bright;
284     off[1] = Loff * yco + Coff * (uco[1] + vco[1]) + bright;
285     off[2] = Loff * yco + Coff * (uco[2] + vco[2]) + bright;
286     gamma = 1.0;
287 
288     glamor_set_alu(screen, GXcopy);
289 
290     for (i = 0; i < 3; i++) {
291         if (port_priv->src_pix[i]) {
292             src_pixmap_priv[i] =
293                 glamor_get_pixmap_private(port_priv->src_pix[i]);
294             pixmap_priv_get_scale(src_pixmap_priv[i], &src_xscale[i],
295                                   &src_yscale[i]);
296         }
297     }
298     glamor_make_current(glamor_priv);
299     glUseProgram(glamor_priv->xv_prog.prog);
300 
301     uloc = glGetUniformLocation(glamor_priv->xv_prog.prog, "offsetyco");
302     glUniform4f(uloc, off[0], off[1], off[2], yco);
303     uloc = glGetUniformLocation(glamor_priv->xv_prog.prog, "ucogamma");
304     glUniform4f(uloc, uco[0], uco[1], uco[2], gamma);
305     uloc = glGetUniformLocation(glamor_priv->xv_prog.prog, "vco");
306     glUniform4f(uloc, vco[0], vco[1], vco[2], 0);
307 
308     glActiveTexture(GL_TEXTURE0);
309     glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[0]->fbo->tex);
310     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
311     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
312     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
313     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
314 
315     glActiveTexture(GL_TEXTURE1);
316     glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[1]->fbo->tex);
317     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
318     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
319     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
320     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
321 
322     glActiveTexture(GL_TEXTURE2);
323     glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->fbo->tex);
324     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
325     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
326     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
327     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
328 
329     glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
330     glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
331 
332     glEnable(GL_SCISSOR_TEST);
333 
334     v = glamor_get_vbo_space(screen, 3 * 4 * sizeof(GLfloat), &vbo_offset);
335 
336     /* Set up a single primitive covering the area being drawn.  We'll
337      * clip it to port_priv->clip using GL scissors instead of just
338      * emitting a GL_QUAD per box, because this way we hopefully avoid
339      * diagonal tearing between the two trangles used to rasterize a
340      * GL_QUAD.
341      */
342     i = 0;
343     v[i++] = port_priv->drw_x;
344     v[i++] = port_priv->drw_y;
345 
346     v[i++] = port_priv->drw_x + port_priv->dst_w * 2;
347     v[i++] = port_priv->drw_y;
348 
349     v[i++] = port_priv->drw_x;
350     v[i++] = port_priv->drw_y + port_priv->dst_h * 2;
351 
352     v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x);
353     v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y);
354 
355     v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x +
356                               port_priv->src_w * 2);
357     v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y);
358 
359     v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x);
360     v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y +
361                               port_priv->src_h * 2);
362 
363     glVertexAttribPointer(GLAMOR_VERTEX_POS, 2,
364                           GL_FLOAT, GL_FALSE,
365                           2 * sizeof(float), vbo_offset);
366 
367     glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
368                           GL_FLOAT, GL_FALSE,
369                           2 * sizeof(float), vbo_offset + 6 * sizeof(GLfloat));
370 
371     glamor_put_vbo_space(screen);
372 
373     /* Now draw our big triangle, clipped to each of the clip boxes. */
374     glamor_pixmap_loop(pixmap_priv, dst_box_index) {
375         int dst_off_x, dst_off_y;
376 
377         glamor_set_destination_drawable(port_priv->pDraw,
378                                         dst_box_index,
379                                         FALSE, FALSE,
380                                         glamor_priv->xv_prog.matrix_uniform,
381                                         &dst_off_x, &dst_off_y);
382 
383         for (i = 0; i < nBox; i++) {
384             int dstx, dsty, dstw, dsth;
385 
386             dstx = box[i].x1 + dst_off_x;
387             dsty = box[i].y1 + dst_off_y;
388             dstw = box[i].x2 - box[i].x1;
389             dsth = box[i].y2 - box[i].y1;
390 
391             glScissor(dstx, dsty, dstw, dsth);
392             glDrawArrays(GL_TRIANGLE_FAN, 0, 3);
393         }
394     }
395     glDisable(GL_SCISSOR_TEST);
396 
397     glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
398     glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
399 
400     DamageDamageRegion(port_priv->pDraw, &port_priv->clip);
401 
402     glamor_xv_free_port_data(port_priv);
403 }
404 
405 int
glamor_xv_put_image(glamor_port_private * port_priv,DrawablePtr pDrawable,short src_x,short src_y,short drw_x,short drw_y,short src_w,short src_h,short drw_w,short drw_h,int id,unsigned char * buf,short width,short height,Bool sync,RegionPtr clipBoxes)406 glamor_xv_put_image(glamor_port_private *port_priv,
407                     DrawablePtr pDrawable,
408                     short src_x, short src_y,
409                     short drw_x, short drw_y,
410                     short src_w, short src_h,
411                     short drw_w, short drw_h,
412                     int id,
413                     unsigned char *buf,
414                     short width,
415                     short height,
416                     Bool sync,
417                     RegionPtr clipBoxes)
418 {
419     ScreenPtr pScreen = pDrawable->pScreen;
420     int srcPitch, srcPitch2;
421     int top, nlines;
422     int s2offset, s3offset, tmp;
423     BoxRec full_box, half_box;
424 
425     s2offset = s3offset = srcPitch2 = 0;
426 
427     if (!port_priv->src_pix[0] ||
428         (width != port_priv->src_pix_w || height != port_priv->src_pix_h)) {
429         int i;
430 
431         for (i = 0; i < 3; i++)
432             if (port_priv->src_pix[i])
433                 glamor_destroy_pixmap(port_priv->src_pix[i]);
434 
435         port_priv->src_pix[0] =
436             glamor_create_pixmap(pScreen, width, height, 8,
437                                  GLAMOR_CREATE_FBO_NO_FBO);
438         port_priv->src_pix[1] =
439             glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
440                                  GLAMOR_CREATE_FBO_NO_FBO);
441         port_priv->src_pix[2] =
442             glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
443                                  GLAMOR_CREATE_FBO_NO_FBO);
444         port_priv->src_pix_w = width;
445         port_priv->src_pix_h = height;
446 
447         if (!port_priv->src_pix[0] || !port_priv->src_pix[1] ||
448             !port_priv->src_pix[2])
449             return BadAlloc;
450     }
451 
452     top = (src_y) & ~1;
453     nlines = (src_y + src_h) - top;
454 
455     switch (id) {
456     case FOURCC_YV12:
457     case FOURCC_I420:
458         srcPitch = ALIGN(width, 4);
459         srcPitch2 = ALIGN(width >> 1, 4);
460         s2offset = srcPitch * height;
461         s3offset = s2offset + (srcPitch2 * ((height + 1) >> 1));
462         s2offset += ((top >> 1) * srcPitch2);
463         s3offset += ((top >> 1) * srcPitch2);
464         if (id == FOURCC_YV12) {
465             tmp = s2offset;
466             s2offset = s3offset;
467             s3offset = tmp;
468         }
469 
470         full_box.x1 = 0;
471         full_box.y1 = 0;
472         full_box.x2 = width;
473         full_box.y2 = nlines;
474 
475         half_box.x1 = 0;
476         half_box.y1 = 0;
477         half_box.x2 = width >> 1;
478         half_box.y2 = (nlines + 1) >> 1;
479 
480         glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
481                             0, 0, 0, 0,
482                             buf + (top * srcPitch), srcPitch);
483 
484         glamor_upload_boxes(port_priv->src_pix[1], &half_box, 1,
485                             0, 0, 0, 0,
486                             buf + s2offset, srcPitch2);
487 
488         glamor_upload_boxes(port_priv->src_pix[2], &half_box, 1,
489                             0, 0, 0, 0,
490                             buf + s3offset, srcPitch2);
491         break;
492     default:
493         return BadMatch;
494     }
495 
496     if (pDrawable->type == DRAWABLE_WINDOW)
497         port_priv->pPixmap = pScreen->GetWindowPixmap((WindowPtr) pDrawable);
498     else
499         port_priv->pPixmap = (PixmapPtr) pDrawable;
500 
501     RegionCopy(&port_priv->clip, clipBoxes);
502 
503     port_priv->src_x = src_x;
504     port_priv->src_y = src_y - top;
505     port_priv->src_w = src_w;
506     port_priv->src_h = src_h;
507     port_priv->dst_w = drw_w;
508     port_priv->dst_h = drw_h;
509     port_priv->drw_x = drw_x;
510     port_priv->drw_y = drw_y;
511     port_priv->w = width;
512     port_priv->h = height;
513     port_priv->pDraw = pDrawable;
514     glamor_xv_render(port_priv);
515     return Success;
516 }
517 
518 void
glamor_xv_init_port(glamor_port_private * port_priv)519 glamor_xv_init_port(glamor_port_private *port_priv)
520 {
521     port_priv->brightness = 0;
522     port_priv->contrast = 0;
523     port_priv->saturation = 0;
524     port_priv->hue = 0;
525     port_priv->gamma = 1000;
526     port_priv->transform_index = 0;
527 
528     REGION_NULL(pScreen, &port_priv->clip);
529 }
530 
531 void
glamor_xv_core_init(ScreenPtr screen)532 glamor_xv_core_init(ScreenPtr screen)
533 {
534     glamorBrightness = MAKE_ATOM("XV_BRIGHTNESS");
535     glamorContrast = MAKE_ATOM("XV_CONTRAST");
536     glamorSaturation = MAKE_ATOM("XV_SATURATION");
537     glamorHue = MAKE_ATOM("XV_HUE");
538     glamorGamma = MAKE_ATOM("XV_GAMMA");
539     glamorColorspace = MAKE_ATOM("XV_COLORSPACE");
540 }
541