s3_video.c revision bd35f0db
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 SET_BLEND_CNTL(0x01000000); 294 295 if (pPriv->area) { 296 xf86FreeOffscreenLinear(pPriv->area); 297 pPriv->area = NULL; 298 } 299 300 pPriv->videoStatus = 0; 301 } 302} 303 304static void S3DisplayVideoOverlay(ScrnInfoPtr pScrn, int id, int offset, 305 short width, short height, int pitch, 306 int x1, int y1, int x2, int y2, 307 BoxPtr dstBox, short src_w, short src_h, 308 short drw_w, short drw_h) 309{ 310 S3Ptr pS3 = S3PTR(pScrn); 311 S3PortPrivPtr pPriv = pS3->portPrivate; 312 int tmp; 313 314 if (drw_w == src_w) 315 tmp = 0; 316 else 317 tmp = 2; 318 319 SET_SSTREAM_CNTL((tmp << 28) | 0x01000000 | 320 ((((src_w - 1) << 1) - (drw_w - 1)) & 0xfff)); 321 SET_SSTRETCH(((src_w - 1) & 0x7ff) | 322 (((src_w - drw_w) & 0x7ff) << 16)); 323 SET_BLEND_CNTL(0x05000000); 324 SET_SSTREAM_FBADDR0(offset & 0x3fffff); 325 SET_SSTREAM_FBADDR1(offset & 0x3fffff); 326 SET_SSTREAM_STRIDE(pitch & 0xfff); 327 SET_SSTREAM_START(((dstBox->x1 + 1) << 16) | (dstBox->y1 + 1)); 328 SET_SSTREAM_WIND((((drw_w - 1) << 16) | drw_h) & 0x7ff07ff); 329 330 SET_K1_VSCALE(src_h - 1); 331 SET_K2_VSCALE((src_h - drw_h) & 0x7ff); 332 SET_DDA_VERT(((~drw_h - 1)) & 0xfff); 333 334 SET_CHROMA_KEY(0x10000000 | 335 ((pScrn->weight.red-1) << 24) | 336 ((pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red) << 337 (16 + 8-pScrn->weight.red) | 338 ((pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green) << 339 (8 + 8-pScrn->weight.green) | 340 ((pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue) << 341 (8-pScrn->weight.blue)); 342 343 SET_FIFO_CNTL(0x00080000 | pS3->Streams_FIFO); 344} 345 346static int S3PutImage(ScrnInfoPtr pScrn, short src_x, short src_y, 347 short drw_x, short drw_y, short src_w, short src_h, 348 short drw_w, short drw_h, int id, unsigned char *buf, 349 short width, short height, Bool sync, 350 RegionPtr clipBoxes, pointer data, DrawablePtr pDraw) 351{ 352 S3Ptr pS3 = S3PTR(pScrn); 353 S3PortPrivPtr pPriv = pS3->portPrivate; 354 INT32 x1, x2, y1, y2; 355 CARD8 *dst_start; 356 int pitch, new_h, offset, offsetV = 0, offsetU = 0; 357 int srcPitch, srcPitchUV = 0, dstPitch, dstSize; 358 int top, bottom, right, left, npixels, nlines; 359 BoxRec dstBox; 360 CARD32 tmp; 361 int cpp = (pScrn->bitsPerPixel + 7) >> 3; 362 363 /* Clip */ 364 x1 = src_x; 365 x2 = src_x + src_w; 366 y1 = src_y; 367 y2 = src_y + src_h; 368 369 dstBox.x1 = drw_x; 370 dstBox.x2 = drw_x + drw_w; 371 dstBox.y1 = drw_y; 372 dstBox.y2 = drw_y + drw_h; 373 374 if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, 375 width, height)) 376 return Success; 377 378 dstBox.x1 -= pScrn->frameX0; 379 dstBox.x2 -= pScrn->frameX0; 380 dstBox.y1 -= pScrn->frameY0; 381 dstBox.y2 -= pScrn->frameY0; 382 383 /* requested size in bytes */ 384 dstPitch = ((width << 1) + 15) & ~15; 385 dstSize = dstPitch * height; 386 387 pPriv->area = S3XVMemAlloc(pScrn, pPriv->area, 388 (dstSize + cpp - 1) / cpp); 389 if (!pPriv->area) 390 return BadAlloc; 391 392 offset = pPriv->area->offset * cpp; 393 dst_start = pS3->FBBase + offset; 394 395 switch (id) { 396 case FOURCC_YV12: 397 case FOURCC_I420: 398 left = (x1 >> 16) & ~1; 399 right = ((x2 + 0x1ffff) >> 16) & ~1; 400 top = (y1 >> 16) & ~1; 401 bottom = ((y2 + 0x1ffff) >> 16) & ~1; 402 403 if ((right < width) && ((x1 & 0x1ffff) <= (x2 & 0x1ffff))) 404 right += 2; 405 if ((bottom < height) && ((y1 & 0x1ffff) <= (y2 & 0x1ffff))) 406 bottom += 2; 407 408 npixels = right - left; 409 nlines = bottom - top; 410 411 srcPitch = (width + 3) & ~3; 412 offsetV = srcPitch * height; 413 srcPitchUV = ((width >> 1) + 3) & ~3; 414 offsetU = ((height >> 1) * srcPitchUV) + offsetV; 415 416 tmp = ((top >> 1) * srcPitchUV) + (left >> 1); 417 offsetV += tmp; 418 offsetU += tmp; 419 420 if (id == FOURCC_I420) 421 { 422 tmp = offsetV; 423 offsetV = offsetU; 424 offsetU = tmp; 425 } 426 427 dst_start += top * dstPitch + (left << 1); 428 429 xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + left, 430 buf + offsetV, buf + offsetU, 431 dst_start, srcPitch, srcPitchUV, 432 dstPitch, nlines, npixels); 433 break; 434 435 case FOURCC_UYVY: 436 case FOURCC_YUY2: 437 default: 438 left = (x1 >> 16) & ~1; 439 right = ((x2 + 0x1ffff) >> 16) & ~1; 440 top = y1 >> 16; 441 bottom = (y2 + 0x0ffff) >> 16; 442 443 if ((right < width) && ((x1 & 0x1ffff) <= (x2 & 0x1ffff))) 444 right += 2; 445 if ((bottom < height) && ((y1 & 0x0ffff) <= (y2 & 0x0ffff))) 446 bottom++; 447 448 npixels = right - left; 449 nlines = bottom - top; 450 451 srcPitch = width << 1; 452 buf += (top * srcPitch) + (left << 1); 453 dst_start += top * dstPitch + (left << 1); 454 455 xf86XVCopyPacked(buf, dst_start, srcPitch, dstPitch, 456 nlines, npixels); 457 break; 458 } 459 460 /* update cliplist */ 461 if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) { 462 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); 463 /* draw these */ 464 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, 465 clipBoxes); 466 } 467 468 offset += (left << 1) + (top * dstPitch); 469 S3DisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch, 470 x1, y1, x2, y2, &dstBox, 471 src_w, src_h, drw_w, drw_h); 472 473 pPriv->videoStatus = CLIENT_VIDEO_ON; 474 return Success; 475} 476 477 478 479static int S3QueryImageAttributes(ScrnInfoPtr pScrn, int id, 480 unsigned short *w, unsigned short *h, 481 int *pitches, int *offsets) 482{ 483 int size, tmp; 484 485 *w = (*w + 1) & ~1; 486 if(offsets) offsets[0] = 0; 487 488 switch(id) { 489 case FOURCC_YV12: 490 case FOURCC_I420: 491 *h = (*h + 1) & ~1; 492 size = (*w + 3) & ~3; 493 if(pitches) pitches[0] = size; 494 size *= *h; 495 if(offsets) offsets[1] = size; 496 tmp = ((*w >> 1) + 3) & ~3; 497 if(pitches) pitches[1] = pitches[2] = tmp; 498 tmp *= (*h >> 1); 499 size += tmp; 500 if(offsets) offsets[2] = size; 501 size += tmp; 502 break; 503 case FOURCC_UYVY: 504 case FOURCC_YUY2: 505 default: 506 size = *w << 1; 507 if(pitches) pitches[0] = size; 508 size *= *h; 509 break; 510 } 511 512 return size; 513} 514 515 516void S3InitStreams(ScrnInfoPtr pScrn, DisplayModePtr mode) 517{ 518 S3Ptr pS3 = S3PTR(pScrn); 519 unsigned int pst_wind = (mode->HDisplay-1) << 16 | (mode->VDisplay); 520 521 WaitVSync(); 522 523 switch (pScrn->bitsPerPixel) { 524 case 8: 525 SET_PSTREAM_CNTL(0x00000000); 526 break; 527 case 15: 528 SET_PSTREAM_CNTL(0x03000000); 529 break; 530 case 16: 531 SET_PSTREAM_CNTL(0x05000000); 532 break; 533 case 24: 534 SET_PSTREAM_CNTL(0x06000000); 535 break; 536 case 32: 537 SET_PSTREAM_CNTL(0x07000000); 538 break; 539 } 540 541 SET_PSTREAM_FBADDR0(0x00000000); 542 SET_PSTREAM_FBADDR1(0x00000000); 543 544 SET_PSTREAM_STRIDE(pS3->s3BppDisplayWidth & 0x0fff); 545 546 SET_PSTREAM_WIND(pst_wind & 0x07ff07ff); 547 SET_PSTREAM_START(0x00010001); 548 549 SET_CHROMA_KEY(0x00000000); 550 SET_SSTRETCH(0x00000000); 551 SET_BLEND_CNTL(0x01000000); 552 SET_DOUBLE_BUFFER(0x00000000); 553 554 SET_SSTREAM_CNTL(0x03000000); 555 SET_SSTREAM_FBADDR0(0x00000000); 556 SET_SSTREAM_FBADDR1(0x00000000); 557 SET_SSTREAM_STRIDE(0x00000001); 558 SET_SSTREAM_START(0x07ff07ff); 559 SET_SSTREAM_WIND(0x00010001); 560 561 SET_OPAQUE_OVERLAY(0x40000000); 562 SET_K1_VSCALE(0x00000000); 563 SET_K2_VSCALE(0x00000000); 564 SET_DDA_VERT(0x00000000); 565 566 /* 567 ps thr | ss thr | ss fifo slots 568 set primary stream FIFO to 24 slots and 12 slots for threshold 569 */ 570 SET_FIFO_CNTL(0x00080000 | FIFO_PS24_SS0); 571} 572 573