37 |
|
#include <sys/shm.h> |
38 |
|
#include <errno.h> |
39 |
|
|
40 |
+ |
#include <algorithm> |
41 |
+ |
|
42 |
+ |
#ifndef NO_STD_NAMESPACE |
43 |
+ |
using std::sort; |
44 |
+ |
#endif |
45 |
+ |
|
46 |
|
#ifdef HAVE_PTHREADS |
47 |
|
# include <pthread.h> |
48 |
|
#endif |
122 |
|
|
123 |
|
// X11 variables |
124 |
|
static int screen; // Screen number |
119 |
– |
static int xdepth; // Depth of X screen |
125 |
|
static Window rootwin; // Root window and our window |
126 |
< |
static XVisualInfo visualInfo; |
127 |
< |
static Visual *vis; |
123 |
< |
static Colormap cmap[2] = {0, 0}; // Colormaps for indexed modes (DGA needs two of them) |
126 |
> |
static int num_depths = 0; // Number of available X depths |
127 |
> |
static int *avail_depths = NULL; // List of available X depths |
128 |
|
static XColor black, white; |
129 |
|
static unsigned long black_pixel, white_pixel; |
130 |
|
static int eventmask; |
131 |
|
|
132 |
+ |
static int xdepth; // Depth of X screen |
133 |
+ |
static XVisualInfo visualInfo; |
134 |
+ |
static Visual *vis; |
135 |
+ |
static int color_class; |
136 |
+ |
|
137 |
|
static int rshift, rloss, gshift, gloss, bshift, bloss; // Pixel format of DirectColor/TrueColor modes |
138 |
|
|
139 |
+ |
static Colormap cmap[2] = {0, 0}; // Colormaps for indexed modes (DGA needs two of them) |
140 |
+ |
|
141 |
|
static XColor palette[256]; // Color palette to be used as CLUT and gamma table |
142 |
|
static bool palette_changed = false; // Flag: Palette changed, redraw thread must set new colors |
143 |
|
|
203 |
|
return ((red >> rloss) << rshift) | ((green >> gloss) << gshift) | ((blue >> bloss) << bshift); |
204 |
|
} |
205 |
|
|
206 |
+ |
// Do we have a visual for handling the specified Mac depth? If so, set the |
207 |
+ |
// global variables "xdepth", "visualInfo", "vis" and "color_class". |
208 |
+ |
static bool find_visual_for_depth(video_depth depth) |
209 |
+ |
{ |
210 |
+ |
D(bug("have_visual_for_depth(%d)\n", 1 << depth)); |
211 |
+ |
|
212 |
+ |
// Calculate minimum and maximum supported X depth |
213 |
+ |
int min_depth = 1, max_depth = 32; |
214 |
+ |
switch (depth) { |
215 |
+ |
case VDEPTH_1BIT: // 1-bit works always |
216 |
+ |
min_depth = 1; |
217 |
+ |
max_depth = 32; |
218 |
+ |
break; |
219 |
+ |
#ifdef ENABLE_VOSF |
220 |
+ |
case VDEPTH_2BIT: |
221 |
+ |
case VDEPTH_4BIT: // VOSF blitters can convert 2/4-bit -> 16/32-bit |
222 |
+ |
min_depth = 15; |
223 |
+ |
max_depth = 32; |
224 |
+ |
break; |
225 |
+ |
case VDEPTH_8BIT: // VOSF blitters can convert 8-bit -> 16/32-bit |
226 |
+ |
min_depth = 8; |
227 |
+ |
max_depth = 32; |
228 |
+ |
break; |
229 |
+ |
#else |
230 |
+ |
case VDEPTH_2BIT: |
231 |
+ |
case VDEPTH_4BIT: // 2/4-bit requires VOSF blitters |
232 |
+ |
return false; |
233 |
+ |
case VDEPTH_8BIT: // 8-bit without VOSF requires an 8-bit visual |
234 |
+ |
min_depth = 8; |
235 |
+ |
max_depth = 8; |
236 |
+ |
break; |
237 |
+ |
#endif |
238 |
+ |
case VDEPTH_16BIT: // 16-bit requires a 15/16-bit visual |
239 |
+ |
min_depth = 15; |
240 |
+ |
max_depth = 16; |
241 |
+ |
break; |
242 |
+ |
case VDEPTH_32BIT: // 32-bit requires a 24/32-bit visual |
243 |
+ |
min_depth = 24; |
244 |
+ |
max_depth = 32; |
245 |
+ |
break; |
246 |
+ |
} |
247 |
+ |
D(bug(" minimum required X depth is %d, maximum supported X depth is %d\n", min_depth, max_depth)); |
248 |
+ |
|
249 |
+ |
// Try to find a visual for one of the color depths |
250 |
+ |
bool visual_found = false; |
251 |
+ |
for (int i=0; i<num_depths && !visual_found; i++) { |
252 |
+ |
|
253 |
+ |
xdepth = avail_depths[i]; |
254 |
+ |
D(bug(" trying to find visual for depth %d\n", xdepth)); |
255 |
+ |
if (xdepth < min_depth || xdepth > max_depth) |
256 |
+ |
continue; |
257 |
+ |
|
258 |
+ |
// Determine best color class for this depth |
259 |
+ |
switch (xdepth) { |
260 |
+ |
case 1: // Try StaticGray or StaticColor |
261 |
+ |
if (XMatchVisualInfo(x_display, screen, xdepth, StaticGray, &visualInfo) |
262 |
+ |
|| XMatchVisualInfo(x_display, screen, xdepth, StaticColor, &visualInfo)) |
263 |
+ |
visual_found = true; |
264 |
+ |
break; |
265 |
+ |
case 8: // Need PseudoColor |
266 |
+ |
if (XMatchVisualInfo(x_display, screen, xdepth, PseudoColor, &visualInfo)) |
267 |
+ |
visual_found = true; |
268 |
+ |
break; |
269 |
+ |
case 15: |
270 |
+ |
case 16: |
271 |
+ |
case 24: |
272 |
+ |
case 32: // Try DirectColor first, as this will allow gamma correction |
273 |
+ |
if (XMatchVisualInfo(x_display, screen, xdepth, DirectColor, &visualInfo) |
274 |
+ |
|| XMatchVisualInfo(x_display, screen, xdepth, TrueColor, &visualInfo)) |
275 |
+ |
visual_found = true; |
276 |
+ |
break; |
277 |
+ |
default: |
278 |
+ |
D(bug(" not a supported depth\n")); |
279 |
+ |
break; |
280 |
+ |
} |
281 |
+ |
} |
282 |
+ |
if (!visual_found) |
283 |
+ |
return false; |
284 |
+ |
|
285 |
+ |
// Visual was found |
286 |
+ |
vis = visualInfo.visual; |
287 |
+ |
color_class = visualInfo.c_class; |
288 |
+ |
D(bug(" found visual ID 0x%02x, depth %d, class ", visualInfo.visualid, xdepth)); |
289 |
+ |
#if DEBUG |
290 |
+ |
switch (color_class) { |
291 |
+ |
case StaticGray: D(bug("StaticGray\n")); break; |
292 |
+ |
case GrayScale: D(bug("GrayScale\n")); break; |
293 |
+ |
case StaticColor: D(bug("StaticColor\n")); break; |
294 |
+ |
case PseudoColor: D(bug("PseudoColor\n")); break; |
295 |
+ |
case TrueColor: D(bug("TrueColor\n")); break; |
296 |
+ |
case DirectColor: D(bug("DirectColor\n")); break; |
297 |
+ |
} |
298 |
+ |
#endif |
299 |
+ |
} |
300 |
+ |
|
301 |
|
// Add mode to list of supported modes |
302 |
|
static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth) |
303 |
|
{ |
528 |
|
int num = 256; |
529 |
|
if (IsDirectMode(VideoMonitor.mode)) |
530 |
|
num = vis->map_entries; // Palette is gamma table |
531 |
< |
else if (vis->c_class == DirectColor) |
531 |
> |
else if (color_class == DirectColor) |
532 |
|
return; // Indexed mode on true color screen, don't set CLUT |
533 |
|
XStoreColors(x_display, cmap[0], palette, num); |
534 |
|
XStoreColors(x_display, cmap[1], palette, num); |
556 |
|
XSetWindowAttributes wattr; |
557 |
|
wattr.event_mask = eventmask = win_eventmask; |
558 |
|
wattr.background_pixel = black_pixel; |
559 |
< |
wattr.colormap = (mode.depth == VDEPTH_1BIT && vis->c_class == PseudoColor ? DefaultColormap(x_display, screen) : cmap[0]); |
559 |
> |
wattr.colormap = (mode.depth == VDEPTH_1BIT && color_class == PseudoColor ? DefaultColormap(x_display, screen) : cmap[0]); |
560 |
|
w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth, |
561 |
< |
InputOutput, vis, CWEventMask | CWBackPixel | (vis->c_class == PseudoColor || vis->c_class == DirectColor ? CWColormap : 0), &wattr); |
561 |
> |
InputOutput, vis, CWEventMask | CWBackPixel | (color_class == PseudoColor || color_class == DirectColor ? CWColormap : 0), &wattr); |
562 |
|
|
563 |
|
// Set window name/class |
564 |
|
set_window_name(w, STR_WINDOW_TITLE); |
1245 |
|
// Open display for specified mode |
1246 |
|
static bool video_open(const video_mode &mode) |
1247 |
|
{ |
1248 |
+ |
// Find best available X visual |
1249 |
+ |
if (!find_visual_for_depth(mode.depth)) { |
1250 |
+ |
ErrorAlert(STR_NO_XVISUAL_ERR); |
1251 |
+ |
return false; |
1252 |
+ |
} |
1253 |
+ |
|
1254 |
+ |
// Create color maps |
1255 |
+ |
if (color_class == PseudoColor || color_class == DirectColor) { |
1256 |
+ |
cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll); |
1257 |
+ |
cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll); |
1258 |
+ |
} |
1259 |
+ |
|
1260 |
+ |
// Find pixel format of direct modes |
1261 |
+ |
if (color_class == DirectColor || color_class == TrueColor) { |
1262 |
+ |
rshift = gshift = bshift = 0; |
1263 |
+ |
rloss = gloss = bloss = 8; |
1264 |
+ |
uint32 mask; |
1265 |
+ |
for (mask=vis->red_mask; !(mask&1); mask>>=1) |
1266 |
+ |
++rshift; |
1267 |
+ |
for (; mask&1; mask>>=1) |
1268 |
+ |
--rloss; |
1269 |
+ |
for (mask=vis->green_mask; !(mask&1); mask>>=1) |
1270 |
+ |
++gshift; |
1271 |
+ |
for (; mask&1; mask>>=1) |
1272 |
+ |
--gloss; |
1273 |
+ |
for (mask=vis->blue_mask; !(mask&1); mask>>=1) |
1274 |
+ |
++bshift; |
1275 |
+ |
for (; mask&1; mask>>=1) |
1276 |
+ |
--bloss; |
1277 |
+ |
} |
1278 |
+ |
|
1279 |
+ |
// Preset palette pixel values for gamma table |
1280 |
+ |
if (color_class == DirectColor) { |
1281 |
+ |
int num = vis->map_entries; |
1282 |
+ |
for (int i=0; i<num; i++) { |
1283 |
+ |
int c = (i * 256) / num; |
1284 |
+ |
palette[i].pixel = map_rgb(c, c, c); |
1285 |
+ |
} |
1286 |
+ |
} |
1287 |
+ |
|
1288 |
|
// Load gray ramp to color map |
1289 |
< |
int num = (vis->c_class == DirectColor ? vis->map_entries : 256); |
1289 |
> |
int num = (color_class == DirectColor ? vis->map_entries : 256); |
1290 |
|
for (int i=0; i<num; i++) { |
1291 |
|
int c = (i * 256) / num; |
1292 |
|
palette[i].red = c * 0x0101; |
1293 |
|
palette[i].green = c * 0x0101; |
1294 |
|
palette[i].blue = c * 0x0101; |
1295 |
< |
if (vis->c_class == PseudoColor) |
1295 |
> |
if (color_class == PseudoColor) |
1296 |
|
palette[i].pixel = i; |
1297 |
|
palette[i].flags = DoRed | DoGreen | DoBlue; |
1298 |
|
} |
1303 |
|
|
1304 |
|
#ifdef ENABLE_VOSF |
1305 |
|
// Load gray ramp to 8->16/32 expand map |
1306 |
< |
if (!IsDirectMode(mode) && (vis->c_class == TrueColor || vis->c_class == DirectColor)) |
1306 |
> |
if (!IsDirectMode(mode) && (color_class == TrueColor || color_class == DirectColor)) |
1307 |
|
for (int i=0; i<256; i++) |
1308 |
|
ExpandMap[i] = map_rgb(i, i, i); |
1309 |
|
#endif |
1395 |
|
// Find screen and root window |
1396 |
|
screen = XDefaultScreen(x_display); |
1397 |
|
rootwin = XRootWindow(x_display, screen); |
1398 |
< |
|
1399 |
< |
// Get screen depth |
1400 |
< |
xdepth = DefaultDepth(x_display, screen); |
1398 |
> |
|
1399 |
> |
// Get sorted list of available depths |
1400 |
> |
avail_depths = XListDepths(x_display, screen, &num_depths); |
1401 |
> |
if (avail_depths == NULL) { |
1402 |
> |
ErrorAlert(STR_UNSUPP_DEPTH_ERR); |
1403 |
> |
return false; |
1404 |
> |
} |
1405 |
> |
sort(avail_depths, avail_depths + num_depths); |
1406 |
|
|
1407 |
|
#ifdef ENABLE_FBDEV_DGA |
1408 |
|
// Frame buffer name |
1442 |
|
black_pixel = BlackPixel(x_display, screen); |
1443 |
|
white_pixel = WhitePixel(x_display, screen); |
1444 |
|
|
1294 |
– |
// Get appropriate visual |
1295 |
– |
int color_class; |
1296 |
– |
switch (xdepth) { |
1297 |
– |
case 1: |
1298 |
– |
color_class = StaticGray; |
1299 |
– |
break; |
1300 |
– |
case 8: |
1301 |
– |
color_class = PseudoColor; |
1302 |
– |
break; |
1303 |
– |
case 15: |
1304 |
– |
case 16: |
1305 |
– |
case 24: |
1306 |
– |
case 32: // Try DirectColor first, as this will allow gamma correction |
1307 |
– |
color_class = DirectColor; |
1308 |
– |
if (!XMatchVisualInfo(x_display, screen, xdepth, color_class, &visualInfo)) |
1309 |
– |
color_class = TrueColor; |
1310 |
– |
break; |
1311 |
– |
default: |
1312 |
– |
ErrorAlert(STR_UNSUPP_DEPTH_ERR); |
1313 |
– |
return false; |
1314 |
– |
} |
1315 |
– |
if (!XMatchVisualInfo(x_display, screen, xdepth, color_class, &visualInfo)) { |
1316 |
– |
ErrorAlert(STR_NO_XVISUAL_ERR); |
1317 |
– |
return false; |
1318 |
– |
} |
1319 |
– |
if (visualInfo.depth != xdepth) { |
1320 |
– |
ErrorAlert(STR_NO_XVISUAL_ERR); |
1321 |
– |
return false; |
1322 |
– |
} |
1323 |
– |
vis = visualInfo.visual; |
1324 |
– |
|
1325 |
– |
// Create color maps |
1326 |
– |
if (color_class == PseudoColor || color_class == DirectColor) { |
1327 |
– |
cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll); |
1328 |
– |
cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll); |
1329 |
– |
} |
1330 |
– |
|
1331 |
– |
// Find pixel format of direct modes |
1332 |
– |
if (color_class == DirectColor || color_class == TrueColor) { |
1333 |
– |
rshift = gshift = bshift = 0; |
1334 |
– |
rloss = gloss = bloss = 8; |
1335 |
– |
uint32 mask; |
1336 |
– |
for (mask=vis->red_mask; !(mask&1); mask>>=1) |
1337 |
– |
++rshift; |
1338 |
– |
for (; mask&1; mask>>=1) |
1339 |
– |
--rloss; |
1340 |
– |
for (mask=vis->green_mask; !(mask&1); mask>>=1) |
1341 |
– |
++gshift; |
1342 |
– |
for (; mask&1; mask>>=1) |
1343 |
– |
--gloss; |
1344 |
– |
for (mask=vis->blue_mask; !(mask&1); mask>>=1) |
1345 |
– |
++bshift; |
1346 |
– |
for (; mask&1; mask>>=1) |
1347 |
– |
--bloss; |
1348 |
– |
} |
1349 |
– |
|
1350 |
– |
// Preset palette pixel values for gamma table |
1351 |
– |
if (color_class == DirectColor) { |
1352 |
– |
int num = vis->map_entries; |
1353 |
– |
for (int i=0; i<num; i++) { |
1354 |
– |
int c = (i * 256) / num; |
1355 |
– |
palette[i].pixel = map_rgb(c, c, c); |
1356 |
– |
} |
1357 |
– |
} |
1358 |
– |
|
1445 |
|
// Get screen mode from preferences |
1446 |
|
const char *mode_str; |
1447 |
|
if (classic_mode) |
1476 |
|
default_height = DisplayHeight(x_display, screen); |
1477 |
|
|
1478 |
|
// Mac screen depth follows X depth |
1479 |
< |
video_depth default_depth = DepthModeForPixelDepth(xdepth); |
1479 |
> |
video_depth default_depth = VDEPTH_1BIT; |
1480 |
> |
switch (DefaultDepth(x_display, screen)) { |
1481 |
> |
case 8: |
1482 |
> |
default_depth = VDEPTH_8BIT; |
1483 |
> |
break; |
1484 |
> |
case 15: case 16: |
1485 |
> |
default_depth = VDEPTH_16BIT; |
1486 |
> |
break; |
1487 |
> |
case 24: case 32: |
1488 |
> |
default_depth = VDEPTH_32BIT; |
1489 |
> |
break; |
1490 |
> |
} |
1491 |
|
|
1492 |
|
// Construct list of supported modes |
1493 |
|
if (display_type == DISPLAY_WINDOW) { |
1494 |
|
if (classic) |
1495 |
|
add_mode(512, 342, 0x80, 64, VDEPTH_1BIT); |
1496 |
|
else { |
1497 |
< |
if (default_depth != VDEPTH_1BIT) |
1498 |
< |
add_window_modes(VDEPTH_1BIT); // 1-bit modes are always available |
1499 |
< |
#ifdef ENABLE_VOSF |
1403 |
< |
if (default_depth > VDEPTH_8BIT) { |
1404 |
< |
add_window_modes(VDEPTH_2BIT); // 2, 4 and 8-bit modes are also possible on 16/32-bit screens with VOSF blitters |
1405 |
< |
add_window_modes(VDEPTH_4BIT); |
1406 |
< |
add_window_modes(VDEPTH_8BIT); |
1497 |
> |
for (unsigned d=VDEPTH_1BIT; d<=VDEPTH_32BIT; d++) { |
1498 |
> |
if (find_visual_for_depth(video_depth(d))) |
1499 |
> |
add_window_modes(video_depth(d)); |
1500 |
|
} |
1408 |
– |
#endif |
1409 |
– |
add_window_modes(default_depth); |
1501 |
|
} |
1502 |
|
} else |
1503 |
|
add_mode(default_width, default_height, 0x80, TrivialBytesPerRow(default_width, default_depth), default_depth); |
1504 |
+ |
if (VideoModes.empty()) { |
1505 |
+ |
ErrorAlert(STR_NO_XVISUAL_ERR); |
1506 |
+ |
return false; |
1507 |
+ |
} |
1508 |
|
video_init_depth_list(); |
1509 |
|
|
1510 |
+ |
#if DEBUG |
1511 |
+ |
D(bug("Available video modes:\n")); |
1512 |
+ |
vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end(); |
1513 |
+ |
while (i != end) { |
1514 |
+ |
int bits = 1 << i->depth; |
1515 |
+ |
if (bits == 16) |
1516 |
+ |
bits = 15; |
1517 |
+ |
else if (bits == 32) |
1518 |
+ |
bits = 24; |
1519 |
+ |
D(bug(" %dx%d (ID %02x), %d colors\n", i->x, i->y, i->resolution_id, 1 << bits)); |
1520 |
+ |
++i; |
1521 |
+ |
} |
1522 |
+ |
#endif |
1523 |
+ |
|
1524 |
|
// Find requested default mode and open display |
1525 |
|
if (VideoModes.size() == 1) |
1526 |
|
return video_open(VideoModes[0]); |
1576 |
|
// Close display |
1577 |
|
delete drv; |
1578 |
|
drv = NULL; |
1470 |
– |
} |
1471 |
– |
|
1472 |
– |
void VideoExit(void) |
1473 |
– |
{ |
1474 |
– |
// Close display |
1475 |
– |
video_close(); |
1579 |
|
|
1580 |
|
// Free colormaps |
1581 |
|
if (cmap[0]) { |
1586 |
|
XFreeColormap(x_display, cmap[1]); |
1587 |
|
cmap[1] = 0; |
1588 |
|
} |
1589 |
+ |
} |
1590 |
+ |
|
1591 |
+ |
void VideoExit(void) |
1592 |
+ |
{ |
1593 |
+ |
// Close display |
1594 |
+ |
video_close(); |
1595 |
|
|
1596 |
|
#ifdef ENABLE_XF86_VIDMODE |
1597 |
|
// Free video mode list |
1608 |
|
fbdev_fd = -1; |
1609 |
|
} |
1610 |
|
#endif |
1611 |
+ |
|
1612 |
+ |
// Free depth list |
1613 |
+ |
if (avail_depths) { |
1614 |
+ |
XFree(avail_depths); |
1615 |
+ |
avail_depths = NULL; |
1616 |
+ |
} |
1617 |
|
} |
1618 |
|
|
1619 |
|
|
1665 |
|
p->red = pal[c*3 + 0] * 0x0101; |
1666 |
|
p->green = pal[c*3 + 1] * 0x0101; |
1667 |
|
p->blue = pal[c*3 + 2] * 0x0101; |
1668 |
< |
if (vis->c_class == PseudoColor) |
1668 |
> |
if (color_class == PseudoColor) |
1669 |
|
p->pixel = i; |
1670 |
|
p->flags = DoRed | DoGreen | DoBlue; |
1671 |
|
p++; |
1673 |
|
|
1674 |
|
#ifdef ENABLE_VOSF |
1675 |
|
// Recalculate pixel color expansion map |
1676 |
< |
if (!IsDirectMode(VideoMonitor.mode) && (vis->c_class == TrueColor || vis->c_class == DirectColor)) { |
1676 |
> |
if (!IsDirectMode(VideoMonitor.mode) && (color_class == TrueColor || color_class == DirectColor)) { |
1677 |
|
for (int i=0; i<256; i++) { |
1678 |
|
int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier) |
1679 |
|
ExpandMap[i] = map_rgb(pal[c*3+0], pal[c*3+1], pal[c*3+2]); |