diff options
author | Segher Boessenkool <segher@kernel.crashing.org> | 2010-04-05 19:13:18 +0200 |
---|---|---|
committer | Segher Boessenkool <segher@kernel.crashing.org> | 2010-04-07 23:49:52 +0200 |
commit | b8b3a4f8ed0907f33b9266c6c38014b16eeb3829 (patch) | |
tree | 4732f0ea8e71c3baf1ff0346fab05b2f84c04d4f | |
parent | 8d2bbbf0b6fd7ef356630b93d4c5fbacecc75afa (diff) |
Make the render cache store multiple entries per hash slot
-rw-r--r-- | platform-sdl.c | 1 | ||||
-rw-r--r-- | render.c | 221 |
2 files changed, 184 insertions, 38 deletions
diff --git a/platform-sdl.c b/platform-sdl.c index 7f82ae6..723f0c0 100644 --- a/platform-sdl.c +++ b/platform-sdl.c @@ -326,6 +326,7 @@ void platform_init(void) fatal("Unable to initialise video: %s\n", SDL_GetError()); #endif + render_kill_cache(); render_init(PIXEL_SIZE); SDL_AudioSpec spec = { @@ -6,6 +6,7 @@ #include "emu.h" #include "video.h" #include "board.h" // for use_centered_coors +#include "platform.h" #include "render.h" @@ -14,11 +15,14 @@ u8 atlas[ATLAS_W*ATLAS_H]; static u32 atlas_x, atlas_y, atlas_h, atlas_low_x, atlas_low_y; -#define CACHESIZE 65536 -static struct { +#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; -} cache[CACHESIZE]; +} cache[CACHE_SIZE]; +struct cache *cache_free_head; struct render_tile render_tiles[N_RENDER_TILES]; @@ -33,8 +37,62 @@ static const u8 colour_sizes[] = { 2, 4, 6, 8 }; void render_kill_cache(void) { u32 i; - for (i = 0; i < CACHESIZE; i++) - cache[i].key = 0; + for (i = 0; i < CACHE_SIZE; i++) { + cache[i].key = -1U; + cache[i].next = 0; + } + + for (i = HASH_SIZE; i < CACHE_SIZE - 1; i++) + cache[i].next = &cache[i + 1]; + cache[CACHE_SIZE - 1].next = 0; + cache_free_head = &cache[HASH_SIZE]; +} + +static u32 cache_key(u32 addr, u16 attr) +{ + return (attr << 24) | addr; +} + +static u32 cache_hash(u32 key) +{ + return (key ^ (key >> 16)) % HASH_SIZE; +} + +static struct cache *cache_get(u32 addr, u16 attr) +{ + u32 key = cache_key(addr, attr); + + struct cache *slot; + for (slot = &cache[cache_hash(key)]; slot; slot = slot->next) { + if (slot->key == 0) + fatal("WHOOPS, CACHE WENT BAD (get)\n"); + if (slot->key == key) + return slot; + } + + fatal("WHOOPS, CACHE WENT BAD (get, slot)\n"); +} + +static struct cache *cache_make(u32 key) +{ + struct cache *slot = &cache[cache_hash(key)]; + if (slot->key == -1U) + return slot; + + for ( ; slot->next; slot = slot->next) { + if (slot->key == key) + return slot; + if (slot->key == -1U) + fatal("WHOOPS, CACHE WENT BAD (make)\n"); + } + +printf("make, new slot %04x\n", cache_free_head - cache); + slot->next = cache_free_head; + slot = cache_free_head; + cache_free_head = cache_free_head->next; + + slot->next = 0; + return slot; } void render_begin(void) @@ -47,56 +105,62 @@ void render_begin(void) __render_begin(); } -static void render_texture(u32 addr, u16 attr, int x, int y, int w, int h, u32 yline, u32 pal_offset, int use_alpha) +static void render_texture_into_atlas(u32 addr, u16 attr, int w, int h) { - u32 key = (attr << 24) | addr; - u32 hash = (key ^ (key >> 16)) % CACHESIZE; - if (cache[hash].key != key) { - if (atlas_x + w > ATLAS_W) { - atlas_x = 0; - atlas_y += atlas_h; - atlas_h = 0; - } + u32 key = cache_key(addr, attr); + struct cache *cache = cache_make(key); + + if (cache->key == key) + return; + + cache->key = key; + + if (atlas_x + w > ATLAS_W) { + atlas_x = 0; + atlas_y += atlas_h; + atlas_h = 0; + } - if (atlas_y + h > ATLAS_H) { - render_atlas(atlas_low_y, atlas_y + atlas_h - atlas_low_y); - atlas_low_x = 0; - atlas_low_y = 0; + if (atlas_y + h > ATLAS_H) { + render_atlas(atlas_low_y, atlas_y + atlas_h - atlas_low_y); + atlas_low_x = 0; + atlas_low_y = 0; - atlas_x = 0; - atlas_y = 0; - atlas_h = 0; + atlas_x = 0; + atlas_y = 0; + atlas_h = 0; printf("filled atlas\n"); // XXX FIXME - u32 i; - for (i = 0; i < CACHESIZE; i++) - cache[i].key = 0; - } + render_kill_cache(); + } - u8 *p = &atlas[atlas_y*ATLAS_W + atlas_x]; + u8 *p = &atlas[atlas_y*ATLAS_W + atlas_x]; //printf("rendering at %d %d\n", atlas_x, atlas_y); - render_bitmap(p, ATLAS_W, addr, attr); + render_bitmap(p, ATLAS_W, addr, attr); - cache[hash].key = key; - cache[hash].atlas_x = atlas_x; - cache[hash].atlas_y = atlas_y; + cache->atlas_x = atlas_x; + cache->atlas_y = atlas_y; - atlas_x += w; + atlas_x += w; - if (h > atlas_h) - atlas_h = h; - } + if (h > atlas_h) + 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[hash].atlas_x; - tile->atlas_y = cache[hash].atlas_y + yline; + 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); } @@ -169,6 +233,82 @@ static void render_tile(u32 page, u32 xoff, u32 yoff, u16 attr, u16 ctrl, u16 ti } } +static void render_tile_into_atlas(u32 page, u16 attr, u16 tile) +{ + 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; + + render_texture_into_atlas(addr, attr, w, h); +} + +static void __noinline render_page_into_atlas(u32 page) +{ + u16 *regs = &mem[0x2810 + 6*page]; + + u32 attr = regs[2]; + u32 ctrl = regs[3]; + u32 tilemap = regs[4]; + u32 palette_map = regs[5]; + + if ((ctrl & 8) == 0) + return; + + u32 h = sizes[(attr & 0x00c0) >> 6]; + u32 w = sizes[(attr & 0x0030) >> 4]; + + 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; + + u16 palette = mem[palette_map + which/2]; + if (which & 1) + palette >>= 8; + + u32 tileattr = attr; + if ((ctrl & 2) == 0) { + tileattr &= ~0x000c; + tileattr |= (palette >> 2) & 0x000c; // flip + } + + render_tile_into_atlas(page, tileattr, tile); + } +} + +static void render_sprite_into_atlas(u16 *sprite) +{ + u16 tile, attr; + + tile = sprite[0]; + attr = sprite[3]; + + if (tile == 0) + return; + + render_tile_into_atlas(2, attr, tile); +} + +static void __noinline render_sprites_into_atlas(void) +{ + if ((mem[0x2842] & 1) == 0) + return; + + u32 i; + for (i = 0; i < 256; i++) + render_sprite_into_atlas(mem + 0x2c00 + 4*i); +} + static void __noinline render_page(u32 page, u32 depth) { u16 *regs = &mem[0x2810 + 6*page]; @@ -235,8 +375,6 @@ static void render_sprite(u32 depth, u16 *sprite) x = sprite[1]; y = sprite[2]; attr = sprite[3]; -//if (tile >= 0x8000) -// printf("UH-OH: %04x %04x %04x %04x\n", tile, x, y, attr); if (tile == 0) return; @@ -302,6 +440,13 @@ void render(void) if ((mem[0x3d20] & 0x0004) == 0) { // video DAC disable render_palette(); + if (!hide_page_1) + render_page_into_atlas(0); + if (!hide_page_2) + render_page_into_atlas(1); + if (!hide_sprites) + render_sprites_into_atlas(); + u32 depth; for (depth = 0; depth < 4; depth++) { if (!hide_page_1) |