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

Archive Download this file

Revision: 1972