Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1054