From e3d1d4e3caaab8076eba89b58d037d24e203e506 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 23 Sep 2013 06:42:24 +0100 Subject: [PATCH] glamor: add initial Xv support This does YV12 and I420 for now, not sure if we can do packed without a GL extension. Signed-off-by: Dave Airlie Reviewed-by: Alex Deucher --- glamor/Makefile.am | 1 + glamor/glamor.c | 6 + glamor/glamor.h | 4 +- glamor/glamor_priv.h | 27 ++ glamor/glamor_xv.c | 646 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 683 insertions(+), 1 deletion(-) create mode 100644 glamor/glamor_xv.c diff --git a/glamor/Makefile.am b/glamor/Makefile.am index c1759c6c5..50cfe97ea 100644 --- a/glamor/Makefile.am +++ b/glamor/Makefile.am @@ -53,6 +53,7 @@ libglamor_la_SOURCES = \ glamor_gl_dispatch.c\ glamor_fbo.c\ glamor_compositerects.c\ + glamor_xv.c\ glamor_utils.h\ glamor.h\ glapi.h diff --git a/glamor/glamor.c b/glamor/glamor.c index d51811e5d..7637f3bfe 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -427,6 +427,9 @@ glamor_init(ScreenPtr screen, unsigned int flags) glamor_init_finish_access_shaders(screen); #ifdef GLAMOR_GRADIENT_SHADER glamor_init_gradient_shader(screen); +#endif +#ifdef GLAMOR_XV + glamor_init_xv_shader(screen); #endif glamor_pixmap_init(screen); @@ -447,6 +450,9 @@ glamor_release_screen_priv(ScreenPtr screen) glamor_screen_private *glamor_priv; glamor_priv = glamor_get_screen_private(screen); +#ifdef GLAMOR_XV + glamor_fini_xv_shader(screen); +#endif #ifdef RENDER glamor_fini_composite_shaders(screen); #endif diff --git a/glamor/glamor.h b/glamor/glamor.h index bafd543b5..c143c4dcb 100644 --- a/glamor/glamor.h +++ b/glamor/glamor.h @@ -37,7 +37,7 @@ #include #include #include - +#include /* * glamor_pixmap_type : glamor pixmap's type. * @MEMORY: pixmap is in memory. @@ -348,4 +348,6 @@ extern _X_EXPORT Bool glamor_poly_line_nf(DrawablePtr pDrawable, GCPtr pGC, int extern _X_EXPORT Bool glamor_poly_lines_nf(DrawablePtr drawable, GCPtr gc, int mode, int n, DDXPointPtr points); +extern _X_EXPORT XF86VideoAdaptorPtr glamor_xv_init(ScreenPtr pScreen, int num_texture_ports); + #endif /* GLAMOR_H */ diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h index 6e80ebdf9..ffdd7fdd0 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -304,6 +304,9 @@ typedef struct glamor_screen_private { int state; unsigned int render_idle_cnt; ScreenPtr screen; + + /* xv */ + GLint xv_prog; } glamor_screen_private; typedef enum glamor_access { @@ -993,6 +996,30 @@ glamor_composite_rectangles(CARD8 op, int num_rects, xRectangle *rects); +/* glamor_xv */ +typedef struct { + uint32_t transform_index; + uint32_t gamma; /* gamma value x 1000 */ + int brightness; + int saturation; + int hue; + int contrast; + + DrawablePtr pDraw; + PixmapPtr pPixmap; + uint32_t src_pitch; + uint8_t *src_addr; + int src_w, src_h, dst_w, dst_h; + int src_x, src_y, drw_x, drw_y; + int w, h; + RegionRec clip; + PixmapPtr src_pix[3]; /* y, u, v for planar */ + int src_pix_w, src_pix_h; +} glamor_port_private; + +void glamor_init_xv_shader(ScreenPtr screen); +void glamor_fini_xv_shader(ScreenPtr screen); + #include"glamor_utils.h" /* Dynamic pixmap upload to texture if needed. diff --git a/glamor/glamor_xv.c b/glamor/glamor_xv.c new file mode 100644 index 000000000..1d77eaa65 --- /dev/null +++ b/glamor/glamor_xv.c @@ -0,0 +1,646 @@ +/* + * Copyright © 2013 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Dave Airlie + * + * some code is derived from the xf86-video-ati radeon driver, mainly + * the calculations. + */ + +/** @file glamor_xv.c + * + * Xv acceleration implementation + */ + +#include "glamor_priv.h" + +#ifdef GLAMOR_XV +#include "xf86xv.h" +#include +#include "fourcc.h" +/* Reference color space transform data */ +typedef struct tagREF_TRANSFORM +{ + float RefLuma; + float RefRCb; + float RefRCr; + float RefGCb; + float RefGCr; + float RefBCb; + float RefBCr; +} REF_TRANSFORM; + +#define RTFSaturation(a) (1.0 + ((a)*1.0)/1000.0) +#define RTFBrightness(a) (((a)*1.0)/2000.0) +#define RTFIntensity(a) (((a)*1.0)/2000.0) +#define RTFContrast(a) (1.0 + ((a)*1.0)/1000.0) +#define RTFHue(a) (((a)*3.1416)/1000.0) + +static const char *xv_vs= "attribute vec4 v_position;\n" + "attribute vec4 v_texcoord0;\n" + "varying vec2 tcs;\n" + "void main()\n" "{\n" " gl_Position = v_position;\n" + "tcs = v_texcoord0.xy;\n" + "}\n"; + +static const char *xv_ps = GLAMOR_DEFAULT_PRECISION + "uniform sampler2D y_sampler;\n" + "uniform sampler2D u_sampler;\n" + "uniform sampler2D v_sampler;\n" + "uniform vec4 offsetyco;\n" + "uniform vec4 ucogamma;\n" + "uniform vec4 vco;\n" + "varying vec2 tcs;\n" + "float sample;\n" + "vec4 temp1;\n" + "void main()\n" "{\n" + "sample = texture2D(y_sampler, tcs).w;\n" + "temp1.xyz = offsetyco.www * vec3(sample) + offsetyco.xyz;\n" + "sample = texture2D(u_sampler, tcs).w;\n" + "temp1.xyz = ucogamma.xyz * vec3(sample) + temp1.xyz;\n" + "sample = texture2D(v_sampler, tcs).w;\n" + "temp1.xyz = clamp(vco.xyz * vec3(sample) + temp1.xyz, 0.0, 1.0);\n" + "temp1.w = 1.0;\n" + "gl_FragColor = temp1;\n" + "}\n"; + +void +glamor_init_xv_shader(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv; + glamor_gl_dispatch *dispatch; + GLint fs_prog, vs_prog; + GLint sampler_loc; + + glamor_priv = glamor_get_screen_private(screen); + dispatch = glamor_get_dispatch(glamor_priv); + glamor_priv->xv_prog = dispatch->glCreateProgram(); + + vs_prog = glamor_compile_glsl_prog(dispatch, GL_VERTEX_SHADER, xv_vs); + fs_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER, xv_ps); + dispatch->glAttachShader(glamor_priv->xv_prog, vs_prog); + dispatch->glAttachShader(glamor_priv->xv_prog, fs_prog); + + dispatch->glBindAttribLocation(glamor_priv->xv_prog, + GLAMOR_VERTEX_POS, "v_position"); + dispatch->glBindAttribLocation(glamor_priv->xv_prog, + GLAMOR_VERTEX_SOURCE, "v_texcoord0"); + glamor_link_glsl_prog(dispatch, glamor_priv->xv_prog); + + glamor_put_dispatch(glamor_priv); +} + +void +glamor_fini_xv_shader(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv; + glamor_gl_dispatch *dispatch; + + glamor_priv = glamor_get_screen_private(screen); + dispatch = glamor_get_dispatch(glamor_priv); + + dispatch->glDeleteProgram(glamor_priv->xv_prog); + glamor_put_dispatch(glamor_priv); +} + +#define ClipValue(v,min,max) ((v) < (min) ? (min) : (v) > (max) ? (max) : (v)) +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +static Atom xvBrightness, xvContrast, xvSaturation, xvHue, xvColorspace, xvGamma; + +#define NUM_ATTRIBUTES 5 +static XF86AttributeRec Attributes_glamor[NUM_ATTRIBUTES+1] = +{ + {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"}, + {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}, + {XvSettable | XvGettable, -1000, 1000, "XV_HUE"}, + {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"}, + {0, 0, 0, NULL} + }; + +#define NUM_FORMATS 3 + +static XF86VideoFormatRec Formats[NUM_FORMATS] = +{ + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} + }; + +#define NUM_IMAGES 2 + +static XF86ImageRec Images[NUM_IMAGES] = +{ +XVIMAGE_YV12, + XVIMAGE_I420, + }; + +static void +glamor_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool cleanup) +{ +glamor_port_private *port_priv = (glamor_port_private *)data; +int i; +if (!cleanup) + return; + +for (i = 0; i < 3; i++) { +if (port_priv->src_pix[i]) { +glamor_destroy_pixmap(port_priv->src_pix[i]); +port_priv->src_pix[i] = NULL; +} +} +} + +static int +glamor_xv_set_port_attribute(ScrnInfoPtr pScrn, + Atom attribute, + INT32 value, + pointer data) +{ +glamor_port_private *port_priv = (glamor_port_private *)data; +if (attribute == xvBrightness) + port_priv->brightness = ClipValue(value, -1000, 1000); +else if (attribute == xvHue) + port_priv->hue = ClipValue(value, -1000, 1000); +else if (attribute == xvContrast) + port_priv->contrast = ClipValue(value, -1000, 1000); +else if (attribute == xvSaturation) + port_priv->saturation = ClipValue(value, -1000, 1000); +else if (attribute == xvGamma) + port_priv->gamma = ClipValue (value, 100, 10000); +else if(attribute == xvColorspace) + port_priv->transform_index = ClipValue (value, 0, 1); +else + return BadMatch; +return Success; +} + +static int +glamor_xv_get_port_attribute(ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value, + pointer data) +{ +glamor_port_private *port_priv = (glamor_port_private *)data; +if (attribute == xvBrightness) + *value = port_priv->brightness; +else if (attribute == xvHue) + *value = port_priv->hue; +else if (attribute == xvContrast) + *value = port_priv->contrast; +else if (attribute == xvSaturation) + *value = port_priv->saturation; +else if (attribute == xvGamma) + *value = port_priv->gamma; +else if(attribute == xvColorspace) + *value = port_priv->transform_index; +else + return BadMatch; + +return Success; +} + +static void +glamor_xv_query_best_size(ScrnInfoPtr pScrn, + Bool motion, + short vid_w, short vid_h, + short drw_w, short drw_h, + unsigned int *p_w, unsigned int *p_h, + pointer data) +{ +*p_w = drw_w; +*p_h = drw_h; +} + +static int +glamor_xv_query_image_attributes(ScrnInfoPtr pScrn, + int id, + unsigned short *w, unsigned short *h, + int *pitches, int *offsets) +{ +int size = 0, tmp; + +if (offsets) offsets[0] = 0; +switch (id) { +case FOURCC_YV12: +case FOURCC_I420: +*h = *h; +*w = *w; +size = *w; +if (pitches) pitches[0] = size; +size *= *h; +if (offsets) offsets[1] = size; +tmp = *w >> 1; +if (pitches) pitches[1] = pitches[2] = tmp; +tmp *= (*h >> 1); +size += tmp; +if (offsets) offsets[2] = size; +size += tmp; +break; +} +return size; +} +/* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces + note the difference to the parameters used in overlay are due + to 10bit vs. float calcs */ +static REF_TRANSFORM trans[2] = +{ + {1.1643, 0.0, 1.5960, -0.3918, -0.8129, 2.0172, 0.0}, /* BT.601 */ + {1.1643, 0.0, 1.7927, -0.2132, -0.5329, 2.1124, 0.0} /* BT.709 */ + }; + +static void +glamor_display_textured_video(glamor_port_private *port_priv) +{ +ScreenPtr screen = port_priv->pPixmap->drawable.pScreen; +glamor_screen_private *glamor_priv = + glamor_get_screen_private(screen); +glamor_pixmap_private *pixmap_priv = + glamor_get_pixmap_private(port_priv->pPixmap); +glamor_pixmap_private *src_pixmap_priv[3]; +glamor_gl_dispatch *dispatch; +float vertices[32], texcoords[8]; +BoxPtr box = REGION_RECTS(&port_priv->clip); +int nBox = REGION_NUM_RECTS(&port_priv->clip); +int dst_x_off, dst_y_off; +GLfloat dst_xscale, dst_yscale; +GLfloat src_xscale[3], src_yscale[3]; +int i; +const float Loff = -0.0627; +const float Coff = -0.502; +float uvcosf, uvsinf; +float yco; +float uco[3], vco[3], off[3]; +float bright, cont, gamma; +int ref = port_priv->transform_index; +GLint uloc, sampler_loc; + +cont = RTFContrast(port_priv->contrast); +bright = RTFBrightness(port_priv->brightness); +gamma = (float)port_priv->gamma / 1000.0; +uvcosf = RTFSaturation(port_priv->saturation) * cos(RTFHue(port_priv->hue)); +uvsinf = RTFSaturation(port_priv->saturation) * sin(RTFHue(port_priv->hue)); +/* overlay video also does pre-gamma contrast/sat adjust, should we? */ + +yco = trans[ref].RefLuma * cont; +uco[0] = -trans[ref].RefRCr * uvsinf; +uco[1] = trans[ref].RefGCb * uvcosf - trans[ref].RefGCr * uvsinf; +uco[2] = trans[ref].RefBCb * uvcosf; +vco[0] = trans[ref].RefRCr * uvcosf; +vco[1] = trans[ref].RefGCb * uvsinf + trans[ref].RefGCr * uvcosf; +vco[2] = trans[ref].RefBCb * uvsinf; +off[0] = Loff * yco + Coff * (uco[0] + vco[0]) + bright; +off[1] = Loff * yco + Coff * (uco[1] + vco[1]) + bright; +off[2] = Loff * yco + Coff * (uco[2] + vco[2]) + bright; +gamma = 1.0; + +pixmap_priv_get_dest_scale(pixmap_priv, &dst_xscale, &dst_yscale); +glamor_get_drawable_deltas(port_priv->pDraw, port_priv->pPixmap, &dst_x_off, + &dst_y_off); +glamor_set_destination_pixmap_priv_nc(pixmap_priv); + +for (i = 0; i < 3; i++) { +if (port_priv->src_pix[i]) { +src_pixmap_priv[i] = glamor_get_pixmap_private(port_priv->src_pix[i]); +pixmap_priv_get_scale(src_pixmap_priv[i], &src_xscale[i], &src_yscale[i]); +} +} +dispatch = glamor_get_dispatch(glamor_priv); +dispatch->glUseProgram(glamor_priv->xv_prog); + +uloc = dispatch->glGetUniformLocation(glamor_priv->xv_prog, "offsetyco"); +dispatch->glUniform4f(uloc, off[0], off[1], off[2], yco); +uloc = dispatch->glGetUniformLocation(glamor_priv->xv_prog, "ucogamma"); +dispatch->glUniform4f(uloc, uco[0], uco[1], uco[2], gamma); +uloc = dispatch->glGetUniformLocation(glamor_priv->xv_prog, "vco"); +dispatch->glUniform4f(uloc, vco[0], vco[1], vco[2], 0); + +dispatch->glActiveTexture(GL_TEXTURE0); +dispatch->glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[0]->base.fbo->tex); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + GL_LINEAR); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MAG_FILTER, + GL_LINEAR); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + +dispatch->glActiveTexture(GL_TEXTURE1); +dispatch->glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[1]->base.fbo->tex); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + GL_LINEAR); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MAG_FILTER, + GL_LINEAR); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + +dispatch->glActiveTexture(GL_TEXTURE2); +dispatch->glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->base.fbo->tex); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + GL_LINEAR); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MAG_FILTER, + GL_LINEAR); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); +dispatch->glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + +sampler_loc = dispatch->glGetUniformLocation(glamor_priv->xv_prog, "y_sampler"); +dispatch->glUniform1i(sampler_loc, 0); +sampler_loc = dispatch->glGetUniformLocation(glamor_priv->xv_prog, "u_sampler"); +dispatch->glUniform1i(sampler_loc, 1); +sampler_loc = dispatch->glGetUniformLocation(glamor_priv->xv_prog, "v_sampler"); +dispatch->glUniform1i(sampler_loc, 2); + +dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, + GL_FLOAT, GL_FALSE, + 2 * sizeof(float), + texcoords); +dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE); + +dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, + GL_FALSE, 2 * sizeof(float), + vertices); + +dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS); +for (i = 0; i < nBox; i++) { +float off_x = box[i].x1 - port_priv->drw_x; +float off_y = box[i].y1 - port_priv->drw_y; +float diff_x = (float)port_priv->src_w / (float)port_priv->dst_w; +float diff_y = (float)port_priv->src_h / (float)port_priv->dst_h; +float srcx, srcy, srcw, srch; +int dstx, dsty, dstw, dsth; + + +dstx = box[i].x1 + dst_x_off; +dsty = box[i].y1 + dst_y_off; +dstw = box[i].x2 - box[i].x1; +dsth = box[i].y2 - box[i].y1; + +srcx = port_priv->src_x + off_x * diff_x; +srcy = port_priv->src_y + off_y * diff_y; +srcw = (port_priv->src_w * dstw) / (float)port_priv->dst_w; +srch = (port_priv->src_h * dsth) / (float)port_priv->dst_h; + +glamor_set_normalize_vcoords(pixmap_priv, + dst_xscale, dst_yscale, + dstx, + dsty, + dstx + dstw, + dsty + dsth, + glamor_priv->yInverted, + vertices); + +glamor_set_normalize_tcoords(src_pixmap_priv[0], + src_xscale[0], + src_yscale[0], + srcx, + srcy, + srcx + srcw, + srcy + srch, + glamor_priv->yInverted, + texcoords); + +dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +} + +dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS); +dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); + +dispatch->glUseProgram(0); +glamor_put_dispatch(glamor_priv); +DamageDamageRegion(port_priv->pDraw, &port_priv->clip); +} + +static int glamor_xv_put_image(ScrnInfoPtr pScrn, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, + short drw_w, short drw_h, + int id, + unsigned char *buf, + short width, + short height, + Bool sync, + RegionPtr clipBoxes, + pointer data, + DrawablePtr pDrawable) +{ + ScreenPtr screen = xf86ScrnToScreen(pScrn); + glamor_port_private *port_priv = (glamor_port_private *)data; + INT32 x1, x2, y1, y2; + int srcPitch, srcPitch2; + BoxRec dstBox; + int top, nlines; + int s2offset, s3offset, tmp; + + s2offset = s3offset = srcPitch2 = 0; + + /* Clip */ + x1 = src_x; + x2 = src_x + src_w; + y1 = src_y; + y2 = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height)) + return Success; + + if ((x1 >= x2) || (y1 >= y2)) + return Success; + + srcPitch = width; + srcPitch2 = width >> 1; + + if (!port_priv->src_pix[0] || (width != port_priv->src_pix_w || height != port_priv->src_pix_h)) { + int i; + for (i = 0; i < 2; i++) + if (port_priv->src_pix[i]) + glamor_destroy_pixmap(port_priv->src_pix[i]); + + port_priv->src_pix[0] = glamor_create_pixmap(screen, width, height, 8, 0); + port_priv->src_pix[1] = glamor_create_pixmap(screen, width >> 1, height >> 1, 8, 0); + port_priv->src_pix[2] = glamor_create_pixmap(screen, width >> 1, height >> 1, 8, 0); + port_priv->src_pix_w = width; + port_priv->src_pix_h = height; + + if (!port_priv->src_pix[0] || !port_priv->src_pix[1] || !port_priv->src_pix[2]) + return BadAlloc; + } + + top = (y1 >> 16) & ~1; + nlines = ((y2 + 0xffff) >> 16) - top; + + switch (id) { + case FOURCC_YV12: + case FOURCC_I420: + s2offset = srcPitch * height; + s3offset = s2offset + (srcPitch2 * ((height + 1) >> 1)); + s2offset += ((top >> 1) * srcPitch2); + s3offset += ((top >> 1) * srcPitch2); + if (id == FOURCC_YV12) { + tmp = s2offset; + s2offset = s3offset; + s3offset = tmp; + } + glamor_upload_sub_pixmap_to_texture(port_priv->src_pix[0], + 0, 0, srcPitch, nlines, + port_priv->src_pix[0]->devKind, + buf + (top * srcPitch), 0); + + glamor_upload_sub_pixmap_to_texture(port_priv->src_pix[1], + 0, 0, srcPitch2, (nlines + 1) >> 1, + port_priv->src_pix[1]->devKind, + buf + s2offset, 0); + + glamor_upload_sub_pixmap_to_texture(port_priv->src_pix[2], + 0, 0, srcPitch2, (nlines + 1) >> 1, + port_priv->src_pix[2]->devKind, + buf + s3offset, 0); + break; + default: + return BadMatch; + } + + if (pDrawable->type == DRAWABLE_WINDOW) + port_priv->pPixmap = (*screen->GetWindowPixmap)((WindowPtr)pDrawable); + else + port_priv->pPixmap = (PixmapPtr)pDrawable; + + if (!RegionEqual(&port_priv->clip, clipBoxes)) { + RegionCopy(&port_priv->clip, clipBoxes); + } + + port_priv->src_x = src_x; + port_priv->src_y = src_y; + port_priv->src_w = src_w; + port_priv->src_h = src_h; + port_priv->dst_w = drw_w; + port_priv->dst_h = drw_h; + port_priv->drw_x = drw_x; + port_priv->drw_y = drw_y; + port_priv->w = width; + port_priv->h = height; + port_priv->pDraw = pDrawable; + glamor_display_textured_video(port_priv); + return Success; +} + +static XF86VideoEncodingRec DummyEncodingGLAMOR[1] = +{ + { + 0, + "XV_IMAGE", + 8192, 8192, + {1, 1} + } +}; + +XF86VideoAdaptorPtr +glamor_xv_init(ScreenPtr screen, int num_texture_ports) +{ + glamor_port_private *port_priv; + XF86VideoAdaptorPtr adapt; + int i; + + adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + num_texture_ports * + (sizeof(glamor_port_private) + sizeof(DevUnion))); + if (adapt == NULL) + return NULL; + + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + xvSaturation = MAKE_ATOM("XV_SATURATION"); + xvHue = MAKE_ATOM("XV_HUE"); + xvGamma = MAKE_ATOM("XV_GAMMA"); + xvColorspace = MAKE_ATOM("XV_COLORSPACE"); + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = 0; + adapt->name = "GLAMOR Textured Video"; + adapt->nEncodings = 1; + adapt->pEncodings = DummyEncodingGLAMOR; + + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = num_texture_ports; + adapt->pPortPrivates = (DevUnion*)(&adapt[1]); + + adapt->pAttributes = Attributes_glamor; + adapt->nAttributes = NUM_ATTRIBUTES; + + port_priv = (glamor_port_private *)(&adapt->pPortPrivates[num_texture_ports]); + adapt->pImages = Images; + adapt->nImages = NUM_IMAGES; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = glamor_xv_stop_video; + adapt->SetPortAttribute = glamor_xv_set_port_attribute; + adapt->GetPortAttribute = glamor_xv_get_port_attribute; + adapt->QueryBestSize = glamor_xv_query_best_size; + adapt->PutImage = glamor_xv_put_image; + adapt->ReputImage = NULL; + adapt->QueryImageAttributes = glamor_xv_query_image_attributes; + + for (i = 0; i < num_texture_ports; i++) { + glamor_port_private *pPriv = &port_priv[i]; + + pPriv->brightness = 0; + pPriv->contrast = 0; + pPriv->saturation = 0; + pPriv->hue = 0; + pPriv->gamma = 1000; + pPriv->transform_index = 0; + + REGION_NULL(pScreen, &pPriv->clip); + + adapt->pPortPrivates[i].ptr = (pointer)(pPriv); + } + return adapt; +} +#else +XF86VideoAdaptorPtr +glamor_xv_init(ScreenPtr screen, int num_texture_ports) +{ + return NULL; +} +#endif