Annotation of margi2/osd.c, revision 1.2
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:
1.2 ! mocm 231: MDEBUG(1,": OSD Open %dX%d, %d bit, mem 0x%08X/0x%08X\n",
1.1 cvs 232: card->OSD.width, card->OSD.height, card->OSD.bpp,
233: card->OSD.evendata, card->OSD.odddata);
234: return 0;
235: }
236:
237: // Disables OSD and releases the buffers
238: // returns 0 on success, 1 on "not open"
239: int OSDClose(struct cvdv_cards *card)
240: {
241: if (card->OSD.open) {
242: OSDHide(card);
243: DRAMFree(card, card->OSD.evenmem);
244: DRAMFree(card, card->OSD.oddmem);
245: card->OSD.open = 0;
246: return 0;
247: } else
248: return -2;
249: }
250:
251: // Opens OSD with this size and bit depth
252: // returns 0 on success, 1 on DRAM allocation error, 2 on "already open"
253: int OSDOpen(struct cvdv_cards *card, int x0, int y0, int x1, int y1,
254: int bit, int mix)
255: {
256: int ret;
257: if (card->OSD.open)
258: OSDClose(card);
259: if (bit < 0)
260: bit = 8;
261: else if (bit < 2)
262: bit = 2;
263: else if (bit < 4)
264: bit = 4;
265: else
266: bit = 8;
267: if (x0 < 0)
268: x0 = 0;
269: if (x1 < 0)
270: x1 = 720 - 1;
271: if (x1 < x0)
272: x1 = x0;
273: if (y0 < 0)
274: y0 = 0;
275: if (y1 < 0)
276: y1 = 576 - 1;
277: if (y1 < y0)
278: y1 = y0;
279: if ((x1 + 1) > 720)
280: x1 = 720 - 1;
281: if (x0 > x1)
282: x0 = x1;
283: if (CCIR601Lines(card->videomode) == 625) { // PAL
284: if ((y1 + 1) > 576)
285: y1 = 576 - 1;
286: if (y0 > y1)
287: y0 = y1;
288: if (!
289: (ret =
290: OSDStartPicture(card, 134 + x0, 48 + y0, x1 - x0 + 1,
291: y1 - y0 + 1, bit, mix)))
292: card->OSD.aspectratio = 12; // pixel aspect ratio 12/11
293: } else { // NTSC
294: if ((y1 + 1) > 484)
295: y1 = 484 - 1;
296: if (y0 > y1)
297: y0 = y1;
298: if (!
299: (ret =
300: OSDStartPicture(card, 126 + x0, 44 + y0, x1 - x0 + 1,
301: y1 - y0 + 1, bit, mix)))
302: card->OSD.aspectratio = 10; // pixel aspect ratio 10/11
303: }
304: return ret;
305: }
306:
307: // fills parameters with the picture dimensions and the pixel aspect ratio (aspy=11)
308: int OSDQuery(struct cvdv_cards *card, int *x0, int *y0, int *x1, int *y1,
309: int *aspx)
310: {
311: if (!card->OSD.open)
312: return -2;
313: *x0 = 0;
314: *x1 = card->OSD.width - 1;
315: *y0 = 0;
316: *y1 = card->OSD.height - 1;
317: *aspx = card->OSD.aspectratio;
318: return 0;
319: }
320:
321: // Sets all pixel to color 0
322: int OSDClear(struct cvdv_cards *card)
323: {
324: if (!card->OSD.open)
325: return -2;
326: DRAMFillByte(card, card->OSD.oddbitmap,
327: (int) (card->OSD.oddterm - card->OSD.oddbitmap) * 2,
328: 0x00);
329: DRAMFillByte(card, card->OSD.evenbitmap,
330: (int) (card->OSD.eventerm - card->OSD.evenbitmap) * 2,
331: 0x00);
332: return 0;
333: }
334:
335: // Sets all pixel to color <col>
336: int OSDFill(struct cvdv_cards *card, int col)
337: {
338: u8 color;
339: if (!card->OSD.open)
340: return -2;
341: if (card->OSD.bpp == 8) {
342: color = col & 0xFF;
343: } else if (card->OSD.bpp == 4) {
344: color = (col & 0xF);
345: color |= (color << 4);
346: } else if (card->OSD.bpp == 2) {
347: color = (col & 0x03);
348: for (col = 1; col <= 3; col++)
349: color |= (color << 2);
350: } else
351: color = 0x00;
352: DRAMFillByte(card, card->OSD.oddbitmap,
353: (int) (card->OSD.oddterm - card->OSD.oddbitmap) * 2,
354: color);
355: DRAMFillByte(card, card->OSD.evenbitmap,
356: (int) (card->OSD.eventerm - card->OSD.evenbitmap) * 2,
357: color);
358: return 0;
359: }
360:
361: // converts RGB(8 bit) to YCrCb(OSD format)
362: // mix: 0=opacity 100% 1=opacity at mix value
363: // trans: 0=mix bit applies 1=opacity 0%
364: // returns word in OSD palette format
365: u16 OSDColor(u8 R, u8 G, u8 B, int mix, int trans)
366: {
367: u16 Y, Cr, Cb;
368: Y = R * 77 + G * 150 + B * 29; // Luma=0.299R+0.587G+0.114B 0..65535
369: Cb = 2048 + B * 8 - (Y >> 5); // Cr 0..4095
370: Cr = 2048 + R * 10 - (Y >> 5); // Cb 0..4095
371: return ((trans) ? 0 : // transparent pixel
372: (Y & 0xFC00) | // Luma 0..63
373: ((mix) ? 0x0100 : 0x0000) | // Opacity applies
374: ((Cb >> 4) & 0x00F0) | // Cb 0..15
375: ((Cr >> 8) & 0x000F) // Cr 0..15
376: );
377: }
378:
379: // set palette entry <num> to <r,g,b>, <mix> and <trans> apply
380: // R,G,B: 0..255
381: // RGB=1: R=Red, G=Green, B=Blue RGB=0: R=Y G=Cb B=Cr
382: // mix=0, trans=0: pixel opacity 100% (only OSD pixel shows)
383: // mix=1, trans=0: pixel opacity as specified in header
384: // trans=1: pixel opacity 0% (only video pixel shows)
385: // returns 0 on success, 1 on error
386: int OSDSetColor(struct cvdv_cards *card, int num, int R, int G, int B,
387: int YUV, int mix, int trans)
388: {
389: u16 burst[4]; // minimal memory unit
390: u32 addr;
391: u16 color;
392: if (!card->OSD.open)
393: return -2;
394: if (R < 0)
395: R = 0;
396: if (R > 255)
397: R = 255;
398: if (G < 0)
399: G = 0;
400: if (G > 255)
401: G = 255;
402: if (B < 0)
403: B = 0;
404: if (B > 255)
405: B = 255;
406: if ((num >= 0) && (num < (1 << card->OSD.bpp))) {
1.2 ! mocm 407: if (num==0) MDEBUG(4,"OSD SetColor num=%d, R=%d, G=%d, B=%d, YUV=%d, mix=%d, trans=%d\n",
! 408: num,R,G,B,YUV,mix,trans);
1.1 cvs 409: color = ((YUV)
410: ? ((trans) ? 0 : ((R << 8) & 0xFC00) |
411: ((mix) ? 0x0100 : 0x0000) | (G & 0x00F0) |
412: ((B >> 4) & 0x000F)) : OSDColor(R, G, B, mix,
413: trans));
414:
415: addr = card->OSD.oddpalette + num;
416: DRAMReadWord(card, addr & ~3, 4, burst, 0);
417: burst[addr & 3] = color;
418: DRAMWriteWord(card, addr & ~3, 4, burst, 0);
419:
420: addr = card->OSD.evenpalette + num;
421: DRAMReadWord(card, addr & ~3, 4, burst, 0);
422: burst[addr & 3] = color;
423: DRAMWriteWord(card, addr & ~3, 4, burst, 0);
424:
425: return 0;
426: } else
427: return -1;
428: }
429:
430: // Set a number of entries in the palette
431: // sets the entries "firstcolor" through "lastcolor" from the array "data"
432: // data has 4 byte for each color:
433: // R,G,B, and a transparency value: 0->tranparent, 1..254->mix, 255->no mix
434: int OSDSetPalette(struct cvdv_cards *card, int firstcolor, int lastcolor,
435: u8 * data)
436: {
437: u16 burst[4]; // minimal memory unit
438: u32 addr;
439: u16 color;
440: int num, i = 0;
441: if (!card->OSD.open)
442: return -2;
443: for (num = firstcolor; num <= lastcolor; num++)
444: if ((num >= 0) && (num < (1 << card->OSD.bpp))) {
445: color =
446: OSDColor(data[i], data[i + 1], data[i + 2],
447: ((data[i + 3] < 255) ? 1 : 0),
448: ((data[i + 3] == 0) ? 1 : 0));
449: i += 4;
450:
451: addr = card->OSD.oddpalette + num;
452: DRAMReadWord(card, addr & ~3, 4, burst, 0);
453: burst[addr & 3] = color;
454: DRAMWriteWord(card, addr & ~3, 4, burst, 0);
455:
456: addr = card->OSD.evenpalette + num;
457: DRAMReadWord(card, addr & ~3, 4, burst, 0);
458: burst[addr & 3] = color;
459: DRAMWriteWord(card, addr & ~3, 4, burst, 0);
460: }
461: return 0;
462: }
463:
464: // Sets transparency of mixed pixel (0..15)
465: int OSDSetTrans(struct cvdv_cards *card, int trans)
466: {
467: u16 burst[4]; // minimal memory unit
468: if (!card->OSD.open)
469: return -2;
470: trans &= 0x000F;
471: DRAMReadWord(card, card->OSD.evendata, 4, burst, 0);
472: burst[1] = (burst[1] & 0x0FFF) | (trans << 12);
473: DRAMWriteWord(card, card->OSD.evendata, 4, burst, 0);
474:
475: DRAMReadWord(card, card->OSD.odddata, 4, burst, 0);
476: burst[1] = (burst[1] & 0x0FFF) | (trans << 12);
477: DRAMWriteWord(card, card->OSD.odddata, 4, burst, 0);
478: return 0;
479: }
480:
481: // sets pixel <x>,<y> to color number <col>
482: // returns 0 on success, 1 on error
483: int OSDSetPixel(struct cvdv_cards *card, int x, int y, int col)
484: {
485: u16 burst[4]; // minimal memory unit od DRAM
486: u32 addr;
487: int offset, ppw, pos, shift, height, posmask;
488: u16 mask;
489:
490: if (!card->OSD.open)
491: return -2;
492: if ((y & 1) == card->OSD.evenfirst) { // even or odd frame?
493: addr = card->OSD.oddbitmap;
494: height = card->OSD.oddheight;
495: } else {
496: addr = card->OSD.evenbitmap;
497: height = card->OSD.evenheight;
498: }
499: y >>= 1;
500: if ((x >= 0) && (x < card->OSD.width) && (y >= 0) && (y < height)) { // clipping
501: ppw =
502: ((card->OSD.bpp == 4) ? 2 : ((card->OSD.bpp == 8) ? 1 : 3)); // OK, 4-(ln(bpp)/ln(2)) would have worked, too...
503: pos = x + y * card->OSD.width; // pixel number in bitfield
504: addr += (pos >> ppw); // 21 bit address of word with our pixel
505: offset = addr & 3; // offset in burst
506: addr &= ~3; // 21 bit burst address
507: posmask = (1 << ppw) - 1; // mask for position inside word
508: shift = ((posmask - (pos & posmask)) << (4 - ppw)); // pixel shift inside word
509: mask = (1 << (1 << (4 - ppw))) - 1; // pixel mask
510: DRAMReadWord(card, addr, 4, burst, 0); // get the burst with our pixel...
511: burst[offset] =
512: (burst[offset] & ~(mask << shift)) | ((col & mask) <<
513: shift);
514: DRAMWriteWord(card, addr, 4, burst, 0); // ...and write it back
515: return 0;
516: } else
517: return -1;
518: }
519:
520: // returns color number of pixel <x>,<y>, or -1
521: int OSDGetPixel(struct cvdv_cards *card, int x, int y)
522: {
523: u16 burst[4]; // minimal memory unit
524: u32 addr;
525: int offset, ppw, pos, shift, height, posmask;
526: u16 mask;
527:
528: if (!card->OSD.open)
529: return -2;
530: if ((y & 1) == card->OSD.evenfirst) { // even or odd frame?
531: addr = card->OSD.oddbitmap;
532: height = card->OSD.oddheight;
533: } else {
534: addr = card->OSD.evenbitmap;
535: height = card->OSD.evenheight;
536: }
537: y >>= 1;
538: if ((x >= 0) && (x < card->OSD.width) && (y >= 0) && (y < height)) { // clipping
539: ppw =
540: ((card->OSD.bpp == 4) ? 2 : ((card->OSD.bpp == 8) ? 1 : 3)); // OK, 4-(ln(bpp)/ln(2)) would have worked, too...
541: pos = x + y * card->OSD.width; // pixel number in bitfield
542: addr += (pos >> ppw); // 21 bit address of word with our pixel
543: offset = addr & 3; // offset in burst
544: addr &= ~3; // 21 bit burst address
545: posmask = (1 << ppw) - 1; // mask for position inside word
546: shift = ((posmask - (pos & posmask)) << (4 - ppw)); // pixel shift inside word
547: mask = (1 << (1 << (4 - ppw))) - 1; // pixel mask
548: DRAMReadWord(card, addr, 4, burst, 0); // get the burst with our pixel...
549: return (burst[offset] >> shift) & mask; // ...and return it's value
550: } else
551: return -1;
552: }
553:
554: // fills pixels x0,y through x1,y with the content of data[]
555: // returns 0 on success, -1 on clipping all pixel
556: int OSDSetRow(struct cvdv_cards *card, int x0, int y, int x1, u8 * data)
557: {
558: u16 burst[4]; // minimal memory unit
559: u32 addr, addr1, bitmap;
560: int offset, offset1, ppw, pos, pos1, shift, shift0, shift1,
561: shiftstep, height, bpp, x, i, endburst, endword;
562: u16 mask, posmask;
563:
564: if (!card->OSD.open)
565: return -2;
566: if ((y & 1) == card->OSD.evenfirst) {
567: bitmap = card->OSD.oddbitmap;
568: height = card->OSD.oddheight;
569: } else {
570: bitmap = card->OSD.evenbitmap;
571: height = card->OSD.evenheight;
572: }
573: y >>= 1;
574: if ((y >= 0) && (y < height)) {
575: i = 0;
576: if (x0 > x1) {
577: x = x1;
578: x1 = x0;
579: x0 = x;
580: }
581: if ((x0 >= card->OSD.width) || (x1 < 0))
582: return -1;
583: if (x0 < 0) {
584: i -= x0;
585: x0 = 0;
586: }
587: if (x1 >= card->OSD.width)
588: x1 = card->OSD.width - 1;
589: bpp = card->OSD.bpp; // bits per pixel
590: ppw = ((bpp == 4) ? 2 : ((bpp == 8) ? 1 : 3)); // positional parameter
591: mask = (1 << bpp) - 1; // mask for one pixel
592: posmask = (1 << ppw) - 1; // mask for position inside word
593:
594: pos = x0 + (y * card->OSD.width); // pixel number of first pixel
595: pos1 = pos + x1 - x0; // pixel number of last pixel
596: shift0 = ((posmask - (pos & posmask)) << (4 - ppw));
597: shift1 = ((posmask - (pos1 & posmask)) << (4 - ppw));
598: shiftstep = 1 << (4 - ppw);
599:
600: addr = bitmap + (pos >> ppw); // DRAM address of word with first pixel
601: addr1 = bitmap + (pos1 >> ppw); // " " " " " last "
602: offset = (int) (addr & 3); // word position inside burst
603: offset1 = (int) (addr1 & 3); // number of last word in the last burst
604: addr &= ~3; // burst address
605: addr1 &= ~3; // burst address of last pixel
606:
607: endburst = (addr1 != addr); // end in other burst
608: endword = (offset1 != offset); // end in other word
609:
610: // read old content of first burst if the row start after the beginning or
611: // end before the end of the first burst
612: if (offset || (pos & posmask) ||
613: (!endburst
614: && ((offset1 != 3)
615: || ((pos1 & posmask) != posmask)))) {
616: DRAMReadWord(card, addr, 4, burst, 0);
617: }
618: // End beyond or at the end of this word?
619: if (endburst || endword || ((pos1 & posmask) == posmask)) {
620: // Fill first word
621: for (shift = shift0; shift >= 0; shift -= shiftstep) { // bit position inside word
622: burst[offset] =
623: (burst[offset] & ~(mask << shift)) |
624: ((data[i++] & mask) << shift);
625: }
626: if (endburst || endword) { // Any more words to fill?
627: shift0 = posmask << (4 - ppw); // from here on, we start at the beginning of each word
628: offset++; // fill the rest of the burst
629: if (endburst) { // end not in this burst?
630: while (offset <= 3) { // fill remaining words
631: burst[offset] = 0x0000; // clear first
632: for (shift = shift0;
633: shift >= 0;
634: shift -= shiftstep) {
635: burst[offset] |=
636: ((data
637: [i++] & mask)
638: << shift);
639: }
640: offset++;
641: }
642: DRAMWriteWord(card, addr, 4, burst, 0); // write first burst
643: addr += 4; // go on to the next burst
644: while (addr < addr1) { // all bursts between start and end burst
645: for (offset = 0;
646: offset <= 3; offset++) { // 4 words per burst
647: burst[offset] = 0x0000; // clear first
648: for (shift =
649: shift0;
650: shift >= 0;
651: shift -=
652: shiftstep) {
653: burst
654: [offset]
655: |=
656: ((data
657: [i++]
658: &
659: mask)
660: <<
661: shift);
662: }
663: }
664: DRAMWriteWord(card, addr,
665: 4, burst, 0); // write full burst
666: addr += 4; // next burst
667: }
668: offset = 0;
669: if ((offset1 < 3) || shift1) { // does the row ends before the end of the burst?
670: DRAMReadWord(card, addr, 4,
671: burst, 0); // then we have to read the old content
672: }
673: }
674: while (offset < offset1) { // end not in this word
675: burst[offset] = 0x0000; // clear first
676: for (shift = shift0; shift >= 0;
677: shift -= shiftstep) {
678: burst[offset] |=
679: ((data[i++] & mask) <<
680: shift);
681: }
682: offset++;
683: }
684: for (shift = shift0; shift >= shift1;
685: shift -= shiftstep) { // last word
686: burst[offset] =
687: (burst[offset] &
688: ~(mask << shift)) |
689: ((data[i++] & mask) << shift);
690: }
691: }
692: } else { // row starts and ends in one word
693: for (shift = shift0; shift >= shift1; shift -= shiftstep) { // bit position inside word
694: burst[offset] =
695: (burst[offset] & ~(mask << shift)) |
696: ((data[i++] & mask) << shift);
697: }
698: }
699: DRAMWriteWord(card, addr, 4, burst, 0); // write only/last burst
700: return 0;
701: } else
702: return -1;
703: }
704:
705: // fills pixels x0,y0 through x1,y1 with the content of data[]
706: // inc contains the width of one line in the data block,
707: // inc<=0 uses blockwidth as linewidth
708: // returns 0 on success, -1 on clipping all pixel
709: int OSDSetBlock(struct cvdv_cards *card, int x0, int y0, int x1, int y1,
710: int inc, u8 * data)
711: {
712: int i, w = x1 - x0 + 1, ret = 0;
713: if (inc > 0)
714: w = inc;
715: for (i = y0; i <= y1; i++) {
716: ret |= OSDSetRow(card, x0, i, x1, data);
717: data += w;
718: }
719: return ret;
720: }
721:
722: // fills pixels x0,y through x1,y with the color <col>
723: // returns 0 on success, -1 on clipping all pixel
724: int OSDFillRow(struct cvdv_cards *card, int x0, int y, int x1, int col)
725: {
726: u16 burst[4]; // minimal memory unit
727: u32 addr, addr1, bitmap;
728: int offset, offset1, ppw, pos, pos1, shift, shift0, shift1,
729: shiftstep, height, bpp, x, i, endburst, endword;
730: u16 mask, posmask;
731:
732: if (!card->OSD.open)
733: return -2;
734: if ((y & 1) == card->OSD.evenfirst) {
735: bitmap = card->OSD.oddbitmap;
736: height = card->OSD.oddheight;
737: } else {
738: bitmap = card->OSD.evenbitmap;
739: height = card->OSD.evenheight;
740: }
741: y >>= 1;
742: if ((y >= 0) && (y < height)) {
743: i = 0;
744: if (x0 > x1) {
745: x = x1;
746: x1 = x0;
747: x0 = x;
748: }
749: if ((x0 >= card->OSD.width) || (x1 < 0))
750: return -1;
751: if (x0 < 0) {
752: i -= x0;
753: x0 = 0;
754: }
755: if (x1 >= card->OSD.width)
756: x1 = card->OSD.width - 1;
757: bpp = card->OSD.bpp; // bits per pixel
758: ppw = ((bpp == 4) ? 2 : ((bpp == 8) ? 1 : 3)); // positional parameter
759: mask = (1 << bpp) - 1; // mask for one pixel
760: posmask = (1 << ppw) - 1; // mask for position inside word
761:
762: pos = x0 + (y * card->OSD.width); // pixel number of first pixel
763: pos1 = pos + x1 - x0; // pixel number of last pixel
764: shift0 = ((posmask - (pos & posmask)) << (4 - ppw));
765: shift1 = ((posmask - (pos1 & posmask)) << (4 - ppw));
766: shiftstep = 1 << (4 - ppw);
767:
768: addr = bitmap + (pos >> ppw); // DRAM address of word with first pixel
769: addr1 = bitmap + (pos1 >> ppw); // " " " " " last "
770: offset = (int) (addr & 3); // word position inside burst
771: offset1 = (int) (addr1 & 3); // number of last word in the last burst
772: addr &= ~3; // burst address
773: addr1 &= ~3; // burst address of last pixel
774:
775: endburst = (addr1 != addr); // end in other burst
776: endword = (offset1 != offset); // end in other word
777:
778: // read old content of first burst if the row start after the beginning or
779: // end before the end of the first burst
780: if (offset || (pos & posmask) ||
781: (!endburst
782: && ((offset1 != 3)
783: || ((pos1 & posmask) != posmask)))) {
784: DRAMReadWord(card, addr, 4, burst, 0);
785: }
786: if (endburst || endword || ((pos1 & posmask) == posmask)) { // end beyond or at the end of this word?
787: for (shift = shift0; shift >= 0; shift -= shiftstep) { // bit position inside word
788: burst[offset] =
789: (burst[offset] & ~(mask << shift)) |
790: ((col & mask) << shift);
791: }
792: if (endburst || endword) {
793: shift0 = posmask << (4 - ppw); // from here on, we start at the beginning of each word
794: offset++; // fill the rest of the burst
795: if (endburst) { // end not in this burst?
796: while (offset <= 3) { // fill remaining words
797: burst[offset] = 0x0000; // clear first
798: for (shift = shift0;
799: shift >= 0;
800: shift -= shiftstep) {
801: burst[offset] |=
802: ((col & mask)
803: << shift);
804: }
805: offset++;
806: }
807: DRAMWriteWord(card, addr, 4, burst, 0); // write first burst
808: addr += 4; // next burst
809: while (addr < addr1) { // write all the bursts between start and end burst
810: for (offset = 0;
811: offset <= 3; offset++) {
812: burst[offset] =
813: 0x0000;
814: for (shift =
815: shift0;
816: shift >= 0;
817: shift -=
818: shiftstep) {
819: burst
820: [offset]
821: |=
822: ((col
823: &
824: mask)
825: <<
826: shift);
827: }
828: }
829: DRAMWriteWord(card, addr,
830: 4, burst, 0);
831: addr += 4;
832: }
833: offset = 0;
834: if ((offset1 < 3) || shift1) { // does the row ends before the end of the burst?
835: DRAMReadWord(card, addr, 4,
836: burst, 0); // then we have to read the old content
837: }
838: }
839: while (offset < offset1) { // end not in this word
840: burst[offset] = 0x0000;
841: for (shift = shift0; shift >= 0;
842: shift -= shiftstep) {
843: burst[offset] |=
844: ((col & mask) <<
845: shift);
846: }
847: offset++;
848: }
849: for (shift = shift0; shift >= shift1;
850: shift -= shiftstep) {
851: burst[offset] =
852: (burst[offset] &
853: ~(mask << shift)) | ((col &
854: mask) <<
855: shift);
856: }
857: }
858: } else { // row starts and ends in one word
859: for (shift = shift0; shift >= shift1; shift -= shiftstep) { // bit position inside word
860: burst[offset] =
861: (burst[offset] & ~(mask << shift)) |
862: ((col & mask) << shift);
863: }
864: }
865: DRAMWriteWord(card, addr, 4, burst, 0);
866: return 0;
867: } else
868: return -1;
869: }
870:
871: // fills pixels x0,y0 through x1,y1 with the color <col>
872: // returns 0 on success, -1 on clipping all pixel
873: int OSDFillBlock(struct cvdv_cards *card, int x0, int y0, int x1, int y1,
874: int col)
875: {
876: int i, ret = 0;
877: for (i = y0; i <= y1; i++)
878: ret |= OSDFillRow(card, x0, i, x1, col);
879: return ret;
880: }
881:
882: // draw a line from x0,y0 to x1,y1 with the color <col>
883: int OSDLine(struct cvdv_cards *card, int x0, int y0, int x1, int y1,
884: int col)
885: {
886: int ct, ix, iy, ax, ay, dx, dy, off;
887: #define sgn(a) ((a)?(((a)>0)?1:-1):0)
888: if (!card->OSD.open)
889: return -2;
890: dx = x1 - x0;
891: dy = y1 - y0;
892: if (dx == 0) {
893: if (dy < 0)
894: for (iy = y1; iy <= y0; iy++)
895: OSDSetPixel(card, x0, iy, col);
896: else
897: for (iy = y0; iy <= y1; iy++)
898: OSDSetPixel(card, x0, iy, col);
899: } else if (dy == 0) {
900: OSDFillRow(card, x0, y0, x1, col);
901: } else {
902: ay = 0;
903: ax = 0;
904: ix = sgn(dx);
905: dx = abs(dx);
906: iy = sgn(dy);
907: dy = abs(dy);
908: if (dx < dy) {
909: off = dx;
910: dx = dy;
911: dy = off;
912: ay = ix;
913: ax = iy;
914: ix = 0;
915: iy = 0;
916: }
917: off = dx >> 1;
918: ct = 1;
919: OSDSetPixel(card, x0, y0, col);
920: x1 = x0;
921: y1 = y0;
922: while (dx >= ct) {
923: x0 += ix;
924: y0 += ax;
925: ct++;
926: off += dy;
927: if (off > dx) {
928: off -= dx;
929: x0 += ay;
930: y0 += iy;
931: }
932: if (ax) {
933: OSDSetPixel(card, x0, y0, col);
934: } else {
935: if (y0 != y1) {
936: OSDFillRow(card, x1, y1, x0 - ay,
937: col);
938: x1 = x0;
939: y1 = y0;
940: }
941: }
942: }
943: if (!ax)
944: OSDFillRow(card, x1, y0, x0, col);
945: }
946: return 0;
947: }
LinuxTV legacy CVS <linuxtv.org/cvs>