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

Archive Download this file

Revision: 2766