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 |
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 |
221 |
> |
const int VOSF_PROFITABLE_THRESHOLD = 16667/2; // 60 Hz (half of the quantum) |
222 |
|
|
223 |
|
static bool video_vosf_profitable(void) |
224 |
|
{ |
225 |
< |
int64 durations[VOSF_PROFITABLE_TRIES]; |
226 |
< |
int mean_duration = 0; |
225 |
> |
uint32 duration = 0; |
226 |
> |
const uint32 n_page_faults = mainBuffer.pageCount * VOSF_PROFITABLE_TRIES; |
227 |
> |
|
228 |
> |
#ifdef SHEEPSHAVER |
229 |
> |
const bool accel = PrefsFindBool("gfxaccel"); |
230 |
> |
#else |
231 |
> |
const bool accel = false; |
232 |
> |
#endif |
233 |
|
|
234 |
|
for (int i = 0; i < VOSF_PROFITABLE_TRIES; i++) { |
235 |
|
uint64 start = GetTicks_usec(); |
236 |
|
for (int p = 0; p < mainBuffer.pageCount; p++) { |
237 |
|
uint8 *addr = (uint8 *)(mainBuffer.memStart + (p * mainBuffer.pageSize)); |
238 |
< |
addr[0] = 0; // Trigger Screen_fault_handler() |
238 |
> |
if (accel) |
239 |
> |
vosf_do_set_dirty_area((uintptr)addr, (uintptr)addr + mainBuffer.pageSize - 1); |
240 |
> |
else |
241 |
> |
addr[0] = 0; // Trigger Screen_fault_handler() |
242 |
|
} |
243 |
< |
int64 duration = GetTicks_usec() - start; |
244 |
< |
mean_duration += duration; |
228 |
< |
durations[i] = duration; |
243 |
> |
uint64 elapsed = GetTicks_usec() - start; |
244 |
> |
duration += elapsed; |
245 |
|
|
246 |
|
PFLAG_CLEAR_ALL; |
247 |
|
mainBuffer.dirty = false; |
249 |
|
return false; |
250 |
|
} |
251 |
|
|
252 |
< |
mean_duration /= VOSF_PROFITABLE_TRIES; |
253 |
< |
D(bug("Triggered %d screen faults in %ld usec on average\n", mainBuffer.pageCount, mean_duration)); |
238 |
< |
return (mean_duration < (VOSF_PROFITABLE_THRESHOLD * (frame_skip ? frame_skip : 1))); |
252 |
> |
D(bug("Triggered %d page faults in %ld usec (%.1f usec per fault)\n", n_page_faults, duration, double(duration) / double(n_page_faults))); |
253 |
> |
return ((duration / VOSF_PROFITABLE_TRIES) < (VOSF_PROFITABLE_THRESHOLD * (frame_skip ? frame_skip : 1))); |
254 |
|
} |
255 |
|
|
256 |
|
|
337 |
|
|
338 |
|
|
339 |
|
/* |
340 |
+ |
* Update VOSF state with specified dirty area |
341 |
+ |
*/ |
342 |
+ |
|
343 |
+ |
static void vosf_do_set_dirty_area(uintptr first, uintptr last) |
344 |
+ |
{ |
345 |
+ |
const int first_page = (first - mainBuffer.memStart) >> mainBuffer.pageBits; |
346 |
+ |
const int last_page = (last - mainBuffer.memStart) >> mainBuffer.pageBits; |
347 |
+ |
uint8 *addr = (uint8 *)(first & -mainBuffer.pageSize); |
348 |
+ |
for (int i = first_page; i <= last_page; i++) { |
349 |
+ |
if (PFLAG_ISCLEAR(i)) { |
350 |
+ |
PFLAG_SET(i); |
351 |
+ |
vm_protect(addr, mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE); |
352 |
+ |
} |
353 |
+ |
addr += mainBuffer.pageSize; |
354 |
+ |
} |
355 |
+ |
} |
356 |
+ |
|
357 |
+ |
static void vosf_set_dirty_area(int x, int y, int w, int h, int screen_width, int screen_height, int bytes_per_row) |
358 |
+ |
{ |
359 |
+ |
if (x < 0) { |
360 |
+ |
w -= -x; |
361 |
+ |
x = 0; |
362 |
+ |
} |
363 |
+ |
if (y < 0) { |
364 |
+ |
h -= -y; |
365 |
+ |
y = 0; |
366 |
+ |
} |
367 |
+ |
if (w <= 0 || h <= 0) |
368 |
+ |
return; |
369 |
+ |
if (x + w > screen_width) |
370 |
+ |
w -= (x + w) - screen_width; |
371 |
+ |
if (y + h > screen_height) |
372 |
+ |
h -= (y + h) - screen_height; |
373 |
+ |
LOCK_VOSF; |
374 |
+ |
if (bytes_per_row >= screen_width) { |
375 |
+ |
const int bytes_per_pixel = bytes_per_row / screen_width; |
376 |
+ |
if (bytes_per_row <= mainBuffer.pageSize) { |
377 |
+ |
const uintptr a0 = mainBuffer.memStart + y * bytes_per_row + x * bytes_per_pixel; |
378 |
+ |
const uintptr a1 = mainBuffer.memStart + (y + h - 1) * bytes_per_row + (x + w - 1) * bytes_per_pixel; |
379 |
+ |
vosf_do_set_dirty_area(a0, a1); |
380 |
+ |
} else { |
381 |
+ |
for (int j = y; j < y + h; j++) { |
382 |
+ |
const uintptr a0 = mainBuffer.memStart + j * bytes_per_row + x * bytes_per_pixel; |
383 |
+ |
const uintptr a1 = a0 + (w - 1) * bytes_per_pixel; |
384 |
+ |
vosf_do_set_dirty_area(a0, a1); |
385 |
+ |
} |
386 |
+ |
} |
387 |
+ |
} else { |
388 |
+ |
const int pixels_per_byte = screen_width / bytes_per_row; |
389 |
+ |
if (bytes_per_row <= mainBuffer.pageSize) { |
390 |
+ |
const uintptr a0 = mainBuffer.memStart + y * bytes_per_row + x / pixels_per_byte; |
391 |
+ |
const uintptr a1 = mainBuffer.memStart + (y + h - 1) * bytes_per_row + (x + w - 1) / pixels_per_byte; |
392 |
+ |
vosf_do_set_dirty_area(a0, a1); |
393 |
+ |
} else { |
394 |
+ |
for (int j = y; j < y + h; j++) { |
395 |
+ |
const uintptr a0 = mainBuffer.memStart + j * bytes_per_row + x / pixels_per_byte; |
396 |
+ |
const uintptr a1 = mainBuffer.memStart + j * bytes_per_row + (x + w - 1) / pixels_per_byte; |
397 |
+ |
vosf_do_set_dirty_area(a0, a1); |
398 |
+ |
} |
399 |
+ |
} |
400 |
+ |
} |
401 |
+ |
mainBuffer.dirty = true; |
402 |
+ |
UNLOCK_VOSF; |
403 |
+ |
} |
404 |
+ |
|
405 |
+ |
|
406 |
+ |
/* |
407 |
|
* Screen fault handler |
408 |
|
*/ |
409 |
|
|
410 |
< |
bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction) |
410 |
> |
bool Screen_fault_handler(sigsegv_info_t *sip) |
411 |
|
{ |
412 |
< |
const uintptr addr = (uintptr)fault_address; |
412 |
> |
const uintptr addr = (uintptr)sigsegv_get_fault_address(sip); |
413 |
|
|
414 |
|
/* Someone attempted to write to the frame buffer. Make it writeable |
415 |
|
* now so that the data could actually be written to. It will be made |
418 |
|
if (((uintptr)addr - mainBuffer.memStart) < mainBuffer.memLength) { |
419 |
|
const int page = ((uintptr)addr - mainBuffer.memStart) >> mainBuffer.pageBits; |
420 |
|
LOCK_VOSF; |
421 |
< |
PFLAG_SET(page); |
422 |
< |
vm_protect((char *)(addr & -mainBuffer.pageSize), mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE); |
421 |
> |
if (PFLAG_ISCLEAR(page)) { |
422 |
> |
PFLAG_SET(page); |
423 |
> |
vm_protect((char *)(addr & -mainBuffer.pageSize), mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE); |
424 |
> |
} |
425 |
|
mainBuffer.dirty = true; |
426 |
|
UNLOCK_VOSF; |
427 |
|
return true; |
469 |
|
than pageCount. |
470 |
|
*/ |
471 |
|
|
472 |
+ |
#ifndef TEST_VOSF_PERFORMANCE |
473 |
|
static void update_display_window_vosf(VIDEO_DRV_WIN_INIT) |
474 |
|
{ |
475 |
|
VIDEO_MODE_INIT; |
516 |
|
} |
517 |
|
mainBuffer.dirty = false; |
518 |
|
} |
519 |
+ |
#endif |
520 |
|
|
521 |
|
|
522 |
|
/* |
524 |
|
* (only in Real or Direct Addressing mode) |
525 |
|
*/ |
526 |
|
|
527 |
+ |
#ifndef TEST_VOSF_PERFORMANCE |
528 |
|
#if REAL_ADDRESSING || DIRECT_ADDRESSING |
529 |
|
static void update_display_dga_vosf(VIDEO_DRV_DGA_INIT) |
530 |
|
{ |
660 |
|
mainBuffer.dirty = false; |
661 |
|
} |
662 |
|
#endif |
663 |
+ |
#endif |
664 |
|
|
665 |
|
#endif /* ENABLE_VOSF */ |
666 |
|
|