diff --git a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj index 20ab8b62a..97e462e4e 100755 --- a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj +++ b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj @@ -1482,6 +1482,37 @@ AB497A2027F2E97A00E8A244 /* README.MAC in Resources */ = {isa = PBXBuildFile; fileRef = AB3ACC3D14C24D5400D7D192 /* README.MAC */; }; AB497A2127F2E97A00E8A244 /* AppIcon_FirmwareConfig.icns in Resources */ = {isa = PBXBuildFile; fileRef = AB75226D14C7BB51009B97B3 /* AppIcon_FirmwareConfig.icns */; }; AB497A2227F2E97A00E8A244 /* DisplayWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB8967DB16D2ED2700F826F1 /* DisplayWindow.xib */; }; + AB49B53A281687B90069F1D7 /* cff.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7B01BB4EC1000B08C25 /* cff.c */; }; + AB49B53B281687B90069F1D7 /* ftbase.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7751BB4EC1000B08C25 /* ftbase.c */; }; + AB49B53C281687B90069F1D7 /* ftbbox.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7771BB4EC1000B08C25 /* ftbbox.c */; }; + AB49B53D281687B90069F1D7 /* ftbitmap.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7791BB4EC1000B08C25 /* ftbitmap.c */; }; + AB49B53E281687B90069F1D7 /* ftdebug.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA77D1BB4EC1000B08C25 /* ftdebug.c */; }; + AB49B53F281687B90069F1D7 /* ftfntfmt.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA77E1BB4EC1000B08C25 /* ftfntfmt.c */; }; + AB49B540281687B90069F1D7 /* ftfstype.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA77F1BB4EC1000B08C25 /* ftfstype.c */; }; + AB49B541281687B90069F1D7 /* ftgasp.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7801BB4EC1000B08C25 /* ftgasp.c */; }; + AB49B542281687B90069F1D7 /* ftglyph.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7821BB4EC1000B08C25 /* ftglyph.c */; }; + AB49B543281687B90069F1D7 /* ftgxval.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7831BB4EC1000B08C25 /* ftgxval.c */; }; + AB49B544281687B90069F1D7 /* ftinit.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7841BB4EC1000B08C25 /* ftinit.c */; }; + AB49B545281687B90069F1D7 /* ftlcdfil.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7851BB4EC1000B08C25 /* ftlcdfil.c */; }; + AB49B546281687B90069F1D7 /* ftmm.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7871BB4EC1000B08C25 /* ftmm.c */; }; + AB49B547281687B90069F1D7 /* ftotval.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7891BB4EC1000B08C25 /* ftotval.c */; }; + AB49B548281687B90069F1D7 /* ftpatent.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA78B1BB4EC1000B08C25 /* ftpatent.c */; }; + AB49B549281687B90069F1D7 /* ftpfr.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA78C1BB4EC1000B08C25 /* ftpfr.c */; }; + AB49B54A281687B90069F1D7 /* ftstroke.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7911BB4EC1000B08C25 /* ftstroke.c */; }; + AB49B54B281687B90069F1D7 /* ftsynth.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7921BB4EC1000B08C25 /* ftsynth.c */; }; + AB49B54C281687B90069F1D7 /* ftsystem.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7931BB4EC1000B08C25 /* ftsystem.c */; }; + AB49B54D281687B90069F1D7 /* fttype1.c in Sources */ = {isa = PBXBuildFile; fileRef = ABA731611BB51F6700B26147 /* fttype1.c */; }; + AB49B54E281687B90069F1D7 /* psaux.c in Sources */ = {isa = PBXBuildFile; fileRef = ABA731661BB51FDC00B26147 /* psaux.c */; }; + AB49B54F281687B90069F1D7 /* pshinter.c in Sources */ = {isa = PBXBuildFile; fileRef = ABA7315D1BB51E7000B26147 /* pshinter.c */; }; + AB49B550281687B90069F1D7 /* psnames.c in Sources */ = {isa = PBXBuildFile; fileRef = ABA731591BB51A8D00B26147 /* psnames.c */; }; + AB49B551281687B90069F1D7 /* sfnt.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7C81BB4EC1000B08C25 /* sfnt.c */; }; + AB49B552281687B90069F1D7 /* smooth.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7E41BB4EC1000B08C25 /* smooth.c */; }; + AB49B553281687B90069F1D7 /* truetype.c in Sources */ = {isa = PBXBuildFile; fileRef = ABFEA7E61BB4EC1000B08C25 /* truetype.c */; }; + AB49B554281687B90069F1D7 /* type1.c in Sources */ = {isa = PBXBuildFile; fileRef = ABA731671BB51FDC00B26147 /* type1.c */; }; + AB49B555281687B90069F1D7 /* type1cid.c in Sources */ = {isa = PBXBuildFile; fileRef = ABA731651BB51FDC00B26147 /* type1cid.c */; }; + AB49B556281707590069F1D7 /* OGLDisplayOutput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABE6840B189E33BC007FD69C /* OGLDisplayOutput.cpp */; }; + AB49B5572817075D0069F1D7 /* OGLDisplayOutput_3_2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABB24F6B1A81EE92006C1108 /* OGLDisplayOutput_3_2.cpp */; }; + AB49B558281707B90069F1D7 /* ClientDisplayView.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABAD07DA1E19CAA6007867CA /* ClientDisplayView.cpp */; }; AB4C81E41B21676C00ACECD5 /* hq3x.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB4C81E31B21676C00ACECD5 /* hq3x.cpp */; }; AB4C81E61B21676C00ACECD5 /* hq3x.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB4C81E31B21676C00ACECD5 /* hq3x.cpp */; }; AB4C81E71B21677700ACECD5 /* hq3x.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB4C81E31B21676C00ACECD5 /* hq3x.cpp */; }; @@ -1495,6 +1526,7 @@ AB53B0C7211E6407003D0ED9 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = AB53B0BD211E63E8003D0ED9 /* libz.tbd */; }; AB54718B1E27610500508C5C /* MacMetalDisplayViewShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = AB54718A1E27610500508C5C /* MacMetalDisplayViewShaders.metal */; }; AB54718C1E27610500508C5C /* MacMetalDisplayViewShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = AB54718A1E27610500508C5C /* MacMetalDisplayViewShaders.metal */; }; + AB552DC8281A079000F48ECD /* OEDisplayView.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB49B5382816879E0069F1D7 /* OEDisplayView.mm */; }; AB5648FF186E6EA8002740F4 /* cocoa_slot2.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB5648FE186E6EA8002740F4 /* cocoa_slot2.mm */; }; AB564901186E6EA8002740F4 /* cocoa_slot2.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB5648FE186E6EA8002740F4 /* cocoa_slot2.mm */; }; AB564904186E6EBC002740F4 /* Slot2WindowDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB564903186E6EBC002740F4 /* Slot2WindowDelegate.mm */; }; @@ -2168,7 +2200,6 @@ AB790294215B84F20082AE82 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABC570D4134431DA00E7B0B1 /* OpenGL.framework */; }; AB790295215B84F20082AE82 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB3BF4321E2562F2003E2B24 /* QuartzCore.framework */; }; AB790296215B84F20082AE82 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABAE1F6E1F6873E70080EFE3 /* CoreVideo.framework */; }; - AB796C9F15CDCB0F00C59155 /* arm_jit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB796C9B15CDCB0F00C59155 /* arm_jit.cpp */; }; AB796CA715CDCBA200C59155 /* KeyNames.plist in Resources */ = {isa = PBXBuildFile; fileRef = AB02475B13886BF300E9F9AB /* KeyNames.plist */; }; AB796CA815CDCBA200C59155 /* DefaultKeyMappings.plist in Resources */ = {isa = PBXBuildFile; fileRef = ABC719E1138CB25E002827A9 /* DefaultKeyMappings.plist */; }; AB796CA915CDCBA200C59155 /* DefaultUserPrefs.plist in Resources */ = {isa = PBXBuildFile; fileRef = ABBC0F8C1394B1AA0028B6BD /* DefaultUserPrefs.plist */; }; @@ -2930,6 +2961,7 @@ ABC503AE1AAC2B90002FCD43 /* Icon_MicrophoneDarkGreen_256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = ABC503AC1AAC2B71002FCD43 /* Icon_MicrophoneDarkGreen_256x256.png */; }; ABC503B01AAC42C2002FCD43 /* coreaudiosound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B9E5F1501A78000464647 /* coreaudiosound.cpp */; }; ABC503B11AAC4355002FCD43 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABB0FBC41A9E5CEA0060C55A /* CoreAudio.framework */; }; + ABCC497B281B0684004BA9F0 /* SourceSansPro-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = ABA731281BB5104200B26147 /* SourceSansPro-Bold.otf */; }; ABCFA9F4178BDE920030C8BA /* encrypt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABCFA9F3178BDE920030C8BA /* encrypt.cpp */; }; ABCFA9F6178BDE920030C8BA /* encrypt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABCFA9F3178BDE920030C8BA /* encrypt.cpp */; }; ABD10AE71715FCDD00B5729D /* audiosamplegenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD10AE51715FCDD00B5729D /* audiosamplegenerator.cpp */; }; @@ -3607,6 +3639,8 @@ AB47B52B18A3F722009A42AF /* xbrz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xbrz.h; sourceTree = ""; }; AB47B52C18A3F722009A42AF /* xbrz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xbrz.cpp; sourceTree = ""; }; AB497B1227F2E97A00E8A244 /* DeSmuME.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DeSmuME.app; sourceTree = BUILT_PRODUCTS_DIR; }; + AB49B5372816879E0069F1D7 /* OEDisplayView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OEDisplayView.h; sourceTree = ""; }; + AB49B5382816879E0069F1D7 /* OEDisplayView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = OEDisplayView.mm; sourceTree = ""; }; AB4C81E31B21676C00ACECD5 /* hq3x.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hq3x.cpp; sourceTree = ""; }; AB4FCEBC1692AB82000F498F /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; AB53B0BC211E63E4003D0ED9 /* libpcap.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libpcap.tbd; path = usr/lib/libpcap.tbd; sourceTree = SDKROOT; }; @@ -5073,6 +5107,8 @@ ABB3C63A1501BB8300E0C22E /* openemu */ = { isa = PBXGroup; children = ( + AB49B5372816879E0069F1D7 /* OEDisplayView.h */, + AB49B5382816879E0069F1D7 /* OEDisplayView.mm */, AB93384928132CD000851FEA /* OEBuildInterface.cpp */, ABB3C63D1501BB8300E0C22E /* NDSGameCore.h */, ABB3C63F1501BB8300E0C22E /* OENDSSystemResponderClient.h */, @@ -6997,6 +7033,7 @@ buildActionMask = 2147483647; files = ( ABB3C6621501BF4E00E0C22E /* InfoPlist.strings in Resources */, + ABCC497B281B0684004BA9F0 /* SourceSansPro-Bold.otf in Resources */, ABB3C6631501BF4E00E0C22E /* FileTypeInfo.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -9029,14 +9066,17 @@ ABCFA9F6178BDE920030C8BA /* encrypt.cpp in Sources */, ABB3C66C1501C04F00E0C22E /* NDSGameCore.mm in Sources */, ABB3C6701501C04F00E0C22E /* videofilter.cpp in Sources */, + AB49B54B281687B90069F1D7 /* ftsynth.c in Sources */, ABB3C6721501C04F00E0C22E /* cocoa_file.mm in Sources */, ABB3C6751501C04F00E0C22E /* cocoa_rom.mm in Sources */, AB29B16418313AF5009B7982 /* slot2.cpp in Sources */, ABB3C6781501C04F00E0C22E /* slot1_none.cpp in Sources */, AB29B16818313C14009B7982 /* slot2_auto.cpp in Sources */, AB9038B417C5ED2200F410BD /* slot1_retail_mcrom.cpp in Sources */, + AB49B546281687B90069F1D7 /* ftmm.c in Sources */, ABB3C6791501C04F00E0C22E /* slot1_r4.cpp in Sources */, AB2ABA3E1C9F9CFA00173B15 /* async_job.c in Sources */, + AB49B53A281687B90069F1D7 /* cff.c in Sources */, ABB3C67A1501C04F00E0C22E /* slot1_retail_nand.cpp in Sources */, ABB3C67C1501C04F00E0C22E /* slot2_expMemory.cpp in Sources */, ABB3C67D1501C04F00E0C22E /* slot2_gbagame.cpp in Sources */, @@ -9046,17 +9086,26 @@ ABB3C6801501C04F00E0C22E /* slot2_none.cpp in Sources */, ABB3C6811501C04F00E0C22E /* slot2_paddle.cpp in Sources */, ABB3C6821501C04F00E0C22E /* slot2_piano.cpp in Sources */, + AB49B541281687B90069F1D7 /* ftgasp.c in Sources */, ABB3C6831501C04F00E0C22E /* slot2_rumblepak.cpp in Sources */, ABB3C6841501C04F00E0C22E /* 2xsai.cpp in Sources */, ABC503B01AAC42C2002FCD43 /* coreaudiosound.cpp in Sources */, ABB3C6851501C04F00E0C22E /* bilinear.cpp in Sources */, + AB49B54A281687B90069F1D7 /* ftstroke.c in Sources */, + AB49B53D281687B90069F1D7 /* ftbitmap.c in Sources */, + AB49B53B281687B90069F1D7 /* ftbase.c in Sources */, ABB3C6861501C04F00E0C22E /* epx.cpp in Sources */, ABB3C6871501C04F00E0C22E /* hq2x.cpp in Sources */, ABB1C94B1F5281AE0004844F /* ClientExecutionControl.cpp in Sources */, ABB3C6881501C04F00E0C22E /* hq4x.cpp in Sources */, ABB3C6891501C04F00E0C22E /* lq2x.cpp in Sources */, + AB49B558281707B90069F1D7 /* ClientDisplayView.cpp in Sources */, + AB49B551281687B90069F1D7 /* sfnt.c in Sources */, + AB49B555281687B90069F1D7 /* type1cid.c in Sources */, ABB3C68A1501C04F00E0C22E /* scanline.cpp in Sources */, ABB3C68B1501C04F00E0C22E /* AAFilter.cpp in Sources */, + AB49B540281687B90069F1D7 /* ftfstype.c in Sources */, + AB49B53F281687B90069F1D7 /* ftfntfmt.c in Sources */, ABB3C68C1501C04F00E0C22E /* cpu_detect_x86_gcc.cpp in Sources */, ABB3C68D1501C04F00E0C22E /* FIFOSampleBuffer.cpp in Sources */, AB9038A817C5ECFD00F410BD /* advanscene.cpp in Sources */, @@ -9083,16 +9132,21 @@ ABB3C69D1501C04F00E0C22E /* disc.cpp in Sources */, ABB3C69E1501C04F00E0C22E /* fatdir.cpp in Sources */, AB11AD8C1F6757F800CB298E /* ClientInputHandler.cpp in Sources */, + AB49B54E281687B90069F1D7 /* psaux.c in Sources */, + AB49B54D281687B90069F1D7 /* fttype1.c in Sources */, ABB3C69F1501C04F00E0C22E /* fatfile.cpp in Sources */, ABB3C6A01501C04F00E0C22E /* file_allocation_table.cpp in Sources */, ABB3C6A11501C04F00E0C22E /* filetime.cpp in Sources */, + AB49B543281687B90069F1D7 /* ftgxval.c in Sources */, ABB3C6A21501C04F00E0C22E /* libfat.cpp in Sources */, ABB3C6A31501C04F00E0C22E /* libfat_public_api.cpp in Sources */, ABB3C6A41501C04F00E0C22E /* lock.cpp in Sources */, ABB3C6A51501C04F00E0C22E /* partition.cpp in Sources */, ABB3C6A61501C04F00E0C22E /* tinystr.cpp in Sources */, + AB49B554281687B90069F1D7 /* type1.c in Sources */, ABB3C6A71501C04F00E0C22E /* tinyxml.cpp in Sources */, ABB3C6A81501C04F00E0C22E /* tinyxmlerror.cpp in Sources */, + AB49B552281687B90069F1D7 /* smooth.c in Sources */, ABB3C6A91501C04F00E0C22E /* tinyxmlparser.cpp in Sources */, ABADF11E1DEA4CFC00A142B1 /* features_cpu.c in Sources */, ABB3C6AB1501C04F00E0C22E /* datetime.cpp in Sources */, @@ -9105,6 +9159,7 @@ ABB3C6B21501C04F00E0C22E /* xstring.cpp in Sources */, ABB3C6B41501C04F00E0C22E /* arm_instructions.cpp in Sources */, ABB3C6B51501C04F00E0C22E /* armcpu.cpp in Sources */, + AB49B54F281687B90069F1D7 /* pshinter.c in Sources */, ABB3C6B61501C04F00E0C22E /* bios.cpp in Sources */, ABB3C6B71501C04F00E0C22E /* cheatSystem.cpp in Sources */, ABB3C6B81501C04F00E0C22E /* common.cpp in Sources */, @@ -9112,15 +9167,20 @@ AB407F371A6206FB00313213 /* xbrz.cpp in Sources */, AB301BE21D9C8BCF00246A93 /* deposterize.cpp in Sources */, ABB3C6BA1501C04F00E0C22E /* debug.cpp in Sources */, + AB49B545281687B90069F1D7 /* ftlcdfil.c in Sources */, ABB3C6BB1501C04F00E0C22E /* Disassembler.cpp in Sources */, ABB3C6BC1501C04F00E0C22E /* driver.cpp in Sources */, ABB3C6BD1501C04F00E0C22E /* emufile.cpp in Sources */, ABB3C6BE1501C04F00E0C22E /* FIFO.cpp in Sources */, ABB3C6BF1501C04F00E0C22E /* firmware.cpp in Sources */, ABB3C6C01501C04F00E0C22E /* gfx3d.cpp in Sources */, + AB49B5572817075D0069F1D7 /* OGLDisplayOutput_3_2.cpp in Sources */, ABB3C6C11501C04F00E0C22E /* GPU.cpp in Sources */, ABB3C6C31501C04F00E0C22E /* matrix.cpp in Sources */, ABB3C6C41501C04F00E0C22E /* mc.cpp in Sources */, + AB49B548281687B90069F1D7 /* ftpatent.c in Sources */, + AB49B542281687B90069F1D7 /* ftglyph.c in Sources */, + AB552DC8281A079000F48ECD /* OEDisplayView.mm in Sources */, ABB3C6C61501C04F00E0C22E /* MMU.cpp in Sources */, ABB3C6C71501C04F00E0C22E /* movie.cpp in Sources */, AB8B7AAE17CE8C440051CEBF /* slot1comp_protocol.cpp in Sources */, @@ -9130,34 +9190,42 @@ AB2ABA461C9F9CFA00173B15 /* rthreads.c in Sources */, ABB3C6CB1501C04F00E0C22E /* rasterize.cpp in Sources */, ABB3C6CC1501C04F00E0C22E /* readwrite.cpp in Sources */, + AB49B553281687B90069F1D7 /* truetype.c in Sources */, ABB3C6CD1501C04F00E0C22E /* render3D.cpp in Sources */, ABB3C6CE1501C04F00E0C22E /* ROMReader.cpp in Sources */, ABB3C6CF1501C04F00E0C22E /* rtc.cpp in Sources */, ABB3C6D01501C04F00E0C22E /* saves.cpp in Sources */, + AB49B54C281687B90069F1D7 /* ftsystem.c in Sources */, + AB49B544281687B90069F1D7 /* ftinit.c in Sources */, ABB3C6D11501C04F00E0C22E /* slot1.cpp in Sources */, ABB3C6D31501C04F00E0C22E /* SPU.cpp in Sources */, ABB3C6D41501C04F00E0C22E /* texcache.cpp in Sources */, + AB49B53C281687B90069F1D7 /* ftbbox.c in Sources */, ABADF1211DEA4D0000A142B1 /* Database.cpp in Sources */, + AB49B547281687B90069F1D7 /* ftotval.c in Sources */, AB9038BA17C5ED2200F410BD /* slot1comp_rom.cpp in Sources */, ABB3C6D51501C04F00E0C22E /* thumb_instructions.cpp in Sources */, AB2EE13317D57F5000F68622 /* fsnitro.cpp in Sources */, ABB3C6D61501C04F00E0C22E /* version.cpp in Sources */, AB93384A28132CD000851FEA /* OEBuildInterface.cpp in Sources */, AB35BD921DEBF41800844310 /* encoding_utf.c in Sources */, + AB49B550281687B90069F1D7 /* psnames.c in Sources */, ABB3C6D71501C04F00E0C22E /* wifi.cpp in Sources */, ABE9EEEA1501C6EB00D3FB19 /* cocoa_firmware.mm in Sources */, AB1949DB15034F900098793E /* OESoundInterface.mm in Sources */, - AB796C9F15CDCB0F00C59155 /* arm_jit.cpp in Sources */, AB2ABA421C9F9CFA00173B15 /* rsemaphore.c in Sources */, AB000DD91CCC6B4300413F02 /* retro_stat.c in Sources */, + AB49B549281687B90069F1D7 /* ftpfr.c in Sources */, AB68A0DD16B139BC00DE0546 /* OGLRender_3_2.cpp in Sources */, AB9038B717C5ED2200F410BD /* slot1comp_mc.cpp in Sources */, AB3A656316CC5438001F5D4A /* cocoa_GPU.mm in Sources */, AB82445D1704AE9A00B8EE20 /* utilities.c in Sources */, + AB49B556281707590069F1D7 /* OGLDisplayOutput.cpp in Sources */, ABD10AE91715FCDD00B5729D /* audiosamplegenerator.cpp in Sources */, ABD10AEC1715FCDD00B5729D /* mic_ext.cpp in Sources */, ABD10AED17160C9300B5729D /* ringbuffer.cpp in Sources */, ABD10AEE17160CDD00B5729D /* cocoa_input.mm in Sources */, + AB49B53E281687B90069F1D7 /* ftdebug.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -9773,10 +9841,13 @@ "$(inherited)", "\"$(SRCROOT)/openemu\"", ); - GCC_OPTIMIZATION_LEVEL = fast; GCC_PREFIX_HEADER = openemu/DeSmuME_Prefix_OpenEmu.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + _DEBUG, + "DEBUG=1", + METAL_DISABLE_FOR_BUILD_TARGET, + ); INFOPLIST_FILE = "openemu/Info (OpenEmu Plug-in).plist"; - LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_NAME = DeSmuME; WRAPPER_EXTENSION = oecoreplugin; @@ -9799,8 +9870,11 @@ "$(inherited)", "\"$(SRCROOT)/openemu\"", ); - GCC_OPTIMIZATION_LEVEL = fast; GCC_PREFIX_HEADER = openemu/DeSmuME_Prefix_OpenEmu.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + METAL_DISABLE_FOR_BUILD_TARGET, + ); INFOPLIST_FILE = "openemu/Info (OpenEmu Plug-in).plist"; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; diff --git a/desmume/src/frontend/cocoa/cocoa_GPU.mm b/desmume/src/frontend/cocoa/cocoa_GPU.mm index 915ddf282..daf74d97c 100644 --- a/desmume/src/frontend/cocoa/cocoa_GPU.mm +++ b/desmume/src/frontend/cocoa/cocoa_GPU.mm @@ -35,6 +35,8 @@ #ifdef ENABLE_APPLE_METAL #import "userinterface/MacMetalDisplayView.h" #endif +#else + #import "openemu/OEDisplayView.h" #endif #ifdef BOOL @@ -145,10 +147,13 @@ GPU3DInterface *core3DList[GPU_3D_RENDERER_COUNT+1] = { } #endif -#ifdef ENABLE_SHARED_FETCH_OBJECT if (fetchObject == NULL) { +#ifdef PORT_VERSION_OS_X_APP fetchObject = new MacOGLClientFetchObject; +#else + fetchObject = new OE_OGLClientFetchObject; +#endif GPU->SetFramebufferPageCount(OPENGL_FETCH_BUFFER_COUNT); } @@ -156,7 +161,6 @@ GPU3DInterface *core3DList[GPU_3D_RENDERER_COUNT+1] = { gpuEvent->SetFetchObject(fetchObject); GPU->SetWillAutoResolveToCustomBuffer(false); -#endif openglDeviceMaxMultisamples = 0; render3DMultisampleSizeString = @"Off"; @@ -164,7 +168,9 @@ GPU3DInterface *core3DList[GPU_3D_RENDERER_COUNT+1] = { bool isTempContextCreated = OSXOpenGLRendererInit(); if (isTempContextCreated) { + CGLContextObj prevContext = CGLGetCurrentContext(); OSXOpenGLRendererBegin(); + GLint maxSamplesOGL = 0; #if defined(GL_MAX_SAMPLES) @@ -177,6 +183,7 @@ GPU3DInterface *core3DList[GPU_3D_RENDERER_COUNT+1] = { OSXOpenGLRendererEnd(); DestroyOpenGLRenderer(); + CGLSetCurrentContext(prevContext); } return self; @@ -243,10 +250,9 @@ GPU3DInterface *core3DList[GPU_3D_RENDERER_COUNT+1] = { #endif GPU->SetCustomFramebufferSize(w, h); - -#ifdef ENABLE_ASYNC_FETCH fetchObject->SetFetchBuffers(GPU->GetDisplayInfo()); - + +#ifdef ENABLE_ASYNC_FETCH for (size_t i = maxPages - 1; i < maxPages; i--) { semaphore_signal( ((MacGPUFetchObjectAsync *)fetchObject)->SemaphoreFramebufferPageAtIndex(i) ); @@ -315,10 +321,9 @@ GPU3DInterface *core3DList[GPU_3D_RENDERER_COUNT+1] = { #endif GPU->SetColorFormat((NDSColorFormat)colorFormat); - -#ifdef ENABLE_ASYNC_FETCH fetchObject->SetFetchBuffers(GPU->GetDisplayInfo()); - + +#ifdef ENABLE_ASYNC_FETCH for (size_t i = maxPages - 1; i < maxPages; i--) { semaphore_signal( ((MacGPUFetchObjectAsync *)fetchObject)->SemaphoreFramebufferPageAtIndex(i) ); diff --git a/desmume/src/frontend/cocoa/openemu/DeSmuME_Prefix_OpenEmu.pch b/desmume/src/frontend/cocoa/openemu/DeSmuME_Prefix_OpenEmu.pch index 56452b374..4dd987aa6 100644 --- a/desmume/src/frontend/cocoa/openemu/DeSmuME_Prefix_OpenEmu.pch +++ b/desmume/src/frontend/cocoa/openemu/DeSmuME_Prefix_OpenEmu.pch @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 DeSmuME team + Copyright (C) 2012-2022 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,8 +23,9 @@ #define DESMUME_COCOA #define HAVE_OPENGL #define HAVE_LIBZ +#define FT2_BUILD_LIBRARY -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) #define HAVE_JIT #endif diff --git a/desmume/src/frontend/cocoa/openemu/NDSGameCore.h b/desmume/src/frontend/cocoa/openemu/NDSGameCore.h index 87153bfb1..aca3ea8fb 100644 --- a/desmume/src/frontend/cocoa/openemu/NDSGameCore.h +++ b/desmume/src/frontend/cocoa/openemu/NDSGameCore.h @@ -22,8 +22,15 @@ #include "../utilities.h" #include +#include "../ClientExecutionControl.h" +#include "OEDisplayView.h" + +#define SILENCE_DEPRECATION_OPENEMU(expression) SILENCE_DEPRECATION(expression) + +class ClientInputHandler; +class OE_OGLDisplayPresenter; + @class CocoaDSCheatManager; -@class CocoaDSController; @class CocoaDSGPU; @class CocoaDSFirmware; @@ -64,12 +71,22 @@ #define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_NONE "Main Display - None" #define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_NDS "Main Display - Let NDS Decide" #define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_FORCEMAIN "Main Display - Force Main Engine" -#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_FORCETOUCH "Main Display - Force Touch Engine" +#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_FORCESUB "Main Display - Force Sub Engine" #define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_NONE "Touch Display - None" #define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_NDS "Touch Display - Let NDS Decide" #define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_FORCEMAIN "Touch Display - Force Main Engine" -#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_FORCETOUCH "Touch Display - Force Touch Engine" +#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_FORCESUB "Touch Display - Force Sub Engine" + +#define NDSDISPLAYMODE_NAMEKEY_HUD_ENABLE "Enable HUD" +#define NDSDISPLAYMODE_NAMEKEY_HUD_EXECUTIONSPEED "Execution Speed" +#define NDSDISPLAYMODE_NAMEKEY_HUD_VIDEOFPS "Video FPS" +#define NDSDISPLAYMODE_NAMEKEY_HUD_3DRENDERERFPS "3D Renderer FPS" +#define NDSDISPLAYMODE_NAMEKEY_HUD_FRAMEINDEX "Frame Index" +#define NDSDISPLAYMODE_NAMEKEY_HUD_LAGFRAMECOUNTER "Lag Frame Counter" +#define NDSDISPLAYMODE_NAMEKEY_HUD_CPULOADAVERAGE "CPU Load Average" +#define NDSDISPLAYMODE_NAMEKEY_HUD_REALTIMECLOCK "Real-Time Clock" +#define NDSDISPLAYMODE_NAMEKEY_HUD_INPUT "Input" #define NDSDISPLAYMODE_PREFKEY_DISPLAYMODE "displayMode" #define NDSDISPLAYMODE_PREFKEY_LAYOUT "layout" @@ -78,6 +95,15 @@ #define NDSDISPLAYMODE_PREFKEY_SEPARATION "gap" #define NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN "videosource_main" #define NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH "videosource_touch" +#define NDSDISPLAYMODE_PREFKEY_HUD_ENABLE "hud_enable" +#define NDSDISPLAYMODE_PREFKEY_HUD_EXECUTIONSPEED "hud_executionspeed" +#define NDSDISPLAYMODE_PREFKEY_HUD_VIDEOFPS "hud_videofps" +#define NDSDISPLAYMODE_PREFKEY_HUD_3DRENDERERFPS "hud_3drendererfps" +#define NDSDISPLAYMODE_PREFKEY_HUD_FRAMEINDEX "hud_frameindex" +#define NDSDISPLAYMODE_PREFKEY_HUD_LAGFRAMECOUNTER "hud_lagframecounter" +#define NDSDISPLAYMODE_PREFKEY_HUD_CPULOADAVERAGE "hud_cpuloadaverage" +#define NDSDISPLAYMODE_PREFKEY_HUD_REALTIMECLOCK "hud_realtimeclock" +#define NDSDISPLAYMODE_PREFKEY_HUD_INPUT "hud_input" // These IDs are used to maintain the data associations for all of // the display mode menu items. @@ -110,60 +136,137 @@ enum NDSDisplayOptionID NDSDisplayOptionID_VideoSourceMain_None, NDSDisplayOptionID_VideoSourceMain_NDS, NDSDisplayOptionID_VideoSourceMain_ForceMain, - NDSDisplayOptionID_VideoSourceMain_ForceTouch, + NDSDisplayOptionID_VideoSourceMain_ForceSub, NDSDisplayOptionID_VideoSourceTouch_None, NDSDisplayOptionID_VideoSourceTouch_NDS, NDSDisplayOptionID_VideoSourceTouch_ForceMain, - NDSDisplayOptionID_VideoSourceTouch_ForceTouch, + NDSDisplayOptionID_VideoSourceTouch_ForceSub, + + NDSDisplayOptionID_HUD_Enable, + NDSDisplayOptionID_HUD_ExecutionSpeed, + NDSDisplayOptionID_HUD_VideoFPS, + NDSDisplayOptionID_HUD_3DRendererFPS, + NDSDisplayOptionID_HUD_FrameIndex, + NDSDisplayOptionID_HUD_LagFrameCounter, + NDSDisplayOptionID_HUD_CPULoadAverage, + NDSDisplayOptionID_HUD_RealTimeClock, + NDSDisplayOptionID_HUD_Input, NDSDisplayOptionID_Count }; -// Used to track the bits that each option group uses, useful for clearing the -// entire group of bits prior to setting a single bit for that particular group. -enum NDSDisplayOptionStateBitmask -{ - NDSDisplayOptionStateBitmask_DisplayMode = (1 << NDSDisplayOptionID_Mode_DualScreen) | (1 << NDSDisplayOptionID_Mode_Main) | (1 << NDSDisplayOptionID_Mode_Touch), - NDSDisplayOptionStateBitmask_Rotation = (1 << NDSDisplayOptionID_Rotation_0) | (1 << NDSDisplayOptionID_Rotation_90) | (1 << NDSDisplayOptionID_Rotation_180) | (1 << NDSDisplayOptionID_Rotation_270), - NDSDisplayOptionStateBitmask_Layout = (1 << NDSDisplayOptionID_Layout_Vertical) | (1 << NDSDisplayOptionID_Layout_Horizontal) | (1 << NDSDisplayOptionID_Layout_Hybrid_2_1) | (1 << NDSDisplayOptionID_Layout_Hybrid_16_9) | (1 << NDSDisplayOptionID_Layout_Hybrid_16_10), - NDSDisplayOptionStateBitmask_Order = (1 << NDSDisplayOptionID_Order_MainFirst) | (1 << NDSDisplayOptionID_Order_TouchFirst), - NDSDisplayOptionStateBitmask_Separation = (1 << NDSDisplayOptionID_Separation_0) | (1 << NDSDisplayOptionID_Separation_50) | (1 << NDSDisplayOptionID_Separation_100) | (1 << NDSDisplayOptionID_Separation_150) | (1 << NDSDisplayOptionID_Separation_200), - NDSDisplayOptionStateBitmask_VideoSourceMain = (1 << NDSDisplayOptionID_VideoSourceMain_None) | (1 << NDSDisplayOptionID_VideoSourceMain_NDS) | (1 << NDSDisplayOptionID_VideoSourceMain_ForceMain) | (1 << NDSDisplayOptionID_VideoSourceMain_ForceTouch), - NDSDisplayOptionStateBitmask_VideoSourceTouch = (1 << NDSDisplayOptionID_VideoSourceTouch_None) | (1 << NDSDisplayOptionID_VideoSourceTouch_NDS) | (1 << NDSDisplayOptionID_VideoSourceTouch_ForceMain) | (1 << NDSDisplayOptionID_VideoSourceTouch_ForceTouch) -}; +// Bitmasks that define the groupings for certain display mode options. +#define NDSDISPLAYMODE_GROUPBITMASK_DISPLAYMODE ((1ULL << NDSDisplayOptionID_Mode_DualScreen) | \ + (1ULL << NDSDisplayOptionID_Mode_Main) | \ + (1ULL << NDSDisplayOptionID_Mode_Touch)) + +#define NDSDISPLAYMODE_GROUPBITMASK_ROTATION ((1ULL << NDSDisplayOptionID_Rotation_0) | \ + (1ULL << NDSDisplayOptionID_Rotation_90) | \ + (1ULL << NDSDisplayOptionID_Rotation_180) | \ + (1ULL << NDSDisplayOptionID_Rotation_270)) + +#define NDSDISPLAYMODE_GROUPBITMASK_LAYOUT ((1ULL << NDSDisplayOptionID_Layout_Vertical) | \ + (1ULL << NDSDisplayOptionID_Layout_Horizontal) | \ + (1ULL << NDSDisplayOptionID_Layout_Hybrid_2_1) | \ + (1ULL << NDSDisplayOptionID_Layout_Hybrid_16_9) | \ + (1ULL << NDSDisplayOptionID_Layout_Hybrid_16_10)) + +#define NDSDISPLAYMODE_GROUPBITMASK_ORDER ((1ULL << NDSDisplayOptionID_Order_MainFirst) | \ + (1ULL << NDSDisplayOptionID_Order_TouchFirst)) + +#define NDSDISPLAYMODE_GROUPBITMASK_SEPARATION ((1ULL << NDSDisplayOptionID_Separation_0) | \ + (1ULL << NDSDisplayOptionID_Separation_50) | \ + (1ULL << NDSDisplayOptionID_Separation_100) | \ + (1ULL << NDSDisplayOptionID_Separation_150) | \ + (1ULL << NDSDisplayOptionID_Separation_200)) + +#define NDSDISPLAYMODE_GROUPBITMASK_VIDEOSOURCEMAIN ((1ULL << NDSDisplayOptionID_VideoSourceMain_None) | \ + (1ULL << NDSDisplayOptionID_VideoSourceMain_NDS) | \ + (1ULL << NDSDisplayOptionID_VideoSourceMain_ForceMain) | \ + (1ULL << NDSDisplayOptionID_VideoSourceMain_ForceSub)) + +#define NDSDISPLAYMODE_GROUPBITMASK_VIDEOSOURCETOUCH ((1ULL << NDSDisplayOptionID_VideoSourceTouch_None) | \ + (1ULL << NDSDisplayOptionID_VideoSourceTouch_NDS) | \ + (1ULL << NDSDisplayOptionID_VideoSourceTouch_ForceMain) | \ + (1ULL << NDSDisplayOptionID_VideoSourceTouch_ForceSub)) // Describes the data associations for a single display mode menu item, used for generating // the NSDictionary items that are part of the display mode menu descriptor. This struct // represents the immutable portions of the data. The mutable parts, such as the menu item // states, are handled elsewhere. -struct NDSDisplayMenuItem +struct OEMenuItemDesc { - NSString *nameKey; - NSString *prefKey; + NSString *nameKey; // The displayed name of the menu item. Must conform to OEGameCoreDisplayModeNameKey. + NSString *prefKey; // The user defaults key of the menu item. Must conform to OEGameCoreDisplayModePrefKeyNameKey. + + uint64_t groupBitmask; // The associated state bits of all menu items that belong in the same group. + // Assigning zero or non-zero controls the behavior of this menu item. + // Zero - Toggle type. This item can be toggled and/or selected all by itself. + // Non-zero - Group type. This item cannot be toggled, and selection is mutually exclusive + // with its associated group. The group is defined by using these bits. + + + // Note: Alternate menu item names are unsupported in OpenEmu. This feature is currently unimplemented. + // + // OpenEmu ties the presented menu item state, denoted by a check mark, with writing out that state + // to user defaults. In other words, using alternate names for presentation in lieu of a check mark + // will disrupt OpenEmu's user defaults system. And so to retain a consistent user defaults behavior, + // we cannot use alternate menu item names in OpenEmu. + // + // This item exists here just in case OpenEmu ever decides to decouple presentation with state. If + // they do, then we'll have another presentation option here. + NSString *altNameKey; // The alternate displayed name of the menu item. Must conform to OEGameCoreDisplayModeNameKey. + // Only used for toggle-type items and ignored for group-type items. + // nil value - Do not use altNameKey when toggle, but use a check mark to denote state. + // Assigned value - Switches between nameKey and altNameKey to denote state. }; -typedef NDSDisplayMenuItem NDSDisplayMenuItem; +typedef struct OEMenuItemDesc OEMenuItemDesc; @interface NDSGameCore : OEGameCore { + char _hudFontPath[4096]; // This should be plenty for storing a file path! apple_unfairlock_t unfairlockDisplayMode; pthread_rwlock_t rwlockCoreExecute; - NSPoint touchLocation; NSMutableDictionary *addedCheatsDict; CocoaDSCheatManager *cdsCheats; - CocoaDSController *cdsController; CocoaDSGPU *cdsGPU; CocoaDSFirmware *cdsFirmware; + MacInputHandler *_inputHandler; + OEIntPoint _lastTouchLocation; + bool _isInitialTouchPress; + bool _isTouchPressInMajorDisplay; + NSUInteger inputID[OENDSButtonCount]; // Key = OpenEmu's input ID, Value = DeSmuME's input ID OEIntRect _displayRect; OEIntSize _displayAspectRatio; + OEIntSize _displayBufferSize; + OEIntSize _OEViewSize; + + CGLContextObj _videoContext; + OE_OGLDisplayPresenter *_cdp; + + NSTimer *_fpsTimer; + BOOL _isTimerAtSecond; + apple_unfairlock_t _unfairlockReceivedFrameIndex; + apple_unfairlock_t _unfairlockNDSFrameInfo; + + uint32_t _receivedFrameIndex; + uint32_t _currentReceivedFrameIndex; + uint32_t _receivedFrameCount; + + double _executionSpeedAverageFramesCollected; + + ClientFrameInfo _clientFrameInfo; + NDSFrameInfo _ndsFrameInfo; // Records the display mode menu states on a per-bit basis. This only works because OpenEmu // tracks only binary states for the menu items. Currently, there are 27 different states // to keep track of, which leaves us another 37 states for future use. - uint64_t ndsDisplayMode; + uint64_t _displayModeStatesPending; + uint64_t _displayModeStatesApplied; // For simplicity's sake, we use NDSDisplayOptionID numbers to maintain all of the internal data // associations for display mode menu items. However, OpenEmu uses OEGameCoreDisplayModeNameKey @@ -177,11 +280,17 @@ typedef NDSDisplayMenuItem NDSDisplayMenuItem; } @property (retain) CocoaDSCheatManager *cdsCheats; -@property (retain) CocoaDSController *cdsController; @property (retain) CocoaDSGPU *cdsGPU; @property (retain) CocoaDSFirmware *cdsFirmware; @property (assign) uint64_t ndsDisplayMode; +- (void) initVideoWithCurrentOpenEmuContext; + +- (void) newFPSTimer; +- (void) getTimedEmulatorStatistics:(NSTimer *)timer; + +- (uint64_t) switchDisplayModeState:(uint64_t)displayModeState nameKey:(NSString *)nameKey; +- (uint64_t) setDisplayModeState:(uint64_t)displayModeState optionID:(NDSDisplayOptionID)optionID state:(NSNumber *)stateObj; - (NSDictionary *) generateDisplayModeItemByID:(NDSDisplayOptionID)optionID states:(const uint64_t)states; @end diff --git a/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm b/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm index 01489104d..6809d19fb 100644 --- a/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm +++ b/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm @@ -27,65 +27,78 @@ #import "../cocoa_input.h" #import "../ClientDisplayView.h" #import "../ClientInputHandler.h" +#include "../OGLDisplayOutput_3_2.h" + +#import "OEDisplayView.h" -#include #include "../../NDSSystem.h" #include "../../GPU.h" #undef BOOL -#define DISPLAYMODE_STATEBIT_CHECK(_STATEBITS_, _ID_) ((((_STATEBITS_) >> (_ID_)) & 1) != 0) +#define DISPLAYMODE_STATEBIT_CHECK(_STATEBITS_, _ID_) ((((_STATEBITS_) >> ((uint64_t)_ID_)) & 1ULL) != 0ULL) #define DISPLAYMODE_STATEBITGROUP_CLEAR(_STATEBITS_, _BITMASK_) _STATEBITS_ = (((_STATEBITS_) | (_BITMASK_)) ^ (_BITMASK_)) -static const NDSDisplayMenuItem kDisplayModeItem[NDSDisplayOptionID_Count] = { - { @NDSDISPLAYMODE_NAMEKEY_MODE_DUALSCREEN, @NDSDISPLAYMODE_PREFKEY_DISPLAYMODE }, - { @NDSDISPLAYMODE_NAMEKEY_MODE_MAIN, @NDSDISPLAYMODE_PREFKEY_DISPLAYMODE }, - { @NDSDISPLAYMODE_NAMEKEY_MODE_TOUCH, @NDSDISPLAYMODE_PREFKEY_DISPLAYMODE }, +static const OEMenuItemDesc kDisplayModeItem[NDSDisplayOptionID_Count] = { + { @NDSDISPLAYMODE_NAMEKEY_MODE_DUALSCREEN, @NDSDISPLAYMODE_PREFKEY_DISPLAYMODE, NDSDISPLAYMODE_GROUPBITMASK_DISPLAYMODE, nil }, + { @NDSDISPLAYMODE_NAMEKEY_MODE_MAIN, @NDSDISPLAYMODE_PREFKEY_DISPLAYMODE, NDSDISPLAYMODE_GROUPBITMASK_DISPLAYMODE, nil }, + { @NDSDISPLAYMODE_NAMEKEY_MODE_TOUCH, @NDSDISPLAYMODE_PREFKEY_DISPLAYMODE, NDSDISPLAYMODE_GROUPBITMASK_DISPLAYMODE, nil }, - { @NDSDISPLAYMODE_NAMEKEY_ROTATION_0, @NDSDISPLAYMODE_PREFKEY_ROTATION }, - { @NDSDISPLAYMODE_NAMEKEY_ROTATION_90, @NDSDISPLAYMODE_PREFKEY_ROTATION }, - { @NDSDISPLAYMODE_NAMEKEY_ROTATION_180, @NDSDISPLAYMODE_PREFKEY_ROTATION }, - { @NDSDISPLAYMODE_NAMEKEY_ROTATION_270, @NDSDISPLAYMODE_PREFKEY_ROTATION }, + { @NDSDISPLAYMODE_NAMEKEY_ROTATION_0, @NDSDISPLAYMODE_PREFKEY_ROTATION, NDSDISPLAYMODE_GROUPBITMASK_ROTATION, nil }, + { @NDSDISPLAYMODE_NAMEKEY_ROTATION_90, @NDSDISPLAYMODE_PREFKEY_ROTATION, NDSDISPLAYMODE_GROUPBITMASK_ROTATION, nil }, + { @NDSDISPLAYMODE_NAMEKEY_ROTATION_180, @NDSDISPLAYMODE_PREFKEY_ROTATION, NDSDISPLAYMODE_GROUPBITMASK_ROTATION, nil }, + { @NDSDISPLAYMODE_NAMEKEY_ROTATION_270, @NDSDISPLAYMODE_PREFKEY_ROTATION, NDSDISPLAYMODE_GROUPBITMASK_ROTATION, nil }, - { @NDSDISPLAYMODE_NAMEKEY_LAYOUT_VERTICAL, @NDSDISPLAYMODE_PREFKEY_LAYOUT }, - { @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HORIZONTAL, @NDSDISPLAYMODE_PREFKEY_LAYOUT }, - { @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_2_1, @NDSDISPLAYMODE_PREFKEY_LAYOUT }, - { @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_16_9, @NDSDISPLAYMODE_PREFKEY_LAYOUT }, - { @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_16_10, @NDSDISPLAYMODE_PREFKEY_LAYOUT }, + { @NDSDISPLAYMODE_NAMEKEY_LAYOUT_VERTICAL, @NDSDISPLAYMODE_PREFKEY_LAYOUT, NDSDISPLAYMODE_GROUPBITMASK_LAYOUT, nil }, + { @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HORIZONTAL, @NDSDISPLAYMODE_PREFKEY_LAYOUT, NDSDISPLAYMODE_GROUPBITMASK_LAYOUT, nil }, + { @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_2_1, @NDSDISPLAYMODE_PREFKEY_LAYOUT, NDSDISPLAYMODE_GROUPBITMASK_LAYOUT, nil }, + { @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_16_9, @NDSDISPLAYMODE_PREFKEY_LAYOUT, NDSDISPLAYMODE_GROUPBITMASK_LAYOUT, nil }, + { @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_16_10, @NDSDISPLAYMODE_PREFKEY_LAYOUT, NDSDISPLAYMODE_GROUPBITMASK_LAYOUT, nil }, - { @NDSDISPLAYMODE_NAMEKEY_DISPLAYORDER_MAIN, @NDSDISPLAYMODE_PREFKEY_ORDER }, - { @NDSDISPLAYMODE_NAMEKEY_DISPLAYORDER_TOUCH, @NDSDISPLAYMODE_PREFKEY_ORDER }, + { @NDSDISPLAYMODE_NAMEKEY_DISPLAYORDER_MAIN, @NDSDISPLAYMODE_PREFKEY_ORDER, NDSDISPLAYMODE_GROUPBITMASK_ORDER, nil }, + { @NDSDISPLAYMODE_NAMEKEY_DISPLAYORDER_TOUCH, @NDSDISPLAYMODE_PREFKEY_ORDER, NDSDISPLAYMODE_GROUPBITMASK_ORDER, nil }, - { @NDSDISPLAYMODE_NAMEKEY_SEPARATION_0, @NDSDISPLAYMODE_PREFKEY_SEPARATION }, - { @NDSDISPLAYMODE_NAMEKEY_SEPARATION_50, @NDSDISPLAYMODE_PREFKEY_SEPARATION }, - { @NDSDISPLAYMODE_NAMEKEY_SEPARATION_100, @NDSDISPLAYMODE_PREFKEY_SEPARATION }, - { @NDSDISPLAYMODE_NAMEKEY_SEPARATION_150, @NDSDISPLAYMODE_PREFKEY_SEPARATION }, - { @NDSDISPLAYMODE_NAMEKEY_SEPARATION_200, @NDSDISPLAYMODE_PREFKEY_SEPARATION }, + { @NDSDISPLAYMODE_NAMEKEY_SEPARATION_0, @NDSDISPLAYMODE_PREFKEY_SEPARATION, NDSDISPLAYMODE_GROUPBITMASK_SEPARATION, nil }, + { @NDSDISPLAYMODE_NAMEKEY_SEPARATION_50, @NDSDISPLAYMODE_PREFKEY_SEPARATION, NDSDISPLAYMODE_GROUPBITMASK_SEPARATION, nil }, + { @NDSDISPLAYMODE_NAMEKEY_SEPARATION_100, @NDSDISPLAYMODE_PREFKEY_SEPARATION, NDSDISPLAYMODE_GROUPBITMASK_SEPARATION, nil }, + { @NDSDISPLAYMODE_NAMEKEY_SEPARATION_150, @NDSDISPLAYMODE_PREFKEY_SEPARATION, NDSDISPLAYMODE_GROUPBITMASK_SEPARATION, nil }, + { @NDSDISPLAYMODE_NAMEKEY_SEPARATION_200, @NDSDISPLAYMODE_PREFKEY_SEPARATION, NDSDISPLAYMODE_GROUPBITMASK_SEPARATION, nil }, - { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_NONE, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN }, - { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_NDS, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN }, - { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_FORCEMAIN, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN }, - { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_FORCETOUCH, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN }, + { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_NONE, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN, NDSDISPLAYMODE_GROUPBITMASK_VIDEOSOURCEMAIN, nil }, + { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_NDS, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN, NDSDISPLAYMODE_GROUPBITMASK_VIDEOSOURCEMAIN, nil }, + { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_FORCEMAIN, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN, NDSDISPLAYMODE_GROUPBITMASK_VIDEOSOURCEMAIN, nil }, + { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_FORCESUB, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN, NDSDISPLAYMODE_GROUPBITMASK_VIDEOSOURCEMAIN, nil }, - { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_NONE, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH }, - { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_NDS, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH }, - { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_FORCEMAIN, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH }, - { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_FORCETOUCH, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH } + { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_NONE, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH, NDSDISPLAYMODE_GROUPBITMASK_VIDEOSOURCETOUCH, nil }, + { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_NDS, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH, NDSDISPLAYMODE_GROUPBITMASK_VIDEOSOURCETOUCH, nil }, + { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_FORCEMAIN, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH, NDSDISPLAYMODE_GROUPBITMASK_VIDEOSOURCETOUCH, nil }, + { @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_FORCESUB, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH, NDSDISPLAYMODE_GROUPBITMASK_VIDEOSOURCETOUCH, nil }, + + { @NDSDISPLAYMODE_NAMEKEY_HUD_ENABLE, @NDSDISPLAYMODE_PREFKEY_HUD_ENABLE, 0, nil }, + { @NDSDISPLAYMODE_NAMEKEY_HUD_EXECUTIONSPEED, @NDSDISPLAYMODE_PREFKEY_HUD_EXECUTIONSPEED, 0, nil }, + { @NDSDISPLAYMODE_NAMEKEY_HUD_VIDEOFPS, @NDSDISPLAYMODE_PREFKEY_HUD_VIDEOFPS, 0, nil }, + { @NDSDISPLAYMODE_NAMEKEY_HUD_3DRENDERERFPS, @NDSDISPLAYMODE_PREFKEY_HUD_3DRENDERERFPS, 0, nil }, + { @NDSDISPLAYMODE_NAMEKEY_HUD_FRAMEINDEX, @NDSDISPLAYMODE_PREFKEY_HUD_FRAMEINDEX, 0, nil }, + { @NDSDISPLAYMODE_NAMEKEY_HUD_LAGFRAMECOUNTER, @NDSDISPLAYMODE_PREFKEY_HUD_LAGFRAMECOUNTER, 0, nil }, + { @NDSDISPLAYMODE_NAMEKEY_HUD_CPULOADAVERAGE, @NDSDISPLAYMODE_PREFKEY_HUD_CPULOADAVERAGE, 0, nil }, + { @NDSDISPLAYMODE_NAMEKEY_HUD_REALTIMECLOCK, @NDSDISPLAYMODE_PREFKEY_HUD_REALTIMECLOCK, 0, nil }, + { @NDSDISPLAYMODE_NAMEKEY_HUD_INPUT, @NDSDISPLAYMODE_PREFKEY_HUD_INPUT, 0, nil } }; -static const uint64_t kDisplayModeStatesDefault = (1 << NDSDisplayOptionID_Mode_DualScreen) | - (1 << NDSDisplayOptionID_Rotation_0) | - (1 << NDSDisplayOptionID_Layout_Vertical) | - (1 << NDSDisplayOptionID_Order_MainFirst) | - (1 << NDSDisplayOptionID_Separation_0) | - (1 << NDSDisplayOptionID_VideoSourceMain_NDS) | - (1 << NDSDisplayOptionID_VideoSourceTouch_NDS); +static const uint64_t kDisplayModeStatesDefault = (1LLU << NDSDisplayOptionID_Mode_DualScreen) | + (1LLU << NDSDisplayOptionID_Rotation_0) | + (1LLU << NDSDisplayOptionID_Layout_Vertical) | + (1LLU << NDSDisplayOptionID_Order_MainFirst) | + (1LLU << NDSDisplayOptionID_Separation_0) | + (1LLU << NDSDisplayOptionID_VideoSourceMain_NDS) | + (1LLU << NDSDisplayOptionID_VideoSourceTouch_NDS) | + (1LLU << NDSDisplayOptionID_HUD_ExecutionSpeed) | + (1LLU << NDSDisplayOptionID_HUD_VideoFPS); volatile bool execute = true; @implementation NDSGameCore -@synthesize cdsController; @synthesize cdsGPU; @synthesize cdsFirmware; @synthesize cdsCheats; @@ -99,13 +112,30 @@ volatile bool execute = true; return self; } + // Retrieve the file path for the HUD font file. + // Because this file must be reloaded due to repeated context changes, we'll + // need to maintain a copy of the file path. + NSString *fontPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"SourceSansPro-Bold" ofType:@"otf"]; + const char *gameCoreFontPath = [[NSFileManager defaultManager] fileSystemRepresentationWithPath:fontPath]; + memset(_hudFontPath, 0, sizeof(_hudFontPath)); + strlcpy(_hudFontPath, gameCoreFontPath, sizeof(_hudFontPath)); + + _fpsTimer = nil; + _videoContext = NULL; + _cdp = NULL; + cdsGPU = NULL; + // Set up threading locks + _unfairlockReceivedFrameIndex = apple_unfairlock_create(); + _unfairlockNDSFrameInfo = apple_unfairlock_create(); + unfairlockDisplayMode = apple_unfairlock_create(); - pthread_rwlock_init(&rwlockCoreExecute, NULL); // Set up input handling - touchLocation.x = 0; - touchLocation.y = 0; + _lastTouchLocation.x = 0; + _lastTouchLocation.y = 0; + _isInitialTouchPress = false; + _isTouchPressInMajorDisplay = false; inputID[OENDSButtonUp] = NDSInputID_Up; inputID[OENDSButtonDown] = NDSInputID_Down; @@ -123,6 +153,16 @@ volatile bool execute = true; inputID[OENDSButtonLid] = NDSInputID_Lid; inputID[OENDSButtonDebug] = NDSInputID_Debug; + memset(&_clientFrameInfo, 0, sizeof(_clientFrameInfo)); + _ndsFrameInfo.clear(); + + _isTimerAtSecond = NO; + _receivedFrameIndex = 0; + _currentReceivedFrameIndex = 0; + _receivedFrameCount = 0; + + _executionSpeedAverageFramesCollected = 0.0; + // Set up the emulation core CommonSettings.advanced_timing = true; CommonSettings.jit_max_block_size = 12; @@ -131,17 +171,11 @@ volatile bool execute = true; #else CommonSettings.use_jit = false; #endif + pthread_rwlock_init(&rwlockCoreExecute, NULL); NDS_Init(); - // Set up the DS GPU - cdsGPU = [[CocoaDSGPU alloc] init]; - [cdsGPU setRender3DThreads:0]; // Pass 0 to automatically set the number of rendering threads - [cdsGPU setRender3DRenderingEngine:CORE3DLIST_SWRASTERIZE]; - [cdsGPU setGpuScale:1]; - [cdsGPU setGpuColorFormat:NDSColorFormat_BGR666_Rev]; - // Set up the DS controller - cdsController = [[CocoaDSController alloc] init]; + _inputHandler = new MacInputHandler; // Set up the cheat system cdsCheats = [[CocoaDSCheatManager alloc] init]; @@ -157,7 +191,15 @@ volatile bool execute = true; CommonSettings.spuInterpolationMode = SPUInterpolation_Cosine; CommonSettings.SPU_sync_mode = SPU_SYNC_MODE_SYNCHRONOUS; CommonSettings.SPU_sync_method = SPU_SYNC_METHOD_N; - openEmuSoundInterfaceBuffer = [self audioBufferAtIndex:0]; + + if ([self respondsToSelector:@selector(audioBufferAtIndex:)]) + { + openEmuSoundInterfaceBuffer = [self audioBufferAtIndex:0]; + } + else + { + SILENCE_DEPRECATION_OPENEMU( openEmuSoundInterfaceBuffer = [self ringBufferAtIndex:0]; ) + } NSInteger result = SPU_ChangeSoundCore(SNDCORE_OPENEMU, (int)SPU_BUFFER_BYTES); if (result == -1) @@ -169,8 +211,12 @@ volatile bool execute = true; SPU_SetVolume(100); // Set up the DS display - ndsDisplayMode = kDisplayModeStatesDefault; - _displayRect = OEIntRectMake(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2); + _displayModeStatesPending = kDisplayModeStatesDefault; + _displayModeStatesApplied = kDisplayModeStatesDefault; + _OEViewSize.width = GPU_FRAMEBUFFER_NATIVE_WIDTH; + _OEViewSize.height = GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2; + _displayBufferSize = OEIntSizeMake(_OEViewSize.width, _OEViewSize.height); + _displayRect = OEIntRectMake(0, 0, _OEViewSize.width, _OEViewSize.height); _displayAspectRatio = OEIntSizeMake(2, 3); _displayModeIDFromString = [[NSDictionary alloc] initWithObjectsAndKeys: @@ -198,15 +244,25 @@ volatile bool execute = true; [NSNumber numberWithInteger:NDSDisplayOptionID_Separation_150], kDisplayModeItem[NDSDisplayOptionID_Separation_150].nameKey, [NSNumber numberWithInteger:NDSDisplayOptionID_Separation_200], kDisplayModeItem[NDSDisplayOptionID_Separation_200].nameKey, - [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_None], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_None].nameKey, - [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_NDS], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_NDS].nameKey, - [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_ForceMain], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_ForceMain].nameKey, - [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_ForceTouch], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_ForceTouch].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_None], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_None].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_NDS], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_NDS].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_ForceMain], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_ForceMain].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_ForceSub], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_ForceSub].nameKey, - [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_None], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_None].nameKey, - [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_NDS], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_NDS].nameKey, - [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_ForceMain], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_ForceMain].nameKey, - [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_ForceTouch], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_ForceTouch].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_None], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_None].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_NDS], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_NDS].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_ForceMain], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_ForceMain].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_ForceSub], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_ForceSub].nameKey, + + [NSNumber numberWithInteger:NDSDisplayOptionID_HUD_Enable], kDisplayModeItem[NDSDisplayOptionID_HUD_Enable].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_HUD_ExecutionSpeed], kDisplayModeItem[NDSDisplayOptionID_HUD_ExecutionSpeed].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_HUD_VideoFPS], kDisplayModeItem[NDSDisplayOptionID_HUD_VideoFPS].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_HUD_3DRendererFPS], kDisplayModeItem[NDSDisplayOptionID_HUD_3DRendererFPS].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_HUD_FrameIndex], kDisplayModeItem[NDSDisplayOptionID_HUD_FrameIndex].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_HUD_LagFrameCounter], kDisplayModeItem[NDSDisplayOptionID_HUD_LagFrameCounter].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_HUD_CPULoadAverage], kDisplayModeItem[NDSDisplayOptionID_HUD_CPULoadAverage].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_HUD_RealTimeClock], kDisplayModeItem[NDSDisplayOptionID_HUD_RealTimeClock].nameKey, + [NSNumber numberWithInteger:NDSDisplayOptionID_HUD_Input], kDisplayModeItem[NDSDisplayOptionID_HUD_Input].nameKey, nil]; return self; @@ -214,62 +270,281 @@ volatile bool execute = true; - (void)dealloc { - SPU_ChangeSoundCore(SNDCORE_DUMMY, 0); - NDS_DeInit(); + [_fpsTimer invalidate]; + _fpsTimer = nil; [addedCheatsDict release]; [cdsCheats release]; - [cdsController release]; - [cdsGPU release]; [cdsFirmware release]; [_displayModeIDFromString release]; + CGLReleaseContext(_videoContext); + _videoContext = NULL; + + delete _cdp; + delete _inputHandler; + + SPU_ChangeSoundCore(SNDCORE_DUMMY, 0); + NDS_DeInit(); + + // Release cdsGPU after NDS_DeInit() to avoid potential crashes. + [cdsGPU release]; + pthread_rwlock_destroy(&rwlockCoreExecute); apple_unfairlock_destroy(unfairlockDisplayMode); + apple_unfairlock_destroy(_unfairlockReceivedFrameIndex); + apple_unfairlock_destroy(_unfairlockNDSFrameInfo); + [super dealloc]; } +- (void) initVideoWithCurrentOpenEmuContext +{ + CGLContextObj oldContext = _videoContext; + OE_OGLClientFetchObject *fetchObj = NULL; + + // Set up the NDS GPU + if (cdsGPU == nil) + { + cdsGPU = [[CocoaDSGPU alloc] init]; + [cdsGPU setRender3DThreads:0]; // Pass 0 to automatically set the number of rendering threads + [cdsGPU setRender3DRenderingEngine:CORE3DLIST_SWRASTERIZE]; + [cdsGPU setGpuScale:1]; + [cdsGPU setGpuColorFormat:NDSColorFormat_BGR666_Rev]; + + fetchObj = (OE_OGLClientFetchObject *)[cdsGPU fetchObject]; + } + else + { + fetchObj = (OE_OGLClientFetchObject *)[cdsGPU fetchObject]; + fetchObj->Init(); + fetchObj->SetFetchBuffers( GPU->GetDisplayInfo() ); + } + + _videoContext = fetchObj->GetContext(); + CGLRetainContext(_videoContext); + + // Set up the presenter + if (_cdp == NULL) + { + _cdp = new OE_OGLDisplayPresenter(fetchObj); + _cdp->Init(); + _cdp->SetHUDFontPath(_hudFontPath); + + // OpenEmu doesn't provide us with the backing scaling factor, which is used to + // adapt ClientDisplayPresenter to HiDPI/Retina displays. But if OpenEmu ever + // does provide this information, we can give ClientDisplayPresenter this hint. + // For now, just assume that the backing scale is 1.0. + double scaleFactor = 1.0; + if (scaleFactor != 1.0) + { + _cdp->SetScaleFactor(scaleFactor); + } + else + { + _cdp->LoadHUDFont(); + } + + _cdp->SetOutputFilter(OutputFilterTypeID_NearestNeighbor); + _cdp->SetPixelScaler(VideoFilterTypeID_None); + _cdp->SetFiltersPreferGPU(true); + _cdp->SetSourceDeposterize(false); + _cdp->SetHUDColorInputAppliedOnly(0xFFFFFFFF); + _cdp->SetHUDColorInputPendingOnly(0xFFFFFFFF); + _cdp->SetHUDColorInputPendingAndApplied(0xFFFFFFFF); + } + else + { + _cdp->Init(); + _cdp->LoadHUDFont(); + } + + if (oldContext != NULL) + { + CGLReleaseContext(oldContext); + } +} + +- (void) newFPSTimer +{ + if (_fpsTimer != nil) + { + [_fpsTimer invalidate]; + } + + _isTimerAtSecond = NO; + _fpsTimer = [NSTimer timerWithTimeInterval:0.5 + target:self + selector:@selector(getTimedEmulatorStatistics:) + userInfo:nil + repeats:YES]; + + [[NSRunLoop currentRunLoop] addTimer:_fpsTimer forMode:NSRunLoopCommonModes]; +} + +- (void) getTimedEmulatorStatistics:(NSTimer *)timer +{ + // The timer should fire every 0.5 seconds, so only take the frame + // count every other instance the timer fires. + _isTimerAtSecond = !_isTimerAtSecond; + + if (_isTimerAtSecond) + { + apple_unfairlock_lock(_unfairlockReceivedFrameIndex); + _receivedFrameCount = _receivedFrameIndex - _currentReceivedFrameIndex; + _currentReceivedFrameIndex = _receivedFrameIndex; + apple_unfairlock_unlock(_unfairlockReceivedFrameIndex); + } +} + - (uint64_t) ndsDisplayMode { apple_unfairlock_lock(unfairlockDisplayMode); - const uint64_t displayModeStates = ndsDisplayMode; + const uint64_t displayModeStates = _displayModeStatesApplied; apple_unfairlock_unlock(unfairlockDisplayMode); return displayModeStates; } +void UpdateDisplayPropertiesFromStates(uint64_t displayModeStates, ClientDisplayPresenterProperties &outProps) +{ + if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_DualScreen) ) outProps.mode = ClientDisplayMode_Dual; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_Main) ) outProps.mode = ClientDisplayMode_Main; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_Touch) ) outProps.mode = ClientDisplayMode_Touch; + + if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Layout_Vertical) ) outProps.layout = ClientDisplayLayout_Vertical; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Layout_Horizontal) ) outProps.layout = ClientDisplayLayout_Horizontal; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Layout_Hybrid_2_1) ) outProps.layout = ClientDisplayLayout_Hybrid_2_1; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Layout_Hybrid_16_9) ) outProps.layout = ClientDisplayLayout_Hybrid_16_9; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Layout_Hybrid_16_10) ) outProps.layout = ClientDisplayLayout_Hybrid_16_10; + + if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Order_MainFirst) ) outProps.order = ClientDisplayOrder_MainFirst; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Order_TouchFirst) ) outProps.order = ClientDisplayOrder_TouchFirst; + + if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Separation_0) ) outProps.gapScale = 0.0; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Separation_50) ) outProps.gapScale = 0.5; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Separation_100) ) outProps.gapScale = 1.0; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Separation_150) ) outProps.gapScale = 1.5; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Separation_200) ) outProps.gapScale = 2.0; + + if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Rotation_0) ) outProps.rotation = 0.0; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Rotation_90) ) outProps.rotation = 90.0; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Rotation_180) ) outProps.rotation = 180.0; + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Rotation_270) ) outProps.rotation = 270.0; +} + - (void) setNdsDisplayMode:(uint64_t)displayModeStates { - OEIntRect newDisplayRect; - OEIntSize newDisplayAspectRatio; + ClientDisplayPresenterProperties newProps; + UpdateDisplayPropertiesFromStates(displayModeStates, newProps); + newProps.clientWidth = _OEViewSize.width; + newProps.clientHeight = _OEViewSize.height; + newProps.gapDistance = (double)DS_DISPLAY_UNSCALED_GAP * newProps.gapScale; - if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_DualScreen) ) - { - newDisplayRect = OEIntRectMake(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2); - newDisplayAspectRatio = OEIntSizeMake(2, 3); - } - else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_Main) ) - { - newDisplayRect = OEIntRectMake(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT); - newDisplayAspectRatio = OEIntSizeMake(4, 3); - } - else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_Touch) ) - { - newDisplayRect = OEIntRectMake(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT + 1, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT); - newDisplayAspectRatio = OEIntSizeMake(4, 3); - } - else + ClientDisplayPresenter::CalculateNormalSize(newProps.mode, newProps.layout, newProps.gapScale, newProps.normalWidth, newProps.normalHeight); + + double transformNormalWidth = newProps.normalWidth; + double transformNormalHeight = newProps.normalHeight; + ClientDisplayPresenter::ConvertNormalToTransformedBounds(1.0, newProps.rotation, transformNormalWidth, transformNormalHeight); + newProps.viewScale = ClientDisplayPresenter::GetMaxScalarWithinBounds(transformNormalWidth, transformNormalHeight, newProps.clientWidth, newProps.clientHeight); + + newProps.viewScale = 1.0; + newProps.clientWidth = transformNormalWidth; + newProps.clientHeight = transformNormalHeight; + + apple_unfairlock_lock(unfairlockDisplayMode); + + // Actual display rendering will be changed in [OEGameCore executeFrame] (see notes + // in that method for why this is so), and so we need to push this change by setting + // _displayModeStatesPending to a non-zero value. + _displayModeStatesPending = displayModeStates; + + // The display buffer size represents the size of an IOSurface, which is fixed by + // OpenEmu. However, ClientDisplayPresenter can draw into any sized framebuffer + // while also assuming that it is drawing into the maximum available space that the + // view can provide. Therefore, we need to manually set the display buffer size to + // whatever size the OpenEmu view is. + _displayBufferSize = _OEViewSize; + + // The display aspect ratio represents the actual drawable area within the view. Due + // to this, the aspect ratio is implicitly defined by its drawable area. Since we + // want to use the entire view as drawable area, this means that we must set the + // "aspect ratio" to the view size. + _displayAspectRatio = _OEViewSize; + + // The display rect represents the emulator's video output at a 1x scaling. Despite + // the description given by OpenEmu's SDK, the "display rect" is what actually sets + // the aspect ratio, but only for the emulator's video output. When the user changes + // the view size, the Scale menu changes itself relative to the display size. + // + // And unlike what the OpenEmu SDK suggests, the "display rect" has absolutely nothing + // to do with the drawable area, since we can draw things, such as the HUD, outside the + // "display rect". Of course, drawing the HUD relative to the view rather than relative + // to the emulator's video output is the intended behavior, but the OpenEmu SDK notes + // don't make this easy to figure out! + _displayRect = OEIntRectMake(0, 0, transformNormalWidth + 0.0005, transformNormalHeight + 0.0005); + + apple_unfairlock_unlock(unfairlockDisplayMode); +} + +- (void) applyDisplayMode:(uint64_t)appliedState +{ + if (appliedState == 0) { return; } - apple_unfairlock_lock(unfairlockDisplayMode); - ndsDisplayMode = displayModeStates; - _displayRect = newDisplayRect; - _displayAspectRatio = newDisplayAspectRatio; - apple_unfairlock_unlock(unfairlockDisplayMode); + ClientDisplaySource displaySource[2] = { ClientDisplaySource_DeterminedByNDS, ClientDisplaySource_DeterminedByNDS }; + + if ( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_VideoSourceMain_None) ) displaySource[NDSDisplayID_Main] = ClientDisplaySource_None; + else if ( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_VideoSourceMain_NDS) ) displaySource[NDSDisplayID_Main] = ClientDisplaySource_DeterminedByNDS; + else if ( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_VideoSourceMain_ForceMain) ) displaySource[NDSDisplayID_Main] = ClientDisplaySource_EngineMain; + else if ( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_VideoSourceMain_ForceSub) ) displaySource[NDSDisplayID_Main] = ClientDisplaySource_EngineSub; + + if ( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_VideoSourceTouch_None) ) displaySource[NDSDisplayID_Touch] = ClientDisplaySource_None; + else if ( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_VideoSourceTouch_NDS) ) displaySource[NDSDisplayID_Touch] = ClientDisplaySource_DeterminedByNDS; + else if ( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_VideoSourceTouch_ForceMain) ) displaySource[NDSDisplayID_Touch] = ClientDisplaySource_EngineMain; + else if ( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_VideoSourceTouch_ForceSub) ) displaySource[NDSDisplayID_Touch] = ClientDisplaySource_EngineSub; + + _cdp->SetDisplayVideoSource(NDSDisplayID_Main, displaySource[NDSDisplayID_Main]); + _cdp->SetDisplayVideoSource(NDSDisplayID_Touch, displaySource[NDSDisplayID_Touch]); + + _cdp->SetHUDVisibility( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_HUD_Enable) ); + _cdp->SetHUDShowExecutionSpeed( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_HUD_ExecutionSpeed) ); + _cdp->SetHUDShowRender3DFPS( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_HUD_3DRendererFPS) ); + _cdp->SetHUDShowFrameIndex( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_HUD_FrameIndex) ); + _cdp->SetHUDShowLagFrameCount( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_HUD_LagFrameCounter) ); + _cdp->SetHUDShowCPULoadAverage( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_HUD_CPULoadAverage) ); + _cdp->SetHUDShowRTC( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_HUD_RealTimeClock) ); + _cdp->SetHUDShowInput( DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_HUD_Input) ); + + const bool isVideoFPSEnabled = DISPLAYMODE_STATEBIT_CHECK(appliedState, NDSDisplayOptionID_HUD_VideoFPS); + if (isVideoFPSEnabled) + { + if (_fpsTimer == nil) + { + [self newFPSTimer]; + } + } + else + { + [_fpsTimer invalidate]; + _fpsTimer = nil; + } + _cdp->SetHUDShowVideoFPS(isVideoFPSEnabled); + + ClientDisplayPresenterProperties newProps; + UpdateDisplayPropertiesFromStates(appliedState, newProps); + newProps.clientWidth = _OEViewSize.width; + newProps.clientHeight = _OEViewSize.height; + + _cdp->CommitPresenterProperties(newProps); + _cdp->SetupPresenterProperties(); + + _displayModeStatesApplied = _displayModeStatesPending; + _displayModeStatesPending = 0; } #pragma mark - Plug-in Support @@ -288,6 +563,12 @@ volatile bool execute = true; * You can do any setup you want here. */ - (BOOL)loadFileAtPath:(NSString *)path error:(NSError **)error +{ + SILENCE_DEPRECATION_OPENEMU( return [self loadFileAtPath:path]; ) +} + +// This older version of [OEGameCore loadFileAtPath:] exists for backwards compatibility. +- (BOOL)loadFileAtPath:(NSString*)path { BOOL isRomLoaded = NO; NSString *openEmuDataPath = [self batterySavesDirectoryPath]; @@ -322,21 +603,27 @@ volatile bool execute = true; userDefaultsDisplayMode = [self displayModeInfo]; } -#define GENDISPLAYMODESTATE(_PREFKEY_, _DEFAULTID_) \ - ( ([userDefaultsDisplayMode objectForKey:(_PREFKEY_)] == nil) || ([_displayModeIDFromString objectForKey:(NSString *)[userDefaultsDisplayMode objectForKey:(_PREFKEY_)]] == nil) ) ? \ - (1 << (_DEFAULTID_)) : \ - (1 << [(NSNumber *)[_displayModeIDFromString objectForKey:(NSString *)[userDefaultsDisplayMode objectForKey:(_PREFKEY_)]] integerValue]) + uint64_t s = _displayModeStatesPending; + s = [self switchDisplayModeState:s nameKey:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_DISPLAYMODE]]; + s = [self switchDisplayModeState:s nameKey:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_ROTATION]]; + s = [self switchDisplayModeState:s nameKey:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_LAYOUT]]; + s = [self switchDisplayModeState:s nameKey:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_ORDER]]; + s = [self switchDisplayModeState:s nameKey:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_SEPARATION]]; + s = [self switchDisplayModeState:s nameKey:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN]]; + s = [self switchDisplayModeState:s nameKey:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH]]; - uint64_t newDisplayModeStates = 0; - newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_DISPLAYMODE, NDSDisplayOptionID_Mode_DualScreen ); - newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_ROTATION, NDSDisplayOptionID_Rotation_0 ); - newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_LAYOUT, NDSDisplayOptionID_Layout_Vertical ); - newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_ORDER, NDSDisplayOptionID_Order_MainFirst ); - newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_SEPARATION, NDSDisplayOptionID_Separation_0 ); - newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN, NDSDisplayOptionID_VideoSourceMain_NDS ); - newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH, NDSDisplayOptionID_VideoSourceTouch_NDS ); + s = [self setDisplayModeState:s optionID:NDSDisplayOptionID_HUD_Enable state:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_HUD_ENABLE]]; + s = [self setDisplayModeState:s optionID:NDSDisplayOptionID_HUD_ExecutionSpeed state:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_HUD_EXECUTIONSPEED]]; + s = [self setDisplayModeState:s optionID:NDSDisplayOptionID_HUD_VideoFPS state:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_HUD_VIDEOFPS]]; + s = [self setDisplayModeState:s optionID:NDSDisplayOptionID_HUD_3DRendererFPS state:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_HUD_3DRENDERERFPS]]; + s = [self setDisplayModeState:s optionID:NDSDisplayOptionID_HUD_FrameIndex state:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_HUD_FRAMEINDEX]]; + s = [self setDisplayModeState:s optionID:NDSDisplayOptionID_HUD_LagFrameCounter state:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_HUD_LAGFRAMECOUNTER]]; + s = [self setDisplayModeState:s optionID:NDSDisplayOptionID_HUD_CPULoadAverage state:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_HUD_CPULOADAVERAGE]]; + s = [self setDisplayModeState:s optionID:NDSDisplayOptionID_HUD_RealTimeClock state:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_HUD_REALTIMECLOCK]]; + s = [self setDisplayModeState:s optionID:NDSDisplayOptionID_HUD_Input state:[userDefaultsDisplayMode objectForKey:@NDSDISPLAYMODE_PREFKEY_HUD_INPUT]]; - [self setNdsDisplayMode:newDisplayModeStates]; + [self setNdsDisplayMode:s]; + _displayModeStatesApplied = _displayModeStatesPending; return isRomLoaded; } @@ -393,15 +680,65 @@ volatile bool execute = true; */ - (void)executeFrame { - ClientInputHandler *inputHandler = [cdsController inputHandler]; - inputHandler->ProcessInputs(); - inputHandler->ApplyInputs(); + // The notes for the [OEGameCore startEmulation] method suggest that the + // OpenGL context is available in that method. That statement is false! + // The only time it's guaranteed to be available is right here in this + // method. Therefore, we have to lazy init this entire side of the + // graphics stack right before we execute the frame because there is no + // other viable way to get the current OpenGL context from OpenEmu. + if ( (_videoContext == NULL) || (_videoContext != CGLGetCurrentContext()) ) + { + [self initVideoWithCurrentOpenEmuContext]; + } + + // Applying the current display mode not only requires a working context, + // which is only guaranteed now, and also requires the current view size, + // which is also only guaranteed now. Due to those reasons, we can only + // apply the display mode right now! + if (_displayModeStatesPending != 0) + { + [self applyDisplayMode:_displayModeStatesPending]; + } + + _inputHandler->ProcessInputs(); + _inputHandler->ApplyInputs(); pthread_rwlock_wrlock(&rwlockCoreExecute); NDS_exec(); pthread_rwlock_unlock(&rwlockCoreExecute); + apple_unfairlock_lock(_unfairlockReceivedFrameIndex); + _receivedFrameIndex++; + apple_unfairlock_unlock(_unfairlockReceivedFrameIndex); + SPU_Emulate_user(); + + // Fetch the frame from the core emulator + const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); + OE_OGLClientFetchObject &fetchObj = (OE_OGLClientFetchObject &)_cdp->GetFetchObject(); + fetchObj.SetFetchDisplayInfo(dispInfo); + fetchObj.FetchFromBufferIndex(dispInfo.bufferIndex); + + // Update HUD information + apple_unfairlock_lock(_unfairlockReceivedFrameIndex); + _clientFrameInfo.videoFPS = _receivedFrameCount; + _executionSpeedAverageFramesCollected += (double)_receivedFrameCount; + apple_unfairlock_unlock(_unfairlockReceivedFrameIndex); + + if ((_ndsFrameInfo.frameIndex & 0x3F) == 0x3F) + { + _ndsFrameInfo.executionSpeed = 100.0 * _executionSpeedAverageFramesCollected / DS_FRAMES_PER_SECOND / ((double)0x3F + 1.0); + _executionSpeedAverageFramesCollected = 0.0; + } + + ClientExecutionControl::GenerateNDSFrameInfo(_inputHandler, _ndsFrameInfo); + _cdp->SetHUDInfo(_clientFrameInfo, _ndsFrameInfo); + + // Render the frame to the presenter + _cdp->LoadDisplays(); + _cdp->ProcessDisplays(); + _cdp->UpdateLayout(); + _cdp->RenderFrameOGL(false); } /*! @@ -438,10 +775,7 @@ volatile bool execute = true; * buffer may be faster. Besides that, returning the same buffer each time * may be faster. */ -- (const void *)getVideoBufferWithHint:(void *)hint -{ - return GPU->GetDisplayInfo().masterCustomBuffer; -} +//- (const void *)getVideoBufferWithHint:(void *)hint; /*! * @method tryToResizeVideoTo: @@ -451,7 +785,13 @@ volatile bool execute = true; * -executeFrame will have a newly sized framebuffer. * It is assumed that only 3D cores can do this. */ -//- (BOOL)tryToResizeVideoTo:(OEIntSize)size; +- (BOOL)tryToResizeVideoTo:(OEIntSize)size +{ + _OEViewSize = size; + [self setNdsDisplayMode:_displayModeStatesApplied]; + + return YES; +} /*! * @property gameCoreRendering @@ -461,7 +801,7 @@ volatile bool execute = true; */ - (OEGameCoreRendering)gameCoreRendering { - return OEGameCoreRendering2DVideo; + return OEGameCoreRenderingOpenGL3Video; } /*! @@ -503,7 +843,11 @@ volatile bool execute = true; */ - (OEIntSize)bufferSize { - return OEIntSizeMake(GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2); + apple_unfairlock_lock(unfairlockDisplayMode); + const OEIntSize theBufferSize = _displayBufferSize; + apple_unfairlock_unlock(unfairlockDisplayMode); + + return theBufferSize; } /*! @@ -545,10 +889,7 @@ volatile bool execute = true; * Defaults to GL_RGB (sometimes GL_SRGB8). You probably do not need to override this. * Ignored for 3D cores. */ -- (GLenum)internalPixelFormat -{ - return GL_RGBA; -} +//- (GLenum)internalPixelFormat; /*! * @property pixelFormat @@ -557,10 +898,7 @@ volatile bool execute = true; * GL_BGRA is preferred, but avoid doing any conversions inside the core. * Ignored for 3D cores. */ -- (GLenum)pixelType -{ - return GL_UNSIGNED_INT_8_8_8_8_REV; -} +//- (GLenum)pixelType; /*! * @property pixelFormat @@ -570,10 +908,7 @@ volatile bool execute = true; * avoid doing any conversions inside the core. * Ignored for 3D cores. */ -- (GLenum)pixelFormat -{ - return GL_RGBA; -} +//- (GLenum)pixelFormat; /*! * @property bytesPerRow @@ -731,6 +1066,21 @@ volatile bool execute = true; #pragma mark - Display Mode - Optional +- (NSDictionary *) generateDisplayModeItemByID:(NDSDisplayOptionID)optionID states:(const uint64_t)states +{ + if ( (optionID < 0) || (optionID >= NDSDisplayOptionID_Count) ) + { + return nil; + } + + return [NSDictionary dictionaryWithObjectsAndKeys: + kDisplayModeItem[optionID].nameKey, OEGameCoreDisplayModeNameKey, + kDisplayModeItem[optionID].prefKey, OEGameCoreDisplayModePrefKeyNameKey, + [NSNumber numberWithBool:(kDisplayModeItem[optionID].groupBitmask == 0) ? YES : NO], OEGameCoreDisplayModeAllowsToggleKey, + [NSNumber numberWithBool:DISPLAYMODE_STATEBIT_CHECK(states, optionID) ? YES : NO], OEGameCoreDisplayModeStateKey, + nil]; +} + /** An array describing the available display mode options and the * appearance of the menu used to select them. * @discussion Each NSDictionary in the array corresponds to an item @@ -745,23 +1095,9 @@ volatile bool execute = true; * See OEGameCoreController.h for a detailed discussion of the keys contained * in each item dictionary. */ -- (NSDictionary *) generateDisplayModeItemByID:(NDSDisplayOptionID)optionID states:(const uint64_t)states -{ - if ( (optionID < 0) || (optionID >= NDSDisplayOptionID_Count) ) - { - return nil; - } - - return [NSDictionary dictionaryWithObjectsAndKeys: - kDisplayModeItem[optionID].nameKey, OEGameCoreDisplayModeNameKey, - kDisplayModeItem[optionID].prefKey, OEGameCoreDisplayModePrefKeyNameKey, - [NSNumber numberWithBool:DISPLAYMODE_STATEBIT_CHECK(states, optionID) ? YES : NO], OEGameCoreDisplayModeStateKey, - nil]; -} - - (NSArray *> *) displayModes { - const uint64_t currentDisplayMode = [self ndsDisplayMode]; + const uint64_t currentDisplayMode = _displayModeStatesPending; // Generate each display option submenu. NSArray< NSDictionary *> *displayModeMenu = @@ -808,12 +1144,26 @@ volatile bool execute = true; [self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceMain_None states:currentDisplayMode], [self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceMain_NDS states:currentDisplayMode], [self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceMain_ForceMain states:currentDisplayMode], - [self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceMain_ForceTouch states:currentDisplayMode], + [self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceMain_ForceSub states:currentDisplayMode], [NSDictionary dictionaryWithObjectsAndKeys:@"---", OEGameCoreDisplayModeSeparatorItemKey, nil], [self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceTouch_None states:currentDisplayMode], [self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceTouch_NDS states:currentDisplayMode], [self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceTouch_ForceMain states:currentDisplayMode], - [self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceTouch_ForceTouch states:currentDisplayMode], + [self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceTouch_ForceSub states:currentDisplayMode], + nil]; + + NSArray< NSDictionary *> *displayHUDMenu = + [NSArray arrayWithObjects: + [self generateDisplayModeItemByID:NDSDisplayOptionID_HUD_Enable states:currentDisplayMode], + [NSDictionary dictionaryWithObjectsAndKeys:@"---", OEGameCoreDisplayModeSeparatorItemKey, nil], + [self generateDisplayModeItemByID:NDSDisplayOptionID_HUD_ExecutionSpeed states:currentDisplayMode], + [self generateDisplayModeItemByID:NDSDisplayOptionID_HUD_VideoFPS states:currentDisplayMode], + [self generateDisplayModeItemByID:NDSDisplayOptionID_HUD_3DRendererFPS states:currentDisplayMode], + [self generateDisplayModeItemByID:NDSDisplayOptionID_HUD_FrameIndex states:currentDisplayMode], + [self generateDisplayModeItemByID:NDSDisplayOptionID_HUD_LagFrameCounter states:currentDisplayMode], + [self generateDisplayModeItemByID:NDSDisplayOptionID_HUD_CPULoadAverage states:currentDisplayMode], + [self generateDisplayModeItemByID:NDSDisplayOptionID_HUD_RealTimeClock states:currentDisplayMode], + [self generateDisplayModeItemByID:NDSDisplayOptionID_HUD_Input states:currentDisplayMode], nil]; // Add each submenu to the menu descriptor. @@ -822,7 +1172,7 @@ volatile bool execute = true; // OpenEmu wants to have a full immutable copy of the menu descriptor so that it can use it for // its Next/Last Display Mode switching feature. Because of this, we can't just generate a // single menu descriptor at init time, modify it as needed, and then send OpenEmu the pointer - // to our menu descriptor. as OpenEmu can modify it in some unpredictable ways. We would have + // to our menu descriptor, as OpenEmu can modify it in some unpredictable ways. We would have // to send a copy to keep our internal working menu descriptor from getting borked. // // Maintaining a mutable version of the menu descriptor for our internal usage is a pain, as @@ -831,7 +1181,7 @@ volatile bool execute = true; // OpenEmu a copy of the menu descriptor anyways, it ends up being easier to just use a single // integer ID, NDSDisplayOptionID in our case, to keep track of all of the data associations // and then use that ID to generate the menu. - /* + NSArray< NSDictionary *> *newDisplayModeMenuDescription = [[NSArray alloc] initWithObjects: [NSDictionary dictionaryWithObjectsAndKeys: @"Mode", OEGameCoreDisplayModeGroupNameKey, displayModeMenu, OEGameCoreDisplayModeGroupItemsKey, nil], @@ -840,15 +1190,8 @@ volatile bool execute = true; [NSDictionary dictionaryWithObjectsAndKeys: @"Order", OEGameCoreDisplayModeGroupNameKey, displayOrderMenu, OEGameCoreDisplayModeGroupItemsKey, nil], [NSDictionary dictionaryWithObjectsAndKeys: @"Separation", OEGameCoreDisplayModeGroupNameKey, displaySeparationMenu, OEGameCoreDisplayModeGroupItemsKey, nil], [NSDictionary dictionaryWithObjectsAndKeys: @"Video Source", OEGameCoreDisplayModeGroupNameKey, displayVideoSourceMenu, OEGameCoreDisplayModeGroupItemsKey, nil], - nil]; - */ - - // Still working on other display modes, so just support the original display modes for now. - NSArray< NSDictionary *> *newDisplayModeMenuDescription = - [[NSArray alloc] initWithObjects: - [self generateDisplayModeItemByID:NDSDisplayOptionID_Mode_DualScreen states:currentDisplayMode], - [self generateDisplayModeItemByID:NDSDisplayOptionID_Mode_Main states:currentDisplayMode], - [self generateDisplayModeItemByID:NDSDisplayOptionID_Mode_Touch states:currentDisplayMode], + [NSDictionary dictionaryWithObjectsAndKeys:@"---", OEGameCoreDisplayModeSeparatorItemKey, nil], + [NSDictionary dictionaryWithObjectsAndKeys: @"Heads-Up Display", OEGameCoreDisplayModeGroupNameKey, displayHUDMenu, OEGameCoreDisplayModeGroupItemsKey, nil], nil]; return newDisplayModeMenuDescription; @@ -858,73 +1201,100 @@ volatile bool execute = true; * @param displayMode The name of the display mode to enable or disable, as * specified in its OEGameCoreDisplayModeNameKey key. */ +- (uint64_t) switchDisplayModeState:(uint64_t)displayModeState nameKey:(NSString *)nameKey +{ + // Validate the incoming nameKey string. + if (nameKey == nil) + { + return displayModeState; + } + + NSNumber *optionIDNumber = [_displayModeIDFromString objectForKey:nameKey]; + if (optionIDNumber == nil) + { + return displayModeState; + } + + // Retrieve the NDSDisplayOptionID and generate its associated state bit. + const NDSDisplayOptionID optionID = (NDSDisplayOptionID)[optionIDNumber integerValue]; + const uint64_t optionBit = (1LLU << optionID); + + // Manipulate our current display mode state using only nameKey. + // + // OpenEmu menu items are explicitly typed as toggle or group. Technically, these are + // two separate switches that make for four possible permutations of menu item type. + // But practically speaking, a toggle item already implies that the menu item is not + // part of a group, while a group item already implies that the menu item will not + // toggle. The code below is written in such a way as to reflect the above behavior. + if (kDisplayModeItem[optionID].groupBitmask == 0) + { + displayModeState ^= optionBit; + } + else + { + DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeState, kDisplayModeItem[optionID].groupBitmask); + displayModeState |= optionBit; + } + + return displayModeState; +} + +- (uint64_t) setDisplayModeState:(uint64_t)displayModeState optionID:(NDSDisplayOptionID)optionID state:(NSNumber *)stateObj +{ + if (stateObj == nil) + { + return displayModeState; + } + + const uint64_t optionBit = (1LLU << optionID); + BOOL newState = [stateObj boolValue]; + + if (newState) + { + displayModeState |= optionBit; + } + else + { + displayModeState &= ~optionBit; + } + + return displayModeState; +} + - (void)changeDisplayWithMode:(NSString *)displayMode { - NSNumber *optionIDNumber = [_displayModeIDFromString objectForKey:displayMode]; - if ( (displayMode == nil) || (optionIDNumber == nil) ) + uint64_t oldState = [self ndsDisplayMode]; + uint64_t newState = [self switchDisplayModeState:oldState nameKey:displayMode]; + + if (newState == oldState) { return; } - uint64_t displayModeStates = [self ndsDisplayMode]; - - const NDSDisplayOptionID optionID = (NDSDisplayOptionID)[optionIDNumber integerValue]; - switch (optionID) - { - case NDSDisplayOptionID_Mode_DualScreen: - case NDSDisplayOptionID_Mode_Main: - case NDSDisplayOptionID_Mode_Touch: - DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_DisplayMode); - break; - - case NDSDisplayOptionID_Rotation_0: - case NDSDisplayOptionID_Rotation_90: - case NDSDisplayOptionID_Rotation_180: - case NDSDisplayOptionID_Rotation_270: - DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_Rotation); - break; - - case NDSDisplayOptionID_Layout_Vertical: - case NDSDisplayOptionID_Layout_Horizontal: - case NDSDisplayOptionID_Layout_Hybrid_2_1: - case NDSDisplayOptionID_Layout_Hybrid_16_9: - case NDSDisplayOptionID_Layout_Hybrid_16_10: - DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_Layout); - break; - - case NDSDisplayOptionID_Order_MainFirst: - case NDSDisplayOptionID_Order_TouchFirst: - DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_Order); - break; - - case NDSDisplayOptionID_Separation_0: - case NDSDisplayOptionID_Separation_50: - case NDSDisplayOptionID_Separation_100: - case NDSDisplayOptionID_Separation_150: - case NDSDisplayOptionID_Separation_200: - DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_Separation); - break; - - case NDSDisplayOptionID_VideoSourceMain_None: - case NDSDisplayOptionID_VideoSourceMain_NDS: - case NDSDisplayOptionID_VideoSourceMain_ForceMain: - case NDSDisplayOptionID_VideoSourceMain_ForceTouch: - DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_VideoSourceMain); - break; - - case NDSDisplayOptionID_VideoSourceTouch_None: - case NDSDisplayOptionID_VideoSourceTouch_NDS: - case NDSDisplayOptionID_VideoSourceTouch_ForceMain: - case NDSDisplayOptionID_VideoSourceTouch_ForceTouch: - DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_VideoSourceTouch); - break; - - default: - break; - } + [self setNdsDisplayMode:newState]; +} - displayModeStates |= (1 << optionID); - [self setNdsDisplayMode:displayModeStates]; +// This older version of [OEGameCore changeDisplayMode] exists for backwards compatibility. +// It cycles through the three NDS display modes, and that's it. +- (void)changeDisplayMode +{ + uint64_t displayModeState = [self ndsDisplayMode]; + + if ( DISPLAYMODE_STATEBIT_CHECK(displayModeState, NDSDisplayOptionID_Mode_DualScreen) ) + { + _OEViewSize.height = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + [self changeDisplayWithMode:kDisplayModeItem[NDSDisplayOptionID_Mode_Main].nameKey]; + } + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeState, NDSDisplayOptionID_Mode_Main) ) + { + _OEViewSize.height = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + [self changeDisplayWithMode:kDisplayModeItem[NDSDisplayOptionID_Mode_Touch].nameKey]; + } + else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeState, NDSDisplayOptionID_Mode_Touch) ) + { + _OEViewSize.height = GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2; + [self changeDisplayWithMode:kDisplayModeItem[NDSDisplayOptionID_Mode_DualScreen].nameKey]; + } } #pragma mark - Internal @@ -949,9 +1319,9 @@ volatile bool execute = true; */ - (void)startEmulation { - [cdsController startHardwareMicDevice]; - [cdsController setHardwareMicMute:NO]; - [cdsController setHardwareMicPause:NO]; + _inputHandler->StartHardwareMicDevice(); + _inputHandler->SetHardwareMicMute(false); + _inputHandler->SetHardwareMicPause(false); [super startEmulation]; } @@ -983,7 +1353,20 @@ volatile bool execute = true; */ - (void)setPauseEmulation:(BOOL)pauseEmulation { - [cdsController setHardwareMicPause:pauseEmulation]; + _inputHandler->SetHardwareMicPause((pauseEmulation) ? YES : NO); + + if (pauseEmulation) + { + [_fpsTimer invalidate]; + _fpsTimer = nil; + } + else + { + if (_fpsTimer == nil) + { + [self newFPSTimer]; + } + } [super setPauseEmulation:pauseEmulation]; } @@ -995,90 +1378,107 @@ volatile bool execute = true; - (oneway void)didPushNDSButton:(OENDSButton)button forPlayer:(NSUInteger)player { - switch (inputID[button]) + const NDSInputID theInput = (NDSInputID)inputID[button]; + + switch (theInput) { case NDSInputID_Microphone: - [cdsController setSoftwareMicState:YES mode:MicrophoneMode_InternalNoise]; + _inputHandler->SetClientSoftwareMicState(true, MicrophoneMode_InternalNoise); break; case NDSInputID_Paddle: // Do nothing for now. OpenEmu doesn't currently support the Taito Paddle Controller. - //[cdsController setPaddleAdjust:0]; + //_inputHandler->SetClientPaddleAdjust(0); break; default: - [cdsController setControllerState:YES controlID:inputID[button]]; + _inputHandler->SetClientInputStateUsingID(theInput, true); break; } + + ClientExecutionControl::UpdateNDSFrameInfoInput(_inputHandler, _ndsFrameInfo); + _cdp->SetHUDInfo(_clientFrameInfo, _ndsFrameInfo); } - (oneway void)didReleaseNDSButton:(OENDSButton)button forPlayer:(NSUInteger)player { - switch (inputID[button]) + const NDSInputID theInput = (NDSInputID)inputID[button]; + + switch (theInput) { case NDSInputID_Microphone: - [cdsController setSoftwareMicState:NO mode:MicrophoneMode_InternalNoise]; + _inputHandler->SetClientSoftwareMicState(false, MicrophoneMode_InternalNoise); break; case NDSInputID_Paddle: - [cdsController setPaddleAdjust:0]; + _inputHandler->SetClientPaddleAdjust(0); break; default: - [cdsController setControllerState:NO controlID:inputID[button]]; + _inputHandler->SetClientInputStateUsingID(theInput, false); break; } + + ClientExecutionControl::UpdateNDSFrameInfoInput(_inputHandler, _ndsFrameInfo); + _cdp->SetHUDInfo(_clientFrameInfo, _ndsFrameInfo); } - (oneway void)didTouchScreenPoint:(OEIntPoint)aPoint { - BOOL isTouchPressed = NO; uint64_t displayModeStates = [self ndsDisplayMode]; - if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_DualScreen) ) - { - isTouchPressed = YES; - aPoint.y -= GPU_FRAMEBUFFER_NATIVE_HEIGHT; // Normalize the y-coordinate to the DS. - } - else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_Main) ) - { - isTouchPressed = NO; // Reject touch input if showing only the main screen. - } - else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_Touch) ) - { - isTouchPressed = YES; - } - else + // Reject touch input if showing only the main screen. + if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_Main) ) { + if (!_isInitialTouchPress) + { + [self didReleaseTouch]; + } + return; } - // Constrain the touch point to the DS dimensions. - if (aPoint.x < 0) - { - aPoint.x = 0; - } - else if (aPoint.x > (GPU_FRAMEBUFFER_NATIVE_WIDTH - 1)) - { - aPoint.x = (GPU_FRAMEBUFFER_NATIVE_WIDTH - 1); - } + ClientDisplayPresenterProperties propsCopy = _cdp->GetPresenterProperties(); - if (aPoint.y < 0) - { - aPoint.y = 0; - } - else if (aPoint.y > (GPU_FRAMEBUFFER_NATIVE_HEIGHT - 1)) - { - aPoint.y = (GPU_FRAMEBUFFER_NATIVE_HEIGHT - 1); - } + // GetNDSPoint() is intended for views where the origin point is in the bottom left, + // translating it into an NDS point where the origin point is in the top left. + // OpenEmu tries to be helpful by flipping the origin point to the top left for us, + // but that's not what GetNDSPoint() wants, and so we need to flip OpenEmu's touch + // point here. + aPoint.y = _displayRect.size.height - aPoint.y; // Normalize the y-coordinate to the DS. - touchLocation = NSMakePoint(aPoint.x, aPoint.y); - [cdsController setTouchState:isTouchPressed location:touchLocation]; + // We also need to center the touch point within the view, since OpenEmu has a hard time + // (due to view behavior bugs) sizing the view to the drawable rect. More than likely, + // there will be some kind of extraneous area around the drawable area, and so we need + // to compensate for that here. + const double displayRectWidthScaled = _displayRect.size.width * propsCopy.viewScale; + const double displayRectHeightScaled = _displayRect.size.height * propsCopy.viewScale; + aPoint.x = aPoint.x - (int)( ((((double)_OEViewSize.width - displayRectWidthScaled) / 2.0) / propsCopy.viewScale) + 0.0005 ); + aPoint.y = aPoint.y + (int)( ((((double)_OEViewSize.height - displayRectHeightScaled) / 2.0) / propsCopy.viewScale) + 0.0005 ); + + uint8_t x = 0; + uint8_t y = 0; + + ClientDisplayViewInterface::GetNDSPoint(propsCopy, + _displayRect.size.width, _displayRect.size.height, + aPoint.x, aPoint.y, + _isInitialTouchPress, x, y, _isTouchPressInMajorDisplay); + _isInitialTouchPress = false; + + _lastTouchLocation = OEIntPointMake(x, y); + _inputHandler->SetClientTouchState(true, x, y, 50); + + ClientExecutionControl::UpdateNDSFrameInfoInput(_inputHandler, _ndsFrameInfo); + _cdp->SetHUDInfo(_clientFrameInfo, _ndsFrameInfo); } - (oneway void)didReleaseTouch { - [cdsController setTouchState:NO location:touchLocation]; + _inputHandler->SetClientTouchState(false, _lastTouchLocation.x, _lastTouchLocation.y, 50); + _isInitialTouchPress = true; + + ClientExecutionControl::UpdateNDSFrameInfoInput(_inputHandler, _ndsFrameInfo); + _cdp->SetHUDInfo(_clientFrameInfo, _ndsFrameInfo); } @end diff --git a/desmume/src/frontend/cocoa/openemu/OEBuildInterface.cpp b/desmume/src/frontend/cocoa/openemu/OEBuildInterface.cpp index eca28a812..45ca6a2f2 100755 --- a/desmume/src/frontend/cocoa/openemu/OEBuildInterface.cpp +++ b/desmume/src/frontend/cocoa/openemu/OEBuildInterface.cpp @@ -60,5 +60,8 @@ #include "../../utils/AsmJit/x86/x86func.cpp" #include "../../utils/AsmJit/x86/x86operand.cpp" #include "../../utils/AsmJit/x86/x86util.cpp" + #include "../../arm_jit.cpp" + #elif defined(__aarch64__) + #include "../../utils/arm_jit/arm_jit_arm.cpp" #endif #endif diff --git a/desmume/src/frontend/cocoa/openemu/OEDisplayView.h b/desmume/src/frontend/cocoa/openemu/OEDisplayView.h new file mode 100644 index 000000000..47086d440 --- /dev/null +++ b/desmume/src/frontend/cocoa/openemu/OEDisplayView.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2022 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . + */ + +#ifndef _OPENEMU_DISPLAYOUTPUT_H_ +#define _OPENEMU_DISPLAYOUTPUT_H_ + +#import +#import +#include "../utilities.h" + +#import "../cocoa_GPU.h" +#import "../cocoa_util.h" +#include "../ClientDisplayView.h" +#include "../OGLDisplayOutput_3_2.h" + +#ifdef BOOL +#undef BOOL +#endif + + +class OE_OGLClientSharedData : public OGLClientSharedData +{ +protected: + apple_unfairlock_t _unfairlockTexFetch[2]; + +public: + OE_OGLClientSharedData(); + ~OE_OGLClientSharedData(); + + virtual GLuint GetFetchTexture(const NDSDisplayID displayID); + virtual void SetFetchTexture(const NDSDisplayID displayID, GLuint texID); +}; + +class OE_OGLClientFetchObject : public GPUClientFetchObject +{ +protected: + CGLContextObj _context; + + // GPUClientFetchObject methods + virtual void _FetchNativeDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex); + virtual void _FetchCustomDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex); + +public: + OE_OGLClientFetchObject(); + ~OE_OGLClientFetchObject(); + + CGLContextObj GetContext() const; + + // GPUClientFetchObject methods + virtual void Init(); + virtual void SetFetchBuffers(const NDSDisplayInfo ¤tDisplayInfo); + virtual void FetchFromBufferIndex(const u8 index); +}; + +class OE_OGLDisplayPresenter : public OGLVideoOutput +{ +private: + void __InstanceInit(OE_OGLClientFetchObject *fetchObject); + +protected: + CGLContextObj _context; + +public: + OE_OGLDisplayPresenter(); + OE_OGLDisplayPresenter(OE_OGLClientFetchObject *fetchObject); + + virtual void Init(); + + CGLContextObj GetContext() const; +}; + +#endif // _OPENEMU_DISPLAYOUTPUT_H_ diff --git a/desmume/src/frontend/cocoa/openemu/OEDisplayView.mm b/desmume/src/frontend/cocoa/openemu/OEDisplayView.mm new file mode 100644 index 000000000..ce175b46d --- /dev/null +++ b/desmume/src/frontend/cocoa/openemu/OEDisplayView.mm @@ -0,0 +1,172 @@ +/* + Copyright (C) 2022 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . + */ + +#include +#import "OEDisplayView.h" +#import "../cocoa_globals.h" + +OE_OGLClientSharedData::OE_OGLClientSharedData() +{ + _useDirectToCPUFilterPipeline = false; + + _unfairlockTexFetch[NDSDisplayID_Main] = apple_unfairlock_create(); + _unfairlockTexFetch[NDSDisplayID_Touch] = apple_unfairlock_create(); +} + +OE_OGLClientSharedData::~OE_OGLClientSharedData() +{ + apple_unfairlock_destroy(this->_unfairlockTexFetch[NDSDisplayID_Main]); + this->_unfairlockTexFetch[NDSDisplayID_Main] = NULL; + apple_unfairlock_destroy(this->_unfairlockTexFetch[NDSDisplayID_Touch]); + this->_unfairlockTexFetch[NDSDisplayID_Touch] = NULL; +} + +GLuint OE_OGLClientSharedData::GetFetchTexture(const NDSDisplayID displayID) +{ + apple_unfairlock_lock(this->_unfairlockTexFetch[displayID]); + const GLuint texFetchID = this->OGLClientSharedData::GetFetchTexture(displayID); + apple_unfairlock_unlock(this->_unfairlockTexFetch[displayID]); + + return texFetchID; +} + +void OE_OGLClientSharedData::SetFetchTexture(const NDSDisplayID displayID, GLuint texID) +{ + apple_unfairlock_lock(this->_unfairlockTexFetch[displayID]); + this->OGLClientSharedData::SetFetchTexture(displayID, texID); + apple_unfairlock_unlock(this->_unfairlockTexFetch[displayID]); +} + +#pragma mark - + +OE_OGLClientFetchObject::OE_OGLClientFetchObject() +{ + _context = NULL; + _clientData = NULL; + _id = GPUClientFetchObjectID_OpenEmu; +} + +OE_OGLClientFetchObject::~OE_OGLClientFetchObject() +{ + delete (OE_OGLClientSharedData *)this->_clientData; +} + +CGLContextObj OE_OGLClientFetchObject::GetContext() const +{ + return this->_context; +} + +void OE_OGLClientFetchObject::Init() +{ + if (this->_clientData == NULL) + { + OGLContextInfo *newContextInfo = new OGLContextInfo_3_2; + snprintf(_name, sizeof(_name) - 1, "OpenEmu OpenGL v%i.%i", newContextInfo->GetVersionMajor(), newContextInfo->GetVersionMinor()); + strlcpy(_description, newContextInfo->GetRendererString(), sizeof(_description) - 1); + + this->_clientData = new OE_OGLClientSharedData; + ((OE_OGLClientSharedData *)this->_clientData)->SetContextInfo(newContextInfo); + } + + if ( this->_context != CGLGetCurrentContext() ) + { + this->_context = CGLGetCurrentContext(); + + OE_OGLClientSharedData *sharedData = (OE_OGLClientSharedData *)this->_clientData; + sharedData->InitOGL(); + } +} + +void OE_OGLClientFetchObject::SetFetchBuffers(const NDSDisplayInfo ¤tDisplayInfo) +{ + OE_OGLClientSharedData *sharedData = (OE_OGLClientSharedData *)this->_clientData; + this->GPUClientFetchObject::SetFetchBuffers(currentDisplayInfo); + sharedData->SetFetchBuffersOGL(this->_fetchDisplayInfo, currentDisplayInfo); +} + +void OE_OGLClientFetchObject::FetchFromBufferIndex(const u8 index) +{ + OE_OGLClientSharedData *sharedData = (OE_OGLClientSharedData *)this->_clientData; + this->GPUClientFetchObject::FetchFromBufferIndex(index); + + const NDSDisplayInfo ¤tDisplayInfo = this->GetFetchDisplayInfoForBufferIndex(index); + sharedData->FetchFromBufferIndexOGL(index, currentDisplayInfo); +} + +void OE_OGLClientFetchObject::_FetchNativeDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex) +{ + // This method is called from OE_OGLClientFetchObject::FetchFromBufferIndex(), and so + // we should have already been assigned the current context. + OE_OGLClientSharedData *sharedData = (OE_OGLClientSharedData *)this->_clientData; + sharedData->FetchNativeDisplayByID_OGL(this->_fetchDisplayInfo, displayID, bufferIndex); +} + +void OE_OGLClientFetchObject::_FetchCustomDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex) +{ + // This method is called from OE_OGLClientFetchObject::FetchFromBufferIndex(), and so + // we should have already been assigned the current context. + OE_OGLClientSharedData *sharedData = (OE_OGLClientSharedData *)this->_clientData; + sharedData->FetchCustomDisplayByID_OGL(this->_fetchDisplayInfo, displayID, bufferIndex); +} + +#pragma mark - + +OE_OGLDisplayPresenter::OE_OGLDisplayPresenter() +{ + __InstanceInit(NULL); +} + +OE_OGLDisplayPresenter::OE_OGLDisplayPresenter(OE_OGLClientFetchObject *fetchObject) +{ + __InstanceInit(fetchObject); +} + +void OE_OGLDisplayPresenter::__InstanceInit(OE_OGLClientFetchObject *fetchObject) +{ + if (fetchObject != NULL) + { + _context = fetchObject->GetContext(); + _contextInfo = ((OGLClientSharedData *)fetchObject->GetClientData())->GetContextInfo(); + } + else + { + _context = CGLGetCurrentContext(); + _contextInfo = new OGLContextInfo_3_2; + } + + SetFetchObject(fetchObject); +} + +void OE_OGLDisplayPresenter::Init() +{ + + if (this->_fetchObject != NULL) + { + this->_context = ((OE_OGLClientFetchObject *)this->_fetchObject)->GetContext(); + } + else + { + this->_context = CGLGetCurrentContext(); + } + + this->OGLVideoOutput::Init(); +} + +CGLContextObj OE_OGLDisplayPresenter::GetContext() const +{ + return this->_context; +} diff --git a/desmume/src/frontend/cocoa/openemu/OESoundInterface.mm b/desmume/src/frontend/cocoa/openemu/OESoundInterface.mm index 550b02dd6..dd00c8e4b 100644 --- a/desmume/src/frontend/cocoa/openemu/OESoundInterface.mm +++ b/desmume/src/frontend/cocoa/openemu/OESoundInterface.mm @@ -19,9 +19,11 @@ #import "../cocoa_globals.h" #include +#include "NDSGameCore.h" OERingBuffer *openEmuSoundInterfaceBuffer = nil; +static BOOL kWillUseOldAPI = NO; // Sound interface to the SPU SoundInterface_struct SNDOpenEmu = { @@ -48,6 +50,7 @@ SoundInterface_struct *SNDCoreList[] = { int SNDOpenEmuInit(int buffer_size) { [openEmuSoundInterfaceBuffer setLength:buffer_size * 4 / SPU_SAMPLE_SIZE]; + kWillUseOldAPI = ![openEmuSoundInterfaceBuffer respondsToSelector:@selector(freeBytes)]; return 0; } @@ -70,6 +73,11 @@ void SNDOpenEmuUpdateAudio(s16 *buffer, u32 num_samples) u32 SNDOpenEmuGetAudioSpace() { + if (kWillUseOldAPI) + { + SILENCE_DEPRECATION_OPENEMU( return (u32)[openEmuSoundInterfaceBuffer usedBytes] / SPU_SAMPLE_SIZE; ) + } + return (u32)[openEmuSoundInterfaceBuffer freeBytes] / SPU_SAMPLE_SIZE; }