# HG changeset patch # User Michael Pavone # Date 1471884378 25200 # Node ID 1a66d5165ea7b0613effb4f8bee87332a6ca5e83 # Parent fa6fe03f218a69cbdeda2cbf85df55d9bf527fcb Cleanup the separation of render backend and VDP code in preparation for having extra debug windows. Make determination of H40/H32 based on number of lines in each mode. diff -r fa6fe03f218a -r 1a66d5165ea7 blastem.c --- a/blastem.c Fri Aug 12 09:39:39 2016 -0700 +++ b/blastem.c Mon Aug 22 09:46:18 2016 -0700 @@ -272,9 +272,7 @@ //printf("reached frame end %d | MCLK Cycles: %d, Target: %d, VDP cycles: %d, vcounter: %d, hslot: %d\n", last_frame_num, mclks, gen->frame_end, v_context->cycles, v_context->vcounter, v_context->hslot); last_frame_num = v_context->frame; - if (!headless) { - break_on_sync |= wait_render_frame(v_context, frame_limit); - } else if(exit_after){ + if(exit_after){ --exit_after; if (!exit_after) { exit(0); diff -r fa6fe03f218a -r 1a66d5165ea7 gst.c --- a/gst.c Fri Aug 12 09:39:39 2016 -0700 +++ b/gst.c Mon Aug 22 09:46:18 2016 -0700 @@ -224,9 +224,6 @@ return 0; } context->double_res = (context->regs[REG_MODE_4] & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); - if (!context->double_res) { - context->framebuf = context->oddbuf; - } latch_mode(context); if (fread(tmp_buf, 1, CRAM_SIZE*2, state_file) != CRAM_SIZE*2) { fputs("Failed to read CRAM from savestate\n", stderr); diff -r fa6fe03f218a -r 1a66d5165ea7 io.c --- a/io.c Fri Aug 12 09:39:39 2016 -0700 +++ b/io.c Mon Aug 22 09:46:18 2016 -0700 @@ -21,6 +21,7 @@ #include "util.h" #define CYCLE_NEVER 0xFFFFFFFF +#define MIN_POLL_INTERVAL 6840 const char * device_type_names[] = { "3-button gamepad", @@ -1146,6 +1147,7 @@ } } +uint32_t last_poll_cycle; void io_adjust_cycles(io_port * port, uint32_t current_cycle, uint32_t deduction) { /*uint8_t control = pad->control | 0x80; @@ -1167,6 +1169,11 @@ port->device.mouse.ready_cycle -= deduction; } } + if (last_poll_cycle >= deduction) { + last_poll_cycle -= deduction; + } else { + last_poll_cycle = 0; + } } #ifndef _WIN32 @@ -1345,6 +1352,10 @@ uint8_t output = (control & port->output) | (~control & 0xFF); uint8_t th = output & 0x40; uint8_t input; + if (current_cycle - last_poll_cycle > MIN_POLL_INTERVAL) { + process_events(); + last_poll_cycle = current_cycle; + } switch (port->device_type) { case IO_GAMEPAD3: diff -r fa6fe03f218a -r 1a66d5165ea7 render.h --- a/render.h Fri Aug 12 09:39:39 2016 -0700 +++ b/render.h Mon Aug 22 09:46:18 2016 -0700 @@ -50,19 +50,16 @@ #define MAX_MICE 8 #define MAX_MOUSE_BUTTONS 8 +#define FRAMEBUFFER_ODD 0 +#define FRAMEBUFFER_EVEN 1 + #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); -void render_alloc_surfaces(vdp_context * context); -void render_free_surfaces(vdp_context *context); +uint32_t *render_get_framebuffer(uint8_t which, int *pitch); +void render_framebuffer_updated(uint8_t which, int width); void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen); void render_update_caption(char *title); void render_context(vdp_context * context); diff -r fa6fe03f218a -r 1a66d5165ea7 render_sdl.c --- a/render_sdl.c Fri Aug 12 09:39:39 2016 -0700 +++ b/render_sdl.c Mon Aug 22 09:46:18 2016 -0700 @@ -16,9 +16,12 @@ #include #endif +#define MAX_EVENT_POLL_PER_FRAME 2 + SDL_Window *main_window; SDL_Renderer *main_renderer; -SDL_Texture *main_texture; +SDL_Texture **sdl_textures; +uint8_t num_textures; SDL_Rect main_clip; SDL_GLContext *main_context; @@ -168,19 +171,20 @@ } #endif -void render_alloc_surfaces(vdp_context * context) +uint32_t texture_buf[512 * 256]; +void render_alloc_surfaces() { static uint8_t texture_init; - 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; if (texture_init) { return; } + sdl_textures= malloc(sizeof(SDL_Texture *) * 2); + num_textures = 2; texture_init = 1; #ifndef DISABLE_OPENGL if (render_gl) { + sdl_textures[0] = sdl_textures[1] = NULL; glGenTextures(3, textures); for (int i = 0; i < 3; i++) { @@ -190,7 +194,7 @@ 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); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf); } else { uint32_t blank = 255 << 24; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); @@ -221,27 +225,26 @@ 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); + + //height=480 to fit interlaced output + sdl_textures[0] = sdl_textures[1] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480); #ifndef DISABLE_OPENGL } #endif } -void render_free_surfaces(vdp_context *context) -{ - free(context->framebuf); -} - char * caption = NULL; char * fps_caption = NULL; static void render_quit() { render_close_audio(); -#ifdef DISABLE_OPENGL - SDL_DestroyTexture(main_texture); -#endif + for (int i = 0; i < num_textures; i++) + { + if (sdl_textures[i]) { + SDL_DestroyTexture(sdl_textures[i]); + } + } } void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen) @@ -356,6 +359,7 @@ } #endif } + render_alloc_surfaces(); def.ptrval = "off"; scanlines = !strcmp(tern_find_path_default(config, "video\0scanlines\0", def).ptrval, "on"); @@ -419,16 +423,57 @@ fps_caption = NULL; } -void render_context(vdp_context * context) +uint32_t *locked_pixels; +uint32_t locked_pitch; +uint32_t *render_get_framebuffer(uint8_t which, int *pitch) { - int width = context->regs[REG_MODE_4] & BIT_H40 ? 320.0f : 256.0f; - int height = 240; +#ifndef DISABLE_OPENGL + if (render_gl && which <= FRAMEBUFFER_EVEN) { + *pitch = 320 * sizeof(uint32_t); //TODO: change this to LINEBUF_SIZE once border rendering is added + return texture_buf; + } else { +#endif + if (which >= num_textures) { + warning("Request for invalid framebuffer number %d\n", which); + return NULL; + } + void *pixels; + if (SDL_LockTexture(sdl_textures[which], NULL, &pixels, pitch) < 0) { + warning("Failed to lock texture: %s\n", SDL_GetError()); + return NULL; + } + static uint8_t last; + if (which <= FRAMEBUFFER_EVEN) { + locked_pixels = pixels; + if (which == FRAMEBUFFER_EVEN) { + pixels += *pitch; + } + locked_pitch = *pitch; + if (which != last) { + *pitch *= 2; + } + last = which; + } + return pixels; +#ifndef DISABLE_OPENGL + } +#endif +} - last_frame = SDL_GetTicks(); +uint8_t events_processed; +#ifdef __ANDROID__ +#define FPS_INTERVAL 10000 +#else +#define FPS_INTERVAL 1000 +#endif + +void render_framebuffer_updated(uint8_t which, int width) +{ + static uint8_t last; #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);; + if (render_gl && which <= FRAMEBUFFER_EVEN) { + glBindTexture(GL_TEXTURE_2D, textures[which]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -439,7 +484,7 @@ glUniform1i(un_textures[0], 0); glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, textures[(context->regs[REG_MODE_4] & BIT_INTERLACE) ? 1 : scanlines ? 2 : 0]); + glBindTexture(GL_TEXTURE_2D, textures[last != which ? 1 : scanlines ? 2 : 0]); glUniform1i(un_textures[1], 1); glUniform1f(un_width, width); @@ -456,48 +501,60 @@ SDL_GL_SwapWindow(main_window); } else { #endif - SDL_Rect area; - - area.x = area.y = 0; - area.w = width; - area.h = height; - - 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; - - for (i = 0; i < 240; ++i) { - memcpy(dst, src, width*sizeof(uint32_t)); - src += 320; - dst += skip; + uint32_t height = 240; + if (which <= FRAMEBUFFER_EVEN && last != which) { + uint8_t *cur_dst = (uint8_t *)locked_pixels; + uint8_t *cur_saved = (uint8_t *)texture_buf; + uint32_t dst_off = which == FRAMEBUFFER_EVEN ? 0 : locked_pitch; + uint32_t src_off = which == FRAMEBUFFER_EVEN ? locked_pitch : 0; + for (int i = 0; i < 240; ++i) + { + //copy saved line from other field + memcpy(cur_dst + dst_off, cur_saved, locked_pitch); + //save line from this field to buffer for next frame + memcpy(cur_saved, cur_dst + src_off, locked_pitch); + cur_dst += locked_pitch * 2; + cur_saved += locked_pitch; } - - SDL_UnlockTexture(main_texture); + height = 480; } - else /* possibly faster path for non-interlaced output */ - SDL_UpdateTexture(main_texture, &area, context->framebuf, 320*sizeof(uint32_t)); - - SDL_RenderClear(main_renderer); - SDL_RenderCopy(main_renderer, main_texture, &area, &main_clip); + SDL_UnlockTexture(sdl_textures[which]); + SDL_Rect src_clip = { + .x = 0, + .y = 0, + .w = width, + .h = height + }; + SDL_RenderCopy(main_renderer, sdl_textures[which], &src_clip, &main_clip); SDL_RenderPresent(main_renderer); #ifndef DISABLE_OPENGL } #endif - - if (context->regs[REG_MODE_4] & BIT_INTERLACE) { - context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; + if (which <= FRAMEBUFFER_EVEN) { + last = which; + static uint32_t frame_counter, start; + frame_counter++; + last_frame= SDL_GetTicks(); + if ((last_frame - start) > FPS_INTERVAL) { + if (start && (last_frame-start)) { + #ifdef __ANDROID__ + info_message("%s - %.1f fps", caption, ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0)); + #else + if (!fps_caption) { + fps_caption = malloc(strlen(caption) + strlen(" - 100000000.1 fps") + 1); + } + sprintf(fps_caption, "%s - %.1f fps", caption, ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0)); + SDL_SetWindowTitle(main_window, fps_caption); + #endif + } + start = last_frame; + frame_counter = 0; + } } + if (!events_processed) { + process_events(); + } + events_processed = 0; } void render_wait_quit(vdp_context * context) @@ -505,20 +562,6 @@ SDL_Event event; while(SDL_WaitEvent(&event)) { switch (event.type) { - case SDL_KEYDOWN: - if (event.key.keysym.sym == SDLK_LEFTBRACKET) { - render_dbg++; - if (render_dbg == 4) { - render_dbg = 0; - } - render_context(context); - } else if(event.key.keysym.sym == SDLK_RIGHTBRACKET) { - debug_pal++; - if (debug_pal == 4) { - debug_pal = 0; - } - } - break; case SDL_QUIT: return; } @@ -720,60 +763,16 @@ return 0; } -uint32_t frame_counter = 0; -uint32_t start = 0; -#ifdef __ANDROID__ -#define FPS_INTERVAL 10000 -#else -#define FPS_INTERVAL 1000 -#endif -int wait_render_frame(vdp_context * context, int frame_limit) -{ - SDL_Event event; - int ret = 0; - while(SDL_PollEvent(&event)) { - ret = handle_event(&event); - } - if (frame_limit) { - //TODO: Adjust frame delay so we actually get 60 FPS rather than 62.5 FPS - uint32_t current = SDL_GetTicks(); - uint32_t desired = last_frame + frame_delay; - if (current < desired) { - uint32_t delay = last_frame + frame_delay - current; - if (delay > min_delay) { - SDL_Delay((delay/min_delay)*min_delay); - } - while ((desired) >= SDL_GetTicks()) { - } - } - } - render_context(context); - - frame_counter++; - if ((last_frame - start) > FPS_INTERVAL) { - if (start && (last_frame-start)) { -#ifdef __ANDROID__ - info_message("%s - %.1f fps", caption, ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0)); -#else - if (!fps_caption) { - fps_caption = malloc(strlen(caption) + strlen(" - 100000000.1 fps") + 1); - } - sprintf(fps_caption, "%s - %.1f fps", caption, ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0)); - SDL_SetWindowTitle(main_window, fps_caption); -#endif - } - start = last_frame; - frame_counter = 0; - } - return ret; -} - void process_events() { + if (events_processed > MAX_EVENT_POLL_PER_FRAME) { + return; + } SDL_Event event; while(SDL_PollEvent(&event)) { handle_event(&event); } + events_processed++; } void render_wait_psg(psg_context * context) diff -r fa6fe03f218a -r 1a66d5165ea7 vdp.c --- a/vdp.c Fri Aug 12 09:39:39 2016 -0700 +++ b/vdp.c Mon Aug 22 09:46:18 2016 -0700 @@ -59,14 +59,11 @@ /* */ if (headless) { - context->oddbuf = context->framebuf = malloc(FRAMEBUF_ENTRIES * (32 / 8)); - memset(context->framebuf, 0, FRAMEBUF_ENTRIES * (32 / 8)); - context->evenbuf = malloc(FRAMEBUF_ENTRIES * (32 / 8)); - memset(context->evenbuf, 0, FRAMEBUF_ENTRIES * (32 / 8)); + context->output = malloc(LINEBUF_SIZE); + context->output_pitch = 0; } else { - render_alloc_surfaces(context); + context->output = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch); } - 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; @@ -146,12 +143,6 @@ { free(context->vdpmem); free(context->linebuf); - if (headless) { - free(context->oddbuf); - free(context->evenbuf); - } else { - render_free_surfaces(context); - } free(context); } @@ -356,7 +347,7 @@ uint8_t height_mult; if (context->double_res) { line *= 2; - if (context->framebuf != context->oddbuf) { + if (context->flags2 & FLAG2_EVEN_FIELD) { line++; } ymask = 0x3FF; @@ -427,7 +418,7 @@ uint8_t height = ((context->sprite_info_list[context->cur_slot].size & 0x3) + 1) * 8; if (context->double_res) { line *= 2; - if (context->framebuf != context->oddbuf) { + if (context->flags2 & FLAG2_EVEN_FIELD) { line++; } height *= 2; @@ -673,7 +664,7 @@ uint16_t window_line_shift, v_offset_mask, vscroll_shift; if (context->double_res) { line *= 2; - if (context->framebuf != context->oddbuf) { + if (context->flags2 & FLAG2_EVEN_FIELD) { line++; } window_line_shift = 4; @@ -886,8 +877,7 @@ if (col) { col-=2; - dst = context->framebuf; - dst += line * 320 + col * 8; + dst = context->output + col * 8; if (context->debug < 2) { sprite_buf = context->linebuf + col * 8; uint8_t a_src, src; @@ -1042,8 +1032,26 @@ } else if (!(context->latched_mode & BIT_PAL) && context->vcounter == 0xEB) { context->vcounter = 0x1E5; } + uint32_t inactive_start = (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START); + if (!headless) { + if (!context->vcounter && !context->output) { + context->output = render_get_framebuffer(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD, &context->output_pitch); + context->h40_lines = 0; + } else if (context->vcounter == inactive_start) { //TODO: Change this once border emulation is added + context->output = NULL; + render_framebuffer_updated(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN: FRAMEBUFFER_ODD, context->h40_lines > inactive_start / 2 ? 320 : 256); + if (context->double_res) { + context->flags2 ^= FLAG2_EVEN_FIELD; + } + } else if (context->output) { + context->output = (uint32_t *)(((char *)context->output) + context->output_pitch); + if (context->regs[REG_MODE_4] & BIT_H40) { + context->h40_lines++; + } + } + } - if (context->vcounter > (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) { + if (context->vcounter > inactive_start) { context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { context->hint_counter--; @@ -1459,19 +1467,16 @@ int starti = -1; if (context->regs[REG_MODE_4] & BIT_H40) { if (slot >= 12 && slot < 172) { - uint32_t x = (slot-12)*2; - starti = line * 320 + x; + starti = (slot-12)*2; } } else { if (slot >= 11 && slot < 139) { - uint32_t x = (slot-11)*2; - starti = line * 320 + x; + starti = (slot-11)*2; } } if (starti >= 0) { uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; - uint32_t * start = context->framebuf; - start += starti; + uint32_t * start = context->output + starti; for (int i = 0; i < 2; i++) { *(start++) = color; } @@ -1650,7 +1655,7 @@ if (reg == REG_MODE_4) { context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); if (!context->double_res) { - context->framebuf = context->oddbuf; + context->flags &= FLAG2_EVEN_FIELD; } } context->cd &= 0x3C; @@ -1728,7 +1733,7 @@ value |= 0x20; context->flags2 &= ~FLAG2_SPRITE_COLLIDE; } - if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && context->framebuf == context->oddbuf) { + if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && !(context->flags2 & FLAG2_EVEN_FIELD)) { value |= 0x10; } uint32_t line= context->vcounter; @@ -1767,16 +1772,8 @@ if (context->cd & 1) { warning("Read from VDP data port while writes are configured, CPU is now frozen. VDP Address: %X, CD: %X\n", context->address, context->cd); } - uint32_t old_frame = context->frame; while (!(context->flags & FLAG_READ_FETCHED)) { vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); - if (context->frame != old_frame) { - if (!headless) { - //TODO: make pushing frames to renderer automatic so this doesn't need to be here - wait_render_frame(context, 0); - } - old_frame = context->frame; - } } context->flags &= ~FLAG_READ_FETCHED; //Should this happen after the prefetch or after the read? diff -r fa6fe03f218a -r 1a66d5165ea7 vdp.h --- a/vdp.h Fri Aug 12 09:39:39 2016 -0700 +++ b/vdp.h Mon Aug 22 09:46:18 2016 -0700 @@ -13,8 +13,8 @@ #define CRAM_SIZE 64 #define VSRAM_SIZE 40 #define VRAM_SIZE (64*1024) -#define LINEBUF_SIZE 320 -#define FRAMEBUF_ENTRIES (320+27)*(240+27) //PAL active display + full border +#define LINEBUF_SIZE (320+27) //H40 + full border +#define BORDER_BOTTOM 13 //TODO: Replace with actual value #define MAX_DRAWS 40 #define MAX_DRAWS_H32 32 #define MAX_SPRITES_LINE 20 @@ -51,6 +51,7 @@ #define FLAG2_READ_PENDING 0x04 #define FLAG2_SPRITE_COLLIDE 0x08 #define FLAG2_REGION_PAL 0x10 +#define FLAG2_EVEN_FIELD 0x20 #define DISPLAY_ENABLE 0x40 @@ -138,15 +139,14 @@ uint8_t *vdpmem; //stores 2-bit palette + 4-bit palette index + priority for current sprite line uint8_t *linebuf; - //stores 12-bit color + shadow/highlight bits - void *framebuf; - void *oddbuf; - void *evenbuf; + //pointer to current line in framebuffer + uint32_t *output; uint16_t cram[CRAM_SIZE]; uint32_t colors[CRAM_SIZE*3]; uint32_t debugcolors[1 << (3 + 1 + 1 + 1)];//3 bits for source, 1 bit for priority, 1 bit for shadow, 1 bit for hilight uint16_t vsram[VSRAM_SIZE]; uint16_t vscroll_latch[2]; + uint32_t output_pitch; uint32_t frame; uint16_t vcounter; uint16_t hscroll_a; @@ -155,6 +155,7 @@ uint8_t latched_mode; uint8_t sprite_index; uint8_t sprite_draws; + uint8_t h40_lines; int8_t slot_counter; int8_t cur_slot; sprite_draw sprite_draw_list[MAX_DRAWS];