21
21
#ifndef VIDEO_VOSF_H
22
22
#define VIDEO_VOSF_H
24
// Note: this file is #include'd in video_x.cpp
24
// Note: this file must be #include'd only in video_x.cpp
29
27
#include "sigsegv.h"
30
28
#include "vm_alloc.h"
30
#include "util_windows.h"
32
// Glue for SheepShaver and BasiliskII
34
#define X11_MONITOR_INIT /* nothing */
35
#define VIDEO_DRV_INIT /* nothing */
33
// Glue for SDL and X11 support
35
#define MONITOR_INIT SDL_monitor_desc &monitor
36
#define VIDEO_DRV_WIN_INIT driver_window *drv
37
#define VIDEO_DRV_DGA_INIT driver_fullscreen *drv
38
#define VIDEO_DRV_LOCK_PIXELS if (SDL_MUSTLOCK(drv->s)) SDL_LockSurface(drv->s)
39
#define VIDEO_DRV_UNLOCK_PIXELS if (SDL_MUSTLOCK(drv->s)) SDL_UnlockSurface(drv->s)
40
#define VIDEO_DRV_DEPTH drv->s->format->BitsPerPixel
41
#define VIDEO_DRV_WIDTH drv->s->w
42
#define VIDEO_DRV_HEIGHT drv->s->h
43
#define VIDEO_DRV_ROW_BYTES drv->s->pitch
46
#define MONITOR_INIT /* nothing */
47
#define VIDEO_DRV_WIN_INIT /* nothing */
48
#define VIDEO_DRV_DGA_INIT /* nothing */
36
49
#define VIDEO_DRV_WINDOW the_win
37
50
#define VIDEO_DRV_GC the_gc
38
51
#define VIDEO_DRV_IMAGE img
39
52
#define VIDEO_DRV_HAVE_SHM have_shm
40
#define VIDEO_MODE_INIT VideoInfo const & mode = VModes[cur_mode]
41
#define VIDEO_MODE_ROW_BYTES mode.viRowBytes
42
#define VIDEO_MODE_X mode.viXsize
43
#define VIDEO_MODE_Y mode.viYsize
44
#define VIDEO_MODE_DEPTH mode.viAppleMode
46
VIDEO_DEPTH_1BIT = APPLE_1_BIT,
47
VIDEO_DEPTH_2BIT = APPLE_2_BIT,
48
VIDEO_DEPTH_4BIT = APPLE_4_BIT,
49
VIDEO_DEPTH_8BIT = APPLE_8_BIT,
50
VIDEO_DEPTH_16BIT = APPLE_16_BIT,
51
VIDEO_DEPTH_32BIT = APPLE_32_BIT
54
#define X11_MONITOR_INIT X11_monitor_desc &monitor
55
#define VIDEO_DRV_INIT driver_window *drv
54
#define MONITOR_INIT X11_monitor_desc &monitor
55
#define VIDEO_DRV_WIN_INIT driver_window *drv
56
#define VIDEO_DRV_DGA_INIT driver_dga *drv
56
57
#define VIDEO_DRV_WINDOW drv->w
57
58
#define VIDEO_DRV_GC drv->gc
58
59
#define VIDEO_DRV_IMAGE drv->img
59
60
#define VIDEO_DRV_HAVE_SHM drv->have_shm
60
#define VIDEO_MODE_INIT video_mode const & mode = drv->monitor.get_current_mode();
61
#define VIDEO_MODE_ROW_BYTES mode.bytes_per_row
62
#define VIDEO_MODE_X mode.x
63
#define VIDEO_MODE_Y mode.y
64
#define VIDEO_MODE_DEPTH (int)mode.depth
66
VIDEO_DEPTH_1BIT = VDEPTH_1BIT,
67
VIDEO_DEPTH_2BIT = VDEPTH_2BIT,
68
VIDEO_DEPTH_4BIT = VDEPTH_4BIT,
69
VIDEO_DEPTH_8BIT = VDEPTH_8BIT,
70
VIDEO_DEPTH_16BIT = VDEPTH_16BIT,
71
VIDEO_DEPTH_32BIT = VDEPTH_32BIT
62
#define VIDEO_DRV_LOCK_PIXELS /* nothing */
63
#define VIDEO_DRV_UNLOCK_PIXELS /* nothing */
64
#define VIDEO_DRV_DEPTH VIDEO_DRV_IMAGE->depth
65
#define VIDEO_DRV_WIDTH VIDEO_DRV_IMAGE->width
66
#define VIDEO_DRV_HEIGHT VIDEO_DRV_IMAGE->height
67
#define VIDEO_DRV_ROW_BYTES VIDEO_DRV_IMAGE->bytes_per_line
75
70
// Variables for Video on SEGV support
190
199
// Extend size to page boundary
191
200
static uint32 page_extend(uint32 size)
193
const uint32 page_size = getpagesize();
202
const uint32 page_size = vm_get_page_size();
194
203
const uint32 page_mask = page_size - 1;
195
204
return (size + page_mask) & ~page_mask;
209
* Check if VOSF acceleration is profitable on this platform
212
const int VOSF_PROFITABLE_TRIES = 3; // Make 3 attempts for full screen update
213
const int VOSF_PROFITABLE_THRESHOLD = 16667; // 60 Hz
215
static bool video_vosf_profitable(void)
217
int64 durations[VOSF_PROFITABLE_TRIES];
218
int mean_duration = 0;
220
for (int i = 0; i < VOSF_PROFITABLE_TRIES; i++) {
221
uint64 start = GetTicks_usec();
222
for (int p = 0; p < mainBuffer.pageCount; p++) {
223
uint8 *addr = (uint8 *)(mainBuffer.memStart + (p * mainBuffer.pageSize));
224
addr[0] = 0; // Trigger Screen_fault_handler()
226
int64 duration = GetTicks_usec() - start;
227
mean_duration += duration;
228
durations[i] = duration;
231
mainBuffer.dirty = false;
232
if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0)
236
mean_duration /= VOSF_PROFITABLE_TRIES;
237
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)));
200
243
* Initialize the VOSF system (mainBuffer structure, SIGSEGV handler)
203
#if !EMULATED_PPC && !POWERPC_ROM
206
bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction);
208
static bool video_vosf_init(X11_MONITOR_INIT)
246
static bool video_vosf_init(MONITOR_INIT)
248
VIDEO_MODE_INIT_MONITOR;
212
const uintptr page_size = getpagesize();
250
const uintptr page_size = vm_get_page_size();
213
251
const uintptr page_mask = page_size - 1;
215
253
// Round up frame buffer base to page boundary
380
407
const int y1 = mainBuffer.pageInfo[first_page].top;
381
408
const int y2 = mainBuffer.pageInfo[page - 1].bottom;
382
409
const int height = y2 - y1 + 1;
384
if (VIDEO_MODE_DEPTH < VIDEO_DEPTH_8BIT) {
386
// Update the_host_buffer and copy of the_buffer
387
const int src_bytes_per_row = VIDEO_MODE_ROW_BYTES;
388
const int dst_bytes_per_row = VIDEO_DRV_IMAGE->bytes_per_line;
389
const int pixels_per_byte = VIDEO_MODE_X / src_bytes_per_row;
390
int i1 = y1 * src_bytes_per_row, i2 = y1 * dst_bytes_per_row, j;
391
for (j = y1; j <= y2; j++) {
392
Screen_blit(the_host_buffer + i2, the_buffer + i1, VIDEO_MODE_X / pixels_per_byte);
393
i1 += src_bytes_per_row;
394
i2 += dst_bytes_per_row;
399
// Update the_host_buffer and copy of the_buffer
400
const int src_bytes_per_row = VIDEO_MODE_ROW_BYTES;
401
const int dst_bytes_per_row = VIDEO_DRV_IMAGE->bytes_per_line;
402
const int bytes_per_pixel = src_bytes_per_row / VIDEO_MODE_X;
403
int i1 = y1 * src_bytes_per_row, i2 = y1 * dst_bytes_per_row, j;
404
for (j = y1; j <= y2; j++) {
405
Screen_blit(the_host_buffer + i2, the_buffer + i1, bytes_per_pixel * VIDEO_MODE_X);
406
i1 += src_bytes_per_row;
407
i2 += dst_bytes_per_row;
411
// Update the_host_buffer
412
VIDEO_DRV_LOCK_PIXELS;
413
const int src_bytes_per_row = VIDEO_MODE_ROW_BYTES;
414
const int dst_bytes_per_row = VIDEO_DRV_ROW_BYTES;
415
int i1 = y1 * src_bytes_per_row, i2 = y1 * dst_bytes_per_row, j;
416
for (j = y1; j <= y2; j++) {
417
Screen_blit(the_host_buffer + i2, the_buffer + i1, src_bytes_per_row);
418
i1 += src_bytes_per_row;
419
i2 += dst_bytes_per_row;
421
VIDEO_DRV_UNLOCK_PIXELS;
424
SDL_UpdateRect(drv->s, 0, y1, VIDEO_MODE_X, height);
411
426
if (VIDEO_DRV_HAVE_SHM)
412
427
XShmPutImage(x_display, VIDEO_DRV_WINDOW, VIDEO_DRV_GC, VIDEO_DRV_IMAGE, 0, y1, 0, y1, VIDEO_MODE_X, height, 0);
414
429
XPutImage(x_display, VIDEO_DRV_WINDOW, VIDEO_DRV_GC, VIDEO_DRV_IMAGE, 0, y1, 0, y1, VIDEO_MODE_X, height);
416
432
mainBuffer.dirty = false;
425
441
#if REAL_ADDRESSING || DIRECT_ADDRESSING
426
static inline void update_display_dga_vosf(void)
442
static void update_display_dga_vosf(VIDEO_DRV_DGA_INIT)
446
// Compute number of bytes per row, take care to virtual screens
447
const int src_bytes_per_row = VIDEO_MODE_ROW_BYTES;
448
const int dst_bytes_per_row = TrivialBytesPerRow(VIDEO_MODE_X, DepthModeForPixelDepth(VIDEO_DRV_DEPTH));
449
const int scr_bytes_per_row = VIDEO_DRV_ROW_BYTES;
450
assert(dst_bytes_per_row <= scr_bytes_per_row);
451
const int scr_bytes_left = scr_bytes_per_row - dst_bytes_per_row;
453
// Full screen update requested?
454
if (mainBuffer.very_dirty) {
456
vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ);
457
memcpy(the_buffer_copy, the_buffer, VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y);
458
VIDEO_DRV_LOCK_PIXELS;
460
for (int j = 0; j < VIDEO_MODE_Y; j++) {
461
Screen_blit(the_host_buffer + i2, the_buffer + i1, src_bytes_per_row);
462
i1 += src_bytes_per_row;
463
i2 += scr_bytes_per_row;
466
SDL_UpdateRect(drv->s, 0, 0, VIDEO_MODE_X, VIDEO_MODE_Y);
468
VIDEO_DRV_UNLOCK_PIXELS;
472
// Setup partial blitter (use 64-pixel wide chunks)
473
const int n_pixels = 64;
474
const int n_chunks = VIDEO_MODE_X / n_pixels;
475
const int n_pixels_left = VIDEO_MODE_X - (n_chunks * n_pixels);
476
const int src_chunk_size = src_bytes_per_row / n_chunks;
477
const int dst_chunk_size = dst_bytes_per_row / n_chunks;
478
const int src_chunk_size_left = src_bytes_per_row - (n_chunks * src_chunk_size);
479
const int dst_chunk_size_left = dst_bytes_per_row - (n_chunks * dst_chunk_size);
481
int page = 0, last_scanline = -1;
432
483
const unsigned first_page = find_next_page_set(page);
433
484
if (first_page >= mainBuffer.pageCount)
440
491
const int32 offset = first_page << mainBuffer.pageBits;
441
492
const uint32 length = (page - first_page) << mainBuffer.pageBits;
442
493
vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ);
444
// I am sure that y2 >= y1 and depth != 1
445
const int y1 = mainBuffer.pageInfo[first_page].top;
446
const int y2 = mainBuffer.pageInfo[page - 1].bottom;
448
const int bytes_per_row = VIDEO_MODE_ROW_BYTES;
449
const int bytes_per_pixel = VIDEO_MODE_ROW_BYTES / VIDEO_MODE_X;
452
// Check for first column from left and first column
453
// from right that have changed
454
int x1 = VIDEO_MODE_X * bytes_per_pixel - 1;
455
for (j = y1; j <= y2; j++) {
456
uint8 * const p1 = &the_buffer[j * bytes_per_row];
457
uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
458
for (i = 0; i < x1; i++) {
459
if (p1[i] != p2[i]) {
465
x1 /= bytes_per_pixel;
467
int x2 = x1 * bytes_per_pixel;
468
for (j = y2; j >= y1; j--) {
469
uint8 * const p1 = &the_buffer[j * bytes_per_row];
470
uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
471
for (i = VIDEO_MODE_X * bytes_per_pixel - 1; i > x2; i--) {
472
if (p1[i] != p2[i]) {
478
x2 /= bytes_per_pixel;
480
// Update the_host_buffer and copy of the_buffer
481
// There should be at least one pixel to copy
482
const int width = x2 - x1 + 1;
483
i = y1 * bytes_per_row + x1 * bytes_per_pixel;
484
for (j = y1; j <= y2; j++) {
485
Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
486
memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
495
// Optimized for scanlines, don't process overlapping lines again
496
int y1 = mainBuffer.pageInfo[first_page].top;
497
int y2 = mainBuffer.pageInfo[page - 1].bottom;
498
if (y1 <= last_scanline && ++y1 >= VIDEO_MODE_Y)
500
if (y2 <= last_scanline && ++y2 >= VIDEO_MODE_Y)
504
// Update the_host_buffer and copy of the_buffer, one line at a time
505
int i1 = y1 * src_bytes_per_row;
506
int i2 = y1 * scr_bytes_per_row;
510
{ VIDEO_MODE_X, y1, 0, 0 },
511
{ VIDEO_MODE_X, -1, 0, 0 },
512
{ VIDEO_MODE_X, -1, 0, 0 }
515
VIDEO_DRV_LOCK_PIXELS;
516
for (int j = y1; j <= y2; j++) {
517
for (int i = 0; i < n_chunks; i++) {
518
if (memcmp(the_buffer_copy + i1, the_buffer + i1, src_chunk_size) != 0) {
519
memcpy(the_buffer_copy + i1, the_buffer + i1, src_chunk_size);
520
Screen_blit(the_host_buffer + i2, the_buffer + i1, src_chunk_size);
522
const int x = i * n_pixels;
525
bb[bbi].w += bb[bbi].x - x;
527
bb[bbi].w = n_pixels;
530
else if (x >= bb[bbi].x + bb[bbi].w)
531
bb[bbi].w = x + n_pixels - bb[bbi].x;
534
i1 += src_chunk_size;
535
i2 += dst_chunk_size;
537
if (src_chunk_size_left && dst_chunk_size_left) {
538
if (memcmp(the_buffer_copy + i1, the_buffer + i1, src_chunk_size_left) != 0) {
539
memcpy(the_buffer_copy + i1, the_buffer + i1, src_chunk_size_left);
540
Screen_blit(the_host_buffer + i2, the_buffer + i1, src_chunk_size_left);
542
i1 += src_chunk_size_left;
543
i2 += dst_chunk_size_left;
545
const int x = n_chunks * n_pixels;
548
bb[bbi].w += bb[bbi].x - x;
550
bb[bbi].w = n_pixels_left;
553
else if (x >= bb[bbi].x + bb[bbi].w)
554
bb[bbi].w = x + n_pixels_left - bb[bbi].x;
557
i2 += scr_bytes_left;
560
if (bb[bbi].w && (j == y1 || j == y2 - 1 || j == y2)) {
569
SDL_UpdateRects(drv->s, bbi, bb);
571
VIDEO_DRV_UNLOCK_PIXELS;
490
573
mainBuffer.dirty = false;