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

Archive Download this file

Revision: 2469