1 |
|
/* |
2 |
|
* video_vosf.h - Video/graphics emulation, video on SEGV signals support |
3 |
|
* |
4 |
< |
* Basilisk II (C) 1997-2005 Christian Bauer |
4 |
> |
* Basilisk II (C) 1997-2008 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 |
31 |
|
#endif |
32 |
|
|
33 |
|
// Glue for SDL and X11 support |
34 |
+ |
#ifdef TEST_VOSF_PERFORMANCE |
35 |
+ |
#define MONITOR_INIT /* nothing */ |
36 |
+ |
#else |
37 |
|
#ifdef USE_SDL_VIDEO |
38 |
|
#define MONITOR_INIT SDL_monitor_desc &monitor |
39 |
|
#define VIDEO_DRV_WIN_INIT driver_window *drv |
40 |
|
#define VIDEO_DRV_DGA_INIT driver_fullscreen *drv |
41 |
< |
#define VIDEO_DRV_LOCK_PIXELS if (SDL_MUSTLOCK(drv->s)) SDL_LockSurface(drv->s) |
42 |
< |
#define VIDEO_DRV_UNLOCK_PIXELS if (SDL_MUSTLOCK(drv->s)) SDL_UnlockSurface(drv->s) |
41 |
> |
#define VIDEO_DRV_LOCK_PIXELS SDL_VIDEO_LOCK_SURFACE(drv->s) |
42 |
> |
#define VIDEO_DRV_UNLOCK_PIXELS SDL_VIDEO_UNLOCK_SURFACE(drv->s) |
43 |
|
#define VIDEO_DRV_DEPTH drv->s->format->BitsPerPixel |
44 |
|
#define VIDEO_DRV_WIDTH drv->s->w |
45 |
|
#define VIDEO_DRV_HEIGHT drv->s->h |
69 |
|
#define VIDEO_DRV_HEIGHT VIDEO_DRV_IMAGE->height |
70 |
|
#define VIDEO_DRV_ROW_BYTES VIDEO_DRV_IMAGE->bytes_per_line |
71 |
|
#endif |
72 |
+ |
#endif |
73 |
+ |
|
74 |
+ |
// Prototypes |
75 |
+ |
static void vosf_do_set_dirty_area(uintptr first, uintptr last); |
76 |
+ |
static void vosf_set_dirty_area(int x, int y, int w, int h, int screen_width, int screen_height, int bytes_per_row); |
77 |
|
|
78 |
|
// Variables for Video on SEGV support |
79 |
|
static uint8 *the_host_buffer; // Host frame buffer in VOSF mode |
176 |
|
#endif |
177 |
|
} |
178 |
|
|
179 |
< |
#ifdef HAVE_SPINLOCKS |
180 |
< |
static spinlock_t vosf_lock = SPIN_LOCK_UNLOCKED; // Mutex to protect frame buffer (dirtyPages in fact) |
181 |
< |
#define LOCK_VOSF spin_lock(&vosf_lock) |
182 |
< |
#define UNLOCK_VOSF spin_unlock(&vosf_lock) |
179 |
> |
#if defined(HAVE_PTHREADS) |
180 |
> |
static pthread_mutex_t vosf_lock = PTHREAD_MUTEX_INITIALIZER; // Mutex to protect frame buffer (dirtyPages in fact) |
181 |
> |
#define LOCK_VOSF pthread_mutex_lock(&vosf_lock); |
182 |
> |
#define UNLOCK_VOSF pthread_mutex_unlock(&vosf_lock); |
183 |
|
#elif defined(_WIN32) |
184 |
|
static mutex_t vosf_lock; // Mutex to protect frame buffer (dirtyPages in fact) |
185 |
|
#define LOCK_VOSF vosf_lock.lock(); |
186 |
|
#define UNLOCK_VOSF vosf_lock.unlock(); |
187 |
< |
#elif defined(HAVE_PTHREADS) |
188 |
< |
static pthread_mutex_t vosf_lock = PTHREAD_MUTEX_INITIALIZER; // Mutex to protect frame buffer (dirtyPages in fact) |
189 |
< |
#define LOCK_VOSF pthread_mutex_lock(&vosf_lock); |
190 |
< |
#define UNLOCK_VOSF pthread_mutex_unlock(&vosf_lock); |
187 |
> |
#elif defined(HAVE_SPINLOCKS) |
188 |
> |
static spinlock_t vosf_lock = SPIN_LOCK_UNLOCKED; // Mutex to protect frame buffer (dirtyPages in fact) |
189 |
> |
#define LOCK_VOSF spin_lock(&vosf_lock) |
190 |
> |
#define UNLOCK_VOSF spin_unlock(&vosf_lock) |
191 |
|
#else |
192 |
|
#define LOCK_VOSF |
193 |
|
#define UNLOCK_VOSF |
217 |
|
* Check if VOSF acceleration is profitable on this platform |
218 |
|
*/ |
219 |
|
|
220 |
< |
const int VOSF_PROFITABLE_TRIES = 3; // Make 3 attempts for full screen update |
221 |
< |
const int VOSF_PROFITABLE_THRESHOLD = 16667; // 60 Hz |
220 |
> |
#ifndef VOSF_PROFITABLE_TRIES |
221 |
> |
#define VOSF_PROFITABLE_TRIES VOSF_PROFITABLE_TRIES_DFL |
222 |
> |
#endif |
223 |
> |
const int VOSF_PROFITABLE_TRIES_DFL = 1000; // Make 3 attempts for full screen update |
224 |
> |
const int VOSF_PROFITABLE_THRESHOLD = 16667/2; // 60 Hz (half of the quantum) |
225 |
|
|
226 |
< |
static bool video_vosf_profitable(void) |
226 |
> |
static bool video_vosf_profitable(uint32 *duration_p = NULL, uint32 *n_page_faults_p = NULL) |
227 |
|
{ |
228 |
< |
int64 durations[VOSF_PROFITABLE_TRIES]; |
229 |
< |
int mean_duration = 0; |
228 |
> |
uint32 duration = 0; |
229 |
> |
uint32 n_tries = VOSF_PROFITABLE_TRIES; |
230 |
> |
const uint32 n_page_faults = mainBuffer.pageCount * n_tries; |
231 |
|
|
232 |
< |
for (int i = 0; i < VOSF_PROFITABLE_TRIES; i++) { |
232 |
> |
#ifdef SHEEPSHAVER |
233 |
> |
const bool accel = PrefsFindBool("gfxaccel"); |
234 |
> |
#else |
235 |
> |
const bool accel = false; |
236 |
> |
#endif |
237 |
> |
|
238 |
> |
for (int i = 0; i < n_tries; i++) { |
239 |
|
uint64 start = GetTicks_usec(); |
240 |
|
for (int p = 0; p < mainBuffer.pageCount; p++) { |
241 |
|
uint8 *addr = (uint8 *)(mainBuffer.memStart + (p * mainBuffer.pageSize)); |
242 |
< |
addr[0] = 0; // Trigger Screen_fault_handler() |
242 |
> |
if (accel) |
243 |
> |
vosf_do_set_dirty_area((uintptr)addr, (uintptr)addr + mainBuffer.pageSize - 1); |
244 |
> |
else |
245 |
> |
addr[0] = 0; // Trigger Screen_fault_handler() |
246 |
|
} |
247 |
< |
int64 duration = GetTicks_usec() - start; |
248 |
< |
mean_duration += duration; |
228 |
< |
durations[i] = duration; |
247 |
> |
uint64 elapsed = GetTicks_usec() - start; |
248 |
> |
duration += elapsed; |
249 |
|
|
250 |
|
PFLAG_CLEAR_ALL; |
251 |
|
mainBuffer.dirty = false; |
253 |
|
return false; |
254 |
|
} |
255 |
|
|
256 |
< |
mean_duration /= VOSF_PROFITABLE_TRIES; |
257 |
< |
D(bug("Triggered %d screen faults in %ld usec on average\n", mainBuffer.pageCount, mean_duration)); |
258 |
< |
return (mean_duration < (VOSF_PROFITABLE_THRESHOLD * (frame_skip ? frame_skip : 1))); |
256 |
> |
if (duration_p) |
257 |
> |
*duration_p = duration; |
258 |
> |
if (n_page_faults_p) |
259 |
> |
*n_page_faults_p = n_page_faults; |
260 |
> |
|
261 |
> |
D(bug("Triggered %d page faults in %ld usec (%.1f usec per fault)\n", n_page_faults, duration, double(duration) / double(n_page_faults))); |
262 |
> |
return ((duration / n_tries) < (VOSF_PROFITABLE_THRESHOLD * (frame_skip ? frame_skip : 1))); |
263 |
|
} |
264 |
|
|
265 |
|
|
346 |
|
|
347 |
|
|
348 |
|
/* |
349 |
+ |
* Update VOSF state with specified dirty area |
350 |
+ |
*/ |
351 |
+ |
|
352 |
+ |
static void vosf_do_set_dirty_area(uintptr first, uintptr last) |
353 |
+ |
{ |
354 |
+ |
const int first_page = (first - mainBuffer.memStart) >> mainBuffer.pageBits; |
355 |
+ |
const int last_page = (last - mainBuffer.memStart) >> mainBuffer.pageBits; |
356 |
+ |
uint8 *addr = (uint8 *)(first & -mainBuffer.pageSize); |
357 |
+ |
for (int i = first_page; i <= last_page; i++) { |
358 |
+ |
if (PFLAG_ISCLEAR(i)) { |
359 |
+ |
PFLAG_SET(i); |
360 |
+ |
vm_protect(addr, mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE); |
361 |
+ |
} |
362 |
+ |
addr += mainBuffer.pageSize; |
363 |
+ |
} |
364 |
+ |
} |
365 |
+ |
|
366 |
+ |
static void vosf_set_dirty_area(int x, int y, int w, int h, int screen_width, int screen_height, int bytes_per_row) |
367 |
+ |
{ |
368 |
+ |
if (x < 0) { |
369 |
+ |
w -= -x; |
370 |
+ |
x = 0; |
371 |
+ |
} |
372 |
+ |
if (y < 0) { |
373 |
+ |
h -= -y; |
374 |
+ |
y = 0; |
375 |
+ |
} |
376 |
+ |
if (w <= 0 || h <= 0) |
377 |
+ |
return; |
378 |
+ |
if (x + w > screen_width) |
379 |
+ |
w -= (x + w) - screen_width; |
380 |
+ |
if (y + h > screen_height) |
381 |
+ |
h -= (y + h) - screen_height; |
382 |
+ |
LOCK_VOSF; |
383 |
+ |
if (bytes_per_row >= screen_width) { |
384 |
+ |
const int bytes_per_pixel = bytes_per_row / screen_width; |
385 |
+ |
if (bytes_per_row <= mainBuffer.pageSize) { |
386 |
+ |
const uintptr a0 = mainBuffer.memStart + y * bytes_per_row + x * bytes_per_pixel; |
387 |
+ |
const uintptr a1 = mainBuffer.memStart + (y + h - 1) * bytes_per_row + (x + w - 1) * bytes_per_pixel; |
388 |
+ |
vosf_do_set_dirty_area(a0, a1); |
389 |
+ |
} else { |
390 |
+ |
for (int j = y; j < y + h; j++) { |
391 |
+ |
const uintptr a0 = mainBuffer.memStart + j * bytes_per_row + x * bytes_per_pixel; |
392 |
+ |
const uintptr a1 = a0 + (w - 1) * bytes_per_pixel; |
393 |
+ |
vosf_do_set_dirty_area(a0, a1); |
394 |
+ |
} |
395 |
+ |
} |
396 |
+ |
} else { |
397 |
+ |
const int pixels_per_byte = screen_width / bytes_per_row; |
398 |
+ |
if (bytes_per_row <= mainBuffer.pageSize) { |
399 |
+ |
const uintptr a0 = mainBuffer.memStart + y * bytes_per_row + x / pixels_per_byte; |
400 |
+ |
const uintptr a1 = mainBuffer.memStart + (y + h - 1) * bytes_per_row + (x + w - 1) / pixels_per_byte; |
401 |
+ |
vosf_do_set_dirty_area(a0, a1); |
402 |
+ |
} else { |
403 |
+ |
for (int j = y; j < y + h; j++) { |
404 |
+ |
const uintptr a0 = mainBuffer.memStart + j * bytes_per_row + x / pixels_per_byte; |
405 |
+ |
const uintptr a1 = mainBuffer.memStart + j * bytes_per_row + (x + w - 1) / pixels_per_byte; |
406 |
+ |
vosf_do_set_dirty_area(a0, a1); |
407 |
+ |
} |
408 |
+ |
} |
409 |
+ |
} |
410 |
+ |
mainBuffer.dirty = true; |
411 |
+ |
UNLOCK_VOSF; |
412 |
+ |
} |
413 |
+ |
|
414 |
+ |
|
415 |
+ |
/* |
416 |
|
* Screen fault handler |
417 |
|
*/ |
418 |
|
|
419 |
< |
bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction) |
419 |
> |
bool Screen_fault_handler(sigsegv_info_t *sip) |
420 |
|
{ |
421 |
< |
const uintptr addr = (uintptr)fault_address; |
421 |
> |
const uintptr addr = (uintptr)sigsegv_get_fault_address(sip); |
422 |
|
|
423 |
|
/* Someone attempted to write to the frame buffer. Make it writeable |
424 |
|
* now so that the data could actually be written to. It will be made |
427 |
|
if (((uintptr)addr - mainBuffer.memStart) < mainBuffer.memLength) { |
428 |
|
const int page = ((uintptr)addr - mainBuffer.memStart) >> mainBuffer.pageBits; |
429 |
|
LOCK_VOSF; |
430 |
< |
PFLAG_SET(page); |
431 |
< |
vm_protect((char *)(addr & -mainBuffer.pageSize), mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE); |
430 |
> |
if (PFLAG_ISCLEAR(page)) { |
431 |
> |
PFLAG_SET(page); |
432 |
> |
vm_protect((char *)(addr & -mainBuffer.pageSize), mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE); |
433 |
> |
} |
434 |
|
mainBuffer.dirty = true; |
435 |
|
UNLOCK_VOSF; |
436 |
|
return true; |
478 |
|
than pageCount. |
479 |
|
*/ |
480 |
|
|
481 |
+ |
#ifndef TEST_VOSF_PERFORMANCE |
482 |
|
static void update_display_window_vosf(VIDEO_DRV_WIN_INIT) |
483 |
|
{ |
484 |
|
VIDEO_MODE_INIT; |
525 |
|
} |
526 |
|
mainBuffer.dirty = false; |
527 |
|
} |
528 |
+ |
#endif |
529 |
|
|
530 |
|
|
531 |
|
/* |
533 |
|
* (only in Real or Direct Addressing mode) |
534 |
|
*/ |
535 |
|
|
536 |
+ |
#ifndef TEST_VOSF_PERFORMANCE |
537 |
|
#if REAL_ADDRESSING || DIRECT_ADDRESSING |
538 |
|
static void update_display_dga_vosf(VIDEO_DRV_DGA_INIT) |
539 |
|
{ |
669 |
|
mainBuffer.dirty = false; |
670 |
|
} |
671 |
|
#endif |
672 |
+ |
#endif |
673 |
|
|
674 |
|
#endif /* ENABLE_VOSF */ |
675 |
|
|