Annotation of margi2/osd.c, revision 1.1
1.1 ! cvs 1: /*
! 2: osd.c
! 3:
! 4: Copyright (C) Christian Wolff for convergence integrated media.
! 5:
! 6: This program is free software; you can redistribute it and/or modify
! 7: it under the terms of the GNU General Public License as published by
! 8: the Free Software Foundation; either version 2 of the License, or
! 9: (at your option) any later version.
! 10:
! 11: This program is distributed in the hope that it will be useful,
! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 14: GNU General Public License for more details.
! 15:
! 16: You should have received a copy of the GNU General Public License
! 17: along with this program; if not, write to the Free Software
! 18: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
! 19: */
! 20:
! 21: ////////////////////////////////////////////////////////////////
! 22: // //
! 23: // Functions to Draw on the On Screen Display of the L64021 //
! 24: // CLUT-Mode with 2, 4, or 8 bit per pixel, up to 720*576 //
! 25: // //
! 26: ////////////////////////////////////////////////////////////////
! 27: // OSD Pixel Aspect Ratio:
! 28: // CCIR601 525 Lines (NTSC,PAL-M): 11/10 (100*100 appears as 100*110)
! 29: // CCIR601 625 Lines (PAL): 11/12 (100*100 appears as 100*91.6)
! 30: //
! 31: // OSD functions for external use:
! 32: // int OSDOpen(struct cvdv_cards *card);
! 33: // int OSDClose(struct cvdv_cards *card);
! 34: // int OSDQuery(struct cvdv_cards *card, int *x0, int *y0, int *x1, int *y1, int *aspx, int *aspy);
! 35: // int OSDStartPicture(struct cvdv_cards *card, int left, int top, int width, int height, int bit, int mix);
! 36: // void OSDShow(struct cvdv_cards *card);
! 37: // void OSDHide(struct cvdv_cards *card);
! 38: // void OSDClear(struct cvdv_cards *card);
! 39: // void OSDFill(struct cvdv_cards *card, int col);
! 40: // int OSDSetColor(struct cvdv_cards *card, int num, int R, int G, int B, int mix, int trans);
! 41: // int OSDSetPixel(struct cvdv_cards *card, int x, int y, int col);
! 42: // int OSDGetPixel(struct cvdv_cards *card, int x, int y);
! 43: // int OSDSetRow(struct cvdv_cards *card, int x0, int y, int x1, u8 *data);
! 44: // int OSDFillRow(struct cvdv_cards *card, int x0, int y, int x1, int col);
! 45: // void OSDLine(struct cvdv_cards *card, int x0, int y0, int x1, int y1, int col);
! 46: //
! 47: // Return codes: (unless otherwise specified)
! 48: // 0: OK
! 49: // -1: Range error
! 50: // -2: OSD not open
! 51: //
! 52:
! 53: #define __NO_VERSION__
! 54:
! 55: #include "osd.h"
! 56: #include "dram.h"
! 57: #include "l64021.h"
! 58:
! 59: // Builds a 4-word picture header in buf
! 60: // returns number of words in pixel field on success, -1 on error
! 61: int OSDHeader(u16 * buf, // 4 words
! 62: int *bit, // bit per pixel: 2, 4, or 8
! 63: int *startrow, // position of our block,
! 64: int *stoprow, // row: 0..313
! 65: int *startcol, // col: 0..864
! 66: int *stopcol, //
! 67: int *mix, // opacity for mixed pixel, 0..15 (0%..94% resp.)
! 68: int nopal)
! 69: { // 1: use previous palette
! 70: int count;
! 71: if (buf != NULL) {
! 72: if (*bit == 8)
! 73: *bit = 1;
! 74: else if (*bit == 2)
! 75: *bit = 0;
! 76: else
! 77: *bit = 2;
! 78: if (*startrow < 0)
! 79: *startrow = 0;
! 80: if (*startrow > 312)
! 81: *startrow = 312;
! 82: if (*stoprow <= *startrow)
! 83: *stoprow = *startrow + 1;
! 84: if (*stoprow > 313)
! 85: *stoprow = 313;
! 86: if (*startcol < 0)
! 87: *startcol = 0;
! 88: if (*startcol > 863)
! 89: *startcol = 863;
! 90: if (*stopcol <= *startcol)
! 91: *stopcol = *startcol + 2;
! 92: if (*stopcol > 864)
! 93: *stopcol = 864;
! 94: if ((*stopcol - *startcol + 1) & 1)
! 95: (*stopcol)--;
! 96: if (*mix < 0)
! 97: *mix = 0;
! 98: if (*mix > 15)
! 99: *mix = 15;
! 100: buf[0] = ((*bit << 14) & 0x8000) | (*startrow & 0x01FF);
! 101: buf[1] =
! 102: ((*mix << 12) & 0xF000) | ((*bit << 11) & 0x0800) |
! 103: ((nopal) ? 0x0400 : 0x0000) | (*stoprow & 0x01FF);
! 104: buf[2] = *startcol & 0x03FF;
! 105: buf[3] = *stopcol & 0x03FF;
! 106: count =
! 107: (*stoprow - *startrow + 1) * (*stopcol - *startcol +
! 108: 1);
! 109: if (*bit == 1) {
! 110: count =
! 111: ((count >> 3) + ((count & 0x07) ? 1 : 0)) << 2;
! 112: *bit = 8;
! 113: } else if (*bit == 0) {
! 114: count =
! 115: ((count >> 5) + ((count & 0x1F) ? 1 : 0)) << 2;
! 116: *bit = 2;
! 117: } else if (*bit == 2) {
! 118: count =
! 119: ((count >> 4) + ((count & 0x0F) ? 1 : 0)) << 2;
! 120: *bit = 4;
! 121: }
! 122: return count; // word count of pixel data
! 123: } else
! 124: return -1;
! 125: }
! 126:
! 127: // enables OSD mode
! 128: int OSDShow(struct cvdv_cards *card)
! 129: {
! 130: if (card->OSD.open) {
! 131: DecoderMaskByte(card, 0x109, 0x03, 0x01);
! 132: DecoderDelByte(card, 0x112, 0x10); // no filter
! 133: return 0;
! 134: } else
! 135: return -2;
! 136: }
! 137:
! 138: // disables OSD mode
! 139: int OSDHide(struct cvdv_cards *card)
! 140: {
! 141: if (card->OSD.open) {
! 142: DecoderMaskByte(card, 0x109, 0x03, 0x00);
! 143: return 0;
! 144: } else
! 145: return -2;
! 146: }
! 147:
! 148: // creates an empty picture in the memory of the card
! 149: // ONLY ONE PICTURE PER CARD!
! 150: // maximum sizes: NTSC: 720*525 PAL: 720*576
! 151: // maximum positions: NTSC: 858*525 PAL: 864*625
! 152: // returns 0 on success, -1 on DRAM allocation error
! 153: int OSDStartPicture(struct cvdv_cards *card, int left, int top, int width,
! 154: int height, int bit, int mix)
! 155: {
! 156: u16 TermHeader[] = { 0x01FF, 0x05FF, 0x0000, 0x0000 };
! 157: u16 header[4];
! 158: int size, pixelsize, palsize, frametop, startrow, stoprow,
! 159: startcol, stopcol;
! 160:
! 161: if (card->OSD.open)
! 162: return -2;
! 163: if (top & 1) {
! 164: card->OSD.evenfirst = 0;
! 165: card->OSD.evenheight = height / 2;
! 166: card->OSD.oddheight = height - card->OSD.evenheight;
! 167: } else {
! 168: card->OSD.evenfirst = 1;
! 169: card->OSD.oddheight = height / 2;
! 170: card->OSD.evenheight = height - card->OSD.oddheight;
! 171: }
! 172:
! 173: // Setting the picture for the lines in the even field
! 174: frametop = top / 2;
! 175: startrow = frametop;
! 176: stoprow = frametop + card->OSD.evenheight - 1;
! 177: startcol = left;
! 178: stopcol = left + width - 1;
! 179: pixelsize =
! 180: OSDHeader(header, &bit, &startrow, &stoprow, &startcol,
! 181: &stopcol, &mix, 0);
! 182: card->OSD.evenheight = stoprow - startrow + 1;
! 183: card->OSD.bpp = bit;
! 184: if (bit == 8)
! 185: palsize = 256;
! 186: else if (bit == 2)
! 187: palsize = 4;
! 188: else
! 189: palsize = 16;
! 190: size = 8 + palsize + pixelsize;
! 191: card->OSD.evenmem = DRAMAlloc(card, size, 32);
! 192: if (card->OSD.evenmem == BLANK)
! 193: return -1;
! 194: card->OSD.evendata = card->OSD.evenmem;
! 195: card->OSD.evenpalette = card->OSD.evendata + 4;
! 196: card->OSD.evenbitmap = card->OSD.evenpalette + palsize;
! 197: card->OSD.eventerm = card->OSD.evenbitmap + pixelsize;
! 198: DecoderWriteWord(card, 0x110, (u16) (card->OSD.evendata >> 5));
! 199: DRAMWriteWord(card, card->OSD.evendata, 4, header, 0);
! 200: DRAMFillByte(card, card->OSD.evenpalette,
! 201: (palsize + pixelsize) * 2, 0x00);
! 202: DRAMWriteWord(card, card->OSD.eventerm, 4, TermHeader, 0);
! 203:
! 204: // Setting the picture for the lines in the odd frame
! 205: frametop += card->OSD.evenfirst;
! 206: startrow = frametop;
! 207: stoprow = frametop + card->OSD.oddheight - 1;
! 208: pixelsize =
! 209: OSDHeader(header, &bit, &startrow, &stoprow, &startcol,
! 210: &stopcol, &mix, 0);
! 211: card->OSD.oddheight = stoprow - startrow + 1;
! 212: size = 8 + palsize + pixelsize;
! 213: card->OSD.oddmem = DRAMAlloc(card, size, 32);
! 214: if (card->OSD.oddmem == BLANK)
! 215: return -1;
! 216: card->OSD.odddata = card->OSD.oddmem;
! 217: card->OSD.oddpalette = card->OSD.odddata + 4;
! 218: card->OSD.oddbitmap = card->OSD.oddpalette + palsize;
! 219: card->OSD.oddterm = card->OSD.oddbitmap + pixelsize;
! 220: DecoderWriteWord(card, 0x10E, (u16) (card->OSD.odddata >> 5));
! 221: DRAMWriteWord(card, card->OSD.odddata, 4, header, 0);
! 222: DRAMFillByte(card, card->OSD.oddpalette, (palsize + pixelsize) * 2,
! 223: 0x00);
! 224: DRAMWriteWord(card, card->OSD.oddterm, 4, TermHeader, 0);
! 225:
! 226: // Update of the picture dimensions
! 227: card->OSD.width = stopcol - startcol + 1;
! 228: card->OSD.height = card->OSD.evenheight + card->OSD.oddheight;
! 229: card->OSD.open = 1;
! 230:
! 231: printk(KERN_DEBUG LOGNAME
! 232: ": OSD Open %dX%d, %d bit, mem 0x%08X/0x%08X\n",
! 233: card->OSD.width, card->OSD.height, card->OSD.bpp,
! 234: card->OSD.evendata, card->OSD.odddata);
! 235: return 0;
! 236: }
! 237:
! 238: // Disables OSD and releases the buffers
! 239: // returns 0 on success, 1 on "not open"
! 240: int OSDClose(struct cvdv_cards *card)
! 241: {
! 242: if (card->OSD.open) {
! 243: OSDHide(card);
! 244: DRAMFree(card, card->OSD.evenmem);
! 245: DRAMFree(card, card->OSD.oddmem);
! 246: card->OSD.open = 0;
! 247: return 0;
! 248: } else
! 249: return -2;
! 250: }
! 251:
! 252: // Opens OSD with this size and bit depth
! 253: // returns 0 on success, 1 on DRAM allocation error, 2 on "already open"
! 254: int OSDOpen(struct cvdv_cards *card, int x0, int y0, int x1, int y1,
! 255: int bit, int mix)
! 256: {
! 257: int ret;
! 258: if (card->OSD.open)
! 259: OSDClose(card);
! 260: if (bit < 0)
! 261: bit = 8;
! 262: else if (bit < 2)
! 263: bit = 2;
! 264: else if (bit < 4)
! 265: bit = 4;
! 266: else
! 267: bit = 8;
! 268: if (x0 < 0)
! 269: x0 = 0;
! 270: if (x1 < 0)
! 271: x1 = 720 - 1;
! 272: if (x1 < x0)
! 273: x1 = x0;
! 274: if (y0 < 0)
! 275: y0 = 0;
! 276: if (y1 < 0)
! 277: y1 = 576 - 1;
! 278: if (y1 < y0)
! 279: y1 = y0;
! 280: if ((x1 + 1) > 720)
! 281: x1 = 720 - 1;
! 282: if (x0 > x1)
! 283: x0 = x1;
! 284: if (CCIR601Lines(card->videomode) == 625) { // PAL
! 285: if ((y1 + 1) > 576)
! 286: y1 = 576 - 1;
! 287: if (y0 > y1)
! 288: y0 = y1;
! 289: if (!
! 290: (ret =
! 291: OSDStartPicture(card, 134 + x0, 48 + y0, x1 - x0 + 1,
! 292: y1 - y0 + 1, bit, mix)))
! 293: card->OSD.aspectratio = 12; // pixel aspect ratio 12/11
! 294: } else { // NTSC
! 295: if ((y1 + 1) > 484)
! 296: y1 = 484 - 1;
! 297: if (y0 > y1)
! 298: y0 = y1;
! 299: if (!
! 300: (ret =
! 301: OSDStartPicture(card, 126 + x0, 44 + y0, x1 - x0 + 1,
! 302: y1 - y0 + 1, bit, mix)))
! 303: card->OSD.aspectratio = 10; // pixel aspect ratio 10/11
! 304: }
! 305: return ret;
! 306: }
! 307:
! 308: // fills parameters with the picture dimensions and the pixel aspect ratio (aspy=11)
! 309: int OSDQuery(struct cvdv_cards *card, int *x0, int *y0, int *x1, int *y1,
! 310: int *aspx)
! 311: {
! 312: if (!card->OSD.open)
! 313: return -2;
! 314: *x0 = 0;
! 315: *x1 = card->OSD.width - 1;
! 316: *y0 = 0;
! 317: *y1 = card->OSD.height - 1;
! 318: *aspx = card->OSD.aspectratio;
! 319: return 0;
! 320: }
! 321:
! 322: // Sets all pixel to color 0
! 323: int OSDClear(struct cvdv_cards *card)
! 324: {
! 325: if (!card->OSD.open)
! 326: return -2;
! 327: DRAMFillByte(card, card->OSD.oddbitmap,
! 328: (int) (card->OSD.oddterm - card->OSD.oddbitmap) * 2,
! 329: 0x00);
! 330: DRAMFillByte(card, card->OSD.evenbitmap,
! 331: (int) (card->OSD.eventerm - card->OSD.evenbitmap) * 2,
! 332: 0x00);
! 333: return 0;
! 334: }
! 335:
! 336: // Sets all pixel to color <col>
! 337: int OSDFill(struct cvdv_cards *card, int col)
! 338: {
! 339: u8 color;
! 340: if (!card->OSD.open)
! 341: return -2;
! 342: if (card->OSD.bpp == 8) {
! 343: color = col & 0xFF;
! 344: } else if (card->OSD.bpp == 4) {
! 345: color = (col & 0xF);
! 346: color |= (color << 4);
! 347: } else if (card->OSD.bpp == 2) {
! 348: color = (col & 0x03);
! 349: for (col = 1; col <= 3; col++)
! 350: color |= (color << 2);
! 351: } else
! 352: color = 0x00;
! 353: DRAMFillByte(card, card->OSD.oddbitmap,
! 354: (int) (card->OSD.oddterm - card->OSD.oddbitmap) * 2,
! 355: color);
! 356: DRAMFillByte(card, card->OSD.evenbitmap,
! 357: (int) (card->OSD.eventerm - card->OSD.evenbitmap) * 2,
! 358: color);
! 359: return 0;
! 360: }
! 361:
! 362: // converts RGB(8 bit) to YCrCb(OSD format)
! 363: // mix: 0=opacity 100% 1=opacity at mix value
! 364: // trans: 0=mix bit applies 1=opacity 0%
! 365: // returns word in OSD palette format
! 366: u16 OSDColor(u8 R, u8 G, u8 B, int mix, int trans)
! 367: {
! 368: u16 Y, Cr, Cb;
! 369: Y = R * 77 + G * 150 + B * 29; // Luma=0.299R+0.587G+0.114B 0..65535
! 370: Cb = 2048 + B * 8 - (Y >> 5); // Cr 0..4095
! 371: Cr = 2048 + R * 10 - (Y >> 5); // Cb 0..4095
! 372: return ((trans) ? 0 : // transparent pixel
! 373: (Y & 0xFC00) | // Luma 0..63
! 374: ((mix) ? 0x0100 : 0x0000) | // Opacity applies
! 375: ((Cb >> 4) & 0x00F0) | // Cb 0..15
! 376: ((Cr >> 8) & 0x000F) // Cr 0..15
! 377: );
! 378: }
! 379:
! 380: // set palette entry <num> to <r,g,b>, <mix> and <trans> apply
! 381: // R,G,B: 0..255
! 382: // RGB=1: R=Red, G=Green, B=Blue RGB=0: R=Y G=Cb B=Cr
! 383: // mix=0, trans=0: pixel opacity 100% (only OSD pixel shows)
! 384: // mix=1, trans=0: pixel opacity as specified in header
! 385: // trans=1: pixel opacity 0% (only video pixel shows)
! 386: // returns 0 on success, 1 on error
! 387: int OSDSetColor(struct cvdv_cards *card, int num, int R, int G, int B,
! 388: int YUV, int mix, int trans)
! 389: {
! 390: u16 burst[4]; // minimal memory unit
! 391: u32 addr;
! 392: u16 color;
! 393: if (!card->OSD.open)
! 394: return -2;
! 395: if (R < 0)
! 396: R = 0;
! 397: if (R > 255)
! 398: R = 255;
! 399: if (G < 0)
! 400: G = 0;
! 401: if (G > 255)
! 402: G = 255;
! 403: if (B < 0)
! 404: B = 0;
! 405: if (B > 255)
! 406: B = 255;
! 407: if ((num >= 0) && (num < (1 << card->OSD.bpp))) {
! 408: //if (num==0) printk(KERN_DEBUG LOGNAME ": OSD SetColor num=%d, R=%d, G=%d, B=%d, YUV=%d, mix=%d, trans=%d\n",
! 409: // num,R,G,B,YUV,mix,trans);
! 410: color = ((YUV)
! 411: ? ((trans) ? 0 : ((R << 8) & 0xFC00) |
! 412: ((mix) ? 0x0100 : 0x0000) | (G & 0x00F0) |
! 413: ((B >> 4) & 0x000F)) : OSDColor(R, G, B, mix,
! 414: trans));
! 415:
! 416: addr = card->OSD.oddpalette + num;
! 417: DRAMReadWord(card, addr & ~3, 4, burst, 0);
! 418: burst[addr & 3] = color;
! 419: DRAMWriteWord(card, addr & ~3, 4, burst, 0);
! 420:
! 421: addr = card->OSD.evenpalette + num;
! 422: DRAMReadWord(card, addr & ~3, 4, burst, 0);
! 423: burst[addr & 3] = color;
! 424: DRAMWriteWord(card, addr & ~3, 4, burst, 0);
! 425:
! 426: return 0;
! 427: } else
! 428: return -1;
! 429: }
! 430:
! 431: // Set a number of entries in the palette
! 432: // sets the entries "firstcolor" through "lastcolor" from the array "data"
! 433: // data has 4 byte for each color:
! 434: // R,G,B, and a transparency value: 0->tranparent, 1..254->mix, 255->no mix
! 435: int OSDSetPalette(struct cvdv_cards *card, int firstcolor, int lastcolor,
! 436: u8 * data)
! 437: {
! 438: u16 burst[4]; // minimal memory unit
! 439: u32 addr;
! 440: u16 color;
! 441: int num, i = 0;
! 442: if (!card->OSD.open)
! 443: return -2;
! 444: for (num = firstcolor; num <= lastcolor; num++)
! 445: if ((num >= 0) && (num < (1 << card->OSD.bpp))) {
! 446: color =
! 447: OSDColor(data[i], data[i + 1], data[i + 2],
! 448: ((data[i + 3] < 255) ? 1 : 0),
! 449: ((data[i + 3] == 0) ? 1 : 0));
! 450: i += 4;
! 451:
! 452: addr = card->OSD.oddpalette + num;
! 453: DRAMReadWord(card, addr & ~3, 4, burst, 0);
! 454: burst[addr & 3] = color;
! 455: DRAMWriteWord(card, addr & ~3, 4, burst, 0);
! 456:
! 457: addr = card->OSD.evenpalette + num;
! 458: DRAMReadWord(card, addr & ~3, 4, burst, 0);
! 459: burst[addr & 3] = color;
! 460: DRAMWriteWord(card, addr & ~3, 4, burst, 0);
! 461: }
! 462: return 0;
! 463: }
! 464:
! 465: // Sets transparency of mixed pixel (0..15)
! 466: int OSDSetTrans(struct cvdv_cards *card, int trans)
! 467: {
! 468: u16 burst[4]; // minimal memory unit
! 469: if (!card->OSD.open)
! 470: return -2;
! 471: trans &= 0x000F;
! 472: DRAMReadWord(card, card->OSD.evendata, 4, burst, 0);
! 473: burst[1] = (burst[1] & 0x0FFF) | (trans << 12);
! 474: DRAMWriteWord(card, card->OSD.evendata, 4, burst, 0);
! 475:
! 476: DRAMReadWord(card, card->OSD.odddata, 4, burst, 0);
! 477: burst[1] = (burst[1] & 0x0FFF) | (trans << 12);
! 478: DRAMWriteWord(card, card->OSD.odddata, 4, burst, 0);
! 479: return 0;
! 480: }
! 481:
! 482: // sets pixel <x>,<y> to color number <col>
! 483: // returns 0 on success, 1 on error
! 484: int OSDSetPixel(struct cvdv_cards *card, int x, int y, int col)
! 485: {
! 486: u16 burst[4]; // minimal memory unit od DRAM
! 487: u32 addr;
! 488: int offset, ppw, pos, shift, height, posmask;
! 489: u16 mask;
! 490:
! 491: if (!card->OSD.open)
! 492: return -2;
! 493: if ((y & 1) == card->OSD.evenfirst) { // even or odd frame?
! 494: addr = card->OSD.oddbitmap;
! 495: height = card->OSD.oddheight;
! 496: } else {
! 497: addr = card->OSD.evenbitmap;
! 498: height = card->OSD.evenheight;
! 499: }
! 500: y >>= 1;
! 501: if ((x >= 0) && (x < card->OSD.width) && (y >= 0) && (y < height)) { // clipping
! 502: ppw =
! 503: ((card->OSD.bpp == 4) ? 2 : ((card->OSD.bpp == 8) ? 1 : 3)); // OK, 4-(ln(bpp)/ln(2)) would have worked, too...
! 504: pos = x + y * card->OSD.width; // pixel number in bitfield
! 505: addr += (pos >> ppw); // 21 bit address of word with our pixel
! 506: offset = addr & 3; // offset in burst
! 507: addr &= ~3; // 21 bit burst address
! 508: posmask = (1 << ppw) - 1; // mask for position inside word
! 509: shift = ((posmask - (pos & posmask)) << (4 - ppw)); // pixel shift inside word
! 510: mask = (1 << (1 << (4 - ppw))) - 1; // pixel mask
! 511: DRAMReadWord(card, addr, 4, burst, 0); // get the burst with our pixel...
! 512: burst[offset] =
! 513: (burst[offset] & ~(mask << shift)) | ((col & mask) <<
! 514: shift);
! 515: DRAMWriteWord(card, addr, 4, burst, 0); // ...and write it back
! 516: return 0;
! 517: } else
! 518: return -1;
! 519: }
! 520:
! 521: // returns color number of pixel <x>,<y>, or -1
! 522: int OSDGetPixel(struct cvdv_cards *card, int x, int y)
! 523: {
! 524: u16 burst[4]; // minimal memory unit
! 525: u32 addr;
! 526: int offset, ppw, pos, shift, height, posmask;
! 527: u16 mask;
! 528:
! 529: if (!card->OSD.open)
! 530: return -2;
! 531: if ((y & 1) == card->OSD.evenfirst) { // even or odd frame?
! 532: addr = card->OSD.oddbitmap;
! 533: height = card->OSD.oddheight;
! 534: } else {
! 535: addr = card->OSD.evenbitmap;
! 536: height = card->OSD.evenheight;
! 537: }
! 538: y >>= 1;
! 539: if ((x >= 0) && (x < card->OSD.width) && (y >= 0) && (y < height)) { // clipping
! 540: ppw =
! 541: ((card->OSD.bpp == 4) ? 2 : ((card->OSD.bpp == 8) ? 1 : 3)); // OK, 4-(ln(bpp)/ln(2)) would have worked, too...
! 542: pos = x + y * card->OSD.width; // pixel number in bitfield
! 543: addr += (pos >> ppw); // 21 bit address of word with our pixel
! 544: offset = addr & 3; // offset in burst
! 545: addr &= ~3; // 21 bit burst address
! 546: posmask = (1 << ppw) - 1; // mask for position inside word
! 547: shift = ((posmask - (pos & posmask)) << (4 - ppw)); // pixel shift inside word
! 548: mask = (1 << (1 << (4 - ppw))) - 1; // pixel mask
! 549: DRAMReadWord(card, addr, 4, burst, 0); // get the burst with our pixel...
! 550: return (burst[offset] >> shift) & mask; // ...and return it's value
! 551: } else
! 552: return -1;
! 553: }
! 554:
! 555: // fills pixels x0,y through x1,y with the content of data[]
! 556: // returns 0 on success, -1 on clipping all pixel
! 557: int OSDSetRow(struct cvdv_cards *card, int x0, int y, int x1, u8 * data)
! 558: {
! 559: u16 burst[4]; // minimal memory unit
! 560: u32 addr, addr1, bitmap;
! 561: int offset, offset1, ppw, pos, pos1, shift, shift0, shift1,
! 562: shiftstep, height, bpp, x, i, endburst, endword;
! 563: u16 mask, posmask;
! 564:
! 565: if (!card->OSD.open)
! 566: return -2;
! 567: if ((y & 1) == card->OSD.evenfirst) {
! 568: bitmap = card->OSD.oddbitmap;
! 569: height = card->OSD.oddheight;
! 570: } else {
! 571: bitmap = card->OSD.evenbitmap;
! 572: height = card->OSD.evenheight;
! 573: }
! 574: y >>= 1;
! 575: if ((y >= 0) && (y < height)) {
! 576: i = 0;
! 577: if (x0 > x1) {
! 578: x = x1;
! 579: x1 = x0;
! 580: x0 = x;
! 581: }
! 582: if ((x0 >= card->OSD.width) || (x1 < 0))
! 583: return -1;
! 584: if (x0 < 0) {
! 585: i -= x0;
! 586: x0 = 0;
! 587: }
! 588: if (x1 >= card->OSD.width)
! 589: x1 = card->OSD.width - 1;
! 590: bpp = card->OSD.bpp; // bits per pixel
! 591: ppw = ((bpp == 4) ? 2 : ((bpp == 8) ? 1 : 3)); // positional parameter
! 592: mask = (1 << bpp) - 1; // mask for one pixel
! 593: posmask = (1 << ppw) - 1; // mask for position inside word
! 594:
! 595: pos = x0 + (y * card->OSD.width); // pixel number of first pixel
! 596: pos1 = pos + x1 - x0; // pixel number of last pixel
! 597: shift0 = ((posmask - (pos & posmask)) << (4 - ppw));
! 598: shift1 = ((posmask - (pos1 & posmask)) << (4 - ppw));
! 599: shiftstep = 1 << (4 - ppw);
! 600:
! 601: addr = bitmap + (pos >> ppw); // DRAM address of word with first pixel
! 602: addr1 = bitmap + (pos1 >> ppw); // " " " " " last "
! 603: offset = (int) (addr & 3); // word position inside burst
! 604: offset1 = (int) (addr1 & 3); // number of last word in the last burst
! 605: addr &= ~3; // burst address
! 606: addr1 &= ~3; // burst address of last pixel
! 607:
! 608: endburst = (addr1 != addr); // end in other burst
! 609: endword = (offset1 != offset); // end in other word
! 610:
! 611: // read old content of first burst if the row start after the beginning or
! 612: // end before the end of the first burst
! 613: if (offset || (pos & posmask) ||
! 614: (!endburst
! 615: && ((offset1 != 3)
! 616: || ((pos1 & posmask) != posmask)))) {
! 617: DRAMReadWord(card, addr, 4, burst, 0);
! 618: }
! 619: // End beyond or at the end of this word?
! 620: if (endburst || endword || ((pos1 & posmask) == posmask)) {
! 621: // Fill first word
! 622: for (shift = shift0; shift >= 0; shift -= shiftstep) { // bit position inside word
! 623: burst[offset] =
! 624: (burst[offset] & ~(mask << shift)) |
! 625: ((data[i++] & mask) << shift);
! 626: }
! 627: if (endburst || endword) { // Any more words to fill?
! 628: shift0 = posmask << (4 - ppw); // from here on, we start at the beginning of each word
! 629: offset++; // fill the rest of the burst
! 630: if (endburst) { // end not in this burst?
! 631: while (offset <= 3) { // fill remaining words
! 632: burst[offset] = 0x0000; // clear first
! 633: for (shift = shift0;
! 634: shift >= 0;
! 635: shift -= shiftstep) {
! 636: burst[offset] |=
! 637: ((data
! 638: [i++] & mask)
! 639: << shift);
! 640: }
! 641: offset++;
! 642: }
! 643: DRAMWriteWord(card, addr, 4, burst, 0); // write first burst
! 644: addr += 4; // go on to the next burst
! 645: while (addr < addr1) { // all bursts between start and end burst
! 646: for (offset = 0;
! 647: offset <= 3; offset++) { // 4 words per burst
! 648: burst[offset] = 0x0000; // clear first
! 649: for (shift =
! 650: shift0;
! 651: shift >= 0;
! 652: shift -=
! 653: shiftstep) {
! 654: burst
! 655: [offset]
! 656: |=
! 657: ((data
! 658: [i++]
! 659: &
! 660: mask)
! 661: <<
! 662: shift);
! 663: }
! 664: }
! 665: DRAMWriteWord(card, addr,
! 666: 4, burst, 0); // write full burst
! 667: addr += 4; // next burst
! 668: }
! 669: offset = 0;
! 670: if ((offset1 < 3) || shift1) { // does the row ends before the end of the burst?
! 671: DRAMReadWord(card, addr, 4,
! 672: burst, 0); // then we have to read the old content
! 673: }
! 674: }
! 675: while (offset < offset1) { // end not in this word
! 676: burst[offset] = 0x0000; // clear first
! 677: for (shift = shift0; shift >= 0;
! 678: shift -= shiftstep) {
! 679: burst[offset] |=
! 680: ((data[i++] & mask) <<
! 681: shift);
! 682: }
! 683: offset++;
! 684: }
! 685: for (shift = shift0; shift >= shift1;
! 686: shift -= shiftstep) { // last word
! 687: burst[offset] =
! 688: (burst[offset] &
! 689: ~(mask << shift)) |
! 690: ((data[i++] & mask) << shift);
! 691: }
! 692: }
! 693: } else { // row starts and ends in one word
! 694: for (shift = shift0; shift >= shift1; shift -= shiftstep) { // bit position inside word
! 695: burst[offset] =
! 696: (burst[offset] & ~(mask << shift)) |
! 697: ((data[i++] & mask) << shift);
! 698: }
! 699: }
! 700: DRAMWriteWord(card, addr, 4, burst, 0); // write only/last burst
! 701: return 0;
! 702: } else
! 703: return -1;
! 704: }
! 705:
! 706: // fills pixels x0,y0 through x1,y1 with the content of data[]
! 707: // inc contains the width of one line in the data block,
! 708: // inc<=0 uses blockwidth as linewidth
! 709: // returns 0 on success, -1 on clipping all pixel
! 710: int OSDSetBlock(struct cvdv_cards *card, int x0, int y0, int x1, int y1,
! 711: int inc, u8 * data)
! 712: {
! 713: int i, w = x1 - x0 + 1, ret = 0;
! 714: if (inc > 0)
! 715: w = inc;
! 716: for (i = y0; i <= y1; i++) {
! 717: ret |= OSDSetRow(card, x0, i, x1, data);
! 718: data += w;
! 719: }
! 720: return ret;
! 721: }
! 722:
! 723: // fills pixels x0,y through x1,y with the color <col>
! 724: // returns 0 on success, -1 on clipping all pixel
! 725: int OSDFillRow(struct cvdv_cards *card, int x0, int y, int x1, int col)
! 726: {
! 727: u16 burst[4]; // minimal memory unit
! 728: u32 addr, addr1, bitmap;
! 729: int offset, offset1, ppw, pos, pos1, shift, shift0, shift1,
! 730: shiftstep, height, bpp, x, i, endburst, endword;
! 731: u16 mask, posmask;
! 732:
! 733: if (!card->OSD.open)
! 734: return -2;
! 735: if ((y & 1) == card->OSD.evenfirst) {
! 736: bitmap = card->OSD.oddbitmap;
! 737: height = card->OSD.oddheight;
! 738: } else {
! 739: bitmap = card->OSD.evenbitmap;
! 740: height = card->OSD.evenheight;
! 741: }
! 742: y >>= 1;
! 743: if ((y >= 0) && (y < height)) {
! 744: i = 0;
! 745: if (x0 > x1) {
! 746: x = x1;
! 747: x1 = x0;
! 748: x0 = x;
! 749: }
! 750: if ((x0 >= card->OSD.width) || (x1 < 0))
! 751: return -1;
! 752: if (x0 < 0) {
! 753: i -= x0;
! 754: x0 = 0;
! 755: }
! 756: if (x1 >= card->OSD.width)
! 757: x1 = card->OSD.width - 1;
! 758: bpp = card->OSD.bpp; // bits per pixel
! 759: ppw = ((bpp == 4) ? 2 : ((bpp == 8) ? 1 : 3)); // positional parameter
! 760: mask = (1 << bpp) - 1; // mask for one pixel
! 761: posmask = (1 << ppw) - 1; // mask for position inside word
! 762:
! 763: pos = x0 + (y * card->OSD.width); // pixel number of first pixel
! 764: pos1 = pos + x1 - x0; // pixel number of last pixel
! 765: shift0 = ((posmask - (pos & posmask)) << (4 - ppw));
! 766: shift1 = ((posmask - (pos1 & posmask)) << (4 - ppw));
! 767: shiftstep = 1 << (4 - ppw);
! 768:
! 769: addr = bitmap + (pos >> ppw); // DRAM address of word with first pixel
! 770: addr1 = bitmap + (pos1 >> ppw); // " " " " " last "
! 771: offset = (int) (addr & 3); // word position inside burst
! 772: offset1 = (int) (addr1 & 3); // number of last word in the last burst
! 773: addr &= ~3; // burst address
! 774: addr1 &= ~3; // burst address of last pixel
! 775:
! 776: endburst = (addr1 != addr); // end in other burst
! 777: endword = (offset1 != offset); // end in other word
! 778:
! 779: // read old content of first burst if the row start after the beginning or
! 780: // end before the end of the first burst
! 781: if (offset || (pos & posmask) ||
! 782: (!endburst
! 783: && ((offset1 != 3)
! 784: || ((pos1 & posmask) != posmask)))) {
! 785: DRAMReadWord(card, addr, 4, burst, 0);
! 786: }
! 787: if (endburst || endword || ((pos1 & posmask) == posmask)) { // end beyond or at the end of this word?
! 788: for (shift = shift0; shift >= 0; shift -= shiftstep) { // bit position inside word
! 789: burst[offset] =
! 790: (burst[offset] & ~(mask << shift)) |
! 791: ((col & mask) << shift);
! 792: }
! 793: if (endburst || endword) {
! 794: shift0 = posmask << (4 - ppw); // from here on, we start at the beginning of each word
! 795: offset++; // fill the rest of the burst
! 796: if (endburst) { // end not in this burst?
! 797: while (offset <= 3) { // fill remaining words
! 798: burst[offset] = 0x0000; // clear first
! 799: for (shift = shift0;
! 800: shift >= 0;
! 801: shift -= shiftstep) {
! 802: burst[offset] |=
! 803: ((col & mask)
! 804: << shift);
! 805: }
! 806: offset++;
! 807: }
! 808: DRAMWriteWord(card, addr, 4, burst, 0); // write first burst
! 809: addr += 4; // next burst
! 810: while (addr < addr1) { // write all the bursts between start and end burst
! 811: for (offset = 0;
! 812: offset <= 3; offset++) {
! 813: burst[offset] =
! 814: 0x0000;
! 815: for (shift =
! 816: shift0;
! 817: shift >= 0;
! 818: shift -=
! 819: shiftstep) {
! 820: burst
! 821: [offset]
! 822: |=
! 823: ((col
! 824: &
! 825: mask)
! 826: <<
! 827: shift);
! 828: }
! 829: }
! 830: DRAMWriteWord(card, addr,
! 831: 4, burst, 0);
! 832: addr += 4;
! 833: }
! 834: offset = 0;
! 835: if ((offset1 < 3) || shift1) { // does the row ends before the end of the burst?
! 836: DRAMReadWord(card, addr, 4,
! 837: burst, 0); // then we have to read the old content
! 838: }
! 839: }
! 840: while (offset < offset1) { // end not in this word
! 841: burst[offset] = 0x0000;
! 842: for (shift = shift0; shift >= 0;
! 843: shift -= shiftstep) {
! 844: burst[offset] |=
! 845: ((col & mask) <<
! 846: shift);
! 847: }
! 848: offset++;
! 849: }
! 850: for (shift = shift0; shift >= shift1;
! 851: shift -= shiftstep) {
! 852: burst[offset] =
! 853: (burst[offset] &
! 854: ~(mask << shift)) | ((col &
! 855: mask) <<
! 856: shift);
! 857: }
! 858: }
! 859: } else { // row starts and ends in one word
! 860: for (shift = shift0; shift >= shift1; shift -= shiftstep) { // bit position inside word
! 861: burst[offset] =
! 862: (burst[offset] & ~(mask << shift)) |
! 863: ((col & mask) << shift);
! 864: }
! 865: }
! 866: DRAMWriteWord(card, addr, 4, burst, 0);
! 867: return 0;
! 868: } else
! 869: return -1;
! 870: }
! 871:
! 872: // fills pixels x0,y0 through x1,y1 with the color <col>
! 873: // returns 0 on success, -1 on clipping all pixel
! 874: int OSDFillBlock(struct cvdv_cards *card, int x0, int y0, int x1, int y1,
! 875: int col)
! 876: {
! 877: int i, ret = 0;
! 878: for (i = y0; i <= y1; i++)
! 879: ret |= OSDFillRow(card, x0, i, x1, col);
! 880: return ret;
! 881: }
! 882:
! 883: // draw a line from x0,y0 to x1,y1 with the color <col>
! 884: int OSDLine(struct cvdv_cards *card, int x0, int y0, int x1, int y1,
! 885: int col)
! 886: {
! 887: int ct, ix, iy, ax, ay, dx, dy, off;
! 888: #define sgn(a) ((a)?(((a)>0)?1:-1):0)
! 889: if (!card->OSD.open)
! 890: return -2;
! 891: dx = x1 - x0;
! 892: dy = y1 - y0;
! 893: if (dx == 0) {
! 894: if (dy < 0)
! 895: for (iy = y1; iy <= y0; iy++)
! 896: OSDSetPixel(card, x0, iy, col);
! 897: else
! 898: for (iy = y0; iy <= y1; iy++)
! 899: OSDSetPixel(card, x0, iy, col);
! 900: } else if (dy == 0) {
! 901: OSDFillRow(card, x0, y0, x1, col);
! 902: } else {
! 903: ay = 0;
! 904: ax = 0;
! 905: ix = sgn(dx);
! 906: dx = abs(dx);
! 907: iy = sgn(dy);
! 908: dy = abs(dy);
! 909: if (dx < dy) {
! 910: off = dx;
! 911: dx = dy;
! 912: dy = off;
! 913: ay = ix;
! 914: ax = iy;
! 915: ix = 0;
! 916: iy = 0;
! 917: }
! 918: off = dx >> 1;
! 919: ct = 1;
! 920: OSDSetPixel(card, x0, y0, col);
! 921: x1 = x0;
! 922: y1 = y0;
! 923: while (dx >= ct) {
! 924: x0 += ix;
! 925: y0 += ax;
! 926: ct++;
! 927: off += dy;
! 928: if (off > dx) {
! 929: off -= dx;
! 930: x0 += ay;
! 931: y0 += iy;
! 932: }
! 933: if (ax) {
! 934: OSDSetPixel(card, x0, y0, col);
! 935: } else {
! 936: if (y0 != y1) {
! 937: OSDFillRow(card, x1, y1, x0 - ay,
! 938: col);
! 939: x1 = x0;
! 940: y1 = y0;
! 941: }
! 942: }
! 943: }
! 944: if (!ax)
! 945: OSDFillRow(card, x1, y0, x0, col);
! 946: }
! 947: return 0;
! 948: }
LinuxTV legacy CVS <linuxtv.org/cvs>