Mercurial > repos > blastem
comparison vdp.c @ 1881:55198fc9cc1f
Don't render lines that are cropped by overscan. Allows submitting frame earlier when bottom overscan is non-zero which can reduce latency in some cases
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 16 Sep 2019 00:45:48 -0700 |
parents | 881083d76212 |
children | b5549258b98b |
comparison
equal
deleted
inserted
replaced
1880:e77f7a7c79a5 | 1881:55198fc9cc1f |
---|---|
68 {127, 0, 0}, //Window | 68 {127, 0, 0}, //Window |
69 {0, 127, 0}, //B | 69 {0, 127, 0}, //B |
70 {127, 0, 127} //Sprites | 70 {127, 0, 127} //Sprites |
71 }; | 71 }; |
72 | 72 |
73 static uint32_t calc_crop(uint32_t crop, uint32_t border) | |
74 { | |
75 return crop >= border ? 0 : border - crop; | |
76 } | |
77 | |
73 static void update_video_params(vdp_context *context) | 78 static void update_video_params(vdp_context *context) |
74 { | 79 { |
80 uint32_t top_crop = render_overscan_top(); | |
81 uint32_t bot_crop = render_overscan_bot(); | |
82 uint32_t border_top; | |
75 if (context->regs[REG_MODE_2] & BIT_MODE_5) { | 83 if (context->regs[REG_MODE_2] & BIT_MODE_5) { |
76 if (context->regs[REG_MODE_2] & BIT_PAL) { | 84 if (context->regs[REG_MODE_2] & BIT_PAL) { |
77 if (context->flags2 & FLAG2_REGION_PAL) { | 85 if (context->flags2 & FLAG2_REGION_PAL) { |
78 context->inactive_start = PAL_INACTIVE_START; | 86 context->inactive_start = PAL_INACTIVE_START; |
79 context->border_top = BORDER_TOP_V30_PAL; | 87 border_top = BORDER_TOP_V30_PAL; |
80 context->border_bot = BORDER_BOT_V30_PAL; | 88 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V30_PAL); |
81 } else { | 89 } else { |
82 //the behavior here is rather weird and needs more investigation | 90 //the behavior here is rather weird and needs more investigation |
83 context->inactive_start = 0xF0; | 91 context->inactive_start = 0xF0; |
84 context->border_top = 1; | 92 border_top = 1; |
85 context->border_bot = 3; | 93 context->border_bot = calc_crop(bot_crop, 3); |
86 } | 94 } |
87 } else { | 95 } else { |
88 context->inactive_start = NTSC_INACTIVE_START; | 96 context->inactive_start = NTSC_INACTIVE_START; |
89 if (context->flags2 & FLAG2_REGION_PAL) { | 97 if (context->flags2 & FLAG2_REGION_PAL) { |
90 context->border_top = BORDER_TOP_V28_PAL; | 98 border_top = BORDER_TOP_V28_PAL; |
91 context->border_bot = BORDER_BOT_V28_PAL; | 99 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V28_PAL); |
92 } else { | 100 } else { |
93 context->border_top = BORDER_TOP_V28; | 101 border_top = BORDER_TOP_V28; |
94 context->border_bot = BORDER_TOP_V28; | 102 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V28); |
95 } | 103 } |
96 } | 104 } |
97 if (context->regs[REG_MODE_4] & BIT_H40) { | 105 if (context->regs[REG_MODE_4] & BIT_H40) { |
98 context->max_sprites_frame = MAX_SPRITES_FRAME; | 106 context->max_sprites_frame = MAX_SPRITES_FRAME; |
99 context->max_sprites_line = MAX_SPRITES_LINE; | 107 context->max_sprites_line = MAX_SPRITES_LINE; |
110 } | 118 } |
111 } | 119 } |
112 } else { | 120 } else { |
113 context->inactive_start = MODE4_INACTIVE_START; | 121 context->inactive_start = MODE4_INACTIVE_START; |
114 if (context->flags2 & FLAG2_REGION_PAL) { | 122 if (context->flags2 & FLAG2_REGION_PAL) { |
115 context->border_top = BORDER_TOP_V24_PAL; | 123 border_top = BORDER_TOP_V24_PAL; |
116 context->border_bot = BORDER_BOT_V24_PAL; | 124 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V24_PAL); |
117 } else { | 125 } else { |
118 context->border_top = BORDER_TOP_V24; | 126 border_top = BORDER_TOP_V24; |
119 context->border_bot = BORDER_BOT_V24; | 127 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V24); |
120 } | 128 } |
121 if (!(context->regs[REG_MODE_1] & BIT_MODE_4)){ | 129 if (!(context->regs[REG_MODE_1] & BIT_MODE_4)){ |
122 context->state = INACTIVE; | 130 context->state = INACTIVE; |
123 } else if (context->state == INACTIVE) { | 131 } else if (context->state == INACTIVE) { |
124 //Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active | 132 //Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active |
128 else if (context->vcounter == 0x1FF) { | 136 else if (context->vcounter == 0x1FF) { |
129 context->state = PREPARING; | 137 context->state = PREPARING; |
130 } | 138 } |
131 } | 139 } |
132 } | 140 } |
141 context->border_top = calc_crop(top_crop, border_top); | |
142 context->top_offset = border_top - context->border_top; | |
133 } | 143 } |
134 | 144 |
135 static uint8_t color_map_init_done; | 145 static uint8_t color_map_init_done; |
136 | 146 |
137 vdp_context *init_vdp_context(uint8_t region_pal) | 147 vdp_context *init_vdp_context(uint8_t region_pal) |
138 { | 148 { |
139 vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE); | 149 vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE); |
140 if (headless) { | 150 if (headless) { |
141 context->output = malloc(LINEBUF_SIZE * sizeof(uint32_t)); | 151 context->fb = malloc(512 * LINEBUF_SIZE * sizeof(uint32_t)); |
142 context->output_pitch = 0; | 152 context->output_pitch = LINEBUF_SIZE * sizeof(uint32_t); |
143 } else { | 153 } else { |
144 context->cur_buffer = FRAMEBUFFER_ODD; | 154 context->cur_buffer = FRAMEBUFFER_ODD; |
145 context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch); | 155 context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch); |
146 } | 156 } |
147 context->sprite_draws = MAX_SPRITES_LINE; | 157 context->sprite_draws = MAX_SPRITES_LINE; |
233 } | 243 } |
234 if (region_pal) { | 244 if (region_pal) { |
235 context->flags2 |= FLAG2_REGION_PAL; | 245 context->flags2 |= FLAG2_REGION_PAL; |
236 } | 246 } |
237 update_video_params(context); | 247 update_video_params(context); |
238 if (!headless) { | 248 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * context->border_top); |
239 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * context->border_top); | |
240 } | |
241 return context; | 249 return context; |
242 } | 250 } |
243 | 251 |
244 void vdp_free(vdp_context *context) | 252 void vdp_free(vdp_context *context) |
245 { | 253 { |
2016 } | 2024 } |
2017 } | 2025 } |
2018 | 2026 |
2019 void vdp_force_update_framebuffer(vdp_context *context) | 2027 void vdp_force_update_framebuffer(vdp_context *context) |
2020 { | 2028 { |
2021 uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL) | 2029 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top; |
2022 ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL | |
2023 : 224 + BORDER_TOP_V28 + BORDER_BOT_V28; | |
2024 | 2030 |
2025 uint16_t to_fill = lines_max - context->output_lines; | 2031 uint16_t to_fill = lines_max - context->output_lines; |
2026 memset( | 2032 memset( |
2027 ((char *)context->fb) + context->output_pitch * context->output_lines, | 2033 ((char *)context->fb) + context->output_pitch * context->output_lines, |
2028 0, | 2034 0, |
2033 vdp_update_per_frame_debug(context); | 2039 vdp_update_per_frame_debug(context); |
2034 } | 2040 } |
2035 | 2041 |
2036 static void advance_output_line(vdp_context *context) | 2042 static void advance_output_line(vdp_context *context) |
2037 { | 2043 { |
2038 if (headless) { | 2044 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top; |
2039 if (context->vcounter == context->inactive_start) { | 2045 |
2040 context->frame++; | 2046 if (context->output_lines == lines_max) { |
2041 } | 2047 if (!headless) { |
2042 context->vcounter &= 0x1FF; | |
2043 } else { | |
2044 uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL) | |
2045 ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL | |
2046 : 224 + BORDER_TOP_V28 + BORDER_BOT_V28; | |
2047 | |
2048 if (context->output_lines == lines_max) { | |
2049 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); | 2048 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); |
2050 context->cur_buffer = context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD; | 2049 context->cur_buffer = context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD; |
2051 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); | 2050 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); |
2052 vdp_update_per_frame_debug(context); | 2051 } |
2053 context->h40_lines = 0; | 2052 vdp_update_per_frame_debug(context); |
2054 context->frame++; | 2053 context->h40_lines = 0; |
2054 context->frame++; | |
2055 context->output_lines = 0; | |
2056 } | |
2057 uint32_t output_line = context->vcounter; | |
2058 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { | |
2059 //vcounter increment occurs much later in Mode 4 | |
2060 output_line++; | |
2061 } | |
2062 if (output_line < context->inactive_start + context->border_bot && context->output_lines > 0) { | |
2063 output_line = context->output_lines++;//context->border_top + context->vcounter; | |
2064 } else if (output_line >= 0x200 - context->border_top || (!context->border_top && !output_line)) { | |
2065 if (output_line == 0x200 - context->border_top || (!context->border_top && !output_line)) { | |
2066 //We're at the top of the display, force context->output_lines to be zero to avoid | |
2067 //potential screen rolling if the mode is changed at an inopportune time | |
2055 context->output_lines = 0; | 2068 context->output_lines = 0; |
2056 } | 2069 } |
2057 uint32_t output_line = context->vcounter; | 2070 output_line = context->output_lines++;//context->vcounter - (0x200 - context->border_top); |
2058 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { | 2071 } else { |
2059 //vcounter increment occurs much later in Mode 4 | 2072 context->output = NULL; |
2060 output_line++; | 2073 return; |
2061 } | 2074 } |
2062 if (output_line < context->inactive_start + context->border_bot && context->output_lines > 0) { | 2075 output_line += context->top_offset; |
2063 output_line = context->output_lines++;//context->border_top + context->vcounter; | 2076 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line); |
2064 } else if (output_line >= 0x200 - context->border_top) { | |
2065 if (output_line == 0x200 - context->border_top) { | |
2066 //We're at the top of the display, force context->output_lines to be zero to avoid | |
2067 //potential screen rolling if the mode is changed at an inopportune time | |
2068 context->output_lines = 0; | |
2069 } | |
2070 output_line = context->output_lines++;//context->vcounter - (0x200 - context->border_top); | |
2071 } else { | |
2072 context->output = NULL; | |
2073 } | |
2074 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line); | |
2075 #ifdef DEBUG_FB_FILL | 2077 #ifdef DEBUG_FB_FILL |
2076 for (int i = 0; i < LINEBUF_SIZE; i++) | 2078 for (int i = 0; i < LINEBUF_SIZE; i++) |
2077 { | 2079 { |
2078 context->output[i] = 0xFFFF00FF; | 2080 context->output[i] = 0xFFFF00FF; |
2079 } | 2081 } |
2080 #endif | 2082 #endif |
2081 if (context->output && (context->regs[REG_MODE_4] & BIT_H40)) { | 2083 if (context->output && (context->regs[REG_MODE_4] & BIT_H40)) { |
2082 context->h40_lines++; | 2084 context->h40_lines++; |
2083 } | |
2084 } | 2085 } |
2085 } | 2086 } |
2086 | 2087 |
2087 void vdp_release_framebuffer(vdp_context *context) | 2088 void vdp_release_framebuffer(vdp_context *context) |
2088 { | 2089 { |
2091 } | 2092 } |
2092 | 2093 |
2093 void vdp_reacquire_framebuffer(vdp_context *context) | 2094 void vdp_reacquire_framebuffer(vdp_context *context) |
2094 { | 2095 { |
2095 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); | 2096 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); |
2096 uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL) | 2097 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top; |
2097 ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL | |
2098 : 224 + BORDER_TOP_V28 + BORDER_BOT_V28; | |
2099 if (context->output_lines <= lines_max && context->output_lines > 0) { | 2098 if (context->output_lines <= lines_max && context->output_lines > 0) { |
2100 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * (context->output_lines - 1)); | 2099 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * (context->output_lines - 1 + context->top_offset)); |
2101 } else { | 2100 } else { |
2102 context->output = NULL; | 2101 context->output = NULL; |
2103 } | 2102 } |
2104 } | 2103 } |
2105 | 2104 |