1 |
|
/* |
2 |
|
* video_x.cpp - Video/graphics emulation, X11 specific stuff |
3 |
|
* |
4 |
< |
* Basilisk II (C) 1997-2000 Christian Bauer |
4 |
> |
* Basilisk II (C) 1997-2001 Christian Bauer |
5 |
|
* |
6 |
|
* This program is free software; you can redistribute it and/or modify |
7 |
|
* it under the terms of the GNU General Public License as published by |
197 |
|
int pageBits; // Shift count to get the page number |
198 |
|
uint32 pageCount; // Number of pages allocated to the screen |
199 |
|
|
200 |
< |
uint8 * dirtyPages; // Table of flags set if page was altered |
200 |
> |
bool dirty; // Flag: set if the frame buffer was touched |
201 |
> |
char * dirtyPages; // Table of flags set if page was altered |
202 |
|
ScreenPageInfo * pageInfo; // Table of mappings page -> Mac scanlines |
203 |
|
}; |
204 |
|
|
205 |
|
static ScreenInfo mainBuffer; |
206 |
|
|
207 |
< |
#define PFLAG_SET(page) mainBuffer.dirtyPages[page] = 1 |
208 |
< |
#define PFLAG_CLEAR(page) mainBuffer.dirtyPages[page] = 0 |
209 |
< |
#define PFLAG_ISSET(page) mainBuffer.dirtyPages[page] |
210 |
< |
#define PFLAG_ISCLEAR(page) (mainBuffer.dirtyPages[page] == 0) |
207 |
> |
#define PFLAG_SET_VALUE 0x00 |
208 |
> |
#define PFLAG_CLEAR_VALUE 0x01 |
209 |
> |
#define PFLAG_SET_VALUE_4 0x00000000 |
210 |
> |
#define PFLAG_CLEAR_VALUE_4 0x01010101 |
211 |
> |
#define PFLAG_SET(page) mainBuffer.dirtyPages[page] = PFLAG_SET_VALUE |
212 |
> |
#define PFLAG_CLEAR(page) mainBuffer.dirtyPages[page] = PFLAG_CLEAR_VALUE |
213 |
> |
#define PFLAG_ISSET(page) (mainBuffer.dirtyPages[page] == PFLAG_SET_VALUE) |
214 |
> |
#define PFLAG_ISCLEAR(page) (mainBuffer.dirtyPages[page] != PFLAG_SET_VALUE) |
215 |
> |
|
216 |
|
#ifdef UNALIGNED_PROFITABLE |
217 |
< |
# define PFLAG_ISCLEAR_4(page) (*((uint32 *)(mainBuffer.dirtyPages + page)) == 0) |
217 |
> |
# define PFLAG_ISSET_4(page) (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_SET_VALUE_4) |
218 |
> |
# define PFLAG_ISCLEAR_4(page) (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_CLEAR_VALUE_4) |
219 |
> |
#else |
220 |
> |
# define PFLAG_ISSET_4(page) \ |
221 |
> |
PFLAG_ISSET(page ) && PFLAG_ISSET(page+1) \ |
222 |
> |
&& PFLAG_ISSET(page+2) && PFLAG_ISSET(page+3) |
223 |
> |
# define PFLAG_ISCLEAR_4(page) \ |
224 |
> |
PFLAG_ISCLEAR(page ) && PFLAG_ISCLEAR(page+1) \ |
225 |
> |
&& PFLAG_ISCLEAR(page+2) && PFLAG_ISCLEAR(page+3) |
226 |
> |
#endif |
227 |
> |
|
228 |
> |
// Set the selected page range [ first_page, last_page [ into the SET state |
229 |
> |
#define PFLAG_SET_RANGE(first_page, last_page) \ |
230 |
> |
memset(mainBuffer.dirtyPages + (first_page), PFLAG_SET_VALUE, \ |
231 |
> |
(last_page) - (first_page)) |
232 |
> |
|
233 |
> |
// Set the selected page range [ first_page, last_page [ into the CLEAR state |
234 |
> |
#define PFLAG_CLEAR_RANGE(first_page, last_page) \ |
235 |
> |
memset(mainBuffer.dirtyPages + (first_page), PFLAG_CLEAR_VALUE, \ |
236 |
> |
(last_page) - (first_page)) |
237 |
> |
|
238 |
> |
#define PFLAG_SET_ALL do { \ |
239 |
> |
PFLAG_SET_RANGE(0, mainBuffer.pageCount); \ |
240 |
> |
mainBuffer.dirty = true; \ |
241 |
> |
} while (0) |
242 |
> |
|
243 |
> |
#define PFLAG_CLEAR_ALL do { \ |
244 |
> |
PFLAG_CLEAR_RANGE(0, mainBuffer.pageCount); \ |
245 |
> |
mainBuffer.dirty = false; \ |
246 |
> |
} while (0) |
247 |
> |
|
248 |
> |
// Set the following macro definition to 1 if your system |
249 |
> |
// provides a really fast strchr() implementation |
250 |
> |
//#define HAVE_FAST_STRCHR 0 |
251 |
> |
|
252 |
> |
static inline int find_next_page_set(int page) |
253 |
> |
{ |
254 |
> |
#if HAVE_FAST_STRCHR |
255 |
> |
char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_SET_VALUE); |
256 |
> |
return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount; |
257 |
|
#else |
258 |
< |
# define PFLAG_ISCLEAR_4(page) \ |
259 |
< |
(mainBuffer.dirtyPages[page ] == 0) \ |
260 |
< |
&& (mainBuffer.dirtyPages[page+1] == 0) \ |
261 |
< |
&& (mainBuffer.dirtyPages[page+2] == 0) \ |
262 |
< |
&& (mainBuffer.dirtyPages[page+3] == 0) |
258 |
> |
while (PFLAG_ISCLEAR_4(page)) |
259 |
> |
page += 4; |
260 |
> |
while (PFLAG_ISCLEAR(page)) |
261 |
> |
page++; |
262 |
> |
return page; |
263 |
|
#endif |
264 |
< |
#define PFLAG_CLEAR_ALL memset(mainBuffer.dirtyPages, 0, mainBuffer.pageCount) |
265 |
< |
#define PFLAG_SET_ALL memset(mainBuffer.dirtyPages, 1, mainBuffer.pageCount) |
264 |
> |
} |
265 |
> |
|
266 |
> |
static inline int find_next_page_clear(int page) |
267 |
> |
{ |
268 |
> |
#if HAVE_FAST_STRCHR |
269 |
> |
char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_CLEAR_VALUE); |
270 |
> |
return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount; |
271 |
> |
#else |
272 |
> |
while (PFLAG_ISSET_4(page)) |
273 |
> |
page += 4; |
274 |
> |
while (PFLAG_ISSET(page)) |
275 |
> |
page++; |
276 |
> |
return page; |
277 |
> |
#endif |
278 |
> |
} |
279 |
|
|
280 |
|
static int zero_fd = -1; |
281 |
|
static bool Screen_fault_handler_init(); |
300 |
|
} |
301 |
|
return l; |
302 |
|
} |
303 |
< |
|
246 |
< |
#endif |
303 |
> |
#endif /* ENABLE_VOSF */ |
304 |
|
|
305 |
|
// VideoRefresh function |
306 |
|
void VideoRefreshInit(void); |
391 |
|
hints->res_name = "BasiliskII"; |
392 |
|
hints->res_class = "BasiliskII"; |
393 |
|
XSetClassHint(x_display, w, hints); |
394 |
< |
XFree((char *)hints); |
394 |
> |
XFree(hints); |
395 |
|
} |
396 |
|
} |
397 |
|
|
404 |
|
hints->initial_state = NormalState; |
405 |
|
hints->flags = InputHint | StateHint; |
406 |
|
XSetWMHints(x_display, w, hints); |
407 |
< |
XFree((char *)hints); |
407 |
> |
XFree(hints); |
408 |
|
} |
409 |
|
} |
410 |
|
|
485 |
|
hints->max_height = height; |
486 |
|
hints->flags = PMinSize | PMaxSize; |
487 |
|
XSetWMNormalHints(x_display, the_win, hints); |
488 |
< |
XFree((char *)hints); |
488 |
> |
XFree(hints); |
489 |
|
} |
490 |
|
} |
491 |
|
|
580 |
|
native_byte_order = (XImageByteOrder(x_display) == LSBFirst); |
581 |
|
#endif |
582 |
|
#ifdef ENABLE_VOSF |
583 |
< |
do_update_framebuffer = GET_FBCOPY_FUNC(depth, native_byte_order, DISPLAY_WINDOW); |
583 |
> |
Screen_blitter_init(&visualInfo, native_byte_order); |
584 |
|
#endif |
585 |
|
set_video_monitor(width, height, img->bytes_per_line, native_byte_order); |
586 |
|
|
719 |
|
|
720 |
|
#if ENABLE_VOSF |
721 |
|
#if REAL_ADDRESSING || DIRECT_ADDRESSING |
722 |
< |
// If the blit function is null, i.e. just a copy of the buffer, |
723 |
< |
// we first try to avoid the allocation of a temporary frame buffer |
724 |
< |
use_vosf = true; |
668 |
< |
do_update_framebuffer = GET_FBCOPY_FUNC(depth, true, DISPLAY_DGA); |
669 |
< |
if (do_update_framebuffer == FBCOPY_FUNC(fbcopy_raw)) |
670 |
< |
use_vosf = false; |
722 |
> |
// Screen_blitter_init() returns TRUE if VOSF is mandatory |
723 |
> |
// i.e. the framebuffer update function is not Blit_Copy_Raw |
724 |
> |
use_vosf = Screen_blitter_init(&visualInfo, true); |
725 |
|
|
726 |
|
if (use_vosf) { |
727 |
|
the_host_buffer = the_buffer; |
826 |
|
} |
827 |
|
|
828 |
|
#if REAL_ADDRESSING || DIRECT_ADDRESSING |
829 |
< |
// If the blit function is null, i.e. just a copy of the buffer, |
830 |
< |
// we first try to avoid the allocation of a temporary frame buffer |
831 |
< |
use_vosf = true; |
778 |
< |
do_update_framebuffer = GET_FBCOPY_FUNC(depth, true, DISPLAY_DGA); |
779 |
< |
if (do_update_framebuffer == FBCOPY_FUNC(fbcopy_raw)) |
780 |
< |
use_vosf = false; |
829 |
> |
// Screen_blitter_init() returns TRUE if VOSF is mandatory |
830 |
> |
// i.e. the framebuffer update function is not Blit_Copy_Raw |
831 |
> |
use_vosf = Screen_blitter_init(&visualInfo, true); |
832 |
|
|
833 |
|
if (use_vosf) { |
834 |
|
the_host_buffer = the_buffer; |
942 |
|
if (mainBuffer.dirtyPages != 0) |
943 |
|
free(mainBuffer.dirtyPages); |
944 |
|
|
945 |
< |
mainBuffer.dirtyPages = (uint8 *) malloc(mainBuffer.pageCount); |
945 |
> |
mainBuffer.dirtyPages = (char *) malloc(mainBuffer.pageCount + 2); |
946 |
|
|
947 |
|
if (mainBuffer.pageInfo != 0) |
948 |
|
free(mainBuffer.pageInfo); |
951 |
|
|
952 |
|
if ((mainBuffer.dirtyPages == 0) || (mainBuffer.pageInfo == 0)) |
953 |
|
return false; |
954 |
+ |
|
955 |
+ |
mainBuffer.dirty = false; |
956 |
|
|
957 |
|
PFLAG_CLEAR_ALL; |
958 |
+ |
// Safety net to insure the loops in the update routines will terminate |
959 |
+ |
// See a discussion in <video_vosf.h> for further details |
960 |
+ |
PFLAG_CLEAR(mainBuffer.pageCount); |
961 |
+ |
PFLAG_SET(mainBuffer.pageCount+1); |
962 |
|
|
963 |
|
uint32 a = 0; |
964 |
|
for (int i = 0; i < mainBuffer.pageCount; i++) { |
1011 |
|
keycode_init(); |
1012 |
|
|
1013 |
|
// Read prefs |
1014 |
< |
mouse_wheel_mode = PrefsFindInt16("mousewheelmode"); |
1015 |
< |
mouse_wheel_lines = PrefsFindInt16("mousewheellines"); |
1014 |
> |
mouse_wheel_mode = PrefsFindInt32("mousewheelmode"); |
1015 |
> |
mouse_wheel_lines = PrefsFindInt32("mousewheellines"); |
1016 |
|
|
1017 |
|
// Find screen and root window |
1018 |
|
screen = XDefaultScreen(x_display); |
1950 |
|
* Screen refresh functions |
1951 |
|
*/ |
1952 |
|
|
1953 |
< |
// The specialisations hereunder are meant to enable VOSF with DGA in direct |
1954 |
< |
// addressing mode in case the address spaces (RAM, ROM, FrameBuffer) could |
1955 |
< |
// not get mapped correctly with respect to the predetermined host frame |
1956 |
< |
// buffer base address. |
1957 |
< |
// |
1901 |
< |
// Hmm, in other words, when in direct addressing mode and DGA is requested, |
1902 |
< |
// we first try to "triple allocate" the address spaces according to the real |
1903 |
< |
// host frame buffer address. Then, if it fails, we will use a temporary |
1904 |
< |
// frame buffer thus making the real host frame buffer updated when pages |
1905 |
< |
// of the temp frame buffer are altered. |
1906 |
< |
// |
1907 |
< |
// As a side effect, a little speed gain in screen updates could be noticed |
1908 |
< |
// for other modes than DGA. |
1909 |
< |
// |
1910 |
< |
// The following two functions below are inline so that a clever compiler |
1911 |
< |
// could specialise the code according to the current screen depth and |
1912 |
< |
// display type. A more clever compiler would the job by itself though... |
1913 |
< |
// (update_display_vosf is inlined as well) |
1953 |
> |
// We suggest the compiler to inline the next two functions so that it |
1954 |
> |
// may specialise the code according to the current screen depth and |
1955 |
> |
// display type. A clever compiler would do that job by itself though... |
1956 |
> |
|
1957 |
> |
// NOTE: update_display_vosf is inlined too |
1958 |
|
|
1959 |
|
static inline void possibly_quit_dga_mode() |
1960 |
|
{ |
2025 |
|
static int tick_counter = 0; |
2026 |
|
if (++tick_counter >= frame_skip) { |
2027 |
|
tick_counter = 0; |
2028 |
< |
LOCK_VOSF; |
2029 |
< |
update_display_dga_vosf(); |
2030 |
< |
UNLOCK_VOSF; |
2028 |
> |
if (mainBuffer.dirty) { |
2029 |
> |
LOCK_VOSF; |
2030 |
> |
update_display_dga_vosf(); |
2031 |
> |
UNLOCK_VOSF; |
2032 |
> |
} |
2033 |
|
} |
2034 |
|
} |
2035 |
|
#endif |
2049 |
|
static int tick_counter = 0; |
2050 |
|
if (++tick_counter >= frame_skip) { |
2051 |
|
tick_counter = 0; |
2052 |
< |
LOCK_VOSF; |
2053 |
< |
update_display_window_vosf(); |
2054 |
< |
UNLOCK_VOSF; |
2052 |
> |
if (mainBuffer.dirty) { |
2053 |
> |
LOCK_VOSF; |
2054 |
> |
update_display_window_vosf(); |
2055 |
> |
UNLOCK_VOSF; |
2056 |
> |
} |
2057 |
|
} |
2058 |
|
} |
2059 |
|
#endif // def ENABLE_VOSF |
2140 |
|
ticks++; |
2141 |
|
} |
2142 |
|
uint64 end = GetTicks_usec(); |
2143 |
< |
printf("%Ld ticks in %Ld usec = %Ld ticks/sec\n", ticks, end - start, (end - start) / ticks); |
2143 |
> |
printf("%Ld ticks in %Ld usec = %Ld ticks/sec\n", ticks, end - start, ticks * 1000000 / (end - start)); |
2144 |
|
return NULL; |
2145 |
|
} |
2146 |
|
#endif |