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 <fourcc.h>
45/* Reference color space transform data */
46typedef 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
62static const glamor_facet glamor_facet_xv_planar_2 = {
63    .name = "xv_planar_2",
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 vec4 offsetyco;\n"
77                "uniform vec4 ucogamma;\n"
78                "uniform vec4 vco;\n"
79                "varying vec2 tcs;\n"),
80    .fs_exec = (
81                "        float sample;\n"
82                "        vec2 sample_uv;\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_uv = texture2D(u_sampler, tcs).xy;\n"
87                "        temp1.xyz = ucogamma.xyz * vec3(sample_uv.x) + temp1.xyz;\n"
88                "        temp1.xyz = clamp(vco.xyz * vec3(sample_uv.y) + temp1.xyz, 0.0, 1.0);\n"
89                "        temp1.w = 1.0;\n"
90                "        gl_FragColor = temp1;\n"
91                ),
92};
93
94static const glamor_facet glamor_facet_xv_planar_3 = {
95    .name = "xv_planar_3",
96
97    .version = 120,
98
99    .source_name = "v_texcoord0",
100    .vs_vars = ("attribute vec2 position;\n"
101                "attribute vec2 v_texcoord0;\n"
102                "varying vec2 tcs;\n"),
103    .vs_exec = (GLAMOR_POS(gl_Position, position)
104                "        tcs = v_texcoord0;\n"),
105
106    .fs_vars = ("uniform sampler2D y_sampler;\n"
107                "uniform sampler2D u_sampler;\n"
108                "uniform sampler2D v_sampler;\n"
109                "uniform vec4 offsetyco;\n"
110                "uniform vec4 ucogamma;\n"
111                "uniform vec4 vco;\n"
112                "varying vec2 tcs;\n"),
113    .fs_exec = (
114                "        float sample;\n"
115                "        vec4 temp1;\n"
116                "        sample = texture2D(y_sampler, tcs).w;\n"
117                "        temp1.xyz = offsetyco.www * vec3(sample) + offsetyco.xyz;\n"
118                "        sample = texture2D(u_sampler, tcs).w;\n"
119                "        temp1.xyz = ucogamma.xyz * vec3(sample) + temp1.xyz;\n"
120                "        sample = texture2D(v_sampler, tcs).w;\n"
121                "        temp1.xyz = clamp(vco.xyz * vec3(sample) + temp1.xyz, 0.0, 1.0);\n"
122                "        temp1.w = 1.0;\n"
123                "        gl_FragColor = temp1;\n"
124                ),
125};
126
127#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
128
129XvAttributeRec glamor_xv_attributes[] = {
130    {XvSettable | XvGettable, -1000, 1000, (char *)"XV_BRIGHTNESS"},
131    {XvSettable | XvGettable, -1000, 1000, (char *)"XV_CONTRAST"},
132    {XvSettable | XvGettable, -1000, 1000, (char *)"XV_SATURATION"},
133    {XvSettable | XvGettable, -1000, 1000, (char *)"XV_HUE"},
134    {XvSettable | XvGettable, 0, 1, (char *)"XV_COLORSPACE"},
135    {0, 0, 0, NULL}
136};
137int glamor_xv_num_attributes = ARRAY_SIZE(glamor_xv_attributes) - 1;
138
139Atom glamorBrightness, glamorContrast, glamorSaturation, glamorHue,
140    glamorColorspace, glamorGamma;
141
142XvImageRec glamor_xv_images[] = {
143    XVIMAGE_YV12,
144    XVIMAGE_I420,
145    XVIMAGE_NV12
146};
147int glamor_xv_num_images = ARRAY_SIZE(glamor_xv_images);
148
149static void
150glamor_init_xv_shader(ScreenPtr screen, int id)
151{
152    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
153    GLint sampler_loc;
154    const glamor_facet *glamor_facet_xv_planar = NULL;
155
156    switch (id) {
157    case FOURCC_YV12:
158    case FOURCC_I420:
159        glamor_facet_xv_planar = &glamor_facet_xv_planar_3;
160        break;
161    case FOURCC_NV12:
162        glamor_facet_xv_planar = &glamor_facet_xv_planar_2;
163        break;
164    default:
165        break;
166    }
167
168    glamor_build_program(screen,
169                         &glamor_priv->xv_prog,
170                         glamor_facet_xv_planar, NULL, NULL, NULL);
171
172    glUseProgram(glamor_priv->xv_prog.prog);
173    sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "y_sampler");
174    glUniform1i(sampler_loc, 0);
175    sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "u_sampler");
176    glUniform1i(sampler_loc, 1);
177
178    switch (id) {
179    case FOURCC_YV12:
180    case FOURCC_I420:
181        sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "v_sampler");
182        glUniform1i(sampler_loc, 2);
183        break;
184    case FOURCC_NV12:
185        break;
186    default:
187        break;
188    }
189
190}
191
192#define ClipValue(v,min,max) ((v) < (min) ? (min) : (v) > (max) ? (max) : (v))
193
194void
195glamor_xv_stop_video(glamor_port_private *port_priv)
196{
197}
198
199static void
200glamor_xv_free_port_data(glamor_port_private *port_priv)
201{
202    int i;
203
204    for (i = 0; i < 3; i++) {
205        if (port_priv->src_pix[i]) {
206            glamor_destroy_pixmap(port_priv->src_pix[i]);
207            port_priv->src_pix[i] = NULL;
208        }
209    }
210    RegionUninit(&port_priv->clip);
211    RegionNull(&port_priv->clip);
212}
213
214int
215glamor_xv_set_port_attribute(glamor_port_private *port_priv,
216                             Atom attribute, INT32 value)
217{
218    if (attribute == glamorBrightness)
219        port_priv->brightness = ClipValue(value, -1000, 1000);
220    else if (attribute == glamorHue)
221        port_priv->hue = ClipValue(value, -1000, 1000);
222    else if (attribute == glamorContrast)
223        port_priv->contrast = ClipValue(value, -1000, 1000);
224    else if (attribute == glamorSaturation)
225        port_priv->saturation = ClipValue(value, -1000, 1000);
226    else if (attribute == glamorGamma)
227        port_priv->gamma = ClipValue(value, 100, 10000);
228    else if (attribute == glamorColorspace)
229        port_priv->transform_index = ClipValue(value, 0, 1);
230    else
231        return BadMatch;
232    return Success;
233}
234
235int
236glamor_xv_get_port_attribute(glamor_port_private *port_priv,
237                             Atom attribute, INT32 *value)
238{
239    if (attribute == glamorBrightness)
240        *value = port_priv->brightness;
241    else if (attribute == glamorHue)
242        *value = port_priv->hue;
243    else if (attribute == glamorContrast)
244        *value = port_priv->contrast;
245    else if (attribute == glamorSaturation)
246        *value = port_priv->saturation;
247    else if (attribute == glamorGamma)
248        *value = port_priv->gamma;
249    else if (attribute == glamorColorspace)
250        *value = port_priv->transform_index;
251    else
252        return BadMatch;
253
254    return Success;
255}
256
257int
258glamor_xv_query_image_attributes(int id,
259                                 unsigned short *w, unsigned short *h,
260                                 int *pitches, int *offsets)
261{
262    int size = 0, tmp;
263
264    if (offsets)
265        offsets[0] = 0;
266    switch (id) {
267    case FOURCC_YV12:
268    case FOURCC_I420:
269        *w = ALIGN(*w, 2);
270        *h = ALIGN(*h, 2);
271        size = ALIGN(*w, 4);
272        if (pitches)
273            pitches[0] = size;
274        size *= *h;
275        if (offsets)
276            offsets[1] = size;
277        tmp = ALIGN(*w >> 1, 4);
278        if (pitches)
279            pitches[1] = pitches[2] = tmp;
280        tmp *= (*h >> 1);
281        size += tmp;
282        if (offsets)
283            offsets[2] = size;
284        size += tmp;
285        break;
286    case FOURCC_NV12:
287        *w = ALIGN(*w, 2);
288        *h = ALIGN(*h, 2);
289        size = ALIGN(*w, 4);
290        if (pitches)
291            pitches[0] = size;
292        size *= *h;
293        if (offsets)
294            offsets[1] = offsets[2] = size;
295        tmp = ALIGN(*w, 4);
296        if (pitches)
297            pitches[1] = pitches[2] = tmp;
298        tmp *= (*h >> 1);
299        size += tmp;
300        break;
301    }
302    return size;
303}
304
305/* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces
306   note the difference to the parameters used in overlay are due
307   to 10bit vs. float calcs */
308static REF_TRANSFORM trans[2] = {
309    {1.1643, 0.0, 1.5960, -0.3918, -0.8129, 2.0172, 0.0},       /* BT.601 */
310    {1.1643, 0.0, 1.7927, -0.2132, -0.5329, 2.1124, 0.0}        /* BT.709 */
311};
312
313void
314glamor_xv_render(glamor_port_private *port_priv, int id)
315{
316    ScreenPtr screen = port_priv->pPixmap->drawable.pScreen;
317    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
318    PixmapPtr pixmap = port_priv->pPixmap;
319    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
320    glamor_pixmap_private *src_pixmap_priv[3];
321    BoxPtr box = REGION_RECTS(&port_priv->clip);
322    int nBox = REGION_NUM_RECTS(&port_priv->clip);
323    GLfloat src_xscale[3], src_yscale[3];
324    int i;
325    const float Loff = -0.0627;
326    const float Coff = -0.502;
327    float uvcosf, uvsinf;
328    float yco;
329    float uco[3], vco[3], off[3];
330    float bright, cont, gamma;
331    int ref = port_priv->transform_index;
332    GLint uloc;
333    GLfloat *v;
334    char *vbo_offset;
335    int dst_box_index;
336
337    if (!glamor_priv->xv_prog.prog)
338        glamor_init_xv_shader(screen, id);
339
340    cont = RTFContrast(port_priv->contrast);
341    bright = RTFBrightness(port_priv->brightness);
342    gamma = (float) port_priv->gamma / 1000.0;
343    uvcosf = RTFSaturation(port_priv->saturation) * cos(RTFHue(port_priv->hue));
344    uvsinf = RTFSaturation(port_priv->saturation) * sin(RTFHue(port_priv->hue));
345/* overlay video also does pre-gamma contrast/sat adjust, should we? */
346
347    yco = trans[ref].RefLuma * cont;
348    uco[0] = -trans[ref].RefRCr * uvsinf;
349    uco[1] = trans[ref].RefGCb * uvcosf - trans[ref].RefGCr * uvsinf;
350    uco[2] = trans[ref].RefBCb * uvcosf;
351    vco[0] = trans[ref].RefRCr * uvcosf;
352    vco[1] = trans[ref].RefGCb * uvsinf + trans[ref].RefGCr * uvcosf;
353    vco[2] = trans[ref].RefBCb * uvsinf;
354    off[0] = Loff * yco + Coff * (uco[0] + vco[0]) + bright;
355    off[1] = Loff * yco + Coff * (uco[1] + vco[1]) + bright;
356    off[2] = Loff * yco + Coff * (uco[2] + vco[2]) + bright;
357    gamma = 1.0;
358
359    glamor_set_alu(screen, GXcopy);
360
361    for (i = 0; i < 3; i++) {
362        if (port_priv->src_pix[i]) {
363            src_pixmap_priv[i] =
364                glamor_get_pixmap_private(port_priv->src_pix[i]);
365            pixmap_priv_get_scale(src_pixmap_priv[i], &src_xscale[i],
366                                  &src_yscale[i]);
367        } else {
368           src_pixmap_priv[i] = NULL;
369        }
370    }
371    glamor_make_current(glamor_priv);
372    glUseProgram(glamor_priv->xv_prog.prog);
373
374    uloc = glGetUniformLocation(glamor_priv->xv_prog.prog, "offsetyco");
375    glUniform4f(uloc, off[0], off[1], off[2], yco);
376    uloc = glGetUniformLocation(glamor_priv->xv_prog.prog, "ucogamma");
377    glUniform4f(uloc, uco[0], uco[1], uco[2], gamma);
378    uloc = glGetUniformLocation(glamor_priv->xv_prog.prog, "vco");
379    glUniform4f(uloc, vco[0], vco[1], vco[2], 0);
380
381    glActiveTexture(GL_TEXTURE0);
382    glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[0]->fbo->tex);
383    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
384    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
385    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
386    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
387
388    glActiveTexture(GL_TEXTURE1);
389    glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[1]->fbo->tex);
390    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
391    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
392    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
393    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
394
395    switch (id) {
396    case FOURCC_YV12:
397    case FOURCC_I420:
398        glActiveTexture(GL_TEXTURE2);
399        glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->fbo->tex);
400        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
401        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
402        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
403        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
404        break;
405    case FOURCC_NV12:
406        break;
407    default:
408        break;
409    }
410
411    glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
412    glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
413
414    glEnable(GL_SCISSOR_TEST);
415
416    v = glamor_get_vbo_space(screen, 3 * 4 * sizeof(GLfloat), &vbo_offset);
417
418    /* Set up a single primitive covering the area being drawn.  We'll
419     * clip it to port_priv->clip using GL scissors instead of just
420     * emitting a GL_QUAD per box, because this way we hopefully avoid
421     * diagonal tearing between the two triangles used to rasterize a
422     * GL_QUAD.
423     */
424    i = 0;
425    v[i++] = port_priv->drw_x;
426    v[i++] = port_priv->drw_y;
427
428    v[i++] = port_priv->drw_x + port_priv->dst_w * 2;
429    v[i++] = port_priv->drw_y;
430
431    v[i++] = port_priv->drw_x;
432    v[i++] = port_priv->drw_y + port_priv->dst_h * 2;
433
434    v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x);
435    v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y);
436
437    v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x +
438                              port_priv->src_w * 2);
439    v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y);
440
441    v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x);
442    v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y +
443                              port_priv->src_h * 2);
444
445    glVertexAttribPointer(GLAMOR_VERTEX_POS, 2,
446                          GL_FLOAT, GL_FALSE,
447                          2 * sizeof(float), vbo_offset);
448
449    glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
450                          GL_FLOAT, GL_FALSE,
451                          2 * sizeof(float), vbo_offset + 6 * sizeof(GLfloat));
452
453    glamor_put_vbo_space(screen);
454
455    /* Now draw our big triangle, clipped to each of the clip boxes. */
456    glamor_pixmap_loop(pixmap_priv, dst_box_index) {
457        int dst_off_x, dst_off_y;
458
459        glamor_set_destination_drawable(port_priv->pDraw,
460                                        dst_box_index,
461                                        FALSE, FALSE,
462                                        glamor_priv->xv_prog.matrix_uniform,
463                                        &dst_off_x, &dst_off_y);
464
465        for (i = 0; i < nBox; i++) {
466            int dstx, dsty, dstw, dsth;
467
468            dstx = box[i].x1 + dst_off_x;
469            dsty = box[i].y1 + dst_off_y;
470            dstw = box[i].x2 - box[i].x1;
471            dsth = box[i].y2 - box[i].y1;
472
473            glScissor(dstx, dsty, dstw, dsth);
474            glDrawArrays(GL_TRIANGLE_FAN, 0, 3);
475        }
476    }
477    glDisable(GL_SCISSOR_TEST);
478
479    glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
480    glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
481
482    DamageDamageRegion(port_priv->pDraw, &port_priv->clip);
483
484    glamor_xv_free_port_data(port_priv);
485}
486
487int
488glamor_xv_put_image(glamor_port_private *port_priv,
489                    DrawablePtr pDrawable,
490                    short src_x, short src_y,
491                    short drw_x, short drw_y,
492                    short src_w, short src_h,
493                    short drw_w, short drw_h,
494                    int id,
495                    unsigned char *buf,
496                    short width,
497                    short height,
498                    Bool sync,
499                    RegionPtr clipBoxes)
500{
501    ScreenPtr pScreen = pDrawable->pScreen;
502    glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
503    int srcPitch, srcPitch2;
504    int top, nlines;
505    int s2offset, s3offset, tmp;
506    BoxRec full_box, half_box;
507
508    s2offset = s3offset = srcPitch2 = 0;
509
510    if (!port_priv->src_pix[0] ||
511        (width != port_priv->src_pix_w || height != port_priv->src_pix_h) ||
512        (port_priv->src_pix[2] && id == FOURCC_NV12) ||
513        (!port_priv->src_pix[2] && id != FOURCC_NV12)) {
514        int i;
515
516        if (glamor_priv->xv_prog.prog) {
517            glDeleteProgram(glamor_priv->xv_prog.prog);
518            glamor_priv->xv_prog.prog = 0;
519        }
520
521        for (i = 0; i < 3; i++)
522            if (port_priv->src_pix[i])
523                glamor_destroy_pixmap(port_priv->src_pix[i]);
524
525        port_priv->src_pix[0] =
526            glamor_create_pixmap(pScreen, width, height, 8,
527                                 GLAMOR_CREATE_FBO_NO_FBO);
528
529        switch (id) {
530        case FOURCC_YV12:
531        case FOURCC_I420:
532            port_priv->src_pix[1] =
533                glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
534                                     GLAMOR_CREATE_FBO_NO_FBO);
535            port_priv->src_pix[2] =
536                glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
537                                     GLAMOR_CREATE_FBO_NO_FBO);
538            if (!port_priv->src_pix[2])
539                return BadAlloc;
540            break;
541        case FOURCC_NV12:
542            port_priv->src_pix[1] =
543                glamor_create_pixmap(pScreen, width >> 1, height >> 1, 16,
544                                     GLAMOR_CREATE_FBO_NO_FBO |
545                                     GLAMOR_CREATE_FORMAT_CBCR);
546            port_priv->src_pix[2] = NULL;
547            break;
548        default:
549            return BadMatch;
550        }
551
552        port_priv->src_pix_w = width;
553        port_priv->src_pix_h = height;
554
555        if (!port_priv->src_pix[0] || !port_priv->src_pix[1])
556            return BadAlloc;
557    }
558
559    top = (src_y) & ~1;
560    nlines = (src_y + src_h) - top;
561
562    switch (id) {
563    case FOURCC_YV12:
564    case FOURCC_I420:
565        srcPitch = ALIGN(width, 4);
566        srcPitch2 = ALIGN(width >> 1, 4);
567        s2offset = srcPitch * height;
568        s3offset = s2offset + (srcPitch2 * ((height + 1) >> 1));
569        s2offset += ((top >> 1) * srcPitch2);
570        s3offset += ((top >> 1) * srcPitch2);
571        if (id == FOURCC_YV12) {
572            tmp = s2offset;
573            s2offset = s3offset;
574            s3offset = tmp;
575        }
576
577        full_box.x1 = 0;
578        full_box.y1 = 0;
579        full_box.x2 = width;
580        full_box.y2 = nlines;
581
582        half_box.x1 = 0;
583        half_box.y1 = 0;
584        half_box.x2 = width >> 1;
585        half_box.y2 = (nlines + 1) >> 1;
586
587        glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
588                            0, 0, 0, 0,
589                            buf + (top * srcPitch), srcPitch);
590
591        glamor_upload_boxes(port_priv->src_pix[1], &half_box, 1,
592                            0, 0, 0, 0,
593                            buf + s2offset, srcPitch2);
594
595        glamor_upload_boxes(port_priv->src_pix[2], &half_box, 1,
596                            0, 0, 0, 0,
597                            buf + s3offset, srcPitch2);
598        break;
599    case FOURCC_NV12:
600        srcPitch = ALIGN(width, 4);
601        s2offset = srcPitch * height;
602        s2offset += ((top >> 1) * srcPitch);
603
604        full_box.x1 = 0;
605        full_box.y1 = 0;
606        full_box.x2 = width;
607        full_box.y2 = nlines;
608
609        half_box.x1 = 0;
610        half_box.y1 = 0;
611        half_box.x2 = width;
612        half_box.y2 = (nlines + 1) >> 1;
613
614        glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
615                            0, 0, 0, 0,
616                            buf + (top * srcPitch), srcPitch);
617
618        glamor_upload_boxes(port_priv->src_pix[1], &half_box, 1,
619                            0, 0, 0, 0,
620                            buf + s2offset, srcPitch);
621        break;
622    default:
623        return BadMatch;
624    }
625
626    if (pDrawable->type == DRAWABLE_WINDOW)
627        port_priv->pPixmap = pScreen->GetWindowPixmap((WindowPtr) pDrawable);
628    else
629        port_priv->pPixmap = (PixmapPtr) pDrawable;
630
631    RegionCopy(&port_priv->clip, clipBoxes);
632
633    port_priv->src_x = src_x;
634    port_priv->src_y = src_y - top;
635    port_priv->src_w = src_w;
636    port_priv->src_h = src_h;
637    port_priv->dst_w = drw_w;
638    port_priv->dst_h = drw_h;
639    port_priv->drw_x = drw_x;
640    port_priv->drw_y = drw_y;
641    port_priv->w = width;
642    port_priv->h = height;
643    port_priv->pDraw = pDrawable;
644    glamor_xv_render(port_priv, id);
645    return Success;
646}
647
648void
649glamor_xv_init_port(glamor_port_private *port_priv)
650{
651    port_priv->brightness = 0;
652    port_priv->contrast = 0;
653    port_priv->saturation = 0;
654    port_priv->hue = 0;
655    port_priv->gamma = 1000;
656    port_priv->transform_index = 0;
657
658    REGION_NULL(pScreen, &port_priv->clip);
659}
660
661void
662glamor_xv_core_init(ScreenPtr screen)
663{
664    glamorBrightness = MAKE_ATOM("XV_BRIGHTNESS");
665    glamorContrast = MAKE_ATOM("XV_CONTRAST");
666    glamorSaturation = MAKE_ATOM("XV_SATURATION");
667    glamorHue = MAKE_ATOM("XV_HUE");
668    glamorGamma = MAKE_ATOM("XV_GAMMA");
669    glamorColorspace = MAKE_ATOM("XV_COLORSPACE");
670}
671