summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSegher Boessenkool <segher@kernel.crashing.org>2010-02-25 19:45:37 +0100
committerSegher Boessenkool <segher@kernel.crashing.org>2010-04-07 23:49:51 +0200
commit8d2bbbf0b6fd7ef356630b93d4c5fbacecc75afa (patch)
tree6e0e03a52eb33674ebf06fb9dc304fe6f3317b84
parenta9bd7b42eb7290b59b49476a718f1968881354b7 (diff)
OpenGL support
-rw-r--r--Makefile17
-rw-r--r--board-VII.c2
-rw-r--r--emu.c3
-rw-r--r--platform-sdl.c47
-rw-r--r--render-gl.c230
-rw-r--r--render-soft.c102
-rw-r--r--render.c325
-rw-r--r--render.h45
-rw-r--r--video.c288
-rw-r--r--video.h4
10 files changed, 765 insertions, 298 deletions
diff --git a/Makefile b/Makefile
index d5f114a..21be1a5 100644
--- a/Makefile
+++ b/Makefile
@@ -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);
diff --git a/emu.c b/emu.c
index 34f5ba2..4554a98 100644
--- a/emu.c
+++ b/emu.c
@@ -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
diff --git a/video.c b/video.c
index a3e9020..fcb0bac 100644
--- a/video.c
+++ b/video.c
@@ -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)
{
diff --git a/video.h b/video.h
index 729b13f..4458f97 100644
--- a/video.h
+++ b/video.h
@@ -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);