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

Archive Download this file

Revision: 2554