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;
784
785 long colorIndex = (index * 3);
786 long red = appleClut8[ colorIndex ];
787 long green = appleClut8[ colorIndex++ ];
788 long blue = appleClut8[ colorIndex++ ];
789
790 switch (depth) {
791 case 16 :
792 result = ((red & 0xF8) << 7) |
793 ((green & 0xF8) << 2) |
794 ((blue & 0xF8) >> 3);
795 result |= (result << 16);
796 break;
797
798 case 32 :
799 result = (red << 16) | (green << 8) | blue;
800 break;
801
802 default :
803 result = index | (index << 8);
804 result |= (result << 16);
805 break;
806 }
807
808 return result;
809}
810
811//==========================================================================
812// drawColorRectangle
813
814void *stosl(void *dst, long val, long len)
815{
816asm volatile ( "rep; stosl"
817 : "=c" (len), "=D" (dst)
818 : "0" (len), "1" (dst), "a" (val)
819 : "memory" );
820
821return dst;
822}
823
824//==============================================================================
825
826void drawColorRectangle( unsigned short x,
827 unsigned short y,
828 unsigned short width,
829 unsigned short height,
830 unsigned char colorIndex )
831{
832longpixelBytes;
833longcolor = lookUpCLUTIndex( colorIndex, VIDEO(depth) );
834char*vram;
835
836pixelBytes = VIDEO(depth) / 8;
837vram = (char *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + pixelBytes * x;
838
839width = MIN(width, VIDEO(width) - x);
840height = MIN(height, VIDEO(height) - y);
841
842while ( height-- )
843{
844int rem = ( pixelBytes * width ) % 4;
845if ( rem )
846{
847bcopy( &color, vram, rem );
848}
849
850stosl( vram + rem, color, pixelBytes * width / 4 );
851vram += VIDEO(rowBytes);
852}
853}
854
855//==========================================================================
856// drawDataRectangle
857
858void drawDataRectangle( unsigned short x,
859 unsigned short y,
860 unsigned short width,
861 unsigned short height,
862 unsigned char * data )
863{
864unsigned short drawWidth;
865long pixelBytes = VIDEO(depth) / 8;
866unsigned char * vram = (unsigned char *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + pixelBytes * x;
867
868drawWidth = MIN(width, VIDEO(width) - x);
869height = MIN(height, VIDEO(height) - y);
870while ( height-- )
871{
872bcopy( data, vram, drawWidth * pixelBytes );
873vram += VIDEO(rowBytes);
874data += width * pixelBytes;
875}
876}
877
878//==============================================================================
879
880void loadImageScale (void *input, int iw, int ih, int ip, void *output, int ow, int oh, int op, int or)
881{
882int x, y, off;
883int red = 0x7f, green = 0x7f, blue = 0x7f;
884for ( x = 0; x < ow; x++)
885for ( y = 0; y < oh; y++ )
886{
887off = ( x * iw ) / ow +( ( y * ih ) / oh ) * iw;
888switch (ip)
889{
890case 16:
891{
892uint16_t val;
893val=((uint16_t *)input)[off];
894red=(val>>7)&0xf8;
895green=(val>>2)&0xf8;
896blue=(val<<3)&0xf8;
897break;
898}
899case 32:
900{
901uint32_t val;
902val=((uint32_t *)input)[off];
903red=(val>>16)&0xff;
904green=(val>>8)&0xff;
905blue=(val)&0xff;
906break;
907}
908}
909char *ptr=(char *)output+x*(op/8)+y*or;
910switch (op)
911{
912case 16:
913*((uint16_t *)ptr) = ((red & 0xF8) << 7) |
914((green & 0xF8) << 2) |
915((blue & 0xF8) >> 3);
916break;
917case 32 :
918*((uint32_t *)ptr) = (red << 16) | (green << 8) | blue;
919break;
920}
921}
922}
923
924//==============================================================================
925
926DECLARE_IOHIBERNATEPROGRESSALPHA
927
928void drawPreview(void *src, uint8_t * saveunder)
929{
930uint8_t * screen;
931uint32_t rowBytes, pixelShift;
932uint32_t x, y;
933int32_t blob;
934uint32_t alpha, in, color, result;
935uint8_t * out;
936void *uncomp;
937int origwidth, origheight, origbpx;
938uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
939
940if (src && (uncomp=DecompressData(src, &origwidth, &origheight, &origbpx)))
941{
942if (!setVESAGraphicsMode(origwidth, origheight, origbpx, 0))
943if (initGraphicsMode () != errSuccess)
944{
945return;
946}
947
948screen = (uint8_t *) VIDEO (baseAddr);
949rowBytes = VIDEO (rowBytes);
950loadImageScale (uncomp, origwidth, origheight, origbpx, screen, VIDEO(width), VIDEO(height), VIDEO(depth), VIDEO (rowBytes));
951}
952else
953{
954if (initGraphicsMode () != errSuccess)
955{
956return;
957}
958
959screen = (uint8_t *) VIDEO (baseAddr);
960rowBytes = VIDEO (rowBytes);
961// Set the screen to 75% grey.
962drawColorRectangle(0, 0, VIDEO(width), VIDEO(height), 0x01 /* color index */);
963}
964
965pixelShift = VIDEO (depth) >> 4;
966if (pixelShift < 1)
967{
968return;
969}
970
971screen += ((VIDEO (width)
972- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
973+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
974
975for (y = 0; y < kIOHibernateProgressHeight; y++)
976{
977out = screen + y * rowBytes;
978for (blob = 0; blob < kIOHibernateProgressCount; blob++)
979{
980color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
981for (x = 0; x < kIOHibernateProgressWidth; x++)
982{
983alpha = gIOHibernateProgressAlpha[y][x];
984result = color;
985if (alpha)
986{
987if (0xff != alpha)
988{
989if (1 == pixelShift)
990{
991in = *((uint16_t *)out) & 0x1f;// 16
992in = (in << 3) | (in >> 2);
993}
994else
995{
996in = *((uint32_t *)out) & 0xff;// 32
997}
998
999saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
1000result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
1001}
1002if (1 == pixelShift)
1003{
1004result >>= 3;
1005*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
1006}
1007else
1008{
1009*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
1010}
1011
1012}
1013out += (1 << pixelShift);
1014}
1015out += (kIOHibernateProgressSpacing << pixelShift);
1016}
1017}
1018}
1019
1020//==============================================================================
1021
1022void updateProgressBar(uint8_t * saveunder, int32_t firstBlob, int32_t select)
1023{
1024uint8_t * screen;
1025uint32_t rowBytes, pixelShift;
1026uint32_t x, y;
1027int32_t blob, lastBlob;
1028uint32_t alpha, in, color, result;
1029uint8_t * out;
1030uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
1031
1032pixelShift = VIDEO(depth) >> 4;
1033if (pixelShift < 1) return;
1034screen = (uint8_t *) VIDEO (baseAddr);
1035rowBytes = VIDEO (rowBytes);
1036
1037screen += ((VIDEO (width)
1038- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1039+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1040
1041lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
1042
1043screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
1044
1045for (y = 0; y < kIOHibernateProgressHeight; y++)
1046{
1047out = screen + y * rowBytes;
1048for (blob = firstBlob; blob <= lastBlob; blob++)
1049{
1050color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
1051for (x = 0; x < kIOHibernateProgressWidth; x++)
1052{
1053alpha = gIOHibernateProgressAlpha[y][x];
1054result = color;
1055if (alpha)
1056{
1057if (0xff != alpha)
1058{
1059in = saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++];
1060result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
1061}
1062
1063if (1 == pixelShift)
1064{
1065result >>= 3;
1066*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
1067}
1068else
1069{
1070*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
1071}
1072}
1073out += (1 << pixelShift);
1074}
1075out += (kIOHibernateProgressSpacing << pixelShift);
1076}
1077}
1078}
1079
1080//==========================================================================
1081// setVESATextMode
1082
1083static int setVESATextMode( unsigned short cols, unsigned short rows, unsigned char bitsPerPixel )
1084{
1085VBEModeInfoBlock minfo;
1086unsigned short mode = modeEndOfList;
1087
1088if ( (cols != 80) || (rows != 25) ) // not 80x25 mode
1089{
1090mode = getVESAModeWithProperties( cols, rows, bitsPerPixel,
1091 maColorModeBit |
1092 maModeIsSupportedBit,
1093 maGraphicsModeBit,
1094 &minfo, NULL );
1095}
1096
1097if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) )
1098{
1099video_mode( 2 ); // VGA BIOS, 80x25 text mode.
1100minfo.XResolution = 80;
1101minfo.YResolution = 25;
1102}
1103
1104// Update KernBootStruct using info provided by the selected
1105// VESA mode.
1106
1107bootArgs->Video.v_display = VGA_TEXT_MODE;
1108bootArgs->Video.v_baseAddr = 0xb8000;
1109bootArgs->Video.v_width = minfo.XResolution;
1110bootArgs->Video.v_height = minfo.YResolution;
1111bootArgs->Video.v_depth = 8;
1112bootArgs->Video.v_rowBytes = 0x8000;
1113
1114return errSuccess; // always return success
1115}
1116
1117//==========================================================================
1118// getNumberArrayFromProperty
1119
1120static int getNumberArrayFromProperty( const char * propKey,
1121 unsigned long numbers[],
1122 unsigned long maxArrayCount )
1123{
1124char*propStr;
1125unsigned longcount = 0;
1126
1127propStr = newStringForKey((char *)propKey , &bootInfo->chameleonConfig);
1128
1129if (propStr)
1130{
1131char *delimiter = propStr;
1132char *p = propStr;
1133
1134while ((count < maxArrayCount) && (*p != '\0'))
1135{
1136unsigned long val = strtoul(p, &delimiter, 10);
1137if (p != delimiter)
1138{
1139numbers[count++] = val;
1140p = delimiter;
1141}
1142while ((*p != '\0') && !isdigit(*p))
1143p++;
1144}
1145
1146free(propStr);
1147}
1148
1149return count;
1150}
1151
1152//==============================================================================
1153
1154int initGraphicsMode ()
1155{
1156unsigned long params[4];
1157int count;
1158
1159params[3] = 0;
1160count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 );
1161
1162// Try to find a resolution if "Graphics Mode" setting is not available.
1163if ( count < 3 )
1164{
1165// Use the default resolution if we don't have an initialized GUI.
1166if (gui.screen.width == 0 || gui.screen.height == 0)
1167{
1168gui.screen.width = DEFAULT_SCREEN_WIDTH;
1169gui.screen.height = DEFAULT_SCREEN_HEIGHT;
1170}
1171
1172params[0] = gui.screen.width;
1173params[1] = gui.screen.height;
1174params[2] = 32;
1175}
1176
1177// Map from pixel format to bits per pixel.
1178
1179if ( params[2] == 256 )
1180params[2] = 8;
1181
1182if ( params[2] == 555 )
1183params[2] = 16;
1184
1185if ( params[2] == 888 )
1186params[2] = 32;
1187
1188return setVESAGraphicsMode( params[0], params[1], params[2], params[3] );
1189}
1190
1191//==========================================================================
1192// setVideoMode
1193//
1194// Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE.
1195
1196void setVideoMode( int mode, int drawgraphics)
1197{
1198unsigned long params[4];
1199int count;
1200int err = errSuccess;
1201
1202if ( mode == GRAPHICS_MODE )
1203{
1204 if ( (err = initGraphicsMode()) == errSuccess )
1205{
1206if (gVerboseMode)
1207{
1208// Tell the kernel to use text mode on a linear frame buffer display
1209bootArgs->Video.v_display = FB_TEXT_MODE;
1210}
1211else
1212{
1213bootArgs->Video.v_display = GRAPHICS_MODE;
1214}
1215}
1216}
1217
1218if ( (mode == VGA_TEXT_MODE) || (err != errSuccess) )
1219{
1220count = getNumberArrayFromProperty(kTextModeKey, params, 2);
1221if ( count < 2 )
1222{
1223params[0] = 80; // Default text mode is 80x25.
1224params[1] = 25;
1225}
1226
1227setVESATextMode(params[0], params[1], 4);
1228bootArgs->Video.v_display = VGA_TEXT_MODE;
1229}
1230
1231currentIndicator = 0;
1232}
1233
1234//==============================================================================
1235void getGraphicModeParams(unsigned long params[])
1236{
1237params[3] = 0;
1238
1239VBEModeInfoBlock minfo;
1240
1241unsigned short vesaVersion;
1242unsigned short mode = modeEndOfList;
1243
1244getNumberArrayFromProperty(kGraphicsModeKey, params, 4);
1245
1246mode = getVESAModeWithProperties(params[0], params[1], params[2],
1247 maColorModeBit |
1248 maModeIsSupportedBit |
1249 maGraphicsModeBit |
1250 maLinearFrameBufferAvailBit,
1251 0,
1252 &minfo, &vesaVersion);
1253
1254params[0] = minfo.XResolution;
1255params[1] = minfo.YResolution;
1256params[2] = 32;
1257}
1258
1259//==========================================================================
1260// Return the current video mode, VGA_TEXT_MODE or GRAPHICS_MODE.
1261
1262int getVideoMode(void)
1263{
1264 return bootArgs->Video.v_display;
1265}
1266
1267//==========================================================================
1268// Display and clear the activity indicator.
1269
1270// BASIC Indicator
1271static char indicator[] = {'-', '\\', '|', '/', '\0'};
1272
1273// To prevent a ridiculously fast-spinning indicator,
1274// ensure a minimum of 1/9 sec between animation frames.
1275#define MIN_TICKS 2
1276
1277//==============================================================================
1278
1279void spinActivityIndicator(int sectors)
1280{
1281 static unsigned long lastTickTime = 0, currentTickTime;
1282
1283if (previewTotalSectors && previewSaveunder)
1284{
1285int blob, lastBlob;
1286
1287lastBlob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
1288previewLoadedSectors+=sectors;
1289blob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
1290
1291if (blob!=lastBlob)
1292{
1293updateProgressBar (previewSaveunder, lastBlob, blob);
1294}
1295return;
1296}
1297
1298currentTickTime = time18(); // late binding
1299if (currentTickTime < lastTickTime + MIN_TICKS)
1300{
1301return;
1302}
1303else
1304{
1305lastTickTime = currentTickTime;
1306}
1307
1308if (getVideoMode() == VGA_TEXT_MODE)
1309{
1310if (currentIndicator >= sizeof(indicator))
1311{
1312currentIndicator = 0;
1313}
1314putchar(indicator[currentIndicator++]);
1315putchar('\b');
1316}
1317}
1318
1319//==============================================================================
1320
1321void clearActivityIndicator( void )
1322{
1323if ( getVideoMode() == VGA_TEXT_MODE )
1324{
1325putchar(' ');
1326putchar('\b');
1327}
1328}
1329
1330//==============================================================================
1331

Archive Download this file

Revision: 2734