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