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

Archive Download this file

Revision: 2118