1
0
mirror of https://github.com/pevans/erc-c.git synced 2024-07-13 08:28:54 +00:00

Avoid polling for events until we're ready for a frame redraw

This change drastically cuts the number of times we poll for events, and
consequently drastically speeds up the number of frames we can draw
within any given span of time.

In other words, we go from "this barely moves as fast as the actual
Apple II" to "holy shit this moves so fast".
This commit is contained in:
Peter Evans 2018-04-06 11:47:54 -05:00
parent f8dd49e892
commit 281544bf43
2 changed files with 44 additions and 19 deletions

View File

@ -1,8 +1,9 @@
#ifndef _VM_SCREEN_H_
#define _VM_SCREEN_H_
#include <stdbool.h>
#include <SDL.h>
#include <stdbool.h>
#include <sys/time.h>
#include "vm_area.h"
#include "vm_bits.h"
@ -45,6 +46,18 @@ typedef struct {
int xcoords;
int ycoords;
/*
* This is the time we last refreshed the screen.
*/
struct timeval reftime;
/*
* This field is the number of microseconds we have to wait until we
* are ready to redraw the frame. It cannot be greater than 1000000,
* which is the number of microseconds within a second.
*/
int usec_until_refresh;
/*
* Hang onto the last key pressed and the status of whether a key
* is pressed right now or not.
@ -68,6 +81,7 @@ typedef struct {
extern bool vm_screen_active(vm_screen *);
extern bool vm_screen_dirty(vm_screen *);
extern bool vm_screen_key_pressed(vm_screen *);
extern bool vm_screen_needs_frame(vm_screen *);
extern char vm_screen_last_key(vm_screen *);
extern int vm_screen_add_window(vm_screen *, int, int);
extern int vm_screen_init();

View File

@ -69,6 +69,9 @@ vm_screen_create()
screen->key_pressed = false;
screen->dirty = false;
screen->should_exit = false;
screen->usec_until_refresh = 33333;
memset(&screen->reftime, 0, sizeof(struct timeval));
screen->window = NULL;
screen->render = NULL;
@ -177,8 +180,6 @@ vm_screen_free(vm_screen *screen)
bool
vm_screen_active(vm_screen *scr)
{
vm_event_poll(scr);
// If something happened in the event loop that caused the user to
// signal an exit, then returning false here will do the trick
if (scr->should_exit) {
@ -257,6 +258,29 @@ vm_screen_last_key(vm_screen *scr)
return scr->last_key;
}
bool
vm_screen_needs_frame(vm_screen *scr)
{
struct timeval now;
unsigned int diff;
if (gettimeofday(&now, NULL) < 0) {
log_crit("Failed call to gettimeofday()");
return false;
}
diff =
((now.tv_sec - scr->reftime.tv_sec) * 1000000) +
(now.tv_usec - scr->reftime.tv_usec);
if (diff > scr->usec_until_refresh) {
memcpy(&scr->reftime, &now, sizeof(struct timeval));
return true;
}
return false;
}
/*
* Return true if the screen is considered dirty (i.e., if the screen
* needs to be redrawn).
@ -264,22 +288,9 @@ vm_screen_last_key(vm_screen *scr)
bool
vm_screen_dirty(vm_screen *scr)
{
struct timeval now;
if (scr->dirty) {
// If this returns an error, I have to assume the computer
// itself may be on fire, or has grown fangs and is presently
// nibbling on the user
if (gettimeofday(&now, NULL) < 0) {
return false;
}
if (now.tv_sec > refresh_time.tv_sec ||
(now.tv_usec > refresh_time.tv_usec + 50000)
) {
memcpy(&refresh_time, &now, sizeof(struct timeval));
return true;
}
if (vm_screen_needs_frame(scr)) {
vm_event_poll(scr);
return scr->dirty;
}
return false;