Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/boot2/graphics.c

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

Archive Download this file

Revision: 2150