#include <stdlib.h>
#include <string.h>
#include "3dgfx.h"
+#include "video.h"
#include "util.h"
+struct rect {
+ int x0, y0, x1, y1;
+};
+
+static void reset_dirty(struct rect *r);
+
static int32_t mvmat[16];
static int32_t pmat[16];
static int vp[4];
-static int dirty_x0, dirty_x1, dirty_y0, dirty_y1;
+static struct rect dirty_rect[2];
+static unsigned int cur_dirty;
unsigned char *g3d_fbpixels;
int g3d_width, g3d_height;
mvmat[0] = mvmat[5] = mvmat[10] = mvmat[15] = 0x10000;
pmat[0] = pmat[5] = pmat[10] = pmat[15] = 0x10000;
g3d_curcidx = 0xff;
+
+ cur_dirty = 0;
return 0;
}
void g3d_framebuffer(int width, int height, void *fb)
{
- g3d_fbpixels = fb;
+ g3d_fbpixels = fb ? fb : vid_backbuf;
g3d_width = width;
g3d_height = height;
vp[2] = width;
vp[3] = height;
- g3d_reset_dirty();
+ reset_dirty(dirty_rect);
+ reset_dirty(dirty_rect + 1);
}
-void g3d_reset_dirty(void)
+void g3d_framebuf_addr(void *fb)
{
- dirty_x0 = XRES;
- dirty_y0 = YRES;
- dirty_x1 = 0;
- dirty_y1 = 0;
+ g3d_fbpixels = vid_backbuf;
}
-void blkclear(void *p, int len, int col);
-#pragma aux blkclear = \
- "mov ah, al" \
- "shl eax, 8" \
- "mov al, ah" \
- "shl eax, 8" \
- "mov al, ah" \
- "shr ecx, 2" \
- "rep stosd" \
- parm [edi] [ecx] [eax] \
- modify [eax ecx edi];
-
-extern volatile long nticks;
-#define COL 0
-
-void g3d_clear_dirty(void)
+static void reset_dirty(struct rect *r)
{
- unsigned char *ptr;
- int i, count, nlines;
-
- if(dirty_x0 < 0) dirty_x0 = 0;
- if(dirty_y0 < 0) dirty_y0 = 0;
- if(dirty_x1 >= XRES) dirty_x1 = XRES - 1;
- if(dirty_y1 >= YRES) dirty_y1 = YRES - 1;
-
- nlines = dirty_y1 - dirty_y0;
- if(dirty_y1 <= 0 || nlines >= YRES) {
- blkclear(g3d_fbpixels, XRES * YRES, COL);
- goto end;
- }
-
- ptr = g3d_fbpixels + dirty_y0 * XRES;
- if(dirty_x1 > XRES - 4) {
- blkclear(ptr, nlines * XRES, COL);
- goto end;
- }
-
- ptr = (unsigned char*)((uintptr_t)(ptr + dirty_x0) & 0xfffffffc);
- count = dirty_x1 + 3 - dirty_x0;
- for(i=0; i<nlines; i++) {
- blkclear(ptr, count, COL);
- ptr += XRES;
- }
-end:
- g3d_reset_dirty();
+ r->x0 = XRES;
+ r->y0 = YRES;
+ r->x1 = 0;
+ r->y1 = 0;
}
-
-void vmemcopy(long fboffs, void *p, int len);
-#pragma aux vmemcopy = \
- "mov edi, 0xa0000" \
- "add edi, eax" \
- "shr ecx, 2" \
- "rep movsd" \
- parm [eax] [esi] [ecx] \
- modify [ecx edi esi];
-
-void g3d_copy_dirty(void)
+void g3d_clear_dirty(void)
{
- int i, count, nlines;
- unsigned long fboffs;
-
- if(dirty_x0 < 0) dirty_x0 = 0;
- if(dirty_y0 < 0) dirty_y0 = 0;
- if(dirty_x1 >= XRES) dirty_x1 = XRES - 1;
- if(dirty_y1 >= YRES) dirty_y1 = YRES - 1;
-
- nlines = dirty_y1 - dirty_y0;
- if(dirty_y1 <= 0 || nlines >= YRES) {
- vmemcopy(0, g3d_fbpixels, XRES * YRES);
- return;
- }
-
- fboffs = dirty_y0 * XRES;
- if(dirty_x1 > XRES - 4) {
- vmemcopy(fboffs, g3d_fbpixels + fboffs, nlines * XRES);
- return;
- }
-
- fboffs += dirty_x0 & 0xfffffffc;
- count = dirty_x1 + 3 - dirty_x0;
- for(i=0; i<nlines; i++) {
- vmemcopy(fboffs, g3d_fbpixels + fboffs, count);
- fboffs += XRES;
- }
+ int width, height;
+ struct rect *dirty;
+
+ /* we need to clear based not on the last current dirty region, but the one
+ * before that. Then we need to reset the same one we used, and increment
+ * cur_dirty in preperation of this frames drawing
+ */
+ cur_dirty = (cur_dirty + 1) & 1;
+ dirty = dirty_rect + cur_dirty;
+
+ if(dirty->x0 < 0) dirty->x0 = 0;
+ if(dirty->y0 < 0) dirty->y0 = 0;
+ if(dirty->x1 >= XRES) dirty->x1 = XRES - 1;
+ if(dirty->y1 >= YRES) dirty->y1 = YRES - 1;
+
+ width = dirty->x1 + 1 - dirty->x0;
+ height = dirty->y1 + 1 - dirty->y0;
+
+ vid_clearfb_rect(dirty->x0, dirty->y0, width, height);
+ reset_dirty(dirty);
}
void g3d_modelview(const int32_t *m)
#if defined(USE_DIRTY_CLEAR) || defined(USE_DIRTY_COPY)
x = v[i].x >> 8;
y = v[i].y >> 8;
- if(x - 4 < dirty_x0) dirty_x0 = x - 4;
- if(y - 4 < dirty_y0) dirty_y0 = y - 4;
- if(x + 8 > dirty_x1) dirty_x1 = x + 8;
- if(y + 8 > dirty_y1) dirty_y1 = y + 8;
+ {
+ struct rect *dirty = dirty_rect + cur_dirty;
+ if(x < dirty->x0) dirty->x0 = x;
+ if(y < dirty->y0) dirty->y0 = y;
+ if(x + 4 > dirty->x1) dirty->x1 = x + 4;
+ if(y > dirty->y1) dirty->y1 = y;
+ }
#endif
}