1/* 2 * Copyright 2008 Alex Deucher 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 FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * 24 * Based on radeon_exa_render.c and kdrive ati_video.c by Eric Anholt, et al. 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include <stdlib.h> 33#include <string.h> 34#include <stdio.h> 35#include <math.h> 36 37#include "radeon.h" 38#include "radeon_reg.h" 39#include "radeon_probe.h" 40#include "radeon_video.h" 41 42#include <X11/extensions/Xv.h> 43#include "fourcc.h" 44 45extern void 46R600DisplayTexturedVideo(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv); 47 48extern void 49EVERGREENDisplayTexturedVideo(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv); 50 51 52#define IMAGE_MAX_WIDTH 2048 53#define IMAGE_MAX_HEIGHT 2048 54 55#define IMAGE_MAX_WIDTH_R500 4096 56#define IMAGE_MAX_HEIGHT_R500 4096 57 58#define IMAGE_MAX_WIDTH_R600 8192 59#define IMAGE_MAX_HEIGHT_R600 8192 60 61#define IMAGE_MAX_WIDTH_EG 16384 62#define IMAGE_MAX_HEIGHT_EG 16384 63 64static Bool 65RADEONTilingEnabled(ScrnInfoPtr pScrn, PixmapPtr pPix) 66{ 67 return FALSE; 68} 69 70static __inline__ uint32_t F_TO_DW(float val) 71{ 72 union { 73 float f; 74 uint32_t l; 75 } tmp; 76 tmp.f = val; 77 return tmp.l; 78} 79 80/* Borrowed from Mesa */ 81static __inline__ uint32_t F_TO_24(float val) 82{ 83 float mantissa; 84 int exponent; 85 uint32_t float24 = 0; 86 87 if (val == 0.0) 88 return 0; 89 90 mantissa = frexpf(val, &exponent); 91 92 /* Handle -ve */ 93 if (mantissa < 0) { 94 float24 |= (1 << 23); 95 mantissa = mantissa * -1.0; 96 } 97 /* Handle exponent, bias of 63 */ 98 exponent += 62; 99 float24 |= (exponent << 16); 100 /* Kill 7 LSB of mantissa */ 101 float24 |= (F_TO_DW(mantissa) & 0x7FFFFF) >> 7; 102 103 return float24; 104} 105 106static __inline__ uint32_t float4touint(float fr, float fg, float fb, float fa) 107{ 108 unsigned ur = fr * 255.0 + 0.5; 109 unsigned ug = fg * 255.0 + 0.5; 110 unsigned ub = fb * 255.0 + 0.5; 111 unsigned ua = fa * 255.0 + 0.5; 112 return (ua << 24) | (ur << 16) | (ug << 8) | ub; 113} 114 115/* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces 116 note the difference to the parameters used in overlay are due 117 to 10bit vs. float calcs */ 118static REF_TRANSFORM trans[2] = 119{ 120 {1.1643, 0.0, 1.5960, -0.3918, -0.8129, 2.0172, 0.0}, /* BT.601 */ 121 {1.1643, 0.0, 1.7927, -0.2132, -0.5329, 2.1124, 0.0} /* BT.709 */ 122}; 123 124 125/* Allocates memory, either by resizing the allocation pointed to by mem_struct, 126 * or by freeing mem_struct (if non-NULL) and allocating a new space. The size 127 * is measured in bytes, and the offset from the beginning of card space is 128 * returned. 129 */ 130static Bool 131radeon_allocate_video_bo(ScrnInfoPtr pScrn, 132 struct radeon_bo **video_bo_p, 133 int size, 134 int align, 135 int domain) 136{ 137 RADEONInfoPtr info = RADEONPTR(pScrn); 138 struct radeon_bo *video_bo; 139 140 if (*video_bo_p) 141 radeon_bo_unref(*video_bo_p); 142 143 video_bo = radeon_bo_open(info->bufmgr, 0, size, align, domain, 0); 144 145 *video_bo_p = video_bo; 146 147 if (!video_bo) 148 return FALSE; 149 150 return TRUE; 151} 152 153static void 154RADEONFreeVideoMemory(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) 155{ 156 if (pPriv->video_memory) { 157 radeon_bo_unref(pPriv->video_memory); 158 pPriv->video_memory = NULL; 159 160 if (pPriv->textured) { 161 pPriv->src_bo[0] = NULL; 162 radeon_bo_unref(pPriv->src_bo[1]); 163 pPriv->src_bo[1] = NULL; 164 } 165 } 166} 167 168static void 169RADEONStopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup) 170{ 171 RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; 172 173 if (pPriv->textured) { 174 if (cleanup) { 175 RADEONFreeVideoMemory(pScrn, pPriv); 176 } 177 return; 178 } 179} 180 181#define OUT_ACCEL_REG_F(reg, val) OUT_RING_REG(reg, F_TO_DW(val)) 182 183#include "radeon_textured_videofuncs.c" 184 185#undef OUT_ACCEL_REG_F 186 187static void 188R600CopyData( 189 ScrnInfoPtr pScrn, 190 unsigned char *src, 191 unsigned char *dst, 192 unsigned int srcPitch, 193 unsigned int dstPitch, 194 unsigned int h, 195 unsigned int w, 196 unsigned int cpp 197){ 198 if (cpp == 2) { 199 w *= 2; 200 cpp = 1; 201 } 202 203 if (srcPitch == dstPitch) 204 memcpy(dst, src, srcPitch * h); 205 else { 206 while (h--) { 207 memcpy(dst, src, srcPitch); 208 src += srcPitch; 209 dst += dstPitch; 210 } 211 } 212} 213 214static int 215RADEONPutImageTextured(ScrnInfoPtr pScrn, 216 short src_x, short src_y, 217 short drw_x, short drw_y, 218 short src_w, short src_h, 219 short drw_w, short drw_h, 220 int id, 221 unsigned char *buf, 222 short width, 223 short height, 224 Bool sync, 225 RegionPtr clipBoxes, 226 pointer data, 227 DrawablePtr pDraw) 228{ 229 ScreenPtr pScreen = pScrn->pScreen; 230 RADEONInfoPtr info = RADEONPTR(pScrn); 231 RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; 232 INT32 x1, x2, y1, y2; 233 int srcPitch, srcPitch2, dstPitch, dstPitch2 = 0; 234 int s2offset, s3offset, tmp; 235 int d2line, d3line; 236 int top, nlines, size; 237 BoxRec dstBox; 238 int dst_width = width, dst_height = height; 239 int aligned_height; 240 int h_align = drmmode_get_height_align(pScrn, 0); 241 struct radeon_bo *src_bo; 242 int ret; 243 244 /* make the compiler happy */ 245 s2offset = s3offset = srcPitch2 = 0; 246 247 /* Clip */ 248 x1 = src_x; 249 x2 = src_x + src_w; 250 y1 = src_y; 251 y2 = src_y + src_h; 252 253 dstBox.x1 = drw_x; 254 dstBox.x2 = drw_x + drw_w; 255 dstBox.y1 = drw_y; 256 dstBox.y2 = drw_y + drw_h; 257 258 if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height)) 259 return Success; 260 261 if ((x1 >= x2) || (y1 >= y2)) 262 return Success; 263 264 /* Bicubic filter setup */ 265 pPriv->bicubic_enabled = (pPriv->bicubic_state != BICUBIC_OFF); 266 if (!(IS_R300_3D || IS_R500_3D)) { 267 pPriv->bicubic_enabled = FALSE; 268 pPriv->bicubic_state = BICUBIC_OFF; 269 } 270 if (pPriv->bicubic_enabled && (pPriv->bicubic_state == BICUBIC_AUTO)) { 271 /* 272 * Applying the bicubic filter with a scale of less than 200% 273 * results in a blurred picture, so disable the filter. 274 */ 275 if ((src_w > drw_w / 2) || (src_h > drw_h / 2)) 276 pPriv->bicubic_enabled = FALSE; 277 } 278 279 if (info->ChipFamily >= CHIP_FAMILY_R600) 280 pPriv->hw_align = drmmode_get_base_align(pScrn, 2, 0); 281 else 282 pPriv->hw_align = 64; 283 284 aligned_height = RADEON_ALIGN(dst_height, h_align); 285 286 switch(id) { 287 case FOURCC_YV12: 288 case FOURCC_I420: 289 srcPitch = RADEON_ALIGN(width, 4); 290 srcPitch2 = RADEON_ALIGN(width >> 1, 4); 291 if (pPriv->bicubic_state != BICUBIC_OFF) { 292 dstPitch = RADEON_ALIGN(dst_width << 1, pPriv->hw_align); 293 dstPitch2 = 0; 294 } else { 295 dstPitch = RADEON_ALIGN(dst_width, pPriv->hw_align); 296 dstPitch2 = RADEON_ALIGN(dstPitch >> 1, pPriv->hw_align); 297 } 298 break; 299 case FOURCC_UYVY: 300 case FOURCC_YUY2: 301 default: 302 dstPitch = RADEON_ALIGN(dst_width << 1, pPriv->hw_align); 303 srcPitch = (width << 1); 304 srcPitch2 = 0; 305 break; 306 } 307 308 size = dstPitch * aligned_height + 2 * dstPitch2 * RADEON_ALIGN(((aligned_height + 1) >> 1), h_align); 309 size = RADEON_ALIGN(size, pPriv->hw_align); 310 311 if (size != pPriv->size) { 312 RADEONFreeVideoMemory(pScrn, pPriv); 313 } 314 315 if (!pPriv->video_memory) { 316 Bool ret; 317 ret = radeon_allocate_video_bo(pScrn, 318 &pPriv->video_memory, 319 size, pPriv->hw_align, 320 RADEON_GEM_DOMAIN_GTT); 321 if (ret == FALSE) 322 return BadAlloc; 323 324 pPriv->src_bo[0] = pPriv->video_memory; 325 radeon_allocate_video_bo(pScrn, (void*)&pPriv->src_bo[1], size, 326 pPriv->hw_align, 327 RADEON_GEM_DOMAIN_GTT); 328 } 329 330 /* Bicubic filter loading */ 331 if (pPriv->bicubic_enabled) { 332 if (!info->bicubic_bo) 333 pPriv->bicubic_enabled = FALSE; 334 } 335 336 if (pDraw->type == DRAWABLE_WINDOW) 337 pPriv->pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw); 338 else 339 pPriv->pPixmap = (PixmapPtr)pDraw; 340 341 /* Force the pixmap into framebuffer so we can draw to it. */ 342 info->exa_force_create = TRUE; 343 exaMoveInPixmap(pPriv->pPixmap); 344 info->exa_force_create = FALSE; 345 346 /* copy data */ 347 top = (y1 >> 16) & ~1; 348 nlines = ((y2 + 0xffff) >> 16) - top; 349 350 pPriv->currentBuffer ^= 1; 351 352 src_bo = pPriv->src_bo[pPriv->currentBuffer]; 353 354 ret = radeon_bo_map(src_bo, 1); 355 if (ret) 356 return BadAlloc; 357 358 pPriv->src_addr = src_bo->ptr; 359 pPriv->src_pitch = dstPitch; 360 361 pPriv->planeu_offset = dstPitch * aligned_height; 362 pPriv->planeu_offset = RADEON_ALIGN(pPriv->planeu_offset, pPriv->hw_align); 363 pPriv->planev_offset = pPriv->planeu_offset + dstPitch2 * RADEON_ALIGN(((aligned_height + 1) >> 1), h_align); 364 pPriv->planev_offset = RADEON_ALIGN(pPriv->planev_offset, pPriv->hw_align); 365 366 pPriv->size = size; 367 pPriv->pDraw = pDraw; 368 369 switch(id) { 370 case FOURCC_YV12: 371 case FOURCC_I420: 372 s2offset = srcPitch * (RADEON_ALIGN(height, 2)); 373 s3offset = s2offset + (srcPitch2 * ((height + 1) >> 1)); 374 s2offset += ((top >> 1) * srcPitch2); 375 s3offset += ((top >> 1) * srcPitch2); 376 if (pPriv->bicubic_state != BICUBIC_OFF) { 377 if (id == FOURCC_I420) { 378 tmp = s2offset; 379 s2offset = s3offset; 380 s3offset = tmp; 381 } 382 RADEONCopyMungedData(pScrn, buf + (top * srcPitch), 383 buf + s2offset, buf + s3offset, pPriv->src_addr + (top * dstPitch), 384 srcPitch, srcPitch2, dstPitch, nlines, width); 385 } else { 386 if (id == FOURCC_YV12) { 387 tmp = s2offset; 388 s2offset = s3offset; 389 s3offset = tmp; 390 } 391 d2line = pPriv->planeu_offset + ((top >> 1) * dstPitch2); 392 d3line = pPriv->planev_offset + ((top >> 1) * dstPitch2); 393 394 if (info->ChipFamily >= CHIP_FAMILY_R600) { 395 R600CopyData(pScrn, buf + (top * srcPitch), pPriv->src_addr + (top * dstPitch), 396 srcPitch, dstPitch, nlines, width, 1); 397 R600CopyData(pScrn, buf + s2offset, pPriv->src_addr + d2line, 398 srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1); 399 R600CopyData(pScrn, buf + s3offset, pPriv->src_addr + d3line, 400 srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1); 401 } else { 402 RADEONCopyData(pScrn, buf + (top * srcPitch), pPriv->src_addr + (top * dstPitch), 403 srcPitch, dstPitch, nlines, width, 1); 404 RADEONCopyData(pScrn, buf + s2offset, pPriv->src_addr + d2line, 405 srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1); 406 RADEONCopyData(pScrn, buf + s3offset, pPriv->src_addr + d3line, 407 srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1); 408 } 409 } 410 break; 411 case FOURCC_UYVY: 412 case FOURCC_YUY2: 413 default: 414 if (info->ChipFamily >= CHIP_FAMILY_R600) 415 R600CopyData(pScrn, buf + (top * srcPitch), 416 pPriv->src_addr + (top * dstPitch), 417 srcPitch, dstPitch, nlines, width, 2); 418 else 419 RADEONCopyData(pScrn, buf + (top * srcPitch), 420 pPriv->src_addr + (top * dstPitch), 421 srcPitch, dstPitch, nlines, width, 2); 422 break; 423 } 424 425 /* update cliplist */ 426 if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) { 427 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); 428 } 429 430 pPriv->id = id; 431 pPriv->src_w = src_w; 432 pPriv->src_h = src_h; 433 pPriv->src_x = src_x; 434 pPriv->src_y = src_y; 435 pPriv->drw_x = drw_x; 436 pPriv->drw_y = drw_y; 437 pPriv->dst_w = drw_w; 438 pPriv->dst_h = drw_h; 439 pPriv->w = width; 440 pPriv->h = height; 441 442 radeon_bo_unmap(pPriv->src_bo[pPriv->currentBuffer]); 443 if (info->directRenderingEnabled) { 444 if (IS_EVERGREEN_3D) 445 EVERGREENDisplayTexturedVideo(pScrn, pPriv); 446 else if (IS_R600_3D) 447 R600DisplayTexturedVideo(pScrn, pPriv); 448 else if (IS_R500_3D) 449 R500DisplayTexturedVideo(pScrn, pPriv); 450 else if (IS_R300_3D) 451 R300DisplayTexturedVideo(pScrn, pPriv); 452 else if (IS_R200_3D) 453 R200DisplayTexturedVideo(pScrn, pPriv); 454 else 455 RADEONDisplayTexturedVideo(pScrn, pPriv); 456 } 457 458 return Success; 459} 460 461/* client libraries expect an encoding */ 462static XF86VideoEncodingRec DummyEncoding[1] = 463{ 464 { 465 0, 466 "XV_IMAGE", 467 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, 468 {1, 1} 469 } 470}; 471 472static XF86VideoEncodingRec DummyEncodingR500[1] = 473{ 474 { 475 0, 476 "XV_IMAGE", 477 IMAGE_MAX_WIDTH_R500, IMAGE_MAX_HEIGHT_R500, 478 {1, 1} 479 } 480}; 481 482static XF86VideoEncodingRec DummyEncodingR600[1] = 483{ 484 { 485 0, 486 "XV_IMAGE", 487 IMAGE_MAX_WIDTH_R600, IMAGE_MAX_HEIGHT_R600, 488 {1, 1} 489 } 490}; 491 492static XF86VideoEncodingRec DummyEncodingEG[1] = 493{ 494 { 495 0, 496 "XV_IMAGE", 497 IMAGE_MAX_WIDTH_EG, IMAGE_MAX_HEIGHT_EG, 498 {1, 1} 499 } 500}; 501 502#define NUM_FORMATS 4 503 504static XF86VideoFormatRec Formats[NUM_FORMATS] = 505{ 506 {15, TrueColor}, {16, TrueColor}, {24, TrueColor}, {30, TrueColor} 507}; 508 509#define NUM_ATTRIBUTES 2 510 511static XF86AttributeRec Attributes[NUM_ATTRIBUTES+1] = 512{ 513 {XvSettable | XvGettable, 0, 1, "XV_VSYNC"}, 514 {XvSettable | XvGettable, -1, 1, "XV_CRTC"}, 515 {0, 0, 0, NULL} 516}; 517 518#define NUM_ATTRIBUTES_R200 7 519 520static XF86AttributeRec Attributes_r200[NUM_ATTRIBUTES_R200+1] = 521{ 522 {XvSettable | XvGettable, 0, 1, "XV_VSYNC"}, 523 {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"}, 524 {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"}, 525 {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}, 526 {XvSettable | XvGettable, -1000, 1000, "XV_HUE"}, 527 {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"}, 528 {XvSettable | XvGettable, -1, 1, "XV_CRTC"}, 529 {0, 0, 0, NULL} 530}; 531 532#define NUM_ATTRIBUTES_R300 9 533 534static XF86AttributeRec Attributes_r300[NUM_ATTRIBUTES_R300+1] = 535{ 536 {XvSettable | XvGettable, 0, 2, "XV_BICUBIC"}, 537 {XvSettable | XvGettable, 0, 1, "XV_VSYNC"}, 538 {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"}, 539 {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"}, 540 {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}, 541 {XvSettable | XvGettable, -1000, 1000, "XV_HUE"}, 542 {XvSettable | XvGettable, 100, 10000, "XV_GAMMA"}, 543 {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"}, 544 {XvSettable | XvGettable, -1, 1, "XV_CRTC"}, 545 {0, 0, 0, NULL} 546}; 547 548#define NUM_ATTRIBUTES_R500 8 549 550static XF86AttributeRec Attributes_r500[NUM_ATTRIBUTES_R500+1] = 551{ 552 {XvSettable | XvGettable, 0, 2, "XV_BICUBIC"}, 553 {XvSettable | XvGettable, 0, 1, "XV_VSYNC"}, 554 {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"}, 555 {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"}, 556 {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}, 557 {XvSettable | XvGettable, -1000, 1000, "XV_HUE"}, 558 {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"}, 559 {XvSettable | XvGettable, -1, 1, "XV_CRTC"}, 560 {0, 0, 0, NULL} 561}; 562 563#define NUM_ATTRIBUTES_R600 7 564 565static XF86AttributeRec Attributes_r600[NUM_ATTRIBUTES_R600+1] = 566{ 567 {XvSettable | XvGettable, 0, 1, "XV_VSYNC"}, 568 {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"}, 569 {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"}, 570 {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}, 571 {XvSettable | XvGettable, -1000, 1000, "XV_HUE"}, 572 {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"}, 573 {XvSettable | XvGettable, -1, 1, "XV_CRTC"}, 574 {0, 0, 0, NULL} 575}; 576 577static XF86AttributeRec Attributes_eg[NUM_ATTRIBUTES_R600+1] = 578{ 579 {XvSettable | XvGettable, 0, 1, "XV_VSYNC"}, 580 {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"}, 581 {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"}, 582 {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}, 583 {XvSettable | XvGettable, -1000, 1000, "XV_HUE"}, 584 {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"}, 585 {XvSettable | XvGettable, -1, 5, "XV_CRTC"}, 586 {0, 0, 0, NULL} 587}; 588 589static Atom xvBicubic; 590static Atom xvVSync; 591static Atom xvBrightness, xvContrast, xvSaturation, xvHue; 592static Atom xvGamma, xvColorspace; 593static Atom xvCRTC; 594 595#define NUM_IMAGES 4 596 597static XF86ImageRec Images[NUM_IMAGES] = 598{ 599 XVIMAGE_YUY2, 600 XVIMAGE_YV12, 601 XVIMAGE_I420, 602 XVIMAGE_UYVY 603}; 604 605int 606RADEONGetTexPortAttribute(ScrnInfoPtr pScrn, 607 Atom attribute, 608 INT32 *value, 609 pointer data) 610{ 611 RADEONInfoPtr info = RADEONPTR(pScrn); 612 RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; 613 614 if (info->accelOn) RADEON_SYNC(info, pScrn); 615 616 if (attribute == xvBicubic) 617 *value = pPriv->bicubic_state; 618 else if (attribute == xvVSync) 619 *value = pPriv->vsync; 620 else if (attribute == xvBrightness) 621 *value = pPriv->brightness; 622 else if (attribute == xvContrast) 623 *value = pPriv->contrast; 624 else if (attribute == xvSaturation) 625 *value = pPriv->saturation; 626 else if (attribute == xvHue) 627 *value = pPriv->hue; 628 else if (attribute == xvGamma) 629 *value = pPriv->gamma; 630 else if(attribute == xvColorspace) 631 *value = pPriv->transform_index; 632 else if(attribute == xvCRTC) { 633 int c; 634 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 635 for (c = 0; c < xf86_config->num_crtc; c++) 636 if (xf86_config->crtc[c] == pPriv->desired_crtc) 637 break; 638 if (c == xf86_config->num_crtc) 639 c = -1; 640 *value = c; 641 } else 642 return BadMatch; 643 644 return Success; 645} 646 647int 648RADEONSetTexPortAttribute(ScrnInfoPtr pScrn, 649 Atom attribute, 650 INT32 value, 651 pointer data) 652{ 653 RADEONInfoPtr info = RADEONPTR(pScrn); 654 RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; 655 656 RADEON_SYNC(info, pScrn); 657 658 if (attribute == xvBicubic) 659 pPriv->bicubic_state = ClipValue (value, 0, 2); 660 else if (attribute == xvVSync) 661 pPriv->vsync = ClipValue (value, 0, 1); 662 else if (attribute == xvBrightness) 663 pPriv->brightness = ClipValue (value, -1000, 1000); 664 else if (attribute == xvContrast) 665 pPriv->contrast = ClipValue (value, -1000, 1000); 666 else if (attribute == xvSaturation) 667 pPriv->saturation = ClipValue (value, -1000, 1000); 668 else if (attribute == xvHue) 669 pPriv->hue = ClipValue (value, -1000, 1000); 670 else if (attribute == xvGamma) 671 pPriv->gamma = ClipValue (value, 100, 10000); 672 else if(attribute == xvColorspace) 673 pPriv->transform_index = ClipValue (value, 0, 1); 674 else if(attribute == xvCRTC) { 675 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 676 if ((value < -1) || (value > xf86_config->num_crtc)) 677 return BadValue; 678 if (value < 0) 679 pPriv->desired_crtc = NULL; 680 else 681 pPriv->desired_crtc = xf86_config->crtc[value]; 682 } else 683 return BadMatch; 684 685 return Success; 686} 687 688Bool radeon_load_bicubic_texture(ScrnInfoPtr pScrn) 689{ 690 RADEONInfoPtr info = RADEONPTR(pScrn); 691 int ret; 692 /* Bicubic filter loading */ 693 ret = radeon_allocate_video_bo(pScrn, 694 &info->bicubic_bo, 695 sizeof(bicubic_tex_512), 64, 696 RADEON_GEM_DOMAIN_VRAM); 697 if (ret == FALSE) 698 return FALSE; 699 700 /* Upload bicubic filter tex */ 701 if (info->ChipFamily < CHIP_FAMILY_R600) { 702 uint8_t *bicubic_addr; 703 int ret; 704 ret = radeon_bo_map(info->bicubic_bo, 1); 705 if (ret) 706 return FALSE; 707 708 bicubic_addr = info->bicubic_bo->ptr; 709 710 RADEONCopySwap(bicubic_addr, (uint8_t *)bicubic_tex_512, 1024, 711#if X_BYTE_ORDER == X_BIG_ENDIAN 712 RADEON_HOST_DATA_SWAP_16BIT 713#else 714 RADEON_HOST_DATA_SWAP_NONE 715#endif 716); 717 radeon_bo_unmap(info->bicubic_bo); 718 } 719 return TRUE; 720} 721 722#if 0 723/* XXX */ 724static void radeon_unload_bicubic_texture(ScrnInfoPtr pScrn) 725{ 726 RADEONInfoPtr info = RADEONPTR(pScrn); 727 728 if (info->bicubic_memory) { 729 radeon_bo_unref(info->bicubic_memory); 730 info->bicubic_memory = NULL; 731 } 732 733} 734#endif 735 736static void 737RADEONQueryBestSize( 738 ScrnInfoPtr pScrn, 739 Bool motion, 740 short vid_w, short vid_h, 741 short drw_w, short drw_h, 742 unsigned int *p_w, unsigned int *p_h, 743 pointer data 744){ 745 RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; 746 747 if (!pPriv->textured) { 748 if (vid_w > (drw_w << 4)) 749 drw_w = vid_w >> 4; 750 if (vid_h > (drw_h << 4)) 751 drw_h = vid_h >> 4; 752 } 753 754 *p_w = drw_w; 755 *p_h = drw_h; 756} 757 758#define FOURCC_RGB24 0x00000000 759#define FOURCC_RGBT16 0x54424752 760#define FOURCC_RGB16 0x32424752 761#define FOURCC_RGBA32 0x41424752 762 763static int 764RADEONQueryImageAttributes( 765 ScrnInfoPtr pScrn, 766 int id, 767 unsigned short *w, unsigned short *h, 768 int *pitches, int *offsets 769){ 770 const RADEONInfoRec * const info = RADEONPTR(pScrn); 771 int size, tmp; 772 773 if(*w > info->xv_max_width) *w = info->xv_max_width; 774 if(*h > info->xv_max_height) *h = info->xv_max_height; 775 776 *w = RADEON_ALIGN(*w, 2); 777 if(offsets) offsets[0] = 0; 778 779 switch(id) { 780 case FOURCC_YV12: 781 case FOURCC_I420: 782 *h = RADEON_ALIGN(*h, 2); 783 size = RADEON_ALIGN(*w, 4); 784 if(pitches) pitches[0] = size; 785 size *= *h; 786 if(offsets) offsets[1] = size; 787 tmp = RADEON_ALIGN(*w >> 1, 4); 788 if(pitches) pitches[1] = pitches[2] = tmp; 789 tmp *= (*h >> 1); 790 size += tmp; 791 if(offsets) offsets[2] = size; 792 size += tmp; 793 break; 794 case FOURCC_RGBA32: 795 size = *w << 2; 796 if(pitches) pitches[0] = size; 797 size *= *h; 798 break; 799 case FOURCC_RGB24: 800 size = *w * 3; 801 if(pitches) pitches[0] = size; 802 size *= *h; 803 break; 804 case FOURCC_RGBT16: 805 case FOURCC_RGB16: 806 case FOURCC_UYVY: 807 case FOURCC_YUY2: 808 default: 809 size = *w << 1; 810 if(pitches) pitches[0] = size; 811 size *= *h; 812 break; 813 } 814 815 return size; 816} 817 818XF86VideoAdaptorPtr 819RADEONSetupImageTexturedVideo(ScreenPtr pScreen) 820{ 821 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 822 RADEONInfoPtr info = RADEONPTR(pScrn); 823 RADEONPortPrivPtr pPortPriv; 824 XF86VideoAdaptorPtr adapt; 825 int i; 826 int num_texture_ports = 16; 827 828 adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + num_texture_ports * 829 (sizeof(RADEONPortPrivRec) + sizeof(DevUnion))); 830 if (!adapt) 831 return NULL; 832 833 xvBicubic = MAKE_ATOM("XV_BICUBIC"); 834 xvVSync = MAKE_ATOM("XV_VSYNC"); 835 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 836 xvContrast = MAKE_ATOM("XV_CONTRAST"); 837 xvSaturation = MAKE_ATOM("XV_SATURATION"); 838 xvHue = MAKE_ATOM("XV_HUE"); 839 xvGamma = MAKE_ATOM("XV_GAMMA"); 840 xvColorspace = MAKE_ATOM("XV_COLORSPACE"); 841 xvCRTC = MAKE_ATOM("XV_CRTC"); 842 843 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 844 adapt->flags = 0; 845 adapt->name = "Radeon Textured Video"; 846 adapt->nEncodings = 1; 847 if (IS_EVERGREEN_3D) 848 adapt->pEncodings = DummyEncodingEG; 849 else if (IS_R600_3D) 850 adapt->pEncodings = DummyEncodingR600; 851 else if (IS_R500_3D) 852 adapt->pEncodings = DummyEncodingR500; 853 else 854 adapt->pEncodings = DummyEncoding; 855 adapt->nFormats = NUM_FORMATS; 856 adapt->pFormats = Formats; 857 adapt->nPorts = num_texture_ports; 858 adapt->pPortPrivates = (DevUnion*)(&adapt[1]); 859 860 pPortPriv = 861 (RADEONPortPrivPtr)(&adapt->pPortPrivates[num_texture_ports]); 862 863 if (IS_EVERGREEN_3D) { 864 adapt->pAttributes = Attributes_eg; 865 adapt->nAttributes = NUM_ATTRIBUTES_R600; 866 } 867 else if (IS_R600_3D) { 868 adapt->pAttributes = Attributes_r600; 869 adapt->nAttributes = NUM_ATTRIBUTES_R600; 870 } 871 else if (IS_R500_3D) { 872 adapt->pAttributes = Attributes_r500; 873 adapt->nAttributes = NUM_ATTRIBUTES_R500; 874 } 875 else if (IS_R300_3D) { 876 adapt->pAttributes = Attributes_r300; 877 adapt->nAttributes = NUM_ATTRIBUTES_R300; 878 } 879 else if (IS_R200_3D) { 880 adapt->pAttributes = Attributes_r200; 881 adapt->nAttributes = NUM_ATTRIBUTES_R200; 882 } 883 else { 884 adapt->pAttributes = Attributes; 885 adapt->nAttributes = NUM_ATTRIBUTES; 886 } 887 adapt->pImages = Images; 888 adapt->nImages = NUM_IMAGES; 889 adapt->PutVideo = NULL; 890 adapt->PutStill = NULL; 891 adapt->GetVideo = NULL; 892 adapt->GetStill = NULL; 893 adapt->StopVideo = RADEONStopVideo; 894 adapt->SetPortAttribute = RADEONSetTexPortAttribute; 895 adapt->GetPortAttribute = RADEONGetTexPortAttribute; 896 adapt->QueryBestSize = RADEONQueryBestSize; 897 adapt->PutImage = RADEONPutImageTextured; 898 adapt->ReputImage = NULL; 899 adapt->QueryImageAttributes = RADEONQueryImageAttributes; 900 901 for (i = 0; i < num_texture_ports; i++) { 902 RADEONPortPrivPtr pPriv = &pPortPriv[i]; 903 904 pPriv->textured = TRUE; 905 pPriv->bicubic_state = BICUBIC_OFF; 906 pPriv->vsync = TRUE; 907 pPriv->brightness = 0; 908 pPriv->contrast = 0; 909 pPriv->saturation = 0; 910 pPriv->hue = 0; 911 pPriv->gamma = 1000; 912 pPriv->transform_index = 0; 913 pPriv->desired_crtc = NULL; 914 915 /* gotta uninit this someplace, XXX: shouldn't be necessary for textured */ 916 REGION_NULL(pScreen, &pPriv->clip); 917 adapt->pPortPrivates[i].ptr = (pointer) (pPriv); 918 } 919 920 if (IS_R500_3D || IS_R300_3D) 921 radeon_load_bicubic_texture(pScrn); 922 923 info->xv_max_width = adapt->pEncodings->width; 924 info->xv_max_height = adapt->pEncodings->height; 925 926 return adapt; 927} 928 929