ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/video.cpp
Revision: 1.25
Committed: 2002-04-25T11:00:30Z (22 years ago) by cebix
Branch: MAIN
Changes since 1.24: +261 -229 lines
Log Message:
- added infrastructure for multi-monitor support; only video_x.cpp is
  converted for the new scheme; not actually tested with a mult-monitor
  setup yet but at least single-monitor display doesn't seem to be broken
  (UAE banked addressing would definitely require some extensions to handle
  multiple frame buffers)
- struct video_mode has an extra field that is free for use by platform-
  specific code

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * video.cpp - Video/graphics emulation
3     *
4 cebix 1.24 * Basilisk II (C) 1997-2002 Christian Bauer
5     * Portions written by Marc Hellwig
6 cebix 1.1 *
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 cebix 1.22 * Designing PCI Cards and Drivers for Power Macintosh Computers
27     * Display Device Driver Guide
28 cebix 1.1 */
29    
30     #include <stdio.h>
31    
32     #include "sysdeps.h"
33     #include "cpu_emulation.h"
34     #include "main.h"
35     #include "macos_util.h"
36 cebix 1.13 #include "slot_rom.h"
37 cebix 1.1 #include "video.h"
38     #include "video_defs.h"
39    
40 cebix 1.11 #define DEBUG 0
41 cebix 1.1 #include "debug.h"
42    
43    
44 cebix 1.25 // Next available NuBus slot ID
45     uint8 monitor_desc::next_slot_id = 0x80;
46 cebix 1.9
47 cebix 1.25 // Vector of pointers to available monitor descriptions, filled by VideoInit()
48     vector<monitor_desc *> VideoMonitors;
49 cebix 1.1
50 cebix 1.20
51 cebix 1.25 /*
52     * Find palette size for given color depth
53     */
54    
55     static int palette_size(video_depth depth)
56     {
57     switch (depth) {
58     case VDEPTH_1BIT: return 2;
59     case VDEPTH_2BIT: return 4;
60     case VDEPTH_4BIT: return 16;
61     case VDEPTH_8BIT: return 256;
62     case VDEPTH_16BIT: return 32;
63     case VDEPTH_32BIT: return 256;
64     default: return 0;
65     }
66     }
67 cebix 1.1
68    
69     /*
70 cebix 1.25 * Find pointer to monitor_desc for given slot ID (or NULL if not found)
71 cebix 1.20 */
72    
73 cebix 1.25 static monitor_desc *find_monitor(uint8 id)
74 cebix 1.20 {
75 cebix 1.25 vector<monitor_desc *>::const_iterator i, end = VideoMonitors.end();
76     for (i = VideoMonitors.begin(); i != end; ++i) {
77     if ((*i)->get_slot_id() == id)
78     return *i;
79     }
80     return NULL;
81     }
82    
83    
84     /*
85     * monitor_desc constructor
86     */
87    
88     monitor_desc::monitor_desc(const vector<video_mode> &available_modes, video_depth default_depth, uint32 default_id) : modes(available_modes)
89     {
90     // Assign the next slot ID on construction
91     slot_id = next_slot_id++;
92    
93     // Initialize Apple mode list
94 cebix 1.20 uint16 mode = 0x80;
95     for (int depth = VDEPTH_1BIT; depth <= VDEPTH_32BIT; depth++) {
96 cebix 1.25 if (has_depth(video_depth(depth)))
97 cebix 1.20 apple_mode_for_depth[depth] = mode++;
98     else
99     apple_mode_for_depth[depth] = 0;
100     }
101 cebix 1.25
102     // Set default mode
103     current_mode = find_mode(depth_to_apple_mode(default_depth), default_id);
104 cebix 1.20 }
105    
106    
107     /*
108 cebix 1.25 * Get bytes-per-row value for specified resolution/depth
109     * (if the mode isn't supported, make a good guess)
110 cebix 1.20 */
111    
112 cebix 1.25 uint32 monitor_desc::get_bytes_per_row(video_depth depth, uint32 id) const
113 cebix 1.20 {
114 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
115     for (i = modes.begin(); i != end; ++i) {
116     if (i->depth == depth && i->resolution_id == id)
117     return i->bytes_per_row;
118     }
119     uint32 x, y;
120     get_size_of_resolution(id, x, y);
121     return TrivialBytesPerRow(x, depth);
122     }
123    
124    
125     /*
126     * Check whether a mode with the specified depth exists on this display
127     */
128    
129     bool monitor_desc::has_depth(video_depth depth) const
130     {
131     vector<video_mode>::const_iterator i = modes.begin(), end = modes.end();
132 cebix 1.20 while (i != end) {
133     if (i->depth == depth)
134     return true;
135     ++i;
136     }
137     return false;
138     }
139    
140    
141     /*
142 cebix 1.25 * Check whether the specified resolution ID is one of the supported resolutions
143 cebix 1.9 */
144    
145 cebix 1.25 bool monitor_desc::has_resolution(uint32 id) const
146 cebix 1.9 {
147 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
148     for (i = modes.begin(); i != end; ++i) {
149 cebix 1.9 if (i->resolution_id == id)
150     return true;
151     }
152     return false;
153     }
154    
155    
156     /*
157 cebix 1.25 * Find specified mode (depth/resolution) (or invalid_mode() if not found)
158 cebix 1.10 */
159    
160 cebix 1.25 vector<video_mode>::const_iterator monitor_desc::find_mode(uint16 apple_mode, uint32 id) const
161 cebix 1.10 {
162 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
163     for (i = modes.begin(); i != end; ++i) {
164     if (i->resolution_id == id && depth_to_apple_mode(i->depth) == apple_mode)
165 cebix 1.10 return i;
166     }
167     return i;
168     }
169    
170    
171     /*
172 cebix 1.9 * Find maximum supported depth for given resolution ID
173     */
174    
175 cebix 1.25 video_depth monitor_desc::max_depth_of_resolution(uint32 id) const
176 cebix 1.9 {
177     video_depth m = VDEPTH_1BIT;
178 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
179     for (i = modes.begin(); i != end; ++i) {
180 cebix 1.9 if (i->depth > m)
181     m = i->depth;
182     }
183     return m;
184     }
185    
186    
187     /*
188     * Get X/Y size of specified resolution
189     */
190    
191 cebix 1.25 void monitor_desc::get_size_of_resolution(uint32 id, uint32 &x, uint32 &y) const
192 cebix 1.9 {
193 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
194     for (i = modes.begin(); i != end; ++i) {
195 cebix 1.9 if (i->resolution_id == id) {
196     x = i->x;
197     y = i->y;
198     return;
199     }
200     }
201 cebix 1.20 x = y = 0;
202     }
203    
204    
205     /*
206 cebix 1.11 * Set palette to 50% gray
207     */
208    
209 cebix 1.25 void monitor_desc::set_gray_palette(void)
210 cebix 1.11 {
211 cebix 1.14 for (int i=0; i<256; i++) {
212 cebix 1.25 palette[i * 3 + 0] = 127;
213     palette[i * 3 + 1] = 127;
214     palette[i * 3 + 2] = 127;
215 cebix 1.14 }
216 cebix 1.25 set_palette(palette, 256);
217 cebix 1.14 }
218    
219    
220     /*
221     * Load gamma-corrected black-to-white ramp to palette for direct-color mode
222     */
223    
224 cebix 1.25 void monitor_desc::load_ramp_palette(void)
225 cebix 1.14 {
226     // Find tables for gamma correction
227 cebix 1.23 uint8 *red_gamma = NULL, *green_gamma = NULL, *blue_gamma = NULL;
228 cebix 1.14 bool have_gamma = false;
229     int data_width = 0;
230 cebix 1.25 if (gamma_table) {
231     uint32 table = gamma_table;
232 cebix 1.14 red_gamma = Mac2HostAddr(table + gFormulaData + ReadMacInt16(table + gFormulaSize));
233     int chan_cnt = ReadMacInt16(table + gChanCnt);
234     if (chan_cnt == 1)
235     green_gamma = blue_gamma = red_gamma;
236     else {
237     int ofs = ReadMacInt16(table + gDataCnt);
238     green_gamma = red_gamma + ofs;
239     blue_gamma = green_gamma + ofs;
240     }
241     data_width = ReadMacInt16(table + gDataWidth);
242     have_gamma = true;
243     }
244    
245 cebix 1.25 int num = (current_mode->depth == VDEPTH_16BIT ? 32 : 256);
246     uint8 *p = palette;
247 cebix 1.14 for (int i=0; i<num; i++) {
248 cebix 1.15 uint8 red = (i * 256 / num), green = red, blue = red;
249 cebix 1.14 if (have_gamma) {
250     red = red_gamma[red >> (8 - data_width)];
251     green = green_gamma[green >> (8 - data_width)];
252     blue = blue_gamma[blue >> (8 - data_width)];
253     }
254     *p++ = red;
255     *p++ = green;
256     *p++ = blue;
257     }
258    
259 cebix 1.25 set_palette(palette, num);
260 cebix 1.14 }
261    
262    
263     /*
264     * Allocate gamma table of specified size
265     */
266    
267 cebix 1.25 bool monitor_desc::allocate_gamma_table(int size)
268 cebix 1.14 {
269     M68kRegisters r;
270    
271 cebix 1.25 if (size > alloc_gamma_table_size) {
272     if (gamma_table) {
273     r.a[0] = gamma_table;
274 cebix 1.14 Execute68kTrap(0xa01f, &r); // DisposePtr()
275 cebix 1.25 gamma_table = 0;
276     alloc_gamma_table_size = 0;
277 cebix 1.11 }
278 cebix 1.14 r.d[0] = size;
279     Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
280     if (r.a[0] == 0)
281     return false;
282 cebix 1.25 gamma_table = r.a[0];
283     alloc_gamma_table_size = size;
284 cebix 1.11 }
285 cebix 1.14 return true;
286     }
287    
288    
289     /*
290     * Set gamma table (0 = build linear ramp)
291     */
292    
293 cebix 1.25 bool monitor_desc::set_gamma_table(uint32 user_table)
294 cebix 1.14 {
295     if (user_table == 0) { // Build linear ramp, 256 entries
296    
297     // Allocate new table, if necessary
298     if (!allocate_gamma_table(SIZEOF_GammaTbl + 256))
299     return memFullErr;
300    
301     // Initialize header
302 cebix 1.25 WriteMacInt16(gamma_table + gVersion, 0);
303     WriteMacInt16(gamma_table + gType, 0);
304     WriteMacInt16(gamma_table + gFormulaSize, 0);
305     WriteMacInt16(gamma_table + gChanCnt, 1);
306     WriteMacInt16(gamma_table + gDataCnt, 256);
307     WriteMacInt16(gamma_table + gDataWidth, 8);
308 cebix 1.14
309     // Build ramp
310 cebix 1.25 uint32 p = gamma_table + gFormulaData;
311 cebix 1.14 for (int i=0; i<256; i++)
312     WriteMacInt8(p + i, i);
313    
314     } else { // User-supplied gamma table
315    
316     // Validate header
317     if (ReadMacInt16(user_table + gVersion))
318     return paramErr;
319     if (ReadMacInt16(user_table + gType))
320     return paramErr;
321     int chan_cnt = ReadMacInt16(user_table + gChanCnt);
322     if (chan_cnt != 1 && chan_cnt != 3)
323     return paramErr;
324     int data_width = ReadMacInt16(user_table + gDataWidth);
325     if (data_width > 8)
326     return paramErr;
327     int data_cnt = ReadMacInt16(user_table + gDataCnt);
328     if (data_cnt != (1 << data_width))
329     return paramErr;
330    
331     // Allocate new table, if necessary
332     int size = SIZEOF_GammaTbl + ReadMacInt16(user_table + gFormulaSize) + chan_cnt * data_cnt;
333     if (!allocate_gamma_table(size))
334     return memFullErr;
335    
336     // Copy table
337 cebix 1.25 Mac2Mac_memcpy(gamma_table, user_table, size);
338 cebix 1.14 }
339    
340 cebix 1.25 if (IsDirectMode(*current_mode))
341 cebix 1.14 load_ramp_palette();
342    
343     return true;
344 cebix 1.11 }
345    
346    
347     /*
348 cebix 1.18 * Switch video mode
349     */
350    
351 cebix 1.25 void monitor_desc::switch_mode(vector<video_mode>::const_iterator it, uint32 param, uint32 dce)
352 cebix 1.18 {
353 cebix 1.25 const video_mode &mode = *it;
354    
355 cebix 1.18 // Switch mode
356     set_gray_palette();
357 cebix 1.25 current_mode = it;
358     switch_to_current_mode();
359 cebix 1.18
360 cebix 1.25 // Update variables
361     current_apple_mode = depth_to_apple_mode(mode.depth);
362     current_id = mode.resolution_id;
363 cebix 1.18
364     M68kRegisters r;
365 cebix 1.25 r.a[0] = slot_param;
366 cebix 1.18
367     // Find functional sResource for this display
368 cebix 1.25 WriteMacInt8(slot_param + spSlot, ReadMacInt8(dce + dCtlSlot));
369     WriteMacInt8(slot_param + spID, ReadMacInt8(dce + dCtlSlotId));
370     WriteMacInt8(slot_param + spExtDev, 0);
371 cebix 1.18 r.d[0] = 0x0016;
372     Execute68kTrap(0xa06e, &r); // SRsrcInfo()
373 cebix 1.25 uint32 rsrc = ReadMacInt32(slot_param + spPointer);
374 cebix 1.18
375     // Patch minorBase (otherwise rebooting won't work)
376 cebix 1.25 WriteMacInt8(slot_param + spID, 0x0a); // minorBase
377 cebix 1.18 r.d[0] = 0x0006;
378     Execute68kTrap(0xa06e, &r); // SFindStruct()
379 cebix 1.25 uint32 minor_base = ReadMacInt32(slot_param + spPointer) - ROMBaseMac;
380     ROMBaseHost[minor_base + 0] = mac_frame_base >> 24;
381     ROMBaseHost[minor_base + 1] = mac_frame_base >> 16;
382     ROMBaseHost[minor_base + 2] = mac_frame_base >> 8;
383     ROMBaseHost[minor_base + 3] = mac_frame_base;
384 cebix 1.18
385     // Patch video mode parameter table
386 cebix 1.25 WriteMacInt32(slot_param + spPointer, rsrc);
387     WriteMacInt8(slot_param + spID, depth_to_apple_mode(mode.depth));
388 cebix 1.18 r.d[0] = 0x0006;
389     Execute68kTrap(0xa06e, &r); // SFindStruct()
390 cebix 1.25 WriteMacInt8(slot_param + spID, 0x01);
391 cebix 1.18 r.d[0] = 0x0006;
392     Execute68kTrap(0xa06e, &r); // SFindStruct()
393 cebix 1.25 uint32 p = ReadMacInt32(slot_param + spPointer) - ROMBaseMac;
394 cebix 1.18 ROMBaseHost[p + 8] = mode.bytes_per_row >> 8;
395     ROMBaseHost[p + 9] = mode.bytes_per_row;
396     ROMBaseHost[p + 14] = mode.y >> 8;
397     ROMBaseHost[p + 15] = mode.y;
398     ROMBaseHost[p + 16] = mode.x >> 8;
399     ROMBaseHost[p + 17] = mode.x;
400    
401     // Recalculate slot ROM checksum
402     ChecksumSlotROM();
403    
404     // Update sResource
405 cebix 1.25 WriteMacInt8(slot_param + spID, ReadMacInt8(dce + dCtlSlotId));
406 cebix 1.18 r.d[0] = 0x002b;
407     Execute68kTrap(0xa06e, &r); // SUpdateSRT()
408    
409     // Update frame buffer base in DCE and param block
410 cebix 1.25 WriteMacInt32(dce + dCtlDevBase, mac_frame_base);
411     WriteMacInt32(param + csBaseAddr, mac_frame_base);
412 cebix 1.20
413     // Patch frame buffer base address for MacOS versions <7.6
414 cebix 1.25 if (!dm_present) { // Only do this when no Display Manager seems to be present; otherwise, the screen will not get redrawn
415     D(bug("No Display Manager, patching frame buffer base\n"));
416     WriteMacInt32(0x824, mac_frame_base); // ScrnBase
417     WriteMacInt32(0x898, mac_frame_base); // CrsrBase
418 cebix 1.20 uint32 gdev = ReadMacInt32(0x8a4); // MainDevice
419     gdev = ReadMacInt32(gdev);
420     uint32 pmap = ReadMacInt32(gdev + 0x16); // gdPMap
421     pmap = ReadMacInt32(pmap);
422 cebix 1.25 WriteMacInt32(pmap, mac_frame_base); // baseAddr
423 cebix 1.20 }
424 cebix 1.18 }
425    
426    
427     /*
428 cebix 1.1 * Driver Open() routine
429     */
430    
431 cebix 1.25 int16 monitor_desc::driver_open(void)
432 cebix 1.1 {
433 cebix 1.9 // This shouldn't happen unless the platform-specific video code is broken
434 cebix 1.25 if (modes.empty())
435 cebix 1.9 fprintf(stderr, "No valid video modes found (broken video driver?)\n");
436    
437 cebix 1.1 // Init local variables
438 cebix 1.25 luminance_mapping = false;
439     interrupts_enabled = false;
440     current_apple_mode = preferred_apple_mode = depth_to_apple_mode(current_mode->depth);
441     current_id = preferred_id = current_mode->resolution_id;
442     dm_present = false;
443 cebix 1.1
444 cebix 1.11 // Allocate Slot Manager parameter block in Mac RAM
445     M68kRegisters r;
446     r.d[0] = SIZEOF_SPBlock;
447     Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
448     if (r.a[0] == 0)
449     return memFullErr;
450 cebix 1.25 slot_param = r.a[0];
451     D(bug("SPBlock at %08x\n", slot_param));
452 cebix 1.11
453     // Find and set default gamma table
454 cebix 1.25 gamma_table = 0;
455     alloc_gamma_table_size = 0;
456 cebix 1.14 set_gamma_table(0);
457 cebix 1.11
458 cebix 1.1 // Init color palette (solid gray)
459 cebix 1.11 set_gray_palette();
460 cebix 1.1 return noErr;
461     }
462    
463 cebix 1.25 int16 VideoDriverOpen(uint32 pb, uint32 dce)
464     {
465     uint8 slot_id = ReadMacInt8(dce + dCtlSlotId);
466     D(bug("VideoDriverOpen slot %02x\n", slot_id));
467    
468     monitor_desc *m = find_monitor(slot_id);
469     if (m)
470     return m->driver_open();
471     else
472     return nsDrvErr;
473     }
474    
475 cebix 1.1
476     /*
477     * Driver Control() routine
478     */
479    
480 cebix 1.25 int16 monitor_desc::driver_control(uint16 code, uint32 param, uint32 dce)
481 cebix 1.1 {
482     switch (code) {
483    
484 cebix 1.9 case cscSetMode: { // Set color depth
485     uint16 mode = ReadMacInt16(param + csMode);
486     D(bug(" SetMode %04x\n", mode));
487 cebix 1.10
488 cebix 1.11 // Set old base address in case the switch fails
489 cebix 1.25 WriteMacInt32(param + csBaseAddr, mac_frame_base);
490 cebix 1.11
491     if (ReadMacInt16(param + csPage))
492     return paramErr;
493    
494 cebix 1.25 if (mode != current_apple_mode) {
495     vector<video_mode>::const_iterator i = find_mode(mode, current_id);
496     if (i == invalid_mode())
497 cebix 1.10 return paramErr;
498 cebix 1.25 switch_mode(i, param, dce);
499 cebix 1.10 }
500 cebix 1.25 D(bug(" base %08x\n", mac_frame_base));
501 cebix 1.10 return noErr;
502 cebix 1.9 }
503 cebix 1.1
504 cebix 1.14 case cscSetEntries: // Set palette
505     case cscDirectSetEntries: {
506     D(bug(" (Direct)SetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart)));
507 cebix 1.25 bool is_direct = IsDirectMode(*current_mode);
508 cebix 1.14 if (code == cscSetEntries && is_direct)
509     return controlErr;
510     if (code == cscDirectSetEntries && !is_direct)
511 cebix 1.1 return controlErr;
512    
513     uint32 s_pal = ReadMacInt32(param + csTable); // Source palette
514     uint8 *d_pal; // Destination palette
515 cebix 1.11 uint16 start = ReadMacInt16(param + csStart);
516 cebix 1.1 uint16 count = ReadMacInt16(param + csCount);
517 cebix 1.11 if (s_pal == 0 || count > 255)
518 cebix 1.1 return paramErr;
519    
520 cebix 1.14 // Find tables for gamma correction
521 cebix 1.23 uint8 *red_gamma = NULL, *green_gamma = NULL, *blue_gamma = NULL;
522 cebix 1.14 bool have_gamma = false;
523     int data_width = 0;
524 cebix 1.25 if (gamma_table) {
525     red_gamma = Mac2HostAddr(gamma_table + gFormulaData + ReadMacInt16(gamma_table + gFormulaSize));
526     int chan_cnt = ReadMacInt16(gamma_table + gChanCnt);
527 cebix 1.14 if (chan_cnt == 1)
528     green_gamma = blue_gamma = red_gamma;
529     else {
530 cebix 1.25 int ofs = ReadMacInt16(gamma_table + gDataCnt);
531 cebix 1.14 green_gamma = red_gamma + ofs;
532     blue_gamma = green_gamma + ofs;
533     }
534 cebix 1.25 data_width = ReadMacInt16(gamma_table + gDataWidth);
535 cebix 1.14 have_gamma = true;
536     }
537    
538     // Convert palette
539 cebix 1.11 if (start == 0xffff) { // Indexed
540 cebix 1.1 for (uint32 i=0; i<=count; i++) {
541 cebix 1.25 d_pal = palette + (ReadMacInt16(s_pal) & 0xff) * 3;
542 cebix 1.1 uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8;
543     uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8;
544     uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8;
545 cebix 1.25 if (luminance_mapping && !is_direct)
546 cebix 1.1 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
547 cebix 1.14 if (have_gamma) {
548     red = red_gamma[red >> (8 - data_width)];
549     green = green_gamma[green >> (8 - data_width)];
550     blue = blue_gamma[blue >> (8 - data_width)];
551     }
552 cebix 1.1 *d_pal++ = red;
553     *d_pal++ = green;
554     *d_pal++ = blue;
555     s_pal += 8;
556     }
557 cebix 1.11 } else { // Sequential
558     if (start + count > 255)
559     return paramErr;
560 cebix 1.25 d_pal = palette + start * 3;
561 cebix 1.1 for (uint32 i=0; i<=count; i++) {
562     uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8;
563     uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8;
564     uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8;
565 cebix 1.25 if (luminance_mapping && !is_direct)
566 cebix 1.1 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
567 cebix 1.14 if (have_gamma) {
568     red = red_gamma[red >> (8 - data_width)];
569     green = green_gamma[green >> (8 - data_width)];
570     blue = blue_gamma[blue >> (8 - data_width)];
571     }
572 cebix 1.1 *d_pal++ = red;
573     *d_pal++ = green;
574     *d_pal++ = blue;
575     s_pal += 8;
576     }
577     }
578 cebix 1.25 set_palette(palette, palette_size(current_mode->depth));
579 cebix 1.1 return noErr;
580     }
581    
582 cebix 1.14 case cscSetGamma: { // Set gamma table
583     uint32 user_table = ReadMacInt32(param + csGTable);
584     D(bug(" SetGamma %08x\n", user_table));
585     return set_gamma_table(user_table) ? noErr : memFullErr;
586     }
587 cebix 1.1
588     case cscGrayPage: { // Fill page with dithered gray pattern
589     D(bug(" GrayPage %d\n", ReadMacInt16(param + csPage)));
590     if (ReadMacInt16(param + csPage))
591     return paramErr;
592    
593     uint32 pattern[6] = {
594     0xaaaaaaaa, // 1 bpp
595     0xcccccccc, // 2 bpp
596     0xf0f0f0f0, // 4 bpp
597     0xff00ff00, // 8 bpp
598     0xffff0000, // 16 bpp
599     0xffffffff // 32 bpp
600     };
601 cebix 1.25 uint32 p = mac_frame_base;
602     uint32 pat = pattern[current_mode->depth];
603     bool invert = (current_mode->depth == VDEPTH_32BIT);
604     for (uint32 y=0; y<current_mode->y; y++) {
605     for (uint32 x=0; x<current_mode->bytes_per_row; x+=4) {
606     WriteMacInt32(p + x, pat);
607 cebix 1.11 if (invert)
608 cebix 1.1 pat = ~pat;
609     }
610 cebix 1.25 p += current_mode->bytes_per_row;
611 cebix 1.1 pat = ~pat;
612     }
613 cebix 1.14
614 cebix 1.25 if (IsDirectMode(*current_mode))
615 cebix 1.14 load_ramp_palette();
616    
617 cebix 1.1 return noErr;
618     }
619    
620     case cscSetGray: // Enable/disable luminance mapping
621     D(bug(" SetGray %02x\n", ReadMacInt8(param + csMode)));
622 cebix 1.25 luminance_mapping = ReadMacInt8(param + csMode);
623 cebix 1.1 return noErr;
624    
625     case cscSetInterrupt: // Enable/disable VBL
626     D(bug(" SetInterrupt %02x\n", ReadMacInt8(param + csMode)));
627 cebix 1.25 interrupts_enabled = (ReadMacInt8(param + csMode) == 0);
628 cebix 1.1 return noErr;
629    
630 cebix 1.9 case cscSetDefaultMode: { // Set default color depth
631 cebix 1.21 uint16 mode = ReadMacInt8(param + csMode);
632     D(bug(" SetDefaultMode %02x\n", mode));
633 cebix 1.25 preferred_apple_mode = mode;
634 cebix 1.9 return noErr;
635     }
636    
637     case cscSwitchMode: { // Switch video mode (depth and resolution)
638     uint16 mode = ReadMacInt16(param + csMode);
639     uint32 id = ReadMacInt32(param + csData);
640     D(bug(" SwitchMode %04x, %08x\n", mode, id));
641 cebix 1.10
642 cebix 1.11 // Set old base address in case the switch fails
643 cebix 1.25 WriteMacInt32(param + csBaseAddr, mac_frame_base);
644 cebix 1.11
645     if (ReadMacInt16(param + csPage))
646     return paramErr;
647    
648 cebix 1.25 if (mode != current_apple_mode || id != current_id) {
649 cebix 1.17 vector<video_mode>::const_iterator i = find_mode(mode, id);
650 cebix 1.25 if (i == invalid_mode())
651 cebix 1.10 return paramErr;
652 cebix 1.25 switch_mode(i, param, dce);
653 cebix 1.10 }
654 cebix 1.25 D(bug(" base %08x\n", mac_frame_base));
655 cebix 1.10 return noErr;
656 cebix 1.9 }
657    
658     case cscSavePreferredConfiguration: {
659     uint16 mode = ReadMacInt16(param + csMode);
660     uint32 id = ReadMacInt32(param + csData);
661     D(bug(" SavePreferredConfiguration %04x, %08x\n", mode, id));
662 cebix 1.25 preferred_apple_mode = mode;
663     preferred_id = id;
664 cebix 1.9 return noErr;
665     }
666    
667 cebix 1.1 default:
668 cebix 1.2 printf("WARNING: Unknown VideoDriverControl(%d)\n", code);
669 cebix 1.1 return controlErr;
670     }
671     }
672    
673 cebix 1.25 int16 VideoDriverControl(uint32 pb, uint32 dce)
674     {
675     uint8 slot_id = ReadMacInt8(dce + dCtlSlotId);
676     uint16 code = ReadMacInt16(pb + csCode);
677     uint32 param = ReadMacInt32(pb + csParam);
678     D(bug("VideoDriverControl slot %02x, code %d\n", slot_id, code));
679    
680     monitor_desc *m = find_monitor(slot_id);
681     if (m)
682     return m->driver_control(code, param, dce);
683     else
684     return nsDrvErr;
685     }
686    
687 cebix 1.1
688     /*
689     * Driver Status() routine
690     */
691    
692 cebix 1.25 int16 monitor_desc::driver_status(uint16 code, uint32 param)
693 cebix 1.1 {
694     switch (code) {
695    
696 cebix 1.9 case cscGetMode: // Get current color depth
697 cebix 1.25 D(bug(" GetMode -> %04x, base %08x\n", current_apple_mode, mac_frame_base));
698     WriteMacInt16(param + csMode, current_apple_mode);
699 cebix 1.9 WriteMacInt16(param + csPage, 0);
700 cebix 1.25 WriteMacInt32(param + csBaseAddr, mac_frame_base);
701 cebix 1.9 return noErr;
702    
703 cebix 1.11 case cscGetEntries: { // Read palette
704     D(bug(" GetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart)));
705 cebix 1.9
706 cebix 1.11 uint8 *s_pal; // Source palette
707     uint32 d_pal = ReadMacInt32(param + csTable); // Destination palette
708     uint16 start = ReadMacInt16(param + csStart);
709     uint16 count = ReadMacInt16(param + csCount);
710     if (d_pal == 0 || count > 255)
711     return paramErr;
712    
713     if (start == 0xffff) { // Indexed
714     for (uint32 i=0; i<=count; i++) {
715 cebix 1.25 s_pal = palette + (ReadMacInt16(d_pal) & 0xff) * 3;
716 cebix 1.11 uint8 red = *s_pal++;
717     uint8 green = *s_pal++;
718     uint8 blue = *s_pal++;
719     WriteMacInt16(d_pal + 2, red * 0x0101);
720     WriteMacInt16(d_pal + 4, green * 0x0101);
721     WriteMacInt16(d_pal + 6, blue * 0x0101);
722     d_pal += 8;
723     }
724     } else { // Sequential
725     if (start + count > 255)
726     return paramErr;
727 cebix 1.25 s_pal = palette + start * 3;
728 cebix 1.11 for (uint32 i=0; i<=count; i++) {
729     uint8 red = *s_pal++;
730     uint8 green = *s_pal++;
731     uint8 blue = *s_pal++;
732     WriteMacInt16(d_pal + 2, red * 0x0101);
733     WriteMacInt16(d_pal + 4, green * 0x0101);
734     WriteMacInt16(d_pal + 6, blue * 0x0101);
735     d_pal += 8;
736     }
737     }
738     return noErr;
739     }
740    
741     case cscGetPages: // Get number of pages
742     D(bug(" GetPages -> 1\n"));
743 cebix 1.1 WriteMacInt16(param + csPage, 1);
744     return noErr;
745    
746 cebix 1.11 case cscGetBaseAddress: // Get page base address
747 cebix 1.25 D(bug(" GetBaseAddress -> %08x\n", mac_frame_base));
748     WriteMacInt32(param + csBaseAddr, mac_frame_base);
749 cebix 1.11 if (ReadMacInt16(param + csPage))
750     return paramErr;
751     else
752     return noErr;
753 cebix 1.1
754     case cscGetGray: // Get luminance mapping flag
755 cebix 1.25 D(bug(" GetGray -> %d\n", luminance_mapping));
756     WriteMacInt8(param, luminance_mapping ? 1 : 0);
757 cebix 1.1 return noErr;
758    
759     case cscGetInterrupt: // Get interrupt disable flag
760 cebix 1.25 D(bug(" GetInterrupt -> %d\n", interrupts_enabled));
761     WriteMacInt8(param, interrupts_enabled ? 0 : 1);
762 cebix 1.1 return noErr;
763    
764 cebix 1.11 case cscGetGamma:
765 cebix 1.25 D(bug(" GetGamma -> %08x\n", gamma_table));
766     WriteMacInt32(param + csGTable, gamma_table);
767 cebix 1.14 return noErr;
768 cebix 1.9
769     case cscGetDefaultMode: // Get default color depth
770 cebix 1.25 D(bug(" GetDefaultMode -> %02x\n", preferred_apple_mode));
771     WriteMacInt8(param + csMode, preferred_apple_mode);
772 cebix 1.1 return noErr;
773    
774 cebix 1.11 case cscGetCurrentMode: // Get current video mode (depth and resolution)
775 cebix 1.25 D(bug(" GetCurMode -> %04x/%08x, base %08x\n", current_apple_mode, current_id, mac_frame_base));
776     WriteMacInt16(param + csMode, current_apple_mode);
777     WriteMacInt32(param + csData, current_id);
778 cebix 1.1 WriteMacInt16(param + csPage, 0);
779 cebix 1.25 WriteMacInt32(param + csBaseAddr, mac_frame_base);
780 cebix 1.1 return noErr;
781    
782     case cscGetConnection: // Get monitor information
783     D(bug(" GetConnection\n"));
784 cebix 1.11 WriteMacInt16(param + csDisplayType, 8); // Modeless connection
785     WriteMacInt8(param + csConnectTaggedType, 0);
786     WriteMacInt8(param + csConnectTaggedData, 0);
787     WriteMacInt32(param + csConnectFlags, 0x43); // All modes valid and safe, non-standard tagging
788 cebix 1.1 WriteMacInt32(param + csDisplayComponent, 0);
789     return noErr;
790    
791 cebix 1.11 case cscGetModeTiming: { // Get video timing for specified resolution
792     uint32 id = ReadMacInt32(param + csTimingMode);
793     D(bug(" GetModeTiming %08x\n", id));
794     if (!has_resolution(id))
795     return paramErr;
796    
797     WriteMacInt32(param + csTimingFormat, FOURCC('d', 'e', 'c', 'l'));
798     WriteMacInt32(param + csTimingData, 0); // unknown
799     uint32 flags = 0xb; // mode valid, safe and shown in Monitors panel
800 cebix 1.25 if (id == preferred_id)
801 cebix 1.11 flags |= 4; // default mode
802     WriteMacInt32(param + csTimingFlags, flags);
803     return noErr;
804     }
805    
806 cebix 1.9 case cscGetModeBaseAddress: // Get frame buffer base address
807 cebix 1.25 D(bug(" GetModeBaseAddress -> base %08x\n", mac_frame_base));
808     WriteMacInt32(param + csBaseAddr, mac_frame_base);
809 cebix 1.1 return noErr;
810    
811 cebix 1.9 case cscGetPreferredConfiguration: // Get default video mode (depth and resolution)
812 cebix 1.25 D(bug(" GetPreferredConfiguration -> %04x/%08x\n", preferred_apple_mode, preferred_id));
813     WriteMacInt16(param + csMode, preferred_apple_mode);
814     WriteMacInt32(param + csData, preferred_id);
815 cebix 1.9 return noErr;
816    
817     case cscGetNextResolution: { // Called iteratively to obtain a list of all supported resolutions
818     uint32 id = ReadMacInt32(param + csPreviousDisplayModeID);
819     D(bug(" GetNextResolution %08x\n", id));
820    
821     switch (id) {
822     case 0:
823     // Return current resolution
824 cebix 1.25 id = current_id;
825 cebix 1.9 break;
826    
827     case 0xfffffffe:
828     // Return first supported resolution
829     id = 0x80;
830     while (!has_resolution(id))
831     id++;
832     break;
833    
834     default:
835     // Get next resolution
836     if (!has_resolution(id))
837     return paramErr;
838     id++;
839     while (!has_resolution(id) && id < 0x100)
840     id++;
841     if (id == 0x100) { // No more resolutions
842     WriteMacInt32(param + csRIDisplayModeID, 0xfffffffd);
843     return noErr;
844     }
845     break;
846     }
847    
848     WriteMacInt32(param + csRIDisplayModeID, id);
849     uint32 x, y;
850     get_size_of_resolution(id, x, y);
851     WriteMacInt32(param + csHorizontalPixels, x);
852     WriteMacInt32(param + csVerticalLines, y);
853     WriteMacInt32(param + csRefreshRate, 75 << 16);
854 cebix 1.25 WriteMacInt16(param + csMaxDepthMode, depth_to_apple_mode(max_depth_of_resolution(id)));
855 cebix 1.21 WriteMacInt32(param + csResolutionFlags, 0);
856 jlachmann 1.5 return noErr;
857 cebix 1.9 }
858 jlachmann 1.5
859 cebix 1.9 case cscGetVideoParameters: { // Get information about specified resolution/depth
860     uint32 id = ReadMacInt32(param + csDisplayModeID);
861     uint16 mode = ReadMacInt16(param + csDepthMode);
862     D(bug(" GetVideoParameters %04x/%08x\n", mode, id));
863 cebix 1.25 dm_present = true; // Display Manager seems to be present
864     D(bug(" Display Manager detected\n"));
865 cebix 1.9
866 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
867     for (i = modes.begin(); i != end; ++i) {
868     if (depth_to_apple_mode(i->depth) == mode && i->resolution_id == id) {
869 cebix 1.9 uint32 vp = ReadMacInt32(param + csVPBlockPtr);
870     WriteMacInt32(vp + vpBaseOffset, 0);
871     WriteMacInt16(vp + vpRowBytes, i->bytes_per_row);
872     WriteMacInt16(vp + vpBounds, 0);
873     WriteMacInt16(vp + vpBounds + 2, 0);
874     WriteMacInt16(vp + vpBounds + 4, i->y);
875     WriteMacInt16(vp + vpBounds + 6, i->x);
876     WriteMacInt16(vp + vpVersion, 0);
877     WriteMacInt16(vp + vpPackType, 0);
878     WriteMacInt32(vp + vpPackSize, 0);
879 cebix 1.11 WriteMacInt32(vp + vpHRes, 0x00480000); // 72 dpi
880 cebix 1.9 WriteMacInt32(vp + vpVRes, 0x00480000);
881     uint32 pix_type, pix_size, cmp_count, cmp_size, dev_type;
882     switch (i->depth) {
883     case VDEPTH_16BIT:
884     pix_type = 0x10; pix_size = 16;
885     cmp_count = 3; cmp_size = 5;
886     dev_type = 2; // direct
887     break;
888     case VDEPTH_32BIT:
889     pix_type = 0x10; pix_size = 32;
890     cmp_count = 3; cmp_size = 8;
891     dev_type = 2; // direct
892 cebix 1.23 break;
893     default:
894     pix_type = 0; pix_size = 1 << i->depth;
895     cmp_count = 1; cmp_size = 1 << i->depth;
896     dev_type = 0; // CLUT
897 cebix 1.9 break;
898     }
899     WriteMacInt16(vp + vpPixelType, pix_type);
900     WriteMacInt16(vp + vpPixelSize, pix_size);
901     WriteMacInt16(vp + vpCmpCount, cmp_count);
902     WriteMacInt16(vp + vpCmpSize, cmp_size);
903     WriteMacInt32(param + csPageCount, 1);
904     WriteMacInt32(param + csDeviceType, dev_type);
905     return noErr;
906     }
907     }
908     return paramErr; // specified resolution/depth not supported
909 cebix 1.21 }
910    
911     case cscGetMultiConnect: {
912     uint32 conn = ReadMacInt32(param + csDisplayCountOrNumber);
913     D(bug(" GetMultiConnect %08x\n", conn));
914     if (conn == 0xffffffff) { // Get number of connections
915     WriteMacInt32(param + csDisplayCountOrNumber, 1); // Single-headed
916     return noErr;
917     } else if (conn == 1) { // Get information about first connection
918     WriteMacInt16(param + csConnectInfo + csDisplayType, 8); // Modeless connection
919     WriteMacInt8(param + csConnectInfo + csConnectTaggedType, 0);
920     WriteMacInt8(param + csConnectInfo + csConnectTaggedData, 0);
921     WriteMacInt32(param + csConnectInfo + csConnectFlags, 0x43); // All modes valid and safe, non-standard tagging
922     WriteMacInt32(param + csConnectInfo + csDisplayComponent, 0);
923     return noErr;
924     } else
925     return paramErr;
926 cebix 1.9 }
927 cebix 1.1
928     default:
929 cebix 1.2 printf("WARNING: Unknown VideoDriverStatus(%d)\n", code);
930 cebix 1.1 return statusErr;
931     }
932 cebix 1.25 }
933    
934     int16 VideoDriverStatus(uint32 pb, uint32 dce)
935     {
936     uint8 slot_id = ReadMacInt8(dce + dCtlSlotId);
937     uint16 code = ReadMacInt16(pb + csCode);
938     uint32 param = ReadMacInt32(pb + csParam);
939     D(bug("VideoDriverStatus slot %02x, code %d\n", slot_id, code));
940    
941     monitor_desc *m = find_monitor(slot_id);
942     if (m)
943     return m->driver_status(code, param);
944     else
945     return nsDrvErr;
946 cebix 1.1 }