# HG changeset patch # User Michael Pavone # Date 1437942331 25200 # Node ID 0b692b5d154b483bc1d2a78b640ead0f6ecfc25f # Parent 062a2199daf6cedd096a41e4387e84d496c01a3a# Parent 792be135d3af9ba6f091ae5c374a8811fcfe55b3 Merge diff -r 792be135d3af -r 0b692b5d154b Makefile --- a/Makefile Sun Jul 26 01:11:04 2015 -0700 +++ b/Makefile Sun Jul 26 13:25:31 2015 -0700 @@ -3,13 +3,19 @@ endif ifeq ($(OS),Windows) +ifndef SDL2_PREFIX +SDL2_PREFIX:="C:/MinGW/usr" +endif +ifndef GLEW32S_LIB +GLEW32S_LIB=glew32s.lib +endif MEM:=mem_win.o TERMINAL:=terminal_win.o BLASTEM:=blastem.exe CC:=wine gcc.exe -CFLAGS:=-O2 -std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -I"C:/MinGW/usr/include/SDL2" -DGLEW_STATIC -LDFLAGS:= -L"C:/MinGW/usr/lib" -lm -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lglu32 -mwindows +CFLAGS:=-O2 -std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -I"$(SDL2_PREFIX)/include/SDL2" -DGLEW_STATIC +LDFLAGS:= $(GLEW32S_LIB) -L"$(SDL2_PREFIX)/lib" -lm -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lglu32 -mwindows CPU:=i686 else @@ -120,7 +126,6 @@ endif ifeq ($(OS),Windows) -MAINOBJS+= glew32s.lib ALL=$(BLASTEM) else ALL= dis zdis stateview vgmplay blastem termhelper diff -r 792be135d3af -r 0b692b5d154b config.c --- a/config.c Sun Jul 26 01:11:04 2015 -0700 +++ b/config.c Sun Jul 26 13:25:31 2015 -0700 @@ -9,7 +9,13 @@ #include #include -#ifdef _WIN32 +#ifdef __MINGW64_VERSION_MAJOR +#define MINGW_W64_VERSION (__MINGW64_VERSION_MAJOR * 1000 + __MINGW64_VERSION_MINOR) +#else +#define MINGW_W64_VERSION 0 +#endif + +#if defined(_WIN32) && (MINGW_W64_VERSION < 3003) char * strtok_r(char * input, char * sep, char ** state) { if (input) { @@ -42,11 +48,11 @@ curline = strip_ws(curline); int len = strlen(curline); if (!len) { - *line++; + *line = *line + 1; continue; } if (curline[0] == '#') { - *line++; + *line = *line + 1; continue; } if (curline[0] == '}') { @@ -60,7 +66,7 @@ if (*end == '{') { *end = 0; curline = strip_ws(curline); - *line++; + *line = *line + 1; head = tern_insert_node(head, curline, parse_config_int(state, 1, line)); } else { char * val = strip_ws(split_keyval(curline)); @@ -70,7 +76,7 @@ } else { fprintf(stderr, "Key %s is missing a value on line %d\n", key, *line); } - *line++; + *line = *line + 1; } } return head; @@ -93,10 +99,12 @@ if (!config_size) { goto config_empty; } - char * config_data = malloc(config_size); + char * config_data = malloc(config_size+1); if (fread(config_data, 1, config_size, config_file) != config_size) { goto config_read_fail; } + config_data[config_size] = '\0'; + ret = parse_config(config_data); config_read_fail: free(config_data); diff -r 792be135d3af -r 0b692b5d154b io.c --- a/io.c Sun Jul 26 01:11:04 2015 -0700 +++ b/io.c Sun Jul 26 13:25:31 2015 -0700 @@ -340,7 +340,7 @@ int parse_binding_target(char * target, tern_node * padbuttons, int * ui_out, int * padnum_out, int * padbutton_out) { int gpadslen = strlen("gamepads."); - if (!memcmp(target, "gamepads.", gpadslen)) { + if (!strncmp(target, "gamepads.", gpadslen)) { if (target[gpadslen] >= '1' && target[gpadslen] <= '8') { int padnum = target[gpadslen] - '0'; int button = tern_find_int(padbuttons, target + gpadslen + 1, 0); @@ -358,7 +358,7 @@ } else { fprintf(stderr, "Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]); } - } else if(!memcmp(target, "ui.", strlen("ui."))) { + } else if(!strncmp(target, "ui.", strlen("ui."))) { *padbutton_out = 0; if (!strcmp(target + 3, "vdp_debug_mode")) { *ui_out = UI_DEBUG_MODE_INC; @@ -368,7 +368,7 @@ *ui_out = UI_ENTER_DEBUGGER; } else if(!strcmp(target + 3, "save_state")) { *ui_out = UI_SAVE_STATE; - } else if(!memcmp(target + 3, "set_speed.", strlen("set_speed."))) { + } else if(!strncmp(target + 3, "set_speed.", strlen("set_speed."))) { *ui_out = UI_SET_SPEED; *padbutton_out = atoi(target + 3 + strlen("set_speed.")); } else if(!strcmp(target + 3, "next_speed")) { diff -r 792be135d3af -r 0b692b5d154b m68k_core.c --- a/m68k_core.c Sun Jul 26 01:11:04 2015 -0700 +++ b/m68k_core.c Sun Jul 26 13:25:31 2015 -0700 @@ -1000,8 +1000,9 @@ m68k_context * init_68k_context(m68k_options * opts) { - m68k_context * context = malloc(sizeof(m68k_context) + ram_size(&opts->gen) / (1 << opts->gen.ram_flags_shift) / 8); - memset(context, 0, sizeof(m68k_context)); + size_t ctx_size = sizeof(m68k_context) + ram_size(&opts->gen) / (1 << opts->gen.ram_flags_shift) / 8; + m68k_context * context = malloc(ctx_size); + memset(context, 0, ctx_size); context->native_code_map = opts->gen.native_code_map; context->options = opts; context->int_cycle = CYCLE_NEVER; diff -r 792be135d3af -r 0b692b5d154b mem_win.c --- a/mem_win.c Sun Jul 26 01:11:04 2015 -0700 +++ b/mem_win.c Sun Jul 26 13:25:31 2015 -0700 @@ -5,7 +5,7 @@ */ #include "mem.h" -#include +#include void * alloc_code(size_t *size) { diff -r 792be135d3af -r 0b692b5d154b render_sdl.c --- a/render_sdl.c Sun Jul 26 01:11:04 2015 -0700 +++ b/render_sdl.c Sun Jul 26 13:25:31 2015 -0700 @@ -12,12 +12,19 @@ #include "io.h" #include "util.h" +#ifndef DISABLE_OPENGL #include +#endif SDL_Window *main_window; +SDL_Renderer *main_renderer; +SDL_Texture *main_texture; +SDL_Rect main_clip; SDL_GLContext *main_context; + uint8_t render_dbg = 0; uint8_t debug_pal = 0; +uint8_t render_gl = 1; uint32_t last_frame = 0; @@ -94,6 +101,7 @@ return 255 << 24 | r << 16 | g << 8 | b; } +#ifndef DISABLE_OPENGL GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, at_pos; GLfloat vertex_data[] = { @@ -147,53 +155,73 @@ } return ret; } +#endif void render_alloc_surfaces(vdp_context * context) { context->oddbuf = context->framebuf = malloc(512 * 256 * 4 * 2); memset(context->oddbuf, 0, 512 * 256 * 4 * 2); context->evenbuf = ((char *)context->oddbuf) + 512 * 256 * 4; - glGenTextures(3, textures); - for (int i = 0; i < 3; i++) - { - glBindTexture(GL_TEXTURE_2D, textures[i]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (i < 2) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, i ? context->evenbuf : context->oddbuf); - } else { - uint32_t blank = 255 << 24; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); + +#ifndef DISABLE_OPENGL + if (render_gl) { + glGenTextures(3, textures); + for (int i = 0; i < 3; i++) + { + glBindTexture(GL_TEXTURE_2D, textures[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (i < 2) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, i ? context->evenbuf : context->oddbuf); + } else { + uint32_t blank = 255 << 24; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); + } } + glGenBuffers(2, buffers); + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); + tern_val def = {.ptrval = "default.v.glsl"}; + vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def).ptrval, GL_VERTEX_SHADER); + def.ptrval = "default.f.glsl"; + fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def).ptrval, GL_FRAGMENT_SHADER); + program = glCreateProgram(); + glAttachShader(program, vshader); + glAttachShader(program, fshader); + glLinkProgram(program); + GLint link_status; + glGetProgramiv(program, GL_LINK_STATUS, &link_status); + if (!link_status) { + fputs("Failed to link shader program\n", stderr); + exit(1); + } + un_textures[0] = glGetUniformLocation(program, "textures[0]"); + un_textures[1] = glGetUniformLocation(program, "textures[1]"); + un_width = glGetUniformLocation(program, "width"); + at_pos = glGetAttribLocation(program, "pos"); + } else { +#endif + /* height=480 to fit interlaced output */ + main_texture = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480); +#ifndef DISABLE_OPENGL } - glGenBuffers(2, buffers); - glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); - tern_val def = {.ptrval = "default.v.glsl"}; - vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def).ptrval, GL_VERTEX_SHADER); - def.ptrval = "default.f.glsl"; - fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def).ptrval, GL_FRAGMENT_SHADER); - program = glCreateProgram(); - glAttachShader(program, vshader); - glAttachShader(program, fshader); - glLinkProgram(program); - GLint link_status; - glGetProgramiv(program, GL_LINK_STATUS, &link_status); - if (!link_status) { - fatal_error("Failed to link shader program\n"); - } - un_textures[0] = glGetUniformLocation(program, "textures[0]"); - un_textures[1] = glGetUniformLocation(program, "textures[1]"); - un_width = glGetUniformLocation(program, "width"); - at_pos = glGetAttribLocation(program, "pos"); +#endif } char * caption = NULL; +static void render_quit() +{ + render_close_audio(); +#ifdef DISABLE_OPENGL + SDL_DestroyTexture(main_texture); +#endif +} + void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { @@ -201,14 +229,9 @@ } atexit(SDL_Quit); printf("width: %d, height: %d\n", width, height); - uint32_t flags = SDL_WINDOW_OPENGL; - - 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_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + uint32_t flags = 0; + if (fullscreen) { flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; SDL_DisplayMode mode; @@ -219,32 +242,79 @@ width = mode.w; height = mode.h; } + + render_gl = 0; + +#ifndef DISABLE_OPENGL + flags |= SDL_WINDOW_OPENGL; + 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_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); main_window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); if (!main_window) { fatal_error("Unable to create SDL window: %s\n", SDL_GetError()); } - SDL_GetWindowSize(main_window, &width, &height); - printf("Window created with size: %d x %d\n", width, height); main_context = SDL_GL_CreateContext(main_window); GLenum res = glewInit(); if (res != GLEW_OK) { - fatal_error("Initialization of GLEW failed with code %d\n", res); + fprintf(stderr, "Initialization of GLEW failed with code %d\n", res); + } + + if (GLEW_VERSION_2_0) { + render_gl = 1; } - if (!GLEW_VERSION_2_0) { - fatal_error("BlastEm requires at least OpenGL 2.0, but it is unavailable\n"); + else { + SDL_DestroyWindow(main_window); + fputs("OpenGL 2.0 is unavailable, falling back to SDL2 renderer\n", stderr); +#endif + SDL_CreateWindowAndRenderer(width, height, flags, &main_window, &main_renderer); + + if (!main_window || !main_renderer) { + fprintf(stderr, "unable to create SDL window: %s\n", SDL_GetError()); + SDL_Quit(); + exit(1); + } + main_clip.x = main_clip.y = 0; + main_clip.w = width; + main_clip.h = height; +#ifndef DISABLE_OPENGL } - float aspect = (float)width / height; +#endif + + SDL_GetWindowSize(main_window, &width, &height); + printf("Window created with size: %d x %d\n", width, height); + float src_aspect = 4.0/3.0; + float aspect = (float)width / height; tern_val def = {.ptrval = "normal"}; - if (fabs(aspect - 4.0/3.0) > 0.01 && strcmp(tern_find_path_default(config, "video\0aspect\0", def).ptrval, "stretch")) { - for (int i = 0; i < 4; i++) - { - if (aspect > 4.0/3.0) { - vertex_data[i*2] *= (4.0/3.0)/aspect; - } else { - vertex_data[i*2+1] *= aspect/(4.0/3.0); + int stretch = fabs(aspect - src_aspect) > 0.01 && !strcmp(tern_find_path_default(config, "video\0aspect\0", def).ptrval, "stretch"); + + if (!stretch) { +#ifndef DISABLE_OPENGL + if (render_gl) { + for (int i = 0; i < 4; i++) + { + if (aspect > src_aspect) { + vertex_data[i*2] *= src_aspect/aspect; + } else { + vertex_data[i*2+1] *= aspect/src_aspect; + } } + } else { +#endif + float scale_x = (float)width / 320.0; + float scale_y = (float)height / 240.0; + float scale = scale_x > scale_y ? scale_y : scale_x; + main_clip.w = 320.0 * scale; + main_clip.h = 240.0 * scale; + main_clip.x = (width - main_clip.w) / 2; + main_clip.y = (height - main_clip.h) / 2; +#ifndef DISABLE_OPENGL } +#endif } + caption = title; min_delay = 0; for (int i = 0; i < 100; i++) { @@ -306,42 +376,86 @@ } SDL_JoystickEventState(SDL_ENABLE); - atexit(render_close_audio); + atexit(render_quit); } void render_context(vdp_context * context) { + int width = context->regs[REG_MODE_4] & BIT_H40 ? 320.0f : 256.0f; + int height = 240; + last_frame = SDL_GetTicks(); - - glBindTexture(GL_TEXTURE_2D, textures[context->framebuf == context->oddbuf ? 0 : 1]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, context->framebuf);; +#ifndef DISABLE_OPENGL + if (render_gl) { + glBindTexture(GL_TEXTURE_2D, textures[context->framebuf == context->oddbuf ? 0 : 1]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, context->framebuf);; + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(program); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textures[0]); + glUniform1i(un_textures[0], 0); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]); + glUniform1i(un_textures[1], 1); + + glUniform1f(un_width, width); + + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); + glEnableVertexAttribArray(at_pos); - glUseProgram(program); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, textures[0]); - glUniform1i(un_textures[0], 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0); + + glDisableVertexAttribArray(at_pos); + + SDL_GL_SwapWindow(main_window); + } else { +#endif + SDL_Rect area; - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]); - glUniform1i(un_textures[1], 1); + area.x = area.y = 0; + area.w = width; + area.h = height; - glUniform1f(un_width, context->regs[REG_MODE_4] & BIT_H40 ? 320.0f : 256.0f); + if (context->regs[REG_MODE_4] & BIT_INTERLACE) { + unsigned skip; + uint32_t *src = (uint32_t*)context->framebuf; + uint8_t *dst; + int i; + + area.h *= 2; + + SDL_LockTexture(main_texture, &area, (void**)&dst, &skip); + + if (context->framebuf == context->evenbuf) + dst += skip; + + skip *= 2; - glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); - glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); - glEnableVertexAttribArray(at_pos); + for (i = 0; i < 240; ++i) { + memcpy(dst, src, width*sizeof(uint32_t)); + src += 320; + dst += skip; + } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); - glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0); + SDL_UnlockTexture(main_texture); + } + else /* possibly faster path for non-interlaced output */ + SDL_UpdateTexture(main_texture, &area, context->framebuf, 320*sizeof(uint32_t)); - glDisableVertexAttribArray(at_pos); + SDL_RenderClear(main_renderer); + SDL_RenderCopy(main_renderer, main_texture, &area, &main_clip); + SDL_RenderPresent(main_renderer); +#ifndef DISABLE_OPENGL + } +#endif - SDL_GL_SwapWindow(main_window); - if (context->regs[REG_MODE_4] & BIT_INTERLACE) - { + if (context->regs[REG_MODE_4] & BIT_INTERLACE) { context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; } } diff -r 792be135d3af -r 0b692b5d154b util.c --- a/util.c Sun Jul 26 01:11:04 2015 -0700 +++ b/util.c Sun Jul 26 13:25:31 2015 -0700 @@ -175,8 +175,8 @@ } #ifdef _WIN32 -#include "Shlobj.h" -#include "Windows.h" +#include +#include char * get_home_dir() {