summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSegher Boessenkool <segher@kernel.crashing.org>2010-04-07 13:52:29 +0200
committerSegher Boessenkool <segher@kernel.crashing.org>2010-04-12 21:17:15 +0200
commit1f86832699b8ec947591125db71cdd347261a84c (patch)
tree18efdcd546d15e9b8216697bfb481ab926378022
parentb8b3a4f8ed0907f33b9266c6c38014b16eeb3829 (diff)
GL: Handle every video page with just one quad
(and as many texture indirections as we can get away with)
-rw-r--r--render-gl.c373
-rw-r--r--render-soft.c80
-rw-r--r--render.c240
-rw-r--r--render.h21
4 files changed, 467 insertions, 247 deletions
diff --git a/render-gl.c b/render-gl.c
index 74dd5c9..294ed83 100644
--- a/render-gl.c
+++ b/render-gl.c
@@ -19,14 +19,13 @@
#include "render.h"
-static GLuint palette_texture;
-static GLuint atlas_texture;
-static GLuint fragment_shader;
+static GLuint atlas_texture, palette_texture, page_coor_texture,
+ page_colour_texture, page_hoff_texture;
+static GLuint tile_fragment_program, page_fragment_program;
static GLuint display_list;
#define error() do { int err = glGetError(); if (err) fatal("GL error 0x%04x at line %d\n", err, __LINE__); } while(0)
-//#define error() do { } while (0)
void render_palette(void)
@@ -43,20 +42,153 @@ void render_palette(void)
}
glActiveTexture(GL_TEXTURE1);
-error();
glBindTexture(GL_TEXTURE_1D, palette_texture);
-error();
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_BGRA, GL_UNSIGNED_BYTE, that);
error();
}
-void __render_begin(void)
+static enum render_state {
+ state_nothing,
+ state_page,
+ state_tile,
+ state_rect
+} current_render_state;
+
+static void set_render_state(enum render_state render_state)
{
+ if (render_state == current_render_state)
+ return;
+ current_render_state = render_state;
+
+ switch (render_state) {
+ case state_nothing:
+ break;
+
+ case state_page:
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, page_fragment_program);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, atlas_texture);
+ glEnable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE2);
+ glEnable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE3);
+ glEnable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE4);
+ glEnable(GL_TEXTURE_1D);
+ break;
+
+ case state_tile:
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, tile_fragment_program);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, atlas_texture);
+ glEnable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE2);
+ glDisable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE3);
+ glDisable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE4);
+ glDisable(GL_TEXTURE_1D);
+ break;
+
+ case state_rect:
+ glDisable(GL_FRAGMENT_PROGRAM_ARB);
+ glActiveTexture(GL_TEXTURE0);
+ glDisable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE2);
+ glDisable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE3);
+ glDisable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE4);
+ glDisable(GL_TEXTURE_1D);
+ }
}
-static void __noinline do_render_texture(int x, int y, int w, int h, u32 atlas_x, u32 atlas_y, u8 pal_offset, u8 alpha)
+
+void render_page(u32 xscroll, u32 yscroll, u32 h, u32 w)
{
+ set_render_state(state_page);
+
+ u16 coors[4096];
+ u8 colours[4096];
+ u16 hoff[256];
+
+ u32 wn = 512/w, hn = 256/h;
+ u32 x, y;
+
+ u16 *coors1 = render_page_atlas_coors;
+ u8 *colours1 = render_page_tile_colours;
+
+ for (y = 0; y < hn; y++) {
+ for (x = 0; x < wn; x++) {
+ coors[128*y + 2*x] = 32 * *coors1++;
+ coors[128*y + 2*x + 1] = 32 * *coors1++;
+ colours[128*y + 2*x] = *colours1++;
+ colours[128*y + 2*x + 1] = *colours1++;
+ }
+ for ( ; x < 64; x += wn) {
+ memcpy(&coors[128*y + 2*x], &coors[128*y], 4*wn);
+ memcpy(&colours[128*y + 2*x], &colours[128*y], 2*wn);
+ }
+ }
+ memcpy(&coors[128*hn], coors, 256*(32-hn));
+ memcpy(&colours[128*hn], colours, 128*(32-hn));
+
+ glActiveTexture(GL_TEXTURE2);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, page_coor_texture);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 64, 32, GL_LUMINANCE_ALPHA,
+ GL_UNSIGNED_SHORT, coors);
+
+ glActiveTexture(GL_TEXTURE3);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, page_colour_texture);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 64, 32, GL_LUMINANCE_ALPHA,
+ GL_UNSIGNED_BYTE, colours);
+
+ for (y = 0; y < 256; y++)
+ hoff[y] = 128*render_page_hoff[y];
+
+ glActiveTexture(GL_TEXTURE4);
+ glEnable(GL_TEXTURE_1D);
+ glBindTexture(GL_TEXTURE_1D, page_hoff_texture);
+ glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_LUMINANCE,
+ GL_UNSIGNED_SHORT, hoff);
+
+ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0,
+ xscroll/w, yscroll/h, 0, 0);
+ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1,
+ 512.0f/w, 256.0f/h, 0, 0);
+ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2,
+ w/2048.0f, h/2048.0f, 0, 0);
+
+ float tx0 = 0.0f;
+ float ty0 = 0.0f;
+ float tx1 = 320.0f/512;
+ float ty1 = 240.0f/256;
+
+ // X and Y texture coordinates swapped to avoid a swizzle on
+ // the first TEX insn (the hoff one), since that costs an extra
+ // indirection on some cards, and then we have too many.
+ glBegin(GL_QUADS);
+ glTexCoord2f(ty0, tx0);
+ glVertex2i(0, 0);
+ glTexCoord2f(ty0, tx1);
+ glVertex2i(320, 0);
+ glTexCoord2f(ty1, tx1);
+ glVertex2i(320, 240);
+ glTexCoord2f(ty1, tx0);
+ glVertex2i(0, 240);
+ glEnd();
+error();
+}
+
+void render_texture(int x, int y, int w, int h, u16 atlas_x, u16 atlas_y, u8 pal_offset, u8 alpha)
+{
+ set_render_state(state_tile);
+
glColor4ub(pal_offset, 0, 0, alpha);
error();
@@ -78,8 +210,10 @@ error();
error();
}
-static void do_render_rect(int x, int y, int w, int h, u8 r, u8 g, u8 b)
+void render_rect(int x, int y, int w, int h, u8 r, u8 g, u8 b)
{
+ set_render_state(state_rect);
+
glBegin(GL_QUADS);
glColor3ub(r, g, b);
glVertex2i(x, y);
@@ -100,84 +234,129 @@ error();
error();
}
-void render_end(void)
-{
- u32 i;
-
- glClearColor(0.25, 0.15, 0.10, 0);
-error();
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-error();
- glNewList(display_list, GL_COMPILE_AND_EXECUTE);
-error();
-
- glEnable(GL_FRAGMENT_PROGRAM_ARB);
-error();
- glActiveTexture(GL_TEXTURE0);
-error();
- glEnable(GL_TEXTURE_2D);
-error();
-
-
- for (i = 0; i < n_render_tiles; i++) {
- struct render_tile *tile = &render_tiles[i];
- do_render_texture(tile->x, tile->y, tile->w, tile->h, tile->atlas_x, tile->atlas_y, tile->pal_offset, tile->alpha);
- }
-
- glActiveTexture(GL_TEXTURE0);
-error();
- glDisable(GL_TEXTURE_2D);
-error();
- glDisable(GL_FRAGMENT_PROGRAM_ARB);
-error();
+void render_begin(void)
+{
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
- for (i = 0; i < n_render_rects; i++) {
- struct render_rect *rect = &render_rects[i];
- do_render_rect(rect->x, rect->y, rect->w, rect->h, rect->r, rect->g, rect->b);
- }
+ set_render_state(state_nothing);
+}
- glEndList();
-error();
+void render_end(void)
+{
}
-static void init_palette(void)
+static void init_textures(void)
{
glGenTextures(1, &palette_texture);
-error();
glBindTexture(GL_TEXTURE_1D, palette_texture);
-error();
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-error();
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-error();
glTexImage1D(GL_TEXTURE_1D, 0, 4, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
-error();
-}
-static void init_textures(void)
-{
glGenTextures(1, &atlas_texture);
-error();
-
glBindTexture(GL_TEXTURE_2D, atlas_texture);
-error();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-error();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-error();
- glTexImage2D(GL_TEXTURE_2D, 0, 1, ATLAS_W, ATLAS_H, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
+ glTexImage2D(GL_TEXTURE_2D, 0, 1, ATLAS_W, ATLAS_H, 0, GL_LUMINANCE,
+ GL_UNSIGNED_BYTE, 0);
+
+ glGenTextures(1, &page_coor_texture);
+ glBindTexture(GL_TEXTURE_2D, page_coor_texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16_ALPHA16, 64, 32, 0,
+ GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT, 0);
+
+ glGenTextures(1, &page_colour_texture);
+ glBindTexture(GL_TEXTURE_2D, page_colour_texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, 2, 64, 32, 0, GL_LUMINANCE_ALPHA,
+ GL_UNSIGNED_BYTE, 0);
+
+ glGenTextures(1, &page_hoff_texture);
+ glBindTexture(GL_TEXTURE_1D, page_hoff_texture);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE16, 256, 0,
+ GL_LUMINANCE, GL_UNSIGNED_SHORT, 0);
+
error();
}
-static void init_fragment_shader(void)
+static void init_fragment_program(GLuint *id, const char *program)
{
- glGenProgramsARB(1, &fragment_shader);
-error();
- glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, fragment_shader);
-error();
- const char frag[] =
+ glGenProgramsARB(1, id);
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, *id);
+
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(program), program);
+ GLint err;
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &err);
+ if (err != -1) {
+ printf("problem compiling fragment problem:\n");
+ printf(" err pos = %ld\n", (long)err);
+ printf(" err msg: %s\n",
+ glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ fatal("");
+ }
+
+ GLint n, nn;
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_INSTRUCTIONS_ARB, &n);
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &nn);
+ printf(">>> %d (%d) insns\n", n, nn);
+
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_TEMPORARIES_ARB, &n);
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_NATIVE_TEMPORARIES_ARB, &nn);
+ printf(">>> %d (%d) temps\n", n, nn);
+
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_PARAMETERS_ARB, &n);
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_NATIVE_PARAMETERS_ARB, &nn);
+ printf(">>> %d (%d) params\n", n, nn);
+
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_ATTRIBS_ARB, &n);
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_NATIVE_ATTRIBS_ARB, &nn);
+ printf(">>> %d (%d) attrs\n", n, nn);
+
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_ALU_INSTRUCTIONS_ARB, &n);
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, &nn);
+ printf(">>> %d (%d) alu insns\n", n, nn);
+
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_TEX_INSTRUCTIONS_ARB, &n);
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB, &nn);
+ printf(">>> %d (%d) tex insns\n", n, nn);
+
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_TEX_INDIRECTIONS_ARB, &n);
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB, &nn);
+ printf(">>> %d (%d) tex indirs\n", n, nn);
+
+ GLint ok;
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &ok);
+ if (!ok)
+ fatal("fragment program exceeds resources\n");
+}
+
+static void init_fragment_programs(void)
+{
+ const char tile_frag[] =
"!!ARBfp1.0\n"
"TEMP r0; \n"
"TEX r0.x, fragment.texcoord[0], texture[0], 2D; \n"
@@ -186,45 +365,65 @@ error();
"MUL r0.a, r0.a, fragment.color.a; \n"
"MOV result.color, r0; \n"
"END";
- glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(frag), frag);
-GLint err; glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &err);
-printf("GL said err pos = %ld\n", (long)err); // (-1 if ok)
-printf("GL has this to say: >>>%s<<<\n", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
-error();
- glEnable(GL_FRAGMENT_PROGRAM_ARB);
-error();
+ init_fragment_program(&tile_fragment_program, tile_frag);
+
+ const char page_frag[] =
+ "!!ARBfp1.0\n"
+
+ "TEMP coor, tile_coor, tile, tile_colour; \n"
+ "TEMP atlas_coor, palette_coor, colour, hoff; \n"
+
+ "TEX hoff, fragment.texcoord[0], texture[4], 1D; \n" //**
+
+ "MOV coor, fragment.texcoord[0]; \n"
+ "ADD coor.y, coor, hoff; \n"
+ "MAD coor, coor.yxxx, program.local[1], program.local[0]; \n"
+ // now coor is integer tile #, fraction coor within tile
+
+ "FLR tile_coor, coor; \n"
+ "FRC atlas_coor, coor; \n"
+
+ // 1/64,1/32
+ "PARAM tile_scale = { 0.015625, 0.03125 }; \n"
+ "MUL tile_coor, tile_coor, tile_scale; \n"
+
+ "TEX tile, tile_coor, texture[2], 2D; \n" //**
+ "TEX tile_colour, tile_coor, texture[3], 2D; \n"
+ "MAD atlas_coor, atlas_coor, program.local[2], tile.xwww; \n"
+
+ "TEX palette_coor, atlas_coor, texture[0], 2D; \n" //**
+ "ADD palette_coor, palette_coor, tile_colour.r; \n"
+
+ "TEX colour, palette_coor, texture[1], 1D; \n" //**
+ "MUL colour.a, colour.a, tile_colour.a; \n"
+ "MOV result.color, colour; \n"
+
+ "END";
+ init_fragment_program(&page_fragment_program, page_frag);
}
void render_init(u32 pixel_size)
{
printf("GL RENDERER: %s\n", glGetString(GL_RENDERER));
printf("GL VENDOR: %s\n", glGetString(GL_VENDOR));
- printf("GL EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
+// printf("GL EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
printf("GL VERSION: %s\n", glGetString(GL_VERSION));
glViewport(0, 0, pixel_size*320, pixel_size*240);
-error();
glMatrixMode(GL_PROJECTION);
-error();
glLoadIdentity();
-error();
glOrtho(0, 320, 240, 0, -1, 1);
-error();
+
glMatrixMode(GL_MODELVIEW);
-error();
glLoadIdentity();
-error();
- glEnable (GL_BLEND);
-error();
- glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-error();
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ error();
- init_palette();
init_textures();
- init_fragment_shader();
+ init_fragment_programs();
display_list = glGenLists(1);
-error();
}
diff --git a/render-soft.c b/render-soft.c
index d314a29..a6ce570 100644
--- a/render-soft.c
+++ b/render-soft.c
@@ -13,30 +13,27 @@
#include "render.h"
-static const u8 sizes[] = { 8, 16, 32, 64 };
-
u32 pixel_mask[3];
u32 pixel_shift[3];
-static inline u8 mix_channel(u8 old, u8 new)
+static inline u8 mix_channel(u8 old, u8 new, u8 alpha)
{
- u8 alpha = mem[0x282a];
- return ((4 - alpha)*old + alpha*new) / 4;
+ return ((255 - alpha)*old + alpha*new) / 255;
}
-static inline void mix_pixel(u32 offset, u32 rgb)
+static inline void mix_pixel(u32 offset, u32 rgb, u8 alpha)
{
u32 x = 0;
u32 i;
for (i = 0; i < 3; i++) {
u8 old = (screen[offset] & pixel_mask[i]) >> pixel_shift[i];
u8 new = (rgb & pixel_mask[i]) >> pixel_shift[i];
- x |= (mix_channel(old, new) << pixel_shift[i]) & pixel_mask[i];
+ x |= (mix_channel(old, new, alpha) << pixel_shift[i]) & pixel_mask[i];
}
screen[offset] = x;
}
-static void do_render_texture(int xoff, int yoff, int w, int h, u32 atlas_x, u32 atlas_y, u8 pal_offset, u8 alpha)
+void render_texture(int xoff, int yoff, int w, int h, u16 atlas_x, u16 atlas_y, u8 pal_offset, u8 alpha)
{
//printf("drawing at %d %d\n", atlas_x, atlas_y);
u8 *p = &atlas[atlas_y*ATLAS_W + atlas_x];
@@ -53,7 +50,7 @@ static void do_render_texture(int xoff, int yoff, int w, int h, u32 atlas_x, u32
u16 rgb = mem[0x2b00 + pal];
if ((rgb & 0x8000) == 0) {
if (alpha != 255)
- mix_pixel(xx + 320*yy, palette_rgb[pal]);
+ mix_pixel(xx + 320*yy, palette_rgb[pal], alpha);
else
screen[xx + 320*yy] = palette_rgb[pal];
}
@@ -62,7 +59,7 @@ static void do_render_texture(int xoff, int yoff, int w, int h, u32 atlas_x, u32
}
}
-static void do_render_rect(int x, int y, int w, int h, u8 r, u8 g, u8 b)
+void render_rect(int x, int y, int w, int h, u8 r, u8 g, u8 b)
{
u32 rgb = get_colour(r, g, b);
@@ -77,26 +74,63 @@ void render_atlas(u32 atlas_y, u32 atlas_h)
printf("atlas: %d+%d\n", atlas_y, atlas_h);
}
-void __render_begin(void)
+
+static void render_page_tile(u32 xoff, u32 yoff, u32 h, u32 w, u16 atlas_x, u16 atlas_y, u8 pal_offset, u8 alpha)
{
+ for (u32 y = 0; y < h; y++) {
+ int yy = yoff + y;
+ yy &= 0x01ff;
+ if (yy >= 0x01c0)
+ yy -= 0x0200;
+
+ int xx = xoff;
+ if (yy < 0 || yy >= 240)
+ continue;
+
+ xx -= render_page_hoff[yy];
+
+ xx &= 0x01ff;
+ if (xx >= 0x01c0)
+ xx -= 0x0200;
+
+ if (xx + w <= 0 || xx >= 320)
+ continue;
+
+ render_texture(xx, yy, w, 1, atlas_x, atlas_y + y, pal_offset, alpha);
+ }
}
-void render_end(void)
+void render_page(u32 xscroll, u32 yscroll, u32 h, u32 w)
{
- memset(screen, 0, sizeof screen);
+ u32 hn = 256/h;
+ u32 wn = 512/w;
- u32 i;
- for (i = 0; i < n_render_tiles; i++) {
- struct render_tile *tile = &render_tiles[i];
- do_render_texture(tile->x, tile->y, tile->w, tile->h, tile->atlas_x, tile->atlas_y, tile->pal_offset, tile->alpha);
- }
+ u32 x0, y0;
+ for (y0 = 0; y0 < hn; y0++)
+ for (x0 = 0; x0 < wn; x0++) {
+ u32 index = x0 + wn*y0;
- for (i = 0; i < n_render_rects; i++) {
- struct render_rect *rect = &render_rects[i];
- do_render_rect(rect->x, rect->y, rect->w, rect->h, rect->r, rect->g, rect->b);
- }
+ u32 y = ((h*y0 - yscroll + 0x10) & 0xff) - 0x10;
+ u32 x = (w*x0 - xscroll) & 0x1ff;
+
+ u16 atlas_x = render_page_atlas_coors[2*index];
+ u16 atlas_y = render_page_atlas_coors[2*index+1];
+ u8 pal_offset = render_page_tile_colours[2*index];
+ u8 alpha = render_page_tile_colours[2*index+1];
+
+ render_page_tile(x, y, h, w, atlas_x, atlas_y, pal_offset, alpha);
+ }
+}
+
+void render_begin(void)
+{
+ memset(screen, 0, sizeof screen);
+}
+
+void render_end(void)
+{
}
-void render_init(u32 pixel_size)
+void render_init(__unused u32 pixel_size)
{
}
diff --git a/render.c b/render.c
index 759f551..24d9404 100644
--- a/render.c
+++ b/render.c
@@ -14,22 +14,21 @@
u8 atlas[ATLAS_W*ATLAS_H];
static u32 atlas_x, atlas_y, atlas_h, atlas_low_x, atlas_low_y;
+u16 render_page_atlas_coors[4096];
+u8 render_page_tile_colours[4096];
+u16 render_page_hoff[256];
+
#define HASH_SIZE 65536
#define CACHE_SIZE (HASH_SIZE + ATLAS_W*ATLAS_H/64)
static struct cache {
u32 key;
struct cache *next;
- u32 atlas_x, atlas_y;
+ u16 atlas_x, atlas_y;
} cache[CACHE_SIZE];
struct cache *cache_free_head;
-struct render_tile render_tiles[N_RENDER_TILES];
-struct render_rect render_rects[N_RENDER_RECTS];
-u32 n_render_tiles, n_render_rects;
-
-
static const u8 sizes[] = { 8, 16, 32, 64 };
static const u8 colour_sizes[] = { 2, 4, 6, 8 };
@@ -95,16 +94,6 @@ printf("make, new slot %04x\n", cache_free_head - cache);
return slot;
}
-void render_begin(void)
-{
- n_render_tiles = 0;
- n_render_rects = 0;
- atlas_low_x = atlas_x;
- atlas_low_y = atlas_y;
-
- __render_begin();
-}
-
static void render_texture_into_atlas(u32 addr, u16 attr, int w, int h)
{
u32 key = cache_key(addr, attr);
@@ -150,87 +139,39 @@ printf("filled atlas\n");
atlas_h = h;
}
-static void render_texture(u32 addr, u16 attr, int x, int y, int w, int h, u32 yline, u32 pal_offset, int use_alpha)
-{
- struct cache *cache = cache_get(addr, attr);
-
- struct render_tile *tile = &render_tiles[n_render_tiles++];
- tile->x = x;
- tile->y = y;
- tile->w = w;
- tile->h = h;
- tile->atlas_x = cache->atlas_x;
- tile->atlas_y = cache->atlas_y + yline;
- tile->pal_offset = pal_offset;
- tile->alpha = (use_alpha ? mem[0x282a] << 6 : 255);
-}
-
-static void render_rect(int x, int y, int w, int h, u8 r, u8 g, u8 b)
-{
- struct render_rect *rect = &render_rects[n_render_rects++];
- rect->x = x;
- rect->y = y;
- rect->w = w;
- rect->h = h;
- rect->r = r;
- rect->g = g;
- rect->b = b;
-}
-
-static void render_tile(u32 page, u32 xoff, u32 yoff, u16 attr, u16 ctrl, u16 tile)
+static void render_tile(u32 xoff, u32 yoff, u32 addr, u16 attr)
{
u32 h = sizes[(attr & 0x00c0) >> 6];
u32 w = sizes[(attr & 0x0030) >> 4];
u32 nc = colour_sizes[attr & 0x0003];
- u32 addr = 0x40*mem[0x2820 + page] + nc*w*h/16*tile;
-
- int use_alpha = !!(attr & 0x4000 || ctrl & 0x0100);
- int use_hoff = !!(ctrl & 0x0010);
+ u8 alpha = 255;
+ if (attr & 0x4000)
+ alpha = mem[0x282a] << 6;
- u32 palette_offset = (attr & 0x0f00) >> 4;
- palette_offset >>= nc;
- palette_offset <<= nc;
+ u32 pal_offset = (attr & 0x0f00) >> 4;
+ pal_offset >>= nc;
+ pal_offset <<= nc;
- if (use_hoff) {
- for (u32 y = 0; y < h; y++) {
- int yy = yoff + y;
- yy &= 0x01ff;
- if (yy >= 0x01c0)
- yy -= 0x0200;
+ int yy = yoff & 0x01ff;
+ if (yy >= 0x01c0)
+ yy -= 0x0200;
- int xx = xoff;
- if (yy < 0 || yy >= 240)
- continue;
-
- xx -= mem[0x2900 + yy];
-
- xx &= 0x01ff;
- if (xx >= 0x01c0)
- xx -= 0x0200;
-
- if (xx + w <= 0 || xx >= 320)
- continue;
+ int xx = xoff & 0x01ff;
+ if (xx >= 0x01c0)
+ xx -= 0x0200;
- render_texture(addr, attr, xx, yy, w, 1, y, palette_offset, use_alpha);
- }
- } else {
- int yy = yoff & 0x01ff;
- if (yy >= 0x01c0)
- yy -= 0x0200;
-
- int xx = xoff & 0x01ff;
- if (xx >= 0x01c0)
- xx -= 0x0200;
+ if (xx + w <= 0 || xx >= 320)
+ return;
+ if (yy + h <= 0 || yy >= 240)
+ return;
- if (xx + w <= 0 || xx >= 320)
- return;
- if (yy + h <= 0 || yy >= 240)
- return;
+ struct cache *cache = cache_get(addr, attr);
+ u16 atlas_x = cache->atlas_x;
+ u16 atlas_y = cache->atlas_y;
- render_texture(addr, attr, xx, yy, w, h, 0, palette_offset, use_alpha);
- }
+ render_texture(xx, yy, w, h, atlas_x, atlas_y, pal_offset, alpha);
}
static void render_tile_into_atlas(u32 page, u16 attr, u16 tile)
@@ -309,12 +250,10 @@ static void __noinline render_sprites_into_atlas(void)
render_sprite_into_atlas(mem + 0x2c00 + 4*i);
}
-static void __noinline render_page(u32 page, u32 depth)
+static void __noinline render_page_arrays(u32 page, u32 depth)
{
u16 *regs = &mem[0x2810 + 6*page];
- u32 xscroll = regs[0];
- u32 yscroll = regs[1];
u32 attr = regs[2];
u32 ctrl = regs[3];
u32 tilemap = regs[4];
@@ -328,42 +267,85 @@ static void __noinline render_page(u32 page, u32 depth)
u32 h = sizes[(attr & 0x00c0) >> 6];
u32 w = sizes[(attr & 0x0030) >> 4];
+ u32 nc = colour_sizes[attr & 0x0003];
u32 hn = 256/h;
u32 wn = 512/w;
- u32 x0, y0;
- for (y0 = 0; y0 < hn; y0++)
- for (x0 = 0; x0 < wn; x0++) {
- u32 which = (ctrl & 4) ? 0 : x0 + wn*y0;
- u16 tile = mem[tilemap + which];
-
- if (tile == 0)
- continue;
+ u32 i;
+ for (i = 0; i < hn*wn; i++) {
+ u32 which = (ctrl & 4) ? 0 : i;
- u16 palette = mem[palette_map + which/2];
- if (which & 1)
- palette >>= 8;
+ u16 tile = mem[tilemap + which];
- u32 tileattr = attr;
- u32 tilectrl = ctrl;
- if ((ctrl & 2) == 0) {
-// -(1) bld(1) flip(2) pal(4)
- tileattr &= ~0x000c;
- tileattr |= (palette >> 2) & 0x000c; // flip
+ u16 palette = mem[palette_map + which/2];
+ if (which & 1)
+ palette >>= 8;
- tileattr &= ~0x0f00;
- tileattr |= (palette << 8) & 0x0f00; // palette
+ u32 tileattr = attr;
+ u32 tilectrl = ctrl;
+ if ((ctrl & 2) == 0) {
+ tileattr &= ~0x000c;
+ tileattr |= (palette >> 2) & 0x000c; // flip
- tilectrl &= ~0x0100;
- tilectrl |= (palette << 2) & 0x0100; // blend
- }
+ tileattr &= ~0x0f00;
+ tileattr |= (palette << 8) & 0x0f00; // palette
- u32 yy = ((h*y0 - yscroll + 0x10) & 0xff) - 0x10;
- u32 xx = (w*x0 - xscroll) & 0x1ff;
+ tilectrl &= ~0x0100;
+ tilectrl |= (palette << 2) & 0x0100; // blend
+ }
- render_tile(page, xx, yy, tileattr, tilectrl, tile);
+ u16 atlas_x, atlas_y;
+ if (tile) {
+ u32 addr = 0x40*mem[0x2820 + page] + nc*w*h/16*tile;
+ struct cache *cache = cache_get(addr, tileattr);
+ atlas_x = cache->atlas_x;
+ atlas_y = cache->atlas_y;
+ } else {
+ atlas_x = 0;
+ atlas_y = 0;
}
+
+ u32 pal_offset = (tileattr & 0x0f00) >> 4;
+ pal_offset >>= nc;
+ pal_offset <<= nc;
+
+ u8 alpha = 255;
+ if (attr & 0x4000 || tilectrl & 0x0100)
+ alpha = mem[0x282a] << 6;
+ if (tile == 0)
+ alpha = 0;
+
+ render_page_atlas_coors[2*i] = atlas_x;
+ render_page_atlas_coors[2*i+1] = atlas_y;
+ render_page_tile_colours[2*i] = pal_offset;
+ render_page_tile_colours[2*i+1] = alpha;
+ }
+}
+
+static void __noinline __render_page(u32 page, u32 depth)
+{
+ u16 *regs = &mem[0x2810 + 6*page];
+
+ u32 xscroll = regs[0];
+ u32 yscroll = regs[1];
+ u32 attr = regs[2];
+ u32 ctrl = regs[3];
+
+ if ((ctrl & 8) == 0)
+ return;
+
+ if ((attr & 0x3000) >> 12 != depth)
+ return;
+
+ u32 h = sizes[(attr & 0x00c0) >> 6];
+ u32 w = sizes[(attr & 0x0030) >> 4];
+
+ u32 i;
+ for (i = 0; i < 240; i++)
+ render_page_hoff[i] = (ctrl & 0x0010) ? mem[0x2900 + i] : 0;
+
+ render_page(xscroll, yscroll, h, w);
}
static void render_sprite(u32 depth, u16 *sprite)
@@ -382,13 +364,14 @@ static void render_sprite(u32 depth, u16 *sprite)
if ((u32)(attr & 0x3000) >> 12 != depth)
return;
+ u32 h = sizes[(attr & 0x00c0) >> 6];
+ u32 w = sizes[(attr & 0x0030) >> 4];
+ u32 nc = colour_sizes[attr & 0x0003];
+
if (board->use_centered_coors) {
x = 160 + x;
y = 120 - y;
- u32 h = sizes[(attr & 0x00c0) >> 6];
- u32 w = sizes[(attr & 0x0030) >> 4];
-
x -= (w/2);
y -= (h/2) - 8;
}
@@ -396,7 +379,9 @@ static void render_sprite(u32 depth, u16 *sprite)
x = x & 0x1ff;
y = y & 0x1ff;
- render_tile(2, x, y, attr, 0, tile);
+ u32 addr = 0x40*mem[0x2822] + nc*w*h/16*tile;
+
+ render_tile(x, y, addr, attr);
}
static void __noinline render_sprites(u32 depth)
@@ -440,6 +425,9 @@ void render(void)
if ((mem[0x3d20] & 0x0004) == 0) { // video DAC disable
render_palette();
+ atlas_low_x = atlas_x;
+ atlas_low_y = atlas_y;
+
if (!hide_page_1)
render_page_into_atlas(0);
if (!hide_page_2)
@@ -447,20 +435,24 @@ void render(void)
if (!hide_sprites)
render_sprites_into_atlas();
+ if (atlas_y != atlas_low_y || atlas_x != atlas_low_x)
+ render_atlas(atlas_low_y, atlas_y + atlas_h - atlas_low_y);
+
u32 depth;
for (depth = 0; depth < 4; depth++) {
- if (!hide_page_1)
- render_page(0, depth);
- if (!hide_page_2)
- render_page(1, depth);
+ if (!hide_page_1) {
+ render_page_arrays(0, depth);
+ __render_page(0, depth);
+ }
+ if (!hide_page_2) {
+ render_page_arrays(1, depth);
+ __render_page(1, depth);
+ }
if (!hide_sprites)
render_sprites(depth);
}
}
- if (atlas_y != atlas_low_y || atlas_x != atlas_low_x)
- render_atlas(atlas_low_y, atlas_y + atlas_h - atlas_low_y);
-
if (show_fps)
do_show_fps();
diff --git a/render.h b/render.h
index b67c557..3538e32 100644
--- a/render.h
+++ b/render.h
@@ -12,24 +12,19 @@ void render_kill_cache(void);
void render_palette(void);
void render_atlas(u32 atlas_y, u32 atlas_h);
-void render_begin(void); // XXX: get rid of this?
+void render_begin(void);
void render_end(void);
-#define N_RENDER_TILES (2*256*32+256)
-#define N_RENDER_RECTS 256
-extern struct render_tile {
- int x, y, w, h;
- u32 atlas_x, atlas_y;
- u8 pal_offset, alpha;
-} render_tiles[N_RENDER_TILES];
+extern u16 render_page_atlas_coors[4096];
+extern u8 render_page_tile_colours[4096];
+extern u16 render_page_hoff[256];
-extern struct render_rect {
- int x, y, w, h;
- u8 r, g, b;
-} render_rects[N_RENDER_RECTS];
+void render_page(u32 xscroll, u32 yscroll, u32 h, u32 w);
-extern u32 n_render_tiles, n_render_rects;
+
+void render_texture(int x, int y, int w, int h, u16 atlas_x, u16 atlas_y, u8 pal_offset, u8 alpha);
+void render_rect(int x, int y, int w, int h, u8 r, u8 g, u8 b);
// ATLAS_W and ATLAS_H should be a multiple of 64 and a power of two;