135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2013 Red Hat
335c4bbdfSmrg *
435c4bbdfSmrg * Permission is hereby granted, free of charge, to any person obtaining a
535c4bbdfSmrg * copy of this software and associated documentation files (the "Software"),
635c4bbdfSmrg * to deal in the Software without restriction, including without limitation
735c4bbdfSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
835c4bbdfSmrg * and/or sell copies of the Software, and to permit persons to whom the
935c4bbdfSmrg * Software is furnished to do so, subject to the following conditions:
1035c4bbdfSmrg *
1135c4bbdfSmrg * The above copyright notice and this permission notice (including the next
1235c4bbdfSmrg * paragraph) shall be included in all copies or substantial portions of the
1335c4bbdfSmrg * Software.
1435c4bbdfSmrg *
1535c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1635c4bbdfSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1735c4bbdfSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1835c4bbdfSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1935c4bbdfSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2035c4bbdfSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2135c4bbdfSmrg * IN THE SOFTWARE.
2235c4bbdfSmrg *
2335c4bbdfSmrg * Authors:
2435c4bbdfSmrg *      Dave Airlie <airlied@redhat.com>
2535c4bbdfSmrg *
2635c4bbdfSmrg * some code is derived from the xf86-video-ati radeon driver, mainly
2735c4bbdfSmrg * the calculations.
2835c4bbdfSmrg */
2935c4bbdfSmrg
3035c4bbdfSmrg/** @file glamor_xv.c
3135c4bbdfSmrg *
3235c4bbdfSmrg * Xv acceleration implementation
3335c4bbdfSmrg */
3435c4bbdfSmrg
3535c4bbdfSmrg#ifdef HAVE_DIX_CONFIG_H
3635c4bbdfSmrg#include <dix-config.h>
3735c4bbdfSmrg#endif
3835c4bbdfSmrg
3935c4bbdfSmrg#include "glamor_priv.h"
4035c4bbdfSmrg#include "glamor_transform.h"
4135c4bbdfSmrg#include "glamor_transfer.h"
4235c4bbdfSmrg
4335c4bbdfSmrg#include <X11/extensions/Xv.h>
44ed6184dfSmrg#include <fourcc.h>
4535c4bbdfSmrg/* Reference color space transform data */
4635c4bbdfSmrgtypedef struct tagREF_TRANSFORM {
4735c4bbdfSmrg    float RefLuma;
4835c4bbdfSmrg    float RefRCb;
4935c4bbdfSmrg    float RefRCr;
5035c4bbdfSmrg    float RefGCb;
5135c4bbdfSmrg    float RefGCr;
5235c4bbdfSmrg    float RefBCb;
5335c4bbdfSmrg    float RefBCr;
5435c4bbdfSmrg} REF_TRANSFORM;
5535c4bbdfSmrg
5635c4bbdfSmrg#define RTFSaturation(a)   (1.0 + ((a)*1.0)/1000.0)
5735c4bbdfSmrg#define RTFBrightness(a)   (((a)*1.0)/2000.0)
5835c4bbdfSmrg#define RTFIntensity(a)   (((a)*1.0)/2000.0)
5935c4bbdfSmrg#define RTFContrast(a)   (1.0 + ((a)*1.0)/1000.0)
6035c4bbdfSmrg#define RTFHue(a)   (((a)*3.1416)/1000.0)
6135c4bbdfSmrg
62ed6184dfSmrgstatic const glamor_facet glamor_facet_xv_planar_2 = {
63ed6184dfSmrg    .name = "xv_planar_2",
64ed6184dfSmrg
65ed6184dfSmrg    .version = 120,
66ed6184dfSmrg
67ed6184dfSmrg    .source_name = "v_texcoord0",
68ed6184dfSmrg    .vs_vars = ("attribute vec2 position;\n"
69ed6184dfSmrg                "attribute vec2 v_texcoord0;\n"
70ed6184dfSmrg                "varying vec2 tcs;\n"),
71ed6184dfSmrg    .vs_exec = (GLAMOR_POS(gl_Position, position)
72ed6184dfSmrg                "        tcs = v_texcoord0;\n"),
73ed6184dfSmrg
74ed6184dfSmrg    .fs_vars = ("uniform sampler2D y_sampler;\n"
75ed6184dfSmrg                "uniform sampler2D u_sampler;\n"
76ed6184dfSmrg                "uniform vec4 offsetyco;\n"
77ed6184dfSmrg                "uniform vec4 ucogamma;\n"
78ed6184dfSmrg                "uniform vec4 vco;\n"
79ed6184dfSmrg                "varying vec2 tcs;\n"),
80ed6184dfSmrg    .fs_exec = (
81ed6184dfSmrg                "        float sample;\n"
82ed6184dfSmrg                "        vec2 sample_uv;\n"
83ed6184dfSmrg                "        vec4 temp1;\n"
84ed6184dfSmrg                "        sample = texture2D(y_sampler, tcs).w;\n"
85ed6184dfSmrg                "        temp1.xyz = offsetyco.www * vec3(sample) + offsetyco.xyz;\n"
86ed6184dfSmrg                "        sample_uv = texture2D(u_sampler, tcs).xy;\n"
87ed6184dfSmrg                "        temp1.xyz = ucogamma.xyz * vec3(sample_uv.x) + temp1.xyz;\n"
88ed6184dfSmrg                "        temp1.xyz = clamp(vco.xyz * vec3(sample_uv.y) + temp1.xyz, 0.0, 1.0);\n"
89ed6184dfSmrg                "        temp1.w = 1.0;\n"
90ed6184dfSmrg                "        gl_FragColor = temp1;\n"
91ed6184dfSmrg                ),
92ed6184dfSmrg};
93ed6184dfSmrg
94ed6184dfSmrgstatic const glamor_facet glamor_facet_xv_planar_3 = {
95ed6184dfSmrg    .name = "xv_planar_3",
9635c4bbdfSmrg
971b5d61b8Smrg    .version = 120,
981b5d61b8Smrg
9935c4bbdfSmrg    .source_name = "v_texcoord0",
10035c4bbdfSmrg    .vs_vars = ("attribute vec2 position;\n"
10135c4bbdfSmrg                "attribute vec2 v_texcoord0;\n"
10235c4bbdfSmrg                "varying vec2 tcs;\n"),
10335c4bbdfSmrg    .vs_exec = (GLAMOR_POS(gl_Position, position)
10435c4bbdfSmrg                "        tcs = v_texcoord0;\n"),
10535c4bbdfSmrg
10635c4bbdfSmrg    .fs_vars = ("uniform sampler2D y_sampler;\n"
10735c4bbdfSmrg                "uniform sampler2D u_sampler;\n"
10835c4bbdfSmrg                "uniform sampler2D v_sampler;\n"
10935c4bbdfSmrg                "uniform vec4 offsetyco;\n"
11035c4bbdfSmrg                "uniform vec4 ucogamma;\n"
11135c4bbdfSmrg                "uniform vec4 vco;\n"
11235c4bbdfSmrg                "varying vec2 tcs;\n"),
11335c4bbdfSmrg    .fs_exec = (
11435c4bbdfSmrg                "        float sample;\n"
11535c4bbdfSmrg                "        vec4 temp1;\n"
11635c4bbdfSmrg                "        sample = texture2D(y_sampler, tcs).w;\n"
11735c4bbdfSmrg                "        temp1.xyz = offsetyco.www * vec3(sample) + offsetyco.xyz;\n"
11835c4bbdfSmrg                "        sample = texture2D(u_sampler, tcs).w;\n"
11935c4bbdfSmrg                "        temp1.xyz = ucogamma.xyz * vec3(sample) + temp1.xyz;\n"
12035c4bbdfSmrg                "        sample = texture2D(v_sampler, tcs).w;\n"
12135c4bbdfSmrg                "        temp1.xyz = clamp(vco.xyz * vec3(sample) + temp1.xyz, 0.0, 1.0);\n"
12235c4bbdfSmrg                "        temp1.w = 1.0;\n"
12335c4bbdfSmrg                "        gl_FragColor = temp1;\n"
12435c4bbdfSmrg                ),
12535c4bbdfSmrg};
12635c4bbdfSmrg
12735c4bbdfSmrg#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
12835c4bbdfSmrg
12935c4bbdfSmrgXvAttributeRec glamor_xv_attributes[] = {
13035c4bbdfSmrg    {XvSettable | XvGettable, -1000, 1000, (char *)"XV_BRIGHTNESS"},
13135c4bbdfSmrg    {XvSettable | XvGettable, -1000, 1000, (char *)"XV_CONTRAST"},
13235c4bbdfSmrg    {XvSettable | XvGettable, -1000, 1000, (char *)"XV_SATURATION"},
13335c4bbdfSmrg    {XvSettable | XvGettable, -1000, 1000, (char *)"XV_HUE"},
13435c4bbdfSmrg    {XvSettable | XvGettable, 0, 1, (char *)"XV_COLORSPACE"},
13535c4bbdfSmrg    {0, 0, 0, NULL}
13635c4bbdfSmrg};
13735c4bbdfSmrgint glamor_xv_num_attributes = ARRAY_SIZE(glamor_xv_attributes) - 1;
13835c4bbdfSmrg
13935c4bbdfSmrgAtom glamorBrightness, glamorContrast, glamorSaturation, glamorHue,
14035c4bbdfSmrg    glamorColorspace, glamorGamma;
14135c4bbdfSmrg
14235c4bbdfSmrgXvImageRec glamor_xv_images[] = {
14335c4bbdfSmrg    XVIMAGE_YV12,
14435c4bbdfSmrg    XVIMAGE_I420,
145ed6184dfSmrg    XVIMAGE_NV12
14635c4bbdfSmrg};
14735c4bbdfSmrgint glamor_xv_num_images = ARRAY_SIZE(glamor_xv_images);
14835c4bbdfSmrg
14935c4bbdfSmrgstatic void
150ed6184dfSmrgglamor_init_xv_shader(ScreenPtr screen, int id)
15135c4bbdfSmrg{
15235c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
15335c4bbdfSmrg    GLint sampler_loc;
154ed6184dfSmrg    const glamor_facet *glamor_facet_xv_planar = NULL;
155ed6184dfSmrg
156ed6184dfSmrg    switch (id) {
157ed6184dfSmrg    case FOURCC_YV12:
158ed6184dfSmrg    case FOURCC_I420:
159ed6184dfSmrg        glamor_facet_xv_planar = &glamor_facet_xv_planar_3;
160ed6184dfSmrg        break;
161ed6184dfSmrg    case FOURCC_NV12:
162ed6184dfSmrg        glamor_facet_xv_planar = &glamor_facet_xv_planar_2;
163ed6184dfSmrg        break;
164ed6184dfSmrg    default:
165ed6184dfSmrg        break;
166ed6184dfSmrg    }
16735c4bbdfSmrg
16835c4bbdfSmrg    glamor_build_program(screen,
16935c4bbdfSmrg                         &glamor_priv->xv_prog,
170ed6184dfSmrg                         glamor_facet_xv_planar, NULL, NULL, NULL);
17135c4bbdfSmrg
17235c4bbdfSmrg    glUseProgram(glamor_priv->xv_prog.prog);
17335c4bbdfSmrg    sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "y_sampler");
17435c4bbdfSmrg    glUniform1i(sampler_loc, 0);
17535c4bbdfSmrg    sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "u_sampler");
17635c4bbdfSmrg    glUniform1i(sampler_loc, 1);
177ed6184dfSmrg
178ed6184dfSmrg    switch (id) {
179ed6184dfSmrg    case FOURCC_YV12:
180ed6184dfSmrg    case FOURCC_I420:
181ed6184dfSmrg        sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "v_sampler");
182ed6184dfSmrg        glUniform1i(sampler_loc, 2);
183ed6184dfSmrg        break;
184ed6184dfSmrg    case FOURCC_NV12:
185ed6184dfSmrg        break;
186ed6184dfSmrg    default:
187ed6184dfSmrg        break;
188ed6184dfSmrg    }
18935c4bbdfSmrg
19035c4bbdfSmrg}
19135c4bbdfSmrg
19235c4bbdfSmrg#define ClipValue(v,min,max) ((v) < (min) ? (min) : (v) > (max) ? (max) : (v))
19335c4bbdfSmrg
19435c4bbdfSmrgvoid
19535c4bbdfSmrgglamor_xv_stop_video(glamor_port_private *port_priv)
19635c4bbdfSmrg{
19735c4bbdfSmrg}
19835c4bbdfSmrg
19935c4bbdfSmrgstatic void
20035c4bbdfSmrgglamor_xv_free_port_data(glamor_port_private *port_priv)
20135c4bbdfSmrg{
20235c4bbdfSmrg    int i;
20335c4bbdfSmrg
20435c4bbdfSmrg    for (i = 0; i < 3; i++) {
20535c4bbdfSmrg        if (port_priv->src_pix[i]) {
20635c4bbdfSmrg            glamor_destroy_pixmap(port_priv->src_pix[i]);
20735c4bbdfSmrg            port_priv->src_pix[i] = NULL;
20835c4bbdfSmrg        }
20935c4bbdfSmrg    }
21035c4bbdfSmrg    RegionUninit(&port_priv->clip);
21135c4bbdfSmrg    RegionNull(&port_priv->clip);
21235c4bbdfSmrg}
21335c4bbdfSmrg
21435c4bbdfSmrgint
21535c4bbdfSmrgglamor_xv_set_port_attribute(glamor_port_private *port_priv,
21635c4bbdfSmrg                             Atom attribute, INT32 value)
21735c4bbdfSmrg{
21835c4bbdfSmrg    if (attribute == glamorBrightness)
21935c4bbdfSmrg        port_priv->brightness = ClipValue(value, -1000, 1000);
22035c4bbdfSmrg    else if (attribute == glamorHue)
22135c4bbdfSmrg        port_priv->hue = ClipValue(value, -1000, 1000);
22235c4bbdfSmrg    else if (attribute == glamorContrast)
22335c4bbdfSmrg        port_priv->contrast = ClipValue(value, -1000, 1000);
22435c4bbdfSmrg    else if (attribute == glamorSaturation)
22535c4bbdfSmrg        port_priv->saturation = ClipValue(value, -1000, 1000);
22635c4bbdfSmrg    else if (attribute == glamorGamma)
22735c4bbdfSmrg        port_priv->gamma = ClipValue(value, 100, 10000);
22835c4bbdfSmrg    else if (attribute == glamorColorspace)
22935c4bbdfSmrg        port_priv->transform_index = ClipValue(value, 0, 1);
23035c4bbdfSmrg    else
23135c4bbdfSmrg        return BadMatch;
23235c4bbdfSmrg    return Success;
23335c4bbdfSmrg}
23435c4bbdfSmrg
23535c4bbdfSmrgint
23635c4bbdfSmrgglamor_xv_get_port_attribute(glamor_port_private *port_priv,
23735c4bbdfSmrg                             Atom attribute, INT32 *value)
23835c4bbdfSmrg{
23935c4bbdfSmrg    if (attribute == glamorBrightness)
24035c4bbdfSmrg        *value = port_priv->brightness;
24135c4bbdfSmrg    else if (attribute == glamorHue)
24235c4bbdfSmrg        *value = port_priv->hue;
24335c4bbdfSmrg    else if (attribute == glamorContrast)
24435c4bbdfSmrg        *value = port_priv->contrast;
24535c4bbdfSmrg    else if (attribute == glamorSaturation)
24635c4bbdfSmrg        *value = port_priv->saturation;
24735c4bbdfSmrg    else if (attribute == glamorGamma)
24835c4bbdfSmrg        *value = port_priv->gamma;
24935c4bbdfSmrg    else if (attribute == glamorColorspace)
25035c4bbdfSmrg        *value = port_priv->transform_index;
25135c4bbdfSmrg    else
25235c4bbdfSmrg        return BadMatch;
25335c4bbdfSmrg
25435c4bbdfSmrg    return Success;
25535c4bbdfSmrg}
25635c4bbdfSmrg
25735c4bbdfSmrgint
25835c4bbdfSmrgglamor_xv_query_image_attributes(int id,
25935c4bbdfSmrg                                 unsigned short *w, unsigned short *h,
26035c4bbdfSmrg                                 int *pitches, int *offsets)
26135c4bbdfSmrg{
26235c4bbdfSmrg    int size = 0, tmp;
26335c4bbdfSmrg
26435c4bbdfSmrg    if (offsets)
26535c4bbdfSmrg        offsets[0] = 0;
26635c4bbdfSmrg    switch (id) {
26735c4bbdfSmrg    case FOURCC_YV12:
26835c4bbdfSmrg    case FOURCC_I420:
2691b5d61b8Smrg        *w = ALIGN(*w, 2);
27035c4bbdfSmrg        *h = ALIGN(*h, 2);
27135c4bbdfSmrg        size = ALIGN(*w, 4);
27235c4bbdfSmrg        if (pitches)
27335c4bbdfSmrg            pitches[0] = size;
27435c4bbdfSmrg        size *= *h;
27535c4bbdfSmrg        if (offsets)
27635c4bbdfSmrg            offsets[1] = size;
27735c4bbdfSmrg        tmp = ALIGN(*w >> 1, 4);
27835c4bbdfSmrg        if (pitches)
27935c4bbdfSmrg            pitches[1] = pitches[2] = tmp;
28035c4bbdfSmrg        tmp *= (*h >> 1);
28135c4bbdfSmrg        size += tmp;
28235c4bbdfSmrg        if (offsets)
28335c4bbdfSmrg            offsets[2] = size;
28435c4bbdfSmrg        size += tmp;
28535c4bbdfSmrg        break;
286ed6184dfSmrg    case FOURCC_NV12:
287ed6184dfSmrg        *w = ALIGN(*w, 2);
288ed6184dfSmrg        *h = ALIGN(*h, 2);
289ed6184dfSmrg        size = ALIGN(*w, 4);
290ed6184dfSmrg        if (pitches)
291ed6184dfSmrg            pitches[0] = size;
292ed6184dfSmrg        size *= *h;
293ed6184dfSmrg        if (offsets)
294ed6184dfSmrg            offsets[1] = offsets[2] = size;
295ed6184dfSmrg        tmp = ALIGN(*w, 4);
296ed6184dfSmrg        if (pitches)
297ed6184dfSmrg            pitches[1] = pitches[2] = tmp;
298ed6184dfSmrg        tmp *= (*h >> 1);
299ed6184dfSmrg        size += tmp;
300ed6184dfSmrg        break;
30135c4bbdfSmrg    }
30235c4bbdfSmrg    return size;
30335c4bbdfSmrg}
30435c4bbdfSmrg
30535c4bbdfSmrg/* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces
30635c4bbdfSmrg   note the difference to the parameters used in overlay are due
30735c4bbdfSmrg   to 10bit vs. float calcs */
30835c4bbdfSmrgstatic REF_TRANSFORM trans[2] = {
30935c4bbdfSmrg    {1.1643, 0.0, 1.5960, -0.3918, -0.8129, 2.0172, 0.0},       /* BT.601 */
31035c4bbdfSmrg    {1.1643, 0.0, 1.7927, -0.2132, -0.5329, 2.1124, 0.0}        /* BT.709 */
31135c4bbdfSmrg};
31235c4bbdfSmrg
31335c4bbdfSmrgvoid
314ed6184dfSmrgglamor_xv_render(glamor_port_private *port_priv, int id)
31535c4bbdfSmrg{
31635c4bbdfSmrg    ScreenPtr screen = port_priv->pPixmap->drawable.pScreen;
31735c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
31835c4bbdfSmrg    PixmapPtr pixmap = port_priv->pPixmap;
31935c4bbdfSmrg    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
32035c4bbdfSmrg    glamor_pixmap_private *src_pixmap_priv[3];
32135c4bbdfSmrg    BoxPtr box = REGION_RECTS(&port_priv->clip);
32235c4bbdfSmrg    int nBox = REGION_NUM_RECTS(&port_priv->clip);
32335c4bbdfSmrg    GLfloat src_xscale[3], src_yscale[3];
32435c4bbdfSmrg    int i;
32535c4bbdfSmrg    const float Loff = -0.0627;
32635c4bbdfSmrg    const float Coff = -0.502;
32735c4bbdfSmrg    float uvcosf, uvsinf;
32835c4bbdfSmrg    float yco;
32935c4bbdfSmrg    float uco[3], vco[3], off[3];
33035c4bbdfSmrg    float bright, cont, gamma;
33135c4bbdfSmrg    int ref = port_priv->transform_index;
33235c4bbdfSmrg    GLint uloc;
33335c4bbdfSmrg    GLfloat *v;
33435c4bbdfSmrg    char *vbo_offset;
33535c4bbdfSmrg    int dst_box_index;
33635c4bbdfSmrg
33735c4bbdfSmrg    if (!glamor_priv->xv_prog.prog)
338ed6184dfSmrg        glamor_init_xv_shader(screen, id);
33935c4bbdfSmrg
34035c4bbdfSmrg    cont = RTFContrast(port_priv->contrast);
34135c4bbdfSmrg    bright = RTFBrightness(port_priv->brightness);
34235c4bbdfSmrg    gamma = (float) port_priv->gamma / 1000.0;
34335c4bbdfSmrg    uvcosf = RTFSaturation(port_priv->saturation) * cos(RTFHue(port_priv->hue));
34435c4bbdfSmrg    uvsinf = RTFSaturation(port_priv->saturation) * sin(RTFHue(port_priv->hue));
34535c4bbdfSmrg/* overlay video also does pre-gamma contrast/sat adjust, should we? */
34635c4bbdfSmrg
34735c4bbdfSmrg    yco = trans[ref].RefLuma * cont;
34835c4bbdfSmrg    uco[0] = -trans[ref].RefRCr * uvsinf;
34935c4bbdfSmrg    uco[1] = trans[ref].RefGCb * uvcosf - trans[ref].RefGCr * uvsinf;
35035c4bbdfSmrg    uco[2] = trans[ref].RefBCb * uvcosf;
35135c4bbdfSmrg    vco[0] = trans[ref].RefRCr * uvcosf;
35235c4bbdfSmrg    vco[1] = trans[ref].RefGCb * uvsinf + trans[ref].RefGCr * uvcosf;
35335c4bbdfSmrg    vco[2] = trans[ref].RefBCb * uvsinf;
35435c4bbdfSmrg    off[0] = Loff * yco + Coff * (uco[0] + vco[0]) + bright;
35535c4bbdfSmrg    off[1] = Loff * yco + Coff * (uco[1] + vco[1]) + bright;
35635c4bbdfSmrg    off[2] = Loff * yco + Coff * (uco[2] + vco[2]) + bright;
35735c4bbdfSmrg    gamma = 1.0;
35835c4bbdfSmrg
35935c4bbdfSmrg    glamor_set_alu(screen, GXcopy);
36035c4bbdfSmrg
36135c4bbdfSmrg    for (i = 0; i < 3; i++) {
36235c4bbdfSmrg        if (port_priv->src_pix[i]) {
36335c4bbdfSmrg            src_pixmap_priv[i] =
36435c4bbdfSmrg                glamor_get_pixmap_private(port_priv->src_pix[i]);
36535c4bbdfSmrg            pixmap_priv_get_scale(src_pixmap_priv[i], &src_xscale[i],
36635c4bbdfSmrg                                  &src_yscale[i]);
367ed6184dfSmrg        } else {
368ed6184dfSmrg           src_pixmap_priv[i] = NULL;
36935c4bbdfSmrg        }
37035c4bbdfSmrg    }
37135c4bbdfSmrg    glamor_make_current(glamor_priv);
37235c4bbdfSmrg    glUseProgram(glamor_priv->xv_prog.prog);
37335c4bbdfSmrg
37435c4bbdfSmrg    uloc = glGetUniformLocation(glamor_priv->xv_prog.prog, "offsetyco");
37535c4bbdfSmrg    glUniform4f(uloc, off[0], off[1], off[2], yco);
37635c4bbdfSmrg    uloc = glGetUniformLocation(glamor_priv->xv_prog.prog, "ucogamma");
37735c4bbdfSmrg    glUniform4f(uloc, uco[0], uco[1], uco[2], gamma);
37835c4bbdfSmrg    uloc = glGetUniformLocation(glamor_priv->xv_prog.prog, "vco");
37935c4bbdfSmrg    glUniform4f(uloc, vco[0], vco[1], vco[2], 0);
38035c4bbdfSmrg
38135c4bbdfSmrg    glActiveTexture(GL_TEXTURE0);
38235c4bbdfSmrg    glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[0]->fbo->tex);
38335c4bbdfSmrg    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
38435c4bbdfSmrg    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
38535c4bbdfSmrg    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
38635c4bbdfSmrg    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
38735c4bbdfSmrg
38835c4bbdfSmrg    glActiveTexture(GL_TEXTURE1);
38935c4bbdfSmrg    glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[1]->fbo->tex);
39035c4bbdfSmrg    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
39135c4bbdfSmrg    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
39235c4bbdfSmrg    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
39335c4bbdfSmrg    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
39435c4bbdfSmrg
395ed6184dfSmrg    switch (id) {
396ed6184dfSmrg    case FOURCC_YV12:
397ed6184dfSmrg    case FOURCC_I420:
398ed6184dfSmrg        glActiveTexture(GL_TEXTURE2);
399ed6184dfSmrg        glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->fbo->tex);
400ed6184dfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
401ed6184dfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
402ed6184dfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
403ed6184dfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
404ed6184dfSmrg        break;
405ed6184dfSmrg    case FOURCC_NV12:
406ed6184dfSmrg        break;
407ed6184dfSmrg    default:
408ed6184dfSmrg        break;
409ed6184dfSmrg    }
41035c4bbdfSmrg
41135c4bbdfSmrg    glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
41235c4bbdfSmrg    glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
41335c4bbdfSmrg
41435c4bbdfSmrg    glEnable(GL_SCISSOR_TEST);
41535c4bbdfSmrg
41635c4bbdfSmrg    v = glamor_get_vbo_space(screen, 3 * 4 * sizeof(GLfloat), &vbo_offset);
41735c4bbdfSmrg
41835c4bbdfSmrg    /* Set up a single primitive covering the area being drawn.  We'll
41935c4bbdfSmrg     * clip it to port_priv->clip using GL scissors instead of just
42035c4bbdfSmrg     * emitting a GL_QUAD per box, because this way we hopefully avoid
421ed6184dfSmrg     * diagonal tearing between the two triangles used to rasterize a
42235c4bbdfSmrg     * GL_QUAD.
42335c4bbdfSmrg     */
42435c4bbdfSmrg    i = 0;
42535c4bbdfSmrg    v[i++] = port_priv->drw_x;
42635c4bbdfSmrg    v[i++] = port_priv->drw_y;
42735c4bbdfSmrg
42835c4bbdfSmrg    v[i++] = port_priv->drw_x + port_priv->dst_w * 2;
42935c4bbdfSmrg    v[i++] = port_priv->drw_y;
43035c4bbdfSmrg
43135c4bbdfSmrg    v[i++] = port_priv->drw_x;
43235c4bbdfSmrg    v[i++] = port_priv->drw_y + port_priv->dst_h * 2;
43335c4bbdfSmrg
43435c4bbdfSmrg    v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x);
43535c4bbdfSmrg    v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y);
43635c4bbdfSmrg
43735c4bbdfSmrg    v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x +
43835c4bbdfSmrg                              port_priv->src_w * 2);
43935c4bbdfSmrg    v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y);
44035c4bbdfSmrg
44135c4bbdfSmrg    v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x);
44235c4bbdfSmrg    v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y +
44335c4bbdfSmrg                              port_priv->src_h * 2);
44435c4bbdfSmrg
44535c4bbdfSmrg    glVertexAttribPointer(GLAMOR_VERTEX_POS, 2,
44635c4bbdfSmrg                          GL_FLOAT, GL_FALSE,
44735c4bbdfSmrg                          2 * sizeof(float), vbo_offset);
44835c4bbdfSmrg
44935c4bbdfSmrg    glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
45035c4bbdfSmrg                          GL_FLOAT, GL_FALSE,
45135c4bbdfSmrg                          2 * sizeof(float), vbo_offset + 6 * sizeof(GLfloat));
45235c4bbdfSmrg
45335c4bbdfSmrg    glamor_put_vbo_space(screen);
45435c4bbdfSmrg
45535c4bbdfSmrg    /* Now draw our big triangle, clipped to each of the clip boxes. */
45635c4bbdfSmrg    glamor_pixmap_loop(pixmap_priv, dst_box_index) {
45735c4bbdfSmrg        int dst_off_x, dst_off_y;
45835c4bbdfSmrg
45935c4bbdfSmrg        glamor_set_destination_drawable(port_priv->pDraw,
46035c4bbdfSmrg                                        dst_box_index,
46135c4bbdfSmrg                                        FALSE, FALSE,
46235c4bbdfSmrg                                        glamor_priv->xv_prog.matrix_uniform,
46335c4bbdfSmrg                                        &dst_off_x, &dst_off_y);
46435c4bbdfSmrg
46535c4bbdfSmrg        for (i = 0; i < nBox; i++) {
46635c4bbdfSmrg            int dstx, dsty, dstw, dsth;
46735c4bbdfSmrg
46835c4bbdfSmrg            dstx = box[i].x1 + dst_off_x;
46935c4bbdfSmrg            dsty = box[i].y1 + dst_off_y;
47035c4bbdfSmrg            dstw = box[i].x2 - box[i].x1;
47135c4bbdfSmrg            dsth = box[i].y2 - box[i].y1;
47235c4bbdfSmrg
47335c4bbdfSmrg            glScissor(dstx, dsty, dstw, dsth);
47435c4bbdfSmrg            glDrawArrays(GL_TRIANGLE_FAN, 0, 3);
47535c4bbdfSmrg        }
47635c4bbdfSmrg    }
47735c4bbdfSmrg    glDisable(GL_SCISSOR_TEST);
47835c4bbdfSmrg
47935c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
48035c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
48135c4bbdfSmrg
48235c4bbdfSmrg    DamageDamageRegion(port_priv->pDraw, &port_priv->clip);
48335c4bbdfSmrg
48435c4bbdfSmrg    glamor_xv_free_port_data(port_priv);
48535c4bbdfSmrg}
48635c4bbdfSmrg
48735c4bbdfSmrgint
48835c4bbdfSmrgglamor_xv_put_image(glamor_port_private *port_priv,
48935c4bbdfSmrg                    DrawablePtr pDrawable,
49035c4bbdfSmrg                    short src_x, short src_y,
49135c4bbdfSmrg                    short drw_x, short drw_y,
49235c4bbdfSmrg                    short src_w, short src_h,
49335c4bbdfSmrg                    short drw_w, short drw_h,
49435c4bbdfSmrg                    int id,
49535c4bbdfSmrg                    unsigned char *buf,
49635c4bbdfSmrg                    short width,
49735c4bbdfSmrg                    short height,
49835c4bbdfSmrg                    Bool sync,
49935c4bbdfSmrg                    RegionPtr clipBoxes)
50035c4bbdfSmrg{
50135c4bbdfSmrg    ScreenPtr pScreen = pDrawable->pScreen;
502ed6184dfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
50335c4bbdfSmrg    int srcPitch, srcPitch2;
50435c4bbdfSmrg    int top, nlines;
50535c4bbdfSmrg    int s2offset, s3offset, tmp;
50635c4bbdfSmrg    BoxRec full_box, half_box;
50735c4bbdfSmrg
50835c4bbdfSmrg    s2offset = s3offset = srcPitch2 = 0;
50935c4bbdfSmrg
51035c4bbdfSmrg    if (!port_priv->src_pix[0] ||
511ed6184dfSmrg        (width != port_priv->src_pix_w || height != port_priv->src_pix_h) ||
512ed6184dfSmrg        (port_priv->src_pix[2] && id == FOURCC_NV12) ||
513ed6184dfSmrg        (!port_priv->src_pix[2] && id != FOURCC_NV12)) {
51435c4bbdfSmrg        int i;
51535c4bbdfSmrg
516ed6184dfSmrg        if (glamor_priv->xv_prog.prog) {
517ed6184dfSmrg            glDeleteProgram(glamor_priv->xv_prog.prog);
518ed6184dfSmrg            glamor_priv->xv_prog.prog = 0;
519ed6184dfSmrg        }
520ed6184dfSmrg
52135c4bbdfSmrg        for (i = 0; i < 3; i++)
52235c4bbdfSmrg            if (port_priv->src_pix[i])
52335c4bbdfSmrg                glamor_destroy_pixmap(port_priv->src_pix[i]);
52435c4bbdfSmrg
52535c4bbdfSmrg        port_priv->src_pix[0] =
5261b5d61b8Smrg            glamor_create_pixmap(pScreen, width, height, 8,
5271b5d61b8Smrg                                 GLAMOR_CREATE_FBO_NO_FBO);
528ed6184dfSmrg
529ed6184dfSmrg        switch (id) {
530ed6184dfSmrg        case FOURCC_YV12:
531ed6184dfSmrg        case FOURCC_I420:
532ed6184dfSmrg            port_priv->src_pix[1] =
533ed6184dfSmrg                glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
534ed6184dfSmrg                                     GLAMOR_CREATE_FBO_NO_FBO);
535ed6184dfSmrg            port_priv->src_pix[2] =
536ed6184dfSmrg                glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
537ed6184dfSmrg                                     GLAMOR_CREATE_FBO_NO_FBO);
538ed6184dfSmrg            if (!port_priv->src_pix[2])
539ed6184dfSmrg                return BadAlloc;
540ed6184dfSmrg            break;
541ed6184dfSmrg        case FOURCC_NV12:
542ed6184dfSmrg            port_priv->src_pix[1] =
543ed6184dfSmrg                glamor_create_pixmap(pScreen, width >> 1, height >> 1, 16,
544ed6184dfSmrg                                     GLAMOR_CREATE_FBO_NO_FBO |
545ed6184dfSmrg                                     GLAMOR_CREATE_FORMAT_CBCR);
546ed6184dfSmrg            port_priv->src_pix[2] = NULL;
547ed6184dfSmrg            break;
548ed6184dfSmrg        default:
549ed6184dfSmrg            return BadMatch;
550ed6184dfSmrg        }
551ed6184dfSmrg
55235c4bbdfSmrg        port_priv->src_pix_w = width;
55335c4bbdfSmrg        port_priv->src_pix_h = height;
55435c4bbdfSmrg
555ed6184dfSmrg        if (!port_priv->src_pix[0] || !port_priv->src_pix[1])
55635c4bbdfSmrg            return BadAlloc;
55735c4bbdfSmrg    }
55835c4bbdfSmrg
55935c4bbdfSmrg    top = (src_y) & ~1;
56035c4bbdfSmrg    nlines = (src_y + src_h) - top;
56135c4bbdfSmrg
56235c4bbdfSmrg    switch (id) {
56335c4bbdfSmrg    case FOURCC_YV12:
56435c4bbdfSmrg    case FOURCC_I420:
56535c4bbdfSmrg        srcPitch = ALIGN(width, 4);
56635c4bbdfSmrg        srcPitch2 = ALIGN(width >> 1, 4);
56735c4bbdfSmrg        s2offset = srcPitch * height;
56835c4bbdfSmrg        s3offset = s2offset + (srcPitch2 * ((height + 1) >> 1));
56935c4bbdfSmrg        s2offset += ((top >> 1) * srcPitch2);
57035c4bbdfSmrg        s3offset += ((top >> 1) * srcPitch2);
57135c4bbdfSmrg        if (id == FOURCC_YV12) {
57235c4bbdfSmrg            tmp = s2offset;
57335c4bbdfSmrg            s2offset = s3offset;
57435c4bbdfSmrg            s3offset = tmp;
57535c4bbdfSmrg        }
57635c4bbdfSmrg
57735c4bbdfSmrg        full_box.x1 = 0;
57835c4bbdfSmrg        full_box.y1 = 0;
57935c4bbdfSmrg        full_box.x2 = width;
58035c4bbdfSmrg        full_box.y2 = nlines;
58135c4bbdfSmrg
58235c4bbdfSmrg        half_box.x1 = 0;
58335c4bbdfSmrg        half_box.y1 = 0;
58435c4bbdfSmrg        half_box.x2 = width >> 1;
58535c4bbdfSmrg        half_box.y2 = (nlines + 1) >> 1;
58635c4bbdfSmrg
58735c4bbdfSmrg        glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
58835c4bbdfSmrg                            0, 0, 0, 0,
58935c4bbdfSmrg                            buf + (top * srcPitch), srcPitch);
59035c4bbdfSmrg
59135c4bbdfSmrg        glamor_upload_boxes(port_priv->src_pix[1], &half_box, 1,
59235c4bbdfSmrg                            0, 0, 0, 0,
59335c4bbdfSmrg                            buf + s2offset, srcPitch2);
59435c4bbdfSmrg
59535c4bbdfSmrg        glamor_upload_boxes(port_priv->src_pix[2], &half_box, 1,
59635c4bbdfSmrg                            0, 0, 0, 0,
59735c4bbdfSmrg                            buf + s3offset, srcPitch2);
59835c4bbdfSmrg        break;
599ed6184dfSmrg    case FOURCC_NV12:
600ed6184dfSmrg        srcPitch = ALIGN(width, 4);
601ed6184dfSmrg        s2offset = srcPitch * height;
602ed6184dfSmrg        s2offset += ((top >> 1) * srcPitch);
603ed6184dfSmrg
604ed6184dfSmrg        full_box.x1 = 0;
605ed6184dfSmrg        full_box.y1 = 0;
606ed6184dfSmrg        full_box.x2 = width;
607ed6184dfSmrg        full_box.y2 = nlines;
608ed6184dfSmrg
609ed6184dfSmrg        half_box.x1 = 0;
610ed6184dfSmrg        half_box.y1 = 0;
611ed6184dfSmrg        half_box.x2 = width;
612ed6184dfSmrg        half_box.y2 = (nlines + 1) >> 1;
613ed6184dfSmrg
614ed6184dfSmrg        glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
615ed6184dfSmrg                            0, 0, 0, 0,
616ed6184dfSmrg                            buf + (top * srcPitch), srcPitch);
617ed6184dfSmrg
618ed6184dfSmrg        glamor_upload_boxes(port_priv->src_pix[1], &half_box, 1,
619ed6184dfSmrg                            0, 0, 0, 0,
620ed6184dfSmrg                            buf + s2offset, srcPitch);
621ed6184dfSmrg        break;
62235c4bbdfSmrg    default:
62335c4bbdfSmrg        return BadMatch;
62435c4bbdfSmrg    }
62535c4bbdfSmrg
62635c4bbdfSmrg    if (pDrawable->type == DRAWABLE_WINDOW)
62735c4bbdfSmrg        port_priv->pPixmap = pScreen->GetWindowPixmap((WindowPtr) pDrawable);
62835c4bbdfSmrg    else
62935c4bbdfSmrg        port_priv->pPixmap = (PixmapPtr) pDrawable;
63035c4bbdfSmrg
63135c4bbdfSmrg    RegionCopy(&port_priv->clip, clipBoxes);
63235c4bbdfSmrg
63335c4bbdfSmrg    port_priv->src_x = src_x;
63435c4bbdfSmrg    port_priv->src_y = src_y - top;
63535c4bbdfSmrg    port_priv->src_w = src_w;
63635c4bbdfSmrg    port_priv->src_h = src_h;
63735c4bbdfSmrg    port_priv->dst_w = drw_w;
63835c4bbdfSmrg    port_priv->dst_h = drw_h;
63935c4bbdfSmrg    port_priv->drw_x = drw_x;
64035c4bbdfSmrg    port_priv->drw_y = drw_y;
64135c4bbdfSmrg    port_priv->w = width;
64235c4bbdfSmrg    port_priv->h = height;
64335c4bbdfSmrg    port_priv->pDraw = pDrawable;
644ed6184dfSmrg    glamor_xv_render(port_priv, id);
64535c4bbdfSmrg    return Success;
64635c4bbdfSmrg}
64735c4bbdfSmrg
64835c4bbdfSmrgvoid
64935c4bbdfSmrgglamor_xv_init_port(glamor_port_private *port_priv)
65035c4bbdfSmrg{
65135c4bbdfSmrg    port_priv->brightness = 0;
65235c4bbdfSmrg    port_priv->contrast = 0;
65335c4bbdfSmrg    port_priv->saturation = 0;
65435c4bbdfSmrg    port_priv->hue = 0;
65535c4bbdfSmrg    port_priv->gamma = 1000;
65635c4bbdfSmrg    port_priv->transform_index = 0;
65735c4bbdfSmrg
65835c4bbdfSmrg    REGION_NULL(pScreen, &port_priv->clip);
65935c4bbdfSmrg}
66035c4bbdfSmrg
66135c4bbdfSmrgvoid
66235c4bbdfSmrgglamor_xv_core_init(ScreenPtr screen)
66335c4bbdfSmrg{
66435c4bbdfSmrg    glamorBrightness = MAKE_ATOM("XV_BRIGHTNESS");
66535c4bbdfSmrg    glamorContrast = MAKE_ATOM("XV_CONTRAST");
66635c4bbdfSmrg    glamorSaturation = MAKE_ATOM("XV_SATURATION");
66735c4bbdfSmrg    glamorHue = MAKE_ATOM("XV_HUE");
66835c4bbdfSmrg    glamorGamma = MAKE_ATOM("XV_GAMMA");
66935c4bbdfSmrg    glamorColorspace = MAKE_ATOM("XV_COLORSPACE");
67035c4bbdfSmrg}
671