diff options
author | Segher Boessenkool <segher@kernel.crashing.org> | 2010-02-25 19:45:37 +0100 |
---|---|---|
committer | Segher Boessenkool <segher@kernel.crashing.org> | 2010-04-07 23:49:51 +0200 |
commit | 8d2bbbf0b6fd7ef356630b93d4c5fbacecc75afa (patch) | |
tree | 6e0e03a52eb33674ebf06fb9dc304fe6f3317b84 | |
parent | a9bd7b42eb7290b59b49476a718f1968881354b7 (diff) |
OpenGL support
-rw-r--r-- | Makefile | 17 | ||||
-rw-r--r-- | board-VII.c | 2 | ||||
-rw-r--r-- | emu.c | 3 | ||||
-rw-r--r-- | platform-sdl.c | 47 | ||||
-rw-r--r-- | render-gl.c | 230 | ||||
-rw-r--r-- | render-soft.c | 102 | ||||
-rw-r--r-- | render.c | 325 | ||||
-rw-r--r-- | render.h | 45 | ||||
-rw-r--r-- | video.c | 288 | ||||
-rw-r--r-- | video.h | 4 |
10 files changed, 765 insertions, 298 deletions
@@ -1,5 +1,14 @@ +# Build for what platform? +PLATFORM := sdl + +# What video renderer? +RENDER := gl +#RENDER := soft + + CC := gcc CFLAGS := -std=gnu99 -Wall -W -O2 -g -Wmissing-declarations -ffast-math +CFLAGS += -DRENDER_$(RENDER) LDFLAGS := -g # Build for what platform? @@ -14,8 +23,8 @@ un-disas: un-disas.o disas.o # The emulator. uuu-$(PLATFORM): uuu-%: uuu-%.o platform-%.o \ - disas.o emu.o timer.o video.o audio.o io.o \ - i2c-bus.o i2c-eeprom.o \ + disas.o emu.o timer.o video.o render.o render-$(RENDER).o \ + audio.o io.o i2c-bus.o i2c-eeprom.o \ board.o board-VII.o board-WAL.o board-BAT.o board-V_X.o board-dummy.o # SDL needs special compiler flags and some libraries. @@ -49,7 +58,9 @@ endif # Clean up. .PHONY: clean clean: - rm -f un-disas un-disas.o disas.o emu.o timer.o video.o audio.o io.o + rm -f un-disas un-disas.o disas.o + rm -f emu.o timer.o video.o audio.o io.o rm -f i2c-bus.o i2c-eeprom.o rm -f board.o board-VII.o board-WAL.o board-BAT.o board-V_X.o board-dummy.o + rm -f render.o render-gl.o render-soft.o rm -f uuu-sdl uuu-sdl.o platform-sdl.o dialog-cocoa.o diff --git a/board-VII.c b/board-VII.c index 7cd2984..08b9902 100644 --- a/board-VII.c +++ b/board-VII.c @@ -21,6 +21,8 @@ static void switch_bank(u32 bank) return; current_bank = bank; + render_kill_cache(); + read_rom(N_MEM*bank); // memset(ever_ran_this, 0, N_MEM); @@ -14,6 +14,7 @@ #include "audio.h" #include "io.h" #include "platform.h" +#include "render.h" #include "board.h" #include "emu.h" @@ -913,7 +914,7 @@ static void run(void) do_idle(); - update_screen(); + render(); // now = get_realtime(); // printf("-> %uus for this field (gfx)\n", now - last); diff --git a/platform-sdl.c b/platform-sdl.c index 361a142..7f82ae6 100644 --- a/platform-sdl.c +++ b/platform-sdl.c @@ -7,11 +7,13 @@ #include <sys/stat.h> #include <sys/time.h> #include <SDL.h> +#include <SDL_opengl.h> #include "types.h" #include "emu.h" #include "video.h" #include "audio.h" +#include "render.h" #include "platform.h" @@ -89,13 +91,19 @@ void save_eeprom(void *cookie, u8 *data, u32 len) static SDL_Surface *sdl_surface; +#ifdef RENDER_soft static inline u8 x58(u32 x) { x &= 31; return (x << 3) | (x >> 2); } -void update_screen(void) +u32 get_colour(u8 r, u8 g, u8 b) +{ + return SDL_MapRGB(sdl_surface->format, r, g, b); +} + +void render_palette(void) { u32 i; for (i = 0; i < 256; i++) { @@ -105,9 +113,10 @@ void update_screen(void) x58((p >> 5) & 31), x58(p & 31)); } +} - blit_screen(); - +void update_screen(void) +{ if (SDL_MUSTLOCK(sdl_surface)) if (SDL_LockSurface(sdl_surface) < 0) fatal("oh crap\n"); @@ -136,6 +145,14 @@ void update_screen(void) SDL_UpdateRect(sdl_surface, 0, 0, 0, 0); } +#endif + +#ifdef RENDER_gl +void update_screen(void) +{ + SDL_GL_SwapBuffers(); +} +#endif u8 button_up; @@ -272,9 +289,6 @@ static void mix(__unused void *cookie, u8 *data, int n) } -u32 pixel_mask[3]; -u32 pixel_shift[3]; - void platform_init(void) { if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0) @@ -283,12 +297,14 @@ void platform_init(void) SDL_WM_SetCaption("Unununium", 0); - sdl_surface = SDL_SetVideoMode(PIXEL_SIZE*320, PIXEL_SIZE*240, 32, SDL_SWSURFACE); +#ifdef RENDER_soft + sdl_surface = SDL_SetVideoMode(PIXEL_SIZE*320, PIXEL_SIZE*240, 0, + SDL_SWSURFACE); if (!sdl_surface) fatal("Unable to initialise video: %s\n", SDL_GetError()); if (sdl_surface->format->BytesPerPixel != 4) - fatal("Didn't get a 32-bit surface"); + fatal("Didn't get a 32-bit surface\n"); pixel_mask[0] = sdl_surface->format->Rmask; pixel_mask[1] = sdl_surface->format->Gmask; @@ -296,6 +312,21 @@ void platform_init(void) pixel_shift[0] = sdl_surface->format->Rshift; pixel_shift[1] = sdl_surface->format->Gshift; pixel_shift[2] = sdl_surface->format->Bshift; +#endif + +#ifdef RENDER_gl + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + + sdl_surface = SDL_SetVideoMode(PIXEL_SIZE*320, PIXEL_SIZE*240, 0, SDL_OPENGL); + + if (!sdl_surface) + fatal("Unable to initialise video: %s\n", SDL_GetError()); +#endif + + render_init(PIXEL_SIZE); SDL_AudioSpec spec = { .freq = 44100, diff --git a/render-gl.c b/render-gl.c new file mode 100644 index 0000000..74dd5c9 --- /dev/null +++ b/render-gl.c @@ -0,0 +1,230 @@ +// Copyright 2010 Segher Boessenkool <segher@kernel.crashing.org> +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include <stdio.h> +#include <string.h> +#ifdef __APPLE__ +#include <OpenGL/gl.h> +#include <OpenGL/glext.h> +#else +#include <GL/gl.h> +#include <GL/glext.h> +#endif + +#include "types.h" +#include "emu.h" +#include "platform.h" + +#include "render.h" + + +static GLuint palette_texture; +static GLuint atlas_texture; +static GLuint fragment_shader; +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) +{ + static u8 that[4*256]; + + u32 i; + for (i = 0; i < 256; i++) { + u16 p = mem[0x2b00 + i]; + that[4*i] = 255*(p & 31) / 31.0f; + that[4*i+1] = 255*((p >> 5) & 31) / 31.0f; + that[4*i+2] = 255*((p >> 10) & 31) / 31.0f; + that[4*i+3] = 255*(1-(p >> 15)); + } + + 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 void __noinline do_render_texture(int x, int y, int w, int h, u32 atlas_x, u32 atlas_y, u8 pal_offset, u8 alpha) +{ + glColor4ub(pal_offset, 0, 0, alpha); +error(); + + float tx0 = (float)atlas_x/ATLAS_W; + float ty0 = (float)atlas_y/ATLAS_H; + float tx1 = (float)(atlas_x + w)/ATLAS_W; + float ty1 = (float)(atlas_y + h)/ATLAS_H; + + glBegin(GL_QUADS); + glTexCoord2f(tx0, ty0); + glVertex2i(x, y); + glTexCoord2f(tx1, ty0); + glVertex2i(x + w, y); + glTexCoord2f(tx1, ty1); + glVertex2i(x + w, y + h); + glTexCoord2f(tx0, ty1); + glVertex2i(x, y + h); + glEnd(); +error(); +} + +static void do_render_rect(int x, int y, int w, int h, u8 r, u8 g, u8 b) +{ + glBegin(GL_QUADS); + glColor3ub(r, g, b); + glVertex2i(x, y); + glVertex2i(x + w, y); + glVertex2i(x + w, y + h); + glVertex2i(x, y + h); + glEnd(); +error(); +} + +void render_atlas(u32 atlas_y, u32 atlas_h) +{ +printf("atlas: %d+%d\n", atlas_y, atlas_h); + + glBindTexture(GL_TEXTURE_2D, atlas_texture); +error(); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, atlas_y, ATLAS_W, atlas_h, GL_LUMINANCE, GL_UNSIGNED_BYTE, &atlas[atlas_y*ATLAS_W]); +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(); + + 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); + } + + glEndList(); +error(); +} + + +static void init_palette(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); +error(); +} + +static void init_fragment_shader(void) +{ + glGenProgramsARB(1, &fragment_shader); +error(); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, fragment_shader); +error(); + const char frag[] = + "!!ARBfp1.0\n" + "TEMP r0; \n" + "TEX r0.x, fragment.texcoord[0], texture[0], 2D; \n" + "ADD r0.x, r0.x, fragment.color.r; \n" + "TEX r0, r0, texture[1], 1D; \n" + "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(); +} + +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 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(); + + init_palette(); + init_textures(); + init_fragment_shader(); + + display_list = glGenLists(1); +error(); +} diff --git a/render-soft.c b/render-soft.c new file mode 100644 index 0000000..d314a29 --- /dev/null +++ b/render-soft.c @@ -0,0 +1,102 @@ +// Copyright 2008-2010 Segher Boessenkool <segher@kernel.crashing.org> +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +//#include <stdio.h> +#include <string.h> + +#include "types.h" +#include "emu.h" +#include "board.h" +#include "video.h" + +#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) +{ + u8 alpha = mem[0x282a]; + return ((4 - alpha)*old + alpha*new) / 4; +} + +static inline void mix_pixel(u32 offset, u32 rgb) +{ + 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]; + } + 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) +{ +//printf("drawing at %d %d\n", atlas_x, atlas_y); + u8 *p = &atlas[atlas_y*ATLAS_W + atlas_x]; + + for (u32 y = 0; y < (u32)h; y++) { + u32 yy = (yoff + y) & 0x1ff; + + for (u32 x = 0; x < (u32)w; x++) { + u32 xx = (xoff + x) & 0x1ff; + + u8 pal = p[y*ATLAS_W + x] + pal_offset; + + if (xx < 320 && yy < 240) { + u16 rgb = mem[0x2b00 + pal]; + if ((rgb & 0x8000) == 0) { + if (alpha != 255) + mix_pixel(xx + 320*yy, palette_rgb[pal]); + else + screen[xx + 320*yy] = palette_rgb[pal]; + } + } + } + } +} + +static void do_render_rect(int x, int y, int w, int h, u8 r, u8 g, u8 b) +{ + u32 rgb = get_colour(r, g, b); + + u32 xx, yy; + for (yy = y; yy < (u32)y + h; yy++) + for (xx = x; xx < (u32)x + w; xx++) + screen[320*yy + xx] = rgb; +} + +void render_atlas(u32 atlas_y, u32 atlas_h) +{ + printf("atlas: %d+%d\n", atlas_y, atlas_h); +} + +void __render_begin(void) +{ +} + +void render_end(void) +{ + memset(screen, 0, sizeof screen); + + 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); + } + + 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); + } +} + +void render_init(u32 pixel_size) +{ +} diff --git a/render.c b/render.c new file mode 100644 index 0000000..b5fb782 --- /dev/null +++ b/render.c @@ -0,0 +1,325 @@ +// Copyright 2008-2010 Segher Boessenkool <segher@kernel.crashing.org> +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "types.h" +#include "emu.h" +#include "video.h" +#include "board.h" // for use_centered_coors + +#include "render.h" + + +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 { + u32 key; + u32 atlas_x, atlas_y; +} cache[CACHESIZE]; + + +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 }; + + +void render_kill_cache(void) +{ + u32 i; + for (i = 0; i < CACHESIZE; i++) + cache[i].key = 0; +} + +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(u32 addr, u16 attr, int x, int y, int w, int h, u32 yline, u32 pal_offset, int use_alpha) +{ + 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; + } + + 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; + +printf("filled atlas\n"); + +// XXX FIXME + u32 i; + for (i = 0; i < CACHESIZE; i++) + cache[i].key = 0; + } + + 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); + + cache[hash].key = key; + cache[hash].atlas_x = atlas_x; + cache[hash].atlas_y = atlas_y; + + atlas_x += w; + + if (h > atlas_h) + atlas_h = h; + } + + 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->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) +{ + 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); + + u32 palette_offset = (attr & 0x0f00) >> 4; + palette_offset >>= nc; + palette_offset <<= nc; + + if (use_hoff) { + 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 -= mem[0x2900 + yy]; + + xx &= 0x01ff; + if (xx >= 0x01c0) + xx -= 0x0200; + + if (xx + w <= 0 || xx >= 320) + continue; + + 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; + + render_texture(addr, attr, xx, yy, w, h, 0, palette_offset, use_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]; + u32 tilemap = regs[4]; + u32 palette_map = regs[5]; + + if ((ctrl & 8) == 0) + return; + + if ((attr & 0x3000) >> 12 != depth) + 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; + u32 tilectrl = ctrl; + if ((ctrl & 2) == 0) { +// -(1) bld(1) flip(2) pal(4) + tileattr &= ~0x000c; + tileattr |= (palette >> 2) & 0x000c; // flip + + tileattr &= ~0x0f00; + tileattr |= (palette << 8) & 0x0f00; // palette + + tilectrl &= ~0x0100; + tilectrl |= (palette << 2) & 0x0100; // blend + } + + u32 yy = ((h*y0 - yscroll + 0x10) & 0xff) - 0x10; + u32 xx = (w*x0 - xscroll) & 0x1ff; + + render_tile(page, xx, yy, tileattr, tilectrl, tile); + } +} + +static void render_sprite(u32 depth, u16 *sprite) +{ + u16 tile, attr; + s16 x, y; + + tile = sprite[0]; + 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; + + if ((u32)(attr & 0x3000) >> 12 != depth) + return; + + 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; + } + + x = x & 0x1ff; + y = y & 0x1ff; + + render_tile(2, x, y, attr, 0, tile); +} + +static void __noinline render_sprites(u32 depth) +{ + if ((mem[0x2842] & 1) == 0) + return; + + u32 i; + for (i = 0; i < 256; i++) + render_sprite(depth, mem + 0x2c00 + 4*i); +} + +static void do_show_fps(void) +{ + static u32 fps = 0; + + const int per_n = 5; + static int count = 0; + count++; + if (count == per_n) { + static u32 last = 0; + u32 now = get_realtime(); + if (last) + fps = 1000000 * per_n / (now - last); + last = now; + count = 0; + } + + if (fps > 50) + fps = 50; + + render_rect(3, 3, 7, 52, 255, 255, 255); + render_rect(4, 4, 5, 50 - fps, 0, 0, 0); + render_rect(4, 54 - fps, 5, fps, 0, 255, 0); +} + +void render(void) +{ + render_begin(); + + if ((mem[0x3d20] & 0x0004) == 0) { // video DAC disable + render_palette(); + + 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_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(); + + render_end(); + + update_screen(); +} diff --git a/render.h b/render.h new file mode 100644 index 0000000..b67c557 --- /dev/null +++ b/render.h @@ -0,0 +1,45 @@ +// Copyright 2010 Segher Boessenkool <segher@kernel.crashing.org> +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#ifndef _RENDER_H +#define _RENDER_H + +void render_init(u32 pixel_size); +void render(void); + +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_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 struct render_rect { + int x, y, w, h; + u8 r, g, b; +} render_rects[N_RENDER_RECTS]; + +extern u32 n_render_tiles, n_render_rects; + + +// ATLAS_W and ATLAS_H should be a multiple of 64 and a power of two; +// We need 2*512*256 for the two video pages, and 256*64*64 for the sprites. +// We also require 64 lines of slack for how we do the update. + +// Let's use a 2048x2048 texture, that's 4MB. +#define ATLAS_W 2048 +#define ATLAS_H 2048 + +extern u8 atlas[ATLAS_W*ATLAS_H]; + +#endif @@ -9,7 +9,6 @@ #include "types.h" #include "emu.h" #include "platform.h" -#include "board.h" #include "video.h" @@ -20,42 +19,10 @@ u32 screen[320*240]; int hide_page_1; int hide_page_2; int hide_sprites; -int show_fps = 0; +int show_fps = 1; int trace_unknown_video = 1; -static void fill_rect(u32 x, u32 y, u32 w, u32 h, u32 rgb) -{ - u32 xx, yy; - for (yy = y; yy < y + h; yy++) - for (xx = x; xx < x + w; xx++) - screen[320*yy + xx] = rgb; -} - -static void do_show_fps(void) -{ - static u32 fps = 0; - - const int per_n = 10; - static int count = 0; - count++; - if (count == per_n) { - static u32 last = 0; - u32 now = get_realtime(); - if (last) - fps = 1000000 * per_n / (now - last); - last = now; - count = 0; - } - - if (fps > 50) - fps = 50; - - fill_rect(3, 3, 7, 52, 0xffffff); - fill_rect(4, 4, 5, 50 - fps, 0x000000); - fill_rect(4, 54 - fps, 5, fps, 0x00ff00); -} - static const u8 sizes[] = { 8, 16, 32, 64 }; static const u8 colour_sizes[] = { 2, 4, 6, 8 }; @@ -158,8 +125,6 @@ void video_store(u16 val, u32 addr) break; case 0x2820 ... 0x2822: // bitmap offsets - if (mem[addr] != val) - bitmap_cache_clear(); break; case 0x282a: // blend level @@ -272,49 +237,18 @@ u16 video_load(u32 addr) } -static u8 *bitmap_cache[65536]; -static u16 bitmap_cache_attr[65536]; - -static u32 bitmap_cache_hash(u32 page, u16 tile, u16 attr) -{ - return (page << 14) ^ tile ^ (attr & 0x0fff); -} - -void bitmap_cache_clear(void) -{ - u32 i; - for (i = 0; i < 65536; i++) - if (bitmap_cache[i]) { - free(bitmap_cache[i]); - bitmap_cache[i] = 0; - } -} -static u8 *bitmap_cache_make(u32 page, u16 tile, u16 attr) +void render_bitmap(u8 *dest, u32 pitch, u32 addr, u16 attr) { - u32 hash = bitmap_cache_hash(page, tile, attr); - if (bitmap_cache[hash] && bitmap_cache_attr[hash] == (attr & 0x0fff)) - return bitmap_cache[hash]; - u32 h = sizes[(attr & 0x00c0) >> 6]; u32 w = sizes[(attr & 0x0030) >> 4]; - u8 *p = malloc(h * w); - free(bitmap_cache[hash]); - bitmap_cache[hash] = p; - bitmap_cache_attr[hash] = attr & 0x0fff; - u32 yflipmask = attr & 0x0008 ? h - 1 : 0; u32 xflipmask = attr & 0x0004 ? w - 1 : 0; u32 nc = colour_sizes[attr & 0x0003]; - u32 palette_offset = (attr & 0x0f00) >> 4; - palette_offset >>= nc; - palette_offset <<= nc; - - u32 bitmap = 0x40*mem[0x2820 + page]; - u32 m = bitmap + nc*w*h/16*tile; + u32 m = addr; u32 bits = 0; u32 nbits = 0; @@ -333,225 +267,13 @@ static u8 *bitmap_cache_make(u32 page, u16 tile, u16 attr) } nbits -= nc; - u32 pal = palette_offset | (bits >> 16); - bits &= 0xffff; - - p[w*yy + xx] = pal; - } - } - - return p; -} - - -static inline u8 mix_channel(u8 old, u8 new) -{ - u8 alpha = mem[0x282a]; - return ((4 - alpha)*old + alpha*new) / 4; -} - -static inline void mix_pixel(u32 offset, u32 rgb) -{ - 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]; - } - screen[offset] = x; -} - -static void blit(u32 page, u32 xoff, u32 yoff, u32 attr, u32 ctrl, u16 tile) -{ - u8 *p = bitmap_cache_make(page, tile, attr); - - u32 h = sizes[(attr & 0x00c0) >> 6]; - u32 w = sizes[(attr & 0x0030) >> 4]; - - for (u32 y = 0; y < h; y++) { - u32 yy = (yoff + y) & 0x1ff; - - for (u32 x = 0; x < w; x++) { - u32 xx = (xoff + x) & 0x1ff; - - u32 pal = *p++; + dest[pitch*yy + xx] = bits >> 16; - if ((ctrl & 0x0010) && yy < 240) - xx = (xx - mem[0x2900 + yy]) & 0x01ff; - - //if ((ctrl & 0x0020) && yy < 240) // hcmp - // xx = (xx - mem[0x2a00 + yy]) & 0x01ff;//WRONG - - if (xx < 320 && yy < 240) { - u16 rgb = mem[0x2b00 + pal]; - if ((rgb & 0x8000) == 0) { - if (attr & 0x4000 || ctrl & 0x0100) - mix_pixel(xx + 320*yy, palette_rgb[pal]); - else - screen[xx + 320*yy] = palette_rgb[pal]; - } - } - } - } -} - -static void __noinline blit_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]; - u32 tilemap = regs[4]; - u32 palette_map = regs[5]; - - if ((ctrl & 8) == 0) - return; - - if ((attr & 0x3000) >> 12 != depth) - return; - - u32 h = sizes[(attr & 0x00c0) >> 6]; - u32 w = sizes[(attr & 0x0030) >> 4]; - - u32 hn = 256/h; - u32 wn = 512/h; - - 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; - u32 tilectrl = ctrl; - if ((ctrl & 2) == 0) { -// -(1) bld(1) flip(2) pal(4) - tileattr &= ~0x000c; - tileattr |= (palette >> 2) & 0x000c; // flip - - tileattr &= ~0x0f00; - tileattr |= (palette << 8) & 0x0f00; // palette - - tilectrl &= ~0x0100; - tilectrl |= (palette << 2) & 0x0100; // blend - } - - u32 yy = ((h*y0 - yscroll + 0x10) & 0xff) - 0x10; - u32 xx = (w*x0 - xscroll) & 0x1ff; - - blit(page, xx, yy, tileattr, tilectrl, tile); + bits &= 0xffff; } -} - -static void blit_sprite(u32 depth, u16 *sprite) -{ - u16 tile, attr; - s16 x, y; - - tile = sprite[0]; - 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; - - if ((u32)(attr & 0x3000) >> 12 != depth) - return; - - 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; } - - x = x & 0x1ff; - y = y & 0x1ff; - - blit(2, x, y, attr, 0, tile); -} - -static void __noinline blit_sprites(u32 depth) -{ - u32 n; - - if ((mem[0x2842] & 1) == 0) - return; - - for (n = 0; n < 256; n++) -/// if (mem[0x2c00 + 4*n]) { -// if (mem[0x2c00 + 4*n] & 0xc000) -// printf("sprite %04x %04x %04x %04x\n", mem[0x2c00 + 4*n], -// mem[0x2c01 + 4*n], mem[0x2c02 + 4*n], mem[0x2c03 + 4*n]); - blit_sprite(depth, mem + 0x2c00 + 4*n); -/// } } -void blit_screen(void) -{ -// printf("\033[H\033[2J\n\n"); -#if 0 - printf("----- VIDEO UPDATE -----\n"); - - printf("page 1:\n"); - printf(" x off = %04x\n", mem[0x2810]); - printf(" y off = %04x\n", mem[0x2811]); - printf(" attr = %04x\n", mem[0x2812]); - printf(" ctrl = %04x\n", mem[0x2813]); // 0x81: non-palette - printf(" tiles = %04x\n", mem[0x2814]); - printf(" dunno5 = %04x\n", mem[0x2815]); - printf(" bitmap = %04x\n", mem[0x2820]); - - printf("page 2:\n"); - printf(" x off = %04x\n", mem[0x2816]); - printf(" y off = %04x\n", mem[0x2817]); - printf(" attr = %04x\n", mem[0x2818]); - printf(" ctrl = %04x\n", mem[0x2819]); - printf(" tiles = %04x\n", mem[0x281a]); - printf(" dunno5 = %04x\n", mem[0x281b]); - printf(" bitmap = %04x\n", mem[0x2821]); - - printf("sprites:\n"); - printf(" bitmap = %04x\n", mem[0x2822]); - - printf("\n"); -#endif - - memset(screen, 0, sizeof screen); - - if (mem[0x3d20] & 0x0004) // video DAC disable - return; - - u32 depth; - for (depth = 0; depth < 4; depth++) { - if (!hide_page_1) - blit_page(0, depth); - if (!hide_page_2) - blit_page(1, depth); - if (!hide_sprites) - blit_sprites(depth); - } - - if (show_fps) - do_show_fps(); -} void video_init(void) { @@ -13,15 +13,13 @@ extern u32 screen[320*240]; extern int hide_page_1; extern int hide_page_2; extern int hide_sprites; - extern int show_fps; void video_store(u16 val, u32 addr); u16 video_load(u32 addr); -void bitmap_cache_clear(void); -void blit_screen(void); +void render_bitmap(u8 *dest, u32 pitch, u32 addr, u16 attr); void video_init(void); |