mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-06-24 11:29:33 +00:00
Refactor all drawing to run on video thread in one scanner pass
- Moves extra work off CPU/audio thread - Prepares the way to possibly remove the vestigal intermediate indexed framebuffer and do direct RGBA_8888 writes to XImage or OpenGL texture - Prepares the ground for possible better emulation of video scanner hardware Conflicts: src/display.c src/video/glvideo.c src/video/video.h
This commit is contained in:
parent
bd9b38cd65
commit
829291feba
|
@ -31,8 +31,6 @@ void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetColor(JNIEnv *env, jc
|
|||
color_mode = color;
|
||||
|
||||
video_reset();
|
||||
video_setpage(!!(softswitches & SS_SCREEN));
|
||||
video_redraw();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -216,8 +216,6 @@
|
|||
|
||||
#warning HACK TODO FIXME need to refactor video resetting procedure
|
||||
video_reset();
|
||||
video_setpage(!!(softswitches & SS_SCREEN));
|
||||
video_redraw();
|
||||
}
|
||||
|
||||
- (IBAction)soundCardChoiceChanged:(id)sender
|
||||
|
|
550
src/display.c
550
src/display.c
|
@ -21,14 +21,19 @@
|
|||
|
||||
#define DYNAMIC_SZ 11 // 7 pixels (as bytes) + 2pre + 2post
|
||||
|
||||
typedef enum drawpage_mode_t {
|
||||
DRAWPAGE_TEXT = 1,
|
||||
DRAWPAGE_HIRES,
|
||||
} drawpage_mode_t;
|
||||
|
||||
// framebuffers
|
||||
static uint8_t vga_mem_page_0[SCANWIDTH*SCANHEIGHT] = { 0 };
|
||||
static uint8_t vga_mem_page_1[SCANWIDTH*SCANHEIGHT] = { 0 };
|
||||
static uint8_t *video__fb = NULL;
|
||||
|
||||
A2Color_s colormap[256] = { { 0 } };
|
||||
video_animation_s *video_animations = NULL;
|
||||
video_backend_s *video_backend = NULL;
|
||||
static pthread_t render_thread_id = 0;
|
||||
static pthread_mutex_t video_scan_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static uint8_t video__wider_font[0x8000] = { 0 };
|
||||
static uint8_t video__font[0x4000] = { 0 };
|
||||
|
@ -38,13 +43,10 @@ static uint8_t video__int_font[3][0x4000] = { { 0 } }; // interface font
|
|||
unsigned int video__screen_addresses[8192] = { INT_MIN };
|
||||
uint8_t video__columns[8192] = { 0 };
|
||||
|
||||
uint8_t *video__fb1 = NULL;
|
||||
uint8_t *video__fb2 = NULL;
|
||||
|
||||
uint8_t video__hires_even[0x800] = { 0 };
|
||||
uint8_t video__hires_odd[0x800] = { 0 };
|
||||
|
||||
int video__current_page = 0; // current visual page
|
||||
volatile unsigned long _vid_dirty = 0;
|
||||
|
||||
// Video constants -- sourced from AppleWin
|
||||
static const bool bVideoScannerNTSC = true;
|
||||
|
@ -475,6 +477,7 @@ static void _initialize_color() {
|
|||
void video_reset(void) {
|
||||
_initialize_hires_values();
|
||||
_initialize_tables_video();
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
void video_loadfont(int first, int quantity, const uint8_t *data, int mode) {
|
||||
|
@ -578,7 +581,7 @@ static inline void _plot_char80(uint8_t **d, uint8_t **s, const unsigned int fb_
|
|||
*d += fb_width-6, *s += 2;
|
||||
}
|
||||
|
||||
static inline void _plot_lores(uint8_t **d, const uint32_t val) {
|
||||
static inline void _plot_lores40(uint8_t **d, const uint32_t val) {
|
||||
*((uint32_t *)(*d)) = val;
|
||||
*d += 4;
|
||||
*((uint32_t *)(*d)) = val;
|
||||
|
@ -596,7 +599,7 @@ static inline void _plot_lores(uint8_t **d, const uint32_t val) {
|
|||
*((uint16_t *)(*d)) = (uint16_t)(val & 0xffff);
|
||||
}
|
||||
|
||||
static inline void _plot_dlores(uint8_t **d, const uint32_t val) {
|
||||
static inline void _plot_lores80(uint8_t **d, const uint32_t val) {
|
||||
*((uint32_t *)(*d)) = val;
|
||||
*d += 4;
|
||||
*((uint16_t *)(*d)) = (uint16_t)val;
|
||||
|
@ -610,8 +613,7 @@ static inline void _plot_dlores(uint8_t **d, const uint32_t val) {
|
|||
*((uint8_t *)(*d)) = (uint8_t)val;
|
||||
}
|
||||
|
||||
static inline void _plot_character(const unsigned int font_off, uint8_t *fb_ptr) {
|
||||
video_setDirty();
|
||||
static inline void __plot_character40(const unsigned int font_off, uint8_t *fb_ptr) {
|
||||
uint8_t *font_ptr = video__wider_font+font_off;
|
||||
_plot_char40(/*dst*/&fb_ptr, /*src*/&font_ptr);
|
||||
_plot_char40(/*dst*/&fb_ptr, /*src*/&font_ptr);
|
||||
|
@ -623,16 +625,14 @@ static inline void _plot_character(const unsigned int font_off, uint8_t *fb_ptr)
|
|||
_plot_char40(/*dst*/&fb_ptr, /*src*/&font_ptr);
|
||||
}
|
||||
|
||||
static void _plot_character0(uint16_t ea, uint8_t b) {
|
||||
_plot_character(b<<7/* *128 */, video__fb1+video__screen_addresses[ea-0x0400]);
|
||||
static void _plot_character40(uint16_t off, int page, int bank) {
|
||||
uint16_t base = page ? 0x0800 : 0x0400;
|
||||
uint16_t ea = base+off;
|
||||
uint8_t b = apple_ii_64k[bank][ea];
|
||||
__plot_character40(b<<7/* *128 */, video__fb+video__screen_addresses[off]);
|
||||
}
|
||||
|
||||
static void _plot_character1(uint16_t ea, uint8_t b) {
|
||||
_plot_character(b<<7/* *128 */, video__fb2+video__screen_addresses[ea-0x0800]);
|
||||
}
|
||||
|
||||
static inline void _plot_80character(const unsigned int font_off, uint8_t *fb_ptr) {
|
||||
video_setDirty();
|
||||
static inline void __plot_character80(const unsigned int font_off, uint8_t *fb_ptr) {
|
||||
uint8_t *font_ptr = video__font+font_off;
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr, SCANWIDTH);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr, SCANWIDTH);
|
||||
|
@ -644,186 +644,168 @@ static inline void _plot_80character(const unsigned int font_off, uint8_t *fb_pt
|
|||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr, SCANWIDTH);
|
||||
}
|
||||
|
||||
// FIXME TODO NOTE : dup'ing work here?
|
||||
static void _plot_80character0(uint16_t ea, uint8_t b) {
|
||||
b = apple_ii_64k[1][ea];
|
||||
_plot_80character(b<<6/* *64 */, video__fb1+video__screen_addresses[ea-0x0400]);
|
||||
b = apple_ii_64k[0][ea];
|
||||
_plot_80character(b<<6/* *64 */, video__fb1+video__screen_addresses[ea-0x0400]+7);
|
||||
static void _plot_character80(uint16_t off, int page, int bank) {
|
||||
uint16_t base = page ? 0x0800 : 0x0400;
|
||||
uint16_t ea = base+off;
|
||||
{
|
||||
uint8_t b = apple_ii_64k[1][ea];
|
||||
__plot_character80(b<<6/* *64 */, video__fb+video__screen_addresses[off]);
|
||||
}
|
||||
{
|
||||
uint8_t b = apple_ii_64k[0][ea];
|
||||
__plot_character80(b<<6/* *64 */, video__fb+video__screen_addresses[off]+7);
|
||||
}
|
||||
}
|
||||
|
||||
static void _plot_80character1(uint16_t ea, uint8_t b) {
|
||||
b = apple_ii_64k[1][ea];
|
||||
_plot_80character(b<<6/* *64 */, video__fb2+video__screen_addresses[ea-0x0800]);
|
||||
b = apple_ii_64k[0][ea];
|
||||
_plot_80character(b<<6/* *64 */, video__fb2+video__screen_addresses[ea-0x0800]+7);
|
||||
}
|
||||
|
||||
static inline void _plot_block(const uint8_t val, uint8_t *fb_ptr) {
|
||||
video_setDirty();
|
||||
static inline void __plot_block40(const uint8_t val, uint8_t *fb_ptr) {
|
||||
uint8_t color = (val & 0x0F) << 4;
|
||||
uint32_t val32 = (color << 24) | (color << 16) | (color << 8) | color;
|
||||
|
||||
_plot_lores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores40(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANSTEP;
|
||||
_plot_lores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores40(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANSTEP;
|
||||
_plot_lores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores40(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANSTEP;
|
||||
_plot_lores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores40(/*dst*/&fb_ptr, val32);
|
||||
|
||||
fb_ptr += SCANSTEP;
|
||||
color = val & 0xF0;
|
||||
val32 = (color << 24) | (color << 16) | (color << 8) | color;
|
||||
|
||||
_plot_lores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores40(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANSTEP;
|
||||
_plot_lores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores40(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANSTEP;
|
||||
_plot_lores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores40(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANSTEP;
|
||||
_plot_lores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores40(/*dst*/&fb_ptr, val32);
|
||||
}
|
||||
|
||||
/* plot lores block first page */
|
||||
static inline void _plot_block0(uint16_t ea, uint8_t b)
|
||||
{
|
||||
_plot_block(b, video__fb1+video__screen_addresses[ea-0x0400]);
|
||||
static void _plot_block40(uint16_t off, int page, int bank) {
|
||||
uint16_t base = page ? 0x0800 : 0x0400;
|
||||
uint16_t ea = base+off;
|
||||
uint8_t b = apple_ii_64k[bank][ea];
|
||||
__plot_block40(b, video__fb+video__screen_addresses[off]);
|
||||
}
|
||||
|
||||
static inline void _plot_block1(uint16_t ea, uint8_t b)
|
||||
{
|
||||
_plot_block(b, video__fb2+video__screen_addresses[ea-0x0800]);
|
||||
}
|
||||
|
||||
static inline void _plot_dblock(const uint8_t val, uint8_t *fb_ptr) {
|
||||
static inline void __plot_block80(const uint8_t val, uint8_t *fb_ptr) {
|
||||
uint8_t color = (val & 0x0F) << 4;
|
||||
uint32_t val32 = (color << 24) | (color << 16) | (color << 8) | color;
|
||||
|
||||
_plot_dlores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores80(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANDSTEP;
|
||||
_plot_dlores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores80(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANDSTEP;
|
||||
_plot_dlores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores80(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANDSTEP;
|
||||
_plot_dlores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores80(/*dst*/&fb_ptr, val32);
|
||||
|
||||
fb_ptr += SCANDSTEP;
|
||||
color = val & 0xF0;
|
||||
val32 = (color << 24) | (color << 16) | (color << 8) | color;
|
||||
|
||||
_plot_dlores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores80(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANDSTEP;
|
||||
_plot_dlores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores80(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANDSTEP;
|
||||
_plot_dlores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores80(/*dst*/&fb_ptr, val32);
|
||||
fb_ptr += SCANDSTEP;
|
||||
_plot_dlores(/*dst*/&fb_ptr, val32);
|
||||
_plot_lores80(/*dst*/&fb_ptr, val32);
|
||||
}
|
||||
|
||||
/* plot double-lores block first page */
|
||||
static inline void _plot_dblock0(uint16_t ea, uint8_t b, bool odd) {
|
||||
uint8_t *fb = video__fb1+video__screen_addresses[ea-0x0400] + (odd ? 7 : 0);
|
||||
_plot_dblock(b, fb);
|
||||
static inline uint8_t __shift_block80(uint8_t b) {
|
||||
// plot even half-block from auxmem, rotate nybbles to match color (according to UTAIIe: 8-29)
|
||||
uint8_t b0 = (b & 0x0F);
|
||||
uint8_t b1 = (b & 0xF0) >> 4;
|
||||
uint8_t rot0 = ((b0 & 0x8) >> 3);
|
||||
uint8_t rot1 = ((b1 & 0x8) >> 3);
|
||||
b0 = (((b0<<5) | (rot0<<4)) >> 4);
|
||||
b1 = ((b1<<5) | (rot1<<4));
|
||||
b = b0 | b1;
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline void _plot_dblock1(uint16_t ea, uint8_t b, bool odd) {
|
||||
uint8_t *fb = video__fb2+video__screen_addresses[ea-0x0800] + (odd ? 7 : 0);
|
||||
_plot_dblock(b, fb);
|
||||
static void _plot_block80(uint16_t off, int page, int bank) {
|
||||
uint16_t base = page ? 0x0800 : 0x0400;
|
||||
uint16_t ea = base+off;
|
||||
|
||||
#warning FIXME TODO INVESTIGATE : ... does RAMRD/80STORE/PAGE2 affect load order here?
|
||||
|
||||
// plot even half-block from auxmem, rotate nybbles to match color (according to UTAIIe)
|
||||
{
|
||||
uint8_t b = apple_ii_64k[1][ea];
|
||||
b = __shift_block80(b);
|
||||
uint8_t *fb = video__fb+video__screen_addresses[off];
|
||||
__plot_block80(b, fb);
|
||||
}
|
||||
|
||||
// plot odd half-block from main mem
|
||||
{
|
||||
uint8_t b = apple_ii_64k[0][ea];
|
||||
uint8_t *fb = video__fb+video__screen_addresses[off] + 7;
|
||||
__plot_block80(b, fb);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _draw_text(uint16_t ea, uint8_t b, int page, uint32_t sw, uint32_t flags) {
|
||||
if (softswitches & flags) {
|
||||
if (softswitches & SS_80COL) {
|
||||
void (*plot80Fn)(uint16_t, uint8_t) = !page ? _plot_80character0 : _plot_80character1;
|
||||
plot80Fn(ea,b);
|
||||
} else if (softswitches & sw) {
|
||||
/* ??? */
|
||||
} else {
|
||||
void (*plotCharFn)(uint16_t, uint8_t) = !page ? _plot_character0 : _plot_character1;
|
||||
plotCharFn(ea, b);
|
||||
}
|
||||
static void (*_textpage_plotter(uint32_t currswitches, uint32_t txtflags))(uint16_t, int, int) {
|
||||
void (*plotFn)(uint16_t, int, int) = NULL;
|
||||
|
||||
if (currswitches & txtflags) {
|
||||
plotFn = (currswitches & SS_80COL) ? _plot_character80 : _plot_character40;
|
||||
} else {
|
||||
if (softswitches & (SS_HIRES|sw)) {
|
||||
/* ??? */
|
||||
} else {
|
||||
if (!(softswitches & SS_80COL)) {
|
||||
void (*plotBlockFn)(uint16_t, uint8_t) = !page ? _plot_block0 : _plot_block1;
|
||||
if (!(softswitches & SS_DHIRES)) {
|
||||
// LORES40 ...
|
||||
plotBlockFn(ea, b);
|
||||
} else {
|
||||
// TODO : abnormal LORES output. See UTAIIe : 8-28
|
||||
plotBlockFn(ea, b);
|
||||
}
|
||||
assert(!(currswitches & SS_HIRES) && "must be lores graphics or programmer error");
|
||||
if (!(currswitches & SS_80COL)) {
|
||||
plotFn = _plot_block40;
|
||||
if (!(currswitches & SS_DHIRES)) {
|
||||
// LORES40 ...
|
||||
} else {
|
||||
if (softswitches & SS_DHIRES) {
|
||||
// LORES80 ...
|
||||
void (*plotBlockFn)(uint16_t, uint8_t, bool) = !page ? _plot_dblock0 : _plot_dblock1;
|
||||
|
||||
// plot even half-block from auxmem, rotate nybbles to match color (according to UTAIIe)
|
||||
b = apple_ii_64k[1][ea];
|
||||
uint8_t b0 = (b & 0x0F);
|
||||
uint8_t b1 = (b & 0xF0) >> 4;
|
||||
uint8_t rot0 = ((b0 & 0x8) >> 3);
|
||||
uint8_t rot1 = ((b1 & 0x8) >> 3);
|
||||
b0 = (((b0<<5) | (rot0<<4)) >> 4);
|
||||
b1 = ((b1<<5) | (rot1<<4));
|
||||
b = b0 | b1;
|
||||
plotBlockFn(ea, b, false);
|
||||
|
||||
// plot odd half-block from main mem
|
||||
b = apple_ii_64k[0][ea];
|
||||
plotBlockFn(ea, b, true);
|
||||
|
||||
video_setDirty();
|
||||
} else {
|
||||
/* ??? */
|
||||
void (*plotBlockFn)(uint16_t, uint8_t) = !page ? _plot_block0 : _plot_block1;
|
||||
plotBlockFn(ea, b);
|
||||
}
|
||||
// TODO : abnormal LORES output. See UTAIIe : 8-28
|
||||
}
|
||||
} else {
|
||||
if (currswitches & SS_DHIRES) {
|
||||
// LORES80 ...
|
||||
plotFn = _plot_block80;
|
||||
} else {
|
||||
/* ??? */
|
||||
RELEASE_LOG("!!!!!!!!!!!! what mode is this? !!!!!!!!!!!!");
|
||||
plotFn = _plot_block40;
|
||||
#warning FIXME TODO ... verify this lores40/lores80 mode ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return plotFn;
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_text0)
|
||||
{
|
||||
base_textwrt[ea] = b;
|
||||
if (!(softswitches & SS_PAGE2)) {
|
||||
_draw_text(ea, b, 0, SS_TEXTWRT, SS_TEXT);
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_text0_mixed)
|
||||
{
|
||||
base_textwrt[ea] = b;
|
||||
if (!(softswitches & SS_PAGE2)) {
|
||||
_draw_text(ea, b, 0, SS_TEXTWRT, (SS_TEXT|SS_MIXED));
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_text1)
|
||||
{
|
||||
base_ramwrt[ea] = b;
|
||||
if (softswitches & SS_PAGE2) {
|
||||
_draw_text(ea, b, 1, SS_RAMWRT, SS_TEXT);
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_text1_mixed)
|
||||
{
|
||||
base_ramwrt[ea] = b;
|
||||
if (softswitches & SS_PAGE2) {
|
||||
_draw_text(ea, b, 1, SS_RAMWRT, (SS_TEXT|SS_MIXED));
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Classic interface and printing HUD messages
|
||||
|
||||
void interface_plotChar(uint8_t *fboff, int fb_pix_width, interface_colorscheme_t cs, uint8_t c) {
|
||||
video_setDirty();
|
||||
uint8_t *src = video__int_font[cs] + c * (FONT_GLYPH_X*FONT_GLYPH_Y);
|
||||
_plot_char80(&fboff, &src, fb_pix_width);
|
||||
_plot_char80(&fboff, &src, fb_pix_width);
|
||||
|
@ -836,10 +818,9 @@ void interface_plotChar(uint8_t *fboff, int fb_pix_width, interface_colorscheme_
|
|||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Double-Hires GRaphics
|
||||
// Double-HIRES (HIRES80) graphics
|
||||
|
||||
// PlotDHiresByte
|
||||
static inline void _plot_dhires_pixels(uint8_t idx, uint8_t *fb_ptr) {
|
||||
static inline void __plot_hires80_pixels(uint8_t idx, uint8_t *fb_ptr) {
|
||||
uint8_t b1 = video__dhires1[idx];
|
||||
uint8_t b2 = video__dhires2[idx];
|
||||
uint32_t b = (b2<<24) | (b1<<8);
|
||||
|
@ -847,13 +828,11 @@ static inline void _plot_dhires_pixels(uint8_t idx, uint8_t *fb_ptr) {
|
|||
*((uint32_t *)(fb_ptr+SCANWIDTH)) = b;
|
||||
}
|
||||
|
||||
// PlotDHires
|
||||
static inline void _plot_dhires(uint16_t base, uint16_t ea, uint8_t *fb_base) {
|
||||
video_setDirty();
|
||||
static inline void __plot_hires80(uint16_t base, uint16_t ea) {
|
||||
ea &= ~0x1;
|
||||
|
||||
uint16_t memoff = ea - base;
|
||||
uint8_t *fb_ptr = fb_base+video__screen_addresses[memoff];
|
||||
uint8_t *fb_ptr = video__fb+video__screen_addresses[memoff];
|
||||
uint8_t col = video__columns[memoff];
|
||||
|
||||
uint8_t b0 = 0x0;
|
||||
|
@ -867,7 +846,7 @@ static inline void _plot_dhires(uint16_t base, uint16_t ea, uint8_t *fb_base) {
|
|||
b0 &= ~0x80;
|
||||
b0 = (b1<<4)|(b0>>3);
|
||||
|
||||
_plot_dhires_pixels(b0, fb_ptr-4);
|
||||
__plot_hires80_pixels(b0, fb_ptr-4);
|
||||
}
|
||||
|
||||
b1 = apple_ii_64k[1][ea+2];
|
||||
|
@ -891,45 +870,42 @@ static inline void _plot_dhires(uint16_t base, uint16_t ea, uint8_t *fb_base) {
|
|||
|
||||
// 00000001 11111122 22222333 3333xxxx
|
||||
|
||||
_plot_dhires_pixels(b, fb_ptr);
|
||||
__plot_hires80_pixels(b, fb_ptr);
|
||||
|
||||
b >>= 4;
|
||||
fb_ptr += 4;
|
||||
_plot_dhires_pixels(b, fb_ptr);
|
||||
__plot_hires80_pixels(b, fb_ptr);
|
||||
|
||||
b >>= 4;
|
||||
fb_ptr += 4;
|
||||
_plot_dhires_pixels(b, fb_ptr);
|
||||
__plot_hires80_pixels(b, fb_ptr);
|
||||
|
||||
b >>= 4;
|
||||
fb_ptr += 4;
|
||||
_plot_dhires_pixels(b, fb_ptr);
|
||||
__plot_hires80_pixels(b, fb_ptr);
|
||||
|
||||
b >>= 4;
|
||||
fb_ptr += 4;
|
||||
_plot_dhires_pixels(b, fb_ptr);
|
||||
__plot_hires80_pixels(b, fb_ptr);
|
||||
|
||||
b >>= 4;
|
||||
fb_ptr += 4;
|
||||
_plot_dhires_pixels(b, fb_ptr);
|
||||
__plot_hires80_pixels(b, fb_ptr);
|
||||
|
||||
b >>= 4;
|
||||
fb_ptr += 4;
|
||||
_plot_dhires_pixels(b, fb_ptr);
|
||||
__plot_hires80_pixels(b, fb_ptr);
|
||||
}
|
||||
|
||||
static inline void iie_plot_dhires0(uint16_t ea) {
|
||||
_plot_dhires(0x2000, ea, video__fb1);
|
||||
}
|
||||
|
||||
static inline void iie_plot_dhires1(uint16_t ea) {
|
||||
_plot_dhires(0x4000, ea, video__fb2);
|
||||
static void _plot_hires80(uint16_t off, int page, int bank, bool is_even) {
|
||||
uint16_t base = page ? 0x4000 : 0x2000;
|
||||
uint16_t ea = base+off;
|
||||
__plot_hires80(base, ea);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Hires GRaphics
|
||||
|
||||
// CalculateInterpColor
|
||||
static inline void _calculate_interp_color(uint8_t *color_buf, const unsigned int idx, const uint8_t *interp_base, const uint16_t ea) {
|
||||
if (color_buf[idx] != 0x0) {
|
||||
return;
|
||||
|
@ -956,7 +932,6 @@ static inline void _calculate_interp_color(uint8_t *color_buf, const unsigned in
|
|||
}
|
||||
}
|
||||
|
||||
// PlotPixelsExtra
|
||||
static inline void _plot_hires_pixels(uint8_t *dst, const uint8_t *src) {
|
||||
for (unsigned int i=2; i; i--) {
|
||||
for (unsigned int j=DYNAMIC_SZ-1; j; j--) {
|
||||
|
@ -972,12 +947,16 @@ static inline void _plot_hires_pixels(uint8_t *dst, const uint8_t *src) {
|
|||
}
|
||||
}
|
||||
|
||||
// PlotByte
|
||||
static inline void _plot_hires(uint16_t ea, uint8_t b, bool is_even, uint8_t *fb_ptr) {
|
||||
static void _plot_hires40(uint16_t off, int page, int bank, bool is_even) {
|
||||
uint16_t base = page ? 0x4000 : 0x2000;
|
||||
uint16_t ea = base+off;
|
||||
uint8_t b = apple_ii_64k[bank][ea];
|
||||
|
||||
uint8_t *fb_ptr = video__fb+video__screen_addresses[off];
|
||||
|
||||
uint8_t _buf[DYNAMIC_SZ] = { 0 };
|
||||
uint8_t *color_buf = (uint8_t *)_buf; // <--- work around for -Wstrict-aliasing
|
||||
uint8_t *apple2_vmem = (uint8_t *)apple_ii_64k[0];
|
||||
uint8_t *apple2_vmem = (uint8_t *)apple_ii_64k[bank];
|
||||
|
||||
uint8_t *hires_ptr = NULL;
|
||||
if (is_even) {
|
||||
|
@ -1051,100 +1030,56 @@ static inline void _plot_hires(uint16_t ea, uint8_t b, bool is_even, uint8_t *fb
|
|||
_plot_hires_pixels(fb_ptr-4, color_buf);
|
||||
}
|
||||
|
||||
// DRAW_GRAPHICS
|
||||
static inline void _draw_hires_graphics(uint16_t ea, uint8_t b, bool is_even, uint8_t page, unsigned int ss_textflags) {
|
||||
if (softswitches & ss_textflags) {
|
||||
return;
|
||||
}
|
||||
if (!(softswitches & SS_HIRES)) {
|
||||
return;
|
||||
}
|
||||
if ((softswitches & SS_80COL) && (softswitches & SS_DHIRES)) {
|
||||
if (page) {
|
||||
iie_plot_dhires1(ea);
|
||||
} else {
|
||||
iie_plot_dhires0(ea);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (softswitches & SS_HGRWRT) {
|
||||
return;
|
||||
}
|
||||
|
||||
video_setDirty();
|
||||
uint16_t off = ea - 0x2000;
|
||||
uint8_t *fb_base = NULL;
|
||||
if (page) {
|
||||
off -= 0x2000;
|
||||
fb_base = video__fb2;
|
||||
} else {
|
||||
fb_base = video__fb1;
|
||||
}
|
||||
_plot_hires(ea, b, is_even, fb_base+video__screen_addresses[off]);
|
||||
static void (*_hirespage_plotter(uint32_t currswitches))(uint16_t, int, int, bool) {
|
||||
return ((currswitches & SS_80COL) && (currswitches & SS_DHIRES)) ? _plot_hires80 : _plot_hires40;
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_even0)
|
||||
{
|
||||
base_hgrwrt[ea] = b;
|
||||
if (!(softswitches & SS_PAGE2)) {
|
||||
_draw_hires_graphics(ea, b, /*even*/true, 0, SS_TEXT);
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_even0_mixed)
|
||||
{
|
||||
base_hgrwrt[ea] = b;
|
||||
if (!(softswitches & SS_PAGE2)) {
|
||||
_draw_hires_graphics(ea, b, /*even*/true, 0, (SS_TEXT|SS_MIXED));
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_odd0)
|
||||
{
|
||||
base_hgrwrt[ea] = b;
|
||||
if (!(softswitches & SS_PAGE2)) {
|
||||
_draw_hires_graphics(ea, b, /*even*/false, 0, SS_TEXT);
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_odd0_mixed)
|
||||
{
|
||||
base_hgrwrt[ea] = b;
|
||||
if (!(softswitches & SS_PAGE2)) {
|
||||
_draw_hires_graphics(ea, b, /*even*/false, 0, (SS_TEXT|SS_MIXED));
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_even1)
|
||||
{
|
||||
base_ramwrt[ea] = b;
|
||||
if (softswitches & SS_PAGE2) {
|
||||
_draw_hires_graphics(ea, b, /*even*/true, 1, SS_TEXT);
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_even1_mixed)
|
||||
{
|
||||
base_ramwrt[ea] = b;
|
||||
if (softswitches & SS_PAGE2) {
|
||||
_draw_hires_graphics(ea, b, /*even*/true, 1, (SS_TEXT|SS_MIXED));
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_odd1)
|
||||
{
|
||||
base_ramwrt[ea] = b;
|
||||
if (softswitches & SS_PAGE2) {
|
||||
_draw_hires_graphics(ea, b, /*even*/false, 1, SS_TEXT);
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
GLUE_C_WRITE(video__write_2e_odd1_mixed)
|
||||
{
|
||||
base_ramwrt[ea] = b;
|
||||
if (softswitches & SS_PAGE2) {
|
||||
_draw_hires_graphics(ea, b, /*even*/false, 1, (SS_TEXT|SS_MIXED));
|
||||
}
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -1154,17 +1089,15 @@ void video_init(void) {
|
|||
LOG("(re)setting render_thread_id : %ld -> %ld", render_thread_id, pthread_self());
|
||||
render_thread_id = pthread_self();
|
||||
|
||||
video__fb1 = vga_mem_page_0;
|
||||
video__fb2 = vga_mem_page_1;
|
||||
|
||||
// reset Apple2 softframebuffers
|
||||
memset(video__fb1,0,SCANWIDTH*SCANHEIGHT);
|
||||
memset(video__fb2,0,SCANWIDTH*SCANHEIGHT);
|
||||
assert(!video__fb);
|
||||
video__fb = MALLOC(SCANWIDTH*SCANHEIGHT*sizeof(uint8_t));
|
||||
video_clear();
|
||||
|
||||
video_backend->init((void*)0);
|
||||
}
|
||||
|
||||
void _video_setRenderThread(pthread_t id) {
|
||||
LOG("setting render_thread_id : %ld -> %ld", render_thread_id, id);
|
||||
render_thread_id = id;
|
||||
}
|
||||
|
||||
|
@ -1178,6 +1111,7 @@ void video_shutdown(bool emulatorShuttingDown) {
|
|||
|
||||
video_backend->shutdown(emulatorShuttingDown);
|
||||
render_thread_id = 0;
|
||||
FREE(video__fb);
|
||||
}
|
||||
|
||||
void video_reshape(int w, int h, bool landscape) {
|
||||
|
@ -1193,19 +1127,9 @@ void video_main_loop(void) {
|
|||
video_backend->main_loop();
|
||||
}
|
||||
|
||||
void video_setpage(int p) {
|
||||
video_setDirty();
|
||||
video__current_page = p;
|
||||
}
|
||||
|
||||
const uint8_t * const video_current_framebuffer(void) {
|
||||
return !video__current_page ? video__fb1 : video__fb2;
|
||||
}
|
||||
|
||||
void video_clear(void) {
|
||||
uint8_t *current_fb = (uint8_t *)video_current_framebuffer();
|
||||
memset(current_fb, 0x0, sizeof(uint8_t)*SCANWIDTH*SCANHEIGHT);
|
||||
video_setDirty();
|
||||
memset(video__fb, 0x0, sizeof(uint8_t)*SCANWIDTH*SCANHEIGHT);
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
bool video_saveState(StateHelper_s *helper) {
|
||||
|
@ -1214,12 +1138,10 @@ bool video_saveState(StateHelper_s *helper) {
|
|||
|
||||
do {
|
||||
uint8_t state = 0x0;
|
||||
|
||||
state = (uint8_t)video__current_page;
|
||||
if (!helper->save(fd, &state, 1)) {
|
||||
break;
|
||||
}
|
||||
LOG("SAVE video__current_page = %02x", state);
|
||||
LOG("SAVE (no-op) video__current_page = %02x", state);
|
||||
|
||||
saved = true;
|
||||
} while (0);
|
||||
|
@ -1237,70 +1159,132 @@ bool video_loadState(StateHelper_s *helper) {
|
|||
if (!helper->load(fd, &state, 1)) {
|
||||
break;
|
||||
}
|
||||
video__current_page = state;
|
||||
LOG("LOAD video__current_page = %02x", video__current_page);
|
||||
LOG("LOAD (no-op) video__current_page = %02x", state);
|
||||
|
||||
loaded = true;
|
||||
} while (0);
|
||||
|
||||
video_redraw();
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
void video_redraw(void) {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// temporarily reset softswitches
|
||||
uint32_t softswitches_save = softswitches;
|
||||
softswitches &= ~(SS_TEXTWRT|SS_HGRWRT|SS_RAMWRT);
|
||||
static inline drawpage_mode_t _currentMainMode(uint32_t currswitches) {
|
||||
if (currswitches & SS_TEXT) {
|
||||
return DRAWPAGE_TEXT;
|
||||
} else {
|
||||
if (currswitches & SS_HIRES) {
|
||||
return DRAWPAGE_HIRES;
|
||||
} else {
|
||||
return DRAWPAGE_TEXT; // (LORES)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int y = 0; y < TEXT_ROWS; y++) {
|
||||
for (unsigned int x = 0; x < TEXT_COLS; x++) {
|
||||
uint16_t ea = video__line_offset[y] + x + 0x400;
|
||||
uint8_t b = apple_ii_64k[0][ea];
|
||||
static inline drawpage_mode_t _currentMixedMode(uint32_t currswitches) {
|
||||
if (currswitches & (SS_TEXT|SS_MIXED)) {
|
||||
return DRAWPAGE_TEXT;
|
||||
} else {
|
||||
if (currswitches & SS_HIRES) {
|
||||
return DRAWPAGE_HIRES;
|
||||
} else {
|
||||
return DRAWPAGE_TEXT; // (LORES)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// text/lores pages
|
||||
if (y < 20) {
|
||||
_draw_text(ea, b, 0, SS_TEXTWRT, SS_TEXT);
|
||||
ea += 0x400;
|
||||
b = apple_ii_64k[0][ea];
|
||||
_draw_text(ea, b, 1, SS_RAMWRT, SS_TEXT);
|
||||
} else {
|
||||
_draw_text(ea, b, 0, SS_TEXTWRT, (SS_TEXT|SS_MIXED));
|
||||
ea += 0x400;
|
||||
b = apple_ii_64k[0][ea];
|
||||
_draw_text(ea, b, 1, SS_RAMWRT, (SS_TEXT|SS_MIXED));
|
||||
static inline void _currentPageAndBank(uint32_t currswitches, drawpage_mode_t mode, OUTPARM int *page, OUTPARM int *bank) {
|
||||
// UTAIIe : 5-25
|
||||
if (currswitches & SS_80STORE) {
|
||||
*page = 0;
|
||||
//*bank = !!(currswitches & SS_PAGE2);
|
||||
*bank = 0;
|
||||
if (mode != DRAWPAGE_TEXT) {
|
||||
assert(currswitches & SS_HIRES);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
*page = !!(currswitches & SS_PAGE2);
|
||||
//*bank = !!(currswitches & SS_RAMRD);
|
||||
*bank = 0;
|
||||
}
|
||||
|
||||
uint8_t *video_currentFramebuffer(void) {
|
||||
return video__fb;
|
||||
}
|
||||
|
||||
uint8_t *video_scan(void) {
|
||||
|
||||
#warning FIXME TODO ... this needs to scan memory in the same way as the actually //e video scanner
|
||||
|
||||
pthread_mutex_lock(&video_scan_mutex);
|
||||
|
||||
int page = 0;
|
||||
int bank = 0;
|
||||
const uint32_t mainswitches = softswitches;
|
||||
|
||||
// render main portion of screen ...
|
||||
|
||||
drawpage_mode_t mainDrawPageMode = _currentMainMode(mainswitches);
|
||||
_currentPageAndBank(mainswitches, mainDrawPageMode, &page, &bank);
|
||||
|
||||
if (mainDrawPageMode == DRAWPAGE_TEXT) {
|
||||
void (*textMainPlotFn)(uint16_t, int, int) = _textpage_plotter(mainswitches, SS_TEXT);
|
||||
for (unsigned int y=0; y < TEXT_ROWS-4; y++) {
|
||||
for (unsigned int x=0; x < TEXT_COLS; x++) {
|
||||
uint16_t off = video__line_offset[y] + x;
|
||||
textMainPlotFn(off, page, bank);
|
||||
}
|
||||
|
||||
// hires/dhires pages
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
uint16_t ea0 = 0x2000 + video__line_offset[y] + (0x400*i) + x;
|
||||
uint16_t ea1 = ea0+0x2000;
|
||||
uint8_t b0 = apple_ii_64k[0][ea0];
|
||||
uint8_t b1 = apple_ii_64k[0][ea1];
|
||||
if (y < 20) {
|
||||
if (x & 1) {
|
||||
_draw_hires_graphics(ea0, b0, /*even*/false, 0, SS_TEXT);
|
||||
_draw_hires_graphics(ea1, b1, /*even*/false, 1, SS_TEXT);
|
||||
} else {
|
||||
_draw_hires_graphics(ea0, b0, /*even*/true, 0, SS_TEXT);
|
||||
_draw_hires_graphics(ea1, b1, /*even*/true, 1, SS_TEXT);
|
||||
}
|
||||
} else {
|
||||
if (x & 1) {
|
||||
_draw_hires_graphics(ea0, b0, /*even*/false, 0, (SS_TEXT|SS_MIXED));
|
||||
_draw_hires_graphics(ea1, b1, /*even*/false, 1, (SS_TEXT|SS_MIXED));
|
||||
} else {
|
||||
_draw_hires_graphics(ea0, b0, /*even*/true, 0, (SS_TEXT|SS_MIXED));
|
||||
_draw_hires_graphics(ea1, b1, /*even*/true, 1, (SS_TEXT|SS_MIXED));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert(!(mainswitches & SS_TEXT) && "TEXT should not be set");
|
||||
assert((mainswitches & SS_HIRES) && "HIRES should be set");
|
||||
void (*hiresMainPlotFn)(uint16_t, int, int, bool) = _hirespage_plotter(mainswitches);
|
||||
for (unsigned int y=0; y < TEXT_ROWS-4; y++) {
|
||||
for (unsigned int x=0; x < TEXT_COLS; x++) {
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
uint16_t off = video__line_offset[y] + (0x400*i) + x;
|
||||
hiresMainPlotFn(off, page, bank, /*even*/!(x & 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
softswitches = softswitches_save;
|
||||
video_setDirty();
|
||||
// resample current switches ... and render mixed portion of screen
|
||||
const uint32_t mixedswitches = softswitches;
|
||||
|
||||
drawpage_mode_t mixedDrawPageMode = _currentMixedMode(mixedswitches);
|
||||
_currentPageAndBank(mixedswitches, mixedDrawPageMode, &page, &bank);
|
||||
|
||||
if (mixedDrawPageMode == DRAWPAGE_TEXT) {
|
||||
void (*textMixedPlotFn)(uint16_t, int, int) = _textpage_plotter(mixedswitches, (SS_TEXT|SS_MIXED));
|
||||
for (unsigned int y=TEXT_ROWS-4; y < TEXT_ROWS; y++) {
|
||||
for (unsigned int x=0; x < TEXT_COLS; x++) {
|
||||
uint16_t off = video__line_offset[y] + x;
|
||||
textMixedPlotFn(off, page, bank);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//assert(!(mixedswitches & SS_TEXT) && "TEXT should not be set"); // TEXT may have been reset from last sample?
|
||||
assert(!(mixedswitches & SS_MIXED) && "MIXED should not be set");
|
||||
assert((mixedswitches & SS_HIRES) && "HIRES should be set");
|
||||
void (*hiresMixedPlotFn)(uint16_t, int, int, bool) = _hirespage_plotter(mixedswitches);
|
||||
for (unsigned int y=TEXT_ROWS-4; y < TEXT_ROWS; y++) {
|
||||
for (unsigned int x=0; x < TEXT_COLS; x++) {
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
uint16_t off = video__line_offset[y] + (0x400*i) + x;
|
||||
hiresMixedPlotFn(off, page, bank, /*even*/!(x & 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
video_setDirty(FB_DIRTY_FLAG);
|
||||
|
||||
pthread_mutex_unlock(&video_scan_mutex);
|
||||
|
||||
return video__fb;
|
||||
}
|
||||
|
||||
void video_flashText(void) {
|
||||
|
@ -1328,10 +1312,22 @@ void video_flashText(void) {
|
|||
colormap[ COLOR_FLASHING_WHITE].blue = 0;
|
||||
}
|
||||
|
||||
video_setDirty();
|
||||
video_setDirty(FB_DIRTY_FLAG);
|
||||
}
|
||||
}
|
||||
|
||||
bool video_isDirty(int flags) {
|
||||
return (_vid_dirty & flags);
|
||||
}
|
||||
|
||||
unsigned long video_setDirty(flags) {
|
||||
return __sync_fetch_and_or(&_vid_dirty, flags);
|
||||
}
|
||||
|
||||
unsigned long video_clearDirty(flags) {
|
||||
return __sync_fetch_and_and(&_vid_dirty, ~flags);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// VBL/timing routines
|
||||
|
||||
|
|
|
@ -104,11 +104,15 @@ void video_reset(void);
|
|||
void video_loadfont(int first, int qty, const uint8_t *data, int mode);
|
||||
|
||||
/*
|
||||
* Redraw the display. This is called after exiting an interface display,
|
||||
* when changes have been made to the Apple's emulated framebuffer that
|
||||
* bypass the driver's hooks, or when the video mode has changed.
|
||||
* Flushes currently set Apple //e video memory into staging framebuffer and returns pointer.
|
||||
* This should only really be called from render thread or testsuite.
|
||||
*/
|
||||
void video_redraw(void);
|
||||
uint8_t *video_scan(void);
|
||||
|
||||
/*
|
||||
* Get a reference to current staging framebuffer
|
||||
*/
|
||||
uint8_t *video_currentFramebuffer(void);
|
||||
|
||||
/*
|
||||
* Toggles FLASHing text between NORMAL and INVERSE character sets.
|
||||
|
@ -120,41 +124,23 @@ void video_flashText(void);
|
|||
*/
|
||||
void video_clear(void);
|
||||
|
||||
/*
|
||||
* Change the displayed video page to PAGE
|
||||
* 0 - Page 1: $400-$7ff/$2000-$3fff
|
||||
* 1 - Page 2: $800-$bff/$4000-$5fff
|
||||
*/
|
||||
void video_setpage(int page);
|
||||
#define A2_DIRTY_FLAG 0x1 // Apple //e video is dirty
|
||||
#define FB_DIRTY_FLAG 0x2 // Internal framebuffer is dirty
|
||||
|
||||
/*
|
||||
* Get a reference to current internal framebuffer
|
||||
* True if dirty bit(s) are set for flag(s)
|
||||
*/
|
||||
const uint8_t * const video_current_framebuffer();
|
||||
|
||||
// do not access directly, but through inline accessor methods
|
||||
extern volatile unsigned long _backend_vid_dirty;
|
||||
bool video_isDirty(int flags);
|
||||
|
||||
/*
|
||||
* True if anything changed in framebuffer and not yet drawn
|
||||
* Atomically set dirty bit(s), return previous bit(s) value
|
||||
*/
|
||||
static inline bool video_isDirty(void) {
|
||||
return _backend_vid_dirty;
|
||||
}
|
||||
unsigned long video_setDirty(int flags);
|
||||
|
||||
/*
|
||||
* Atomically set dirty bit, return previous value
|
||||
* Atomically clear dirty bit(s), return previous bit(s) value
|
||||
*/
|
||||
static inline unsigned long video_setDirty(void) {
|
||||
return __sync_fetch_and_or(&_backend_vid_dirty, 1UL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Atomically clear dirty bit, return previous value
|
||||
*/
|
||||
static inline unsigned long video_clearDirty(void) {
|
||||
return __sync_fetch_and_and(&_backend_vid_dirty, 0UL);
|
||||
}
|
||||
unsigned long video_clearDirty(int flags);
|
||||
|
||||
extern bool video_saveState(StateHelper_s *helper);
|
||||
extern bool video_loadState(StateHelper_s *helper);
|
||||
|
@ -275,17 +261,6 @@ uint8_t floating_bus_hibit(const bool hibit);
|
|||
generic graphics globals
|
||||
---------------------------------- */
|
||||
|
||||
/*
|
||||
* Pointers to framebuffer (can be VGA memory or host buffer)
|
||||
*/
|
||||
extern uint8_t *video__fb1;
|
||||
extern uint8_t *video__fb2;
|
||||
|
||||
/*
|
||||
* Current visual page
|
||||
*/
|
||||
extern READONLY int video__current_page;
|
||||
|
||||
/*
|
||||
* font glyph data
|
||||
*/
|
||||
|
|
|
@ -165,7 +165,8 @@ static int altdrive = 0;
|
|||
|
||||
void video_plotchar(const int col, const int row, const interface_colorscheme_t cs, const uint8_t c) {
|
||||
unsigned int off = row * SCANWIDTH * FONT_HEIGHT_PIXELS + col * FONT80_WIDTH_PIXELS + _INTERPOLATED_PIXEL_ADJUSTMENT_PRE;
|
||||
interface_plotChar(video__fb1+off, SCANWIDTH, cs, c);
|
||||
interface_plotChar(video_currentFramebuffer()+off, SCANWIDTH, cs, c);
|
||||
video_setDirty(FB_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
void copy_and_pad_string(char *dest, const char* src, const char c, const int len, const char cap) {
|
||||
|
@ -198,7 +199,8 @@ static void pad_string(char *s, const char c, const int len) {
|
|||
}
|
||||
|
||||
void c_interface_print( int x, int y, const interface_colorscheme_t cs, const char *s ) {
|
||||
_interface_plotLine(video__fb1, SCANWIDTH, _INTERPOLATED_PIXEL_ADJUSTMENT_PRE, x, y, cs, s);
|
||||
_interface_plotLine(video_currentFramebuffer(), SCANWIDTH, _INTERPOLATED_PIXEL_ADJUSTMENT_PRE, x, y, cs, s);
|
||||
video_setDirty(FB_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
|
@ -219,7 +221,8 @@ void c_interface_translate_screen( char screen[24][INTERFACE_SCREEN_X+1] ) {
|
|||
}
|
||||
|
||||
void c_interface_print_submenu_centered( char *submenu, const int message_cols, const int message_rows ) {
|
||||
_interface_plotMessageCentered(video__fb1, INTERFACE_SCREEN_X, TEXT_ROWS, RED_ON_BLACK, submenu, message_cols, message_rows);
|
||||
_interface_plotMessageCentered(video_currentFramebuffer(), INTERFACE_SCREEN_X, TEXT_ROWS, RED_ON_BLACK, submenu, message_cols, message_rows);
|
||||
video_setDirty(FB_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
@ -303,8 +306,7 @@ void c_interface_exit(int ch)
|
|||
}
|
||||
else
|
||||
{
|
||||
video_setpage(!!(softswitches & SS_SCREEN));
|
||||
video_redraw();
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -374,8 +376,6 @@ void c_interface_select_diskette( int drive )
|
|||
|
||||
screen[ 1 ][ DRIVE_X ] = (drive == 0) ? 'A' : 'B';
|
||||
|
||||
video_setpage( 0 );
|
||||
|
||||
c_interface_translate_screen( screen );
|
||||
|
||||
do {
|
||||
|
@ -757,7 +757,6 @@ void c_interface_parameters()
|
|||
|
||||
/* reset the x position, so we don't lose our cursor if path changes */
|
||||
cur_x = 0;
|
||||
video_setpage( 0 );
|
||||
|
||||
screen[ 2 ][ 33 ] = MOUSETEXT_OPENAPPLE;
|
||||
screen[ 2 ][ 46 ] = MOUSETEXT_CLOSEDAPPLE;
|
||||
|
@ -1416,8 +1415,6 @@ void c_interface_credits()
|
|||
" ",
|
||||
" " };
|
||||
|
||||
video_setpage( 0 );
|
||||
|
||||
c_interface_translate_screen( screen );
|
||||
c_interface_translate_screen_x_y( credits[0], SCROLL_WIDTH, SCROLL_LENGTH);
|
||||
c_interface_print_screen( screen );
|
||||
|
@ -1506,8 +1503,6 @@ void c_interface_keyboard_layout()
|
|||
"| (Press any key to exit) |",
|
||||
"||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" };
|
||||
|
||||
video_setpage( 0 );
|
||||
|
||||
screen[ 6 ][ 68 ] = MOUSETEXT_UP;
|
||||
screen[ 7 ][ 67 ] = MOUSETEXT_LEFT;
|
||||
screen[ 7 ][ 69 ] = MOUSETEXT_RIGHT;
|
||||
|
|
|
@ -978,7 +978,6 @@ void show_opcode_breakpts() {
|
|||
------------------------------------------------------------------------- */
|
||||
void show_lc_info() {
|
||||
int i = num_buffer_lines;
|
||||
#warning FIXME TODO ... investigate/refactor all uses of !! here and elsewhere
|
||||
sprintf(second_buf[i++], "lc bank = %d", 1 + !!(softswitches & SS_BANK2));
|
||||
(softswitches & SS_LCWRT) ? sprintf(second_buf[i++], "write LC") : sprintf(second_buf[i++], "LC write protected");
|
||||
(softswitches & SS_LCRAM) ? sprintf(second_buf[i++], "read LC") : sprintf(second_buf[i++], "read ROM");
|
||||
|
@ -1075,7 +1074,6 @@ void show_disk_info() {
|
|||
void clear_debugger_screen() {
|
||||
#ifdef INTERFACE_CLASSIC
|
||||
int i;
|
||||
video_setpage( 0 );
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
c_interface_print(0, i, 2, screen[ i ] );
|
||||
|
@ -1090,10 +1088,7 @@ void fb_sha1() {
|
|||
uint8_t md[SHA_DIGEST_LENGTH];
|
||||
char buf[(SHA_DIGEST_LENGTH*2)+1];
|
||||
|
||||
video_setpage(!!(softswitches & SS_SCREEN));
|
||||
video_redraw();
|
||||
|
||||
const uint8_t * const fb = video_current_framebuffer();
|
||||
const uint8_t * const fb = video_scan();
|
||||
SHA1(fb, SCANWIDTH*SCANHEIGHT, md);
|
||||
|
||||
int i=0;
|
||||
|
@ -1440,7 +1435,6 @@ void c_interface_debugging() {
|
|||
lex_initted = 1;
|
||||
}
|
||||
|
||||
video_setpage( 0 );
|
||||
c_interface_translate_screen( screen );
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
|
|
|
@ -49,7 +49,7 @@ void sha1_to_str(const uint8_t * const md, char *buf);
|
|||
|
||||
static inline int ASSERT_SHA(const char *SHA_STR) {
|
||||
uint8_t md[SHA_DIGEST_LENGTH];
|
||||
const uint8_t * const fb = video_current_framebuffer();
|
||||
const uint8_t * const fb = video_scan();
|
||||
SHA1(fb, SCANWIDTH*SCANHEIGHT, md);
|
||||
sha1_to_str(md, mdstr);
|
||||
ASSERT(strcmp(mdstr, SHA_STR) == 0);
|
||||
|
|
|
@ -163,9 +163,7 @@ void reinitialize(void) {
|
|||
|
||||
softswitches = SS_TEXT | SS_IOUDIS | SS_C3ROM | SS_LCWRT | SS_LCSEC;
|
||||
|
||||
video_setpage( 0 );
|
||||
|
||||
video_redraw();
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
|
||||
cpu65_init();
|
||||
|
||||
|
@ -438,7 +436,7 @@ static void *cpu_thread(void *dummyptr) {
|
|||
#ifdef AUDIO_ENABLED
|
||||
!speaker_isActive() &&
|
||||
#endif
|
||||
!video_isDirty() && (!disk6.motor_off && (disk_motor_time.tv_sec || disk_motor_time.tv_nsec > DISK_MOTOR_QUIET_NSECS)) )
|
||||
!video_isDirty(A2_DIRTY_FLAG) && (!disk6.motor_off && (disk_motor_time.tv_sec || disk_motor_time.tv_nsec > DISK_MOTOR_QUIET_NSECS)) )
|
||||
{
|
||||
TIMING_LOG("auto switching to full speed");
|
||||
_timing_initialize(CPU_SCALE_FASTEST);
|
||||
|
@ -509,7 +507,7 @@ static void *cpu_thread(void *dummyptr) {
|
|||
#ifdef AUDIO_ENABLED
|
||||
speaker_isActive() ||
|
||||
#endif
|
||||
video_isDirty() || (disk6.motor_off && (disk_motor_time.tv_sec || disk_motor_time.tv_nsec > DISK_MOTOR_QUIET_NSECS))) )
|
||||
video_isDirty(A2_DIRTY_FLAG) || (disk6.motor_off && (disk_motor_time.tv_sec || disk_motor_time.tv_nsec > DISK_MOTOR_QUIET_NSECS))) )
|
||||
{
|
||||
double speed = alt_speed_enabled ? cpu_altscale_factor : cpu_scale_factor;
|
||||
if (speed < CPU_SCALE_FASTEST) {
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
#include <regex.h>
|
||||
|
||||
volatile unsigned long _backend_vid_dirty = 0;
|
||||
|
||||
static int viewportX = 0;
|
||||
static int viewportY = 0;
|
||||
static int viewportWidth = SCANWIDTH*1.5;
|
||||
|
@ -276,7 +274,7 @@ static void glvideo_shutdown(void) {
|
|||
static void glvideo_render(void) {
|
||||
SCOPE_TRACE_VIDEO("glvideo render");
|
||||
|
||||
const uint8_t * const fb = video_current_framebuffer();
|
||||
uint8_t *fb = video_currentFramebuffer();
|
||||
if (UNLIKELY(!fb)) {
|
||||
return;
|
||||
}
|
||||
|
@ -309,8 +307,17 @@ static void glvideo_render(void) {
|
|||
glUniformMatrix4fv(uniformMVPIdx, 1, GL_FALSE, mvpIdentity);
|
||||
#endif
|
||||
|
||||
unsigned long wasDirty = video_clearDirty();
|
||||
if (!cpu_isPaused()) {
|
||||
// check if a2 video memory is dirty
|
||||
unsigned long wasDirty = video_clearDirty(A2_DIRTY_FLAG);
|
||||
wasDirty = 1;
|
||||
#warning HACK FIXME TODO ... always setting A2 video memory dirty bit for now ...
|
||||
if (wasDirty) {
|
||||
fb = video_scan();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long wasDirty = video_clearDirty(FB_DIRTY_FLAG);
|
||||
char *pixels = (char *)crtModel->texPixels;
|
||||
if (wasDirty) {
|
||||
SCOPE_TRACE_VIDEO("pixel convert");
|
||||
|
|
|
@ -41,7 +41,7 @@ typedef struct A2Color_s {
|
|||
/*
|
||||
* Reference to the internal 8bit-indexed color format
|
||||
*/
|
||||
extern A2Color_s colormap[256];
|
||||
extern A2Color_s colormap[];
|
||||
|
||||
#endif /* !A2_VIDEO_H */
|
||||
|
||||
|
|
|
@ -62,8 +62,6 @@ static video_backend_s xvideo_backend = { 0 };
|
|||
static bool request_set_mode = false;
|
||||
static int request_mode = 0;
|
||||
|
||||
volatile unsigned long _backend_vid_dirty = 0;
|
||||
|
||||
typedef struct {
|
||||
unsigned long flags;
|
||||
unsigned long functions;
|
||||
|
@ -338,7 +336,7 @@ static int keysym_to_scancode(void) {
|
|||
|
||||
static void post_image() {
|
||||
// copy Apple //e video memory into XImage uint32_t buffer
|
||||
uint8_t *fb = !video__current_page ? video__fb1 : video__fb2;
|
||||
uint8_t *fb = video_scan();
|
||||
uint8_t index;
|
||||
|
||||
unsigned int count = SCANWIDTH * SCANHEIGHT;
|
||||
|
|
30
src/vm.c
30
src/vm.c
|
@ -135,8 +135,7 @@ GLUE_C_READ(iie_page2_off)
|
|||
}
|
||||
}
|
||||
|
||||
video_setpage(0);
|
||||
video_redraw();
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
|
||||
return floating_bus();
|
||||
}
|
||||
|
@ -160,8 +159,7 @@ GLUE_C_READ(iie_page2_on)
|
|||
}
|
||||
} else {
|
||||
softswitches |= SS_SCREEN;
|
||||
video_setpage(1);
|
||||
video_redraw();
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
return floating_bus();
|
||||
|
@ -176,7 +174,6 @@ GLUE_C_READ(read_switch_graphics)
|
|||
{
|
||||
if (softswitches & SS_TEXT) {
|
||||
softswitches &= ~SS_TEXT;
|
||||
video_redraw();
|
||||
}
|
||||
return floating_bus();
|
||||
}
|
||||
|
@ -185,7 +182,6 @@ GLUE_C_READ(read_switch_text)
|
|||
{
|
||||
if (!(softswitches & SS_TEXT)) {
|
||||
softswitches |= SS_TEXT;
|
||||
video_redraw();
|
||||
}
|
||||
return floating_bus();
|
||||
}
|
||||
|
@ -199,7 +195,6 @@ GLUE_C_READ(read_switch_no_mixed)
|
|||
{
|
||||
if (softswitches & SS_MIXED) {
|
||||
softswitches &= ~SS_MIXED;
|
||||
video_redraw();
|
||||
}
|
||||
return floating_bus();
|
||||
}
|
||||
|
@ -208,7 +203,6 @@ GLUE_C_READ(read_switch_mixed)
|
|||
{
|
||||
if (!(softswitches & SS_MIXED)) {
|
||||
softswitches |= SS_MIXED;
|
||||
video_redraw();
|
||||
}
|
||||
return floating_bus();
|
||||
}
|
||||
|
@ -246,7 +240,6 @@ GLUE_C_READ(iie_hires_off)
|
|||
softswitches |= SS_HGRWRT;
|
||||
}
|
||||
|
||||
video_redraw();
|
||||
return floating_bus();
|
||||
}
|
||||
|
||||
|
@ -270,7 +263,6 @@ GLUE_C_READ(iie_hires_on)
|
|||
}
|
||||
}
|
||||
|
||||
video_redraw();
|
||||
return floating_bus();
|
||||
}
|
||||
|
||||
|
@ -544,7 +536,7 @@ GLUE_C_READ(iie_80store_off)
|
|||
|
||||
if (softswitches & SS_PAGE2) {
|
||||
softswitches |= SS_SCREEN;
|
||||
video_setpage(1);
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
return floating_bus();
|
||||
|
@ -579,7 +571,8 @@ GLUE_C_READ(iie_80store_on)
|
|||
}
|
||||
|
||||
softswitches &= ~SS_SCREEN;
|
||||
video_setpage(0);
|
||||
video_setDirty(A2_DIRTY_FLAG);
|
||||
|
||||
return floating_bus();
|
||||
}
|
||||
|
||||
|
@ -741,10 +734,6 @@ GLUE_C_READ(iie_80col_off)
|
|||
|
||||
softswitches &= ~SS_80COL;
|
||||
|
||||
if (softswitches & (SS_TEXT|SS_MIXED|SS_DHIRES)) {
|
||||
video_redraw();
|
||||
}
|
||||
|
||||
return floating_bus();
|
||||
}
|
||||
|
||||
|
@ -756,10 +745,6 @@ GLUE_C_READ(iie_80col_on)
|
|||
|
||||
softswitches |= SS_80COL;
|
||||
|
||||
if (softswitches & (SS_TEXT|SS_MIXED|SS_DHIRES)) {
|
||||
video_redraw();
|
||||
}
|
||||
|
||||
return floating_bus();
|
||||
}
|
||||
|
||||
|
@ -773,7 +758,6 @@ GLUE_C_READ(iie_altchar_off)
|
|||
if (softswitches & SS_ALTCHAR) {
|
||||
softswitches &= ~SS_ALTCHAR;
|
||||
video_loadfont(0x40,0x40,ucase_glyphs,3);
|
||||
video_redraw();
|
||||
}
|
||||
return floating_bus();
|
||||
}
|
||||
|
@ -784,7 +768,6 @@ GLUE_C_READ(iie_altchar_on)
|
|||
softswitches |= SS_ALTCHAR;
|
||||
video_loadfont(0x40,0x20,mousetext_glyphs,1);
|
||||
video_loadfont(0x60,0x20,lcase_glyphs,2);
|
||||
video_redraw();
|
||||
}
|
||||
return floating_bus();
|
||||
}
|
||||
|
@ -816,7 +799,6 @@ GLUE_C_READ(iie_dhires_on)
|
|||
{
|
||||
if (!(softswitches & SS_DHIRES)) {
|
||||
softswitches |= SS_DHIRES;
|
||||
video_redraw();
|
||||
}
|
||||
return floating_bus();
|
||||
}
|
||||
|
@ -825,7 +807,6 @@ GLUE_C_READ(iie_dhires_off)
|
|||
{
|
||||
if (softswitches & SS_DHIRES) {
|
||||
softswitches &= ~SS_DHIRES;
|
||||
video_redraw();
|
||||
}
|
||||
return floating_bus();
|
||||
}
|
||||
|
@ -945,7 +926,6 @@ static void _initialize_font(void) {
|
|||
video_loadfont(0x80,0x40,ucase_glyphs,0);
|
||||
video_loadfont(0xC0,0x20,ucase_glyphs,0);
|
||||
video_loadfont(0xE0,0x20,lcase_glyphs,0);
|
||||
video_redraw();
|
||||
}
|
||||
|
||||
static void _initialize_apple_ii_memory(void) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user