rayzor

annotate src/dosemu/dosemu.c @ 10:235c8b764c0b

optimized swap_buffers
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 10 Apr 2014 08:03:52 +0300
parents fcd06a15dfdd
children d94a69933a71
rev   line source
nuclear@5 1 /* This file implements all calls made to dos-specific code using SDL */
nuclear@5 2 #include <stdlib.h>
nuclear@5 3 #include <assert.h>
nuclear@5 4 #include <SDL/SDL.h>
nuclear@5 5 #ifdef DOSEMU_CAPTURE
nuclear@5 6 #include <imago2.h>
nuclear@5 7 #endif
nuclear@5 8 #include "gfx.h"
nuclear@5 9 #include "mouse.h"
nuclear@5 10 #include "keyb.h"
nuclear@5 11 #include "timer.h"
nuclear@5 12
nuclear@9 13 static void cleanup(void);
nuclear@5 14 static void proc_events(void);
nuclear@5 15 static void capture_frame(unsigned char *frame);
nuclear@5 16
nuclear@9 17 static void init_sdl(void)
nuclear@5 18 {
nuclear@5 19 const SDL_version *ver;
nuclear@5 20
nuclear@5 21 if(!SDL_WasInit(SDL_INIT_EVERYTHING)) {
nuclear@5 22 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
nuclear@5 23
nuclear@5 24 if((ver = SDL_Linked_Version())) {
nuclear@5 25 printf("SDL %d.%d.%d initialized\n", ver->major, ver->minor, ver->patch);
nuclear@5 26 }
nuclear@9 27 atexit(cleanup);
nuclear@5 28 }
nuclear@5 29 }
nuclear@5 30
nuclear@9 31 static void cleanup(void)
nuclear@9 32 {
nuclear@9 33 SDL_Quit();
nuclear@9 34 }
nuclear@9 35
nuclear@5 36 /* ----- graphics (gfx.c (vbe) implementation) ----- */
nuclear@5 37 static SDL_Surface *fbsurf;
nuclear@5 38 static int scale = 1;
nuclear@5 39 static int frames_to_capture;
nuclear@5 40
nuclear@5 41 static struct {
nuclear@5 42 unsigned char r, g, b;
nuclear@5 43 } palette[256];
nuclear@5 44
nuclear@5 45
nuclear@5 46 void *set_video_mode(int xsz, int ysz, int bpp)
nuclear@5 47 {
nuclear@5 48 unsigned int sdl_flags = bpp <= 8 ? SDL_HWPALETTE : 0;
nuclear@5 49 char *env;
nuclear@5 50
nuclear@5 51 if(getenv("DOSEMU_DOUBLESIZE")) {
nuclear@5 52 scale = 2;
nuclear@5 53 }
nuclear@5 54
nuclear@5 55 if((env = getenv("DOSEMU_SCALE"))) {
nuclear@5 56 int n = atoi(env);
nuclear@5 57 if(n > 0) {
nuclear@5 58 scale = n;
nuclear@5 59 }
nuclear@5 60 }
nuclear@5 61 xsz *= scale;
nuclear@5 62 ysz *= scale;
nuclear@5 63
nuclear@5 64 if(getenv("DOSEMU_FULLSCREEN")) {
nuclear@5 65 sdl_flags |= SDL_FULLSCREEN;
nuclear@5 66 }
nuclear@5 67
nuclear@5 68 init_sdl();
nuclear@5 69
nuclear@5 70 if(!(fbsurf = SDL_SetVideoMode(xsz, ysz, bpp, sdl_flags))) {
nuclear@5 71 fprintf(stderr, "failed to set video mode\n");
nuclear@5 72 abort();
nuclear@5 73 }
nuclear@5 74 SDL_WM_SetCaption("Rayzor", 0);
nuclear@5 75 /*SDL_ShowCursor(0);*/
nuclear@5 76
nuclear@5 77 return fbsurf->pixels;
nuclear@5 78 }
nuclear@5 79
nuclear@5 80 int set_text_mode(void)
nuclear@5 81 {
nuclear@5 82 SDL_ShowCursor(1);
nuclear@5 83 SDL_EnableKeyRepeat(0, 0);
nuclear@5 84 return 0;
nuclear@5 85 }
nuclear@5 86
nuclear@5 87 int get_color_depth(void)
nuclear@5 88 {
nuclear@5 89 return fbsurf->format->BitsPerPixel;
nuclear@5 90 }
nuclear@5 91
nuclear@5 92 static int count_bits(unsigned int x)
nuclear@5 93 {
nuclear@5 94 int i, count = 0;
nuclear@5 95 for(i=0; i<32; i++) {
nuclear@5 96 if(x & 1) {
nuclear@5 97 count++;
nuclear@5 98 }
nuclear@5 99 x >>= 1;
nuclear@5 100 }
nuclear@5 101 return count;
nuclear@5 102 }
nuclear@5 103
nuclear@5 104 int get_color_bits(int *rbits, int *gbits, int *bbits)
nuclear@5 105 {
nuclear@5 106 *rbits = count_bits(fbsurf->format->Rmask);
nuclear@5 107 *gbits = count_bits(fbsurf->format->Gmask);
nuclear@5 108 *bbits = count_bits(fbsurf->format->Bmask);
nuclear@5 109 return *rbits + *gbits + *bbits;
nuclear@5 110 }
nuclear@5 111
nuclear@5 112 int get_color_shift(int *rshift, int *gshift, int *bshift)
nuclear@5 113 {
nuclear@5 114 *rshift = fbsurf->format->Rshift;
nuclear@5 115 *gshift = fbsurf->format->Gshift;
nuclear@5 116 *bshift = fbsurf->format->Bshift;
nuclear@5 117 return 0;
nuclear@5 118 }
nuclear@5 119
nuclear@5 120 int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask)
nuclear@5 121 {
nuclear@5 122 *rmask = fbsurf->format->Rmask;
nuclear@5 123 *gmask = fbsurf->format->Gmask;
nuclear@5 124 *bmask = fbsurf->format->Bmask;
nuclear@5 125 return 0;
nuclear@5 126 }
nuclear@5 127
nuclear@5 128
nuclear@5 129 void set_palette(int idx, int r, int g, int b)
nuclear@5 130 {
nuclear@5 131 SDL_Color col;
nuclear@5 132 col.r = r;
nuclear@5 133 col.g = g;
nuclear@5 134 col.b = b;
nuclear@5 135
nuclear@5 136 if(SDL_SetPalette(fbsurf, SDL_LOGPAL | SDL_PHYSPAL, &col, idx, 1) != 1) {
nuclear@5 137 fprintf(stderr, "set_palette failed to set the required color\n");
nuclear@5 138 }
nuclear@5 139
nuclear@5 140 palette[idx].r = r;
nuclear@5 141 palette[idx].g = g;
nuclear@5 142 palette[idx].b = b;
nuclear@5 143 }
nuclear@5 144
nuclear@5 145 static int copy_frame_called;
nuclear@5 146
nuclear@5 147 void copy_frame(void *pixels)
nuclear@5 148 {
nuclear@5 149 unsigned char *frame = (unsigned char*)pixels;
nuclear@5 150 copy_frame_called = 1;
nuclear@5 151
nuclear@5 152 if(SDL_MUSTLOCK(fbsurf)) {
nuclear@5 153 SDL_LockSurface(fbsurf);
nuclear@5 154 }
nuclear@5 155
nuclear@5 156 if(pixels) {
nuclear@5 157 if(scale > 1) {
nuclear@5 158 int i, j, xsz, ysz;
nuclear@5 159 unsigned char *dest = fbsurf->pixels;
nuclear@5 160
nuclear@5 161 xsz = fbsurf->w * scale;
nuclear@5 162 ysz = fbsurf->h * scale;
nuclear@5 163
nuclear@5 164 for(i=0; i<ysz; i++) {
nuclear@5 165 for(j=0; j<xsz; j++) {
nuclear@5 166 *dest++ = frame[(i / scale) * fbsurf->w + (j / scale)];
nuclear@5 167 }
nuclear@5 168 }
nuclear@5 169 } else {
nuclear@5 170 int num_pixels = fbsurf->w * fbsurf->h;
nuclear@5 171 memcpy(fbsurf->pixels, frame, num_pixels * fbsurf->format->BytesPerPixel);
nuclear@5 172 }
nuclear@5 173 }
nuclear@5 174
nuclear@5 175 if(SDL_MUSTLOCK(fbsurf)) {
nuclear@5 176 SDL_UnlockSurface(fbsurf);
nuclear@5 177 }
nuclear@5 178
nuclear@5 179 SDL_Flip(fbsurf);
nuclear@5 180
nuclear@5 181 if(frames_to_capture > 0) {
nuclear@5 182 capture_frame(pixels);
nuclear@5 183 --frames_to_capture;
nuclear@5 184 }
nuclear@5 185
nuclear@5 186 /* also print fps every second ... */
nuclear@9 187 /*{
nuclear@5 188 static long prev_fps, num_frames;
nuclear@5 189 long msec, dt;
nuclear@5 190
nuclear@5 191 msec = get_msec();
nuclear@5 192 dt = msec - prev_fps;
nuclear@5 193 if(dt >= 1000) {
nuclear@5 194 float fps = (float)num_frames / ((float)dt / 1000.0f);
nuclear@5 195 printf("framerate: %.1f \r", fps);
nuclear@5 196 fflush(stdout);
nuclear@5 197 num_frames = 0;
nuclear@5 198 prev_fps = msec;
nuclear@5 199 } else {
nuclear@5 200 num_frames++;
nuclear@5 201 }
nuclear@9 202 }*/
nuclear@5 203 }
nuclear@5 204
nuclear@5 205 #define spin_delay(ms) \
nuclear@5 206 do { \
nuclear@5 207 unsigned int end = SDL_GetTicks() + ms; \
nuclear@5 208 while((prev_msec = SDL_GetTicks()) < end); \
nuclear@5 209 } while(0)
nuclear@5 210
nuclear@5 211 #define FRAME_INTERVAL (1000/70)
nuclear@5 212
nuclear@5 213 void wait_vsync(void)
nuclear@5 214 {
nuclear@9 215 /*static int prev_msec;
nuclear@9 216 int msec, dt, tleft;*/
nuclear@5 217
nuclear@5 218 if(!copy_frame_called) {
nuclear@5 219 copy_frame(0);
nuclear@5 220 copy_frame_called = 0;
nuclear@5 221 }
nuclear@5 222
nuclear@9 223 /*
nuclear@5 224 msec = SDL_GetTicks();
nuclear@5 225
nuclear@5 226 dt = msec - prev_msec;
nuclear@5 227
nuclear@5 228 tleft = FRAME_INTERVAL - dt;
nuclear@5 229 if(tleft > 0) {
nuclear@5 230 int coarse = tleft & 0xfffffff8;
nuclear@5 231 tleft = tleft & 7;
nuclear@5 232
nuclear@5 233 if(coarse) {
nuclear@5 234 SDL_Delay(coarse);
nuclear@5 235 }
nuclear@5 236 if(tleft) {
nuclear@5 237 spin_delay(tleft);
nuclear@5 238 } else {
nuclear@5 239 prev_msec = SDL_GetTicks();
nuclear@5 240 }
nuclear@5 241 } else {
nuclear@5 242 prev_msec = msec;
nuclear@5 243 }
nuclear@9 244 */
nuclear@5 245 }
nuclear@5 246
nuclear@5 247 static int cap_count = 0;
nuclear@5 248 void begin_capture(int frames)
nuclear@5 249 {
nuclear@5 250 frames_to_capture = frames;
nuclear@5 251 }
nuclear@5 252
nuclear@5 253 void end_capture(void)
nuclear@5 254 {
nuclear@5 255 cap_count = 0;
nuclear@5 256 frames_to_capture = 0;
nuclear@5 257 }
nuclear@5 258
nuclear@5 259 #define NUMPIX (fbsurf->w * fbsurf->h)
nuclear@5 260 static void capture_frame(unsigned char *frame)
nuclear@5 261 {
nuclear@5 262 #ifdef DOSEMU_CAPTURE
nuclear@5 263 static unsigned char rgbpix[NUMPIX * 4];
nuclear@5 264 char fname[32];
nuclear@5 265 int i;
nuclear@5 266 unsigned char *src, *dest;
nuclear@5 267
nuclear@5 268 sprintf(fname, "frame%04d.png", cap_count++);
nuclear@5 269
nuclear@5 270 src = frame;
nuclear@5 271 dest = rgbpix;
nuclear@5 272
nuclear@5 273 for(i=0; i<NUMPIX; i++) {
nuclear@5 274 unsigned char c = *src++;
nuclear@5 275 *dest++ = palette[c].r;
nuclear@5 276 *dest++ = palette[c].g;
nuclear@5 277 *dest++ = palette[c].b;
nuclear@5 278 *dest++ = 255;
nuclear@5 279 }
nuclear@5 280
nuclear@5 281 img_save_pixels(fname, rgbpix, fbsurf->w, fbsurf->h, IMG_FMT_RGBA32);
nuclear@5 282 #endif
nuclear@5 283 }
nuclear@5 284
nuclear@5 285
nuclear@5 286 /* ----- event handling (conio.h) ----- */
nuclear@5 287 static SDL_Event *keybev;
nuclear@5 288 static int mousex, mousey, bnmask;
nuclear@5 289
nuclear@5 290 static int keystate[256];
nuclear@5 291 static int num_pressed;
nuclear@5 292
nuclear@5 293 int kbhit(void)
nuclear@5 294 {
nuclear@5 295 if(!keybev) {
nuclear@5 296 proc_events();
nuclear@5 297 }
nuclear@5 298 return keybev != 0;
nuclear@5 299 }
nuclear@5 300
nuclear@5 301 int getch(void)
nuclear@5 302 {
nuclear@5 303 int res;
nuclear@5 304
nuclear@5 305 while(!keybev) {
nuclear@5 306 SDL_Event ev;
nuclear@5 307 SDL_WaitEvent(&ev);
nuclear@5 308 SDL_PushEvent(&ev);
nuclear@5 309 proc_events();
nuclear@5 310 }
nuclear@5 311 res = keybev->key.keysym.sym;
nuclear@5 312 keybev = 0;
nuclear@5 313 return res;
nuclear@5 314 }
nuclear@5 315
nuclear@5 316 /* ----- improved event handling (keyb.h) ---- */
nuclear@5 317
nuclear@5 318 int kb_init(int bufsz)
nuclear@5 319 {
nuclear@5 320 init_sdl();
nuclear@5 321
nuclear@5 322 return 0;
nuclear@5 323 }
nuclear@5 324
nuclear@5 325 void kb_shutdown(void)
nuclear@5 326 {
nuclear@5 327 }
nuclear@5 328
nuclear@5 329 int kb_getkey(void)
nuclear@5 330 {
nuclear@5 331 int res = -1;
nuclear@5 332
nuclear@5 333 proc_events();
nuclear@5 334 if(keybev) {
nuclear@5 335 res = keybev->key.keysym.sym;
nuclear@5 336 keybev = 0;
nuclear@5 337 }
nuclear@5 338 return res;
nuclear@5 339 }
nuclear@5 340
nuclear@5 341 int kb_isdown(int key)
nuclear@5 342 {
nuclear@5 343 if(key == KB_ANY) {
nuclear@5 344 return num_pressed;
nuclear@5 345 }
nuclear@5 346 return keystate[key];
nuclear@5 347 }
nuclear@5 348
nuclear@5 349 /* mouse handling (mouse.c implementation) */
nuclear@5 350 static unsigned long last_mouse_hide_time;
nuclear@5 351
nuclear@5 352 int have_mouse(void)
nuclear@5 353 {
nuclear@5 354 return 1;
nuclear@5 355 }
nuclear@5 356
nuclear@8 357 void set_mouse_limits(int xmin, int ymin, int xmax, int ymax)
nuclear@8 358 {
nuclear@8 359 }
nuclear@8 360
nuclear@5 361 void set_mouse(int x, int y)
nuclear@5 362 {
nuclear@5 363 SDL_ShowCursor(0);
nuclear@5 364 last_mouse_hide_time = get_msec();
nuclear@5 365
nuclear@5 366 SDL_WarpMouse(x * scale, y * scale);
nuclear@5 367 mousex = x;
nuclear@5 368 mousey = y;
nuclear@5 369 }
nuclear@5 370
nuclear@5 371 int read_mouse(int *xp, int *yp)
nuclear@5 372 {
nuclear@5 373 if(xp) *xp = mousex;
nuclear@5 374 if(yp) *yp = mousey;
nuclear@5 375 return bnmask;
nuclear@5 376 }
nuclear@5 377
nuclear@5 378 static void proc_events(void)
nuclear@5 379 {
nuclear@5 380 static SDL_Event ev;
nuclear@5 381
nuclear@5 382 if(last_mouse_hide_time > 0 && get_msec() - last_mouse_hide_time > 3000) {
nuclear@5 383 last_mouse_hide_time = 0;
nuclear@5 384 SDL_ShowCursor(1);
nuclear@5 385 }
nuclear@5 386
nuclear@5 387 while(SDL_PollEvent(&ev)) {
nuclear@5 388 switch(ev.type) {
nuclear@5 389 case SDL_KEYDOWN:
nuclear@5 390 {
nuclear@5 391 int key = ev.key.keysym.sym;
nuclear@5 392
nuclear@5 393 if(!keybev) {
nuclear@5 394 keybev = &ev;
nuclear@5 395 }
nuclear@5 396
nuclear@5 397 if(!keystate[key]) {
nuclear@5 398 keystate[key] = 1;
nuclear@5 399 num_pressed++;
nuclear@5 400 }
nuclear@5 401 }
nuclear@5 402 break;
nuclear@5 403
nuclear@5 404 case SDL_KEYUP:
nuclear@5 405 {
nuclear@5 406 int key = ev.key.keysym.sym;
nuclear@5 407
nuclear@5 408 if(keystate[key]) {
nuclear@5 409 keystate[key] = 0;
nuclear@5 410 if(--num_pressed < 0) {
nuclear@5 411 num_pressed = 0;
nuclear@5 412 }
nuclear@5 413 }
nuclear@5 414 }
nuclear@5 415 break;
nuclear@5 416
nuclear@5 417 case SDL_MOUSEMOTION:
nuclear@5 418 mousex = ev.motion.x / scale;
nuclear@5 419 mousey = ev.motion.y / scale;
nuclear@5 420 break;
nuclear@5 421
nuclear@5 422 case SDL_MOUSEBUTTONDOWN:
nuclear@5 423 case SDL_MOUSEBUTTONUP:
nuclear@5 424 {
nuclear@5 425 int mask = 0;
nuclear@5 426 switch(ev.button.button) {
nuclear@5 427 case SDL_BUTTON_LEFT:
nuclear@5 428 mask = MOUSE_LEFT;
nuclear@5 429 break;
nuclear@5 430 case SDL_BUTTON_MIDDLE:
nuclear@5 431 mask = MOUSE_MIDDLE;
nuclear@5 432 break;
nuclear@5 433 case SDL_BUTTON_RIGHT:
nuclear@5 434 mask = MOUSE_RIGHT;
nuclear@5 435 default:
nuclear@5 436 break;
nuclear@5 437 }
nuclear@5 438 if(!mask) {
nuclear@5 439 break;
nuclear@5 440 }
nuclear@5 441
nuclear@5 442 if(ev.button.state == SDL_PRESSED) {
nuclear@5 443 bnmask |= mask;
nuclear@5 444 } else {
nuclear@5 445 bnmask &= ~mask;
nuclear@5 446 }
nuclear@5 447 }
nuclear@5 448 break;
nuclear@5 449
nuclear@5 450 default:
nuclear@5 451 break;
nuclear@5 452 }
nuclear@5 453 }
nuclear@5 454 }
nuclear@5 455
nuclear@5 456 /* ---- timer.c implementation ---- */
nuclear@5 457 static Uint32 start_time;
nuclear@5 458
nuclear@5 459 void init_timer(int res_hz)
nuclear@5 460 {
nuclear@5 461 init_sdl();
nuclear@5 462 reset_timer();
nuclear@5 463 }
nuclear@5 464
nuclear@5 465 void reset_timer(void)
nuclear@5 466 {
nuclear@5 467 start_time = SDL_GetTicks();
nuclear@5 468 printf("resetting timer: %u, %lu\n", start_time, get_msec());
nuclear@5 469 }
nuclear@5 470
nuclear@5 471 unsigned long get_msec(void)
nuclear@5 472 {
nuclear@5 473 Uint32 ticks = SDL_GetTicks();
nuclear@5 474 return (unsigned long)(ticks - start_time);
nuclear@5 475 }