diff options
author | Segher Boessenkool <segher@kernel.crashing.org> | 2010-04-07 13:52:29 +0200 |
---|---|---|
committer | Segher Boessenkool <segher@kernel.crashing.org> | 2010-04-12 21:17:15 +0200 |
commit | 1f86832699b8ec947591125db71cdd347261a84c (patch) | |
tree | 18efdcd546d15e9b8216697bfb481ab926378022 | |
parent | b8b3a4f8ed0907f33b9266c6c38014b16eeb3829 (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.c | 373 | ||||
-rw-r--r-- | render-soft.c | 80 | ||||
-rw-r--r-- | render.c | 240 | ||||
-rw-r--r-- | render.h | 21 |
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) { } @@ -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(); @@ -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; |