summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSegher Boessenkool <segher@kernel.crashing.org>2010-04-05 19:13:18 +0200
committerSegher Boessenkool <segher@kernel.crashing.org>2010-04-07 23:49:52 +0200
commitb8b3a4f8ed0907f33b9266c6c38014b16eeb3829 (patch)
tree4732f0ea8e71c3baf1ff0346fab05b2f84c04d4f
parent8d2bbbf0b6fd7ef356630b93d4c5fbacecc75afa (diff)
Make the render cache store multiple entries per hash slot
-rw-r--r--platform-sdl.c1
-rw-r--r--render.c221
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 = {
diff --git a/render.c b/render.c
index b5fb782..759f551 100644
--- a/render.c
+++ b/render.c
@@ -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)