1/* 2 * Copyright 2008 Ben Skeggs 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 shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23#ifdef HAVE_CONFIG_H 24#include "config.h" 25#endif 26 27#include "xorg-config.h" 28#include "xf86xv.h" 29#include <X11/extensions/Xv.h> 30#include "exa.h" 31#include "damage.h" 32#include "dixstruct.h" 33#include "fourcc.h" 34 35#include "nv_include.h" 36#include "nv_dma.h" 37#include "nv50_accel.h" 38 39extern Atom xvSyncToVBlank, xvSetDefaults; 40extern Atom xvBrightness, xvContrast, xvHue, xvSaturation; 41extern Atom xvITURBT709; 42 43static Bool 44nv50_xv_check_image_put(PixmapPtr ppix) 45{ 46 switch (ppix->drawable.bitsPerPixel) { 47 case 32: 48 case 24: 49 case 16: 50 case 15: 51 break; 52 default: 53 return FALSE; 54 } 55 56 if (!nv50_style_tiled_pixmap(ppix)) 57 return FALSE; 58 59 return TRUE; 60} 61 62int 63nv50_xv_image_put(ScrnInfoPtr pScrn, 64 struct nouveau_bo *src, int packed_y, int uv, 65 int id, int src_pitch, BoxPtr dstBox, 66 int x1, int y1, int x2, int y2, 67 uint16_t width, uint16_t height, 68 uint16_t src_w, uint16_t src_h, 69 uint16_t drw_w, uint16_t drw_h, 70 RegionPtr clipBoxes, PixmapPtr ppix, 71 NVPortPrivPtr pPriv) 72{ 73 NVPtr pNv = NVPTR(pScrn); 74 struct nouveau_bo *dst = nouveau_pixmap_bo(ppix); 75 struct nouveau_pushbuf *push = pNv->pushbuf; 76 struct nouveau_pushbuf_refn refs[] = { 77 { pNv->scratch, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR }, 78 { src, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD }, 79 { dst, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR }, 80 }; 81 uint32_t mode = 0xd0005000 | (src->config.nv50.tile_mode << 18); 82 float X1, X2, Y1, Y2; 83 BoxPtr pbox; 84 int nbox; 85 86 if (!nv50_xv_check_image_put(ppix)) 87 return BadMatch; 88 89 if (!PUSH_SPACE(push, 256)) 90 return BadImplementation; 91 92 BEGIN_NV04(push, NV50_3D(RT_ADDRESS_HIGH(0)), 5); 93 PUSH_DATA (push, dst->offset >> 32); 94 PUSH_DATA (push, dst->offset); 95 switch (ppix->drawable.depth) { 96 case 32: PUSH_DATA (push, NV50_SURFACE_FORMAT_BGRA8_UNORM); break; 97 case 30: PUSH_DATA (push, NV50_SURFACE_FORMAT_RGB10_A2_UNORM); break; 98 case 24: PUSH_DATA (push, NV50_SURFACE_FORMAT_BGRX8_UNORM); break; 99 case 16: PUSH_DATA (push, NV50_SURFACE_FORMAT_B5G6R5_UNORM); break; 100 case 15: PUSH_DATA (push, NV50_SURFACE_FORMAT_BGR5_X1_UNORM); break; 101 } 102 PUSH_DATA (push, dst->config.nv50.tile_mode); 103 PUSH_DATA (push, 0); 104 BEGIN_NV04(push, NV50_3D(RT_HORIZ(0)), 2); 105 PUSH_DATA (push, ppix->drawable.width); 106 PUSH_DATA (push, ppix->drawable.height); 107 BEGIN_NV04(push, NV50_3D(RT_ARRAY_MODE), 1); 108 PUSH_DATA (push, 1); 109 110 BEGIN_NV04(push, NV50_3D(BLEND_ENABLE(0)), 1); 111 PUSH_DATA (push, 0); 112 113 PUSH_DATAu(push, pNv->scratch, TIC_OFFSET, 16); 114 if (id == FOURCC_YV12 || id == FOURCC_I420) { 115 PUSH_DATA (push, NV50TIC_0_0_MAPA_C0 | NV50TIC_0_0_TYPEA_UNORM | 116 NV50TIC_0_0_MAPB_ZERO | NV50TIC_0_0_TYPEB_UNORM | 117 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM | 118 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM | 119 NV50TIC_0_0_FMT_8); 120 PUSH_DATA (push, (src->offset + packed_y)); 121 PUSH_DATA (push, (src->offset + packed_y) >> 32 | mode); 122 PUSH_DATA (push, 0x00300000); 123 PUSH_DATA (push, width); 124 PUSH_DATA (push, (1 << NV50TIC_0_5_DEPTH_SHIFT) | height); 125 PUSH_DATA (push, 0x03000000); 126 PUSH_DATA (push, 0x00000000); 127 PUSH_DATA (push, NV50TIC_0_0_MAPA_C1 | NV50TIC_0_0_TYPEA_UNORM | 128 NV50TIC_0_0_MAPB_C0 | NV50TIC_0_0_TYPEB_UNORM | 129 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM | 130 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM | 131 NV50TIC_0_0_FMT_8_8); 132 PUSH_DATA (push, (src->offset + uv)); 133 PUSH_DATA (push, (src->offset + uv) >> 32 | mode); 134 PUSH_DATA (push, 0x00300000); 135 PUSH_DATA (push, width >> 1); 136 PUSH_DATA (push, (1 << NV50TIC_0_5_DEPTH_SHIFT) | (height >> 1)); 137 PUSH_DATA (push, 0x03000000); 138 PUSH_DATA (push, 0x00000000); 139 } else { 140 if (id == FOURCC_UYVY) { 141 PUSH_DATA (push, NV50TIC_0_0_MAPA_C1 | NV50TIC_0_0_TYPEA_UNORM | 142 NV50TIC_0_0_MAPB_ZERO | NV50TIC_0_0_TYPEB_UNORM | 143 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM | 144 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM | 145 NV50TIC_0_0_FMT_8_8); 146 } else { 147 PUSH_DATA (push, NV50TIC_0_0_MAPA_C0 | NV50TIC_0_0_TYPEA_UNORM | 148 NV50TIC_0_0_MAPB_ZERO | NV50TIC_0_0_TYPEB_UNORM | 149 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM | 150 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM | 151 NV50TIC_0_0_FMT_8_8); 152 } 153 PUSH_DATA (push, (src->offset + packed_y)); 154 PUSH_DATA (push, (src->offset + packed_y) >> 32 | mode); 155 PUSH_DATA (push, 0x00300000); 156 PUSH_DATA (push, width); 157 PUSH_DATA (push, (1 << NV50TIC_0_5_DEPTH_SHIFT) | height); 158 PUSH_DATA (push, 0x03000000); 159 PUSH_DATA (push, 0x00000000); 160 if (id == FOURCC_UYVY) { 161 PUSH_DATA (push, NV50TIC_0_0_MAPA_C2 | NV50TIC_0_0_TYPEA_UNORM | 162 NV50TIC_0_0_MAPB_C0 | NV50TIC_0_0_TYPEB_UNORM | 163 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM | 164 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM | 165 NV50TIC_0_0_FMT_8_8_8_8); 166 } else { 167 PUSH_DATA (push, NV50TIC_0_0_MAPA_C3 | NV50TIC_0_0_TYPEA_UNORM | 168 NV50TIC_0_0_MAPB_C1 | NV50TIC_0_0_TYPEB_UNORM | 169 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM | 170 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM | 171 NV50TIC_0_0_FMT_8_8_8_8); 172 } 173 PUSH_DATA (push, (src->offset + packed_y)); 174 PUSH_DATA (push, (src->offset + packed_y) >> 32 | mode); 175 PUSH_DATA (push, 0x00300000); 176 PUSH_DATA (push, (width >> 1)); 177 PUSH_DATA (push, (1 << NV50TIC_0_5_DEPTH_SHIFT) | height); 178 PUSH_DATA (push, 0x03000000); 179 PUSH_DATA (push, 0x00000000); 180 } 181 182 PUSH_DATAu(push, pNv->scratch, TSC_OFFSET, 16); 183 PUSH_DATA (push, NV50TSC_1_0_WRAPS_CLAMP_TO_EDGE | 184 NV50TSC_1_0_WRAPT_CLAMP_TO_EDGE | 185 NV50TSC_1_0_WRAPR_CLAMP_TO_EDGE); 186 PUSH_DATA (push, NV50TSC_1_1_MAGF_LINEAR | 187 NV50TSC_1_1_MINF_LINEAR | 188 NV50TSC_1_1_MIPF_NONE); 189 PUSH_DATA (push, 0x00000000); 190 PUSH_DATA (push, 0x00000000); 191 PUSH_DATA (push, 0x00000000); 192 PUSH_DATA (push, 0x00000000); 193 PUSH_DATA (push, 0x00000000); 194 PUSH_DATA (push, 0x00000000); 195 PUSH_DATA (push, NV50TSC_1_0_WRAPS_CLAMP_TO_EDGE | 196 NV50TSC_1_0_WRAPT_CLAMP_TO_EDGE | 197 NV50TSC_1_0_WRAPR_CLAMP_TO_EDGE); 198 PUSH_DATA (push, NV50TSC_1_1_MAGF_LINEAR | 199 NV50TSC_1_1_MINF_LINEAR | 200 NV50TSC_1_1_MIPF_NONE); 201 PUSH_DATA (push, 0x00000000); 202 PUSH_DATA (push, 0x00000000); 203 PUSH_DATA (push, 0x00000000); 204 PUSH_DATA (push, 0x00000000); 205 PUSH_DATA (push, 0x00000000); 206 PUSH_DATA (push, 0x00000000); 207 208 BEGIN_NV04(push, NV50_3D(FP_START_ID), 1); 209 PUSH_DATA (push, PFP_NV12); 210 211 BEGIN_NV04(push, NV50_3D(TIC_FLUSH), 1); 212 PUSH_DATA (push, 0); 213 214 BEGIN_NV04(push, NV50_3D(BIND_TIC(2)), 1); 215 PUSH_DATA (push, 1); 216 BEGIN_NV04(push, NV50_3D(BIND_TIC(2)), 1); 217 PUSH_DATA (push, 0x203); 218 219 PUSH_DATAu(push, pNv->scratch, PVP_DATA, 11); 220 PUSH_DATAf(push, 1.0); 221 PUSH_DATAf(push, 0.0); 222 PUSH_DATAf(push, 0.0); 223 PUSH_DATAf(push, 0.0); 224 PUSH_DATAf(push, 1.0); 225 PUSH_DATAf(push, 0.0); 226 PUSH_DATAf(push, 0.0); 227 PUSH_DATAf(push, 0.0); 228 PUSH_DATAf(push, 1.0); 229 PUSH_DATAf(push, 1.0 / width); 230 PUSH_DATAf(push, 1.0 / height); 231 232 if (pPriv->SyncToVBlank) 233 NV50SyncToVBlank(ppix, dstBox); 234 235 /* These are fixed point values in the 16.16 format. */ 236 X1 = (float)(x1>>16)+(float)(x1&0xFFFF)/(float)0x10000; 237 Y1 = (float)(y1>>16)+(float)(y1&0xFFFF)/(float)0x10000; 238 X2 = (float)(x2>>16)+(float)(x2&0xFFFF)/(float)0x10000; 239 Y2 = (float)(y2>>16)+(float)(y2&0xFFFF)/(float)0x10000; 240 241 pbox = REGION_RECTS(clipBoxes); 242 nbox = REGION_NUM_RECTS(clipBoxes); 243 while(nbox--) { 244 float tx1=X1+(float)(pbox->x1 - dstBox->x1)*(X2-X1)/(float)(drw_w); 245 float tx2=X1+(float)(pbox->x2 - dstBox->x1)*(src_w)/(float)(drw_w); 246 float ty1=Y1+(float)(pbox->y1 - dstBox->y1)*(Y2-Y1)/(float)(drw_h); 247 float ty2=Y1+(float)(pbox->y2 - dstBox->y1)*(src_h)/(float)(drw_h); 248 int sx1=pbox->x1; 249 int sx2=pbox->x2; 250 int sy1=pbox->y1; 251 int sy2=pbox->y2; 252 253 if (nouveau_pushbuf_space(push, 64, 0, 0) || 254 nouveau_pushbuf_refn (push, refs, 3)) 255 return BadImplementation; 256 257 /* NV50_3D_SCISSOR_VERT_T_SHIFT is wrong, because it was deducted with 258 * origin lying at the bottom left. This will be changed to _MIN_ and _MAX_ 259 * later, because it is origin dependent. 260 */ 261 BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(0)), 2); 262 PUSH_DATA (push, sx2 << NV50_3D_SCISSOR_HORIZ_MAX__SHIFT | sx1); 263 PUSH_DATA (push, sy2 << NV50_3D_SCISSOR_VERT_MAX__SHIFT | sy1 ); 264 BEGIN_NV04(push, NV50_3D(VERTEX_BEGIN_GL), 1); 265 PUSH_DATA (push, NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_TRIANGLES); 266 PUSH_VTX1s(push, tx1, ty1, sx1, sy1); 267 PUSH_VTX1s(push, tx2+(tx2-tx1), ty1, sx2+(sx2-sx1), sy1); 268 PUSH_VTX1s(push, tx1, ty2+(ty2-ty1), sx1, sy2+(sy2-sy1)); 269 BEGIN_NV04(push, NV50_3D(VERTEX_END_GL), 1); 270 PUSH_DATA (push, 0); 271 272 pbox++; 273 } 274 275 PUSH_KICK(push); 276 return Success; 277} 278 279void 280nv50_xv_video_stop(ScrnInfoPtr pScrn, pointer data, Bool exit) 281{ 282} 283 284/* Reference color space transform data */ 285struct REF_TRANSFORM { 286 float RefLuma; 287 float RefRCb; 288 float RefRCr; 289 float RefGCb; 290 float RefGCr; 291 float RefBCb; 292 float RefBCr; 293} trans[] = { 294 { 1.1643, 0.0, 1.5960, -0.3918, -0.8129, 2.0172, 0.0 }, /* BT.601 */ 295 { 1.1643, 0.0, 1.7927, -0.2132, -0.5329, 2.1124, 0.0 } /* BT.709 */ 296}; 297 298#define RTFSaturation(a) (1.0 + ((a)*1.0)/1000.0) 299#define RTFBrightness(a) (((a)*1.0)/2000.0) 300#define RTFContrast(a) (1.0 + ((a)*1.0)/1000.0) 301#define RTFHue(a) (((a)*3.1416)/1000.0) 302 303void 304nv50_xv_csc_update(ScrnInfoPtr pScrn, NVPortPrivPtr pPriv) 305{ 306 NVPtr pNv = NVPTR(pScrn); 307 struct nouveau_pushbuf *push = pNv->pushbuf; 308 const float Loff = -0.0627; 309 const float Coff = -0.502; 310 float yco, off[3], uco[3], vco[3]; 311 float uvcosf, uvsinf; 312 float bright, cont; 313 int ref = pPriv->iturbt_709; 314 315 cont = RTFContrast(pPriv->contrast); 316 bright = RTFBrightness(pPriv->brightness); 317 uvcosf = RTFSaturation(pPriv->saturation) * cos(RTFHue(pPriv->hue)); 318 uvsinf = RTFSaturation(pPriv->saturation) * sin(RTFHue(pPriv->hue)); 319 320 yco = trans[ref].RefLuma * cont; 321 uco[0] = -trans[ref].RefRCr * uvsinf; 322 uco[1] = trans[ref].RefGCb * uvcosf - trans[ref].RefGCr * uvsinf; 323 uco[2] = trans[ref].RefBCb * uvcosf; 324 vco[0] = trans[ref].RefRCr * uvcosf; 325 vco[1] = trans[ref].RefGCb * uvsinf + trans[ref].RefGCr * uvcosf; 326 vco[2] = trans[ref].RefBCb * uvsinf; 327 off[0] = Loff * yco + Coff * (uco[0] + vco[0]) + bright; 328 off[1] = Loff * yco + Coff * (uco[1] + vco[1]) + bright; 329 off[2] = Loff * yco + Coff * (uco[2] + vco[2]) + bright; 330 331 if (pNv->Architecture >= NV_FERMI) { 332 nvc0_xv_csc_update(pNv, yco, off, uco, vco); 333 return; 334 } 335 336 if (nouveau_pushbuf_space(push, 64, 0, 0) || 337 nouveau_pushbuf_refn (push, &(struct nouveau_pushbuf_refn) { 338 pNv->scratch, NOUVEAU_BO_WR | 339 NOUVEAU_BO_VRAM }, 1)) 340 return; 341 342 PUSH_DATAu(push, pNv->scratch, PFP_DATA, 10); 343 PUSH_DATAf(push, yco); 344 PUSH_DATAf(push, off[0]); 345 PUSH_DATAf(push, off[1]); 346 PUSH_DATAf(push, off[2]); 347 PUSH_DATAf(push, uco[0]); 348 PUSH_DATAf(push, uco[1]); 349 PUSH_DATAf(push, uco[2]); 350 PUSH_DATAf(push, vco[0]); 351 PUSH_DATAf(push, vco[1]); 352 PUSH_DATAf(push, vco[2]); 353} 354 355void 356nv50_xv_set_port_defaults(ScrnInfoPtr pScrn, NVPortPrivPtr pPriv) 357{ 358 pPriv->videoStatus = 0; 359 pPriv->grabbedByV4L = FALSE; 360 pPriv->blitter = FALSE; 361 pPriv->texture = TRUE; 362 pPriv->doubleBuffer = FALSE; 363 pPriv->SyncToVBlank = TRUE; 364 pPriv->brightness = 0; 365 pPriv->contrast = 0; 366 pPriv->saturation = 0; 367 pPriv->hue = 0; 368 pPriv->iturbt_709 = 0; 369 pPriv->max_image_dim = 8192; 370} 371 372int 373nv50_xv_port_attribute_set(ScrnInfoPtr pScrn, Atom attribute, 374 INT32 value, pointer data) 375{ 376 NVPortPrivPtr pPriv = (NVPortPrivPtr)data; 377 378 if (attribute == xvSyncToVBlank) { 379 if (value < 0 || value > 1) 380 return BadValue; 381 pPriv->SyncToVBlank = value; 382 } else 383 if (attribute == xvBrightness) { 384 if (value < -1000 || value > 1000) 385 return BadValue; 386 pPriv->brightness = value; 387 } else 388 if (attribute == xvContrast) { 389 if (value < -1000 || value > 1000) 390 return BadValue; 391 pPriv->contrast = value; 392 } else 393 if (attribute == xvSaturation) { 394 if (value < -1000 || value > 1000) 395 return BadValue; 396 pPriv->saturation = value; 397 } else 398 if (attribute == xvHue) { 399 if (value < -1000 || value > 1000) 400 return BadValue; 401 pPriv->hue = value; 402 } else 403 if (attribute == xvITURBT709) { 404 if (value < 0 || value > 1) 405 return BadValue; 406 pPriv->iturbt_709 = value; 407 } else 408 if (attribute == xvSetDefaults) { 409 nv50_xv_set_port_defaults(pScrn, pPriv); 410 } else 411 return BadMatch; 412 413 nv50_xv_csc_update(pScrn, pPriv); 414 return Success; 415} 416 417int 418nv50_xv_port_attribute_get(ScrnInfoPtr pScrn, Atom attribute, 419 INT32 *value, pointer data) 420{ 421 NVPortPrivPtr pPriv = (NVPortPrivPtr)data; 422 423 if (attribute == xvSyncToVBlank) 424 *value = (pPriv->SyncToVBlank) ? 1 : 0; 425 else 426 if (attribute == xvBrightness) 427 *value = pPriv->brightness; 428 else 429 if (attribute == xvContrast) 430 *value = pPriv->contrast; 431 else 432 if (attribute == xvSaturation) 433 *value = pPriv->saturation; 434 else 435 if (attribute == xvHue) 436 *value = pPriv->hue; 437 else 438 if (attribute == xvITURBT709) 439 *value = pPriv->iturbt_709; 440 else 441 return BadMatch; 442 443 return Success; 444} 445 446 447