ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/video.cpp
Revision: 1.14
Committed: 2001-06-30T17:21:51Z (23 years, 5 months ago) by cebix
Branch: MAIN
Changes since 1.13: +190 -22 lines
Log Message:
- experimental gamma table support
- restructured video_x.cpp: uses classes for display types

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     int inc = 256 / num, value = 0;
173     uint8 *p = VidLocal.palette;
174     for (int i=0; i<num; i++) {
175     uint8 red = value, green = value, blue = value;
176     if (have_gamma) {
177     red = red_gamma[red >> (8 - data_width)];
178     green = green_gamma[green >> (8 - data_width)];
179     blue = blue_gamma[blue >> (8 - data_width)];
180     }
181     *p++ = red;
182     *p++ = green;
183     *p++ = blue;
184     value += inc;
185     }
186    
187     video_set_palette(VidLocal.palette);
188     }
189    
190    
191     /*
192     * Allocate gamma table of specified size
193     */
194    
195     static bool allocate_gamma_table(int size)
196     {
197     M68kRegisters r;
198    
199     if (size > VidLocal.alloc_gamma_table_size) {
200     if (VidLocal.gamma_table) {
201     r.a[0] = VidLocal.gamma_table;
202     Execute68kTrap(0xa01f, &r); // DisposePtr()
203     VidLocal.gamma_table = 0;
204     VidLocal.alloc_gamma_table_size = 0;
205 cebix 1.11 }
206 cebix 1.14 r.d[0] = size;
207     Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
208     if (r.a[0] == 0)
209     return false;
210     VidLocal.gamma_table = r.a[0];
211     VidLocal.alloc_gamma_table_size = size;
212 cebix 1.11 }
213 cebix 1.14 return true;
214     }
215    
216    
217     /*
218     * Set gamma table (0 = build linear ramp)
219     */
220    
221     static bool set_gamma_table(uint32 user_table)
222     {
223     if (user_table == 0) { // Build linear ramp, 256 entries
224    
225     // Allocate new table, if necessary
226     if (!allocate_gamma_table(SIZEOF_GammaTbl + 256))
227     return memFullErr;
228     uint32 table = VidLocal.gamma_table;
229    
230     // Initialize header
231     WriteMacInt16(table + gVersion, 0);
232     WriteMacInt16(table + gType, 0);
233     WriteMacInt16(table + gFormulaSize, 0);
234     WriteMacInt16(table + gChanCnt, 1);
235     WriteMacInt16(table + gDataCnt, 256);
236     WriteMacInt16(table + gDataWidth, 8);
237    
238     // Build ramp
239     uint32 p = table + gFormulaData;
240     for (int i=0; i<256; i++)
241     WriteMacInt8(p + i, i);
242    
243     } else { // User-supplied gamma table
244    
245     // Validate header
246     if (ReadMacInt16(user_table + gVersion))
247     return paramErr;
248     if (ReadMacInt16(user_table + gType))
249     return paramErr;
250     int chan_cnt = ReadMacInt16(user_table + gChanCnt);
251     if (chan_cnt != 1 && chan_cnt != 3)
252     return paramErr;
253     int data_width = ReadMacInt16(user_table + gDataWidth);
254     if (data_width > 8)
255     return paramErr;
256     int data_cnt = ReadMacInt16(user_table + gDataCnt);
257     if (data_cnt != (1 << data_width))
258     return paramErr;
259    
260     // Allocate new table, if necessary
261     int size = SIZEOF_GammaTbl + ReadMacInt16(user_table + gFormulaSize) + chan_cnt * data_cnt;
262     if (!allocate_gamma_table(size))
263     return memFullErr;
264     uint32 table = VidLocal.gamma_table;
265    
266     // Copy table
267     Mac2Mac_memcpy(table, user_table, size);
268     }
269    
270     if (IsDirectMode(VidLocal.current_mode))
271     load_ramp_palette();
272    
273     return true;
274 cebix 1.11 }
275    
276    
277     /*
278 cebix 1.1 * Driver Open() routine
279     */
280    
281 cebix 1.2 int16 VideoDriverOpen(uint32 pb, uint32 dce)
282 cebix 1.1 {
283 cebix 1.2 D(bug("VideoDriverOpen\n"));
284 cebix 1.1
285 cebix 1.9 // This shouldn't happen unless the platform-specific video code is broken
286     if (VideoModes.empty())
287     fprintf(stderr, "No valid video modes found (broken video driver?)\n");
288    
289 cebix 1.1 // Init local variables
290     VidLocal.desc = &VideoMonitor;
291     VidLocal.luminance_mapping = false;
292     VidLocal.interrupts_enabled = false;
293 cebix 1.9 VidLocal.current_mode = DepthToAppleMode(VidLocal.desc->mode.depth);
294     VidLocal.current_id = VidLocal.desc->mode.resolution_id;
295     VidLocal.preferred_mode = VidLocal.current_mode;
296     VidLocal.preferred_id = VidLocal.current_id;
297 cebix 1.1
298 cebix 1.11 // Allocate Slot Manager parameter block in Mac RAM
299     M68kRegisters r;
300     r.d[0] = SIZEOF_SPBlock;
301     Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
302     if (r.a[0] == 0)
303     return memFullErr;
304     VidLocal.sp = r.a[0];
305     D(bug("SPBlock at %08x\n", VidLocal.sp));
306    
307     // Find and set default gamma table
308 cebix 1.14 VidLocal.gamma_table = 0;
309     VidLocal.alloc_gamma_table_size = 0;
310     set_gamma_table(0);
311 cebix 1.11
312 cebix 1.1 // Init color palette (solid gray)
313 cebix 1.11 set_gray_palette();
314 cebix 1.1 return noErr;
315     }
316    
317    
318     /*
319     * Driver Control() routine
320     */
321    
322 cebix 1.2 int16 VideoDriverControl(uint32 pb, uint32 dce)
323 cebix 1.1 {
324     uint16 code = ReadMacInt16(pb + csCode);
325     uint32 param = ReadMacInt32(pb + csParam);
326 cebix 1.2 D(bug("VideoDriverControl %d\n", code));
327 cebix 1.1 switch (code) {
328    
329 cebix 1.9 case cscSetMode: { // Set color depth
330     uint16 mode = ReadMacInt16(param + csMode);
331     D(bug(" SetMode %04x\n", mode));
332 cebix 1.10
333 cebix 1.11 // Set old base address in case the switch fails
334     WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
335    
336     if (ReadMacInt16(param + csPage))
337     return paramErr;
338    
339 cebix 1.10 if (mode != VidLocal.current_mode) {
340     std::vector<video_mode>::const_iterator i = find_mode(mode, VidLocal.current_id);
341 cebix 1.11 if (i == VideoModes.end())
342 cebix 1.10 return paramErr;
343 cebix 1.11 set_gray_palette();
344 cebix 1.10 video_switch_to_mode(*i);
345     VidLocal.current_mode = mode;
346 cebix 1.11 WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
347     WriteMacInt32(dce + dCtlDevBase, VidLocal.desc->mac_frame_base);
348 cebix 1.10 }
349 cebix 1.11 D(bug(" base %08x\n", VidLocal.desc->mac_frame_base));
350 cebix 1.10 return noErr;
351 cebix 1.9 }
352 cebix 1.1
353 cebix 1.14 case cscSetEntries: // Set palette
354     case cscDirectSetEntries: {
355     D(bug(" (Direct)SetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart)));
356     bool is_direct = IsDirectMode(VidLocal.current_mode);
357     if (code == cscSetEntries && is_direct)
358     return controlErr;
359     if (code == cscDirectSetEntries && !is_direct)
360 cebix 1.1 return controlErr;
361    
362     uint32 s_pal = ReadMacInt32(param + csTable); // Source palette
363     uint8 *d_pal; // Destination palette
364 cebix 1.11 uint16 start = ReadMacInt16(param + csStart);
365 cebix 1.1 uint16 count = ReadMacInt16(param + csCount);
366 cebix 1.11 if (s_pal == 0 || count > 255)
367 cebix 1.1 return paramErr;
368    
369 cebix 1.14 // Find tables for gamma correction
370     uint8 *red_gamma, *green_gamma, *blue_gamma;
371     bool have_gamma = false;
372     int data_width = 0;
373     if (VidLocal.gamma_table) {
374     uint32 table = VidLocal.gamma_table;
375     red_gamma = Mac2HostAddr(table + gFormulaData + ReadMacInt16(table + gFormulaSize));
376     int chan_cnt = ReadMacInt16(table + gChanCnt);
377     if (chan_cnt == 1)
378     green_gamma = blue_gamma = red_gamma;
379     else {
380     int ofs = ReadMacInt16(table + gDataCnt);
381     green_gamma = red_gamma + ofs;
382     blue_gamma = green_gamma + ofs;
383     }
384     data_width = ReadMacInt16(table + gDataWidth);
385     have_gamma = true;
386     }
387    
388     // Convert palette
389 cebix 1.11 if (start == 0xffff) { // Indexed
390 cebix 1.1 for (uint32 i=0; i<=count; i++) {
391 cebix 1.11 d_pal = VidLocal.palette + (ReadMacInt16(s_pal) & 0xff) * 3;
392 cebix 1.1 uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8;
393     uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8;
394     uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8;
395 cebix 1.14 if (VidLocal.luminance_mapping && !is_direct)
396 cebix 1.1 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
397 cebix 1.14 if (have_gamma) {
398     red = red_gamma[red >> (8 - data_width)];
399     green = green_gamma[green >> (8 - data_width)];
400     blue = blue_gamma[blue >> (8 - data_width)];
401     }
402 cebix 1.1 *d_pal++ = red;
403     *d_pal++ = green;
404     *d_pal++ = blue;
405     s_pal += 8;
406     }
407 cebix 1.11 } else { // Sequential
408     if (start + count > 255)
409     return paramErr;
410     d_pal = VidLocal.palette + start * 3;
411 cebix 1.1 for (uint32 i=0; i<=count; i++) {
412     uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8;
413     uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8;
414     uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8;
415 cebix 1.14 if (VidLocal.luminance_mapping && !is_direct)
416 cebix 1.1 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
417 cebix 1.14 if (have_gamma) {
418     red = red_gamma[red >> (8 - data_width)];
419     green = green_gamma[green >> (8 - data_width)];
420     blue = blue_gamma[blue >> (8 - data_width)];
421     }
422 cebix 1.1 *d_pal++ = red;
423     *d_pal++ = green;
424     *d_pal++ = blue;
425     s_pal += 8;
426     }
427     }
428     video_set_palette(VidLocal.palette);
429     return noErr;
430     }
431    
432 cebix 1.14 case cscSetGamma: { // Set gamma table
433     uint32 user_table = ReadMacInt32(param + csGTable);
434     D(bug(" SetGamma %08x\n", user_table));
435     return set_gamma_table(user_table) ? noErr : memFullErr;
436     }
437 cebix 1.1
438     case cscGrayPage: { // Fill page with dithered gray pattern
439     D(bug(" GrayPage %d\n", ReadMacInt16(param + csPage)));
440     if (ReadMacInt16(param + csPage))
441     return paramErr;
442    
443     uint32 pattern[6] = {
444     0xaaaaaaaa, // 1 bpp
445     0xcccccccc, // 2 bpp
446     0xf0f0f0f0, // 4 bpp
447     0xff00ff00, // 8 bpp
448     0xffff0000, // 16 bpp
449     0xffffffff // 32 bpp
450     };
451     uint32 p = VidLocal.desc->mac_frame_base;
452 cebix 1.9 uint32 pat = pattern[VidLocal.desc->mode.depth];
453 cebix 1.11 bool invert = (VidLocal.desc->mode.depth == VDEPTH_32BIT);
454 cebix 1.9 for (uint32 y=0; y<VidLocal.desc->mode.y; y++) {
455     for (uint32 x=0; x<VidLocal.desc->mode.bytes_per_row; x+=4) {
456 cebix 1.8 WriteMacInt32(p + x, pat);
457 cebix 1.11 if (invert)
458 cebix 1.1 pat = ~pat;
459     }
460 cebix 1.9 p += VidLocal.desc->mode.bytes_per_row;
461 cebix 1.1 pat = ~pat;
462     }
463 cebix 1.14
464     if (IsDirectMode(VidLocal.current_mode))
465     load_ramp_palette();
466    
467 cebix 1.1 return noErr;
468     }
469    
470     case cscSetGray: // Enable/disable luminance mapping
471     D(bug(" SetGray %02x\n", ReadMacInt8(param + csMode)));
472     VidLocal.luminance_mapping = ReadMacInt8(param + csMode);
473     return noErr;
474    
475     case cscSetInterrupt: // Enable/disable VBL
476     D(bug(" SetInterrupt %02x\n", ReadMacInt8(param + csMode)));
477     VidLocal.interrupts_enabled = (ReadMacInt8(param + csMode) == 0);
478     return noErr;
479    
480 cebix 1.9 case cscSetDefaultMode: { // Set default color depth
481     uint16 mode = ReadMacInt16(param + csMode);
482     D(bug(" SetDefaultMode %04x\n", mode));
483     VidLocal.preferred_mode = mode;
484     return noErr;
485     }
486    
487     case cscSwitchMode: { // Switch video mode (depth and resolution)
488     uint16 mode = ReadMacInt16(param + csMode);
489     uint32 id = ReadMacInt32(param + csData);
490     D(bug(" SwitchMode %04x, %08x\n", mode, id));
491 cebix 1.10
492 cebix 1.11 // Set old base address in case the switch fails
493     WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
494    
495     if (ReadMacInt16(param + csPage))
496     return paramErr;
497    
498 cebix 1.10 if (mode != VidLocal.current_mode || id != VidLocal.current_id) {
499     std::vector<video_mode>::const_iterator i = find_mode(mode, id);
500 cebix 1.11 if (i == VideoModes.end())
501 cebix 1.10 return paramErr;
502 cebix 1.11 set_gray_palette();
503 cebix 1.10 video_switch_to_mode(*i);
504     VidLocal.current_mode = mode;
505     VidLocal.current_id = id;
506 cebix 1.11 uint32 frame_base = VidLocal.desc->mac_frame_base;
507     WriteMacInt32(param + csBaseAddr, frame_base);
508    
509     M68kRegisters r;
510     uint32 sp = VidLocal.sp;
511     r.a[0] = sp;
512    
513     // Find functional sResource for this display
514     WriteMacInt8(sp + spSlot, ReadMacInt8(dce + dCtlSlot));
515     WriteMacInt8(sp + spID, ReadMacInt8(dce + dCtlSlotId));
516     WriteMacInt8(sp + spExtDev, 0);
517     r.d[0] = 0x0016;
518     Execute68kTrap(0xa06e, &r); // SRsrcInfo()
519     uint32 rsrc = ReadMacInt32(sp + spPointer);
520    
521 cebix 1.13 // Patch minorBase (otherwise rebooting won't work)
522 cebix 1.11 WriteMacInt8(sp + spID, 0x0a); // minorBase
523     r.d[0] = 0x0006;
524     Execute68kTrap(0xa06e, &r); // SFindStruct()
525     uint32 minor_base = ReadMacInt32(sp + spPointer) - ROMBaseMac;
526     ROMBaseHost[minor_base + 0] = frame_base >> 24;
527     ROMBaseHost[minor_base + 1] = frame_base >> 16;
528     ROMBaseHost[minor_base + 2] = frame_base >> 8;
529     ROMBaseHost[minor_base + 3] = frame_base;
530    
531     // Patch video mode parameter table
532     WriteMacInt32(sp + spPointer, rsrc);
533     WriteMacInt8(sp + spID, mode);
534     r.d[0] = 0x0006;
535     Execute68kTrap(0xa06e, &r); // SFindStruct()
536     WriteMacInt8(sp + spID, 0x01);
537     r.d[0] = 0x0006;
538     Execute68kTrap(0xa06e, &r); // SFindStruct()
539     uint32 p = ReadMacInt32(sp + spPointer) - ROMBaseMac;
540     ROMBaseHost[p + 8] = i->bytes_per_row >> 8;
541     ROMBaseHost[p + 9] = i->bytes_per_row;
542     ROMBaseHost[p + 14] = i->y >> 8;
543     ROMBaseHost[p + 15] = i->y;
544     ROMBaseHost[p + 16] = i->x >> 8;
545     ROMBaseHost[p + 17] = i->x;
546 cebix 1.13
547     // Recalculate slot ROM checksum
548     ChecksumSlotROM();
549 cebix 1.11
550     // Update sResource
551     WriteMacInt8(sp + spID, ReadMacInt8(dce + dCtlSlotId));
552     r.d[0] = 0x002b;
553     Execute68kTrap(0xa06e, &r); // SUpdateSRT()
554    
555     // Update frame buffer base in DCE
556     WriteMacInt32(dce + dCtlDevBase, frame_base);
557 cebix 1.10 }
558 cebix 1.11 D(bug(" base %08x\n", VidLocal.desc->mac_frame_base));
559 cebix 1.10 return noErr;
560 cebix 1.9 }
561    
562     case cscSavePreferredConfiguration: {
563     uint16 mode = ReadMacInt16(param + csMode);
564     uint32 id = ReadMacInt32(param + csData);
565     D(bug(" SavePreferredConfiguration %04x, %08x\n", mode, id));
566     VidLocal.preferred_mode = mode;
567     VidLocal.preferred_id = id;
568     return noErr;
569     }
570    
571 cebix 1.1 default:
572 cebix 1.2 printf("WARNING: Unknown VideoDriverControl(%d)\n", code);
573 cebix 1.1 return controlErr;
574     }
575     }
576    
577    
578     /*
579     * Driver Status() routine
580     */
581    
582 cebix 1.2 int16 VideoDriverStatus(uint32 pb, uint32 dce)
583 cebix 1.1 {
584     uint16 code = ReadMacInt16(pb + csCode);
585     uint32 param = ReadMacInt32(pb + csParam);
586 cebix 1.2 D(bug("VideoDriverStatus %d\n", code));
587 cebix 1.1 switch (code) {
588    
589 cebix 1.9 case cscGetMode: // Get current color depth
590     D(bug(" GetMode -> %04x, base %08x\n", VidLocal.current_mode, VidLocal.desc->mac_frame_base));
591     WriteMacInt16(param + csMode, VidLocal.current_mode);
592     WriteMacInt16(param + csPage, 0);
593     WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
594     return noErr;
595    
596 cebix 1.11 case cscGetEntries: { // Read palette
597     D(bug(" GetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart)));
598 cebix 1.9
599 cebix 1.11 uint8 *s_pal; // Source palette
600     uint32 d_pal = ReadMacInt32(param + csTable); // Destination palette
601     uint16 start = ReadMacInt16(param + csStart);
602     uint16 count = ReadMacInt16(param + csCount);
603     if (d_pal == 0 || count > 255)
604     return paramErr;
605    
606     if (start == 0xffff) { // Indexed
607     for (uint32 i=0; i<=count; i++) {
608     s_pal = VidLocal.palette + (ReadMacInt16(d_pal) & 0xff) * 3;
609     uint8 red = *s_pal++;
610     uint8 green = *s_pal++;
611     uint8 blue = *s_pal++;
612     WriteMacInt16(d_pal + 2, red * 0x0101);
613     WriteMacInt16(d_pal + 4, green * 0x0101);
614     WriteMacInt16(d_pal + 6, blue * 0x0101);
615     d_pal += 8;
616     }
617     } else { // Sequential
618     if (start + count > 255)
619     return paramErr;
620     s_pal = VidLocal.palette + start * 3;
621     for (uint32 i=0; i<=count; i++) {
622     uint8 red = *s_pal++;
623     uint8 green = *s_pal++;
624     uint8 blue = *s_pal++;
625     WriteMacInt16(d_pal + 2, red * 0x0101);
626     WriteMacInt16(d_pal + 4, green * 0x0101);
627     WriteMacInt16(d_pal + 6, blue * 0x0101);
628     d_pal += 8;
629     }
630     }
631     return noErr;
632     }
633    
634     case cscGetPages: // Get number of pages
635     D(bug(" GetPages -> 1\n"));
636 cebix 1.1 WriteMacInt16(param + csPage, 1);
637     return noErr;
638    
639 cebix 1.11 case cscGetBaseAddress: // Get page base address
640     D(bug(" GetBaseAddress -> %08x\n", VidLocal.desc->mac_frame_base));
641 cebix 1.1 WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
642 cebix 1.11 if (ReadMacInt16(param + csPage))
643     return paramErr;
644     else
645     return noErr;
646 cebix 1.1
647     case cscGetGray: // Get luminance mapping flag
648 cebix 1.9 D(bug(" GetGray -> %d\n", VidLocal.luminance_mapping));
649 cebix 1.11 WriteMacInt16(param, VidLocal.luminance_mapping ? 0x0100 : 0);
650 cebix 1.1 return noErr;
651    
652     case cscGetInterrupt: // Get interrupt disable flag
653 cebix 1.9 D(bug(" GetInterrupt -> %d\n", VidLocal.interrupts_enabled));
654 cebix 1.11 WriteMacInt16(param, VidLocal.interrupts_enabled ? 0 : 0x0100);
655 cebix 1.1 return noErr;
656    
657 cebix 1.11 case cscGetGamma:
658 cebix 1.14 D(bug(" GetGamma -> %08x\n", VidLocal.gamma_table));
659     WriteMacInt32(param + csGTable, VidLocal.gamma_table);
660     return noErr;
661 cebix 1.9
662     case cscGetDefaultMode: // Get default color depth
663     D(bug(" GetDefaultMode -> %04x\n", VidLocal.preferred_mode));
664     WriteMacInt16(param + csMode, VidLocal.preferred_mode);
665 cebix 1.1 return noErr;
666    
667 cebix 1.11 case cscGetCurrentMode: // Get current video mode (depth and resolution)
668     D(bug(" GetCurMode -> %04x/%08x, base %08x\n", VidLocal.current_mode, VidLocal.current_id, VidLocal.desc->mac_frame_base));
669 cebix 1.9 WriteMacInt16(param + csMode, VidLocal.current_mode);
670     WriteMacInt32(param + csData, VidLocal.current_id);
671 cebix 1.1 WriteMacInt16(param + csPage, 0);
672     WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
673     return noErr;
674    
675     case cscGetConnection: // Get monitor information
676     D(bug(" GetConnection\n"));
677 cebix 1.11 WriteMacInt16(param + csDisplayType, 8); // Modeless connection
678     WriteMacInt8(param + csConnectTaggedType, 0);
679     WriteMacInt8(param + csConnectTaggedData, 0);
680     WriteMacInt32(param + csConnectFlags, 0x43); // All modes valid and safe, non-standard tagging
681 cebix 1.1 WriteMacInt32(param + csDisplayComponent, 0);
682     return noErr;
683    
684 cebix 1.11 case cscGetModeTiming: { // Get video timing for specified resolution
685     uint32 id = ReadMacInt32(param + csTimingMode);
686     D(bug(" GetModeTiming %08x\n", id));
687     if (!has_resolution(id))
688     return paramErr;
689    
690     WriteMacInt32(param + csTimingFormat, FOURCC('d', 'e', 'c', 'l'));
691     WriteMacInt32(param + csTimingData, 0); // unknown
692     uint32 flags = 0xb; // mode valid, safe and shown in Monitors panel
693     if (id == VidLocal.preferred_id)
694     flags |= 4; // default mode
695     WriteMacInt32(param + csTimingFlags, flags);
696     return noErr;
697     }
698    
699 cebix 1.9 case cscGetModeBaseAddress: // Get frame buffer base address
700 cebix 1.11 D(bug(" GetModeBaseAddress -> base %08x\n", VidLocal.desc->mac_frame_base));
701     WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base);
702 cebix 1.1 return noErr;
703    
704 cebix 1.9 case cscGetPreferredConfiguration: // Get default video mode (depth and resolution)
705     D(bug(" GetPreferredConfiguration -> %04x/%08x\n", VidLocal.preferred_mode, VidLocal.preferred_id));
706     WriteMacInt16(param + csMode, VidLocal.preferred_mode);
707     WriteMacInt32(param + csData, VidLocal.preferred_id);
708     return noErr;
709    
710     case cscGetNextResolution: { // Called iteratively to obtain a list of all supported resolutions
711     uint32 id = ReadMacInt32(param + csPreviousDisplayModeID);
712     D(bug(" GetNextResolution %08x\n", id));
713    
714     switch (id) {
715     case 0:
716     // Return current resolution
717     id = VidLocal.current_id;
718     break;
719    
720     case 0xfffffffe:
721     // Return first supported resolution
722     id = 0x80;
723     while (!has_resolution(id))
724     id++;
725     break;
726    
727     default:
728     // Get next resolution
729     if (!has_resolution(id))
730     return paramErr;
731     id++;
732     while (!has_resolution(id) && id < 0x100)
733     id++;
734     if (id == 0x100) { // No more resolutions
735     WriteMacInt32(param + csRIDisplayModeID, 0xfffffffd);
736     return noErr;
737     }
738     break;
739     }
740    
741     WriteMacInt32(param + csRIDisplayModeID, id);
742     uint32 x, y;
743     get_size_of_resolution(id, x, y);
744     WriteMacInt32(param + csHorizontalPixels, x);
745     WriteMacInt32(param + csVerticalLines, y);
746     WriteMacInt32(param + csRefreshRate, 75 << 16);
747     WriteMacInt16(param + csMaxDepthMode, DepthToAppleMode(max_depth_of_resolution(id)));
748 jlachmann 1.5 return noErr;
749 cebix 1.9 }
750 jlachmann 1.5
751 cebix 1.9 case cscGetVideoParameters: { // Get information about specified resolution/depth
752     uint32 id = ReadMacInt32(param + csDisplayModeID);
753     uint16 mode = ReadMacInt16(param + csDepthMode);
754     D(bug(" GetVideoParameters %04x/%08x\n", mode, id));
755    
756 gbeauche 1.12 std::vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
757 cebix 1.9 while (i != end) {
758     if (DepthToAppleMode(i->depth) == mode && i->resolution_id == id) {
759     uint32 vp = ReadMacInt32(param + csVPBlockPtr);
760     WriteMacInt32(vp + vpBaseOffset, 0);
761     WriteMacInt16(vp + vpRowBytes, i->bytes_per_row);
762     WriteMacInt16(vp + vpBounds, 0);
763     WriteMacInt16(vp + vpBounds + 2, 0);
764     WriteMacInt16(vp + vpBounds + 4, i->y);
765     WriteMacInt16(vp + vpBounds + 6, i->x);
766     WriteMacInt16(vp + vpVersion, 0);
767     WriteMacInt16(vp + vpPackType, 0);
768     WriteMacInt32(vp + vpPackSize, 0);
769 cebix 1.11 WriteMacInt32(vp + vpHRes, 0x00480000); // 72 dpi
770 cebix 1.9 WriteMacInt32(vp + vpVRes, 0x00480000);
771     uint32 pix_type, pix_size, cmp_count, cmp_size, dev_type;
772     switch (i->depth) {
773     case VDEPTH_1BIT:
774     pix_type = 0; pix_size = 1;
775     cmp_count = 1; cmp_size = 1;
776     dev_type = 0; // CLUT
777     break;
778     case VDEPTH_2BIT:
779     pix_type = 0; pix_size = 2;
780     cmp_count = 1; cmp_size = 2;
781     dev_type = 0; // CLUT
782     break;
783     case VDEPTH_4BIT:
784     pix_type = 0; pix_size = 4;
785     cmp_count = 1; cmp_size = 4;
786     dev_type = 0; // CLUT
787     break;
788     case VDEPTH_8BIT:
789     pix_type = 0; pix_size = 8;
790     cmp_count = 1; cmp_size = 8;
791     dev_type = 0; // CLUT
792     break;
793     case VDEPTH_16BIT:
794     pix_type = 0x10; pix_size = 16;
795     cmp_count = 3; cmp_size = 5;
796     dev_type = 2; // direct
797     break;
798     case VDEPTH_32BIT:
799     pix_type = 0x10; pix_size = 32;
800     cmp_count = 3; cmp_size = 8;
801     dev_type = 2; // direct
802     break;
803     }
804     WriteMacInt16(vp + vpPixelType, pix_type);
805     WriteMacInt16(vp + vpPixelSize, pix_size);
806     WriteMacInt16(vp + vpCmpCount, cmp_count);
807     WriteMacInt16(vp + vpCmpSize, cmp_size);
808     WriteMacInt32(param + csPageCount, 1);
809     WriteMacInt32(param + csDeviceType, dev_type);
810     return noErr;
811     }
812     ++i;
813     }
814     return paramErr; // specified resolution/depth not supported
815     }
816 cebix 1.1
817     default:
818 cebix 1.2 printf("WARNING: Unknown VideoDriverStatus(%d)\n", code);
819 cebix 1.1 return statusErr;
820     }
821     }