Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/modules/HibernateEnabler/graphic_utils.c

1
2/* Graphic utility functions and data types
3 * Prashant Vaibhav (C) 12/12/2008
4 * Chameleon
5 */
6#include "libsaio.h"
7#include "bootstruct.h"
8#include "graphic_utils.h"
9#include "IOHibernatePrivate.h"
10#include "bmdecompress.h"
11#include "vbe.h"
12#include "appleClut8.h"
13
14
15#ifndef offsetof
16#define offsetof(st, m) \
17((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
18#endif
19
20#define VIDEO(x) (((boot_args_common*)getBootArgs())->Video.v_ ## x)
21
22
23#define MIN(x, y) ((x) < (y) ? (x) : (y))
24
25int previewTotalSectors = 0;
26uint8_t *previewSaveunder = 0;
27int previewLoadedSectors = 0;
28#if UNUSED
29static int setVESAGraphicsMode( unsigned short width, unsigned short height, unsigned char bitsPerPixel, unsigned short refreshRate );
30#else
31static int setVESAGraphicsMode( unsigned short width, unsigned short height, unsigned char bitsPerPixel);
32#endif
33
34void
35loadImageScale (void *input, int iw, int ih, int ip, void *output, int ow, int oh, int op, int or)
36{
37int x,y, off;
38int red=0x7f, green=0x7f, blue=0x7f;
39for (x=0;x<ow;x++)
40for (y=0;y<oh;y++)
41{
42off=(x*iw)/ow+((y*ih)/oh)*iw;
43switch (ip)
44{
45case 16:
46{
47uint16_t val;
48val=((uint16_t *)input)[off];
49red=(val>>7)&0xf8;
50green=(val>>2)&0xf8;
51blue=(val<<3)&0xf8;
52break;
53}
54case 32:
55{
56uint32_t val;
57val=((uint32_t *)input)[off];
58red=(val>>16)&0xff;
59green=(val>>8)&0xff;
60blue=(val)&0xff;
61break;
62}
63default:
64break;
65}
66char *ptr=(char *)output+x*(op/8)+y*or;
67switch (op)
68{
69case 16:
70*((uint16_t *)ptr) = ((red & 0xF8) << 7) |
71((green & 0xF8) << 2) |
72((blue & 0xF8) >> 3);
73break;
74case 32 :
75*((uint32_t *)ptr) = (red << 16) | (green << 8) | blue;
76break;
77default:
78break;
79}
80}
81}
82
83//==========================================================================
84// getNumberArrayFromProperty
85
86static int
87getNumberArrayFromProperty( const char * propKey,
88 unsigned long numbers[],
89 unsigned long maxArrayCount )
90{
91 char * propStr;
92 unsigned long count = 0;
93
94 propStr = newStringForKey( (char *) propKey , DEFAULT_BOOT_CONFIG );
95 if ( propStr )
96 {
97 char * delimiter = propStr;
98 char * p = propStr;
99
100 while ( count < maxArrayCount && *p != '\0' )
101 {
102 unsigned long val = strtoul( p, &delimiter, 10 );
103 if ( p != delimiter )
104 {
105 numbers[count++] = val;
106 p = delimiter;
107 }
108 while ( ( *p != '\0' ) && !isdigit(*p) )
109 p++;
110 }
111
112 free( propStr );
113 }
114
115 return count;
116}
117
118static int initGraphicsMode ()
119{
120unsigned long params[4];
121int count;
122
123params[3] = 0;
124count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 );
125
126// Try to find a resolution if "Graphics Mode" setting is not available.
127if ( count < 3 )
128{
129params[0] = DEFAULT_SCREEN_WIDTH;
130params[1] = DEFAULT_SCREEN_HEIGHT;
131params[2] = 32;
132}
133
134// Map from pixel format to bits per pixel.
135
136if ( params[2] == 256 ) params[2] = 8;
137if ( params[2] == 555 ) params[2] = 16;
138if ( params[2] == 888 ) params[2] = 32;
139#if UNUSED
140return setVESAGraphicsMode( params[0], params[1], params[2], params[3] );
141#else
142return setVESAGraphicsMode( params[0], params[1], params[2] );
143#endif
144}
145
146//==========================================================================
147// setupPalette
148
149static void setupPalette( VBEPalette * p, const unsigned char * g )
150{
151 int i;
152 unsigned char * source = (unsigned char *) g;
153
154 for (i = 0; i < 256; i++)
155 {
156 (*p)[i] = 0;
157 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red
158 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green
159 (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue
160
161 }
162}
163
164//==========================================================================
165// getVESAModeWithProperties
166//
167// Return the VESA mode that matches the properties specified.
168// If a mode is not found, then return the "best" available mode.
169
170static unsigned short
171getVESAModeWithProperties( unsigned short width,
172 unsigned short height,
173 unsigned char bitsPerPixel,
174 unsigned short attributesSet,
175 unsigned short attributesClear,
176 VBEModeInfoBlock * outModeInfo,
177 unsigned short * vesaVersion )
178{
179 VBEInfoBlock vbeInfo;
180 unsigned short * modePtr;
181 VBEModeInfoBlock modeInfo;
182 unsigned char modeBitsPerPixel;
183 unsigned short matchedMode = modeEndOfList;
184 int err;
185
186 // Clear output mode info.
187
188 //bzero( outModeInfo, sizeof(*outModeInfo) );
189bzero( outModeInfo, sizeof(VBEModeInfoBlock) );
190
191 // Get VBE controller info containing the list of supported modes.
192
193 //bzero( &vbeInfo, sizeof(vbeInfo) );
194 bzero( &vbeInfo, sizeof(VBEInfoBlock) );
195
196 strcpy( (char*)&vbeInfo, "VBE2" );
197 err = getVBEInfo( &vbeInfo );
198 if ( err != errSuccess )
199 {
200 return modeEndOfList;
201 }
202
203 // Report the VESA major/minor version number.
204
205 if (vesaVersion) *vesaVersion = vbeInfo.VESAVersion;
206
207 // Loop through the mode list, and find the matching mode.
208
209 for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
210 *modePtr != modeEndOfList; modePtr++ )
211 {
212 // Get mode information.
213
214 //bzero( &modeInfo, sizeof(modeInfo) );
215 bzero( &modeInfo, sizeof(VBEModeInfoBlock) );
216
217 err = getVBEModeInfo( *modePtr, &modeInfo );
218 if ( err != errSuccess )
219 {
220 continue;
221 }
222
223#if DEBUG
224 printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
225 *modePtr, modeInfo.XResolution, modeInfo.YResolution,
226 modeInfo.BitsPerPixel, modeInfo.MemoryModel,
227 modeInfo.ModeAttributes);
228#endif
229
230 // Filter out unwanted modes based on mode attributes.
231
232 if ( ( ( modeInfo.ModeAttributes & attributesSet ) != attributesSet )
233|| ( ( modeInfo.ModeAttributes & attributesClear ) != 0 ) )
234 {
235 continue;
236 }
237
238 // Pixel depth in bits.
239
240 modeBitsPerPixel = modeInfo.BitsPerPixel;
241
242 if ( ( modeBitsPerPixel == 4 ) && ( modeInfo.MemoryModel == 0 ) )
243 {
244 // Text mode, 16 colors.
245 }
246 else if ( ( modeBitsPerPixel == 8 ) && ( modeInfo.MemoryModel == 4 ) )
247 {
248 // Packed pixel, 256 colors.
249 }
250 else if ( ( ( modeBitsPerPixel == 16 ) || ( modeBitsPerPixel == 15 ) )
251 && ( modeInfo.MemoryModel == 6 )
252 && ( modeInfo.RedMaskSize == 5 )
253 && ( modeInfo.GreenMaskSize == 5 )
254 && ( modeInfo.BlueMaskSize == 5 ) )
255 {
256 // Direct color, 16 bpp (1:5:5:5).
257 modeInfo.BitsPerPixel = modeBitsPerPixel = 16;
258 }
259 else if ( ( modeBitsPerPixel == 32 )
260 && ( modeInfo.MemoryModel == 6 )
261 && ( modeInfo.RedMaskSize == 8 )
262 && ( modeInfo.GreenMaskSize == 8 )
263 && ( modeInfo.BlueMaskSize == 8 ) )
264 {
265 // Direct color, 32 bpp (8:8:8:8).
266 }
267 else
268 {
269 continue; // Not a supported mode.
270 }
271
272 // Modes larger than the specified dimensions are skipped.
273
274 if ( ( modeInfo.XResolution > width ) ||
275( modeInfo.YResolution > height ) )
276 {
277 continue;
278 }
279
280 // Perfect match, we're done looking.
281
282 if ( ( modeInfo.XResolution == width ) &&
283( modeInfo.YResolution == height ) &&
284( modeBitsPerPixel == bitsPerPixel ) )
285 {
286 matchedMode = *modePtr;
287 //bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
288 bcopy( &modeInfo, outModeInfo, sizeof(VBEModeInfoBlock) );
289
290 break;
291 }
292
293 // Save the next "best" mode in case a perfect match is not found.
294
295 if ( modeInfo.XResolution == outModeInfo->XResolution &&
296modeInfo.YResolution == outModeInfo->YResolution &&
297modeBitsPerPixel <= outModeInfo->BitsPerPixel )
298 {
299 continue; // Saved mode has more depth.
300 }
301 if ( modeInfo.XResolution < outModeInfo->XResolution ||
302modeInfo.YResolution < outModeInfo->YResolution ||
303modeBitsPerPixel < outModeInfo->BitsPerPixel )
304 {
305 continue; // Saved mode has more resolution.
306 }
307
308 matchedMode = *modePtr;
309 bcopy( &modeInfo, outModeInfo, sizeof(VBEModeInfoBlock) );
310
311 }
312
313 return matchedMode;
314}
315
316//==========================================================================
317// setVESAGraphicsMode
318#if UNUSED
319static int setVESAGraphicsMode( unsigned short width, unsigned short height, unsigned char bitsPerPixel, unsigned short refreshRate )
320#else
321static int setVESAGraphicsMode( unsigned short width, unsigned short height, unsigned char bitsPerPixel)
322#endif
323{
324 VBEModeInfoBlock minfo;
325 unsigned short mode;
326 unsigned short vesaVersion;
327 int err = errFuncNotSupported;
328
329 do {
330 mode = getVESAModeWithProperties( width, height, bitsPerPixel,
331 maColorModeBit |
332 maModeIsSupportedBit |
333 maGraphicsModeBit |
334 maLinearFrameBufferAvailBit,
335 0,
336 &minfo, &vesaVersion );
337 if ( mode == modeEndOfList )
338 {
339 break;
340 }
341#if UNUSED
342//
343// FIXME : generateCRTCTiming() causes crash.
344//
345
346// if ( (vesaVersion >> 8) >= 3 && refreshRate >= 60 &&
347// (gBootMode & kBootModeSafe) == 0 )
348// {
349// VBECRTCInfoBlock timing;
350//
351// // Generate CRTC timing for given refresh rate.
352//
353// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
354// refreshRate, kCRTCParamRefreshRate,
355// &timing );
356//
357// // Find the actual pixel clock supported by the hardware.
358//
359// getVBEPixelClock( mode, &timing.PixelClock );
360//
361// // Re-compute CRTC timing based on actual pixel clock.
362//
363// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
364// timing.PixelClock, kCRTCParamPixelClock,
365// &timing );
366//
367// // Set the video mode and use specified CRTC timing.
368//
369// err = setVBEMode( mode | kLinearFrameBufferBit |
370// kCustomRefreshRateBit, &timing );
371// }
372// else
373// {
374// // Set the mode with default refresh rate.
375//
376// err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
377// }
378#endif
379 // Set the mode with default refresh rate.
380
381 err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
382
383 if ( err != errSuccess )
384 {
385 break;
386 }
387
388 // Set 8-bit color palette.
389
390 if ( minfo.BitsPerPixel == 8 )
391 {
392 VBEPalette palette;
393 setupPalette( &palette, appleClut8 );
394 if ((err = setVBEPalette(palette)) != errSuccess)
395 {
396 break;
397 }
398 }
399
400 // Is this required for buggy Video BIOS implementations?
401 // On which adapter?
402
403 if ( minfo.BytesPerScanline == 0 )
404minfo.BytesPerScanline = ( minfo.XResolution *
405 minfo.BitsPerPixel ) >> 3;
406
407 // Update KernBootStruct using info provided by the selected
408 // VESA mode.
409 Boot_VideoVideo;/* Video Information */
410
411
412 Video.v_display = GRAPHICS_MODE;
413 Video.v_width = minfo.XResolution;
414 Video.v_height = minfo.YResolution;
415 Video.v_depth = minfo.BitsPerPixel;
416 Video.v_rowBytes = minfo.BytesPerScanline;
417 Video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr);
418
419
420setBootArgsVideoStruct(&Video);
421
422 }
423 while ( 0 );
424
425 return err;
426}
427
428//==========================================================================
429// setVESATextMode
430
431static int
432setVESATextMode( unsigned short cols,
433unsigned short rows,
434unsigned char bitsPerPixel )
435{
436 VBEModeInfoBlock minfo;
437minfo.XResolution = 0;
438 minfo.YResolution = 0;
439 unsigned short mode = modeEndOfList;
440
441 if ( (cols != 80) || (rows != 25) ) // not 80x25 mode
442 {
443 mode = getVESAModeWithProperties( cols, rows, bitsPerPixel,
444 maColorModeBit |
445 maModeIsSupportedBit,
446 maGraphicsModeBit,
447 &minfo, NULL );
448 }
449
450 if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) )
451 {
452 video_mode( 2 ); // VGA BIOS, 80x25 text mode.
453 minfo.XResolution = 80;
454 minfo.YResolution = 25;
455 }
456
457 // Update KernBootStruct using info provided by the selected
458 // VESA mode.
459Boot_VideoVideo;/* Video Information */
460
461
462 Video.v_display = VGA_TEXT_MODE;
463 Video.v_width = 0xb8000;
464 Video.v_height = minfo.XResolution;
465 Video.v_depth = minfo.YResolution;
466 Video.v_rowBytes = 8;
467 Video.v_baseAddr = 0x8000;
468
469 setBootArgsVideoStruct(&Video);
470
471
472 return errSuccess; // always return success
473}
474
475//==========================================================================
476// setVideoMode
477//
478// Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE.
479#if UNUSED
480void
481setVideoMode( int mode, int drawgraphics)
482#else
483void
484setVideoMode( int mode)
485#endif
486{
487 unsigned long params[4];
488 int count;
489 int err = errSuccess;
490
491 if ( mode == GRAPHICS_MODE )
492 {
493 if ( (err=initGraphicsMode ()) == errSuccess ) {
494if (gVerboseMode) {
495// Tell the kernel to use text mode on a linear frame buffer display
496 setBootArgsVideoMode(FB_TEXT_MODE);
497} else {
498 setBootArgsVideoMode(GRAPHICS_MODE);
499}
500}
501 }
502
503 if ( (mode == VGA_TEXT_MODE) || (err != errSuccess) )
504 {
505 count = getNumberArrayFromProperty( kTextModeKey, params, 2 );
506 if ( count < 2 )
507 {
508 params[0] = 80; // Default text mode is 80x25.
509 params[1] = 25;
510 }
511
512setVESATextMode( params[0], params[1], 4 );
513 setBootArgsVideoMode(VGA_TEXT_MODE);
514
515 }
516
517}
518
519//==========================================================================
520// LookUpCLUTIndex
521
522static unsigned long lookUpCLUTIndex( unsigned char index,
523 unsigned char depth )
524{
525 long result, red, green, blue;
526
527 red = appleClut8[index * 3 + 0];
528 green = appleClut8[index * 3 + 1];
529 blue = appleClut8[index * 3 + 2];
530
531 switch (depth) {
532 case 16 :
533 result = ((red & 0xF8) << 7) |
534((green & 0xF8) << 2) |
535((blue & 0xF8) >> 3);
536 result |= (result << 16);
537 break;
538
539 case 32 :
540 result = (red << 16) | (green << 8) | blue;
541 break;
542
543 default :
544 result = index | (index << 8);
545 result |= (result << 16);
546 break;
547 }
548
549 return result;
550}
551
552static void * stosl(void * dst, long val, long len)
553{
554 asm volatile ( "rep; stosl"
555 : "=c" (len), "=D" (dst)
556 : "0" (len), "1" (dst), "a" (val)
557 : "memory" );
558
559 return dst;
560}
561
562static void drawColorRectangle( unsigned short x,
563 unsigned short y,
564 unsigned short width,
565 unsigned short height,
566 unsigned char colorIndex )
567{
568 long pixelBytes;
569 long color = lookUpCLUTIndex( colorIndex, VIDEO(depth) );
570 char * vram;
571
572 pixelBytes = VIDEO(depth) / 8;
573 vram = (char *) VIDEO(baseAddr) +
574VIDEO(rowBytes) * y + pixelBytes * x;
575
576 width = MIN(width, VIDEO(width) - x);
577 height = MIN(height, VIDEO(height) - y);
578
579 while ( height-- )
580 {
581 int rem = ( pixelBytes * width ) % 4;
582 if ( rem ) bcopy( &color, vram, rem );
583 stosl( vram + rem, color, pixelBytes * width / 4 );
584 vram += VIDEO(rowBytes);
585 }
586}
587
588DECLARE_IOHIBERNATEPROGRESSALPHA
589
590void drawPreview(void *src, uint8_t * saveunder)
591{
592uint8_t * screen;
593uint32_t rowBytes, pixelShift;
594uint32_t x, y;
595int32_t blob;
596uint32_t alpha, in, color, result;
597uint8_t * out;
598void *uncomp;
599int origwidth, origheight, origbpx;
600uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
601
602if (src && (uncomp=DecompressData(src, &origwidth, &origheight, &origbpx)))
603{
604#if UNUSED
605if (!setVESAGraphicsMode(origwidth, origheight, origbpx, 0))
606#else
607if (!setVESAGraphicsMode(origwidth, origheight, origbpx))
608#endif
609if (initGraphicsMode () != errSuccess)
610return;
611screen = (uint8_t *) VIDEO (baseAddr);
612rowBytes = VIDEO (rowBytes);
613loadImageScale (uncomp, origwidth, origheight, origbpx, screen, VIDEO(width), VIDEO(height), VIDEO(depth), VIDEO (rowBytes));
614}
615else
616{
617if (initGraphicsMode () != errSuccess)
618return;
619screen = (uint8_t *) VIDEO (baseAddr);
620rowBytes = VIDEO (rowBytes);
621// Set the screen to 75% grey.
622 drawColorRectangle(0, 0, VIDEO(width), VIDEO(height), 0x01 /* color index */);
623}
624
625
626pixelShift = VIDEO (depth) >> 4;
627if (pixelShift < 1) return;
628
629screen += ((VIDEO (width)
630- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
631+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
632
633for (y = 0; y < kIOHibernateProgressHeight; y++)
634{
635out = screen + y * rowBytes;
636for (blob = 0; blob < kIOHibernateProgressCount; blob++)
637{
638color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
639for (x = 0; x < kIOHibernateProgressWidth; x++)
640{
641alpha = gIOHibernateProgressAlpha[y][x];
642result = color;
643if (alpha)
644{
645if (0xff != alpha)
646{
647if (1 == pixelShift)
648{
649in = *((uint16_t *)out) & 0x1f;// 16
650in = (in << 3) | (in >> 2);
651}
652else
653in = *((uint32_t *)out) & 0xff;// 32
654saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
655result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
656}
657if (1 == pixelShift)
658{
659result >>= 3;
660*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
661}
662else
663*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
664}
665out += (1 << pixelShift);
666}
667out += (kIOHibernateProgressSpacing << pixelShift);
668}
669}
670}
671
672void updateProgressBar(uint8_t * saveunder, int32_t firstBlob, int32_t select)
673{
674uint8_t * screen;
675uint32_t rowBytes, pixelShift;
676uint32_t x, y;
677int32_t blob, lastBlob;
678uint32_t alpha, in, color, result;
679uint8_t * out;
680uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
681
682pixelShift = VIDEO(depth) >> 4;
683if (pixelShift < 1) return;
684screen = (uint8_t *) VIDEO (baseAddr);
685rowBytes = VIDEO (rowBytes);
686
687screen += ((VIDEO (width)
688- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
689+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
690
691lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
692
693screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
694
695for (y = 0; y < kIOHibernateProgressHeight; y++)
696{
697out = screen + y * rowBytes;
698for (blob = firstBlob; blob <= lastBlob; blob++)
699{
700color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
701for (x = 0; x < kIOHibernateProgressWidth; x++)
702{
703alpha = gIOHibernateProgressAlpha[y][x];
704result = color;
705if (alpha)
706{
707if (0xff != alpha)
708{
709in = saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++];
710result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
711}
712if (1 == pixelShift)
713{
714result >>= 3;
715*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
716}
717else
718*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
719}
720out += (1 << pixelShift);
721}
722out += (kIOHibernateProgressSpacing << pixelShift);
723}
724}
725}
726
727void
728spinActivityIndicator_hook(void *arg1, void *arg2, void *arg3, void *arg4, void* arg5, void* arg6)
729{
730int sectors = *(int*)arg1;
731bool *doreturn = (bool*)arg2;
732
733if (previewTotalSectors && previewSaveunder)
734{
735int blob, lastBlob;
736
737lastBlob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
738previewLoadedSectors+=sectors;
739blob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
740
741if (blob!=lastBlob)
742updateProgressBar (previewSaveunder, lastBlob, blob);
743*doreturn = true;
744}
745}

Archive Download this file

Revision: 1929