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