1
0
mirror of https://github.com/Interlisp/maiko.git synced 2026-01-14 23:46:14 +00:00

Implement bitblt to texture at bit level rather than word level, some cleanup

sdl_bitblt_to_texture2 is an experiment, parallel to sdl_bitblt_to_texture
that only moves as many bits as are required, rather than rounding down(up) to the
nearest (16-bit) word boundary for the start(end) of the line.

Introduces some name changes to make things a little clearer.
This commit is contained in:
Nick Briggs 2021-11-20 18:26:50 -08:00
parent 78bcb188a8
commit 878168f4f5

176
src/sdl.c
View File

@ -19,6 +19,8 @@ static SDL_Texture *sdl_texture = NULL;
#else
static SDL_Surface *sdl_windowsurface = NULL;
static SDL_Surface *sdl_buffersurface = NULL;
static int buffer_size = 0;
static void *buffer = NULL;
#endif
static Uint32 sdl_white;
static Uint32 sdl_black;
@ -26,8 +28,6 @@ static Uint32 sdl_foreground;
static Uint32 sdl_background;
static int sdl_bytesperpixel;
static SDL_PixelFormat *sdl_pixelformat;
static int buffer_size = 0;
static void *buffer = NULL;
extern void kb_trans(u_short keycode, u_short upflg);
extern int error(const char *s);
@ -216,7 +216,7 @@ static int min(int a, int b) {
return b;
}
static int should_update_texture = 0;
static int display_update_needed = 0;
static int min_x = 0;
static int min_y = 0;
@ -231,7 +231,7 @@ void sdl_notify_damage(int x, int y, int w, int h) {
max_x = min(x + w, sdl_displaywidth - 1);
if(y + h > max_y)
max_y = min(y + h, sdl_displayheight - 1);
should_update_texture = 1;
display_update_needed = 1;
}
/* a simple linked list to remember generated cursors
@ -286,6 +286,7 @@ static SDL_Cursor *sdl_getOrAllocateCursor(Uint8 cursor[32], int hot_x, int hot_
/*
* Read a cursor bitmap from lisp. Try to find a cached cursor, then use that.
* Use HOT_X and HOT_Y as the cursor hotspot.
* XXX: needs to deal with sdl_pixelscale > 1, and where is the hotspot?
*/
void sdl_setCursor(int hot_x, int hot_y) {
DLword *newbm = ((DLword *)(IOPage->dlcursorbitmap));
@ -310,51 +311,86 @@ void sdl_setCursor(int hot_x, int hot_y) {
#if defined(SDLRENDERING)
void sdl_bitblt_to_texture(int _x, int _y, int _w, int _h) {
// printf("bitblt(%d, %d, %d, %d)\n", _x, _y, _w, _h);
// Uint32 *dr = (Uint32 *)DisplayRegion68k;
// Uint32 *src = (Uint32 *)DisplayRegion68k;
static const DLword mask[16] = {1<<15, 1<<14, 1<<13, 1<<12, 1<<11, 1<<10, 1<<9, 1<<8,
1<<7, 1<<6, 1<<5, 1<<4, 1<<3, 1<<2, 1<<1, 1<<0};
DLword *dr = DisplayRegion68k;
void *destbuffer;
int destpitchbytes;
int destpitchpixels;
// const int bitsperword = 8 * sizeof(Uint32);
DLword *src = DisplayRegion68k;
void *dst;
int dstpitchbytes;
int dstpitchpixels;
const int bitsperword = 8 * sizeof(DLword);
int sourcepitchwords = sdl_displaywidth / bitsperword;
int xstart = _x / bitsperword;
int xlimit = (_x + _w + bitsperword - 1) / bitsperword;
int ystart = _y * sourcepitchwords;
int ylimit = (_y + _h) * sourcepitchwords;
SDL_Rect destrect;
SDL_Rect dstrect;
/* printf("_x %d _y %d _w %d _h %d; xstart %d xlimit %d ystart %d ylimit %d sourcepitchwords %d\n",
_x, _y, _w, _h, xstart, xlimit, ystart, ylimit, sourcepitchwords); */
// Avoid dealing with partial words in the update by stretching the source rectangle
// left and right to cover complete units (32-bit words) and lock the corresponding
// left and right to cover complete units and lock the corresponding
// region in the texture
destrect.x = (_x / bitsperword) * bitsperword;
destrect.w = ((_x + _w + bitsperword - 1) / bitsperword * bitsperword) - destrect.x;
destrect.y = _y;
destrect.h = _h;
SDL_LockTexture(sdl_texture, &destrect, &destbuffer, &destpitchbytes);
destpitchpixels = destpitchbytes / sdl_bytesperpixel;
dstrect.x = (_x / bitsperword) * bitsperword;
dstrect.w = ((_x + _w + bitsperword - 1) / bitsperword * bitsperword) - dstrect.x;
dstrect.y = _y;
dstrect.h = _h;
SDL_LockTexture(sdl_texture, &dstrect, &dst, &dstpitchbytes);
dstpitchpixels = dstpitchbytes / sdl_bytesperpixel;
int dy = 0;
// for each line in the source image
for(int sy = ystart; sy < ylimit ; sy += sourcepitchwords, dy += destpitchpixels) {
for(int sy = ystart; sy < ylimit ; sy += sourcepitchwords, dy += dstpitchpixels) {
// for each word in the line
int dx = 0;
for(int sx = xstart; sx < xlimit; sx++, dx += bitsperword) {
int w = GETBASEWORD(dr, sy + sx);
int srcw = GETBASEWORD(src, sy + sx);
// for each bit in the word
for(int b = 0; b < bitsperword; b++) {
((Uint32 *)destbuffer)[dy + dx + b] = (w & mask[b]) ? sdl_foreground : sdl_background;
((Uint32 *)dst)[dy + dx + b] = (srcw & mask[b]) ? sdl_foreground : sdl_background;
}
}
}
SDL_UnlockTexture(sdl_texture);
}
void sdl_bitblt_to_texture2(int _x, int _y, int _w, int _h) {
static const int mask[16] = {1<<15, 1<<14, 1<<13, 1<<12, 1<<11, 1<<10, 1<<9, 1<<8,
1<<7, 1<<6, 1<<5, 1<<4, 1<<3, 1<<2, 1<<1, 1<<0};
DLword *src = DisplayRegion68k;
void *dst;
int dstpitchbytes;
int dstpitchpixels;
const int bitsperword = 8 * sizeof(DLword);
int sourcepitchwords = sdl_displaywidth / bitsperword;
int xstart = _x / bitsperword; // "word" index of first accessed word in line
int xstartb = _x % bitsperword; // bit within word
int xlimit = (_x + _w + bitsperword - 1) / bitsperword; // word index
int ystart = _y * sourcepitchwords;
int ylimit = (_y + _h) * sourcepitchwords;
SDL_Rect dstrect = {.x = _x, .y = _y, .w = _w, .h = _h};
SDL_LockTexture(sdl_texture, &dstrect, &dst, &dstpitchbytes);
dstpitchpixels = dstpitchbytes / sdl_bytesperpixel;
int dy = 0;
// for each line in the source image
for(int sy = ystart; sy < ylimit ; sy += sourcepitchwords, dy += dstpitchpixels) {
int dx = 0;
int sx = xstart;
int b = xstartb;
int srcw = GETBASEWORD(src, sy + sx);
// for each pixel within the dstination region line
for (int dx = 0; dx < _w; dx++) {
((Uint32 *)dst)[dy + dx] = (srcw & mask[b]) ? sdl_foreground : sdl_background;
if (++b == bitsperword) {
b = 0;
sx++;
srcw = GETBASEWORD(src, sy + sx);
}
}
}
SDL_UnlockTexture(sdl_texture);
}
#else
void sdl_bitblt_to_screen(int _x, int _y, int _w, int _h) {
void sdl_bitblt_to_buffer(int _x, int _y, int _w, int _h) {
// printf("bitblt(%d, %d, %d, %d)\n", _x, _y, _w, _h);
Uint32 *dr = (Uint32*)DisplayRegion68k;
Uint32 *src = (Uint32*)DisplayRegion68k;
int before = SDL_GetTicks();
int width = sdl_displaywidth;
@ -366,12 +402,12 @@ void sdl_bitblt_to_screen(int _x, int _y, int _w, int _h) {
for(int y = _y; y < ylimit; y++) {
int they = y * sdl_displaywidth;
for(int x = _x / bpw; x < xlimit; x++) {
int w = dr[y * pitch + x];
int srcw = src[y * pitch + x];
int thex = x * bpw;
for(int b = 0; b < bpw; b++) {
//printf("%d/%d %d\n", x, y, b);
uint32_t px = 0;
if(w & (1 << (bpw - 1 - b))) {
if(srcw & (1 << (bpw - 1 - b))) {
px = sdl_foreground;
} else {
px = sdl_background;
@ -387,37 +423,31 @@ void sdl_bitblt_to_screen(int _x, int _y, int _w, int _h) {
// printf("bitblting took %dms\n", after - before);
}
void sdl_bitblt_to_window_surface(int _x, int _y, int _w, int _h) {
// printf("bitblt(%d, %d, %d, %d)\n", _x, _y, _w, _h);
Uint32 *dr = (Uint32*)DisplayRegion68k;
int before = SDL_GetTicks();
int width = sdl_displaywidth;
int height = sdl_displayheight;
int bpw = 8 * sizeof(Uint32);
int pitch = sdl_displaywidth / bpw;
int xlimit = (_x + _w + bpw - 1) / bpw;
int ylimit = _y + _h;
for(int y = _y; y < ylimit; y++) {
int they = y * sdl_displaywidth;
for(int x = _x / bpw; x < xlimit; x++) {
int w = dr[y * pitch + x];
int thex = x * bpw;
for(int b = 0; b < bpw; b++) {
//printf("%d/%d %d\n", x, y, b);
uint32_t px = 0;
if(w & (1 << (bpw - 1 - b))) {
px = sdl_foreground;
} else {
px = sdl_background;
}
//printf("px is %x\n", px);
int pxindex = they + thex + b;
assert(pxindex >= 0 && pxindex < buffer_size);
((Uint32 *)sdl_windowsurface->pixels)[pxindex] = px;
static const DLword mask[16] = {1<<15, 1<<14, 1<<13, 1<<12, 1<<11, 1<<10, 1<<9, 1<<8,
1<<7, 1<<6, 1<<5, 1<<4, 1<<3, 1<<2, 1<<1, 1<<0};
DLword *src = DisplayRegion68k;
Uint32 *dst = (Uint32 *)sdl_windowsurface->pixels;
int dstpitchbytes = sdl_windowsurface->pitch;
int dstpitchpixels = dstpitchbytes / sdl_bytesperpixel;
const int bitsperword = 8 * sizeof(DLword);
int sourcepitchwords = sdl_displaywidth / bitsperword;
int xstart = _x / bitsperword;
int xlimit = (_x + _w + bitsperword - 1) / bitsperword;
int ystart = _y * sourcepitchwords;
int ylimit = (_y + _h) * sourcepitchwords;
int dy = _y * dstpitchpixels;
// for each line in the source image
for(int sy = ystart; sy < ylimit ; sy += sourcepitchwords, dy += dstpitchpixels) {
// for each word in the line
int dx = (_x / bitsperword) * bitsperword;
for(int sx = xstart; sx < xlimit; sx++, dx+=bitsperword) {
int srcw = GETBASEWORD(src, sy + sx);
// for each bit in the word
for(int b = 0; b < bitsperword; b++) {
((Uint32 *)dst)[dy + dx + b] = (srcw & mask[b]) ? sdl_foreground : sdl_background;
}
}
}
int after = SDL_GetTicks();
// printf("bitblting took %dms\n", after - before);
}
#endif
@ -520,25 +550,24 @@ void sdl_setMousePosition(int x, int y) {
SDL_WarpMouseInWindow(sdl_window, x * sdl_pixelscale, y * sdl_pixelscale);
}
#if defined(SDLRENDERING)
void sdl_update_display_rendering() {
void sdl_update_display() {
int before = 0;
int after = 0;
if(should_update_texture) {
before = SDL_GetTicks();
sdl_bitblt_to_texture(min_x, min_y, max_x - min_x, max_y - min_y);
after = SDL_GetTicks();
// printf("UpdateTexture took %dms\n", after - before);
should_update_texture = 0;
min_x = sdl_displaywidth;
min_y = sdl_displayheight;
max_x = max_y = 0;
}
int this_draw = SDL_GetTicks();
if(this_draw - last_draw <= 16) return;
sdl_bitblt_to_texture2(min_x, min_y, max_x - min_x, max_y - min_y);
after = SDL_GetTicks();
// printf("UpdateTexture took %dms\n", after - before);
display_update_needed = 0;
min_x = sdl_displaywidth;
min_y = sdl_displayheight;
max_x = max_y = 0;
before = SDL_GetTicks();
if(this_draw - last_draw > 10) {
before = SDL_GetTicks();
//SDL_RenderClear(sdl_renderer);
SDL_Rect r;
@ -557,16 +586,15 @@ void sdl_update_display_rendering() {
last_draw = this_draw;
after = SDL_GetTicks();
// printf("rendering took %dms\n", after - before);
}
}
#else
void sdl_update_display_surfaces() {
void sdl_update_display() {
int before = 0;
int after = 0;
int this_draw = SDL_GetTicks();
/* check if there's anything to do and sufficient time has elapsed */
if (!should_update_texture || this_draw - last_draw <= 16) {
if (!display_update_needed || this_draw - last_draw <= 16) {
return;
}
SDL_Rect r;
@ -583,7 +611,7 @@ void sdl_update_display_surfaces() {
s.y = r.y * sdl_pixelscale;
s.w = r.w * sdl_pixelscale;
s.h = r.h * sdl_pixelscale;
sdl_bitblt_to_screen(r.x, r.y, r.w, r.h);
sdl_bitblt_to_buffer(r.x, r.y, r.w, r.h);
SDL_BlitScaled(sdl_buffersurface, &r, sdl_windowsurface, &s);
SDL_UpdateWindowSurfaceRects(sdl_window, &s, 1);
}
@ -591,7 +619,7 @@ void sdl_update_display_surfaces() {
max_x = 0;
min_y = sdl_displayheight;
max_y = 0;
should_update_texture = 0;
display_update_needed = 0;
after = SDL_GetTicks();
last_draw = this_draw;
// printf("surface update took %dms\n", after - before);
@ -685,11 +713,9 @@ void process_SDLevents() {
printf("other event type: %d\n", event.type);
}
}
#if defined(SDLRENDERING)
sdl_update_display_rendering();
#else
sdl_update_display_surfaces();
#endif
if (display_update_needed) {
sdl_update_display();
}
}
int init_SDL(char *windowtitle, int w, int h, int s) {