s3_video.c revision b27e1915
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 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 malloc((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 free(newAdaptors); 97} 98 99 100/* client libraries expect an encoding */ 101static XF86VideoEncodingRec DummyEncoding[2] = 102{ 103 { /* overlay limit */ 104 0, 105 "XV_IMAGE", 106 1024, 1024, 107 {1, 1} 108 }, 109 { /* texture limit */ 110 0, 111 "XV_IMAGE", 112 2046, 2046, 113 {1, 1} 114 } 115}; 116 117 118static FBLinearPtr S3XVMemAlloc(ScrnInfoPtr pScrn, pointer pVideo, int size) 119{ 120 FBLinearPtr pLinear = (FBLinearPtr)pVideo; 121 ScreenPtr pScreen = pScrn->pScreen; 122 123 if (pLinear) { 124 if ((pLinear->size >= size) || 125 xf86ResizeOffscreenLinear(pLinear, size)) { 126 pLinear->MoveLinearCallback = NULL; 127 pLinear->RemoveLinearCallback = NULL; 128 return pLinear; 129 } 130 xf86FreeOffscreenLinear(pLinear); 131 } 132 pLinear = xf86AllocateOffscreenLinear(pScreen, size, 16, 133 NULL, NULL, NULL); 134 135 if (!pLinear) { 136 int maxSize; 137 138 xf86QueryLargestOffscreenLinear(pScreen, &maxSize, 16, 139 PRIORITY_EXTREME); 140 if (maxSize < size) 141 return NULL; 142 143 xf86PurgeUnlockedOffscreenAreas(pScreen); 144 pLinear = xf86AllocateOffscreenLinear(pScreen, size, 16, 145 NULL, NULL, NULL); 146 } 147 return pLinear; 148} 149 150static XF86VideoFormatRec Formats[NUM_FORMATS_TEXTURE] = 151{ 152 {16, TrueColor}, {24, TrueColor}, 153 {16, DirectColor}, {24, DirectColor} 154}; 155 156 157 158#define NUM_IMAGES 3 159 160static XF86ImageRec Images[NUM_IMAGES] = 161{ 162 XVIMAGE_YUY2, 163 /* As in mga, YV12 & I420 are converted to YUY2 on the fly by */ 164 /* copy over conversion. */ 165 XVIMAGE_YV12, 166 XVIMAGE_I420 167 /* XVIMAGE_UYVY */ 168}; 169 170 171 172static int S3SetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute, 173 INT32 value, pointer data) 174{ 175 return BadMatch; 176} 177 178 179static int S3GetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute, 180 INT32 *value, pointer data) 181{ 182 return BadMatch; 183} 184 185 186 187static void S3QueryBestSize(ScrnInfoPtr pScrn, Bool motion, short vid_w, 188 short vid_h, short drw_w, short drw_h, 189 unsigned int *p_w, unsigned int *p_h, 190 pointer data) 191{ 192 *p_w = drw_w; 193 *p_h = drw_h; 194} 195 196 197 198static void S3ResetVideoOverlay(ScrnInfoPtr pScrn) 199{ 200} 201 202 203static XF86VideoAdaptorPtr S3AllocAdaptor(ScrnInfoPtr pScrn) 204{ 205 S3Ptr pS3 = S3PTR(pScrn); 206 XF86VideoAdaptorPtr adapt; 207 S3PortPrivPtr pPriv; 208 int i; 209 210 if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn))) 211 return NULL; 212 213 if(!(pPriv = calloc(1, sizeof(S3PortPrivRec) + 214 (sizeof(DevUnion) * S3_MAX_PORTS)))) 215 { 216 free(adapt); 217 return NULL; 218 } 219 220 adapt->pPortPrivates = (DevUnion*)(&pPriv[1]); 221 222 for(i = 0; i < S3_MAX_PORTS; i++) 223 adapt->pPortPrivates[i].val = i; 224 225 pPriv->colorKey = (1 << pScrn->offset.red) | 226 (1 << pScrn->offset.green) | 227 (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue); 228 229 pPriv->videoStatus = 0; 230 pPriv->lastPort = -1; 231 232 pS3->adaptor = adapt; 233 pS3->portPrivate = pPriv; 234 235 return adapt; 236} 237 238 239static XF86VideoAdaptorPtr S3SetupImageVideoOverlay(ScreenPtr pScreen) 240{ 241 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 242 S3Ptr pS3 = S3PTR(pScrn); 243 XF86VideoAdaptorPtr adapt; 244 245 adapt = S3AllocAdaptor(pScrn); 246 if (adapt == NULL) 247 return NULL; 248 249 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 250 adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; 251 adapt->name = "S3 Backend Scaler"; 252 adapt->nEncodings = 1; 253 adapt->pEncodings = &DummyEncoding[0]; 254 adapt->nFormats = NUM_FORMATS_OVERLAY; 255 adapt->pFormats = Formats; 256 adapt->nPorts = 1; 257 adapt->pAttributes = NULL /*Attributes*/; 258 adapt->nImages = 3; 259 adapt->nAttributes = 0; 260 261 adapt->pImages = Images; 262 adapt->PutVideo = NULL; 263 adapt->PutStill = NULL; 264 adapt->GetVideo = NULL; 265 adapt->GetStill = NULL; 266 adapt->StopVideo = S3StopVideo; 267 /* Empty Attrib functions - required anyway */ 268 adapt->SetPortAttribute = S3SetPortAttributeOverlay; 269 adapt->GetPortAttribute = S3GetPortAttributeOverlay; 270 adapt->QueryBestSize = S3QueryBestSize; 271 adapt->PutImage = S3PutImage; 272 adapt->QueryImageAttributes = S3QueryImageAttributes; 273 274 /* gotta uninit this someplace */ 275 REGION_NULL(pScreen, &(pS3->portPrivate->clip)); 276 277 S3ResetVideoOverlay(pScrn); 278 279 return adapt; 280} 281 282 283static void S3StopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit) 284{ 285 S3Ptr pS3 = S3PTR(pScrn); 286 S3PortPrivPtr pPriv = pS3->portPrivate; 287 288 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 289 290 if (exit) { 291 SET_FIFO_CNTL(0x00080000 | FIFO_PS24_SS0); 292 293 if (pPriv->videoStatus & CLIENT_VIDEO_ON) { 294 WaitVSync(); 295 SET_SSTREAM_CNTL(0x03000000); 296 SET_SSTREAM_FBADDR0(0x00000000); 297 SET_SSTREAM_FBADDR1(0x00000000); 298 SET_SSTREAM_STRIDE(0x00000001); 299 SET_SSTREAM_START(0x07ff07ff); 300 SET_SSTREAM_WIND(0x00010001); 301 302 SET_CHROMA_KEY(0x00000000); 303 SET_SSTRETCH(0x00000000); 304 SET_OPAQUE_OVERLAY(0x40000000); 305 SET_K1_VSCALE(0x00000000); 306 SET_K2_VSCALE(0x00000000); 307 SET_DDA_VERT(0x00000000); 308 SET_BLEND_CNTL(0x01000000); 309 WaitVSync(); 310 } 311 312 if (pPriv->area) { 313 xf86FreeOffscreenLinear(pPriv->area); 314 pPriv->area = NULL; 315 } 316 317 pPriv->videoStatus = 0; 318 } 319} 320 321static void S3DisplayVideoOverlay(ScrnInfoPtr pScrn, int id, int offset, 322 short width, short height, int pitch, 323 int x1, int y1, int x2, int y2, 324 BoxPtr dstBox, short src_w, short src_h, 325 short drw_w, short drw_h) 326{ 327 S3Ptr pS3 = S3PTR(pScrn); 328 S3PortPrivPtr pPriv = pS3->portPrivate; 329 int tmp; 330 331 if (drw_w == src_w) 332 tmp = 0; 333 else 334 tmp = 2; 335 336 SET_SSTREAM_CNTL((tmp << 28) | 0x01000000 | 337 ((((src_w - 1) << 1) - (drw_w - 1)) & 0xfff)); 338 SET_SSTRETCH(((src_w - 1) & 0x7ff) | 339 (((src_w - drw_w) & 0x7ff) << 16)); 340 SET_BLEND_CNTL(0x05000000); 341 SET_SSTREAM_FBADDR0(offset & 0x3fffff); 342 SET_SSTREAM_FBADDR1(offset & 0x3fffff); 343 SET_SSTREAM_STRIDE(pitch & 0xfff); 344 SET_SSTREAM_START(((dstBox->x1 + 1) << 16) | (dstBox->y1 + 1)); 345 SET_SSTREAM_WIND((((drw_w - 1) << 16) | drw_h) & 0x7ff07ff); 346 347 SET_K1_VSCALE(src_h - 1); 348 SET_K2_VSCALE((src_h - drw_h) & 0x7ff); 349 SET_DDA_VERT(((~drw_h - 1)) & 0xfff); 350 351 SET_CHROMA_KEY(0x10000000 | 352 ((pScrn->weight.red-1) << 24) | 353 ((pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red) << 354 (16 + 8-pScrn->weight.red) | 355 ((pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green) << 356 (8 + 8-pScrn->weight.green) | 357 ((pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue) << 358 (8-pScrn->weight.blue)); 359 360 SET_FIFO_CNTL(0x00080000 | pS3->Streams_FIFO); 361} 362 363static int S3PutImage(ScrnInfoPtr pScrn, short src_x, short src_y, 364 short drw_x, short drw_y, short src_w, short src_h, 365 short drw_w, short drw_h, int id, unsigned char *buf, 366 short width, short height, Bool sync, 367 RegionPtr clipBoxes, pointer data, DrawablePtr pDraw) 368{ 369 S3Ptr pS3 = S3PTR(pScrn); 370 S3PortPrivPtr pPriv = pS3->portPrivate; 371 INT32 x1, x2, y1, y2; 372 CARD8 *dst_start; 373 int offset, offsetV = 0, offsetU = 0; 374 int srcPitch, srcPitchUV = 0, dstPitch, dstSize; 375 int top, bottom, right, left, npixels, nlines; 376 BoxRec dstBox; 377 CARD32 tmp; 378 int cpp = (pScrn->bitsPerPixel + 7) >> 3; 379 380 /* Clip */ 381 x1 = src_x; 382 x2 = src_x + src_w; 383 y1 = src_y; 384 y2 = src_y + src_h; 385 386 dstBox.x1 = drw_x; 387 dstBox.x2 = drw_x + drw_w; 388 dstBox.y1 = drw_y; 389 dstBox.y2 = drw_y + drw_h; 390 391 if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, 392 width, height)) 393 return Success; 394 395 dstBox.x1 -= pScrn->frameX0; 396 dstBox.x2 -= pScrn->frameX0; 397 dstBox.y1 -= pScrn->frameY0; 398 dstBox.y2 -= pScrn->frameY0; 399 400 /* requested size in bytes */ 401 dstPitch = ((width << 1) + 15) & ~15; 402 dstSize = dstPitch * height; 403 404 pPriv->area = S3XVMemAlloc(pScrn, pPriv->area, 405 (dstSize + cpp - 1) / cpp); 406 if (!pPriv->area) 407 return BadAlloc; 408 409 offset = pPriv->area->offset * cpp; 410 dst_start = pS3->FBBase + offset; 411 412 switch (id) { 413 case FOURCC_YV12: 414 case FOURCC_I420: 415 left = (x1 >> 16) & ~1; 416 right = ((x2 + 0x1ffff) >> 16) & ~1; 417 top = (y1 >> 16) & ~1; 418 bottom = ((y2 + 0x1ffff) >> 16) & ~1; 419 420 if ((right < width) && ((x1 & 0x1ffff) <= (x2 & 0x1ffff))) 421 right += 2; 422 if ((bottom < height) && ((y1 & 0x1ffff) <= (y2 & 0x1ffff))) 423 bottom += 2; 424 425 npixels = right - left; 426 nlines = bottom - top; 427 428 srcPitch = (width + 3) & ~3; 429 offsetV = srcPitch * height; 430 srcPitchUV = ((width >> 1) + 3) & ~3; 431 offsetU = ((height >> 1) * srcPitchUV) + offsetV; 432 433 tmp = ((top >> 1) * srcPitchUV) + (left >> 1); 434 offsetV += tmp; 435 offsetU += tmp; 436 437 if (id == FOURCC_I420) 438 { 439 tmp = offsetV; 440 offsetV = offsetU; 441 offsetU = tmp; 442 } 443 444 dst_start += top * dstPitch + (left << 1); 445 446 xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + left, 447 buf + offsetV, buf + offsetU, 448 dst_start, srcPitch, srcPitchUV, 449 dstPitch, nlines, npixels); 450 break; 451 452 case FOURCC_UYVY: 453 case FOURCC_YUY2: 454 default: 455 left = (x1 >> 16) & ~1; 456 right = ((x2 + 0x1ffff) >> 16) & ~1; 457 top = y1 >> 16; 458 bottom = (y2 + 0x0ffff) >> 16; 459 460 if ((right < width) && ((x1 & 0x1ffff) <= (x2 & 0x1ffff))) 461 right += 2; 462 if ((bottom < height) && ((y1 & 0x0ffff) <= (y2 & 0x0ffff))) 463 bottom++; 464 465 npixels = right - left; 466 nlines = bottom - top; 467 468 srcPitch = width << 1; 469 buf += (top * srcPitch) + (left << 1); 470 dst_start += top * dstPitch + (left << 1); 471 472 xf86XVCopyPacked(buf, dst_start, srcPitch, dstPitch, 473 nlines, npixels); 474 break; 475 } 476 477 /* update cliplist */ 478 if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) { 479 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); 480 /* draw these */ 481 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, 482 clipBoxes); 483 } 484 485 offset += (left << 1) + (top * dstPitch); 486 S3DisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch, 487 x1, y1, x2, y2, &dstBox, 488 src_w, src_h, drw_w, drw_h); 489 490 pPriv->videoStatus = CLIENT_VIDEO_ON; 491 return Success; 492} 493 494 495 496static int S3QueryImageAttributes(ScrnInfoPtr pScrn, int id, 497 unsigned short *w, unsigned short *h, 498 int *pitches, int *offsets) 499{ 500 int size, tmp; 501 502 *w = (*w + 1) & ~1; 503 if(offsets) offsets[0] = 0; 504 505 switch(id) { 506 case FOURCC_YV12: 507 case FOURCC_I420: 508 *h = (*h + 1) & ~1; 509 size = (*w + 3) & ~3; 510 if(pitches) pitches[0] = size; 511 size *= *h; 512 if(offsets) offsets[1] = size; 513 tmp = ((*w >> 1) + 3) & ~3; 514 if(pitches) pitches[1] = pitches[2] = tmp; 515 tmp *= (*h >> 1); 516 size += tmp; 517 if(offsets) offsets[2] = size; 518 size += tmp; 519 break; 520 case FOURCC_UYVY: 521 case FOURCC_YUY2: 522 default: 523 size = *w << 1; 524 if(pitches) pitches[0] = size; 525 size *= *h; 526 break; 527 } 528 529 return size; 530} 531 532 533void S3InitStreams(ScrnInfoPtr pScrn, DisplayModePtr mode) 534{ 535 S3Ptr pS3 = S3PTR(pScrn); 536 unsigned int pst_wind = (mode->HDisplay-1) << 16 | (mode->VDisplay); 537 538 WaitVSync(); 539 540 switch (pScrn->bitsPerPixel) { 541 case 8: 542 SET_PSTREAM_CNTL(0x00000000); 543 break; 544 case 15: 545 SET_PSTREAM_CNTL(0x03000000); 546 break; 547 case 16: 548 SET_PSTREAM_CNTL(0x05000000); 549 break; 550 case 24: 551 SET_PSTREAM_CNTL(0x06000000); 552 break; 553 case 32: 554 SET_PSTREAM_CNTL(0x07000000); 555 break; 556 } 557 558 SET_PSTREAM_FBADDR0(0x00000000); 559 SET_PSTREAM_FBADDR1(0x00000000); 560 561 SET_PSTREAM_STRIDE(pS3->s3BppDisplayWidth & 0x0fff); 562 563 SET_PSTREAM_WIND(pst_wind & 0x07ff07ff); 564 SET_PSTREAM_START(0x00010001); 565 566 SET_CHROMA_KEY(0x00000000); 567 SET_SSTRETCH(0x00000000); 568 SET_BLEND_CNTL(0x01000000); 569 SET_DOUBLE_BUFFER(0x00000000); 570 571 SET_SSTREAM_CNTL(0x03000000); 572 SET_SSTREAM_FBADDR0(0x00000000); 573 SET_SSTREAM_FBADDR1(0x00000000); 574 SET_SSTREAM_STRIDE(0x00000001); 575 SET_SSTREAM_START(0x07ff07ff); 576 SET_SSTREAM_WIND(0x00010001); 577 578 SET_OPAQUE_OVERLAY(0x40000000); 579 SET_K1_VSCALE(0x00000000); 580 SET_K2_VSCALE(0x00000000); 581 SET_DDA_VERT(0x00000000); 582 583 /* 584 ps thr | ss thr | ss fifo slots 585 set primary stream FIFO to 24 slots and 12 slots for threshold 586 */ 587 SET_FIFO_CNTL(0x00080000 | FIFO_PS24_SS0); 588} 589 590