Home | History | Annotate | Line # | Download | only in glamor
      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 (at) 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 */
     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_2 = {
     63     .name = "xv_planar_2",
     64 
     65     .source_name = "v_texcoord0",
     66     .vs_vars = ("in vec2 position;\n"
     67                 "in vec2 v_texcoord0;\n"
     68                 "out vec2 tcs;\n"),
     69     .vs_exec = (GLAMOR_POS(gl_Position, position)
     70                 "        tcs = v_texcoord0;\n"),
     71 
     72     .fs_vars = ("uniform sampler2D y_sampler;\n"
     73                 "uniform sampler2D u_sampler;\n"
     74                 "uniform vec4 offsetyco;\n"
     75                 "uniform vec4 ucogamma;\n"
     76                 "uniform vec4 vco;\n"
     77                 "in vec2 tcs;\n"),
     78     .fs_exec = (
     79                 "        float sample;\n"
     80                 "        vec2 sample_uv;\n"
     81                 "        vec4 temp1;\n"
     82                 "        sample = texture(y_sampler, tcs).w;\n"
     83                 "        temp1.xyz = offsetyco.www * vec3(sample) + offsetyco.xyz;\n"
     84                 "        sample_uv = texture(u_sampler, tcs).xy;\n"
     85                 "        temp1.xyz = ucogamma.xyz * vec3(sample_uv.x) + temp1.xyz;\n"
     86                 "        temp1.xyz = clamp(vco.xyz * vec3(sample_uv.y) + temp1.xyz, 0.0, 1.0);\n"
     87                 "        temp1.w = 1.0;\n"
     88                 "        frag_color = temp1;\n"
     89                 ),
     90 };
     91 
     92 static const glamor_facet glamor_facet_xv_planar_3 = {
     93     .name = "xv_planar_3",
     94 
     95     .source_name = "v_texcoord0",
     96     .vs_vars = ("in vec2 position;\n"
     97                 "in vec2 v_texcoord0;\n"
     98                 "out vec2 tcs;\n"),
     99     .vs_exec = (GLAMOR_POS(gl_Position, position)
    100                 "        tcs = v_texcoord0;\n"),
    101 
    102     .fs_vars = ("uniform sampler2D y_sampler;\n"
    103                 "uniform sampler2D u_sampler;\n"
    104                 "uniform sampler2D v_sampler;\n"
    105                 "uniform vec4 offsetyco;\n"
    106                 "uniform vec4 ucogamma;\n"
    107                 "uniform vec4 vco;\n"
    108                 "in vec2 tcs;\n"),
    109     .fs_exec = (
    110                 "        float sample;\n"
    111                 "        vec4 temp1;\n"
    112                 "        sample = texture(y_sampler, tcs).w;\n"
    113                 "        temp1.xyz = offsetyco.www * vec3(sample) + offsetyco.xyz;\n"
    114                 "        sample = texture(u_sampler, tcs).w;\n"
    115                 "        temp1.xyz = ucogamma.xyz * vec3(sample) + temp1.xyz;\n"
    116                 "        sample = texture(v_sampler, tcs).w;\n"
    117                 "        temp1.xyz = clamp(vco.xyz * vec3(sample) + temp1.xyz, 0.0, 1.0);\n"
    118                 "        temp1.w = 1.0;\n"
    119                 "        frag_color = temp1;\n"
    120                 ),
    121 };
    122 
    123 static const glamor_facet glamor_facet_xv_uyvy = {
    124     .name = "xv_uyvy",
    125 
    126     .source_name = "v_texcoord0",
    127     .vs_vars = ("in vec2 position;\n"
    128                 "in vec2 v_texcoord0;\n"
    129                 "out vec2 tcs;\n"),
    130     .vs_exec = (GLAMOR_POS(gl_Position, position)
    131                 "        tcs = v_texcoord0;\n"),
    132 
    133     .fs_vars = ("#ifdef GL_ES\n"
    134                 "precision highp float;\n"
    135                 "#endif\n"
    136                 "uniform sampler2D sampler;\n"
    137                 "uniform vec2 texelSize;\n"
    138                 "uniform vec4 offsetyco;\n"
    139                 "uniform vec4 ucogamma;\n"
    140                 "uniform vec4 vco;\n"
    141                 "in vec2 tcs;\n"
    142                 ),
    143     .fs_exec = (
    144                 "        vec4 temp1;\n"
    145                 "        vec2 xy = texture(sampler, tcs.st).xy;\n"
    146                 "        vec2 prev_xy = texture(sampler, vec2(tcs.s - texelSize.x, tcs.t)).xy;\n"
    147                 "        vec2 next_xy = texture(sampler, vec2(tcs.s + texelSize.x, tcs.t)).xy;\n"
    148                 "\n"
    149                 "        vec3 sample_yuv;\n"
    150                 "        int odd = int(mod(tcs.x / texelSize.x, 2.0));\n"
    151                 "        int even = 1 - odd;\n"
    152                 "        sample_yuv.yxz = float(even)*vec3(xy, next_xy.x) + float(odd)*vec3(prev_xy.x, xy.yx);\n"
    153                 "\n"
    154                 "        temp1.xyz = offsetyco.www * vec3(sample_yuv.x) + offsetyco.xyz;\n"
    155                 "        temp1.xyz = ucogamma.xyz * vec3(sample_yuv.y) + temp1.xyz;\n"
    156                 "        temp1.xyz = clamp(vco.xyz * vec3(sample_yuv.z) + temp1.xyz, 0.0, 1.0);\n"
    157                 "        temp1.w = 1.0;\n"
    158                 "        frag_color = temp1;\n"
    159                 ),
    160 };
    161 
    162 static const glamor_facet glamor_facet_xv_rgb_raw = {
    163     .name = "xv_rgb",
    164 
    165     .source_name = "v_texcoord0",
    166     .vs_vars = ("in vec2 position;\n"
    167                 "in vec2 v_texcoord0;\n"
    168                 "out vec2 tcs;\n"),
    169     .vs_exec = (GLAMOR_POS(gl_Position, position)
    170                 "        tcs = v_texcoord0;\n"),
    171 
    172     .fs_vars = ("uniform sampler2D sampler;\n"
    173                 "in vec2 tcs;\n"),
    174     .fs_exec = (
    175                 "        frag_color = texture2D(sampler, tcs);\n"
    176                 ),
    177 };
    178 
    179 #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
    180 
    181 XvAttributeRec glamor_xv_attributes[] = {
    182     {XvSettable | XvGettable, -1000, 1000, (char *)"XV_BRIGHTNESS"},
    183     {XvSettable | XvGettable, -1000, 1000, (char *)"XV_CONTRAST"},
    184     {XvSettable | XvGettable, -1000, 1000, (char *)"XV_SATURATION"},
    185     {XvSettable | XvGettable, -1000, 1000, (char *)"XV_HUE"},
    186     {XvSettable | XvGettable, 0, 1, (char *)"XV_COLORSPACE"},
    187     {0, 0, 0, NULL}
    188 };
    189 int glamor_xv_num_attributes = ARRAY_SIZE(glamor_xv_attributes) - 1;
    190 
    191 Atom glamorBrightness, glamorContrast, glamorSaturation, glamorHue,
    192     glamorColorspace, glamorGamma;
    193 
    194 XvImageRec glamor_xv_images[] = {
    195     XVIMAGE_YV12,
    196     XVIMAGE_I420,
    197     XVIMAGE_NV12,
    198     XVIMAGE_UYVY,
    199     XVIMAGE_RGB32,
    200     XVIMAGE_RGB565,
    201 };
    202 int glamor_xv_num_images = ARRAY_SIZE(glamor_xv_images);
    203 
    204 static void
    205 glamor_init_xv_shader(ScreenPtr screen, glamor_port_private *port_priv, int id)
    206 {
    207     GLint sampler_loc;
    208     const glamor_facet *glamor_facet_xv_planar = NULL;
    209 
    210     switch (id) {
    211     case FOURCC_YV12:
    212     case FOURCC_I420:
    213         glamor_facet_xv_planar = &glamor_facet_xv_planar_3;
    214         break;
    215     case FOURCC_NV12:
    216         glamor_facet_xv_planar = &glamor_facet_xv_planar_2;
    217         break;
    218     case FOURCC_UYVY:
    219         glamor_facet_xv_planar = &glamor_facet_xv_uyvy;
    220         break;
    221     case FOURCC_RGBA32:
    222     case FOURCC_RGB565:
    223         glamor_facet_xv_planar = &glamor_facet_xv_rgb_raw;
    224         break;
    225     default:
    226         break;
    227     }
    228 
    229     glamor_build_program(screen,
    230                          &port_priv->xv_prog,
    231                          glamor_facet_xv_planar, NULL, NULL, NULL);
    232 
    233     glUseProgram(port_priv->xv_prog.prog);
    234 
    235     switch (id) {
    236     case FOURCC_YV12:
    237     case FOURCC_I420:
    238         sampler_loc = glGetUniformLocation(port_priv->xv_prog.prog, "y_sampler");
    239         glUniform1i(sampler_loc, 0);
    240         sampler_loc = glGetUniformLocation(port_priv->xv_prog.prog, "u_sampler");
    241         glUniform1i(sampler_loc, 1);
    242         sampler_loc = glGetUniformLocation(port_priv->xv_prog.prog, "v_sampler");
    243         glUniform1i(sampler_loc, 2);
    244         break;
    245     case FOURCC_NV12:
    246         sampler_loc = glGetUniformLocation(port_priv->xv_prog.prog, "y_sampler");
    247         glUniform1i(sampler_loc, 0);
    248         sampler_loc = glGetUniformLocation(port_priv->xv_prog.prog, "u_sampler");
    249         glUniform1i(sampler_loc, 1);
    250         break;
    251     case FOURCC_UYVY:
    252     case FOURCC_RGBA32:
    253     case FOURCC_RGB565:
    254         sampler_loc = glGetUniformLocation(port_priv->xv_prog.prog, "sampler");
    255         glUniform1i(sampler_loc, 0);
    256         break;
    257     default:
    258         break;
    259     }
    260 
    261 }
    262 
    263 #define ClipValue(v,min,max) ((v) < (min) ? (min) : (v) > (max) ? (max) : (v))
    264 
    265 void
    266 glamor_xv_stop_video(glamor_port_private *port_priv)
    267 {
    268 }
    269 
    270 static void
    271 glamor_xv_free_port_data(glamor_port_private *port_priv)
    272 {
    273     int i;
    274 
    275     for (i = 0; i < 3; i++) {
    276         if (port_priv->src_pix[i]) {
    277             glamor_destroy_pixmap(port_priv->src_pix[i]);
    278             port_priv->src_pix[i] = NULL;
    279         }
    280     }
    281     RegionUninit(&port_priv->clip);
    282     RegionNull(&port_priv->clip);
    283 }
    284 
    285 int
    286 glamor_xv_set_port_attribute(glamor_port_private *port_priv,
    287                              Atom attribute, INT32 value)
    288 {
    289     if (attribute == glamorBrightness)
    290         port_priv->brightness = ClipValue(value, -1000, 1000);
    291     else if (attribute == glamorHue)
    292         port_priv->hue = ClipValue(value, -1000, 1000);
    293     else if (attribute == glamorContrast)
    294         port_priv->contrast = ClipValue(value, -1000, 1000);
    295     else if (attribute == glamorSaturation)
    296         port_priv->saturation = ClipValue(value, -1000, 1000);
    297     else if (attribute == glamorGamma)
    298         port_priv->gamma = ClipValue(value, 100, 10000);
    299     else if (attribute == glamorColorspace)
    300         port_priv->transform_index = ClipValue(value, 0, 1);
    301     else
    302         return BadMatch;
    303     return Success;
    304 }
    305 
    306 int
    307 glamor_xv_get_port_attribute(glamor_port_private *port_priv,
    308                              Atom attribute, INT32 *value)
    309 {
    310     if (attribute == glamorBrightness)
    311         *value = port_priv->brightness;
    312     else if (attribute == glamorHue)
    313         *value = port_priv->hue;
    314     else if (attribute == glamorContrast)
    315         *value = port_priv->contrast;
    316     else if (attribute == glamorSaturation)
    317         *value = port_priv->saturation;
    318     else if (attribute == glamorGamma)
    319         *value = port_priv->gamma;
    320     else if (attribute == glamorColorspace)
    321         *value = port_priv->transform_index;
    322     else
    323         return BadMatch;
    324 
    325     return Success;
    326 }
    327 
    328 int
    329 glamor_xv_query_image_attributes(int id,
    330                                  unsigned short *w, unsigned short *h,
    331                                  int *pitches, int *offsets)
    332 {
    333     int size = 0, tmp;
    334 
    335     if (offsets)
    336         offsets[0] = 0;
    337     switch (id) {
    338     case FOURCC_YV12:
    339     case FOURCC_I420:
    340         *w = ALIGN(*w, 2);
    341         *h = ALIGN(*h, 2);
    342         size = ALIGN(*w, 4);
    343         if (pitches)
    344             pitches[0] = size;
    345         size *= *h;
    346         if (offsets)
    347             offsets[1] = size;
    348         tmp = ALIGN(*w >> 1, 4);
    349         if (pitches)
    350             pitches[1] = pitches[2] = tmp;
    351         tmp *= (*h >> 1);
    352         size += tmp;
    353         if (offsets)
    354             offsets[2] = size;
    355         size += tmp;
    356         break;
    357     case FOURCC_NV12:
    358         *w = ALIGN(*w, 2);
    359         *h = ALIGN(*h, 2);
    360         size = ALIGN(*w, 4);
    361         if (pitches)
    362             pitches[0] = size;
    363         size *= *h;
    364         if (offsets)
    365             offsets[1] = size;
    366         tmp = ALIGN(*w, 4);
    367         if (pitches)
    368             pitches[1] = tmp;
    369         tmp *= (*h >> 1);
    370         size += tmp;
    371         break;
    372     case FOURCC_RGBA32:
    373         size = *w * 4;
    374         if(pitches)
    375             pitches[0] = size;
    376         if(offsets)
    377             offsets[0] = 0;
    378         size *= *h;
    379         break;
    380     case FOURCC_UYVY:
    381         /* UYVU is single-plane really, all tranformation is processed inside a shader */
    382         size = ALIGN(*w, 2) * 2;
    383         if (pitches)
    384             pitches[0] = size;
    385         if (offsets)
    386             offsets[0] = 0;
    387         size *= *h;
    388         break;
    389     case FOURCC_RGB565:
    390         size = *w * 2;
    391         if (pitches)
    392             pitches[0] = size;
    393         if (offsets)
    394             offsets[0] = 0;
    395         size *= *h;
    396         break;
    397     }
    398     return size;
    399 }
    400 
    401 /* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces
    402    note the difference to the parameters used in overlay are due
    403    to 10bit vs. float calcs */
    404 static REF_TRANSFORM trans[2] = {
    405     {1.1643, 0.0, 1.5960, -0.3918, -0.8129, 2.0172, 0.0},       /* BT.601 */
    406     {1.1643, 0.0, 1.7927, -0.2132, -0.5329, 2.1124, 0.0}        /* BT.709 */
    407 };
    408 
    409 void
    410 glamor_xv_render(glamor_port_private *port_priv, int id)
    411 {
    412     ScreenPtr screen = port_priv->pPixmap->drawable.pScreen;
    413     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    414     PixmapPtr pixmap = port_priv->pPixmap;
    415     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
    416     glamor_pixmap_private *src_pixmap_priv[3];
    417     BoxPtr box = REGION_RECTS(&port_priv->clip);
    418     int nBox = REGION_NUM_RECTS(&port_priv->clip);
    419     GLfloat src_xscale[3], src_yscale[3];
    420     int i;
    421     const float Loff = -0.0627;
    422     const float Coff = -0.502;
    423     float uvcosf, uvsinf;
    424     float yco;
    425     float uco[3], vco[3], off[3];
    426     float bright, cont, gamma;
    427     int ref = port_priv->transform_index;
    428     GLint uloc;
    429     GLfloat *v;
    430     char *vbo_offset;
    431     int dst_box_index;
    432 
    433     if (!port_priv->xv_prog.prog)
    434         glamor_init_xv_shader(screen, port_priv, id);
    435 
    436     cont = RTFContrast(port_priv->contrast);
    437     bright = RTFBrightness(port_priv->brightness);
    438     gamma = (float) port_priv->gamma / 1000.0;
    439     uvcosf = RTFSaturation(port_priv->saturation) * cos(RTFHue(port_priv->hue));
    440     uvsinf = RTFSaturation(port_priv->saturation) * sin(RTFHue(port_priv->hue));
    441 /* overlay video also does pre-gamma contrast/sat adjust, should we? */
    442 
    443     yco = trans[ref].RefLuma * cont;
    444     uco[0] = -trans[ref].RefRCr * uvsinf;
    445     uco[1] = trans[ref].RefGCb * uvcosf - trans[ref].RefGCr * uvsinf;
    446     uco[2] = trans[ref].RefBCb * uvcosf;
    447     vco[0] = trans[ref].RefRCr * uvcosf;
    448     vco[1] = trans[ref].RefGCb * uvsinf + trans[ref].RefGCr * uvcosf;
    449     vco[2] = trans[ref].RefBCb * uvsinf;
    450     off[0] = Loff * yco + Coff * (uco[0] + vco[0]) + bright;
    451     off[1] = Loff * yco + Coff * (uco[1] + vco[1]) + bright;
    452     off[2] = Loff * yco + Coff * (uco[2] + vco[2]) + bright;
    453     gamma = 1.0;
    454 
    455     glamor_set_alu(screen, GXcopy);
    456 
    457     for (i = 0; i < 3; i++) {
    458         if (port_priv->src_pix[i]) {
    459             src_pixmap_priv[i] =
    460                 glamor_get_pixmap_private(port_priv->src_pix[i]);
    461             pixmap_priv_get_scale(src_pixmap_priv[i], &src_xscale[i],
    462                                   &src_yscale[i]);
    463         } else {
    464            src_pixmap_priv[i] = NULL;
    465         }
    466     }
    467     glamor_make_current(glamor_priv);
    468     glUseProgram(port_priv->xv_prog.prog);
    469 
    470     uloc = glGetUniformLocation(port_priv->xv_prog.prog, "offsetyco");
    471     glUniform4f(uloc, off[0], off[1], off[2], yco);
    472     uloc = glGetUniformLocation(port_priv->xv_prog.prog, "ucogamma");
    473     glUniform4f(uloc, uco[0], uco[1], uco[2], gamma);
    474     uloc = glGetUniformLocation(port_priv->xv_prog.prog, "vco");
    475     glUniform4f(uloc, vco[0], vco[1], vco[2], 0);
    476 
    477     switch (id) {
    478     case FOURCC_YV12:
    479     case FOURCC_I420:
    480         glActiveTexture(GL_TEXTURE0);
    481         glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[0]->fbo->tex);
    482         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    483         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    484         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    485         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    486 
    487         glActiveTexture(GL_TEXTURE1);
    488         glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[1]->fbo->tex);
    489         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    490         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    491         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    492         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    493 
    494         glActiveTexture(GL_TEXTURE2);
    495         glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->fbo->tex);
    496         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    497         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    498         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    499         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    500         break;
    501     case FOURCC_NV12:
    502         glActiveTexture(GL_TEXTURE0);
    503         glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[0]->fbo->tex);
    504         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    505         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    506         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    507         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    508 
    509         glActiveTexture(GL_TEXTURE1);
    510         glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[1]->fbo->tex);
    511         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    512         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    513         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    514         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    515         break;
    516     case FOURCC_UYVY:
    517         uloc = glGetUniformLocation(port_priv->xv_prog.prog, "texelSize");
    518         glUniform2f(uloc, 1.0 / port_priv->w, 1.0 / port_priv->h);
    519 
    520         glActiveTexture(GL_TEXTURE0);
    521         glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[0]->fbo->tex);
    522         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    523         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    524         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    525         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    526         break;
    527     case FOURCC_RGBA32:
    528     case FOURCC_RGB565:
    529         glActiveTexture(GL_TEXTURE0);
    530         glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[0]->fbo->tex);
    531         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    532         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    533         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    534         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    535         break;
    536     default:
    537         break;
    538     }
    539 
    540     glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
    541     glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
    542 
    543     glEnable(GL_SCISSOR_TEST);
    544 
    545     v = glamor_get_vbo_space(screen, 3 * 4 * sizeof(GLfloat), &vbo_offset);
    546 
    547     /* Set up a single primitive covering the area being drawn.  We'll
    548      * clip it to port_priv->clip using GL scissors instead of just
    549      * emitting a GL_QUAD per box, because this way we hopefully avoid
    550      * diagonal tearing between the two triangles used to rasterize a
    551      * GL_QUAD.
    552      */
    553     i = 0;
    554     v[i++] = port_priv->drw_x;
    555     v[i++] = port_priv->drw_y;
    556 
    557     v[i++] = port_priv->drw_x + port_priv->dst_w * 2;
    558     v[i++] = port_priv->drw_y;
    559 
    560     v[i++] = port_priv->drw_x;
    561     v[i++] = port_priv->drw_y + port_priv->dst_h * 2;
    562 
    563     v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x);
    564     v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y);
    565 
    566     v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x +
    567                               port_priv->src_w * 2);
    568     v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y);
    569 
    570     v[i++] = t_from_x_coord_x(src_xscale[0], port_priv->src_x);
    571     v[i++] = t_from_x_coord_y(src_yscale[0], port_priv->src_y +
    572                               port_priv->src_h * 2);
    573 
    574     glVertexAttribPointer(GLAMOR_VERTEX_POS, 2,
    575                           GL_FLOAT, GL_FALSE,
    576                           2 * sizeof(float), vbo_offset);
    577 
    578     glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
    579                           GL_FLOAT, GL_FALSE,
    580                           2 * sizeof(float), vbo_offset + 6 * sizeof(GLfloat));
    581 
    582     glamor_put_vbo_space(screen);
    583 
    584     /* Now draw our big triangle, clipped to each of the clip boxes. */
    585     glamor_pixmap_loop(pixmap_priv, dst_box_index) {
    586         int dst_off_x, dst_off_y;
    587 
    588         glamor_set_destination_drawable(port_priv->pDraw,
    589                                         dst_box_index,
    590                                         FALSE, FALSE,
    591                                         port_priv->xv_prog.matrix_uniform,
    592                                         &dst_off_x, &dst_off_y);
    593 
    594         for (i = 0; i < nBox; i++) {
    595             int dstx, dsty, dstw, dsth;
    596 
    597             dstx = box[i].x1 + dst_off_x;
    598             dsty = box[i].y1 + dst_off_y;
    599             dstw = box[i].x2 - box[i].x1;
    600             dsth = box[i].y2 - box[i].y1;
    601 
    602             glScissor(dstx, dsty, dstw, dsth);
    603             glDrawArrays(GL_TRIANGLE_FAN, 0, 3);
    604         }
    605     }
    606     glDisable(GL_SCISSOR_TEST);
    607 
    608     glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
    609     glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
    610 
    611     DamageDamageRegion(port_priv->pDraw, &port_priv->clip);
    612 }
    613 
    614 static Bool
    615 glamor_xv_can_reuse_port(glamor_port_private *port_priv, int id, short w, short h)
    616 {
    617     int ret = TRUE;
    618 
    619     if (port_priv->prev_fmt != id)
    620         ret = FALSE;
    621 
    622     if (w != port_priv->src_pix_w || h != port_priv->src_pix_h)
    623         ret = FALSE;
    624 
    625     if (!port_priv->src_pix[0])
    626         ret = FALSE;
    627 
    628     port_priv->prev_fmt = id;
    629 
    630     return ret;
    631 }
    632 
    633 int
    634 glamor_xv_put_image(glamor_port_private *port_priv,
    635                     DrawablePtr pDrawable,
    636                     short src_x, short src_y,
    637                     short drw_x, short drw_y,
    638                     short src_w, short src_h,
    639                     short drw_w, short drw_h,
    640                     int id,
    641                     unsigned char *buf,
    642                     short width,
    643                     short height,
    644                     Bool sync,
    645                     RegionPtr clipBoxes)
    646 {
    647     ScreenPtr pScreen = pDrawable->pScreen;
    648     int srcPitch, srcPitch2;
    649     int top, nlines;
    650     int s2offset, s3offset, tmp;
    651     BoxRec full_box, half_box;
    652 
    653     s2offset = s3offset = srcPitch2 = 0;
    654 
    655     if (!glamor_xv_can_reuse_port(port_priv, id, width, height)) {
    656         int i;
    657 
    658         glamor_xv_free_port_data(port_priv);
    659 
    660         if (port_priv->xv_prog.prog) {
    661             glDeleteProgram(port_priv->xv_prog.prog);
    662             port_priv->xv_prog.prog = 0;
    663         }
    664 
    665         for (i = 0; i < 3; i++)
    666             if (port_priv->src_pix[i])
    667                 glamor_destroy_pixmap(port_priv->src_pix[i]);
    668 
    669         switch (id) {
    670         case FOURCC_YV12:
    671         case FOURCC_I420:
    672             port_priv->src_pix[0] =
    673                 glamor_create_pixmap(pScreen, width, height, 8,
    674                                      GLAMOR_CREATE_FBO_NO_FBO);
    675 
    676             port_priv->src_pix[1] =
    677                 glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
    678                                      GLAMOR_CREATE_FBO_NO_FBO);
    679             port_priv->src_pix[2] =
    680                 glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
    681                                      GLAMOR_CREATE_FBO_NO_FBO);
    682             if (!port_priv->src_pix[1] || !port_priv->src_pix[2])
    683                 return BadAlloc;
    684             break;
    685         case FOURCC_NV12:
    686             port_priv->src_pix[0] =
    687                 glamor_create_pixmap(pScreen, width, height, 8,
    688                                      GLAMOR_CREATE_FBO_NO_FBO);
    689             port_priv->src_pix[1] =
    690                 glamor_create_pixmap(pScreen, width >> 1, height >> 1, 16,
    691                                      GLAMOR_CREATE_FBO_NO_FBO |
    692                                      GLAMOR_CREATE_FORMAT_CBCR);
    693             port_priv->src_pix[2] = NULL;
    694 
    695             if (!port_priv->src_pix[1])
    696                 return BadAlloc;
    697             break;
    698         case FOURCC_RGBA32:
    699             port_priv->src_pix[0] =
    700             glamor_create_pixmap(pScreen, width, height, 32,
    701                                      GLAMOR_CREATE_FBO_NO_FBO);
    702             port_priv->src_pix[1] = NULL;
    703             port_priv->src_pix[2] = NULL;
    704             break;
    705         case FOURCC_RGB565:
    706             port_priv->src_pix[0] =
    707             glamor_create_pixmap(pScreen, width, height, 16,
    708                                      GLAMOR_CREATE_FBO_NO_FBO);
    709             port_priv->src_pix[1] = NULL;
    710             port_priv->src_pix[2] = NULL;
    711             break;
    712         case FOURCC_UYVY:
    713             port_priv->src_pix[0] =
    714                 glamor_create_pixmap(pScreen, width, height, 32,
    715                                      GLAMOR_CREATE_FBO_NO_FBO |
    716                                      GLAMOR_CREATE_FORMAT_CBCR);
    717             port_priv->src_pix[1] = NULL;
    718             port_priv->src_pix[2] = NULL;
    719             break;
    720         default:
    721             return BadMatch;
    722         }
    723 
    724         port_priv->src_pix_w = width;
    725         port_priv->src_pix_h = height;
    726 
    727         if (!port_priv->src_pix[0])
    728             return BadAlloc;
    729     }
    730 
    731     top = (src_y) & ~1;
    732     nlines = (src_y + src_h) - top;
    733 
    734     switch (id) {
    735     case FOURCC_YV12:
    736     case FOURCC_I420:
    737         srcPitch = ALIGN(width, 4);
    738         srcPitch2 = ALIGN(width >> 1, 4);
    739         s2offset = srcPitch * height;
    740         s3offset = s2offset + (srcPitch2 * ((height + 1) >> 1));
    741         s2offset += ((top >> 1) * srcPitch2);
    742         s3offset += ((top >> 1) * srcPitch2);
    743         if (id == FOURCC_YV12) {
    744             tmp = s2offset;
    745             s2offset = s3offset;
    746             s3offset = tmp;
    747         }
    748 
    749         full_box.x1 = 0;
    750         full_box.y1 = 0;
    751         full_box.x2 = width;
    752         full_box.y2 = nlines;
    753 
    754         half_box.x1 = 0;
    755         half_box.y1 = 0;
    756         half_box.x2 = width >> 1;
    757         half_box.y2 = (nlines + 1) >> 1;
    758 
    759         glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
    760                             0, 0, 0, 0,
    761                             buf + (top * srcPitch), srcPitch);
    762 
    763         glamor_upload_boxes(port_priv->src_pix[1], &half_box, 1,
    764                             0, 0, 0, 0,
    765                             buf + s2offset, srcPitch2);
    766 
    767         glamor_upload_boxes(port_priv->src_pix[2], &half_box, 1,
    768                             0, 0, 0, 0,
    769                             buf + s3offset, srcPitch2);
    770         break;
    771     case FOURCC_NV12:
    772         srcPitch = ALIGN(width, 4);
    773         s2offset = srcPitch * height;
    774         s2offset += ((top >> 1) * srcPitch);
    775 
    776         full_box.x1 = 0;
    777         full_box.y1 = 0;
    778         full_box.x2 = width;
    779         full_box.y2 = nlines;
    780 
    781         half_box.x1 = 0;
    782         half_box.y1 = 0;
    783         half_box.x2 = width;
    784         half_box.y2 = (nlines + 1) >> 1;
    785 
    786         glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
    787                             0, 0, 0, 0,
    788                             buf + (top * srcPitch), srcPitch);
    789 
    790         glamor_upload_boxes(port_priv->src_pix[1], &half_box, 1,
    791                             0, 0, 0, 0,
    792                             buf + s2offset, srcPitch);
    793         break;
    794     case FOURCC_UYVY:
    795         srcPitch = ALIGN(width, 2) * 2;
    796         full_box.x1 = 0;
    797         full_box.y1 = 0;
    798         full_box.x2 = width;
    799         full_box.y2 = height;
    800         glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
    801                             0, 0, 0, 0,
    802                             buf, srcPitch);
    803         break;
    804     case FOURCC_RGB565:
    805         srcPitch = width * 2;
    806         full_box.x1 = 0;
    807         full_box.y1 = 0;
    808         full_box.x2 = width;
    809         full_box.y2 = height;
    810         glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
    811                             0, 0, 0, 0,
    812                             buf, srcPitch);
    813         break;
    814     case FOURCC_RGBA32:
    815         srcPitch = width * 4;
    816         full_box.x1 = 0;
    817         full_box.y1 = 0;
    818         full_box.x2 = width;
    819         full_box.y2 = height;
    820         glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
    821                             0, 0, 0, 0,
    822                             buf, srcPitch);
    823         break;
    824     default:
    825         return BadMatch;
    826     }
    827 
    828     if (pDrawable->type == DRAWABLE_WINDOW)
    829         port_priv->pPixmap = pScreen->GetWindowPixmap((WindowPtr) pDrawable);
    830     else
    831         port_priv->pPixmap = (PixmapPtr) pDrawable;
    832 
    833     RegionCopy(&port_priv->clip, clipBoxes);
    834 
    835     port_priv->src_x = src_x;
    836     port_priv->src_y = src_y - top;
    837     port_priv->src_w = src_w;
    838     port_priv->src_h = src_h;
    839     port_priv->dst_w = drw_w;
    840     port_priv->dst_h = drw_h;
    841     port_priv->drw_x = drw_x;
    842     port_priv->drw_y = drw_y;
    843     port_priv->w = width;
    844     port_priv->h = height;
    845     port_priv->pDraw = pDrawable;
    846     glamor_xv_render(port_priv, id);
    847     return Success;
    848 }
    849 
    850 void
    851 glamor_xv_init_port(glamor_port_private *port_priv)
    852 {
    853     port_priv->brightness = 0;
    854     port_priv->contrast = 0;
    855     port_priv->saturation = 0;
    856     port_priv->hue = 0;
    857     port_priv->gamma = 1000;
    858     port_priv->transform_index = 0;
    859 
    860     REGION_NULL(pScreen, &port_priv->clip);
    861 }
    862 
    863 void
    864 glamor_xv_core_init(ScreenPtr screen)
    865 {
    866     glamorBrightness = MAKE_ATOM("XV_BRIGHTNESS");
    867     glamorContrast = MAKE_ATOM("XV_CONTRAST");
    868     glamorSaturation = MAKE_ATOM("XV_SATURATION");
    869     glamorHue = MAKE_ATOM("XV_HUE");
    870     glamorGamma = MAKE_ATOM("XV_GAMMA");
    871     glamorColorspace = MAKE_ATOM("XV_COLORSPACE");
    872 }
    873