--- BasiliskII/src/include/video.h 2001/06/27 19:03:38 1.6 +++ BasiliskII/src/include/video.h 2008/01/01 09:40:35 1.17 @@ -1,7 +1,7 @@ /* * video.h - Video/graphics emulation * - * Basilisk II (C) 1997-2001 Christian Bauer + * Basilisk II (C) 1997-2008 Christian Bauer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,29 @@ #include +#ifndef NO_STD_NAMESPACE +using std::vector; +#endif + + +/* + Some of the terminology here is completely frelled. In Basilisk II, a + "video mode" refers to a combination of resolution and color depth, and + this information is stored in a video_mode structure. In Apple + documentation, a "mode" historically refers to the color depth only + (because old Macs had fixed-frequency monitors and could not change the + resolution). These "modes" are assigned a number (0x80, 0x81, etc.), + which we here call "Apple mode". When Macs learned how to deal with + multiscan monitors, Apple introduced another type of "mode", also having + numbers starting from 0x80 but refrerring to the resolution and/or video + timing of the display (it's possible to have two modes with the same + dimension but different refresh rates). We call this a "resolution ID". + The combination of "Apple mode" and "ID" corresponds to a Basilisk II + "video mode". To make the confusion worse, the video driver control call + that sets the color depth is called "SetMode" while the one that sets + both depth and resolution is "SwitchMode"... +*/ + // Color depth codes enum video_depth { VDEPTH_1BIT, // 2 colors @@ -33,28 +56,77 @@ enum video_depth { VDEPTH_32BIT // "Millions" }; +// 1, 2, 4 and 8 bit depths use a color palette inline bool IsDirectMode(video_depth depth) { return depth == VDEPTH_16BIT || depth == VDEPTH_32BIT; } -inline uint16 DepthToAppleMode(video_depth depth) +// Return the depth code that corresponds to the specified bits-per-pixel value +inline video_depth DepthModeForPixelDepth(int depth) { - return depth + 0x80; + switch (depth) { + case 1: return VDEPTH_1BIT; + case 2: return VDEPTH_2BIT; + case 4: return VDEPTH_4BIT; + case 8: return VDEPTH_8BIT; + case 15: case 16: return VDEPTH_16BIT; + case 24: case 32: return VDEPTH_32BIT; + default: return VDEPTH_1BIT; + } } -inline video_depth AppleModeToDepth(uint16 mode) +// Return a bytes-per-row value (assuming no padding) for the specified depth and pixel width +inline uint32 TrivialBytesPerRow(uint32 width, video_depth depth) { - return video_depth(mode - 0x80); + switch (depth) { + case VDEPTH_1BIT: return width / 8; + case VDEPTH_2BIT: return width / 4; + case VDEPTH_4BIT: return width / 2; + case VDEPTH_8BIT: return width; + case VDEPTH_16BIT: return width * 2; + case VDEPTH_32BIT: return width * 4; + default: return width; + } } -// Description of one video mode + +/* + You are not completely free in your selection of depth/resolution + combinations: + 1) the lowest supported color depth must be available in all + resolutions + 2) if one resolution provides a certain color depth, it must also + provide all lower supported depths + + For example, it is possible to have this set of modes: + 640x480 @ 8 bit + 640x480 @ 32 bit + 800x600 @ 8 bit + 800x600 @ 32 bit + 1024x768 @ 8 bit + + But this is not possible (violates rule 1): + 640x480 @ 8 bit + 800x600 @ 8 bit + 1024x768 @ 1 bit + + And neither is this (violates rule 2, 640x480 @ 16 bit is missing): + 640x480 @ 8 bit + 640x480 @ 32 bit + 800x600 @ 8 bit + 800x600 @ 16 bit + 1024x768 @ 8 bit +*/ + +// Description of a video mode struct video_mode { uint32 x; // X size of screen (pixels) uint32 y; // Y size of screen (pixels) uint32 resolution_id; // Resolution ID (should be >= 0x80 and uniquely identify the sets of modes with the same X/Y size) - uint32 bytes_per_row; // Bytes per row of frame buffer video_depth depth; // Color depth (see definitions above) + uint32 bytes_per_row; // Bytes per row of frame buffer + uint32 user_data; // Free for use by platform-specific code }; inline bool IsDirectMode(const video_mode &mode) @@ -62,21 +134,132 @@ inline bool IsDirectMode(const video_mod return IsDirectMode(mode.depth); } -// List of all supported video modes -extern vector VideoModes; -// Description for one (possibly virtual) monitor -struct monitor_desc { - uint32 mac_frame_base; // Mac frame buffer address - video_mode mode; // Currently selected video mode description +// Mac video driver per-display private variables (opaque) +struct video_locals; + + +// Abstract base class representing one (possibly virtual) monitor +// ("monitor" = rectangular display with a contiguous frame buffer) +class monitor_desc { +public: + monitor_desc(const vector &available_modes, video_depth default_depth, uint32 default_id); + virtual ~monitor_desc() {} + + // Get Mac slot ID number + uint8 get_slot_id(void) const {return slot_id;} + + // Get current Mac frame buffer base address + uint32 get_mac_frame_base(void) const {return mac_frame_base;} + + // Set Mac frame buffer base address (called from switch_to_mode()) + void set_mac_frame_base(uint32 base) {mac_frame_base = base;} + + // Get current video mode + const video_mode &get_current_mode(void) const {return *current_mode;} + + // Get Apple mode id for given depth + uint16 depth_to_apple_mode(video_depth depth) const {return apple_mode_for_depth[depth];} + + // Get current color depth + uint16 get_apple_mode(void) const {return depth_to_apple_mode(current_mode->depth);} + + // Get bytes-per-row value for specified resolution/depth + // (if the mode isn't supported, make a good guess) + uint32 get_bytes_per_row(video_depth depth, uint32 id) const; + + // Check whether a mode with the specified depth exists on this display + bool has_depth(video_depth depth) const; + + // Mac video driver functions + int16 driver_open(void); + int16 driver_control(uint16 code, uint32 param, uint32 dce); + int16 driver_status(uint16 code, uint32 param); + +protected: + vector modes; // List of supported video modes + vector::const_iterator current_mode; // Currently selected video mode + + uint32 mac_frame_base; // Mac frame buffer address for current mode + +// Mac video driver per-display private variables/functions +private: + // Check whether the specified resolution ID is one of the supported resolutions + bool has_resolution(uint32 id) const; + + // Return iterator signifying "invalid mode" + vector::const_iterator invalid_mode(void) const {return modes.end();} + + // Find specified mode (depth/resolution) (or invalid_mode() if not found) + vector::const_iterator find_mode(uint16 apple_mode, uint32 id) const; + + // Find maximum supported depth for given resolution ID + video_depth max_depth_of_resolution(uint32 id) const; + + // Get X/Y size of specified resolution + void get_size_of_resolution(uint32 id, uint32 &x, uint32 &y) const; + + // Set palette to 50% gray + void set_gray_palette(void); + + // Load gamma-corrected black-to-white ramp to palette for direct-color mode + void load_ramp_palette(void); + + // Allocate gamma table of specified size + bool allocate_gamma_table(int size); + + // Set gamma table (0 = build linear ramp) + bool set_gamma_table(uint32 user_table); + + // Switch video mode + void switch_mode(vector::const_iterator it, uint32 param, uint32 dce); + + uint8 slot_id; // NuBus slot ID number + static uint8 next_slot_id; // Next available slot ID + + uint8 palette[256 * 3]; // Color palette, 256 entries, RGB + + bool luminance_mapping; // Luminance mapping on/off + bool interrupts_enabled; // VBL interrupts on/off + bool dm_present; // We received a GetVideoParameters call, so the Display Manager seems to be present + + uint32 gamma_table; // Mac address of gamma table + int alloc_gamma_table_size; // Allocated size of gamma table + + uint16 current_apple_mode; // Currently selected depth/resolution + uint32 current_id; + uint16 preferred_apple_mode; // Preferred depth/resolution + uint32 preferred_id; + + uint32 slot_param; // Mac address of Slot Manager parameter block + + // For compatibility reasons with older (pre-Display Manager) versions of + // MacOS, the Apple modes must start at 0x80 and be contiguous. Therefore + // we maintain an array to map the depth codes to the corresponding Apple + // mode. + uint16 apple_mode_for_depth[6]; + +// The following functions are implemented by platform-specific code +public: + + // Called by the video driver to switch the video mode on this display + // (must call set_mac_frame_base()) + virtual void switch_to_current_mode(void) = 0; + + // Called by the video driver to set the color palette (in indexed modes) + // or the gamma table (in direct modes) + virtual void set_palette(uint8 *pal, int num) = 0; }; -extern monitor_desc VideoMonitor; // Description of the main monitor, set by VideoInit() +// Vector of pointers to available monitor descriptions, filled by VideoInit() +extern vector VideoMonitors; + extern int16 VideoDriverOpen(uint32 pb, uint32 dce); extern int16 VideoDriverControl(uint32 pb, uint32 dce); extern int16 VideoDriverStatus(uint32 pb, uint32 dce); + // System specific and internal functions/data extern bool VideoInit(bool classic); extern void VideoExit(void); @@ -86,6 +269,4 @@ extern void VideoQuitFullScreen(void); extern void VideoInterrupt(void); extern void VideoRefresh(void); -extern void video_set_palette(uint8 *pal); - #endif