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

Archive Download this file

Revision: 2839