Browse Source

Refactor to separate SDL rendering from platform code

v2
Nathaniel Walizer 7 months ago
parent
commit
8bdb482cf4
9 changed files with 264 additions and 187 deletions
  1. +6
    -1
      Makefile
  2. +47
    -0
      src/cartinfo.c
  3. +20
    -0
      src/cartinfo.h
  4. +25
    -186
      src/linux/port.c
  5. +2
    -0
      src/port.h
  6. +0
    -0
      src/sdl/overlay.c
  7. +0
    -0
      src/sdl/overlay.h
  8. +138
    -0
      src/sdl/render.c
  9. +26
    -0
      src/sdl/render.h

+ 6
- 1
Makefile View File

@@ -1,5 +1,6 @@
#CROSS_COMPILE = arm-none-eabi-
OS = linux
GFX = sdl

CC = $(CROSS_COMPILE)gcc
LD = $(CC)
@@ -26,19 +27,22 @@ TEST_OBJS = $(TEST_SRCS:%.c=$(OBJDIR)/%.o)


MAPDIR = $(SRCDIR)/map
GFXDIR = $(SRCDIR)/$(GFX)

NESE_SRC_SRCS = f6502.c f6502_opcodes.c
NESE_SRC_SRCS += nese.c nes.c cart.c mapper.c
NESE_SRC_SRCS += ppu.c apu.c
NESE_SRC_SRCS += memory.c serdes.c save.c rle.c
NESE_SRC_SRCS += overlay.c
NESE_SRC_SRCS += cartinfo.c
NESE_SRC_SRCS += $(OS)/port.c
NESE_GFX_SRCS = $(notdir $(wildcard $(GFXDIR)/*.c))
NESE_MAP_SRCS = $(notdir $(wildcard $(MAPDIR)/*.c))

NESE_DEBUG = CART

NESE_SRCS += $(NESE_SRC_SRCS:%=$(SRCDIR)/%)
NESE_SRCS += $(NESE_MAP_SRCS:%=$(MAPDIR)/%)
NESE_SRCS += $(NESE_GFX_SRCS:%=$(GFXDIR)/%)
NESE_OBJS = $(NESE_SRCS:%.c=$(OBJDIR)/%.o)


@@ -49,6 +53,7 @@ all: $(BINDIR)/nese
$(BINDIR)/test: CFLAGS += -DF6502_FLAT -DF6502_TEST -DF6502_TRACE

$(BINDIR)/nese: CFLAGS += $(foreach debug,$(NESE_DEBUG), -DDEBUG_$(debug))
$(BINDIR)/nese: CFLAGS += -I$(GFXDIR)
$(BINDIR)/nese: CFLAGS += $(shell sdl2-config --cflags)
$(BINDIR)/nese: LDFLAGS += $(shell sdl2-config --libs)
$(BINDIR)/nese: $(NESE_OBJS)


+ 47
- 0
src/cartinfo.c View File

@@ -0,0 +1,47 @@
#include "cart.h"
#include "cartinfo.h"
#include "port.h"


void unload_cart(Cart_Info* cart) {
if (cart->cart_data) {
nese_unmap_file(cart->cart_data, cart->filesize);
cart->cart_data = NULL;
cart->filesize = 0;
}

if (cart->file) {
fclose(cart->file);
cart->file = NULL;
}
}

int load_cart(Cart_Info* cart, const char* filename, nes* sys) {
int status = 0;
int filesize = 0;
void* cart_data = NULL;

FILE* file = fopen(filename, "rb");
if (NULL == file) {
status = -1;
} else {
filesize = nese_file_size(file);
cart_data = nese_map_file(file, filesize,
Filemap_Mode_Read);
if (NULL == cart_data) {
fprintf(stderr, "Failed to map %s\n", filename);
status = -1;
} else {
status = nes_cart_load_mem(cart_data, filesize, sys);
}
}

if (0 == status) {
cart->filename = filename;
cart->filesize = filesize;
cart->file = file;
cart->cart_data = cart_data;
}

return status;
}

+ 20
- 0
src/cartinfo.h View File

@@ -0,0 +1,20 @@
#ifndef NESE_INFO_H_
#define NESE_INFO_H_

#include <stdio.h>

#include "nes.h"


typedef struct {
const char* filename;
FILE* file;
int filesize;
void* cart_data;
} Cart_Info;

int load_cart(Cart_Info*, const char* filename, nes*);
void unload_cart(Cart_Info* cart);


#endif // NESE_INFO_H_

+ 25
- 186
src/linux/port.c View File

@@ -7,14 +7,13 @@
#include <sys/mman.h>
#include <sys/stat.h>


#include <SDL.h>

#include "cart.h"
#include "nese.h"
#include "overlay.h"
#include "port.h"
#include "save.h"
#include "render.h"
#include "cartinfo.h"

#define NESE_DEBUG "Port"
#include "log.h"
@@ -48,8 +47,7 @@ int nese_mkdir(const char* dir) {
return mkdir(dir, 0777);
}


static int nese_file_size(FILE* file) {
int nese_file_size(FILE* file) {
int size = -1;
if (0 == fseek(file, 0, SEEK_END)) {
size = ftell(file);
@@ -79,31 +77,18 @@ void* nese_alloc(int size) {


/*
* SDL-specific init and entry point
* This should be maximally reusable across platforms
* Platform-specific features and controls
*/

typedef struct {
const char* filename;
FILE* file;
int filesize;
void* cart_data;
} cart_info;

typedef enum {
Flag_Turbo = 0b1,
} Platform_Flags;

typedef struct {
nes* sys;
cart_info cart;
Cart_Info cart;
int64_t t_target;
SDL_Window* window;
SDL_Renderer* renderer;
SDL_Texture* texture;
SDL_Surface* target;
SDL_Surface* screen;
SDL_Rect view;
Render_Info renderer;
Overlay overlay;
int fps_msg_id;
Platform_Flags flags;
@@ -209,40 +194,13 @@ static nese_Action process_events(nes* sys) {
}


/* Time / Video */

static SDL_Color nes_palette[64] = {
{0x80,0x80,0x80}, {0x00,0x00,0xBB}, {0x37,0x00,0xBF}, {0x84,0x00,0xA6},
{0xBB,0x00,0x6A}, {0xB7,0x00,0x1E}, {0xB3,0x00,0x00}, {0x91,0x26,0x00},
{0x7B,0x2B,0x00}, {0x00,0x3E,0x00}, {0x00,0x48,0x0D}, {0x00,0x3C,0x22},
{0x00,0x2F,0x66}, {0x00,0x00,0x00}, {0x05,0x05,0x05}, {0x05,0x05,0x05},

{0xC8,0xC8,0xC8}, {0x00,0x59,0xFF}, {0x44,0x3C,0xFF}, {0xB7,0x33,0xCC},
{0xFF,0x33,0xAA}, {0xFF,0x37,0x5E}, {0xFF,0x37,0x1A}, {0xD5,0x4B,0x00},
{0xC4,0x62,0x00}, {0x3C,0x7B,0x00}, {0x1E,0x84,0x15}, {0x00,0x95,0x66},
{0x00,0x84,0xC4}, {0x11,0x11,0x11}, {0x09,0x09,0x09}, {0x09,0x09,0x09},

{0xFF,0xFF,0xFF}, {0x00,0x95,0xFF}, {0x6F,0x84,0xFF}, {0xD5,0x6F,0xFF},
{0xFF,0x77,0xCC}, {0xFF,0x6F,0x99}, {0xFF,0x7B,0x59}, {0xFF,0x91,0x5F},
{0xFF,0xA2,0x33}, {0xA6,0xBF,0x00}, {0x51,0xD9,0x6A}, {0x4D,0xD5,0xAE},
{0x00,0xD9,0xFF}, {0x66,0x66,0x66}, {0x0D,0x0D,0x0D}, {0x0D,0x0D,0x0D},

{0xFF,0xFF,0xFF}, {0x84,0xBF,0xFF}, {0xBB,0xBB,0xFF}, {0xD0,0xBB,0xFF},
{0xFF,0xBF,0xEA}, {0xFF,0xBF,0xCC}, {0xFF,0xC4,0xB7}, {0xFF,0xCC,0xAE},
{0xFF,0xD9,0xA2}, {0xCC,0xE1,0x99}, {0xAE,0xEE,0xB7}, {0xAA,0xF7,0xEE},
{0xB3,0xEE,0xFF}, {0xDD,0xDD,0xDD}, {0x11,0x11,0x11}, {0x11,0x11,0x11}
};
/*
* Time / Video - Should be maximally reusable across platforms
*/

int nese_frame_start(void* plat_data, uint8_t background) {
platform_data* plat = (platform_data*)plat_data;

SDL_Color ext = nes_palette[background];
// TODO: Compose color according to GPU format?
// Why are R/B reversed on STM32?
SDL_FillRect(plat->target, NULL, ((int)ext.r << 16) |
((int)ext.g << 8) | ext.b);

return 0;
return render_frame_start( &((platform_data*)plat_data)->renderer,
background);
}

int nese_line_ready(void* plat_data, uint8_t* buffer, int line) {
@@ -258,7 +216,6 @@ int nese_line_ready(void* plat_data, uint8_t* buffer, int line) {

SDL_BlitSurface(plat->scanline, NULL, plat->target, &rect);
*/

return 0;
}

@@ -283,7 +240,6 @@ int64_t time_sleep_until(int64_t t_target) {


int nese_frame_ready(void* plat_data) {
int status = 0;
platform_data* plat = (platform_data*)plat_data;
/*
static int frame = 0;
@@ -320,22 +276,20 @@ int nese_frame_ready(void* plat_data) {
}
putc('\n', stdout);
*/
SDL_RenderFlush(plat->renderer);
int status = render_frame(&plat->renderer);

SDL_BlitSurface(plat->screen, NULL, plat->target, NULL);

SDL_UnlockTexture(plat->texture);
SDL_RenderCopy(plat->renderer, plat->texture,
NULL, NULL);
SDL_LockTextureToSurface(plat->texture, NULL,
&plat->target);
if (0 == status) {
overlay_render(&plat->overlay,
nes_ppu_render_w, nes_ppu_render_h,
&plat->renderer.view, plat->renderer.renderer);
}

overlay_render(&plat->overlay,
nes_ppu_render_w, nes_ppu_render_h,
&plat->view, plat->renderer);
if (0 == status) {
status = render_frame_end(&plat->renderer);
}

SDL_RenderPresent(plat->renderer);

// TODO: Check status first?

nese_Action action = process_events(plat->sys);
switch (action) {
@@ -423,78 +377,10 @@ int nese_get_audio_frequency(void*) {
/* Platform Data */

static int plat_init(platform_data* plat) {
int status = SDL_Init(
SDL_INIT_EVENTS |
SDL_INIT_VIDEO
);
int status = render_info_init(&plat->renderer, plat->sys);

if (0 == status) {
plat->view = (SDL_Rect){
.w = nes_ppu_render_w * 8,
.h = nes_ppu_render_h * 7,
};
plat->window = SDL_CreateWindow(
"NESe",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
plat->view.w, plat->view.h,
0
);
if (NULL == plat->window) {
LOGE("SDL: Failed to create window");
status = -1;
}
}

if (0 == status) {
plat->renderer = SDL_CreateRenderer(
plat->window, -1,
SDL_RENDERER_ACCELERATED/* |
SDL_RENDERER_PRESENTVSYNC*/
);
if (NULL == plat->renderer) {
LOGE("SDL: Failed to create renderer");
status = -1;
}
}

if (0 == status) {
plat->texture = SDL_CreateTexture(
plat->renderer, SDL_PIXELFORMAT_RGB888,
SDL_TEXTUREACCESS_STREAMING,
nes_ppu_render_w, nes_ppu_render_h
);
if (NULL == plat->texture) {
LOGE("SDL: Failed to create target");
status = -1;
} else {
SDL_LockTextureToSurface(plat->texture, NULL,
&plat->target);
// SDL_FillRect(data->target, NULL, color_background);
}
}

if (0 == status) {
plat->screen = SDL_CreateRGBSurfaceWithFormatFrom(
plat->sys->ppu.screen_data,
nes_ppu_render_w, nes_ppu_render_h,
8, nes_ppu_render_w,
SDL_PIXELFORMAT_INDEX8
);
if (NULL == plat->screen) {
LOGE("SDL: Failed to create screen");
status = -1;
} else {
SDL_SetPaletteColors(
plat->screen->format->palette,
nes_palette, 0U, 64U
);
SDL_SetColorKey(plat->screen, SDL_TRUE, 0xFFU);
}
}

if (0 == status) {
status = overlay_init(&plat->overlay, plat->renderer);
status = overlay_init(&plat->overlay, plat->renderer.renderer);
}

if (0 == status) {
@@ -505,59 +391,12 @@ static int plat_init(platform_data* plat) {
}

static void plat_done(platform_data* plat) {
if (NULL != plat->texture) SDL_DestroyTexture(plat->texture);
if (NULL != plat->renderer) SDL_DestroyRenderer(plat->renderer);
if (NULL != plat->window) SDL_DestroyWindow(plat->window);
render_info_done(&plat->renderer);
overlay_done(&plat->overlay);
SDL_Quit();
}


static int load_cart(const char* filename, platform_data* plat) {
int status = 0;
int filesize = 0;
void* cart_data = NULL;

FILE* file = fopen(filename, "rb");
if (NULL == file) {
status = -1;
} else {
filesize = nese_file_size(file);
cart_data = nese_map_file(file, filesize,
Filemap_Mode_Read);
if (NULL == cart_data) {
fprintf(stderr, "Failed to map %s\n", filename);
status = -1;
} else {
status = nes_cart_load_mem(cart_data, filesize,
plat->sys);
}
}

if (0 == status) {
plat->cart.filename = filename;
plat->cart.filesize = filesize;
plat->cart.file = file;
plat->cart.cart_data = cart_data;
}

return status;
}

static void unload_cart(cart_info* cart) {
if (cart->cart_data) {
nese_unmap_file(cart->cart_data, cart->filesize);
cart->cart_data = NULL;
cart->filesize = 0;
}

if (cart->file) {
fclose(cart->file);
cart->file = NULL;
}
}


// This is too big for the stack.
static nes sys = {0};

@@ -576,7 +415,7 @@ int main(int argc, char* argv[]) {
}

if (0 == status) {
status = load_cart(argv[1], &plat);
status = load_cart(&plat.cart, argv[1], &sys);
}

if (0 == status) {


+ 2
- 0
src/port.h View File

@@ -6,6 +6,8 @@
#include "input.h"


int nese_file_size(FILE* file);

typedef enum {
Filemap_Mode_Read = 0,
Filemap_Mode_Write,


src/overlay.c → src/sdl/overlay.c View File


src/overlay.h → src/sdl/overlay.h View File


+ 138
- 0
src/sdl/render.c View File

@@ -0,0 +1,138 @@
#include "render.h"

#define NESE_DEBUG "SDL"
#include "log.h"


static SDL_Color nes_palette[64] = {
{0x80,0x80,0x80}, {0x00,0x00,0xBB}, {0x37,0x00,0xBF}, {0x84,0x00,0xA6},
{0xBB,0x00,0x6A}, {0xB7,0x00,0x1E}, {0xB3,0x00,0x00}, {0x91,0x26,0x00},
{0x7B,0x2B,0x00}, {0x00,0x3E,0x00}, {0x00,0x48,0x0D}, {0x00,0x3C,0x22},
{0x00,0x2F,0x66}, {0x00,0x00,0x00}, {0x05,0x05,0x05}, {0x05,0x05,0x05},

{0xC8,0xC8,0xC8}, {0x00,0x59,0xFF}, {0x44,0x3C,0xFF}, {0xB7,0x33,0xCC},
{0xFF,0x33,0xAA}, {0xFF,0x37,0x5E}, {0xFF,0x37,0x1A}, {0xD5,0x4B,0x00},
{0xC4,0x62,0x00}, {0x3C,0x7B,0x00}, {0x1E,0x84,0x15}, {0x00,0x95,0x66},
{0x00,0x84,0xC4}, {0x11,0x11,0x11}, {0x09,0x09,0x09}, {0x09,0x09,0x09},

{0xFF,0xFF,0xFF}, {0x00,0x95,0xFF}, {0x6F,0x84,0xFF}, {0xD5,0x6F,0xFF},
{0xFF,0x77,0xCC}, {0xFF,0x6F,0x99}, {0xFF,0x7B,0x59}, {0xFF,0x91,0x5F},
{0xFF,0xA2,0x33}, {0xA6,0xBF,0x00}, {0x51,0xD9,0x6A}, {0x4D,0xD5,0xAE},
{0x00,0xD9,0xFF}, {0x66,0x66,0x66}, {0x0D,0x0D,0x0D}, {0x0D,0x0D,0x0D},

{0xFF,0xFF,0xFF}, {0x84,0xBF,0xFF}, {0xBB,0xBB,0xFF}, {0xD0,0xBB,0xFF},
{0xFF,0xBF,0xEA}, {0xFF,0xBF,0xCC}, {0xFF,0xC4,0xB7}, {0xFF,0xCC,0xAE},
{0xFF,0xD9,0xA2}, {0xCC,0xE1,0x99}, {0xAE,0xEE,0xB7}, {0xAA,0xF7,0xEE},
{0xB3,0xEE,0xFF}, {0xDD,0xDD,0xDD}, {0x11,0x11,0x11}, {0x11,0x11,0x11}
};


int render_frame_start(Render_Info* renderer, uint8_t background) {
SDL_Color ext = nes_palette[background];
// TODO: Compose color according to GPU format?
// Why are R/B reversed on STM32?
SDL_FillRect(renderer->target, NULL, ((int)ext.r << 16) |
((int)ext.g << 8) | ext.b);
return 0;
}

int render_frame(Render_Info* renderer) {
SDL_RenderFlush(renderer->renderer);

SDL_BlitSurface(renderer->screen, NULL, renderer->target, NULL);

SDL_UnlockTexture(renderer->texture);
SDL_RenderCopy(renderer->renderer, renderer->texture,
NULL, NULL);
SDL_LockTextureToSurface(renderer->texture, NULL,
&renderer->target);

return 0;
}

int render_frame_end(Render_Info* renderer) {
SDL_RenderPresent(renderer->renderer);

return 0;
}


int render_info_init(Render_Info* renderer, nes* sys) {
int status = SDL_Init(
SDL_INIT_EVENTS |
SDL_INIT_VIDEO
);

if (0 == status) {
renderer->view = (SDL_Rect){
.w = nes_ppu_render_w * 4,
.h = nes_ppu_render_h * 4,
};
renderer->window = SDL_CreateWindow(
"NESe",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
renderer->view.w, renderer->view.h,
0
);
if (NULL == renderer->window) {
LOGE("Failed to create window");
status = -1;
}
}

if (0 == status) {
renderer->renderer = SDL_CreateRenderer(
renderer->window, -1,
SDL_RENDERER_ACCELERATED/* |
SDL_RENDERER_PRESENTVSYNC*/
);
if (NULL == renderer->renderer) {
LOGE("Failed to create renderer");
status = -1;
}
}

if (0 == status) {
renderer->texture = SDL_CreateTexture(
renderer->renderer, SDL_PIXELFORMAT_RGB888,
SDL_TEXTUREACCESS_STREAMING,
nes_ppu_render_w, nes_ppu_render_h
);
if (NULL == renderer->texture) {
LOGE("Failed to create target");
status = -1;
} else {
SDL_LockTextureToSurface(renderer->texture, NULL,
&renderer->target);
// SDL_FillRect(data->target, NULL, color_background);
}
}

if (0 == status) {
renderer->screen = SDL_CreateRGBSurfaceWithFormatFrom(
sys->ppu.screen_data,
nes_ppu_render_w, nes_ppu_render_h,
8, nes_ppu_render_w,
SDL_PIXELFORMAT_INDEX8
);
if (NULL == renderer->screen) {
LOGE("Failed to create screen");
status = -1;
} else {
SDL_SetPaletteColors(
renderer->screen->format->palette,
nes_palette, 0U, 64U
);
SDL_SetColorKey(renderer->screen, SDL_TRUE, 0xFFU);
}
}

return status;
}

void render_info_done(Render_Info* renderer) {
if (NULL != renderer->texture) SDL_DestroyTexture(renderer->texture);
if (NULL != renderer->renderer) SDL_DestroyRenderer(renderer->renderer);
if (NULL != renderer->window) SDL_DestroyWindow(renderer->window);
}

+ 26
- 0
src/sdl/render.h View File

@@ -0,0 +1,26 @@
#ifndef NESE_RENDER_H_
#define NESE_RENDER_H_

#include <SDL.h>

#include "nes.h"


typedef struct {
SDL_Window* window;
SDL_Renderer* renderer;
SDL_Texture* texture;
SDL_Surface* target;
SDL_Surface* screen;
SDL_Rect view;
} Render_Info;

int render_info_init(Render_Info*, nes*);
void render_info_done(Render_Info*);

int render_frame_start(Render_Info*, uint8_t background);
int render_frame(Render_Info*);
int render_frame_end(Render_Info*);


#endif // NESE_RENDER_H_

Loading…
Cancel
Save