s3_video.c revision 340e3fbd
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/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/s3/s3_video.c,v 1.4tsi Exp $ */ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#include "xf86.h" 34#include "xf86_OSproc.h" 35 36#include "compiler.h" 37 38#include "s3.h" 39#include "s3_reg.h" 40 41 42#define CLIENT_VIDEO_ON 0x04 43#define S3_MAX_PORTS 1 44#define NUM_FORMATS_OVERLAY 4 45#define NUM_FORMATS_TEXTURE 4 46 47 48static XF86VideoAdaptorPtr S3AllocAdaptor(ScrnInfoPtr pScrn); 49static XF86VideoAdaptorPtr S3SetupImageVideoOverlay(ScreenPtr); 50static int S3SetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer); 51static int S3GetPortAttributeOverlay(ScrnInfoPtr, Atom ,INT32 *, pointer); 52static void S3StopVideo(ScrnInfoPtr, pointer, Bool); 53static void S3QueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, 54 unsigned int *, unsigned int *, pointer); 55static int S3PutImage(ScrnInfoPtr, short, short, short, short, short, 56 short, short, short, int, unsigned char*, short, 57 short, Bool, RegionPtr, pointer, DrawablePtr); 58static int S3QueryImageAttributes(ScrnInfoPtr, int, unsigned short *, 59 unsigned short *, int *, int *); 60static void S3ResetVideoOverlay(ScrnInfoPtr); 61 62 63 64void S3InitVideo(ScreenPtr pScreen) 65{ 66 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 67 S3Ptr pS3 = S3PTR(pScrn); 68 XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; 69 XF86VideoAdaptorPtr newAdaptor = NULL; 70 int num_adaptors; 71 72 if (((pScrn->bitsPerPixel == 16) || 73 (pScrn->bitsPerPixel == 24)) && (pS3->S3NewMMIO)) { 74 newAdaptor = S3SetupImageVideoOverlay(pScreen); 75 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using overlay video\n"); 76 } else 77 return; 78 79 num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); 80 81 if(newAdaptor) { 82 if(!num_adaptors) { 83 num_adaptors = 1; 84 adaptors = &newAdaptor; 85 } else { 86 newAdaptors = /* need to free this someplace */ 87 xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); 88 if(newAdaptors) { 89 memcpy(newAdaptors, adaptors, num_adaptors * 90 sizeof(XF86VideoAdaptorPtr)); 91 newAdaptors[num_adaptors] = newAdaptor; 92 adaptors = newAdaptors; 93 num_adaptors++; 94 } 95 } 96 } 97 98 if(num_adaptors) 99 xf86XVScreenInit(pScreen, adaptors, num_adaptors); 100 101 if(newAdaptors) 102 xfree(newAdaptors); 103} 104 105 106/* client libraries expect an encoding */ 107static XF86VideoEncodingRec DummyEncoding[2] = 108{ 109 { /* overlay limit */ 110 0, 111 "XV_IMAGE", 112 1024, 1024, 113 {1, 1} 114 }, 115 { /* texture limit */ 116 0, 117 "XV_IMAGE", 118 2046, 2046, 119 {1, 1} 120 } 121}; 122 123 124 125 126static XF86VideoFormatRec Formats[NUM_FORMATS_TEXTURE] = 127{ 128 /*{15, TrueColor},*/ {16, TrueColor}, {24, TrueColor} /* , 129 {15, DirectColor}*/, {16, DirectColor}, {24, DirectColor} 130}; 131 132 133 134#define NUM_IMAGES 3 135 136static XF86ImageRec Images[NUM_IMAGES] = 137{ 138 XVIMAGE_YUY2, 139 /* As in mga, YV12 & I420 are converted to YUY2 on the fly by */ 140 /* copy over conversion. */ 141 XVIMAGE_YV12, 142 XVIMAGE_I420 143 /* XVIMAGE_UYVY */ 144}; 145 146 147 148static int S3SetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute, 149 INT32 value, pointer data) 150{ 151 return BadMatch; 152} 153 154 155static int S3GetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute, 156 INT32 *value, pointer data) 157{ 158 return BadMatch; 159} 160 161 162 163static void S3QueryBestSize(ScrnInfoPtr pScrn, Bool motion, short vid_w, 164 short vid_h, short drw_w, short drw_h, 165 unsigned int *p_w, unsigned int *p_h, 166 pointer data) 167{ 168 *p_w = drw_w; 169 *p_h = drw_h; 170} 171 172 173 174static void S3ResetVideoOverlay(ScrnInfoPtr pScrn) 175{ 176} 177 178 179static XF86VideoAdaptorPtr S3AllocAdaptor(ScrnInfoPtr pScrn) 180{ 181 S3Ptr pS3 = S3PTR(pScrn); 182 XF86VideoAdaptorPtr adapt; 183 S3PortPrivPtr pPriv; 184 int i; 185 186 if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn))) 187 return NULL; 188 189 if(!(pPriv = xcalloc(1, sizeof(S3PortPrivRec) + 190 (sizeof(DevUnion) * S3_MAX_PORTS)))) 191 { 192 xfree(adapt); 193 return NULL; 194 } 195 196 adapt->pPortPrivates = (DevUnion*)(&pPriv[1]); 197 198 for(i = 0; i < S3_MAX_PORTS; i++) 199 adapt->pPortPrivates[i].val = i; 200 201 pPriv->colorKey = (1 << pScrn->offset.red) | (1 << pScrn->offset.green) | 202 (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue); 203 204 pPriv->videoStatus = 0; 205 pPriv->lastPort = -1; 206 207 pS3->adaptor = adapt; 208 pS3->portPrivate = pPriv; 209 210 return adapt; 211} 212 213 214static XF86VideoAdaptorPtr S3SetupImageVideoOverlay(ScreenPtr pScreen) 215{ 216 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 217 S3Ptr pS3 = S3PTR(pScrn); 218 XF86VideoAdaptorPtr adapt; 219 220 adapt = S3AllocAdaptor(pScrn); 221 222 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 223 adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; 224 adapt->name = "S3 Backend Scaler"; 225 adapt->nEncodings = 1; 226 adapt->pEncodings = &DummyEncoding[0]; 227 adapt->nFormats = NUM_FORMATS_OVERLAY; 228 adapt->pFormats = Formats; 229 adapt->nPorts = 1; 230 adapt->pAttributes = NULL /*Attributes*/; 231 adapt->nImages = 3; 232 adapt->nAttributes = 0; 233 234 adapt->pImages = Images; 235 adapt->PutVideo = NULL; 236 adapt->PutStill = NULL; 237 adapt->GetVideo = NULL; 238 adapt->GetStill = NULL; 239 adapt->StopVideo = S3StopVideo; 240 /* Empty Attrib functions - required anyway */ 241 adapt->SetPortAttribute = S3SetPortAttributeOverlay; 242 adapt->GetPortAttribute = S3GetPortAttributeOverlay; 243 adapt->QueryBestSize = S3QueryBestSize; 244 adapt->PutImage = S3PutImage; 245 adapt->QueryImageAttributes = S3QueryImageAttributes; 246 247 /* gotta uninit this someplace */ 248 REGION_NULL(pScreen, &(pS3->portPrivate->clip)); 249 250 S3ResetVideoOverlay(pScrn); 251 252 return adapt; 253} 254 255 256static void S3StopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit) 257{ 258 S3Ptr pS3 = S3PTR(pScrn); 259 S3PortPrivPtr pPriv = pS3->portPrivate; 260 261 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 262 263 if (exit) { 264 if (pPriv->videoStatus & CLIENT_VIDEO_ON) 265 SET_BLEND_CNTL(0x01000000); 266 267 if (pPriv->area) { 268 xf86FreeOffscreenArea(pPriv->area); 269 pPriv->area = NULL; 270 } 271 272 pPriv->videoStatus = 0; 273 } 274} 275 276 277static FBAreaPtr S3AllocateMemory(ScrnInfoPtr pScrn, FBAreaPtr area, 278 int numlines) 279{ 280 ScreenPtr pScreen; 281 FBAreaPtr new_area; 282 283 if(area) { 284 if((area->box.y2 - area->box.y1) >= numlines) 285 return area; 286 287 if(xf86ResizeOffscreenArea(area, pScrn->displayWidth, numlines)) 288 return area; 289 290 xf86FreeOffscreenArea(area); 291 } 292 293 pScreen = screenInfo.screens[pScrn->scrnIndex]; 294 295 new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth, 296 numlines, 0, NULL, NULL, NULL); 297 298 if(!new_area) { 299 int max_w, max_h; 300 301 xf86QueryLargestOffscreenArea(pScreen, &max_w, &max_h, 0, 302 FAVOR_WIDTH_THEN_AREA, PRIORITY_EXTREME); 303 304 if((max_w < pScrn->displayWidth) || (max_h < numlines)) 305 return NULL; 306 307 xf86PurgeUnlockedOffscreenAreas(pScreen); 308 new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth, 309 numlines, 0, NULL, NULL, NULL); 310 } 311 312 return new_area; 313} 314 315 316 317static void S3DisplayVideoOverlay(ScrnInfoPtr pScrn, int id, int offset, 318 short width, short height, int pitch, 319 int x1, int y1, int x2, int y2, 320 BoxPtr dstBox, short src_w, short src_h, 321 short drw_w, short drw_h) 322{ 323 S3Ptr pS3 = S3PTR(pScrn); 324 S3PortPrivPtr pPriv = pS3->portPrivate; 325 int tmp; 326 327 if (drw_w == src_w) 328 tmp = 0; 329 else 330 tmp = 2; 331 332 SET_SSTREAM_CNTL(tmp << 28 | 0x01000000 | 333 ((((src_w-1)<<1)-(drw_w-1)) & 0xfff)); 334 SET_SSTRETCH(((src_w - 1) & 0x7ff) | (((src_w-drw_w) & 0x7ff) << 16)); 335 SET_BLEND_CNTL(0x05000000); 336 SET_SSTREAM_FBADDR(offset & 0x3fffff); 337 SET_SSTREAM_STRIDE(pitch & 0xfff); 338 339 SET_K1_VSCALE(src_h - 1); 340 SET_K2_VSCALE((src_h - drw_h) & 0x7ff); 341 342 SET_DDA_VERT((((~drw_h)-1)) & 0xfff); 343 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_CHROMA_KEY(0x10000000 | 348 ((pScrn->weight.red-1) << 24) | 349 ((pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red) << 350 (16 + 8-pScrn->weight.red) | 351 ((pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green) << 352 (8 + 8-pScrn->weight.green) | 353 ((pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue) << 354 (8-pScrn->weight.blue)); 355} 356 357 358static int S3PutImage(ScrnInfoPtr pScrn, short src_x, short src_y, 359 short drw_x, short drw_y, short src_w, short src_h, 360 short drw_w, short drw_h, int id, unsigned char *buf, 361 short width, short height, Bool sync, RegionPtr clipBoxes, 362 pointer data, DrawablePtr pDraw) 363{ 364 S3Ptr pS3 = S3PTR(pScrn); 365 S3PortPrivPtr pPriv = pS3->portPrivate; 366 INT32 x1, x2, y1, y2; 367 unsigned char *dst_start; 368 int pitch, new_h, offset, offset2=0, offset3=0; 369 int srcPitch, srcPitch2=0, dstPitch; 370 int top, left, npixels, nlines; 371 BoxRec dstBox; 372 CARD32 tmp; 373 374 /* Clip */ 375 x1 = src_x; 376 x2 = src_x + src_w; 377 y1 = src_y; 378 y2 = src_y + src_h; 379 380 dstBox.x1 = drw_x; 381 dstBox.x2 = drw_x + drw_w; 382 dstBox.y1 = drw_y; 383 dstBox.y2 = drw_y + drw_h; 384 385 if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, 386 clipBoxes, width, height)) 387 return Success; 388 389 /*if(!pMga->TexturedVideo) {*/ 390 dstBox.x1 -= pScrn->frameX0; 391 dstBox.x2 -= pScrn->frameX0; 392 dstBox.y1 -= pScrn->frameY0; 393 dstBox.y2 -= pScrn->frameY0; 394 /*}*/ 395 396 pitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3; 397 dstPitch = ((width << 1) + 15) & ~15; 398 new_h = ((dstPitch * height) + pitch - 1) / pitch; 399 400 switch(id) { 401 case FOURCC_YV12: 402 case FOURCC_I420: 403 srcPitch = (width + 3) & ~3; 404 offset2 = srcPitch * height; 405 srcPitch2 = ((width >> 1) + 3) & ~3; 406 offset3 = (srcPitch2 * (height >> 1)) + offset2; 407 break; 408 case FOURCC_UYVY: 409 case FOURCC_YUY2: 410 default: 411 srcPitch = (width << 1); 412 break; 413 } 414 415 if(!(pPriv->area = S3AllocateMemory(pScrn, pPriv->area, new_h))) 416 return BadAlloc; 417 418 /* copy data */ 419 top = y1 >> 16; 420 left = (x1 >> 16) & ~1; 421 npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left; 422 left <<= 1; 423 424 offset = pPriv->area->box.y1 * pitch; 425 dst_start = pS3->FBBase + offset + left + (top * dstPitch); 426 switch(id) { 427 case FOURCC_YV12: 428 case FOURCC_I420: 429 top &= ~1; 430 tmp = ((top >> 1) * srcPitch2) + (left >> 2); 431 offset2 += tmp; 432 offset3 += tmp; 433 if(id == FOURCC_I420) { 434 tmp = offset2; 435 offset2 = offset3; 436 offset3 = tmp; 437 } 438 nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top; 439 xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1), 440 buf + offset2, buf + offset3, dst_start, 441 srcPitch, srcPitch2, dstPitch, nlines, npixels); 442 break; 443 case FOURCC_UYVY: 444 case FOURCC_YUY2: 445 default: 446 buf += (top * srcPitch) + left; 447 nlines = ((y2 + 0xffff) >> 16) - top; 448 xf86XVCopyPacked(buf, dst_start, srcPitch, dstPitch, nlines, npixels); 449 break; 450 } 451 452 /* update cliplist */ 453 if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) { 454 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); 455 /* draw these */ 456 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes); 457 } 458 459 offset += left + (top * dstPitch); 460 S3DisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch, 461 x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h); 462 463 pPriv->videoStatus = CLIENT_VIDEO_ON; 464 return Success; 465} 466 467 468 469static int S3QueryImageAttributes(ScrnInfoPtr pScrn, int id, 470 unsigned short *w, unsigned short *h, 471 int *pitches, int *offsets) 472{ 473 int size, tmp; 474 475 *w = (*w + 1) & ~1; 476 if(offsets) offsets[0] = 0; 477 478 switch(id) { 479 case FOURCC_YV12: 480 case FOURCC_I420: 481 *h = (*h + 1) & ~1; 482 size = (*w + 3) & ~3; 483 if(pitches) pitches[0] = size; 484 size *= *h; 485 if(offsets) offsets[1] = size; 486 tmp = ((*w >> 1) + 3) & ~3; 487 if(pitches) pitches[1] = pitches[2] = tmp; 488 tmp *= (*h >> 1); 489 size += tmp; 490 if(offsets) offsets[2] = size; 491 size += tmp; 492 break; 493 case FOURCC_UYVY: 494 case FOURCC_YUY2: 495 default: 496 size = *w << 1; 497 if(pitches) pitches[0] = size; 498 size *= *h; 499 break; 500 } 501 502 return size; 503} 504 505 506 507void S3InitStreams(ScrnInfoPtr pScrn, DisplayModePtr mode) 508{ 509 S3Ptr pS3 = S3PTR(pScrn); 510 unsigned int pst_wind = (mode->HDisplay-1) << 16 | (mode->VDisplay); 511 512 SET_PSTREAM_CNTL(0x05000000 & 0x77000000); 513 SET_CHROMA_KEY(0x00); 514 SET_SSTREAM_CNTL(0x03000000); 515 SET_BLEND_CNTL(0x01000000); 516 SET_PSTREAM_STRIDE((pScrn->displayWidth * 2) & 0x0fff); 517 SET_SSTREAM_STRIDE(0x01); 518 SET_OPAQUE_OVERLAY(0x40000000); 519 SET_PSTREAM_START(0x00010001); 520 SET_PSTREAM_WIND(pst_wind & 0x07ff07ff); 521 SET_SSTREAM_START(0x07ff07ff); 522 SET_SSTREAM_WIND(0x00010001); 523} 524 525