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",
103 vbeInfo.VESAVersion >> 8,
104 vbeInfo.VESAVersion & 0xf,
105 small ? (vbeInfo.TotalMemory * 64) : (vbeInfo.TotalMemory / 16),
106 small ? "KB" : "MB",
107 VBEDecodeFP(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) {
141error("[printVBEModeInfo] Error: getVBEInfoString failed\n");
142return;
143}
144verbose("vbeInfoString: %s", vbeInfoString);
145free(vbeInfoString);
146vbeInfoString = NULL;
147
148verbose("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
164verbose("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}
179
180setActiveDisplayPage(0);
181}
182
183//==============================================================================
184
185char *getVBEModeInfoString()
186{
187VBEInfoBlock vbeInfo;
188unsigned short * modePtr;
189VBEModeInfoBlock modeInfo;
190int err;
191
192 bzero( &vbeInfo, sizeof(vbeInfo) );
193strcpy( (char*)&vbeInfo, "VBE2" );
194err = getVBEInfo( &vbeInfo );
195if ( err != errSuccess ) {
196return 0;
197}
198
199char *buff=malloc(sizeof(char)*3072);
200if(!buff) {
201return 0;
202}
203
204int bufflen = 0;
205
206// Loop through the mode list, and find the matching mode.
207for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
208(*modePtr != modeEndOfList) && (bufflen < 3072); /* prevent buffer overrun */
209modePtr++ )
210{
211// Get mode information.
212
213bzero( &modeInfo, sizeof(modeInfo) );
214err = getVBEModeInfo( *modePtr, &modeInfo );
215if ( err != errSuccess ) {
216continue;
217}
218
219bufflen +=
220snprintf(buff+bufflen, 3072-bufflen, "Mode %x: %dx%dx%d mm:%d attr:%x\n",
221*modePtr, modeInfo.XResolution, modeInfo.YResolution,
222modeInfo.BitsPerPixel, modeInfo.MemoryModel,
223modeInfo.ModeAttributes);
224}
225return buff;
226}
227
228//==========================================================================
229// getVESAModeWithProperties
230//
231// Return the VESA mode that matches the properties specified.
232// If a mode is not found, then return the "best" available mode.
233
234static unsigned short
235getVESAModeWithProperties( unsigned shortwidth,
236 unsigned shortheight,
237 unsigned charbitsPerPixel,
238 unsigned shortattributesSet,
239 unsigned shortattributesClear,
240 VBEModeInfoBlock*outModeInfo,
241 unsigned short*vesaVersion
242)
243{
244 VBEInfoBlock vbeInfo;
245 unsigned short * modePtr;
246 VBEModeInfoBlock modeInfo;
247 unsigned char modeBitsPerPixel;
248 unsigned short matchedMode = modeEndOfList;
249 int err;
250
251 // Clear output mode info.
252
253 bzero( outModeInfo, sizeof(*outModeInfo) );
254
255 // Get VBE controller info containing the list of supported modes.
256
257 bzero( &vbeInfo, sizeof(vbeInfo) );
258 strcpy( (char*)&vbeInfo, "VBE2" );
259 err = getVBEInfo( &vbeInfo );
260 if ( err != errSuccess )
261 {
262 return modeEndOfList;
263 }
264
265 // Report the VESA major/minor version number.
266
267 if (vesaVersion) *vesaVersion = vbeInfo.VESAVersion;
268
269 // Loop through the mode list, and find the matching mode.
270
271//#if DEBUG
272 verbose("\nGraphics Modes [VESA %d.%d %dMB mode=0x%04X]:\n", vbeInfo.VESAVersion >> 8, vbeInfo.VESAVersion & 0xf, (vbeInfo.TotalMemory * 64)/1024, getCurrentGraphicsMode());
273//#endif
274
275 for ( modePtr = VBEDecodeFP(unsigned short *, vbeInfo.VideoModePtr); *modePtr != modeEndOfList; modePtr++ )
276 {
277 // Get mode information.
278
279 bzero( &modeInfo, sizeof(modeInfo) );
280
281 err = getVBEModeInfo( *modePtr, &modeInfo );
282 if ( err != errSuccess )
283 {
284 verbose("\t%x: mode not suported. [ERROR: %d]\n", *modePtr, err);
285 continue;
286 }
287
288//#if DEBUG
289 verbose("\t0x%04X: res=%dx%dx%d, mm=%d, attr=0x%04X %s\n",
290 *modePtr, modeInfo.XResolution, modeInfo.YResolution,
291 modeInfo.BitsPerPixel, modeInfo.MemoryModel,
292 modeInfo.ModeAttributes, (*modePtr == GraphicsModeCurrent)? "<-":"");
293//#endif
294
295 // Filter out unwanted modes based on mode attributes.
296
297 if ( ( ( modeInfo.ModeAttributes & attributesSet ) != attributesSet )
298 || ( ( modeInfo.ModeAttributes & attributesClear ) != 0 ) )
299 {
300 continue;
301 }
302
303 // Pixel depth in bits.
304
305 modeBitsPerPixel = modeInfo.BitsPerPixel;
306
307 if ( ( modeBitsPerPixel == 4 ) && ( modeInfo.MemoryModel == 0 ) )
308 {
309 // Text mode, 16 colors.
310 }
311 else if ( ( modeBitsPerPixel == 8 ) && ( modeInfo.MemoryModel == 4 ) )
312 {
313 // Packed pixel, 256 colors.
314 }
315 else if ( ( ( modeBitsPerPixel == 16 ) || ( modeBitsPerPixel == 15 ) )
316 && ( modeInfo.MemoryModel == 6 )
317 && ( modeInfo.RedMaskSize == 5 )
318 && ( modeInfo.GreenMaskSize == 5 )
319 && ( modeInfo.BlueMaskSize == 5 ) )
320 {
321 // Direct color, 16 bpp (1:5:5:5).
322 modeInfo.BitsPerPixel = modeBitsPerPixel = 16;
323 }
324 else if ( ( modeBitsPerPixel == 32 )
325 && ( modeInfo.MemoryModel == 6 )
326 && ( modeInfo.RedMaskSize == 8 )
327 && ( modeInfo.GreenMaskSize == 8 )
328 && ( modeInfo.BlueMaskSize == 8 ) )
329 {
330 // Direct color, 32 bpp (8:8:8:8).
331 }
332 else
333 {
334 continue; // Not a supported mode.
335 }
336
337 // Modes larger than the specified dimensions are skipped.
338
339 if ( ( modeInfo.XResolution > width ) ||
340 ( modeInfo.YResolution > height ) )
341 {
342 continue;
343 }
344
345 // Perfect match, we're done looking.
346
347 if ( ( modeInfo.XResolution == width ) &&
348 ( modeInfo.YResolution == height ) &&
349 ( modeBitsPerPixel == bitsPerPixel ) )
350 {
351 matchedMode = *modePtr;
352 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
353 break;
354 }
355
356 // Save the next "best" mode in case a perfect match is not found.
357
358 if ( modeInfo.XResolution == outModeInfo->XResolution &&
359 modeInfo.YResolution == outModeInfo->YResolution &&
360 modeBitsPerPixel <= outModeInfo->BitsPerPixel )
361 {
362 continue; // Saved mode has more depth.
363 }
364 if ( modeInfo.XResolution < outModeInfo->XResolution ||
365 modeInfo.YResolution < outModeInfo->YResolution ||
366 modeBitsPerPixel < outModeInfo->BitsPerPixel )
367 {
368 continue; // Saved mode has more resolution.
369 }
370
371 matchedMode = *modePtr;
372 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
373 }
374
375 return matchedMode;
376}
377
378//==========================================================================
379// setupPalette
380
381static void setupPalette( VBEPalette * p, const unsigned char * g )
382{
383 int i;
384 unsigned char * source = (unsigned char *) g;
385
386 for (i = 0; i < 256; i++)
387 {
388 (*p)[i] = 0;
389 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red
390 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green
391 (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue
392 }
393}
394
395//==========================================================================
396// Simple decompressor for boot images encoded in RLE format.
397
398char * decodeRLE( const void * rleData, int rleBlocks, int outBytes )
399{
400 char *out, *cp;
401
402 struct RLEBlock {
403 unsigned char count;
404 unsigned char value;
405 } * bp = (struct RLEBlock *) rleData;
406
407 out = cp = malloc( outBytes );
408 if ( out == NULL ) return NULL;
409
410 while ( rleBlocks-- )
411 {
412 memset( cp, bp->value, bp->count );
413 cp += bp->count;
414 bp++;
415 }
416
417 return out;
418}
419
420//==========================================================================
421// getCurrentGraphicsMode
422
423uint16_t getCurrentGraphicsMode()
424{
425 if (getVBECurrentMode(&GraphicsModeCurrent) != errSuccess)
426 GraphicsModeCurrent = 0;
427 GraphicsModeCurrent &= 0x3FFF;
428 return GraphicsModeCurrent;
429}
430
431//==========================================================================
432// getCurrentEDID
433
434int getCurrentEDID()
435{
436 struct EDID edid;
437 //edid_mode mode;
438
439 uint8_t status = getVBEEDID(&edid);
440
441 if (status == errSuccess) {
442 /*
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 DBG("EDID read!\n", status);
458 */
459 } else {
460 verbose("Failed to get EDID! [ERROR: 0x%02X]\n", status);
461 }
462
463 return status;
464
465}
466//==========================================================================
467// setVESAGraphicsMode
468
469static int
470setVESAGraphicsMode( unsigned short width,
471 unsigned short height,
472 unsigned char bitsPerPixel,
473 unsigned short refreshRate )
474{
475 VBEModeInfoBlock minfo;
476 unsigned short modeOld, mode;
477 unsigned short vesaVersion;
478 int err = errFuncNotSupported;
479
480 modeOld = getCurrentGraphicsMode();
481 do {
482 mode = getVESAModeWithProperties( width, height, bitsPerPixel,
483 maColorModeBit |
484 maModeIsSupportedBit |
485 maGraphicsModeBit |
486 maLinearFrameBufferAvailBit,
487 0,
488 &minfo, &vesaVersion );
489 if ( mode == modeEndOfList )
490 {
491 break;
492 }
493
494//
495// FIXME : generateCRTCTiming() causes crash.
496//
497
498// if ( (vesaVersion >> 8) >= 3 && refreshRate >= 60 &&
499// (gBootMode & kBootModeSafe) == 0 )
500// {
501// VBECRTCInfoBlock timing;
502//
503// // Generate CRTC timing for given refresh rate.
504//
505// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
506// refreshRate, kCRTCParamRefreshRate,
507// &timing );
508//
509// // Find the actual pixel clock supported by the hardware.
510//
511// getVBEPixelClock( mode, &timing.PixelClock );
512//
513// // Re-compute CRTC timing based on actual pixel clock.
514//
515// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
516// timing.PixelClock, kCRTCParamPixelClock,
517// &timing );
518//
519// // Set the video mode and use specified CRTC timing.
520//
521// err = setVBEMode( mode | kLinearFrameBufferBit |
522// kCustomRefreshRateBit, &timing );
523// }
524// else
525// {
526// // Set the mode with default refresh rate.
527//
528// err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
529// }
530
531 // Set the mode with default refresh rate.
532
533 err = setVBEMode(mode | kLinearFrameBufferBit, NULL);
534
535 if (err != errSuccess)
536 {
537 break;
538 }
539
540 verbose("Succesfuly set mode: 0x%04X (old mode: 0x%04X)\n", getCurrentGraphicsMode(), modeOld);
541
542 // Set 8-bit color palette.
543
544 if ( minfo.BitsPerPixel == 8 )
545 {
546 VBEPalette palette;
547 setupPalette( &palette, appleClut8 );
548 if ((err = setVBEPalette(palette)) != errSuccess)
549 {
550 break;
551 }
552 }
553
554 // Is this required for buggy Video BIOS implementations?
555 // On which adapter?
556
557 if ( minfo.BytesPerScanline == 0 )
558 minfo.BytesPerScanline = ( minfo.XResolution *
559 minfo.BitsPerPixel ) >> 3;
560
561 // Update KernBootStruct using info provided by the selected
562 // VESA mode.
563
564 bootArgs->Video.v_display = GRAPHICS_MODE;
565 bootArgs->Video.v_width = minfo.XResolution;
566 bootArgs->Video.v_height = minfo.YResolution;
567 bootArgs->Video.v_depth = minfo.BitsPerPixel;
568 bootArgs->Video.v_rowBytes = minfo.BytesPerScanline;
569 bootArgs->Video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr);
570
571 } while ( 0 );
572
573 return err;
574}
575
576//==============================================================================
577
578int convertImage( unsigned short width, unsigned short height, const unsigned char *imageData, unsigned char **newImageData )
579{
580 int cnt;
581 unsigned char *img = 0;
582 unsigned short *img16;
583 unsigned long *img32;
584
585 switch ( VIDEO(depth) ) {
586 case 16 :
587 img16 = malloc(width * height * 2);
588 if ( !img16 ) break;
589 for (cnt = 0; cnt < (width * height); cnt++)
590 img16[cnt] = lookUpCLUTIndex(imageData[cnt], 16);
591 img = (unsigned char *)img16;
592 break;
593
594 case 32 :
595 img32 = malloc(width * height * 4);
596 if ( !img32 ) break;
597 for (cnt = 0; cnt < (width * height); cnt++)
598 img32[cnt] = lookUpCLUTIndex(imageData[cnt], 32);
599 img = (unsigned char *)img32;
600 break;
601
602 default :
603 img = malloc(width * height);
604 bcopy(imageData, img, width * height);
605 break;
606 }
607 *newImageData = img;
608 return 0;
609}
610
611//==============================================================================
612
613int loadPngImage(const char *filename, uint16_t *width, uint16_t *height,
614 uint8_t **imageData)
615{
616 uint8_t *pngData = NULL;
617 int pngFile = 0, pngSize;
618 PNG_info_t *info;
619 int error = 0;
620
621 pngFile = open_bvdev("bt(0,0)", filename, 0);
622 if (pngFile == -1) {
623 error = -1;
624 goto failed;
625 }
626 pngSize = file_size(pngFile);
627 if (!pngSize) {
628 error = -1;
629 goto failed;
630 }
631 pngData = malloc(pngSize);
632 if (read(pngFile, (char *) pngData, pngSize) != pngSize) {
633 error = -1;
634 goto failed;
635 }
636
637 PNG_error = -1;
638 info = PNG_decode(pngData, pngSize);
639 if (PNG_error != 0) {
640 error = PNG_error;
641 goto failed;
642 } else if ((info->width > 0xffff) || (info->height > 0xffff)) {
643 error = -1;
644 goto failed;
645 } else if ((info->width * info->height * 4) != info->image->size) {
646 error = -1;
647 goto failed;
648 }
649uint8_t *result = malloc(info->width*4*info->height);
650 *width = info->width;
651 *height = info->height;
652memcpy(result, info->image->data, info->width*4*info->height);
653*imageData = result;
654
655failed:
656png_alloc_free_all();
657 if (pngData)
658 free(pngData);
659 if (pngFile != -1)
660 close(pngFile);
661
662 return error;
663}
664
665//==============================================================================
666
667int loadEmbeddedPngImage(uint8_t *pngData, int pngSize, uint16_t *width, uint16_t *height, uint8_t **imageData) {
668 PNG_info_t *info;
669 int error = 0;
670
671 PNG_error = -1;
672 info = PNG_decode(pngData, pngSize);
673if (PNG_error != 0) {
674 error = PNG_error;
675 goto failed;
676 } else if ((info->width > 0xffff) || (info->height > 0xffff)) {
677 error = -1;
678 goto failed;
679 } else if ((info->width * info->height * 4) != info->image->size) {
680 error = -1;
681 goto failed;
682 }
683uint8_t *result = malloc(info->width*4*info->height);
684*width = info->width;
685 *height = info->height;
686memcpy(result, info->image->data, info->width*4*info->height);
687*imageData = result;
688
689failed:
690png_alloc_free_all();
691
692 return error;
693}
694
695//==============================================================================
696
697void blendImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height,
698 uint8_t *data)
699{
700 uint16_t drawWidth;
701 uint8_t *vram = (uint8_t *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + 4 * x;
702
703 drawWidth = MIN(width, VIDEO(width) - x);
704 height = MIN(height, VIDEO(height) - y);
705 while (height--) {
706switch (VIDEO (depth))
707{
708case 32: /* Optimized version*/
709{
710uint32_t s; uint32_t* d; // Source (img) and destination (bkgd) pixels
711uint32_t a; // Alpha
712uint32_t dstrb, dstg, srcrb, srcg, drb, dg, rb, g, tempB; // Intermediate variables
713uint16_t pos;
714
715for (pos = 0; pos < drawWidth * 4; pos += 4) {
716// Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html
717s = *((uint32_t*) (data + pos));
718d = (uint32_t*) (vram + pos);
719
720// Flip B and R in source
721// TODO: use XCHG and inline assembly to do this in a faster, saner way
722tempB = (s & 0xFF0000); // save B
723s = (s & 0xFF00FFFF) | ((s & 0xFF) << 16); // put R in B
724s = (s & 0xFFFFFF00) | (tempB >> 16); // put B in R
725
726a = (s >> 24) + 1;
727
728dstrb = *d & 0xFF00FF; dstg = *d & 0xFF00;
729srcrb = s & 0xFF00FF; srcg = s & 0xFF00;
730
731drb = srcrb - dstrb;
732dg = srcg - dstg;
733drb *= a; dg *= a;
734drb >>= 8; dg >>= 8;
735
736rb = (drb + dstrb) & 0xFF00FF;
737g = (dg + dstg) & 0xFF00;
738
739*d = rb | g;
740}
741}
742break;
743
744default: /*Universal version*/
745{
746uint32_t s;
747uint32_t a; // Alpha
748uint32_t dr, dg, db, sr, sg, sb; // Intermediate variables
749uint16_t pos;
750int bpp = (VIDEO (depth) + 7)/8;
751
752for (pos = 0; pos < drawWidth; pos ++) {
753// Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html
754s = *((uint32_t*) (data + 4*pos));
755
756sb = (s & 0xFF0000) >> 16;
757sg = (s & 0xFF00) >> 8;
758sr = (s & 0xFF);
759
760a = (s >> 24) + 1;
761
762switch (VIDEO (depth))
763{
764case 24:
765db = ((*(uint32_t *)(vram + bpp*pos))&0xff);
766dg = ((*(uint32_t *)(vram + bpp*pos))&0xff00)>>8;
767dr = ((*(uint32_t *)(vram + bpp*pos))&0xff0000)>>16;
768break;
769case 16://16-bit seems to be 15-bit
770/*db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3;
771dg = ((*(uint16_t *)(vram + bpp*pos))&0x07e0)>>3;
772dr = ((*(uint16_t *)(vram + bpp*pos))&0xf800)>>8;
773break;*/
774case 15:
775db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3;
776dg = ((*(uint16_t *)(vram + bpp*pos))&0x03e0)>>2;
777dr = ((*(uint16_t *)(vram + bpp*pos))&0x7c00)>>7;
778break;
779default:
780return;
781}
782
783dr = (((sr - dr) * a) >> 8) + dr;
784dg = (((sg - dg) * a) >> 8) + dg;
785db = (((sb - db) * a) >> 8) + db;
786switch (VIDEO (depth))
787{
788case 24:
789*(uint32_t *)(vram + bpp*pos) = (*(uint32_t *)(vram + bpp*pos) &0xff000000)
790| (db&0xff) | ((dg&0xff)<<8) | ((dr&0xff)<<16);
791break;
792case 16:
793//*(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xfc)<<3) | ((dr&0xf8)<<8);
794//break;
795case 15:
796*(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xf8)<<2) | ((dr&0xf8)<<7);
797break;
798}
799
800}
801}
802break;
803 }
804 vram += VIDEO(rowBytes);
805 data += width * 4;
806 }
807}
808
809//==============================================================================
810
811void drawCheckerBoard()
812{
813 uint32_t *vram = (uint32_t *) VIDEO(baseAddr);
814 uint16_t x, y;
815 uint8_t color;
816
817 for (y = 0; y < VIDEO(height); y++, vram += VIDEO(width)) {
818 for (x = 0; x < VIDEO(width); x++) {
819 color = 204 + 51 * (((x / 8) % 2) == ((y / 8) % 2));
820 vram[x] = (color << 16) | (color << 8) | color;
821 }
822 }
823}
824
825//==========================================================================
826// LookUpCLUTIndex
827
828unsigned long lookUpCLUTIndex( unsigned char index, unsigned char depth )
829{
830 long result, red, green, blue;
831
832 red = appleClut8[index * 3 + 0];
833 green = appleClut8[index * 3 + 1];
834 blue = appleClut8[index * 3 + 2];
835
836 switch (depth) {
837 case 16 :
838 result = ((red & 0xF8) << 7) |
839 ((green & 0xF8) << 2) |
840 ((blue & 0xF8) >> 3);
841 result |= (result << 16);
842 break;
843
844 case 32 :
845 result = (red << 16) | (green << 8) | blue;
846 break;
847
848 default :
849 result = index | (index << 8);
850 result |= (result << 16);
851 break;
852 }
853
854 return result;
855}
856
857//==========================================================================
858// drawColorRectangle
859
860void * stosl(void * dst, long val, long len)
861{
862asm volatile ( "rep; stosl"
863 : "=c" (len), "=D" (dst)
864 : "0" (len), "1" (dst), "a" (val)
865 : "memory" );
866
867return dst;
868}
869
870//==============================================================================
871
872void drawColorRectangle( unsigned short x,
873 unsigned short y,
874 unsigned short width,
875 unsigned short height,
876 unsigned char colorIndex )
877{
878 long pixelBytes;
879 long color = lookUpCLUTIndex( colorIndex, VIDEO(depth) );
880 char * vram;
881
882pixelBytes = VIDEO(depth) / 8;
883vram = (char *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + pixelBytes * x;
884
885 width = MIN(width, VIDEO(width) - x);
886 height = MIN(height, VIDEO(height) - y);
887
888 while ( height-- )
889 {
890 int rem = ( pixelBytes * width ) % 4;
891 if ( rem ) bcopy( &color, vram, rem );
892 stosl( vram + rem, color, pixelBytes * width / 4 );
893 vram += VIDEO(rowBytes);
894 }
895}
896
897//==========================================================================
898// drawDataRectangle
899
900void drawDataRectangle( unsigned short x,
901 unsigned short y,
902 unsigned short width,
903 unsigned short height,
904 unsigned char * data )
905{
906unsigned short drawWidth;
907long pixelBytes = VIDEO(depth) / 8;
908unsigned char * vram = (unsigned char *) VIDEO(baseAddr) + 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
1000pixelShift = VIDEO (depth) >> 4;
1001if (pixelShift < 1) return;
1002
1003screen += ((VIDEO (width)
1004- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1005+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1006
1007for (y = 0; y < kIOHibernateProgressHeight; y++)
1008{
1009out = screen + y * rowBytes;
1010for (blob = 0; blob < kIOHibernateProgressCount; blob++)
1011{
1012color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
1013for (x = 0; x < kIOHibernateProgressWidth; x++)
1014{
1015alpha = gIOHibernateProgressAlpha[y][x];
1016result = color;
1017if (alpha)
1018{
1019if (0xff != alpha)
1020{
1021if (1 == pixelShift)
1022{
1023in = *((uint16_t *)out) & 0x1f;// 16
1024in = (in << 3) | (in >> 2);
1025}
1026else
1027in = *((uint32_t *)out) & 0xff;// 32
1028saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
1029result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
1030}
1031if (1 == pixelShift)
1032{
1033result >>= 3;
1034*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
1035}
1036else
1037*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
1038}
1039out += (1 << pixelShift);
1040}
1041out += (kIOHibernateProgressSpacing << pixelShift);
1042}
1043}
1044}
1045
1046//==============================================================================
1047
1048void updateProgressBar(uint8_t * saveunder, int32_t firstBlob, int32_t select)
1049{
1050uint8_t * screen;
1051uint32_t rowBytes, pixelShift;
1052uint32_t x, y;
1053int32_t blob, lastBlob;
1054uint32_t alpha, in, color, result;
1055uint8_t * out;
1056uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
1057
1058pixelShift = VIDEO(depth) >> 4;
1059if (pixelShift < 1) return;
1060screen = (uint8_t *) VIDEO (baseAddr);
1061rowBytes = VIDEO (rowBytes);
1062
1063screen += ((VIDEO (width)
1064- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1065+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1066
1067lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
1068
1069screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
1070
1071for (y = 0; y < kIOHibernateProgressHeight; y++)
1072{
1073out = screen + y * rowBytes;
1074for (blob = firstBlob; blob <= lastBlob; blob++)
1075{
1076color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
1077for (x = 0; x < kIOHibernateProgressWidth; x++)
1078{
1079alpha = gIOHibernateProgressAlpha[y][x];
1080result = color;
1081if (alpha)
1082{
1083if (0xff != alpha)
1084{
1085in = saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++];
1086result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
1087}
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// setVESATextMode
1106
1107static int setVESATextMode( unsigned short cols, unsigned short rows, unsigned char bitsPerPixel )
1108{
1109 VBEModeInfoBlock minfo;
1110 unsigned short mode = modeEndOfList;
1111
1112 if ( (cols != 80) || (rows != 25) ) // not 80x25 mode
1113 {
1114 mode = getVESAModeWithProperties( cols, rows, bitsPerPixel,
1115 maColorModeBit |
1116 maModeIsSupportedBit,
1117 maGraphicsModeBit,
1118 &minfo, NULL );
1119 }
1120
1121 if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) )
1122 {
1123 video_mode( 2 ); // VGA BIOS, 80x25 text mode.
1124 minfo.XResolution = 80;
1125 minfo.YResolution = 25;
1126 }
1127
1128 // Update KernBootStruct using info provided by the selected
1129 // VESA mode.
1130
1131 bootArgs->Video.v_display = VGA_TEXT_MODE;
1132 bootArgs->Video.v_baseAddr = 0xb8000;
1133 bootArgs->Video.v_width = minfo.XResolution;
1134 bootArgs->Video.v_height = minfo.YResolution;
1135 bootArgs->Video.v_depth = 8;
1136 bootArgs->Video.v_rowBytes = 0x8000;
1137
1138 return errSuccess; // always return success
1139}
1140
1141//==========================================================================
1142// getNumberArrayFromProperty
1143
1144static int getNumberArrayFromProperty( const char * propKey,
1145 unsigned long numbers[],
1146 unsigned long maxArrayCount )
1147{
1148 char *propStr;
1149 unsigned long count = 0;
1150
1151 propStr = newStringForKey((char *)propKey , &bootInfo->chameleonConfig);
1152
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
1249//==============================================================================
1250void getGraphicModeParams(unsigned long params[])
1251{
1252params[3] = 0;
1253
1254VBEModeInfoBlock minfo;
1255
1256 unsigned short vesaVersion;
1257 unsigned short mode = modeEndOfList;
1258
1259getNumberArrayFromProperty(kGraphicsModeKey, params, 4);
1260
1261mode = getVESAModeWithProperties(params[0], params[1], params[2],
1262 maColorModeBit |
1263 maModeIsSupportedBit |
1264 maGraphicsModeBit |
1265 maLinearFrameBufferAvailBit,
1266 0,
1267 &minfo, &vesaVersion);
1268
1269params[0] = minfo.XResolution;
1270params[1] = minfo.YResolution;
1271params[2] = 32;
1272}
1273
1274//==========================================================================
1275// Return the current video mode, VGA_TEXT_MODE or GRAPHICS_MODE.
1276
1277int getVideoMode(void)
1278{
1279 return bootArgs->Video.v_display;
1280}
1281
1282//==========================================================================
1283// Display and clear the activity indicator.
1284
1285// BASIC Indicator
1286static char indicator[] = {'-', '\\', '|', '/', '-', '\\', '|', '/', '\0'};
1287
1288// To prevent a ridiculously fast-spinning indicator,
1289// ensure a minimum of 1/9 sec between animation frames.
1290#define MIN_TICKS 2
1291
1292//==============================================================================
1293
1294void spinActivityIndicator(int sectors)
1295{
1296 static unsigned long lastTickTime = 0, currentTickTime;
1297
1298if (previewTotalSectors && previewSaveunder)
1299{
1300int blob, lastBlob;
1301
1302lastBlob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
1303previewLoadedSectors+=sectors;
1304blob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
1305
1306if (blob!=lastBlob)
1307updateProgressBar (previewSaveunder, lastBlob, blob);
1308return;
1309}
1310
1311currentTickTime = time18(); // late binding
1312if (currentTickTime < lastTickTime + MIN_TICKS)
1313{
1314return;
1315}
1316else
1317{
1318lastTickTime = currentTickTime;
1319}
1320
1321if (getVideoMode() == VGA_TEXT_MODE)
1322{
1323if (currentIndicator >= sizeof(indicator))
1324{
1325currentIndicator = 0;
1326}
1327putchar(indicator[currentIndicator++]);
1328putchar('\b');
1329}
1330}
1331
1332//==============================================================================
1333
1334void clearActivityIndicator( void )
1335{
1336 if ( getVideoMode() == VGA_TEXT_MODE )
1337 {
1338putchar(' ');
1339putchar('\b');
1340 }
1341}
1342
1343//==============================================================================
1344

Archive Download this file

Revision: 2531