diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs index 403eb0d370..fa4743348c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs @@ -1,18 +1,7 @@ //TODO hook up newer file ID stuff, think about how to combine it with the disc ID -//TODO not liking the name ShockFramebufferJob //TODO change display manager to not require 0xFF alpha channel set on videoproviders. check gdi+ and opengl! this will get us a speedup in some places //TODO Disc.Structure.Sessions[0].length_aba was 0 -//looks like we can have (in NTSC) framebuffer dimensions like this: -//width: 280, 350, 700 -//height: 240, 480 -//mednafen's strategy is to put everything in a 320x240 and scale it up 3x to 960x720 by default (which is adequate to contain the largest PSX framebuffer) -//heres my strategy. -//1. we should have a native output mode, for debugging. but most users wont want it (massively distorted resolutions are common in games) -//2. do the right thing: -//always double a height of 240, and double a width of 280 or 350. For 280, float content in center screen. -//but lets not do this til we're on an upgraded mednafen - using System; using System.Runtime.InteropServices; using System.IO; @@ -149,14 +138,13 @@ namespace BizHawk.Emulation.Cores.Sony.PSX } } - + //note: its annoying that we have to have a disc before constructing this. + //might want to change that later. HOWEVER - we need to definitely have a region, at least public Octoshock(CoreComm comm, DiscSystem.Disc disc) { ServiceProvider = new BasicServiceProvider(this); var domains = new List(); CoreComm = comm; - VirtualWidth = BufferWidth = 256; - BufferHeight = 192; Attach(); @@ -177,6 +165,23 @@ namespace BizHawk.Emulation.Cores.Sony.PSX fixed (byte* pFirmware = firmware) OctoshockDll.shock_Create(out psx, discInfo.region, pFirmware); + + //these should track values in octoshock gpu.cpp FillVideoParams + //if (discInfo.region == OctoshockDll.eRegion.EU) + //{ + // VirtualWidth = 377; // " Dunno :( " + // VirtualHeight = 288; + //} + //else + //{ + // VirtualWidth = 320; // Dunno :( + // VirtualHeight = 240; + //} + //BUT-for now theyre normalized (NOTE: THIS MESSES UP THE ASPECT RATIOS) + VirtualWidth = 700; + VirtualHeight = 480; + + OctoshockDll.shock_OpenTray(psx); OctoshockDll.shock_SetDisc(psx, discInterface.OctoshockHandle); OctoshockDll.shock_CloseTray(psx); @@ -218,7 +223,8 @@ namespace BizHawk.Emulation.Cores.Sony.PSX { OctoshockDll.shock_Step(psx, OctoshockDll.eShockStep.Frame); - OctoshockDll.ShockFramebufferJob fb = new OctoshockDll.ShockFramebufferJob(); + OctoshockDll.ShockFramebufferInfo fb = new OctoshockDll.ShockFramebufferInfo(); + fb.flags = OctoshockDll.eShockFramebufferFlags.Normalize; OctoshockDll.shock_GetFramebuffer(psx, ref fb); //Console.WriteLine(fb.height); @@ -265,7 +271,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX public int[] GetVideoBuffer() { return frameBuffer; } public int VirtualWidth { get; private set; } - public int VirtualHeight { get { return BufferHeight; } } + public int VirtualHeight { get; private set; } public int BufferWidth { get; private set; } public int BufferHeight { get; private set; } public int BackgroundColor { get { return 0; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/OctoshockDll.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/OctoshockDll.cs index e65a136617..f8f7fa7358 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/OctoshockDll.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/OctoshockDll.cs @@ -19,6 +19,12 @@ public unsafe static class OctoshockDll Frame }; + public enum eShockFramebufferFlags + { + None = 0, + Normalize = 1 + } + public const int SHOCK_OK = 0; public const int SHOCK_ERROR = -1; public const int SHOCK_NOCANDO = -2; @@ -47,9 +53,11 @@ public unsafe static class OctoshockDll }; [StructLayout(LayoutKind.Sequential)] - public struct ShockFramebufferJob + public struct ShockFramebufferInfo { public int width, height; + [MarshalAs(UnmanagedType.I4)] + public eShockFramebufferFlags flags; public void* ptr; }; @@ -93,5 +101,5 @@ public unsafe static class OctoshockDll public static extern int shock_Step(IntPtr psx, eShockStep step); [DllImport("octoshock.dll")] - public static extern int shock_GetFramebuffer(IntPtr psx, ref ShockFramebufferJob fb); + public static extern int shock_GetFramebuffer(IntPtr psx, ref ShockFramebufferInfo fb); } diff --git a/output/dll/octoshock.dll b/output/dll/octoshock.dll index 72c1f18238..82e973c111 100644 Binary files a/output/dll/octoshock.dll and b/output/dll/octoshock.dll differ diff --git a/psx/octoshock/psx/psx.cpp b/psx/octoshock/psx/psx.cpp index 7e7866230d..5e82bbc6d7 100644 --- a/psx/octoshock/psx/psx.cpp +++ b/psx/octoshock/psx/psx.cpp @@ -1346,6 +1346,9 @@ static void MountCPUAddressSpace() static MDFN_Surface *VTBuffer[2] = { NULL, NULL }; static int *VTLineWidths[2] = { NULL, NULL }; +static bool s_FramebufferNormalized; +static int s_FramebufferCurrent; +static int s_FramebufferCurrentWidth; EW_EXPORT s32 shock_Create(void** psx, eRegion region, void* firmware512k) { @@ -1374,33 +1377,37 @@ EW_EXPORT s32 shock_Create(void** psx, eRegion region, void* firmware512k) { sls = 0; sle = 287; - s_ShockConfig.nominal_width = 367; // Dunno. :( - s_ShockConfig.nominal_height = 288; - - s_ShockConfig.fb_width = 768; - s_ShockConfig.fb_height = 576; } else { sls = 0; sle = 239; - s_ShockConfig.lcm_width = 2720; - s_ShockConfig.lcm_height = 480; - - s_ShockConfig.nominal_width = 310; - s_ShockConfig.nominal_height = 240; - - s_ShockConfig.fb_width = 768; - s_ShockConfig.fb_height = 480; } - //setup gpu output surfaces - MDFN_PixelFormat nf(MDFN_COLORSPACE_RGB, 16, 8, 0, 24); - VTBuffer[0] = new MDFN_Surface(NULL, s_ShockConfig.fb_width, s_ShockConfig.fb_height, s_ShockConfig.fb_width, nf); - VTLineWidths[0] = (int *)calloc(s_ShockConfig.fb_height, sizeof(int)); - //these steps can't be done without more information GPU = new PS_GPU(region == REGION_EU, sls, sle); + + //fetch video parameters, stash in a simpler format + MDFNGI givp; + GPU->FillVideoParams(&givp); + s_ShockConfig.lcm_width = givp.lcm_width; + s_ShockConfig.lcm_height = givp.lcm_height; + s_ShockConfig.fb_height = givp.fb_height; + s_ShockConfig.fb_width = givp.fb_width; + s_ShockConfig.fb_height = givp.fb_height; + s_ShockConfig.nominal_width = givp.nominal_width; + s_ShockConfig.nominal_height = givp.nominal_height; + //givp.fps // TODO + + + //setup gpu output surfaces + MDFN_PixelFormat nf(MDFN_COLORSPACE_RGB, 16, 8, 0, 24); + for(int i=0;i<2;i++) + { + VTBuffer[i] = new MDFN_Surface(NULL, s_ShockConfig.fb_width, s_ShockConfig.fb_height, s_ShockConfig.fb_width, nf); + VTLineWidths[i] = (int *)calloc(s_ShockConfig.fb_height, sizeof(int)); + } + //TODO - configuration static bool emulate_memcard[8] = {0}; @@ -1521,16 +1528,161 @@ EW_EXPORT s32 shock_Step(void* psx, eShockStep step) espec.InterlaceField = 0; } - //pixel-double some dimensions as needed (TBD) + //new frame, hasnt been normalized + s_FramebufferNormalized = false; + s_FramebufferCurrent = 0; + s_FramebufferCurrentWidth = s_ShockConfig.fb_width; return SHOCK_OK; } -EW_EXPORT s32 shock_GetFramebuffer(void* psx, ShockFramebufferJob* fb) +//`normalizes` the framebuffer to 700x480 by pixel doubling and wrecking the AR a little bit as needed +void NormalizeFramebuffer() { - //always fetch description + //mednafen's advised solution for smooth gaming: "scale the output width to z * nominal_width, and the output height to z * nominal_height, where nominal_width and nominal_height are members of the MDFNGI struct" + //IOW, mednafen's strategy is to put everything in a 320x240 and scale it up 3x to 960x720 by default (which is adequate to contain the largest PSX framebuffer of 700x480) + + //psxtech says horizontal resolutions can be: 256, 320, 368, 512, 640 pixels + //mednafen will turn those into 2800/{ 10, 8, 5, 4, 7 } -> 280,350,560,700,400 + + //heres my strategy: + //try to do the smart thing, try to get aspect ratio near the right value + //intended AR = 320/240 = 1.3333 + //280x240 - ok (AR 1.1666666666666666666666666666667) + //350x240 - ok (AR 1.4583333333333333333333333333333) + //400x240 - ok (AR 1.6666666666666666666666666666667) + //560x240 - scale vertically by 2 = 560x480 ~ 280x240 + //700x240 - scale vertically by 2 = 700x480 ~ 350x240 + //280x480 - scale horizontally by 2 = 560x480 ~ 280x240 + //350x480 - scale horizontally by 2 = 700x480 ~ 350x240 + //400x480 - scale horizontally by 2 = 800x480 ~ 400x240 + //560x480 - ok ~ 280x240 + //700x480 - ok ~ 350x240 + + //NOTE: this approach is very redundant with the displaymanager AR tracking stuff + //however, it will help us avoid stressing the displaymanager (for example, a 700x240 will freak it out kind of. we could send it a much more sensible 700x480) + + int width = VTLineWidths[0][0]; //presently, except for contrived test programs, it is safe to assume this is the same for the entire frame (no known use by games) int height = espec.DisplayRect.h; + + int xs=1,ys=1,xm=0; + + //I. as described above + //if(width == 280 && height == 240) {} + //if(width == 350 && height == 240) {} + //if(width == 400 && height == 240) {} + //if(width == 560 && height == 240) ys=2; + //if(width == 700 && height == 240) ys=2; + //if(width == 280 && height == 480) xs=2; + //if(width == 350 && height == 480) xs=2; + //if(width == 400 && height == 480) xs=2; + //if(width == 560 && height == 480) {} + //if(width == 700 && height == 480) {} + + //II. as the snes 'always double size framebuffer'. I think thats a better idea, and we already have the concept + if(width == 280 && height == 240) xs=ys=2; + if(width == 350 && height == 240) xs=ys=2; + if(width == 400 && height == 240) xs=ys=2; + if(width == 560 && height == 240) ys=2; + if(width == 700 && height == 240) ys=2; + if(width == 280 && height == 480) xs=2; + if(width == 350 && height == 480) xs=2; + if(width == 400 && height == 480) xs=2; + if(width == 560 && height == 480) {} + if(width == 700 && height == 480) {} + xm = (700-width*xs)/2; + + int curr = 0; + + //1. double the height, while cropping down + if(ys==2) //should handle ntsc or pal, but not tested yet for pal + { + uint32* src = VTBuffer[curr]->pixels + (s_ShockConfig.fb_width*espec.DisplayRect.y) + espec.DisplayRect.x; + uint32* dst = VTBuffer[curr^1]->pixels; + int tocopy = width*4; + for(int y=0;ypixels + (s_ShockConfig.fb_width*espec.DisplayRect.y) + espec.DisplayRect.x; + uint32* dst = VTBuffer[curr^1]->pixels; + + for(int y=0;yflags & eShockFramebufferFlags_Normalize) + if(!s_FramebufferNormalized) + { + NormalizeFramebuffer(); + s_FramebufferNormalized = true; + } + + int fbIndex = s_FramebufferCurrent; + + //always fetch description + int width = VTLineWidths[fbIndex][0]; //presently, except for contrived test programs, it is safe to assume this is the same for the entire frame (no known use by games) + int height = espec.DisplayRect.h; fb->width = width; fb->height = height; @@ -1542,7 +1694,7 @@ EW_EXPORT s32 shock_GetFramebuffer(void* psx, ShockFramebufferJob* fb) //maybe we need to output the framebuffer //do a raster loop and copy it to the target - uint32* src = VTBuffer[0]->pixels + (s_ShockConfig.fb_width*espec.DisplayRect.y) + espec.DisplayRect.x; + uint32* src = VTBuffer[fbIndex]->pixels + (s_FramebufferCurrentWidth*espec.DisplayRect.y) + espec.DisplayRect.x; uint32* dst = (u32*)fb->ptr; int tocopy = width*4; for(int y=0;y