From 4788b58c7290ad4a4a161d6bc69bc184acc2ef66 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Tue, 23 Jul 2013 23:01:03 -0700 Subject: Started work on OpenGL support in new branch --HG-- branch : opengl --- blastem.c | 50 ++++----- render.h | 10 +- render_sdl.c | 329 +++++++++++++++++++++++++++++++++++++---------------------- 3 files changed, 242 insertions(+), 147 deletions(-) diff --git a/blastem.c b/blastem.c index dfa950d..e05e9d2 100644 --- a/blastem.c +++ b/blastem.c @@ -50,7 +50,7 @@ int load_smd_rom(long filesize, FILE * f) uint8_t block[SMD_BLOCK_SIZE]; filesize -= SMD_HEADER_SIZE; fseek(f, SMD_HEADER_SIZE, SEEK_SET); - + uint16_t * dst = cart; while (filesize > 0) { fread(block, 1, SMD_BLOCK_SIZE, f); @@ -137,15 +137,15 @@ void adjust_int_cycle(m68k_context * context, vdp_context * v_context) if (next_hint < context->int_cycle) { context->int_cycle = next_hint; context->int_num = 4; - + } } } } context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; - /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", - context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), + /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", + context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), v_context->regs[REG_MODE_2] & 0x20, v_context->regs[REG_MODE_1] & 0x10, v_context->hint_counter, v_context->regs[REG_HINT], v_context->cycles / MCLKS_LINE);*/ } @@ -197,7 +197,7 @@ void sync_sound(genesis_context * gen, uint32_t target) //printf("YM | Cycle: %d, bpos: %d, PSG | Cycle: %d, bpos: %d\n", gen->ym->current_cycle, gen->ym->buffer_pos, gen->psg->cycles, gen->psg->buffer_pos * 2); psg_run(gen->psg, target); ym_run(gen->ym, target); - + //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2); } @@ -219,7 +219,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) } //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); vdp_run_context(v_context, mclks_per_frame); - + if (!headless) { break_on_sync |= wait_render_frame(v_context, frame_limit); } @@ -496,7 +496,7 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value } if (value & 1) { dputs("bus requesting Z80"); - + if(!reset && !busreq) { busack_cycle = ((gen->z80->current_cycle + Z80_ACK_DELAY) * MCLKS_PER_Z80) / MCLKS_PER_68K;//context->current_cycle + Z80_ACK_DELAY; new_busack = Z80_REQ_ACK; @@ -518,7 +518,7 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value } //busack_cycle = CYCLE_NEVER; //busack = Z80_REQ_BUSY; - + } } else if (location == 0x1200) { sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); @@ -1433,7 +1433,7 @@ m68k_context * debugger(m68k_context * context, uint32_t address) //Z80 debug commands switch(input_buf[1]) { - case 'b': + case 'b': param = find_param(input_buf); if (!param) { fputs("zb command requires a parameter\n", stderr); @@ -1552,7 +1552,7 @@ uint8_t z80_load_gst(z80_context * context, FILE * gstfile) context->flags[ZF_Z] = f & 1; f >>= 1; context->flags[ZF_S] = f; - + context->regs[Z80_A] = *curpos; curpos += 3; for (int reg = Z80_C; reg <= Z80_IYH; reg++) { @@ -1640,7 +1640,7 @@ uint32_t load_gst(genesis_context * gen, char * fname) adjust_int_cycle(gen->m68k, gen->vdp); fclose(gstfile); return pc; - + error_close: fclose(gstfile); error: @@ -1658,7 +1658,7 @@ error: const memmap_chunk static_map[] = { {0, 0x400000, 0xFFFFFF, 0, MMAP_READ, cart, NULL, NULL, NULL, NULL}, - {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, + {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, NULL, NULL, NULL, NULL}, {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, NULL, (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, @@ -1711,7 +1711,7 @@ void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * s memmap[0].mask = 0xFFFFFF; memmap[0].flags = MMAP_READ; memmap[0].buffer = cart; - + ram_start &= 0xFFFFFE; ram_end |= 1; memmap[1].start = ram_start; @@ -1728,7 +1728,7 @@ void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * s size /= 2; } memmap[1].buffer = gen->save_ram = malloc(size); - + memcpy(memmap+2, static_map+1, sizeof(static_map)-sizeof(static_map[0])); num_chunks = sizeof(static_map)/sizeof(memmap_chunk)+1; } else { @@ -1737,7 +1737,7 @@ void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * s memmap[0].mask = 0xFFFFFF; memmap[0].flags = MMAP_READ; memmap[0].buffer = cart; - + memmap[1].start = 0x200000; memmap[1].end = 0x400000; memmap[1].mask = 0x1FFFFF; @@ -1757,7 +1757,7 @@ void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * s memmap[num_chunks].end = 0xA13100; memmap[num_chunks].mask = 0xFF; memmap[num_chunks].write_16 = (write_16_fun)write_bank_reg_w; - memmap[num_chunks].write_8 = (write_8_fun)write_bank_reg_b; + memmap[num_chunks].write_8 = (write_8_fun)write_bank_reg_b; num_chunks++; ram_end++; size = ram_end-ram_start; @@ -1786,7 +1786,7 @@ void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * s init_x86_68k_opts(&opts, memmap, num_chunks); opts.address_log = address_log; init_68k_context(&context, opts.native_code_map, &opts); - + context.video_context = gen->vdp; context.system = gen; //cartridge ROM @@ -1958,18 +1958,18 @@ int main(int argc, char ** argv) fps = 50; } if (!headless) { - render_init(width, height, title, fps); + render_init(width, height, title, fps, 0); } vdp_context v_context; - + init_vdp_context(&v_context); - + ym2612_context y_context; ym_init(&y_context, render_sample_rate(), fps == 60 ? MCLKS_NTSC : MCLKS_PAL, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); - + psg_context p_context; psg_init(&p_context, render_sample_rate(), fps == 60 ? MCLKS_NTSC : MCLKS_PAL, MCLKS_PER_PSG, render_audio_buffer()); - + z80_context z_context; x86_z80_options z_opts; init_x86_z80_opts(&z_opts); @@ -1983,13 +1983,13 @@ int main(int argc, char ** argv) z_context.sync_cycle = z_context.target_cycle = mclks_per_frame/MCLKS_PER_Z80; z_context.int_cycle = CYCLE_NEVER; z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; - + gen.z80 = &z_context; gen.vdp = &v_context; gen.ym = &y_context; gen.psg = &p_context; genesis = &gen; - + int fname_size = strlen(argv[1]); sram_filename = malloc(fname_size+6); memcpy(sram_filename, argv[1], fname_size); @@ -2004,7 +2004,7 @@ int main(int argc, char ** argv) strcpy(sram_filename + fname_size, ".sram"); } set_keybindings(); - + init_run_cpu(&gen, debug, address_log, statefile); return 0; } diff --git a/render.h b/render.h index 24456be..339dd36 100644 --- a/render.h +++ b/render.h @@ -4,9 +4,17 @@ #include "vdp.h" #include "psg.h" #include "ym2612.h" + +typedef struct { + void *oddbuf; + void *evenbuf; + int stride; +} surface_info; + uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b); +surface_info render_alloc_surfaces(); uint8_t render_depth(); -void render_init(int width, int height, char * title, uint32_t fps); +void render_init(int width, int height, char * title, uint32_t fps, uint8_t use_gl); void render_context(vdp_context * context); void render_wait_quit(vdp_context * context); void render_wait_psg(psg_context * context); diff --git a/render_sdl.c b/render_sdl.c index 5fbf518..b70a373 100644 --- a/render_sdl.c +++ b/render_sdl.c @@ -4,9 +4,14 @@ #include "blastem.h" #include "io.h" +#ifndef DISABLE_OPENGL +#include +#endif + SDL_Surface *screen; uint8_t render_dbg = 0; uint8_t debug_pal = 0; +uint8_t render_gl; uint32_t last_frame = 0; @@ -75,7 +80,54 @@ int num_joysticks; uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) { - return SDL_MapRGB(screen->format, r, g, b); + if (render_gl) { + return b << 24 | g << 16 | r << 8 | 255; + } else { + return SDL_MapRGB(screen->format, r, g, b); + } +} + +GLuint textures[3], buffers[2]; + +const GLfloat vertex_data[] = { + -1.0f, -1.0f, + 1.0f, -1.0f, + -1.0f, 1.0f, + 1.0f, 1.0f +}; + +const GLushort element_data[] = {0, 1, 2, 3}; + +void render_alloc_surfaces(vdp_context * context) +{ + if (render_gl) { + context->oddbuf = context->framebuf = malloc(320 * 240 * 4 * 2); + memset(context->oddbuf, 0, 320 * 240 * 4 * 2); + context->evenbuf = ((char *)context->oddbuf) + 320 * 240 * 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; + 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[0]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); + } else { + context->oddbuf = context->framebuf = malloc(320 * 240 * screen->format->BytesPerPixel * 2); + context->evenbuf = ((char *)context->oddbuf) + 320 * 240 * screen->format->BytesPerPixel; + } } uint8_t render_depth() @@ -83,74 +135,104 @@ uint8_t render_depth() return screen->format->BytesPerPixel * 8; } -void render_init(int width, int height, char * title, uint32_t fps) +void render_init(int width, int height, char * title, uint32_t fps, uint8_t use_gl) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { - fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); - exit(1); - } - atexit(SDL_Quit); - atexit(render_close_audio); - printf("width: %d, height: %d\n", width, height); - screen = SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE | SDL_ANYFORMAT); - if (!screen) { - fprintf(stderr, "Unable to get SDL surface: %s\n", SDL_GetError()); - exit(1); - } - if (screen->format->BytesPerPixel != 2 && screen->format->BytesPerPixel != 4) { - fprintf(stderr, "BlastEm requires a 16-bit or 32-bit surface, SDL returned a %d-bit surface\n", screen->format->BytesPerPixel * 8); - exit(1); - } - SDL_WM_SetCaption(title, title); - min_delay = 0; - for (int i = 0; i < 100; i++) { - uint32_t start = SDL_GetTicks(); - SDL_Delay(1); - uint32_t delay = SDL_GetTicks()-start; - if (delay > min_delay) { - min_delay = delay; - } - } - if (!min_delay) { - min_delay = 1; - } - printf("minimum delay: %d\n", min_delay); - - frame_delay = 1000/fps; - - audio_mutex = SDL_CreateMutex(); - psg_cond = SDL_CreateCond(); - ym_cond = SDL_CreateCond(); - audio_ready = SDL_CreateCond(); - - SDL_AudioSpec desired, actual; - desired.freq = 48000; - desired.format = AUDIO_S16SYS; - desired.channels = 2; - desired.samples = 2048;//1024; - desired.callback = audio_callback; - desired.userdata = NULL; - - if (SDL_OpenAudio(&desired, &actual) < 0) { - fprintf(stderr, "Unable to open SDL audio: %s\n", SDL_GetError()); - exit(1); - } - buffer_samples = actual.samples; - sample_rate = actual.freq; - printf("Initialized audio at frequency %d with a %d sample buffer\n", actual.freq, actual.samples); - SDL_PauseAudio(0); - num_joysticks = SDL_NumJoysticks(); - if (num_joysticks > MAX_JOYSTICKS) { - num_joysticks = MAX_JOYSTICKS; - } - for (int i = 0; i < num_joysticks; i++) { - printf("Joystick %d: %s\n", i, SDL_JoystickName(i)); - SDL_Joystick * joy = joysticks[i] = SDL_JoystickOpen(i); - if (joy) { - printf("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy)); - } - } - SDL_JoystickEventState(SDL_ENABLE); + fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); + exit(1); + } + atexit(SDL_Quit); + atexit(render_close_audio); + printf("width: %d, height: %d\n", width, height); + uint32_t flags +#ifndef DISABLE_OPENGL + if (use_gl) + { + 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); + flags = SDL_OPENGL; + } else { +#else + { +#endif + flags = SDL_SWSURFACE | SDL_ANYFORMAT; + } + screen = SDL_SetVideoMode(width, height, 32, flags); + if (!screen) { + fprintf(stderr, "Unable to get SDL surface: %s\n", SDL_GetError()); + exit(1); + } + if (!use_gl && screen->format->BytesPerPixel != 2 && screen->format->BytesPerPixel != 4) { + fprintf(stderr, "BlastEm requires a 16-bit or 32-bit surface, SDL returned a %d-bit surface\n", screen->format->BytesPerPixel * 8); + exit(1); + } +#ifndef DISABLE_OPENGL + //TODO: Fallback to plain SDL if OpenGL 2.0 not available + render_gl = use_gl; +#endif + SDL_WM_SetCaption(title, title); + min_delay = 0; + for (int i = 0; i < 100; i++) { + uint32_t start = SDL_GetTicks(); + SDL_Delay(1); + uint32_t delay = SDL_GetTicks()-start; + if (delay > min_delay) { + min_delay = delay; + } + } + if (!min_delay) { + min_delay = 1; + } + printf("minimum delay: %d\n", min_delay); + + frame_delay = 1000/fps; + + audio_mutex = SDL_CreateMutex(); + psg_cond = SDL_CreateCond(); + ym_cond = SDL_CreateCond(); + audio_ready = SDL_CreateCond(); + + SDL_AudioSpec desired, actual; + desired.freq = 48000; + desired.format = AUDIO_S16SYS; + desired.channels = 2; + desired.samples = 2048;//1024; + desired.callback = audio_callback; + desired.userdata = NULL; + + if (SDL_OpenAudio(&desired, &actual) < 0) { + fprintf(stderr, "Unable to open SDL audio: %s\n", SDL_GetError()); + exit(1); + } + buffer_samples = actual.samples; + sample_rate = actual.freq; + printf("Initialized audio at frequency %d with a %d sample buffer\n", actual.freq, actual.samples); + SDL_PauseAudio(0); + num_joysticks = SDL_NumJoysticks(); + if (num_joysticks > MAX_JOYSTICKS) { + num_joysticks = MAX_JOYSTICKS; + } + for (int i = 0; i < num_joysticks; i++) { + printf("Joystick %d: %s\n", i, SDL_JoystickName(i)); + SDL_Joystick * joy = joysticks[i] = SDL_JoystickOpen(i); + if (joy) { + printf("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy)); + } + } + SDL_JoystickEventState(SDL_ENABLE); +} + +void render_context_gl(vdp_context * context) +{ + 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); + } uint32_t blankbuf[320*240]; @@ -158,64 +240,69 @@ uint32_t blankbuf[320*240]; void render_context(vdp_context * context) { uint16_t *buf_16; - uint32_t *buf_32; + uint32_t *buf_32; uint8_t b,g,r; last_frame = SDL_GetTicks(); + if (render_gl) + { + render_context_gl(context); + return; + } if (SDL_MUSTLOCK(screen)) { if (SDL_LockSurface(screen) < 0) { return; } - } - uint16_t repeat_x = screen->clip_rect.w / 320; - uint16_t repeat_y = screen->clip_rect.h / 240; - if (repeat_x > repeat_y) { - repeat_x = repeat_y; - } else { - repeat_y = repeat_x; - } - int othermask = repeat_y >> 1; - - if (screen->format->BytesPerPixel == 2) { - uint16_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint16_t *)blankbuf; - uint16_t * oddbuf = context->oddbuf; - buf_16 = (uint16_t *)screen->pixels; - for (int y = 0; y < 240; y++) { - for (int i = 0; i < repeat_y; i++,buf_16 += screen->pitch/2) { - uint16_t *line = buf_16; - uint16_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; - for (int x = 0; x < 320; x++) { - uint16_t color = *(src_line++); - for (int j = 0; j < repeat_x; j++) { - *(line++) = color; - } - } - } - } - } else { - uint32_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint32_t *)blankbuf; - uint32_t * oddbuf = context->oddbuf; - buf_32 = (uint32_t *)screen->pixels; - for (int y = 0; y < 240; y++) { - for (int i = 0; i < repeat_y; i++,buf_32 += screen->pitch/4) { - uint32_t *line = buf_32; - uint32_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; - for (int x = 0; x < 320; x++) { - uint32_t color = *(src_line++); - for (int j = 0; j < repeat_x; j++) { - *(line++) = color; - } - } - } - } - } - if ( SDL_MUSTLOCK(screen) ) { - SDL_UnlockSurface(screen); - } - SDL_UpdateRect(screen, 0, 0, screen->clip_rect.w, screen->clip_rect.h); - if (context->regs[REG_MODE_4] & BIT_INTERLACE) - { - context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; - } + } + uint16_t repeat_x = screen->clip_rect.w / 320; + uint16_t repeat_y = screen->clip_rect.h / 240; + if (repeat_x > repeat_y) { + repeat_x = repeat_y; + } else { + repeat_y = repeat_x; + } + int othermask = repeat_y >> 1; + + if (screen->format->BytesPerPixel == 2) { + uint16_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint16_t *)blankbuf; + uint16_t * oddbuf = context->oddbuf; + buf_16 = (uint16_t *)screen->pixels; + for (int y = 0; y < 240; y++) { + for (int i = 0; i < repeat_y; i++,buf_16 += screen->pitch/2) { + uint16_t *line = buf_16; + uint16_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; + for (int x = 0; x < 320; x++) { + uint16_t color = *(src_line++); + for (int j = 0; j < repeat_x; j++) { + *(line++) = color; + } + } + } + } + } else { + uint32_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint32_t *)blankbuf; + uint32_t * oddbuf = context->oddbuf; + buf_32 = (uint32_t *)screen->pixels; + for (int y = 0; y < 240; y++) { + for (int i = 0; i < repeat_y; i++,buf_32 += screen->pitch/4) { + uint32_t *line = buf_32; + uint32_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; + for (int x = 0; x < 320; x++) { + uint32_t color = *(src_line++); + for (int j = 0; j < repeat_x; j++) { + *(line++) = color; + } + } + } + } + } + if ( SDL_MUSTLOCK(screen) ) { + SDL_UnlockSurface(screen); + } + SDL_UpdateRect(screen, 0, 0, screen->clip_rect.w, screen->clip_rect.h); + if (context->regs[REG_MODE_4] & BIT_INTERLACE) + { + context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; + } } int render_joystick_num_buttons(int joystick) @@ -321,8 +408,8 @@ int wait_render_frame(vdp_context * context, int frame_limit) } } render_context(context); - - + + //TODO: Figure out why this causes segfaults /*frame_counter++; if ((last_frame - start) > 1000) { -- cgit v1.2.3 From 7b604db493ad6663b864a5d1b9f509118f9860b2 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Sun, 27 Oct 2013 01:29:50 -0700 Subject: Basic OpenGL rendering is working --HG-- branch : opengl --- Makefile | 2 +- blastem.c | 51 ++++++++++++++++-------------- default.f.glsl | 10 ++++++ default.v.glsl | 10 ++++++ render_sdl.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- vdp.c | 5 ++- 6 files changed, 143 insertions(+), 33 deletions(-) create mode 100644 default.f.glsl create mode 100644 default.v.glsl diff --git a/Makefile b/Makefile index 90b805a..b403988 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -LIBS=sdl gl +LIBS=sdl glew gl LDFLAGS=-lm `pkg-config --libs $(LIBS)` ifdef DEBUG CFLAGS=-ggdb -std=gnu99 `pkg-config --cflags-only-I $(LIBS)` -Wreturn-type -Werror=return-type diff --git a/blastem.c b/blastem.c index b29f4ad..85f92d3 100644 --- a/blastem.c +++ b/blastem.c @@ -62,7 +62,7 @@ int load_smd_rom(long filesize, FILE * f) uint8_t block[SMD_BLOCK_SIZE]; filesize -= SMD_HEADER_SIZE; fseek(f, SMD_HEADER_SIZE, SEEK_SET); - + uint16_t * dst = cart; while (filesize > 0) { fread(block, 1, SMD_BLOCK_SIZE, f); @@ -149,15 +149,15 @@ void adjust_int_cycle(m68k_context * context, vdp_context * v_context) if (next_hint < context->int_cycle) { context->int_cycle = next_hint; context->int_num = 4; - + } } } } context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; - /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", - context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), + /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", + context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), v_context->regs[REG_MODE_2] & 0x20, v_context->regs[REG_MODE_1] & 0x10, v_context->hint_counter, v_context->regs[REG_HINT], v_context->cycles / MCLKS_LINE);*/ } @@ -217,7 +217,7 @@ void sync_sound(genesis_context * gen, uint32_t target) } psg_run(gen->psg, target); ym_run(gen->ym, target); - + //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2); } @@ -239,7 +239,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) } //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); vdp_run_context(v_context, mclks_per_frame); - + if (!headless) { break_on_sync |= wait_render_frame(v_context, frame_limit); } @@ -532,7 +532,7 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value } if (value & 1) { dputs("bus requesting Z80"); - + if(!reset && !busreq) { sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K + Z80_ACK_DELAY*MCLKS_PER_Z80); busack_cycle = (gen->z80->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_68K;//context->current_cycle + Z80_ACK_DELAY; @@ -556,7 +556,7 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value } //busack_cycle = CYCLE_NEVER; //busack = Z80_REQ_BUSY; - + } } else if (location == 0x1200) { sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); @@ -1471,7 +1471,7 @@ m68k_context * debugger(m68k_context * context, uint32_t address) //Z80 debug commands switch(input_buf[1]) { - case 'b': + case 'b': param = find_param(input_buf); if (!param) { fputs("zb command requires a parameter\n", stderr); @@ -1523,7 +1523,7 @@ void set_speed_percent(genesis_context * context, uint32_t percent) const memmap_chunk static_map[] = { {0, 0x400000, 0xFFFFFF, 0, MMAP_READ, cart, NULL, NULL, NULL, NULL}, - {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, + {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, NULL, NULL, NULL, NULL}, {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, NULL, (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, @@ -1576,7 +1576,7 @@ void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * s memmap[0].mask = 0xFFFFFF; memmap[0].flags = MMAP_READ; memmap[0].buffer = cart; - + ram_start &= 0xFFFFFE; ram_end |= 1; memmap[1].start = ram_start; @@ -1593,7 +1593,7 @@ void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * s size /= 2; } memmap[1].buffer = gen->save_ram = malloc(size); - + memcpy(memmap+2, static_map+1, sizeof(static_map)-sizeof(static_map[0])); num_chunks = sizeof(static_map)/sizeof(memmap_chunk)+1; } else { @@ -1602,7 +1602,7 @@ void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * s memmap[0].mask = 0xFFFFFF; memmap[0].flags = MMAP_READ; memmap[0].buffer = cart; - + memmap[1].start = 0x200000; memmap[1].end = 0x400000; memmap[1].mask = 0x1FFFFF; @@ -1622,7 +1622,7 @@ void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * s memmap[num_chunks].end = 0xA13100; memmap[num_chunks].mask = 0xFF; memmap[num_chunks].write_16 = (write_16_fun)write_bank_reg_w; - memmap[num_chunks].write_8 = (write_8_fun)write_bank_reg_b; + memmap[num_chunks].write_8 = (write_8_fun)write_bank_reg_b; num_chunks++; ram_end++; size = ram_end-ram_start; @@ -1651,7 +1651,7 @@ void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * s init_x86_68k_opts(&opts, memmap, num_chunks); opts.address_log = address_log; init_68k_context(&context, opts.native_code_map, &opts); - + context.video_context = gen->vdp; context.system = gen; //cartridge ROM @@ -1773,7 +1773,7 @@ int main(int argc, char ** argv) char * romfname = NULL; FILE *address_log = NULL; char * statefile = NULL; - uint8_t fullscreen = 0; + uint8_t fullscreen = 0, use_gl = 0; for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch(argv[i][1]) { @@ -1783,6 +1783,9 @@ int main(int argc, char ** argv) case 'f': fullscreen = 1; break; + case 'g': + use_gl = 1; + break; case 'l': address_log = fopen("address.log", "w"); break; @@ -1885,21 +1888,21 @@ int main(int argc, char ** argv) fps = 50; } if (!headless) { - render_init(width, height, title, fps, fullscreen, 0); + render_init(width, height, title, fps, fullscreen, use_gl); } vdp_context v_context; genesis_context gen; memset(&gen, 0, sizeof(gen)); gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL; - + init_vdp_context(&v_context); - + ym2612_context y_context; ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); - + psg_context p_context; psg_init(&p_context, render_sample_rate(), gen.master_clock, MCLKS_PER_PSG, render_audio_buffer()); - + z80_context z_context; x86_z80_options z_opts; init_x86_z80_opts(&z_opts); @@ -1910,13 +1913,13 @@ int main(int argc, char ** argv) z_context.sync_cycle = z_context.target_cycle = mclks_per_frame/MCLKS_PER_Z80; z_context.int_cycle = CYCLE_NEVER; z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; - + gen.z80 = &z_context; gen.vdp = &v_context; gen.ym = &y_context; gen.psg = &p_context; genesis = &gen; - + int fname_size = strlen(romfname); sram_filename = malloc(fname_size+6); memcpy(sram_filename, romfname, fname_size); @@ -1931,7 +1934,7 @@ int main(int argc, char ** argv) strcpy(sram_filename + fname_size, ".sram"); } set_keybindings(); - + init_run_cpu(&gen, debug, address_log, statefile); return 0; } diff --git a/default.f.glsl b/default.f.glsl new file mode 100644 index 0000000..55b6c52 --- /dev/null +++ b/default.f.glsl @@ -0,0 +1,10 @@ +#version 110 + +uniform sampler2D textures[2]; + +varying vec2 texcoord; + +void main() +{ + gl_FragColor = texture2D(textures[0], texcoord); +} diff --git a/default.v.glsl b/default.v.glsl new file mode 100644 index 0000000..367c128 --- /dev/null +++ b/default.v.glsl @@ -0,0 +1,10 @@ +#version 110 + +attribute vec2 pos; +varying vec2 texcoord; + +void main() +{ + gl_Position = vec4(pos, 0.0, 1.0); + texcoord = pos * vec2(320.0/1024.0, 240.0/-512.0) + vec2(320.0/1024.0, 240.0/512.0); +} diff --git a/render_sdl.c b/render_sdl.c index 47fbcec..f62ba66 100644 --- a/render_sdl.c +++ b/render_sdl.c @@ -10,9 +10,7 @@ #include "io.h" #ifndef DISABLE_OPENGL -#define GL_GLEXT_PROTOTYPES -#include -#include +#include #endif SDL_Surface *screen; @@ -93,13 +91,13 @@ int render_num_joysticks() uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) { if (render_gl) { - return b << 24 | g << 16 | r << 8 | 255; + return 255 << 24 | r << 16 | g << 8 | b; } else { return SDL_MapRGB(screen->format, r, g, b); } } -GLuint textures[3], buffers[2]; +GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], at_pos; const GLfloat vertex_data[] = { -1.0f, -1.0f, @@ -110,6 +108,41 @@ const GLfloat vertex_data[] = { const GLushort element_data[] = {0, 1, 2, 3}; +GLuint load_shader(char * fname, GLenum shader_type) +{ + FILE * f = fopen(fname, "r"); + if (!f) { + fprintf(stderr, "Failed to open shader file %s for reading\n", fname); + return 0; + } + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + GLchar * text = malloc(fsize); + if (fread(text, 1, fsize, f) != fsize) { + fprintf(stderr, "Error reading from shader file %s\n", fname); + free(text); + return 0; + } + GLuint ret = glCreateShader(shader_type); + glShaderSource(ret, 1, (const GLchar **)&text, (const GLint *)&fsize); + free(text); + glCompileShader(ret); + GLint compile_status, loglen; + glGetShaderiv(ret, GL_COMPILE_STATUS, &compile_status); + if (!compile_status) { + fprintf(stderr, "Shader %s failed to compile\n", fname); + glGetShaderiv(ret, GL_INFO_LOG_LENGTH, &loglen); + text = malloc(loglen); + glGetShaderInfoLog(ret, loglen, NULL, text); + fputs(text, stderr); + free(text); + glDeleteShader(ret); + return 0; + } + return ret; +} + void render_alloc_surfaces(vdp_context * context) { if (render_gl) { @@ -134,8 +167,23 @@ void render_alloc_surfaces(vdp_context * context) 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[0]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); + vshader = load_shader("default.v.glsl", GL_VERTEX_SHADER); + fshader = load_shader("default.f.glsl", 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]"); + at_pos = glGetAttribLocation(program, "pos"); } else { context->oddbuf = context->framebuf = malloc(320 * 240 * screen->format->BytesPerPixel * 2); context->evenbuf = ((char *)context->oddbuf) + 320 * 240 * screen->format->BytesPerPixel; @@ -159,6 +207,7 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full atexit(render_close_audio); printf("width: %d, height: %d\n", width, height); uint32_t flags = SDL_ANYFORMAT; + #ifndef DISABLE_OPENGL if (use_gl) { @@ -188,7 +237,21 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full exit(1); } #ifndef DISABLE_OPENGL - //TODO: Fallback to plain SDL if OpenGL 2.0 not available + //TODO: fallback on standard rendering if OpenGL 2.0 is unavailable or if init fails + if (use_gl) + { + GLenum res = glewInit(); + if (res != GLEW_OK) + { + fprintf(stderr, "Initialization of GLEW failed with code %d\n", res); + exit(1); + } + if (!GLEW_VERSION_2_0) + { + fputs("OpenGL 2.0 is unable, falling back to standard SDL rendering\n", stderr); + exit(1); + } + } render_gl = use_gl; #endif SDL_WM_SetCaption(title, title); @@ -263,6 +326,27 @@ void render_context_gl(vdp_context * context) 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); + + glActiveTexture(GL_TEXTURE1); + //TODO: Select appropriate texture based on status of interlace + glBindTexture(GL_TEXTURE_2D, textures[1]); + glUniform1i(un_textures[1], 1); + + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); + glEnableVertexAttribArray(at_pos); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0); + + glDisableVertexAttribArray(at_pos); + + SDL_GL_SwapBuffers(); + } uint32_t blankbuf[320*240]; diff --git a/vdp.c b/vdp.c index c1e04f0..e962a67 100644 --- a/vdp.c +++ b/vdp.c @@ -50,10 +50,13 @@ void init_vdp_context(vdp_context * context) memset(context, 0, sizeof(*context)); context->vdpmem = malloc(VRAM_SIZE); memset(context->vdpmem, 0, VRAM_SIZE); - context->oddbuf = context->framebuf = malloc(FRAMEBUF_ENTRIES * (render_depth() / 8)); + /*context->oddbuf = context->framebuf = malloc(FRAMEBUF_ENTRIES * (render_depth() / 8)); memset(context->framebuf, 0, FRAMEBUF_ENTRIES * (render_depth() / 8)); context->evenbuf = malloc(FRAMEBUF_ENTRIES * (render_depth() / 8)); memset(context->evenbuf, 0, FRAMEBUF_ENTRIES * (render_depth() / 8)); + */ + render_alloc_surfaces(context); + context->framebuf = context->oddbuf; context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); context->tmp_buf_a = context->linebuf + LINEBUF_SIZE; -- cgit v1.2.3 From b5e181c3f87201b95e6b6e6b96de2ac15ed35f35 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Sun, 27 Oct 2013 21:41:21 -0700 Subject: Support interlace mode with OpenGL backend --HG-- branch : opengl --- default.f.glsl | 6 +++++- render_sdl.c | 10 ++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/default.f.glsl b/default.f.glsl index 55b6c52..f7bb89a 100644 --- a/default.f.glsl +++ b/default.f.glsl @@ -6,5 +6,9 @@ varying vec2 texcoord; void main() { - gl_FragColor = texture2D(textures[0], texcoord); + gl_FragColor = mix( + texture2D(textures[0], texcoord), + texture2D(textures[1], vec2(texcoord.x, texcoord.y - 1.0/512.0)), + sin((texcoord.y * 512.0 - 0.75) * 3.14159265359) / 2.0 + 0.5 + ); } diff --git a/render_sdl.c b/render_sdl.c index f62ba66..ad99025 100644 --- a/render_sdl.c +++ b/render_sdl.c @@ -160,7 +160,7 @@ void render_alloc_surfaces(vdp_context * context) 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; + uint32_t blank = 255 << 24; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); } } @@ -332,8 +332,7 @@ void render_context_gl(vdp_context * context) glUniform1i(un_textures[0], 0); glActiveTexture(GL_TEXTURE1); - //TODO: Select appropriate texture based on status of interlace - glBindTexture(GL_TEXTURE_2D, textures[1]); + glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]); glUniform1i(un_textures[1], 1); glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); @@ -346,7 +345,10 @@ void render_context_gl(vdp_context * context) glDisableVertexAttribArray(at_pos); SDL_GL_SwapBuffers(); - + if (context->regs[REG_MODE_4] & BIT_INTERLACE) + { + context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; + } } uint32_t blankbuf[320*240]; -- cgit v1.2.3 From acf09d7b87b54e9e63ff49bd9c09842d6daf1708 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Sun, 27 Oct 2013 21:58:03 -0700 Subject: Enable fullscreen mode in OpenGL renderer --HG-- branch : opengl --- render_sdl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/render_sdl.c b/render_sdl.c index ad99025..3c01eeb 100644 --- a/render_sdl.c +++ b/render_sdl.c @@ -217,6 +217,9 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); flags = SDL_OPENGL; + if (fullscreen) { + flags |= SDL_FULLSCREEN; + } } else { #else { -- cgit v1.2.3 -- cgit v1.2.3