s3_video.c revision 4178061c
1/* 2 * Copyright 2001 Ani Joshi <ajoshi@unixbox.com> 3 * 4 * XFree86 4.x driver for S3 chipsets 5 * 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and its 8 * documentation for any purpose is hereby granted without fee, provided that 9 * the above copyright notice appear in all copies and that both that copyright 10 * notice and this permission notice appear in supporting documentation and 11 * that the name of Ani Joshi not be used in advertising or 12 * publicity pertaining to distribution of the software without specific, 13 * written prior permission. Ani Joshi makes no representations 14 * about the suitability of this software for any purpose. It is provided 15 * "as-is" without express or implied warranty. 16 * 17 * ANI JOSHI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 19 * EVENT SHALL ANI JOSHI BE LIABLE FOR ANY SPECIAL, INDIRECT OR 20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 23 * PERFORMANCE OF THIS SOFTWARE. 24 * 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include "xf86.h" 33#include "xf86_OSproc.h" 34 35#include "compiler.h" 36 37#include "s3.h" 38#include "s3_reg.h" 39 40 41#define CLIENT_VIDEO_ON 0x04 42#define S3_MAX_PORTS 1 43#define NUM_FORMATS_OVERLAY 4 44#define NUM_FORMATS_TEXTURE 4 45 46 47static XF86VideoAdaptorPtr S3AllocAdaptor(ScrnInfoPtr pScrn); 48static XF86VideoAdaptorPtr S3SetupImageVideoOverlay(ScreenPtr); 49static int S3SetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer); 50static int S3GetPortAttributeOverlay(ScrnInfoPtr, Atom ,INT32 *, pointer); 51static void S3StopVideo(ScrnInfoPtr, pointer, Bool); 52static void S3QueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, 53 unsigned int *, unsigned int *, pointer); 54static int S3PutImage(ScrnInfoPtr, short, short, short, short, short, 55 short, short, short, int, unsigned char*, short, 56 short, Bool, RegionPtr, pointer, DrawablePtr); 57static int S3QueryImageAttributes(ScrnInfoPtr, int, unsigned short *, 58 unsigned short *, int *, int *); 59static void S3ResetVideoOverlay(ScrnInfoPtr); 60static FBLinearPtr S3XVMemAlloc(ScrnInfoPtr pScrn, pointer pVideo, int size); 61 62 63void S3InitVideo(ScreenPtr pScreen) 64{ 65 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 66 S3Ptr pS3 = S3PTR(pScrn); 67 XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; 68 XF86VideoAdaptorPtr newAdaptor = NULL; 69 int num_adaptors; 70 71 newAdaptor = S3SetupImageVideoOverlay(pScreen); 72 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using overlay video\n"); 73 74 num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); 75 76 if(newAdaptor) { 77 if(!num_adaptors) { 78 num_adaptors = 1; 79 adaptors = &newAdaptor; 80 } else { 81 newAdaptors = /* need to free this someplace */ 82 xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); 83 if(newAdaptors) { 84 memcpy(newAdaptors, adaptors, num_adaptors * 85 sizeof(XF86VideoAdaptorPtr)); 86 newAdaptors[num_adaptors] = newAdaptor; 87 adaptors = newAdaptors; 88 num_adaptors++; 89 } 90 } 91 } 92 93 if(num_adaptors) 94 xf86XVScreenInit(pScreen, adaptors, num_adaptors); 95 96 if(newAdaptors) 97 xfree(newAdaptors); 98} 99 100 101/* client libraries expect an encoding */ 102static XF86VideoEncodingRec DummyEncoding[2] = 103{ 104 { /* overlay limit */ 105 0, 106 "XV_IMAGE", 107 1024, 1024, 108 {1, 1} 109 }, 110 { /* texture limit */ 111 0, 112 "XV_IMAGE", 113 2046, 2046, 114 {1, 1} 115 } 116}; 117 118 119static FBLinearPtr S3XVMemAlloc(ScrnInfoPtr pScrn, pointer pVideo, int size) 120{ 121 FBLinearPtr pLinear = (FBLinearPtr)pVideo; 122 ScreenPtr pScreen = pScrn->pScreen; 123 124 if (pLinear) { 125 if ((pLinear->size >= size) || 126 xf86ResizeOffscreenLinear(pLinear, size)) { 127 pLinear->MoveLinearCallback = NULL; 128 pLinear->RemoveLinearCallback = NULL; 129 return pLinear; 130 } 131 xf86FreeOffscreenLinear(pLinear); 132 } 133 pLinear = xf86AllocateOffscreenLinear(pScreen, size, 16, 134 NULL, NULL, NULL); 135 136 if (!pLinear) { 137 int maxSize; 138 139 xf86QueryLargestOffscreenLinear(pScreen, &maxSize, 16, 140 PRIORITY_EXTREME); 141 if (maxSize < size) 142 return NULL; 143 144 xf86PurgeUnlockedOffscreenAreas(pScreen); 145 pLinear = xf86AllocateOffscreenLinear(pScreen, size, 16, 146 NULL, NULL, NULL); 147 } 148 return pLinear; 149} 150 151static XF86VideoFormatRec Formats[NUM_FORMATS_TEXTURE] = 152{ 153 {16, TrueColor}, {24, TrueColor}, 154 {16, DirectColor}, {24, DirectColor} 155}; 156 157 158 159#define NUM_IMAGES 3 160 161static XF86ImageRec Images[NUM_IMAGES] = 162{ 163 XVIMAGE_YUY2, 164 /* As in mga, YV12 & I420 are converted to YUY2 on the fly by */ 165 /* copy over conversion. */ 166 XVIMAGE_YV12, 167 XVIMAGE_I420 168 /* XVIMAGE_UYVY */ 169}; 170 171 172 173static int S3SetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute, 174 INT32 value, pointer data) 175{ 176 return BadMatch; 177} 178 179 180static int S3GetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute, 181 INT32 *value, pointer data) 182{ 183 return BadMatch; 184} 185 186 187 188static void S3QueryBestSize(ScrnInfoPtr pScrn, Bool motion, short vid_w, 189 short vid_h, short drw_w, short drw_h, 190 unsigned int *p_w, unsigned int *p_h, 191 pointer data) 192{ 193 *p_w = drw_w; 194 *p_h = drw_h; 195} 196 197 198 199static void S3ResetVideoOverlay(ScrnInfoPtr pScrn) 200{ 201} 202 203 204static XF86VideoAdaptorPtr S3AllocAdaptor(ScrnInfoPtr pScrn) 205{ 206 S3Ptr pS3 = S3PTR(pScrn); 207 XF86VideoAdaptorPtr adapt; 208 S3PortPrivPtr pPriv; 209 int i; 210 211 if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn))) 212 return NULL; 213 214 if(!(pPriv = xcalloc(1, sizeof(S3PortPrivRec) + 215 (sizeof(DevUnion) * S3_MAX_PORTS)))) 216 { 217 xfree(adapt); 218 return NULL; 219 } 220 221 adapt->pPortPrivates = (DevUnion*)(&pPriv[1]); 222 223 for(i = 0; i < S3_MAX_PORTS; i++) 224 adapt->pPortPrivates[i].val = i; 225 226 pPriv->colorKey = (1 << pScrn->offset.red) | 227 (1 << pScrn->offset.green) | 228 (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue); 229 230 pPriv->videoStatus = 0; 231 pPriv->lastPort = -1; 232 233 pS3->adaptor = adapt; 234 pS3->portPrivate = pPriv; 235 236 return adapt; 237} 238 239 240static XF86VideoAdaptorPtr S3SetupImageVideoOverlay(ScreenPtr pScreen) 241{ 242 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 243 S3Ptr pS3 = S3PTR(pScrn); 244 XF86VideoAdaptorPtr adapt; 245 246 adapt = S3AllocAdaptor(pScrn); 247 248 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 249 adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; 250 adapt->name = "S3 Backend Scaler"; 251 adapt->nEncodings = 1; 252 adapt->pEncodings = &DummyEncoding[0]; 253 adapt->nFormats = NUM_FORMATS_OVERLAY; 254 adapt->pFormats = Formats; 255 adapt->nPorts = 1; 256 adapt->pAttributes = NULL /*Attributes*/; 257 adapt->nImages = 3; 258 adapt->nAttributes = 0; 259 260 adapt->pImages = Images; 261 adapt->PutVideo = NULL; 262 adapt->PutStill = NULL; 263 adapt->GetVideo = NULL; 264 adapt->GetStill = NULL; 265 adapt->StopVideo = S3StopVideo; 266 /* Empty Attrib functions - required anyway */ 267 adapt->SetPortAttribute = S3SetPortAttributeOverlay; 268 adapt->GetPortAttribute = S3GetPortAttributeOverlay; 269 adapt->QueryBestSize = S3QueryBestSize; 270 adapt->PutImage = S3PutImage; 271 adapt->QueryImageAttributes = S3QueryImageAttributes; 272 273 /* gotta uninit this someplace */ 274 REGION_NULL(pScreen, &(pS3->portPrivate->clip)); 275 276 S3ResetVideoOverlay(pScrn); 277 278 return adapt; 279} 280 281 282static void S3StopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit) 283{ 284 S3Ptr pS3 = S3PTR(pScrn); 285 S3PortPrivPtr pPriv = pS3->portPrivate; 286 287 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 288 289 if (exit) { 290 SET_FIFO_CNTL(0x00080000 | FIFO_PS24_SS0); 291 292 if (pPriv->videoStatus & CLIENT_VIDEO_ON) { 293 WaitVSync(); 294 SET_SSTREAM_CNTL(0x03000000); 295 SET_SSTREAM_FBADDR0(0x00000000); 296 SET_SSTREAM_FBADDR1(0x00000000); 297 SET_SSTREAM_STRIDE(0x00000001); 298 SET_SSTREAM_START(0x07ff07ff); 299 SET_SSTREAM_WIND(0x00010001); 300 301 SET_CHROMA_KEY(0x00000000); 302 SET_SSTRETCH(0x00000000); 303 SET_OPAQUE_OVERLAY(0x40000000); 304 SET_K1_VSCALE(0x00000000); 305 SET_K2_VSCALE(0x00000000); 306 SET_DDA_VERT(0x00000000); 307 SET_BLEND_CNTL(0x01000000); 308 WaitVSync(); 309 } 310 311 if (pPriv->area) { 312 xf86FreeOffscreenLinear(pPriv->area); 313 pPriv->area = NULL; 314 } 315 316 pPriv->videoStatus = 0; 317 } 318} 319 320static void S3DisplayVideoOverlay(ScrnInfoPtr pScrn, int id, int offset, 321 short width, short height, int pitch, 322 int x1, int y1, int x2, int y2, 323 BoxPtr dstBox, short src_w, short src_h, 324 short drw_w, short drw_h) 325{ 326 S3Ptr pS3 = S3PTR(pScrn); 327 S3PortPrivPtr pPriv = pS3->portPrivate; 328 int tmp; 329 330 if (drw_w == src_w) 331 tmp = 0; 332 else 333 tmp = 2; 334 335 SET_SSTREAM_CNTL((tmp << 28) | 0x01000000 | 336 ((((src_w - 1) << 1) - (drw_w - 1)) & 0xfff)); 337 SET_SSTRETCH(((src_w - 1) & 0x7ff) | 338 (((src_w - drw_w) & 0x7ff) << 16)); 339 SET_BLEND_CNTL(0x05000000); 340 SET_SSTREAM_FBADDR0(offset & 0x3fffff); 341 SET_SSTREAM_FBADDR1(offset & 0x3fffff); 342 SET_SSTREAM_STRIDE(pitch & 0xfff); 343 SET_SSTREAM_START(((dstBox->x1 + 1) << 16) | (dstBox->y1 + 1)); 344 SET_SSTREAM_WIND((((drw_w - 1) << 16) | drw_h) & 0x7ff07ff); 345 346 SET_K1_VSCALE(src_h - 1); 347 SET_K2_VSCALE((src_h - drw_h) & 0x7ff); 348 SET_DDA_VERT(((~drw_h - 1)) & 0xfff); 349 350 SET_CHROMA_KEY(0x10000000 | 351 ((pScrn->weight.red-1) << 24) | 352 ((pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red) << 353 (16 + 8-pScrn->weight.red) | 354 ((pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green) << 355 (8 + 8-pScrn->weight.green) | 356 ((pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue) << 357 (8-pScrn->weight.blue)); 358 359 SET_FIFO_CNTL(0x00080000 | pS3->Streams_FIFO); 360} 361 362static int S3PutImage(ScrnInfoPtr pScrn, short src_x, short src_y, 363 short drw_x, short drw_y, short src_w, short src_h, 364 short drw_w, short drw_h, int id, unsigned char *buf, 365 short width, short height, Bool sync, 366 RegionPtr clipBoxes, pointer data, DrawablePtr pDraw) 367{ 368 S3Ptr pS3 = S3PTR(pScrn); 369 S3PortPrivPtr pPriv = pS3->portPrivate; 370 INT32 x1, x2, y1, y2; 371 CARD8 *dst_start; 372 int offset, offsetV = 0, offsetU = 0; 373 int srcPitch, srcPitchUV = 0, dstPitch, dstSize; 374 int top, bottom, right, left, npixels, nlines; 375 BoxRec dstBox; 376 CARD32 tmp; 377 int cpp = (pScrn->bitsPerPixel + 7) >> 3; 378 379 /* Clip */ 380 x1 = src_x; 381 x2 = src_x + src_w; 382 y1 = src_y; 383 y2 = src_y + src_h; 384 385 dstBox.x1 = drw_x; 386 dstBox.x2 = drw_x + drw_w; 387 dstBox.y1 = drw_y; 388 dstBox.y2 = drw_y + drw_h; 389 390 if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, 391 width, height)) 392 return Success; 393 394 dstBox.x1 -= pScrn->frameX0; 395 dstBox.x2 -= pScrn->frameX0; 396 dstBox.y1 -= pScrn->frameY0; 397 dstBox.y2 -= pScrn->frameY0; 398 399 /* requested size in bytes */ 400 dstPitch = ((width << 1) + 15) & ~15; 401 dstSize = dstPitch * height; 402 403 pPriv->area = S3XVMemAlloc(pScrn, pPriv->area, 404 (dstSize + cpp - 1) / cpp); 405 if (!pPriv->area) 406 return BadAlloc; 407 408 offset = pPriv->area->offset * cpp; 409 dst_start = pS3->FBBase + offset; 410 411 switch (id) { 412 case FOURCC_YV12: 413 case FOURCC_I420: 414 left = (x1 >> 16) & ~1; 415 right = ((x2 + 0x1ffff) >> 16) & ~1; 416 top = (y1 >> 16) & ~1; 417 bottom = ((y2 + 0x1ffff) >> 16) & ~1; 418 419 if ((right < width) && ((x1 & 0x1ffff) <= (x2 & 0x1ffff))) 420 right += 2; 421 if ((bottom < height) && ((y1 & 0x1ffff) <= (y2 & 0x1ffff))) 422 bottom += 2; 423 424 npixels = right - left; 425 nlines = bottom - top; 426 427 srcPitch = (width + 3) & ~3; 428 offsetV = srcPitch * height; 429 srcPitchUV = ((width >> 1) + 3) & ~3; 430 offsetU = ((height >> 1) * srcPitchUV) + offsetV; 431 432 tmp = ((top >> 1) * srcPitchUV) + (left >> 1); 433 offsetV += tmp; 434 offsetU += tmp; 435 436 if (id == FOURCC_I420) 437 { 438 tmp = offsetV; 439 offsetV = offsetU; 440 offsetU = tmp; 441 } 442 443 dst_start += top * dstPitch + (left << 1); 444 445 xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + left, 446 buf + offsetV, buf + offsetU, 447 dst_start, srcPitch, srcPitchUV, 448 dstPitch, nlines, npixels); 449 break; 450 451 case FOURCC_UYVY: 452 case FOURCC_YUY2: 453 default: 454 left = (x1 >> 16) & ~1; 455 right = ((x2 + 0x1ffff) >> 16) & ~1; 456 top = y1 >> 16; 457 bottom = (y2 + 0x0ffff) >> 16; 458 459 if ((right < width) && ((x1 & 0x1ffff) <= (x2 & 0x1ffff))) 460 right += 2; 461 if ((bottom < height) && ((y1 & 0x0ffff) <= (y2 & 0x0ffff))) 462 bottom++; 463 464 npixels = right - left; 465 nlines = bottom - top; 466 467 srcPitch = width << 1; 468 buf += (top * srcPitch) + (left << 1); 469 dst_start += top * dstPitch + (left << 1); 470 471 xf86XVCopyPacked(buf, dst_start, srcPitch, dstPitch, 472 nlines, npixels); 473 break; 474 } 475 476 /* update cliplist */ 477 if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) { 478 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); 479 /* draw these */ 480 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, 481 clipBoxes); 482 } 483 484 offset += (left << 1) + (top * dstPitch); 485 S3DisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch, 486 x1, y1, x2, y2, &dstBox, 487 src_w, src_h, drw_w, drw_h); 488 489 pPriv->videoStatus = CLIENT_VIDEO_ON; 490 return Success; 491} 492 493 494 495static int S3QueryImageAttributes(ScrnInfoPtr pScrn, int id, 496 unsigned short *w, unsigned short *h, 497 int *pitches, int *offsets) 498{ 499 int size, tmp; 500 501 *w = (*w + 1) & ~1; 502 if(offsets) offsets[0] = 0; 503 504 switch(id) { 505 case FOURCC_YV12: 506 case FOURCC_I420: 507 *h = (*h + 1) & ~1; 508 size = (*w + 3) & ~3; 509 if(pitches) pitches[0] = size; 510 size *= *h; 511 if(offsets) offsets[1] = size; 512 tmp = ((*w >> 1) + 3) & ~3; 513 if(pitches) pitches[1] = pitches[2] = tmp; 514 tmp *= (*h >> 1); 515 size += tmp; 516 if(offsets) offsets[2] = size; 517 size += tmp; 518 break; 519 case FOURCC_UYVY: 520 case FOURCC_YUY2: 521 default: 522 size = *w << 1; 523 if(pitches) pitches[0] = size; 524 size *= *h; 525 break; 526 } 527 528 return size; 529} 530 531 532void S3InitStreams(ScrnInfoPtr pScrn, DisplayModePtr mode) 533{ 534 S3Ptr pS3 = S3PTR(pScrn); 535 unsigned int pst_wind = (mode->HDisplay-1) << 16 | (mode->VDisplay); 536 537 WaitVSync(); 538 539 switch (pScrn->bitsPerPixel) { 540 case 8: 541 SET_PSTREAM_CNTL(0x00000000); 542 break; 543 case 15: 544 SET_PSTREAM_CNTL(0x03000000); 545 break; 546 case 16: 547 SET_PSTREAM_CNTL(0x05000000); 548 break; 549 case 24: 550 SET_PSTREAM_CNTL(0x06000000); 551 break; 552 case 32: 553 SET_PSTREAM_CNTL(0x07000000); 554 break; 555 } 556 557 SET_PSTREAM_FBADDR0(0x00000000); 558 SET_PSTREAM_FBADDR1(0x00000000); 559 560 SET_PSTREAM_STRIDE(pS3->s3BppDisplayWidth & 0x0fff); 561 562 SET_PSTREAM_WIND(pst_wind & 0x07ff07ff); 563 SET_PSTREAM_START(0x00010001); 564 565 SET_CHROMA_KEY(0x00000000); 566 SET_SSTRETCH(0x00000000); 567 SET_BLEND_CNTL(0x01000000); 568 SET_DOUBLE_BUFFER(0x00000000); 569 570 SET_SSTREAM_CNTL(0x03000000); 571 SET_SSTREAM_FBADDR0(0x00000000); 572 SET_SSTREAM_FBADDR1(0x00000000); 573 SET_SSTREAM_STRIDE(0x00000001); 574 SET_SSTREAM_START(0x07ff07ff); 575 SET_SSTREAM_WIND(0x00010001); 576 577 SET_OPAQUE_OVERLAY(0x40000000); 578 SET_K1_VSCALE(0x00000000); 579 SET_K2_VSCALE(0x00000000); 580 SET_DDA_VERT(0x00000000); 581 582 /* 583 ps thr | ss thr | ss fifo slots 584 set primary stream FIFO to 24 slots and 12 slots for threshold 585 */ 586 SET_FIFO_CNTL(0x00080000 | FIFO_PS24_SS0); 587} 588 589