# HG changeset patch # User Michael Pavone # Date 1541400710 28800 # Node ID c4ba3177b72d8a169fdb3f3518b1637c64920756 # Parent 5aa0c3c43b979a3cd1e128512410829313611b30 WIP new VDP plane debug view and support for detached VDP debug views generally diff -r 5aa0c3c43b97 -r c4ba3177b72d bindings.c --- a/bindings.c Sun Nov 04 11:45:41 2018 -0800 +++ b/bindings.c Sun Nov 04 22:51:50 2018 -0800 @@ -6,6 +6,7 @@ #include "saves.h" #include "util.h" #include "genesis.h" +#include "sms.h" #include "menu.h" #include "bindings.h" #include "controller_info.h" @@ -35,7 +36,8 @@ UI_RELOAD, UI_SMS_PAUSE, UI_SCREENSHOT, - UI_EXIT + UI_EXIT, + UI_PLANE_DEBUG } ui_action; typedef struct { @@ -372,6 +374,20 @@ } #endif break; + case UI_PLANE_DEBUG: { + vdp_context *vdp = NULL; + if (current_system->type == SYSTEM_GENESIS) { + genesis_context *gen = (genesis_context *)current_system; + vdp = gen->vdp; + } else if (current_system->type == SYSTEM_SMS) { + sms_context *sms = (sms_context *)current_system; + vdp = sms->vdp; + } + if (vdp) { + vdp_toggle_debug_view(vdp, VDP_DEBUG_PLANE); + } + break; + } } break; } @@ -575,6 +591,8 @@ *subtype_a = UI_SCREENSHOT; } else if(!strcmp(target + 3, "exit")) { *subtype_a = UI_EXIT; + } else if (!strcmp(target + 3, "plane_debug")) { + *subtype_a = UI_PLANE_DEBUG; } else { warning("Unreconized UI binding type %s\n", target); return 0; diff -r 5aa0c3c43b97 -r c4ba3177b72d default.cfg --- a/default.cfg Sun Nov 04 11:45:41 2018 -0800 +++ b/default.cfg Sun Nov 04 22:51:50 2018 -0800 @@ -19,6 +19,7 @@ ] ui.vdp_debug_pal u ui.enter_debugger p ui.screenshot + b ui.plane_debug esc ui.exit ` ui.save_state 0 ui.set_speed.0 diff -r 5aa0c3c43b97 -r c4ba3177b72d genesis.c --- a/genesis.c Sun Nov 04 11:45:41 2018 -0800 +++ b/genesis.c Sun Nov 04 22:51:50 2018 -0800 @@ -1126,10 +1126,7 @@ static void inc_debug_mode(system_header *system) { genesis_context *gen = (genesis_context *)system; - gen->vdp->debug++; - if (gen->vdp->debug == 7) { - gen->vdp->debug = 0; - } + vdp_inc_debug_mode(gen->vdp); } static void inc_debug_pal(system_header *system) diff -r 5aa0c3c43b97 -r c4ba3177b72d render.h --- a/render.h Sun Nov 04 11:45:41 2018 -0800 +++ b/render.h Sun Nov 04 22:51:50 2018 -0800 @@ -68,6 +68,7 @@ #define FRAMEBUFFER_ODD 0 #define FRAMEBUFFER_EVEN 1 +#define FRAMEBUFFER_USER_START 2 #include "vdp.h" @@ -88,8 +89,11 @@ uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b); void render_save_screenshot(char *path); +uint8_t render_create_window(char *caption, uint32_t width, uint32_t height); uint32_t *render_get_framebuffer(uint8_t which, int *pitch); void render_framebuffer_updated(uint8_t which, int width); +//returns the framebuffer index associated with the Window that has focus +uint8_t render_get_active_framebuffer(void); void render_init(int width, int height, char * title, uint8_t fullscreen); void render_set_video_standard(vid_std std); void render_toggle_fullscreen(); diff -r 5aa0c3c43b97 -r c4ba3177b72d render_sdl.c --- a/render_sdl.c Sun Nov 04 11:45:41 2018 -0800 +++ b/render_sdl.c Sun Nov 04 22:51:50 2018 -0800 @@ -25,7 +25,9 @@ #define MAX_EVENT_POLL_PER_FRAME 2 static SDL_Window *main_window; +static SDL_Window **extra_windows; static SDL_Renderer *main_renderer; +static SDL_Renderer **extra_renderers; static SDL_Texture **sdl_textures; static uint8_t num_textures; static SDL_Rect main_clip; @@ -1035,6 +1037,7 @@ } } } + render_gl = 0; #ifndef DISABLE_OPENGL char *gl_enabled_str = tern_find_path_default(config, "video\0gl\0", def, TVAL_PTR).ptrval; @@ -1323,6 +1326,37 @@ screenshot_path = path; } +uint8_t render_create_window(char *caption, uint32_t width, uint32_t height) +{ + num_textures++; + sdl_textures = realloc(sdl_textures, num_textures * sizeof(*sdl_textures)); + extra_windows = realloc(extra_windows, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_windows)); + extra_renderers = realloc(extra_renderers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_renderers)); + uint8_t win_idx = num_textures - FRAMEBUFFER_USER_START - 1; + extra_windows[win_idx] = SDL_CreateWindow(caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0); + if (!extra_windows[win_idx]) { + goto fail_window; + } + extra_renderers[win_idx] = SDL_CreateRenderer(extra_windows[win_idx], -1, SDL_RENDERER_ACCELERATED); + if (!extra_renderers[win_idx]) { + goto fail_renderer; + } + uint8_t texture_idx = num_textures-1; + sdl_textures[texture_idx] = SDL_CreateTexture(extra_renderers[win_idx], SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); + if (!sdl_textures[texture_idx]) { + goto fail_texture; + } + return texture_idx; + +fail_texture: + SDL_DestroyRenderer(extra_renderers[win_idx]); +fail_renderer: + SDL_DestroyWindow(extra_windows[win_idx]); +fail_window: + num_textures--; + return 0; +} + uint32_t *locked_pixels; uint32_t locked_pitch; uint32_t *render_get_framebuffer(uint8_t which, int *pitch) @@ -1467,7 +1501,12 @@ } #endif last_height = height; - render_update_display(); + if (which <= FRAMEBUFFER_EVEN) { + render_update_display(); + } else { + SDL_RenderCopy(extra_renderers[which - FRAMEBUFFER_USER_START], sdl_textures[which], NULL, NULL); + SDL_RenderPresent(extra_renderers[which - FRAMEBUFFER_USER_START]); + } if (screenshot_file) { fclose(screenshot_file); } @@ -1835,3 +1874,17 @@ { return render_gl; } + +uint8_t render_get_active_framebuffer(void) +{ + if (SDL_GetWindowFlags(main_window) & SDL_WINDOW_INPUT_FOCUS) { + return FRAMEBUFFER_ODD; + } + for (int i = 0; i < num_textures - 2; i++) + { + if (extra_windows[i] && (SDL_GetWindowFlags(extra_windows[i]) & SDL_WINDOW_INPUT_FOCUS)) { + return FRAMEBUFFER_USER_START + i; + } + } + return 0xFF; +} diff -r 5aa0c3c43b97 -r c4ba3177b72d vdp.c --- a/vdp.c Sun Nov 04 11:45:41 2018 -0800 +++ b/vdp.c Sun Nov 04 22:51:50 2018 -0800 @@ -1720,6 +1720,109 @@ } } +static void vdp_update_per_frame_debug(vdp_context *context) +{ + if (context->enabled_debuggers & (1 << VDP_DEBUG_PLANE)) { + uint32_t pitch; + uint32_t *fb = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_PLANE], &pitch); + uint16_t hscroll_mask; + uint16_t v_mul; + uint16_t vscroll_mask = 0x1F | (context->regs[REG_SCROLL] & 0x30) << 1; + switch(context->regs[REG_SCROLL] & 0x3) + { + case 0: + hscroll_mask = 0x1F; + v_mul = 64; + break; + case 0x1: + hscroll_mask = 0x3F; + v_mul = 128; + break; + case 0x2: + //TODO: Verify this behavior + hscroll_mask = 0x1F; + v_mul = 0; + break; + case 0x3: + hscroll_mask = 0x7F; + v_mul = 256; + break; + } + uint16_t table_address; + switch(context->debug_modes[VDP_DEBUG_PLANE] % 3) + { + case 0: + table_address = context->regs[REG_SCROLL_A] << 10 & 0xE000; + break; + case 1: + table_address = context->regs[REG_SCROLL_B] << 13 & 0xE000; + break; + case 2: + table_address = context->regs[REG_WINDOW] << 10; + if (context->regs[REG_MODE_4] & BIT_H40) { + table_address &= 0xF000; + v_mul = 128; + hscroll_mask = 0x3F; + } else { + table_address &= 0xF800; + v_mul = 64; + hscroll_mask = 0x1F; + } + vscroll_mask = 0x1F; + break; + } + uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR & 0x3F]]; + for (uint16_t row = 0; row < 128; row++) + { + uint16_t row_address = table_address + (row & vscroll_mask) * v_mul; + for (uint16_t col = 0; col < 128; col++) + { + uint16_t address = row_address + (col & hscroll_mask) * 2; + //pccv hnnn nnnn nnnn + // + uint16_t entry = context->vdpmem[address] << 8 | context->vdpmem[address + 1]; + uint8_t pal = entry >> 9 & 0x30; + + uint32_t *dst = fb + (row * pitch * 8 / sizeof(uint32_t)) + col * 8; + address = (entry & 0x7FF) * 32; + int y_diff = 4; + if (entry & 0x1000) { + y_diff = -4; + address += 7 * 4; + } + int x_diff = 1; + if (entry & 0x800) { + x_diff = -1; + address += 3; + } + for (int y = 0; y < 8; y++) + { + uint16_t trow_address = address; + uint32_t *row_dst = dst; + for (int x = 0; x < 4; x++) + { + uint8_t byte = context->vdpmem[trow_address]; + trow_address += x_diff; + uint8_t left, right; + if (x_diff > 0) { + left = byte >> 4; + right = byte & 0xF; + } else { + left = byte & 0xF; + right = byte >> 4; + } + *(row_dst++) = left ? context->colors[left|pal] : bg_color; + *(row_dst++) = right ? context->colors[right|pal] : bg_color; + } + address += y_diff; + dst += pitch / sizeof(uint32_t); + } + } + } + render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_PLANE], 1024); + } +} + void vdp_force_update_framebuffer(vdp_context *context) { uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL) @@ -1734,6 +1837,7 @@ ); render_framebuffer_updated(context->cur_buffer, context->h40_lines > context->output_lines / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); + vdp_update_per_frame_debug(context); } static void advance_output_line(vdp_context *context) @@ -1752,6 +1856,7 @@ render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); context->cur_buffer = context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD; context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); + vdp_update_per_frame_debug(context); context->h40_lines = 0; context->frame++; context->output_lines = 0; @@ -3740,3 +3845,43 @@ context->pending_hint_start = load_int32(buf); update_video_params(context); } + +void vdp_toggle_debug_view(vdp_context *context, uint8_t debug_type) +{ + if (context->enabled_debuggers & 1 << debug_type) { + //TODO: implement me + } else { + char *caption; + switch(debug_type) + { + case VDP_DEBUG_PLANE: + caption = "BlastEm - VDP Plane Debugger"; + break; + default: + return; + } + context->debug_fb_indices[debug_type] = render_create_window(caption, 1024, 1024); + if (context->debug_fb_indices[debug_type]) { + context->enabled_debuggers |= 1 << debug_type; + } + } +} + +void vdp_inc_debug_mode(vdp_context *context) +{ + uint8_t active = render_get_active_framebuffer(); + if (active < FRAMEBUFFER_USER_START) { + context->debug++; + if (context->debug == 7) { + context->debug = 0; + } + return; + } + for (int i = 0; i < VDP_NUM_DEBUG_TYPES; i++) + { + if (context->enabled_debuggers & (1 << i) && context->debug_fb_indices[i] == active) { + context->debug_modes[i]++; + return; + } + } +} diff -r 5aa0c3c43b97 -r c4ba3177b72d vdp.h --- a/vdp.h Sun Nov 04 11:45:41 2018 -0800 +++ b/vdp.h Sun Nov 04 22:51:50 2018 -0800 @@ -147,6 +147,14 @@ uint8_t partial; } fifo_entry; +enum { + VDP_DEBUG_PLANE, + VDP_DEBUG_VRAM, + VDP_DEBUG_CRAM, + VDP_DEBUG_COMPOSITE, + VDP_NUM_DEBUG_TYPES +}; + typedef struct { fifo_entry fifo[FIFO_SIZE]; int32_t fifo_write; @@ -212,8 +220,13 @@ uint8_t cur_buffer; uint8_t *tmp_buf_a; uint8_t *tmp_buf_b; + uint8_t enabled_debuggers; + uint8_t debug_fb_indices[VDP_NUM_DEBUG_TYPES]; + uint8_t debug_modes[VDP_NUM_DEBUG_TYPES]; } vdp_context; + + void init_vdp_context(vdp_context * context, uint8_t region_pal); void vdp_free(vdp_context *context); void vdp_run_context_full(vdp_context * context, uint32_t target_cycles); @@ -253,5 +266,7 @@ void vdp_serialize(vdp_context *context, serialize_buffer *buf); void vdp_deserialize(deserialize_buffer *buf, void *vcontext); void vdp_force_update_framebuffer(vdp_context *context); +void vdp_toggle_debug_view(vdp_context *context, uint8_t debug_type); +void vdp_inc_debug_mode(vdp_context *context); #endif //VDP_H_