From f87fc498091658aaf609c4b37f5d2ad1f58fbf45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Strohh=C3=A4cker?= Date: Sun, 9 Dec 2007 17:02:55 +0000 Subject: [PATCH] add scanline-precise changeability of some vga features (hal) Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3058 --- include/vga.h | 3 + src/hardware/pic.cpp | 4 +- src/hardware/vga.cpp | 4 + src/hardware/vga_crtc.cpp | 4 +- src/hardware/vga_dac.cpp | 10 ++ src/hardware/vga_draw.cpp | 240 +++++++++++++++++++++++++++++++++++--- 6 files changed, 244 insertions(+), 21 deletions(-) diff --git a/include/vga.h b/include/vga.h index 6e080aae..582f9b7b 100644 --- a/include/vga.h +++ b/include/vga.h @@ -129,6 +129,7 @@ typedef struct { double vdend, vtotal; double hdend, htotal; double parts; + double virtline; } delay; double aspect_ratio; bool double_scan; @@ -318,6 +319,7 @@ typedef struct { Bitu first_changed; Bit8u combine[16]; RGBEntry rgb[0x100]; + Bit16u xlat16[256]; } VGA_Dac; typedef struct { @@ -354,6 +356,7 @@ typedef struct { typedef struct { VGAModes mode; /* The mode the vga system is in */ VGAModes lastmode; + Bits screenflip; Bit8u misc_output; VGA_Draw draw; VGA_Config config; diff --git a/src/hardware/pic.cpp b/src/hardware/pic.cpp index f44037b1..6c00de53 100644 --- a/src/hardware/pic.cpp +++ b/src/hardware/pic.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: pic.cpp,v 1.41 2007-06-12 20:22:08 c2woody Exp $ */ +/* $Id: pic.cpp,v 1.42 2007-12-09 17:02:55 c2woody Exp $ */ #include @@ -28,7 +28,7 @@ #include "timer.h" #include "setup.h" -#define PIC_QUEUESIZE 128 +#define PIC_QUEUESIZE 512 struct IRQ_Block { bool masked; diff --git a/src/hardware/vga.cpp b/src/hardware/vga.cpp index 1ef5192b..dd6cdb83 100644 --- a/src/hardware/vga.cpp +++ b/src/hardware/vga.cpp @@ -18,6 +18,7 @@ #include "dosbox.h" +//#include "setup.h" #include "video.h" #include "pic.h" #include "vga.h" @@ -148,6 +149,9 @@ void VGA_SetCGA4Table(Bit8u val0,Bit8u val1,Bit8u val2,Bit8u val3) { } void VGA_Init(Section* sec) { +// Section_prop * section=static_cast(sec); +// vga.screenflip = section->Get_int("screenflip"); + vga.screenflip = 0; vga.draw.resizing=false; vga.mode=M_ERROR; //For first init VGA_SetupMemory(); diff --git a/src/hardware/vga_crtc.cpp b/src/hardware/vga_crtc.cpp index 58f81b80..c2e3e1b0 100644 --- a/src/hardware/vga_crtc.cpp +++ b/src/hardware/vga_crtc.cpp @@ -138,7 +138,9 @@ void vga_write_p3d5(Bitu port,Bitu val,Bitu iolen) { case 0x09: /* Maximum Scan Line Register */ if (IS_VGA_ARCH) vga.config.line_compare=(vga.config.line_compare & 0x5ff)|(val&0x40)<<3; - if ((vga.crtc.maximum_scan_line ^ val) & 0xbf) { + + // don't call resize on doublescan change (magic.exe by European Technology) + if ((vga.crtc.maximum_scan_line ^ val) & ((svgaCard==SVGA_None)?0x3f:0xbf)) { crtc(maximum_scan_line)=val; VGA_StartResize(); } else crtc(maximum_scan_line)=val; diff --git a/src/hardware/vga_dac.cpp b/src/hardware/vga_dac.cpp index d568eec0..80dc7196 100644 --- a/src/hardware/vga_dac.cpp +++ b/src/hardware/vga_dac.cpp @@ -52,6 +52,9 @@ enum {DAC_READ,DAC_WRITE}; static INLINE void VGA_DAC_UpdateColor( Bitu index ) { Bitu maskIndex = index & vga.dac.pel_mask; + vga.dac.xlat16[index] = ((vga.dac.rgb[maskIndex].blue>>1)&0x1f) | + (((vga.dac.rgb[maskIndex].green)&0x3f)<<5)| + (((vga.dac.rgb[maskIndex].red>>1)&0x1f) << 11); RENDER_SetPal( index, vga.dac.rgb[maskIndex].red << 2, vga.dac.rgb[maskIndex].green << 2, @@ -126,6 +129,10 @@ static void write_p3c9(Bitu port,Bitu val,Bitu iolen) { /* Check for attributes and DAC entry link */ for (Bitu i=0;i<16;i++) { if (vga.dac.combine[i]==vga.dac.write_index) { + vga.dac.xlat16[i] = ( + (vga.dac.rgb[vga.dac.write_index].blue>>1)&0x1f) | + (((vga.dac.rgb[vga.dac.write_index].green)&0x3f)<<5)| + (((vga.dac.rgb[vga.dac.write_index].red>>1)&0x1f) << 11); RENDER_SetPal(i, vga.dac.rgb[vga.dac.write_index].red << 2, vga.dac.rgb[vga.dac.write_index].green << 2, @@ -176,6 +183,9 @@ void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal) { case M_LIN8: break; default: + vga.dac.xlat16[attr] = ((vga.dac.rgb[pal].blue>>1)&0x1f) | + (((vga.dac.rgb[pal].green)&0x3f)<<5)| + (((vga.dac.rgb[pal].red>>1)&0x1f) << 11); RENDER_SetPal(attr, vga.dac.rgb[pal].red << 2, vga.dac.rgb[pal].green << 2, diff --git a/src/hardware/vga_draw.cpp b/src/hardware/vga_draw.cpp index 842ec49a..251cedfb 100644 --- a/src/hardware/vga_draw.cpp +++ b/src/hardware/vga_draw.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: vga_draw.cpp,v 1.87 2007-10-14 13:12:19 c2woody Exp $ */ +/* $Id: vga_draw.cpp,v 1.88 2007-12-09 17:02:55 c2woody Exp $ */ #include #include @@ -178,6 +178,23 @@ static Bit8u * VGA_Draw_Linear_Line(Bitu vidstart, Bitu line) { return ret; } +static Bit8u * VGA_Draw_Xlat16_Linear_Line(Bitu vidstart, Bitu line) { + Bit8u *ret = &vga.draw.linear_base[ vidstart & vga.draw.linear_mask ]; + Bit16u* temps = (Bit16u*) TempLine; + for(Bitu i = 0; i < vga.draw.line_length; i++) { + temps[i]=vga.dac.xlat16[ret[i]]; + } + return TempLine; + /* +#if !defined(C_UNALIGNED_MEMORY) + if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) { + memcpy( TempLine, ret, vga.draw.line_length ); + return TempLine; + } +#endif + return ret;*/ +} + //Test version, might as well keep it static Bit8u * VGA_Draw_Chain_Line(Bitu vidstart, Bitu line) { Bitu i = 0; @@ -409,6 +426,44 @@ skip_cursor: return TempLine; } +static Bit8u * VGA_TEXT_Xlat16_Draw_Line(Bitu vidstart, Bitu line) { + Bits font_addr; + Bit16u * draw=(Bit16u *)TempLine; + const Bit8u *vidmem = &vga.tandy.draw_base[vidstart]; + for (Bitu cx=0;cx> 3)&1][chr*32+line]; + Bit32u mask1=TXT_Font_Table[font>>4] & FontMask[col >> 7]; + Bit32u mask2=TXT_Font_Table[font&0xf] & FontMask[col >> 7]; + Bit32u fg=TXT_FG_Table[col&0xf]; + Bit32u bg=TXT_BG_Table[col>>4]; + + mask1=fg&mask1 | bg&~mask1; + mask2=fg&mask2 | bg&~mask2; + + for(int i = 0; i < 4; i++) { + *draw++ = vga.dac.xlat16[(mask1>>8*i)&0xff]; + } + for(int i = 0; i < 4; i++) { + *draw++ = vga.dac.xlat16[(mask2>>8*i)&0xff]; + } + } + if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor; + font_addr = (vga.draw.cursor.address-vidstart) >> 1; + if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) { + if (linevga.draw.cursor.eline) goto skip_cursor; + draw=(Bit16u *)&TempLine[font_addr*16]; + Bit8u att=(Bit8u)(TXT_FG_Table[vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf]&0xff); + for(int i = 0; i < 8; i++) { + *draw++ = vga.dac.xlat16[att]; + } + } +skip_cursor: + return TempLine; +} + static Bit8u * VGA_TEXT_Draw_Line_9(Bitu vidstart, Bitu line) { Bits font_addr; Bit8u * draw=(Bit8u *)TempLine; @@ -447,7 +502,7 @@ static Bit8u * VGA_TEXT_Draw_Line_9(Bitu vidstart, Bitu line) { *draw++=(font&0x02)?fg:bg; Bit8u last=(font&0x01)?fg:bg; *draw++=last; - *draw++=((chr<0xc0) || (chr>0xdf)) ? bg : last; + *draw++=((vga.attr.mode_control&0x04) && ((chr<0xc0) || (chr>0xdf))) ? bg : last; if (pel_pan) { if (underline && ((col&0x07) == 0x01)) font=0xff; else font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<=vga.draw.split_line)) pel_pan=0; + const Bit8u *vidmem = &vga.tandy.draw_base[vidstart]; + Bit8u chr=vidmem[0]; + Bit8u col=vidmem[1]; + Bit8u font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<>4]&0xff); + Bitu draw_blocks=vga.draw.blocks; + draw_blocks++; + for (Bitu cx=1;cx>(8-pel_pan); + else font|=vga.draw.font_tables[(col >> 3)&1][chr*32+line]>>(8-pel_pan); + fg=col&0xf; + bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff); + } else { + chr=vidmem[(cx-1)*2]; + col=vidmem[(cx-1)*2+1]; + if (underline && ((col&0x07) == 0x01)) font=0xff; + else font=vga.draw.font_tables[(col >> 3)&1][chr*32+line]; + fg=col&0xf; + bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff); + } + if (FontMask[col>>7]==0) font=0; + Bit8u mask=0x80; + for(int i = 0; i < 8; i++) { + *draw++= vga.dac.xlat16[font&mask?fg:bg]; + mask>>=1; + } + *draw++=(((vga.attr.mode_control&0x04) && ((chr<0xc0) || (chr>0xdf))) && + !(underline && ((col&0x07) == 0x01))) ? + (vga.dac.xlat16[bg]) : draw[-1]; + if (pel_pan) { + if (underline && ((col&0x07) == 0x01)) font=0xff; + else font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<> 1; + if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) { + if (linevga.draw.cursor.eline) goto skip_cursor; + draw=(Bit16u*)&TempLine[font_addr*18]; + Bit8u fg=vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf; + for(int i = 0; i < 8; i++) { + *draw++ = vga.dac.xlat16[fg]; + } + //if(underline && ((col&0x07) == 0x01)) + // *draw = vga.dac.xlat16[fg]; + } +skip_cursor: + return TempLine; +} + static void VGA_VerticalDisplayEnd(Bitu val) { // vga.config.retrace=true; vga.config.real_start=vga.config.display_start & ((2*1024*1024)-1); @@ -494,6 +611,40 @@ static INLINE void VGA_ChangesEnd(void ) { #endif +static void VGA_DrawSingleLine(Bitu blah) { + if(vga.attr.enabled || (!(vga.mode==M_VGA || vga.mode==M_EGA))) { + Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line ); + // Magic Circle last part + if((vga.crtc.maximum_scan_line & 0x80)&& !vga.draw.doubleheight) + RENDER_DrawLine(data); + RENDER_DrawLine(data); + } else { + // else draw overscan color line + // TODO: black line should be good enough for now + // (DoWhackaDo) + memset(TempLine, 0, sizeof(TempLine)); + if((vga.crtc.maximum_scan_line & 0x80)&& !vga.draw.doubleheight) + RENDER_DrawLine(TempLine); + RENDER_DrawLine(TempLine); + } + + vga.draw.address_line++; + if (vga.draw.address_line>=vga.draw.address_line_total) { + vga.draw.address_line=0; + vga.draw.address+=vga.draw.address_add; + } + vga.draw.lines_done++; + if (vga.draw.split_line==vga.draw.lines_done) { + vga.draw.address=0; + if(!(vga.attr.mode_control&0x20)) + vga.draw.address += vga.config.pel_panning; + vga.draw.address_line=0; + } + if ((vga.draw.lines_done < vga.draw.lines_total) && (!vga.draw.resizing)) { + PIC_AddEvent(VGA_DrawSingleLine,(float)vga.draw.delay.virtline); + } else RENDER_EndUpdate(); +} + static void VGA_DrawPart(Bitu lines) { while (lines--) { Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line ); @@ -568,29 +719,61 @@ static void INLINE VGA_ChangesStart( void ) { static void VGA_VerticalTimer(Bitu val) { + + /* + // Panic plasma appears more stable with this variant + vga.draw.delay.framestart += vga.draw.delay.vtotal; + double error = PIC_FullIndex()-vga.draw.delay.framestart; + //vga.draw.delay.framestart = PIC_FullIndex(); + //error = vga.draw.delay.framestart - error - vga.draw.delay.vtotal; + //if (abs(error) > 0.001 ) LOG_MSG("vgaerror: %f",error); + + //PIC_RemoveEvents(VGA_VerticalDisplayEnd); + PIC_AddEvent( VGA_VerticalTimer, (float)vga.draw.delay.vtotal - error); + double flip_offset = vga.screenflip/1000.0 + vga.draw.delay.vrstart; + if(flip_offset > vga.draw.delay.vtotal) { + VGA_VerticalDisplayEnd(0); + } else PIC_AddEvent( VGA_VerticalDisplayEnd, + (float)(flip_offset - error)); +*/ double error = vga.draw.delay.framestart; vga.draw.delay.framestart = PIC_FullIndex(); error = vga.draw.delay.framestart - error - vga.draw.delay.vtotal; // if (abs(error) > 0.001 ) // LOG_MSG("vgaerror: %f",error); PIC_AddEvent( VGA_VerticalTimer, (float)vga.draw.delay.vtotal ); - PIC_AddEvent( VGA_VerticalDisplayEnd, (float)vga.draw.delay.vrstart ); - if ( GCC_UNLIKELY( vga.draw.parts_left )) { - LOG(LOG_VGAMISC,LOG_NORMAL)( "Parts left: %d", vga.draw.parts_left ); - PIC_RemoveEvents( &VGA_DrawPart ); - RENDER_EndUpdate(); - vga.draw.parts_left = 0; + //PIC_AddEvent( VGA_VerticalDisplayEnd, (float)vga.draw.delay.vrstart ); + double flip_offset = vga.screenflip/1000.0 + vga.draw.delay.vrstart; + if(flip_offset > vga.draw.delay.vtotal) { + VGA_VerticalDisplayEnd(0); + } else PIC_AddEvent( VGA_VerticalDisplayEnd,(float)flip_offset); + + if ( GCC_UNLIKELY( vga.draw.parts_left)) { + if (!IS_VGA_ARCH || (svgaCard!=SVGA_None)) { + LOG(LOG_VGAMISC,LOG_NORMAL)( "Parts left: %d", vga.draw.parts_left ); + PIC_RemoveEvents( &VGA_DrawPart ); + RENDER_EndUpdate(); + vga.draw.parts_left = 0; + } } //Check if we can actually render, else skip the rest if (!RENDER_StartUpdate()) return; + if ( GCC_UNLIKELY( vga.draw.lines_done < vga.draw.lines_total)) { + if (IS_VGA_ARCH && (svgaCard==SVGA_None)) { + while(vga.draw.lines_done < vga.draw.lines_total) + VGA_DrawSingleLine(0); + PIC_RemoveEvents(VGA_DrawSingleLine); + } + } //TODO Maybe check for an active frame on parts_left and clear that first? vga.draw.parts_left = vga.draw.parts_total; vga.draw.lines_done = 0; // vga.draw.address=vga.config.display_start; - vga.draw.address = vga.config.real_start; vga.draw.address_line = vga.config.hlines_skip; vga.draw.split_line = (vga.config.line_compare/vga.draw.lines_scaled); + if (vga.draw.split_line==0) vga.draw.address = 0; + else vga.draw.address = vga.config.real_start; // go figure... if (machine==MCH_EGA) vga.draw.split_line*=2; // if (machine==MCH_EGA) vga.draw.split_line = ((((vga.config.line_compare&0x5ff)+1)*2-1)/vga.draw.lines_scaled); @@ -642,15 +825,17 @@ static void VGA_VerticalTimer(Bitu val) { vga.draw.address *= 2; break; } - //VGA_DrawPart( vga.draw.parts_lines ); - PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts,vga.draw.parts_lines); -// PIC_AddEvent(VGA_DrawPart,(float)(vga.draw.delay.parts/2),vga.draw.parts_lines); //Else tearline in Tyrian and second reality if (GCC_UNLIKELY(machine==MCH_EGA)) { if (!(vga.crtc.vertical_retrace_end&0x20)) { PIC_ActivateIRQ(2); vga.draw.vret_triggered=true; } } + if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) PIC_AddEvent(VGA_DrawSingleLine,(float)vga.draw.delay.htotal); + else PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts,vga.draw.parts_lines); + //VGA_DrawPart( vga.draw.parts_lines ); + //PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts,vga.draw.parts_lines); + //PIC_AddEvent(VGA_DrawPart,(float)(vga.draw.delay.parts/2),vga.draw.parts_lines); //Else tearline in Tyrian and second reality } void VGA_CheckScanLength(void) { @@ -919,7 +1104,9 @@ void VGA_SetupDrawing(Bitu val) { //Check to prevent useless black areas if (hbstart 0; vga.draw.blocks = width; width<<=3; - VGA_DrawLine=VGA_Draw_Linear_Line; + if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) { + bpp=16; + VGA_DrawLine = VGA_Draw_Xlat16_Linear_Line; + } else VGA_DrawLine=VGA_Draw_Linear_Line; + vga.draw.linear_base = vga.mem.linear + VGA_CACHE_OFFSET; vga.draw.linear_mask = 512 * 1024 - 1; break; @@ -1000,12 +1194,17 @@ void VGA_SetupDrawing(Bitu val) { aspect_ratio=1.0; vga.draw.blocks=width; doublewidth=(vga.seq.clocking_mode & 0x8) > 0; - if ((IS_VGA_ARCH) && (svgaCard==SVGA_None) && (vga.attr.mode_control&0x04)) { + if ((IS_VGA_ARCH) && (svgaCard==SVGA_None) && (vga.seq.clocking_mode&0x01)) { width*=9; /* 9 bit wide text font */ - VGA_DrawLine=VGA_TEXT_Draw_Line_9; + VGA_DrawLine=VGA_TEXT_Xlat16_Draw_Line_9; + bpp=16; +// VGA_DrawLine=VGA_TEXT_Draw_Line_9; } else { width<<=3; /* 8 bit wide text font */ - VGA_DrawLine=VGA_TEXT_Draw_Line; + if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) { + VGA_DrawLine=VGA_TEXT_Xlat16_Draw_Line; + bpp=16; + } else VGA_DrawLine=VGA_TEXT_Draw_Line; } break; case M_HERC_GFX: @@ -1101,6 +1300,7 @@ void VGA_SetupDrawing(Bitu val) { PIC_RemoveEvents(VGA_VerticalTimer); PIC_RemoveEvents(VGA_VerticalDisplayEnd); PIC_RemoveEvents(VGA_DrawPart); + PIC_RemoveEvents(VGA_DrawSingleLine); vga.draw.width = width; vga.draw.height = height; vga.draw.doublewidth = doublewidth; @@ -1114,6 +1314,9 @@ void VGA_SetupDrawing(Bitu val) { doublewidth ? "double":"normal",doubleheight ? "double":"normal",aspect_ratio); #endif RENDER_SetSize(width,height,bpp,fps,aspect_ratio,doublewidth,doubleheight); + if(doubleheight) vga.draw.delay.virtline = vga.draw.delay.htotal * 2.0; + // On doubleheight modes we need twice the time to pass to the next scanline + else vga.draw.delay.virtline = vga.draw.delay.htotal; vga.draw.delay.framestart = PIC_FullIndex(); PIC_AddEvent( VGA_VerticalTimer , (float)vga.draw.delay.vtotal ); } @@ -1121,4 +1324,5 @@ void VGA_SetupDrawing(Bitu val) { void VGA_KillDrawing(void) { PIC_RemoveEvents(VGA_DrawPart); + PIC_RemoveEvents(VGA_DrawSingleLine); }