2 * TinyPTC x11 v0.7.3 X Direct Graphics Access Extension v2 target
3 * Copyright (C) 2001-2002 Alessandro Gatti <a.gatti@tiscali.it>
5 * http://www.sourceforge.net/projects/tinyptc/
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library 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 GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <X11/Xutil.h>
27 #include <X11/extensions/xf86dga.h>
33 #include <sys/types.h>
38 #define __PTC_FROM_SOURCE
45 ptc_open (char *title, int width, int height)
47 /* Check for the effective UID of the running process */
52 /* Open a display on the current root window */
53 ptc_display = XOpenDisplay (NULL);
54 if (ptc_display == NULL)
58 /* Get the default screen associated with the previously opened display */
59 ptc_screen = DefaultScreen (ptc_display);
60 /* Get the default visual */
61 ptc_visual = DefaultVisual (ptc_display, ptc_screen);
63 /* Check for DGA extension avaliability */
64 if (!XDGAQueryExtension (ptc_display, &ptc_dga_event_base, &ptc_error_base))
66 XCloseDisplay (ptc_display);
69 /* Check for version 2.x of the extension */
70 ptc_dga_major_version = 0;
72 (ptc_display, &ptc_dga_major_version, &ptc_dga_minor_version)
73 || (ptc_dga_major_version < 2))
75 XCloseDisplay (ptc_display);
78 /* Enable framebuffer access */
79 if (!XDGAOpenFramebuffer (ptc_display, ptc_screen))
81 XCloseDisplay (ptc_display);
84 /* Get all the modelines */
85 ptc_dga_mode = XDGAQueryModes (ptc_display, ptc_screen, &ptc_dga_modes);
86 ptc_dga_emulate_fullscreen = True;
87 #ifdef __PTC_ENABLE_CONVERSIONS__
88 ptc_dga_mode_32 = INT_MIN;
89 ptc_dga_mode_24 = INT_MIN;
90 ptc_dga_mode_16 = INT_MIN;
91 ptc_dga_mode_15 = INT_MIN;
92 #endif /* __PTC_ENABLE_CONVERSIONS__ */
93 ptc_dga_new_mode = INT_MIN;
94 /* Search for desired mode in parameter list */
95 for (ptc_dga_counter = 0; ptc_dga_counter < ptc_dga_modes;
98 if ((ptc_dga_mode[ptc_dga_counter].viewportWidth == width)
99 && (ptc_dga_mode[ptc_dga_counter].viewportHeight == height))
101 #ifdef __PTC_ENABLE_CONVERSIONS__
102 /* Get the right videomode for each colordepth */
103 if (ptc_dga_mode[ptc_dga_counter].depth == 24)
105 if (ptc_dga_mode[ptc_dga_counter].bitsPerPixel == 32)
107 ptc_dga_mode_32 = ptc_dga_counter;
108 ptc_dga_emulate_fullscreen = False;
110 if (ptc_dga_mode[ptc_dga_counter].bitsPerPixel == 24)
112 ptc_dga_mode_24 = ptc_dga_counter;
113 ptc_dga_emulate_fullscreen = False;
116 if (ptc_dga_mode[ptc_dga_counter].bitsPerPixel == 16)
118 if (ptc_dga_mode[ptc_dga_counter].depth == 15)
120 ptc_dga_mode_15 = ptc_dga_counter;
121 ptc_dga_emulate_fullscreen = False;
123 if (ptc_dga_mode[ptc_dga_counter].depth == 16)
125 ptc_dga_mode_16 = ptc_dga_counter;
126 ptc_dga_emulate_fullscreen = False;
130 /* Get the right videomode */
131 if ((ptc_dga_mode[ptc_dga_counter].bitsPerPixel == 32)
132 && (ptc_dga_mode[ptc_dga_counter].depth == 32))
134 ptc_dga_new_mode = ptc_dga_counter;
135 ptc_dga_emulate_fullscreen = False;
138 #endif /* __PTC_ENABLE_CONVERSIONS__ */
142 #ifdef __PTC_ENABLE_CONVERSIONS__
143 /* Simple heuristics for getting the best videomode and the right
144 * converter for that videomode */
145 if (ptc_dga_mode_32 == INT_MIN)
147 if (ptc_dga_mode_24 == INT_MIN)
149 if (ptc_dga_mode_16 == INT_MIN)
151 if (ptc_dga_mode_15 == INT_MIN)
157 ptc_request_converter (15,
158 ptc_dga_mode[ptc_dga_mode_15].
160 ptc_dga_mode[ptc_dga_mode_15].
162 ptc_dga_mode[ptc_dga_mode_15].
166 ptc_dga_new_mode = INT_MIN;
170 ptc_dga_new_mode = ptc_dga_mode_15;
171 ptc_dga_output_pitch = 2;
178 ptc_request_converter (16,
179 ptc_dga_mode[ptc_dga_mode_16].
181 ptc_dga_mode[ptc_dga_mode_16].
183 ptc_dga_mode[ptc_dga_mode_16].
187 ptc_dga_new_mode = INT_MIN;
191 ptc_dga_new_mode = ptc_dga_mode_16;
192 ptc_dga_output_pitch = 2;
199 ptc_request_converter (24, ptc_dga_mode[ptc_dga_mode_24].redMask,
200 ptc_dga_mode[ptc_dga_mode_24].greenMask,
201 ptc_dga_mode[ptc_dga_mode_24].blueMask);
204 ptc_dga_new_mode = INT_MIN;
208 ptc_dga_new_mode = ptc_dga_mode_24;
209 ptc_dga_output_pitch = 3;
216 ptc_request_converter (32, ptc_dga_mode[ptc_dga_mode_32].redMask,
217 ptc_dga_mode[ptc_dga_mode_32].greenMask,
218 ptc_dga_mode[ptc_dga_mode_32].blueMask);
221 ptc_dga_new_mode = INT_MIN;
225 ptc_dga_new_mode = ptc_dga_mode_32;
226 ptc_dga_output_pitch = 4;
230 ptc_dga_output_pitch = 4;
231 #endif /* __PTC_ENABLE_CONVERSIONS__ */
233 #ifdef __PTC_BEST_VIDEOMODE__
234 /* It works for fullscreen emulation only */
235 if (ptc_dga_emulate_fullscreen)
238 #ifdef __PTC_ENABLE_CONVERSIONS__
239 ptc_dga_32.best_delta = INT_MAX;
240 ptc_dga_24.best_delta = INT_MAX;
241 ptc_dga_16.best_delta = INT_MAX;
242 ptc_dga_15.best_delta = INT_MAX;
243 ptc_dga_32.best_videomode = INT_MIN;
244 ptc_dga_24.best_videomode = INT_MIN;
245 ptc_dga_16.best_videomode = INT_MIN;
246 ptc_dga_15.best_videomode = INT_MIN;
248 ptc_dga_best_delta = INT_MAX;
249 ptc_dga_best_videomode = INT_MIN;
250 #endif /* __PTC_ENABLE_CONVERSIONS__ */
251 /* Check for all avaliable modes */
252 for (ptc_dga_counter = 0; ptc_dga_counter < ptc_dga_modes;
255 if ((ptc_dga_mode[ptc_dga_counter].viewportWidth >= width)
256 && (ptc_dga_mode[ptc_dga_counter].viewportHeight >= height))
258 ptc_dga_best_x_delta =
259 ptc_dga_mode[ptc_dga_counter].viewportWidth - width;
260 ptc_dga_best_x_delta *= ptc_dga_best_x_delta;
261 ptc_dga_best_y_delta =
262 ptc_dga_mode[ptc_dga_counter].viewportHeight - height;
263 ptc_dga_best_y_delta *= ptc_dga_best_y_delta;
265 /* Check if the mode fits better than the previous one */
267 #ifdef __PTC_ENABLE_CONVERSIONS__
268 if (ptc_dga_mode[ptc_dga_counter].depth == 24)
270 if (ptc_dga_mode[ptc_dga_counter].bitsPerPixel == 32)
272 if (ptc_dga_best_x_delta + ptc_dga_best_y_delta <
273 ptc_dga_32.best_delta)
275 ptc_dga_32.best_delta =
276 ptc_dga_best_x_delta + ptc_dga_best_y_delta;
277 ptc_dga_32.best_videomode = ptc_dga_counter;
280 if (ptc_dga_mode[ptc_dga_counter].bitsPerPixel == 24)
282 if (ptc_dga_best_x_delta + ptc_dga_best_y_delta <
283 ptc_dga_24.best_delta)
285 ptc_dga_24.best_delta =
286 ptc_dga_best_x_delta + ptc_dga_best_y_delta;
287 ptc_dga_24.best_videomode = ptc_dga_counter;
291 if (ptc_dga_mode[ptc_dga_counter].bitsPerPixel == 16)
293 if (ptc_dga_mode[ptc_dga_counter].depth == 15)
295 if (ptc_dga_best_x_delta + ptc_dga_best_y_delta <
296 ptc_dga_15.best_delta)
298 ptc_dga_15.best_delta =
299 ptc_dga_best_x_delta + ptc_dga_best_y_delta;
300 ptc_dga_15.best_videomode = ptc_dga_counter;
303 if (ptc_dga_mode[ptc_dga_counter].depth == 16)
305 if (ptc_dga_best_x_delta + ptc_dga_best_y_delta <
306 ptc_dga_16.best_delta)
308 ptc_dga_16.best_delta =
309 ptc_dga_best_x_delta + ptc_dga_best_y_delta;
310 ptc_dga_16.best_videomode = ptc_dga_counter;
315 /* Set up next iteration */
317 ptc_dga_best_x_delta + ptc_dga_best_y_delta;
318 ptc_dga_best_videomode = ptc_dga_counter;
319 #endif /* __PTC_ENABLE_CONVERSIONS__ */
324 #ifdef __PTC_ENABLE_CONVERSIONS__
325 /* Simple heuristics for getting the best videomode and the right
326 * converter for that videomode */
328 if (ptc_dga_32.best_videomode == INT_MIN)
330 if (ptc_dga_24.best_videomode == INT_MIN)
332 if (ptc_dga_16.best_videomode == INT_MIN)
334 if (ptc_dga_15.best_videomode == INT_MIN)
340 ptc_request_converter (15,
341 ptc_dga_mode[ptc_dga_15.
344 ptc_dga_mode[ptc_dga_15.
347 ptc_dga_mode[ptc_dga_15.
352 ptc_dga_new_mode = INT_MIN;
356 ptc_dga_new_mode = ptc_dga_15.best_videomode;
357 ptc_dga_output_pitch = 2;
365 ptc_request_converter (16,
366 ptc_dga_mode[ptc_dga_16.
367 best_videomode].redMask,
368 ptc_dga_mode[ptc_dga_16.
369 best_videomode].greenMask,
370 ptc_dga_mode[ptc_dga_16.
371 best_videomode].blueMask);
374 ptc_dga_new_mode = INT_MIN;
378 ptc_dga_new_mode = ptc_dga_16.best_videomode;
379 ptc_dga_output_pitch = 2;
387 ptc_request_converter (24,
388 ptc_dga_mode[ptc_dga_24.best_videomode].
390 ptc_dga_mode[ptc_dga_24.best_videomode].
392 ptc_dga_mode[ptc_dga_24.best_videomode].
396 ptc_dga_new_mode = INT_MIN;
400 ptc_dga_new_mode = ptc_dga_24.best_videomode;
401 ptc_dga_output_pitch = 3;
408 ptc_request_converter (32,
409 ptc_dga_mode[ptc_dga_32.best_videomode].
411 ptc_dga_mode[ptc_dga_32.best_videomode].
413 ptc_dga_mode[ptc_dga_32.best_videomode].
417 ptc_dga_new_mode = INT_MIN;
421 ptc_dga_new_mode = ptc_dga_32.best_videomode;
422 ptc_dga_output_pitch = 4;
426 ptc_dga_output_pitch = 4;
427 ptc_dga_new_mode = ptc_dga_best_videomode;
428 #endif /* __PTC_ENABLE_CONVERSIONS__ */
429 #endif /* __PTC_BEST_VIDEOMODE__ */
431 /* No suitable mode found */
432 if (ptc_dga_new_mode == INT_MIN)
434 XFree (ptc_dga_mode);
435 XCloseDisplay (ptc_display);
438 /* Try to switch mode */
440 XDGASetMode (ptc_display, ptc_screen, ptc_dga_mode[ptc_dga_new_mode].num);
441 if (ptc_dga_device == NULL)
443 XFree (ptc_dga_mode);
444 XCloseDisplay (ptc_display);
447 /* Clear event queue */
448 XFlush (ptc_display);
449 /* Leave root mode */
451 /* Get viewport parameters */
452 ptc_screen_width = ptc_dga_device->mode.viewportWidth;
453 ptc_screen_height = ptc_dga_device->mode.viewportHeight;
454 /* Get framebuffer address */
455 ptc_dga_framebuffer_address = (char *)ptc_dga_device->data;
458 /* Set fullscreen emulation up */
459 if (ptc_dga_emulate_fullscreen)
461 /* Get effective framebuffer address */
462 ptc_framebuffer_start =
463 ptc_dga_device->mode.bytesPerScanline *
464 ((ptc_screen_height - height) / 2) +
465 (((ptc_screen_width - width) / 2) * ptc_dga_output_pitch);
470 ptc_framebuffer_start = 0;
472 ptc_dga_video_length =
473 ptc_dga_device->mode.bytesPerScanline *
474 ptc_dga_device->mode.viewportHeight;
476 ptc_dga_first_page_address = ptc_dga_framebuffer_address + ptc_framebuffer_start;
477 ptc_dga_second_page_address =
478 ptc_dga_first_page_address + ptc_dga_video_length;
480 /* Set the final viewport */
481 XDGASetViewport (ptc_display, ptc_screen, 0, 0, XDGAFlipRetrace);
482 /* Select the input events that should be reported */
483 XDGASelectInput (ptc_display, ptc_screen, KeyPressMask | KeyReleaseMask);
484 /* Clear event queue */
485 XFlush (ptc_display);
486 /* Clear video memory */
487 memset (ptc_dga_device->data, 0x00, ptc_dga_video_length * 2);
488 /* Save the buffer size */
489 ptc_viewport_width = width;
490 ptc_viewport_height = height;
491 ptc_dga_first_page = False;
495 /* Update the screen */
498 ptc_update (void *buffer)
500 char *ptc_vram_pointer;
502 /* This is here just to keep the c++ compiler happy */
505 ptc_buffer=(char *)buffer;
507 ptc_framebuffer_index = 0;
508 #ifdef __PTC_ENABLE_CONVERSIONS__
509 ptc_source_index = 0;
510 ptc_destination_index = 0;
511 #endif /* __PTC_ENABLE_CONVERSIONS__ */
513 /* Get the right memory area to write into */
514 if (ptc_dga_first_page == True)
516 ptc_vram_pointer = ptc_dga_first_page_address;
520 ptc_vram_pointer = ptc_dga_second_page_address;
523 /* Do the blit line by line */
524 for (ptc_blitcounter = 0; ptc_blitcounter < ptc_viewport_height;
527 #ifdef __PTC_ENABLE_CONVERSIONS__
529 ptc_convert (ptc_buffer + ptc_source_index,
530 ptc_vram_pointer + ptc_destination_index,
532 /* Pointers update */
533 ptc_source_index += ptc_viewport_width * sizeof (int);
534 ptc_destination_index += ptc_dga_device->mode.bytesPerScanline;
537 memcpy (ptc_vram_pointer + ptc_framebuffer_index, ptc_buffer,
538 ptc_viewport_width * sizeof (int));
539 ptc_buffer += ptc_viewport_width * sizeof (int);
541 ptc_framebuffer_index += ptc_dga_device->mode.bytesPerScanline;
542 #endif /* __PTC_ENABLE_CONVERSIONS__ */
545 /* Wait for retrace */
546 while (XDGAGetViewportStatus (ptc_display, ptc_screen));
548 /* Flip the two pages */
549 if (ptc_dga_first_page == True)
551 XDGASetViewport (ptc_display, ptc_screen, 0, 0, XDGAFlipImmediate);
555 XDGASetViewport (ptc_display, ptc_screen, 0,
556 ptc_dga_device->mode.viewportHeight,
559 ptc_dga_first_page = !ptc_dga_first_page;
561 /* Process incoming events */
562 if (ptc_process_events ())
564 #ifdef __PTC_CLEANUP_CALLBACK__
565 ptc_cleanup_callback ();
566 #endif /* __PTC_CLEANUP_CALLBACK__ */
576 ptc_process_events (void)
578 XDGAEvent ptc_dga_event;
580 XKeyEvent ptc_dga_keyevent;
581 /* Check if there are events waiting in the display's queue */
582 if (XPending (ptc_display))
584 /* Get the next event in queue */
585 XNextEvent (ptc_display, (XEvent *) & ptc_dga_event);
586 ptc_dga_event.type -= ptc_dga_event_base;
588 /* Check if it's a keypress event */
589 if (ptc_dga_event.type == KeyPress)
591 /* Translate the event */
592 XDGAKeyEventToXKeyEvent (&ptc_dga_event.xkey, &ptc_dga_keyevent);
594 ptc_keysym = XLookupKeysym (&ptc_dga_keyevent, 0);
595 /* Check if the key pressed was a function one */
596 if ((ptc_keysym >> 8) == __PTC_FUNCTION_KEY__)
598 /* Check if it was the escape key */
599 if ((ptc_keysym & 0xFF) == __PTC_ESCAPE_KEY__)
609 /* Close the screen */
614 /* Switch back to the previous video mode */
615 XDGASetMode (ptc_display, ptc_screen, 0);
616 /* Disable framebuffer access */
617 XDGACloseFramebuffer (ptc_display, ptc_screen);
618 /* Close the display */
619 XCloseDisplay (ptc_display);
620 /* Deallocate the buffer */
627 #endif /* __PTC_XDGA2__ */