Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2658