Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2537