ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/video.cpp
Revision: 1.15
Committed: 2001-06-30T22:23:43Z (23 years, 5 months ago) by cebix
Branch: MAIN
Changes since 1.14: +1 -3 lines
Log Message:
gamma tables work with X11

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * video.cpp - Video/graphics emulation
3     *
4 cebix 1.7 * Basilisk II (C) 1997-2001 Christian Bauer
5 cebix 1.1 * Portions (C) 1997-1999 Marc Hellwig
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21    
22     /*
23     * SEE ALSO
24     * Inside Macintosh: Devices, chapter 1 "Device Manager"
25     * Designing Cards and Drivers for the Macintosh Family, Second Edition
26     */
27    
28     #include <stdio.h>
29    
30     #include "sysdeps.h"
31     #include "cpu_emulation.h"
32     #include "main.h"
33     #include "macos_util.h"
34 cebix 1.13 #include "slot_rom.h"
35 cebix 1.1 #include "video.h"
36     #include "video_defs.h"
37    
38 cebix 1.11 #define DEBUG 0
39 cebix 1.1 #include "debug.h"
40    
41    
42 cebix 1.9 // List of supported video modes
43 gbeauche 1.12 std::vector<video_mode> VideoModes;
44 cebix 1.9
45 cebix 1.1 // Description of the main monitor
46 cebix 1.9 monitor_desc VideoMonitor;
47 cebix 1.1
48     // Local variables (per monitor)
49     struct {
50 cebix 1.9 monitor_desc *desc; // Pointer to description of monitor handled by this instance of the driver
51 cebix 1.1 uint8 palette[256 * 3]; // Color palette, 256 entries, RGB
52     bool luminance_mapping; // Luminance mapping on/off
53     bool interrupts_enabled; // VBL interrupts on/off
54 cebix 1.11 uint32 gamma_table; // Mac address of gamma table
55 cebix 1.14 int alloc_gamma_table_size; // Allocated size of gamma table
56 cebix 1.9 uint16 current_mode; // Currently selected depth/resolution
57     uint32 current_id;
58     uint16 preferred_mode; // Preferred depth/resolution
59     uint32 preferred_id;
60 cebix 1.11 uint32 sp; // Mac address of Slot Manager parameter block
61 cebix 1.1 } VidLocal;
62    
63    
64     /*
65 cebix 1.9 * Check whether specified resolution ID is one of the supported resolutions
66     */
67    
68     static bool has_resolution(uint32 id)
69     {
70 cebix 1.10 std::vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
71 cebix 1.9 while (i != end) {
72     if (i->resolution_id == id)
73     return true;
74     ++i;
75     }
76     return false;
77     }
78    
79    
80     /*
81 cebix 1.10 * Find specified mode (depth/resolution) (or VideoModes.end() if not found)
82     */
83    
84     static std::vector<video_mode>::const_iterator find_mode(uint16 mode, uint32 id)
85     {
86     std::vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
87     while (i != end) {
88     if (i->resolution_id == id && DepthToAppleMode(i->depth) == mode)
89     return i;
90     ++i;
91     }
92     return i;
93     }
94    
95    
96     /*
97 cebix 1.9 * Find maximum supported depth for given resolution ID
98     */
99    
100     static video_depth max_depth_of_resolution(uint32 id)
101     {
102     video_depth m = VDEPTH_1BIT;
103 gbeauche 1.12 std::vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
104 cebix 1.9 while (i != end) {
105     if (i->depth > m)
106     m = i->depth;
107     ++i;
108     }
109     return m;
110     }
111    
112    
113     /*
114     * Get X/Y size of specified resolution
115     */
116    
117     static void get_size_of_resolution(uint32 id, uint32 &x, uint32 &y)
118     {
119 gbeauche 1.12 std::vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
120 cebix 1.9 while (i != end) {
121     if (i->resolution_id == id) {
122     x = i->x;
123     y = i->y;
124     return;
125     }
126     ++i;
127     }
128     }
129    
130    
131     /*
132 cebix 1.11 * Set palette to 50% gray
133     */
134    
135     static void set_gray_palette(void)
136     {
137 cebix 1.14 for (int i=0; i<256; i++) {
138     VidLocal.palette[i * 3 + 0] = 127;
139     VidLocal.palette[i * 3 + 1] = 127;
140     VidLocal.palette[i * 3 + 2] = 127;
141     }
142     video_set_palette(VidLocal.palette);
143     }
144    
145    
146     /*
147     * Load gamma-corrected black-to-white ramp to palette for direct-color mode
148     */
149    
150     static void load_ramp_palette(void)
151     {
152     // Find tables for gamma correction
153     uint8 *red_gamma, *green_gamma, *blue_gamma;
154     bool have_gamma = false;
155     int data_width = 0;
156     if (VidLocal.gamma_table) {
157     uint32 table = VidLocal.gamma_table;
158     red_gamma = Mac2HostAddr(table + gFormulaData + ReadMacInt16(table + gFormulaSize));
159     int chan_cnt = ReadMacInt16(table + gChanCnt);
160     if (chan_cnt == 1)
161     green_gamma = blue_gamma = red_gamma;
162     else {
163     int ofs = ReadMacInt16(table + gDataCnt);
164     green_gamma = red_gamma + ofs;
165     blue_gamma = green_gamma + ofs;
166     }
167     data_width = ReadMacInt16(table + gDataWidth);
168     have_gamma = true;
169     }
170    
171     int num = (VidLocal.desc->mode.depth == VDEPTH_16BIT ? 32 : 256);
172     uint8 *p = VidLocal.palette;
173     for (int i=0; i<num; i++) {
174 cebix 1.15 uint8 red = (i * 256 / num), green = red, blue = red;
175 cebix 1.14 if (have_gamma) {
176     red = red_gamma[red >> (8 - data_width)];
177     green = green_gamma[green >> (8 - data_width)];
178     blue = blue_gamma[blue >> (8 - data_width)];
179     }
180     *p++ = red;
181     *p++ = green;
182     *p++ = blue;
183     }
184    
185     video_set_palette(VidLocal.palette);
186     }
187    
188    
189     /*
190     * Allocate gamma table of specified size
191     */
192    
193     static bool allocate_gamma_table(int size)
194     {
195     M68kRegisters r;
196    
197     if (size > VidLocal.alloc_gamma_table_size) {
198     if (VidLocal.gamma_table) {
199     r.a[0] = VidLocal.gamma_table;
200     Execute68kTrap(0xa01f, &r); // DisposePtr()
201     VidLocal.gamma_table = 0;
202     VidLocal.alloc_gamma_table_size = 0;
203 cebix 1.11 }
204 cebix 1.14 r.d[0] = size;
205     Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
206     if (r.a[0] == 0)
207     return false;
208     VidLocal.gamma_table = r.a[0];
209     VidLocal.alloc_gamma_table_size = size;
210 cebix 1.11 }
211 cebix 1.14 return true;
212     }
213    
214    
215     /*
216     * Set gamma table (0 = build linear ramp)
217     */
218    
219     static bool set_gamma_table(uint32 user_table)
220     {
221     if (user_table == 0) { // Build linear ramp, 256 entries
222    
223     // Allocate new table, if necessary
224     if (!allocate_gamma_table(SIZEOF_GammaTbl + 256))
225     return memFullErr;
226     uint32 table = VidLocal.gamma_table;
227    
228     // Initialize header
229     WriteMacInt16(table + gVersion, 0);
230     WriteMacInt16(table + gType, 0);
231     WriteMacInt16(table + gFormulaSize, 0);
232     WriteMacInt16(table + gChanCnt, 1);
233     WriteMacInt16(table + gDataCnt, 256);
234     WriteMacInt16(table + gDataWidth, 8);
235    
236     // Build ramp
237     uint32 p = table + gFormulaData;
238     for (int i=0; i<256; i++)
239     WriteMacInt8(p + i, i);
240    
241     } else { // User-supplied gamma table
242    
243     // Validate header
244     if (ReadMacInt16(user_table + gVersion))
245     return paramErr;
246     if (ReadMacInt16(user_table + gType))
247     return paramErr;
248     int chan_cnt = ReadMacInt16(user_table + gChanCnt);
249     if (chan_cnt != 1 && chan_cnt != 3)
250     return paramErr;
251     int data_width = ReadMacInt16(user_table + gDataWidth);
252     if (data_width > 8)
253     return paramErr;
254     int data_cnt = ReadMacInt16(user_table + gDataCnt);
255     if (data_cnt != (1 << data_width))
256     return paramErr;
257    
258     // Allocate new table, if necessary
259     int size = SIZEOF_GammaTbl + ReadMacInt16(user_table + gFormulaSize) + chan_cnt * data_cnt;
260     if (!allocate_gamma_table(size))
261     return memFullErr;
262     uint32 table = VidLocal.gamma_table;
263    
264     // Copy table
265     Mac2Mac_memcpy(table, user_table, size);
266     }
267    
268     if (IsDirectMode(VidLocal.current_mode))
269     load_ramp_palette();
270    
271     return true;
272 cebix 1.11 }
273    
274    
275     /*
276 cebix 1.1 * Driver Open() routine
277     */
278    
279 cebix 1.2 int16 VideoDriverOpen(uint32 pb, uint32 dce)
280 cebix 1.1 {
281 cebix 1.2 D(bug("VideoDriverOpen\n"));
282 cebix 1.1
283 cebix 1.9 // This shouldn't happen unless the platform-specific video code is broken
284     if (VideoModes.empty())
285     fprintf(stderr, "No valid video modes found (broken video driver?)\n");
286    
287 cebix 1.1 // Init local variables
288     VidLocal.desc = &VideoMonitor;
289     VidLocal.luminance_mapping = false;
290     VidLocal.interrupts_enabled = false;
291 cebix 1.9 VidLocal.current_mode = DepthToAppleMode(VidLocal.desc->mode.depth);
292     VidLocal.current_id = VidLocal.desc->mode.resolution_id;
293     VidLocal.preferred_mode = VidLocal.current_mode;
294     VidLocal.preferred_id = VidLocal.current_id;
295 cebix 1.1
296 cebix 1.11 // Allocate Slot Manager parameter block in Mac RAM
297     M68kRegisters r;
298     r.d[0] = SIZEOF_SPBlock;
299     Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
300     if (r.a[0] == 0)
301     return memFullErr;
302     VidLocal.sp = r.a[0];
303     D(bug("SPBlock at %08x\n", VidLocal.sp));
304    
305     // Find and set default gamma table
306 cebix 1.14 VidLocal.gamma_table = 0;
307     VidLocal.alloc_gamma_table_size = 0;
308     set_gamma_table(0);
309 cebix 1.11
310 cebix 1.1 // Init color palette (solid gray)
311 cebix 1.11 set_gray_palette();
312 cebix 1.1 return noErr;
313     }
314    
315    
316     /*
317     * Driver Control() routine
318     */
319    
320 cebix 1.2 int16 VideoDriverControl(uint32 pb, uint32 dce)
321 cebix 1.1 {
322     uint16 code = ReadMacInt16(pb + csCode);
323     uint32 param = ReadMacInt32(pb + csParam);
324 cebix 1.2 D(bug("VideoDriverControl %d\n", code));
325 cebix 1.1 switch (code) {
326    
327 cebix 1.9 case cscSetMode: { // Set color depth
328     uint16 mode = ReadMacInt16(param + csMode);
329     D(bug(" SetMode %04x\n", mode));
330 cebix 1.10
331 cebix 1.11 // Set old base address in case the switch fails
332     WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
333    
334     if (ReadMacInt16(param + csPage))
335     return paramErr;
336    
337 cebix 1.10 if (mode != VidLocal.current_mode) {
338     std::vector<video_mode>::const_iterator i = find_mode(mode, VidLocal.current_id);
339 cebix 1.11 if (i == VideoModes.end())
340 cebix 1.10 return paramErr;
341 cebix 1.11 set_gray_palette();
342 cebix 1.10 video_switch_to_mode(*i);
343     VidLocal.current_mode = mode;
344 cebix 1.11 WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
345     WriteMacInt32(dce + dCtlDevBase, VidLocal.desc->mac_frame_base);
346 cebix 1.10 }
347 cebix 1.11 D(bug(" base %08x\n", VidLocal.desc->mac_frame_base));
348 cebix 1.10 return noErr;
349 cebix 1.9 }
350 cebix 1.1
351 cebix 1.14 case cscSetEntries: // Set palette
352     case cscDirectSetEntries: {
353     D(bug(" (Direct)SetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart)));
354     bool is_direct = IsDirectMode(VidLocal.current_mode);
355     if (code == cscSetEntries && is_direct)
356     return controlErr;
357     if (code == cscDirectSetEntries && !is_direct)
358 cebix 1.1 return controlErr;
359    
360     uint32 s_pal = ReadMacInt32(param + csTable); // Source palette
361     uint8 *d_pal; // Destination palette
362 cebix 1.11 uint16 start = ReadMacInt16(param + csStart);
363 cebix 1.1 uint16 count = ReadMacInt16(param + csCount);
364 cebix 1.11 if (s_pal == 0 || count > 255)
365 cebix 1.1 return paramErr;
366    
367 cebix 1.14 // Find tables for gamma correction
368     uint8 *red_gamma, *green_gamma, *blue_gamma;
369     bool have_gamma = false;
370     int data_width = 0;
371     if (VidLocal.gamma_table) {
372     uint32 table = VidLocal.gamma_table;
373     red_gamma = Mac2HostAddr(table + gFormulaData + ReadMacInt16(table + gFormulaSize));
374     int chan_cnt = ReadMacInt16(table + gChanCnt);
375     if (chan_cnt == 1)
376     green_gamma = blue_gamma = red_gamma;
377     else {
378     int ofs = ReadMacInt16(table + gDataCnt);
379     green_gamma = red_gamma + ofs;
380     blue_gamma = green_gamma + ofs;
381     }
382     data_width = ReadMacInt16(table + gDataWidth);
383     have_gamma = true;
384     }
385    
386     // Convert palette
387 cebix 1.11 if (start == 0xffff) { // Indexed
388 cebix 1.1 for (uint32 i=0; i<=count; i++) {
389 cebix 1.11 d_pal = VidLocal.palette + (ReadMacInt16(s_pal) & 0xff) * 3;
390 cebix 1.1 uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8;
391     uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8;
392     uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8;
393 cebix 1.14 if (VidLocal.luminance_mapping && !is_direct)
394 cebix 1.1 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
395 cebix 1.14 if (have_gamma) {
396     red = red_gamma[red >> (8 - data_width)];
397     green = green_gamma[green >> (8 - data_width)];
398     blue = blue_gamma[blue >> (8 - data_width)];
399     }
400 cebix 1.1 *d_pal++ = red;
401     *d_pal++ = green;
402     *d_pal++ = blue;
403     s_pal += 8;
404     }
405 cebix 1.11 } else { // Sequential
406     if (start + count > 255)
407     return paramErr;
408     d_pal = VidLocal.palette + start * 3;
409 cebix 1.1 for (uint32 i=0; i<=count; i++) {
410     uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8;
411     uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8;
412     uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8;
413 cebix 1.14 if (VidLocal.luminance_mapping && !is_direct)
414 cebix 1.1 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
415 cebix 1.14 if (have_gamma) {
416     red = red_gamma[red >> (8 - data_width)];
417     green = green_gamma[green >> (8 - data_width)];
418     blue = blue_gamma[blue >> (8 - data_width)];
419     }
420 cebix 1.1 *d_pal++ = red;
421     *d_pal++ = green;
422     *d_pal++ = blue;
423     s_pal += 8;
424     }
425     }
426     video_set_palette(VidLocal.palette);
427     return noErr;
428     }
429    
430 cebix 1.14 case cscSetGamma: { // Set gamma table
431     uint32 user_table = ReadMacInt32(param + csGTable);
432     D(bug(" SetGamma %08x\n", user_table));
433     return set_gamma_table(user_table) ? noErr : memFullErr;
434     }
435 cebix 1.1
436     case cscGrayPage: { // Fill page with dithered gray pattern
437     D(bug(" GrayPage %d\n", ReadMacInt16(param + csPage)));
438     if (ReadMacInt16(param + csPage))
439     return paramErr;
440    
441     uint32 pattern[6] = {
442     0xaaaaaaaa, // 1 bpp
443     0xcccccccc, // 2 bpp
444     0xf0f0f0f0, // 4 bpp
445     0xff00ff00, // 8 bpp
446     0xffff0000, // 16 bpp
447     0xffffffff // 32 bpp
448     };
449     uint32 p = VidLocal.desc->mac_frame_base;
450 cebix 1.9 uint32 pat = pattern[VidLocal.desc->mode.depth];
451 cebix 1.11 bool invert = (VidLocal.desc->mode.depth == VDEPTH_32BIT);
452 cebix 1.9 for (uint32 y=0; y<VidLocal.desc->mode.y; y++) {
453     for (uint32 x=0; x<VidLocal.desc->mode.bytes_per_row; x+=4) {
454 cebix 1.8 WriteMacInt32(p + x, pat);
455 cebix 1.11 if (invert)
456 cebix 1.1 pat = ~pat;
457     }
458 cebix 1.9 p += VidLocal.desc->mode.bytes_per_row;
459 cebix 1.1 pat = ~pat;
460     }
461 cebix 1.14
462     if (IsDirectMode(VidLocal.current_mode))
463     load_ramp_palette();
464    
465 cebix 1.1 return noErr;
466     }
467    
468     case cscSetGray: // Enable/disable luminance mapping
469     D(bug(" SetGray %02x\n", ReadMacInt8(param + csMode)));
470     VidLocal.luminance_mapping = ReadMacInt8(param + csMode);
471     return noErr;
472    
473     case cscSetInterrupt: // Enable/disable VBL
474     D(bug(" SetInterrupt %02x\n", ReadMacInt8(param + csMode)));
475     VidLocal.interrupts_enabled = (ReadMacInt8(param + csMode) == 0);
476     return noErr;
477    
478 cebix 1.9 case cscSetDefaultMode: { // Set default color depth
479     uint16 mode = ReadMacInt16(param + csMode);
480     D(bug(" SetDefaultMode %04x\n", mode));
481     VidLocal.preferred_mode = mode;
482     return noErr;
483     }
484    
485     case cscSwitchMode: { // Switch video mode (depth and resolution)
486     uint16 mode = ReadMacInt16(param + csMode);
487     uint32 id = ReadMacInt32(param + csData);
488     D(bug(" SwitchMode %04x, %08x\n", mode, id));
489 cebix 1.10
490 cebix 1.11 // Set old base address in case the switch fails
491     WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
492    
493     if (ReadMacInt16(param + csPage))
494     return paramErr;
495    
496 cebix 1.10 if (mode != VidLocal.current_mode || id != VidLocal.current_id) {
497     std::vector<video_mode>::const_iterator i = find_mode(mode, id);
498 cebix 1.11 if (i == VideoModes.end())
499 cebix 1.10 return paramErr;
500 cebix 1.11 set_gray_palette();
501 cebix 1.10 video_switch_to_mode(*i);
502     VidLocal.current_mode = mode;
503     VidLocal.current_id = id;
504 cebix 1.11 uint32 frame_base = VidLocal.desc->mac_frame_base;
505     WriteMacInt32(param + csBaseAddr, frame_base);
506    
507     M68kRegisters r;
508     uint32 sp = VidLocal.sp;
509     r.a[0] = sp;
510    
511     // Find functional sResource for this display
512     WriteMacInt8(sp + spSlot, ReadMacInt8(dce + dCtlSlot));
513     WriteMacInt8(sp + spID, ReadMacInt8(dce + dCtlSlotId));
514     WriteMacInt8(sp + spExtDev, 0);
515     r.d[0] = 0x0016;
516     Execute68kTrap(0xa06e, &r); // SRsrcInfo()
517     uint32 rsrc = ReadMacInt32(sp + spPointer);
518    
519 cebix 1.13 // Patch minorBase (otherwise rebooting won't work)
520 cebix 1.11 WriteMacInt8(sp + spID, 0x0a); // minorBase
521     r.d[0] = 0x0006;
522     Execute68kTrap(0xa06e, &r); // SFindStruct()
523     uint32 minor_base = ReadMacInt32(sp + spPointer) - ROMBaseMac;
524     ROMBaseHost[minor_base + 0] = frame_base >> 24;
525     ROMBaseHost[minor_base + 1] = frame_base >> 16;
526     ROMBaseHost[minor_base + 2] = frame_base >> 8;
527     ROMBaseHost[minor_base + 3] = frame_base;
528    
529     // Patch video mode parameter table
530     WriteMacInt32(sp + spPointer, rsrc);
531     WriteMacInt8(sp + spID, mode);
532     r.d[0] = 0x0006;
533     Execute68kTrap(0xa06e, &r); // SFindStruct()
534     WriteMacInt8(sp + spID, 0x01);
535     r.d[0] = 0x0006;
536     Execute68kTrap(0xa06e, &r); // SFindStruct()
537     uint32 p = ReadMacInt32(sp + spPointer) - ROMBaseMac;
538     ROMBaseHost[p + 8] = i->bytes_per_row >> 8;
539     ROMBaseHost[p + 9] = i->bytes_per_row;
540     ROMBaseHost[p + 14] = i->y >> 8;
541     ROMBaseHost[p + 15] = i->y;
542     ROMBaseHost[p + 16] = i->x >> 8;
543     ROMBaseHost[p + 17] = i->x;
544 cebix 1.13
545     // Recalculate slot ROM checksum
546     ChecksumSlotROM();
547 cebix 1.11
548     // Update sResource
549     WriteMacInt8(sp + spID, ReadMacInt8(dce + dCtlSlotId));
550     r.d[0] = 0x002b;
551     Execute68kTrap(0xa06e, &r); // SUpdateSRT()
552    
553     // Update frame buffer base in DCE
554     WriteMacInt32(dce + dCtlDevBase, frame_base);
555 cebix 1.10 }
556 cebix 1.11 D(bug(" base %08x\n", VidLocal.desc->mac_frame_base));
557 cebix 1.10 return noErr;
558 cebix 1.9 }
559    
560     case cscSavePreferredConfiguration: {
561     uint16 mode = ReadMacInt16(param + csMode);
562     uint32 id = ReadMacInt32(param + csData);
563     D(bug(" SavePreferredConfiguration %04x, %08x\n", mode, id));
564     VidLocal.preferred_mode = mode;
565     VidLocal.preferred_id = id;
566     return noErr;
567     }
568    
569 cebix 1.1 default:
570 cebix 1.2 printf("WARNING: Unknown VideoDriverControl(%d)\n", code);
571 cebix 1.1 return controlErr;
572     }
573     }
574    
575    
576     /*
577     * Driver Status() routine
578     */
579    
580 cebix 1.2 int16 VideoDriverStatus(uint32 pb, uint32 dce)
581 cebix 1.1 {
582     uint16 code = ReadMacInt16(pb + csCode);
583     uint32 param = ReadMacInt32(pb + csParam);
584 cebix 1.2 D(bug("VideoDriverStatus %d\n", code));
585 cebix 1.1 switch (code) {
586    
587 cebix 1.9 case cscGetMode: // Get current color depth
588     D(bug(" GetMode -> %04x, base %08x\n", VidLocal.current_mode, VidLocal.desc->mac_frame_base));
589     WriteMacInt16(param + csMode, VidLocal.current_mode);
590     WriteMacInt16(param + csPage, 0);
591     WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
592     return noErr;
593    
594 cebix 1.11 case cscGetEntries: { // Read palette
595     D(bug(" GetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart)));
596 cebix 1.9
597 cebix 1.11 uint8 *s_pal; // Source palette
598     uint32 d_pal = ReadMacInt32(param + csTable); // Destination palette
599     uint16 start = ReadMacInt16(param + csStart);
600     uint16 count = ReadMacInt16(param + csCount);
601     if (d_pal == 0 || count > 255)
602     return paramErr;
603    
604     if (start == 0xffff) { // Indexed
605     for (uint32 i=0; i<=count; i++) {
606     s_pal = VidLocal.palette + (ReadMacInt16(d_pal) & 0xff) * 3;
607     uint8 red = *s_pal++;
608     uint8 green = *s_pal++;
609     uint8 blue = *s_pal++;
610     WriteMacInt16(d_pal + 2, red * 0x0101);
611     WriteMacInt16(d_pal + 4, green * 0x0101);
612     WriteMacInt16(d_pal + 6, blue * 0x0101);
613     d_pal += 8;
614     }
615     } else { // Sequential
616     if (start + count > 255)
617     return paramErr;
618     s_pal = VidLocal.palette + start * 3;
619     for (uint32 i=0; i<=count; i++) {
620     uint8 red = *s_pal++;
621     uint8 green = *s_pal++;
622     uint8 blue = *s_pal++;
623     WriteMacInt16(d_pal + 2, red * 0x0101);
624     WriteMacInt16(d_pal + 4, green * 0x0101);
625     WriteMacInt16(d_pal + 6, blue * 0x0101);
626     d_pal += 8;
627     }
628     }
629     return noErr;
630     }
631    
632     case cscGetPages: // Get number of pages
633     D(bug(" GetPages -> 1\n"));
634 cebix 1.1 WriteMacInt16(param + csPage, 1);
635     return noErr;
636    
637 cebix 1.11 case cscGetBaseAddress: // Get page base address
638     D(bug(" GetBaseAddress -> %08x\n", VidLocal.desc->mac_frame_base));
639 cebix 1.1 WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
640 cebix 1.11 if (ReadMacInt16(param + csPage))
641     return paramErr;
642     else
643     return noErr;
644 cebix 1.1
645     case cscGetGray: // Get luminance mapping flag
646 cebix 1.9 D(bug(" GetGray -> %d\n", VidLocal.luminance_mapping));
647 cebix 1.11 WriteMacInt16(param, VidLocal.luminance_mapping ? 0x0100 : 0);
648 cebix 1.1 return noErr;
649    
650     case cscGetInterrupt: // Get interrupt disable flag
651 cebix 1.9 D(bug(" GetInterrupt -> %d\n", VidLocal.interrupts_enabled));
652 cebix 1.11 WriteMacInt16(param, VidLocal.interrupts_enabled ? 0 : 0x0100);
653 cebix 1.1 return noErr;
654    
655 cebix 1.11 case cscGetGamma:
656 cebix 1.14 D(bug(" GetGamma -> %08x\n", VidLocal.gamma_table));
657     WriteMacInt32(param + csGTable, VidLocal.gamma_table);
658     return noErr;
659 cebix 1.9
660     case cscGetDefaultMode: // Get default color depth
661     D(bug(" GetDefaultMode -> %04x\n", VidLocal.preferred_mode));
662     WriteMacInt16(param + csMode, VidLocal.preferred_mode);
663 cebix 1.1 return noErr;
664    
665 cebix 1.11 case cscGetCurrentMode: // Get current video mode (depth and resolution)
666     D(bug(" GetCurMode -> %04x/%08x, base %08x\n", VidLocal.current_mode, VidLocal.current_id, VidLocal.desc->mac_frame_base));
667 cebix 1.9 WriteMacInt16(param + csMode, VidLocal.current_mode);
668     WriteMacInt32(param + csData, VidLocal.current_id);
669 cebix 1.1 WriteMacInt16(param + csPage, 0);
670     WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
671     return noErr;
672    
673     case cscGetConnection: // Get monitor information
674     D(bug(" GetConnection\n"));
675 cebix 1.11 WriteMacInt16(param + csDisplayType, 8); // Modeless connection
676     WriteMacInt8(param + csConnectTaggedType, 0);
677     WriteMacInt8(param + csConnectTaggedData, 0);
678     WriteMacInt32(param + csConnectFlags, 0x43); // All modes valid and safe, non-standard tagging
679 cebix 1.1 WriteMacInt32(param + csDisplayComponent, 0);
680     return noErr;
681    
682 cebix 1.11 case cscGetModeTiming: { // Get video timing for specified resolution
683     uint32 id = ReadMacInt32(param + csTimingMode);
684     D(bug(" GetModeTiming %08x\n", id));
685     if (!has_resolution(id))
686     return paramErr;
687    
688     WriteMacInt32(param + csTimingFormat, FOURCC('d', 'e', 'c', 'l'));
689     WriteMacInt32(param + csTimingData, 0); // unknown
690     uint32 flags = 0xb; // mode valid, safe and shown in Monitors panel
691     if (id == VidLocal.preferred_id)
692     flags |= 4; // default mode
693     WriteMacInt32(param + csTimingFlags, flags);
694     return noErr;
695     }
696    
697 cebix 1.9 case cscGetModeBaseAddress: // Get frame buffer base address
698 cebix 1.11 D(bug(" GetModeBaseAddress -> base %08x\n", VidLocal.desc->mac_frame_base));
699     WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
700 cebix 1.1 return noErr;
701    
702 cebix 1.9 case cscGetPreferredConfiguration: // Get default video mode (depth and resolution)
703     D(bug(" GetPreferredConfiguration -> %04x/%08x\n", VidLocal.preferred_mode, VidLocal.preferred_id));
704     WriteMacInt16(param + csMode, VidLocal.preferred_mode);
705     WriteMacInt32(param + csData, VidLocal.preferred_id);
706     return noErr;
707    
708     case cscGetNextResolution: { // Called iteratively to obtain a list of all supported resolutions
709     uint32 id = ReadMacInt32(param + csPreviousDisplayModeID);
710     D(bug(" GetNextResolution %08x\n", id));
711    
712     switch (id) {
713     case 0:
714     // Return current resolution
715     id = VidLocal.current_id;
716     break;
717    
718     case 0xfffffffe:
719     // Return first supported resolution
720     id = 0x80;
721     while (!has_resolution(id))
722     id++;
723     break;
724    
725     default:
726     // Get next resolution
727     if (!has_resolution(id))
728     return paramErr;
729     id++;
730     while (!has_resolution(id) && id < 0x100)
731     id++;
732     if (id == 0x100) { // No more resolutions
733     WriteMacInt32(param + csRIDisplayModeID, 0xfffffffd);
734     return noErr;
735     }
736     break;
737     }
738    
739     WriteMacInt32(param + csRIDisplayModeID, id);
740     uint32 x, y;
741     get_size_of_resolution(id, x, y);
742     WriteMacInt32(param + csHorizontalPixels, x);
743     WriteMacInt32(param + csVerticalLines, y);
744     WriteMacInt32(param + csRefreshRate, 75 << 16);
745     WriteMacInt16(param + csMaxDepthMode, DepthToAppleMode(max_depth_of_resolution(id)));
746 jlachmann 1.5 return noErr;
747 cebix 1.9 }
748 jlachmann 1.5
749 cebix 1.9 case cscGetVideoParameters: { // Get information about specified resolution/depth
750     uint32 id = ReadMacInt32(param + csDisplayModeID);
751     uint16 mode = ReadMacInt16(param + csDepthMode);
752     D(bug(" GetVideoParameters %04x/%08x\n", mode, id));
753    
754 gbeauche 1.12 std::vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
755 cebix 1.9 while (i != end) {
756     if (DepthToAppleMode(i->depth) == mode && i->resolution_id == id) {
757     uint32 vp = ReadMacInt32(param + csVPBlockPtr);
758     WriteMacInt32(vp + vpBaseOffset, 0);
759     WriteMacInt16(vp + vpRowBytes, i->bytes_per_row);
760     WriteMacInt16(vp + vpBounds, 0);
761     WriteMacInt16(vp + vpBounds + 2, 0);
762     WriteMacInt16(vp + vpBounds + 4, i->y);
763     WriteMacInt16(vp + vpBounds + 6, i->x);
764     WriteMacInt16(vp + vpVersion, 0);
765     WriteMacInt16(vp + vpPackType, 0);
766     WriteMacInt32(vp + vpPackSize, 0);
767 cebix 1.11 WriteMacInt32(vp + vpHRes, 0x00480000); // 72 dpi
768 cebix 1.9 WriteMacInt32(vp + vpVRes, 0x00480000);
769     uint32 pix_type, pix_size, cmp_count, cmp_size, dev_type;
770     switch (i->depth) {
771     case VDEPTH_1BIT:
772     pix_type = 0; pix_size = 1;
773     cmp_count = 1; cmp_size = 1;
774     dev_type = 0; // CLUT
775     break;
776     case VDEPTH_2BIT:
777     pix_type = 0; pix_size = 2;
778     cmp_count = 1; cmp_size = 2;
779     dev_type = 0; // CLUT
780     break;
781     case VDEPTH_4BIT:
782     pix_type = 0; pix_size = 4;
783     cmp_count = 1; cmp_size = 4;
784     dev_type = 0; // CLUT
785     break;
786     case VDEPTH_8BIT:
787     pix_type = 0; pix_size = 8;
788     cmp_count = 1; cmp_size = 8;
789     dev_type = 0; // CLUT
790     break;
791     case VDEPTH_16BIT:
792     pix_type = 0x10; pix_size = 16;
793     cmp_count = 3; cmp_size = 5;
794     dev_type = 2; // direct
795     break;
796     case VDEPTH_32BIT:
797     pix_type = 0x10; pix_size = 32;
798     cmp_count = 3; cmp_size = 8;
799     dev_type = 2; // direct
800     break;
801     }
802     WriteMacInt16(vp + vpPixelType, pix_type);
803     WriteMacInt16(vp + vpPixelSize, pix_size);
804     WriteMacInt16(vp + vpCmpCount, cmp_count);
805     WriteMacInt16(vp + vpCmpSize, cmp_size);
806     WriteMacInt32(param + csPageCount, 1);
807     WriteMacInt32(param + csDeviceType, dev_type);
808     return noErr;
809     }
810     ++i;
811     }
812     return paramErr; // specified resolution/depth not supported
813     }
814 cebix 1.1
815     default:
816 cebix 1.2 printf("WARNING: Unknown VideoDriverStatus(%d)\n", code);
817 cebix 1.1 return statusErr;
818     }
819     }