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 = xf86ScreenToScrn(pScreen); 66 XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; 67 XF86VideoAdaptorPtr newAdaptor = NULL; 68 int num_adaptors; 69 70 newAdaptor = S3SetupImageVideoOverlay(pScreen); 71 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using overlay video\n"); 72 73 num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); 74 75 if(newAdaptor) { 76 if(!num_adaptors) { 77 num_adaptors = 1; 78 adaptors = &newAdaptor; 79 } else { 80 newAdaptors = /* need to free this someplace */ 81 malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); 82 if(newAdaptors) { 83 memcpy(newAdaptors, adaptors, num_adaptors * 84 sizeof(XF86VideoAdaptorPtr)); 85 newAdaptors[num_adaptors] = newAdaptor; 86 adaptors = newAdaptors; 87 num_adaptors++; 88 } 89 } 90 } 91 92 if(num_adaptors) 93 xf86XVScreenInit(pScreen, adaptors, num_adaptors); 94 95 free(newAdaptors); 96} 97 98 99/* client libraries expect an encoding */ 100static XF86VideoEncodingRec DummyEncoding[2] = 101{ 102 { /* overlay limit */ 103 0, 104 "XV_IMAGE", 105 1024, 1024, 106 {1, 1} 107 }, 108 { /* texture limit */ 109 0, 110 "XV_IMAGE", 111 2046, 2046, 112 {1, 1} 113 } 114}; 115 116 117static FBLinearPtr S3XVMemAlloc(ScrnInfoPtr pScrn, pointer pVideo, int size) 118{ 119 FBLinearPtr pLinear = (FBLinearPtr)pVideo; 120 ScreenPtr pScreen = pScrn->pScreen; 121 122 if (pLinear) { 123 if ((pLinear->size >= size) || 124 xf86ResizeOffscreenLinear(pLinear, size)) { 125 pLinear->MoveLinearCallback = NULL; 126 pLinear->RemoveLinearCallback = NULL; 127 return pLinear; 128 } 129 xf86FreeOffscreenLinear(pLinear); 130 } 131 pLinear = xf86AllocateOffscreenLinear(pScreen, size, 16, 132 NULL, NULL, NULL); 133 134 if (!pLinear) { 135 int maxSize; 136 137 xf86QueryLargestOffscreenLinear(pScreen, &maxSize, 16, 138 PRIORITY_EXTREME); 139 if (maxSize < size) 140 return NULL; 141 142 xf86PurgeUnlockedOffscreenAreas(pScreen); 143 pLinear = xf86AllocateOffscreenLinear(pScreen, size, 16, 144 NULL, NULL, NULL); 145 } 146 return pLinear; 147} 148 149static XF86VideoFormatRec Formats[NUM_FORMATS_TEXTURE] = 150{ 151 {16, TrueColor}, {24, TrueColor}, 152 {16, DirectColor}, {24, DirectColor} 153}; 154 155 156 157#define NUM_IMAGES 3 158 159static XF86ImageRec Images[NUM_IMAGES] = 160{ 161 XVIMAGE_YUY2, 162 /* As in mga, YV12 & I420 are converted to YUY2 on the fly by */ 163 /* copy over conversion. */ 164 XVIMAGE_YV12, 165 XVIMAGE_I420 166 /* XVIMAGE_UYVY */ 167}; 168 169 170 171static int S3SetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute, 172 INT32 value, pointer data) 173{ 174 return BadMatch; 175} 176 177 178static int S3GetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute, 179 INT32 *value, pointer data) 180{ 181 return BadMatch; 182} 183 184 185 186static void S3QueryBestSize(ScrnInfoPtr pScrn, Bool motion, short vid_w, 187 short vid_h, short drw_w, short drw_h, 188 unsigned int *p_w, unsigned int *p_h, 189 pointer data) 190{ 191 *p_w = drw_w; 192 *p_h = drw_h; 193} 194 195 196 197static void S3ResetVideoOverlay(ScrnInfoPtr pScrn) 198{ 199} 200 201 202static XF86VideoAdaptorPtr S3AllocAdaptor(ScrnInfoPtr pScrn) 203{ 204 S3Ptr pS3 = S3PTR(pScrn); 205 XF86VideoAdaptorPtr adapt; 206 S3PortPrivPtr pPriv; 207 int i; 208 209 if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn))) 210 return NULL; 211 212 if(!(pPriv = calloc(1, sizeof(S3PortPrivRec) + 213 (sizeof(DevUnion) * S3_MAX_PORTS)))) 214 { 215 free(adapt); 216 return NULL; 217 } 218 219 adapt->pPortPrivates = (DevUnion*)(&pPriv[1]); 220 221 for(i = 0; i < S3_MAX_PORTS; i++) 222 adapt->pPortPrivates[i].val = i; 223 224 pPriv->colorKey = (1 << pScrn->offset.red) | 225 (1 << pScrn->offset.green) | 226 (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue); 227 228 pPriv->videoStatus = 0; 229 pPriv->lastPort = -1; 230 231 pS3->adaptor = adapt; 232 pS3->portPrivate = pPriv; 233 234 return adapt; 235} 236 237 238static XF86VideoAdaptorPtr S3SetupImageVideoOverlay(ScreenPtr pScreen) 239{ 240 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 241 S3Ptr pS3 = S3PTR(pScrn); 242 XF86VideoAdaptorPtr adapt; 243 244 adapt = S3AllocAdaptor(pScrn); 245 if (adapt == NULL) 246 return NULL; 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