Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/boot2/graphics.c

1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Copyright 1993 NeXT, Inc.
26 * All rights reserved.
27 */
28
29#include "boot.h"
30#include "vbe.h"
31#include "appleClut8.h"
32#include "gui.h"
33#include "IOHibernatePrivate.h"
34
35/*
36 * for spinning disk
37 */
38static int currentIndicator = 0;
39
40int previewTotalSectors = 0;
41int previewLoadedSectors = 0;
42uint8_t *previewSaveunder = 0;
43
44#define VIDEO(x) (bootArgs->Video.v_ ## x)
45
46#define MIN(x, y) ((x) < (y) ? (x) : (y))
47
48//==========================================================================
49// getVBEInfoString
50
51char *getVBEInfoString()
52{
53VBEInfoBlock vbeInfo;
54int err, small;
55char *buff = malloc(sizeof(char)*256);
56if(!buff) return 0;
57
58bzero( &vbeInfo, sizeof(vbeInfo) );
59strcpy( (char*)&vbeInfo, "VBE2" );
60err = getVBEInfo( &vbeInfo );
61if (err != errSuccess)
62return 0;
63
64if ( strncmp( (char *)vbeInfo.VESASignature, "VESA", 4 ) )
65return 0;
66
67small = (vbeInfo.TotalMemory < 16);
68
69sprintf(buff, "VESA v%d.%d %d%s (%s)\n",
70 vbeInfo.VESAVersion >> 8,
71 vbeInfo.VESAVersion & 0xf,
72 small ? (vbeInfo.TotalMemory * 64) : (vbeInfo.TotalMemory / 16),
73 small ? "KB" : "MB",
74 VBEDecodeFP(const char *, vbeInfo.OEMStringPtr) );
75
76return buff;
77}
78
79//==========================================================================
80//
81
82void
83printVBEModeInfo()
84{
85 VBEInfoBlock vbeInfo;
86 unsigned short * modePtr;
87 VBEModeInfoBlock modeInfo;
88 int err;
89 int line;
90
91 bzero( &vbeInfo, sizeof(vbeInfo) );
92 strcpy( (char*)&vbeInfo, "VBE2" );
93 err = getVBEInfo( &vbeInfo );
94 if ( err != errSuccess )
95 return;
96
97 line = 0;
98
99 // Activate and clear page 1
100 setActiveDisplayPage(1);
101 clearScreenRows(0, 24);
102 setCursorPosition( 0, 0, 1 );
103
104 printf( getVBEInfoString() );
105printf("Video modes supported:\n", VBEDecodeFP(const char *, vbeInfo.OEMStringPtr));
106
107 // Loop through the mode list, and find the matching mode.
108
109 for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
110 *modePtr != modeEndOfList; modePtr++ )
111 {
112 // Get mode information.
113
114 bzero( &modeInfo, sizeof(modeInfo) );
115 err = getVBEModeInfo( *modePtr, &modeInfo );
116 if ( err != errSuccess )
117 {
118 continue;
119 }
120
121 printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
122 *modePtr, modeInfo.XResolution, modeInfo.YResolution,
123 modeInfo.BitsPerPixel, modeInfo.MemoryModel,
124 modeInfo.ModeAttributes);
125
126 if (line++ >= 20) {
127 pause();
128 line = 0;
129 clearScreenRows(0, 24);
130 setCursorPosition( 0, 0, 1 );
131 }
132 }
133 if (line != 0) {
134 pause();
135 }
136 setActiveDisplayPage(0);
137}
138
139char *getVBEModeInfoString()
140{
141VBEInfoBlock vbeInfo;
142 unsigned short * modePtr;
143 VBEModeInfoBlock modeInfo;
144 int err;
145
146 bzero( &vbeInfo, sizeof(vbeInfo) );
147 strcpy( (char*)&vbeInfo, "VBE2" );
148 err = getVBEInfo( &vbeInfo );
149 if ( err != errSuccess )
150 return 0;
151
152char *buff=malloc(sizeof(char)*3072);
153if(!buff) return 0;
154
155// Loop through the mode list, and find the matching mode.
156 for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
157 *modePtr != modeEndOfList; modePtr++ )
158 {
159 // Get mode information.
160
161 bzero( &modeInfo, sizeof(modeInfo) );
162 err = getVBEModeInfo( *modePtr, &modeInfo );
163 if ( err != errSuccess )
164 {
165 continue;
166 }
167
168 sprintf(buff+strlen(buff), "Mode %x: %dx%dx%d mm:%d attr:%x\n",
169 *modePtr, modeInfo.XResolution, modeInfo.YResolution,
170 modeInfo.BitsPerPixel, modeInfo.MemoryModel,
171 modeInfo.ModeAttributes);
172
173 }
174return buff;
175}
176
177//==========================================================================
178// getVESAModeWithProperties
179//
180// Return the VESA mode that matches the properties specified.
181// If a mode is not found, then return the "best" available mode.
182
183static unsigned short
184getVESAModeWithProperties( unsigned short width,
185 unsigned short height,
186 unsigned char bitsPerPixel,
187 unsigned short attributesSet,
188 unsigned short attributesClear,
189 VBEModeInfoBlock * outModeInfo,
190 unsigned short * vesaVersion )
191{
192 VBEInfoBlock vbeInfo;
193 unsigned short * modePtr;
194 VBEModeInfoBlock modeInfo;
195 unsigned char modeBitsPerPixel;
196 unsigned short matchedMode = modeEndOfList;
197 int err;
198
199 // Clear output mode info.
200
201 bzero( outModeInfo, sizeof(*outModeInfo) );
202
203 // Get VBE controller info containing the list of supported modes.
204
205 bzero( &vbeInfo, sizeof(vbeInfo) );
206 strcpy( (char*)&vbeInfo, "VBE2" );
207 err = getVBEInfo( &vbeInfo );
208 if ( err != errSuccess )
209 {
210 return modeEndOfList;
211 }
212
213 // Report the VESA major/minor version number.
214
215 if (vesaVersion) *vesaVersion = vbeInfo.VESAVersion;
216
217 // Loop through the mode list, and find the matching mode.
218
219 for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
220 *modePtr != modeEndOfList; modePtr++ )
221 {
222 // Get mode information.
223
224 bzero( &modeInfo, sizeof(modeInfo) );
225 err = getVBEModeInfo( *modePtr, &modeInfo );
226 if ( err != errSuccess )
227 {
228 continue;
229 }
230
231#if DEBUG
232 printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
233 *modePtr, modeInfo.XResolution, modeInfo.YResolution,
234 modeInfo.BitsPerPixel, modeInfo.MemoryModel,
235 modeInfo.ModeAttributes);
236#endif
237
238 // Filter out unwanted modes based on mode attributes.
239
240 if ( ( ( modeInfo.ModeAttributes & attributesSet ) != attributesSet )
241 || ( ( modeInfo.ModeAttributes & attributesClear ) != 0 ) )
242 {
243 continue;
244 }
245
246 // Pixel depth in bits.
247
248 modeBitsPerPixel = modeInfo.BitsPerPixel;
249
250 if ( ( modeBitsPerPixel == 4 ) && ( modeInfo.MemoryModel == 0 ) )
251 {
252 // Text mode, 16 colors.
253 }
254 else if ( ( modeBitsPerPixel == 8 ) && ( modeInfo.MemoryModel == 4 ) )
255 {
256 // Packed pixel, 256 colors.
257 }
258 else if ( ( ( modeBitsPerPixel == 16 ) || ( modeBitsPerPixel == 15 ) )
259 && ( modeInfo.MemoryModel == 6 )
260 && ( modeInfo.RedMaskSize == 5 )
261 && ( modeInfo.GreenMaskSize == 5 )
262 && ( modeInfo.BlueMaskSize == 5 ) )
263 {
264 // Direct color, 16 bpp (1:5:5:5).
265 modeInfo.BitsPerPixel = modeBitsPerPixel = 16;
266 }
267 else if ( ( modeBitsPerPixel == 32 )
268 && ( modeInfo.MemoryModel == 6 )
269 && ( modeInfo.RedMaskSize == 8 )
270 && ( modeInfo.GreenMaskSize == 8 )
271 && ( modeInfo.BlueMaskSize == 8 ) )
272 {
273 // Direct color, 32 bpp (8:8:8:8).
274 }
275 else
276 {
277 continue; // Not a supported mode.
278 }
279
280 // Modes larger than the specified dimensions are skipped.
281
282 if ( ( modeInfo.XResolution > width ) ||
283 ( modeInfo.YResolution > height ) )
284 {
285 continue;
286 }
287
288 // Perfect match, we're done looking.
289
290 if ( ( modeInfo.XResolution == width ) &&
291 ( modeInfo.YResolution == height ) &&
292 ( modeBitsPerPixel == bitsPerPixel ) )
293 {
294 matchedMode = *modePtr;
295 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
296 break;
297 }
298
299 // Save the next "best" mode in case a perfect match is not found.
300
301 if ( modeInfo.XResolution == outModeInfo->XResolution &&
302 modeInfo.YResolution == outModeInfo->YResolution &&
303 modeBitsPerPixel <= outModeInfo->BitsPerPixel )
304 {
305 continue; // Saved mode has more depth.
306 }
307 if ( modeInfo.XResolution < outModeInfo->XResolution ||
308 modeInfo.YResolution < outModeInfo->YResolution ||
309 modeBitsPerPixel < outModeInfo->BitsPerPixel )
310 {
311 continue; // Saved mode has more resolution.
312 }
313
314 matchedMode = *modePtr;
315 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
316 }
317
318 return matchedMode;
319}
320
321//==========================================================================
322// setupPalette
323
324static void setupPalette( VBEPalette * p, const unsigned char * g )
325{
326 int i;
327 unsigned char * source = (unsigned char *) g;
328
329 for (i = 0; i < 256; i++)
330 {
331 (*p)[i] = 0;
332 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red
333 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green
334 (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue
335 }
336}
337
338//==========================================================================
339// Simple decompressor for boot images encoded in RLE format.
340
341char * decodeRLE( const void * rleData, int rleBlocks, int outBytes )
342{
343 char *out, *cp;
344
345 struct RLEBlock {
346 unsigned char count;
347 unsigned char value;
348 } * bp = (struct RLEBlock *) rleData;
349
350 out = cp = malloc( outBytes );
351 if ( out == NULL ) return NULL;
352
353 while ( rleBlocks-- )
354 {
355 memset( cp, bp->value, bp->count );
356 cp += bp->count;
357 bp++;
358 }
359
360 return out;
361}
362
363//==========================================================================
364// setVESAGraphicsMode
365
366static int
367setVESAGraphicsMode( unsigned short width,
368 unsigned short height,
369 unsigned char bitsPerPixel,
370 unsigned short refreshRate )
371{
372 VBEModeInfoBlock minfo;
373 unsigned short mode;
374 unsigned short vesaVersion;
375 int err = errFuncNotSupported;
376
377 do {
378 mode = getVESAModeWithProperties( width, height, bitsPerPixel,
379 maColorModeBit |
380 maModeIsSupportedBit |
381 maGraphicsModeBit |
382 maLinearFrameBufferAvailBit,
383 0,
384 &minfo, &vesaVersion );
385 if ( mode == modeEndOfList )
386 {
387 break;
388 }
389
390//
391// FIXME : generateCRTCTiming() causes crash.
392//
393
394// if ( (vesaVersion >> 8) >= 3 && refreshRate >= 60 &&
395// (gBootMode & kBootModeSafe) == 0 )
396// {
397// VBECRTCInfoBlock timing;
398//
399// // Generate CRTC timing for given refresh rate.
400//
401// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
402// refreshRate, kCRTCParamRefreshRate,
403// &timing );
404//
405// // Find the actual pixel clock supported by the hardware.
406//
407// getVBEPixelClock( mode, &timing.PixelClock );
408//
409// // Re-compute CRTC timing based on actual pixel clock.
410//
411// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
412// timing.PixelClock, kCRTCParamPixelClock,
413// &timing );
414//
415// // Set the video mode and use specified CRTC timing.
416//
417// err = setVBEMode( mode | kLinearFrameBufferBit |
418// kCustomRefreshRateBit, &timing );
419// }
420// else
421// {
422// // Set the mode with default refresh rate.
423//
424// err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
425// }
426
427 // Set the mode with default refresh rate.
428
429 err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
430
431 if ( err != errSuccess )
432 {
433 break;
434 }
435
436 // Set 8-bit color palette.
437
438 if ( minfo.BitsPerPixel == 8 )
439 {
440 VBEPalette palette;
441 setupPalette( &palette, appleClut8 );
442 if ((err = setVBEPalette(palette)) != errSuccess)
443 {
444 break;
445 }
446 }
447
448 // Is this required for buggy Video BIOS implementations?
449 // On which adapter?
450
451 if ( minfo.BytesPerScanline == 0 )
452 minfo.BytesPerScanline = ( minfo.XResolution *
453 minfo.BitsPerPixel ) >> 3;
454
455 // Update KernBootStruct using info provided by the selected
456 // VESA mode.
457
458 bootArgs->Video.v_display = GRAPHICS_MODE;
459 bootArgs->Video.v_width = minfo.XResolution;
460 bootArgs->Video.v_height = minfo.YResolution;
461 bootArgs->Video.v_depth = minfo.BitsPerPixel;
462 bootArgs->Video.v_rowBytes = minfo.BytesPerScanline;
463 bootArgs->Video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr);
464
465 }
466 while ( 0 );
467
468 return err;
469}
470
471int
472convertImage( unsigned short width,
473 unsigned short height,
474 const unsigned char *imageData,
475 unsigned char **newImageData )
476{
477 int cnt;
478 unsigned char *img = 0;
479 unsigned short *img16;
480 unsigned long *img32;
481
482 switch ( VIDEO(depth) ) {
483 case 16 :
484 img16 = malloc(width * height * 2);
485 if ( !img16 ) break;
486 for (cnt = 0; cnt < (width * height); cnt++)
487 img16[cnt] = lookUpCLUTIndex(imageData[cnt], 16);
488 img = (unsigned char *)img16;
489 break;
490
491 case 32 :
492 img32 = malloc(width * height * 4);
493 if ( !img32 ) break;
494 for (cnt = 0; cnt < (width * height); cnt++)
495 img32[cnt] = lookUpCLUTIndex(imageData[cnt], 32);
496 img = (unsigned char *)img32;
497 break;
498
499 default :
500 img = malloc(width * height);
501 bcopy(imageData, img, width * height);
502 break;
503 }
504 *newImageData = img;
505 return 0;
506}
507
508int loadPngImage(const char *filename, uint16_t *width, uint16_t *height,
509 uint8_t **imageData)
510{
511 uint8_t *pngData = NULL;
512 int pngFile = 0, pngSize;
513 PNG_info_t *info;
514 int error = 0;
515
516 pngFile = open_bvdev("bt(0,0)", filename, 0);
517 if (pngFile == -1) {
518 error = -1;
519 goto failed;
520 }
521 pngSize = file_size(pngFile);
522 if (!pngSize) {
523 error = -1;
524 goto failed;
525 }
526 pngData = malloc(pngSize);
527 if (read(pngFile, (char *) pngData, pngSize) != pngSize) {
528 error = -1;
529 goto failed;
530 }
531
532 PNG_error = -1;
533 info = PNG_decode(pngData, pngSize);
534 if (PNG_error != 0) {
535 error = PNG_error;
536 goto failed;
537 } else if ((info->width > 0xffff) || (info->height > 0xffff)) {
538 error = -1;
539 goto failed;
540 } else if ((info->width * info->height * 4) != info->image->size) {
541 error = -1;
542 goto failed;
543 }
544uint8_t *result = malloc(info->width*4*info->height);
545 *width = info->width;
546 *height = info->height;
547memcpy(result, info->image->data, info->width*4*info->height);
548*imageData = result;
549
550failed:
551png_alloc_free_all();
552 if (pngData)
553 free(pngData);
554 if (pngFile != -1)
555 close(pngFile);
556
557 return error;
558}
559
560int loadEmbeddedPngImage(uint8_t *pngData, int pngSize, uint16_t *width, uint16_t *height, uint8_t **imageData) {
561 PNG_info_t *info;
562 int error = 0;
563
564 PNG_error = -1;
565 info = PNG_decode(pngData, pngSize);
566if (PNG_error != 0) {
567 error = PNG_error;
568 goto failed;
569 } else if ((info->width > 0xffff) || (info->height > 0xffff)) {
570 error = -1;
571 goto failed;
572 } else if ((info->width * info->height * 4) != info->image->size) {
573 error = -1;
574 goto failed;
575 }
576uint8_t *result = malloc(info->width*4*info->height);
577*width = info->width;
578 *height = info->height;
579memcpy(result, info->image->data, info->width*4*info->height);
580*imageData = result;
581
582failed:
583png_alloc_free_all();
584
585 return error;
586}
587
588void blendImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height,
589 uint8_t *data)
590{
591 uint16_t drawWidth;
592 uint8_t *vram = (uint8_t *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + 4 * x;
593
594 drawWidth = MIN(width, VIDEO(width) - x);
595 height = MIN(height, VIDEO(height) - y);
596 while (height--) {
597switch (VIDEO (depth))
598{
599case 32: /* Optimized version*/
600{
601uint32_t s; uint32_t* d; // Source (img) and destination (bkgd) pixels
602uint32_t a; // Alpha
603uint32_t dstrb, dstg, srcrb, srcg, drb, dg, rb, g, tempB; // Intermediate variables
604uint16_t pos;
605
606for (pos = 0; pos < drawWidth * 4; pos += 4) {
607// Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html
608s = *((uint32_t*) (data + pos));
609d = (uint32_t*) (vram + pos);
610
611// Flip B and R in source
612// TODO: use XCHG and inline assembly to do this in a faster, saner way
613tempB = (s & 0xFF0000); // save B
614s = (s & 0xFF00FFFF) | ((s & 0xFF) << 16); // put R in B
615s = (s & 0xFFFFFF00) | (tempB >> 16); // put B in R
616
617a = (s >> 24) + 1;
618
619dstrb = *d & 0xFF00FF; dstg = *d & 0xFF00;
620srcrb = s & 0xFF00FF; srcg = s & 0xFF00;
621
622drb = srcrb - dstrb;
623dg = srcg - dstg;
624drb *= a; dg *= a;
625drb >>= 8; dg >>= 8;
626
627rb = (drb + dstrb) & 0xFF00FF;
628g = (dg + dstg) & 0xFF00;
629
630*d = rb | g;
631}
632}
633break;
634
635default: /*Universal version*/
636{
637uint32_t s;
638uint32_t a; // Alpha
639uint32_t dr, dg, db, sr, sg, sb; // Intermediate variables
640uint16_t pos;
641int bpp = (VIDEO (depth) + 7)/8;
642
643for (pos = 0; pos < drawWidth; pos ++) {
644// Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html
645s = *((uint32_t*) (data + 4*pos));
646
647sb = (s & 0xFF0000) >> 16;
648sg = (s & 0xFF00) >> 8;
649sr = (s & 0xFF);
650
651a = (s >> 24) + 1;
652
653switch (VIDEO (depth))
654{
655case 24:
656db = ((*(uint32_t *)(vram + bpp*pos))&0xff);
657dg = ((*(uint32_t *)(vram + bpp*pos))&0xff00)>>8;
658dr = ((*(uint32_t *)(vram + bpp*pos))&0xff0000)>>16;
659break;
660case 16://16-bit seems to be 15-bit
661/*db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3;
662dg = ((*(uint16_t *)(vram + bpp*pos))&0x07e0)>>3;
663dr = ((*(uint16_t *)(vram + bpp*pos))&0xf800)>>8;
664break;*/
665case 15:
666db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3;
667dg = ((*(uint16_t *)(vram + bpp*pos))&0x03e0)>>2;
668dr = ((*(uint16_t *)(vram + bpp*pos))&0x7c00)>>7;
669break;
670default:
671return;
672}
673
674dr = (((sr - dr) * a) >> 8) + dr;
675dg = (((sg - dg) * a) >> 8) + dg;
676db = (((sb - db) * a) >> 8) + db;
677switch (VIDEO (depth))
678{
679case 24:
680*(uint32_t *)(vram + bpp*pos) = (*(uint32_t *)(vram + bpp*pos) &0xff000000)
681| (db&0xff) | ((dg&0xff)<<8) | ((dr&0xff)<<16);
682break;
683case 16:
684//*(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xfc)<<3) | ((dr&0xf8)<<8);
685//break;
686case 15:
687*(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xf8)<<2) | ((dr&0xf8)<<7);
688break;
689}
690
691}
692}
693break;
694 }
695 vram += VIDEO(rowBytes);
696 data += width * 4;
697 }
698}
699
700void drawCheckerBoard()
701{
702 uint32_t *vram = (uint32_t *) VIDEO(baseAddr);
703 uint16_t x, y;
704 uint8_t color;
705
706 for (y = 0; y < VIDEO(height); y++, vram += VIDEO(width)) {
707 for (x = 0; x < VIDEO(width); x++) {
708 color = 204 + 51 * (((x / 8) % 2) == ((y / 8) % 2));
709 vram[x] = (color << 16) | (color << 8) | color;
710 }
711 }
712}
713
714//==========================================================================
715// LookUpCLUTIndex
716
717unsigned long lookUpCLUTIndex( unsigned char index,
718 unsigned char depth )
719{
720 long result, red, green, blue;
721
722 red = appleClut8[index * 3 + 0];
723 green = appleClut8[index * 3 + 1];
724 blue = appleClut8[index * 3 + 2];
725
726 switch (depth) {
727 case 16 :
728 result = ((red & 0xF8) << 7) |
729 ((green & 0xF8) << 2) |
730 ((blue & 0xF8) >> 3);
731 result |= (result << 16);
732 break;
733
734 case 32 :
735 result = (red << 16) | (green << 8) | blue;
736 break;
737
738 default :
739 result = index | (index << 8);
740 result |= (result << 16);
741 break;
742 }
743
744 return result;
745}
746
747//==========================================================================
748// drawColorRectangle
749
750void * stosl(void * dst, long val, long len)
751{
752 asm volatile ( "rep; stosl"
753 : "=c" (len), "=D" (dst)
754 : "0" (len), "1" (dst), "a" (val)
755 : "memory" );
756
757 return dst;
758}
759
760void drawColorRectangle( unsigned short x,
761 unsigned short y,
762 unsigned short width,
763 unsigned short height,
764 unsigned char colorIndex )
765{
766 long pixelBytes;
767 long color = lookUpCLUTIndex( colorIndex, VIDEO(depth) );
768 char * vram;
769
770 pixelBytes = VIDEO(depth) / 8;
771 vram = (char *) VIDEO(baseAddr) +
772 VIDEO(rowBytes) * y + pixelBytes * x;
773
774 width = MIN(width, VIDEO(width) - x);
775 height = MIN(height, VIDEO(height) - y);
776
777 while ( height-- )
778 {
779 int rem = ( pixelBytes * width ) % 4;
780 if ( rem ) bcopy( &color, vram, rem );
781 stosl( vram + rem, color, pixelBytes * width / 4 );
782 vram += VIDEO(rowBytes);
783 }
784}
785
786//==========================================================================
787// drawDataRectangle
788
789void drawDataRectangle( unsigned short x,
790 unsigned short y,
791 unsigned short width,
792 unsigned short height,
793 unsigned char * data )
794{
795 unsigned short drawWidth;
796 long pixelBytes = VIDEO(depth) / 8;
797 unsigned char * vram = (unsigned char *) VIDEO(baseAddr) +
798 VIDEO(rowBytes) * y + pixelBytes * x;
799
800 drawWidth = MIN(width, VIDEO(width) - x);
801 height = MIN(height, VIDEO(height) - y);
802 while ( height-- ) {
803 bcopy( data, vram, drawWidth * pixelBytes );
804 vram += VIDEO(rowBytes);
805 data += width * pixelBytes;
806 }
807}
808
809void
810loadImageScale (void *input, int iw, int ih, int ip, void *output, int ow, int oh, int op, int or)
811{
812int x,y, off;
813int red=0x7f, green=0x7f, blue=0x7f;
814for (x=0;x<ow;x++)
815for (y=0;y<oh;y++)
816{
817off=(x*iw)/ow+((y*ih)/oh)*iw;
818switch (ip)
819{
820case 16:
821{
822uint16_t val;
823val=((uint16_t *)input)[off];
824red=(val>>7)&0xf8;
825green=(val>>2)&0xf8;
826blue=(val<<3)&0xf8;
827break;
828}
829case 32:
830{
831uint32_t val;
832val=((uint32_t *)input)[off];
833red=(val>>16)&0xff;
834green=(val>>8)&0xff;
835blue=(val)&0xff;
836break;
837}
838}
839char *ptr=(char *)output+x*(op/8)+y*or;
840switch (op)
841{
842case 16:
843*((uint16_t *)ptr) = ((red & 0xF8) << 7) |
844((green & 0xF8) << 2) |
845((blue & 0xF8) >> 3);
846break;
847case 32 :
848*((uint32_t *)ptr) = (red << 16) | (green << 8) | blue;
849break;
850}
851}
852}
853
854DECLARE_IOHIBERNATEPROGRESSALPHA
855
856void drawPreview(void *src, uint8_t * saveunder)
857{
858uint8_t * screen;
859uint32_t rowBytes, pixelShift;
860uint32_t x, y;
861int32_t blob;
862uint32_t alpha, in, color, result;
863uint8_t * out;
864void *uncomp;
865int origwidth, origheight, origbpx;
866uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
867
868if (src && (uncomp=DecompressData(src, &origwidth, &origheight, &origbpx)))
869{
870if (!setVESAGraphicsMode(origwidth, origheight, origbpx, 0))
871if (initGraphicsMode () != errSuccess)
872return;
873screen = (uint8_t *) VIDEO (baseAddr);
874rowBytes = VIDEO (rowBytes);
875loadImageScale (uncomp, origwidth, origheight, origbpx, screen, VIDEO(width), VIDEO(height), VIDEO(depth), VIDEO (rowBytes));
876}
877else
878{
879if (initGraphicsMode () != errSuccess)
880return;
881screen = (uint8_t *) VIDEO (baseAddr);
882rowBytes = VIDEO (rowBytes);
883// Set the screen to 75% grey.
884 drawColorRectangle(0, 0, VIDEO(width), VIDEO(height), 0x01 /* color index */);
885}
886
887
888pixelShift = VIDEO (depth) >> 4;
889if (pixelShift < 1) return;
890
891screen += ((VIDEO (width)
892- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
893+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
894
895for (y = 0; y < kIOHibernateProgressHeight; y++)
896{
897out = screen + y * rowBytes;
898for (blob = 0; blob < kIOHibernateProgressCount; blob++)
899{
900color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
901for (x = 0; x < kIOHibernateProgressWidth; x++)
902{
903alpha = gIOHibernateProgressAlpha[y][x];
904result = color;
905if (alpha)
906{
907if (0xff != alpha)
908{
909if (1 == pixelShift)
910{
911in = *((uint16_t *)out) & 0x1f;// 16
912in = (in << 3) | (in >> 2);
913}
914else
915in = *((uint32_t *)out) & 0xff;// 32
916saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
917result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
918}
919if (1 == pixelShift)
920{
921result >>= 3;
922*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
923}
924else
925*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
926}
927out += (1 << pixelShift);
928}
929out += (kIOHibernateProgressSpacing << pixelShift);
930}
931}
932}
933
934void updateProgressBar(uint8_t * saveunder, int32_t firstBlob, int32_t select)
935{
936uint8_t * screen;
937uint32_t rowBytes, pixelShift;
938uint32_t x, y;
939int32_t blob, lastBlob;
940uint32_t alpha, in, color, result;
941uint8_t * out;
942uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
943
944pixelShift = VIDEO(depth) >> 4;
945if (pixelShift < 1) return;
946screen = (uint8_t *) VIDEO (baseAddr);
947rowBytes = VIDEO (rowBytes);
948
949screen += ((VIDEO (width)
950- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
951+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
952
953lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
954
955screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
956
957for (y = 0; y < kIOHibernateProgressHeight; y++)
958{
959out = screen + y * rowBytes;
960for (blob = firstBlob; blob <= lastBlob; blob++)
961{
962color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
963for (x = 0; x < kIOHibernateProgressWidth; x++)
964{
965alpha = gIOHibernateProgressAlpha[y][x];
966result = color;
967if (alpha)
968{
969if (0xff != alpha)
970{
971in = saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++];
972result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
973}
974if (1 == pixelShift)
975{
976result >>= 3;
977*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
978}
979else
980*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
981}
982out += (1 << pixelShift);
983}
984out += (kIOHibernateProgressSpacing << pixelShift);
985}
986}
987}
988
989
990//==========================================================================
991// setVESATextMode
992
993static int
994setVESATextMode( unsigned short cols,
995 unsigned short rows,
996 unsigned char bitsPerPixel )
997{
998 VBEModeInfoBlock minfo;
999 unsigned short mode = modeEndOfList;
1000
1001 if ( (cols != 80) || (rows != 25) ) // not 80x25 mode
1002 {
1003 mode = getVESAModeWithProperties( cols, rows, bitsPerPixel,
1004 maColorModeBit |
1005 maModeIsSupportedBit,
1006 maGraphicsModeBit,
1007 &minfo, NULL );
1008 }
1009
1010 if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) )
1011 {
1012 video_mode( 2 ); // VGA BIOS, 80x25 text mode.
1013 minfo.XResolution = 80;
1014 minfo.YResolution = 25;
1015 }
1016
1017 // Update KernBootStruct using info provided by the selected
1018 // VESA mode.
1019
1020 bootArgs->Video.v_display = VGA_TEXT_MODE;
1021 bootArgs->Video.v_baseAddr = 0xb8000;
1022 bootArgs->Video.v_width = minfo.XResolution;
1023 bootArgs->Video.v_height = minfo.YResolution;
1024 bootArgs->Video.v_depth = 8;
1025 bootArgs->Video.v_rowBytes = 0x8000;
1026
1027 return errSuccess; // always return success
1028}
1029
1030//==========================================================================
1031// getNumberArrayFromProperty
1032
1033static int
1034getNumberArrayFromProperty( const char * propKey,
1035 unsigned long numbers[],
1036 unsigned long maxArrayCount )
1037{
1038 char * propStr;
1039 unsigned long count = 0;
1040
1041 propStr = newStringForKey( (char *) propKey , &bootInfo->bootConfig );
1042 if ( propStr )
1043 {
1044 char * delimiter = propStr;
1045 char * p = propStr;
1046
1047 while ( count < maxArrayCount && *p != '\0' )
1048 {
1049 unsigned long val = strtoul( p, &delimiter, 10 );
1050 if ( p != delimiter )
1051 {
1052 numbers[count++] = val;
1053 p = delimiter;
1054 }
1055 while ( ( *p != '\0' ) && !isdigit(*p) )
1056 p++;
1057 }
1058
1059 free( propStr );
1060 }
1061
1062 return count;
1063}
1064
1065int initGraphicsMode ()
1066{
1067 unsigned long params[4];
1068 int count;
1069
1070 params[3] = 0;
1071 count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 );
1072
1073 // Try to find a resolution if "Graphics Mode" setting is not available.
1074 if ( count < 3 )
1075 {
1076 // Use the default resolution if we don't have an initialized GUI.
1077 if (gui.screen.width == 0 || gui.screen.height == 0)
1078 {
1079 gui.screen.width = DEFAULT_SCREEN_WIDTH;
1080 gui.screen.height = DEFAULT_SCREEN_HEIGHT;
1081 }
1082
1083 params[0] = gui.screen.width;
1084 params[1] = gui.screen.height;
1085 params[2] = 32;
1086 }
1087
1088 // Map from pixel format to bits per pixel.
1089
1090 if ( params[2] == 256 ) params[2] = 8;
1091 if ( params[2] == 555 ) params[2] = 16;
1092 if ( params[2] == 888 ) params[2] = 32;
1093
1094return setVESAGraphicsMode( params[0], params[1], params[2], params[3] );
1095}
1096
1097//==========================================================================
1098// setVideoMode
1099//
1100// Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE.
1101
1102void
1103setVideoMode( int mode, int drawgraphics)
1104{
1105 unsigned long params[4];
1106 int count;
1107 int err = errSuccess;
1108
1109 if ( mode == GRAPHICS_MODE )
1110 {
1111 if ( (err=initGraphicsMode ()) == errSuccess ) {
1112 if (gVerboseMode) {
1113 // Tell the kernel to use text mode on a linear frame buffer display
1114 bootArgs->Video.v_display = FB_TEXT_MODE;
1115 } else {
1116 bootArgs->Video.v_display = GRAPHICS_MODE;
1117 }
1118 }
1119 }
1120
1121 if ( (mode == VGA_TEXT_MODE) || (err != errSuccess) )
1122 {
1123 count = getNumberArrayFromProperty( kTextModeKey, params, 2 );
1124 if ( count < 2 )
1125 {
1126 params[0] = 80; // Default text mode is 80x25.
1127 params[1] = 25;
1128 }
1129
1130 setVESATextMode( params[0], params[1], 4 );
1131 bootArgs->Video.v_display = VGA_TEXT_MODE;
1132 }
1133
1134 currentIndicator = 0;
1135}
1136
1137void getGraphicModeParams(unsigned long params[]) {
1138
1139params[3] = 0;
1140
1141VBEModeInfoBlock minfo;
1142
1143 unsigned short vesaVersion;
1144 unsigned short mode = modeEndOfList;
1145
1146getNumberArrayFromProperty( kGraphicsModeKey, params, 4);
1147
1148mode = getVESAModeWithProperties( params[0], params[1], params[2],
1149 maColorModeBit |
1150 maModeIsSupportedBit |
1151 maGraphicsModeBit |
1152 maLinearFrameBufferAvailBit,
1153 0,
1154 &minfo, &vesaVersion );
1155
1156params[0] = minfo.XResolution;
1157params[1] = minfo.YResolution;
1158params[2] = 32;
1159}
1160
1161//==========================================================================
1162// Return the current video mode, VGA_TEXT_MODE or GRAPHICS_MODE.
1163
1164int getVideoMode(void)
1165{
1166 return bootArgs->Video.v_display;
1167}
1168
1169//==========================================================================
1170// Display and clear the activity indicator.
1171
1172static char indicator[] = {'-', '\\', '|', '/', '-', '\\', '|', '/', '\0'};
1173
1174// To prevent a ridiculously fast-spinning indicator,
1175// ensure a minimum of 1/9 sec between animation frames.
1176#define MIN_TICKS 2
1177
1178void
1179spinActivityIndicator(int sectors)
1180{
1181 static unsigned long lastTickTime = 0, currentTickTime;
1182
1183if (previewTotalSectors && previewSaveunder)
1184{
1185int blob, lastBlob;
1186
1187lastBlob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
1188previewLoadedSectors+=sectors;
1189blob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
1190
1191if (blob!=lastBlob)
1192updateProgressBar (previewSaveunder, lastBlob, blob);
1193return;
1194}
1195
1196if (gVerboseMode) {
1197 currentTickTime = time18(); // late binding
1198 if (currentTickTime < lastTickTime + MIN_TICKS) {
1199 return;
1200 } else {
1201 lastTickTime = currentTickTime;
1202 }
1203
1204 if (getVideoMode() == VGA_TEXT_MODE) {
1205 if (currentIndicator >= sizeof(indicator)) {
1206 currentIndicator = 0;
1207 }
1208 printf("%c\b", indicator[currentIndicator++]);
1209 }
1210 }
1211}
1212
1213void
1214clearActivityIndicator( void )
1215{
1216 if ( getVideoMode() == VGA_TEXT_MODE )
1217 {
1218 printf(" \b");
1219 }
1220}
1221
1222

Archive Download this file

Revision: 151