summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2018-11-04 22:51:50 -0800
committerMichael Pavone <pavone@retrodev.com>2018-11-04 22:51:50 -0800
commit85dbe449fe94f8cb4d4b88eaa4acbbba2d52b153 (patch)
tree2c9fbfad84c55198c8aa50b9d1ea0d3d26ea7e45
parent09884a02e3877fe74c0d2845acdca115d316f3be (diff)
WIP new VDP plane debug view and support for detached VDP debug views generally
-rw-r--r--bindings.c20
-rw-r--r--default.cfg1
-rw-r--r--genesis.c5
-rw-r--r--render.h4
-rwxr-xr-xrender_sdl.c55
-rw-r--r--vdp.c145
-rw-r--r--vdp.h15
7 files changed, 239 insertions, 6 deletions
diff --git a/bindings.c b/bindings.c
index 6b45800..8ab1b61 100644
--- a/bindings.c
+++ b/bindings.c
@@ -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 @@ typedef enum {
UI_RELOAD,
UI_SMS_PAUSE,
UI_SCREENSHOT,
- UI_EXIT
+ UI_EXIT,
+ UI_PLANE_DEBUG
} ui_action;
typedef struct {
@@ -372,6 +374,20 @@ void handle_binding_up(keybinding * binding)
}
#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 @@ int parse_binding_target(int device_num, char * target, tern_node * padbuttons,
*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 --git a/default.cfg b/default.cfg
index c9ed2bf..d20d4df 100644
--- a/default.cfg
+++ b/default.cfg
@@ -19,6 +19,7 @@ bindings {
] 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 --git a/genesis.c b/genesis.c
index 7f2b103..0a614dc 100644
--- a/genesis.c
+++ b/genesis.c
@@ -1126,10 +1126,7 @@ static void resume_genesis(system_header *system)
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 --git a/render.h b/render.h
index e59e0ab..8625ad5 100644
--- a/render.h
+++ b/render.h
@@ -68,6 +68,7 @@
#define FRAMEBUFFER_ODD 0
#define FRAMEBUFFER_EVEN 1
+#define FRAMEBUFFER_USER_START 2
#include "vdp.h"
@@ -88,8 +89,11 @@ typedef void (*drop_handler)(const char *filename);
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 --git a/render_sdl.c b/render_sdl.c
index 7175e23..05a0948 100755
--- a/render_sdl.c
+++ b/render_sdl.c
@@ -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 @@ void window_setup(void)
}
}
}
+ 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 @@ void render_save_screenshot(char *path)
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 @@ void render_framebuffer_updated(uint8_t which, int width)
}
#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 @@ uint8_t render_has_gl(void)
{
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 --git a/vdp.c b/vdp.c
index b09861d..1283b99 100644
--- a/vdp.c
+++ b/vdp.c
@@ -1720,6 +1720,109 @@ static void vdp_advance_line(vdp_context *context)
}
}
+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 @@ void vdp_force_update_framebuffer(vdp_context *context)
);
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 @@ static void advance_output_line(vdp_context *context)
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 @@ void vdp_deserialize(deserialize_buffer *buf, void *vcontext)
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 --git a/vdp.h b/vdp.h
index fa3cdc3..ed5230f 100644
--- a/vdp.h
+++ b/vdp.h
@@ -147,6 +147,14 @@ typedef struct {
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 @@ typedef struct {
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_reacquire_framebuffer(vdp_context *context);
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_