From 12ab8bc3e245a4acf9203bd1eca9115ff921bdff Mon Sep 17 00:00:00 2001 From: Stossy11 <69031796+stossy11@users.noreply.github.com> Date: Sat, 8 Mar 2025 10:13:40 +1100 Subject: [PATCH 1/3] Merge Latest Ryujinx (Unstable) --- .editorconfig | 12 +- .github/ISSUE_TEMPLATE/bug_report.yml | 4 +- .github/ISSUE_TEMPLATE/feature_request.yml | 1 + .github/dependabot.yml | 22 +- .github/labeler.yml | 2 +- .github/reviewers.yml | 7 - .github/workflows/build.yml | 87 +- .github/workflows/checks.yml | 2 +- .github/workflows/flatpak.yml | 72 +- .github/workflows/mako.yml | 41 + .github/workflows/nightly_pr_comment.yml | 10 +- .github/workflows/pr_triage.yml | 19 - .github/workflows/release.yml | 76 +- Directory.Packages.props | 60 +- README.md | 3 + Ryujinx.sln | 14 +- Ryujinx.sln.DotSettings | 2 + distribution/linux/Ryujinx.desktop | 2 +- distribution/linux/Ryujinx.sh | 15 +- distribution/macos/create_app_bundle.sh | 4 +- distribution/macos/create_macos_build_ava.sh | 17 +- distribution/macos/shortcut-launch-script.sh | 8 + docs/README.md | 5 - .../CodeGen/Arm64/CodeGenContext.cs | 2 +- .../RegisterAllocators/LinearScanAllocator.cs | 39 +- .../RegisterAllocators/LiveInterval.cs | 21 + src/ARMeilleure/CodeGen/X86/Assembler.cs | 2 +- src/ARMeilleure/Decoders/OpCodeTable.cs | 15 + src/ARMeilleure/Instructions/InstEmitAlu32.cs | 309 +++++ .../Instructions/InstEmitMemoryHelper.cs | 18 +- .../Instructions/InstEmitSimdArithmetic.cs | 12 +- .../Instructions/InstEmitSimdArithmetic32.cs | 34 + .../Instructions/InstEmitSimdCvt32.cs | 16 + .../Instructions/InstEmitSimdHelper32.cs | 29 + .../Instructions/InstEmitSimdMove32.cs | 20 + .../Instructions/InstEmitSimdShift.cs | 105 +- .../Instructions/InstEmitSimdShift32.cs | 62 + src/ARMeilleure/Instructions/InstName.cs | 12 + .../Instructions/NativeInterface.cs | 20 +- src/ARMeilleure/Memory/IJitMemoryAllocator.cs | 2 - src/ARMeilleure/Memory/IMemoryManager.cs | 22 + src/ARMeilleure/Memory/MemoryManagerType.cs | 15 +- ...ler.cs => NativeSignalHandlerGenerator.cs} | 286 ++-- .../Signal/WindowsPartialUnmapHandler.cs | 37 +- .../WindowsSignalHandlerRegistration.cs | 44 - src/ARMeilleure/Translation/Cache/JitCache.cs | 11 +- .../Translation/ControlFlowGraph.cs | 11 +- src/ARMeilleure/Translation/PTC/Ptc.cs | 12 +- src/ARMeilleure/Translation/RegisterUsage.cs | 13 +- src/ARMeilleure/Translation/Translator.cs | 10 - .../Translation/TranslatorQueue.cs | 5 +- .../OpenALHardwareDeviceDriver.cs | 25 +- .../OpenALHardwareDeviceSession.cs | 22 +- .../SDL2HardwareDeviceDriver.cs | 8 +- .../SDL2HardwareDeviceSession.cs | 12 +- .../Ryujinx.Audio.Backends.SoundIo.csproj | 6 +- .../SoundIoHardwareDeviceDriver.cs | 25 +- .../SoundIoHardwareDeviceSession.cs | 25 +- .../Backends/Common/DynamicRingBuffer.cs | 63 +- .../CompatLayerHardwareDeviceDriver.cs | 12 +- .../Backends/CompatLayer/Downmixing.cs | 20 +- .../DelayLayerHardwareDeviceDriver.cs | 6 +- .../Dummy/DummyHardwareDeviceDriver.cs | 8 +- .../Dummy/DummyHardwareDeviceSessionOutput.cs | 4 +- src/Ryujinx.Audio/Input/AudioInputManager.cs | 8 +- .../Integration/HardwareDeviceImpl.cs | 4 +- .../Integration/IHardwareDeviceDriver.cs | 4 +- .../Output/AudioOutputManager.cs | 47 +- .../Renderer/Common/BehaviourParameter.cs | 2 +- .../Renderer/Common/UpdateDataHeader.cs | 2 +- .../Renderer/Common/VoiceUpdateState.cs | 1 - .../Renderer/Dsp/AudioProcessor.cs | 34 +- .../Renderer/Dsp/BiquadFilterHelper.cs | 234 +++- .../Dsp/Command/BiquadFilterAndMixCommand.cs | 123 ++ .../Renderer/Dsp/Command/CommandType.cs | 4 +- .../Renderer/Dsp/Command/CompressorCommand.cs | 45 +- .../Dsp/Command/LimiterCommandVersion1.cs | 46 +- .../Dsp/Command/LimiterCommandVersion2.cs | 48 +- .../Dsp/Command/MixRampGroupedCommand.cs | 16 +- .../MultiTapBiquadFilterAndMixCommand.cs | 145 +++ ...mand.cs => MultiTapBiquadFilterCommand.cs} | 6 +- .../Renderer/Dsp/State/BiquadFilterState.cs | 6 +- .../Parameter/BehaviourErrorInfoOutStatus.cs | 2 +- .../Parameter/Effect/CompressorParameter.cs | 11 +- .../Parameter/Effect/CompressorStatistics.cs | 38 + .../ISplitterDestinationInParameter.cs | 48 + ...SplitterDestinationInParameterVersion1.cs} | 24 +- .../SplitterDestinationInParameterVersion2.cs | 88 ++ .../Renderer/Server/AudioRenderSystem.cs | 36 +- .../Renderer/Server/AudioRendererManager.cs | 28 +- .../Renderer/Server/BehaviourContext.cs | 44 +- .../Renderer/Server/CommandBuffer.cs | 137 +- .../Renderer/Server/CommandGenerator.cs | 586 ++++++--- .../CommandProcessingTimeEstimatorVersion1.cs | 12 +- .../CommandProcessingTimeEstimatorVersion2.cs | 12 +- .../CommandProcessingTimeEstimatorVersion3.cs | 12 +- .../CommandProcessingTimeEstimatorVersion4.cs | 2 +- .../CommandProcessingTimeEstimatorVersion5.cs | 104 +- .../Server/Effect/AuxiliaryBufferEffect.cs | 14 +- .../Renderer/Server/Effect/BaseEffect.cs | 14 +- .../Server/Effect/BiquadFilterEffect.cs | 14 +- .../Renderer/Server/Effect/BufferMixEffect.cs | 14 +- .../Server/Effect/CaptureBufferEffect.cs | 14 +- .../Server/Effect/CompressorEffect.cs | 21 +- .../Renderer/Server/Effect/DelayEffect.cs | 14 +- .../Renderer/Server/Effect/LimiterEffect.cs | 14 +- .../Renderer/Server/Effect/Reverb3dEffect.cs | 14 +- .../Renderer/Server/Effect/ReverbEffect.cs | 14 +- .../Server/ICommandProcessingTimeEstimator.cs | 4 +- .../Renderer/Server/MemoryPool/PoolMapper.cs | 2 +- .../Renderer/Server/Mix/MixState.cs | 12 +- .../Server/Performance/PerformanceManager.cs | 8 +- .../Performance/PerformanceManagerGeneric.cs | 4 +- .../Renderer/Server/Sink/BaseSink.cs | 8 +- .../Server/Sink/CircularBufferSink.cs | 6 +- .../Renderer/Server/Sink/DeviceSink.cs | 6 +- .../Server/Splitter/SplitterContext.cs | 276 +++- .../Server/Splitter/SplitterDestination.cs | 376 ++++-- .../Splitter/SplitterDestinationVersion1.cs | 208 +++ .../Splitter/SplitterDestinationVersion2.cs | 252 ++++ .../Renderer/Server/Splitter/SplitterState.cs | 86 +- .../Renderer/Server/StateUpdater.cs | 154 +-- .../Renderer/Server/Voice/VoiceState.cs | 26 +- src/Ryujinx.Ava/Assets/Locales/zh_CN.json | 656 ---------- src/Ryujinx.Ava/Assets/Locales/zh_TW.json | 656 ---------- src/Ryujinx.Ava/Modules/Updater/Updater.cs | 777 ----------- src/Ryujinx.Ava/Program.cs | 236 ---- .../UI/Helpers/KeyValueConverter.cs | 46 - src/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs | 19 - .../UI/ViewModels/GamePadInputViewModel.cs | 63 - .../UI/ViewModels/InputViewModel.cs | 64 - .../UI/ViewModels/KeyboardInputViewModel.cs | 47 - .../UI/Views/Input/GamePadInputView.axaml | 741 ----------- .../UI/Views/Input/GamePadInputView.axaml.cs | 14 - .../UI/Views/Input/KeyboardInputView.axaml | 672 ---------- .../UI/Views/Input/KeyboardInputView.axaml.cs | 14 - .../Views/Settings/SettingsHotkeysView.axaml | 103 -- .../Settings/SettingsHotkeysView.axaml.cs | 81 -- .../Configuration/AppDataManager.cs | 243 +++- .../Configuration/Hid/KeyboardHotkeys.cs | 4 +- src/Ryujinx.Common/Configuration/Mod.cs | 9 + .../Configuration/ModMetadata.cs | 14 + .../ModMetadataJsonSerializerContext.cs | 10 + .../Extensions/SequenceReaderExtensions.cs | 181 +++ .../GraphicsDriver/DriverUtilities.cs | 24 +- src/Ryujinx.Common/Logging/LogClass.cs | 2 +- src/Ryujinx.Common/Logging/Logger.cs | 11 +- .../Logging/Targets/FileLogTarget.cs | 73 +- .../ByteMemoryPool.ByteMemoryPoolBuffer.cs | 51 - src/Ryujinx.Common/Memory/ByteMemoryPool.cs | 108 -- src/Ryujinx.Common/Memory/MemoryOwner.cs | 140 ++ src/Ryujinx.Common/Memory/SpanOrArray.cs | 89 -- src/Ryujinx.Common/Memory/SpanOwner.cs | 114 ++ .../Memory/StructArrayHelpers.cs | 11 + .../Memory/StructByteArrayHelpers.cs | 12 + src/Ryujinx.Common/ReleaseInformation.cs | 60 +- .../Utilities/EmbeddedResources.cs | 17 + .../Utilities/FileSystemUtils.cs | 56 + src/Ryujinx.Common/Utilities/OsUtils.cs | 24 + src/Ryujinx.Common/Utilities/StreamUtils.cs | 66 +- src/Ryujinx.Cpu/AddressSpace.cs | 437 +------ src/Ryujinx.Cpu/AppleHv/HvCodePatcher.cs | 62 - src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs | 711 ++-------- .../IVirtualMemoryManagerTracked.cs | 6 +- .../Jit/AddressSpacePartitionAllocator.cs | 22 +- .../AddressIntrusiveRedBlackTree.cs | 35 + .../Jit/HostTracked/AddressSpacePartition.cs | 708 ++++++++++ .../AddressSpacePartitionAllocator.cs | 202 +++ .../AddressSpacePartitionMultiAllocation.cs | 101 ++ .../HostTracked/AddressSpacePartitioned.cs | 407 ++++++ .../Jit/HostTracked/NativePageTable.cs | 223 ++++ src/Ryujinx.Cpu/Jit/JitCpuContext.cs | 8 + src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs | 2 - src/Ryujinx.Cpu/Jit/MemoryManager.cs | 487 +++---- .../Jit/MemoryManagerHostMapped.cs | 475 +------ .../Jit/MemoryManagerHostTracked.cs | 752 +++-------- src/Ryujinx.Cpu/LightningJit/Arm32/Block.cs | 5 + src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs | 18 +- .../LightningJit/Arm32/MultiBlock.cs | 3 + .../LightningJit/Arm32/RegisterAllocator.cs | 1 + .../Arm32/Target/Arm64/Compiler.cs | 27 +- .../Arm32/Target/Arm64/InstEmitFlow.cs | 4 +- .../Arm32/Target/Arm64/InstEmitMemory.cs | 7 +- .../Arm32/Target/Arm64/InstEmitMove.cs | 1 - .../Arm32/Target/Arm64/InstEmitNeonMemory.cs | 1 + .../Arm32/Target/Arm64/InstEmitSaturate.cs | 32 +- .../Arm32/Target/Arm64/InstEmitSystem.cs | 70 +- .../LightningJit/Arm64/InstName.cs | 33 + .../LightningJit/Arm64/RegisterAllocator.cs | 19 +- .../LightningJit/Arm64/RegisterUtils.cs | 4 +- .../LightningJit/Arm64/SysUtils.cs | 48 + .../Arm64/Target/Arm64/Compiler.cs | 15 +- .../Arm64/Target/Arm64/Decoder.cs | 20 +- .../Arm64/Target/Arm64/InstEmitMemory.cs | 120 +- .../Arm64/Target/Arm64/InstEmitSystem.cs | 16 +- .../LightningJit/Cache/CacheEntry.cs | 1 - .../LightningJit/Cache/NoWxCache.cs | 2 +- .../LightningJit/LightningJitCpuContext.cs | 2 +- src/Ryujinx.Cpu/LightningJit/Translator.cs | 19 +- src/Ryujinx.Cpu/ManagedPageFlags.cs | 389 ++++++ src/Ryujinx.Cpu/MemoryEhMeilleure.cs | 28 +- src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs | 184 +++ .../Signal/UnixSignalHandlerRegistration.cs | 2 +- .../WindowsSignalHandlerRegistration.cs | 24 + ... => VirtualMemoryManagerRefCountedBase.cs} | 2 +- .../DeviceMemoryManager.cs | 396 ++++++ src/Ryujinx.Graphics.Device/DeviceState.cs | 9 +- .../ISynchronizationManager.cs | 39 + .../Ryujinx.Graphics.Device.csproj | 4 + src/Ryujinx.Graphics.GAL/BufferAccess.cs | 11 +- src/Ryujinx.Graphics.GAL/Capabilities.cs | 34 +- src/Ryujinx.Graphics.GAL/Format.cs | 39 + src/Ryujinx.Graphics.GAL/HardwareInfo.cs | 4 +- src/Ryujinx.Graphics.GAL/IImageArray.cs | 9 + src/Ryujinx.Graphics.GAL/IPipeline.cs | 6 +- src/Ryujinx.Graphics.GAL/IRenderer.cs | 5 +- src/Ryujinx.Graphics.GAL/ITexture.cs | 16 +- src/Ryujinx.Graphics.GAL/ITextureArray.cs | 10 + .../Multithreading/CommandHelper.cs | 16 +- .../Multithreading/CommandType.cs | 14 +- .../ImageArray/ImageArrayDisposeCommand.cs | 21 + .../ImageArray/ImageArraySetImagesCommand.cs | 27 + .../Commands/Renderer/CreateBufferCommand.cs | 31 - .../Renderer/CreateImageArrayCommand.cs | 25 + .../Renderer/CreateTextureArrayCommand.cs | 25 + .../Commands/SetImageArrayCommand.cs | 26 + .../Commands/SetImageArraySeparateCommand.cs | 26 + .../Commands/SetImageCommand.cs | 9 +- .../Commands/SetTextureArrayCommand.cs | 26 + .../SetTextureArraySeparateCommand.cs | 26 + .../Commands/Texture/TextureSetDataCommand.cs | 7 +- .../Texture/TextureSetDataSliceCommand.cs | 7 +- .../TextureSetDataSliceRegionCommand.cs | 7 +- .../TextureArrayDisposeCommand.cs | 21 + .../TextureArraySetSamplersCommand.cs | 27 + .../TextureArraySetTexturesCommand.cs | 27 + .../Resources/ThreadedImageArray.cs | 36 + .../Resources/ThreadedTexture.cs | 9 +- .../Resources/ThreadedTextureArray.cs | 43 + .../Multithreading/ThreadedPipeline.cs | 28 +- .../Multithreading/ThreadedRenderer.cs | 26 +- src/Ryujinx.Graphics.GAL/ResourceLayout.cs | 10 +- src/Ryujinx.Graphics.GAL/SystemMemoryType.cs | 29 + src/Ryujinx.Graphics.GAL/TextureCreateInfo.cs | 20 - src/Ryujinx.Graphics.GAL/UpscaleType.cs | 1 + src/Ryujinx.Graphics.Gpu/Constants.cs | 5 + .../Engine/Compute/ComputeClass.cs | 6 +- .../Engine/Dma/DmaClass.cs | 67 +- .../Engine/GPFifo/GPFifoClass.cs | 3 + .../Engine/GPFifo/GPFifoProcessor.cs | 6 + .../InlineToMemory/InlineToMemoryClass.cs | 6 +- .../Engine/MME/MacroHLE.cs | 5 +- .../Engine/ShaderTexture.cs | 85 +- .../Threed/ComputeDraw/VtgAsComputeContext.cs | 8 +- .../Threed/ComputeDraw/VtgAsComputeState.cs | 7 +- .../Engine/Threed/DrawManager.cs | 16 +- .../Engine/Threed/DrawState.cs | 10 +- .../Engine/Threed/StateUpdateTracker.cs | 4 +- .../Engine/Threed/StateUpdater.cs | 51 +- .../Engine/Threed/ThreedClassState.cs | 8 +- .../Engine/Types/ColorFormat.cs | 2 + .../Engine/Types/ZetaFormat.cs | 28 +- src/Ryujinx.Graphics.Gpu/GpuContext.cs | 48 +- .../Image/AutoDeleteCache.cs | 33 +- src/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs | 21 +- src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs | 8 +- src/Ryujinx.Graphics.Gpu/Image/Pool.cs | 34 +- src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs | 7 +- src/Ryujinx.Graphics.Gpu/Image/Sampler.cs | 7 + .../Image/SamplerDescriptor.cs | 9 + src/Ryujinx.Graphics.Gpu/Image/Texture.cs | 175 ++- .../Image/TextureBindingInfo.cs | 41 +- .../Image/TextureBindingsArrayCache.cs | 1153 +++++++++++++++++ .../Image/TextureBindingsManager.cs | 111 +- .../Image/TextureCache.cs | 164 ++- .../Image/TextureCompatibility.cs | 10 +- .../Image/TextureGroup.cs | 38 +- .../Image/TextureGroupHandle.cs | 9 +- .../Image/TextureManager.cs | 30 +- src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs | 239 +++- src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs | 397 +++++- .../Memory/BufferBackingState.cs | 294 +++++ .../Memory/BufferBounds.cs | 23 +- .../Memory/BufferCache.cs | 298 ++++- .../Memory/BufferManager.cs | 146 ++- .../Memory/BufferMigration.cs | 250 +++- .../Memory/BufferModifiedRangeList.cs | 138 +- .../Memory/BufferPreFlush.cs | 295 +++++ .../Memory/BufferStage.cs | 99 ++ .../Memory/BufferTextureArrayBinding.cs | 59 + .../Memory/BufferTextureBinding.cs | 8 - .../Memory/MemoryManager.cs | 60 +- .../Memory/MultiRangeBuffer.cs | 187 ++- .../Memory/PhysicalMemory.cs | 41 +- ...ualBufferCache.cs => VirtualRangeCache.cs} | 22 +- .../Shader/CachedShaderBindings.cs | 28 +- .../Shader/DiskCache/BinarySerializer.cs | 43 +- .../Shader/DiskCache/CompressionAlgorithm.cs | 5 + .../Shader/DiskCache/DiskCacheCommon.cs | 2 +- .../Shader/DiskCache/DiskCacheGpuAccessor.cs | 72 +- .../Shader/DiskCache/DiskCacheGuestStorage.cs | 4 +- .../Shader/DiskCache/DiskCacheHostStorage.cs | 2 +- .../Shader/DiskCache/DiskCacheLoadResult.cs | 6 + .../DiskCache/ParallelDiskCacheLoader.cs | 8 +- .../Shader/GpuAccessor.cs | 63 +- .../Shader/GpuAccessorBase.cs | 111 +- .../Shader/GpuAccessorState.cs | 8 + .../Shader/GpuChannelGraphicsState.cs | 11 +- .../Shader/GpuChannelPoolState.cs | 7 +- .../Shader/ResourceCounts.cs | 5 + .../Shader/ShaderCache.cs | 13 +- .../Shader/ShaderInfoBuilder.cs | 207 ++- .../Shader/ShaderSpecializationState.cs | 149 ++- .../Synchronization/SynchronizationManager.cs | 27 +- src/Ryujinx.Graphics.Gpu/Window.cs | 2 +- src/Ryujinx.Graphics.Host1x/Host1xClass.cs | 5 +- src/Ryujinx.Graphics.Host1x/Host1xDevice.cs | 3 +- .../Ryujinx.Graphics.Host1x.csproj | 1 - .../SyncptIncrManager.cs | 6 +- src/Ryujinx.Graphics.Nvdec/H264Decoder.cs | 8 +- .../Image/SurfaceCache.cs | 12 +- .../Image/SurfaceReader.cs | 8 +- .../Image/SurfaceWriter.cs | 18 +- .../MemoryExtensions.cs | 14 +- src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs | 5 +- src/Ryujinx.Graphics.Nvdec/ResourceManager.cs | 8 +- .../Ryujinx.Graphics.Nvdec.csproj | 1 - src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs | 6 +- src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs | 24 +- .../BackgroundContextWorker.cs | 2 + .../Effects/AreaScalingFilter.cs | 106 ++ .../Effects/FsrScalingFilter.cs | 6 +- .../Effects/ShaderHelper.cs | 23 +- .../Effects/Shaders/area_scaling.glsl | 119 ++ .../Effects/Shaders/fsr_scaling.glsl | 2 +- .../Effects/SmaaPostProcessingEffect.cs | 7 +- src/Ryujinx.Graphics.OpenGL/FormatTable.cs | 14 + src/Ryujinx.Graphics.OpenGL/Framebuffer.cs | 16 +- src/Ryujinx.Graphics.OpenGL/IOpenGLContext.cs | 17 +- .../Image/FormatConverter.cs | 9 +- .../Image/ImageArray.cs | 63 + .../Image/TextureArray.cs | 56 + .../Image/TextureBuffer.cs | 11 +- .../Image/TextureCopy.cs | 11 +- .../Image/TextureStorage.cs | 2 +- .../Image/TextureView.cs | 105 +- src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs | 37 +- src/Ryujinx.Graphics.OpenGL/Pipeline.cs | 35 +- src/Ryujinx.Graphics.OpenGL/Program.cs | 9 +- .../Ryujinx.Graphics.OpenGL.csproj | 1 + src/Ryujinx.Graphics.OpenGL/Window.cs | 10 + .../BufferDescriptor.cs | 7 +- .../CodeGen/Glsl/Declarations.cs | 49 +- .../CodeGen/Glsl/Instructions/InstGen.cs | 10 +- .../Glsl/Instructions/InstGenBallot.cs | 2 +- .../CodeGen/Glsl/Instructions/InstGenCall.cs | 2 +- .../Glsl/Instructions/InstGenHelper.cs | 2 +- .../Glsl/Instructions/InstGenMemory.cs | 188 +-- .../Glsl/Instructions/InstGenPacking.cs | 12 +- .../Glsl/Instructions/InstGenShuffle.cs | 4 +- .../Glsl/Instructions/InstGenVector.cs | 4 +- .../CodeGen/Glsl/OperandManager.cs | 4 +- .../CodeGen/Spirv/CodeGenContext.cs | 11 +- .../CodeGen/Spirv/Declarations.cs | 99 +- .../CodeGen/Spirv/ImageDeclaration.cs | 20 + .../CodeGen/Spirv/Instructions.cs | 250 ++-- .../CodeGen/Spirv/SamplerDeclaration.cs | 27 + .../CodeGen/Spirv/SpirvGenerator.cs | 12 +- .../GpuGraphicsState.cs | 10 +- src/Ryujinx.Graphics.Shader/IGpuAccessor.cs | 70 +- .../Instructions/InstEmitAttribute.cs | 10 + .../Instructions/InstEmitMemory.cs | 69 +- .../Instructions/InstEmitPredicate.cs | 2 +- .../Instructions/InstEmitSurface.cs | 20 +- .../Instructions/InstEmitTexture.cs | 36 +- .../IntermediateRepresentation/Instruction.cs | 32 + .../IntermediateRepresentation/Operation.cs | 15 +- .../TextureOperation.cs | 26 +- src/Ryujinx.Graphics.Shader/SamplerType.cs | 61 +- src/Ryujinx.Graphics.Shader/SetBindingPair.cs | 4 + .../StructuredIr/AstTextureOperation.cs | 21 + .../StructuredIr/PhiFunctions.cs | 8 +- .../StructuredIr/ShaderProperties.cs | 16 +- .../StructuredIr/StructuredProgram.cs | 12 +- .../StructuredIr/TextureDefinition.cs | 20 +- .../TextureDescriptor.cs | 18 +- src/Ryujinx.Graphics.Shader/TextureHandle.cs | 5 +- .../Translation/EmitterContext.cs | 9 +- .../Translation/EmitterContextInsts.cs | 91 +- .../Translation/HostCapabilities.cs | 3 + .../Optimizations/BindlessElimination.cs | 485 ++++--- .../Optimizations/BindlessToArray.cs | 238 ++++ .../Optimizations/BindlessToIndexed.cs | 118 -- .../Translation/Optimizations/Optimizer.cs | 33 +- .../Optimizations/Simplification.cs | 30 + .../Translation/Optimizations/Utils.cs | 98 +- .../Translation/RegisterUsage.cs | 9 +- .../Translation/ResourceManager.cs | 298 +++-- .../Translation/ResourceReservations.cs | 17 + .../Translation/ShaderDefinitions.cs | 2 + .../Translation/TransformContext.cs | 3 + .../Translation/Transforms/TexturePass.cs | 50 +- .../Translation/Transforms/VertexToCompute.cs | 8 +- .../Translation/Translator.cs | 12 +- .../Translation/TranslatorContext.cs | 14 +- .../Astc/AstcDecoder.cs | 4 +- src/Ryujinx.Graphics.Texture/BCnDecoder.cs | 44 +- src/Ryujinx.Graphics.Texture/BCnEncoder.cs | 7 +- src/Ryujinx.Graphics.Texture/ETC2Decoder.cs | 18 +- .../LayoutConverter.cs | 12 +- .../PixelConverter.cs | 37 +- .../Image/SurfaceReader.cs | 4 +- .../Image/SurfaceWriter.cs | 4 +- src/Ryujinx.Graphics.Vic/ResourceManager.cs | 8 +- .../Ryujinx.Graphics.Vic.csproj | 2 - src/Ryujinx.Graphics.Vic/VicDevice.cs | 11 +- .../BackgroundResources.cs | 9 +- src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs | 458 +++++++ src/Ryujinx.Graphics.Vulkan/BufferHolder.cs | 243 +--- src/Ryujinx.Graphics.Vulkan/BufferManager.cs | 96 +- src/Ryujinx.Graphics.Vulkan/BufferState.cs | 5 +- .../CommandBufferPool.cs | 49 +- .../CommandBufferScoped.cs | 5 - src/Ryujinx.Graphics.Vulkan/Constants.cs | 1 + .../DescriptorSetCollection.cs | 34 +- .../DescriptorSetManager.cs | 4 +- .../DescriptorSetTemplate.cs | 210 +++ .../DescriptorSetTemplateUpdater.cs | 77 ++ .../DescriptorSetUpdater.cs | 638 +++++++-- .../Effects/AreaScalingFilter.cs | 101 ++ .../Effects/FsrScalingFilter.cs | 25 +- .../Effects/FxaaPostProcessingEffect.cs | 12 +- .../Effects/Shaders/AreaScaling.glsl | 122 ++ .../Effects/Shaders/AreaScaling.spv | Bin 0 -> 12428 bytes .../Effects/SmaaPostProcessingEffect.cs | 27 +- src/Ryujinx.Graphics.Vulkan/EnumConversion.cs | 16 +- .../FeedbackLoopAspects.cs | 12 + src/Ryujinx.Graphics.Vulkan/FenceHolder.cs | 79 +- .../FormatCapabilities.cs | 2 +- src/Ryujinx.Graphics.Vulkan/FormatTable.cs | 16 + .../FramebufferParams.cs | 138 +- .../HardwareCapabilities.cs | 9 + src/Ryujinx.Graphics.Vulkan/HashTableSlim.cs | 87 +- src/Ryujinx.Graphics.Vulkan/HelperShader.cs | 198 +-- .../HostMemoryAllocator.cs | 2 +- src/Ryujinx.Graphics.Vulkan/ImageArray.cs | 207 +++ .../MemoryAllocatorBlockList.cs | 2 +- .../MoltenVK/MVKInitialization.cs | 18 + .../MultiFenceHolder.cs | 29 +- src/Ryujinx.Graphics.Vulkan/PipelineBase.cs | 513 ++++---- .../PipelineConverter.cs | 48 +- .../PipelineDynamicState.cs | 34 +- src/Ryujinx.Graphics.Vulkan/PipelineFull.cs | 35 +- .../PipelineHelperShader.cs | 13 +- .../PipelineLayoutCacheEntry.cs | 280 +++- .../PipelineLayoutFactory.cs | 37 +- src/Ryujinx.Graphics.Vulkan/PipelineState.cs | 280 ++-- src/Ryujinx.Graphics.Vulkan/PipelineUid.cs | 19 +- .../Queries/BufferedQuery.cs | 6 +- .../Queries/CounterQueue.cs | 13 +- .../RenderPassCacheKey.cs | 43 + .../RenderPassHolder.cs | 221 ++++ src/Ryujinx.Graphics.Vulkan/ResourceArray.cs | 81 ++ .../ResourceBindingSegment.cs | 4 +- .../ResourceLayoutBuilder.cs | 4 +- .../Ryujinx.Graphics.Vulkan.csproj | 1 + src/Ryujinx.Graphics.Vulkan/SamplerHolder.cs | 2 +- .../SemaphoreHolder.cs | 60 - src/Ryujinx.Graphics.Vulkan/Shader.cs | 2 +- .../ShaderCollection.cs | 266 +++- src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs | 23 +- src/Ryujinx.Graphics.Vulkan/TextureArray.cs | 234 ++++ src/Ryujinx.Graphics.Vulkan/TextureBuffer.cs | 45 +- src/Ryujinx.Graphics.Vulkan/TextureCopy.cs | 14 +- src/Ryujinx.Graphics.Vulkan/TextureStorage.cs | 218 ++-- src/Ryujinx.Graphics.Vulkan/TextureView.cs | 266 +++- src/Ryujinx.Graphics.Vulkan/Vendor.cs | 38 + .../VulkanConfiguration.cs | 2 +- .../VulkanException.cs | 8 +- .../VulkanInitialization.cs | 89 +- .../VulkanPhysicalDevice.cs | 27 + src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs | 242 +++- src/Ryujinx.Graphics.Vulkan/Window.cs | 58 +- .../Input/GTK3/GTK3Keyboard.cs | 0 .../Input/GTK3/GTK3KeyboardDriver.cs | 5 + .../Input/GTK3/GTK3MappingHelper.cs | 0 .../Input/GTK3/GTK3Mouse.cs | 0 .../Input/GTK3/GTK3MouseDriver.cs | 0 .../Modules/Updater/UpdateDialog.cs | 13 +- .../Modules/Updater/UpdateDialog.glade | 0 src/Ryujinx.Gtk3/Modules/Updater/Updater.cs | 622 +++++++++ src/Ryujinx.Gtk3/Program.cs | 403 ++++++ src/Ryujinx.Gtk3/Ryujinx.Gtk3.csproj | 103 ++ src/{Ryujinx.Ava => Ryujinx.Gtk3}/Ryujinx.ico | Bin .../UI}/Applet/ErrorAppletDialog.cs | 6 +- .../UI}/Applet/GtkDynamicTextInputHandler.cs | 6 +- .../UI/Applet/GtkHostUIHandler.cs} | 18 +- .../UI/Applet/GtkHostUITheme.cs} | 8 +- .../UI}/Applet/SwkbdAppletDialog.cs | 2 +- src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs | 158 +++ .../UI}/Helper/MetalHelper.cs | 2 +- .../UI}/Helper/SortHelper.cs | 4 +- .../UI}/Helper/ThemeHelper.cs | 17 +- .../Ui => Ryujinx.Gtk3/UI}/MainWindow.cs | 285 ++-- .../Ui => Ryujinx.Gtk3/UI}/MainWindow.glade | 4 +- .../Ui => Ryujinx.Gtk3/UI}/OpenGLRenderer.cs | 6 +- .../UI}/OpenToolkitBindingsContext.cs | 2 +- .../UI}/RendererWidgetBase.cs | 80 +- .../UI}/SPBOpenGLContext.cs | 4 +- .../UI}/StatusUpdatedEventArgs.cs | 2 +- .../Ui => Ryujinx.Gtk3/UI}/VulkanRenderer.cs | 4 +- .../Widgets/GameTableContextMenu.Designer.cs | 5 +- .../UI}/Widgets/GameTableContextMenu.cs | 124 +- .../UI}/Widgets/GtkDialog.cs | 6 +- .../UI}/Widgets/GtkInputDialog.cs | 2 +- .../UI}/Widgets/ProfileDialog.cs | 8 +- .../UI}/Widgets/ProfileDialog.glade | 0 .../UI}/Widgets/RawInputToTextEntry.cs | 2 +- .../UI}/Widgets/UserErrorDialog.cs | 6 +- .../UI}/Windows/AboutWindow.Designer.cs | 14 +- .../UI}/Windows/AboutWindow.cs | 6 +- .../UI}/Windows/AmiiboWindow.Designer.cs | 2 +- .../UI}/Windows/AmiiboWindow.cs | 120 +- .../UI}/Windows/AvatarWindow.cs | 37 +- .../UI}/Windows/CheatWindow.cs | 17 +- .../UI}/Windows/CheatWindow.glade | 0 .../UI}/Windows/ControllerWindow.cs | 24 +- .../UI}/Windows/ControllerWindow.glade | 0 .../UI}/Windows/DlcWindow.cs | 132 +- .../UI}/Windows/DlcWindow.glade | 0 .../UI}/Windows/SettingsWindow.cs | 26 +- .../UI}/Windows/SettingsWindow.glade | 0 .../UI}/Windows/TitleUpdateWindow.cs | 104 +- .../UI}/Windows/TitleUpdateWindow.glade | 0 .../UserProfilesManagerWindow.Designer.cs | 2 +- .../UI}/Windows/UserProfilesManagerWindow.cs | 18 +- src/Ryujinx.HLE.Generators/CodeGenerator.cs | 2 +- .../IpcServiceGenerator.cs | 21 +- .../ServiceSyntaxReceiver.cs | 8 +- src/Ryujinx.HLE/FileSystem/ContentManager.cs | 63 +- src/Ryujinx.HLE/FileSystem/ContentMetaData.cs | 61 + src/Ryujinx.HLE/FileSystem/ContentPath.cs | 16 +- .../FileSystem/VirtualFileSystem.cs | 7 +- src/Ryujinx.HLE/HLEConfiguration.cs | 8 +- .../Applets/Controller/ControllerApplet.cs | 4 +- ...letUiArgs.cs => ControllerAppletUIArgs.cs} | 2 +- .../HOS/Applets/Error/ErrorApplet.cs | 8 +- src/Ryujinx.HLE/HOS/Applets/IApplet.cs | 2 +- .../SoftwareKeyboardApplet.cs | 21 +- .../SoftwareKeyboardRenderer.cs | 21 +- .../SoftwareKeyboardRendererBase.cs | 443 +++---- ...ardUiArgs.cs => SoftwareKeyboardUIArgs.cs} | 2 +- ...dUiState.cs => SoftwareKeyboardUIState.cs} | 4 +- src/Ryujinx.HLE/HOS/ArmProcessContext.cs | 2 + .../HOS/ArmProcessContextFactory.cs | 7 +- src/Ryujinx.HLE/HOS/Horizon.cs | 98 +- .../HOS/Kernel/Common/KSystemControl.cs | 8 +- .../HOS/Kernel/Ipc/KServerSession.cs | 4 +- .../HOS/Kernel/Memory/AddressSpaceType.cs | 10 - .../HOS/Kernel/Memory/KPageTable.cs | 19 +- .../HOS/Kernel/Memory/KPageTableBase.cs | 118 +- .../HOS/Kernel/Memory/KSharedMemory.cs | 13 +- .../HOS/Kernel/Process/KProcess.cs | 29 +- .../Kernel/Process/KProcessCapabilities.cs | 14 +- .../Kernel/Process/ProcessCreationFlags.cs | 6 +- .../Kernel/SupervisorCall/ExternalEvent.cs | 25 + .../HOS/Kernel/SupervisorCall/InfoType.cs | 7 +- .../HOS/Kernel/SupervisorCall/Syscall.cs | 182 +-- .../HOS/Kernel/Threading/KScheduler.cs | 153 ++- .../HOS/Kernel/Threading/KSynchronization.cs | 2 +- .../HOS/Kernel/Threading/KThread.cs | 5 +- .../HOS/Kernel/Threading/ThreadType.cs | 1 - src/Ryujinx.HLE/HOS/ModLoader.cs | 173 ++- .../Services/Account/Acc/AccountManager.cs | 13 +- .../Acc/AccountService/ManagerServer.cs | 50 +- .../ApplicationProxy/IApplicationFunctions.cs | 4 +- src/Ryujinx.HLE/HOS/Services/Arp/IReader.cs | 8 - src/Ryujinx.HLE/HOS/Services/Arp/IWriter.cs | 8 - .../HOS/Services/Audio/AudioIn/AudioIn.cs | 108 -- .../Services/Audio/AudioIn/AudioInServer.cs | 200 --- .../HOS/Services/Audio/AudioIn/IAudioIn.cs | 34 - .../HOS/Services/Audio/AudioInManager.cs | 40 - .../Services/Audio/AudioInManagerServer.cs | 243 ---- .../HOS/Services/Audio/AudioOut/AudioOut.cs | 108 -- .../Services/Audio/AudioOut/AudioOutServer.cs | 181 --- .../HOS/Services/Audio/AudioOut/IAudioOut.cs | 33 - .../HOS/Services/Audio/AudioOutManager.cs | 40 - .../Services/Audio/AudioOutManagerServer.cs | 166 --- .../Audio/AudioRenderer/AudioDevice.cs | 174 --- .../Audio/AudioRenderer/AudioDeviceServer.cs | 320 ----- .../Audio/AudioRenderer/AudioKernelEvent.cs | 25 - .../Audio/AudioRenderer/AudioRenderer.cs | 122 -- .../AudioRenderer/AudioRendererServer.cs | 215 --- .../Audio/AudioRenderer/IAudioDevice.cs | 18 - .../Audio/AudioRenderer/IAudioRenderer.cs | 22 - .../Services/Audio/AudioRendererManager.cs | 67 - .../Audio/AudioRendererManagerServer.cs | 116 -- .../HardwareOpusDecoderManager/Decoder.cs | 27 - .../DecoderCommon.cs | 92 -- .../HardwareOpusDecoderManager/IDecoder.cs | 11 - .../IHardwareOpusDecoder.cs | 116 -- .../MultiSampleDecoder.cs | 28 - .../HOS/Services/Audio/IAudioController.cs | 8 - .../HOS/Services/Audio/IAudioInManager.cs | 12 - .../Audio/IAudioInManagerForApplet.cs | 8 - .../Audio/IAudioInManagerForDebugger.cs | 8 - .../HOS/Services/Audio/IAudioOutManager.cs | 12 - .../Audio/IAudioOutManagerForApplet.cs | 8 - .../Audio/IAudioOutManagerForDebugger.cs | 8 - .../Services/Audio/IAudioRendererManager.cs | 19 - .../Audio/IAudioRendererManagerForApplet.cs | 8 - .../Audio/IAudioRendererManagerForDebugger.cs | 8 - .../HOS/Services/Audio/IAudioSnoopManager.cs | 8 - .../Audio/IFinalOutputRecorderManager.cs | 8 - .../IFinalOutputRecorderManagerForApplet.cs | 8 - .../IFinalOutputRecorderManagerForDebugger.cs | 8 - .../Audio/IHardwareOpusDecoderManager.cs | 227 ---- .../HOS/Services/Audio/ResultCode.cs | 21 - .../Services/Audio/Types/OpusPacketHeader.cs | 23 - .../Services/Audio/Types/OpusParametersEx.cs | 15 - .../HOS/Services/Caps/CaptureManager.cs | 10 +- .../HOS/Services/Fatal/IService.cs | 2 +- .../HOS/Services/Friend/IServiceCreator.cs | 55 - .../HOS/Services/Friend/ResultCode.cs | 14 - .../FriendService/Types/Friend.cs | 29 - .../FriendService/Types/FriendFilter.cs | 24 - .../FriendService/Types/UserPresence.cs | 34 - .../IDaemonSuspendSessionService.cs | 14 - .../Friend/ServiceCreator/IFriendService.cs | 374 ------ .../ServiceCreator/INotificationService.cs | 178 --- .../NotificationEventHandler.cs | 74 -- .../Types/NotificationInfo.cs | 13 - .../Fs/FileSystemProxy/IFileSystem.cs | 9 +- .../Services/Fs/FileSystemProxy/LazyFile.cs | 65 + .../Services/Hid/HidDevices/MouseDevice.cs | 4 +- .../HOS/Services/Hid/IHidServer.cs | 27 + .../Nim/IShopServiceAccessServerInterface.cs | 7 + .../HOS/Services/Nv/Host1xContext.cs | 6 +- .../NvHostAsGpu/NvHostAsGpuDeviceFile.cs | 2 +- .../NvHostChannel/NvHostChannelDeviceFile.cs | 8 +- .../NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs | 33 + .../NvHostCtrlGpu/Types/NumVsmsArguments.cs | 11 + .../Types/VsmsMappingArguments.cs | 14 + .../Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs | 6 +- .../NvDrvServices/NvMap/Types/NvMapCreate.cs | 2 +- .../Nv/NvDrvServices/NvMap/Types/NvMapFree.cs | 2 +- .../NvDrvServices/NvMap/Types/NvMapHandle.cs | 4 +- .../IParentalControlService.cs | 2 - .../HOS/Services/Ptm/Ts/IMeasurementServer.cs | 39 - src/Ryujinx.HLE/HOS/Services/ServerBase.cs | 26 +- .../HOS/Services/Sockets/Bsd/IClient.cs | 12 +- .../SslService/SslManagedSocketConnection.cs | 31 + .../HOS/Services/SurfaceFlinger/IBinder.cs | 4 +- .../SurfaceFlinger/IHOSBinderDriver.cs | 4 +- .../HOS/Services/SurfaceFlinger/Parcel.cs | 31 +- .../Services/SurfaceFlinger/SurfaceFlinger.cs | 4 +- .../RootService/IApplicationDisplayService.cs | 6 +- src/Ryujinx.HLE/HOS/TamperMachine.cs | 6 +- src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs | 6 + src/Ryujinx.HLE/Loaders/Npdm/ACID.cs | 5 + .../Loaders/Npdm/FsAccessControl.cs | 4 + .../Loaders/Npdm/FsAccessHeader.cs | 6 + .../Loaders/Npdm/KernelAccessControl.cs | 4 + src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs | 7 + .../Loaders/Npdm/ServiceAccessControl.cs | 5 + .../Extensions/FileSystemExtensions.cs | 3 +- .../Extensions/LocalFileSystemExtensions.cs | 8 +- .../Processes/Extensions/NcaExtensions.cs | 88 +- .../PartitionFileSystemExtensions.cs | 85 +- .../Loaders/Processes/ProcessLoader.cs | 13 +- .../Loaders/Processes/ProcessLoaderHelper.cs | 32 +- src/Ryujinx.HLE/Ryujinx.HLE.csproj | 17 +- src/Ryujinx.HLE/Switch.cs | 21 +- .../{Ui => UI}/DynamicTextChangedHandler.cs | 2 +- .../{Ui => UI}/IDynamicTextInputHandler.cs | 2 +- .../IHostUIHandler.cs} | 10 +- .../IHostUiTheme.cs => UI/IHostUITheme.cs} | 4 +- .../{Ui => UI}/Input/NpadButtonHandler.cs | 2 +- .../{Ui => UI}/Input/NpadReader.cs | 2 +- .../{Ui => UI}/KeyPressedHandler.cs | 2 +- .../{Ui => UI}/KeyReleasedHandler.cs | 2 +- .../{Ui => UI}/RenderingSurfaceInfo.cs | 2 +- src/Ryujinx.HLE/{Ui => UI}/ThemeColor.cs | 2 +- .../Utilities/PartitionFileSystemUtils.cs | 45 + .../HeadlessDynamicTextInputHandler.cs | 2 +- .../HeadlessHostUiTheme.cs | 4 +- src/Ryujinx.Headless.SDL2/Keyboard-iOS.cs | 2 +- .../OpenGL/OpenGLWindow.cs | 2 + src/Ryujinx.Headless.SDL2/Options.cs | 2 +- src/Ryujinx.Headless.SDL2/Program.cs | 72 +- .../Ryujinx.Headless.SDL2.csproj | 4 +- src/Ryujinx.Headless.SDL2/WindowBase.cs | 42 +- src/Ryujinx.Horizon.Common/IExternalEvent.cs | 10 + src/Ryujinx.Horizon.Common/ISyscallApi.cs | 5 + src/Ryujinx.Horizon.Common/Result.cs | 5 + .../Hipc/HipcGenerator.cs | 130 +- src/Ryujinx.Horizon/Arp/ArpIpcServer.cs | 62 + src/Ryujinx.Horizon/Arp/ArpMain.cs | 20 + src/Ryujinx.Horizon/Arp/Ipc/Reader.cs | 135 ++ src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs | 52 + .../Arp/Ipc/UnregistrationNotifier.cs | 25 + src/Ryujinx.Horizon/Arp/Ipc/Updater.cs | 74 ++ src/Ryujinx.Horizon/Arp/Ipc/Writer.cs | 75 ++ src/Ryujinx.Horizon/Audio/AudioMain.cs | 17 + src/Ryujinx.Horizon/Audio/AudioManagers.cs | 78 ++ .../Audio/AudioUserIpcServer.cs | 55 + src/Ryujinx.Horizon/Audio/HwopusIpcServer.cs | 46 + src/Ryujinx.Horizon/Audio/HwopusMain.cs | 17 + src/Ryujinx.Horizon/Bcat/BcatIpcServer.cs | 1 + .../Friends/FriendsIpcServer.cs | 50 + src/Ryujinx.Horizon/Friends/FriendsMain.cs | 17 + .../Friends/FriendsPortIndex.cs | 11 + .../Friends/FriendsServerManager.cs | 36 + src/Ryujinx.Horizon/HorizonOptions.cs | 17 +- src/Ryujinx.Horizon/Hshl/HshlIpcServer.cs | 1 + src/Ryujinx.Horizon/Ins/InsIpcServer.cs | 1 + src/Ryujinx.Horizon/Lbl/LblIpcServer.cs | 1 + src/Ryujinx.Horizon/LogManager/LmIpcServer.cs | 1 + src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs | 1 + src/Ryujinx.Horizon/Ngc/Ipc/Service.cs | 6 +- src/Ryujinx.Horizon/Ngc/NgcIpcServer.cs | 2 +- src/Ryujinx.Horizon/Ovln/OvlnIpcServer.cs | 1 + src/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs | 21 +- src/Ryujinx.Horizon/Prepo/PrepoIpcServer.cs | 8 +- .../Prepo/PrepoServerManager.cs | 18 +- src/Ryujinx.Horizon/Psc/PscIpcServer.cs | 1 + .../Ptm/Ipc/MeasurementServer.cs | 63 + src/Ryujinx.Horizon/Ptm/Ipc/Session.cs | 47 + src/Ryujinx.Horizon/Ptm/TsIpcServer.cs | 44 + src/Ryujinx.Horizon/Ptm/TsMain.cs | 17 + src/Ryujinx.Horizon/Ryujinx.Horizon.csproj | 5 +- .../Sdk/Account/IEmulatorAccountManager.cs | 8 + .../Sdk/Account/NetworkServiceAccountId.cs | 20 + src/Ryujinx.Horizon/Sdk/Account/Nickname.cs | 29 + src/Ryujinx.Horizon/Sdk/Account/Uid.cs | 18 +- src/Ryujinx.Horizon/Sdk/Applet/AppletId.cs | 71 + .../Sdk/Applet/AppletResourceUserId.cs | 15 + .../Sdk/Arp/ApplicationCertificate.cs | 9 + .../Sdk/Arp/ApplicationKind.cs | 8 + .../Sdk/Arp/ApplicationLaunchProperty.cs | 14 + .../Sdk/Arp/ApplicationProcessProperty.cs | 10 + src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs | 130 ++ src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs | 17 + .../Sdk/Arp/Detail/ApplicationInstance.cs | 13 + .../Arp/Detail/ApplicationInstanceManager.cs | 31 + src/Ryujinx.Horizon/Sdk/Arp/IReader.cs | 18 + src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs | 12 + .../Sdk/Arp/IUnregistrationNotifier.cs | 9 + src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs | 12 + src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs | 12 + src/Ryujinx.Horizon/Sdk/Audio/AudioEvent.cs | 50 + src/Ryujinx.Horizon/Sdk/Audio/AudioResult.cs | 13 + .../Sdk/Audio/Detail/AudioDevice.cs | 294 +++++ .../Sdk/Audio/Detail/AudioIn.cs | 171 +++ .../Sdk/Audio/Detail/AudioInManager.cs | 130 ++ .../Sdk/Audio/Detail/AudioInProtocol.cs | 23 + .../Sdk/Audio/Detail/AudioInProtocolName.cs | 8 + .../Sdk/Audio/Detail/AudioOut.cs | 154 +++ .../Sdk/Audio/Detail/AudioOutManager.cs | 93 ++ .../Sdk/Audio/Detail/AudioRenderer.cs | 178 +++ .../Sdk/Audio/Detail/AudioRendererManager.cs | 132 ++ .../Detail/AudioRendererParameterInternal.cs | 14 + .../Sdk/Audio/Detail/AudioSnoopManager.cs | 30 + .../Sdk/Audio/Detail/DeviceName.cs | 30 + .../Sdk/Audio/Detail/FinalOutputRecorder.cs | 147 +++ .../Detail/FinalOutputRecorderManager.cs | 23 + .../Detail/FinalOutputRecorderParameter.cs | 17 + .../FinalOutputRecorderParameterInternal.cs | 21 + .../Sdk/Audio/Detail/IAudioDevice.cs | 24 + .../Sdk/Audio/Detail/IAudioIn.cs | 26 + .../Sdk/Audio/Detail/IAudioInManager.cs | 43 + .../Sdk/Audio/Detail/IAudioOut.cs | 25 + .../Sdk/Audio/Detail/IAudioOutManager.cs | 32 + .../Sdk/Audio/Detail/IAudioRenderer.cs | 25 + .../Sdk/Audio/Detail/IAudioRendererManager.cs | 29 + .../Sdk/Audio/Detail/IAudioSnoopManager.cs | 12 + .../Sdk/Audio/Detail/IFinalOutputRecorder.cs | 22 + .../Detail/IFinalOutputRecorderManager.cs | 16 + src/Ryujinx.Horizon/Sdk/Codec/CodecResult.cs | 16 + .../Sdk/Codec/Detail/HardwareOpusDecoder.cs | 375 ++++++ .../Detail/HardwareOpusDecoderManager.cs | 386 ++++++ .../HardwareOpusDecoderParameterInternal.cs | 11 + .../HardwareOpusDecoderParameterInternalEx.cs | 13 + ...pusMultiStreamDecoderParameterInternal.cs} | 6 +- ...sMultiStreamDecoderParameterInternalEx.cs} | 10 +- .../Sdk/Codec/Detail/IHardwareOpusDecoder.cs | 20 + .../Detail/IHardwareOpusDecoderManager.cs | 19 + .../Sdk/Codec/Detail}/OpusDecoderFlags.cs | 2 +- .../Sdk/Friends/ApplicationInfo.cs | 12 + .../Sdk/Friends/Detail/BlockedUserImpl.cs | 8 + .../Sdk/Friends/Detail/FriendCandidateImpl.cs | 8 + .../Friends/Detail/FriendDetailedInfoImpl.cs | 9 + .../Sdk/Friends/Detail/FriendImpl.cs | 19 + .../Detail/FriendInvitationForViewerImpl.cs | 8 + .../Detail/FriendInvitationGroupImpl.cs | 9 + .../Sdk/Friends/Detail/FriendRequestImpl.cs | 8 + .../Sdk/Friends/Detail/FriendSettingImpl.cs | 9 + .../Detail/Ipc/DaemonSuspendSessionService.cs | 7 + .../Sdk/Friends/Detail/Ipc/FriendService.cs | 1015 +++++++++++++++ .../Ipc/FriendsServicePermissionLevel.cs} | 9 +- .../Ipc/IDaemonSuspendSessionService.cs | 9 + .../Sdk/Friends/Detail/Ipc/IFriendService.cs | 97 ++ .../Detail/Ipc/INotificationService.cs | 12 + .../Sdk/Friends/Detail/Ipc/IServiceCreator.cs | 13 + .../Detail/Ipc/NotificationEventHandler.cs | 58 + .../Detail/Ipc}/NotificationEventType.cs | 2 +- .../Friends/Detail/Ipc/NotificationService.cs | 172 +++ .../Detail/Ipc}/PresenceStatusFilter.cs | 2 +- .../Sdk/Friends/Detail/Ipc/ServiceCreator.cs | 51 + .../Friends/Detail/Ipc/SizedFriendFilter.cs | 25 + .../Detail/Ipc/SizedNotificationInfo.cs | 13 + .../Detail/NintendoNetworkIdFriendImpl.cs | 8 + .../Sdk/Friends/Detail/PlayHistoryImpl.cs | 8 + .../Sdk/Friends/Detail}/PresenceStatus.cs | 2 +- .../Sdk/Friends/Detail/ProfileExtraImpl.cs | 9 + .../Sdk/Friends/Detail/ProfileImpl.cs | 8 + .../Friends/Detail/SnsAccountFriendImpl.cs | 8 + .../Sdk/Friends/Detail/UserPresenceImpl.cs | 29 + .../Friends/Detail/UserPresenceViewImpl.cs | 9 + .../Sdk/Friends/Detail/UserSettingImpl.cs | 9 + .../Sdk/Friends/ExternalApplicationCatalog.cs | 9 + .../Friends/ExternalApplicationCatalogId.cs | 9 + .../FacedFriendRequestRegistrationKey.cs | 9 + src/Ryujinx.Horizon/Sdk/Friends/FriendCode.cs | 9 + .../FriendInvitationGameModeDescription.cs | 9 + .../Sdk/Friends/FriendInvitationGroupId.cs | 9 + .../Sdk/Friends/FriendInvitationId.cs | 8 + .../Sdk/Friends/FriendResult.cs | 13 + .../Sdk/Friends/InAppScreenName.cs | 26 + .../Sdk/Friends/MiiImageUrlParam.cs | 9 + src/Ryujinx.Horizon/Sdk/Friends/MiiName.cs | 9 + .../Sdk/Friends/NintendoNetworkIdUserInfo.cs | 9 + .../Friends}/PlayHistoryRegistrationKey.cs | 8 +- .../Sdk/Friends/PlayHistoryStatistics.cs | 9 + .../Sdk/Friends/Relationship.cs | 9 + src/Ryujinx.Horizon/Sdk/Friends/RequestId.cs | 9 + .../Sdk/Friends/SnsAccountLinkage.cs | 9 + .../Sdk/Friends/SnsAccountProfile.cs | 9 + src/Ryujinx.Horizon/Sdk/Friends/Url.cs | 30 + src/Ryujinx.Horizon/Sdk/Friends/WebPageUrl.cs | 9 + src/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs | 2 +- src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs | 13 + .../Sdk/Ns/ApplicationControlProperty.cs | 309 +++++ .../Sdk/OsTypes/Impl/MultiWaitImpl.cs | 2 + src/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs | 3 + src/Ryujinx.Horizon/Sdk/ServiceUtil.cs | 249 ++++ .../Sdk/Settings/BatteryLot.cs | 9 + .../Settings/Factory/AccelerometerOffset.cs | 12 + .../Settings/Factory/AccelerometerScale.cs | 12 + .../Factory/AmiiboEcdsaCertificate.cs | 9 + .../Factory/AmiiboEcqvBlsCertificate.cs | 9 + .../Sdk/Settings/Factory/AmiiboEcqvBlsKey.cs | 9 + .../Factory/AmiiboEcqvBlsRootCertificate.cs | 9 + .../Settings/Factory/AmiiboEcqvCertificate.cs | 9 + .../Sdk/Settings/Factory/AmiiboKey.cs | 9 + .../Factory/AnalogStickFactoryCalibration.cs | 9 + .../Factory/AnalogStickModelParameter.cs | 9 + .../Sdk/Settings/Factory/BdAddress.cs | 9 + .../Sdk/Settings/Factory/ConfigurationId1.cs | 9 + .../ConsoleSixAxisSensorHorizontalOffset.cs | 12 + .../Sdk/Settings/Factory/CountryCode.cs | 8 + .../Factory/EccB233DeviceCertificate.cs | 9 + .../Sdk/Settings/Factory/EccB233DeviceKey.cs | 9 + .../Settings/Factory/GameCardCertificate.cs | 9 + .../Sdk/Settings/Factory/GameCardKey.cs | 9 + .../Sdk/Settings/Factory/GyroscopeOffset.cs | 12 + .../Sdk/Settings/Factory/GyroscopeScale.cs | 12 + .../Sdk/Settings/Factory/MacAddress.cs | 9 + .../Factory/Rsa2048DeviceCertificate.cs | 9 + .../Sdk/Settings/Factory/Rsa2048DeviceKey.cs | 9 + .../Sdk/Settings/Factory/SerialNumber.cs | 9 + .../Sdk/Settings/Factory/SpeakerParameter.cs | 32 + .../Sdk/Settings/Factory/SslCertificate.cs | 9 + .../Sdk/Settings/Factory/SslKey.cs | 9 + src/Ryujinx.Horizon/Sdk/Settings/Language.cs | 24 + .../Sdk/Settings/LanguageCode.cs | 63 + .../Sdk/Settings/SettingsItemKey.cs | 9 + .../Sdk/Settings/SettingsName.cs | 9 + .../System/AccountNotificationSettings.cs | 15 + .../System/AccountOnlineStorageSettings.cs | 6 + .../Sdk/Settings/System/AccountSettings.cs | 9 + .../Sdk/Settings/System/AllowedSslHost.cs | 9 + .../System/AnalogStickUserCalibration.cs | 9 + .../Sdk/Settings/System/AppletLaunchFlag.cs | 9 + .../Sdk/Settings/System/AudioVolume.cs | 9 + .../Sdk/Settings/System/BacklightSettings.cs | 22 + .../Settings/System/BacklightSettingsEx.cs | 9 + .../Sdk/Settings/System/BlePairingSettings.cs | 6 + .../System/BluetoothDevicesSettings.cs | 29 + .../System/ButtonConfigRegisteredSettings.cs | 9 + .../Settings/System/ButtonConfigSettings.cs | 9 + .../ConsoleSixAxisSensorAccelerationBias.cs | 9 + .../ConsoleSixAxisSensorAccelerationGain.cs | 9 + ...ConsoleSixAxisSensorAngularAcceleration.cs | 9 + ...ConsoleSixAxisSensorAngularVelocityBias.cs | 9 + ...ConsoleSixAxisSensorAngularVelocityGain.cs | 9 + ...oleSixAxisSensorAngularVelocityTimeBias.cs | 9 + .../Settings/System/DataDeletionSettings.cs | 18 + .../Sdk/Settings/System/DeviceNickName.cs | 25 + .../Sdk/Settings/System/Edid.cs | 9 + .../Sdk/Settings/System/EulaVersion.cs | 6 + .../Sdk/Settings/System/FatalDirtyFlag.cs | 9 + .../Sdk/Settings/System/FirmwareVersion.cs | 9 + .../Settings/System/FirmwareVersionDigest.cs | 9 + .../Sdk/Settings/System/HomeMenuScheme.cs | 14 + .../Sdk/Settings/System/HostFsMountPoint.cs | 9 + .../Settings/System/InitialLaunchSettings.cs | 14 + .../Sdk/Settings/System/NetworkSettings.cs | 6 + .../Settings/System/NotificationSettings.cs | 38 + .../System/NxControllerLegacySettings.cs | 9 + .../Settings/System/NxControllerSettings.cs | 9 + .../Settings/System/PtmFuelGaugeParameter.cs | 20 + .../System/RebootlessSystemUpdateVersion.cs | 9 + .../Sdk/Settings/System/SerialNumber.cs | 9 + .../System/ServiceDiscoveryControlSettings.cs | 10 + .../Sdk/Settings/System/SleepSettings.cs | 40 + .../Sdk/Settings/System/TelemetryDirtyFlag.cs | 9 + .../Sdk/Settings/System/ThemeId.cs | 9 + .../Sdk/Settings/System/ThemeSettings.cs | 9 + .../Sdk/Settings/System/TvSettings.cs | 59 + .../Sdk/Sf/Cmif/CmifRequest.cs | 7 + .../Sdk/Sf/CommandSerialization.cs | 6 + .../Sdk/Sf/Hipc/HipcBufferDescriptor.cs | 7 + .../Sdk/Sf/Hipc/HipcMessage.cs | 3 + .../Sdk/Sf/Hipc/HipcMessageData.cs | 1 + .../Sdk/Sf/Hipc/ServerManagerBase.cs | 13 + .../Sdk/Sf/HipcCommandProcessor.cs | 6 +- src/Ryujinx.Horizon/Sdk/Ts/DeviceCode.cs | 8 + .../Sdk/Ts/IMeasurementServer.cs | 14 + src/Ryujinx.Horizon/Sdk/Ts/ISession.cs | 12 + .../Sdk/Ts}/Location.cs | 2 +- src/Ryujinx.Horizon/ServiceTable.cs | 13 + src/Ryujinx.Horizon/Srepo/SrepoIpcServer.cs | 1 + src/Ryujinx.Horizon/Usb/UsbIpcServer.cs | 1 + src/Ryujinx.Horizon/Wlan/WlanIpcServer.cs | 1 + src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs | 78 +- .../Assigner/GamepadButtonAssigner.cs | 15 +- src/Ryujinx.Input/Assigner/IButtonAssigner.cs | 4 +- .../Assigner/KeyboardKeyAssigner.cs | 12 +- src/Ryujinx.Input/Button.cs | 33 + src/Ryujinx.Input/ButtonType.cs | 9 + src/Ryujinx.Input/HLE/NpadController.cs | 77 +- src/Ryujinx.Input/HLE/NpadManager.cs | 62 +- src/Ryujinx.Input/IGamepadDriver.cs | 6 + src/Ryujinx.Memory/AddressSpaceManager.cs | 257 +--- .../BytesReadOnlySequenceSegment.cs | 60 + src/Ryujinx.Memory/IVirtualMemoryManager.cs | 19 +- src/Ryujinx.Memory/IWritableBlock.cs | 16 + src/Ryujinx.Memory/MemoryBlock.cs | 8 +- src/Ryujinx.Memory/NativeMemoryManager.cs | 9 + src/Ryujinx.Memory/Range/IMultiRangeItem.cs | 18 +- src/Ryujinx.Memory/Range/MemoryRange.cs | 18 +- src/Ryujinx.Memory/Range/MultiRangeList.cs | 17 +- src/Ryujinx.Memory/Tracking/MemoryTracking.cs | 137 +- .../Tracking/MultiRegionHandle.cs | 9 +- src/Ryujinx.Memory/Tracking/RegionFlags.cs | 21 + src/Ryujinx.Memory/Tracking/RegionHandle.cs | 68 +- src/Ryujinx.Memory/Tracking/VirtualRegion.cs | 17 +- .../VirtualMemoryManagerBase.cs | 405 ++++++ src/Ryujinx.Memory/WritableRegion.cs | 10 + src/Ryujinx.SDL2.Common/SDL2Driver.cs | 5 +- src/Ryujinx.ShaderTools/Program.cs | 50 + .../MockVirtualMemoryManager.cs | 10 +- .../Renderer/Server/BehaviourContextTests.cs | 137 +- .../Server/SplitterDestinationTests.cs | 3 +- .../SequenceReaderExtensionsTests.cs | 359 +++++ src/Ryujinx.Tests/Cpu/CpuTest.cs | 1 - src/Ryujinx.Tests/Cpu/CpuTest32.cs | 1 - src/Ryujinx.Tests/Cpu/CpuTestAlu32.cs | 55 + src/Ryujinx.Tests/Cpu/CpuTestSimd32.cs | 49 + src/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs | 39 + src/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs | 71 + src/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs | 151 +++ src/Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs | 36 +- src/Ryujinx.Tests/Memory/PartialUnmaps.cs | 6 +- .../App/ApplicationAddedEventArgs.cs | 2 +- .../App/ApplicationCountUpdatedEventArgs.cs | 2 +- .../App/ApplicationData.cs | 26 +- .../App/ApplicationJsonSerializerContext.cs | 2 +- .../App/ApplicationMetadata.cs | 2 +- .../Configuration/AudioBackend.cs | 2 +- .../Configuration/ConfigurationFileFormat.cs | 20 +- .../ConfigurationFileFormatSettings.cs | 2 +- .../ConfigurationJsonSerializerContext.cs | 2 +- .../Configuration/ConfigurationState.cs | 293 +++-- .../Configuration/FileTypes.cs | 2 +- .../Configuration/LoggerModule.cs | 22 +- .../Configuration/System/Language.cs | 2 +- .../Configuration/System/Region.cs | 2 +- .../Configuration/UI}/ColumnSort.cs | 2 +- .../Configuration/UI}/GuiColumns.cs | 2 +- .../Configuration/UI}/ShownFileTypes.cs | 2 +- .../Configuration/UI}/WindowStartup.cs | 2 +- .../DiscordIntegrationModule.cs | 59 +- .../Extensions/FileTypeExtensions.cs | 4 +- .../Helper/CommandLineState.cs | 11 +- .../Helper/ConsoleHelper.cs | 2 +- .../Helper/FileAssociationHelper.cs | 6 +- .../Helper/LinuxHelper.cs | 2 +- .../Helper/ObjectiveC.cs | 2 +- .../Helper/OpenHelper.cs | 2 +- .../Helper/SetupValidator.cs | 2 +- .../Helper/ShortcutHelper.cs | 69 +- .../Helper/TitleHelper.cs | 2 +- .../Helper/ValueFormatUtils.cs | 2 +- .../Models/Amiibo/AmiiboApi.cs | 2 +- .../Models/Amiibo/AmiiboApiGamesSwitch.cs | 2 +- .../Models/Amiibo/AmiiboApiUsage.cs | 2 +- .../Models/Amiibo/AmiiboJson.cs | 2 +- .../Amiibo/AmiiboJsonSerializerContext.cs | 2 +- .../Github/GithubReleaseAssetJsonResponse.cs | 2 +- .../Github/GithubReleasesJsonResponse.cs | 2 +- .../GithubReleasesJsonSerializerContext.cs | 2 +- .../Resources/Controller_JoyConLeft.svg | 0 .../Resources/Controller_JoyConPair.svg | 0 .../Resources/Controller_JoyConRight.svg | 0 .../Resources/Controller_ProCon.svg | 0 .../Resources/Icon_Blank.png | Bin 0 -> 16179 bytes src/Ryujinx.UI.Common/Resources/Icon_NCA.png | Bin 0 -> 18432 bytes src/Ryujinx.UI.Common/Resources/Icon_NRO.png | Bin 0 -> 18404 bytes src/Ryujinx.UI.Common/Resources/Icon_NSO.png | Bin 0 -> 18705 bytes src/Ryujinx.UI.Common/Resources/Icon_NSP.png | Bin 0 -> 18260 bytes src/Ryujinx.UI.Common/Resources/Icon_XCI.png | Bin 0 -> 18220 bytes .../Resources/Logo_Amiibo.png | Bin .../Resources/Logo_Discord_Dark.png | Bin .../Resources/Logo_Discord_Light.png | Bin .../Resources/Logo_GitHub_Dark.png | Bin .../Resources/Logo_GitHub_Light.png | Bin .../Resources/Logo_Patreon_Dark.png | Bin .../Resources/Logo_Patreon_Light.png | Bin .../Resources/Logo_Ryujinx.png | Bin .../Resources/Logo_Twitter_Dark.png | Bin .../Resources/Logo_Twitter_Light.png | Bin .../Ryujinx.UI.Common.csproj} | 4 +- .../SystemInfo/LinuxSystemInfo.cs | 2 +- .../SystemInfo/MacOSSystemInfo.cs | 2 +- .../SystemInfo/SystemInfo.cs | 4 +- .../SystemInfo/WindowsSystemInfo.cs | 2 +- .../UserError.cs | 2 +- .../LocaleGenerator.cs | 2 +- .../Ryujinx.UI.LocaleGenerator.csproj} | 0 .../App/ApplicationLibrary.cs | 1040 +++++++-------- src/Ryujinx.Ui.Common/Resources/Icon_NCA.png | Bin 10190 -> 0 bytes src/Ryujinx.Ui.Common/Resources/Icon_NRO.png | Bin 10254 -> 0 bytes src/Ryujinx.Ui.Common/Resources/Icon_NSO.png | Bin 10354 -> 0 bytes src/Ryujinx.Ui.Common/Resources/Icon_NSP.png | Bin 9899 -> 0 bytes src/Ryujinx.Ui.Common/Resources/Icon_XCI.png | Bin 9809 -> 0 bytes src/{Ryujinx.Ava => Ryujinx}/App.axaml | 0 src/{Ryujinx.Ava => Ryujinx}/App.axaml.cs | 69 +- src/{Ryujinx.Ava => Ryujinx}/AppHost.cs | 281 ++-- .../Assets/Fonts/SegoeFluentIcons.ttf | Bin .../Assets/Icons/Controller_JoyConLeft.svg | 155 +++ .../Assets/Icons/Controller_JoyConPair.svg | 341 +++++ .../Assets/Icons/Controller_JoyConRight.svg | 185 +++ .../Assets/Icons/Controller_ProCon.svg | 84 ++ src/Ryujinx/Assets/Locales/ar_SA.json | 780 +++++++++++ .../Assets/Locales/de_DE.json | 212 ++- .../Assets/Locales/el_GR.json | 230 +++- .../Assets/Locales/en_US.json | 191 ++- .../Assets/Locales/es_ES.json | 216 ++- .../Assets/Locales/fr_FR.json | 328 +++-- .../Assets/Locales/he_IL.json | 202 ++- .../Assets/Locales/it_IT.json | 496 ++++--- .../Assets/Locales/ja_JP.json | 212 ++- .../Assets/Locales/ko_KR.json | 202 ++- .../Assets/Locales/pl_PL.json | 470 ++++--- .../Assets/Locales/pt_BR.json | 242 +++- .../Assets/Locales/ru_RU.json | 634 +++++---- src/Ryujinx/Assets/Locales/th_TH.json | 780 +++++++++++ .../Assets/Locales/tr_TR.json | 210 ++- .../Assets/Locales/uk_UA.json | 358 +++-- src/Ryujinx/Assets/Locales/zh_CN.json | 780 +++++++++++ src/Ryujinx/Assets/Locales/zh_TW.json | 780 +++++++++++ .../Assets/Styles/Styles.xaml | 3 + .../Assets/Styles/Themes.xaml | 0 .../Common/ApplicationHelper.cs | 11 +- .../Common/ApplicationSort.cs | 0 .../Common/KeyboardHotkeyState.cs | 2 +- .../Common/Locale/LocaleExtension.cs | 7 +- .../Common/Locale/LocaleManager.cs | 74 +- src/Ryujinx/Common/ThemeManager.cs | 14 + .../Input/AvaloniaKeyboard.cs | 2 +- .../Input/AvaloniaKeyboardDriver.cs | 2 +- .../Input/AvaloniaKeyboardMappingHelper.cs | 0 .../Input/AvaloniaMouse.cs | 0 .../Input/AvaloniaMouseDriver.cs | 0 src/Ryujinx/Modules/Updater/Updater.cs | 565 +++++--- src/Ryujinx/Program.cs | 345 ++--- src/Ryujinx/Ryujinx.csproj | 139 +- .../UI/Applet/AvaHostUIHandler.cs} | 78 +- .../Applet/AvaloniaDynamicTextInputHandler.cs | 11 +- .../UI/Applet/AvaloniaHostUITheme.cs} | 6 +- .../UI/Applet/ControllerAppletDialog.axaml | 145 +++ .../UI/Applet/ControllerAppletDialog.axaml.cs | 137 ++ .../UI/Applet/ErrorAppletWindow.axaml | 2 +- .../UI/Applet/ErrorAppletWindow.axaml.cs | 0 .../UI/Applet/SwkbdAppletDialog.axaml | 2 +- .../UI/Applet/SwkbdAppletDialog.axaml.cs | 2 +- .../UI/Controls/ApplicationContextMenu.axaml | 7 +- .../Controls/ApplicationContextMenu.axaml.cs | 68 +- .../UI/Controls/ApplicationGridView.axaml | 10 +- .../UI/Controls/ApplicationGridView.axaml.cs | 2 +- .../UI/Controls/ApplicationListView.axaml | 20 +- .../UI/Controls/ApplicationListView.axaml.cs | 2 +- .../UI/Controls/NavigationDialogHost.axaml | 0 .../UI/Controls/NavigationDialogHost.axaml.cs | 0 .../UI/Controls/SliderScroll.axaml.cs | 0 .../UI/Controls/UpdateWaitWindow.axaml | 4 +- .../UI/Controls/UpdateWaitWindow.axaml.cs | 0 .../UI/Helpers/ApplicationOpenedEventArgs.cs | 2 +- .../UI/Helpers/BitmapArrayValueConverter.cs | 0 .../UI/Helpers/ButtonKeyAssigner.cs | 30 +- .../UI/Helpers/ContentDialogHelper.cs | 48 +- .../UI/Helpers/Glyph.cs | 0 .../UI/Helpers/GlyphValueConverter.cs | 0 src/Ryujinx/UI/Helpers/KeyValueConverter.cs | 184 +++ .../UI/Helpers/LocalizedNeverConverter.cs | 2 +- .../UI/Helpers/LoggerAdapter.cs | 5 +- .../UI/Helpers/MiniCommand.cs | 0 .../UI/Helpers/NotificationHelper.cs | 0 .../UI/Helpers/OffscreenTextBox.cs | 3 + .../UI/Helpers/TimeZoneConverter.cs | 0 .../UI/Helpers/UserErrorDialog.cs | 4 +- .../UI/Helpers/UserResult.cs | 0 .../UI/Helpers/Win32NativeInterop.cs | 22 +- .../UI/Models/CheatNode.cs | 0 .../UI/Models/ControllerModel.cs | 0 .../UI/Models/DeviceType.cs | 0 .../UI/Models/DownloadableContentModel.cs | 4 + .../Models/Generic/LastPlayedSortComparer.cs | 2 +- .../Models/Generic/TimePlayedSortComparer.cs | 2 +- .../UI/Models/Input/GamepadInputConfig.cs | 606 +++++++++ src/Ryujinx/UI/Models/Input/HotkeyConfig.cs | 141 ++ .../UI/Models/Input/KeyboardInputConfig.cs | 448 +++++++ src/Ryujinx/UI/Models/ModModel.cs | 32 + .../UI/Models/PlayerModel.cs | 0 .../UI/Models/ProfileImageModel.cs | 0 .../UI/Models/SaveModel.cs | 8 +- src/Ryujinx/UI/Models/StatusInitEventArgs.cs | 16 + .../UI/Models/StatusUpdatedEventArgs.cs | 6 +- .../UI/Models/TempProfile.cs | 0 .../UI/Models/TimeZone.cs | 0 src/Ryujinx/UI/Models/TitleUpdateModel.cs | 21 + .../UI/Models/UserProfile.cs | 0 .../UI/Renderer/EmbeddedWindow.cs | 84 +- .../UI/Renderer/EmbeddedWindowOpenGL.cs | 4 +- .../UI/Renderer/EmbeddedWindowVulkan.cs | 0 .../UI/Renderer/OpenTKBindingsContext.cs | 0 .../UI/Renderer/RendererHost.axaml | 9 +- .../UI/Renderer/RendererHost.axaml.cs | 2 +- .../UI/Renderer/SPBOpenGLContext.cs | 2 + .../UI/ViewModels/AboutWindowViewModel.cs | 54 +- .../UI/ViewModels/AmiiboWindowViewModel.cs | 90 +- .../ViewModels/AppListFavoriteComparable.cs | 43 + .../UI/ViewModels/BaseModel.cs | 0 .../DownloadableContentManagerViewModel.cs | 77 +- .../Input/ControllerInputViewModel.cs | 84 ++ .../UI/ViewModels/Input/InputViewModel.cs} | 152 +-- .../Input/KeyboardInputViewModel.cs | 73 ++ .../ViewModels/Input}/MotionInputViewModel.cs | 2 +- .../ViewModels/Input}/RumbleInputViewModel.cs | 2 +- .../UI/ViewModels/MainWindowViewModel.cs | 192 +-- .../UI/ViewModels/ModManagerViewModel.cs | 336 +++++ .../UI/ViewModels/SettingsViewModel.cs | 80 +- .../UI/ViewModels/TitleUpdateViewModel.cs | 110 +- .../UserFirmwareAvatarSelectorViewModel.cs | 13 +- .../UserProfileImageSelectorViewModel.cs | 0 .../UI/ViewModels/UserProfileViewModel.cs | 4 +- .../UI/ViewModels/UserSaveManagerViewModel.cs | 0 .../UI/Views/Input/ControllerInputView.axaml | 799 ++++++++++++ .../Views/Input/ControllerInputView.axaml.cs | 204 +++ .../UI/Views/Input/InputView.axaml} | 61 +- src/Ryujinx/UI/Views/Input/InputView.axaml.cs | 61 + .../UI/Views/Input/KeyboardInputView.axaml | 709 ++++++++++ .../UI/Views/Input/KeyboardInputView.axaml.cs | 214 +++ .../UI/Views/Input/MotionInputView.axaml | 2 +- .../UI/Views/Input/MotionInputView.axaml.cs | 8 +- .../UI/Views/Input/RumbleInputView.axaml | 2 +- .../UI/Views/Input/RumbleInputView.axaml.cs | 8 +- .../UI/Views/Main/MainMenuBarView.axaml | 14 +- .../UI/Views/Main/MainMenuBarView.axaml.cs | 74 +- .../UI/Views/Main/MainStatusBarView.axaml | 12 +- .../UI/Views/Main/MainStatusBarView.axaml.cs | 4 +- .../UI/Views/Main/MainViewControls.axaml | 0 .../UI/Views/Main/MainViewControls.axaml.cs | 0 .../UI/Views/Settings/SettingsAudioView.axaml | 0 .../Views/Settings/SettingsAudioView.axaml.cs | 0 .../UI/Views/Settings/SettingsCPUView.axaml | 0 .../Views/Settings/SettingsCPUView.axaml.cs | 0 .../Views/Settings/SettingsGraphicsView.axaml | 11 +- .../Settings/SettingsGraphicsView.axaml.cs | 0 .../Views/Settings/SettingsHotkeysView.axaml | 109 ++ .../Settings/SettingsHotkeysView.axaml.cs | 144 ++ .../UI/Views/Settings/SettingsInputView.axaml | 4 +- .../Views/Settings/SettingsInputView.axaml.cs | 2 +- .../Views/Settings/SettingsLoggingView.axaml | 0 .../Settings/SettingsLoggingView.axaml.cs | 0 .../Views/Settings/SettingsNetworkView.axaml | 10 +- .../Settings/SettingsNetworkView.axaml.cs | 0 .../Views/Settings/SettingsSystemView.axaml | 7 +- .../Settings/SettingsSystemView.axaml.cs | 0 .../UI/Views/Settings/SettingsUIView.axaml | 82 +- .../UI/Views/Settings/SettingsUIView.axaml.cs | 24 - .../UI/Views/User/UserEditorView.axaml | 0 .../UI/Views/User/UserEditorView.axaml.cs | 0 .../User/UserFirmwareAvatarSelectorView.axaml | 0 .../UserFirmwareAvatarSelectorView.axaml.cs | 32 +- .../User/UserProfileImageSelectorView.axaml | 4 +- .../UserProfileImageSelectorView.axaml.cs | 18 +- .../UI/Views/User/UserRecovererView.axaml | 4 +- .../UI/Views/User/UserRecovererView.axaml.cs | 0 .../UI/Views/User/UserSaveManagerView.axaml | 0 .../Views/User/UserSaveManagerView.axaml.cs | 0 .../UI/Views/User/UserSelectorView.axaml | 12 +- .../UI/Views/User/UserSelectorView.axaml.cs | 0 .../UI/Windows/AboutWindow.axaml | 57 +- .../UI/Windows/AboutWindow.axaml.cs | 2 +- .../UI/Windows/AmiiboWindow.axaml | 2 +- .../UI/Windows/AmiiboWindow.axaml.cs | 2 +- .../UI/Windows/CheatWindow.axaml | 0 .../UI/Windows/CheatWindow.axaml.cs | 11 +- .../Windows/ContentDialogOverlayWindow.axaml | 0 .../ContentDialogOverlayWindow.axaml.cs | 1 - .../DownloadableContentManagerWindow.axaml | 2 +- .../DownloadableContentManagerWindow.axaml.cs | 17 +- .../UI/Windows/IconColorPicker.cs | 55 +- .../UI/Windows/MainWindow.axaml | 15 +- .../UI/Windows/MainWindow.axaml.cs | 196 ++- src/Ryujinx/UI/Windows/ModManagerWindow.axaml | 179 +++ .../UI/Windows/ModManagerWindow.axaml.cs | 139 ++ .../UI/Windows/SettingsWindow.axaml | 5 +- .../UI/Windows/SettingsWindow.axaml.cs | 2 +- .../UI/Windows/StyleableWindow.cs | 14 +- .../UI/Windows/TitleUpdateWindow.axaml | 2 +- .../UI/Windows/TitleUpdateWindow.axaml.cs | 31 +- src/{Ryujinx.Ava => Ryujinx}/app.manifest | 0 src/{Ryujinx.Ava => Ryujinx}/rd.xml | 0 1237 files changed, 48656 insertions(+), 21399 deletions(-) create mode 100644 .github/workflows/mako.yml mode change 100644 => 100755 distribution/linux/Ryujinx.sh create mode 100644 distribution/macos/shortcut-launch-script.sh rename src/ARMeilleure/Signal/{NativeSignalHandler.cs => NativeSignalHandlerGenerator.cs} (62%) delete mode 100644 src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs create mode 100644 src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterAndMixCommand.cs create mode 100644 src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterAndMixCommand.cs rename src/Ryujinx.Audio/Renderer/Dsp/Command/{GroupedBiquadFilterCommand.cs => MultiTapBiquadFilterCommand.cs} (84%) create mode 100644 src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorStatistics.cs create mode 100644 src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs rename src/Ryujinx.Audio/Renderer/Parameter/{SplitterDestinationInParameter.cs => SplitterDestinationInParameterVersion1.cs} (63%) create mode 100644 src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs create mode 100644 src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion1.cs create mode 100644 src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs delete mode 100644 src/Ryujinx.Ava/Assets/Locales/zh_CN.json delete mode 100644 src/Ryujinx.Ava/Assets/Locales/zh_TW.json delete mode 100644 src/Ryujinx.Ava/Modules/Updater/Updater.cs delete mode 100644 src/Ryujinx.Ava/Program.cs delete mode 100644 src/Ryujinx.Ava/UI/Helpers/KeyValueConverter.cs delete mode 100644 src/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs delete mode 100644 src/Ryujinx.Ava/UI/ViewModels/GamePadInputViewModel.cs delete mode 100644 src/Ryujinx.Ava/UI/ViewModels/InputViewModel.cs delete mode 100644 src/Ryujinx.Ava/UI/ViewModels/KeyboardInputViewModel.cs delete mode 100644 src/Ryujinx.Ava/UI/Views/Input/GamePadInputView.axaml delete mode 100644 src/Ryujinx.Ava/UI/Views/Input/GamePadInputView.axaml.cs delete mode 100644 src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml delete mode 100644 src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs delete mode 100644 src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml delete mode 100644 src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs create mode 100644 src/Ryujinx.Common/Configuration/Mod.cs create mode 100644 src/Ryujinx.Common/Configuration/ModMetadata.cs create mode 100644 src/Ryujinx.Common/Configuration/ModMetadataJsonSerializerContext.cs create mode 100644 src/Ryujinx.Common/Extensions/SequenceReaderExtensions.cs delete mode 100644 src/Ryujinx.Common/Memory/ByteMemoryPool.ByteMemoryPoolBuffer.cs delete mode 100644 src/Ryujinx.Common/Memory/ByteMemoryPool.cs create mode 100644 src/Ryujinx.Common/Memory/MemoryOwner.cs delete mode 100644 src/Ryujinx.Common/Memory/SpanOrArray.cs create mode 100644 src/Ryujinx.Common/Memory/SpanOwner.cs create mode 100644 src/Ryujinx.Common/Utilities/FileSystemUtils.cs create mode 100644 src/Ryujinx.Common/Utilities/OsUtils.cs delete mode 100644 src/Ryujinx.Cpu/AppleHv/HvCodePatcher.cs create mode 100644 src/Ryujinx.Cpu/Jit/HostTracked/AddressIntrusiveRedBlackTree.cs create mode 100644 src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartition.cs create mode 100644 src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionAllocator.cs create mode 100644 src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionMultiAllocation.cs create mode 100644 src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitioned.cs create mode 100644 src/Ryujinx.Cpu/Jit/HostTracked/NativePageTable.cs create mode 100644 src/Ryujinx.Cpu/LightningJit/Arm64/SysUtils.cs create mode 100644 src/Ryujinx.Cpu/ManagedPageFlags.cs create mode 100644 src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs rename src/{ARMeilleure => Ryujinx.Cpu}/Signal/UnixSignalHandlerRegistration.cs (98%) create mode 100644 src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs rename src/Ryujinx.Cpu/{MemoryManagerBase.cs => VirtualMemoryManagerRefCountedBase.cs} (86%) create mode 100644 src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs create mode 100644 src/Ryujinx.Graphics.Device/ISynchronizationManager.cs create mode 100644 src/Ryujinx.Graphics.GAL/IImageArray.cs create mode 100644 src/Ryujinx.Graphics.GAL/ITextureArray.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArrayDisposeCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArraySetImagesCommand.cs delete mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateBufferCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateImageArrayCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateTextureArrayCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArrayCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArraySeparateCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArrayCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArraySeparateCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArrayDisposeCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArraySetSamplersCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArraySetTexturesCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTextureArray.cs create mode 100644 src/Ryujinx.Graphics.GAL/SystemMemoryType.cs create mode 100644 src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs create mode 100644 src/Ryujinx.Graphics.Gpu/Memory/BufferBackingState.cs create mode 100644 src/Ryujinx.Graphics.Gpu/Memory/BufferPreFlush.cs create mode 100644 src/Ryujinx.Graphics.Gpu/Memory/BufferStage.cs create mode 100644 src/Ryujinx.Graphics.Gpu/Memory/BufferTextureArrayBinding.cs rename src/Ryujinx.Graphics.Gpu/Memory/{VirtualBufferCache.cs => VirtualRangeCache.cs} (92%) create mode 100644 src/Ryujinx.Graphics.OpenGL/Effects/AreaScalingFilter.cs create mode 100644 src/Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl create mode 100644 src/Ryujinx.Graphics.OpenGL/Image/ImageArray.cs create mode 100644 src/Ryujinx.Graphics.OpenGL/Image/TextureArray.cs create mode 100644 src/Ryujinx.Graphics.Shader/CodeGen/Spirv/ImageDeclaration.cs create mode 100644 src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SamplerDeclaration.cs create mode 100644 src/Ryujinx.Graphics.Shader/SetBindingPair.cs create mode 100644 src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs delete mode 100644 src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs create mode 100644 src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs create mode 100644 src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplate.cs create mode 100644 src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplateUpdater.cs create mode 100644 src/Ryujinx.Graphics.Vulkan/Effects/AreaScalingFilter.cs create mode 100644 src/Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.glsl create mode 100644 src/Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.spv create mode 100644 src/Ryujinx.Graphics.Vulkan/FeedbackLoopAspects.cs create mode 100644 src/Ryujinx.Graphics.Vulkan/ImageArray.cs create mode 100644 src/Ryujinx.Graphics.Vulkan/RenderPassCacheKey.cs create mode 100644 src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs create mode 100644 src/Ryujinx.Graphics.Vulkan/ResourceArray.cs delete mode 100644 src/Ryujinx.Graphics.Vulkan/SemaphoreHolder.cs create mode 100644 src/Ryujinx.Graphics.Vulkan/TextureArray.cs rename src/{Ryujinx => Ryujinx.Gtk3}/Input/GTK3/GTK3Keyboard.cs (100%) rename src/{Ryujinx => Ryujinx.Gtk3}/Input/GTK3/GTK3KeyboardDriver.cs (96%) rename src/{Ryujinx => Ryujinx.Gtk3}/Input/GTK3/GTK3MappingHelper.cs (100%) rename src/{Ryujinx => Ryujinx.Gtk3}/Input/GTK3/GTK3Mouse.cs (100%) rename src/{Ryujinx => Ryujinx.Gtk3}/Input/GTK3/GTK3MouseDriver.cs (100%) rename src/{Ryujinx => Ryujinx.Gtk3}/Modules/Updater/UpdateDialog.cs (87%) rename src/{Ryujinx => Ryujinx.Gtk3}/Modules/Updater/UpdateDialog.glade (100%) create mode 100644 src/Ryujinx.Gtk3/Modules/Updater/Updater.cs create mode 100644 src/Ryujinx.Gtk3/Program.cs create mode 100644 src/Ryujinx.Gtk3/Ryujinx.Gtk3.csproj rename src/{Ryujinx.Ava => Ryujinx.Gtk3}/Ryujinx.ico (100%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Applet/ErrorAppletDialog.cs (84%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Applet/GtkDynamicTextInputHandler.cs (97%) rename src/{Ryujinx/Ui/Applet/GtkHostUiHandler.cs => Ryujinx.Gtk3/UI/Applet/GtkHostUIHandler.cs} (92%) rename src/{Ryujinx/Ui/Applet/GtkHostUiTheme.cs => Ryujinx.Gtk3/UI/Applet/GtkHostUITheme.cs} (96%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Applet/SwkbdAppletDialog.cs (99%) create mode 100644 src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Helper/MetalHelper.cs (99%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Helper/SortHelper.cs (94%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Helper/ThemeHelper.cs (54%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/MainWindow.cs (87%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/MainWindow.glade (99%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/OpenGLRenderer.cs (96%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/OpenToolkitBindingsContext.cs (95%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/RendererWidgetBase.cs (92%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/SPBOpenGLContext.cs (94%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/StatusUpdatedEventArgs.cs (97%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/VulkanRenderer.cs (98%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Widgets/GameTableContextMenu.Designer.cs (96%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Widgets/GameTableContextMenu.cs (83%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Widgets/GtkDialog.cs (96%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Widgets/GtkInputDialog.cs (97%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Widgets/ProfileDialog.cs (87%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Widgets/ProfileDialog.glade (100%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Widgets/RawInputToTextEntry.cs (95%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Widgets/UserErrorDialog.cs (97%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/AboutWindow.Designer.cs (97%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/AboutWindow.cs (95%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/AmiiboWindow.Designer.cs (99%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/AmiiboWindow.cs (74%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/AvatarWindow.cs (88%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/CheatWindow.cs (90%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/CheatWindow.glade (100%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/ControllerWindow.cs (98%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/ControllerWindow.glade (100%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/DlcWindow.cs (73%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/DlcWindow.glade (100%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/SettingsWindow.cs (98%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/SettingsWindow.glade (100%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/TitleUpdateWindow.cs (62%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/TitleUpdateWindow.glade (100%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/UserProfilesManagerWindow.Designer.cs (99%) rename src/{Ryujinx/Ui => Ryujinx.Gtk3/UI}/Windows/UserProfilesManagerWindow.cs (96%) create mode 100644 src/Ryujinx.HLE/FileSystem/ContentMetaData.cs rename src/Ryujinx.HLE/HOS/Applets/Controller/{ControllerAppletUiArgs.cs => ControllerAppletUIArgs.cs} (88%) rename src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/{SoftwareKeyboardUiArgs.cs => SoftwareKeyboardUIArgs.cs} (90%) rename src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/{SoftwareKeyboardUiState.cs => SoftwareKeyboardUIState.cs} (89%) delete mode 100644 src/Ryujinx.HLE/HOS/Kernel/Memory/AddressSpaceType.cs create mode 100644 src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/ExternalEvent.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Arp/IReader.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Arp/IWriter.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioIn.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/IAudioIn.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioInManager.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioInManagerServer.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOut.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/IAudioOut.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioOutManagerServer.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDevice.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioKernelEvent.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioDevice.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/Decoder.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/DecoderCommon.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IDecoder.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IHardwareOpusDecoder.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/MultiSampleDecoder.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IAudioController.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForApplet.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForDebugger.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForApplet.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForDebugger.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForApplet.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForDebugger.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IAudioSnoopManager.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManager.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForApplet.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForDebugger.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/ResultCode.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusPacketHeader.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusParametersEx.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Friend/ResultCode.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs create mode 100644 src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/LazyFile.cs create mode 100644 src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/NumVsmsArguments.cs create mode 100644 src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/VsmsMappingArguments.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs rename src/Ryujinx.HLE/{Ui => UI}/DynamicTextChangedHandler.cs (82%) rename src/Ryujinx.HLE/{Ui => UI}/IDynamicTextInputHandler.cs (94%) rename src/Ryujinx.HLE/{Ui/IHostUiHandler.cs => UI/IHostUIHandler.cs} (90%) rename src/Ryujinx.HLE/{Ui/IHostUiTheme.cs => UI/IHostUITheme.cs} (83%) rename src/Ryujinx.HLE/{Ui => UI}/Input/NpadButtonHandler.cs (81%) rename src/Ryujinx.HLE/{Ui => UI}/Input/NpadReader.cs (99%) rename src/Ryujinx.HLE/{Ui => UI}/KeyPressedHandler.cs (79%) rename src/Ryujinx.HLE/{Ui => UI}/KeyReleasedHandler.cs (79%) rename src/Ryujinx.HLE/{Ui => UI}/RenderingSurfaceInfo.cs (98%) rename src/Ryujinx.HLE/{Ui => UI}/ThemeColor.cs (93%) create mode 100644 src/Ryujinx.HLE/Utilities/PartitionFileSystemUtils.cs create mode 100644 src/Ryujinx.Horizon.Common/IExternalEvent.cs create mode 100644 src/Ryujinx.Horizon/Arp/ArpIpcServer.cs create mode 100644 src/Ryujinx.Horizon/Arp/ArpMain.cs create mode 100644 src/Ryujinx.Horizon/Arp/Ipc/Reader.cs create mode 100644 src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs create mode 100644 src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs create mode 100644 src/Ryujinx.Horizon/Arp/Ipc/Updater.cs create mode 100644 src/Ryujinx.Horizon/Arp/Ipc/Writer.cs create mode 100644 src/Ryujinx.Horizon/Audio/AudioMain.cs create mode 100644 src/Ryujinx.Horizon/Audio/AudioManagers.cs create mode 100644 src/Ryujinx.Horizon/Audio/AudioUserIpcServer.cs create mode 100644 src/Ryujinx.Horizon/Audio/HwopusIpcServer.cs create mode 100644 src/Ryujinx.Horizon/Audio/HwopusMain.cs create mode 100644 src/Ryujinx.Horizon/Friends/FriendsIpcServer.cs create mode 100644 src/Ryujinx.Horizon/Friends/FriendsMain.cs create mode 100644 src/Ryujinx.Horizon/Friends/FriendsPortIndex.cs create mode 100644 src/Ryujinx.Horizon/Friends/FriendsServerManager.cs create mode 100644 src/Ryujinx.Horizon/Ptm/Ipc/MeasurementServer.cs create mode 100644 src/Ryujinx.Horizon/Ptm/Ipc/Session.cs create mode 100644 src/Ryujinx.Horizon/Ptm/TsIpcServer.cs create mode 100644 src/Ryujinx.Horizon/Ptm/TsMain.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Account/IEmulatorAccountManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Account/NetworkServiceAccountId.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Account/Nickname.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Applet/AppletId.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Applet/AppletResourceUserId.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstanceManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/IReader.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/AudioEvent.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/AudioResult.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioIn.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInProtocol.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInProtocolName.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioOut.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioOutManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRenderer.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererParameterInternal.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioSnoopManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/DeviceName.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorder.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderParameter.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderParameterInternal.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioDevice.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioIn.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioInManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioOut.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioOutManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioRenderer.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioRendererManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioSnoopManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/IFinalOutputRecorder.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Audio/Detail/IFinalOutputRecorderManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Codec/CodecResult.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoder.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderManager.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderParameterInternal.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderParameterInternalEx.cs rename src/{Ryujinx.HLE/HOS/Services/Audio/Types/OpusMultiStreamParameters.cs => Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusMultiStreamDecoderParameterInternal.cs} (65%) rename src/{Ryujinx.HLE/HOS/Services/Audio/Types/OpusMultiStreamParametersEx.cs => Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusMultiStreamDecoderParameterInternalEx.cs} (64%) create mode 100644 src/Ryujinx.Horizon/Sdk/Codec/Detail/IHardwareOpusDecoder.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Codec/Detail/IHardwareOpusDecoderManager.cs rename src/{Ryujinx.HLE/HOS/Services/Audio/Types => Ryujinx.Horizon/Sdk/Codec/Detail}/OpusDecoderFlags.cs (72%) create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/ApplicationInfo.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/BlockedUserImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendCandidateImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendDetailedInfoImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationForViewerImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationGroupImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendRequestImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendSettingImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/DaemonSuspendSessionService.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendService.cs rename src/{Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs => Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendsServicePermissionLevel.cs} (64%) create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IDaemonSuspendSessionService.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IFriendService.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/INotificationService.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IServiceCreator.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventHandler.cs rename src/{Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types => Ryujinx.Horizon/Sdk/Friends/Detail/Ipc}/NotificationEventType.cs (64%) create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs rename src/{Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types => Ryujinx.Horizon/Sdk/Friends/Detail/Ipc}/PresenceStatusFilter.cs (64%) create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/ServiceCreator.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedFriendFilter.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedNotificationInfo.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/NintendoNetworkIdFriendImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/PlayHistoryImpl.cs rename src/{Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types => Ryujinx.Horizon/Sdk/Friends/Detail}/PresenceStatus.cs (58%) create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileExtraImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/SnsAccountFriendImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceViewImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Detail/UserSettingImpl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalog.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalogId.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/FacedFriendRequestRegistrationKey.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/FriendCode.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGameModeDescription.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGroupId.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationId.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/FriendResult.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/InAppScreenName.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/MiiImageUrlParam.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/MiiName.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/NintendoNetworkIdUserInfo.cs rename src/{Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types => Ryujinx.Horizon/Sdk/Friends}/PlayHistoryRegistrationKey.cs (59%) create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryStatistics.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Relationship.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/RequestId.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/SnsAccountLinkage.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/SnsAccountProfile.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/Url.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Friends/WebPageUrl.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Ns/ApplicationControlProperty.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/BatteryLot.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerOffset.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerScale.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcdsaCertificate.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsCertificate.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsKey.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsRootCertificate.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvCertificate.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboKey.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickFactoryCalibration.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickModelParameter.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/BdAddress.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/ConfigurationId1.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/ConsoleSixAxisSensorHorizontalOffset.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/CountryCode.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceCertificate.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceKey.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardCertificate.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardKey.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeOffset.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeScale.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/MacAddress.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceCertificate.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceKey.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/SerialNumber.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/SpeakerParameter.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/SslCertificate.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Factory/SslKey.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/Language.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/LanguageCode.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/SettingsItemKey.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/SettingsName.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/AccountNotificationSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/AccountOnlineStorageSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/AccountSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/AllowedSslHost.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/AnalogStickUserCalibration.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/AppletLaunchFlag.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/AudioVolume.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettingsEx.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/BlePairingSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/BluetoothDevicesSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigRegisteredSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationBias.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationGain.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularAcceleration.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityBias.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityGain.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityTimeBias.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/DataDeletionSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/DeviceNickName.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/Edid.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/EulaVersion.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/FatalDirtyFlag.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersion.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersionDigest.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/HomeMenuScheme.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/HostFsMountPoint.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/InitialLaunchSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/NetworkSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/NotificationSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerLegacySettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/PtmFuelGaugeParameter.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/RebootlessSystemUpdateVersion.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/SerialNumber.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/ServiceDiscoveryControlSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/SleepSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/TelemetryDirtyFlag.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/ThemeId.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/ThemeSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Settings/System/TvSettings.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Ts/DeviceCode.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Ts/IMeasurementServer.cs create mode 100644 src/Ryujinx.Horizon/Sdk/Ts/ISession.cs rename src/{Ryujinx.HLE/HOS/Services/Ptm/Ts/Types => Ryujinx.Horizon/Sdk/Ts}/Location.cs (61%) create mode 100644 src/Ryujinx.Input/Button.cs create mode 100644 src/Ryujinx.Input/ButtonType.cs create mode 100644 src/Ryujinx.Memory/BytesReadOnlySequenceSegment.cs create mode 100644 src/Ryujinx.Memory/Tracking/RegionFlags.cs create mode 100644 src/Ryujinx.Memory/VirtualMemoryManagerBase.cs create mode 100644 src/Ryujinx.Tests/Common/Extensions/SequenceReaderExtensionsTests.cs rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/App/ApplicationAddedEventArgs.cs (81%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/App/ApplicationCountUpdatedEventArgs.cs (85%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/App/ApplicationData.cs (85%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/App/ApplicationJsonSerializerContext.cs (88%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/App/ApplicationMetadata.cs (98%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Configuration/AudioBackend.cs (85%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Configuration/ConfigurationFileFormat.cs (96%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Configuration/ConfigurationFileFormatSettings.cs (85%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Configuration/ConfigurationJsonSerializerContext.cs (85%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Configuration/ConfigurationState.cs (87%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Configuration/FileTypes.cs (81%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Configuration/LoggerModule.cs (81%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Configuration/System/Language.cs (91%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Configuration/System/Region.cs (85%) rename src/{Ryujinx.Ui.Common/Configuration/Ui => Ryujinx.UI.Common/Configuration/UI}/ColumnSort.cs (75%) rename src/{Ryujinx.Ui.Common/Configuration/Ui => Ryujinx.UI.Common/Configuration/UI}/GuiColumns.cs (91%) rename src/{Ryujinx.Ui.Common/Configuration/Ui => Ryujinx.UI.Common/Configuration/UI}/ShownFileTypes.cs (86%) rename src/{Ryujinx.Ui.Common/Configuration/Ui => Ryujinx.UI.Common/Configuration/UI}/WindowStartup.cs (86%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/DiscordIntegrationModule.cs (60%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Extensions/FileTypeExtensions.cs (91%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Helper/CommandLineState.cs (87%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Helper/ConsoleHelper.cs (97%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Helper/FileAssociationHelper.cs (97%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Helper/LinuxHelper.cs (98%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Helper/ObjectiveC.cs (99%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Helper/OpenHelper.cs (99%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Helper/SetupValidator.cs (99%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Helper/ShortcutHelper.cs (69%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Helper/TitleHelper.cs (96%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Helper/ValueFormatUtils.cs (99%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Models/Amiibo/AmiiboApi.cs (97%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Models/Amiibo/AmiiboApiGamesSwitch.cs (90%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Models/Amiibo/AmiiboApiUsage.cs (85%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Models/Amiibo/AmiiboJson.cs (88%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Models/Amiibo/AmiiboJsonSerializerContext.cs (80%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Models/Github/GithubReleaseAssetJsonResponse.cs (82%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Models/Github/GithubReleasesJsonResponse.cs (83%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Models/Github/GithubReleasesJsonSerializerContext.cs (85%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Controller_JoyConLeft.svg (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Controller_JoyConPair.svg (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Controller_JoyConRight.svg (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Controller_ProCon.svg (100%) create mode 100644 src/Ryujinx.UI.Common/Resources/Icon_Blank.png create mode 100644 src/Ryujinx.UI.Common/Resources/Icon_NCA.png create mode 100644 src/Ryujinx.UI.Common/Resources/Icon_NRO.png create mode 100644 src/Ryujinx.UI.Common/Resources/Icon_NSO.png create mode 100644 src/Ryujinx.UI.Common/Resources/Icon_NSP.png create mode 100644 src/Ryujinx.UI.Common/Resources/Icon_XCI.png rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Logo_Amiibo.png (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Logo_Discord_Dark.png (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Logo_Discord_Light.png (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Logo_GitHub_Dark.png (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Logo_GitHub_Light.png (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Logo_Patreon_Dark.png (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Logo_Patreon_Light.png (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Logo_Ryujinx.png (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Logo_Twitter_Dark.png (100%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/Resources/Logo_Twitter_Light.png (100%) rename src/{Ryujinx.Ui.Common/Ryujinx.Ui.Common.csproj => Ryujinx.UI.Common/Ryujinx.UI.Common.csproj} (94%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/SystemInfo/LinuxSystemInfo.cs (98%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/SystemInfo/MacOSSystemInfo.cs (99%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/SystemInfo/SystemInfo.cs (97%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/SystemInfo/WindowsSystemInfo.cs (98%) rename src/{Ryujinx.Ui.Common => Ryujinx.UI.Common}/UserError.cs (96%) rename src/{Ryujinx.Ui.LocaleGenerator => Ryujinx.UI.LocaleGenerator}/LocaleGenerator.cs (97%) rename src/{Ryujinx.Ui.LocaleGenerator/Ryujinx.Ui.LocaleGenerator.csproj => Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj} (100%) delete mode 100644 src/Ryujinx.Ui.Common/Resources/Icon_NCA.png delete mode 100644 src/Ryujinx.Ui.Common/Resources/Icon_NRO.png delete mode 100644 src/Ryujinx.Ui.Common/Resources/Icon_NSO.png delete mode 100644 src/Ryujinx.Ui.Common/Resources/Icon_NSP.png delete mode 100644 src/Ryujinx.Ui.Common/Resources/Icon_XCI.png rename src/{Ryujinx.Ava => Ryujinx}/App.axaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/App.axaml.cs (71%) rename src/{Ryujinx.Ava => Ryujinx}/AppHost.cs (82%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Fonts/SegoeFluentIcons.ttf (100%) create mode 100644 src/Ryujinx/Assets/Icons/Controller_JoyConLeft.svg create mode 100644 src/Ryujinx/Assets/Icons/Controller_JoyConPair.svg create mode 100644 src/Ryujinx/Assets/Icons/Controller_JoyConRight.svg create mode 100644 src/Ryujinx/Assets/Icons/Controller_ProCon.svg create mode 100644 src/Ryujinx/Assets/Locales/ar_SA.json rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/de_DE.json (79%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/el_GR.json (80%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/en_US.json (81%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/es_ES.json (79%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/fr_FR.json (73%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/he_IL.json (81%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/it_IT.json (57%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/ja_JP.json (80%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/ko_KR.json (78%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/pl_PL.json (65%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/pt_BR.json (76%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/ru_RU.json (52%) create mode 100644 src/Ryujinx/Assets/Locales/th_TH.json rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/tr_TR.json (79%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Locales/uk_UA.json (72%) create mode 100644 src/Ryujinx/Assets/Locales/zh_CN.json create mode 100644 src/Ryujinx/Assets/Locales/zh_TW.json rename src/{Ryujinx.Ava => Ryujinx}/Assets/Styles/Styles.xaml (99%) rename src/{Ryujinx.Ava => Ryujinx}/Assets/Styles/Themes.xaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/Common/ApplicationHelper.cs (97%) rename src/{Ryujinx.Ava => Ryujinx}/Common/ApplicationSort.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/Common/KeyboardHotkeyState.cs (94%) rename src/{Ryujinx.Ava => Ryujinx}/Common/Locale/LocaleExtension.cs (86%) rename src/{Ryujinx.Ava => Ryujinx}/Common/Locale/LocaleManager.cs (70%) create mode 100644 src/Ryujinx/Common/ThemeManager.cs rename src/{Ryujinx.Ava => Ryujinx}/Input/AvaloniaKeyboard.cs (99%) rename src/{Ryujinx.Ava => Ryujinx}/Input/AvaloniaKeyboardDriver.cs (98%) rename src/{Ryujinx.Ava => Ryujinx}/Input/AvaloniaKeyboardMappingHelper.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/Input/AvaloniaMouse.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/Input/AvaloniaMouseDriver.cs (100%) rename src/{Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs => Ryujinx/UI/Applet/AvaHostUIHandler.cs} (66%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Applet/AvaloniaDynamicTextInputHandler.cs (95%) rename src/{Ryujinx.Ava/UI/Applet/AvaloniaHostUiTheme.cs => Ryujinx/UI/Applet/AvaloniaHostUITheme.cs} (92%) create mode 100644 src/Ryujinx/UI/Applet/ControllerAppletDialog.axaml create mode 100644 src/Ryujinx/UI/Applet/ControllerAppletDialog.axaml.cs rename src/{Ryujinx.Ava => Ryujinx}/UI/Applet/ErrorAppletWindow.axaml (94%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Applet/ErrorAppletWindow.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Applet/SwkbdAppletDialog.axaml (95%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Applet/SwkbdAppletDialog.axaml.cs (99%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Controls/ApplicationContextMenu.axaml (92%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Controls/ApplicationContextMenu.axaml.cs (84%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Controls/ApplicationGridView.axaml (93%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Controls/ApplicationGridView.axaml.cs (98%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Controls/ApplicationListView.axaml (92%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Controls/ApplicationListView.axaml.cs (98%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Controls/NavigationDialogHost.axaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Controls/NavigationDialogHost.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Controls/SliderScroll.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Controls/UpdateWaitWindow.axaml (92%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Controls/UpdateWaitWindow.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/ApplicationOpenedEventArgs.cs (93%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/BitmapArrayValueConverter.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/ButtonKeyAssigner.cs (69%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/ContentDialogHelper.cs (88%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/Glyph.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/GlyphValueConverter.cs (100%) create mode 100644 src/Ryujinx/UI/Helpers/KeyValueConverter.cs rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/LocalizedNeverConverter.cs (97%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/LoggerAdapter.cs (95%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/MiniCommand.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/NotificationHelper.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/OffscreenTextBox.cs (91%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/TimeZoneConverter.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/UserErrorDialog.cs (98%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/UserResult.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Helpers/Win32NativeInterop.cs (87%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/CheatNode.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/ControllerModel.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/DeviceType.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/DownloadableContentModel.cs (79%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/Generic/LastPlayedSortComparer.cs (96%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/Generic/TimePlayedSortComparer.cs (96%) create mode 100644 src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs create mode 100644 src/Ryujinx/UI/Models/Input/HotkeyConfig.cs create mode 100644 src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs create mode 100644 src/Ryujinx/UI/Models/ModModel.cs rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/PlayerModel.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/ProfileImageModel.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/SaveModel.cs (94%) create mode 100644 src/Ryujinx/UI/Models/StatusInitEventArgs.cs rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/StatusUpdatedEventArgs.cs (71%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/TempProfile.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/TimeZone.cs (100%) create mode 100644 src/Ryujinx/UI/Models/TitleUpdateModel.cs rename src/{Ryujinx.Ava => Ryujinx}/UI/Models/UserProfile.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Renderer/EmbeddedWindow.cs (61%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Renderer/EmbeddedWindowOpenGL.cs (96%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Renderer/EmbeddedWindowVulkan.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Renderer/OpenTKBindingsContext.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Renderer/RendererHost.axaml (76%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Renderer/RendererHost.axaml.cs (97%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Renderer/SPBOpenGLContext.cs (96%) rename src/{Ryujinx.Ava => Ryujinx}/UI/ViewModels/AboutWindowViewModel.cs (64%) rename src/{Ryujinx.Ava => Ryujinx}/UI/ViewModels/AmiiboWindowViewModel.cs (80%) create mode 100644 src/Ryujinx/UI/ViewModels/AppListFavoriteComparable.cs rename src/{Ryujinx.Ava => Ryujinx}/UI/ViewModels/BaseModel.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/ViewModels/DownloadableContentManagerViewModel.cs (82%) create mode 100644 src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs rename src/{Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs => Ryujinx/UI/ViewModels/Input/InputViewModel.cs} (89%) create mode 100644 src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs rename src/{Ryujinx.Ava/UI/ViewModels => Ryujinx/UI/ViewModels/Input}/MotionInputViewModel.cs (97%) rename src/{Ryujinx.Ava/UI/ViewModels => Ryujinx/UI/ViewModels/Input}/RumbleInputViewModel.cs (92%) rename src/{Ryujinx.Ava => Ryujinx}/UI/ViewModels/MainWindowViewModel.cs (91%) create mode 100644 src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs rename src/{Ryujinx.Ava => Ryujinx}/UI/ViewModels/SettingsViewModel.cs (93%) rename src/{Ryujinx.Ava => Ryujinx}/UI/ViewModels/TitleUpdateViewModel.cs (65%) rename src/{Ryujinx.Ava => Ryujinx}/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs (93%) rename src/{Ryujinx.Ava => Ryujinx}/UI/ViewModels/UserProfileImageSelectorViewModel.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/ViewModels/UserProfileViewModel.cs (88%) rename src/{Ryujinx.Ava => Ryujinx}/UI/ViewModels/UserSaveManagerViewModel.cs (100%) create mode 100644 src/Ryujinx/UI/Views/Input/ControllerInputView.axaml create mode 100644 src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs rename src/{Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml => Ryujinx/UI/Views/Input/InputView.axaml} (83%) create mode 100644 src/Ryujinx/UI/Views/Input/InputView.axaml.cs create mode 100644 src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml create mode 100644 src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml.cs rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Input/MotionInputView.axaml (99%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Input/MotionInputView.axaml.cs (87%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Input/RumbleInputView.axaml (97%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Input/RumbleInputView.axaml.cs (82%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Main/MainMenuBarView.axaml (93%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Main/MainMenuBarView.axaml.cs (76%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Main/MainStatusBarView.axaml (98%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Main/MainStatusBarView.axaml.cs (93%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Main/MainViewControls.axaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Main/MainViewControls.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsAudioView.axaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsAudioView.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsCPUView.axaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsCPUView.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsGraphicsView.axaml (97%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsGraphicsView.axaml.cs (100%) create mode 100644 src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml create mode 100644 src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsInputView.axaml (96%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsInputView.axaml.cs (86%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsLoggingView.axaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsLoggingView.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsNetworkView.axaml (87%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsNetworkView.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsSystemView.axaml (97%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsSystemView.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsUIView.axaml (68%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/Settings/SettingsUIView.axaml.cs (68%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserEditorView.axaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserEditorView.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserFirmwareAvatarSelectorView.axaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs (70%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserProfileImageSelectorView.axaml (97%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserProfileImageSelectorView.axaml.cs (88%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserRecovererView.axaml (97%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserRecovererView.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserSaveManagerView.axaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserSaveManagerView.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserSelectorView.axaml (95%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Views/User/UserSelectorView.axaml.cs (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/AboutWindow.axaml (87%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/AboutWindow.axaml.cs (98%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/AmiiboWindow.axaml (99%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/AmiiboWindow.axaml.cs (97%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/CheatWindow.axaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/CheatWindow.axaml.cs (88%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/ContentDialogOverlayWindow.axaml (100%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/ContentDialogOverlayWindow.axaml.cs (91%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/DownloadableContentManagerWindow.axaml (99%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/DownloadableContentManagerWindow.axaml.cs (89%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/IconColorPicker.cs (78%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/MainWindow.axaml (95%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/MainWindow.axaml.cs (71%) create mode 100644 src/Ryujinx/UI/Windows/ModManagerWindow.axaml create mode 100644 src/Ryujinx/UI/Windows/ModManagerWindow.axaml.cs rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/SettingsWindow.axaml (95%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/SettingsWindow.axaml.cs (98%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/StyleableWindow.cs (69%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/TitleUpdateWindow.axaml (99%) rename src/{Ryujinx.Ava => Ryujinx}/UI/Windows/TitleUpdateWindow.axaml.cs (74%) rename src/{Ryujinx.Ava => Ryujinx}/app.manifest (100%) rename src/{Ryujinx.Ava => Ryujinx}/rd.xml (100%) diff --git a/.editorconfig b/.editorconfig index ae4c97662..76edc491c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,8 +17,8 @@ tab_width = 4 end_of_line = lf insert_final_newline = true -# JSON files -[*.json] +# Markdown, JSON, YAML, props and csproj files +[*.{md,json,yml,props,csproj}] # Indentation and spacing indent_size = 2 @@ -259,12 +259,12 @@ dotnet_diagnostic.CA1861.severity = none # Disable "Prefer using 'string.Equals(string, StringComparison)' to perform a case-insensitive comparison, but keep in mind that this might cause subtle changes in behavior, so make sure to conduct thorough testing after applying the suggestion, or if culturally sensitive comparison is not required, consider using 'StringComparison.OrdinalIgnoreCase'" dotnet_diagnostic.CA1862.severity = none -[src/Ryujinx.HLE/HOS/Services/**.cs] -# Disable "mark members as static" rule for services +[src/Ryujinx/UI/ViewModels/**.cs] +# Disable "mark members as static" rule for ViewModels dotnet_diagnostic.CA1822.severity = none -[src/Ryujinx.Ava/UI/ViewModels/**.cs] -# Disable "mark members as static" rule for ViewModels +[src/Ryujinx.HLE/HOS/Services/**.cs] +# Disable "mark members as static" rule for services dotnet_diagnostic.CA1822.severity = none [src/Ryujinx.Tests/Cpu/*.cs] diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 68be1f5e0..ffb5d5f8b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -23,7 +23,7 @@ body: attributes: label: Log file description: A log file will help our developers to better diagnose and fix the issue. - placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. You can drag and drop the log on to the text area + placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. They can also be accessed by opening Ryujinx, then going to File > Open Logs Folder. You can drag and drop the log on to the text area (do not copy paste). validations: required: true - type: input @@ -83,4 +83,4 @@ body: - Additional info about your environment: - Any other information relevant to your issue. validations: - required: false \ No newline at end of file + required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 383bbb151..399aa039c 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,7 @@ name: Feature Request description: Suggest a new feature for Ryujinx. title: "[Feature Request]" +labels: enhancement body: - type: textarea id: overview diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1516f8a7d..20bdc19d1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,18 +7,34 @@ updates: labels: - "infra" reviewers: - - marysaka + - TSRBerry commit-message: prefix: "ci" - package-ecosystem: nuget directory: / - open-pull-requests-limit: 5 + open-pull-requests-limit: 10 schedule: interval: daily labels: - "infra" reviewers: - - marysaka + - TSRBerry commit-message: prefix: nuget + groups: + Avalonia: + patterns: + - "*Avalonia*" + Silk.NET: + patterns: + - "Silk.NET*" + OpenTK: + patterns: + - "OpenTK*" + SixLabors: + patterns: + - "SixLabors*" + NUnit: + patterns: + - "NUnit*" diff --git a/.github/labeler.yml b/.github/labeler.yml index 027448437..cd7650a9d 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -20,7 +20,7 @@ gpu: gui: - changed-files: - - any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.Ui.Common/**', 'src/Ryujinx.Ui.LocaleGenerator/**', 'src/Ryujinx.Ava/**'] + - any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.Common/**', 'src/Ryujinx.UI.LocaleGenerator/**', 'src/Ryujinx.Gtk3/**'] horizon: - changed-files: diff --git a/.github/reviewers.yml b/.github/reviewers.yml index 052594f23..46c0d5c11 100644 --- a/.github/reviewers.yml +++ b/.github/reviewers.yml @@ -1,31 +1,24 @@ -audio: - - marysaka cpu: - gdkchan - riperiperi - - marysaka - LDj3SNuD gpu: - gdkchan - riperiperi - - marysaka gui: - Ack77 - emmauss - TSRBerry - - marysaka horizon: - gdkchan - Ack77 - - marysaka - TSRBerry infra: - - marysaka - TSRBerry default: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cf4fdf051..221c7732e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,28 +10,17 @@ env: jobs: build: - name: ${{ matrix.OS_NAME }} (${{ matrix.configuration }}) - runs-on: ${{ matrix.os }} + name: ${{ matrix.platform.name }} (${{ matrix.configuration }}) + runs-on: ${{ matrix.platform.os }} timeout-minutes: 45 strategy: matrix: - os: [ubuntu-latest, macOS-latest, windows-latest] configuration: [Debug, Release] - include: - - os: ubuntu-latest - OS_NAME: Linux x64 - DOTNET_RUNTIME_IDENTIFIER: linux-x64 - RELEASE_ZIP_OS_NAME: linux_x64 - - - os: macOS-latest - OS_NAME: macOS x64 - DOTNET_RUNTIME_IDENTIFIER: osx-x64 - RELEASE_ZIP_OS_NAME: osx_x64 - - - os: windows-latest - OS_NAME: Windows x64 - DOTNET_RUNTIME_IDENTIFIER: win-x64 - RELEASE_ZIP_OS_NAME: win_x64 + platform: + - { name: win-x64, os: windows-latest, zip_os_name: win_x64 } + - { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 } + - { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 } + - { name: osx-x64, os: macos-13, zip_os_name: osx_x64 } fail-fast: false steps: @@ -40,7 +29,7 @@ jobs: - uses: actions/setup-dotnet@v4 with: global-json-file: global.json - + - name: Overwrite csc problem matcher run: echo "::add-matcher::.github/csc.json" @@ -49,6 +38,16 @@ jobs: run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT shell: bash + - name: Change config filename + run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs + shell: bash + if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13' + + - name: Change config filename for macOS + run: sed -r -i '' 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs + shell: bash + if: github.event_name == 'pull_request' && matrix.platform.os == 'macos-13' + - name: Build run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER @@ -58,46 +57,47 @@ jobs: commands: dotnet test --no-build -c "${{ matrix.configuration }}" timeout-minutes: 10 retry-codes: 139 + if: matrix.platform.name != 'linux-arm64' - name: Publish Ryujinx - run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true + if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13' - name: Publish Ryujinx.Headless.SDL2 - run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true + if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13' - - name: Publish Ryujinx.Ava - run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Ava --self-contained true - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + - name: Publish Ryujinx.Gtk3 + run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_gtk -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Gtk3 --self-contained true + if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13' - name: Set executable bit run: | chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh - chmod +x ./publish_ava/Ryujinx.Ava ./publish_ava/Ryujinx.sh - if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest' + chmod +x ./publish_gtk/Ryujinx.Gtk3 ./publish_gtk/Ryujinx.sh + if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest' - name: Upload Ryujinx artifact uses: actions/upload-artifact@v4 with: - name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }} + name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }} path: publish - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13' - name: Upload Ryujinx.Headless.SDL2 artifact uses: actions/upload-artifact@v4 with: - name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }} + name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }} path: publish_sdl2_headless - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13' - - name: Upload Ryujinx.Ava artifact + - name: Upload Ryujinx.Gtk3 artifact uses: actions/upload-artifact@v4 with: - name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }} - path: publish_ava - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + name: gtk-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }} + path: publish_gtk + if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13' build_macos: name: macOS Universal (${{ matrix.configuration }}) @@ -135,19 +135,24 @@ jobs: id: git_short_hash run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT - - name: Publish macOS Ryujinx.Ava + - name: Change config filename + run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs + shell: bash + if: github.event_name == 'pull_request' + + - name: Publish macOS Ryujinx run: | - ./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER" + ./distribution/macos/create_macos_build_ava.sh . publish_tmp publish ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER" - name: Publish macOS Ryujinx.Headless.SDL2 run: | ./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER" - - name: Upload Ryujinx.Ava artifact + - name: Upload Ryujinx artifact uses: actions/upload-artifact@v4 with: - name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal - path: "publish_ava/*.tar.gz" + name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal + path: "publish/*.tar.gz" if: github.event_name == 'pull_request' - name: Upload Ryujinx.Headless.SDL2 artifact diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 5311a67f6..2bef2d8e0 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -8,7 +8,7 @@ on: - '!.github/**' - '!*.yml' - '!*.config' - - '!README.md' + - '!*.md' - '.github/workflows/*.yml' permissions: diff --git a/.github/workflows/flatpak.yml b/.github/workflows/flatpak.yml index f529bea03..bfed328c9 100644 --- a/.github/workflows/flatpak.yml +++ b/.github/workflows/flatpak.yml @@ -51,38 +51,76 @@ jobs: - name: Restore Nuget packages # With .NET 8.0.100, Microsoft.NET.ILLink.Tasks isn't restored by default and only seems to appears when publishing. # So we just publish to grab the dependencies - run: dotnet publish -c Release -r linux-x64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained + run: | + dotnet publish -c Release -r linux-x64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained + dotnet publish -c Release -r linux-arm64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained - name: Generate nuget_sources.json shell: python run: | + import hashlib from pathlib import Path import base64 import binascii import json import os + import urllib.request sources = [] - for path in Path(os.environ['NUGET_PACKAGES']).glob('**/*.nupkg.sha512'): - name = path.parent.parent.name - version = path.parent.name - filename = '{}.{}.nupkg'.format(name, version) - url = 'https://api.nuget.org/v3-flatcontainer/{}/{}/{}'.format(name, version, filename) - with path.open() as fp: - sha512 = binascii.hexlify(base64.b64decode(fp.read())).decode('ascii') + def create_source_from_external(name, version): + full_dir_path = Path(os.environ["NUGET_PACKAGES"]).joinpath(name).joinpath(version) + os.makedirs(full_dir_path, exist_ok=True) - sources.append({ - 'type': 'file', - 'url': url, - 'sha512': sha512, - 'dest': os.environ['NUGET_SOURCES_DESTDIR'], - 'dest-filename': filename, - }) + filename = "{}.{}.nupkg".format(name, version) + url = "https://api.nuget.org/v3-flatcontainer/{}/{}/{}".format( + name, version, filename + ) - with open('flathub/nuget_sources.json', 'w') as fp: - json.dump(sources, fp, indent=4) + print(f"Processing {url}...") + response = urllib.request.urlopen(url) + sha512 = hashlib.sha512(response.read()).hexdigest() + + return { + "type": "file", + "url": url, + "sha512": sha512, + "dest": os.environ["NUGET_SOURCES_DESTDIR"], + "dest-filename": filename, + } + + + has_added_x64_apphost = False + + for path in Path(os.environ["NUGET_PACKAGES"]).glob("**/*.nupkg.sha512"): + name = path.parent.parent.name + version = path.parent.name + filename = "{}.{}.nupkg".format(name, version) + url = "https://api.nuget.org/v3-flatcontainer/{}/{}/{}".format( + name, version, filename + ) + + with path.open() as fp: + sha512 = binascii.hexlify(base64.b64decode(fp.read())).decode("ascii") + + sources.append( + { + "type": "file", + "url": url, + "sha512": sha512, + "dest": os.environ["NUGET_SOURCES_DESTDIR"], + "dest-filename": filename, + } + ) + + # .NET will not add current installed application host to the list, force inject it here. + if not has_added_x64_apphost and name.startswith('microsoft.netcore.app.host'): + sources.append(create_source_from_external("microsoft.netcore.app.host.linux-x64", version)) + has_added_x64_apphost = True + + with open("flathub/nuget_sources.json", "w") as fp: + json.dump(sources, fp, indent=4) - name: Update flatpak metadata id: metadata diff --git a/.github/workflows/mako.yml b/.github/workflows/mako.yml new file mode 100644 index 000000000..19165fb04 --- /dev/null +++ b/.github/workflows/mako.yml @@ -0,0 +1,41 @@ +name: Mako +on: + discussion: + types: [created, edited, answered, unanswered, category_changed] + discussion_comment: + types: [created, edited] + gollum: + issue_comment: + types: [created, edited] + issues: + types: [opened, edited, reopened, pinned, milestoned, demilestoned, assigned, unassigned, labeled, unlabeled] + pull_request_target: + types: [opened, edited, reopened, synchronize, ready_for_review, assigned, unassigned] + +jobs: + tasks: + name: Run Ryujinx tasks + permissions: + actions: read + contents: read + discussions: write + issues: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + if: github.event_name == 'pull_request_target' + with: + # Ensure we pin the source origin as pull_request_target run under forks. + fetch-depth: 0 + repository: Ryujinx/Ryujinx + ref: master + + - name: Run Mako command + uses: Ryujinx/Ryujinx-Mako@master + with: + command: exec-ryujinx-tasks + args: --event-name "${{ github.event_name }}" --event-path "${{ github.event_path }}" -w "${{ github.workspace }}" "${{ github.repository }}" "${{ github.run_id }}" + app_id: ${{ secrets.MAKO_APP_ID }} + private_key: ${{ secrets.MAKO_PRIVATE_KEY }} + installation_id: ${{ secrets.MAKO_INSTALLATION_ID }} diff --git a/.github/workflows/nightly_pr_comment.yml b/.github/workflows/nightly_pr_comment.yml index f59a6be1f..38850df06 100644 --- a/.github/workflows/nightly_pr_comment.yml +++ b/.github/workflows/nightly_pr_comment.yml @@ -39,24 +39,24 @@ jobs: return core.error(`No artifacts found`); } let body = `Download the artifacts for this pull request:\n`; - let hidden_avalonia_artifacts = `\n\n
Experimental GUI (Avalonia)\n`; + let hidden_gtk_artifacts = `\n\n
Old GUI (GTK3)\n`; let hidden_headless_artifacts = `\n\n
GUI-less (SDL2)\n`; let hidden_debug_artifacts = `\n\n
Only for Developers\n`; for (const art of artifacts) { if(art.name.includes('Debug')) { hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; - } else if(art.name.includes('ava-ryujinx')) { - hidden_avalonia_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; + } else if(art.name.includes('gtk-ryujinx')) { + hidden_gtk_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; } else if(art.name.includes('sdl2-ryujinx-headless')) { hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; } else { body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; } } - hidden_avalonia_artifacts += `\n
`; + hidden_gtk_artifacts += `\n
`; hidden_headless_artifacts += `\n
`; hidden_debug_artifacts += `\n
`; - body += hidden_avalonia_artifacts; + body += hidden_gtk_artifacts; body += hidden_headless_artifacts; body += hidden_debug_artifacts; diff --git a/.github/workflows/pr_triage.yml b/.github/workflows/pr_triage.yml index 93aa89626..d8d66b70f 100644 --- a/.github/workflows/pr_triage.yml +++ b/.github/workflows/pr_triage.yml @@ -21,27 +21,8 @@ jobs: repository: Ryujinx/Ryujinx ref: master - - name: Checkout Ryujinx-Mako - uses: actions/checkout@v4 - with: - repository: Ryujinx/Ryujinx-Mako - ref: master - path: '.ryujinx-mako' - - - name: Setup Ryujinx-Mako - uses: ./.ryujinx-mako/.github/actions/setup-mako - - name: Update labels based on changes uses: actions/labeler@v5 with: sync-labels: true dot: true - - - name: Assign reviewers - run: | - poetry -n -C .ryujinx-mako run ryujinx-mako update-reviewers ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml - shell: bash - env: - MAKO_APP_ID: ${{ secrets.MAKO_APP_ID }} - MAKO_PRIVATE_KEY: ${{ secrets.MAKO_PRIVATE_KEY }} - MAKO_INSTALLATION_ID: ${{ secrets.MAKO_INSTALLATION_ID }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7a4b13d7d..f2bebc77f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ on: - '*.yml' - '*.json' - '*.config' - - 'README.md' + - '*.md' concurrency: release @@ -44,30 +44,34 @@ jobs: sha: context.sha }) + - name: Create release + uses: ncipollo/release-action@v1 + with: + name: ${{ steps.version_info.outputs.build_version }} + tag: ${{ steps.version_info.outputs.build_version }} + body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)." + omitBodyDuringUpdate: true + owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }} + repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }} + token: ${{ secrets.RELEASE_TOKEN }} + release: - name: Release ${{ matrix.OS_NAME }} - runs-on: ${{ matrix.os }} + name: Release for ${{ matrix.platform.name }} + runs-on: ${{ matrix.platform.os }} timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }} strategy: matrix: - os: [ ubuntu-latest, windows-latest ] - include: - - os: ubuntu-latest - OS_NAME: Linux x64 - DOTNET_RUNTIME_IDENTIFIER: linux-x64 - RELEASE_ZIP_OS_NAME: linux_x64 - - - os: windows-latest - OS_NAME: Windows x64 - DOTNET_RUNTIME_IDENTIFIER: win-x64 - RELEASE_ZIP_OS_NAME: win_x64 + platform: + - { name: win-x64, os: windows-latest, zip_os_name: win_x64 } + - { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 } + - { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 } steps: - uses: actions/checkout@v4 - uses: actions/setup-dotnet@v4 with: global-json-file: global.json - + - name: Overwrite csc problem matcher run: echo "::add-matcher::.github/csc.json" @@ -85,6 +89,7 @@ jobs: sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs shell: bash - name: Create output dir @@ -92,42 +97,36 @@ jobs: - name: Publish run: | - dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_gtk/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true - dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true - dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true + dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true + dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true - name: Packing Windows builds - if: matrix.os == 'windows-latest' + if: matrix.platform.os == 'windows-latest' run: | - pushd publish_gtk - 7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish + pushd publish_ava + cp publish/Ryujinx.exe publish/Ryujinx.Ava.exe + 7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish + 7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish popd pushd publish_sdl2_headless - 7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish - popd - - pushd publish_ava - 7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish + 7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish popd shell: bash - name: Packing Linux builds - if: matrix.os == 'ubuntu-latest' + if: matrix.platform.os == 'ubuntu-latest' run: | - pushd publish_gtk - chmod +x publish/Ryujinx.sh publish/Ryujinx - tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish + pushd publish_ava + cp publish/Ryujinx publish/Ryujinx.Ava + chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava publish/Ryujinx + tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish + tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish popd pushd publish_sdl2_headless chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2 - tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish - popd - - pushd publish_ava - chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava - tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish + tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish popd shell: bash @@ -186,12 +185,13 @@ jobs: sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs shell: bash - - name: Publish macOS Ryujinx.Ava + - name: Publish macOS Ryujinx run: | ./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release - + - name: Publish macOS Ryujinx.Headless.SDL2 run: | ./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release diff --git a/Directory.Packages.props b/Directory.Packages.props index 40275763b..301024cf8 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,52 +3,50 @@ true - - - - - - - + + + + + + + - + - - + + - - - - + + + + - + - - - - + + + + - - + + - + - - - - - - - - + + + + + + - + \ No newline at end of file diff --git a/README.md b/README.md index 58f0dfd35..b8af36811 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,9 @@

MeloNX

+## Documentation + +If you are planning to contribute or just want to learn more about this project please read through our [documentation](docs/README.md).

diff --git a/Ryujinx.sln b/Ryujinx.sln index bb196cabc..76ebd573f 100644 --- a/Ryujinx.sln +++ b/Ryujinx.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.1.32228.430 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Gtk3", "src\Ryujinx.Gtk3\Ryujinx.Gtk3.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests", "src\Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}" EndProject @@ -69,9 +69,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "sr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ava", "src\Ryujinx.Ava\Ryujinx.Ava.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.Common", "src\Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.Common", "src\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}" EndProject @@ -79,7 +79,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "src\Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.LocaleGenerator", "src\Ryujinx.Ui.LocaleGenerator\Ryujinx.Ui.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.LocaleGenerator", "src\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "src\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}" EndProject @@ -87,6 +87,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryuj EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -249,6 +251,10 @@ Global {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU + {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Ryujinx.sln.DotSettings b/Ryujinx.sln.DotSettings index 049bdaf69..ed7f3e911 100644 --- a/Ryujinx.sln.DotSettings +++ b/Ryujinx.sln.DotSettings @@ -4,6 +4,8 @@ UseExplicitType UseExplicitType <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="I" Suffix="" Style="AaBb" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"><ElementKinds><Kind Name="NAMESPACE" /><Kind Name="CLASS" /><Kind Name="STRUCT" /><Kind Name="ENUM" /><Kind Name="DELEGATE" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="I" Suffix="" Style="AaBb" /></Policy></Policy> + True True True True diff --git a/distribution/linux/Ryujinx.desktop b/distribution/linux/Ryujinx.desktop index a4550d104..44f05bf3f 100644 --- a/distribution/linux/Ryujinx.desktop +++ b/distribution/linux/Ryujinx.desktop @@ -4,7 +4,7 @@ Name=Ryujinx Type=Application Icon=Ryujinx Exec=Ryujinx.sh %f -Comment=Plays Nintendo Switch applications +Comment=A Nintendo Switch Emulator GenericName=Nintendo Switch Emulator Terminal=false Categories=Game;Emulator; diff --git a/distribution/linux/Ryujinx.sh b/distribution/linux/Ryujinx.sh old mode 100644 new mode 100755 index f356cad01..30eb14399 --- a/distribution/linux/Ryujinx.sh +++ b/distribution/linux/Ryujinx.sh @@ -1,20 +1,23 @@ #!/bin/sh SCRIPT_DIR=$(dirname "$(realpath "$0")") -RYUJINX_BIN="Ryujinx" - -if [ -f "$SCRIPT_DIR/Ryujinx.Ava" ]; then - RYUJINX_BIN="Ryujinx.Ava" -fi if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then RYUJINX_BIN="Ryujinx.Headless.SDL2" fi +if [ -f "$SCRIPT_DIR/Ryujinx" ]; then + RYUJINX_BIN="Ryujinx" +fi + +if [ -z "$RYUJINX_BIN" ]; then + exit 1 +fi + COMMAND="env DOTNET_EnableAlternateStackCheck=1" if command -v gamemoderun > /dev/null 2>&1; then COMMAND="$COMMAND gamemoderun" fi -$COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@" \ No newline at end of file +exec $COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@" diff --git a/distribution/macos/create_app_bundle.sh b/distribution/macos/create_app_bundle.sh index 858c06f59..0fa54eadd 100755 --- a/distribution/macos/create_app_bundle.sh +++ b/distribution/macos/create_app_bundle.sh @@ -14,8 +14,8 @@ mkdir "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" mkdir "$APP_BUNDLE_DIRECTORY/Contents/MacOS" mkdir "$APP_BUNDLE_DIRECTORY/Contents/Resources" -# Copy executables first -cp "$PUBLISH_DIRECTORY/Ryujinx.Ava" "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx" +# Copy executable and nsure executable can be executed +cp "$PUBLISH_DIRECTORY/Ryujinx" "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx" chmod u+x "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx" # Then all libraries diff --git a/distribution/macos/create_macos_build_ava.sh b/distribution/macos/create_macos_build_ava.sh index 80594a40a..23eafc129 100755 --- a/distribution/macos/create_macos_build_ava.sh +++ b/distribution/macos/create_macos_build_ava.sh @@ -22,9 +22,9 @@ EXTRA_ARGS=$8 if [ "$VERSION" == "1.1.0" ]; then - RELEASE_TAR_FILE_NAME=test-ava-ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar + RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar else - RELEASE_TAR_FILE_NAME=test-ava-ryujinx-$VERSION-macos_universal.app.tar + RELEASE_TAR_FILE_NAME=ryujinx-$VERSION-macos_universal.app.tar fi ARM64_APP_BUNDLE="$TEMP_DIRECTORY/output_arm64/Ryujinx.app" @@ -38,9 +38,9 @@ mkdir -p "$TEMP_DIRECTORY" DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS) dotnet restore -dotnet build -c "$CONFIGURATION" src/Ryujinx.Ava -dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Ava -dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Ava +dotnet build -c "$CONFIGURATION" src/Ryujinx +dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx +dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx # Get rid of the support library for ARMeilleure for x64 (that's only for arm64) rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib" @@ -108,6 +108,13 @@ tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf "$RELEASE_TAR_FILE_NAME" python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx" gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz" rm "$RELEASE_TAR_FILE_NAME" + +# Create legacy update package for Avalonia to not left behind old testers. +if [ "$VERSION" != "1.1.0" ]; +then + cp $RELEASE_TAR_FILE_NAME.gz test-ava-ryujinx-$VERSION-macos_universal.app.tar.gz +fi + popd echo "Done" \ No newline at end of file diff --git a/distribution/macos/shortcut-launch-script.sh b/distribution/macos/shortcut-launch-script.sh new file mode 100644 index 000000000..784d780aa --- /dev/null +++ b/distribution/macos/shortcut-launch-script.sh @@ -0,0 +1,8 @@ +#!/bin/sh +launch_arch="$(uname -m)" +if [ "$(sysctl -in sysctl.proc_translated)" = "1" ] +then + launch_arch="arm64" +fi + +arch -$launch_arch {0} {1} diff --git a/docs/README.md b/docs/README.md index 2213086f6..a22da3c7c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -33,8 +33,3 @@ Project Docs ================= To be added. Many project files will contain basic XML docs for key functions and classes in the meantime. - -Other Information -================= - -- N/A diff --git a/src/ARMeilleure/CodeGen/Arm64/CodeGenContext.cs b/src/ARMeilleure/CodeGen/Arm64/CodeGenContext.cs index 12ebabddd..89b1e9e6b 100644 --- a/src/ARMeilleure/CodeGen/Arm64/CodeGenContext.cs +++ b/src/ARMeilleure/CodeGen/Arm64/CodeGenContext.cs @@ -237,7 +237,7 @@ namespace ARMeilleure.CodeGen.Arm64 long originalPosition = _stream.Position; _stream.Seek(0, SeekOrigin.Begin); - _stream.Read(code, 0, code.Length); + _stream.ReadExactly(code, 0, code.Length); _stream.Seek(originalPosition, SeekOrigin.Begin); RelocInfo relocInfo; diff --git a/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs b/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs index f156e0886..16feeb914 100644 --- a/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs +++ b/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs @@ -251,7 +251,20 @@ namespace ARMeilleure.CodeGen.RegisterAllocators } } - int selectedReg = GetHighestValueIndex(freePositions); + // If this is a copy destination variable, we prefer the register used for the copy source. + // If the register is available, then the copy can be eliminated later as both source + // and destination will use the same register. + int selectedReg; + + if (current.TryGetCopySourceRegister(out int preferredReg) && freePositions[preferredReg] >= current.GetEnd()) + { + selectedReg = preferredReg; + } + else + { + selectedReg = GetHighestValueIndex(freePositions); + } + int selectedNextUse = freePositions[selectedReg]; // Intervals starts and ends at odd positions, unless they span an entire @@ -431,7 +444,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators } } - private static int GetHighestValueIndex(Span span) + private static int GetHighestValueIndex(ReadOnlySpan span) { int highest = int.MinValue; @@ -798,12 +811,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators // The "visited" state is stored in the MSB of the local's value. const ulong VisitedMask = 1ul << 63; - bool IsVisited(Operand local) + static bool IsVisited(Operand local) { return (local.GetValueUnsafe() & VisitedMask) != 0; } - void SetVisited(Operand local) + static void SetVisited(Operand local) { local.GetValueUnsafe() |= VisitedMask; } @@ -826,9 +839,25 @@ namespace ARMeilleure.CodeGen.RegisterAllocators { dest.NumberLocal(_intervals.Count); - _intervals.Add(new LiveInterval(dest)); + LiveInterval interval = new LiveInterval(dest); + _intervals.Add(interval); SetVisited(dest); + + // If this is a copy (or copy-like operation), set the copy source interval as well. + // This is used for register preferencing later on, which allows the copy to be eliminated + // in some cases. + if (node.Instruction == Instruction.Copy || node.Instruction == Instruction.ZeroExtend32) + { + Operand source = node.GetSource(0); + + if (source.Kind == OperandKind.LocalVariable && + source.GetLocalNumber() > 0 && + (node.Instruction == Instruction.Copy || source.Type == OperandType.I32)) + { + interval.SetCopySource(_intervals[source.GetLocalNumber()]); + } + } } } } diff --git a/src/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs b/src/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs index 333d3951b..cfe1bc7ca 100644 --- a/src/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs +++ b/src/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs @@ -19,6 +19,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators public LiveRange CurrRange; public LiveInterval Parent; + public LiveInterval CopySource; public UseList Uses; public LiveIntervalList Children; @@ -37,6 +38,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators private ref LiveRange CurrRange => ref _data->CurrRange; private ref LiveRange PrevRange => ref _data->PrevRange; private ref LiveInterval Parent => ref _data->Parent; + private ref LiveInterval CopySource => ref _data->CopySource; private ref UseList Uses => ref _data->Uses; private ref LiveIntervalList Children => ref _data->Children; @@ -78,6 +80,25 @@ namespace ARMeilleure.CodeGen.RegisterAllocators Register = register; } + public void SetCopySource(LiveInterval copySource) + { + CopySource = copySource; + } + + public bool TryGetCopySourceRegister(out int copySourceRegIndex) + { + if (CopySource._data != null) + { + copySourceRegIndex = CopySource.Register.Index; + + return true; + } + + copySourceRegIndex = 0; + + return false; + } + public void Reset() { PrevRange = default; diff --git a/src/ARMeilleure/CodeGen/X86/Assembler.cs b/src/ARMeilleure/CodeGen/X86/Assembler.cs index 55bf07248..96f4de049 100644 --- a/src/ARMeilleure/CodeGen/X86/Assembler.cs +++ b/src/ARMeilleure/CodeGen/X86/Assembler.cs @@ -1444,7 +1444,7 @@ namespace ARMeilleure.CodeGen.X86 Span buffer = new byte[jump.JumpPosition - _stream.Position]; - _stream.Read(buffer); + _stream.ReadExactly(buffer); _stream.Seek(ReservedBytesForJump, SeekOrigin.Current); codeStream.Write(buffer); diff --git a/src/ARMeilleure/Decoders/OpCodeTable.cs b/src/ARMeilleure/Decoders/OpCodeTable.cs index 9e13bd9b5..20d567fe5 100644 --- a/src/ARMeilleure/Decoders/OpCodeTable.cs +++ b/src/ARMeilleure/Decoders/OpCodeTable.cs @@ -517,7 +517,10 @@ namespace ARMeilleure.Decoders SetA64("0x00111100>>>xxx100111xxxxxxxxxx", InstName.Sqrshrn_V, InstEmit.Sqrshrn_V, OpCodeSimdShImm.Create); SetA64("0111111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_S, InstEmit.Sqrshrun_S, OpCodeSimdShImm.Create); SetA64("0x10111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_V, InstEmit.Sqrshrun_V, OpCodeSimdShImm.Create); + SetA64("010111110>>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Si, InstEmit.Sqshl_Si, OpCodeSimdShImm.Create); SetA64("0>001110<<1xxxxx010011xxxxxxxxxx", InstName.Sqshl_V, InstEmit.Sqshl_V, OpCodeSimdReg.Create); + SetA64("0000111100>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Vi, InstEmit.Sqshl_Vi, OpCodeSimdShImm.Create); + SetA64("010011110>>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Vi, InstEmit.Sqshl_Vi, OpCodeSimdShImm.Create); SetA64("0101111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_S, InstEmit.Sqshrn_S, OpCodeSimdShImm.Create); SetA64("0x00111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_V, InstEmit.Sqshrn_V, OpCodeSimdShImm.Create); SetA64("0111111100>>>xxx100001xxxxxxxxxx", InstName.Sqshrun_S, InstEmit.Sqshrun_S, OpCodeSimdShImm.Create); @@ -743,6 +746,7 @@ namespace ARMeilleure.Decoders SetA32("<<<<01101000xxxxxxxxxxxxxx01xxxx", InstName.Pkh, InstEmit32.Pkh, OpCode32AluRsImm.Create); SetA32("11110101xx01xxxx1111xxxxxxxxxxxx", InstName.Pld, InstEmit32.Nop, OpCode32.Create); SetA32("11110111xx01xxxx1111xxxxxxx0xxxx", InstName.Pld, InstEmit32.Nop, OpCode32.Create); + SetA32("<<<<01100010xxxxxxxx11110001xxxx", InstName.Qadd16, InstEmit32.Qadd16, OpCode32AluReg.Create); SetA32("<<<<011011111111xxxx11110011xxxx", InstName.Rbit, InstEmit32.Rbit, OpCode32AluReg.Create); SetA32("<<<<011010111111xxxx11110011xxxx", InstName.Rev, InstEmit32.Rev, OpCode32AluReg.Create); SetA32("<<<<011010111111xxxx11111011xxxx", InstName.Rev16, InstEmit32.Rev16, OpCode32AluReg.Create); @@ -819,6 +823,10 @@ namespace ARMeilleure.Decoders SetA32("<<<<00000100xxxxxxxxxxxx1001xxxx", InstName.Umaal, InstEmit32.Umaal, OpCode32AluUmull.Create); SetA32("<<<<0000101xxxxxxxxxxxxx1001xxxx", InstName.Umlal, InstEmit32.Umlal, OpCode32AluUmull.Create); SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, OpCode32AluUmull.Create); + SetA32("<<<<01100110xxxxxxxx11110001xxxx", InstName.Uqadd16, InstEmit32.Uqadd16, OpCode32AluReg.Create); + SetA32("<<<<01100110xxxxxxxx11111001xxxx", InstName.Uqadd8, InstEmit32.Uqadd8, OpCode32AluReg.Create); + SetA32("<<<<01100110xxxxxxxx11110111xxxx", InstName.Uqsub16, InstEmit32.Uqsub16, OpCode32AluReg.Create); + SetA32("<<<<01100110xxxxxxxx11111111xxxx", InstName.Uqsub8, InstEmit32.Uqsub8, OpCode32AluReg.Create); SetA32("<<<<0110111xxxxxxxxxxxxxxx01xxxx", InstName.Usat, InstEmit32.Usat, OpCode32Sat.Create); SetA32("<<<<01101110xxxxxxxx11110011xxxx", InstName.Usat16, InstEmit32.Usat16, OpCode32Sat16.Create); SetA32("<<<<01100101xxxxxxxx11111111xxxx", InstName.Usub8, InstEmit32.Usub8, OpCode32AluReg.Create); @@ -872,6 +880,7 @@ namespace ARMeilleure.Decoders SetVfp("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32); SetVfp("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); SetVfp("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); + SetVfp("<<<<11101x110110xxxx101x01x0xxxx", InstName.Vrintr, InstEmit32.Vrintr_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); SetVfp("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); SetVfp("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); SetVfp("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create, OpCode32SimdSel.CreateT32); @@ -992,6 +1001,7 @@ namespace ARMeilleure.Decoders SetAsimd("1111001x1x000xxxxxxx<>>xxxxxxx100101x1xxx0", InstName.Vqrshrn, InstEmit32.Vqrshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32); SetAsimd("111100111x>>>xxxxxxx100001x1xxx0", InstName.Vqrshrun, InstEmit32.Vqrshrun, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32); SetAsimd("1111001x1x>>>xxxxxxx100100x1xxx0", InstName.Vqshrn, InstEmit32.Vqshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32); @@ -1023,8 +1035,10 @@ namespace ARMeilleure.Decoders SetAsimd("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32); SetAsimd("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32); SetAsimd("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create, OpCode32SimdShImmLong.CreateT32); // A1 encoding. + SetAsimd("111100111x11<<10xxxx001100x0xxxx", InstName.Vshll, InstEmit32.Vshll2, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32); // A2 encoding. SetAsimd("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32); SetAsimd("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32); + SetAsimd("111100111x>>>xxxxxxx0101>xx1xxxx", InstName.Vsli, InstEmit32.Vsli_I, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32); SetAsimd("1111001x1x>>>xxxxxxx0001>xx1xxxx", InstName.Vsra, InstEmit32.Vsra, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32); SetAsimd("111101001x00xxxxxxxx0000xxx0xxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32); SetAsimd("111101001x00xxxxxxxx0100xx0xxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32); @@ -1049,6 +1063,7 @@ namespace ARMeilleure.Decoders SetAsimd("111100100x10xxxxxxxx1101xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32); SetAsimd("1111001x1x< + { + EmitSaturateRange(context, d, context.Add(n, m), 16, unsigned: false, setQ: false); + })); + } + public static void Rbit(ArmEmitterContext context) { Operand m = GetAluM(context); @@ -467,6 +485,12 @@ namespace ARMeilleure.Instructions Operand n = GetAluN(context); Operand m = GetAluM(context, setCarry: false); + if (op.Rn == RegisterAlias.Aarch32Pc && op is OpCodeT32AluImm12) + { + // For ADR, PC is always 4 bytes aligned, even in Thumb mode. + n = context.BitwiseAnd(n, Const(~3u)); + } + Operand res = context.Subtract(n, m); if (ShouldSetFlags(context)) @@ -546,6 +570,46 @@ namespace ARMeilleure.Instructions EmitHsub8(context, unsigned: true); } + public static void Uqadd16(ArmEmitterContext context) + { + OpCode32AluReg op = (OpCode32AluReg)context.CurrOp; + + SetIntA32(context, op.Rd, EmitUnsigned16BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) => + { + EmitSaturateUqadd(context, d, context.Add(n, m), 16); + })); + } + + public static void Uqadd8(ArmEmitterContext context) + { + OpCode32AluReg op = (OpCode32AluReg)context.CurrOp; + + SetIntA32(context, op.Rd, EmitUnsigned8BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) => + { + EmitSaturateUqadd(context, d, context.Add(n, m), 8); + })); + } + + public static void Uqsub16(ArmEmitterContext context) + { + OpCode32AluReg op = (OpCode32AluReg)context.CurrOp; + + SetIntA32(context, op.Rd, EmitUnsigned16BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) => + { + EmitSaturateUqsub(context, d, context.Subtract(n, m), 16); + })); + } + + public static void Uqsub8(ArmEmitterContext context) + { + OpCode32AluReg op = (OpCode32AluReg)context.CurrOp; + + SetIntA32(context, op.Rd, EmitUnsigned8BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) => + { + EmitSaturateUqsub(context, d, context.Subtract(n, m), 8); + })); + } + public static void Usat(ArmEmitterContext context) { OpCode32Sat op = (OpCode32Sat)context.CurrOp; @@ -922,6 +986,251 @@ namespace ARMeilleure.Instructions } } + private static void EmitSaturateRange(ArmEmitterContext context, Operand result, Operand value, uint saturateTo, bool unsigned, bool setQ = true) + { + Debug.Assert(saturateTo <= 32); + Debug.Assert(!unsigned || saturateTo < 32); + + if (!unsigned && saturateTo == 32) + { + // No saturation possible for this case. + + context.Copy(result, value); + + return; + } + else if (saturateTo == 0) + { + // Result is always zero if we saturate 0 bits. + + context.Copy(result, Const(0)); + + return; + } + + Operand satValue; + + if (unsigned) + { + // Negative values always saturate (to zero). + // So we must always ignore the sign bit when masking, so that the truncated value will differ from the original one. + + satValue = context.BitwiseAnd(value, Const((int)(uint.MaxValue >> (32 - (int)saturateTo)))); + } + else + { + satValue = context.ShiftLeft(value, Const(32 - (int)saturateTo)); + satValue = context.ShiftRightSI(satValue, Const(32 - (int)saturateTo)); + } + + // If the result is 0, the values are equal and we don't need saturation. + Operand lblNoSat = Label(); + context.BranchIfFalse(lblNoSat, context.Subtract(value, satValue)); + + // Saturate and set Q flag. + if (unsigned) + { + if (saturateTo == 31) + { + // Only saturation case possible when going from 32 bits signed to 32 or 31 bits unsigned + // is when the signed input is negative, as all positive values are representable on a 31 bits range. + + satValue = Const(0); + } + else + { + satValue = context.ShiftRightSI(value, Const(31)); + satValue = context.BitwiseNot(satValue); + satValue = context.ShiftRightUI(satValue, Const(32 - (int)saturateTo)); + } + } + else + { + if (saturateTo == 1) + { + satValue = context.ShiftRightSI(value, Const(31)); + } + else + { + satValue = Const(uint.MaxValue >> (33 - (int)saturateTo)); + satValue = context.BitwiseExclusiveOr(satValue, context.ShiftRightSI(value, Const(31))); + } + } + + if (setQ) + { + SetFlag(context, PState.QFlag, Const(1)); + } + + context.Copy(result, satValue); + + Operand lblExit = Label(); + context.Branch(lblExit); + + context.MarkLabel(lblNoSat); + + context.Copy(result, value); + + context.MarkLabel(lblExit); + } + + private static void EmitSaturateUqadd(ArmEmitterContext context, Operand result, Operand value, uint saturateTo) + { + Debug.Assert(saturateTo <= 32); + + if (saturateTo == 32) + { + // No saturation possible for this case. + + context.Copy(result, value); + + return; + } + else if (saturateTo == 0) + { + // Result is always zero if we saturate 0 bits. + + context.Copy(result, Const(0)); + + return; + } + + // If the result is 0, the values are equal and we don't need saturation. + Operand lblNoSat = Label(); + context.BranchIfFalse(lblNoSat, context.ShiftRightUI(value, Const((int)saturateTo))); + + // Saturate. + context.Copy(result, Const(uint.MaxValue >> (32 - (int)saturateTo))); + + Operand lblExit = Label(); + context.Branch(lblExit); + + context.MarkLabel(lblNoSat); + + context.Copy(result, value); + + context.MarkLabel(lblExit); + } + + private static void EmitSaturateUqsub(ArmEmitterContext context, Operand result, Operand value, uint saturateTo) + { + Debug.Assert(saturateTo <= 32); + + if (saturateTo == 32) + { + // No saturation possible for this case. + + context.Copy(result, value); + + return; + } + else if (saturateTo == 0) + { + // Result is always zero if we saturate 0 bits. + + context.Copy(result, Const(0)); + + return; + } + + // If the result is 0, the values are equal and we don't need saturation. + Operand lblNoSat = Label(); + context.BranchIf(lblNoSat, value, Const(0), Comparison.GreaterOrEqual); + + // Saturate. + // Assumes that the value can only underflow, since this is only used for unsigned subtraction. + context.Copy(result, Const(0)); + + Operand lblExit = Label(); + context.Branch(lblExit); + + context.MarkLabel(lblNoSat); + + context.Copy(result, value); + + context.MarkLabel(lblExit); + } + + private static Operand EmitSigned16BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action elementAction) + { + Operand tempD = context.AllocateLocal(OperandType.I32); + + Operand tempN = context.SignExtend16(OperandType.I32, rn); + Operand tempM = context.SignExtend16(OperandType.I32, rm); + elementAction(tempD, tempN, tempM); + Operand tempD2 = context.ZeroExtend16(OperandType.I32, tempD); + + tempN = context.ShiftRightSI(rn, Const(16)); + tempM = context.ShiftRightSI(rm, Const(16)); + elementAction(tempD, tempN, tempM); + return context.BitwiseOr(tempD2, context.ShiftLeft(tempD, Const(16))); + } + + private static Operand EmitUnsigned16BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action elementAction) + { + Operand tempD = context.AllocateLocal(OperandType.I32); + + Operand tempN = context.ZeroExtend16(OperandType.I32, rn); + Operand tempM = context.ZeroExtend16(OperandType.I32, rm); + elementAction(tempD, tempN, tempM); + Operand tempD2 = context.ZeroExtend16(OperandType.I32, tempD); + + tempN = context.ShiftRightUI(rn, Const(16)); + tempM = context.ShiftRightUI(rm, Const(16)); + elementAction(tempD, tempN, tempM); + return context.BitwiseOr(tempD2, context.ShiftLeft(tempD, Const(16))); + } + + private static Operand EmitSigned8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action elementAction) + { + return Emit8BitPair(context, rn, rm, elementAction, unsigned: false); + } + + private static Operand EmitUnsigned8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action elementAction) + { + return Emit8BitPair(context, rn, rm, elementAction, unsigned: true); + } + + private static Operand Emit8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action elementAction, bool unsigned) + { + Operand tempD = context.AllocateLocal(OperandType.I32); + Operand result = default; + + for (int b = 0; b < 4; b++) + { + Operand nByte = b != 0 ? context.ShiftRightUI(rn, Const(b * 8)) : rn; + Operand mByte = b != 0 ? context.ShiftRightUI(rm, Const(b * 8)) : rm; + + if (unsigned) + { + nByte = context.ZeroExtend8(OperandType.I32, nByte); + mByte = context.ZeroExtend8(OperandType.I32, mByte); + } + else + { + nByte = context.SignExtend8(OperandType.I32, nByte); + mByte = context.SignExtend8(OperandType.I32, mByte); + } + + elementAction(tempD, nByte, mByte); + + if (b == 0) + { + result = context.ZeroExtend8(OperandType.I32, tempD); + } + else if (b < 3) + { + result = context.BitwiseOr(result, context.ShiftLeft(context.ZeroExtend8(OperandType.I32, tempD), Const(b * 8))); + } + else + { + result = context.BitwiseOr(result, context.ShiftLeft(tempD, Const(24))); + } + } + + return result; + } + private static void EmitAluStore(ArmEmitterContext context, Operand value) { IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; diff --git a/src/ARMeilleure/Instructions/InstEmitMemoryHelper.cs b/src/ARMeilleure/Instructions/InstEmitMemoryHelper.cs index 5610b7749..ace6fe1ce 100644 --- a/src/ARMeilleure/Instructions/InstEmitMemoryHelper.cs +++ b/src/ARMeilleure/Instructions/InstEmitMemoryHelper.cs @@ -403,19 +403,25 @@ namespace ARMeilleure.Instructions { return EmitHostMappedPointer(context, address); } - else if (context.Memory.Type == MemoryManagerType.HostTracked) + else if (context.Memory.Type.IsHostTracked()) { + if (address.Type == OperandType.I32) + { + address = context.ZeroExtend32(OperandType.I64, address); + } + + if (context.Memory.Type == MemoryManagerType.HostTracked) + { + Operand mask = Const(ulong.MaxValue >> (64 - context.Memory.AddressSpaceBits)); + address = context.BitwiseAnd(address, mask); + } + Operand ptBase = !context.HasPtc ? Const(context.Memory.PageTablePointer.ToInt64()) : Const(context.Memory.PageTablePointer.ToInt64(), Ptc.PageTableSymbol); Operand ptOffset = context.ShiftRightUI(address, Const(PageBits)); - if (ptOffset.Type == OperandType.I32) - { - ptOffset = context.ZeroExtend32(OperandType.I64, ptOffset); - } - return context.Add(address, context.Load(OperandType.I64, context.Add(ptBase, context.ShiftLeft(ptOffset, Const(3))))); } diff --git a/src/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs b/src/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs index 543aab023..13d9fac68 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs @@ -2426,7 +2426,11 @@ namespace ARMeilleure.Instructions } else if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0) { - Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rsqrtss, GetVec(op.Rn)), scalar: true); + // RSQRTSS handles subnormals as zero, which differs from Arm, so we can't use it here. + + Operand res = context.AddIntrinsic(Intrinsic.X86Sqrtss, GetVec(op.Rn)); + res = context.AddIntrinsic(Intrinsic.X86Rcpss, res); + res = EmitSse41Round32Exp8OpF(context, res, scalar: true); context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res)); } @@ -2451,7 +2455,11 @@ namespace ARMeilleure.Instructions } else if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0) { - Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rsqrtps, GetVec(op.Rn)), scalar: false); + // RSQRTPS handles subnormals as zero, which differs from Arm, so we can't use it here. + + Operand res = context.AddIntrinsic(Intrinsic.X86Sqrtps, GetVec(op.Rn)); + res = context.AddIntrinsic(Intrinsic.X86Rcpps, res); + res = EmitSse41Round32Exp8OpF(context, res, scalar: false); if (op.RegisterSize == RegisterSize.Simd64) { diff --git a/src/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs b/src/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs index 27608ebf8..c807fc858 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs @@ -1115,6 +1115,13 @@ namespace ARMeilleure.Instructions } } + public static void Vpadal(ArmEmitterContext context) + { + OpCode32Simd op = (OpCode32Simd)context.CurrOp; + + EmitVectorPairwiseTernaryLongOpI32(context, (op1, op2, op3) => context.Add(context.Add(op1, op2), op3), op.Opc != 1); + } + public static void Vpaddl(ArmEmitterContext context) { OpCode32Simd op = (OpCode32Simd)context.CurrOp; @@ -1239,6 +1246,33 @@ namespace ARMeilleure.Instructions EmitVectorUnaryNarrowOp32(context, (op1) => EmitSatQ(context, op1, 8 << op.Size, signedSrc: true, signedDst: false), signed: true); } + public static void Vqrdmulh(ArmEmitterContext context) + { + OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp; + int eSize = 8 << op.Size; + + EmitVectorBinaryOpI32(context, (op1, op2) => + { + if (op.Size == 2) + { + op1 = context.SignExtend32(OperandType.I64, op1); + op2 = context.SignExtend32(OperandType.I64, op2); + } + + Operand res = context.Multiply(op1, op2); + res = context.Add(res, Const(res.Type, 1L << (eSize - 2))); + res = context.ShiftRightSI(res, Const(eSize - 1)); + res = EmitSatQ(context, res, eSize, signedSrc: true, signedDst: true); + + if (op.Size == 2) + { + res = context.ConvertI64ToI32(res); + } + + return res; + }, signed: true); + } + public static void Vqsub(ArmEmitterContext context) { OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp; diff --git a/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs index 630e114c4..8eef6b14d 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs @@ -578,6 +578,22 @@ namespace ARMeilleure.Instructions } } + // VRINTR (floating-point). + public static void Vrintr_S(ArmEmitterContext context) + { + if (Optimizations.UseAdvSimd) + { + InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, Intrinsic.Arm64FrintiS); + } + else + { + EmitScalarUnaryOpF32(context, (op1) => + { + return EmitRoundByRMode(context, op1); + }); + } + } + // VRINTZ (floating-point). public static void Vrint_Z(ArmEmitterContext context) { diff --git a/src/ARMeilleure/Instructions/InstEmitSimdHelper32.cs b/src/ARMeilleure/Instructions/InstEmitSimdHelper32.cs index c1c59b87b..2f021a1a1 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdHelper32.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdHelper32.cs @@ -673,6 +673,35 @@ namespace ARMeilleure.Instructions context.Copy(GetVecA32(op.Qd), res); } + public static void EmitVectorPairwiseTernaryLongOpI32(ArmEmitterContext context, Func3I emit, bool signed) + { + OpCode32Simd op = (OpCode32Simd)context.CurrOp; + + int elems = op.GetBytesCount() >> op.Size; + int pairs = elems >> 1; + + Operand res = GetVecA32(op.Qd); + + for (int index = 0; index < pairs; index++) + { + int pairIndex = index * 2; + Operand m1 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex, op.Size, signed); + Operand m2 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex + 1, op.Size, signed); + + if (op.Size == 2) + { + m1 = signed ? context.SignExtend32(OperandType.I64, m1) : context.ZeroExtend32(OperandType.I64, m1); + m2 = signed ? context.SignExtend32(OperandType.I64, m2) : context.ZeroExtend32(OperandType.I64, m2); + } + + Operand d1 = EmitVectorExtract32(context, op.Qd, op.Id + index, op.Size + 1, signed); + + res = EmitVectorInsert(context, res, emit(m1, m2, d1), op.Id + index, op.Size + 1); + } + + context.Copy(GetVecA32(op.Qd), res); + } + // Narrow public static void EmitVectorUnaryNarrowOp32(ArmEmitterContext context, Func1I emit, bool signed = false) diff --git a/src/ARMeilleure/Instructions/InstEmitSimdMove32.cs b/src/ARMeilleure/Instructions/InstEmitSimdMove32.cs index 9fa740997..fb2641f66 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdMove32.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdMove32.cs @@ -191,6 +191,26 @@ namespace ARMeilleure.Instructions context.Copy(GetVecA32(op.Qd), res); } + public static void Vswp(ArmEmitterContext context) + { + OpCode32Simd op = (OpCode32Simd)context.CurrOp; + + if (op.Q) + { + Operand temp = context.Copy(GetVecA32(op.Qd)); + + context.Copy(GetVecA32(op.Qd), GetVecA32(op.Qm)); + context.Copy(GetVecA32(op.Qm), temp); + } + else + { + Operand temp = ExtractScalar(context, OperandType.I64, op.Vd); + + InsertScalar(context, op.Vd, ExtractScalar(context, OperandType.I64, op.Vm)); + InsertScalar(context, op.Vm, temp); + } + } + public static void Vtbl(ArmEmitterContext context) { OpCode32SimdTbl op = (OpCode32SimdTbl)context.CurrOp; diff --git a/src/ARMeilleure/Instructions/InstEmitSimdShift.cs b/src/ARMeilleure/Instructions/InstEmitSimdShift.cs index be0670645..94e912579 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdShift.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdShift.cs @@ -116,7 +116,7 @@ namespace ARMeilleure.Instructions } else if (shift >= eSize) { - if ((op.RegisterSize == RegisterSize.Simd64)) + if (op.RegisterSize == RegisterSize.Simd64) { Operand res = context.VectorZeroUpper64(GetVec(op.Rd)); @@ -359,6 +359,16 @@ namespace ARMeilleure.Instructions } } + public static void Sqshl_Si(ArmEmitterContext context) + { + EmitShlImmOp(context, signedDst: true, ShlRegFlags.Signed | ShlRegFlags.Scalar | ShlRegFlags.Saturating); + } + + public static void Sqshl_Vi(ArmEmitterContext context) + { + EmitShlImmOp(context, signedDst: true, ShlRegFlags.Signed | ShlRegFlags.Saturating); + } + public static void Sqshrn_S(ArmEmitterContext context) { if (Optimizations.UseAdvSimd) @@ -1593,6 +1603,99 @@ namespace ARMeilleure.Instructions Saturating = 1 << 3, } + private static void EmitShlImmOp(ArmEmitterContext context, bool signedDst, ShlRegFlags flags = ShlRegFlags.None) + { + bool scalar = flags.HasFlag(ShlRegFlags.Scalar); + bool signed = flags.HasFlag(ShlRegFlags.Signed); + bool saturating = flags.HasFlag(ShlRegFlags.Saturating); + + OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; + + Operand res = context.VectorZero(); + + int elems = !scalar ? op.GetBytesCount() >> op.Size : 1; + + for (int index = 0; index < elems; index++) + { + Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size, signed); + + Operand e = !saturating + ? EmitShlImm(context, ne, GetImmShl(op), op.Size) + : EmitShlImmSatQ(context, ne, GetImmShl(op), op.Size, signed, signedDst); + + res = EmitVectorInsert(context, res, e, index, op.Size); + } + + context.Copy(GetVec(op.Rd), res); + } + + private static Operand EmitShlImm(ArmEmitterContext context, Operand op, int shiftLsB, int size) + { + int eSize = 8 << size; + + Debug.Assert(op.Type == OperandType.I64); + Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64); + + Operand res = context.AllocateLocal(OperandType.I64); + + if (shiftLsB >= eSize) + { + Operand shl = context.ShiftLeft(op, Const(shiftLsB)); + context.Copy(res, shl); + } + else + { + Operand zeroL = Const(0L); + context.Copy(res, zeroL); + } + + return res; + } + + private static Operand EmitShlImmSatQ(ArmEmitterContext context, Operand op, int shiftLsB, int size, bool signedSrc, bool signedDst) + { + int eSize = 8 << size; + + Debug.Assert(op.Type == OperandType.I64); + Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64); + + Operand lblEnd = Label(); + + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); + + if (shiftLsB >= eSize) + { + context.Copy(res, signedSrc + ? EmitSignedSignSatQ(context, op, size) + : EmitUnsignedSignSatQ(context, op, size)); + } + else + { + Operand shl = context.ShiftLeft(op, Const(shiftLsB)); + if (eSize == 64) + { + Operand sarOrShr = signedSrc + ? context.ShiftRightSI(shl, Const(shiftLsB)) + : context.ShiftRightUI(shl, Const(shiftLsB)); + context.Copy(res, shl); + context.BranchIf(lblEnd, sarOrShr, op, Comparison.Equal); + context.Copy(res, signedSrc + ? EmitSignedSignSatQ(context, op, size) + : EmitUnsignedSignSatQ(context, op, size)); + } + else + { + context.Copy(res, signedSrc + ? EmitSignedSrcSatQ(context, shl, size, signedDst) + : EmitUnsignedSrcSatQ(context, shl, size, signedDst)); + } + } + + context.MarkLabel(lblEnd); + + return res; + } + private static void EmitShlRegOp(ArmEmitterContext context, ShlRegFlags flags = ShlRegFlags.None) { bool scalar = flags.HasFlag(ShlRegFlags.Scalar); diff --git a/src/ARMeilleure/Instructions/InstEmitSimdShift32.cs b/src/ARMeilleure/Instructions/InstEmitSimdShift32.cs index e40600a47..eb28a0c5a 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdShift32.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdShift32.cs @@ -106,6 +106,38 @@ namespace ARMeilleure.Instructions context.Copy(GetVecA32(op.Qd), res); } + public static void Vshll2(ArmEmitterContext context) + { + OpCode32Simd op = (OpCode32Simd)context.CurrOp; + + Operand res = context.VectorZero(); + + int elems = op.GetBytesCount() >> op.Size; + + for (int index = 0; index < elems; index++) + { + Operand me = EmitVectorExtract32(context, op.Qm, op.Im + index, op.Size, !op.U); + + if (op.Size == 2) + { + if (op.U) + { + me = context.ZeroExtend32(OperandType.I64, me); + } + else + { + me = context.SignExtend32(OperandType.I64, me); + } + } + + me = context.ShiftLeft(me, Const(8 << op.Size)); + + res = EmitVectorInsert(context, res, me, index, op.Size + 1); + } + + context.Copy(GetVecA32(op.Qd), res); + } + public static void Vshr(ArmEmitterContext context) { OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp; @@ -130,6 +162,36 @@ namespace ARMeilleure.Instructions EmitVectorUnaryNarrowOp32(context, (op1) => context.ShiftRightUI(op1, Const(shift))); } + public static void Vsli_I(ArmEmitterContext context) + { + OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp; + int shift = op.Shift; + int eSize = 8 << op.Size; + + ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0UL; + + Operand res = GetVec(op.Qd); + + int elems = op.GetBytesCount() >> op.Size; + + for (int index = 0; index < elems; index++) + { + Operand me = EmitVectorExtractZx(context, op.Qm, op.Im + index, op.Size); + + Operand neShifted = context.ShiftLeft(me, Const(shift)); + + Operand de = EmitVectorExtractZx(context, op.Qd, op.Id + index, op.Size); + + Operand deMasked = context.BitwiseAnd(de, Const(mask)); + + Operand e = context.BitwiseOr(neShifted, deMasked); + + res = EmitVectorInsert(context, res, e, op.Id + index, op.Size); + } + + context.Copy(GetVec(op.Qd), res); + } + public static void Vsra(ArmEmitterContext context) { OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp; diff --git a/src/ARMeilleure/Instructions/InstName.cs b/src/ARMeilleure/Instructions/InstName.cs index 32ae38dad..74c33155b 100644 --- a/src/ARMeilleure/Instructions/InstName.cs +++ b/src/ARMeilleure/Instructions/InstName.cs @@ -384,7 +384,9 @@ namespace ARMeilleure.Instructions Sqrshrn_V, Sqrshrun_S, Sqrshrun_V, + Sqshl_Si, Sqshl_V, + Sqshl_Vi, Sqshrn_S, Sqshrn_V, Sqshrun_S, @@ -525,6 +527,7 @@ namespace ARMeilleure.Instructions Pld, Pop, Push, + Qadd16, Rev, Revsh, Rsb, @@ -569,6 +572,10 @@ namespace ARMeilleure.Instructions Umaal, Umlal, Umull, + Uqadd16, + Uqadd8, + Uqsub16, + Uqsub8, Usat, Usat16, Usub8, @@ -635,6 +642,7 @@ namespace ARMeilleure.Instructions Vorn, Vorr, Vpadd, + Vpadal, Vpaddl, Vpmax, Vpmin, @@ -642,6 +650,7 @@ namespace ARMeilleure.Instructions Vqdmulh, Vqmovn, Vqmovun, + Vqrdmulh, Vqrshrn, Vqrshrun, Vqshrn, @@ -654,6 +663,7 @@ namespace ARMeilleure.Instructions Vrintm, Vrintn, Vrintp, + Vrintr, Vrintx, Vrshr, Vrshrn, @@ -662,6 +672,7 @@ namespace ARMeilleure.Instructions Vshll, Vshr, Vshrn, + Vsli, Vst1, Vst2, Vst3, @@ -678,6 +689,7 @@ namespace ARMeilleure.Instructions Vsub, Vsubl, Vsubw, + Vswp, Vtbl, Vtrn, Vtst, diff --git a/src/ARMeilleure/Instructions/NativeInterface.cs b/src/ARMeilleure/Instructions/NativeInterface.cs index d1b2e353c..0cd3754f7 100644 --- a/src/ARMeilleure/Instructions/NativeInterface.cs +++ b/src/ARMeilleure/Instructions/NativeInterface.cs @@ -91,54 +91,54 @@ namespace ARMeilleure.Instructions #region "Read" public static byte ReadByte(ulong address) { - return GetMemoryManager().ReadTracked(address); + return GetMemoryManager().ReadGuest(address); } public static ushort ReadUInt16(ulong address) { - return GetMemoryManager().ReadTracked(address); + return GetMemoryManager().ReadGuest(address); } public static uint ReadUInt32(ulong address) { - return GetMemoryManager().ReadTracked(address); + return GetMemoryManager().ReadGuest(address); } public static ulong ReadUInt64(ulong address) { - return GetMemoryManager().ReadTracked(address); + return GetMemoryManager().ReadGuest(address); } public static V128 ReadVector128(ulong address) { - return GetMemoryManager().ReadTracked(address); + return GetMemoryManager().ReadGuest(address); } #endregion #region "Write" public static void WriteByte(ulong address, byte value) { - GetMemoryManager().Write(address, value); + GetMemoryManager().WriteGuest(address, value); } public static void WriteUInt16(ulong address, ushort value) { - GetMemoryManager().Write(address, value); + GetMemoryManager().WriteGuest(address, value); } public static void WriteUInt32(ulong address, uint value) { - GetMemoryManager().Write(address, value); + GetMemoryManager().WriteGuest(address, value); } public static void WriteUInt64(ulong address, ulong value) { - GetMemoryManager().Write(address, value); + GetMemoryManager().WriteGuest(address, value); } public static void WriteVector128(ulong address, V128 value) { - GetMemoryManager().Write(address, value); + GetMemoryManager().WriteGuest(address, value); } #endregion diff --git a/src/ARMeilleure/Memory/IJitMemoryAllocator.cs b/src/ARMeilleure/Memory/IJitMemoryAllocator.cs index 171bfd2f1..ff64bf13e 100644 --- a/src/ARMeilleure/Memory/IJitMemoryAllocator.cs +++ b/src/ARMeilleure/Memory/IJitMemoryAllocator.cs @@ -4,7 +4,5 @@ namespace ARMeilleure.Memory { IJitMemoryBlock Allocate(ulong size); IJitMemoryBlock Reserve(ulong size); - - ulong GetPageSize(); } } diff --git a/src/ARMeilleure/Memory/IMemoryManager.cs b/src/ARMeilleure/Memory/IMemoryManager.cs index 952cd2b4f..46d442655 100644 --- a/src/ARMeilleure/Memory/IMemoryManager.cs +++ b/src/ARMeilleure/Memory/IMemoryManager.cs @@ -28,6 +28,17 @@ namespace ARMeilleure.Memory /// The data T ReadTracked(ulong va) where T : unmanaged; + ///

+ /// Reads data from CPU mapped memory, from guest code. (with read tracking) + /// + /// Type of the data being read + /// Virtual address of the data in memory + /// The data + T ReadGuest(ulong va) where T : unmanaged + { + return ReadTracked(va); + } + /// /// Writes data to CPU mapped memory. /// @@ -36,6 +47,17 @@ namespace ARMeilleure.Memory /// Data to be written void Write(ulong va, T value) where T : unmanaged; + /// + /// Writes data to CPU mapped memory, from guest code. + /// + /// Type of the data being written + /// Virtual address to write the data into + /// Data to be written + void WriteGuest(ulong va, T value) where T : unmanaged + { + Write(va, value); + } + /// /// Gets a read-only span of data from CPU mapped memory. /// diff --git a/src/ARMeilleure/Memory/MemoryManagerType.cs b/src/ARMeilleure/Memory/MemoryManagerType.cs index 757322b4b..290503837 100644 --- a/src/ARMeilleure/Memory/MemoryManagerType.cs +++ b/src/ARMeilleure/Memory/MemoryManagerType.cs @@ -35,18 +35,29 @@ namespace ARMeilleure.Memory /// Allows invalid access from JIT code to the rest of the program, but is faster. /// HostMappedUnsafe, + + /// + /// High level implementation using a software flat page table for address translation + /// without masking the address and no support for handling invalid or non-contiguous memory access. + /// + HostTrackedUnsafe, } - static class MemoryManagerTypeExtensions + public static class MemoryManagerTypeExtensions { public static bool IsHostMapped(this MemoryManagerType type) { return type == MemoryManagerType.HostMapped || type == MemoryManagerType.HostMappedUnsafe; } + public static bool IsHostTracked(this MemoryManagerType type) + { + return type == MemoryManagerType.HostTracked || type == MemoryManagerType.HostTrackedUnsafe; + } + public static bool IsHostMappedOrTracked(this MemoryManagerType type) { - return type == MemoryManagerType.HostTracked || type == MemoryManagerType.HostMapped || type == MemoryManagerType.HostMappedUnsafe; + return type.IsHostMapped() || type.IsHostTracked(); } } } diff --git a/src/ARMeilleure/Signal/NativeSignalHandler.cs b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs similarity index 62% rename from src/ARMeilleure/Signal/NativeSignalHandler.cs rename to src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs index 40860a5d7..49c73ae3d 100644 --- a/src/ARMeilleure/Signal/NativeSignalHandler.cs +++ b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs @@ -1,63 +1,14 @@ -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Memory; +using ARMeilleure.IntermediateRepresentation; using ARMeilleure.Translation; -using ARMeilleure.Translation.Cache; using System; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using static ARMeilleure.IntermediateRepresentation.Operand.Factory; namespace ARMeilleure.Signal { - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SignalHandlerRange + public static class NativeSignalHandlerGenerator { - public int IsActive; - public nuint RangeAddress; - public nuint RangeEndAddress; - public IntPtr ActionPointer; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SignalHandlerConfig - { - /// - /// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct. - /// - public int StructAddressOffset; - - /// - /// The byte offset of the write flag in the SigInfo or ExceptionRecord struct. - /// - public int StructWriteOffset; - - /// - /// The sigaction handler that was registered before this one. (unix only) - /// - public nuint UnixOldSigaction; - - /// - /// The type of the previous sigaction. True for the 3 argument variant. (unix only) - /// - public int UnixOldSigaction3Arg; - - public SignalHandlerRange Range0; - public SignalHandlerRange Range1; - public SignalHandlerRange Range2; - public SignalHandlerRange Range3; - public SignalHandlerRange Range4; - public SignalHandlerRange Range5; - public SignalHandlerRange Range6; - public SignalHandlerRange Range7; - } - - public static class NativeSignalHandler - { - private delegate void UnixExceptionHandler(int sig, IntPtr info, IntPtr ucontext); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - private delegate int VectoredExceptionHandler(IntPtr exceptionInfo); - - private const int MaxTrackedRanges = 8; + public const int MaxTrackedRanges = 8; private const int StructAddressOffset = 0; private const int StructWriteOffset = 4; @@ -70,124 +21,7 @@ namespace ARMeilleure.Signal private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005; - private static ulong _pageSize; - private static ulong _pageMask; - - private static readonly IntPtr _handlerConfig; - private static IntPtr _signalHandlerPtr; - private static IntPtr _signalHandlerHandle; - - private static readonly object _lock = new(); - private static bool _initialized; - - static NativeSignalHandler() - { - _handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf()); - ref SignalHandlerConfig config = ref GetConfigRef(); - - config = new SignalHandlerConfig(); - } - - public static void Initialize(IJitMemoryAllocator allocator) - { - JitCache.Initialize(allocator); - } - - public static void InitializeSignalHandler(ulong pageSize, Func customSignalHandlerFactory = null) - { - if (_initialized) - { - return; - } - - lock (_lock) - { - if (_initialized) - { - return; - } - - _pageSize = pageSize; - _pageMask = pageSize - 1; - - ref SignalHandlerConfig config = ref GetConfigRef(); - - if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) - { - _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig)); - - if (customSignalHandlerFactory != null) - { - _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr); - } - - var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr); - - config.UnixOldSigaction = (nuint)(ulong)old.sa_handler; - config.UnixOldSigaction3Arg = old.sa_flags & 4; - } - else - { - config.StructAddressOffset = 40; // ExceptionInformation1 - config.StructWriteOffset = 32; // ExceptionInformation0 - - _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateWindowsSignalHandler(_handlerConfig)); - - if (customSignalHandlerFactory != null) - { - _signalHandlerPtr = customSignalHandlerFactory(IntPtr.Zero, _signalHandlerPtr); - } - - _signalHandlerHandle = WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr); - } - - _initialized = true; - } - } - - private static unsafe ref SignalHandlerConfig GetConfigRef() - { - return ref Unsafe.AsRef((void*)_handlerConfig); - } - - public static unsafe bool AddTrackedRegion(nuint address, nuint endAddress, IntPtr action) - { - var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0; - - for (int i = 0; i < MaxTrackedRanges; i++) - { - if (ranges[i].IsActive == 0) - { - ranges[i].RangeAddress = address; - ranges[i].RangeEndAddress = endAddress; - ranges[i].ActionPointer = action; - ranges[i].IsActive = 1; - - return true; - } - } - - return false; - } - - public static unsafe bool RemoveTrackedRegion(nuint address) - { - var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0; - - for (int i = 0; i < MaxTrackedRanges; i++) - { - if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address) - { - ranges[i].IsActive = 0; - - return true; - } - } - - return false; - } - - private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite) + private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize) { Operand inRegionLocal = context.AllocateLocal(OperandType.I32); context.Copy(inRegionLocal, Const(0)); @@ -196,7 +30,7 @@ namespace ARMeilleure.Signal for (int i = 0; i < MaxTrackedRanges; i++) { - ulong rangeBaseOffset = (ulong)(RangeOffset + i * Unsafe.SizeOf()); + ulong rangeBaseOffset = (ulong)(RangeOffset + i * rangeStructSize); Operand nextLabel = Label(); @@ -210,13 +44,12 @@ namespace ARMeilleure.Signal // Is the fault address within this tracked region? Operand inRange = context.BitwiseAnd( context.ICompare(faultAddress, rangeAddress, Comparison.GreaterOrEqualUI), - context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI) - ); + context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI)); // Only call tracking if in range. context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold); - Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~_pageMask)); + Operand offset = context.Subtract(faultAddress, rangeAddress); // Call the tracking action, with the pointer's relative offset to the base address. Operand trackingActionPtr = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 20)); @@ -227,8 +60,10 @@ namespace ARMeilleure.Signal // Tracking action should be non-null to call it, otherwise assume false return. context.BranchIfFalse(skipActionLabel, trackingActionPtr); - Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(_pageSize), isWrite); - context.Copy(inRegionLocal, result); + Operand result = context.Call(trackingActionPtr, OperandType.I64, offset, Const(1UL), isWrite); + context.Copy(inRegionLocal, context.ICompareNotEqual(result, Const(0UL))); + + GenerateFaultAddressPatchCode(context, faultAddress, result); context.MarkLabel(skipActionLabel); @@ -269,8 +104,7 @@ namespace ARMeilleure.Signal Operand esr = context.Load(OperandType.I64, context.Add(ctxPtr, Const(EsrOffset))); return context.BitwiseAnd(esr, Const(0x40ul)); } - - if (RuntimeInformation.ProcessArchitecture == Architecture.X64) + else if (RuntimeInformation.ProcessArchitecture == Architecture.X64) { const ulong ErrOffset = 4; // __es.__err Operand err = context.Load(OperandType.I64, context.Add(ctxPtr, Const(ErrOffset))); @@ -310,8 +144,7 @@ namespace ARMeilleure.Signal Operand esr = context.Load(OperandType.I64, context.Add(auxPtr, Const(8ul))); return context.BitwiseAnd(esr, Const(0x40ul)); } - - if (RuntimeInformation.ProcessArchitecture == Architecture.X64) + else if (RuntimeInformation.ProcessArchitecture == Architecture.X64) { const int ErrOffset = 192; // uc_mcontext.gregs[REG_ERR] Operand err = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(ErrOffset))); @@ -322,7 +155,7 @@ namespace ARMeilleure.Signal throw new PlatformNotSupportedException(); } - private static UnixExceptionHandler GenerateUnixSignalHandler(IntPtr signalStructPtr) + public static byte[] GenerateUnixSignalHandler(IntPtr signalStructPtr, int rangeStructSize) { EmitterContext context = new(); @@ -335,7 +168,7 @@ namespace ARMeilleure.Signal Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1. - Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite); + Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize); Operand endLabel = Label(); @@ -367,10 +200,10 @@ namespace ARMeilleure.Signal OperandType[] argTypes = new OperandType[] { OperandType.I32, OperandType.I64, OperandType.I64 }; - return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map(); + return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code; } - private static VectoredExceptionHandler GenerateWindowsSignalHandler(IntPtr signalStructPtr) + public static byte[] GenerateWindowsSignalHandler(IntPtr signalStructPtr, int rangeStructSize) { EmitterContext context = new(); @@ -399,7 +232,7 @@ namespace ARMeilleure.Signal Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1. - Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite); + Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize); Operand endLabel = Label(); @@ -421,7 +254,88 @@ namespace ARMeilleure.Signal OperandType[] argTypes = new OperandType[] { OperandType.I64 }; - return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map(); + return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code; + } + + private static void GenerateFaultAddressPatchCode(EmitterContext context, Operand faultAddress, Operand newAddress) + { + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + if (SupportsFaultAddressPatchingForHostOs()) + { + Operand lblSkip = Label(); + + context.BranchIf(lblSkip, faultAddress, newAddress, Comparison.Equal); + + Operand ucontextPtr = context.LoadArgument(OperandType.I64, 2); + Operand pcCtxAddress = default; + ulong baseRegsOffset = 0; + + if (OperatingSystem.IsLinux()) + { + pcCtxAddress = context.Add(ucontextPtr, Const(440UL)); + baseRegsOffset = 184UL; + } + else if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) + { + ucontextPtr = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(48UL))); + + pcCtxAddress = context.Add(ucontextPtr, Const(272UL)); + baseRegsOffset = 16UL; + } + + Operand pc = context.Load(OperandType.I64, pcCtxAddress); + + Operand reg = GetAddressRegisterFromArm64Instruction(context, pc); + Operand reg64 = context.ZeroExtend32(OperandType.I64, reg); + Operand regCtxAddress = context.Add(ucontextPtr, context.Add(context.ShiftLeft(reg64, Const(3)), Const(baseRegsOffset))); + Operand regAddress = context.Load(OperandType.I64, regCtxAddress); + + Operand addressDelta = context.Subtract(regAddress, faultAddress); + + context.Store(regCtxAddress, context.Add(newAddress, addressDelta)); + + context.MarkLabel(lblSkip); + } + } + } + + private static Operand GetAddressRegisterFromArm64Instruction(EmitterContext context, Operand pc) + { + Operand inst = context.Load(OperandType.I32, pc); + Operand reg = context.AllocateLocal(OperandType.I32); + + Operand isSysInst = context.ICompareEqual(context.BitwiseAnd(inst, Const(0xFFF80000)), Const(0xD5080000)); + + Operand lblSys = Label(); + Operand lblEnd = Label(); + + context.BranchIfTrue(lblSys, isSysInst, BasicBlockFrequency.Cold); + + context.Copy(reg, context.BitwiseAnd(context.ShiftRightUI(inst, Const(5)), Const(0x1F))); + context.Branch(lblEnd); + + context.MarkLabel(lblSys); + context.Copy(reg, context.BitwiseAnd(inst, Const(0x1F))); + + context.MarkLabel(lblEnd); + + return reg; + } + + public static bool SupportsFaultAddressPatchingForHost() + { + return SupportsFaultAddressPatchingForHostArch() && SupportsFaultAddressPatchingForHostOs(); + } + + private static bool SupportsFaultAddressPatchingForHostArch() + { + return RuntimeInformation.ProcessArchitecture == Architecture.Arm64; + } + + private static bool SupportsFaultAddressPatchingForHostOs() + { + return OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS(); } } } diff --git a/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs b/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs index 27a9ea83c..3bf6a4498 100644 --- a/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs +++ b/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs @@ -2,7 +2,7 @@ using ARMeilleure.IntermediateRepresentation; using ARMeilleure.Translation; using Ryujinx.Common.Memory.PartialUnmaps; using System; - +using System.Runtime.InteropServices; using static ARMeilleure.IntermediateRepresentation.Operand.Factory; namespace ARMeilleure.Signal @@ -10,8 +10,28 @@ namespace ARMeilleure.Signal /// /// Methods to handle signals caused by partial unmaps. See the structs for C# implementations of the methods. /// - internal static class WindowsPartialUnmapHandler + internal static partial class WindowsPartialUnmapHandler { + [LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")] + private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName); + + [LibraryImport("kernel32.dll", SetLastError = true)] + private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName); + + private static IntPtr _getCurrentThreadIdPtr; + + public static IntPtr GetCurrentThreadIdFunc() + { + if (_getCurrentThreadIdPtr == IntPtr.Zero) + { + IntPtr handle = LoadLibrary("kernel32.dll"); + + _getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId"); + } + + return _getCurrentThreadIdPtr; + } + public static Operand EmitRetryFromAccessViolation(EmitterContext context) { IntPtr partialRemapStatePtr = PartialUnmapState.GlobalState; @@ -20,7 +40,7 @@ namespace ARMeilleure.Signal // Get the lock first. EmitNativeReaderLockAcquire(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset)); - IntPtr getCurrentThreadId = WindowsSignalHandlerRegistration.GetCurrentThreadIdFunc(); + IntPtr getCurrentThreadId = GetCurrentThreadIdFunc(); Operand threadId = context.Call(Const((ulong)getCurrentThreadId), OperandType.I32); Operand threadIndex = EmitThreadLocalMapIntGetOrReserve(context, localCountsPtr, threadId, Const(0)); @@ -137,17 +157,6 @@ namespace ARMeilleure.Signal return context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset)); } -#pragma warning disable IDE0051 // Remove unused private member - private static void EmitThreadLocalMapIntRelease(EmitterContext context, IntPtr threadLocalMapPtr, Operand threadId, Operand index) - { - Operand offset = context.Multiply(index, Const(sizeof(int))); - Operand idsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap.ThreadIdsOffset)); - Operand idPtr = context.Add(idsPtr, context.SignExtend32(OperandType.I64, offset)); - - context.CompareAndSwap(idPtr, threadId, Const(0)); - } -#pragma warning restore IDE0051 - private static void EmitAtomicAddI32(EmitterContext context, Operand ptr, Operand additive) { Operand loop = Label(); diff --git a/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs b/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs deleted file mode 100644 index 5444da0ca..000000000 --- a/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace ARMeilleure.Signal -{ - unsafe partial class WindowsSignalHandlerRegistration - { - [LibraryImport("kernel32.dll")] - private static partial IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler); - - [LibraryImport("kernel32.dll")] - private static partial ulong RemoveVectoredExceptionHandler(IntPtr handle); - - [LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")] - private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName); - - [LibraryImport("kernel32.dll", SetLastError = true)] - private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName); - - private static IntPtr _getCurrentThreadIdPtr; - - public static IntPtr RegisterExceptionHandler(IntPtr action) - { - return AddVectoredExceptionHandler(1, action); - } - - public static bool RemoveExceptionHandler(IntPtr handle) - { - return RemoveVectoredExceptionHandler(handle) != 0; - } - - public static IntPtr GetCurrentThreadIdFunc() - { - if (_getCurrentThreadIdPtr == IntPtr.Zero) - { - IntPtr handle = LoadLibrary("kernel32.dll"); - - _getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId"); - } - - return _getCurrentThreadIdPtr; - } - } -} diff --git a/src/ARMeilleure/Translation/Cache/JitCache.cs b/src/ARMeilleure/Translation/Cache/JitCache.cs index 862c9e7b5..45f0688bf 100644 --- a/src/ARMeilleure/Translation/Cache/JitCache.cs +++ b/src/ARMeilleure/Translation/Cache/JitCache.cs @@ -117,8 +117,15 @@ namespace ARMeilleure.Translation.Cache if (OperatingSystem.IsIOS()) { Marshal.Copy(code, 0, funcPtr, code.Length); - ReprotectAsExecutable(targetRegion, funcOffset, code.Length); - JitSupportDarwinAot.Invalidate(funcPtr, (ulong)code.Length); + if (deferProtect) + { + _deferredRxProtect.Enqueue((funcOffset, code.Length)); + } + else + { + ReprotectAsExecutable(targetRegion, funcOffset, code.Length); + JitSupportDarwinAot.Invalidate(funcPtr, (ulong)code.Length); + } } else if (OperatingSystem.IsMacOS()&& RuntimeInformation.ProcessArchitecture == Architecture.Arm64) { diff --git a/src/ARMeilleure/Translation/ControlFlowGraph.cs b/src/ARMeilleure/Translation/ControlFlowGraph.cs index 3ead49c93..45b092ec5 100644 --- a/src/ARMeilleure/Translation/ControlFlowGraph.cs +++ b/src/ARMeilleure/Translation/ControlFlowGraph.cs @@ -11,7 +11,7 @@ namespace ARMeilleure.Translation private int[] _postOrderMap; public int LocalsCount { get; private set; } - public BasicBlock Entry { get; } + public BasicBlock Entry { get; private set; } public IntrusiveList Blocks { get; } public BasicBlock[] PostOrderBlocks => _postOrderBlocks; public int[] PostOrderMap => _postOrderMap; @@ -34,6 +34,15 @@ namespace ARMeilleure.Translation return result; } + public void UpdateEntry(BasicBlock newEntry) + { + newEntry.AddSuccessor(Entry); + + Entry = newEntry; + Blocks.AddFirst(newEntry); + Update(); + } + public void Update() { RemoveUnreachableBlocks(Blocks); diff --git a/src/ARMeilleure/Translation/PTC/Ptc.cs b/src/ARMeilleure/Translation/PTC/Ptc.cs index 5ed27927a..a8383ee11 100644 --- a/src/ARMeilleure/Translation/PTC/Ptc.cs +++ b/src/ARMeilleure/Translation/PTC/Ptc.cs @@ -30,7 +30,7 @@ namespace ARMeilleure.Translation.PTC private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0"; - private const uint InternalVersion = 5518; //! To be incremented manually for each change to the ARMeilleure project. + private const uint InternalVersion = 6950; //! To be incremented manually for each change to the ARMeilleure project. private const string ActualDir = "0"; private const string BackupDir = "1"; @@ -858,8 +858,14 @@ namespace ARMeilleure.Translation.PTC Stopwatch sw = Stopwatch.StartNew(); - threads.ForEach((thread) => thread.Start()); - threads.ForEach((thread) => thread.Join()); + foreach (var thread in threads) + { + thread.Start(); + } + foreach (var thread in threads) + { + thread.Join(); + } threads.Clear(); diff --git a/src/ARMeilleure/Translation/RegisterUsage.cs b/src/ARMeilleure/Translation/RegisterUsage.cs index c8c250626..472b0f67b 100644 --- a/src/ARMeilleure/Translation/RegisterUsage.cs +++ b/src/ARMeilleure/Translation/RegisterUsage.cs @@ -89,6 +89,17 @@ namespace ARMeilleure.Translation public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode) { + if (cfg.Entry.Predecessors.Count != 0) + { + // We expect the entry block to have no predecessors. + // This is required because we have a implicit context load at the start of the function, + // but if there is a jump to the start of the function, the context load would trash the modified values. + // Here we insert a new entry block that will jump to the existing entry block. + BasicBlock newEntry = new BasicBlock(cfg.Blocks.Count); + + cfg.UpdateEntry(newEntry); + } + // Compute local register inputs and outputs used inside blocks. RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count]; @@ -201,7 +212,7 @@ namespace ARMeilleure.Translation // The only block without any predecessor should be the entry block. // It always needs a context load as it is the first block to run. - if (block.Predecessors.Count == 0 || hasContextLoad) + if (block == cfg.Entry || hasContextLoad) { long vecMask = globalInputs[block.Index].VecMask; long intMask = globalInputs[block.Index].IntMask; diff --git a/src/ARMeilleure/Translation/Translator.cs b/src/ARMeilleure/Translation/Translator.cs index 253f25e4a..9b28bed53 100644 --- a/src/ARMeilleure/Translation/Translator.cs +++ b/src/ARMeilleure/Translation/Translator.cs @@ -57,9 +57,6 @@ namespace ARMeilleure.Translation private Thread[] _backgroundTranslationThreads; private volatile int _threadCount; - // FIXME: Remove this once the init logic of the emulator will be redone. - public static readonly ManualResetEvent IsReadyForTranslation = new(false); - public Translator(IJitMemoryAllocator allocator, IMemoryManager memory, bool for64Bits) { _allocator = allocator; @@ -79,11 +76,6 @@ namespace ARMeilleure.Translation Stubs = new TranslatorStubs(FunctionTable); FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub; - - if (memory.Type.IsHostMappedOrTracked()) - { - NativeSignalHandler.InitializeSignalHandler(allocator.GetPageSize()); - } } public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled) @@ -105,8 +97,6 @@ namespace ARMeilleure.Translation { if (Interlocked.Increment(ref _threadCount) == 1) { - IsReadyForTranslation.WaitOne(); - if (_ptc.State == PtcState.Enabled) { Debug.Assert(Functions.Count == 0); diff --git a/src/ARMeilleure/Translation/TranslatorQueue.cs b/src/ARMeilleure/Translation/TranslatorQueue.cs index cee2f9080..831522bc1 100644 --- a/src/ARMeilleure/Translation/TranslatorQueue.cs +++ b/src/ARMeilleure/Translation/TranslatorQueue.cs @@ -80,7 +80,10 @@ namespace ARMeilleure.Translation return true; } - Monitor.Wait(Sync); + if (!_disposed) + { + Monitor.Wait(Sync); + } } } diff --git a/src/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceDriver.cs b/src/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceDriver.cs index 744a4bc56..01286992f 100644 --- a/src/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceDriver.cs +++ b/src/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceDriver.cs @@ -20,6 +20,25 @@ namespace Ryujinx.Audio.Backends.OpenAL private bool _stillRunning; private readonly Thread _updaterThread; + private float _volume; + + public float Volume + { + get + { + return _volume; + } + set + { + _volume = value; + + foreach (OpenALHardwareDeviceSession session in _sessions.Keys) + { + session.UpdateMasterVolume(value); + } + } + } + public OpenALHardwareDeviceDriver() { _device = ALC.OpenDevice(""); @@ -34,6 +53,8 @@ namespace Ryujinx.Audio.Backends.OpenAL Name = "HardwareDeviceDriver.OpenAL", }; + _volume = 1f; + _updaterThread.Start(); } @@ -52,7 +73,7 @@ namespace Ryujinx.Audio.Backends.OpenAL } } - public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume) + public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount) { if (channelCount == 0) { @@ -73,7 +94,7 @@ namespace Ryujinx.Audio.Backends.OpenAL throw new ArgumentException($"{channelCount}"); } - OpenALHardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount, volume); + OpenALHardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount); _sessions.TryAdd(session, 0); diff --git a/src/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceSession.cs b/src/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceSession.cs index 73e914083..ff35f86e1 100644 --- a/src/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceSession.cs +++ b/src/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceSession.cs @@ -16,10 +16,11 @@ namespace Ryujinx.Audio.Backends.OpenAL private bool _isActive; private readonly Queue _queuedBuffers; private ulong _playedSampleCount; + private float _volume; private readonly object _lock = new(); - public OpenALHardwareDeviceSession(OpenALHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) + public OpenALHardwareDeviceSession(OpenALHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) { _driver = driver; _queuedBuffers = new Queue(); @@ -27,7 +28,7 @@ namespace Ryujinx.Audio.Backends.OpenAL _targetFormat = GetALFormat(); _isActive = false; _playedSampleCount = 0; - SetVolume(requestedVolume); + SetVolume(1f); } private ALFormat GetALFormat() @@ -85,17 +86,22 @@ namespace Ryujinx.Audio.Backends.OpenAL public override void SetVolume(float volume) { - lock (_lock) - { - AL.Source(_sourceId, ALSourcef.Gain, volume); - } + _volume = volume; + + UpdateMasterVolume(_driver.Volume); } public override float GetVolume() { - AL.GetSource(_sourceId, ALSourcef.Gain, out float volume); + return _volume; + } - return volume; + public void UpdateMasterVolume(float newVolume) + { + lock (_lock) + { + AL.Source(_sourceId, ALSourcef.Gain, newVolume * _volume); + } } public override void Start() diff --git a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs b/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs index 58137bb38..03a036936 100644 --- a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs +++ b/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs @@ -20,6 +20,8 @@ namespace Ryujinx.Audio.Backends.SDL2 private readonly bool _supportSurroundConfiguration; + public float Volume { get; set; } + // TODO: Add this to SDL2-CS // NOTE: We use a DllImport here because of marshaling issue for spec. #pragma warning disable SYSLIB1054 @@ -48,6 +50,8 @@ namespace Ryujinx.Audio.Backends.SDL2 { _supportSurroundConfiguration = spec.channels >= 6; } + + Volume = 1f; } public static bool IsSupported => IsSupportedInternal(); @@ -74,7 +78,7 @@ namespace Ryujinx.Audio.Backends.SDL2 return _pauseEvent; } - public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume) + public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount) { if (channelCount == 0) { @@ -91,7 +95,7 @@ namespace Ryujinx.Audio.Backends.SDL2 throw new NotImplementedException("Input direction is currently not implemented on SDL2 backend!"); } - SDL2HardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount, volume); + SDL2HardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount); _sessions.TryAdd(session, 0); diff --git a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceSession.cs b/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceSession.cs index cf3be473e..ea5ae3661 100644 --- a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceSession.cs +++ b/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceSession.cs @@ -1,8 +1,10 @@ using Ryujinx.Audio.Backends.Common; using Ryujinx.Audio.Common; using Ryujinx.Common.Logging; +using Ryujinx.Common.Memory; using Ryujinx.Memory; using System; +using System.Buffers; using System.Collections.Concurrent; using System.Threading; @@ -26,7 +28,7 @@ namespace Ryujinx.Audio.Backends.SDL2 private float _volume; private readonly ushort _nativeSampleFormat; - public SDL2HardwareDeviceSession(SDL2HardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) + public SDL2HardwareDeviceSession(SDL2HardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) { _driver = driver; _updateRequiredEvent = _driver.GetUpdateRequiredEvent(); @@ -37,7 +39,7 @@ namespace Ryujinx.Audio.Backends.SDL2 _nativeSampleFormat = SDL2HardwareDeviceDriver.GetSDL2Format(RequestedSampleFormat); _sampleCount = uint.MaxValue; _started = false; - _volume = requestedVolume; + _volume = 1f; } private void EnsureAudioStreamSetup(AudioBuffer buffer) @@ -87,7 +89,9 @@ namespace Ryujinx.Audio.Backends.SDL2 return; } - byte[] samples = new byte[frameCount * _bytesPerFrame]; + using SpanOwner samplesOwner = SpanOwner.Rent(frameCount * _bytesPerFrame); + + Span samples = samplesOwner.Span; _ringBuffer.Read(samples, 0, samples.Length); @@ -99,7 +103,7 @@ namespace Ryujinx.Audio.Backends.SDL2 streamSpan.Clear(); // Apply volume to written data - SDL_MixAudioFormat(stream, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, (int)(_volume * SDL_MIX_MAXVOLUME)); + SDL_MixAudioFormat(stream, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, (int)(_driver.Volume * _volume * SDL_MIX_MAXVOLUME)); } ulong sampleCount = GetSampleCount(samples.Length); diff --git a/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj b/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj index 1d92d9d2e..5c9423463 100644 --- a/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj +++ b/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj @@ -11,15 +11,15 @@ - + PreserveNewest libsoundio.dll - + PreserveNewest libsoundio.dylib - + PreserveNewest libsoundio.so diff --git a/src/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs b/src/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs index ff0392882..e3e5d2913 100644 --- a/src/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs +++ b/src/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs @@ -19,6 +19,25 @@ namespace Ryujinx.Audio.Backends.SoundIo private readonly ConcurrentDictionary _sessions; private int _disposeState; + private float _volume = 1f; + + public float Volume + { + get + { + return _volume; + } + set + { + _volume = value; + + foreach (SoundIoHardwareDeviceSession session in _sessions.Keys) + { + session.UpdateMasterVolume(value); + } + } + } + public SoundIoHardwareDeviceDriver() { _audioContext = SoundIoContext.Create(); @@ -122,7 +141,7 @@ namespace Ryujinx.Audio.Backends.SoundIo return _pauseEvent; } - public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume) + public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount) { if (channelCount == 0) { @@ -134,14 +153,12 @@ namespace Ryujinx.Audio.Backends.SoundIo sampleRate = Constants.TargetSampleRate; } - volume = Math.Clamp(volume, 0, 1); - if (direction != Direction.Output) { throw new NotImplementedException("Input direction is currently not implemented on SoundIO backend!"); } - SoundIoHardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount, volume); + SoundIoHardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount); _sessions.TryAdd(session, 0); diff --git a/src/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs b/src/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs index b9070dc48..2ef83b34b 100644 --- a/src/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs +++ b/src/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs @@ -1,8 +1,10 @@ using Ryujinx.Audio.Backends.Common; using Ryujinx.Audio.Backends.SoundIo.Native; using Ryujinx.Audio.Common; +using Ryujinx.Common.Memory; using Ryujinx.Memory; using System; +using System.Buffers; using System.Collections.Concurrent; using System.Runtime.CompilerServices; using System.Threading; @@ -18,16 +20,18 @@ namespace Ryujinx.Audio.Backends.SoundIo private readonly DynamicRingBuffer _ringBuffer; private ulong _playedSampleCount; private readonly ManualResetEvent _updateRequiredEvent; + private float _volume; private int _disposeState; - public SoundIoHardwareDeviceSession(SoundIoHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) + public SoundIoHardwareDeviceSession(SoundIoHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) { _driver = driver; _updateRequiredEvent = _driver.GetUpdateRequiredEvent(); _queuedBuffers = new ConcurrentQueue(); _ringBuffer = new DynamicRingBuffer(); + _volume = 1f; - SetupOutputStream(requestedVolume); + SetupOutputStream(driver.Volume); } private void SetupOutputStream(float requestedVolume) @@ -35,7 +39,7 @@ namespace Ryujinx.Audio.Backends.SoundIo _outputStream = _driver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount); _outputStream.WriteCallback += Update; _outputStream.Volume = requestedVolume; - // TODO: Setup other callbacks (errors, ect). + // TODO: Setup other callbacks (errors, etc.) _outputStream.Open(); } @@ -47,7 +51,7 @@ namespace Ryujinx.Audio.Backends.SoundIo public override float GetVolume() { - return _outputStream.Volume; + return _volume; } public override void PrepareToClose() { } @@ -63,7 +67,14 @@ namespace Ryujinx.Audio.Backends.SoundIo public override void SetVolume(float volume) { - _outputStream.SetVolume(volume); + _volume = volume; + + _outputStream.SetVolume(_driver.Volume * volume); + } + + public void UpdateMasterVolume(float newVolume) + { + _outputStream.SetVolume(newVolume * _volume); } public override void Start() @@ -111,7 +122,9 @@ namespace Ryujinx.Audio.Backends.SoundIo int channelCount = areas.Length; - byte[] samples = new byte[frameCount * bytesPerFrame]; + using SpanOwner samplesOwner = SpanOwner.Rent(frameCount * bytesPerFrame); + + Span samples = samplesOwner.Span; _ringBuffer.Read(samples, 0, samples.Length); diff --git a/src/Ryujinx.Audio/Backends/Common/DynamicRingBuffer.cs b/src/Ryujinx.Audio/Backends/Common/DynamicRingBuffer.cs index 05dd2162a..7aefe8865 100644 --- a/src/Ryujinx.Audio/Backends/Common/DynamicRingBuffer.cs +++ b/src/Ryujinx.Audio/Backends/Common/DynamicRingBuffer.cs @@ -1,5 +1,7 @@ using Ryujinx.Common; +using Ryujinx.Common.Memory; using System; +using System.Buffers; namespace Ryujinx.Audio.Backends.Common { @@ -12,7 +14,8 @@ namespace Ryujinx.Audio.Backends.Common private readonly object _lock = new(); - private byte[] _buffer; + private MemoryOwner _bufferOwner; + private Memory _buffer; private int _size; private int _headOffset; private int _tailOffset; @@ -21,7 +24,8 @@ namespace Ryujinx.Audio.Backends.Common public DynamicRingBuffer(int initialCapacity = RingBufferAlignment) { - _buffer = new byte[initialCapacity]; + _bufferOwner = MemoryOwner.RentCleared(initialCapacity); + _buffer = _bufferOwner.Memory; } public void Clear() @@ -33,6 +37,11 @@ namespace Ryujinx.Audio.Backends.Common public void Clear(int size) { + if (size == 0) + { + return; + } + lock (_lock) { if (size > _size) @@ -40,11 +49,6 @@ namespace Ryujinx.Audio.Backends.Common size = _size; } - if (size == 0) - { - return; - } - _headOffset = (_headOffset + size) % _buffer.Length; _size -= size; @@ -58,28 +62,31 @@ namespace Ryujinx.Audio.Backends.Common private void SetCapacityLocked(int capacity) { - byte[] buffer = new byte[capacity]; + MemoryOwner newBufferOwner = MemoryOwner.RentCleared(capacity); + Memory newBuffer = newBufferOwner.Memory; if (_size > 0) { if (_headOffset < _tailOffset) { - Buffer.BlockCopy(_buffer, _headOffset, buffer, 0, _size); + _buffer.Slice(_headOffset, _size).CopyTo(newBuffer); } else { - Buffer.BlockCopy(_buffer, _headOffset, buffer, 0, _buffer.Length - _headOffset); - Buffer.BlockCopy(_buffer, 0, buffer, _buffer.Length - _headOffset, _tailOffset); + _buffer[_headOffset..].CopyTo(newBuffer); + _buffer[.._tailOffset].CopyTo(newBuffer[(_buffer.Length - _headOffset)..]); } } - _buffer = buffer; + _bufferOwner.Dispose(); + + _bufferOwner = newBufferOwner; + _buffer = newBuffer; _headOffset = 0; _tailOffset = _size; } - - public void Write(T[] buffer, int index, int count) + public void Write(ReadOnlySpan buffer, int index, int count) { if (count == 0) { @@ -99,17 +106,17 @@ namespace Ryujinx.Audio.Backends.Common if (tailLength >= count) { - Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, count); + buffer.Slice(index, count).CopyTo(_buffer.Span[_tailOffset..]); } else { - Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, tailLength); - Buffer.BlockCopy(buffer, index + tailLength, _buffer, 0, count - tailLength); + buffer.Slice(index, tailLength).CopyTo(_buffer.Span[_tailOffset..]); + buffer.Slice(index + tailLength, count - tailLength).CopyTo(_buffer.Span); } } else { - Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, count); + buffer.Slice(index, count).CopyTo(_buffer.Span[_tailOffset..]); } _size += count; @@ -117,8 +124,13 @@ namespace Ryujinx.Audio.Backends.Common } } - public int Read(T[] buffer, int index, int count) + public int Read(Span buffer, int index, int count) { + if (count == 0) + { + return 0; + } + lock (_lock) { if (count > _size) @@ -126,14 +138,9 @@ namespace Ryujinx.Audio.Backends.Common count = _size; } - if (count == 0) - { - return 0; - } - if (_headOffset < _tailOffset) { - Buffer.BlockCopy(_buffer, _headOffset, buffer, index, count); + _buffer.Span.Slice(_headOffset, count).CopyTo(buffer[index..]); } else { @@ -141,12 +148,12 @@ namespace Ryujinx.Audio.Backends.Common if (tailLength >= count) { - Buffer.BlockCopy(_buffer, _headOffset, buffer, index, count); + _buffer.Span.Slice(_headOffset, count).CopyTo(buffer[index..]); } else { - Buffer.BlockCopy(_buffer, _headOffset, buffer, index, tailLength); - Buffer.BlockCopy(_buffer, 0, buffer, index + tailLength, count - tailLength); + _buffer.Span.Slice(_headOffset, tailLength).CopyTo(buffer[index..]); + _buffer.Span[..(count - tailLength)].CopyTo(buffer[(index + tailLength)..]); } } diff --git a/src/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs b/src/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs index 3f3806c3e..a2c2cdcd0 100644 --- a/src/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs +++ b/src/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs @@ -16,6 +16,12 @@ namespace Ryujinx.Audio.Backends.CompatLayer public static bool IsSupported => true; + public float Volume + { + get => _realDriver.Volume; + set => _realDriver.Volume = value; + } + public CompatLayerHardwareDeviceDriver(IHardwareDeviceDriver realDevice) { _realDriver = realDevice; @@ -90,7 +96,7 @@ namespace Ryujinx.Audio.Backends.CompatLayer throw new ArgumentException("No valid sample format configuration found!"); } - public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume) + public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount) { if (channelCount == 0) { @@ -102,8 +108,6 @@ namespace Ryujinx.Audio.Backends.CompatLayer sampleRate = Constants.TargetSampleRate; } - volume = Math.Clamp(volume, 0, 1); - if (!_realDriver.SupportsDirection(direction)) { if (direction == Direction.Input) @@ -119,7 +123,7 @@ namespace Ryujinx.Audio.Backends.CompatLayer SampleFormat hardwareSampleFormat = SelectHardwareSampleFormat(sampleFormat); uint hardwareChannelCount = SelectHardwareChannelCount(channelCount); - IHardwareDeviceSession realSession = _realDriver.OpenDeviceSession(direction, memoryManager, hardwareSampleFormat, sampleRate, hardwareChannelCount, volume); + IHardwareDeviceSession realSession = _realDriver.OpenDeviceSession(direction, memoryManager, hardwareSampleFormat, sampleRate, hardwareChannelCount); if (hardwareChannelCount == channelCount && hardwareSampleFormat == sampleFormat) { diff --git a/src/Ryujinx.Audio/Backends/CompatLayer/Downmixing.cs b/src/Ryujinx.Audio/Backends/CompatLayer/Downmixing.cs index ffd427a5e..7a5ea0deb 100644 --- a/src/Ryujinx.Audio/Backends/CompatLayer/Downmixing.cs +++ b/src/Ryujinx.Audio/Backends/CompatLayer/Downmixing.cs @@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Backends.CompatLayer private const int Minus6dBInQ15 = (int)(0.501f * RawQ15One); private const int Minus12dBInQ15 = (int)(0.251f * RawQ15One); - private static readonly int[] _defaultSurroundToStereoCoefficients = new int[4] + private static readonly long[] _defaultSurroundToStereoCoefficients = new long[4] { RawQ15One, Minus3dBInQ15, @@ -39,7 +39,7 @@ namespace Ryujinx.Audio.Backends.CompatLayer Minus3dBInQ15, }; - private static readonly int[] _defaultStereoToMonoCoefficients = new int[2] + private static readonly long[] _defaultStereoToMonoCoefficients = new long[2] { Minus6dBInQ15, Minus6dBInQ15, @@ -62,19 +62,23 @@ namespace Ryujinx.Audio.Backends.CompatLayer } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static short DownMixStereoToMono(ReadOnlySpan coefficients, short left, short right) + private static short DownMixStereoToMono(ReadOnlySpan coefficients, short left, short right) { - return (short)((left * coefficients[0] + right * coefficients[1]) >> Q15Bits); + return (short)Math.Clamp((left * coefficients[0] + right * coefficients[1]) >> Q15Bits, short.MinValue, short.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static short DownMixSurroundToStereo(ReadOnlySpan coefficients, short back, short lfe, short center, short front) + private static short DownMixSurroundToStereo(ReadOnlySpan coefficients, short back, short lfe, short center, short front) { - return (short)((coefficients[3] * back + coefficients[2] * lfe + coefficients[1] * center + coefficients[0] * front + RawQ15HalfOne) >> Q15Bits); + return (short)Math.Clamp( + (coefficients[3] * back + + coefficients[2] * lfe + + coefficients[1] * center + + coefficients[0] * front + RawQ15HalfOne) >> Q15Bits, short.MinValue, short.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static short[] DownMixSurroundToStereo(ReadOnlySpan coefficients, ReadOnlySpan data) + private static short[] DownMixSurroundToStereo(ReadOnlySpan coefficients, ReadOnlySpan data) { int samplePerChannelCount = data.Length / SurroundChannelCount; @@ -94,7 +98,7 @@ namespace Ryujinx.Audio.Backends.CompatLayer } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static short[] DownMixStereoToMono(ReadOnlySpan coefficients, ReadOnlySpan data) + private static short[] DownMixStereoToMono(ReadOnlySpan coefficients, ReadOnlySpan data) { int samplePerChannelCount = data.Length / StereoChannelCount; diff --git a/src/Ryujinx.Audio/Backends/DelayLayer/DelayLayerHardwareDeviceDriver.cs b/src/Ryujinx.Audio/Backends/DelayLayer/DelayLayerHardwareDeviceDriver.cs index cdd5eb8a8..b46b38f5a 100644 --- a/src/Ryujinx.Audio/Backends/DelayLayer/DelayLayerHardwareDeviceDriver.cs +++ b/src/Ryujinx.Audio/Backends/DelayLayer/DelayLayerHardwareDeviceDriver.cs @@ -16,15 +16,17 @@ namespace Ryujinx.Audio.Backends.DelayLayer public ulong SampleDelay48k; + public float Volume { get; set; } + public DelayLayerHardwareDeviceDriver(IHardwareDeviceDriver realDevice, ulong sampleDelay48k) { _realDriver = realDevice; SampleDelay48k = sampleDelay48k; } - public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume) + public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount) { - IHardwareDeviceSession session = _realDriver.OpenDeviceSession(direction, memoryManager, sampleFormat, sampleRate, channelCount, volume); + IHardwareDeviceSession session = _realDriver.OpenDeviceSession(direction, memoryManager, sampleFormat, sampleRate, channelCount); if (direction == Direction.Output) { diff --git a/src/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceDriver.cs b/src/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceDriver.cs index bac21c448..3a3c1d1b1 100644 --- a/src/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceDriver.cs +++ b/src/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceDriver.cs @@ -14,13 +14,17 @@ namespace Ryujinx.Audio.Backends.Dummy public static bool IsSupported => true; + public float Volume { get; set; } + public DummyHardwareDeviceDriver() { _updateRequiredEvent = new ManualResetEvent(false); _pauseEvent = new ManualResetEvent(true); + + Volume = 1f; } - public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume) + public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount) { if (sampleRate == 0) { @@ -34,7 +38,7 @@ namespace Ryujinx.Audio.Backends.Dummy if (direction == Direction.Output) { - return new DummyHardwareDeviceSessionOutput(this, memoryManager, sampleFormat, sampleRate, channelCount, volume); + return new DummyHardwareDeviceSessionOutput(this, memoryManager, sampleFormat, sampleRate, channelCount); } return new DummyHardwareDeviceSessionInput(this, memoryManager); diff --git a/src/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceSessionOutput.cs b/src/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceSessionOutput.cs index 1c248faaa..34cf653c2 100644 --- a/src/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceSessionOutput.cs +++ b/src/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceSessionOutput.cs @@ -13,9 +13,9 @@ namespace Ryujinx.Audio.Backends.Dummy private ulong _playedSampleCount; - public DummyHardwareDeviceSessionOutput(IHardwareDeviceDriver manager, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) + public DummyHardwareDeviceSessionOutput(IHardwareDeviceDriver manager, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) { - _volume = requestedVolume; + _volume = 1f; _manager = manager; } diff --git a/src/Ryujinx.Audio/Input/AudioInputManager.cs b/src/Ryujinx.Audio/Input/AudioInputManager.cs index 4d1796c96..d56997e9c 100644 --- a/src/Ryujinx.Audio/Input/AudioInputManager.cs +++ b/src/Ryujinx.Audio/Input/AudioInputManager.cs @@ -166,7 +166,6 @@ namespace Ryujinx.Audio.Input /// /// If true, filter disconnected devices /// The list of all audio inputs name -#pragma warning disable CA1822 // Mark member as static public string[] ListAudioIns(bool filtered) { if (filtered) @@ -176,7 +175,6 @@ namespace Ryujinx.Audio.Input return new[] { Constants.DefaultDeviceInputName }; } -#pragma warning restore CA1822 /// /// Open a new . @@ -188,8 +186,6 @@ namespace Ryujinx.Audio.Input /// The input device name wanted by the user /// The sample format to use /// The user configuration - /// The applet resource user id of the application - /// The process handle of the application /// A reporting an error or a success public ResultCode OpenAudioIn(out string outputDeviceName, out AudioOutputConfiguration outputConfiguration, @@ -197,9 +193,7 @@ namespace Ryujinx.Audio.Input IVirtualMemoryManager memoryManager, string inputDeviceName, SampleFormat sampleFormat, - ref AudioInputConfiguration parameter, - ulong appletResourceUserId, - uint processHandle) + ref AudioInputConfiguration parameter) { int sessionId = AcquireSessionId(); diff --git a/src/Ryujinx.Audio/Integration/HardwareDeviceImpl.cs b/src/Ryujinx.Audio/Integration/HardwareDeviceImpl.cs index 576954b96..1369f953a 100644 --- a/src/Ryujinx.Audio/Integration/HardwareDeviceImpl.cs +++ b/src/Ryujinx.Audio/Integration/HardwareDeviceImpl.cs @@ -13,9 +13,9 @@ namespace Ryujinx.Audio.Integration private readonly byte[] _buffer; - public HardwareDeviceImpl(IHardwareDeviceDriver deviceDriver, uint channelCount, uint sampleRate, float volume) + public HardwareDeviceImpl(IHardwareDeviceDriver deviceDriver, uint channelCount, uint sampleRate) { - _session = deviceDriver.OpenDeviceSession(IHardwareDeviceDriver.Direction.Output, null, SampleFormat.PcmInt16, sampleRate, channelCount, volume); + _session = deviceDriver.OpenDeviceSession(IHardwareDeviceDriver.Direction.Output, null, SampleFormat.PcmInt16, sampleRate, channelCount); _channelCount = channelCount; _sampleRate = sampleRate; _currentBufferTag = 0; diff --git a/src/Ryujinx.Audio/Integration/IHardwareDeviceDriver.cs b/src/Ryujinx.Audio/Integration/IHardwareDeviceDriver.cs index 9c812fb9a..95b0e4e5e 100644 --- a/src/Ryujinx.Audio/Integration/IHardwareDeviceDriver.cs +++ b/src/Ryujinx.Audio/Integration/IHardwareDeviceDriver.cs @@ -16,7 +16,9 @@ namespace Ryujinx.Audio.Integration Output, } - IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume = 1f); + float Volume { get; set; } + + IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount); ManualResetEvent GetUpdateRequiredEvent(); ManualResetEvent GetPauseEvent(); diff --git a/src/Ryujinx.Audio/Output/AudioOutputManager.cs b/src/Ryujinx.Audio/Output/AudioOutputManager.cs index 5232357bb..308cd1564 100644 --- a/src/Ryujinx.Audio/Output/AudioOutputManager.cs +++ b/src/Ryujinx.Audio/Output/AudioOutputManager.cs @@ -165,12 +165,10 @@ namespace Ryujinx.Audio.Output /// Get the list of all audio outputs name. /// /// The list of all audio outputs name -#pragma warning disable CA1822 // Mark member as static public string[] ListAudioOuts() { return new[] { Constants.DefaultDeviceOutputName }; } -#pragma warning restore CA1822 /// /// Open a new . @@ -182,9 +180,6 @@ namespace Ryujinx.Audio.Output /// The input device name wanted by the user /// The sample format to use /// The user configuration - /// The applet resource user id of the application - /// The process handle of the application - /// The volume level to request /// A reporting an error or a success public ResultCode OpenAudioOut(out string outputDeviceName, out AudioOutputConfiguration outputConfiguration, @@ -192,16 +187,13 @@ namespace Ryujinx.Audio.Output IVirtualMemoryManager memoryManager, string inputDeviceName, SampleFormat sampleFormat, - ref AudioInputConfiguration parameter, - ulong appletResourceUserId, - uint processHandle, - float volume) + ref AudioInputConfiguration parameter) { int sessionId = AcquireSessionId(); _sessionsBufferEvents[sessionId].Clear(); - IHardwareDeviceSession deviceSession = _deviceDriver.OpenDeviceSession(IHardwareDeviceDriver.Direction.Output, memoryManager, sampleFormat, parameter.SampleRate, parameter.ChannelCount, volume); + IHardwareDeviceSession deviceSession = _deviceDriver.OpenDeviceSession(IHardwareDeviceDriver.Direction.Output, memoryManager, sampleFormat, parameter.SampleRate, parameter.ChannelCount); AudioOutputSystem audioOut = new(this, _lock, deviceSession, _sessionsBufferEvents[sessionId]); @@ -234,41 +226,6 @@ namespace Ryujinx.Audio.Output return result; } - /// - /// Sets the volume for all output devices. - /// - /// The volume to set. - public void SetVolume(float volume) - { - if (_sessions != null) - { - foreach (AudioOutputSystem session in _sessions) - { - session?.SetVolume(volume); - } - } - } - - /// - /// Gets the volume for all output devices. - /// - /// A float indicating the volume level. - public float GetVolume() - { - if (_sessions != null) - { - foreach (AudioOutputSystem session in _sessions) - { - if (session != null) - { - return session.GetVolume(); - } - } - } - - return 0.0f; - } - public void Dispose() { GC.SuppressFinalize(this); diff --git a/src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs b/src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs index b0963c935..3b8d15dc5 100644 --- a/src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs +++ b/src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs @@ -25,7 +25,7 @@ namespace Ryujinx.Audio.Renderer.Common public ulong Flags; /// - /// Represents an error during . + /// Represents an error during . /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct ErrorInfo diff --git a/src/Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs b/src/Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs index 7efe3b02b..98b224ebf 100644 --- a/src/Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs +++ b/src/Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs @@ -4,7 +4,7 @@ using System.Runtime.CompilerServices; namespace Ryujinx.Audio.Renderer.Common { /// - /// Update data header used for input and output of . + /// Update data header used for input and output of . /// public struct UpdateDataHeader { diff --git a/src/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs b/src/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs index 608381af1..7f881373f 100644 --- a/src/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs +++ b/src/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs @@ -15,7 +15,6 @@ namespace Ryujinx.Audio.Renderer.Common { public const int Align = 0x10; public const int BiquadStateOffset = 0x0; - public const int BiquadStateSize = 0x10; /// /// The state of the biquad filters of this voice. diff --git a/src/Ryujinx.Audio/Renderer/Dsp/AudioProcessor.cs b/src/Ryujinx.Audio/Renderer/Dsp/AudioProcessor.cs index 9c885b2cf..3e11df056 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/AudioProcessor.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/AudioProcessor.cs @@ -45,7 +45,6 @@ namespace Ryujinx.Audio.Renderer.Dsp _event = new ManualResetEvent(false); } -#pragma warning disable IDE0051 // Remove unused private member private static uint GetHardwareChannelCount(IHardwareDeviceDriver deviceDriver) { // Get the real device driver (In case the compat layer is on top of it). @@ -59,9 +58,8 @@ namespace Ryujinx.Audio.Renderer.Dsp // NOTE: We default to stereo as this will get downmixed to mono by the compat layer if it's not compatible. return 2; } -#pragma warning restore IDE0051 - public void Start(IHardwareDeviceDriver deviceDriver, float volume) + public void Start(IHardwareDeviceDriver deviceDriver) { OutputDevices = new IHardwareDevice[Constants.AudioRendererSessionCountMax]; @@ -70,7 +68,7 @@ namespace Ryujinx.Audio.Renderer.Dsp for (int i = 0; i < OutputDevices.Length; i++) { // TODO: Don't hardcode sample rate. - OutputDevices[i] = new HardwareDeviceImpl(deviceDriver, channelCount, Constants.TargetSampleRate, volume); + OutputDevices[i] = new HardwareDeviceImpl(deviceDriver, channelCount, Constants.TargetSampleRate); } _mailbox = new Mailbox(); @@ -231,33 +229,6 @@ namespace Ryujinx.Audio.Renderer.Dsp _mailbox.SendResponse(MailboxMessage.Stop); } - public float GetVolume() - { - if (OutputDevices != null) - { - foreach (IHardwareDevice outputDevice in OutputDevices) - { - if (outputDevice != null) - { - return outputDevice.GetVolume(); - } - } - } - - return 0f; - } - - public void SetVolume(float volume) - { - if (OutputDevices != null) - { - foreach (IHardwareDevice outputDevice in OutputDevices) - { - outputDevice?.SetVolume(volume); - } - } - } - public void Dispose() { GC.SuppressFinalize(this); @@ -269,6 +240,7 @@ namespace Ryujinx.Audio.Renderer.Dsp if (disposing) { _event.Dispose(); + _mailbox?.Dispose(); } } } diff --git a/src/Ryujinx.Audio/Renderer/Dsp/BiquadFilterHelper.cs b/src/Ryujinx.Audio/Renderer/Dsp/BiquadFilterHelper.cs index 1a51a1fbd..31f614d67 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/BiquadFilterHelper.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/BiquadFilterHelper.cs @@ -16,10 +16,15 @@ namespace Ryujinx.Audio.Renderer.Dsp /// The biquad filter parameter /// The biquad filter state /// The output buffer to write the result - /// The input buffer to write the result + /// The input buffer to read the samples from /// The count of samples to process [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ProcessBiquadFilter(ref BiquadFilterParameter parameter, ref BiquadFilterState state, Span outputBuffer, ReadOnlySpan inputBuffer, uint sampleCount) + public static void ProcessBiquadFilter( + ref BiquadFilterParameter parameter, + ref BiquadFilterState state, + Span outputBuffer, + ReadOnlySpan inputBuffer, + uint sampleCount) { float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter); float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter); @@ -40,6 +45,96 @@ namespace Ryujinx.Audio.Renderer.Dsp } } + /// + /// Apply a single biquad filter and mix the result into the output buffer. + /// + /// This is implemented with a direct form 1. + /// The biquad filter parameter + /// The biquad filter state + /// The output buffer to write the result + /// The input buffer to read the samples from + /// The count of samples to process + /// Mix volume + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ProcessBiquadFilterAndMix( + ref BiquadFilterParameter parameter, + ref BiquadFilterState state, + Span outputBuffer, + ReadOnlySpan inputBuffer, + uint sampleCount, + float volume) + { + float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter); + float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter); + float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter); + + float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter); + float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter); + + for (int i = 0; i < sampleCount; i++) + { + float input = inputBuffer[i]; + float output = input * a0 + state.State0 * a1 + state.State1 * a2 + state.State2 * b1 + state.State3 * b2; + + state.State1 = state.State0; + state.State0 = input; + state.State3 = state.State2; + state.State2 = output; + + outputBuffer[i] += FloatingPointHelper.MultiplyRoundUp(output, volume); + } + } + + /// + /// Apply a single biquad filter and mix the result into the output buffer with volume ramp. + /// + /// This is implemented with a direct form 1. + /// The biquad filter parameter + /// The biquad filter state + /// The output buffer to write the result + /// The input buffer to read the samples from + /// The count of samples to process + /// Initial mix volume + /// Volume increment step + /// Last filtered sample value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float ProcessBiquadFilterAndMixRamp( + ref BiquadFilterParameter parameter, + ref BiquadFilterState state, + Span outputBuffer, + ReadOnlySpan inputBuffer, + uint sampleCount, + float volume, + float ramp) + { + float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter); + float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter); + float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter); + + float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter); + float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter); + + float mixState = 0f; + + for (int i = 0; i < sampleCount; i++) + { + float input = inputBuffer[i]; + float output = input * a0 + state.State0 * a1 + state.State1 * a2 + state.State2 * b1 + state.State3 * b2; + + state.State1 = state.State0; + state.State0 = input; + state.State3 = state.State2; + state.State2 = output; + + mixState = FloatingPointHelper.MultiplyRoundUp(output, volume); + + outputBuffer[i] += mixState; + volume += ramp; + } + + return mixState; + } + /// /// Apply multiple biquad filter. /// @@ -47,10 +142,15 @@ namespace Ryujinx.Audio.Renderer.Dsp /// The biquad filter parameter /// The biquad filter state /// The output buffer to write the result - /// The input buffer to write the result + /// The input buffer to read the samples from /// The count of samples to process [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ProcessBiquadFilter(ReadOnlySpan parameters, Span states, Span outputBuffer, ReadOnlySpan inputBuffer, uint sampleCount) + public static void ProcessBiquadFilter( + ReadOnlySpan parameters, + Span states, + Span outputBuffer, + ReadOnlySpan inputBuffer, + uint sampleCount) { for (int stageIndex = 0; stageIndex < parameters.Length; stageIndex++) { @@ -67,7 +167,7 @@ namespace Ryujinx.Audio.Renderer.Dsp for (int i = 0; i < sampleCount; i++) { - float input = inputBuffer[i]; + float input = stageIndex != 0 ? outputBuffer[i] : inputBuffer[i]; float output = input * a0 + state.State0 * a1 + state.State1 * a2 + state.State2 * b1 + state.State3 * b2; state.State1 = state.State0; @@ -79,5 +179,129 @@ namespace Ryujinx.Audio.Renderer.Dsp } } } + + /// + /// Apply double biquad filter and mix the result into the output buffer. + /// + /// This is implemented with a direct form 1. + /// The biquad filter parameter + /// The biquad filter state + /// The output buffer to write the result + /// The input buffer to read the samples from + /// The count of samples to process + /// Mix volume + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ProcessDoubleBiquadFilterAndMix( + ref BiquadFilterParameter parameter0, + ref BiquadFilterParameter parameter1, + ref BiquadFilterState state0, + ref BiquadFilterState state1, + Span outputBuffer, + ReadOnlySpan inputBuffer, + uint sampleCount, + float volume) + { + float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter); + float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter); + float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter); + + float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter); + float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter); + + float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter); + float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter); + float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter); + + float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter); + float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter); + + for (int i = 0; i < sampleCount; i++) + { + float input = inputBuffer[i]; + float output = input * a00 + state0.State0 * a10 + state0.State1 * a20 + state0.State2 * b10 + state0.State3 * b20; + + state0.State1 = state0.State0; + state0.State0 = input; + state0.State3 = state0.State2; + state0.State2 = output; + + input = output; + output = input * a01 + state1.State0 * a11 + state1.State1 * a21 + state1.State2 * b11 + state1.State3 * b21; + + state1.State1 = state1.State0; + state1.State0 = input; + state1.State3 = state1.State2; + state1.State2 = output; + + outputBuffer[i] += FloatingPointHelper.MultiplyRoundUp(output, volume); + } + } + + /// + /// Apply double biquad filter and mix the result into the output buffer with volume ramp. + /// + /// This is implemented with a direct form 1. + /// The biquad filter parameter + /// The biquad filter state + /// The output buffer to write the result + /// The input buffer to read the samples from + /// The count of samples to process + /// Initial mix volume + /// Volume increment step + /// Last filtered sample value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float ProcessDoubleBiquadFilterAndMixRamp( + ref BiquadFilterParameter parameter0, + ref BiquadFilterParameter parameter1, + ref BiquadFilterState state0, + ref BiquadFilterState state1, + Span outputBuffer, + ReadOnlySpan inputBuffer, + uint sampleCount, + float volume, + float ramp) + { + float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter); + float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter); + float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter); + + float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter); + float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter); + + float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter); + float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter); + float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter); + + float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter); + float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter); + + float mixState = 0f; + + for (int i = 0; i < sampleCount; i++) + { + float input = inputBuffer[i]; + float output = input * a00 + state0.State0 * a10 + state0.State1 * a20 + state0.State2 * b10 + state0.State3 * b20; + + state0.State1 = state0.State0; + state0.State0 = input; + state0.State3 = state0.State2; + state0.State2 = output; + + input = output; + output = input * a01 + state1.State0 * a11 + state1.State1 * a21 + state1.State2 * b11 + state1.State3 * b21; + + state1.State1 = state1.State0; + state1.State0 = input; + state1.State3 = state1.State2; + state1.State2 = output; + + mixState = FloatingPointHelper.MultiplyRoundUp(output, volume); + + outputBuffer[i] += mixState; + volume += ramp; + } + + return mixState; + } } } diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterAndMixCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterAndMixCommand.cs new file mode 100644 index 000000000..106fc0357 --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterAndMixCommand.cs @@ -0,0 +1,123 @@ +using Ryujinx.Audio.Renderer.Common; +using Ryujinx.Audio.Renderer.Dsp.State; +using Ryujinx.Audio.Renderer.Parameter; +using System; + +namespace Ryujinx.Audio.Renderer.Dsp.Command +{ + public class BiquadFilterAndMixCommand : ICommand + { + public bool Enabled { get; set; } + + public int NodeId { get; } + + public CommandType CommandType => CommandType.BiquadFilterAndMix; + + public uint EstimatedProcessingTime { get; set; } + + public ushort InputBufferIndex { get; } + public ushort OutputBufferIndex { get; } + + private BiquadFilterParameter _parameter; + + public Memory BiquadFilterState { get; } + public Memory PreviousBiquadFilterState { get; } + + public Memory State { get; } + + public int LastSampleIndex { get; } + + public float Volume0 { get; } + public float Volume1 { get; } + + public bool NeedInitialization { get; } + public bool HasVolumeRamp { get; } + public bool IsFirstMixBuffer { get; } + + public BiquadFilterAndMixCommand( + float volume0, + float volume1, + uint inputBufferIndex, + uint outputBufferIndex, + int lastSampleIndex, + Memory state, + ref BiquadFilterParameter filter, + Memory biquadFilterState, + Memory previousBiquadFilterState, + bool needInitialization, + bool hasVolumeRamp, + bool isFirstMixBuffer, + int nodeId) + { + Enabled = true; + NodeId = nodeId; + + InputBufferIndex = (ushort)inputBufferIndex; + OutputBufferIndex = (ushort)outputBufferIndex; + + _parameter = filter; + BiquadFilterState = biquadFilterState; + PreviousBiquadFilterState = previousBiquadFilterState; + + State = state; + LastSampleIndex = lastSampleIndex; + + Volume0 = volume0; + Volume1 = volume1; + + NeedInitialization = needInitialization; + HasVolumeRamp = hasVolumeRamp; + IsFirstMixBuffer = isFirstMixBuffer; + } + + public void Process(CommandList context) + { + ReadOnlySpan inputBuffer = context.GetBuffer(InputBufferIndex); + Span outputBuffer = context.GetBuffer(OutputBufferIndex); + + if (NeedInitialization) + { + // If there is no previous state, initialize to zero. + + BiquadFilterState.Span[0] = new BiquadFilterState(); + } + else if (IsFirstMixBuffer) + { + // This is the first buffer, set previous state to current state. + + PreviousBiquadFilterState.Span[0] = BiquadFilterState.Span[0]; + } + else + { + // Rewind the current state by copying back the previous state. + + BiquadFilterState.Span[0] = PreviousBiquadFilterState.Span[0]; + } + + if (HasVolumeRamp) + { + float volume = Volume0; + float ramp = (Volume1 - Volume0) / (int)context.SampleCount; + + State.Span[0].LastSamples[LastSampleIndex] = BiquadFilterHelper.ProcessBiquadFilterAndMixRamp( + ref _parameter, + ref BiquadFilterState.Span[0], + outputBuffer, + inputBuffer, + context.SampleCount, + volume, + ramp); + } + else + { + BiquadFilterHelper.ProcessBiquadFilterAndMix( + ref _parameter, + ref BiquadFilterState.Span[0], + outputBuffer, + inputBuffer, + context.SampleCount, + Volume1); + } + } + } +} diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandType.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandType.cs index 098a04a04..de5c0ea2c 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandType.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandType.cs @@ -30,8 +30,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command CopyMixBuffer, LimiterVersion1, LimiterVersion2, - GroupedBiquadFilter, + MultiTapBiquadFilter, CaptureBuffer, Compressor, + BiquadFilterAndMix, + MultiTapBiquadFilterAndMix, } } diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs index 09f415d20..33f61e6a5 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs @@ -1,9 +1,11 @@ using Ryujinx.Audio.Renderer.Dsp.Effect; using Ryujinx.Audio.Renderer.Dsp.State; +using Ryujinx.Audio.Renderer.Parameter; using Ryujinx.Audio.Renderer.Parameter.Effect; using Ryujinx.Audio.Renderer.Server.Effect; using System; using System.Diagnostics; +using System.Runtime.InteropServices; namespace Ryujinx.Audio.Renderer.Dsp.Command { @@ -21,18 +23,20 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CompressorParameter Parameter => _parameter; public Memory State { get; } + public Memory ResultState { get; } public ushort[] OutputBufferIndices { get; } public ushort[] InputBufferIndices { get; } public bool IsEffectEnabled { get; } private CompressorParameter _parameter; - public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory state, bool isEnabled, int nodeId) + public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory state, Memory resultState, bool isEnabled, int nodeId) { Enabled = true; NodeId = nodeId; _parameter = parameter; State = state; + ResultState = resultState; IsEffectEnabled = isEnabled; @@ -71,9 +75,16 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command if (IsEffectEnabled && _parameter.IsChannelCountValid()) { - Span inputBuffers = stackalloc IntPtr[Parameter.ChannelCount]; - Span outputBuffers = stackalloc IntPtr[Parameter.ChannelCount]; - Span channelInput = stackalloc float[Parameter.ChannelCount]; + if (!ResultState.IsEmpty && _parameter.StatisticsReset) + { + ref CompressorStatistics statistics = ref MemoryMarshal.Cast(ResultState.Span[0].SpecificData)[0]; + + statistics.Reset(_parameter.ChannelCount); + } + + Span inputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; + Span outputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; + Span channelInput = stackalloc float[_parameter.ChannelCount]; ExponentialMovingAverage inputMovingAverage = state.InputMovingAverage; float unknown4 = state.Unknown4; ExponentialMovingAverage compressionGainAverage = state.CompressionGainAverage; @@ -92,7 +103,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command channelInput[channelIndex] = *((float*)inputBuffers[channelIndex] + sampleIndex); } - float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain); + float mean = FloatingPointHelper.MeanSquare(channelInput); + float newMean = inputMovingAverage.Update(mean, _parameter.InputGain); float y = FloatingPointHelper.Log10(newMean) * 10.0f; float z = 1.0f; @@ -111,7 +123,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command if (y >= state.Unknown14) { - tmpGain = ((1.0f / Parameter.Ratio) - 1.0f) * (y - Parameter.Threshold); + tmpGain = ((1.0f / _parameter.Ratio) - 1.0f) * (y - _parameter.Threshold); } else { @@ -126,7 +138,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command if ((unknown4 - z) <= 0.08f) { - compressionEmaAlpha = Parameter.ReleaseCoefficient; + compressionEmaAlpha = _parameter.ReleaseCoefficient; if ((unknown4 - z) >= -0.08f) { @@ -140,18 +152,31 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command } else { - compressionEmaAlpha = Parameter.AttackCoefficient; + compressionEmaAlpha = _parameter.AttackCoefficient; } float compressionGain = compressionGainAverage.Update(z, compressionEmaAlpha); - for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++) + for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++) { *((float*)outputBuffers[channelIndex] + sampleIndex) = channelInput[channelIndex] * compressionGain * state.OutputGain; } unknown4 = unknown4New; previousCompressionEmaAlpha = compressionEmaAlpha; + + if (!ResultState.IsEmpty) + { + ref CompressorStatistics statistics = ref MemoryMarshal.Cast(ResultState.Span[0].SpecificData)[0]; + + statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain); + statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean); + + for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++) + { + statistics.LastSamples[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f)); + } + } } state.InputMovingAverage = inputMovingAverage; @@ -161,7 +186,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command } else { - for (int i = 0; i < Parameter.ChannelCount; i++) + for (int i = 0; i < _parameter.ChannelCount; i++) { if (InputBufferIndices[i] != OutputBufferIndices[i]) { diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs index 3ba0b5884..06e932199 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs @@ -38,10 +38,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command InputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; - for (int i = 0; i < Parameter.ChannelCount; i++) + for (int i = 0; i < _parameter.ChannelCount; i++) { - InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]); - OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]); + InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]); + OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]); } } @@ -51,11 +51,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command if (IsEffectEnabled) { - if (Parameter.Status == UsageState.Invalid) + if (_parameter.Status == UsageState.Invalid) { state = new LimiterState(ref _parameter, WorkBuffer); } - else if (Parameter.Status == UsageState.New) + else if (_parameter.Status == UsageState.New) { LimiterState.UpdateParameter(ref _parameter); } @@ -66,56 +66,56 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command private unsafe void ProcessLimiter(CommandList context, ref LimiterState state) { - Debug.Assert(Parameter.IsChannelCountValid()); + Debug.Assert(_parameter.IsChannelCountValid()); - if (IsEffectEnabled && Parameter.IsChannelCountValid()) + if (IsEffectEnabled && _parameter.IsChannelCountValid()) { - Span inputBuffers = stackalloc IntPtr[Parameter.ChannelCount]; - Span outputBuffers = stackalloc IntPtr[Parameter.ChannelCount]; + Span inputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; + Span outputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; - for (int i = 0; i < Parameter.ChannelCount; i++) + for (int i = 0; i < _parameter.ChannelCount; i++) { inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]); outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]); } - for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++) + for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++) { for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++) { float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex); - float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain; + float inputSample = (rawInputSample / short.MaxValue) * _parameter.InputGain; float sampleInputMax = Math.Abs(inputSample); - float inputCoefficient = Parameter.ReleaseCoefficient; + float inputCoefficient = _parameter.ReleaseCoefficient; if (sampleInputMax > state.DetectorAverage[channelIndex].Read()) { - inputCoefficient = Parameter.AttackCoefficient; + inputCoefficient = _parameter.AttackCoefficient; } float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient); float attenuation = 1.0f; - if (detectorValue > Parameter.Threshold) + if (detectorValue > _parameter.Threshold) { - attenuation = Parameter.Threshold / detectorValue; + attenuation = _parameter.Threshold / detectorValue; } - float outputCoefficient = Parameter.ReleaseCoefficient; + float outputCoefficient = _parameter.ReleaseCoefficient; if (state.CompressionGainAverage[channelIndex].Read() > attenuation) { - outputCoefficient = Parameter.AttackCoefficient; + outputCoefficient = _parameter.AttackCoefficient; } float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient); - ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]]; + ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * _parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]]; - float outputSample = delayedSample * compressionGain * Parameter.OutputGain; + float outputSample = delayedSample * compressionGain * _parameter.OutputGain; *((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue; @@ -123,16 +123,16 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command state.DelayedSampleBufferPosition[channelIndex]++; - while (state.DelayedSampleBufferPosition[channelIndex] >= Parameter.DelayBufferSampleCountMin) + while (state.DelayedSampleBufferPosition[channelIndex] >= _parameter.DelayBufferSampleCountMin) { - state.DelayedSampleBufferPosition[channelIndex] -= Parameter.DelayBufferSampleCountMin; + state.DelayedSampleBufferPosition[channelIndex] -= _parameter.DelayBufferSampleCountMin; } } } } else { - for (int i = 0; i < Parameter.ChannelCount; i++) + for (int i = 0; i < _parameter.ChannelCount; i++) { if (InputBufferIndices[i] != OutputBufferIndices[i]) { diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs index f6e1654dd..ed0538c06 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs @@ -49,10 +49,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command InputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; - for (int i = 0; i < Parameter.ChannelCount; i++) + for (int i = 0; i < _parameter.ChannelCount; i++) { - InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]); - OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]); + InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]); + OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]); } } @@ -62,11 +62,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command if (IsEffectEnabled) { - if (Parameter.Status == UsageState.Invalid) + if (_parameter.Status == UsageState.Invalid) { state = new LimiterState(ref _parameter, WorkBuffer); } - else if (Parameter.Status == UsageState.New) + else if (_parameter.Status == UsageState.New) { LimiterState.UpdateParameter(ref _parameter); } @@ -77,63 +77,63 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command private unsafe void ProcessLimiter(CommandList context, ref LimiterState state) { - Debug.Assert(Parameter.IsChannelCountValid()); + Debug.Assert(_parameter.IsChannelCountValid()); - if (IsEffectEnabled && Parameter.IsChannelCountValid()) + if (IsEffectEnabled && _parameter.IsChannelCountValid()) { - if (!ResultState.IsEmpty && Parameter.StatisticsReset) + if (!ResultState.IsEmpty && _parameter.StatisticsReset) { ref LimiterStatistics statistics = ref MemoryMarshal.Cast(ResultState.Span[0].SpecificData)[0]; statistics.Reset(); } - Span inputBuffers = stackalloc IntPtr[Parameter.ChannelCount]; - Span outputBuffers = stackalloc IntPtr[Parameter.ChannelCount]; + Span inputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; + Span outputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; - for (int i = 0; i < Parameter.ChannelCount; i++) + for (int i = 0; i < _parameter.ChannelCount; i++) { inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]); outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]); } - for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++) + for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++) { for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++) { float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex); - float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain; + float inputSample = (rawInputSample / short.MaxValue) * _parameter.InputGain; float sampleInputMax = Math.Abs(inputSample); - float inputCoefficient = Parameter.ReleaseCoefficient; + float inputCoefficient = _parameter.ReleaseCoefficient; if (sampleInputMax > state.DetectorAverage[channelIndex].Read()) { - inputCoefficient = Parameter.AttackCoefficient; + inputCoefficient = _parameter.AttackCoefficient; } float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient); float attenuation = 1.0f; - if (detectorValue > Parameter.Threshold) + if (detectorValue > _parameter.Threshold) { - attenuation = Parameter.Threshold / detectorValue; + attenuation = _parameter.Threshold / detectorValue; } - float outputCoefficient = Parameter.ReleaseCoefficient; + float outputCoefficient = _parameter.ReleaseCoefficient; if (state.CompressionGainAverage[channelIndex].Read() > attenuation) { - outputCoefficient = Parameter.AttackCoefficient; + outputCoefficient = _parameter.AttackCoefficient; } float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient); - ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]]; + ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * _parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]]; - float outputSample = delayedSample * compressionGain * Parameter.OutputGain; + float outputSample = delayedSample * compressionGain * _parameter.OutputGain; *((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue; @@ -141,9 +141,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command state.DelayedSampleBufferPosition[channelIndex]++; - while (state.DelayedSampleBufferPosition[channelIndex] >= Parameter.DelayBufferSampleCountMin) + while (state.DelayedSampleBufferPosition[channelIndex] >= _parameter.DelayBufferSampleCountMin) { - state.DelayedSampleBufferPosition[channelIndex] -= Parameter.DelayBufferSampleCountMin; + state.DelayedSampleBufferPosition[channelIndex] -= _parameter.DelayBufferSampleCountMin; } if (!ResultState.IsEmpty) @@ -158,7 +158,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command } else { - for (int i = 0; i < Parameter.ChannelCount; i++) + for (int i = 0; i < _parameter.ChannelCount; i++) { if (InputBufferIndices[i] != OutputBufferIndices[i]) { diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs index 3c7dd63b2..41ac84c1a 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs @@ -24,7 +24,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public Memory State { get; } - public MixRampGroupedCommand(uint mixBufferCount, uint inputBufferIndex, uint outputBufferIndex, Span volume0, Span volume1, Memory state, int nodeId) + public MixRampGroupedCommand( + uint mixBufferCount, + uint inputBufferIndex, + uint outputBufferIndex, + ReadOnlySpan volume0, + ReadOnlySpan volume1, + Memory state, + int nodeId) { Enabled = true; MixBufferCount = mixBufferCount; @@ -48,7 +55,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static float ProcessMixRampGrouped(Span outputBuffer, ReadOnlySpan inputBuffer, float volume0, float volume1, int sampleCount) + private static float ProcessMixRampGrouped( + Span outputBuffer, + ReadOnlySpan inputBuffer, + float volume0, + float volume1, + int sampleCount) { float ramp = (volume1 - volume0) / sampleCount; float volume = volume0; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterAndMixCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterAndMixCommand.cs new file mode 100644 index 000000000..e359371b4 --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterAndMixCommand.cs @@ -0,0 +1,145 @@ +using Ryujinx.Audio.Renderer.Common; +using Ryujinx.Audio.Renderer.Dsp.State; +using Ryujinx.Audio.Renderer.Parameter; +using System; + +namespace Ryujinx.Audio.Renderer.Dsp.Command +{ + public class MultiTapBiquadFilterAndMixCommand : ICommand + { + public bool Enabled { get; set; } + + public int NodeId { get; } + + public CommandType CommandType => CommandType.MultiTapBiquadFilterAndMix; + + public uint EstimatedProcessingTime { get; set; } + + public ushort InputBufferIndex { get; } + public ushort OutputBufferIndex { get; } + + private BiquadFilterParameter _parameter0; + private BiquadFilterParameter _parameter1; + + public Memory BiquadFilterState0 { get; } + public Memory BiquadFilterState1 { get; } + public Memory PreviousBiquadFilterState0 { get; } + public Memory PreviousBiquadFilterState1 { get; } + + public Memory State { get; } + + public int LastSampleIndex { get; } + + public float Volume0 { get; } + public float Volume1 { get; } + + public bool NeedInitialization0 { get; } + public bool NeedInitialization1 { get; } + public bool HasVolumeRamp { get; } + public bool IsFirstMixBuffer { get; } + + public MultiTapBiquadFilterAndMixCommand( + float volume0, + float volume1, + uint inputBufferIndex, + uint outputBufferIndex, + int lastSampleIndex, + Memory state, + ref BiquadFilterParameter filter0, + ref BiquadFilterParameter filter1, + Memory biquadFilterState0, + Memory biquadFilterState1, + Memory previousBiquadFilterState0, + Memory previousBiquadFilterState1, + bool needInitialization0, + bool needInitialization1, + bool hasVolumeRamp, + bool isFirstMixBuffer, + int nodeId) + { + Enabled = true; + NodeId = nodeId; + + InputBufferIndex = (ushort)inputBufferIndex; + OutputBufferIndex = (ushort)outputBufferIndex; + + _parameter0 = filter0; + _parameter1 = filter1; + BiquadFilterState0 = biquadFilterState0; + BiquadFilterState1 = biquadFilterState1; + PreviousBiquadFilterState0 = previousBiquadFilterState0; + PreviousBiquadFilterState1 = previousBiquadFilterState1; + + State = state; + LastSampleIndex = lastSampleIndex; + + Volume0 = volume0; + Volume1 = volume1; + + NeedInitialization0 = needInitialization0; + NeedInitialization1 = needInitialization1; + HasVolumeRamp = hasVolumeRamp; + IsFirstMixBuffer = isFirstMixBuffer; + } + + private void UpdateState(Memory state, Memory previousState, bool needInitialization) + { + if (needInitialization) + { + // If there is no previous state, initialize to zero. + + state.Span[0] = new BiquadFilterState(); + } + else if (IsFirstMixBuffer) + { + // This is the first buffer, set previous state to current state. + + previousState.Span[0] = state.Span[0]; + } + else + { + // Rewind the current state by copying back the previous state. + + state.Span[0] = previousState.Span[0]; + } + } + + public void Process(CommandList context) + { + ReadOnlySpan inputBuffer = context.GetBuffer(InputBufferIndex); + Span outputBuffer = context.GetBuffer(OutputBufferIndex); + + UpdateState(BiquadFilterState0, PreviousBiquadFilterState0, NeedInitialization0); + UpdateState(BiquadFilterState1, PreviousBiquadFilterState1, NeedInitialization1); + + if (HasVolumeRamp) + { + float volume = Volume0; + float ramp = (Volume1 - Volume0) / (int)context.SampleCount; + + State.Span[0].LastSamples[LastSampleIndex] = BiquadFilterHelper.ProcessDoubleBiquadFilterAndMixRamp( + ref _parameter0, + ref _parameter1, + ref BiquadFilterState0.Span[0], + ref BiquadFilterState1.Span[0], + outputBuffer, + inputBuffer, + context.SampleCount, + volume, + ramp); + } + else + { + BiquadFilterHelper.ProcessDoubleBiquadFilterAndMix( + ref _parameter0, + ref _parameter1, + ref BiquadFilterState0.Span[0], + ref BiquadFilterState1.Span[0], + outputBuffer, + inputBuffer, + context.SampleCount, + Volume1); + } + } + } +} diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/GroupedBiquadFilterCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterCommand.cs similarity index 84% rename from src/Ryujinx.Audio/Renderer/Dsp/Command/GroupedBiquadFilterCommand.cs rename to src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterCommand.cs index 7af851bdc..e159f8ef7 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/GroupedBiquadFilterCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterCommand.cs @@ -4,13 +4,13 @@ using System; namespace Ryujinx.Audio.Renderer.Dsp.Command { - public class GroupedBiquadFilterCommand : ICommand + public class MultiTapBiquadFilterCommand : ICommand { public bool Enabled { get; set; } public int NodeId { get; } - public CommandType CommandType => CommandType.GroupedBiquadFilter; + public CommandType CommandType => CommandType.MultiTapBiquadFilter; public uint EstimatedProcessingTime { get; set; } @@ -20,7 +20,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command private readonly int _outputBufferIndex; private readonly bool[] _isInitialized; - public GroupedBiquadFilterCommand(int baseIndex, ReadOnlySpan filters, Memory biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan isInitialized, int nodeId) + public MultiTapBiquadFilterCommand(int baseIndex, ReadOnlySpan filters, Memory biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan isInitialized, int nodeId) { _parameters = filters.ToArray(); _biquadFilterStates = biquadFilterStateMemory; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/State/BiquadFilterState.cs b/src/Ryujinx.Audio/Renderer/Dsp/State/BiquadFilterState.cs index f9a32b3f9..58a2d9cce 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/State/BiquadFilterState.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/State/BiquadFilterState.cs @@ -2,12 +2,16 @@ using System.Runtime.InteropServices; namespace Ryujinx.Audio.Renderer.Dsp.State { - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] + [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x20)] public struct BiquadFilterState { public float State0; public float State1; public float State2; public float State3; + public float State4; + public float State5; + public float State6; + public float State7; } } diff --git a/src/Ryujinx.Audio/Renderer/Parameter/BehaviourErrorInfoOutStatus.cs b/src/Ryujinx.Audio/Renderer/Parameter/BehaviourErrorInfoOutStatus.cs index 5a0565dc6..72438be0e 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/BehaviourErrorInfoOutStatus.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/BehaviourErrorInfoOutStatus.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Parameter /// /// Output information for behaviour. /// - /// This is used to report errors to the user during processing. + /// This is used to report errors to the user during processing. [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct BehaviourErrorInfoOutStatus { diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs index b403f1370..c00118e49 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs @@ -90,9 +90,16 @@ namespace Ryujinx.Audio.Renderer.Parameter.Effect public bool MakeupGainEnabled; /// - /// Reserved/padding. + /// Indicate if the compressor effect should output statistics. /// - private Array2 _reserved; + [MarshalAs(UnmanagedType.I1)] + public bool StatisticsEnabled; + + /// + /// Indicate to the DSP that the user did a statistics reset. + /// + [MarshalAs(UnmanagedType.I1)] + public bool StatisticsReset; /// /// Check if the is valid. diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorStatistics.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorStatistics.cs new file mode 100644 index 000000000..65335e2d9 --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorStatistics.cs @@ -0,0 +1,38 @@ +using Ryujinx.Common.Memory; +using System.Runtime.InteropServices; + +namespace Ryujinx.Audio.Renderer.Parameter.Effect +{ + /// + /// Effect result state for . + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct CompressorStatistics + { + /// + /// Maximum input mean value since last reset. + /// + public float MaximumMean; + + /// + /// Minimum output gain since last reset. + /// + public float MinimumGain; + + /// + /// Last processed input sample, per channel. + /// + public Array6 LastSamples; + + /// + /// Reset the statistics. + /// + /// Number of channels to reset. + public void Reset(ushort channelCount) + { + MaximumMean = 0.0f; + MinimumGain = 1.0f; + LastSamples.AsSpan()[..channelCount].Clear(); + } + } +} diff --git a/src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs new file mode 100644 index 000000000..7ee49f11a --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs @@ -0,0 +1,48 @@ +using Ryujinx.Common.Memory; +using System; + +namespace Ryujinx.Audio.Renderer.Parameter +{ + /// + /// Generic interface for the splitter destination parameters. + /// + public interface ISplitterDestinationInParameter + { + /// + /// Target splitter destination data id. + /// + int Id { get; } + + /// + /// The mix to output the result of the splitter. + /// + int DestinationId { get; } + + /// + /// Biquad filter parameters. + /// + Array2 BiquadFilters { get; } + + /// + /// Set to true if in use. + /// + bool IsUsed { get; } + + /// + /// Set to true to force resetting the previous mix volumes. + /// + bool ResetPrevVolume { get; } + + /// + /// Mix buffer volumes. + /// + /// Used when a splitter id is specified in the mix. + Span MixBufferVolume { get; } + + /// + /// Check if the magic is valid. + /// + /// Returns true if the magic is valid. + bool IsMagicValid(); + } +} diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs similarity index 63% rename from src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameter.cs rename to src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs index b74b67be0..f346efcb0 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameter.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Memory; using Ryujinx.Common.Utilities; using System; using System.Runtime.InteropServices; @@ -5,10 +6,10 @@ using System.Runtime.InteropServices; namespace Ryujinx.Audio.Renderer.Parameter { /// - /// Input header for a splitter destination update. + /// Input header for a splitter destination version 1 update. /// [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct SplitterDestinationInParameter + public struct SplitterDestinationInParameterVersion1 : ISplitterDestinationInParameter { /// /// Magic of the input header. @@ -36,12 +37,18 @@ namespace Ryujinx.Audio.Renderer.Parameter [MarshalAs(UnmanagedType.I1)] public bool IsUsed; + /// + /// Set to true to force resetting the previous mix volumes. + /// + [MarshalAs(UnmanagedType.I1)] + public bool ResetPrevVolume; + /// /// Reserved/padding. /// - private unsafe fixed byte _reserved[3]; + private unsafe fixed byte _reserved[2]; - [StructLayout(LayoutKind.Sequential, Size = 4 * Constants.MixBufferCountMax, Pack = 1)] + [StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)] private struct MixArray { } /// @@ -50,6 +57,15 @@ namespace Ryujinx.Audio.Renderer.Parameter /// Used when a splitter id is specified in the mix. public Span MixBufferVolume => SpanHelpers.AsSpan(ref _mixBufferVolume); + readonly int ISplitterDestinationInParameter.Id => Id; + + readonly int ISplitterDestinationInParameter.DestinationId => DestinationId; + + readonly Array2 ISplitterDestinationInParameter.BiquadFilters => default; + + readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed; + readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume; + /// /// The expected constant of any input header. /// diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs new file mode 100644 index 000000000..1d867919d --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs @@ -0,0 +1,88 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Common.Utilities; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Audio.Renderer.Parameter +{ + /// + /// Input header for a splitter destination version 2 update. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct SplitterDestinationInParameterVersion2 : ISplitterDestinationInParameter + { + /// + /// Magic of the input header. + /// + public uint Magic; + + /// + /// Target splitter destination data id. + /// + public int Id; + + /// + /// Mix buffer volumes storage. + /// + private MixArray _mixBufferVolume; + + /// + /// The mix to output the result of the splitter. + /// + public int DestinationId; + + /// + /// Biquad filter parameters. + /// + public Array2 BiquadFilters; + + /// + /// Set to true if in use. + /// + [MarshalAs(UnmanagedType.I1)] + public bool IsUsed; + + /// + /// Set to true to force resetting the previous mix volumes. + /// + [MarshalAs(UnmanagedType.I1)] + public bool ResetPrevVolume; + + /// + /// Reserved/padding. + /// + private unsafe fixed byte _reserved[10]; + + [StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)] + private struct MixArray { } + + /// + /// Mix buffer volumes. + /// + /// Used when a splitter id is specified in the mix. + public Span MixBufferVolume => SpanHelpers.AsSpan(ref _mixBufferVolume); + + readonly int ISplitterDestinationInParameter.Id => Id; + + readonly int ISplitterDestinationInParameter.DestinationId => DestinationId; + + readonly Array2 ISplitterDestinationInParameter.BiquadFilters => BiquadFilters; + + readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed; + readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume; + + /// + /// The expected constant of any input header. + /// + private const uint ValidMagic = 0x44444E53; + + /// + /// Check if the magic is valid. + /// + /// Returns true if the magic is valid. + public readonly bool IsMagicValid() + { + return Magic == ValidMagic; + } + } +} diff --git a/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs b/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs index 7bb8ae5ba..246889c48 100644 --- a/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs +++ b/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs @@ -1,6 +1,7 @@ using Ryujinx.Audio.Integration; using Ryujinx.Audio.Renderer.Common; using Ryujinx.Audio.Renderer.Dsp.Command; +using Ryujinx.Audio.Renderer.Dsp.State; using Ryujinx.Audio.Renderer.Parameter; using Ryujinx.Audio.Renderer.Server.Effect; using Ryujinx.Audio.Renderer.Server.MemoryPool; @@ -173,6 +174,22 @@ namespace Ryujinx.Audio.Renderer.Server return ResultCode.WorkBufferTooSmall; } + Memory splitterBqfStates = Memory.Empty; + + if (_behaviourContext.IsBiquadFilterParameterForSplitterEnabled() && + parameter.SplitterCount > 0 && + parameter.SplitterDestinationCount > 0) + { + splitterBqfStates = workBufferAllocator.Allocate(parameter.SplitterDestinationCount * SplitterContext.BqfStatesPerDestination, 0x10); + + if (splitterBqfStates.IsEmpty) + { + return ResultCode.WorkBufferTooSmall; + } + + splitterBqfStates.Span.Clear(); + } + // Invalidate DSP cache on what was currently allocated with workBuffer. AudioProcessorMemoryManager.InvalidateDspCache(_dspMemoryPoolState.Translate(workBuffer, workBufferAllocator.Offset), workBufferAllocator.Offset); @@ -292,7 +309,7 @@ namespace Ryujinx.Audio.Renderer.Server state = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); } - if (!_splitterContext.Initialize(ref _behaviourContext, ref parameter, workBufferAllocator)) + if (!_splitterContext.Initialize(ref _behaviourContext, ref parameter, workBufferAllocator, splitterBqfStates)) { return ResultCode.WorkBufferTooSmall; } @@ -386,7 +403,7 @@ namespace Ryujinx.Audio.Renderer.Server } } - public ResultCode Update(Memory output, Memory performanceOutput, ReadOnlyMemory input) + public ResultCode Update(Memory output, Memory performanceOutput, ReadOnlySequence input) { lock (_lock) { @@ -419,14 +436,16 @@ namespace Ryujinx.Audio.Renderer.Server return result; } - result = stateUpdater.UpdateVoices(_voiceContext, _memoryPools); + PoolMapper poolMapper = new PoolMapper(_processHandle, _memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); + + result = stateUpdater.UpdateVoices(_voiceContext, poolMapper); if (result != ResultCode.Success) { return result; } - result = stateUpdater.UpdateEffects(_effectContext, _isActive, _memoryPools); + result = stateUpdater.UpdateEffects(_effectContext, _isActive, poolMapper); if (result != ResultCode.Success) { @@ -450,7 +469,7 @@ namespace Ryujinx.Audio.Renderer.Server return result; } - result = stateUpdater.UpdateSinks(_sinkContext, _memoryPools); + result = stateUpdater.UpdateSinks(_sinkContext, poolMapper); if (result != ResultCode.Success) { @@ -773,6 +792,13 @@ namespace Ryujinx.Audio.Renderer.Server // Splitter size = SplitterContext.GetWorkBufferSize(size, ref behaviourContext, ref parameter); + if (behaviourContext.IsBiquadFilterParameterForSplitterEnabled() && + parameter.SplitterCount > 0 && + parameter.SplitterDestinationCount > 0) + { + size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterDestinationCount * SplitterContext.BqfStatesPerDestination, 0x10); + } + // DSP Voice size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, VoiceUpdateState.Align); diff --git a/src/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs b/src/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs index 0dbbd26c8..e334a89f6 100644 --- a/src/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs +++ b/src/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs @@ -177,12 +177,12 @@ namespace Ryujinx.Audio.Renderer.Server /// /// Start the and worker thread. /// - private void StartLocked(float volume) + private void StartLocked() { _isRunning = true; // TODO: virtual device mapping (IAudioDevice) - Processor.Start(_deviceDriver, volume); + Processor.Start(_deviceDriver); _workerThread = new Thread(SendCommands) { @@ -254,7 +254,7 @@ namespace Ryujinx.Audio.Renderer.Server /// Register a new . /// /// The to register. - private void Register(AudioRenderSystem renderer, float volume) + private void Register(AudioRenderSystem renderer) { lock (_sessionLock) { @@ -265,7 +265,7 @@ namespace Ryujinx.Audio.Renderer.Server { if (!_isRunning) { - StartLocked(volume); + StartLocked(); } } } @@ -312,8 +312,7 @@ namespace Ryujinx.Audio.Renderer.Server ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, - uint processHandle, - float volume) + uint processHandle) { int sessionId = AcquireSessionId(); @@ -338,7 +337,7 @@ namespace Ryujinx.Audio.Renderer.Server { renderer = audioRenderer; - Register(renderer, volume); + Register(renderer); } else { @@ -350,21 +349,6 @@ namespace Ryujinx.Audio.Renderer.Server return result; } - public float GetVolume() - { - if (Processor != null) - { - return Processor.GetVolume(); - } - - return 0f; - } - - public void SetVolume(float volume) - { - Processor?.SetVolume(volume); - } - public void Dispose() { GC.SuppressFinalize(this); diff --git a/src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs b/src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs index 3297b5d9f..f725eb9f3 100644 --- a/src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs +++ b/src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Diagnostics; using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; @@ -44,7 +45,6 @@ namespace Ryujinx.Audio.Renderer.Server /// was added to supply the count of update done sent to the DSP. /// A new version of the command estimator was added to address timing changes caused by the voice changes. /// Additionally, the rendering limit percent was incremented to 80%. - /// /// /// This was added in system update 6.0.0 public const int Revision5 = 5 << 24; @@ -100,10 +100,26 @@ namespace Ryujinx.Audio.Renderer.Server /// This was added in system update 14.0.0 but some changes were made in 15.0.0 public const int Revision11 = 11 << 24; + /// + /// REV12: + /// Two new commands were added to for biquad filtering and mixing (with optinal volume ramp) on the same command. + /// Splitter destinations can now specify up to two biquad filtering parameters, used for filtering the buffer before mixing. + /// + /// This was added in system update 17.0.0 + public const int Revision12 = 12 << 24; + + /// + /// REV13: + /// The compressor effect can now output statistics. + /// Splitter destinations now explicitly reset the previous mix volume, instead of doing so on first use. + /// + /// This was added in system update 18.0.0 + public const int Revision13 = 13 << 24; + /// /// Last revision supported by the implementation. /// - public const int LastRevision = Revision11; + public const int LastRevision = Revision13; /// /// Target revision magic supported by the implementation. @@ -211,7 +227,7 @@ namespace Ryujinx.Audio.Renderer.Server /// /// Check if the audio renderer should fix the GC-ADPCM context not being provided to the DSP. /// - /// True if if the audio renderer should fix it. + /// True if the audio renderer should fix it. public bool IsAdpcmLoopContextBugFixed() { return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision2); @@ -273,7 +289,7 @@ namespace Ryujinx.Audio.Renderer.Server } /// - /// Check if the audio renderer should trust the user destination count in . + /// Check if the audio renderer should trust the user destination count in . /// /// True if the audio renderer should trust the user destination count. public bool IsSplitterBugFixed() @@ -353,7 +369,7 @@ namespace Ryujinx.Audio.Renderer.Server /// Check if the audio renderer should use an optimized Biquad Filter (Direct Form 1) in case of two biquad filters are defined on a voice. /// /// True if the audio renderer should use the optimization. - public bool IsBiquadFilterGroupedOptimizationSupported() + public bool UseMultiTapBiquadFilterProcessing() { return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision10); } @@ -367,6 +383,24 @@ namespace Ryujinx.Audio.Renderer.Server return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision11); } + /// + /// Check if the audio renderer should support biquad filter on splitter. + /// + /// True if the audio renderer support biquad filter on splitter + public bool IsBiquadFilterParameterForSplitterEnabled() + { + return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision12); + } + + /// + /// Check if the audio renderer should support explicit previous mix volume reset on splitter. + /// + /// True if the audio renderer support explicit previous mix volume reset on splitter + public bool IsSplitterPrevVolumeResetSupported() + { + return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision13); + } + /// /// Get the version of the . /// diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs b/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs index f4174a913..4c353b37e 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs @@ -204,7 +204,7 @@ namespace Ryujinx.Audio.Renderer.Server } /// - /// Create a new . + /// Create a new . /// /// The base index of the input and output buffer. /// The biquad filter parameters. @@ -213,9 +213,9 @@ namespace Ryujinx.Audio.Renderer.Server /// The output buffer offset. /// Set to true if the biquad filter state is initialized. /// The node id associated to this command. - public void GenerateGroupedBiquadFilter(int baseIndex, ReadOnlySpan filters, Memory biquadFilterStatesMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan isInitialized, int nodeId) + public void GenerateMultiTapBiquadFilter(int baseIndex, ReadOnlySpan filters, Memory biquadFilterStatesMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan isInitialized, int nodeId) { - GroupedBiquadFilterCommand command = new(baseIndex, filters, biquadFilterStatesMemory, inputBufferOffset, outputBufferOffset, isInitialized, nodeId); + MultiTapBiquadFilterCommand command = new(baseIndex, filters, biquadFilterStatesMemory, inputBufferOffset, outputBufferOffset, isInitialized, nodeId); command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); @@ -232,7 +232,7 @@ namespace Ryujinx.Audio.Renderer.Server /// The new volume. /// The to generate the command from. /// The node id associated to this command. - public void GenerateMixRampGrouped(uint mixBufferCount, uint inputBufferIndex, uint outputBufferIndex, Span previousVolume, Span volume, Memory state, int nodeId) + public void GenerateMixRampGrouped(uint mixBufferCount, uint inputBufferIndex, uint outputBufferIndex, ReadOnlySpan previousVolume, ReadOnlySpan volume, Memory state, int nodeId) { MixRampGroupedCommand command = new(mixBufferCount, inputBufferIndex, outputBufferIndex, previousVolume, volume, state, nodeId); @@ -260,6 +260,120 @@ namespace Ryujinx.Audio.Renderer.Server AddCommand(command); } + /// + /// Generate a new . + /// + /// The previous volume. + /// The new volume. + /// The input buffer index. + /// The output buffer index. + /// The index in the array to store the ramped sample. + /// The to generate the command from. + /// The biquad filter parameter. + /// The biquad state. + /// The previous biquad state. + /// Set to true if the biquad filter state needs to be initialized. + /// Set to true if the mix has volume ramp, and should be taken into account. + /// Set to true if the buffer is the first mix buffer. + /// The node id associated to this command. + public void GenerateBiquadFilterAndMix( + float previousVolume, + float volume, + uint inputBufferIndex, + uint outputBufferIndex, + int lastSampleIndex, + Memory state, + ref BiquadFilterParameter filter, + Memory biquadFilterState, + Memory previousBiquadFilterState, + bool needInitialization, + bool hasVolumeRamp, + bool isFirstMixBuffer, + int nodeId) + { + BiquadFilterAndMixCommand command = new( + previousVolume, + volume, + inputBufferIndex, + outputBufferIndex, + lastSampleIndex, + state, + ref filter, + biquadFilterState, + previousBiquadFilterState, + needInitialization, + hasVolumeRamp, + isFirstMixBuffer, + nodeId); + + command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); + + AddCommand(command); + } + + /// + /// Generate a new . + /// + /// The previous volume. + /// The new volume. + /// The input buffer index. + /// The output buffer index. + /// The index in the array to store the ramped sample. + /// The to generate the command from. + /// First biquad filter parameter. + /// Second biquad filter parameter. + /// First biquad state. + /// Second biquad state. + /// First previous biquad state. + /// Second previous biquad state. + /// Set to true if the first biquad filter state needs to be initialized. + /// Set to true if the second biquad filter state needs to be initialized. + /// Set to true if the mix has volume ramp, and should be taken into account. + /// Set to true if the buffer is the first mix buffer. + /// The node id associated to this command. + public void GenerateMultiTapBiquadFilterAndMix( + float previousVolume, + float volume, + uint inputBufferIndex, + uint outputBufferIndex, + int lastSampleIndex, + Memory state, + ref BiquadFilterParameter filter0, + ref BiquadFilterParameter filter1, + Memory biquadFilterState0, + Memory biquadFilterState1, + Memory previousBiquadFilterState0, + Memory previousBiquadFilterState1, + bool needInitialization0, + bool needInitialization1, + bool hasVolumeRamp, + bool isFirstMixBuffer, + int nodeId) + { + MultiTapBiquadFilterAndMixCommand command = new( + previousVolume, + volume, + inputBufferIndex, + outputBufferIndex, + lastSampleIndex, + state, + ref filter0, + ref filter1, + biquadFilterState0, + biquadFilterState1, + previousBiquadFilterState0, + previousBiquadFilterState1, + needInitialization0, + needInitialization1, + hasVolumeRamp, + isFirstMixBuffer, + nodeId); + + command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); + + AddCommand(command); + } + /// /// Generate a new . /// @@ -268,7 +382,7 @@ namespace Ryujinx.Audio.Renderer.Server /// The buffer count. /// The node id associated to this command. /// The target sample rate in use. - public void GenerateDepopForMixBuffersCommand(Memory depopBuffer, uint bufferOffset, uint bufferCount, int nodeId, uint sampleRate) + public void GenerateDepopForMixBuffers(Memory depopBuffer, uint bufferOffset, uint bufferCount, int nodeId, uint sampleRate) { DepopForMixBuffersCommand command = new(depopBuffer, bufferOffset, bufferCount, nodeId, sampleRate); @@ -469,11 +583,20 @@ namespace Ryujinx.Audio.Renderer.Server } } - public void GenerateCompressorEffect(uint bufferOffset, CompressorParameter parameter, Memory state, bool isEnabled, int nodeId) + /// + /// Generate a new . + /// + /// The target buffer offset. + /// The compressor parameter. + /// The compressor state. + /// The DSP effect result state. + /// Set to true if the effect should be active. + /// The node id associated to this command. + public void GenerateCompressorEffect(uint bufferOffset, CompressorParameter parameter, Memory state, Memory effectResultState, bool isEnabled, int nodeId) { if (parameter.IsChannelCountValid()) { - CompressorCommand command = new(bufferOffset, parameter, state, isEnabled, nodeId); + CompressorCommand command = new(bufferOffset, parameter, state, effectResultState, isEnabled, nodeId); command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs b/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs index ae8f699f3..0b789537a 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs @@ -12,6 +12,7 @@ using Ryujinx.Audio.Renderer.Server.Voice; using Ryujinx.Audio.Renderer.Utils; using System; using System.Diagnostics; +using System.Runtime.CompilerServices; namespace Ryujinx.Audio.Renderer.Server { @@ -46,12 +47,13 @@ namespace Ryujinx.Audio.Renderer.Server { ref MixState mix = ref _mixContext.GetState(voiceState.MixId); - _commandBuffer.GenerateDepopPrepare(dspState, - _rendererContext.DepopBuffer, - mix.BufferCount, - mix.BufferOffset, - voiceState.NodeId, - voiceState.WasPlaying); + _commandBuffer.GenerateDepopPrepare( + dspState, + _rendererContext.DepopBuffer, + mix.BufferCount, + mix.BufferOffset, + voiceState.NodeId, + voiceState.WasPlaying); } else if (voiceState.SplitterId != Constants.UnusedSplitterId) { @@ -59,15 +61,13 @@ namespace Ryujinx.Audio.Renderer.Server while (true) { - Span destinationSpan = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId++); + SplitterDestination destination = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId++); - if (destinationSpan.IsEmpty) + if (destination.IsNull) { break; } - ref SplitterDestination destination = ref destinationSpan[0]; - if (destination.IsConfigured()) { int mixId = destination.DestinationId; @@ -76,12 +76,13 @@ namespace Ryujinx.Audio.Renderer.Server { ref MixState mix = ref _mixContext.GetState(mixId); - _commandBuffer.GenerateDepopPrepare(dspState, - _rendererContext.DepopBuffer, - mix.BufferCount, - mix.BufferOffset, - voiceState.NodeId, - voiceState.WasPlaying); + _commandBuffer.GenerateDepopPrepare( + dspState, + _rendererContext.DepopBuffer, + mix.BufferCount, + mix.BufferOffset, + voiceState.NodeId, + voiceState.WasPlaying); destination.MarkAsNeedToUpdateInternalState(); } @@ -95,35 +96,39 @@ namespace Ryujinx.Audio.Renderer.Server if (_rendererContext.BehaviourContext.IsWaveBufferVersion2Supported()) { - _commandBuffer.GenerateDataSourceVersion2(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - (ushort)channelIndex, - voiceState.NodeId); + _commandBuffer.GenerateDataSourceVersion2( + ref voiceState, + dspState, + (ushort)_rendererContext.MixBufferCount, + (ushort)channelIndex, + voiceState.NodeId); } else { switch (voiceState.SampleFormat) { case SampleFormat.PcmInt16: - _commandBuffer.GeneratePcmInt16DataSourceVersion1(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - (ushort)channelIndex, - voiceState.NodeId); + _commandBuffer.GeneratePcmInt16DataSourceVersion1( + ref voiceState, + dspState, + (ushort)_rendererContext.MixBufferCount, + (ushort)channelIndex, + voiceState.NodeId); break; case SampleFormat.PcmFloat: - _commandBuffer.GeneratePcmFloatDataSourceVersion1(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - (ushort)channelIndex, - voiceState.NodeId); + _commandBuffer.GeneratePcmFloatDataSourceVersion1( + ref voiceState, + dspState, + (ushort)_rendererContext.MixBufferCount, + (ushort)channelIndex, + voiceState.NodeId); break; case SampleFormat.Adpcm: - _commandBuffer.GenerateAdpcmDataSourceVersion1(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - voiceState.NodeId); + _commandBuffer.GenerateAdpcmDataSourceVersion1( + ref voiceState, + dspState, + (ushort)_rendererContext.MixBufferCount, + voiceState.NodeId); break; default: throw new NotImplementedException($"Unsupported data source {voiceState.SampleFormat}"); @@ -134,14 +139,14 @@ namespace Ryujinx.Audio.Renderer.Server private void GenerateBiquadFilterForVoice(ref VoiceState voiceState, Memory state, int baseIndex, int bufferOffset, int nodeId) { - bool supportsOptimizedPath = _rendererContext.BehaviourContext.IsBiquadFilterGroupedOptimizationSupported(); + bool supportsOptimizedPath = _rendererContext.BehaviourContext.UseMultiTapBiquadFilterProcessing(); if (supportsOptimizedPath && voiceState.BiquadFilters[0].Enable && voiceState.BiquadFilters[1].Enable) { - Memory biquadStateRawMemory = SpanMemoryManager.Cast(state)[..(VoiceUpdateState.BiquadStateSize * Constants.VoiceBiquadFilterCount)]; + Memory biquadStateRawMemory = SpanMemoryManager.Cast(state)[..(Unsafe.SizeOf() * Constants.VoiceBiquadFilterCount)]; Memory stateMemory = SpanMemoryManager.Cast(biquadStateRawMemory); - _commandBuffer.GenerateGroupedBiquadFilter(baseIndex, voiceState.BiquadFilters.AsSpan(), stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId); + _commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, voiceState.BiquadFilters.AsSpan(), stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId); } else { @@ -151,33 +156,134 @@ namespace Ryujinx.Audio.Renderer.Server if (filter.Enable) { - Memory biquadStateRawMemory = SpanMemoryManager.Cast(state)[..(VoiceUpdateState.BiquadStateSize * Constants.VoiceBiquadFilterCount)]; - + Memory biquadStateRawMemory = SpanMemoryManager.Cast(state)[..(Unsafe.SizeOf() * Constants.VoiceBiquadFilterCount)]; Memory stateMemory = SpanMemoryManager.Cast(biquadStateRawMemory); - _commandBuffer.GenerateBiquadFilter(baseIndex, - ref filter, - stateMemory.Slice(i, 1), - bufferOffset, - bufferOffset, - !voiceState.BiquadFilterNeedInitialization[i], - nodeId); + _commandBuffer.GenerateBiquadFilter( + baseIndex, + ref filter, + stateMemory.Slice(i, 1), + bufferOffset, + bufferOffset, + !voiceState.BiquadFilterNeedInitialization[i], + nodeId); } } } } - private void GenerateVoiceMix(Span mixVolumes, Span previousMixVolumes, Memory state, uint bufferOffset, uint bufferCount, uint bufferIndex, int nodeId) + private void GenerateVoiceMixWithSplitter( + SplitterDestination destination, + Memory state, + uint bufferOffset, + uint bufferCount, + uint bufferIndex, + int nodeId) + { + ReadOnlySpan mixVolumes = destination.MixBufferVolume; + ReadOnlySpan previousMixVolumes = destination.PreviousMixBufferVolume; + + ref BiquadFilterParameter bqf0 = ref destination.GetBiquadFilterParameter(0); + ref BiquadFilterParameter bqf1 = ref destination.GetBiquadFilterParameter(1); + + Memory bqfState = _splitterContext.GetBiquadFilterState(destination); + + bool isFirstMixBuffer = true; + + for (int i = 0; i < bufferCount; i++) + { + float previousMixVolume = previousMixVolumes[i]; + float mixVolume = mixVolumes[i]; + + if (mixVolume != 0.0f || previousMixVolume != 0.0f) + { + if (bqf0.Enable && bqf1.Enable) + { + _commandBuffer.GenerateMultiTapBiquadFilterAndMix( + previousMixVolume, + mixVolume, + bufferIndex, + bufferOffset + (uint)i, + i, + state, + ref bqf0, + ref bqf1, + bqfState[..1], + bqfState.Slice(1, 1), + bqfState.Slice(2, 1), + bqfState.Slice(3, 1), + !destination.IsBiquadFilterEnabledPrev(), + !destination.IsBiquadFilterEnabledPrev(), + true, + isFirstMixBuffer, + nodeId); + + destination.UpdateBiquadFilterEnabledPrev(0); + destination.UpdateBiquadFilterEnabledPrev(1); + } + else if (bqf0.Enable) + { + _commandBuffer.GenerateBiquadFilterAndMix( + previousMixVolume, + mixVolume, + bufferIndex, + bufferOffset + (uint)i, + i, + state, + ref bqf0, + bqfState[..1], + bqfState.Slice(1, 1), + !destination.IsBiquadFilterEnabledPrev(), + true, + isFirstMixBuffer, + nodeId); + + destination.UpdateBiquadFilterEnabledPrev(0); + } + else if (bqf1.Enable) + { + _commandBuffer.GenerateBiquadFilterAndMix( + previousMixVolume, + mixVolume, + bufferIndex, + bufferOffset + (uint)i, + i, + state, + ref bqf1, + bqfState[..1], + bqfState.Slice(1, 1), + !destination.IsBiquadFilterEnabledPrev(), + true, + isFirstMixBuffer, + nodeId); + + destination.UpdateBiquadFilterEnabledPrev(1); + } + + isFirstMixBuffer = false; + } + } + } + + private void GenerateVoiceMix( + ReadOnlySpan mixVolumes, + ReadOnlySpan previousMixVolumes, + Memory state, + uint bufferOffset, + uint bufferCount, + uint bufferIndex, + int nodeId) { if (bufferCount > Constants.VoiceChannelCountMax) { - _commandBuffer.GenerateMixRampGrouped(bufferCount, - bufferIndex, - bufferOffset, - previousMixVolumes, - mixVolumes, - state, - nodeId); + _commandBuffer.GenerateMixRampGrouped( + bufferCount, + bufferIndex, + bufferOffset, + previousMixVolumes, + mixVolumes, + state, + nodeId); } else { @@ -188,13 +294,14 @@ namespace Ryujinx.Audio.Renderer.Server if (mixVolume != 0.0f || previousMixVolume != 0.0f) { - _commandBuffer.GenerateMixRamp(previousMixVolume, - mixVolume, - bufferIndex, - bufferOffset + (uint)i, - i, - state, - nodeId); + _commandBuffer.GenerateMixRamp( + previousMixVolume, + mixVolume, + bufferIndex, + bufferOffset + (uint)i, + i, + state, + nodeId); } } } @@ -271,10 +378,11 @@ namespace Ryujinx.Audio.Renderer.Server GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); } - _commandBuffer.GenerateVolumeRamp(voiceState.PreviousVolume, - voiceState.Volume, - _rendererContext.MixBufferCount + (uint)channelIndex, - nodeId); + _commandBuffer.GenerateVolumeRamp( + voiceState.PreviousVolume, + voiceState.Volume, + _rendererContext.MixBufferCount + (uint)channelIndex, + nodeId); if (performanceInitialized) { @@ -291,15 +399,13 @@ namespace Ryujinx.Audio.Renderer.Server while (true) { - Span destinationSpan = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId); + SplitterDestination destination = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId); - if (destinationSpan.IsEmpty) + if (destination.IsNull) { break; } - ref SplitterDestination destination = ref destinationSpan[0]; - destinationId += (int)channelsCount; if (destination.IsConfigured()) @@ -310,13 +416,27 @@ namespace Ryujinx.Audio.Renderer.Server { ref MixState mix = ref _mixContext.GetState(mixId); - GenerateVoiceMix(destination.MixBufferVolume, - destination.PreviousMixBufferVolume, - dspStateMemory, - mix.BufferOffset, - mix.BufferCount, - _rendererContext.MixBufferCount + (uint)channelIndex, - nodeId); + if (destination.IsBiquadFilterEnabled()) + { + GenerateVoiceMixWithSplitter( + destination, + dspStateMemory, + mix.BufferOffset, + mix.BufferCount, + _rendererContext.MixBufferCount + (uint)channelIndex, + nodeId); + } + else + { + GenerateVoiceMix( + destination.MixBufferVolume, + destination.PreviousMixBufferVolume, + dspStateMemory, + mix.BufferOffset, + mix.BufferCount, + _rendererContext.MixBufferCount + (uint)channelIndex, + nodeId); + } destination.MarkAsNeedToUpdateInternalState(); } @@ -337,13 +457,14 @@ namespace Ryujinx.Audio.Renderer.Server GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); } - GenerateVoiceMix(channelResource.Mix.AsSpan(), - channelResource.PreviousMix.AsSpan(), - dspStateMemory, - mix.BufferOffset, - mix.BufferCount, - _rendererContext.MixBufferCount + (uint)channelIndex, - nodeId); + GenerateVoiceMix( + channelResource.Mix.AsSpan(), + channelResource.PreviousMix.AsSpan(), + dspStateMemory, + mix.BufferOffset, + mix.BufferCount, + _rendererContext.MixBufferCount + (uint)channelIndex, + nodeId); if (performanceInitialized) { @@ -409,10 +530,11 @@ namespace Ryujinx.Audio.Renderer.Server { if (effect.Parameter.Volumes[i] != 0.0f) { - _commandBuffer.GenerateMix((uint)bufferOffset + effect.Parameter.Input[i], - (uint)bufferOffset + effect.Parameter.Output[i], - nodeId, - effect.Parameter.Volumes[i]); + _commandBuffer.GenerateMix( + (uint)bufferOffset + effect.Parameter.Input[i], + (uint)bufferOffset + effect.Parameter.Output[i], + nodeId, + effect.Parameter.Volumes[i]); } } } @@ -447,17 +569,18 @@ namespace Ryujinx.Audio.Renderer.Server updateCount = newUpdateCount; } - _commandBuffer.GenerateAuxEffect(bufferOffset, - effect.Parameter.Input[i], - effect.Parameter.Output[i], - ref effect.State, - effect.IsEnabled, - effect.Parameter.BufferStorageSize, - effect.State.SendBufferInfoBase, - effect.State.ReturnBufferInfoBase, - updateCount, - writeOffset, - nodeId); + _commandBuffer.GenerateAuxEffect( + bufferOffset, + effect.Parameter.Input[i], + effect.Parameter.Output[i], + ref effect.State, + effect.IsEnabled, + effect.Parameter.BufferStorageSize, + effect.State.SendBufferInfoBase, + effect.State.ReturnBufferInfoBase, + updateCount, + writeOffset, + nodeId); writeOffset = newUpdateCount; @@ -500,7 +623,7 @@ namespace Ryujinx.Audio.Renderer.Server if (effect.IsEnabled) { bool needInitialization = effect.Parameter.Status == UsageState.Invalid || - (effect.Parameter.Status == UsageState.New && !_rendererContext.BehaviourContext.IsBiquadFilterEffectStateClearBugFixed()); + (effect.Parameter.Status == UsageState.New && !_rendererContext.BehaviourContext.IsBiquadFilterEffectStateClearBugFixed()); BiquadFilterParameter parameter = new() { @@ -512,11 +635,14 @@ namespace Ryujinx.Audio.Renderer.Server for (int i = 0; i < effect.Parameter.ChannelCount; i++) { - _commandBuffer.GenerateBiquadFilter((int)bufferOffset, ref parameter, effect.State.Slice(i, 1), - effect.Parameter.Input[i], - effect.Parameter.Output[i], - needInitialization, - nodeId); + _commandBuffer.GenerateBiquadFilter( + (int)bufferOffset, + ref parameter, + effect.State.Slice(i, 1), + effect.Parameter.Input[i], + effect.Parameter.Output[i], + needInitialization, + nodeId); } } else @@ -591,15 +717,16 @@ namespace Ryujinx.Audio.Renderer.Server updateCount = newUpdateCount; } - _commandBuffer.GenerateCaptureEffect(bufferOffset, - effect.Parameter.Input[i], - effect.State.SendBufferInfo, - effect.IsEnabled, - effect.Parameter.BufferStorageSize, - effect.State.SendBufferInfoBase, - updateCount, - writeOffset, - nodeId); + _commandBuffer.GenerateCaptureEffect( + bufferOffset, + effect.Parameter.Input[i], + effect.State.SendBufferInfo, + effect.IsEnabled, + effect.Parameter.BufferStorageSize, + effect.State.SendBufferInfoBase, + updateCount, + writeOffset, + nodeId); writeOffset = newUpdateCount; @@ -608,15 +735,28 @@ namespace Ryujinx.Audio.Renderer.Server } } - private void GenerateCompressorEffect(uint bufferOffset, CompressorEffect effect, int nodeId) + private void GenerateCompressorEffect(uint bufferOffset, CompressorEffect effect, int nodeId, int effectId) { Debug.Assert(effect.Type == EffectType.Compressor); - _commandBuffer.GenerateCompressorEffect(bufferOffset, - effect.Parameter, - effect.State, - effect.IsEnabled, - nodeId); + Memory dspResultState; + + if (effect.Parameter.StatisticsEnabled) + { + dspResultState = _effectContext.GetDspStateMemory(effectId); + } + else + { + dspResultState = Memory.Empty; + } + + _commandBuffer.GenerateCompressorEffect( + bufferOffset, + effect.Parameter, + effect.State, + dspResultState, + effect.IsEnabled, + nodeId); } private void GenerateEffect(ref MixState mix, int effectId, BaseEffect effect) @@ -629,8 +769,11 @@ namespace Ryujinx.Audio.Renderer.Server bool performanceInitialized = false; - if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, effect.GetPerformanceDetailType(), - isFinalMix ? PerformanceEntryType.FinalMix : PerformanceEntryType.SubMix, nodeId)) + if (_performanceManager != null && _performanceManager.GetNextEntry( + out performanceEntry, + effect.GetPerformanceDetailType(), + isFinalMix ? PerformanceEntryType.FinalMix : PerformanceEntryType.SubMix, + nodeId)) { performanceInitialized = true; @@ -664,7 +807,7 @@ namespace Ryujinx.Audio.Renderer.Server GenerateCaptureEffect(mix.BufferOffset, (CaptureBufferEffect)effect, nodeId); break; case EffectType.Compressor: - GenerateCompressorEffect(mix.BufferOffset, (CompressorEffect)effect, nodeId); + GenerateCompressorEffect(mix.BufferOffset, (CompressorEffect)effect, nodeId, effectId); break; default: throw new NotImplementedException($"Unsupported effect type {effect.Type}"); @@ -706,6 +849,85 @@ namespace Ryujinx.Audio.Renderer.Server } } + private void GenerateMixWithSplitter( + uint inputBufferIndex, + uint outputBufferIndex, + float volume, + SplitterDestination destination, + ref bool isFirstMixBuffer, + int nodeId) + { + ref BiquadFilterParameter bqf0 = ref destination.GetBiquadFilterParameter(0); + ref BiquadFilterParameter bqf1 = ref destination.GetBiquadFilterParameter(1); + + Memory bqfState = _splitterContext.GetBiquadFilterState(destination); + + if (bqf0.Enable && bqf1.Enable) + { + _commandBuffer.GenerateMultiTapBiquadFilterAndMix( + 0f, + volume, + inputBufferIndex, + outputBufferIndex, + 0, + Memory.Empty, + ref bqf0, + ref bqf1, + bqfState[..1], + bqfState.Slice(1, 1), + bqfState.Slice(2, 1), + bqfState.Slice(3, 1), + !destination.IsBiquadFilterEnabledPrev(), + !destination.IsBiquadFilterEnabledPrev(), + false, + isFirstMixBuffer, + nodeId); + + destination.UpdateBiquadFilterEnabledPrev(0); + destination.UpdateBiquadFilterEnabledPrev(1); + } + else if (bqf0.Enable) + { + _commandBuffer.GenerateBiquadFilterAndMix( + 0f, + volume, + inputBufferIndex, + outputBufferIndex, + 0, + Memory.Empty, + ref bqf0, + bqfState[..1], + bqfState.Slice(1, 1), + !destination.IsBiquadFilterEnabledPrev(), + false, + isFirstMixBuffer, + nodeId); + + destination.UpdateBiquadFilterEnabledPrev(0); + } + else if (bqf1.Enable) + { + _commandBuffer.GenerateBiquadFilterAndMix( + 0f, + volume, + inputBufferIndex, + outputBufferIndex, + 0, + Memory.Empty, + ref bqf1, + bqfState[..1], + bqfState.Slice(1, 1), + !destination.IsBiquadFilterEnabledPrev(), + false, + isFirstMixBuffer, + nodeId); + + destination.UpdateBiquadFilterEnabledPrev(1); + } + + isFirstMixBuffer = false; + } + private void GenerateMix(ref MixState mix) { if (mix.HasAnyDestination()) @@ -722,15 +944,13 @@ namespace Ryujinx.Audio.Renderer.Server { int destinationIndex = destinationId++; - Span destinationSpan = _splitterContext.GetDestination((int)mix.DestinationSplitterId, destinationIndex); + SplitterDestination destination = _splitterContext.GetDestination((int)mix.DestinationSplitterId, destinationIndex); - if (destinationSpan.IsEmpty) + if (destination.IsNull) { break; } - ref SplitterDestination destination = ref destinationSpan[0]; - if (destination.IsConfigured()) { int mixId = destination.DestinationId; @@ -741,16 +961,32 @@ namespace Ryujinx.Audio.Renderer.Server uint inputBufferIndex = mix.BufferOffset + ((uint)destinationIndex % mix.BufferCount); + bool isFirstMixBuffer = true; + for (uint bufferDestinationIndex = 0; bufferDestinationIndex < destinationMix.BufferCount; bufferDestinationIndex++) { float volume = mix.Volume * destination.GetMixVolume((int)bufferDestinationIndex); if (volume != 0.0f) { - _commandBuffer.GenerateMix(inputBufferIndex, - destinationMix.BufferOffset + bufferDestinationIndex, - mix.NodeId, - volume); + if (destination.IsBiquadFilterEnabled()) + { + GenerateMixWithSplitter( + inputBufferIndex, + destinationMix.BufferOffset + bufferDestinationIndex, + volume, + destination, + ref isFirstMixBuffer, + mix.NodeId); + } + else + { + _commandBuffer.GenerateMix( + inputBufferIndex, + destinationMix.BufferOffset + bufferDestinationIndex, + mix.NodeId, + volume); + } } } } @@ -770,10 +1006,11 @@ namespace Ryujinx.Audio.Renderer.Server if (volume != 0.0f) { - _commandBuffer.GenerateMix(mix.BufferOffset + bufferIndex, - destinationMix.BufferOffset + bufferDestinationIndex, - mix.NodeId, - volume); + _commandBuffer.GenerateMix( + mix.BufferOffset + bufferIndex, + destinationMix.BufferOffset + bufferDestinationIndex, + mix.NodeId, + volume); } } } @@ -783,11 +1020,12 @@ namespace Ryujinx.Audio.Renderer.Server private void GenerateSubMix(ref MixState subMix) { - _commandBuffer.GenerateDepopForMixBuffersCommand(_rendererContext.DepopBuffer, - subMix.BufferOffset, - subMix.BufferCount, - subMix.NodeId, - subMix.SampleRate); + _commandBuffer.GenerateDepopForMixBuffers( + _rendererContext.DepopBuffer, + subMix.BufferOffset, + subMix.BufferCount, + subMix.NodeId, + subMix.SampleRate); GenerateEffects(ref subMix); @@ -847,11 +1085,12 @@ namespace Ryujinx.Audio.Renderer.Server { ref MixState finalMix = ref _mixContext.GetFinalState(); - _commandBuffer.GenerateDepopForMixBuffersCommand(_rendererContext.DepopBuffer, - finalMix.BufferOffset, - finalMix.BufferCount, - finalMix.NodeId, - finalMix.SampleRate); + _commandBuffer.GenerateDepopForMixBuffers( + _rendererContext.DepopBuffer, + finalMix.BufferOffset, + finalMix.BufferCount, + finalMix.NodeId, + finalMix.SampleRate); GenerateEffects(ref finalMix); @@ -882,9 +1121,10 @@ namespace Ryujinx.Audio.Renderer.Server GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); } - _commandBuffer.GenerateVolume(finalMix.Volume, - finalMix.BufferOffset + bufferIndex, - nodeId); + _commandBuffer.GenerateVolume( + finalMix.Volume, + finalMix.BufferOffset + bufferIndex, + nodeId); if (performanceSubInitialized) { @@ -938,41 +1178,45 @@ namespace Ryujinx.Audio.Renderer.Server if (useCustomDownMixingCommand) { - _commandBuffer.GenerateDownMixSurroundToStereo(finalMix.BufferOffset, - sink.Parameter.Input.AsSpan(), - sink.Parameter.Input.AsSpan(), - sink.DownMixCoefficients, - Constants.InvalidNodeId); + _commandBuffer.GenerateDownMixSurroundToStereo( + finalMix.BufferOffset, + sink.Parameter.Input.AsSpan(), + sink.Parameter.Input.AsSpan(), + sink.DownMixCoefficients, + Constants.InvalidNodeId); } // NOTE: We do the downmixing at the DSP level as it's easier that way. else if (_rendererContext.ChannelCount == 2 && sink.Parameter.InputCount == 6) { - _commandBuffer.GenerateDownMixSurroundToStereo(finalMix.BufferOffset, - sink.Parameter.Input.AsSpan(), - sink.Parameter.Input.AsSpan(), - Constants.DefaultSurroundToStereoCoefficients, - Constants.InvalidNodeId); + _commandBuffer.GenerateDownMixSurroundToStereo( + finalMix.BufferOffset, + sink.Parameter.Input.AsSpan(), + sink.Parameter.Input.AsSpan(), + Constants.DefaultSurroundToStereoCoefficients, + Constants.InvalidNodeId); } CommandList commandList = _commandBuffer.CommandList; if (sink.UpsamplerState != null) { - _commandBuffer.GenerateUpsample(finalMix.BufferOffset, - sink.UpsamplerState, - sink.Parameter.InputCount, - sink.Parameter.Input.AsSpan(), - commandList.BufferCount, - commandList.SampleCount, - commandList.SampleRate, - Constants.InvalidNodeId); + _commandBuffer.GenerateUpsample( + finalMix.BufferOffset, + sink.UpsamplerState, + sink.Parameter.InputCount, + sink.Parameter.Input.AsSpan(), + commandList.BufferCount, + commandList.SampleCount, + commandList.SampleRate, + Constants.InvalidNodeId); } - _commandBuffer.GenerateDeviceSink(finalMix.BufferOffset, - sink, - _rendererContext.SessionId, - commandList.Buffers, - Constants.InvalidNodeId); + _commandBuffer.GenerateDeviceSink( + finalMix.BufferOffset, + sink, + _rendererContext.SessionId, + commandList.Buffers, + Constants.InvalidNodeId); } private void GenerateSink(BaseSink sink, ref MixState finalMix) diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs index d95e9aa71..cff754b82 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs @@ -170,7 +170,7 @@ namespace Ryujinx.Audio.Renderer.Server return 0; } - public uint Estimate(GroupedBiquadFilterCommand command) + public uint Estimate(MultiTapBiquadFilterCommand command) { return 0; } @@ -184,5 +184,15 @@ namespace Ryujinx.Audio.Renderer.Server { return 0; } + + public uint Estimate(BiquadFilterAndMixCommand command) + { + return 0; + } + + public uint Estimate(MultiTapBiquadFilterAndMixCommand command) + { + return 0; + } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs index 929aaf383..ef1326924 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs @@ -462,7 +462,7 @@ namespace Ryujinx.Audio.Renderer.Server return 0; } - public uint Estimate(GroupedBiquadFilterCommand command) + public uint Estimate(MultiTapBiquadFilterCommand command) { return 0; } @@ -476,5 +476,15 @@ namespace Ryujinx.Audio.Renderer.Server { return 0; } + + public uint Estimate(BiquadFilterAndMixCommand command) + { + return 0; + } + + public uint Estimate(MultiTapBiquadFilterAndMixCommand command) + { + return 0; + } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs index 8ae4bc059..31a5347b4 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs @@ -632,7 +632,7 @@ namespace Ryujinx.Audio.Renderer.Server }; } - public virtual uint Estimate(GroupedBiquadFilterCommand command) + public virtual uint Estimate(MultiTapBiquadFilterCommand command) { return 0; } @@ -646,5 +646,15 @@ namespace Ryujinx.Audio.Renderer.Server { return 0; } + + public virtual uint Estimate(BiquadFilterAndMixCommand command) + { + return 0; + } + + public virtual uint Estimate(MultiTapBiquadFilterAndMixCommand command) + { + return 0; + } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion4.cs b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion4.cs index 25bc67cd9..fb357120d 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion4.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion4.cs @@ -10,7 +10,7 @@ namespace Ryujinx.Audio.Renderer.Server { public CommandProcessingTimeEstimatorVersion4(uint sampleCount, uint bufferCount) : base(sampleCount, bufferCount) { } - public override uint Estimate(GroupedBiquadFilterCommand command) + public override uint Estimate(MultiTapBiquadFilterCommand command) { Debug.Assert(SampleCount == 160 || SampleCount == 240); diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs index 7135c1c4f..bc9ba073d 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs @@ -169,14 +169,28 @@ namespace Ryujinx.Audio.Renderer.Server { if (command.Enabled) { - return command.Parameter.ChannelCount switch + if (command.Parameter.StatisticsEnabled) { - 1 => 34431, - 2 => 44253, - 4 => 63827, - 6 => 83361, - _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"), - }; + return command.Parameter.ChannelCount switch + { + 1 => 22100, + 2 => 33211, + 4 => 41587, + 6 => 58819, + _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"), + }; + } + else + { + return command.Parameter.ChannelCount switch + { + 1 => 19052, + 2 => 29852, + 4 => 37904, + 6 => 55020, + _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"), + }; + } } return command.Parameter.ChannelCount switch @@ -191,14 +205,28 @@ namespace Ryujinx.Audio.Renderer.Server if (command.Enabled) { - return command.Parameter.ChannelCount switch + if (command.Parameter.StatisticsEnabled) { - 1 => 51095, - 2 => 65693, - 4 => 95383, - 6 => 124510, - _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"), - }; + return command.Parameter.ChannelCount switch + { + 1 => 32518, + 2 => 49102, + 4 => 61685, + 6 => 87250, + _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"), + }; + } + else + { + return command.Parameter.ChannelCount switch + { + 1 => 27963, + 2 => 44016, + 4 => 56183, + 6 => 81862, + _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"), + }; + } } return command.Parameter.ChannelCount switch @@ -210,5 +238,53 @@ namespace Ryujinx.Audio.Renderer.Server _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"), }; } + + public override uint Estimate(BiquadFilterAndMixCommand command) + { + Debug.Assert(SampleCount == 160 || SampleCount == 240); + + if (command.HasVolumeRamp) + { + if (SampleCount == 160) + { + return 5204; + } + + return 6683; + } + else + { + if (SampleCount == 160) + { + return 3427; + } + + return 4752; + } + } + + public override uint Estimate(MultiTapBiquadFilterAndMixCommand command) + { + Debug.Assert(SampleCount == 160 || SampleCount == 240); + + if (command.HasVolumeRamp) + { + if (SampleCount == 160) + { + return 7939; + } + + return 10669; + } + else + { + if (SampleCount == 160) + { + return 6256; + } + + return 8683; + } + } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/AuxiliaryBufferEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/AuxiliaryBufferEffect.cs index 57ca266f4..74a9baff2 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/AuxiliaryBufferEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/AuxiliaryBufferEffect.cs @@ -33,21 +33,21 @@ namespace Ryujinx.Audio.Renderer.Server.Effect return WorkBuffers[index].GetReference(true); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion1 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion2 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter + public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); - UpdateParameterBase(ref parameter); + UpdateParameterBase(in parameter); Parameter = MemoryMarshal.Cast(parameter.SpecificData)[0]; IsEnabled = parameter.IsEnabled; diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs index a9716db2a..77d9b5c29 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs @@ -81,7 +81,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect /// /// The user parameter. /// Returns true if the sent by the user matches the internal . - public bool IsTypeValid(ref T parameter) where T : unmanaged, IEffectInParameter + public bool IsTypeValid(in T parameter) where T : unmanaged, IEffectInParameter { return parameter.Type == TargetEffectType; } @@ -98,7 +98,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect /// Update the internal common parameters from a user parameter. /// /// The user parameter. - protected void UpdateParameterBase(ref T parameter) where T : unmanaged, IEffectInParameter + protected void UpdateParameterBase(in T parameter) where T : unmanaged, IEffectInParameter { MixId = parameter.MixId; ProcessingOrder = parameter.ProcessingOrder; @@ -139,7 +139,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect /// /// Initialize the given result state. /// - /// The state to initalize + /// The state to initialize public virtual void InitializeResultState(ref EffectResultState state) { } /// @@ -155,9 +155,9 @@ namespace Ryujinx.Audio.Renderer.Server.Effect /// The possible that was generated. /// The user parameter. /// The mapper to use. - public virtual void Update(out ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper) + public virtual void Update(out ErrorInfo updateErrorInfo, in EffectInParameterVersion1 parameter, PoolMapper mapper) { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); updateErrorInfo = new ErrorInfo(); } @@ -168,9 +168,9 @@ namespace Ryujinx.Audio.Renderer.Server.Effect /// The possible that was generated. /// The user parameter. /// The mapper to use. - public virtual void Update(out ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper) + public virtual void Update(out ErrorInfo updateErrorInfo, in EffectInParameterVersion2 parameter, PoolMapper mapper) { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); updateErrorInfo = new ErrorInfo(); } diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs index b987f7c85..3b3e1021c 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs @@ -35,21 +35,21 @@ namespace Ryujinx.Audio.Renderer.Server.Effect public override EffectType TargetEffectType => EffectType.BiquadFilter; - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion1 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion2 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter + public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); - UpdateParameterBase(ref parameter); + UpdateParameterBase(in parameter); Parameter = MemoryMarshal.Cast(parameter.SpecificData)[0]; IsEnabled = parameter.IsEnabled; diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/BufferMixEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/BufferMixEffect.cs index d6cb9cfa3..5d82b5ae8 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/BufferMixEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/BufferMixEffect.cs @@ -19,21 +19,21 @@ namespace Ryujinx.Audio.Renderer.Server.Effect public override EffectType TargetEffectType => EffectType.BufferMix; - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion1 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion2 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter + public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); - UpdateParameterBase(ref parameter); + UpdateParameterBase(in parameter); Parameter = MemoryMarshal.Cast(parameter.SpecificData)[0]; IsEnabled = parameter.IsEnabled; diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/CaptureBufferEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/CaptureBufferEffect.cs index 5be4b4ed5..6917222f0 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/CaptureBufferEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/CaptureBufferEffect.cs @@ -32,21 +32,21 @@ namespace Ryujinx.Audio.Renderer.Server.Effect return WorkBuffers[index].GetReference(true); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion1 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion2 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter + public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); - UpdateParameterBase(ref parameter); + UpdateParameterBase(in parameter); Parameter = MemoryMarshal.Cast(parameter.SpecificData)[0]; IsEnabled = parameter.IsEnabled; diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs index 826c32cb0..de0f44e47 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs @@ -39,17 +39,17 @@ namespace Ryujinx.Audio.Renderer.Server.Effect return GetSingleBuffer(); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion1 parameter, PoolMapper mapper) { // Nintendo doesn't do anything here but we still require updateErrorInfo to be initialised. updateErrorInfo = new BehaviourParameter.ErrorInfo(); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion2 parameter, PoolMapper mapper) { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); - UpdateParameterBase(ref parameter); + UpdateParameterBase(in parameter); Parameter = MemoryMarshal.Cast(parameter.SpecificData)[0]; IsEnabled = parameter.IsEnabled; @@ -62,6 +62,19 @@ namespace Ryujinx.Audio.Renderer.Server.Effect UpdateUsageStateForCommandGeneration(); Parameter.Status = UsageState.Enabled; + Parameter.StatisticsReset = false; + } + + public override void InitializeResultState(ref EffectResultState state) + { + ref CompressorStatistics statistics = ref MemoryMarshal.Cast(state.SpecificData)[0]; + + statistics.Reset(Parameter.ChannelCount); + } + + public override void UpdateResultState(ref EffectResultState destState, ref EffectResultState srcState) + { + destState = srcState; } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/DelayEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/DelayEffect.cs index 43cabb7db..9db1ce465 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/DelayEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/DelayEffect.cs @@ -37,19 +37,19 @@ namespace Ryujinx.Audio.Renderer.Server.Effect return GetSingleBuffer(); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion1 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion2 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter + public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); ref DelayParameter delayParameter = ref MemoryMarshal.Cast(parameter.SpecificData)[0]; @@ -57,7 +57,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect if (delayParameter.IsChannelCountMaxValid()) { - UpdateParameterBase(ref parameter); + UpdateParameterBase(in parameter); UsageState oldParameterStatus = Parameter.Status; diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/LimiterEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/LimiterEffect.cs index 3e2f7326d..d9b3d5666 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/LimiterEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/LimiterEffect.cs @@ -39,25 +39,25 @@ namespace Ryujinx.Audio.Renderer.Server.Effect return GetSingleBuffer(); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion1 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion2 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter + public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); ref LimiterParameter limiterParameter = ref MemoryMarshal.Cast(parameter.SpecificData)[0]; updateErrorInfo = new BehaviourParameter.ErrorInfo(); - UpdateParameterBase(ref parameter); + UpdateParameterBase(in parameter); Parameter = limiterParameter; diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/Reverb3dEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/Reverb3dEffect.cs index f9d7f4943..4b13cfec6 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/Reverb3dEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/Reverb3dEffect.cs @@ -36,19 +36,19 @@ namespace Ryujinx.Audio.Renderer.Server.Effect return GetSingleBuffer(); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion1 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion2 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter + public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); ref Reverb3dParameter reverbParameter = ref MemoryMarshal.Cast(parameter.SpecificData)[0]; @@ -56,7 +56,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect if (reverbParameter.IsChannelCountMaxValid()) { - UpdateParameterBase(ref parameter); + UpdateParameterBase(in parameter); UsageState oldParameterStatus = Parameter.ParameterStatus; diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/ReverbEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/ReverbEffect.cs index 6fdf8fc23..aa6e67448 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/ReverbEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/ReverbEffect.cs @@ -39,19 +39,19 @@ namespace Ryujinx.Audio.Renderer.Server.Effect return GetSingleBuffer(); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion1 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion2 parameter, PoolMapper mapper) { - Update(out updateErrorInfo, ref parameter, mapper); + Update(out updateErrorInfo, in parameter, mapper); } - public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter + public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); ref ReverbParameter reverbParameter = ref MemoryMarshal.Cast(parameter.SpecificData)[0]; @@ -59,7 +59,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect if (reverbParameter.IsChannelCountMaxValid()) { - UpdateParameterBase(ref parameter); + UpdateParameterBase(in parameter); UsageState oldParameterStatus = Parameter.Status; diff --git a/src/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs b/src/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs index 27b22363a..9c4312ad6 100644 --- a/src/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs +++ b/src/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs @@ -33,8 +33,10 @@ namespace Ryujinx.Audio.Renderer.Server uint Estimate(UpsampleCommand command); uint Estimate(LimiterCommandVersion1 command); uint Estimate(LimiterCommandVersion2 command); - uint Estimate(GroupedBiquadFilterCommand command); + uint Estimate(MultiTapBiquadFilterCommand command); uint Estimate(CaptureBufferCommand command); uint Estimate(CompressorCommand command); + uint Estimate(BiquadFilterAndMixCommand command); + uint Estimate(MultiTapBiquadFilterAndMixCommand command); } } diff --git a/src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs index 391b80f8d..f67d0c124 100644 --- a/src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs +++ b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs @@ -249,7 +249,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool /// Input user parameter. /// Output user parameter. /// Returns the of the operations performed. - public UpdateResult Update(ref MemoryPoolState memoryPool, ref MemoryPoolInParameter inParameter, ref MemoryPoolOutStatus outStatus) + public UpdateResult Update(ref MemoryPoolState memoryPool, in MemoryPoolInParameter inParameter, ref MemoryPoolOutStatus outStatus) { MemoryPoolUserState inputState = inParameter.State; diff --git a/src/Ryujinx.Audio/Renderer/Server/Mix/MixState.cs b/src/Ryujinx.Audio/Renderer/Server/Mix/MixState.cs index 88ae44831..5ba58ea5b 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Mix/MixState.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Mix/MixState.cs @@ -195,7 +195,7 @@ namespace Ryujinx.Audio.Renderer.Server.Mix /// The input parameter of the mix. /// The splitter context. /// Return true, new connections were done on the adjacency matrix. - private bool UpdateConnection(EdgeMatrix edgeMatrix, ref MixParameter parameter, ref SplitterContext splitterContext) + private bool UpdateConnection(EdgeMatrix edgeMatrix, in MixParameter parameter, ref SplitterContext splitterContext) { bool hasNewConnections; @@ -225,11 +225,11 @@ namespace Ryujinx.Audio.Renderer.Server.Mix for (int i = 0; i < splitter.DestinationCount; i++) { - Span destination = splitter.GetData(i); + SplitterDestination destination = splitter.GetData(i); - if (!destination.IsEmpty) + if (!destination.IsNull) { - int destinationMixId = destination[0].DestinationId; + int destinationMixId = destination.DestinationId; if (destinationMixId != UnusedMixId) { @@ -259,7 +259,7 @@ namespace Ryujinx.Audio.Renderer.Server.Mix /// The splitter context. /// The behaviour context. /// Return true if the mix was changed. - public bool Update(EdgeMatrix edgeMatrix, ref MixParameter parameter, EffectContext effectContext, SplitterContext splitterContext, BehaviourContext behaviourContext) + public bool Update(EdgeMatrix edgeMatrix, in MixParameter parameter, EffectContext effectContext, SplitterContext splitterContext, BehaviourContext behaviourContext) { bool isDirty; @@ -273,7 +273,7 @@ namespace Ryujinx.Audio.Renderer.Server.Mix if (behaviourContext.IsSplitterSupported()) { - isDirty = UpdateConnection(edgeMatrix, ref parameter, ref splitterContext); + isDirty = UpdateConnection(edgeMatrix, in parameter, ref splitterContext); } else { diff --git a/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs b/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs index 0a035916c..da5a0ad45 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs @@ -18,16 +18,12 @@ namespace Ryujinx.Audio.Renderer.Server.Performance if (version == 2) { - return (ulong)PerformanceManagerGeneric.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); + return (ulong)PerformanceManagerGeneric.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); } if (version == 1) { - return (ulong)PerformanceManagerGeneric.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); + return (ulong)PerformanceManagerGeneric.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); } throw new NotImplementedException($"Unknown Performance metrics data format version {version}"); diff --git a/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManagerGeneric.cs b/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManagerGeneric.cs index 5a70a1bcf..2e5d25b9c 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManagerGeneric.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManagerGeneric.cs @@ -234,7 +234,7 @@ namespace Ryujinx.Audio.Renderer.Server.Performance { performanceEntry = null; - if (_entryDetailIndex > MaxFrameDetailCount) + if (_entryDetailIndex >= MaxFrameDetailCount) { return false; } @@ -245,7 +245,7 @@ namespace Ryujinx.Audio.Renderer.Server.Performance EntryCountOffset = (uint)CurrentHeader.GetEntryCountOffset(), }; - uint baseEntryOffset = (uint)(Unsafe.SizeOf() + GetEntriesSize() + Unsafe.SizeOf() * _entryDetailIndex); + uint baseEntryOffset = (uint)(Unsafe.SizeOf() + GetEntriesSize() + Unsafe.SizeOf() * _entryDetailIndex); ref TEntryDetail entryDetail = ref EntriesDetail[_entryDetailIndex]; diff --git a/src/Ryujinx.Audio/Renderer/Server/Sink/BaseSink.cs b/src/Ryujinx.Audio/Renderer/Server/Sink/BaseSink.cs index d36c5e260..8c65e09bc 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Sink/BaseSink.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Sink/BaseSink.cs @@ -59,7 +59,7 @@ namespace Ryujinx.Audio.Renderer.Server.Sink /// /// The user parameter. /// Return true, if the sent by the user match the internal . - public bool IsTypeValid(ref SinkInParameter parameter) + public bool IsTypeValid(in SinkInParameter parameter) { return parameter.Type == TargetSinkType; } @@ -76,7 +76,7 @@ namespace Ryujinx.Audio.Renderer.Server.Sink /// Update the internal common parameters from user parameter. /// /// The user parameter. - protected void UpdateStandardParameter(ref SinkInParameter parameter) + protected void UpdateStandardParameter(in SinkInParameter parameter) { if (IsUsed != parameter.IsUsed) { @@ -92,9 +92,9 @@ namespace Ryujinx.Audio.Renderer.Server.Sink /// The user parameter. /// The user output status. /// The mapper to use. - public virtual void Update(out ErrorInfo errorInfo, ref SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) + public virtual void Update(out ErrorInfo errorInfo, in SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); errorInfo = new ErrorInfo(); } diff --git a/src/Ryujinx.Audio/Renderer/Server/Sink/CircularBufferSink.cs b/src/Ryujinx.Audio/Renderer/Server/Sink/CircularBufferSink.cs index 097757988..f2751cf29 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Sink/CircularBufferSink.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Sink/CircularBufferSink.cs @@ -44,18 +44,18 @@ namespace Ryujinx.Audio.Renderer.Server.Sink public override SinkType TargetSinkType => SinkType.CircularBuffer; - public override void Update(out BehaviourParameter.ErrorInfo errorInfo, ref SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo errorInfo, in SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) { errorInfo = new BehaviourParameter.ErrorInfo(); outStatus = new SinkOutStatus(); - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); ref CircularBufferParameter inputDeviceParameter = ref MemoryMarshal.Cast(parameter.SpecificData)[0]; if (parameter.IsUsed != IsUsed || ShouldSkip) { - UpdateStandardParameter(ref parameter); + UpdateStandardParameter(in parameter); if (parameter.IsUsed) { diff --git a/src/Ryujinx.Audio/Renderer/Server/Sink/DeviceSink.cs b/src/Ryujinx.Audio/Renderer/Server/Sink/DeviceSink.cs index e03fe11d4..afe2d4b1b 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Sink/DeviceSink.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Sink/DeviceSink.cs @@ -49,15 +49,15 @@ namespace Ryujinx.Audio.Renderer.Server.Sink public override SinkType TargetSinkType => SinkType.Device; - public override void Update(out BehaviourParameter.ErrorInfo errorInfo, ref SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) + public override void Update(out BehaviourParameter.ErrorInfo errorInfo, in SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) { - Debug.Assert(IsTypeValid(ref parameter)); + Debug.Assert(IsTypeValid(in parameter)); ref DeviceParameter inputDeviceParameter = ref MemoryMarshal.Cast(parameter.SpecificData)[0]; if (parameter.IsUsed != IsUsed) { - UpdateStandardParameter(ref parameter); + UpdateStandardParameter(in parameter); Parameter = inputDeviceParameter; } else diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs index e408692ab..6dddb4315 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs @@ -1,11 +1,13 @@ using Ryujinx.Audio.Renderer.Common; +using Ryujinx.Audio.Renderer.Dsp.State; using Ryujinx.Audio.Renderer.Parameter; using Ryujinx.Audio.Renderer.Utils; using Ryujinx.Common; +using Ryujinx.Common.Extensions; using System; +using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; namespace Ryujinx.Audio.Renderer.Server.Splitter { @@ -14,33 +16,63 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// public class SplitterContext { + /// + /// Amount of biquad filter states per splitter destination. + /// + public const int BqfStatesPerDestination = 4; + /// /// Storage for . /// private Memory _splitters; /// - /// Storage for . + /// Storage for . /// - private Memory _splitterDestinations; + private Memory _splitterDestinationsV1; /// - /// If set to true, trust the user destination count in . + /// Storage for . + /// + private Memory _splitterDestinationsV2; + + /// + /// Splitter biquad filtering states. + /// + private Memory _splitterBqfStates; + + /// + /// Version of the splitter context that is being used, currently can be 1 or 2. + /// + public int Version { get; private set; } + + /// + /// If set to true, trust the user destination count in . /// public bool IsBugFixed { get; private set; } + /// + /// If set to true, the previous mix volume is explicitly resetted using the input parameter, instead of implicitly on first use. + /// + public bool IsSplitterPrevVolumeResetSupported { get; private set; } + /// /// Initialize . /// /// The behaviour context. /// The audio renderer configuration. /// The . + /// Memory to store the biquad filtering state for splitters during processing. /// Return true if the initialization was successful. - public bool Initialize(ref BehaviourContext behaviourContext, ref AudioRendererConfiguration parameter, WorkBufferAllocator workBufferAllocator) + public bool Initialize( + ref BehaviourContext behaviourContext, + ref AudioRendererConfiguration parameter, + WorkBufferAllocator workBufferAllocator, + Memory splitterBqfStates) { if (!behaviourContext.IsSplitterSupported() || parameter.SplitterCount <= 0 || parameter.SplitterDestinationCount <= 0) { - Setup(Memory.Empty, Memory.Empty, false); + Setup(Memory.Empty, Memory.Empty, Memory.Empty, false); return true; } @@ -59,23 +91,64 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter splitter = new SplitterState(splitterId++); } - Memory splitterDestinations = workBufferAllocator.Allocate(parameter.SplitterDestinationCount, - SplitterDestination.Alignment); + Memory splitterDestinationsV1 = Memory.Empty; + Memory splitterDestinationsV2 = Memory.Empty; - if (splitterDestinations.IsEmpty) + if (!behaviourContext.IsBiquadFilterParameterForSplitterEnabled()) { - return false; + Version = 1; + + splitterDestinationsV1 = workBufferAllocator.Allocate(parameter.SplitterDestinationCount, + SplitterDestinationVersion1.Alignment); + + if (splitterDestinationsV1.IsEmpty) + { + return false; + } + + int splitterDestinationId = 0; + foreach (ref SplitterDestinationVersion1 data in splitterDestinationsV1.Span) + { + data = new SplitterDestinationVersion1(splitterDestinationId++); + } + } + else + { + Version = 2; + + splitterDestinationsV2 = workBufferAllocator.Allocate(parameter.SplitterDestinationCount, + SplitterDestinationVersion2.Alignment); + + if (splitterDestinationsV2.IsEmpty) + { + return false; + } + + int splitterDestinationId = 0; + foreach (ref SplitterDestinationVersion2 data in splitterDestinationsV2.Span) + { + data = new SplitterDestinationVersion2(splitterDestinationId++); + } + + if (parameter.SplitterDestinationCount > 0) + { + // Official code stores it in the SplitterDestinationVersion2 struct, + // but we don't to avoid using unsafe code. + + splitterBqfStates.Span.Clear(); + _splitterBqfStates = splitterBqfStates; + } + else + { + _splitterBqfStates = Memory.Empty; + } } - int splitterDestinationId = 0; - foreach (ref SplitterDestination data in splitterDestinations.Span) - { - data = new SplitterDestination(splitterDestinationId++); - } + IsSplitterPrevVolumeResetSupported = behaviourContext.IsSplitterPrevVolumeResetSupported(); SplitterState.InitializeSplitters(splitters.Span); - Setup(splitters, splitterDestinations, behaviourContext.IsSplitterBugFixed()); + Setup(splitters, splitterDestinationsV1, splitterDestinationsV2, behaviourContext.IsSplitterBugFixed()); return true; } @@ -92,7 +165,15 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter if (behaviourContext.IsSplitterSupported()) { size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterCount, SplitterState.Alignment); - size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterDestinationCount, SplitterDestination.Alignment); + + if (behaviourContext.IsBiquadFilterParameterForSplitterEnabled()) + { + size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterDestinationCount, SplitterDestinationVersion2.Alignment); + } + else + { + size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterDestinationCount, SplitterDestinationVersion1.Alignment); + } if (behaviourContext.IsSplitterBugFixed()) { @@ -109,12 +190,18 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// Setup the instance. /// /// The storage. - /// The storage. - /// If set to true, trust the user destination count in . - private void Setup(Memory splitters, Memory splitterDestinations, bool isBugFixed) + /// The storage. + /// The storage. + /// If set to true, trust the user destination count in . + private void Setup( + Memory splitters, + Memory splitterDestinationsV1, + Memory splitterDestinationsV2, + bool isBugFixed) { _splitters = splitters; - _splitterDestinations = splitterDestinations; + _splitterDestinationsV1 = splitterDestinationsV1; + _splitterDestinationsV2 = splitterDestinationsV2; IsBugFixed = isBugFixed; } @@ -140,7 +227,9 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter return 0; } - return _splitterDestinations.Length / _splitters.Length; + int length = _splitterDestinationsV2.IsEmpty ? _splitterDestinationsV1.Length : _splitterDestinationsV2.Length; + + return length / _splitters.Length; } /// @@ -148,11 +237,11 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// /// The splitter header. /// The raw data after the splitter header. - private void UpdateState(scoped ref SplitterInParameterHeader inputHeader, ref ReadOnlySpan input) + private void UpdateState(in SplitterInParameterHeader inputHeader, ref SequenceReader input) { for (int i = 0; i < inputHeader.SplitterCount; i++) { - SplitterInParameter parameter = MemoryMarshal.Read(input); + ref readonly SplitterInParameter parameter = ref input.GetRefOrRefToCopy(out _); Debug.Assert(parameter.IsMagicValid()); @@ -162,37 +251,78 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter { ref SplitterState splitter = ref GetState(parameter.Id); - splitter.Update(this, ref parameter, input[Unsafe.SizeOf()..]); + splitter.Update(this, in parameter, ref input); } - input = input[(0x1C + parameter.DestinationCount * 4)..]; + // NOTE: there are 12 bytes of unused/unknown data after the destination IDs array. + input.Advance(0xC); + } + else + { + input.Rewind(Unsafe.SizeOf()); + break; } } } /// - /// Update one or multiple from user parameters. + /// Update one splitter destination data from user parameters. + /// + /// The raw data after the splitter header. + /// True if the update was successful, false otherwise + private bool UpdateData(ref SequenceReader input) where T : unmanaged, ISplitterDestinationInParameter + { + ref readonly T parameter = ref input.GetRefOrRefToCopy(out _); + + Debug.Assert(parameter.IsMagicValid()); + + if (parameter.IsMagicValid()) + { + int length = _splitterDestinationsV2.IsEmpty ? _splitterDestinationsV1.Length : _splitterDestinationsV2.Length; + + if (parameter.Id >= 0 && parameter.Id < length) + { + SplitterDestination destination = GetDestination(parameter.Id); + + destination.Update(parameter, IsSplitterPrevVolumeResetSupported); + } + + return true; + } + else + { + input.Rewind(Unsafe.SizeOf()); + + return false; + } + } + + /// + /// Update one or multiple splitter destination data from user parameters. /// /// The splitter header. /// The raw data after the splitter header. - private void UpdateData(scoped ref SplitterInParameterHeader inputHeader, ref ReadOnlySpan input) + private void UpdateData(in SplitterInParameterHeader inputHeader, ref SequenceReader input) { for (int i = 0; i < inputHeader.SplitterDestinationCount; i++) { - SplitterDestinationInParameter parameter = MemoryMarshal.Read(input); - - Debug.Assert(parameter.IsMagicValid()); - - if (parameter.IsMagicValid()) + if (Version == 1) { - if (parameter.Id >= 0 && parameter.Id < _splitterDestinations.Length) + if (!UpdateData(ref input)) { - ref SplitterDestination destination = ref GetDestination(parameter.Id); - - destination.Update(parameter); + break; } - - input = input[Unsafe.SizeOf()..]; + } + else if (Version == 2) + { + if (!UpdateData(ref input)) + { + break; + } + } + else + { + Debug.Fail($"Invalid splitter context version {Version}."); } } } @@ -201,36 +331,33 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// Update splitter from user parameters. /// /// The input raw user data. - /// The total consumed size. /// Return true if the update was successful. - public bool Update(ReadOnlySpan input, out int consumedSize) + public bool Update(ref SequenceReader input) { - if (_splitterDestinations.IsEmpty || _splitters.IsEmpty) + if (!UsingSplitter()) { - consumedSize = 0; - return true; } - int originalSize = input.Length; - - SplitterInParameterHeader header = SpanIOHelper.Read(ref input); + ref readonly SplitterInParameterHeader header = ref input.GetRefOrRefToCopy(out _); if (header.IsMagicValid()) { ClearAllNewConnectionFlag(); - UpdateState(ref header, ref input); - UpdateData(ref header, ref input); + UpdateState(in header, ref input); + UpdateData(in header, ref input); - consumedSize = BitUtils.AlignUp(originalSize - input.Length, 0x10); + input.SetConsumed(BitUtils.AlignUp(input.Consumed, 0x10)); return true; } + else + { + input.Rewind(Unsafe.SizeOf()); - consumedSize = 0; - - return false; + return false; + } } /// @@ -244,45 +371,52 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter } /// - /// Get a reference to a at the given . + /// Get a reference to the splitter destination data at the given . /// /// The index to use. - /// A reference to a at the given . - public ref SplitterDestination GetDestination(int id) + /// A reference to the splitter destination data at the given . + public SplitterDestination GetDestination(int id) { - return ref SpanIOHelper.GetFromMemory(_splitterDestinations, id, (uint)_splitterDestinations.Length); + if (_splitterDestinationsV2.IsEmpty) + { + return new SplitterDestination(ref SpanIOHelper.GetFromMemory(_splitterDestinationsV1, id, (uint)_splitterDestinationsV1.Length)); + } + else + { + return new SplitterDestination(ref SpanIOHelper.GetFromMemory(_splitterDestinationsV2, id, (uint)_splitterDestinationsV2.Length)); + } } /// - /// Get a at the given . - /// - /// The index to use. - /// A at the given . - public Memory GetDestinationMemory(int id) - { - return SpanIOHelper.GetMemory(_splitterDestinations, id, (uint)_splitterDestinations.Length); - } - - /// - /// Get a in the at and pass to . + /// Get a in the at and pass to . /// /// The index to use to get the . /// The index of the . - /// A . - public Span GetDestination(int id, int destinationId) + /// A . + public SplitterDestination GetDestination(int id, int destinationId) { ref SplitterState splitter = ref GetState(id); return splitter.GetData(destinationId); } + /// + /// Gets the biquad filter state for a given splitter destination. + /// + /// The splitter destination. + /// Biquad filter state for the specified destination. + public Memory GetBiquadFilterState(SplitterDestination destination) + { + return _splitterBqfStates.Slice(destination.Id * BqfStatesPerDestination, BqfStatesPerDestination); + } + /// /// Return true if the audio renderer has any splitters. /// /// True if the audio renderer has any splitters. public bool UsingSplitter() { - return !_splitters.IsEmpty && !_splitterDestinations.IsEmpty; + return !_splitters.IsEmpty && (!_splitterDestinationsV1.IsEmpty || !_splitterDestinationsV2.IsEmpty); } /// diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs index 1faf7921f..1a46d41fd 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs @@ -1,115 +1,199 @@ using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Common.Utilities; using System; using System.Diagnostics; -using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; namespace Ryujinx.Audio.Renderer.Server.Splitter { /// /// Server state for a splitter destination. /// - [StructLayout(LayoutKind.Sequential, Size = 0xE0, Pack = Alignment)] - public struct SplitterDestination + public ref struct SplitterDestination { - public const int Alignment = 0x10; + private ref SplitterDestinationVersion1 _v1; + private ref SplitterDestinationVersion2 _v2; /// - /// The unique id of this . + /// Checks if the splitter destination data reference is null. /// - public int Id; + public bool IsNull => Unsafe.IsNullRef(ref _v1) && Unsafe.IsNullRef(ref _v2); /// - /// The mix to output the result of the splitter. + /// The splitter unique id. /// - public int DestinationId; - - /// - /// Mix buffer volumes storage. - /// - private MixArray _mix; - private MixArray _previousMix; - - /// - /// Pointer to the next linked element. - /// - private unsafe SplitterDestination* _next; - - /// - /// Set to true if in use. - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsUsed; - - /// - /// Set to true if the internal state need to be updated. - /// - [MarshalAs(UnmanagedType.I1)] - public bool NeedToUpdateInternalState; - - [StructLayout(LayoutKind.Sequential, Size = 4 * Constants.MixBufferCountMax, Pack = 1)] - private struct MixArray { } - - /// - /// Mix buffer volumes. - /// - /// Used when a splitter id is specified in the mix. - public Span MixBufferVolume => SpanHelpers.AsSpan(ref _mix); - - /// - /// Previous mix buffer volumes. - /// - /// Used when a splitter id is specified in the mix. - public Span PreviousMixBufferVolume => SpanHelpers.AsSpan(ref _previousMix); - - /// - /// Get the of the next element or if not present. - /// - public readonly Span Next + public int Id { get { - unsafe + if (Unsafe.IsNullRef(ref _v2)) { - return _next != null ? new Span(_next, 1) : Span.Empty; + if (Unsafe.IsNullRef(ref _v1)) + { + return 0; + } + else + { + return _v1.Id; + } + } + else + { + return _v2.Id; } } } /// - /// Create a new . + /// The mix to output the result of the splitter. /// - /// The unique id of this . - public SplitterDestination(int id) : this() + public int DestinationId { - Id = id; - DestinationId = Constants.UnusedMixId; - - ClearVolumes(); + get + { + if (Unsafe.IsNullRef(ref _v2)) + { + if (Unsafe.IsNullRef(ref _v1)) + { + return 0; + } + else + { + return _v1.DestinationId; + } + } + else + { + return _v2.DestinationId; + } + } } /// - /// Update the from user parameter. + /// Mix buffer volumes. + /// + /// Used when a splitter id is specified in the mix. + public Span MixBufferVolume + { + get + { + if (Unsafe.IsNullRef(ref _v2)) + { + if (Unsafe.IsNullRef(ref _v1)) + { + return Span.Empty; + } + else + { + return _v1.MixBufferVolume; + } + } + else + { + return _v2.MixBufferVolume; + } + } + } + + /// + /// Previous mix buffer volumes. + /// + /// Used when a splitter id is specified in the mix. + public Span PreviousMixBufferVolume + { + get + { + if (Unsafe.IsNullRef(ref _v2)) + { + if (Unsafe.IsNullRef(ref _v1)) + { + return Span.Empty; + } + else + { + return _v1.PreviousMixBufferVolume; + } + } + else + { + return _v2.PreviousMixBufferVolume; + } + } + } + + /// + /// Get the of the next element or null if not present. + /// + public readonly SplitterDestination Next + { + get + { + unsafe + { + if (Unsafe.IsNullRef(ref _v2)) + { + if (Unsafe.IsNullRef(ref _v1)) + { + return new SplitterDestination(); + } + else + { + return new SplitterDestination(ref _v1.Next); + } + } + else + { + return new SplitterDestination(ref _v2.Next); + } + } + } + } + + /// + /// Creates a new splitter destination wrapper for the version 1 splitter destination data. + /// + /// Version 1 splitter destination data + public SplitterDestination(ref SplitterDestinationVersion1 v1) + { + _v1 = ref v1; + _v2 = ref Unsafe.NullRef(); + } + + /// + /// Creates a new splitter destination wrapper for the version 2 splitter destination data. + /// + /// Version 2 splitter destination data + public SplitterDestination(ref SplitterDestinationVersion2 v2) + { + + _v1 = ref Unsafe.NullRef(); + _v2 = ref v2; + } + + /// + /// Creates a new splitter destination wrapper for the splitter destination data. + /// + /// Version 1 splitter destination data + /// Version 2 splitter destination data + public unsafe SplitterDestination(SplitterDestinationVersion1* v1, SplitterDestinationVersion2* v2) + { + _v1 = ref Unsafe.AsRef(v1); + _v2 = ref Unsafe.AsRef(v2); + } + + /// + /// Update the splitter destination data from user parameter. /// /// The user parameter. - public void Update(SplitterDestinationInParameter parameter) + /// Indicates that the audio renderer revision in use supports explicitly resetting the volume. + public void Update(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter { - Debug.Assert(Id == parameter.Id); - - if (parameter.IsMagicValid() && Id == parameter.Id) + if (Unsafe.IsNullRef(ref _v2)) { - DestinationId = parameter.DestinationId; - - parameter.MixBufferVolume.CopyTo(MixBufferVolume); - - if (!IsUsed && parameter.IsUsed) - { - MixBufferVolume.CopyTo(PreviousMixBufferVolume); - - NeedToUpdateInternalState = false; - } - - IsUsed = parameter.IsUsed; + _v1.Update(parameter, isPrevVolumeResetSupported); + } + else + { + _v2.Update(parameter, isPrevVolumeResetSupported); } } @@ -118,12 +202,14 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// public void UpdateInternalState() { - if (IsUsed && NeedToUpdateInternalState) + if (Unsafe.IsNullRef(ref _v2)) { - MixBufferVolume.CopyTo(PreviousMixBufferVolume); + _v1.UpdateInternalState(); + } + else + { + _v2.UpdateInternalState(); } - - NeedToUpdateInternalState = false; } /// @@ -131,16 +217,23 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// public void MarkAsNeedToUpdateInternalState() { - NeedToUpdateInternalState = true; + if (Unsafe.IsNullRef(ref _v2)) + { + _v1.MarkAsNeedToUpdateInternalState(); + } + else + { + _v2.MarkAsNeedToUpdateInternalState(); + } } /// - /// Return true if the is used and has a destination. + /// Return true if the splitter destination is used and has a destination. /// - /// True if the is used and has a destination. + /// True if the splitter destination is used and has a destination. public readonly bool IsConfigured() { - return IsUsed && DestinationId != Constants.UnusedMixId; + return Unsafe.IsNullRef(ref _v2) ? _v1.IsConfigured() : _v2.IsConfigured(); } /// @@ -150,9 +243,17 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// The volume for the given destination. public float GetMixVolume(int destinationIndex) { - Debug.Assert(destinationIndex >= 0 && destinationIndex < Constants.MixBufferCountMax); + return Unsafe.IsNullRef(ref _v2) ? _v1.GetMixVolume(destinationIndex) : _v2.GetMixVolume(destinationIndex); + } - return MixBufferVolume[destinationIndex]; + /// + /// Get the previous volume for a given destination. + /// + /// The destination index to use. + /// The volume for the given destination. + public float GetMixVolumePrev(int destinationIndex) + { + return Unsafe.IsNullRef(ref _v2) ? _v1.GetMixVolumePrev(destinationIndex) : _v2.GetMixVolumePrev(destinationIndex); } /// @@ -160,22 +261,33 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// public void ClearVolumes() { - MixBufferVolume.Clear(); - PreviousMixBufferVolume.Clear(); + if (Unsafe.IsNullRef(ref _v2)) + { + _v1.ClearVolumes(); + } + else + { + _v2.ClearVolumes(); + } } /// - /// Link the next element to the given . + /// Link the next element to the given splitter destination. /// - /// The given to link. - public void Link(ref SplitterDestination next) + /// The given splitter destination to link. + public void Link(SplitterDestination next) { - unsafe + if (Unsafe.IsNullRef(ref _v2)) { - fixed (SplitterDestination* nextPtr = &next) - { - _next = nextPtr; - } + Debug.Assert(!Unsafe.IsNullRef(ref next._v1)); + + _v1.Link(ref next._v1); + } + else + { + Debug.Assert(!Unsafe.IsNullRef(ref next._v2)); + + _v2.Link(ref next._v2); } } @@ -184,10 +296,74 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// public void Unlink() { - unsafe + if (Unsafe.IsNullRef(ref _v2)) { - _next = null; + _v1.Unlink(); } + else + { + _v2.Unlink(); + } + } + + /// + /// Checks if any biquad filter is enabled. + /// + /// True if any biquad filter is enabled. + public bool IsBiquadFilterEnabled() + { + return !Unsafe.IsNullRef(ref _v2) && _v2.IsBiquadFilterEnabled(); + } + + /// + /// Checks if any biquad filter was previously enabled. + /// + /// True if any biquad filter was previously enabled. + public bool IsBiquadFilterEnabledPrev() + { + return !Unsafe.IsNullRef(ref _v2) && _v2.IsBiquadFilterEnabledPrev(); + } + + /// + /// Gets the biquad filter parameters. + /// + /// Biquad filter index (0 or 1). + /// Biquad filter parameters. + public ref BiquadFilterParameter GetBiquadFilterParameter(int index) + { + Debug.Assert(!Unsafe.IsNullRef(ref _v2)); + + return ref _v2.GetBiquadFilterParameter(index); + } + + /// + /// Checks if any biquad filter was previously enabled. + /// + /// Biquad filter index (0 or 1). + public void UpdateBiquadFilterEnabledPrev(int index) + { + if (!Unsafe.IsNullRef(ref _v2)) + { + _v2.UpdateBiquadFilterEnabledPrev(index); + } + } + + /// + /// Get the reference for the version 1 splitter destination data, or null if version 2 is being used or the destination is null. + /// + /// Reference for the version 1 splitter destination data. + public ref SplitterDestinationVersion1 GetV1RefOrNull() + { + return ref _v1; + } + + /// + /// Get the reference for the version 2 splitter destination data, or null if version 1 is being used or the destination is null. + /// + /// Reference for the version 2 splitter destination data. + public ref SplitterDestinationVersion2 GetV2RefOrNull() + { + return ref _v2; } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion1.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion1.cs new file mode 100644 index 000000000..ce8f33685 --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion1.cs @@ -0,0 +1,208 @@ +using Ryujinx.Audio.Renderer.Parameter; +using Ryujinx.Common.Utilities; +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Audio.Renderer.Server.Splitter +{ + /// + /// Server state for a splitter destination (version 1). + /// + [StructLayout(LayoutKind.Sequential, Size = 0xE0, Pack = Alignment)] + public struct SplitterDestinationVersion1 + { + public const int Alignment = 0x10; + + /// + /// The unique id of this . + /// + public int Id; + + /// + /// The mix to output the result of the splitter. + /// + public int DestinationId; + + /// + /// Mix buffer volumes storage. + /// + private MixArray _mix; + private MixArray _previousMix; + + /// + /// Pointer to the next linked element. + /// + private unsafe SplitterDestinationVersion1* _next; + + /// + /// Set to true if in use. + /// + [MarshalAs(UnmanagedType.I1)] + public bool IsUsed; + + /// + /// Set to true if the internal state need to be updated. + /// + [MarshalAs(UnmanagedType.I1)] + public bool NeedToUpdateInternalState; + + [StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)] + private struct MixArray { } + + /// + /// Mix buffer volumes. + /// + /// Used when a splitter id is specified in the mix. + public Span MixBufferVolume => SpanHelpers.AsSpan(ref _mix); + + /// + /// Previous mix buffer volumes. + /// + /// Used when a splitter id is specified in the mix. + public Span PreviousMixBufferVolume => SpanHelpers.AsSpan(ref _previousMix); + + /// + /// Get the reference of the next element or null if not present. + /// + public readonly ref SplitterDestinationVersion1 Next + { + get + { + unsafe + { + return ref Unsafe.AsRef(_next); + } + } + } + + /// + /// Create a new . + /// + /// The unique id of this . + public SplitterDestinationVersion1(int id) : this() + { + Id = id; + DestinationId = Constants.UnusedMixId; + + ClearVolumes(); + } + + /// + /// Update the from user parameter. + /// + /// The user parameter. + /// Indicates that the audio renderer revision in use supports explicitly resetting the volume. + public void Update(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter + { + Debug.Assert(Id == parameter.Id); + + if (parameter.IsMagicValid() && Id == parameter.Id) + { + DestinationId = parameter.DestinationId; + + parameter.MixBufferVolume.CopyTo(MixBufferVolume); + + bool resetPrevVolume = isPrevVolumeResetSupported ? parameter.ResetPrevVolume : !IsUsed && parameter.IsUsed; + if (resetPrevVolume) + { + MixBufferVolume.CopyTo(PreviousMixBufferVolume); + + NeedToUpdateInternalState = false; + } + + IsUsed = parameter.IsUsed; + } + } + + /// + /// Update the internal state of the instance. + /// + public void UpdateInternalState() + { + if (IsUsed && NeedToUpdateInternalState) + { + MixBufferVolume.CopyTo(PreviousMixBufferVolume); + } + + NeedToUpdateInternalState = false; + } + + /// + /// Set the update internal state marker. + /// + public void MarkAsNeedToUpdateInternalState() + { + NeedToUpdateInternalState = true; + } + + /// + /// Return true if the is used and has a destination. + /// + /// True if the is used and has a destination. + public readonly bool IsConfigured() + { + return IsUsed && DestinationId != Constants.UnusedMixId; + } + + /// + /// Get the volume for a given destination. + /// + /// The destination index to use. + /// The volume for the given destination. + public float GetMixVolume(int destinationIndex) + { + Debug.Assert(destinationIndex >= 0 && destinationIndex < Constants.MixBufferCountMax); + + return MixBufferVolume[destinationIndex]; + } + + /// + /// Get the previous volume for a given destination. + /// + /// The destination index to use. + /// The volume for the given destination. + public float GetMixVolumePrev(int destinationIndex) + { + Debug.Assert(destinationIndex >= 0 && destinationIndex < Constants.MixBufferCountMax); + + return PreviousMixBufferVolume[destinationIndex]; + } + + /// + /// Clear the volumes. + /// + public void ClearVolumes() + { + MixBufferVolume.Clear(); + PreviousMixBufferVolume.Clear(); + } + + /// + /// Link the next element to the given . + /// + /// The given to link. + public void Link(ref SplitterDestinationVersion1 next) + { + unsafe + { + fixed (SplitterDestinationVersion1* nextPtr = &next) + { + _next = nextPtr; + } + } + } + + /// + /// Remove the link to the next element. + /// + public void Unlink() + { + unsafe + { + _next = null; + } + } + } +} diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs new file mode 100644 index 000000000..5f96ef3aa --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs @@ -0,0 +1,252 @@ +using Ryujinx.Audio.Renderer.Parameter; +using Ryujinx.Common.Memory; +using Ryujinx.Common.Utilities; +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Audio.Renderer.Server.Splitter +{ + /// + /// Server state for a splitter destination (version 2). + /// + [StructLayout(LayoutKind.Sequential, Size = 0x110, Pack = Alignment)] + public struct SplitterDestinationVersion2 + { + public const int Alignment = 0x10; + + /// + /// The unique id of this . + /// + public int Id; + + /// + /// The mix to output the result of the splitter. + /// + public int DestinationId; + + /// + /// Mix buffer volumes storage. + /// + private MixArray _mix; + private MixArray _previousMix; + + /// + /// Pointer to the next linked element. + /// + private unsafe SplitterDestinationVersion2* _next; + + /// + /// Set to true if in use. + /// + [MarshalAs(UnmanagedType.I1)] + public bool IsUsed; + + /// + /// Set to true if the internal state need to be updated. + /// + [MarshalAs(UnmanagedType.I1)] + public bool NeedToUpdateInternalState; + + [StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)] + private struct MixArray { } + + /// + /// Mix buffer volumes. + /// + /// Used when a splitter id is specified in the mix. + public Span MixBufferVolume => SpanHelpers.AsSpan(ref _mix); + + /// + /// Previous mix buffer volumes. + /// + /// Used when a splitter id is specified in the mix. + public Span PreviousMixBufferVolume => SpanHelpers.AsSpan(ref _previousMix); + + /// + /// Get the reference of the next element or null if not present. + /// + public readonly ref SplitterDestinationVersion2 Next + { + get + { + unsafe + { + return ref Unsafe.AsRef(_next); + } + } + } + + private Array2 _biquadFilters; + + private Array2 _isPreviousBiquadFilterEnabled; + + /// + /// Create a new . + /// + /// The unique id of this . + public SplitterDestinationVersion2(int id) : this() + { + Id = id; + DestinationId = Constants.UnusedMixId; + + ClearVolumes(); + } + + /// + /// Update the from user parameter. + /// + /// The user parameter. + /// Indicates that the audio renderer revision in use supports explicitly resetting the volume. + public void Update(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter + { + Debug.Assert(Id == parameter.Id); + + if (parameter.IsMagicValid() && Id == parameter.Id) + { + DestinationId = parameter.DestinationId; + + parameter.MixBufferVolume.CopyTo(MixBufferVolume); + + _biquadFilters = parameter.BiquadFilters; + + bool resetPrevVolume = isPrevVolumeResetSupported ? parameter.ResetPrevVolume : !IsUsed && parameter.IsUsed; + if (resetPrevVolume) + { + MixBufferVolume.CopyTo(PreviousMixBufferVolume); + + NeedToUpdateInternalState = false; + } + + IsUsed = parameter.IsUsed; + } + } + + /// + /// Update the internal state of the instance. + /// + public void UpdateInternalState() + { + if (IsUsed && NeedToUpdateInternalState) + { + MixBufferVolume.CopyTo(PreviousMixBufferVolume); + } + + NeedToUpdateInternalState = false; + } + + /// + /// Set the update internal state marker. + /// + public void MarkAsNeedToUpdateInternalState() + { + NeedToUpdateInternalState = true; + } + + /// + /// Return true if the is used and has a destination. + /// + /// True if the is used and has a destination. + public readonly bool IsConfigured() + { + return IsUsed && DestinationId != Constants.UnusedMixId; + } + + /// + /// Get the volume for a given destination. + /// + /// The destination index to use. + /// The volume for the given destination. + public float GetMixVolume(int destinationIndex) + { + Debug.Assert(destinationIndex >= 0 && destinationIndex < Constants.MixBufferCountMax); + + return MixBufferVolume[destinationIndex]; + } + + /// + /// Get the previous volume for a given destination. + /// + /// The destination index to use. + /// The volume for the given destination. + public float GetMixVolumePrev(int destinationIndex) + { + Debug.Assert(destinationIndex >= 0 && destinationIndex < Constants.MixBufferCountMax); + + return PreviousMixBufferVolume[destinationIndex]; + } + + /// + /// Clear the volumes. + /// + public void ClearVolumes() + { + MixBufferVolume.Clear(); + PreviousMixBufferVolume.Clear(); + } + + /// + /// Link the next element to the given . + /// + /// The given to link. + public void Link(ref SplitterDestinationVersion2 next) + { + unsafe + { + fixed (SplitterDestinationVersion2* nextPtr = &next) + { + _next = nextPtr; + } + } + } + + /// + /// Remove the link to the next element. + /// + public void Unlink() + { + unsafe + { + _next = null; + } + } + + /// + /// Checks if any biquad filter is enabled. + /// + /// True if any biquad filter is enabled. + public bool IsBiquadFilterEnabled() + { + return _biquadFilters[0].Enable || _biquadFilters[1].Enable; + } + + /// + /// Checks if any biquad filter was previously enabled. + /// + /// True if any biquad filter was previously enabled. + public bool IsBiquadFilterEnabledPrev() + { + return _isPreviousBiquadFilterEnabled[0]; + } + + /// + /// Gets the biquad filter parameters. + /// + /// Biquad filter index (0 or 1). + /// Biquad filter parameters. + public ref BiquadFilterParameter GetBiquadFilterParameter(int index) + { + return ref _biquadFilters[index]; + } + + /// + /// Checks if any biquad filter was previously enabled. + /// + /// Biquad filter index (0 or 1). + public void UpdateBiquadFilterEnabledPrev(int index) + { + _isPreviousBiquadFilterEnabled[index] = _biquadFilters[index].Enable; + } + } +} diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterState.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterState.cs index e08ee9ea7..3e7dce559 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterState.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterState.cs @@ -1,4 +1,5 @@ using Ryujinx.Audio.Renderer.Parameter; +using Ryujinx.Common.Extensions; using System; using System.Buffers; using System.Diagnostics; @@ -14,6 +15,8 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter { public const int Alignment = 0x10; + private delegate void SplitterDestinationAction(SplitterDestination destination, int index); + /// /// The unique id of this . /// @@ -25,7 +28,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter public uint SampleRate; /// - /// Count of splitter destinations (). + /// Count of splitter destinations. /// public int DestinationCount; @@ -36,20 +39,25 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter public bool HasNewConnection; /// - /// Linked list of . + /// Linked list of . /// - private unsafe SplitterDestination* _destinationsData; + private unsafe SplitterDestinationVersion1* _destinationDataV1; /// - /// Span to the first element of the linked list of . + /// Linked list of . /// - public readonly Span Destinations + private unsafe SplitterDestinationVersion2* _destinationDataV2; + + /// + /// First element of the linked list of splitter destinations data. + /// + public readonly SplitterDestination Destination { get { unsafe { - return (IntPtr)_destinationsData != IntPtr.Zero ? new Span(_destinationsData, 1) : Span.Empty; + return new SplitterDestination(_destinationDataV1, _destinationDataV2); } } } @@ -63,20 +71,20 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter Id = id; } - public readonly Span GetData(int index) + public readonly SplitterDestination GetData(int index) { int i = 0; - Span result = Destinations; + SplitterDestination result = Destination; while (i < index) { - if (result.IsEmpty) + if (result.IsNull) { break; } - result = result[0].Next; + result = result.Next; i++; } @@ -92,25 +100,25 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter } /// - /// Utility function to apply a given to all . + /// Utility function to apply an action to all . /// /// The action to execute on each elements. - private readonly void ForEachDestination(SpanAction action) + private readonly void ForEachDestination(SplitterDestinationAction action) { - Span temp = Destinations; + SplitterDestination temp = Destination; int i = 0; while (true) { - if (temp.IsEmpty) + if (temp.IsNull) { break; } - Span next = temp[0].Next; + SplitterDestination next = temp.Next; - action.Invoke(temp, i++); + action(temp, i++); temp = next; } @@ -122,7 +130,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// The splitter context. /// The user parameter. /// The raw input data after the . - public void Update(SplitterContext context, ref SplitterInParameter parameter, ReadOnlySpan input) + public void Update(SplitterContext context, in SplitterInParameter parameter, ref SequenceReader input) { ClearLinks(); @@ -139,23 +147,30 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter if (destinationCount > 0) { - ReadOnlySpan destinationIds = MemoryMarshal.Cast(input); + input.ReadLittleEndian(out int destinationId); - Memory destination = context.GetDestinationMemory(destinationIds[0]); + SplitterDestination destination = context.GetDestination(destinationId); - SetDestination(ref destination.Span[0]); + SetDestination(destination); DestinationCount = destinationCount; for (int i = 1; i < destinationCount; i++) { - Memory nextDestination = context.GetDestinationMemory(destinationIds[i]); + input.ReadLittleEndian(out destinationId); - destination.Span[0].Link(ref nextDestination.Span[0]); + SplitterDestination nextDestination = context.GetDestination(destinationId); + + destination.Link(nextDestination); destination = nextDestination; } } + if (destinationCount < parameter.DestinationCount) + { + input.Advance((parameter.DestinationCount - destinationCount) * sizeof(int)); + } + Debug.Assert(parameter.Id == Id); if (parameter.Id == Id) @@ -166,16 +181,21 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter } /// - /// Set the head of the linked list of . + /// Set the head of the linked list of . /// - /// A reference to a . - public void SetDestination(ref SplitterDestination newValue) + /// New destination value. + public void SetDestination(SplitterDestination newValue) { unsafe { - fixed (SplitterDestination* newValuePtr = &newValue) + fixed (SplitterDestinationVersion1* newValuePtr = &newValue.GetV1RefOrNull()) { - _destinationsData = newValuePtr; + _destinationDataV1 = newValuePtr; + } + + fixed (SplitterDestinationVersion2* newValuePtr = &newValue.GetV2RefOrNull()) + { + _destinationDataV2 = newValuePtr; } } } @@ -185,19 +205,20 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// public readonly void UpdateInternalState() { - ForEachDestination((destination, _) => destination[0].UpdateInternalState()); + ForEachDestination((destination, _) => destination.UpdateInternalState()); } /// - /// Clear all links from the . + /// Clear all links from the . /// public void ClearLinks() { - ForEachDestination((destination, _) => destination[0].Unlink()); + ForEachDestination((destination, _) => destination.Unlink()); unsafe { - _destinationsData = (SplitterDestination*)IntPtr.Zero; + _destinationDataV1 = null; + _destinationDataV2 = null; } } @@ -211,7 +232,8 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter { unsafe { - splitter._destinationsData = (SplitterDestination*)IntPtr.Zero; + splitter._destinationDataV1 = null; + splitter._destinationDataV2 = null; } splitter.DestinationCount = 0; diff --git a/src/Ryujinx.Audio/Renderer/Server/StateUpdater.cs b/src/Ryujinx.Audio/Renderer/Server/StateUpdater.cs index 22eebc7cc..f8d87f2d1 100644 --- a/src/Ryujinx.Audio/Renderer/Server/StateUpdater.cs +++ b/src/Ryujinx.Audio/Renderer/Server/StateUpdater.cs @@ -9,41 +9,40 @@ using Ryujinx.Audio.Renderer.Server.Sink; using Ryujinx.Audio.Renderer.Server.Splitter; using Ryujinx.Audio.Renderer.Server.Voice; using Ryujinx.Audio.Renderer.Utils; +using Ryujinx.Common.Extensions; using Ryujinx.Common.Logging; using System; using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; namespace Ryujinx.Audio.Renderer.Server { - public class StateUpdater + public ref struct StateUpdater { - private readonly ReadOnlyMemory _inputOrigin; + private SequenceReader _inputReader; + private readonly ReadOnlyMemory _outputOrigin; - private ReadOnlyMemory _input; private Memory _output; private readonly uint _processHandle; private BehaviourContext _behaviourContext; - private UpdateDataHeader _inputHeader; + private readonly ref readonly UpdateDataHeader _inputHeader; private readonly Memory _outputHeader; - private ref UpdateDataHeader OutputHeader => ref _outputHeader.Span[0]; + private readonly ref UpdateDataHeader OutputHeader => ref _outputHeader.Span[0]; - public StateUpdater(ReadOnlyMemory input, Memory output, uint processHandle, BehaviourContext behaviourContext) + public StateUpdater(ReadOnlySequence input, Memory output, uint processHandle, BehaviourContext behaviourContext) { - _input = input; - _inputOrigin = _input; + _inputReader = new SequenceReader(input); _output = output; _outputOrigin = _output; _processHandle = processHandle; _behaviourContext = behaviourContext; - _inputHeader = SpanIOHelper.Read(ref _input); + _inputHeader = ref _inputReader.GetRefOrRefToCopy(out _); _outputHeader = SpanMemoryManager.Cast(_output[..Unsafe.SizeOf()]); OutputHeader.Initialize(_behaviourContext.UserRevision); @@ -52,7 +51,7 @@ namespace Ryujinx.Audio.Renderer.Server public ResultCode UpdateBehaviourContext() { - BehaviourParameter parameter = SpanIOHelper.Read(ref _input); + ref readonly BehaviourParameter parameter = ref _inputReader.GetRefOrRefToCopy(out _); if (!BehaviourContext.CheckValidRevision(parameter.UserRevision) || parameter.UserRevision != _behaviourContext.UserRevision) { @@ -81,11 +80,11 @@ namespace Ryujinx.Audio.Renderer.Server foreach (ref MemoryPoolState memoryPool in memoryPools) { - MemoryPoolInParameter parameter = SpanIOHelper.Read(ref _input); + ref readonly MemoryPoolInParameter parameter = ref _inputReader.GetRefOrRefToCopy(out _); ref MemoryPoolOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - PoolMapper.UpdateResult updateResult = mapper.Update(ref memoryPool, ref parameter, ref outStatus); + PoolMapper.UpdateResult updateResult = mapper.Update(ref memoryPool, in parameter, ref outStatus); if (updateResult != PoolMapper.UpdateResult.Success && updateResult != PoolMapper.UpdateResult.MapError && @@ -115,7 +114,7 @@ namespace Ryujinx.Audio.Renderer.Server for (int i = 0; i < context.GetCount(); i++) { - VoiceChannelResourceInParameter parameter = SpanIOHelper.Read(ref _input); + ref readonly VoiceChannelResourceInParameter parameter = ref _inputReader.GetRefOrRefToCopy(out _); ref VoiceChannelResource resource = ref context.GetChannelResource(i); @@ -127,7 +126,7 @@ namespace Ryujinx.Audio.Renderer.Server return ResultCode.Success; } - public ResultCode UpdateVoices(VoiceContext context, Memory memoryPools) + public ResultCode UpdateVoices(VoiceContext context, PoolMapper mapper) { if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.VoicesSize) { @@ -136,11 +135,7 @@ namespace Ryujinx.Audio.Renderer.Server int initialOutputSize = _output.Length; - ReadOnlySpan parameters = MemoryMarshal.Cast(_input[..(int)_inputHeader.VoicesSize].Span); - - _input = _input[(int)_inputHeader.VoicesSize..]; - - PoolMapper mapper = new(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); + long initialInputConsumed = _inputReader.Consumed; // First make everything not in use. for (int i = 0; i < context.GetCount(); i++) @@ -157,7 +152,7 @@ namespace Ryujinx.Audio.Renderer.Server // Start processing for (int i = 0; i < context.GetCount(); i++) { - VoiceInParameter parameter = parameters[i]; + ref readonly VoiceInParameter parameter = ref _inputReader.GetRefOrRefToCopy(out _); voiceUpdateStates.Fill(Memory.Empty); @@ -181,14 +176,14 @@ namespace Ryujinx.Audio.Renderer.Server currentVoiceState.Initialize(); } - currentVoiceState.UpdateParameters(out ErrorInfo updateParameterError, ref parameter, ref mapper, ref _behaviourContext); + currentVoiceState.UpdateParameters(out ErrorInfo updateParameterError, in parameter, mapper, ref _behaviourContext); if (updateParameterError.ErrorCode != ResultCode.Success) { _behaviourContext.AppendError(ref updateParameterError); } - currentVoiceState.UpdateWaveBuffers(out ErrorInfo[] waveBufferUpdateErrorInfos, ref parameter, voiceUpdateStates, ref mapper, ref _behaviourContext); + currentVoiceState.UpdateWaveBuffers(out ErrorInfo[] waveBufferUpdateErrorInfos, in parameter, voiceUpdateStates, mapper, ref _behaviourContext); foreach (ref ErrorInfo errorInfo in waveBufferUpdateErrorInfos.AsSpan()) { @@ -198,7 +193,7 @@ namespace Ryujinx.Audio.Renderer.Server } } - currentVoiceState.WriteOutStatus(ref outStatus, ref parameter, voiceUpdateStates); + currentVoiceState.WriteOutStatus(ref outStatus, in parameter, voiceUpdateStates); } } @@ -211,10 +206,12 @@ namespace Ryujinx.Audio.Renderer.Server Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.VoicesSize); + _inputReader.SetConsumed(initialInputConsumed + _inputHeader.VoicesSize); + return ResultCode.Success; } - private static void ResetEffect(ref BaseEffect effect, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter + private static void ResetEffect(ref BaseEffect effect, in T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter { effect.ForceUnmapBuffers(mapper); @@ -234,17 +231,17 @@ namespace Ryujinx.Audio.Renderer.Server }; } - public ResultCode UpdateEffects(EffectContext context, bool isAudioRendererActive, Memory memoryPools) + public ResultCode UpdateEffects(EffectContext context, bool isAudioRendererActive, PoolMapper mapper) { if (_behaviourContext.IsEffectInfoVersion2Supported()) { - return UpdateEffectsVersion2(context, isAudioRendererActive, memoryPools); + return UpdateEffectsVersion2(context, isAudioRendererActive, mapper); } - return UpdateEffectsVersion1(context, isAudioRendererActive, memoryPools); + return UpdateEffectsVersion1(context, isAudioRendererActive, mapper); } - public ResultCode UpdateEffectsVersion2(EffectContext context, bool isAudioRendererActive, Memory memoryPools) + public ResultCode UpdateEffectsVersion2(EffectContext context, bool isAudioRendererActive, PoolMapper mapper) { if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.EffectsSize) { @@ -253,26 +250,22 @@ namespace Ryujinx.Audio.Renderer.Server int initialOutputSize = _output.Length; - ReadOnlySpan parameters = MemoryMarshal.Cast(_input[..(int)_inputHeader.EffectsSize].Span); - - _input = _input[(int)_inputHeader.EffectsSize..]; - - PoolMapper mapper = new(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); + long initialInputConsumed = _inputReader.Consumed; for (int i = 0; i < context.GetCount(); i++) { - EffectInParameterVersion2 parameter = parameters[i]; + ref readonly EffectInParameterVersion2 parameter = ref _inputReader.GetRefOrRefToCopy(out _); ref EffectOutStatusVersion2 outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; ref BaseEffect effect = ref context.GetEffect(i); - if (!effect.IsTypeValid(ref parameter)) + if (!effect.IsTypeValid(in parameter)) { - ResetEffect(ref effect, ref parameter, mapper); + ResetEffect(ref effect, in parameter, mapper); } - effect.Update(out ErrorInfo updateErrorInfo, ref parameter, mapper); + effect.Update(out ErrorInfo updateErrorInfo, in parameter, mapper); if (updateErrorInfo.ErrorCode != ResultCode.Success) { @@ -297,10 +290,12 @@ namespace Ryujinx.Audio.Renderer.Server Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.EffectsSize); + _inputReader.SetConsumed(initialInputConsumed + _inputHeader.EffectsSize); + return ResultCode.Success; } - public ResultCode UpdateEffectsVersion1(EffectContext context, bool isAudioRendererActive, Memory memoryPools) + public ResultCode UpdateEffectsVersion1(EffectContext context, bool isAudioRendererActive, PoolMapper mapper) { if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.EffectsSize) { @@ -309,26 +304,22 @@ namespace Ryujinx.Audio.Renderer.Server int initialOutputSize = _output.Length; - ReadOnlySpan parameters = MemoryMarshal.Cast(_input[..(int)_inputHeader.EffectsSize].Span); - - _input = _input[(int)_inputHeader.EffectsSize..]; - - PoolMapper mapper = new(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); + long initialInputConsumed = _inputReader.Consumed; for (int i = 0; i < context.GetCount(); i++) { - EffectInParameterVersion1 parameter = parameters[i]; + ref readonly EffectInParameterVersion1 parameter = ref _inputReader.GetRefOrRefToCopy(out _); ref EffectOutStatusVersion1 outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; ref BaseEffect effect = ref context.GetEffect(i); - if (!effect.IsTypeValid(ref parameter)) + if (!effect.IsTypeValid(in parameter)) { - ResetEffect(ref effect, ref parameter, mapper); + ResetEffect(ref effect, in parameter, mapper); } - effect.Update(out ErrorInfo updateErrorInfo, ref parameter, mapper); + effect.Update(out ErrorInfo updateErrorInfo, in parameter, mapper); if (updateErrorInfo.ErrorCode != ResultCode.Success) { @@ -345,38 +336,40 @@ namespace Ryujinx.Audio.Renderer.Server Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.EffectsSize); + _inputReader.SetConsumed(initialInputConsumed + _inputHeader.EffectsSize); + return ResultCode.Success; } public ResultCode UpdateSplitter(SplitterContext context) { - if (context.Update(_input.Span, out int consumedSize)) + if (context.Update(ref _inputReader)) { - _input = _input[consumedSize..]; - return ResultCode.Success; } return ResultCode.InvalidUpdateInfo; } - private static bool CheckMixParametersValidity(MixContext mixContext, uint mixBufferCount, uint inputMixCount, ReadOnlySpan parameters) + private static bool CheckMixParametersValidity(MixContext mixContext, uint mixBufferCount, uint inputMixCount, SequenceReader parameters) { uint maxMixStateCount = mixContext.GetCount(); uint totalRequiredMixBufferCount = 0; for (int i = 0; i < inputMixCount; i++) { - if (parameters[i].IsUsed) + ref readonly MixParameter parameter = ref parameters.GetRefOrRefToCopy(out _); + + if (parameter.IsUsed) { - if (parameters[i].DestinationMixId != Constants.UnusedMixId && - parameters[i].DestinationMixId > maxMixStateCount && - parameters[i].MixId != Constants.FinalMixId) + if (parameter.DestinationMixId != Constants.UnusedMixId && + parameter.DestinationMixId > maxMixStateCount && + parameter.MixId != Constants.FinalMixId) { return true; } - totalRequiredMixBufferCount += parameters[i].BufferCount; + totalRequiredMixBufferCount += parameter.BufferCount; } } @@ -391,7 +384,7 @@ namespace Ryujinx.Audio.Renderer.Server if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) { - MixInParameterDirtyOnlyUpdate parameter = MemoryMarshal.Cast(_input.Span)[0]; + ref readonly MixInParameterDirtyOnlyUpdate parameter = ref _inputReader.GetRefOrRefToCopy(out _); mixCount = parameter.MixCount; @@ -411,25 +404,20 @@ namespace Ryujinx.Audio.Renderer.Server return ResultCode.InvalidUpdateInfo; } - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) - { - _input = _input[Unsafe.SizeOf()..]; - } + long initialInputConsumed = _inputReader.Consumed; - ReadOnlySpan parameters = MemoryMarshal.Cast(_input.Span[..(int)inputMixSize]); + int parameterCount = (int)inputMixSize / Unsafe.SizeOf(); - _input = _input[(int)inputMixSize..]; - - if (CheckMixParametersValidity(mixContext, mixBufferCount, mixCount, parameters)) + if (CheckMixParametersValidity(mixContext, mixBufferCount, mixCount, _inputReader)) { return ResultCode.InvalidUpdateInfo; } bool isMixContextDirty = false; - for (int i = 0; i < parameters.Length; i++) + for (int i = 0; i < parameterCount; i++) { - MixParameter parameter = parameters[i]; + ref readonly MixParameter parameter = ref _inputReader.GetRefOrRefToCopy(out _); int mixId = i; @@ -454,7 +442,7 @@ namespace Ryujinx.Audio.Renderer.Server if (mix.IsUsed) { - isMixContextDirty |= mix.Update(mixContext.EdgeMatrix, ref parameter, effectContext, splitterContext, _behaviourContext); + isMixContextDirty |= mix.Update(mixContext.EdgeMatrix, in parameter, effectContext, splitterContext, _behaviourContext); } } @@ -473,10 +461,12 @@ namespace Ryujinx.Audio.Renderer.Server } } + _inputReader.SetConsumed(initialInputConsumed + inputMixSize); + return ResultCode.Success; } - private static void ResetSink(ref BaseSink sink, ref SinkInParameter parameter) + private static void ResetSink(ref BaseSink sink, in SinkInParameter parameter) { sink.CleanUp(); @@ -489,10 +479,8 @@ namespace Ryujinx.Audio.Renderer.Server }; } - public ResultCode UpdateSinks(SinkContext context, Memory memoryPools) + public ResultCode UpdateSinks(SinkContext context, PoolMapper mapper) { - PoolMapper mapper = new(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.SinksSize) { return ResultCode.InvalidUpdateInfo; @@ -500,22 +488,20 @@ namespace Ryujinx.Audio.Renderer.Server int initialOutputSize = _output.Length; - ReadOnlySpan parameters = MemoryMarshal.Cast(_input[..(int)_inputHeader.SinksSize].Span); - - _input = _input[(int)_inputHeader.SinksSize..]; + long initialInputConsumed = _inputReader.Consumed; for (int i = 0; i < context.GetCount(); i++) { - SinkInParameter parameter = parameters[i]; + ref readonly SinkInParameter parameter = ref _inputReader.GetRefOrRefToCopy(out _); ref SinkOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; ref BaseSink sink = ref context.GetSink(i); - if (!sink.IsTypeValid(ref parameter)) + if (!sink.IsTypeValid(in parameter)) { - ResetSink(ref sink, ref parameter); + ResetSink(ref sink, in parameter); } - sink.Update(out ErrorInfo updateErrorInfo, ref parameter, ref outStatus, mapper); + sink.Update(out ErrorInfo updateErrorInfo, in parameter, ref outStatus, mapper); if (updateErrorInfo.ErrorCode != ResultCode.Success) { @@ -530,6 +516,8 @@ namespace Ryujinx.Audio.Renderer.Server Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.SinksSize); + _inputReader.SetConsumed(initialInputConsumed + _inputHeader.SinksSize); + return ResultCode.Success; } @@ -540,7 +528,7 @@ namespace Ryujinx.Audio.Renderer.Server return ResultCode.InvalidUpdateInfo; } - PerformanceInParameter parameter = SpanIOHelper.Read(ref _input); + ref readonly PerformanceInParameter parameter = ref _inputReader.GetRefOrRefToCopy(out _); ref PerformanceOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; @@ -585,9 +573,9 @@ namespace Ryujinx.Audio.Renderer.Server return ResultCode.Success; } - public ResultCode CheckConsumedSize() + public readonly ResultCode CheckConsumedSize() { - int consumedInputSize = _inputOrigin.Length - _input.Length; + long consumedInputSize = _inputReader.Consumed; int consumedOutputSize = _outputOrigin.Length - _output.Length; if (consumedInputSize != _inputHeader.TotalSize) diff --git a/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs b/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs index 225f7d31b..040c70e6c 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs @@ -254,7 +254,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// /// The user parameter. /// Return true, if the server voice information needs to be updated. - private readonly bool ShouldUpdateParameters(ref VoiceInParameter parameter) + private readonly bool ShouldUpdateParameters(in VoiceInParameter parameter) { if (DataSourceStateAddressInfo.CpuAddress == parameter.DataSourceStateAddress) { @@ -273,7 +273,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// The user parameter. /// The mapper to use. /// The behaviour context. - public void UpdateParameters(out ErrorInfo outErrorInfo, ref VoiceInParameter parameter, ref PoolMapper poolMapper, ref BehaviourContext behaviourContext) + public void UpdateParameters(out ErrorInfo outErrorInfo, in VoiceInParameter parameter, PoolMapper poolMapper, ref BehaviourContext behaviourContext) { InUse = parameter.InUse; Id = parameter.Id; @@ -326,7 +326,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice VoiceDropFlag = false; } - if (ShouldUpdateParameters(ref parameter)) + if (ShouldUpdateParameters(in parameter)) { DataSourceStateUnmapped = !poolMapper.TryAttachBuffer(out outErrorInfo, ref DataSourceStateAddressInfo, parameter.DataSourceStateAddress, parameter.DataSourceStateSize); } @@ -380,7 +380,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// The given user output. /// The user parameter. /// The voice states associated to the . - public void WriteOutStatus(ref VoiceOutStatus outStatus, ref VoiceInParameter parameter, ReadOnlySpan> voiceUpdateStates) + public void WriteOutStatus(ref VoiceOutStatus outStatus, in VoiceInParameter parameter, ReadOnlySpan> voiceUpdateStates) { #if DEBUG // Sanity check in debug mode of the internal state @@ -426,7 +426,12 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// The voice states associated to the . /// The mapper to use. /// The behaviour context. - public void UpdateWaveBuffers(out ErrorInfo[] errorInfos, ref VoiceInParameter parameter, ReadOnlySpan> voiceUpdateStates, ref PoolMapper mapper, ref BehaviourContext behaviourContext) + public void UpdateWaveBuffers( + out ErrorInfo[] errorInfos, + in VoiceInParameter parameter, + ReadOnlySpan> voiceUpdateStates, + PoolMapper mapper, + ref BehaviourContext behaviourContext) { errorInfos = new ErrorInfo[Constants.VoiceWaveBufferCount * 2]; @@ -444,7 +449,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice for (int i = 0; i < Constants.VoiceWaveBufferCount; i++) { - UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref WaveBuffers[i], ref parameter.WaveBuffers[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], ref mapper, ref behaviourContext); + UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref WaveBuffers[i], ref parameter.WaveBuffers[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], mapper, ref behaviourContext); } } @@ -458,7 +463,14 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// If set to true, the server side wavebuffer is considered valid. /// The mapper to use. /// The behaviour context. - private void UpdateWaveBuffer(Span errorInfos, ref WaveBuffer waveBuffer, ref WaveBufferInternal inputWaveBuffer, SampleFormat sampleFormat, bool isValid, ref PoolMapper mapper, ref BehaviourContext behaviourContext) + private void UpdateWaveBuffer( + Span errorInfos, + ref WaveBuffer waveBuffer, + ref WaveBufferInternal inputWaveBuffer, + SampleFormat sampleFormat, + bool isValid, + PoolMapper mapper, + ref BehaviourContext behaviourContext) { if (!isValid && waveBuffer.IsSendToAudioProcessor && waveBuffer.BufferAddressInfo.CpuAddress != 0) { diff --git a/src/Ryujinx.Ava/Assets/Locales/zh_CN.json b/src/Ryujinx.Ava/Assets/Locales/zh_CN.json deleted file mode 100644 index d09a80ec6..000000000 --- a/src/Ryujinx.Ava/Assets/Locales/zh_CN.json +++ /dev/null @@ -1,656 +0,0 @@ -{ - "Language": "简体中文", - "MenuBarFileOpenApplet": "打开小程序", - "MenuBarFileOpenAppletOpenMiiAppletToolTip": "打开独立的 Mii 小程序", - "SettingsTabInputDirectMouseAccess": "直通鼠标操作", - "SettingsTabSystemMemoryManagerMode": "内存管理模式:", - "SettingsTabSystemMemoryManagerModeSoftware": "软件", - "SettingsTabSystemMemoryManagerModeHost": "本机 (快速)", - "SettingsTabSystemMemoryManagerModeHostUnchecked": "跳过检查的本机 (最快)", - "SettingsTabSystemUseHypervisor": "使用 Hypervisor 虚拟化", - "MenuBarFile": "文件", - "MenuBarFileOpenFromFile": "加载文件", - "MenuBarFileOpenUnpacked": "加载解包后的游戏", - "MenuBarFileOpenEmuFolder": "打开 Ryujinx 文件夹", - "MenuBarFileOpenLogsFolder": "打开日志文件夹", - "MenuBarFileExit": "退出", - "MenuBarOptions": "选项", - "MenuBarOptionsToggleFullscreen": "切换全屏", - "MenuBarOptionsStartGamesInFullscreen": "全屏模式启动游戏", - "MenuBarOptionsStopEmulation": "停止模拟", - "MenuBarOptionsSettings": "设置", - "MenuBarOptionsManageUserProfiles": "管理用户账户", - "MenuBarActions": "操作", - "MenuBarOptionsSimulateWakeUpMessage": "模拟唤醒消息", - "MenuBarActionsScanAmiibo": "扫描 Amiibo", - "MenuBarTools": "工具", - "MenuBarToolsInstallFirmware": "安装固件", - "MenuBarFileToolsInstallFirmwareFromFile": "从 XCI 或 ZIP 安装固件", - "MenuBarFileToolsInstallFirmwareFromDirectory": "从文件夹安装固件", - "MenuBarToolsManageFileTypes": "管理文件扩展名", - "MenuBarToolsInstallFileTypes": "关联文件扩展名", - "MenuBarToolsUninstallFileTypes": "取消关联扩展名", - "MenuBarHelp": "帮助", - "MenuBarHelpCheckForUpdates": "检查更新", - "MenuBarHelpAbout": "关于", - "MenuSearch": "搜索…", - "GameListHeaderFavorite": "收藏", - "GameListHeaderIcon": "图标", - "GameListHeaderApplication": "名称", - "GameListHeaderDeveloper": "制作商", - "GameListHeaderVersion": "版本", - "GameListHeaderTimePlayed": "游玩时长", - "GameListHeaderLastPlayed": "最近游玩", - "GameListHeaderFileExtension": "扩展名", - "GameListHeaderFileSize": "大小", - "GameListHeaderPath": "路径", - "GameListContextMenuOpenUserSaveDirectory": "打开用户存档目录", - "GameListContextMenuOpenUserSaveDirectoryToolTip": "打开储存游戏存档的目录", - "GameListContextMenuOpenDeviceSaveDirectory": "打开系统目录", - "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "打开包含游戏系统设置的目录", - "GameListContextMenuOpenBcatSaveDirectory": "打开 BCAT 目录", - "GameListContextMenuOpenBcatSaveDirectoryToolTip": "打开包含游戏 BCAT 数据的目录", - "GameListContextMenuManageTitleUpdates": "管理游戏更新", - "GameListContextMenuManageTitleUpdatesToolTip": "打开更新管理器", - "GameListContextMenuManageDlc": "管理 DLC", - "GameListContextMenuManageDlcToolTip": "打开 DLC 管理窗口", - "GameListContextMenuOpenModsDirectory": "打开 MOD 目录", - "GameListContextMenuOpenModsDirectoryToolTip": "打开存放游戏 MOD 的目录", - "GameListContextMenuCacheManagement": "缓存管理", - "GameListContextMenuCacheManagementPurgePptc": "清除已编译的 PPTC 文件", - "GameListContextMenuCacheManagementPurgePptcToolTip": "仅删除 PPTC 转换后的文件,下次打开游戏时将根据 .info 文件重新生成 PPTC 文件。\n如想彻底清除缓存,请进入目录把 .info 文件一并删除", - "GameListContextMenuCacheManagementPurgeShaderCache": "清除着色器缓存", - "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "删除游戏的着色器缓存", - "GameListContextMenuCacheManagementOpenPptcDirectory": "打开 PPTC 目录", - "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "打开包含游戏 PPTC 缓存的目录", - "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "打开着色器缓存目录", - "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "打开包含游戏着色器缓存的目录", - "GameListContextMenuExtractData": "提取数据", - "GameListContextMenuExtractDataExeFS": "ExeFS", - "GameListContextMenuExtractDataExeFSToolTip": "从游戏的当前状态中提取 ExeFS 分区 (包括更新)", - "GameListContextMenuExtractDataRomFS": "RomFS", - "GameListContextMenuExtractDataRomFSToolTip": "从游戏的当前状态中提取 RomFS 分区 (包括更新)", - "GameListContextMenuExtractDataLogo": "图标", - "GameListContextMenuExtractDataLogoToolTip": "从游戏的当前状态中提取图标 (包括更新)", - "StatusBarGamesLoaded": "{0}/{1} 游戏加载完成", - "StatusBarSystemVersion": "系统版本:{0}", - "LinuxVmMaxMapCountDialogTitle": "检测到内存映射的限制过低", - "LinuxVmMaxMapCountDialogTextPrimary": "你想要将 vm.max_map_count 的值增加到 {0} 吗", - "LinuxVmMaxMapCountDialogTextSecondary": "有些游戏可能会试图创建超过当前允许的内存映射数量。当超过此限制时,Ryujinx会立即崩溃。", - "LinuxVmMaxMapCountDialogButtonUntilRestart": "确定,关闭后重置", - "LinuxVmMaxMapCountDialogButtonPersistent": "确定,永久保存", - "LinuxVmMaxMapCountWarningTextPrimary": "内存映射的最大数量低于推荐值。", - "LinuxVmMaxMapCountWarningTextSecondary": "vm.max_map_count ({0}) 的当前值小于 {1}。 有些游戏可能会试图创建超过当前允许的内存映射量。当大于此限制时,Ryujinx 会立即崩溃。\n\n你可以手动增加内存映射限制或者安装 pkexec,它可以辅助Ryujinx解决该问题。", - "Settings": "设置", - "SettingsTabGeneral": "用户界面", - "SettingsTabGeneralGeneral": "常规", - "SettingsTabGeneralEnableDiscordRichPresence": "启用 Discord 在线状态展示", - "SettingsTabGeneralCheckUpdatesOnLaunch": "自动检查更新", - "SettingsTabGeneralShowConfirmExitDialog": "显示 \"确认退出\" 对话框", - "SettingsTabGeneralHideCursor": "隐藏鼠标指针:", - "SettingsTabGeneralHideCursorNever": "从不", - "SettingsTabGeneralHideCursorOnIdle": "自动隐藏", - "SettingsTabGeneralHideCursorAlways": "始终", - "SettingsTabGeneralGameDirectories": "游戏目录", - "SettingsTabGeneralAdd": "添加", - "SettingsTabGeneralRemove": "删除", - "SettingsTabSystem": "系统", - "SettingsTabSystemCore": "核心", - "SettingsTabSystemSystemRegion": "系统区域:", - "SettingsTabSystemSystemRegionJapan": "日本", - "SettingsTabSystemSystemRegionUSA": "美国", - "SettingsTabSystemSystemRegionEurope": "欧洲", - "SettingsTabSystemSystemRegionAustralia": "澳大利亚", - "SettingsTabSystemSystemRegionChina": "中国", - "SettingsTabSystemSystemRegionKorea": "韩国", - "SettingsTabSystemSystemRegionTaiwan": "台湾地区", - "SettingsTabSystemSystemLanguage": "系统语言:", - "SettingsTabSystemSystemLanguageJapanese": "日语", - "SettingsTabSystemSystemLanguageAmericanEnglish": "美式英语", - "SettingsTabSystemSystemLanguageFrench": "法语", - "SettingsTabSystemSystemLanguageGerman": "德语", - "SettingsTabSystemSystemLanguageItalian": "意大利语", - "SettingsTabSystemSystemLanguageSpanish": "西班牙语", - "SettingsTabSystemSystemLanguageChinese": "简体中文", - "SettingsTabSystemSystemLanguageKorean": "韩语", - "SettingsTabSystemSystemLanguageDutch": "荷兰语", - "SettingsTabSystemSystemLanguagePortuguese": "葡萄牙语", - "SettingsTabSystemSystemLanguageRussian": "俄语", - "SettingsTabSystemSystemLanguageTaiwanese": "繁体中文(台湾)", - "SettingsTabSystemSystemLanguageBritishEnglish": "英式英语", - "SettingsTabSystemSystemLanguageCanadianFrench": "加拿大法语", - "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "拉美西班牙语", - "SettingsTabSystemSystemLanguageSimplifiedChinese": "简体中文(推荐)", - "SettingsTabSystemSystemLanguageTraditionalChinese": "繁体中文(推荐)", - "SettingsTabSystemSystemTimeZone": "系统时区:", - "SettingsTabSystemSystemTime": "系统时钟:", - "SettingsTabSystemEnableVsync": "启用垂直同步", - "SettingsTabSystemEnablePptc": "开启 PPTC 缓存", - "SettingsTabSystemEnableFsIntegrityChecks": "文件系统完整性检查", - "SettingsTabSystemAudioBackend": "音频后端:", - "SettingsTabSystemAudioBackendDummy": "无", - "SettingsTabSystemAudioBackendOpenAL": "OpenAL", - "SettingsTabSystemAudioBackendSoundIO": "音频输入/输出", - "SettingsTabSystemAudioBackendSDL2": "SDL2", - "SettingsTabSystemHacks": "修正", - "SettingsTabSystemHacksNote": "(会引起模拟器不稳定)", - "SettingsTabSystemExpandDramSize": "使用开发机的内存布局", - "SettingsTabSystemIgnoreMissingServices": "忽略缺失的服务", - "SettingsTabGraphics": "图形", - "SettingsTabGraphicsAPI": "图形 API", - "SettingsTabGraphicsEnableShaderCache": "启用着色器缓存", - "SettingsTabGraphicsAnisotropicFiltering": "各向异性过滤:", - "SettingsTabGraphicsAnisotropicFilteringAuto": "自动", - "SettingsTabGraphicsAnisotropicFiltering2x": "2x", - "SettingsTabGraphicsAnisotropicFiltering4x": "4x", - "SettingsTabGraphicsAnisotropicFiltering8x": "8x", - "SettingsTabGraphicsAnisotropicFiltering16x": "16x", - "SettingsTabGraphicsResolutionScale": "分辨率缩放:", - "SettingsTabGraphicsResolutionScaleCustom": "自定义(不推荐)", - "SettingsTabGraphicsResolutionScaleNative": "原生 (720p/1080p)", - "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", - "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", - "SettingsTabGraphicsAspectRatio": "宽高比:", - "SettingsTabGraphicsAspectRatio4x3": "4:3", - "SettingsTabGraphicsAspectRatio16x9": "16:9", - "SettingsTabGraphicsAspectRatio16x10": "16:10", - "SettingsTabGraphicsAspectRatio21x9": "21:9", - "SettingsTabGraphicsAspectRatio32x9": "32:9", - "SettingsTabGraphicsAspectRatioStretch": "拉伸以适应窗口", - "SettingsTabGraphicsDeveloperOptions": "开发者选项", - "SettingsTabGraphicsShaderDumpPath": "图形着色器转储路径:", - "SettingsTabLogging": "日志", - "SettingsTabLoggingLogging": "日志", - "SettingsTabLoggingEnableLoggingToFile": "保存日志为文件", - "SettingsTabLoggingEnableStubLogs": "启用 Stub 日志", - "SettingsTabLoggingEnableInfoLogs": "启用信息日志", - "SettingsTabLoggingEnableWarningLogs": "启用警告日志", - "SettingsTabLoggingEnableErrorLogs": "启用错误日志", - "SettingsTabLoggingEnableTraceLogs": "启用跟踪日志", - "SettingsTabLoggingEnableGuestLogs": "启用来宾日志", - "SettingsTabLoggingEnableFsAccessLogs": "启用访问日志", - "SettingsTabLoggingFsGlobalAccessLogMode": "全局访问日志模式:", - "SettingsTabLoggingDeveloperOptions": "开发者选项", - "SettingsTabLoggingDeveloperOptionsNote": "警告:会降低性能", - "SettingsTabLoggingGraphicsBackendLogLevel": "图形后端日志级别:", - "SettingsTabLoggingGraphicsBackendLogLevelNone": "无", - "SettingsTabLoggingGraphicsBackendLogLevelError": "错误", - "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "减速", - "SettingsTabLoggingGraphicsBackendLogLevelAll": "全部", - "SettingsTabLoggingEnableDebugLogs": "启用调试日志", - "SettingsTabInput": "输入", - "SettingsTabInputEnableDockedMode": "主机模式", - "SettingsTabInputDirectKeyboardAccess": "直通键盘控制", - "SettingsButtonSave": "保存", - "SettingsButtonClose": "取消", - "SettingsButtonOk": "确定", - "SettingsButtonCancel": "取消", - "SettingsButtonApply": "应用", - "ControllerSettingsPlayer": "玩家", - "ControllerSettingsPlayer1": "玩家 1", - "ControllerSettingsPlayer2": "玩家 2", - "ControllerSettingsPlayer3": "玩家 3", - "ControllerSettingsPlayer4": "玩家 4", - "ControllerSettingsPlayer5": "玩家 5", - "ControllerSettingsPlayer6": "玩家 6", - "ControllerSettingsPlayer7": "玩家 7", - "ControllerSettingsPlayer8": "玩家 8", - "ControllerSettingsHandheld": "掌机模式", - "ControllerSettingsInputDevice": "输入设备", - "ControllerSettingsRefresh": "刷新", - "ControllerSettingsDeviceDisabled": "关闭", - "ControllerSettingsControllerType": "手柄类型", - "ControllerSettingsControllerTypeHandheld": "掌机", - "ControllerSettingsControllerTypeProController": "Pro 手柄", - "ControllerSettingsControllerTypeJoyConPair": "JoyCon 组合", - "ControllerSettingsControllerTypeJoyConLeft": "左 JoyCon", - "ControllerSettingsControllerTypeJoyConRight": "右 JoyCon", - "ControllerSettingsProfile": "预设", - "ControllerSettingsProfileDefault": "默认布局", - "ControllerSettingsLoad": "加载", - "ControllerSettingsAdd": "新建", - "ControllerSettingsRemove": "删除", - "ControllerSettingsButtons": "按键", - "ControllerSettingsButtonA": "A", - "ControllerSettingsButtonB": "B", - "ControllerSettingsButtonX": "X", - "ControllerSettingsButtonY": "Y", - "ControllerSettingsButtonPlus": "+", - "ControllerSettingsButtonMinus": "-", - "ControllerSettingsDPad": "方向键", - "ControllerSettingsDPadUp": "上", - "ControllerSettingsDPadDown": "下", - "ControllerSettingsDPadLeft": "左", - "ControllerSettingsDPadRight": "右", - "ControllerSettingsStickButton": "按下摇杆", - "ControllerSettingsStickUp": "上", - "ControllerSettingsStickDown": "下", - "ControllerSettingsStickLeft": "左", - "ControllerSettingsStickRight": "右", - "ControllerSettingsStickStick": "摇杆", - "ControllerSettingsStickInvertXAxis": "反转 X 轴方向", - "ControllerSettingsStickInvertYAxis": "反转 Y 轴方向", - "ControllerSettingsStickDeadzone": "死区:", - "ControllerSettingsLStick": "左摇杆", - "ControllerSettingsRStick": "右摇杆", - "ControllerSettingsTriggersLeft": "左扳机", - "ControllerSettingsTriggersRight": "右扳机", - "ControllerSettingsTriggersButtonsLeft": "左扳机键", - "ControllerSettingsTriggersButtonsRight": "右扳机键", - "ControllerSettingsTriggers": "扳机", - "ControllerSettingsTriggerL": "L", - "ControllerSettingsTriggerR": "R", - "ControllerSettingsTriggerZL": "ZL", - "ControllerSettingsTriggerZR": "ZR", - "ControllerSettingsLeftSL": "SL", - "ControllerSettingsLeftSR": "SR", - "ControllerSettingsRightSL": "SL", - "ControllerSettingsRightSR": "SR", - "ControllerSettingsExtraButtonsLeft": "左背键", - "ControllerSettingsExtraButtonsRight": "右背键", - "ControllerSettingsMisc": "其他", - "ControllerSettingsTriggerThreshold": "扳机阈值:", - "ControllerSettingsMotion": "体感", - "ControllerSettingsMotionUseCemuhookCompatibleMotion": "使用 CemuHook 体感协议", - "ControllerSettingsMotionControllerSlot": "手柄:", - "ControllerSettingsMotionMirrorInput": "镜像操作", - "ControllerSettingsMotionRightJoyConSlot": "右JoyCon:", - "ControllerSettingsMotionServerHost": "服务器Host:", - "ControllerSettingsMotionGyroSensitivity": "陀螺仪敏感度:", - "ControllerSettingsMotionGyroDeadzone": "陀螺仪死区:", - "ControllerSettingsSave": "保存", - "ControllerSettingsClose": "关闭", - "UserProfilesSelectedUserProfile": "选择的用户账户:", - "UserProfilesSaveProfileName": "保存名称", - "UserProfilesChangeProfileImage": "更换头像", - "UserProfilesAvailableUserProfiles": "现有账户:", - "UserProfilesAddNewProfile": "新建账户", - "UserProfilesDelete": "删除", - "UserProfilesClose": "关闭", - "ProfileNameSelectionWatermark": "选择昵称", - "ProfileImageSelectionTitle": "选择头像", - "ProfileImageSelectionHeader": "选择合适的头像图片", - "ProfileImageSelectionNote": "您可以导入自定义头像,或从系统中选择头像", - "ProfileImageSelectionImportImage": "导入图像文件", - "ProfileImageSelectionSelectAvatar": "选择系统头像", - "InputDialogTitle": "输入对话框", - "InputDialogOk": "完成", - "InputDialogCancel": "取消", - "InputDialogAddNewProfileTitle": "选择用户名称", - "InputDialogAddNewProfileHeader": "请输入账户名称", - "InputDialogAddNewProfileSubtext": "(最大长度:{0})", - "AvatarChoose": "选择头像", - "AvatarSetBackgroundColor": "设置背景色", - "AvatarClose": "关闭", - "ControllerSettingsLoadProfileToolTip": "加载预设", - "ControllerSettingsAddProfileToolTip": "新增预设", - "ControllerSettingsRemoveProfileToolTip": "删除预设", - "ControllerSettingsSaveProfileToolTip": "保存预设", - "MenuBarFileToolsTakeScreenshot": "保存截图", - "MenuBarFileToolsHideUi": "隐藏界面", - "GameListContextMenuRunApplication": "运行应用", - "GameListContextMenuToggleFavorite": "收藏", - "GameListContextMenuToggleFavoriteToolTip": "标记喜爱的游戏", - "SettingsTabGeneralTheme": "主题", - "SettingsTabGeneralThemeCustomTheme": "自选主题路径", - "SettingsTabGeneralThemeBaseStyle": "主题色调", - "SettingsTabGeneralThemeBaseStyleDark": "暗黑", - "SettingsTabGeneralThemeBaseStyleLight": "浅色", - "SettingsTabGeneralThemeEnableCustomTheme": "使用自选主题界面", - "ButtonBrowse": "浏览", - "ControllerSettingsConfigureGeneral": "配置", - "ControllerSettingsRumble": "震动", - "ControllerSettingsRumbleStrongMultiplier": "强震动幅度", - "ControllerSettingsRumbleWeakMultiplier": "弱震动幅度", - "DialogMessageSaveNotAvailableMessage": "没有{0} [{1:x16}]的游戏存档", - "DialogMessageSaveNotAvailableCreateSaveMessage": "是否创建该游戏的存档文件夹?", - "DialogConfirmationTitle": "Ryujinx - 设置", - "DialogUpdaterTitle": "Ryujinx - 更新", - "DialogErrorTitle": "Ryujinx - 错误", - "DialogWarningTitle": "Ryujinx - 警告", - "DialogExitTitle": "Ryujinx - 关闭", - "DialogErrorMessage": "Ryujinx 发生错误", - "DialogExitMessage": "是否关闭 Ryujinx?", - "DialogExitSubMessage": "未保存的进度将会丢失!", - "DialogMessageCreateSaveErrorMessage": "创建特定的存档时出错:{0}", - "DialogMessageFindSaveErrorMessage": "查找特定的存档时出错:{0}", - "FolderDialogExtractTitle": "选择要解压到的文件夹", - "DialogNcaExtractionMessage": "提取 {1} 的 {0} 分区...", - "DialogNcaExtractionTitle": "Ryujinx - NCA分区提取", - "DialogNcaExtractionMainNcaNotFoundErrorMessage": "提取失败。所选文件中不含主NCA文件", - "DialogNcaExtractionCheckLogErrorMessage": "提取失败。请查看日志文件获取详情。", - "DialogNcaExtractionSuccessMessage": "提取成功。", - "DialogUpdaterConvertFailedMessage": "无法转换当前 Ryujinx 版本。", - "DialogUpdaterCancelUpdateMessage": "更新取消!", - "DialogUpdaterAlreadyOnLatestVersionMessage": "您使用的 Ryujinx 是最新版本。", - "DialogUpdaterFailedToGetVersionMessage": "尝试从 Github 获取版本信息时无效。\n可能由于 GitHub Actions 正在编译新版本。请过一会再试。", - "DialogUpdaterConvertFailedGithubMessage": "无法转换从 Github 接收到的 Ryujinx 版本。", - "DialogUpdaterDownloadingMessage": "下载新版本中...", - "DialogUpdaterExtractionMessage": "正在提取更新...", - "DialogUpdaterRenamingMessage": "正在删除旧文件...", - "DialogUpdaterAddingFilesMessage": "安装更新中...", - "DialogUpdaterCompleteMessage": "更新成功!", - "DialogUpdaterRestartMessage": "立即重启 Ryujinx 完成更新?", - "DialogUpdaterArchNotSupportedMessage": "您运行的系统架构不受支持!", - "DialogUpdaterArchNotSupportedSubMessage": "(仅支持 x64 系统)", - "DialogUpdaterNoInternetMessage": "没有连接到互联网", - "DialogUpdaterNoInternetSubMessage": "请确保互联网连接正常。", - "DialogUpdaterDirtyBuildMessage": "不能更新非官方版本的 Ryujinx!", - "DialogUpdaterDirtyBuildSubMessage": "如果希望使用受支持的版本,请您在 https://ryujinx.org/ 下载。", - "DialogRestartRequiredMessage": "需要重启模拟器", - "DialogThemeRestartMessage": "主题设置已保存。需要重新启动才能生效。", - "DialogThemeRestartSubMessage": "您是否要重启?", - "DialogFirmwareInstallEmbeddedMessage": "要安装游戏内置的固件吗?(固件 {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "未找到已安装的固件,但 Ryujinx 可以从现有的游戏安装固件{0}.\n模拟器现在可以运行。", - "DialogFirmwareNoFirmwareInstalledMessage": "未安装固件", - "DialogFirmwareInstalledMessage": "已安装固件 {0}", - "DialogInstallFileTypesSuccessMessage": "关联文件类型成功!", - "DialogInstallFileTypesErrorMessage": "关联文件类型失败。", - "DialogUninstallFileTypesSuccessMessage": "成功解除文件类型关联!", - "DialogUninstallFileTypesErrorMessage": "解除文件类型关联失败。", - "DialogOpenSettingsWindowLabel": "打开设置窗口", - "DialogControllerAppletTitle": "控制器小窗口", - "DialogMessageDialogErrorExceptionMessage": "显示消息对话框时出错:{0}", - "DialogSoftwareKeyboardErrorExceptionMessage": "显示软件键盘时出错:{0}", - "DialogErrorAppletErrorExceptionMessage": "显示错误对话框时出错:{0}", - "DialogUserErrorDialogMessage": "{0}: {1}", - "DialogUserErrorDialogInfoMessage": "\n有关修复此错误的更多信息,可以遵循我们的设置指南。", - "DialogUserErrorDialogTitle": "Ryujinx 错误 ({0})", - "DialogAmiiboApiTitle": "Amiibo API", - "DialogAmiiboApiFailFetchMessage": "从 API 获取信息时出错。", - "DialogAmiiboApiConnectErrorMessage": "无法连接到 Amiibo API 服务器。服务器可能已关闭,或者您没有连接网络。", - "DialogProfileInvalidProfileErrorMessage": "预设 {0} 与当前输入配置系统不兼容。", - "DialogProfileDefaultProfileOverwriteErrorMessage": "默认预设不能被覆盖", - "DialogProfileDeleteProfileTitle": "删除预设", - "DialogProfileDeleteProfileMessage": "删除后不可恢复,确认删除吗?", - "DialogWarning": "警告", - "DialogPPTCDeletionMessage": "您即将删除:\n\n{0} 的 PPTC 缓存\n\n确定吗?", - "DialogPPTCDeletionErrorMessage": "清除位于 {0} 的 PPTC 缓存时出错:{1}", - "DialogShaderDeletionMessage": "您即将删除:\n\n{0} 的着色器缓存\n\n确定吗?", - "DialogShaderDeletionErrorMessage": "清除位于 {0} 的着色器缓存时出错:{1}", - "DialogRyujinxErrorMessage": "Ryujinx 遇到错误", - "DialogInvalidTitleIdErrorMessage": "UI错误:所选游戏没有有效的标题ID", - "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "路径 {0} 找不到有效的系统固件。", - "DialogFirmwareInstallerFirmwareInstallTitle": "固件 {0}", - "DialogFirmwareInstallerFirmwareInstallMessage": "即将安装系统版本 {0} 。", - "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\n会替换当前系统版本 {0} 。", - "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n是否确认继续?", - "DialogFirmwareInstallerFirmwareInstallWaitMessage": "安装固件中...", - "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "成功安装系统版本 {0} 。", - "DialogUserProfileDeletionWarningMessage": "删除后将没有可选择的用户账户", - "DialogUserProfileDeletionConfirmMessage": "是否删除选择的账户", - "DialogUserProfileUnsavedChangesTitle": "警告 - 未保存的更改", - "DialogUserProfileUnsavedChangesMessage": "您为该用户做出的部分改动尚未保存。", - "DialogUserProfileUnsavedChangesSubMessage": "是否舍弃这些改动?", - "DialogControllerSettingsModifiedConfirmMessage": "目前的输入预设已更新", - "DialogControllerSettingsModifiedConfirmSubMessage": "要保存吗?", - "DialogLoadNcaErrorMessage": "{0}. 错误的文件:{1}", - "DialogDlcNoDlcErrorMessage": "选择的文件不包含所选游戏的 DLC!", - "DialogPerformanceCheckLoggingEnabledMessage": "您启用了跟踪日志,仅供开发人员使用。", - "DialogPerformanceCheckLoggingEnabledConfirmMessage": "为了获得最佳性能,建议禁用跟踪日志记录。您是否要立即禁用?", - "DialogPerformanceCheckShaderDumpEnabledMessage": "您启用了着色器转储,仅供开发人员使用。", - "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "为了获得最佳性能,建议禁用着色器转储。您是否要立即禁用?", - "DialogLoadAppGameAlreadyLoadedMessage": "已有游戏正在运行", - "DialogLoadAppGameAlreadyLoadedSubMessage": "请停止模拟或关闭程序,再启动另一个游戏。", - "DialogUpdateAddUpdateErrorMessage": "选择的文件不包含所选游戏的更新!", - "DialogSettingsBackendThreadingWarningTitle": "警告 - 后端多线程", - "DialogSettingsBackendThreadingWarningMessage": "改变此选项后必须重启 Ryujinx 才能生效。\n\n取决于您的硬件,可能需要手动禁用驱动面板中的线程优化。", - "SettingsTabGraphicsFeaturesOptions": "功能", - "SettingsTabGraphicsBackendMultithreading": "多线程图形后端:", - "CommonAuto": "自动(推荐)", - "CommonOff": "关闭", - "CommonOn": "打开", - "InputDialogYes": "是", - "InputDialogNo": "否", - "DialogProfileInvalidProfileNameErrorMessage": "文件名包含无效字符,请重试。", - "MenuBarOptionsPauseEmulation": "暂停", - "MenuBarOptionsResumeEmulation": "继续", - "AboutUrlTooltipMessage": "在浏览器中打开 Ryujinx 官网。", - "AboutDisclaimerMessage": "Ryujinx 以任何方式与 Nintendo™ 及其任何商业伙伴都没有关联", - "AboutAmiiboDisclaimerMessage": "我们的 Amiibo 模拟使用了\nAmiiboAPI (www.amiiboapi.com) ", - "AboutPatreonUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Patreon 赞助页。", - "AboutGithubUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 GitHub 代码库。", - "AboutDiscordUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Discord 邀请链接。", - "AboutTwitterUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Twitter 主页。", - "AboutRyujinxAboutTitle": "关于:", - "AboutRyujinxAboutContent": "Ryujinx 是一款 Nintendo Switch™ 模拟器。\n您可以在 Patreon 上赞助 Ryujinx。\n关注 Twitter 或 Discord 可以获取模拟器最新动态。\n如果您对开发感兴趣,欢迎来 GitHub 或 Discord 加入我们!", - "AboutRyujinxMaintainersTitle": "由以下作者维护:", - "AboutRyujinxMaintainersContentTooltipMessage": "在浏览器中打开贡献者页面", - "AboutRyujinxSupprtersTitle": "感谢 Patreon 的赞助者:", - "AmiiboSeriesLabel": "Amiibo 系列", - "AmiiboCharacterLabel": "角色", - "AmiiboScanButtonLabel": "扫描", - "AmiiboOptionsShowAllLabel": "显示所有 Amiibo 系列", - "AmiiboOptionsUsRandomTagLabel": "修复:使用随机标记的 UUID", - "DlcManagerTableHeadingEnabledLabel": "启用", - "DlcManagerTableHeadingTitleIdLabel": "游戏ID", - "DlcManagerTableHeadingContainerPathLabel": "文件夹路径", - "DlcManagerTableHeadingFullPathLabel": "完整路径", - "DlcManagerRemoveAllButton": "全部删除", - "DlcManagerEnableAllButton": "全部启用", - "DlcManagerDisableAllButton": "全部禁用", - "MenuBarOptionsChangeLanguage": "更改语言", - "MenuBarShowFileTypes": "主页显示的文件类型", - "CommonSort": "排序", - "CommonShowNames": "显示名称", - "CommonFavorite": "收藏", - "OrderAscending": "从小到大", - "OrderDescending": "从大到小", - "SettingsTabGraphicsFeatures": "功能与增强", - "ErrorWindowTitle": "错误窗口", - "ToggleDiscordTooltip": "控制是否在 Discord 中显示您的游玩状态", - "AddGameDirBoxTooltip": "输入要添加的游戏目录", - "AddGameDirTooltip": "添加游戏目录到列表中", - "RemoveGameDirTooltip": "移除选中的目录", - "CustomThemeCheckTooltip": "使用自定义UI主题来更改模拟器的外观样式", - "CustomThemePathTooltip": "自定义主题的目录", - "CustomThemeBrowseTooltip": "查找自定义主题", - "DockModeToggleTooltip": "启用 Switch 的主机模式。\n绝大多数游戏画质会提高,略微增加性能消耗。\n在掌机和主机模式切换的过程中,您可能需要重新设置手柄类型。", - "DirectKeyboardTooltip": "开启 \"直连键盘访问(HID)支持\"\n(部分游戏可以使用您的键盘输入文字)", - "DirectMouseTooltip": "开启 \"直连鼠标访问(HID)支持\"\n(部分游戏可以使用您的鼠标导航)", - "RegionTooltip": "更改系统区域", - "LanguageTooltip": "更改系统语言", - "TimezoneTooltip": "更改系统时区", - "TimeTooltip": "更改系统时钟", - "VSyncToggleTooltip": "关闭后,小部分游戏可以超过60FPS帧率,以获得高帧率体验。\n但是可能出现软锁或读盘时间增加。\n如不确定,就请保持开启状态。", - "PptcToggleTooltip": "缓存编译完成的游戏CPU指令。减少启动时间和卡顿,提高游戏响应速度。\n如不确定,就请保持开启状态。", - "FsIntegrityToggleTooltip": "检查游戏文件内容的完整性。\n遇到损坏的文件则记录到日志文件,有助于排查错误。\n对性能没有影响。\n如不确定,就请保持开启状态。", - "AudioBackendTooltip": "默认推荐SDL2,但每种音频后端对各类游戏兼容性不同,遇到音频问题可以尝试切换后端。", - "MemoryManagerTooltip": "改变 Switch 内存映射到电脑内存的方式,会影响CPU性能消耗。", - "MemoryManagerSoftwareTooltip": "使用软件内存页管理,最精确但是速度最慢。", - "MemoryManagerHostTooltip": "直接映射内存页到电脑内存,使得即时编译效率更高。", - "MemoryManagerUnsafeTooltip": "直接映射内存页,但不检查内存溢出,使得即时编译效率更高。\nRyujinx 可以访问任何位置的内存,因而相对不安全。\n此模式下只应运行您信任的游戏或软件(即官方游戏)。", - "UseHypervisorTooltip": "使用 Hypervisor 虚拟机代替即时编译。在可用的情况下能大幅提高性能。但目前可能不稳定。", - "DRamTooltip": "使用Switch开发机的内存布局。\n不会提高任何性能,某些高清纹理包或 4k 分辨率 MOD 可能需要此选项。\n如果不确定,请始终关闭该选项。", - "IgnoreMissingServicesTooltip": "开启后,游戏会忽略未实现的系统服务,从而继续运行。\n少部分新发布的游戏由于使用新的未知系统服务,可能需要此选项来避免闪退。\n模拟器更新完善系统服务之后,则无需开启选项。\n如您的游戏已经正常运行,请保持此选项关闭。", - "GraphicsBackendThreadingTooltip": "在第二个线程上执行图形后端命令。\n\n加速着色器编译,减少卡顿,提高 GPU 的性能。\n\n如果不确定,请设置为自动。", - "GalThreadingTooltip": "在第二个线程上执行图形后端命令。\n\n加速着色器编译,减少卡顿,提高 GPU 的性能。\n\n如果不确定,请设置为自动。", - "ShaderCacheToggleTooltip": "开启后,模拟器会保存编译完成的着色器到磁盘,减少游戏渲染新特效和场景时的卡顿。", - "ResolutionScaleTooltip": "缩放渲染的分辨率", - "ResolutionScaleEntryTooltip": "尽可能使用例如1.5的浮点倍数。非整数的倍率易引起 BUG。", - "AnisotropyTooltip": "各向异性过滤等级。提高倾斜视角纹理的清晰度\n('自动'使用游戏默认的等级)", - "AspectRatioTooltip": "渲染窗口的宽高比。", - "ShaderDumpPathTooltip": "转储图形着色器的路径", - "FileLogTooltip": "保存日志文件到硬盘。不会影响性能。", - "StubLogTooltip": "在控制台中打印 stub 日志消息。不影响性能。", - "InfoLogTooltip": "在控制台中打印信息日志消息。不影响性能。", - "WarnLogTooltip": "在控制台中打印警告日志消息。不影响性能。", - "ErrorLogTooltip": "打印控制台中的错误日志消息。不影响性能。", - "TraceLogTooltip": "在控制台中打印跟踪日志消息。不影响性能。", - "GuestLogTooltip": "在控制台中打印访客日志消息。不影响性能。", - "FileAccessLogTooltip": "在控制台中打印文件访问日志信息。", - "FSAccessLogModeTooltip": "启用访问日志输出到控制台。可能的模式为 0-3", - "DeveloperOptionTooltip": "谨慎使用", - "OpenGlLogLevel": "需要打开适当的日志等级", - "DebugLogTooltip": "记录Debug消息", - "LoadApplicationFileTooltip": "选择 Switch 支持的游戏格式并加载", - "LoadApplicationFolderTooltip": "选择解包后的 Switch 游戏并加载", - "OpenRyujinxFolderTooltip": "打开 Ryujinx 系统目录", - "OpenRyujinxLogsTooltip": "打开日志存放的目录", - "ExitTooltip": "关闭 Ryujinx", - "OpenSettingsTooltip": "打开设置窗口", - "OpenProfileManagerTooltip": "打开用户账户管理界面", - "StopEmulationTooltip": "停止运行当前游戏并回到主界面", - "CheckUpdatesTooltip": "检查 Ryujinx 新版本", - "OpenAboutTooltip": "打开“关于”窗口", - "GridSize": "网格尺寸", - "GridSizeTooltip": "调整网格模式的大小", - "SettingsTabSystemSystemLanguageBrazilianPortuguese": "巴西葡萄牙语", - "AboutRyujinxContributorsButtonHeader": "查看所有参与者", - "SettingsTabSystemAudioVolume": "音量:", - "AudioVolumeTooltip": "调节音量", - "SettingsTabSystemEnableInternetAccess": "允许网络访问/局域网模式", - "EnableInternetAccessTooltip": "允许模拟的游戏进程访问互联网。\n当多个模拟器/真实的 Switch 连接到同一个局域网时,带有 LAN 模式的游戏可以相互通信。\n即使开启选项也无法访问 Nintendo 服务器。此外可能导致某些尝试联网的游戏崩溃。\n如果您不确定,请关闭该选项。", - "GameListContextMenuManageCheatToolTip": "管理金手指", - "GameListContextMenuManageCheat": "管理金手指", - "ControllerSettingsStickRange": "范围:", - "DialogStopEmulationTitle": "Ryujinx - 停止模拟", - "DialogStopEmulationMessage": "是否确定停止模拟?", - "SettingsTabCpu": "CPU", - "SettingsTabAudio": "音频", - "SettingsTabNetwork": "网络", - "SettingsTabNetworkConnection": "网络连接", - "SettingsTabCpuCache": "CPU 缓存", - "SettingsTabCpuMemory": "CPU 内存", - "DialogUpdaterFlatpakNotSupportedMessage": "请通过 FlatHub 更新 Ryujinx。", - "UpdaterDisabledWarningTitle": "更新已禁用!", - "GameListContextMenuOpenSdModsDirectory": "打开 Atmosphere MOD 目录", - "GameListContextMenuOpenSdModsDirectoryToolTip": "打开适用于 Atmosphere 自制系统的 MOD 目录", - "ControllerSettingsRotate90": "顺时针旋转 90°", - "IconSize": "图标尺寸", - "IconSizeTooltip": "更改游戏图标大小", - "MenuBarOptionsShowConsole": "显示控制台", - "ShaderCachePurgeError": "清除着色器缓存时出错:{0}: {1}", - "UserErrorNoKeys": "找不到密钥", - "UserErrorNoFirmware": "找不到固件", - "UserErrorFirmwareParsingFailed": "固件解析错误", - "UserErrorApplicationNotFound": "找不到应用程序", - "UserErrorUnknown": "未知错误", - "UserErrorUndefined": "未定义错误", - "UserErrorNoKeysDescription": "Ryujinx 找不到 'prod.keys' 文件", - "UserErrorNoFirmwareDescription": "Ryujinx 找不到任何已安装的固件", - "UserErrorFirmwareParsingFailedDescription": "Ryujinx 无法解密选择的固件。这通常是由于使用了过旧的密钥。", - "UserErrorApplicationNotFoundDescription": "Ryujinx 在选中路径找不到有效的应用程序。", - "UserErrorUnknownDescription": "发生未知错误!", - "UserErrorUndefinedDescription": "发生了未定义错误!此类错误不应出现,请联系开发人员!", - "OpenSetupGuideMessage": "打开设置教程", - "NoUpdate": "无更新", - "TitleUpdateVersionLabel": "版本 {0}", - "RyujinxInfo": "Ryujinx - 信息", - "RyujinxConfirm": "Ryujinx - 确认", - "FileDialogAllTypes": "全部类型", - "Never": "从不", - "SwkbdMinCharacters": "至少应为 {0} 个字长", - "SwkbdMinRangeCharacters": "必须为 {0}-{1} 个字长", - "SoftwareKeyboard": "软件键盘", - "SoftwareKeyboardModeNumbersOnly": "只接受数字", - "SoftwareKeyboardModeAlphabet": "只接受非中日韩文字", - "SoftwareKeyboardModeASCII": "只接受 ASCII 符号", - "DialogControllerAppletMessagePlayerRange": "游戏需要 {0} 个玩家并满足以下要求:\n\n手柄类型:{1}\n\n玩家类型:{2}\n\n{3} 请打开设置窗口,重新配置手柄输入;或者关闭返回。", - "DialogControllerAppletMessage": "游戏需要刚好 {0} 个玩家并满足以下要求:\n\n手柄类型:{1}\n\n玩家类型:{2}\n\n{3} 请打开设置窗口,重新配置手柄输入;或者关闭返回。", - "DialogControllerAppletDockModeSet": "目前处于主机模式,无法使用掌机操作方式", - "UpdaterRenaming": "正在删除旧文件...", - "UpdaterRenameFailed": "更新过程中无法重命名文件:{0}", - "UpdaterAddingFiles": "安装更新中...", - "UpdaterExtracting": "正在提取更新...", - "UpdaterDownloading": "下载新版本中...", - "Game": "游戏", - "Docked": "主机模式", - "Handheld": "掌机模式", - "ConnectionError": "连接错误。", - "AboutPageDeveloperListMore": "{0} 等开发者...", - "ApiError": "API错误。", - "LoadingHeading": "正在启动 {0}", - "CompilingPPTC": "编译PPTC缓存中", - "CompilingShaders": "编译着色器中", - "AllKeyboards": "所有键盘", - "OpenFileDialogTitle": "选择一个支持的文件以打开", - "OpenFolderDialogTitle": "选择一个包含解包游戏的文件夹", - "AllSupportedFormats": "所有支持的格式", - "RyujinxUpdater": "Ryujinx 更新程序", - "SettingsTabHotkeys": "快捷键", - "SettingsTabHotkeysHotkeys": "键盘快捷键", - "SettingsTabHotkeysToggleVsyncHotkey": "切换垂直同步:", - "SettingsTabHotkeysScreenshotHotkey": "截屏:", - "SettingsTabHotkeysShowUiHotkey": "隐藏 界面:", - "SettingsTabHotkeysPauseHotkey": "暂停:", - "SettingsTabHotkeysToggleMuteHotkey": "静音:", - "ControllerMotionTitle": "体感操作设置", - "ControllerRumbleTitle": "震动设置", - "SettingsSelectThemeFileDialogTitle": "选择主题文件", - "SettingsXamlThemeFile": "Xaml 主题文件", - "AvatarWindowTitle": "管理账户 - 头像", - "Amiibo": "Amiibo", - "Unknown": "未知", - "Usage": "扫描可获得", - "Writable": "可写入", - "SelectDlcDialogTitle": "选择 DLC 文件", - "SelectUpdateDialogTitle": "选择更新文件", - "UserProfileWindowTitle": "管理用户账户", - "CheatWindowTitle": "金手指管理器", - "DlcWindowTitle": "管理 {0} ({1}) 的 DLC", - "UpdateWindowTitle": "游戏更新管理器", - "CheatWindowHeading": "适用于 {0} [{1}] 的金手指", - "BuildId": "游戏版本ID:", - "DlcWindowHeading": "{0} 个适用于 {1} ({2}) 的 DLC", - "UserProfilesEditProfile": "编辑选中账户", - "Cancel": "取消", - "Save": "保存", - "Discard": "返回", - "UserProfilesSetProfileImage": "选择头像", - "UserProfileEmptyNameError": "必须输入名称", - "UserProfileNoImageError": "请选择您的头像", - "GameUpdateWindowHeading": "管理 {0} ({1}) 的更新", - "SettingsTabHotkeysResScaleUpHotkey": "提高分辨率:", - "SettingsTabHotkeysResScaleDownHotkey": "降低分辨率:", - "UserProfilesName": "名称:", - "UserProfilesUserId": "用户ID:", - "SettingsTabGraphicsBackend": "图形后端", - "SettingsTabGraphicsBackendTooltip": "显卡使用的图形后端", - "SettingsEnableTextureRecompression": "启用纹理重压缩", - "SettingsEnableTextureRecompressionTooltip": "压缩某些纹理以减少显存的使用。\n适合显存小于 4GiB 的 GPU 开启。\n如果您不确定,请保持此项关闭。", - "SettingsTabGraphicsPreferredGpu": "首选 GPU", - "SettingsTabGraphicsPreferredGpuTooltip": "选择 Vulkan API 使用的显卡。\n此选项不会影响 OpenGL API。\n如果您不确定,建议选择\"dGPU(独立显卡)\"。如果没有独立显卡,则无需改动此选项。", - "SettingsAppRequiredRestartMessage": "Ryujinx 需要重启", - "SettingsGpuBackendRestartMessage": "您修改了图形 API 或显卡设置。需要重新启动才能生效", - "SettingsGpuBackendRestartSubMessage": "是否重启模拟器?", - "RyujinxUpdaterMessage": "是否更新 Ryujinx 到最新的版本?", - "SettingsTabHotkeysVolumeUpHotkey": "音量加:", - "SettingsTabHotkeysVolumeDownHotkey": "音量减:", - "SettingsEnableMacroHLE": "启用 HLE 宏", - "SettingsEnableMacroHLETooltip": "GPU 宏代码的高级模拟。\n提高性能表现,但可能在某些游戏中引起图形错误。\n如果您不确定,请保持此项开启。", - "SettingsEnableColorSpacePassthrough": "颜色空间穿透", - "SettingsEnableColorSpacePassthroughTooltip": "指示 Vulkan 后端在不指定颜色空间的情况下传递颜色信息。对于具有宽色域显示器的用户来说,这可能会以颜色正确性为代价,产生更鲜艳的颜色。", - "VolumeShort": "音量", - "UserProfilesManageSaves": "管理存档", - "DeleteUserSave": "确定删除这个游戏的存档吗?", - "IrreversibleActionNote": "删除后不可恢复。", - "SaveManagerHeading": "管理 {0} ({1}) 的存档", - "SaveManagerTitle": "存档管理器", - "Name": "名称", - "Size": "大小", - "Search": "搜索", - "UserProfilesRecoverLostAccounts": "恢复丢失的账户", - "Recover": "恢复", - "UserProfilesRecoverHeading": "找到了这些用户的存档数据", - "UserProfilesRecoverEmptyList": "没有可以恢复的配置文件", - "GraphicsAATooltip": "将抗锯齿使用到游戏渲染中", - "GraphicsAALabel": "抗锯齿:", - "GraphicsScalingFilterLabel": "缩放过滤:", - "GraphicsScalingFilterTooltip": "对帧缓冲区进行缩放", - "GraphicsScalingFilterLevelLabel": "等级", - "GraphicsScalingFilterLevelTooltip": "设置缩放过滤级别", - "SmaaLow": "SMAA 低质量", - "SmaaMedium": "SMAA 中质量", - "SmaaHigh": "SMAA 高质量", - "SmaaUltra": "SMAA 极致质量", - "UserEditorTitle": "编辑用户", - "UserEditorTitleCreate": "创建用户", - "SettingsTabNetworkInterface": "网络接口:", - "NetworkInterfaceTooltip": "用于局域网功能的网络接口", - "NetworkInterfaceDefault": "默认", - "PackagingShaders": "整合着色器中", - "AboutChangelogButton": "在Github上查看更新日志", - "AboutChangelogButtonTooltipMessage": "点击这里在您的默认浏览器中打开此版本的更新日志。" -} \ No newline at end of file diff --git a/src/Ryujinx.Ava/Assets/Locales/zh_TW.json b/src/Ryujinx.Ava/Assets/Locales/zh_TW.json deleted file mode 100644 index a2f59f60d..000000000 --- a/src/Ryujinx.Ava/Assets/Locales/zh_TW.json +++ /dev/null @@ -1,656 +0,0 @@ -{ - "Language": "英文 (美國)", - "MenuBarFileOpenApplet": "開啟 Applet 應用程序", - "MenuBarFileOpenAppletOpenMiiAppletToolTip": "開啟獨立的Mii修改器應用程序", - "SettingsTabInputDirectMouseAccess": "滑鼠直接操作", - "SettingsTabSystemMemoryManagerMode": "記憶體管理模式:", - "SettingsTabSystemMemoryManagerModeSoftware": "軟體", - "SettingsTabSystemMemoryManagerModeHost": "主機模式 (快速)", - "SettingsTabSystemMemoryManagerModeHostUnchecked": "主機略過檢查模式 (最快, 但不安全)", - "SettingsTabSystemUseHypervisor": "使用 Hypervisor", - "MenuBarFile": "_檔案", - "MenuBarFileOpenFromFile": "_載入檔案", - "MenuBarFileOpenUnpacked": "載入_已解開封裝的遊戲", - "MenuBarFileOpenEmuFolder": "開啟 Ryujinx 資料夾", - "MenuBarFileOpenLogsFolder": "開啟日誌資料夾", - "MenuBarFileExit": "_退出", - "MenuBarOptions": "選項", - "MenuBarOptionsToggleFullscreen": "切換全螢幕模式", - "MenuBarOptionsStartGamesInFullscreen": "使用全螢幕模式啟動遊戲", - "MenuBarOptionsStopEmulation": "停止模擬", - "MenuBarOptionsSettings": "_設定", - "MenuBarOptionsManageUserProfiles": "_管理使用者帳戶", - "MenuBarActions": "_動作", - "MenuBarOptionsSimulateWakeUpMessage": "模擬喚醒訊息", - "MenuBarActionsScanAmiibo": "掃描 Amiibo", - "MenuBarTools": "_工具", - "MenuBarToolsInstallFirmware": "安裝韌體", - "MenuBarFileToolsInstallFirmwareFromFile": "從 XCI 或 ZIP 安裝韌體", - "MenuBarFileToolsInstallFirmwareFromDirectory": "從資料夾安裝韌體", - "MenuBarToolsManageFileTypes": "管理檔案類型", - "MenuBarToolsInstallFileTypes": "註冊檔案類型", - "MenuBarToolsUninstallFileTypes": "取消註冊檔案類型", - "MenuBarHelp": "幫助", - "MenuBarHelpCheckForUpdates": "檢查更新", - "MenuBarHelpAbout": "關於", - "MenuSearch": "搜尋...", - "GameListHeaderFavorite": "收藏", - "GameListHeaderIcon": "圖示", - "GameListHeaderApplication": "名稱", - "GameListHeaderDeveloper": "開發人員", - "GameListHeaderVersion": "版本", - "GameListHeaderTimePlayed": "遊玩時數", - "GameListHeaderLastPlayed": "最近遊玩", - "GameListHeaderFileExtension": "副檔名", - "GameListHeaderFileSize": "檔案大小", - "GameListHeaderPath": "路徑", - "GameListContextMenuOpenUserSaveDirectory": "開啟使用者存檔資料夾", - "GameListContextMenuOpenUserSaveDirectoryToolTip": "開啟此遊戲的存檔資料夾", - "GameListContextMenuOpenDeviceSaveDirectory": "開啟系統資料夾", - "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "開啟此遊戲的系統設定資料夾", - "GameListContextMenuOpenBcatSaveDirectory": "開啟 BCAT 資料夾", - "GameListContextMenuOpenBcatSaveDirectoryToolTip": "開啟此遊戲的 BCAT 資料夾\n", - "GameListContextMenuManageTitleUpdates": "管理遊戲更新", - "GameListContextMenuManageTitleUpdatesToolTip": "開啟遊戲更新管理視窗", - "GameListContextMenuManageDlc": "管理 DLC", - "GameListContextMenuManageDlcToolTip": "開啟 DLC 管理視窗", - "GameListContextMenuOpenModsDirectory": "開啟模組資料夾", - "GameListContextMenuOpenModsDirectoryToolTip": "開啟此遊戲的模組資料夾", - "GameListContextMenuCacheManagement": "快取管理", - "GameListContextMenuCacheManagementPurgePptc": "清除 PPTC 快取", - "GameListContextMenuCacheManagementPurgePptcToolTip": "刪除遊戲的 PPTC 快取", - "GameListContextMenuCacheManagementPurgeShaderCache": "清除著色器快取", - "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "刪除遊戲的著色器快取", - "GameListContextMenuCacheManagementOpenPptcDirectory": "開啟 PPTC 資料夾", - "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "開啟此遊戲的 PPTC 快取資料夾", - "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "開啟著色器快取資料夾", - "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "開啟此遊戲的著色器快取資料夾", - "GameListContextMenuExtractData": "提取資料", - "GameListContextMenuExtractDataExeFS": "ExeFS", - "GameListContextMenuExtractDataExeFSToolTip": "從遊戲的目前狀態中提取 ExeFS 分區(包含更新)", - "GameListContextMenuExtractDataRomFS": "RomFS", - "GameListContextMenuExtractDataRomFSToolTip": "從遊戲的目前狀態中提取 RomFS 分區(包含更新)", - "GameListContextMenuExtractDataLogo": "圖示", - "GameListContextMenuExtractDataLogoToolTip": "從遊戲的目前狀態中提取圖示(包含更新)", - "StatusBarGamesLoaded": "{0}/{1} 遊戲載入完成", - "StatusBarSystemVersion": "系統版本: {0}", - "LinuxVmMaxMapCountDialogTitle": "檢測到映射的記憶體上限過低", - "LinuxVmMaxMapCountDialogTextPrimary": "你願意增加 vm.max_map_count to {0} 的數值嗎?", - "LinuxVmMaxMapCountDialogTextSecondary": "遊戲佔用的記憶體超出了映射的上限. Ryujinx的處理程序即將面臨崩潰.", - "LinuxVmMaxMapCountDialogButtonUntilRestart": "碓定 (直至下一次重新啟動)", - "LinuxVmMaxMapCountDialogButtonPersistent": "碓定 (永遠設定)", - "LinuxVmMaxMapCountWarningTextPrimary": "映射記憶體的最大值少於目前建議的下限.", - "LinuxVmMaxMapCountWarningTextSecondary": "目前 vm.max_map_count ({0}) 的數值少於 {1}. 遊戲佔用的記憶體超出了映射的上限. Ryujinx的處理程序即將面臨崩潰.\n\n你可能需要手動增加上限或安裝 pkexec, 這些都能協助Ryujinx完成此操作.", - "Settings": "設定", - "SettingsTabGeneral": "使用者介面", - "SettingsTabGeneralGeneral": "一般", - "SettingsTabGeneralEnableDiscordRichPresence": "啟用 Discord 動態狀態展示", - "SettingsTabGeneralCheckUpdatesOnLaunch": "自動檢查更新", - "SettingsTabGeneralShowConfirmExitDialog": "顯示「確認離開」對話框", - "SettingsTabGeneralHideCursor": "隱藏滑鼠遊標:", - "SettingsTabGeneralHideCursorNever": "永不", - "SettingsTabGeneralHideCursorOnIdle": "自動隱藏滑鼠", - "SettingsTabGeneralHideCursorAlways": "總是", - "SettingsTabGeneralGameDirectories": "遊戲資料夾", - "SettingsTabGeneralAdd": "新增", - "SettingsTabGeneralRemove": "刪除", - "SettingsTabSystem": "系統", - "SettingsTabSystemCore": "核心", - "SettingsTabSystemSystemRegion": "系統區域:", - "SettingsTabSystemSystemRegionJapan": "日本", - "SettingsTabSystemSystemRegionUSA": "美國", - "SettingsTabSystemSystemRegionEurope": "歐洲", - "SettingsTabSystemSystemRegionAustralia": "澳洲", - "SettingsTabSystemSystemRegionChina": "中國", - "SettingsTabSystemSystemRegionKorea": "韓國", - "SettingsTabSystemSystemRegionTaiwan": "台灣", - "SettingsTabSystemSystemLanguage": "系統語言:", - "SettingsTabSystemSystemLanguageJapanese": "日文", - "SettingsTabSystemSystemLanguageAmericanEnglish": "英文 (美國)", - "SettingsTabSystemSystemLanguageFrench": "法文", - "SettingsTabSystemSystemLanguageGerman": "德文", - "SettingsTabSystemSystemLanguageItalian": "義大利文", - "SettingsTabSystemSystemLanguageSpanish": "西班牙文", - "SettingsTabSystemSystemLanguageChinese": "中文 (中國)", - "SettingsTabSystemSystemLanguageKorean": "韓文", - "SettingsTabSystemSystemLanguageDutch": "荷蘭文", - "SettingsTabSystemSystemLanguagePortuguese": "葡萄牙文", - "SettingsTabSystemSystemLanguageRussian": "俄文", - "SettingsTabSystemSystemLanguageTaiwanese": "中文 (台灣)", - "SettingsTabSystemSystemLanguageBritishEnglish": "英文 (英國)", - "SettingsTabSystemSystemLanguageCanadianFrench": "加拿大法語", - "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "拉丁美洲西班牙文", - "SettingsTabSystemSystemLanguageSimplifiedChinese": "簡體中文", - "SettingsTabSystemSystemLanguageTraditionalChinese": "繁體中文", - "SettingsTabSystemSystemTimeZone": "系統時區:", - "SettingsTabSystemSystemTime": "系統時鐘:", - "SettingsTabSystemEnableVsync": "垂直同步", - "SettingsTabSystemEnablePptc": "啟用 PPTC 快取", - "SettingsTabSystemEnableFsIntegrityChecks": "開啟檔案系統完整性檢查", - "SettingsTabSystemAudioBackend": "音效處理後台架構:", - "SettingsTabSystemAudioBackendDummy": "模擬", - "SettingsTabSystemAudioBackendOpenAL": "OpenAL", - "SettingsTabSystemAudioBackendSoundIO": "SoundIO", - "SettingsTabSystemAudioBackendSDL2": "SDL2", - "SettingsTabSystemHacks": "修正", - "SettingsTabSystemHacksNote": " (會引起模擬器不穩定)", - "SettingsTabSystemExpandDramSize": "使用額外的記憶體佈局 (開發人員)", - "SettingsTabSystemIgnoreMissingServices": "忽略缺少的服務", - "SettingsTabGraphics": "圖像", - "SettingsTabGraphicsAPI": "圖像處理應用程式介面", - "SettingsTabGraphicsEnableShaderCache": "啟用著色器快取", - "SettingsTabGraphicsAnisotropicFiltering": "各向異性過濾:", - "SettingsTabGraphicsAnisotropicFilteringAuto": "自動", - "SettingsTabGraphicsAnisotropicFiltering2x": "2 倍", - "SettingsTabGraphicsAnisotropicFiltering4x": "4 倍", - "SettingsTabGraphicsAnisotropicFiltering8x": "8 倍", - "SettingsTabGraphicsAnisotropicFiltering16x": "16倍", - "SettingsTabGraphicsResolutionScale": "解析度比例:", - "SettingsTabGraphicsResolutionScaleCustom": "自訂 (不建議使用)", - "SettingsTabGraphicsResolutionScaleNative": "原生 (720p/1080p)", - "SettingsTabGraphicsResolutionScale2x": "2 倍 (1440p/2160p)", - "SettingsTabGraphicsResolutionScale3x": "3 倍 (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4 倍 (2880p/4320p)", - "SettingsTabGraphicsAspectRatio": "螢幕長寬比例:", - "SettingsTabGraphicsAspectRatio4x3": "4:3", - "SettingsTabGraphicsAspectRatio16x9": "16:9", - "SettingsTabGraphicsAspectRatio16x10": "16:10", - "SettingsTabGraphicsAspectRatio21x9": "21:9", - "SettingsTabGraphicsAspectRatio32x9": "32:9", - "SettingsTabGraphicsAspectRatioStretch": "伸展至螢幕大小", - "SettingsTabGraphicsDeveloperOptions": "開發者選項", - "SettingsTabGraphicsShaderDumpPath": "圖形著色器轉存路徑:", - "SettingsTabLogging": "日誌", - "SettingsTabLoggingLogging": "日誌", - "SettingsTabLoggingEnableLoggingToFile": "儲存記錄日誌為檔案", - "SettingsTabLoggingEnableStubLogs": "啟用 Stub 記錄", - "SettingsTabLoggingEnableInfoLogs": "啟用資訊記錄", - "SettingsTabLoggingEnableWarningLogs": "啟用警告記錄", - "SettingsTabLoggingEnableErrorLogs": "啟用錯誤記錄", - "SettingsTabLoggingEnableTraceLogs": "啟用追蹤記錄", - "SettingsTabLoggingEnableGuestLogs": "啟用賓客記錄", - "SettingsTabLoggingEnableFsAccessLogs": "啟用檔案存取記錄", - "SettingsTabLoggingFsGlobalAccessLogMode": "記錄全域檔案存取模式:", - "SettingsTabLoggingDeveloperOptions": "開發者選項", - "SettingsTabLoggingDeveloperOptionsNote": "警告:此操作會降低效能", - "SettingsTabLoggingGraphicsBackendLogLevel": "圖像處理後台記錄等級:", - "SettingsTabLoggingGraphicsBackendLogLevelNone": "無", - "SettingsTabLoggingGraphicsBackendLogLevelError": "錯誤", - "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "減速", - "SettingsTabLoggingGraphicsBackendLogLevelAll": "全部", - "SettingsTabLoggingEnableDebugLogs": "啟用除錯記錄", - "SettingsTabInput": "輸入", - "SettingsTabInputEnableDockedMode": "Docked 模式", - "SettingsTabInputDirectKeyboardAccess": "鍵盤直接操作", - "SettingsButtonSave": "儲存", - "SettingsButtonClose": "關閉", - "SettingsButtonOk": "確定", - "SettingsButtonCancel": "取消", - "SettingsButtonApply": "套用", - "ControllerSettingsPlayer": "玩家", - "ControllerSettingsPlayer1": "玩家 1", - "ControllerSettingsPlayer2": "玩家 2", - "ControllerSettingsPlayer3": "玩家 3", - "ControllerSettingsPlayer4": "玩家 4", - "ControllerSettingsPlayer5": "玩家 5", - "ControllerSettingsPlayer6": "玩家 6", - "ControllerSettingsPlayer7": "玩家 7", - "ControllerSettingsPlayer8": "玩家 8", - "ControllerSettingsHandheld": "掌機模式", - "ControllerSettingsInputDevice": "輸入裝置", - "ControllerSettingsRefresh": "更新", - "ControllerSettingsDeviceDisabled": "關閉", - "ControllerSettingsControllerType": "控制器類型", - "ControllerSettingsControllerTypeHandheld": "掌機", - "ControllerSettingsControllerTypeProController": "Nintendo Switch Pro控制器", - "ControllerSettingsControllerTypeJoyConPair": "JoyCon", - "ControllerSettingsControllerTypeJoyConLeft": "左 JoyCon", - "ControllerSettingsControllerTypeJoyConRight": "右 JoyCon", - "ControllerSettingsProfile": "配置檔案", - "ControllerSettingsProfileDefault": "預設", - "ControllerSettingsLoad": "載入", - "ControllerSettingsAdd": "建立", - "ControllerSettingsRemove": "刪除", - "ControllerSettingsButtons": "按鍵", - "ControllerSettingsButtonA": "A", - "ControllerSettingsButtonB": "B", - "ControllerSettingsButtonX": "X", - "ControllerSettingsButtonY": "Y", - "ControllerSettingsButtonPlus": "+", - "ControllerSettingsButtonMinus": "-", - "ControllerSettingsDPad": "方向鍵", - "ControllerSettingsDPadUp": "上", - "ControllerSettingsDPadDown": "下", - "ControllerSettingsDPadLeft": "左", - "ControllerSettingsDPadRight": "右", - "ControllerSettingsStickButton": "按鍵", - "ControllerSettingsStickUp": "上", - "ControllerSettingsStickDown": "下", - "ControllerSettingsStickLeft": "左", - "ControllerSettingsStickRight": "右", - "ControllerSettingsStickStick": "搖桿", - "ControllerSettingsStickInvertXAxis": "搖桿左右反向", - "ControllerSettingsStickInvertYAxis": "搖桿上下反向", - "ControllerSettingsStickDeadzone": "盲區:", - "ControllerSettingsLStick": "左搖桿", - "ControllerSettingsRStick": "右搖桿", - "ControllerSettingsTriggersLeft": "左 Triggers", - "ControllerSettingsTriggersRight": "右 Triggers", - "ControllerSettingsTriggersButtonsLeft": "左 Triggers 鍵", - "ControllerSettingsTriggersButtonsRight": "右 Triggers 鍵", - "ControllerSettingsTriggers": "板機", - "ControllerSettingsTriggerL": "L", - "ControllerSettingsTriggerR": "R", - "ControllerSettingsTriggerZL": "ZL", - "ControllerSettingsTriggerZR": "ZR", - "ControllerSettingsLeftSL": "SL", - "ControllerSettingsLeftSR": "SR", - "ControllerSettingsRightSL": "SL", - "ControllerSettingsRightSR": "SR", - "ControllerSettingsExtraButtonsLeft": "左按鍵", - "ControllerSettingsExtraButtonsRight": "右按鍵", - "ControllerSettingsMisc": "其他", - "ControllerSettingsTriggerThreshold": "Triggers 閾值:", - "ControllerSettingsMotion": "傳感器", - "ControllerSettingsMotionUseCemuhookCompatibleMotion": "使用 CemuHook 相容性傳感協定", - "ControllerSettingsMotionControllerSlot": "控制器插槽:", - "ControllerSettingsMotionMirrorInput": "鏡像輸入", - "ControllerSettingsMotionRightJoyConSlot": "右 JoyCon:", - "ControllerSettingsMotionServerHost": "伺服器IP地址:", - "ControllerSettingsMotionGyroSensitivity": "陀螺儀敏感度:", - "ControllerSettingsMotionGyroDeadzone": "陀螺儀盲區:", - "ControllerSettingsSave": "儲存", - "ControllerSettingsClose": "關閉", - "UserProfilesSelectedUserProfile": "選擇使用者帳戶:", - "UserProfilesSaveProfileName": "儲存帳戶名稱", - "UserProfilesChangeProfileImage": "更換帳戶頭像", - "UserProfilesAvailableUserProfiles": "現有的使用者帳戶:", - "UserProfilesAddNewProfile": "建立帳戶", - "UserProfilesDelete": "刪除", - "UserProfilesClose": "關閉", - "ProfileNameSelectionWatermark": "選擇一個暱稱", - "ProfileImageSelectionTitle": "帳戶頭像選擇", - "ProfileImageSelectionHeader": "選擇帳戶頭像", - "ProfileImageSelectionNote": "你可以導入自訂頭像,或從系統中選擇頭像", - "ProfileImageSelectionImportImage": "導入圖片檔案", - "ProfileImageSelectionSelectAvatar": "選擇系統頭像", - "InputDialogTitle": "輸入對話框", - "InputDialogOk": "完成", - "InputDialogCancel": "取消", - "InputDialogAddNewProfileTitle": "選擇帳戶名稱", - "InputDialogAddNewProfileHeader": "請輸入帳戶名稱", - "InputDialogAddNewProfileSubtext": "(最大長度:{0})", - "AvatarChoose": "選擇", - "AvatarSetBackgroundColor": "設定背景顏色", - "AvatarClose": "關閉", - "ControllerSettingsLoadProfileToolTip": "載入配置檔案", - "ControllerSettingsAddProfileToolTip": "新增配置檔案", - "ControllerSettingsRemoveProfileToolTip": "刪除配置檔案", - "ControllerSettingsSaveProfileToolTip": "儲存配置檔案", - "MenuBarFileToolsTakeScreenshot": "儲存截圖", - "MenuBarFileToolsHideUi": "隱藏使用者介面", - "GameListContextMenuRunApplication": "執行程式", - "GameListContextMenuToggleFavorite": "標記為收藏", - "GameListContextMenuToggleFavoriteToolTip": "啟用或取消收藏標記", - "SettingsTabGeneralTheme": "佈景主題", - "SettingsTabGeneralThemeCustomTheme": "自訂佈景主題路徑", - "SettingsTabGeneralThemeBaseStyle": "基本佈景主題式樣", - "SettingsTabGeneralThemeBaseStyleDark": "深色模式", - "SettingsTabGeneralThemeBaseStyleLight": "淺色模式", - "SettingsTabGeneralThemeEnableCustomTheme": "使用自訂佈景主題", - "ButtonBrowse": "瀏覽", - "ControllerSettingsConfigureGeneral": "配置", - "ControllerSettingsRumble": "震動", - "ControllerSettingsRumbleStrongMultiplier": "強震動調節", - "ControllerSettingsRumbleWeakMultiplier": "弱震動調節", - "DialogMessageSaveNotAvailableMessage": "沒有{0} [{1:x16}]的遊戲存檔", - "DialogMessageSaveNotAvailableCreateSaveMessage": "是否建立該遊戲的存檔資料夾?", - "DialogConfirmationTitle": "Ryujinx - 設定", - "DialogUpdaterTitle": "Ryujinx - 更新", - "DialogErrorTitle": "Ryujinx - 錯誤", - "DialogWarningTitle": "Ryujinx - 警告", - "DialogExitTitle": "Ryujinx - 關閉", - "DialogErrorMessage": "Ryujinx 遇到了錯誤", - "DialogExitMessage": "你確定要關閉 Ryujinx 嗎?", - "DialogExitSubMessage": "所有未儲存的資料將會遺失!", - "DialogMessageCreateSaveErrorMessage": "建立特定的存檔時出現錯誤: {0}", - "DialogMessageFindSaveErrorMessage": "查找特定的存檔時出現錯誤: {0}", - "FolderDialogExtractTitle": "選擇要解壓到的資料夾", - "DialogNcaExtractionMessage": "提取{1}的{0}分區...", - "DialogNcaExtractionTitle": "Ryujinx - NCA分區提取", - "DialogNcaExtractionMainNcaNotFoundErrorMessage": "提取失敗。所選檔案中不含主NCA檔案", - "DialogNcaExtractionCheckLogErrorMessage": "提取失敗。請查看日誌檔案取得詳情。", - "DialogNcaExtractionSuccessMessage": "提取成功。", - "DialogUpdaterConvertFailedMessage": "無法轉換目前 Ryujinx 版本。", - "DialogUpdaterCancelUpdateMessage": "更新取消!", - "DialogUpdaterAlreadyOnLatestVersionMessage": "你使用的 Ryujinx 是最新版本。", - "DialogUpdaterFailedToGetVersionMessage": "嘗試從 Github 取得版本訊息時失敗。可能是因為 GitHub Actions 正在編譯新版本。請於數分數後重試。", - "DialogUpdaterConvertFailedGithubMessage": "無法轉換從 Github 接收到的 Ryujinx 版本。", - "DialogUpdaterDownloadingMessage": "下載最新版本中...", - "DialogUpdaterExtractionMessage": "正在提取更新...", - "DialogUpdaterRenamingMessage": "正在刪除舊檔案...", - "DialogUpdaterAddingFilesMessage": "安裝更新中...", - "DialogUpdaterCompleteMessage": "更新成功!", - "DialogUpdaterRestartMessage": "你確定要立即重新啟動 Ryujinx 嗎?", - "DialogUpdaterArchNotSupportedMessage": "你執行的系統架構不被支援!", - "DialogUpdaterArchNotSupportedSubMessage": "(僅支援 x64 系統)", - "DialogUpdaterNoInternetMessage": "你沒有連接到網際網絡!", - "DialogUpdaterNoInternetSubMessage": "請確保網際網絡連接正常!", - "DialogUpdaterDirtyBuildMessage": "不能更新非官方版本的 Ryujinx!", - "DialogUpdaterDirtyBuildSubMessage": "如果你希望使用被受支援的Ryujinx版本,請你在官方網址 https://ryujinx.org/ 下載.", - "DialogRestartRequiredMessage": "模擬器必須重新啟動", - "DialogThemeRestartMessage": "佈景主題設定已儲存。需要重新啟動才能生效。", - "DialogThemeRestartSubMessage": "你確定要現在重新啟動嗎?", - "DialogFirmwareInstallEmbeddedMessage": "要安裝遊戲內建的韌體嗎?(韌體 {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "未找到已安裝的韌體,但 Ryujinx 可以從現有的遊戲安裝韌體{0}.\\n模擬器現在可以執行。", - "DialogFirmwareNoFirmwareInstalledMessage": "未安裝韌體", - "DialogFirmwareInstalledMessage": "已安裝韌體{0}", - "DialogInstallFileTypesSuccessMessage": "成功註冊檔案類型!", - "DialogInstallFileTypesErrorMessage": "註冊檔案類型失敗。", - "DialogUninstallFileTypesSuccessMessage": "成功取消註冊檔案類型!", - "DialogUninstallFileTypesErrorMessage": "取消註冊檔案類型失敗。", - "DialogOpenSettingsWindowLabel": "開啟設定視窗", - "DialogControllerAppletTitle": "控制器小視窗", - "DialogMessageDialogErrorExceptionMessage": "顯示訊息對話框時出現錯誤: {0}", - "DialogSoftwareKeyboardErrorExceptionMessage": "顯示軟體鍵盤時出現錯誤: {0}", - "DialogErrorAppletErrorExceptionMessage": "顯示錯誤對話框時出現錯誤: {0}", - "DialogUserErrorDialogMessage": "{0}: {1}", - "DialogUserErrorDialogInfoMessage": "\n有關修復此錯誤的更多訊息,可以遵循我們的設定指南。", - "DialogUserErrorDialogTitle": "Ryujinx 錯誤 ({0})", - "DialogAmiiboApiTitle": "Amiibo 應用程式介面", - "DialogAmiiboApiFailFetchMessage": "從 API 取得訊息時出錯。", - "DialogAmiiboApiConnectErrorMessage": "無法連接到 Amiibo API 伺服器。伺服器可能已關閉,或你沒有連接到網際網路。", - "DialogProfileInvalidProfileErrorMessage": "配置檔案 {0} 與目前輸入系統不相容。", - "DialogProfileDefaultProfileOverwriteErrorMessage": "無法覆蓋預設的配置檔案", - "DialogProfileDeleteProfileTitle": "刪除帳戶", - "DialogProfileDeleteProfileMessage": "此操作不可撤銷, 您確定要繼續嗎?", - "DialogWarning": "警告", - "DialogPPTCDeletionMessage": "下一次重啟時將會重新建立以下遊戲的 PPTC 快取\n\n{0}\n\n你確定要繼續嗎?", - "DialogPPTCDeletionErrorMessage": "清除位於{0}的 PPTC 快取時出錯: {1}", - "DialogShaderDeletionMessage": "即將刪除以下遊戲的著色器快取:\n\n{0}\n\n你確定要繼續嗎?", - "DialogShaderDeletionErrorMessage": "清除{0}的著色器快取時出現錯誤: {1}", - "DialogRyujinxErrorMessage": "Ryujinx 遇到錯誤", - "DialogInvalidTitleIdErrorMessage": "UI 錯誤:所選遊戲沒有有效的標題ID", - "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "路徑{0}找不到有效的系統韌體。", - "DialogFirmwareInstallerFirmwareInstallTitle": "安裝韌體{0}", - "DialogFirmwareInstallerFirmwareInstallMessage": "將安裝{0}版本的系統。", - "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\n這將替換目前系統版本{0}。", - "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "你確定要繼續嗎?", - "DialogFirmwareInstallerFirmwareInstallWaitMessage": "安裝韌體中...", - "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "成功安裝系統版本{0}。", - "DialogUserProfileDeletionWarningMessage": "刪除後將沒有可選擇的使用者帳戶", - "DialogUserProfileDeletionConfirmMessage": "你確定要刪除選擇中的帳戶嗎?", - "DialogUserProfileUnsavedChangesTitle": "警告 - 有未儲存的更改", - "DialogUserProfileUnsavedChangesMessage": "你對此帳戶所做的更改尚未儲存.", - "DialogUserProfileUnsavedChangesSubMessage": "你確定要捨棄更改嗎?", - "DialogControllerSettingsModifiedConfirmMessage": "目前的輸入配置檔案已更新", - "DialogControllerSettingsModifiedConfirmSubMessage": "你確定要儲存嗎?", - "DialogLoadNcaErrorMessage": "{0}. 錯誤的檔案: {1}", - "DialogDlcNoDlcErrorMessage": "選擇的檔案不包含所選遊戲的 DLC!", - "DialogPerformanceCheckLoggingEnabledMessage": "你啟用了跟蹤記錄,它的設計僅限開發人員使用。", - "DialogPerformanceCheckLoggingEnabledConfirmMessage": "為了獲得最佳效能,建議停用追蹤記錄。你是否要立即停用?", - "DialogPerformanceCheckShaderDumpEnabledMessage": "你啟用了著色器轉存,它的設計僅限開發人員使用。", - "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "為了獲得最佳效能,建議停用著色器轉存。你是否要立即停用?", - "DialogLoadAppGameAlreadyLoadedMessage": "目前已載入此遊戲", - "DialogLoadAppGameAlreadyLoadedSubMessage": "請停止模擬或關閉程式,再啟動另一個遊戲。", - "DialogUpdateAddUpdateErrorMessage": "選擇的檔案不包含所選遊戲的更新!", - "DialogSettingsBackendThreadingWarningTitle": "警告 - 後台多工執行中", - "DialogSettingsBackendThreadingWarningMessage": "更改此選項後必須重啟 Ryujinx 才能生效。根據你的硬體,您開啟該選項時,可能需要手動停用驅動程式本身的GPU多執行緒。", - "SettingsTabGraphicsFeaturesOptions": "功能", - "SettingsTabGraphicsBackendMultithreading": "圖像處理後台多線程支援:", - "CommonAuto": "自動(推薦)", - "CommonOff": "關閉", - "CommonOn": "打開", - "InputDialogYes": "是", - "InputDialogNo": "否", - "DialogProfileInvalidProfileNameErrorMessage": "檔案名包含無效字元,請重試。", - "MenuBarOptionsPauseEmulation": "暫停", - "MenuBarOptionsResumeEmulation": "繼續", - "AboutUrlTooltipMessage": "在瀏覽器中打開 Ryujinx 的官方網站。", - "AboutDisclaimerMessage": "Ryujinx 與 Nintendo™ 並沒有任何關聯, 包括其合作伙伴, 及任何形式上。", - "AboutAmiiboDisclaimerMessage": "我們的 Amiibo 模擬使用了\nAmiiboAPI (www.amiiboapi.com) ", - "AboutPatreonUrlTooltipMessage": "在瀏覽器中打開 Ryujinx 的 Patreon 贊助網頁。", - "AboutGithubUrlTooltipMessage": "在瀏覽器中打開 Ryujinx 的 GitHub 儲存庫。", - "AboutDiscordUrlTooltipMessage": "在瀏覽器中打開 Ryujinx 的 Discord 伺服器邀請連結。", - "AboutTwitterUrlTooltipMessage": "在瀏覽器中打開 Ryujinx 的 Twitter 首頁。", - "AboutRyujinxAboutTitle": "關於:", - "AboutRyujinxAboutContent": "Ryujinx 是 Nintendo Switch™ 的一款模擬器。\n懇請您在 Patreon 上贊助我們。\n關注 Twitter 或 Discord 可以取得我們的最新動態。\n如果您對開發本軟體感興趣,歡迎來 GitHub 和 Discord 加入我們!", - "AboutRyujinxMaintainersTitle": "開發及維護名單:", - "AboutRyujinxMaintainersContentTooltipMessage": "在瀏覽器中打開貢獻者的網頁", - "AboutRyujinxSupprtersTitle": "Patreon 的贊助人:", - "AmiiboSeriesLabel": "Amiibo 系列", - "AmiiboCharacterLabel": "角色", - "AmiiboScanButtonLabel": "掃描", - "AmiiboOptionsShowAllLabel": "顯示所有 Amiibo", - "AmiiboOptionsUsRandomTagLabel": "侵略:使用隨機標記的 Uuid 編碼", - "DlcManagerTableHeadingEnabledLabel": "已啟用", - "DlcManagerTableHeadingTitleIdLabel": "遊戲ID", - "DlcManagerTableHeadingContainerPathLabel": "資料夾路徑", - "DlcManagerTableHeadingFullPathLabel": "完整路徑", - "DlcManagerRemoveAllButton": "全部刪除", - "DlcManagerEnableAllButton": "啟用全部", - "DlcManagerDisableAllButton": "停用全部", - "MenuBarOptionsChangeLanguage": "更改語言", - "MenuBarShowFileTypes": "顯示檔案類型", - "CommonSort": "排序", - "CommonShowNames": "顯示名稱", - "CommonFavorite": "收藏", - "OrderAscending": "從小到大", - "OrderDescending": "從大到小", - "SettingsTabGraphicsFeatures": "功能及優化", - "ErrorWindowTitle": "錯誤視窗", - "ToggleDiscordTooltip": "啟用或關閉 Discord 動態狀態展示", - "AddGameDirBoxTooltip": "輸入要添加的遊戲資料夾", - "AddGameDirTooltip": "添加遊戲資料夾到列表中", - "RemoveGameDirTooltip": "移除選擇中的遊戲資料夾", - "CustomThemeCheckTooltip": "啟用或關閉自訂佈景主題", - "CustomThemePathTooltip": "自訂佈景主題的資料夾", - "CustomThemeBrowseTooltip": "查找自訂佈景主題", - "DockModeToggleTooltip": "是否開啟 Switch 的 Docked 模式", - "DirectKeyboardTooltip": "支援鍵盤直接存取 (HID協定) . 可供給遊戲使用你的鍵盤作為輸入文字裝置.", - "DirectMouseTooltip": "支援滑鼠直接存取 (HID協定) . 可供給遊戲使用你的滑鼠作為瞄準裝置.", - "RegionTooltip": "更改系統區域", - "LanguageTooltip": "更改系統語言", - "TimezoneTooltip": "更改系統時區", - "TimeTooltip": "更改系統時鐘", - "VSyncToggleTooltip": "模擬遊戲主機垂直同步更新頻率. 重要地反映著遊戲本身的速度; 關閉它可能會令後使用動態更新率的遊戲速度過高, 或會引致載入錯誤等等.\n\n可在遊戲中利用自訂快速鍵開關此功能. 我們也建議使用快速鍵, 如果你計劃關上它.\n\n如果不確定請設定為\"開啟\".", - "PptcToggleTooltip": "開啟以後減少遊戲啟動時間和卡頓", - "FsIntegrityToggleTooltip": "是否檢查遊戲檔案內容的完整性", - "AudioBackendTooltip": "更改音效處理後台架構.\n\n推薦使用SDL2架構, 而OpenAL及SoundIO架構用作後備. Dummy是沒有音效的.\n\n如果不確定請設定為\"SDL2\".", - "MemoryManagerTooltip": "更改模擬器記憶體至電腦記憶體的映射和存取方式,極其影響CPU效能.\n\n如果不確定, 請設定為\"主機略過檢查模式\".", - "MemoryManagerSoftwareTooltip": "使用軟體虛擬分頁表換算, 最精確但是速度最慢.", - "MemoryManagerHostTooltip": "直接地映射模擬記憶體到電腦記憶體. 對 JIT 編譯和執行效率有顯著提升. ", - "MemoryManagerUnsafeTooltip": "直接地映射模擬記憶體到電腦記憶體, 但是不檢查記憶體溢出. 由於 Ryujinx 的子程式可以存取任何位置的記憶體, 因而相對不安全. 故在此模式下只應執行你信任的遊戲或軟體.", - "UseHypervisorTooltip": "使用 Hypervisor 代替 JIT。在本功能可用時就可以大幅增大效能,但目前狀態還不穩定。", - "DRamTooltip": "利用可選擇性的記憶體模式來模擬Switch發展中型號.\n\n此選項只會對高畫質材質包或4K模組有用. 而這並不會提升效能. \n\n如果不確定請關閉本功能.", - "IgnoreMissingServicesTooltip": "忽略某些未被實施的系統服務. 此功能有助於繞過當啟動遊戲時帶來的故障.\n\n如果不確定請關閉本功能。", - "GraphicsBackendThreadingTooltip": "執行雙線程後台繪圖指令, 能夠減少著色器編譯斷續, 並提高GPU驅動效能, 即將它不支持多線程處理. 而對於多線程處理也有少量提升.\n\n如果你不確定請設定為\"自動\"", - "GalThreadingTooltip": "執行雙線程後台繪圖指令.\n\n能夠加速著色器編譯及減少斷續, 並提高GPU驅動效能, 即將它不支持多線程處理. 而對於多線程處理也有少量提升.\n\n如果你不確定請設定為\"自動\"", - "ShaderCacheToggleTooltip": "儲存著色器快取到硬碟,減少存取斷續。\n\n如果不確定請設定為\"開啟\"。", - "ResolutionScaleTooltip": "解析度繪圖倍率", - "ResolutionScaleEntryTooltip": "盡量使用如1.5的浮點倍數。非整數的倍率易引起錯誤", - "AnisotropyTooltip": "各向異性過濾等級。提高傾斜視角材質的清晰度\n(選擇「自動」將使用遊戲預設指定的等級)", - "AspectRatioTooltip": "模擬器視窗解析度的長寬比", - "ShaderDumpPathTooltip": "圖形著色器轉存路徑", - "FileLogTooltip": "是否儲存日誌檔案到硬碟", - "StubLogTooltip": "在控制台顯示及記錄 Stub 訊息", - "InfoLogTooltip": "在控制台顯示及記錄資訊訊息", - "WarnLogTooltip": "在控制台顯示及記錄警告訊息\n", - "ErrorLogTooltip": "在控制台顯示及記錄錯誤訊息", - "TraceLogTooltip": "在控制台顯示及記錄追蹤訊息", - "GuestLogTooltip": "在控制台顯示及記錄賓客訊息", - "FileAccessLogTooltip": "在控制台顯示及記錄檔案存取訊息", - "FSAccessLogModeTooltip": "在控制台顯示及記錄FS 存取訊息. 可選的模式是 0-3", - "DeveloperOptionTooltip": "使用請謹慎", - "OpenGlLogLevel": "需要打開適當的日誌等級", - "DebugLogTooltip": "在控制台顯示及記錄除錯訊息.\n\n僅限於受訓的成員使用, 因為它很難理解而且令模擬的效能非常地差.\n", - "LoadApplicationFileTooltip": "選擇 Switch 支援的遊戲格式並載入", - "LoadApplicationFolderTooltip": "選擇解包後的 Switch 遊戲並載入", - "OpenRyujinxFolderTooltip": "開啟 Ryujinx 系統資料夾", - "OpenRyujinxLogsTooltip": "開啟存放日誌的資料夾", - "ExitTooltip": "關閉 Ryujinx", - "OpenSettingsTooltip": "開啟設定視窗", - "OpenProfileManagerTooltip": "開啟使用者帳戶管理視窗", - "StopEmulationTooltip": "停止執行目前遊戲並回到選擇界面", - "CheckUpdatesTooltip": "檢查 Ryujinx 新版本", - "OpenAboutTooltip": "開啟關於視窗", - "GridSize": "網格尺寸", - "GridSizeTooltip": "調整網格模式的大小", - "SettingsTabSystemSystemLanguageBrazilianPortuguese": "巴西葡萄牙語", - "AboutRyujinxContributorsButtonHeader": "查看所有參與者", - "SettingsTabSystemAudioVolume": "音量:", - "AudioVolumeTooltip": "調節音量", - "SettingsTabSystemEnableInternetAccess": "啟用網路連接", - "EnableInternetAccessTooltip": "開啟網路存取。此選項打開後,效果類似於 Switch 連接到網路的狀態。注意即使此選項關閉,應用程式偶爾也有可能連接到網路", - "GameListContextMenuManageCheatToolTip": "管理金手指", - "GameListContextMenuManageCheat": "管理金手指", - "ControllerSettingsStickRange": "範圍:", - "DialogStopEmulationTitle": "Ryujinx - 停止模擬", - "DialogStopEmulationMessage": "你確定要停止模擬嗎?", - "SettingsTabCpu": "處理器", - "SettingsTabAudio": "音訊", - "SettingsTabNetwork": "網路", - "SettingsTabNetworkConnection": "網路連接", - "SettingsTabCpuCache": "CPU 快取", - "SettingsTabCpuMemory": "CPU 模式", - "DialogUpdaterFlatpakNotSupportedMessage": "請透過 Flathub 更新 Ryujinx。", - "UpdaterDisabledWarningTitle": "更新已停用!", - "GameListContextMenuOpenSdModsDirectory": "開啟 Atmosphere 模組資料夾", - "GameListContextMenuOpenSdModsDirectoryToolTip": "開啟此遊戲額外的SD記憶卡Atmosphere模組資料夾. 有用於包裝在真實主機上的模組.\n", - "ControllerSettingsRotate90": "順時針旋轉 90°", - "IconSize": "圖示尺寸", - "IconSizeTooltip": "更改遊戲圖示大小", - "MenuBarOptionsShowConsole": "顯示控制台", - "ShaderCachePurgeError": "清除 {0} 著色器快取時出現錯誤: {1}", - "UserErrorNoKeys": "找不到金鑰", - "UserErrorNoFirmware": "找不到韌體", - "UserErrorFirmwareParsingFailed": "韌體解析錯誤", - "UserErrorApplicationNotFound": "找不到應用程式", - "UserErrorUnknown": "未知錯誤", - "UserErrorUndefined": "未定義錯誤", - "UserErrorNoKeysDescription": "Ryujinx 找不到 『prod.keys』 檔案", - "UserErrorNoFirmwareDescription": "Ryujinx 找不到任何已安裝的韌體", - "UserErrorFirmwareParsingFailedDescription": "Ryujinx 無法解密選擇的韌體。這通常是由於金鑰過舊。", - "UserErrorApplicationNotFoundDescription": "Ryujinx 在選中路徑找不到有效的應用程式。", - "UserErrorUnknownDescription": "發生未知錯誤!", - "UserErrorUndefinedDescription": "發生了未定義錯誤!此類錯誤不應出現,請聯絡開發人員!", - "OpenSetupGuideMessage": "開啟設定教學", - "NoUpdate": "沒有新版本", - "TitleUpdateVersionLabel": "版本 {0} - {1}", - "RyujinxInfo": "Ryujinx - 訊息", - "RyujinxConfirm": "Ryujinx - 確認", - "FileDialogAllTypes": "全部類型", - "Never": "從不", - "SwkbdMinCharacters": "至少應為 {0} 個字長", - "SwkbdMinRangeCharacters": "必須為 {0}-{1} 個字長", - "SoftwareKeyboard": "軟體鍵盤", - "SoftwareKeyboardModeNumbersOnly": "只接受數字", - "SoftwareKeyboardModeAlphabet": "不支援中日韓統一表意文字字元", - "SoftwareKeyboardModeASCII": "只接受 ASCII 符號", - "DialogControllerAppletMessagePlayerRange": "本遊戲需要 {0} 個玩家持有:\n\n類型:{1}\n\n玩家:{2}\n\n{3}請打開設定畫面並配置控制器,或者關閉本視窗。", - "DialogControllerAppletMessage": "本遊戲需要剛好 {0} 個玩家持有:\n\n類型:{1}\n\n玩家:{2}\n\n{3}請打開設定畫面並配置控制器,或者關閉本視窗。", - "DialogControllerAppletDockModeSet": "現在處於主機模式,無法使用掌機操作方式\n\n", - "UpdaterRenaming": "正在重新命名舊檔案...", - "UpdaterRenameFailed": "更新過程中無法重新命名檔案: {0}", - "UpdaterAddingFiles": "安裝更新中...", - "UpdaterExtracting": "正在提取更新...", - "UpdaterDownloading": "下載新版本中...", - "Game": "遊戲", - "Docked": "主機模式", - "Handheld": "掌機模式", - "ConnectionError": "連接錯誤。", - "AboutPageDeveloperListMore": "{0} 等開發者...", - "ApiError": "API 錯誤", - "LoadingHeading": "正在啟動 {0}", - "CompilingPPTC": "編譯 PPTC 快取中", - "CompilingShaders": "編譯著色器中", - "AllKeyboards": "所有鍵盤", - "OpenFileDialogTitle": "選擇支援的檔案格式", - "OpenFolderDialogTitle": "選擇一個包含已解開封裝遊戲的資料夾\n", - "AllSupportedFormats": "全部支援的格式", - "RyujinxUpdater": "Ryujinx 更新程式", - "SettingsTabHotkeys": "快捷鍵", - "SettingsTabHotkeysHotkeys": "鍵盤快捷鍵", - "SettingsTabHotkeysToggleVsyncHotkey": "切換垂直同步:", - "SettingsTabHotkeysScreenshotHotkey": "截圖:", - "SettingsTabHotkeysShowUiHotkey": "隱藏使用者介面:", - "SettingsTabHotkeysPauseHotkey": "暫停:", - "SettingsTabHotkeysToggleMuteHotkey": "靜音:", - "ControllerMotionTitle": "體感操作設定", - "ControllerRumbleTitle": "震動設定", - "SettingsSelectThemeFileDialogTitle": "選擇主題檔案", - "SettingsXamlThemeFile": "Xaml 主題檔案", - "AvatarWindowTitle": "管理帳號 - 頭貼", - "Amiibo": "Amiibo", - "Unknown": "未知", - "Usage": "用途", - "Writable": "可寫入", - "SelectDlcDialogTitle": "選擇 DLC 檔案", - "SelectUpdateDialogTitle": "選擇更新檔", - "UserProfileWindowTitle": "管理使用者帳戶", - "CheatWindowTitle": "管理遊戲金手指", - "DlcWindowTitle": "管理遊戲 DLC", - "UpdateWindowTitle": "管理遊戲更新", - "CheatWindowHeading": "金手指可用於 {0} [{1}]", - "BuildId": "版本編號:", - "DlcWindowHeading": "DLC 可用於 {0} [{1}]", - "UserProfilesEditProfile": "編輯所選", - "Cancel": "取消", - "Save": "儲存", - "Discard": "放棄更改", - "UserProfilesSetProfileImage": "設定帳戶頭像", - "UserProfileEmptyNameError": "使用者名稱為必填", - "UserProfileNoImageError": "必須設定帳戶頭像", - "GameUpdateWindowHeading": "更新可用於 {0} [{1}]", - "SettingsTabHotkeysResScaleUpHotkey": "提高解析度:", - "SettingsTabHotkeysResScaleDownHotkey": "降低解析度:", - "UserProfilesName": "使用者名稱:", - "UserProfilesUserId": "使用者 ID:", - "SettingsTabGraphicsBackend": "圖像處理後台架構", - "SettingsTabGraphicsBackendTooltip": "用來圖像處理的後台架構", - "SettingsEnableTextureRecompression": "開啟材質重新壓縮", - "SettingsEnableTextureRecompressionTooltip": "壓縮某些材質以減少 VRAM 使用。\n\n推薦用於小於 4GiB VRAM 的 GPU。\n\n如果不確定請關閉本功能。", - "SettingsTabGraphicsPreferredGpu": "優先選取的 GPU", - "SettingsTabGraphicsPreferredGpuTooltip": "選擇支持運行Vulkan圖像處理架構的GPU.\n\n此設定不會影響GPU運行OpenGL.\n\n如果不確定, 請設定標籤為\"dGPU\"的GPU. 如果沒有, 請保留原始設定.", - "SettingsAppRequiredRestartMessage": "必須重啟 Ryujinx", - "SettingsGpuBackendRestartMessage": "圖像處理後台架構或GPU相關設定已被修改。需要重新啟動才能套用。", - "SettingsGpuBackendRestartSubMessage": "你確定要現在重新啟動嗎?", - "RyujinxUpdaterMessage": "你確定要將 Ryujinx 更新到最新版本嗎?", - "SettingsTabHotkeysVolumeUpHotkey": "增加音量:", - "SettingsTabHotkeysVolumeDownHotkey": "降低音量:", - "SettingsEnableMacroHLE": "啟用 Macro HLE", - "SettingsEnableMacroHLETooltip": "GPU 微代碼的高階模擬。\n\n可以提升效能,但可能會導致某些遊戲出現圖形顯示故障。\n\n如果不確定請設定為\"開啟\"。", - "SettingsEnableColorSpacePassthrough": "色彩空間直通", - "SettingsEnableColorSpacePassthroughTooltip": "指揮Vulkan後端直通色彩資訊而不需指定色彩空間,對於廣色域顯示的使用者,這會造成較多抖色,犧牲色彩正確性。", - "VolumeShort": "音量", - "UserProfilesManageSaves": "管理遊戲存檔", - "DeleteUserSave": "你確定要刪除此遊戲的存檔嗎?", - "IrreversibleActionNote": "本動作將無法挽回。", - "SaveManagerHeading": "管理 {0} 的遊戲存檔", - "SaveManagerTitle": "遊戲存檔管理器", - "Name": "名稱", - "Size": "大小", - "Search": "搜尋", - "UserProfilesRecoverLostAccounts": "恢復遺失的帳戶", - "Recover": "恢復", - "UserProfilesRecoverHeading": "在以下帳戶找到了一些遊戲存檔", - "UserProfilesRecoverEmptyList": "沒有可恢復的使用者帳戶", - "GraphicsAATooltip": "在遊戲繪圖上套用抗鋸齒", - "GraphicsAALabel": "抗鋸齒:", - "GraphicsScalingFilterLabel": "縮放過濾器:", - "GraphicsScalingFilterTooltip": "啟用畫幀緩衝區縮放", - "GraphicsScalingFilterLevelLabel": "記錄檔等級", - "GraphicsScalingFilterLevelTooltip": "設定縮放過濾器的強度", - "SmaaLow": "低階 SMAA", - "SmaaMedium": "中階 SMAA", - "SmaaHigh": "高階 SMAA", - "SmaaUltra": "超高階 SMAA", - "UserEditorTitle": "編輯使用者", - "UserEditorTitleCreate": "建立使用者", - "SettingsTabNetworkInterface": "網路介面:", - "NetworkInterfaceTooltip": "用於具有 LAN 功能的網路介面", - "NetworkInterfaceDefault": "預設", - "PackagingShaders": "著色器封裝", - "AboutChangelogButton": "在 GitHub 查看更新日誌", - "AboutChangelogButtonTooltipMessage": "在瀏覽器中打開此Ryujinx版本的更新日誌。" -} \ No newline at end of file diff --git a/src/Ryujinx.Ava/Modules/Updater/Updater.cs b/src/Ryujinx.Ava/Modules/Updater/Updater.cs deleted file mode 100644 index af7608d34..000000000 --- a/src/Ryujinx.Ava/Modules/Updater/Updater.cs +++ /dev/null @@ -1,777 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Threading; -using FluentAvalonia.UI.Controls; -using ICSharpCode.SharpZipLib.GZip; -using ICSharpCode.SharpZipLib.Tar; -using ICSharpCode.SharpZipLib.Zip; -using Ryujinx.Ava; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Common.Models.Github; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.NetworkInformation; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Ryujinx.Modules -{ - internal static class Updater - { - private const string GitHubApiUrl = "https://api.github.com"; - private static readonly GithubReleasesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - - private static readonly string _homeDir = AppDomain.CurrentDomain.BaseDirectory; - private static readonly string _updateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update"); - private static readonly string _updatePublishDir = Path.Combine(_updateDir, "publish"); - private const int ConnectionCount = 4; - - private static string _buildVer; - private static string _platformExt; - private static string _buildUrl; - private static long _buildSize; - private static bool _updateSuccessful; - private static bool _running; - - private static readonly string[] _windowsDependencyDirs = Array.Empty(); - - public static async Task BeginParse(Window mainWindow, bool showVersionUpToDate) - { - if (_running) - { - return; - } - - _running = true; - - // Detect current platform - if (OperatingSystem.IsMacOS()) - { - _platformExt = "macos_universal.app.tar.gz"; - } - else if (OperatingSystem.IsWindows()) - { - _platformExt = "win_x64.zip"; - } - else if (OperatingSystem.IsLinux()) - { - _platformExt = "linux_x64.tar.gz"; - } - - Version newVersion; - Version currentVersion; - - try - { - currentVersion = Version.Parse(Program.Version); - } - catch - { - Logger.Error?.Print(LogClass.Application, "Failed to convert the current Ryujinx version!"); - - await ContentDialogHelper.CreateWarningDialog( - LocaleManager.Instance[LocaleKeys.DialogUpdaterConvertFailedMessage], - LocaleManager.Instance[LocaleKeys.DialogUpdaterCancelUpdateMessage]); - - _running = false; - - return; - } - - // Get latest version number from GitHub API - try - { - using HttpClient jsonClient = ConstructHttpClient(); - - string buildInfoUrl = $"{GitHubApiUrl}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest"; - string fetchedJson = await jsonClient.GetStringAsync(buildInfoUrl); - var fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse); - _buildVer = fetched.Name; - - foreach (var asset in fetched.Assets) - { - if (asset.Name.StartsWith("test-ava-ryujinx") && asset.Name.EndsWith(_platformExt)) - { - _buildUrl = asset.BrowserDownloadUrl; - - if (asset.State != "uploaded") - { - if (showVersionUpToDate) - { - await ContentDialogHelper.CreateUpdaterInfoDialog( - LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], - ""); - } - - _running = false; - - return; - } - - break; - } - } - - // If build not done, assume no new update are available. - if (_buildUrl is null) - { - if (showVersionUpToDate) - { - await ContentDialogHelper.CreateUpdaterInfoDialog( - LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], - ""); - } - - _running = false; - - return; - } - } - catch (Exception exception) - { - Logger.Error?.Print(LogClass.Application, exception.Message); - - await ContentDialogHelper.CreateErrorDialog( - LocaleManager.Instance[LocaleKeys.DialogUpdaterFailedToGetVersionMessage]); - - _running = false; - - return; - } - - try - { - newVersion = Version.Parse(_buildVer); - } - catch - { - Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from Github!"); - - await ContentDialogHelper.CreateWarningDialog( - LocaleManager.Instance[LocaleKeys.DialogUpdaterConvertFailedGithubMessage], - LocaleManager.Instance[LocaleKeys.DialogUpdaterCancelUpdateMessage]); - - _running = false; - - return; - } - - if (newVersion <= currentVersion) - { - if (showVersionUpToDate) - { - await ContentDialogHelper.CreateUpdaterInfoDialog( - LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], - ""); - } - - _running = false; - - return; - } - - // Fetch build size information to learn chunk sizes. - using HttpClient buildSizeClient = ConstructHttpClient(); - try - { - buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0"); - - HttpResponseMessage message = await buildSizeClient.GetAsync(new Uri(_buildUrl), HttpCompletionOption.ResponseHeadersRead); - - _buildSize = message.Content.Headers.ContentRange.Length.Value; - } - catch (Exception ex) - { - Logger.Warning?.Print(LogClass.Application, ex.Message); - Logger.Warning?.Print(LogClass.Application, "Couldn't determine build size for update, using single-threaded updater"); - - _buildSize = -1; - } - - await Dispatcher.UIThread.InvokeAsync(async () => - { - // Show a message asking the user if they want to update - var shouldUpdate = await ContentDialogHelper.CreateChoiceDialog( - LocaleManager.Instance[LocaleKeys.RyujinxUpdater], - LocaleManager.Instance[LocaleKeys.RyujinxUpdaterMessage], - $"{Program.Version} -> {newVersion}"); - - if (shouldUpdate) - { - await UpdateRyujinx(mainWindow, _buildUrl); - } - else - { - _running = false; - } - }); - } - - private static HttpClient ConstructHttpClient() - { - HttpClient result = new(); - - // Required by GitHub to interact with APIs. - result.DefaultRequestHeaders.Add("User-Agent", "Ryujinx-Updater/1.0.0"); - - return result; - } - - private static async Task UpdateRyujinx(Window parent, string downloadUrl) - { - _updateSuccessful = false; - - // Empty update dir, although it shouldn't ever have anything inside it - if (Directory.Exists(_updateDir)) - { - Directory.Delete(_updateDir, true); - } - - Directory.CreateDirectory(_updateDir); - - string updateFile = Path.Combine(_updateDir, "update.bin"); - - TaskDialog taskDialog = new() - { - Header = LocaleManager.Instance[LocaleKeys.RyujinxUpdater], - SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterDownloading], - IconSource = new SymbolIconSource { Symbol = Symbol.Download }, - ShowProgressBar = true, - XamlRoot = parent, - }; - - taskDialog.Opened += (s, e) => - { - if (_buildSize >= 0) - { - DoUpdateWithMultipleThreads(taskDialog, downloadUrl, updateFile); - } - else - { - DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile); - } - }; - - await taskDialog.ShowAsync(true); - - if (_updateSuccessful) - { - bool shouldRestart = true; - - if (!OperatingSystem.IsMacOS()) - { - shouldRestart = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance[LocaleKeys.RyujinxUpdater], - LocaleManager.Instance[LocaleKeys.DialogUpdaterCompleteMessage], - LocaleManager.Instance[LocaleKeys.DialogUpdaterRestartMessage]); - } - - if (shouldRestart) - { - List arguments = CommandLineState.Arguments.ToList(); - string executableDirectory = AppDomain.CurrentDomain.BaseDirectory; - - // On macOS we perform the update at relaunch. - if (OperatingSystem.IsMacOS()) - { - string baseBundlePath = Path.GetFullPath(Path.Combine(executableDirectory, "..", "..")); - string newBundlePath = Path.Combine(_updateDir, "Ryujinx.app"); - string updaterScriptPath = Path.Combine(newBundlePath, "Contents", "Resources", "updater.sh"); - string currentPid = Environment.ProcessId.ToString(); - - arguments.InsertRange(0, new List { updaterScriptPath, baseBundlePath, newBundlePath, currentPid }); - Process.Start("/bin/bash", arguments); - } - else - { - // Find the process name. - string ryuName = Path.GetFileName(Environment.ProcessPath); - - // Some operating systems can see the renamed executable, so strip off the .ryuold if found. - if (ryuName.EndsWith(".ryuold")) - { - ryuName = ryuName[..^7]; - } - - // Fallback if the executable could not be found. - if (!Path.Exists(Path.Combine(executableDirectory, ryuName))) - { - ryuName = OperatingSystem.IsWindows() ? "Ryujinx.Ava.exe" : "Ryujinx.Ava"; - } - - ProcessStartInfo processStart = new(ryuName) - { - UseShellExecute = true, - WorkingDirectory = executableDirectory, - }; - - foreach (string argument in CommandLineState.Arguments) - { - processStart.ArgumentList.Add(argument); - } - - Process.Start(processStart); - } - - Environment.Exit(0); - } - } - } - - private static void DoUpdateWithMultipleThreads(TaskDialog taskDialog, string downloadUrl, string updateFile) - { - // Multi-Threaded Updater - long chunkSize = _buildSize / ConnectionCount; - long remainderChunk = _buildSize % ConnectionCount; - - int completedRequests = 0; - int totalProgressPercentage = 0; - int[] progressPercentage = new int[ConnectionCount]; - - List list = new(ConnectionCount); - List webClients = new(ConnectionCount); - - for (int i = 0; i < ConnectionCount; i++) - { - list.Add(Array.Empty()); - } - - for (int i = 0; i < ConnectionCount; i++) - { -#pragma warning disable SYSLIB0014 - // TODO: WebClient is obsolete and need to be replaced with a more complex logic using HttpClient. - using WebClient client = new(); -#pragma warning restore SYSLIB0014 - - webClients.Add(client); - - if (i == ConnectionCount - 1) - { - client.Headers.Add("Range", $"bytes={chunkSize * i}-{(chunkSize * (i + 1) - 1) + remainderChunk}"); - } - else - { - client.Headers.Add("Range", $"bytes={chunkSize * i}-{chunkSize * (i + 1) - 1}"); - } - - client.DownloadProgressChanged += (_, args) => - { - int index = (int)args.UserState; - - Interlocked.Add(ref totalProgressPercentage, -1 * progressPercentage[index]); - Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage); - Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage); - - taskDialog.SetProgressBarState(totalProgressPercentage / ConnectionCount, TaskDialogProgressState.Normal); - }; - - client.DownloadDataCompleted += (_, args) => - { - int index = (int)args.UserState; - - if (args.Cancelled) - { - webClients[index].Dispose(); - - taskDialog.Hide(); - - return; - } - - list[index] = args.Result; - Interlocked.Increment(ref completedRequests); - - if (Equals(completedRequests, ConnectionCount)) - { - byte[] mergedFileBytes = new byte[_buildSize]; - for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++) - { - Array.Copy(list[connectionIndex], 0, mergedFileBytes, destinationOffset, list[connectionIndex].Length); - destinationOffset += list[connectionIndex].Length; - } - - File.WriteAllBytes(updateFile, mergedFileBytes); - - // On macOS, ensure that we remove the quarantine bit to prevent Gatekeeper from blocking execution. - if (OperatingSystem.IsMacOS()) - { - using Process xattrProcess = Process.Start("xattr", new List { "-d", "com.apple.quarantine", updateFile }); - - xattrProcess.WaitForExit(); - } - - try - { - InstallUpdate(taskDialog, updateFile); - } - catch (Exception e) - { - Logger.Warning?.Print(LogClass.Application, e.Message); - Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater."); - - DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile); - } - } - }; - - try - { - client.DownloadDataAsync(new Uri(downloadUrl), i); - } - catch (WebException ex) - { - Logger.Warning?.Print(LogClass.Application, ex.Message); - Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater."); - - foreach (WebClient webClient in webClients) - { - webClient.CancelAsync(); - } - - DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile); - - return; - } - } - } - - private static void DoUpdateWithSingleThreadWorker(TaskDialog taskDialog, string downloadUrl, string updateFile) - { - using HttpClient client = new(); - // We do not want to timeout while downloading - client.Timeout = TimeSpan.FromDays(1); - - using HttpResponseMessage response = client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead).Result; - using Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result; - using Stream updateFileStream = File.Open(updateFile, FileMode.Create); - - long totalBytes = response.Content.Headers.ContentLength.Value; - long byteWritten = 0; - - byte[] buffer = new byte[32 * 1024]; - - while (true) - { - int readSize = remoteFileStream.Read(buffer); - - if (readSize == 0) - { - break; - } - - byteWritten += readSize; - - taskDialog.SetProgressBarState(GetPercentage(byteWritten, totalBytes), TaskDialogProgressState.Normal); - - updateFileStream.Write(buffer, 0, readSize); - } - - InstallUpdate(taskDialog, updateFile); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static double GetPercentage(double value, double max) - { - return max == 0 ? 0 : value / max * 100; - } - - private static void DoUpdateWithSingleThread(TaskDialog taskDialog, string downloadUrl, string updateFile) - { - Thread worker = new(() => DoUpdateWithSingleThreadWorker(taskDialog, downloadUrl, updateFile)) - { - Name = "Updater.SingleThreadWorker", - }; - - worker.Start(); - } - - [SupportedOSPlatform("linux")] - [SupportedOSPlatform("macos")] - private static void ExtractTarGzipFile(TaskDialog taskDialog, string archivePath, string outputDirectoryPath) - { - using Stream inStream = File.OpenRead(archivePath); - using GZipInputStream gzipStream = new(inStream); - using TarInputStream tarStream = new(gzipStream, Encoding.ASCII); - - TarEntry tarEntry; - - while ((tarEntry = tarStream.GetNextEntry()) is not null) - { - if (tarEntry.IsDirectory) - { - continue; - } - - string outPath = Path.Combine(outputDirectoryPath, tarEntry.Name); - - Directory.CreateDirectory(Path.GetDirectoryName(outPath)); - - using FileStream outStream = File.OpenWrite(outPath); - tarStream.CopyEntryContents(outStream); - - File.SetUnixFileMode(outPath, (UnixFileMode)tarEntry.TarHeader.Mode); - File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc)); - - Dispatcher.UIThread.Post(() => - { - if (tarEntry is null) - { - return; - } - - taskDialog.SetProgressBarState(GetPercentage(tarEntry.Size, inStream.Length), TaskDialogProgressState.Normal); - }); - } - } - - private static void ExtractZipFile(TaskDialog taskDialog, string archivePath, string outputDirectoryPath) - { - using Stream inStream = File.OpenRead(archivePath); - using ZipFile zipFile = new(inStream); - - double count = 0; - foreach (ZipEntry zipEntry in zipFile) - { - count++; - if (zipEntry.IsDirectory) - { - continue; - } - - string outPath = Path.Combine(outputDirectoryPath, zipEntry.Name); - - Directory.CreateDirectory(Path.GetDirectoryName(outPath)); - - using Stream zipStream = zipFile.GetInputStream(zipEntry); - using FileStream outStream = File.OpenWrite(outPath); - - zipStream.CopyTo(outStream); - - File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc)); - - Dispatcher.UIThread.Post(() => - { - taskDialog.SetProgressBarState(GetPercentage(count, zipFile.Count), TaskDialogProgressState.Normal); - }); - } - } - - private static void InstallUpdate(TaskDialog taskDialog, string updateFile) - { - // Extract Update - taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterExtracting]; - taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal); - - if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) - { - ExtractTarGzipFile(taskDialog, updateFile, _updateDir); - } - else if (OperatingSystem.IsWindows()) - { - ExtractZipFile(taskDialog, updateFile, _updateDir); - } - else - { - throw new NotSupportedException(); - } - - // Delete downloaded zip - File.Delete(updateFile); - - List allFiles = EnumerateFilesToDelete().ToList(); - - taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterRenaming]; - taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal); - - // NOTE: On macOS, replacement is delayed to the restart phase. - if (!OperatingSystem.IsMacOS()) - { - // Replace old files - double count = 0; - foreach (string file in allFiles) - { - count++; - try - { - File.Move(file, file + ".ryuold"); - - Dispatcher.UIThread.InvokeAsync(() => - { - taskDialog.SetProgressBarState(GetPercentage(count, allFiles.Count), TaskDialogProgressState.Normal); - }); - } - catch - { - Logger.Warning?.Print(LogClass.Application, LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.UpdaterRenameFailed, file)); - } - } - - Dispatcher.UIThread.InvokeAsync(() => - { - taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterAddingFiles]; - taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal); - }); - - MoveAllFilesOver(_updatePublishDir, _homeDir, taskDialog); - - Directory.Delete(_updateDir, true); - } - - _updateSuccessful = true; - - taskDialog.Hide(); - } - - public static bool CanUpdate(bool showWarnings) - { -#if !DISABLE_UPDATER - if (RuntimeInformation.OSArchitecture != Architecture.X64 && !OperatingSystem.IsMacOS()) - { - if (showWarnings) - { - Dispatcher.UIThread.InvokeAsync(() => - ContentDialogHelper.CreateWarningDialog( - LocaleManager.Instance[LocaleKeys.DialogUpdaterArchNotSupportedMessage], - LocaleManager.Instance[LocaleKeys.DialogUpdaterArchNotSupportedSubMessage]) - ); - } - - return false; - } - - if (!NetworkInterface.GetIsNetworkAvailable()) - { - if (showWarnings) - { - Dispatcher.UIThread.InvokeAsync(() => - ContentDialogHelper.CreateWarningDialog( - LocaleManager.Instance[LocaleKeys.DialogUpdaterNoInternetMessage], - LocaleManager.Instance[LocaleKeys.DialogUpdaterNoInternetSubMessage]) - ); - } - - return false; - } - - if (Program.Version.Contains("dirty") || !ReleaseInformation.IsValid()) - { - if (showWarnings) - { - Dispatcher.UIThread.InvokeAsync(() => - ContentDialogHelper.CreateWarningDialog( - LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildMessage], - LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildSubMessage]) - ); - } - - return false; - } - - return true; -#else - if (showWarnings) - { - if (ReleaseInformation.IsFlatHubBuild()) - { - Dispatcher.UIThread.InvokeAsync(() => - ContentDialogHelper.CreateWarningDialog( - LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], - LocaleManager.Instance[LocaleKeys.DialogUpdaterFlatpakNotSupportedMessage]) - ); - } - else - { - Dispatcher.UIThread.InvokeAsync(() => - ContentDialogHelper.CreateWarningDialog( - LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], - LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildSubMessage]) - ); - } - } - - return false; -#endif - } - - // NOTE: This method should always reflect the latest build layout. - private static IEnumerable EnumerateFilesToDelete() - { - var files = Directory.EnumerateFiles(_homeDir); // All files directly in base dir. - - // Determine and exclude user files only when the updater is running, not when cleaning old files - if (_running && !OperatingSystem.IsMacOS()) - { - // Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list. - var oldFiles = Directory.EnumerateFiles(_homeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName); - var newFiles = Directory.EnumerateFiles(_updatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName); - var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(_homeDir, filename)); - - // Remove user files from the paths in files. - files = files.Except(userFiles); - } - - if (OperatingSystem.IsWindows()) - { - foreach (string dir in _windowsDependencyDirs) - { - string dirPath = Path.Combine(_homeDir, dir); - if (Directory.Exists(dirPath)) - { - files = files.Concat(Directory.EnumerateFiles(dirPath, "*", SearchOption.AllDirectories)); - } - } - } - - return files.Where(f => !new FileInfo(f).Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System)); - } - - private static void MoveAllFilesOver(string root, string dest, TaskDialog taskDialog) - { - int total = Directory.GetFiles(root, "*", SearchOption.AllDirectories).Length; - foreach (string directory in Directory.GetDirectories(root)) - { - string dirName = Path.GetFileName(directory); - - if (!Directory.Exists(Path.Combine(dest, dirName))) - { - Directory.CreateDirectory(Path.Combine(dest, dirName)); - } - - MoveAllFilesOver(directory, Path.Combine(dest, dirName), taskDialog); - } - - double count = 0; - foreach (string file in Directory.GetFiles(root)) - { - count++; - - File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true); - - Dispatcher.UIThread.InvokeAsync(() => - { - taskDialog.SetProgressBarState(GetPercentage(count, total), TaskDialogProgressState.Normal); - }); - } - } - - public static void CleanupUpdate() - { - foreach (string file in Directory.GetFiles(_homeDir, "*.ryuold", SearchOption.AllDirectories)) - { - File.Delete(file); - } - } - } -} diff --git a/src/Ryujinx.Ava/Program.cs b/src/Ryujinx.Ava/Program.cs deleted file mode 100644 index cc062a256..000000000 --- a/src/Ryujinx.Ava/Program.cs +++ /dev/null @@ -1,236 +0,0 @@ -using Avalonia; -using Avalonia.Threading; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.Common; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.GraphicsDriver; -using Ryujinx.Common.Logging; -using Ryujinx.Common.SystemInterop; -using Ryujinx.Modules; -using Ryujinx.SDL2.Common; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Common.SystemInfo; -using System; -using System.IO; -using System.Runtime.InteropServices; -using System.Threading.Tasks; - -namespace Ryujinx.Ava -{ - internal partial class Program - { - public static double WindowScaleFactor { get; set; } - public static double DesktopScaleFactor { get; set; } = 1.0; - public static string Version { get; private set; } - public static string ConfigurationPath { get; private set; } - public static bool PreviewerDetached { get; private set; } - - [LibraryImport("user32.dll", SetLastError = true)] - public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type); - - private const uint MbIconwarning = 0x30; - - public static void Main(string[] args) - { - Version = ReleaseInformation.GetVersion(); - - if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134)) - { - _ = MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MbIconwarning); - } - - PreviewerDetached = true; - - Initialize(args); - - LoggerAdapter.Register(); - - BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); - } - - public static AppBuilder BuildAvaloniaApp() - { - return AppBuilder.Configure() - .UsePlatformDetect() - .With(new X11PlatformOptions - { - EnableMultiTouch = true, - EnableIme = true, - RenderingMode = new[] { X11RenderingMode.Glx, X11RenderingMode.Software }, - }) - .With(new Win32PlatformOptions - { - WinUICompositionBackdropCornerRadius = 8.0f, - RenderingMode = new[] { Win32RenderingMode.AngleEgl, Win32RenderingMode.Software }, - }) - .UseSkia(); - } - - private static void Initialize(string[] args) - { - // Parse arguments - CommandLineState.ParseArguments(args); - - // Delete backup files after updating. - Task.Run(Updater.CleanupUpdate); - - Console.Title = $"Ryujinx Console {Version}"; - - // Hook unhandled exception and process exit events. - AppDomain.CurrentDomain.UnhandledException += (sender, e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); - AppDomain.CurrentDomain.ProcessExit += (sender, e) => Exit(); - - // Setup base data directory. - AppDataManager.Initialize(CommandLineState.BaseDirPathArg); - - // Initialize the configuration. - ConfigurationState.Initialize(); - - // Initialize the logger system. - LoggerModule.Initialize(); - - // Initialize Discord integration. - DiscordIntegrationModule.Initialize(); - - // Initialize SDL2 driver - SDL2Driver.MainThreadDispatcher = action => Dispatcher.UIThread.InvokeAsync(action, DispatcherPriority.Input); - - ReloadConfig(); - - WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor(); - - // Logging system information. - PrintSystemInfo(); - - // Enable OGL multithreading on the driver, when available. - DriverUtilities.ToggleOGLThreading(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off); - - // Check if keys exists. - if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys"))) - { - if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys")))) - { - MainWindow.ShowKeyErrorOnLoad = true; - } - } - - if (CommandLineState.LaunchPathArg != null) - { - MainWindow.DeferLoadApplication(CommandLineState.LaunchPathArg, CommandLineState.StartFullscreenArg); - } - } - - public static void ReloadConfig() - { - string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); - string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json"); - - // Now load the configuration as the other subsystems are now registered - if (File.Exists(localConfigurationPath)) - { - ConfigurationPath = localConfigurationPath; - } - else if (File.Exists(appDataConfigurationPath)) - { - ConfigurationPath = appDataConfigurationPath; - } - - if (ConfigurationPath == null) - { - // No configuration, we load the default values and save it to disk - ConfigurationPath = appDataConfigurationPath; - - ConfigurationState.Instance.LoadDefault(); - ConfigurationState.Instance.ToFileFormat().SaveConfig(ConfigurationPath); - } - else - { - if (ConfigurationFileFormat.TryLoad(ConfigurationPath, out ConfigurationFileFormat configurationFileFormat)) - { - ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); - } - else - { - ConfigurationState.Instance.LoadDefault(); - - Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}"); - } - } - - // Check if graphics backend was overridden - if (CommandLineState.OverrideGraphicsBackend != null) - { - if (CommandLineState.OverrideGraphicsBackend.ToLower() == "opengl") - { - ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.OpenGl; - } - else if (CommandLineState.OverrideGraphicsBackend.ToLower() == "vulkan") - { - ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.Vulkan; - } - } - - // Check if docked mode was overriden. - if (CommandLineState.OverrideDockedMode.HasValue) - { - ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value; - } - - // Check if HideCursor was overridden. - if (CommandLineState.OverrideHideCursor is not null) - { - ConfigurationState.Instance.HideCursor.Value = CommandLineState.OverrideHideCursor!.ToLower() switch - { - "never" => HideCursorMode.Never, - "onidle" => HideCursorMode.OnIdle, - "always" => HideCursorMode.Always, - _ => ConfigurationState.Instance.HideCursor.Value, - }; - } - } - - private static void PrintSystemInfo() - { - Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}"); - SystemInfo.Gather().Print(); - - Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(Logger.GetEnabledLevels().Count == 0 ? "" : string.Join(", ", Logger.GetEnabledLevels()))}"); - - if (AppDataManager.Mode == AppDataManager.LaunchMode.Custom) - { - Logger.Notice.Print(LogClass.Application, $"Launch Mode: Custom Path {AppDataManager.BaseDirPath}"); - } - else - { - Logger.Notice.Print(LogClass.Application, $"Launch Mode: {AppDataManager.Mode}"); - } - } - - private static void ProcessUnhandledException(Exception ex, bool isTerminating) - { - string message = $"Unhandled exception caught: {ex}"; - - Logger.Error?.PrintMsg(LogClass.Application, message); - - if (Logger.Error == null) - { - Logger.Notice.PrintMsg(LogClass.Application, message); - } - - if (isTerminating) - { - Exit(); - } - } - - public static void Exit() - { - DiscordIntegrationModule.Exit(); - - Logger.Shutdown(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/KeyValueConverter.cs b/src/Ryujinx.Ava/UI/Helpers/KeyValueConverter.cs deleted file mode 100644 index 028ed6bf4..000000000 --- a/src/Ryujinx.Ava/UI/Helpers/KeyValueConverter.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Avalonia.Data.Converters; -using Ryujinx.Common.Configuration.Hid; -using Ryujinx.Common.Configuration.Hid.Controller; -using System; -using System.Globalization; - -namespace Ryujinx.Ava.UI.Helpers -{ - internal class KeyValueConverter : IValueConverter - { - public static KeyValueConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return value.ToString(); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - object key = null; - - if (value != null) - { - if (targetType == typeof(Key)) - { - key = Enum.Parse(value.ToString()); - } - else if (targetType == typeof(GamepadInputId)) - { - key = Enum.Parse(value.ToString()); - } - else if (targetType == typeof(StickInputId)) - { - key = Enum.Parse(value.ToString()); - } - } - - return key; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs b/src/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs deleted file mode 100644 index c270c9ed4..000000000 --- a/src/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs +++ /dev/null @@ -1,19 +0,0 @@ -using LibHac.Ns; -using Ryujinx.Ava.Common.Locale; - -namespace Ryujinx.Ava.UI.Models -{ - public class TitleUpdateModel - { - public ApplicationControlProperty Control { get; } - public string Path { get; } - - public string Label => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TitleUpdateVersionLabel, Control.DisplayVersionString.ToString()); - - public TitleUpdateModel(ApplicationControlProperty control, string path) - { - Control = control; - Path = path; - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/GamePadInputViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/GamePadInputViewModel.cs deleted file mode 100644 index c8d98d24d..000000000 --- a/src/Ryujinx.Ava/UI/ViewModels/GamePadInputViewModel.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.Views.Input; -using Ryujinx.Common.Configuration.Hid; -using System; -using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId; -using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class GamePadInputViewModel : InputViewModel - { - private InputConfiguration _configuration; - private Func _showMotionConfigCommand; - private Func _showRumbleConfigCommand; - - - public InputConfiguration Configuration - { - get => _configuration; - set - { - _configuration = value; - - OnPropertyChanged(); - } - } - - internal override object Config => _configuration; - - public GamePadInputViewModel(InputConfiguration configuration, Func showMotionConfigCommand, Func showRumbleConfigCommand) - { - Configuration = configuration; - _showMotionConfigCommand = showMotionConfigCommand; - _showRumbleConfigCommand = showRumbleConfigCommand; - } - - public GamePadInputViewModel() - { - } - - public override void NotifyChanges() - { - OnPropertyChanged(nameof(Configuration)); - - base.NotifyChanges(); - } - - public override InputConfig GetConfig() - { - return _configuration.GetConfig(); - } - - public async void ShowMotionConfig() - { - await _showMotionConfigCommand(); - } - - public async void ShowRumbleConfig() - { - await _showRumbleConfigCommand(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/InputViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/InputViewModel.cs deleted file mode 100644 index 2021746cf..000000000 --- a/src/Ryujinx.Ava/UI/ViewModels/InputViewModel.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Avalonia.Svg.Skia; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Common; -using Ryujinx.Common.Configuration.Hid; -using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; -using Key = Ryujinx.Common.Configuration.Hid.Key; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public abstract class InputViewModel : BaseModel - { - private string _controllerImage; - - public bool IsRight { get; set; } - public bool IsLeft { get; set; } - - internal abstract object Config { get; } - - public void NotifyChange(string property) - { - OnPropertyChanged(property); - } - - public string ControllerImage - { - get => _controllerImage; - set - { - _controllerImage = value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(Image)); - } - } - - public SvgImage Image - { - get - { - SvgImage image = new(); - - if (!string.IsNullOrWhiteSpace(_controllerImage)) - { - SvgSource source = new(); - - source.Load(EmbeddedResources.GetStream(_controllerImage)); - - image.Source = source; - } - - return image; - } - } - - public virtual void NotifyChanges() - { - OnPropertyChanged(nameof(IsRight)); - OnPropertyChanged(nameof(IsLeft)); - OnPropertyChanged(nameof(Image)); - } - - public abstract InputConfig GetConfig(); - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/KeyboardInputViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/KeyboardInputViewModel.cs deleted file mode 100644 index b918e6732..000000000 --- a/src/Ryujinx.Ava/UI/ViewModels/KeyboardInputViewModel.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Ryujinx.Ava.UI.Models; -using Ryujinx.Common.Configuration.Hid; -using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; -using Key = Ryujinx.Common.Configuration.Hid.Key; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class KeyboardInputViewModel : InputViewModel - { - private InputConfiguration _configuration; - - - public InputConfiguration Configuration - { - get => _configuration; - set - { - _configuration = value; - - OnPropertyChanged(); - } - } - - internal override object Config => _configuration; - - public KeyboardInputViewModel(InputConfiguration configuration) - { - Configuration = configuration; - } - - public KeyboardInputViewModel() - { - } - - public override void NotifyChanges() - { - OnPropertyChanged(nameof(Configuration)); - - base.NotifyChanges(); - } - - public override InputConfig GetConfig() - { - return _configuration.GetConfig(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Input/GamePadInputView.axaml b/src/Ryujinx.Ava/UI/Views/Input/GamePadInputView.axaml deleted file mode 100644 index db1e588e6..000000000 --- a/src/Ryujinx.Ava/UI/Views/Input/GamePadInputView.axaml +++ /dev/null @@ -1,741 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Ryujinx.Ava/UI/Views/Input/GamePadInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/GamePadInputView.axaml.cs deleted file mode 100644 index cf1037f5d..000000000 --- a/src/Ryujinx.Ava/UI/Views/Input/GamePadInputView.axaml.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; - -namespace Ryujinx.Ava.UI.Views.Input -{ - public partial class GamePadInputView : UserControl - { - public GamePadInputView() - { - InitializeComponent(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml b/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml deleted file mode 100644 index bcc31873f..000000000 --- a/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml +++ /dev/null @@ -1,672 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs deleted file mode 100644 index 9e1470589..000000000 --- a/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; - -namespace Ryujinx.Ava.UI.Views.Input -{ - public partial class KeyboardInputView : UserControl - { - public KeyboardInputView() - { - InitializeComponent(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml deleted file mode 100644 index a53c1dfe4..000000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs deleted file mode 100644 index b006d703f..000000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Input; -using Avalonia.Interactivity; -using Ryujinx.Ava.Input; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Input; -using Ryujinx.Input.Assigner; - -namespace Ryujinx.Ava.UI.Views.Settings -{ - public partial class SettingsHotkeysView : UserControl - { - private ButtonKeyAssigner _currentAssigner; - private readonly IGamepadDriver _avaloniaKeyboardDriver; - - public SettingsHotkeysView() - { - InitializeComponent(); - _avaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this); - } - - private void MouseClick(object sender, PointerPressedEventArgs e) - { - bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed; - - _currentAssigner?.Cancel(shouldUnbind); - - PointerPressed -= MouseClick; - } - - private void Button_Checked(object sender, RoutedEventArgs e) - { - if (sender is ToggleButton button) - { - if (_currentAssigner != null && button == _currentAssigner.ToggledButton) - { - return; - } - - if (_currentAssigner == null && button.IsChecked != null && (bool)button.IsChecked) - { - _currentAssigner = new ButtonKeyAssigner(button); - - this.Focus(NavigationMethod.Pointer); - - PointerPressed += MouseClick; - - var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad(_avaloniaKeyboardDriver.GamepadsIds[0]); - IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard); - - _currentAssigner.GetInputAndAssign(assigner); - } - else - { - if (_currentAssigner != null) - { - ToggleButton oldButton = _currentAssigner.ToggledButton; - - _currentAssigner.Cancel(); - _currentAssigner = null; - - button.IsChecked = false; - } - } - } - } - - private void Button_Unchecked(object sender, RoutedEventArgs e) - { - _currentAssigner?.Cancel(); - _currentAssigner = null; - } - - public void Dispose() - { - _currentAssigner?.Cancel(); - _currentAssigner = null; - } - } -} diff --git a/src/Ryujinx.Common/Configuration/AppDataManager.cs b/src/Ryujinx.Common/Configuration/AppDataManager.cs index 2e7765a15..619d5f237 100644 --- a/src/Ryujinx.Common/Configuration/AppDataManager.cs +++ b/src/Ryujinx.Common/Configuration/AppDataManager.cs @@ -1,13 +1,15 @@ using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using System; using System.IO; +using System.Runtime.Versioning; namespace Ryujinx.Common.Configuration { public static class AppDataManager { - public const string DefaultBaseDir = "Ryujinx"; - public const string DefaultPortableDir = "portable"; + private const string DefaultBaseDir = "Ryujinx"; + private const string DefaultPortableDir = "portable"; // The following 3 are always part of Base Directory private const string GamesDir = "games"; @@ -29,6 +31,8 @@ namespace Ryujinx.Common.Configuration public static string KeysDirPath { get; private set; } public static string KeysDirPathUser { get; } + public static string LogsDirPath { get; private set; } + public const string DefaultNandDir = "bis"; public const string DefaultSdcardDir = "sdcard"; private const string DefaultModsDir = "mods"; @@ -75,6 +79,17 @@ namespace Ryujinx.Common.Configuration string portablePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DefaultPortableDir); + // On macOS, check for a portable directory next to the app bundle as well. + if (OperatingSystem.IsMacOS() && !Directory.Exists(portablePath)) + { + string bundlePath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..")); + // Make sure we're actually running within an app bundle. + if (bundlePath.EndsWith(".app")) + { + portablePath = Path.GetFullPath(Path.Combine(bundlePath, "..", DefaultPortableDir)); + } + } + if (Directory.Exists(portablePath)) { BaseDirPath = portablePath; @@ -101,65 +116,227 @@ namespace Ryujinx.Common.Configuration BaseDirPath = Path.GetFullPath(BaseDirPath); // convert relative paths - // NOTE: Moves the Ryujinx folder in `~/.config` to `~/Library/Application Support` if one is found - // and a Ryujinx folder does not already exist in Application Support. - // Also creates a symlink from `~/.config/Ryujinx` to `~/Library/Application Support/Ryujinx` to preserve backwards compatibility. - // This should be removed in the future. - if (OperatingSystem.IsMacOS() && Mode == LaunchMode.UserProfile) + if (IsPathSymlink(BaseDirPath)) { - string oldConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir); - if (Path.Exists(oldConfigPath) && !IsPathSymlink(oldConfigPath) && !Path.Exists(BaseDirPath)) - { - CopyDirectory(oldConfigPath, BaseDirPath); - Directory.Delete(oldConfigPath, true); - Directory.CreateSymbolicLink(oldConfigPath, BaseDirPath); - } + Logger.Warning?.Print(LogClass.Application, $"Application data directory is a symlink. This may be unintended."); } SetupBasePaths(); } + public static string GetOrCreateLogsDir() + { + if (Directory.Exists(LogsDirPath)) + { + return LogsDirPath; + } + + Logger.Notice.Print(LogClass.Application, "Logging directory not found; attempting to create new logging directory."); + LogsDirPath = SetUpLogsDir(); + + return LogsDirPath; + } + + private static string SetUpLogsDir() + { + string logDir = ""; + + if (Mode == LaunchMode.Portable) + { + logDir = Path.Combine(BaseDirPath, "Logs"); + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + else + { + if (OperatingSystem.IsMacOS()) + { + // NOTE: Should evaluate to "~/Library/Logs/Ryujinx/". + logDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Logs", DefaultBaseDir); + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + logDir = ""; + } + + if (string.IsNullOrEmpty(logDir)) + { + // NOTE: Should evaluate to "~/Library/Application Support/Ryujinx/Logs". + logDir = Path.Combine(BaseDirPath, "Logs"); + + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + } + else if (OperatingSystem.IsWindows()) + { + // NOTE: Should evaluate to a "Logs" directory in whatever directory Ryujinx was launched from. + logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + logDir = ""; + } + + if (string.IsNullOrEmpty(logDir)) + { + // NOTE: Should evaluate to "C:\Users\user\AppData\Roaming\Ryujinx\Logs". + logDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir, "Logs"); + + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + } + else if (OperatingSystem.IsLinux()) + { + // NOTE: Should evaluate to "~/.config/Ryujinx/Logs". + logDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir, "Logs"); + + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + } + + return logDir; + } + private static void SetupBasePaths() { Directory.CreateDirectory(BaseDirPath); + LogsDirPath = SetUpLogsDir(); Directory.CreateDirectory(GamesDirPath = Path.Combine(BaseDirPath, GamesDir)); Directory.CreateDirectory(ProfilesDirPath = Path.Combine(BaseDirPath, ProfilesDir)); Directory.CreateDirectory(KeysDirPath = Path.Combine(BaseDirPath, KeysDir)); } // Check if existing old baseDirPath is a symlink, to prevent possible errors. - // Should be removed, when the existance of the old directory isn't checked anymore. + // Should be removed, when the existence of the old directory isn't checked anymore. private static bool IsPathSymlink(string path) { - FileAttributes attributes = File.GetAttributes(path); - return (attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint; + try + { + FileAttributes attributes = File.GetAttributes(path); + return (attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint; + } + catch + { + return false; + } } - private static void CopyDirectory(string sourceDir, string destinationDir) + [SupportedOSPlatform("macos")] + public static void FixMacOSConfigurationFolders() { - var dir = new DirectoryInfo(sourceDir); - - if (!dir.Exists) + string oldConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".config", DefaultBaseDir); + if (Path.Exists(oldConfigPath) && !IsPathSymlink(oldConfigPath) && !Path.Exists(BaseDirPath)) { - throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}"); + FileSystemUtils.MoveDirectory(oldConfigPath, BaseDirPath); + Directory.CreateSymbolicLink(oldConfigPath, BaseDirPath); } - DirectoryInfo[] subDirs = dir.GetDirectories(); - Directory.CreateDirectory(destinationDir); - - foreach (FileInfo file in dir.GetFiles()) + string correctApplicationDataDirectoryPath = + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir); + if (IsPathSymlink(correctApplicationDataDirectoryPath)) { - if (file.Name == ".DS_Store") + //copy the files somewhere temporarily + string tempPath = Path.Combine(Path.GetTempPath(), DefaultBaseDir); + try { - continue; + FileSystemUtils.CopyDirectory(correctApplicationDataDirectoryPath, tempPath, true); + } + catch (Exception exception) + { + Logger.Error?.Print(LogClass.Application, + $"Critical error copying Ryujinx application data into the temp folder. {exception}"); + try + { + FileSystemInfo resolvedDirectoryInfo = + Directory.ResolveLinkTarget(correctApplicationDataDirectoryPath, true); + string resolvedPath = resolvedDirectoryInfo.FullName; + Logger.Error?.Print(LogClass.Application, $"Please manually move your Ryujinx data from {resolvedPath} to {correctApplicationDataDirectoryPath}, and remove the symlink."); + } + catch (Exception symlinkException) + { + Logger.Error?.Print(LogClass.Application, $"Unable to resolve the symlink for Ryujinx application data: {symlinkException}. Follow the symlink at {correctApplicationDataDirectoryPath} and move your data back to the Application Support folder."); + } + return; } - file.CopyTo(Path.Combine(destinationDir, file.Name)); - } + //delete the symlink + try + { + //This will fail if this is an actual directory, so there is no way we can actually delete user data here. + File.Delete(correctApplicationDataDirectoryPath); + } + catch (Exception exception) + { + Logger.Error?.Print(LogClass.Application, + $"Critical error deleting the Ryujinx application data folder symlink at {correctApplicationDataDirectoryPath}. {exception}"); + try + { + FileSystemInfo resolvedDirectoryInfo = + Directory.ResolveLinkTarget(correctApplicationDataDirectoryPath, true); + string resolvedPath = resolvedDirectoryInfo.FullName; + Logger.Error?.Print(LogClass.Application, $"Please manually move your Ryujinx data from {resolvedPath} to {correctApplicationDataDirectoryPath}, and remove the symlink."); + } + catch (Exception symlinkException) + { + Logger.Error?.Print(LogClass.Application, $"Unable to resolve the symlink for Ryujinx application data: {symlinkException}. Follow the symlink at {correctApplicationDataDirectoryPath} and move your data back to the Application Support folder."); + } + return; + } - foreach (DirectoryInfo subDir in subDirs) - { - CopyDirectory(subDir.FullName, Path.Combine(destinationDir, subDir.Name)); + //put the files back + try + { + FileSystemUtils.CopyDirectory(tempPath, correctApplicationDataDirectoryPath, true); + } + catch (Exception exception) + { + Logger.Error?.Print(LogClass.Application, + $"Critical error copying Ryujinx application data into the correct location. {exception}. Please manually move your application data from {tempPath} to {correctApplicationDataDirectoryPath}."); + } } } diff --git a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs index b4f2f9468..0cb49ca8c 100644 --- a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs +++ b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs @@ -1,12 +1,10 @@ namespace Ryujinx.Common.Configuration.Hid { - // NOTE: Please don't change this to struct. - // This breaks Avalonia's TwoWay binding, which makes us unable to save new KeyboardHotkeys. public class KeyboardHotkeys { public Key ToggleVsync { get; set; } public Key Screenshot { get; set; } - public Key ShowUi { get; set; } + public Key ShowUI { get; set; } public Key Pause { get; set; } public Key ToggleMute { get; set; } public Key ResScaleUp { get; set; } diff --git a/src/Ryujinx.Common/Configuration/Mod.cs b/src/Ryujinx.Common/Configuration/Mod.cs new file mode 100644 index 000000000..052c7c8d1 --- /dev/null +++ b/src/Ryujinx.Common/Configuration/Mod.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Common.Configuration +{ + public class Mod + { + public string Name { get; set; } + public string Path { get; set; } + public bool Enabled { get; set; } + } +} diff --git a/src/Ryujinx.Common/Configuration/ModMetadata.cs b/src/Ryujinx.Common/Configuration/ModMetadata.cs new file mode 100644 index 000000000..174320d0a --- /dev/null +++ b/src/Ryujinx.Common/Configuration/ModMetadata.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Ryujinx.Common.Configuration +{ + public struct ModMetadata + { + public List Mods { get; set; } + + public ModMetadata() + { + Mods = new List(); + } + } +} diff --git a/src/Ryujinx.Common/Configuration/ModMetadataJsonSerializerContext.cs b/src/Ryujinx.Common/Configuration/ModMetadataJsonSerializerContext.cs new file mode 100644 index 000000000..8c1e242ad --- /dev/null +++ b/src/Ryujinx.Common/Configuration/ModMetadataJsonSerializerContext.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace Ryujinx.Common.Configuration +{ + [JsonSourceGenerationOptions(WriteIndented = true)] + [JsonSerializable(typeof(ModMetadata))] + public partial class ModMetadataJsonSerializerContext : JsonSerializerContext + { + } +} diff --git a/src/Ryujinx.Common/Extensions/SequenceReaderExtensions.cs b/src/Ryujinx.Common/Extensions/SequenceReaderExtensions.cs new file mode 100644 index 000000000..79b5d743b --- /dev/null +++ b/src/Ryujinx.Common/Extensions/SequenceReaderExtensions.cs @@ -0,0 +1,181 @@ +using System; +using System.Buffers; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Common.Extensions +{ + public static class SequenceReaderExtensions + { + /// + /// Dumps the entire to a file, restoring its previous location afterward. + /// Useful for debugging purposes. + /// + /// The to write to a file + /// The path and name of the file to create and dump to + public static void DumpToFile(this ref SequenceReader reader, string fileFullName) + { + var initialConsumed = reader.Consumed; + + reader.Rewind(initialConsumed); + + using (var fileStream = System.IO.File.Create(fileFullName, 4096, System.IO.FileOptions.None)) + { + while (reader.End == false) + { + var span = reader.CurrentSpan; + fileStream.Write(span); + reader.Advance(span.Length); + } + } + + reader.SetConsumed(initialConsumed); + } + + /// + /// Returns a reference to the desired value. This ref should always be used. The argument passed in should never be used, as this is only used for storage if the value + /// must be copied from multiple segments held by the . + /// + /// Type to get + /// The to read from + /// A location used as storage if (and only if) the value to be read spans multiple segments + /// A reference to the desired value, either directly to memory in the , or to if it has been used for copying the value in to + /// + /// DO NOT use after calling this method, as it will only + /// contain a value if the value couldn't be referenced directly because it spans multiple segments. + /// To discourage use, it is recommended to call this method like the following: + /// + /// ref readonly MyStruct value = ref sequenceReader.GetRefOrRefToCopy{MyStruct}(out _); + /// + /// + /// The does not contain enough data to read a value of type + public static ref readonly T GetRefOrRefToCopy(this scoped ref SequenceReader reader, out T copyDestinationIfRequiredDoNotUse) where T : unmanaged + { + int lengthRequired = Unsafe.SizeOf(); + + ReadOnlySpan span = reader.UnreadSpan; + if (lengthRequired <= span.Length) + { + reader.Advance(lengthRequired); + + copyDestinationIfRequiredDoNotUse = default; + + ReadOnlySpan spanOfT = MemoryMarshal.Cast(span); + + return ref spanOfT[0]; + } + else + { + copyDestinationIfRequiredDoNotUse = default; + + Span valueSpan = MemoryMarshal.CreateSpan(ref copyDestinationIfRequiredDoNotUse, 1); + + Span valueBytesSpan = MemoryMarshal.AsBytes(valueSpan); + + if (!reader.TryCopyTo(valueBytesSpan)) + { + throw new ArgumentOutOfRangeException(nameof(reader), "The sequence is not long enough to read the desired value."); + } + + reader.Advance(lengthRequired); + + return ref valueSpan[0]; + } + } + + /// + /// Reads an as little endian. + /// + /// The to read from + /// A location to receive the read value + /// Thrown if there wasn't enough data for an + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ReadLittleEndian(this ref SequenceReader reader, out int value) + { + if (!reader.TryReadLittleEndian(out value)) + { + throw new ArgumentOutOfRangeException(nameof(value), "The sequence is not long enough to read the desired value."); + } + } + + /// + /// Reads the desired unmanaged value by copying it to the specified . + /// + /// Type to read + /// The to read from + /// The target that will receive the read value + /// The does not contain enough data to read a value of type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ReadUnmanaged(this ref SequenceReader reader, out T value) where T : unmanaged + { + if (!reader.TryReadUnmanaged(out value)) + { + throw new ArgumentOutOfRangeException(nameof(value), "The sequence is not long enough to read the desired value."); + } + } + + /// + /// Sets the reader's position as bytes consumed. + /// + /// The to set the position + /// The number of bytes consumed + public static void SetConsumed(ref this SequenceReader reader, long consumed) + { + reader.Rewind(reader.Consumed); + reader.Advance(consumed); + } + + /// + /// Try to read the given type out of the buffer if possible. Warning: this is dangerous to use with arbitrary + /// structs - see remarks for full details. + /// + /// Type to read + /// + /// IMPORTANT: The read is a straight copy of bits. If a struct depends on specific state of it's members to + /// behave correctly this can lead to exceptions, etc. If reading endian specific integers, use the explicit + /// overloads such as + /// + /// + /// True if successful. will be default if failed (due to lack of space). + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool TryReadUnmanaged(ref this SequenceReader reader, out T value) where T : unmanaged + { + ReadOnlySpan span = reader.UnreadSpan; + + if (span.Length < sizeof(T)) + { + return TryReadUnmanagedMultiSegment(ref reader, out value); + } + + value = Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(span)); + + reader.Advance(sizeof(T)); + + return true; + } + + private static unsafe bool TryReadUnmanagedMultiSegment(ref SequenceReader reader, out T value) where T : unmanaged + { + Debug.Assert(reader.UnreadSpan.Length < sizeof(T)); + + // Not enough data in the current segment, try to peek for the data we need. + T buffer = default; + + Span tempSpan = new Span(&buffer, sizeof(T)); + + if (!reader.TryCopyTo(tempSpan)) + { + value = default; + return false; + } + + value = Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(tempSpan)); + + reader.Advance(sizeof(T)); + + return true; + } + } +} diff --git a/src/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs b/src/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs index 7fe2a4f02..a9163f348 100644 --- a/src/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs +++ b/src/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs @@ -1,13 +1,33 @@ +using Ryujinx.Common.Utilities; using System; namespace Ryujinx.Common.GraphicsDriver { public static class DriverUtilities { + private static void AddMesaFlags(string envVar, string newFlags) + { + string existingFlags = Environment.GetEnvironmentVariable(envVar); + + string flags = existingFlags == null ? newFlags : $"{existingFlags},{newFlags}"; + + OsUtils.SetEnvironmentVariableNoCaching(envVar, flags); + } + + public static void InitDriverConfig(bool oglThreading) + { + if (OperatingSystem.IsLinux()) + { + AddMesaFlags("RADV_DEBUG", "nodcc"); + } + + ToggleOGLThreading(oglThreading); + } + public static void ToggleOGLThreading(bool enabled) { - Environment.SetEnvironmentVariable("mesa_glthread", enabled.ToString().ToLower()); - Environment.SetEnvironmentVariable("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0"); + OsUtils.SetEnvironmentVariableNoCaching("mesa_glthread", enabled.ToString().ToLower()); + OsUtils.SetEnvironmentVariableNoCaching("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0"); try { diff --git a/src/Ryujinx.Common/Logging/LogClass.cs b/src/Ryujinx.Common/Logging/LogClass.cs index f277dd06d..1b404a06a 100644 --- a/src/Ryujinx.Common/Logging/LogClass.cs +++ b/src/Ryujinx.Common/Logging/LogClass.cs @@ -70,7 +70,7 @@ namespace Ryujinx.Common.Logging ServiceVi, SurfaceFlinger, TamperMachine, - Ui, + UI, Vic, } } diff --git a/src/Ryujinx.Common/Logging/Logger.cs b/src/Ryujinx.Common/Logging/Logger.cs index f03a7fd8f..db46739ac 100644 --- a/src/Ryujinx.Common/Logging/Logger.cs +++ b/src/Ryujinx.Common/Logging/Logger.cs @@ -3,6 +3,7 @@ using Ryujinx.Common.SystemInterop; using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Runtime.CompilerServices; using System.Threading; @@ -22,6 +23,9 @@ namespace Ryujinx.Common.Logging public readonly struct Log { + private static readonly string _homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + private static readonly string _homeDirRedacted = Path.Combine(Directory.GetParent(_homeDir).FullName, "[redacted]"); + internal readonly LogLevel Level; internal Log(LogLevel level) @@ -100,7 +104,12 @@ namespace Ryujinx.Common.Logging } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static string FormatMessage(LogClass logClass, string caller, string message) => $"{logClass} {caller}: {message}"; + private static string FormatMessage(LogClass logClass, string caller, string message) + { + message = message.Replace(_homeDir, _homeDirRedacted); + + return $"{logClass} {caller}: {message}"; + } } public static Log? Debug { get; private set; } diff --git a/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs b/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs index 8aa2a26b9..8d4ede96c 100644 --- a/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs +++ b/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs @@ -13,31 +13,82 @@ namespace Ryujinx.Common.Logging.Targets string ILogTarget.Name { get => _name; } - public FileLogTarget(string path, string name) - : this(path, name, FileShare.Read, FileMode.Append) - { } + public FileLogTarget(string name, FileStream fileStream) + { + _name = name; + _logWriter = new StreamWriter(fileStream); + _formatter = new DefaultLogFormatter(); + } - public FileLogTarget(string path, string name, FileShare fileShare, FileMode fileMode) + public static FileStream PrepareLogFile(string path) { // Ensure directory is present - DirectoryInfo logDir = new(Path.Combine(path, "Logs")); - logDir.Create(); + DirectoryInfo logDir; + try + { + logDir = new DirectoryInfo(path); + } + catch (ArgumentException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory path ('{path}') was invalid: {exception}"); + + return null; + } + + try + { + logDir.Create(); + } + catch (IOException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}': {exception}"); + + return null; + } // Clean up old logs, should only keep 3 FileInfo[] files = logDir.GetFiles("*.log").OrderBy((info => info.CreationTime)).ToArray(); for (int i = 0; i < files.Length - 2; i++) { - files[i].Delete(); + try + { + files[i].Delete(); + } + catch (UnauthorizedAccessException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Old log file could not be deleted '{files[i].FullName}': {exception}"); + + return null; + } + catch (IOException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Old log file could not be deleted '{files[i].FullName}': {exception}"); + + return null; + } } - string version = ReleaseInformation.GetVersion(); + string version = ReleaseInformation.Version; // Get path for the current time path = Path.Combine(logDir.FullName, $"Ryujinx_{version}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log"); - _name = name; - _logWriter = new StreamWriter(File.Open(path, fileMode, FileAccess.Write, fileShare)); - _formatter = new DefaultLogFormatter(); + try + { + return File.Open(path, FileMode.Append, FileAccess.Write, FileShare.Read); + } + catch (UnauthorizedAccessException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Log file could not be created '{path}': {exception}"); + + return null; + } + catch (IOException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Log file could not be created '{path}': {exception}"); + + return null; + } } public void Log(object sender, LogEventArgs args) diff --git a/src/Ryujinx.Common/Memory/ByteMemoryPool.ByteMemoryPoolBuffer.cs b/src/Ryujinx.Common/Memory/ByteMemoryPool.ByteMemoryPoolBuffer.cs deleted file mode 100644 index df3f8dc93..000000000 --- a/src/Ryujinx.Common/Memory/ByteMemoryPool.ByteMemoryPoolBuffer.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Buffers; -using System.Threading; - -namespace Ryujinx.Common.Memory -{ - public sealed partial class ByteMemoryPool - { - /// - /// Represents a that wraps an array rented from - /// and exposes it as - /// with a length of the requested size. - /// - private sealed class ByteMemoryPoolBuffer : IMemoryOwner - { - private byte[] _array; - private readonly int _length; - - public ByteMemoryPoolBuffer(int length) - { - _array = ArrayPool.Shared.Rent(length); - _length = length; - } - - /// - /// Returns a belonging to this owner. - /// - public Memory Memory - { - get - { - byte[] array = _array; - - ObjectDisposedException.ThrowIf(array is null, this); - - return new Memory(array, 0, _length); - } - } - - public void Dispose() - { - var array = Interlocked.Exchange(ref _array, null); - - if (array != null) - { - ArrayPool.Shared.Return(array); - } - } - } - } -} diff --git a/src/Ryujinx.Common/Memory/ByteMemoryPool.cs b/src/Ryujinx.Common/Memory/ByteMemoryPool.cs deleted file mode 100644 index 071f56b13..000000000 --- a/src/Ryujinx.Common/Memory/ByteMemoryPool.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Buffers; - -namespace Ryujinx.Common.Memory -{ - /// - /// Provides a pool of re-usable byte array instances. - /// - public sealed partial class ByteMemoryPool - { - private static readonly ByteMemoryPool _shared = new(); - - /// - /// Constructs a instance. Private to force access through - /// the instance. - /// - private ByteMemoryPool() - { - // No implementation - } - - /// - /// Retrieves a shared instance. - /// - public static ByteMemoryPool Shared => _shared; - - /// - /// Returns the maximum buffer size supported by this pool. - /// - public static int MaxBufferSize => Array.MaxLength; - - /// - /// Rents a byte memory buffer from . - /// The buffer may contain data from a prior use. - /// - /// The buffer's required length in bytes - /// A wrapping the rented memory - /// - public static IMemoryOwner Rent(long length) - => RentImpl(checked((int)length)); - - /// - /// Rents a byte memory buffer from . - /// The buffer may contain data from a prior use. - /// - /// The buffer's required length in bytes - /// A wrapping the rented memory - /// - public static IMemoryOwner Rent(ulong length) - => RentImpl(checked((int)length)); - - /// - /// Rents a byte memory buffer from . - /// The buffer may contain data from a prior use. - /// - /// The buffer's required length in bytes - /// A wrapping the rented memory - /// - public static IMemoryOwner Rent(int length) - => RentImpl(length); - - /// - /// Rents a byte memory buffer from . - /// The buffer's contents are cleared (set to all 0s) before returning. - /// - /// The buffer's required length in bytes - /// A wrapping the rented memory - /// - public static IMemoryOwner RentCleared(long length) - => RentCleared(checked((int)length)); - - /// - /// Rents a byte memory buffer from . - /// The buffer's contents are cleared (set to all 0s) before returning. - /// - /// The buffer's required length in bytes - /// A wrapping the rented memory - /// - public static IMemoryOwner RentCleared(ulong length) - => RentCleared(checked((int)length)); - - /// - /// Rents a byte memory buffer from . - /// The buffer's contents are cleared (set to all 0s) before returning. - /// - /// The buffer's required length in bytes - /// A wrapping the rented memory - /// - public static IMemoryOwner RentCleared(int length) - { - var buffer = RentImpl(length); - - buffer.Memory.Span.Clear(); - - return buffer; - } - - private static ByteMemoryPoolBuffer RentImpl(int length) - { - if ((uint)length > Array.MaxLength) - { - throw new ArgumentOutOfRangeException(nameof(length), length, null); - } - - return new ByteMemoryPoolBuffer(length); - } - } -} diff --git a/src/Ryujinx.Common/Memory/MemoryOwner.cs b/src/Ryujinx.Common/Memory/MemoryOwner.cs new file mode 100644 index 000000000..b7fe1db77 --- /dev/null +++ b/src/Ryujinx.Common/Memory/MemoryOwner.cs @@ -0,0 +1,140 @@ +#nullable enable +using System; +using System.Buffers; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Ryujinx.Common.Memory +{ + /// + /// An implementation with an embedded length and fast + /// accessor, with memory allocated from . + /// + /// The type of item to store. + public sealed class MemoryOwner : IMemoryOwner + { + private readonly int _length; + private T[]? _array; + + /// + /// Initializes a new instance of the class with the specified parameters. + /// + /// The length of the new memory buffer to use + private MemoryOwner(int length) + { + _length = length; + _array = ArrayPool.Shared.Rent(length); + } + + /// + /// Creates a new instance with the specified length. + /// + /// The length of the new memory buffer to use + /// A instance of the requested length + /// Thrown when is not valid + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static MemoryOwner Rent(int length) => new(length); + + /// + /// Creates a new instance with the specified length and the content cleared. + /// + /// The length of the new memory buffer to use + /// A instance of the requested length and the content cleared + /// Thrown when is not valid + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static MemoryOwner RentCleared(int length) + { + MemoryOwner result = new(length); + + result._array.AsSpan(0, length).Clear(); + + return result; + } + + /// + /// Creates a new instance with the content copied from the specified buffer. + /// + /// The buffer to copy + /// A instance with the same length and content as + public static MemoryOwner RentCopy(ReadOnlySpan buffer) + { + MemoryOwner result = new(buffer.Length); + + buffer.CopyTo(result._array); + + return result; + } + + /// + /// Gets the number of items in the current instance. + /// + public int Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _length; + } + + /// + public Memory Memory + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + T[]? array = _array; + + if (array is null) + { + ThrowObjectDisposedException(); + } + + return new(array, 0, _length); + } + } + + /// + /// Gets a wrapping the memory belonging to the current instance. + /// + /// + /// Uses a trick made possible by the .NET 6+ runtime array layout. + /// + public Span Span + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + T[]? array = _array; + + if (array is null) + { + ThrowObjectDisposedException(); + } + + ref T firstElementRef = ref MemoryMarshal.GetArrayDataReference(array); + + return MemoryMarshal.CreateSpan(ref firstElementRef, _length); + } + } + + /// + public void Dispose() + { + T[]? array = Interlocked.Exchange(ref _array, null); + + if (array is not null) + { + ArrayPool.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences()); + } + } + + /// + /// Throws an when is . + /// + [DoesNotReturn] + private static void ThrowObjectDisposedException() + { + throw new ObjectDisposedException(nameof(MemoryOwner), "The buffer has already been disposed."); + } + } +} diff --git a/src/Ryujinx.Common/Memory/SpanOrArray.cs b/src/Ryujinx.Common/Memory/SpanOrArray.cs deleted file mode 100644 index 269ac02fd..000000000 --- a/src/Ryujinx.Common/Memory/SpanOrArray.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; - -namespace Ryujinx.Common.Memory -{ - /// - /// A struct that can represent both a Span and Array. - /// This is useful to keep the Array representation when possible to avoid copies. - /// - /// Element Type - public readonly ref struct SpanOrArray where T : unmanaged - { - public readonly T[] Array; - public readonly ReadOnlySpan Span; - - /// - /// Create a new SpanOrArray from an array. - /// - /// Array to store - public SpanOrArray(T[] array) - { - Array = array; - Span = ReadOnlySpan.Empty; - } - - /// - /// Create a new SpanOrArray from a readonly span. - /// - /// Span to store - public SpanOrArray(ReadOnlySpan span) - { - Array = null; - Span = span; - } - - /// - /// Return the contained array, or convert the span if necessary. - /// - /// An array containing the data - public T[] ToArray() - { - return Array ?? Span.ToArray(); - } - - /// - /// Return a ReadOnlySpan from either the array or ReadOnlySpan. - /// - /// A ReadOnlySpan containing the data - public ReadOnlySpan AsSpan() - { - return Array ?? Span; - } - - /// - /// Cast an array to a SpanOrArray. - /// - /// Source array - public static implicit operator SpanOrArray(T[] array) - { - return new SpanOrArray(array); - } - - /// - /// Cast a ReadOnlySpan to a SpanOrArray. - /// - /// Source ReadOnlySpan - public static implicit operator SpanOrArray(ReadOnlySpan span) - { - return new SpanOrArray(span); - } - - /// - /// Cast a Span to a SpanOrArray. - /// - /// Source Span - public static implicit operator SpanOrArray(Span span) - { - return new SpanOrArray(span); - } - - /// - /// Cast a SpanOrArray to a ReadOnlySpan - /// - /// Source SpanOrArray - public static implicit operator ReadOnlySpan(SpanOrArray spanOrArray) - { - return spanOrArray.AsSpan(); - } - } -} diff --git a/src/Ryujinx.Common/Memory/SpanOwner.cs b/src/Ryujinx.Common/Memory/SpanOwner.cs new file mode 100644 index 000000000..acb20bcad --- /dev/null +++ b/src/Ryujinx.Common/Memory/SpanOwner.cs @@ -0,0 +1,114 @@ +using System; +using System.Buffers; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Common.Memory +{ + /// + /// A stack-only type that rents a buffer of a specified length from . + /// It does not implement to avoid being boxed, but should still be disposed. This + /// is easy since C# 8, which allows use of C# `using` constructs on any type that has a public Dispose() method. + /// To keep this type simple, fast, and read-only, it does not check or guard against multiple disposals. + /// For all these reasons, all usage should be with a `using` block or statement. + /// + /// The type of item to store. + public readonly ref struct SpanOwner + { + private readonly int _length; + private readonly T[] _array; + + /// + /// Initializes a new instance of the struct with the specified parameters. + /// + /// The length of the new memory buffer to use + private SpanOwner(int length) + { + _length = length; + _array = ArrayPool.Shared.Rent(length); + } + + /// + /// Gets an empty instance. + /// + public static SpanOwner Empty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => new(0); + } + + /// + /// Creates a new instance with the specified length. + /// + /// The length of the new memory buffer to use + /// A instance of the requested length + /// Thrown when is not valid + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static SpanOwner Rent(int length) => new(length); + + /// + /// Creates a new instance with the length and the content cleared. + /// + /// The length of the new memory buffer to use + /// A instance of the requested length and the content cleared + /// Thrown when is not valid + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static SpanOwner RentCleared(int length) + { + SpanOwner result = new(length); + + result._array.AsSpan(0, length).Clear(); + + return result; + } + + /// + /// Creates a new instance with the content copied from the specified buffer. + /// + /// The buffer to copy + /// A instance with the same length and content as + public static SpanOwner RentCopy(ReadOnlySpan buffer) + { + SpanOwner result = new(buffer.Length); + + buffer.CopyTo(result._array); + + return result; + } + + /// + /// Gets the number of items in the current instance + /// + public int Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _length; + } + + /// + /// Gets a wrapping the memory belonging to the current instance. + /// + /// + /// Uses a trick made possible by the .NET 6+ runtime array layout. + /// + public Span Span + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ref T firstElementRef = ref MemoryMarshal.GetArrayDataReference(_array); + + return MemoryMarshal.CreateSpan(ref firstElementRef, _length); + } + } + + /// + /// Implements the duck-typed method. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + ArrayPool.Shared.Return(_array, RuntimeHelpers.IsReferenceOrContainsReferences()); + } + } +} diff --git a/src/Ryujinx.Common/Memory/StructArrayHelpers.cs b/src/Ryujinx.Common/Memory/StructArrayHelpers.cs index 94ce8d2f5..762c73889 100644 --- a/src/Ryujinx.Common/Memory/StructArrayHelpers.cs +++ b/src/Ryujinx.Common/Memory/StructArrayHelpers.cs @@ -744,6 +744,17 @@ namespace Ryujinx.Common.Memory public Span AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length); } + public struct Array65 : IArray where T : unmanaged + { + T _e0; + Array64 _other; + public readonly int Length => 65; + public ref T this[int index] => ref AsSpan()[index]; + + [Pure] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length); + } + public struct Array73 : IArray where T : unmanaged { T _e0; diff --git a/src/Ryujinx.Common/Memory/StructByteArrayHelpers.cs b/src/Ryujinx.Common/Memory/StructByteArrayHelpers.cs index 3b0666628..79b7d681a 100644 --- a/src/Ryujinx.Common/Memory/StructByteArrayHelpers.cs +++ b/src/Ryujinx.Common/Memory/StructByteArrayHelpers.cs @@ -63,6 +63,18 @@ namespace Ryujinx.Common.Memory public Span AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size); } + [StructLayout(LayoutKind.Sequential, Size = Size, Pack = 1)] + public struct ByteArray3000 : IArray + { + private const int Size = 3000; + + byte _element; + + public readonly int Length => Size; + public ref byte this[int index] => ref AsSpan()[index]; + public Span AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size); + } + [StructLayout(LayoutKind.Sequential, Size = Size, Pack = 1)] public struct ByteArray4096 : IArray { diff --git a/src/Ryujinx.Common/ReleaseInformation.cs b/src/Ryujinx.Common/ReleaseInformation.cs index bf68cbbc8..af9600038 100644 --- a/src/Ryujinx.Common/ReleaseInformation.cs +++ b/src/Ryujinx.Common/ReleaseInformation.cs @@ -1,5 +1,3 @@ -using Ryujinx.Common.Configuration; -using System; using System.Reflection; namespace Ryujinx.Common @@ -9,55 +7,25 @@ namespace Ryujinx.Common { private const string FlatHubChannelOwner = "flathub"; - public const string BuildVersion = "%%RYUJINX_BUILD_VERSION%%"; - public const string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%"; - public const string ReleaseChannelName = "%%RYUJINX_TARGET_RELEASE_CHANNEL_NAME%%"; + private const string BuildVersion = "%%RYUJINX_BUILD_VERSION%%"; + private const string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%"; + private const string ReleaseChannelName = "%%RYUJINX_TARGET_RELEASE_CHANNEL_NAME%%"; + private const string ConfigFileName = "%%RYUJINX_CONFIG_FILE_NAME%%"; + public const string ReleaseChannelOwner = "%%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER%%"; public const string ReleaseChannelRepo = "%%RYUJINX_TARGET_RELEASE_CHANNEL_REPO%%"; - public static bool IsValid() - { - return !BuildGitHash.StartsWith("%%") && - !ReleaseChannelName.StartsWith("%%") && - !ReleaseChannelOwner.StartsWith("%%") && - !ReleaseChannelRepo.StartsWith("%%"); - } + public static string ConfigName => !ConfigFileName.StartsWith("%%") ? ConfigFileName : "Config.json"; - public static bool IsFlatHubBuild() - { - return IsValid() && ReleaseChannelOwner.Equals(FlatHubChannelOwner); - } + public static bool IsValid => + !BuildGitHash.StartsWith("%%") && + !ReleaseChannelName.StartsWith("%%") && + !ReleaseChannelOwner.StartsWith("%%") && + !ReleaseChannelRepo.StartsWith("%%") && + !ConfigFileName.StartsWith("%%"); - public static string GetVersion() - { - if (OperatingSystem.IsIOS()) - { - return "ios"; - } + public static bool IsFlatHubBuild => IsValid && ReleaseChannelOwner.Equals(FlatHubChannelOwner); - if (IsValid()) - { - return BuildVersion; - } - - return Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion; - } - -#if FORCE_EXTERNAL_BASE_DIR - public static string GetBaseApplicationDirectory() - { - return AppDataManager.BaseDirPath; - } -#else - public static string GetBaseApplicationDirectory() - { - if (IsFlatHubBuild() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) - { - return AppDataManager.BaseDirPath; - } - - return AppDomain.CurrentDomain.BaseDirectory; - } -#endif + public static string Version => IsValid ? BuildVersion : Assembly.GetEntryAssembly()!.GetCustomAttribute()?.InformationalVersion ?? ""; } } diff --git a/src/Ryujinx.Common/Utilities/EmbeddedResources.cs b/src/Ryujinx.Common/Utilities/EmbeddedResources.cs index a4facc2e3..7530c012a 100644 --- a/src/Ryujinx.Common/Utilities/EmbeddedResources.cs +++ b/src/Ryujinx.Common/Utilities/EmbeddedResources.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Memory; using Ryujinx.Common.Utilities; using System; using System.IO; @@ -41,6 +42,22 @@ namespace Ryujinx.Common return StreamUtils.StreamToBytes(stream); } + public static MemoryOwner ReadFileToRentedMemory(string filename) + { + var (assembly, path) = ResolveManifestPath(filename); + + return ReadFileToRentedMemory(assembly, path); + } + + public static MemoryOwner ReadFileToRentedMemory(Assembly assembly, string filename) + { + using var stream = GetStream(assembly, filename); + + return stream is null + ? null + : StreamUtils.StreamToRentedMemory(stream); + } + public async static Task ReadAsync(Assembly assembly, string filename) { using var stream = GetStream(assembly, filename); diff --git a/src/Ryujinx.Common/Utilities/FileSystemUtils.cs b/src/Ryujinx.Common/Utilities/FileSystemUtils.cs new file mode 100644 index 000000000..a57fa8a78 --- /dev/null +++ b/src/Ryujinx.Common/Utilities/FileSystemUtils.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Ryujinx.Common.Utilities +{ + public static class FileSystemUtils + { + public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive) + { + // Get information about the source directory + var dir = new DirectoryInfo(sourceDir); + + // Check if the source directory exists + if (!dir.Exists) + { + throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}"); + } + + // Cache directories before we start copying + DirectoryInfo[] dirs = dir.GetDirectories(); + + // Create the destination directory + Directory.CreateDirectory(destinationDir); + + // Get the files in the source directory and copy to the destination directory + foreach (FileInfo file in dir.GetFiles()) + { + string targetFilePath = Path.Combine(destinationDir, file.Name); + file.CopyTo(targetFilePath); + } + + // If recursive and copying subdirectories, recursively call this method + if (recursive) + { + foreach (DirectoryInfo subDir in dirs) + { + string newDestinationDir = Path.Combine(destinationDir, subDir.Name); + CopyDirectory(subDir.FullName, newDestinationDir, true); + } + } + } + + public static void MoveDirectory(string sourceDir, string destinationDir) + { + CopyDirectory(sourceDir, destinationDir, true); + Directory.Delete(sourceDir, true); + } + + public static string SanitizeFileName(string fileName) + { + var reservedChars = new HashSet(Path.GetInvalidFileNameChars()); + return string.Concat(fileName.Select(c => reservedChars.Contains(c) ? '_' : c)); + } + } +} diff --git a/src/Ryujinx.Common/Utilities/OsUtils.cs b/src/Ryujinx.Common/Utilities/OsUtils.cs new file mode 100644 index 000000000..a0791b092 --- /dev/null +++ b/src/Ryujinx.Common/Utilities/OsUtils.cs @@ -0,0 +1,24 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Ryujinx.Common.Utilities +{ + public partial class OsUtils + { + [LibraryImport("libc", SetLastError = true)] + private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite); + + public static void SetEnvironmentVariableNoCaching(string key, string value) + { + // Set the value in the cached environment variables, too. + Environment.SetEnvironmentVariable(key, value); + + if (!OperatingSystem.IsWindows()) + { + int res = setenv(key, value, 1); + Debug.Assert(res != -1); + } + } + } +} diff --git a/src/Ryujinx.Common/Utilities/StreamUtils.cs b/src/Ryujinx.Common/Utilities/StreamUtils.cs index 7a20c98e9..aeb6e0d52 100644 --- a/src/Ryujinx.Common/Utilities/StreamUtils.cs +++ b/src/Ryujinx.Common/Utilities/StreamUtils.cs @@ -1,3 +1,4 @@ +using Microsoft.IO; using Ryujinx.Common.Memory; using System.IO; using System.Threading; @@ -9,12 +10,50 @@ namespace Ryujinx.Common.Utilities { public static byte[] StreamToBytes(Stream input) { - using MemoryStream stream = MemoryStreamManager.Shared.GetStream(); + using RecyclableMemoryStream output = StreamToRecyclableMemoryStream(input); + return output.ToArray(); + } - input.CopyTo(stream); + public static MemoryOwner StreamToRentedMemory(Stream input) + { + if (input is MemoryStream inputMemoryStream) + { + return MemoryStreamToRentedMemory(inputMemoryStream); + } + else if (input.CanSeek) + { + long bytesExpected = input.Length; - return stream.ToArray(); + MemoryOwner ownedMemory = MemoryOwner.Rent(checked((int)bytesExpected)); + + var destSpan = ownedMemory.Span; + + int totalBytesRead = 0; + + while (totalBytesRead < bytesExpected) + { + int bytesRead = input.Read(destSpan[totalBytesRead..]); + + if (bytesRead == 0) + { + ownedMemory.Dispose(); + + throw new IOException($"Tried reading {bytesExpected} but the stream closed after reading {totalBytesRead}."); + } + + totalBytesRead += bytesRead; + } + + return ownedMemory; + } + else + { + // If input is (non-seekable) then copy twice: first into a RecyclableMemoryStream, then to a rented IMemoryOwner. + using RecyclableMemoryStream output = StreamToRecyclableMemoryStream(input); + + return MemoryStreamToRentedMemory(output); + } } public static async Task StreamToBytesAsync(Stream input, CancellationToken cancellationToken = default) @@ -25,5 +64,26 @@ namespace Ryujinx.Common.Utilities return stream.ToArray(); } + + private static MemoryOwner MemoryStreamToRentedMemory(MemoryStream input) + { + input.Position = 0; + + MemoryOwner ownedMemory = MemoryOwner.Rent(checked((int)input.Length)); + + // Discard the return value because we assume reading a MemoryStream always succeeds completely. + _ = input.Read(ownedMemory.Span); + + return ownedMemory; + } + + private static RecyclableMemoryStream StreamToRecyclableMemoryStream(Stream input) + { + RecyclableMemoryStream stream = MemoryStreamManager.Shared.GetStream(); + + input.CopyTo(stream); + + return stream; + } } } diff --git a/src/Ryujinx.Cpu/AddressSpace.cs b/src/Ryujinx.Cpu/AddressSpace.cs index beea14bee..6664ed134 100644 --- a/src/Ryujinx.Cpu/AddressSpace.cs +++ b/src/Ryujinx.Cpu/AddressSpace.cs @@ -1,5 +1,3 @@ -using Ryujinx.Common; -using Ryujinx.Common.Collections; using Ryujinx.Memory; using System; @@ -7,175 +5,23 @@ namespace Ryujinx.Cpu { public class AddressSpace : IDisposable { - private const int DefaultBlockAlignment = 1 << 20; - - private enum MappingType : byte - { - None, - Private, - Shared, - } - - private class Mapping : IntrusiveRedBlackTreeNode, IComparable - { - public ulong Address { get; private set; } - public ulong Size { get; private set; } - public ulong EndAddress => Address + Size; - public MappingType Type { get; private set; } - - public Mapping(ulong address, ulong size, MappingType type) - { - Address = address; - Size = size; - Type = type; - } - - public Mapping Split(ulong splitAddress) - { - ulong leftSize = splitAddress - Address; - ulong rightSize = EndAddress - splitAddress; - - Mapping left = new(Address, leftSize, Type); - - Address = splitAddress; - Size = rightSize; - - return left; - } - - public void UpdateState(MappingType newType) - { - Type = newType; - } - - public void Extend(ulong sizeDelta) - { - Size += sizeDelta; - } - - public int CompareTo(Mapping other) - { - if (Address < other.Address) - { - return -1; - } - else if (Address <= other.EndAddress - 1UL) - { - return 0; - } - else - { - return 1; - } - } - } - - private class PrivateMapping : IntrusiveRedBlackTreeNode, IComparable - { - public ulong Address { get; private set; } - public ulong Size { get; private set; } - public ulong EndAddress => Address + Size; - public PrivateMemoryAllocation PrivateAllocation { get; private set; } - - public PrivateMapping(ulong address, ulong size, PrivateMemoryAllocation privateAllocation) - { - Address = address; - Size = size; - PrivateAllocation = privateAllocation; - } - - public PrivateMapping Split(ulong splitAddress) - { - ulong leftSize = splitAddress - Address; - ulong rightSize = EndAddress - splitAddress; - - (var leftAllocation, PrivateAllocation) = PrivateAllocation.Split(leftSize); - - PrivateMapping left = new(Address, leftSize, leftAllocation); - - Address = splitAddress; - Size = rightSize; - - return left; - } - - public void Map(MemoryBlock baseBlock, MemoryBlock mirrorBlock, PrivateMemoryAllocation newAllocation) - { - baseBlock.MapView(newAllocation.Memory, newAllocation.Offset, Address, Size); - mirrorBlock.MapView(newAllocation.Memory, newAllocation.Offset, Address, Size); - PrivateAllocation = newAllocation; - } - - public void Unmap(MemoryBlock baseBlock, MemoryBlock mirrorBlock) - { - if (PrivateAllocation.IsValid) - { - baseBlock.UnmapView(PrivateAllocation.Memory, Address, Size); - mirrorBlock.UnmapView(PrivateAllocation.Memory, Address, Size); - PrivateAllocation.Dispose(); - } - - PrivateAllocation = default; - } - - public void Extend(ulong sizeDelta) - { - Size += sizeDelta; - } - - public int CompareTo(PrivateMapping other) - { - if (Address < other.Address) - { - return -1; - } - else if (Address <= other.EndAddress - 1UL) - { - return 0; - } - else - { - return 1; - } - } - } - private readonly MemoryBlock _backingMemory; - private readonly PrivateMemoryAllocator _privateMemoryAllocator; - private readonly IntrusiveRedBlackTree _mappingTree; - private readonly IntrusiveRedBlackTree _privateTree; - - private readonly object _treeLock; - - private readonly bool _supports4KBPages; public MemoryBlock Base { get; } public MemoryBlock Mirror { get; } public ulong AddressSpaceSize { get; } - public AddressSpace(MemoryBlock backingMemory, MemoryBlock baseMemory, MemoryBlock mirrorMemory, ulong addressSpaceSize, bool supports4KBPages) + public AddressSpace(MemoryBlock backingMemory, MemoryBlock baseMemory, MemoryBlock mirrorMemory, ulong addressSpaceSize) { - if (!supports4KBPages) - { - _privateMemoryAllocator = new PrivateMemoryAllocator(DefaultBlockAlignment, MemoryAllocationFlags.Mirrorable | MemoryAllocationFlags.NoMap); - _mappingTree = new IntrusiveRedBlackTree(); - _privateTree = new IntrusiveRedBlackTree(); - _treeLock = new object(); - - _mappingTree.Add(new Mapping(0UL, addressSpaceSize, MappingType.None)); - _privateTree.Add(new PrivateMapping(0UL, addressSpaceSize, default)); - } - _backingMemory = backingMemory; - _supports4KBPages = supports4KBPages; Base = baseMemory; Mirror = mirrorMemory; AddressSpaceSize = addressSpaceSize; } - public static bool TryCreate(MemoryBlock backingMemory, ulong asSize, bool supports4KBPages, out AddressSpace addressSpace) + public static bool TryCreate(MemoryBlock backingMemory, ulong asSize, out AddressSpace addressSpace) { addressSpace = null; @@ -193,7 +39,7 @@ namespace Ryujinx.Cpu { baseMemory = new MemoryBlock(addressSpaceSize, AsFlags); mirrorMemory = new MemoryBlock(addressSpaceSize, AsFlags); - addressSpace = new AddressSpace(backingMemory, baseMemory, mirrorMemory, addressSpaceSize, supports4KBPages); + addressSpace = new AddressSpace(backingMemory, baseMemory, mirrorMemory, addressSpaceSize); break; } @@ -209,289 +55,20 @@ namespace Ryujinx.Cpu public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags) { - if (_supports4KBPages) - { - Base.MapView(_backingMemory, pa, va, size); - Mirror.MapView(_backingMemory, pa, va, size); - - return; - } - - lock (_treeLock) - { - ulong alignment = MemoryBlock.GetPageSize(); - bool isAligned = ((va | pa | size) & (alignment - 1)) == 0; - - if (flags.HasFlag(MemoryMapFlags.Private) && !isAligned) - { - Update(va, pa, size, MappingType.Private); - } - else - { - // The update method assumes that shared mappings are already aligned. - - if (!flags.HasFlag(MemoryMapFlags.Private)) - { - if ((va & (alignment - 1)) != (pa & (alignment - 1))) - { - throw new InvalidMemoryRegionException($"Virtual address 0x{va:X} and physical address 0x{pa:X} are misaligned and can't be aligned."); - } - - ulong endAddress = va + size; - va = BitUtils.AlignDown(va, alignment); - pa = BitUtils.AlignDown(pa, alignment); - size = BitUtils.AlignUp(endAddress, alignment) - va; - } - - Update(va, pa, size, MappingType.Shared); - } - } + Base.MapView(_backingMemory, pa, va, size); + Mirror.MapView(_backingMemory, pa, va, size); } public void Unmap(ulong va, ulong size) { - if (_supports4KBPages) - { - Base.UnmapView(_backingMemory, va, size); - Mirror.UnmapView(_backingMemory, va, size); - - return; - } - - lock (_treeLock) - { - Update(va, 0UL, size, MappingType.None); - } - } - - private void Update(ulong va, ulong pa, ulong size, MappingType type) - { - Mapping map = _mappingTree.GetNode(new Mapping(va, 1UL, MappingType.None)); - - Update(map, va, pa, size, type); - } - - private Mapping Update(Mapping map, ulong va, ulong pa, ulong size, MappingType type) - { - ulong endAddress = va + size; - - for (; map != null; map = map.Successor) - { - if (map.Address < va) - { - _mappingTree.Add(map.Split(va)); - } - - if (map.EndAddress > endAddress) - { - Mapping newMap = map.Split(endAddress); - _mappingTree.Add(newMap); - map = newMap; - } - - switch (type) - { - case MappingType.None: - if (map.Type == MappingType.Shared) - { - ulong startOffset = map.Address - va; - ulong mapVa = va + startOffset; - ulong mapSize = Math.Min(size - startOffset, map.Size); - ulong mapEndAddress = mapVa + mapSize; - ulong alignment = MemoryBlock.GetPageSize(); - - mapVa = BitUtils.AlignDown(mapVa, alignment); - mapEndAddress = BitUtils.AlignUp(mapEndAddress, alignment); - - mapSize = mapEndAddress - mapVa; - - Base.UnmapView(_backingMemory, mapVa, mapSize); - Mirror.UnmapView(_backingMemory, mapVa, mapSize); - } - else - { - UnmapPrivate(va, size); - } - break; - case MappingType.Private: - if (map.Type == MappingType.Shared) - { - throw new InvalidMemoryRegionException($"Private mapping request at 0x{va:X} with size 0x{size:X} overlaps shared mapping at 0x{map.Address:X} with size 0x{map.Size:X}."); - } - else - { - MapPrivate(va, size); - } - break; - case MappingType.Shared: - if (map.Type != MappingType.None) - { - throw new InvalidMemoryRegionException($"Shared mapping request at 0x{va:X} with size 0x{size:X} overlaps mapping at 0x{map.Address:X} with size 0x{map.Size:X}."); - } - else - { - ulong startOffset = map.Address - va; - ulong mapPa = pa + startOffset; - ulong mapVa = va + startOffset; - ulong mapSize = Math.Min(size - startOffset, map.Size); - - Base.MapView(_backingMemory, mapPa, mapVa, mapSize); - Mirror.MapView(_backingMemory, mapPa, mapVa, mapSize); - } - break; - } - - map.UpdateState(type); - map = TryCoalesce(map); - - if (map.EndAddress >= endAddress) - { - break; - } - } - - return map; - } - - private Mapping TryCoalesce(Mapping map) - { - Mapping previousMap = map.Predecessor; - Mapping nextMap = map.Successor; - - if (previousMap != null && CanCoalesce(previousMap, map)) - { - previousMap.Extend(map.Size); - _mappingTree.Remove(map); - map = previousMap; - } - - if (nextMap != null && CanCoalesce(map, nextMap)) - { - map.Extend(nextMap.Size); - _mappingTree.Remove(nextMap); - } - - return map; - } - - private static bool CanCoalesce(Mapping left, Mapping right) - { - return left.Type == right.Type; - } - - private void MapPrivate(ulong va, ulong size) - { - ulong endAddress = va + size; - - ulong alignment = MemoryBlock.GetPageSize(); - - // Expand the range outwards based on page size to ensure that at least the requested region is mapped. - ulong vaAligned = BitUtils.AlignDown(va, alignment); - ulong endAddressAligned = BitUtils.AlignUp(endAddress, alignment); - - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default)); - - for (; map != null; map = map.Successor) - { - if (!map.PrivateAllocation.IsValid) - { - if (map.Address < vaAligned) - { - _privateTree.Add(map.Split(vaAligned)); - } - - if (map.EndAddress > endAddressAligned) - { - PrivateMapping newMap = map.Split(endAddressAligned); - _privateTree.Add(newMap); - map = newMap; - } - - map.Map(Base, Mirror, _privateMemoryAllocator.Allocate(map.Size, MemoryBlock.GetPageSize())); - } - - if (map.EndAddress >= endAddressAligned) - { - break; - } - } - } - - private void UnmapPrivate(ulong va, ulong size) - { - ulong endAddress = va + size; - - ulong alignment = MemoryBlock.GetPageSize(); - - // Shrink the range inwards based on page size to ensure we won't unmap memory that might be still in use. - ulong vaAligned = BitUtils.AlignUp(va, alignment); - ulong endAddressAligned = BitUtils.AlignDown(endAddress, alignment); - - if (endAddressAligned <= vaAligned) - { - return; - } - - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default)); - - for (; map != null; map = map.Successor) - { - if (map.PrivateAllocation.IsValid) - { - if (map.Address < vaAligned) - { - _privateTree.Add(map.Split(vaAligned)); - } - - if (map.EndAddress > endAddressAligned) - { - PrivateMapping newMap = map.Split(endAddressAligned); - _privateTree.Add(newMap); - map = newMap; - } - - map.Unmap(Base, Mirror); - map = TryCoalesce(map); - } - - if (map.EndAddress >= endAddressAligned) - { - break; - } - } - } - - private PrivateMapping TryCoalesce(PrivateMapping map) - { - PrivateMapping previousMap = map.Predecessor; - PrivateMapping nextMap = map.Successor; - - if (previousMap != null && CanCoalesce(previousMap, map)) - { - previousMap.Extend(map.Size); - _privateTree.Remove(map); - map = previousMap; - } - - if (nextMap != null && CanCoalesce(map, nextMap)) - { - map.Extend(nextMap.Size); - _privateTree.Remove(nextMap); - } - - return map; - } - - private static bool CanCoalesce(PrivateMapping left, PrivateMapping right) - { - return !left.PrivateAllocation.IsValid && !right.PrivateAllocation.IsValid; + Base.UnmapView(_backingMemory, va, size); + Mirror.UnmapView(_backingMemory, va, size); } public void Dispose() { GC.SuppressFinalize(this); - _privateMemoryAllocator?.Dispose(); Base.Dispose(); Mirror.Dispose(); } diff --git a/src/Ryujinx.Cpu/AppleHv/HvCodePatcher.cs b/src/Ryujinx.Cpu/AppleHv/HvCodePatcher.cs deleted file mode 100644 index 876597b78..000000000 --- a/src/Ryujinx.Cpu/AppleHv/HvCodePatcher.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; - -namespace Ryujinx.Cpu.AppleHv -{ - static class HvCodePatcher - { - private const uint XMask = 0x3f808000u; - private const uint XValue = 0x8000000u; - - private const uint ZrIndex = 31u; - - public static void RewriteUnorderedExclusiveInstructions(Span code) - { - Span codeUint = MemoryMarshal.Cast(code); - Span> codeVector = MemoryMarshal.Cast>(code); - - Vector128 mask = Vector128.Create(XMask); - Vector128 value = Vector128.Create(XValue); - - for (int index = 0; index < codeVector.Length; index++) - { - Vector128 v = codeVector[index]; - - if (Vector128.EqualsAny(Vector128.BitwiseAnd(v, mask), value)) - { - int baseIndex = index * 4; - - for (int instIndex = baseIndex; instIndex < baseIndex + 4; instIndex++) - { - ref uint inst = ref codeUint[instIndex]; - - if ((inst & XMask) != XValue) - { - continue; - } - - bool isPair = (inst & (1u << 21)) != 0; - bool isLoad = (inst & (1u << 22)) != 0; - - uint rt2 = (inst >> 10) & 0x1fu; - uint rs = (inst >> 16) & 0x1fu; - - if (isLoad && rs != ZrIndex) - { - continue; - } - - if (!isPair && rt2 != ZrIndex) - { - continue; - } - - // Set the ordered flag. - inst |= 1u << 15; - } - } - } - } - } -} diff --git a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs index fff5f2030..f54259e37 100644 --- a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs +++ b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs @@ -3,12 +3,11 @@ using Ryujinx.Memory; using Ryujinx.Memory.Range; using Ryujinx.Memory.Tracking; using System; +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Runtime.Versioning; -using System.Threading; namespace Ryujinx.Cpu.AppleHv { @@ -17,31 +16,10 @@ namespace Ryujinx.Cpu.AppleHv /// [SupportedOSPlatform("macos")] [SupportedOSPlatform("ios")] - public class HvMemoryManager : MemoryManagerBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock + public sealed class HvMemoryManager : VirtualMemoryManagerRefCountedBase, IMemoryManager, IVirtualMemoryManagerTracked { - public const int PageBits = 12; - public const int PageSize = 1 << PageBits; - public const int PageMask = PageSize - 1; - - public const int PageToPteShift = 5; // 32 pages (2 bits each) in one ulong page table entry. - public const ulong BlockMappedMask = 0x5555555555555555; // First bit of each table entry set. - - private enum HostMappedPtBits : ulong - { - Unmapped = 0, - Mapped, - WriteTracked, - ReadWriteTracked, - - MappedReplicated = 0x5555555555555555, - WriteTrackedReplicated = 0xaaaaaaaaaaaaaaaa, - ReadWriteTrackedReplicated = ulong.MaxValue, - } - private readonly InvalidAccessHandler _invalidAccessHandler; - private readonly ulong _addressSpaceSize; - private readonly HvAddressSpace _addressSpace; internal HvAddressSpace AddressSpace => _addressSpace; @@ -49,9 +27,9 @@ namespace Ryujinx.Cpu.AppleHv private readonly MemoryBlock _backingMemory; private readonly PageTable _pageTable; - private readonly ulong[] _pageBitmap; + private readonly ManagedPageFlags _pages; - public bool Supports4KBPages => true; + public bool UsesPrivateAllocations => false; public int AddressSpaceBits { get; } @@ -63,6 +41,8 @@ namespace Ryujinx.Cpu.AppleHv public event Action UnmapEvent; + protected override ulong AddressSpaceSize { get; } + /// /// Creates a new instance of the Hypervisor memory manager. /// @@ -74,7 +54,7 @@ namespace Ryujinx.Cpu.AppleHv _backingMemory = backingMemory; _pageTable = new PageTable(); _invalidAccessHandler = invalidAccessHandler; - _addressSpaceSize = addressSpaceSize; + AddressSpaceSize = addressSpaceSize; ulong asSize = PageSize; int asBits = PageBits; @@ -89,46 +69,10 @@ namespace Ryujinx.Cpu.AppleHv AddressSpaceBits = asBits; - _pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))]; + _pages = new ManagedPageFlags(AddressSpaceBits); Tracking = new MemoryTracking(this, PageSize, invalidAccessHandler); } - /// - /// Checks if the virtual address is part of the addressable space. - /// - /// Virtual address - /// True if the virtual address is part of the addressable space - private bool ValidateAddress(ulong va) - { - return va < _addressSpaceSize; - } - - /// - /// Checks if the combination of virtual address and size is part of the addressable space. - /// - /// Virtual address of the range - /// Size of the range in bytes - /// True if the combination of virtual address and size is part of the addressable space - private bool ValidateAddressAndSize(ulong va, ulong size) - { - ulong endVa = va + size; - return endVa >= va && endVa >= size && endVa <= _addressSpaceSize; - } - - /// - /// Ensures the combination of virtual address and size is part of the addressable space. - /// - /// Virtual address of the range - /// Size of the range in bytes - /// Throw when the memory region specified outside the addressable space - private void AssertValidAddressAndSize(ulong va, ulong size) - { - if (!ValidateAddressAndSize(va, size)) - { - throw new InvalidMemoryRegionException($"va=0x{va:X16}, size=0x{size:X16}"); - } - } - /// public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags) { @@ -136,7 +80,7 @@ namespace Ryujinx.Cpu.AppleHv PtMap(va, pa, size); _addressSpace.MapUser(va, pa, size, MemoryPermission.ReadWriteExecute); - AddMapping(va, size); + _pages.AddMapping(va, size); Tracking.Map(va, size); } @@ -153,12 +97,6 @@ namespace Ryujinx.Cpu.AppleHv } } - /// - public void MapForeign(ulong va, nuint hostPointer, ulong size) - { - throw new NotSupportedException(); - } - /// public void Unmap(ulong va, ulong size) { @@ -167,7 +105,7 @@ namespace Ryujinx.Cpu.AppleHv UnmapEvent?.Invoke(va, size); Tracking.Unmap(va, size); - RemoveMapping(va, size); + _pages.RemoveMapping(va, size); _addressSpace.UnmapUser(va, size); PtUnmap(va, size); } @@ -183,20 +121,11 @@ namespace Ryujinx.Cpu.AppleHv } } - /// - public T Read(ulong va) where T : unmanaged - { - return MemoryMarshal.Cast(GetSpan(va, Unsafe.SizeOf()))[0]; - } - - /// - public T ReadTracked(ulong va) where T : unmanaged + public override T ReadTracked(ulong va) { try { - SignalMemoryTracking(va, (ulong)Unsafe.SizeOf(), false); - - return Read(va); + return base.ReadTracked(va); } catch (InvalidMemoryRegionException) { @@ -209,107 +138,11 @@ namespace Ryujinx.Cpu.AppleHv } } - /// - public void Read(ulong va, Span data) - { - ReadImpl(va, data); - } - - /// - public void Write(ulong va, T value) where T : unmanaged - { - Write(va, MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref value, 1))); - } - - /// - public void Write(ulong va, ReadOnlySpan data) - { - if (data.Length == 0) - { - return; - } - - SignalMemoryTracking(va, (ulong)data.Length, true); - - WriteImpl(va, data); - } - - /// - public void WriteUntracked(ulong va, ReadOnlySpan data) - { - if (data.Length == 0) - { - return; - } - - WriteImpl(va, data); - } - - /// - public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan data) - { - if (data.Length == 0) - { - return false; - } - - SignalMemoryTracking(va, (ulong)data.Length, false); - - if (IsContiguousAndMapped(va, data.Length)) - { - var target = _backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length); - - bool changed = !data.SequenceEqual(target); - - if (changed) - { - data.CopyTo(target); - } - - return changed; - } - else - { - WriteImpl(va, data); - - return true; - } - } - - private void WriteImpl(ulong va, ReadOnlySpan data) + public override void Read(ulong va, Span data) { try { - AssertValidAddressAndSize(va, (ulong)data.Length); - - if (IsContiguousAndMapped(va, data.Length)) - { - data.CopyTo(_backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length)); - } - else - { - int offset = 0, size; - - if ((va & PageMask) != 0) - { - ulong pa = GetPhysicalAddressChecked(va); - - size = Math.Min(data.Length, PageSize - (int)(va & PageMask)); - - data[..size].CopyTo(_backingMemory.GetSpan(pa, size)); - - offset += size; - } - - for (; offset < data.Length; offset += size) - { - ulong pa = GetPhysicalAddressChecked(va + (ulong)offset); - - size = Math.Min(data.Length - offset, PageSize); - - data.Slice(offset, size).CopyTo(_backingMemory.GetSpan(pa, size)); - } - } + base.Read(va, data); } catch (InvalidMemoryRegionException) { @@ -320,61 +153,53 @@ namespace Ryujinx.Cpu.AppleHv } } - /// - public ReadOnlySpan GetSpan(ulong va, int size, bool tracked = false) + public override void Write(ulong va, ReadOnlySpan data) { - if (size == 0) + try { - return ReadOnlySpan.Empty; + base.Write(va, data); } - - if (tracked) + catch (InvalidMemoryRegionException) { - SignalMemoryTracking(va, (ulong)size, false); - } - - if (IsContiguousAndMapped(va, size)) - { - return _backingMemory.GetSpan(GetPhysicalAddressInternal(va), size); - } - else - { - Span data = new byte[size]; - - ReadImpl(va, data); - - return data; + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } } } - /// - public WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) + public override void WriteUntracked(ulong va, ReadOnlySpan data) { - if (size == 0) + try { - return new WritableRegion(null, va, Memory.Empty); + base.WriteUntracked(va, data); } - - if (tracked) + catch (InvalidMemoryRegionException) { - SignalMemoryTracking(va, (ulong)size, true); - } - - if (IsContiguousAndMapped(va, size)) - { - return new WritableRegion(null, va, _backingMemory.GetMemory(GetPhysicalAddressInternal(va), size)); - } - else - { - Memory memory = new byte[size]; - - ReadImpl(va, memory.Span); - - return new WritableRegion(this, va, memory); + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } + } + } + + public override ReadOnlySequence GetReadOnlySequence(ulong va, int size, bool tracked = false) + { + try + { + return base.GetReadOnlySequence(va, size, tracked); + } + catch (InvalidMemoryRegionException) + { + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } + + return ReadOnlySequence.Empty; } } - /// public ref T GetRef(ulong va) where T : unmanaged { if (!IsContiguous(va, Unsafe.SizeOf())) @@ -387,26 +212,10 @@ namespace Ryujinx.Cpu.AppleHv return ref _backingMemory.GetRef(GetPhysicalAddressChecked(va)); } - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsMapped(ulong va) + public override bool IsMapped(ulong va) { - return ValidateAddress(va) && IsMappedImpl(va); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsMappedImpl(ulong va) - { - ulong page = va >> PageBits; - - int bit = (int)((page & 31) << 1); - - int pageIndex = (int)(page >> PageToPteShift); - ref ulong pageRef = ref _pageBitmap[pageIndex]; - - ulong pte = Volatile.Read(ref pageRef); - - return ((pte >> bit) & 3) != 0; + return ValidateAddress(va) && _pages.IsMapped(va); } /// @@ -414,91 +223,7 @@ namespace Ryujinx.Cpu.AppleHv { AssertValidAddressAndSize(va, size); - return IsRangeMappedImpl(va, size); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void GetPageBlockRange(ulong pageStart, ulong pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex) - { - startMask = ulong.MaxValue << ((int)(pageStart & 31) << 1); - endMask = ulong.MaxValue >> (64 - ((int)(pageEnd & 31) << 1)); - - pageIndex = (int)(pageStart >> PageToPteShift); - pageEndIndex = (int)((pageEnd - 1) >> PageToPteShift); - } - - private bool IsRangeMappedImpl(ulong va, ulong size) - { - int pages = GetPagesCount(va, size, out _); - - if (pages == 1) - { - return IsMappedImpl(va); - } - - ulong pageStart = va >> PageBits; - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - // Check if either bit in each 2 bit page entry is set. - // OR the block with itself shifted down by 1, and check the first bit of each entry. - - ulong mask = BlockMappedMask & startMask; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - ulong pte = Volatile.Read(ref pageRef); - - pte |= pte >> 1; - if ((pte & mask) != mask) - { - return false; - } - - mask = BlockMappedMask; - } - - return true; - } - - private static void ThrowMemoryNotContiguous() => throw new MemoryNotContiguousException(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsContiguousAndMapped(ulong va, int size) => IsContiguous(va, size) && IsMapped(va); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsContiguous(ulong va, int size) - { - if (!ValidateAddress(va) || !ValidateAddressAndSize(va, (ulong)size)) - { - return false; - } - - int pages = GetPagesCount(va, (uint)size, out va); - - for (int page = 0; page < pages - 1; page++) - { - if (!ValidateAddress(va + PageSize)) - { - return false; - } - - if (GetPhysicalAddressInternal(va) + PageSize != GetPhysicalAddressInternal(va + PageSize)) - { - return false; - } - - va += PageSize; - } - - return true; + return _pages.IsRangeMapped(va, size); } /// @@ -577,53 +302,10 @@ namespace Ryujinx.Cpu.AppleHv return regions; } - private void ReadImpl(ulong va, Span data) - { - if (data.Length == 0) - { - return; - } - - try - { - AssertValidAddressAndSize(va, (ulong)data.Length); - - int offset = 0, size; - - if ((va & PageMask) != 0) - { - ulong pa = GetPhysicalAddressChecked(va); - - size = Math.Min(data.Length, PageSize - (int)(va & PageMask)); - - _backingMemory.GetSpan(pa, size).CopyTo(data[..size]); - - offset += size; - } - - for (; offset < data.Length; offset += size) - { - ulong pa = GetPhysicalAddressChecked(va + (ulong)offset); - - size = Math.Min(data.Length - offset, PageSize); - - _backingMemory.GetSpan(pa, size).CopyTo(data.Slice(offset, size)); - } - } - catch (InvalidMemoryRegionException) - { - if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) - { - throw; - } - } - } - - /// /// /// This function also validates that the given range is both valid and mapped, and will throw if it is not. /// - public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) + public override void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) { AssertValidAddressAndSize(va, size); @@ -633,211 +315,37 @@ namespace Ryujinx.Cpu.AppleHv return; } - // Software table, used for managed memory tracking. - - int pages = GetPagesCount(va, size, out _); - ulong pageStart = va >> PageBits; - - if (pages == 1) - { - ulong tag = (ulong)(write ? HostMappedPtBits.WriteTracked : HostMappedPtBits.ReadWriteTracked); - - int bit = (int)((pageStart & 31) << 1); - - int pageIndex = (int)(pageStart >> PageToPteShift); - ref ulong pageRef = ref _pageBitmap[pageIndex]; - - ulong pte = Volatile.Read(ref pageRef); - ulong state = ((pte >> bit) & 3); - - if (state >= tag) - { - Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId); - return; - } - else if (state == 0) - { - ThrowInvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}"); - } - } - else - { - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - ulong mask = startMask; - - ulong anyTrackingTag = (ulong)HostMappedPtBits.WriteTrackedReplicated; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - - ulong pte = Volatile.Read(ref pageRef); - ulong mappedMask = mask & BlockMappedMask; - - ulong mappedPte = pte | (pte >> 1); - if ((mappedPte & mappedMask) != mappedMask) - { - ThrowInvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}"); - } - - pte &= mask; - if ((pte & anyTrackingTag) != 0) // Search for any tracking. - { - // Writes trigger any tracking. - // Only trigger tracking from reads if both bits are set on any page. - if (write || (pte & (pte >> 1) & BlockMappedMask) != 0) - { - Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId); - break; - } - } - - mask = ulong.MaxValue; - } - } + _pages.SignalMemoryTracking(Tracking, va, size, write, exemptId); } - /// - /// Computes the number of pages in a virtual address range. - /// - /// Virtual address of the range - /// Size of the range - /// The virtual address of the beginning of the first page - /// This function does not differentiate between allocated and unallocated pages. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetPagesCount(ulong va, ulong size, out ulong startVa) - { - // WARNING: Always check if ulong does not overflow during the operations. - startVa = va & ~(ulong)PageMask; - ulong vaSpan = (va - startVa + size + PageMask) & ~(ulong)PageMask; - - return (int)(vaSpan / PageSize); - } - - /// public void Reprotect(ulong va, ulong size, MemoryPermission protection) { - if (protection.HasFlag(MemoryPermission.Execute)) - { - // Some applications use unordered exclusive memory access instructions - // where it is not valid to do so, leading to memory re-ordering that - // makes the code behave incorrectly on some CPUs. - // To work around this, we force all such accesses to be ordered. - - using WritableRegion writableRegion = GetWritableRegion(va, (int)size); - - HvCodePatcher.RewriteUnorderedExclusiveInstructions(writableRegion.Memory.Span); - } - // TODO } /// - public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection) + public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection, bool guest) { - // Protection is inverted on software pages, since the default value is 0. - protection = (~protection) & MemoryPermission.ReadAndWrite; - - int pages = GetPagesCount(va, size, out va); - ulong pageStart = va >> PageBits; - - if (pages == 1) + if (guest) { - ulong protTag = protection switch - { - MemoryPermission.None => (ulong)HostMappedPtBits.Mapped, - MemoryPermission.Write => (ulong)HostMappedPtBits.WriteTracked, - _ => (ulong)HostMappedPtBits.ReadWriteTracked, - }; - - int bit = (int)((pageStart & 31) << 1); - - ulong tagMask = 3UL << bit; - ulong invTagMask = ~tagMask; - - ulong tag = protTag << bit; - - int pageIndex = (int)(pageStart >> PageToPteShift); - ref ulong pageRef = ref _pageBitmap[pageIndex]; - - ulong pte; - - do - { - pte = Volatile.Read(ref pageRef); - } - while ((pte & tagMask) != 0 && Interlocked.CompareExchange(ref pageRef, (pte & invTagMask) | tag, pte) != pte); + _addressSpace.ReprotectUser(va, size, protection); } else { - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - ulong mask = startMask; - - ulong protTag = protection switch - { - MemoryPermission.None => (ulong)HostMappedPtBits.MappedReplicated, - MemoryPermission.Write => (ulong)HostMappedPtBits.WriteTrackedReplicated, - _ => (ulong)HostMappedPtBits.ReadWriteTrackedReplicated, - }; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - - ulong pte; - ulong mappedMask; - - // Change the protection of all 2 bit entries that are mapped. - do - { - pte = Volatile.Read(ref pageRef); - - mappedMask = pte | (pte >> 1); - mappedMask |= (mappedMask & BlockMappedMask) << 1; - mappedMask &= mask; // Only update mapped pages within the given range. - } - while (Interlocked.CompareExchange(ref pageRef, (pte & (~mappedMask)) | (protTag & mappedMask), pte) != pte); - - mask = ulong.MaxValue; - } + _pages.TrackingReprotect(va, size, protection); } - - protection = protection switch - { - MemoryPermission.None => MemoryPermission.ReadAndWrite, - MemoryPermission.Write => MemoryPermission.Read, - _ => MemoryPermission.None, - }; - - _addressSpace.ReprotectUser(va, size, protection); } /// - public RegionHandle BeginTracking(ulong address, ulong size, int id) + public RegionHandle BeginTracking(ulong address, ulong size, int id, RegionFlags flags = RegionFlags.None) { - return Tracking.BeginTracking(address, size, id); + return Tracking.BeginTracking(address, size, id, flags); } /// - public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id) + public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id, RegionFlags flags = RegionFlags.None) { - return Tracking.BeginGranularTracking(address, size, handles, granularity, id); + return Tracking.BeginGranularTracking(address, size, handles, granularity, id, flags); } /// @@ -846,87 +354,7 @@ namespace Ryujinx.Cpu.AppleHv return Tracking.BeginSmartGranularTracking(address, size, granularity, id); } - /// - /// Adds the given address mapping to the page table. - /// - /// Virtual memory address - /// Size to be mapped - private void AddMapping(ulong va, ulong size) - { - int pages = GetPagesCount(va, size, out _); - ulong pageStart = va >> PageBits; - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - ulong mask = startMask; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - - ulong pte; - ulong mappedMask; - - // Map all 2-bit entries that are unmapped. - do - { - pte = Volatile.Read(ref pageRef); - - mappedMask = pte | (pte >> 1); - mappedMask |= (mappedMask & BlockMappedMask) << 1; - mappedMask |= ~mask; // Treat everything outside the range as mapped, thus unchanged. - } - while (Interlocked.CompareExchange(ref pageRef, (pte & mappedMask) | (BlockMappedMask & (~mappedMask)), pte) != pte); - - mask = ulong.MaxValue; - } - } - - /// - /// Removes the given address mapping from the page table. - /// - /// Virtual memory address - /// Size to be unmapped - private void RemoveMapping(ulong va, ulong size) - { - int pages = GetPagesCount(va, size, out _); - ulong pageStart = va >> PageBits; - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - startMask = ~startMask; - endMask = ~endMask; - - ulong mask = startMask; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask |= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - ulong pte; - - do - { - pte = Volatile.Read(ref pageRef); - } - while (Interlocked.CompareExchange(ref pageRef, pte & mask, pte) != pte); - - mask = 0; - } - } - - private ulong GetPhysicalAddressChecked(ulong va) + private nuint GetPhysicalAddressChecked(ulong va) { if (!IsMapped(va)) { @@ -936,9 +364,9 @@ namespace Ryujinx.Cpu.AppleHv return GetPhysicalAddressInternal(va); } - private ulong GetPhysicalAddressInternal(ulong va) + private nuint GetPhysicalAddressInternal(ulong va) { - return _pageTable.Read(va) + (va & PageMask); + return (nuint)(_pageTable.Read(va) + (va & PageMask)); } /// @@ -949,6 +377,17 @@ namespace Ryujinx.Cpu.AppleHv _addressSpace.Dispose(); } - private static void ThrowInvalidMemoryRegionException(string message) => throw new InvalidMemoryRegionException(message); + protected override Memory GetPhysicalAddressMemory(nuint pa, int size) + => _backingMemory.GetMemory(pa, size); + + protected override Span GetPhysicalAddressSpan(nuint pa, int size) + => _backingMemory.GetSpan(pa, size); + + protected override nuint TranslateVirtualAddressChecked(ulong va) + => GetPhysicalAddressChecked(va); + + protected override nuint TranslateVirtualAddressUnchecked(ulong va) + => GetPhysicalAddressInternal(va); + } } diff --git a/src/Ryujinx.Cpu/IVirtualMemoryManagerTracked.cs b/src/Ryujinx.Cpu/IVirtualMemoryManagerTracked.cs index 199bff240..e8d11ede5 100644 --- a/src/Ryujinx.Cpu/IVirtualMemoryManagerTracked.cs +++ b/src/Ryujinx.Cpu/IVirtualMemoryManagerTracked.cs @@ -28,8 +28,9 @@ namespace Ryujinx.Cpu /// CPU virtual address of the region /// Size of the region /// Handle ID + /// Region flags /// The memory tracking handle - RegionHandle BeginTracking(ulong address, ulong size, int id); + RegionHandle BeginTracking(ulong address, ulong size, int id, RegionFlags flags = RegionFlags.None); /// /// Obtains a memory tracking handle for the given virtual region, with a specified granularity. This should be disposed when finished with. @@ -39,8 +40,9 @@ namespace Ryujinx.Cpu /// Handles to inherit state from or reuse. When none are present, provide null /// Desired granularity of write tracking /// Handle ID + /// Region flags /// The memory tracking handle - MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id); + MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id, RegionFlags flags = RegionFlags.None); /// /// Obtains a smart memory tracking handle for the given virtual region, with a specified granularity. This should be disposed when finished with. diff --git a/src/Ryujinx.Cpu/Jit/AddressSpacePartitionAllocator.cs b/src/Ryujinx.Cpu/Jit/AddressSpacePartitionAllocator.cs index 244639457..7fa085737 100644 --- a/src/Ryujinx.Cpu/Jit/AddressSpacePartitionAllocator.cs +++ b/src/Ryujinx.Cpu/Jit/AddressSpacePartitionAllocator.cs @@ -133,28 +133,34 @@ namespace Ryujinx.Cpu.Jit _mappingTree.Remove(_mappingTree.GetNode(offset)); } - private bool VirtualMemoryEvent(ulong address, ulong size, bool write) + private ulong VirtualMemoryEvent(ulong address, ulong size, bool write) { Mapping map; - + lock (_lock) { map = _mappingTree.GetNode(address); } - + if (map == null) { - return false; + return 0; // Return 0 instead of false } - + address -= map.Address; - + if (address >= (map.EndVa - map.Va)) { address -= (ulong)(map.BridgeSize / 2); } - - return _tracking.VirtualMemoryEvent(map.Va + address, size, write); + + // The original was returning a bool, now we need to return a ulong + if (_tracking.VirtualMemoryEvent(map.Va + address, size, write)) + { + return map.Va + address; + } + + return 0; // Return 0 on failure } public override void Destroy() diff --git a/src/Ryujinx.Cpu/Jit/HostTracked/AddressIntrusiveRedBlackTree.cs b/src/Ryujinx.Cpu/Jit/HostTracked/AddressIntrusiveRedBlackTree.cs new file mode 100644 index 000000000..0e2443303 --- /dev/null +++ b/src/Ryujinx.Cpu/Jit/HostTracked/AddressIntrusiveRedBlackTree.cs @@ -0,0 +1,35 @@ +using Ryujinx.Common.Collections; +using System; + +namespace Ryujinx.Cpu.Jit.HostTracked +{ + internal class AddressIntrusiveRedBlackTree : IntrusiveRedBlackTree where T : IntrusiveRedBlackTreeNode, IComparable, IComparable + { + /// + /// Retrieve the node that is considered equal to the specified address by the comparator. + /// + /// Address to compare with + /// Node that is equal to + public T GetNode(ulong address) + { + T node = Root; + while (node != null) + { + int cmp = node.CompareTo(address); + if (cmp < 0) + { + node = node.Left; + } + else if (cmp > 0) + { + node = node.Right; + } + else + { + return node; + } + } + return null; + } + } +} diff --git a/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartition.cs b/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartition.cs new file mode 100644 index 000000000..224c5edc3 --- /dev/null +++ b/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartition.cs @@ -0,0 +1,708 @@ +using Ryujinx.Common; +using Ryujinx.Common.Collections; +using Ryujinx.Memory; +using System; +using System.Diagnostics; +using System.Threading; + +namespace Ryujinx.Cpu.Jit.HostTracked +{ + readonly struct PrivateRange + { + public readonly MemoryBlock Memory; + public readonly ulong Offset; + public readonly ulong Size; + + public static PrivateRange Empty => new(null, 0, 0); + + public PrivateRange(MemoryBlock memory, ulong offset, ulong size) + { + Memory = memory; + Offset = offset; + Size = size; + } + } + + class AddressSpacePartition : IDisposable + { + public const ulong GuestPageSize = 0x1000; + + private const int DefaultBlockAlignment = 1 << 20; + + private enum MappingType : byte + { + None, + Private, + } + + private class Mapping : IntrusiveRedBlackTreeNode, IComparable, IComparable + { + public ulong Address { get; private set; } + public ulong Size { get; private set; } + public ulong EndAddress => Address + Size; + public MappingType Type { get; private set; } + + public Mapping(ulong address, ulong size, MappingType type) + { + Address = address; + Size = size; + Type = type; + } + + public Mapping Split(ulong splitAddress) + { + ulong leftSize = splitAddress - Address; + ulong rightSize = EndAddress - splitAddress; + + Mapping left = new(Address, leftSize, Type); + + Address = splitAddress; + Size = rightSize; + + return left; + } + + public void UpdateState(MappingType newType) + { + Type = newType; + } + + public void Extend(ulong sizeDelta) + { + Size += sizeDelta; + } + + public int CompareTo(Mapping other) + { + if (Address < other.Address) + { + return -1; + } + else if (Address <= other.EndAddress - 1UL) + { + return 0; + } + else + { + return 1; + } + } + + public int CompareTo(ulong address) + { + if (address < Address) + { + return -1; + } + else if (address <= EndAddress - 1UL) + { + return 0; + } + else + { + return 1; + } + } + } + + private class PrivateMapping : IntrusiveRedBlackTreeNode, IComparable, IComparable + { + public ulong Address { get; private set; } + public ulong Size { get; private set; } + public ulong EndAddress => Address + Size; + public PrivateMemoryAllocation PrivateAllocation { get; private set; } + + public PrivateMapping(ulong address, ulong size, PrivateMemoryAllocation privateAllocation) + { + Address = address; + Size = size; + PrivateAllocation = privateAllocation; + } + + public PrivateMapping Split(ulong splitAddress) + { + ulong leftSize = splitAddress - Address; + ulong rightSize = EndAddress - splitAddress; + + Debug.Assert(leftSize > 0); + Debug.Assert(rightSize > 0); + + (var leftAllocation, PrivateAllocation) = PrivateAllocation.Split(leftSize); + + PrivateMapping left = new(Address, leftSize, leftAllocation); + + Address = splitAddress; + Size = rightSize; + + return left; + } + + public void Map(AddressSpacePartitionMultiAllocation baseBlock, ulong baseAddress, PrivateMemoryAllocation newAllocation) + { + baseBlock.MapView(newAllocation.Memory, newAllocation.Offset, Address - baseAddress, Size); + PrivateAllocation = newAllocation; + } + + public void Unmap(AddressSpacePartitionMultiAllocation baseBlock, ulong baseAddress) + { + if (PrivateAllocation.IsValid) + { + baseBlock.UnmapView(PrivateAllocation.Memory, Address - baseAddress, Size); + PrivateAllocation.Dispose(); + } + + PrivateAllocation = default; + } + + public void Extend(ulong sizeDelta) + { + Size += sizeDelta; + } + + public int CompareTo(PrivateMapping other) + { + if (Address < other.Address) + { + return -1; + } + else if (Address <= other.EndAddress - 1UL) + { + return 0; + } + else + { + return 1; + } + } + + public int CompareTo(ulong address) + { + if (address < Address) + { + return -1; + } + else if (address <= EndAddress - 1UL) + { + return 0; + } + else + { + return 1; + } + } + } + + private readonly MemoryBlock _backingMemory; + private readonly AddressSpacePartitionMultiAllocation _baseMemory; + private readonly PrivateMemoryAllocator _privateMemoryAllocator; + + private readonly AddressIntrusiveRedBlackTree _mappingTree; + private readonly AddressIntrusiveRedBlackTree _privateTree; + + private readonly ReaderWriterLockSlim _treeLock; + + private readonly ulong _hostPageSize; + + private ulong? _firstPagePa; + private ulong? _lastPagePa; + private ulong _cachedFirstPagePa; + private ulong _cachedLastPagePa; + private MemoryBlock _firstPageMemoryForUnmap; + private ulong _firstPageOffsetForLateMap; + private MemoryPermission _firstPageMemoryProtection; + + public ulong Address { get; } + public ulong Size { get; } + public ulong EndAddress => Address + Size; + + public AddressSpacePartition(AddressSpacePartitionAllocation baseMemory, MemoryBlock backingMemory, ulong address, ulong size) + { + _privateMemoryAllocator = new PrivateMemoryAllocator(DefaultBlockAlignment, MemoryAllocationFlags.Mirrorable); + _mappingTree = new AddressIntrusiveRedBlackTree(); + _privateTree = new AddressIntrusiveRedBlackTree(); + _treeLock = new ReaderWriterLockSlim(); + + _mappingTree.Add(new Mapping(address, size, MappingType.None)); + _privateTree.Add(new PrivateMapping(address, size, default)); + + _hostPageSize = MemoryBlock.GetPageSize(); + + _backingMemory = backingMemory; + _baseMemory = new(baseMemory); + + _cachedFirstPagePa = ulong.MaxValue; + _cachedLastPagePa = ulong.MaxValue; + + Address = address; + Size = size; + } + + public bool IsEmpty() + { + _treeLock.EnterReadLock(); + + try + { + Mapping map = _mappingTree.GetNode(Address); + + return map != null && map.Address == Address && map.Size == Size && map.Type == MappingType.None; + } + finally + { + _treeLock.ExitReadLock(); + } + } + + public void Map(ulong va, ulong pa, ulong size) + { + Debug.Assert(va >= Address); + Debug.Assert(va + size <= EndAddress); + + if (va == Address) + { + _firstPagePa = pa; + } + + if (va <= EndAddress - GuestPageSize && va + size > EndAddress - GuestPageSize) + { + _lastPagePa = pa + ((EndAddress - GuestPageSize) - va); + } + + Update(va, pa, size, MappingType.Private); + } + + public void Unmap(ulong va, ulong size) + { + Debug.Assert(va >= Address); + Debug.Assert(va + size <= EndAddress); + + if (va == Address) + { + _firstPagePa = null; + } + + if (va <= EndAddress - GuestPageSize && va + size > EndAddress - GuestPageSize) + { + _lastPagePa = null; + } + + Update(va, 0UL, size, MappingType.None); + } + + public void ReprotectAligned(ulong va, ulong size, MemoryPermission protection) + { + Debug.Assert(va >= Address); + Debug.Assert(va + size <= EndAddress); + + _baseMemory.Reprotect(va - Address, size, protection, false); + + if (va == Address) + { + _firstPageMemoryProtection = protection; + } + } + + public void Reprotect( + ulong va, + ulong size, + MemoryPermission protection, + AddressSpacePartitioned addressSpace, + Action updatePtCallback) + { + if (_baseMemory.LazyInitMirrorForProtection(addressSpace, Address, Size, protection)) + { + LateMap(); + } + + updatePtCallback(va, _baseMemory.GetPointerForProtection(va - Address, size, protection), size); + } + + public IntPtr GetPointer(ulong va, ulong size) + { + Debug.Assert(va >= Address); + Debug.Assert(va + size <= EndAddress); + + return _baseMemory.GetPointer(va - Address, size); + } + + public void InsertBridgeAtEnd(AddressSpacePartition partitionAfter, bool useProtectionMirrors) + { + ulong firstPagePa = partitionAfter?._firstPagePa ?? ulong.MaxValue; + ulong lastPagePa = _lastPagePa ?? ulong.MaxValue; + + if (firstPagePa != _cachedFirstPagePa || lastPagePa != _cachedLastPagePa) + { + if (partitionAfter != null && partitionAfter._firstPagePa.HasValue) + { + (MemoryBlock firstPageMemory, ulong firstPageOffset) = partitionAfter.GetFirstPageMemoryAndOffset(); + + _baseMemory.MapView(firstPageMemory, firstPageOffset, Size, _hostPageSize); + + if (!useProtectionMirrors) + { + _baseMemory.Reprotect(Size, _hostPageSize, partitionAfter._firstPageMemoryProtection, throwOnFail: false); + } + + _firstPageMemoryForUnmap = firstPageMemory; + _firstPageOffsetForLateMap = firstPageOffset; + } + else + { + MemoryBlock firstPageMemoryForUnmap = _firstPageMemoryForUnmap; + + if (firstPageMemoryForUnmap != null) + { + _baseMemory.UnmapView(firstPageMemoryForUnmap, Size, _hostPageSize); + _firstPageMemoryForUnmap = null; + } + } + + _cachedFirstPagePa = firstPagePa; + _cachedLastPagePa = lastPagePa; + } + } + + public void ReprotectBridge(MemoryPermission protection) + { + if (_firstPageMemoryForUnmap != null) + { + _baseMemory.Reprotect(Size, _hostPageSize, protection, throwOnFail: false); + } + } + + private (MemoryBlock, ulong) GetFirstPageMemoryAndOffset() + { + _treeLock.EnterReadLock(); + + try + { + PrivateMapping map = _privateTree.GetNode(Address); + + if (map != null && map.PrivateAllocation.IsValid) + { + return (map.PrivateAllocation.Memory, map.PrivateAllocation.Offset + (Address - map.Address)); + } + } + finally + { + _treeLock.ExitReadLock(); + } + + return (_backingMemory, _firstPagePa.Value); + } + + public PrivateRange GetPrivateAllocation(ulong va) + { + _treeLock.EnterReadLock(); + + try + { + PrivateMapping map = _privateTree.GetNode(va); + + if (map != null && map.PrivateAllocation.IsValid) + { + return new(map.PrivateAllocation.Memory, map.PrivateAllocation.Offset + (va - map.Address), map.Size - (va - map.Address)); + } + } + finally + { + _treeLock.ExitReadLock(); + } + + return PrivateRange.Empty; + } + + private void Update(ulong va, ulong pa, ulong size, MappingType type) + { + _treeLock.EnterWriteLock(); + + try + { + Mapping map = _mappingTree.GetNode(va); + + Update(map, va, pa, size, type); + } + finally + { + _treeLock.ExitWriteLock(); + } + } + + private Mapping Update(Mapping map, ulong va, ulong pa, ulong size, MappingType type) + { + ulong endAddress = va + size; + + for (; map != null; map = map.Successor) + { + if (map.Address < va) + { + _mappingTree.Add(map.Split(va)); + } + + if (map.EndAddress > endAddress) + { + Mapping newMap = map.Split(endAddress); + _mappingTree.Add(newMap); + map = newMap; + } + + switch (type) + { + case MappingType.None: + ulong alignment = _hostPageSize; + + bool unmappedBefore = map.Predecessor == null || + (map.Predecessor.Type == MappingType.None && map.Predecessor.Address <= BitUtils.AlignDown(va, alignment)); + + bool unmappedAfter = map.Successor == null || + (map.Successor.Type == MappingType.None && map.Successor.EndAddress >= BitUtils.AlignUp(endAddress, alignment)); + + UnmapPrivate(va, size, unmappedBefore, unmappedAfter); + break; + case MappingType.Private: + MapPrivate(va, size); + break; + } + + map.UpdateState(type); + map = TryCoalesce(map); + + if (map.EndAddress >= endAddress) + { + break; + } + } + + return map; + } + + private Mapping TryCoalesce(Mapping map) + { + Mapping previousMap = map.Predecessor; + Mapping nextMap = map.Successor; + + if (previousMap != null && CanCoalesce(previousMap, map)) + { + previousMap.Extend(map.Size); + _mappingTree.Remove(map); + map = previousMap; + } + + if (nextMap != null && CanCoalesce(map, nextMap)) + { + map.Extend(nextMap.Size); + _mappingTree.Remove(nextMap); + } + + return map; + } + + private static bool CanCoalesce(Mapping left, Mapping right) + { + return left.Type == right.Type; + } + + private void MapPrivate(ulong va, ulong size) + { + ulong endAddress = va + size; + + ulong alignment = _hostPageSize; + + // Expand the range outwards based on page size to ensure that at least the requested region is mapped. + ulong vaAligned = BitUtils.AlignDown(va, alignment); + ulong endAddressAligned = BitUtils.AlignUp(endAddress, alignment); + + PrivateMapping map = _privateTree.GetNode(va); + + for (; map != null; map = map.Successor) + { + if (!map.PrivateAllocation.IsValid) + { + if (map.Address < vaAligned) + { + _privateTree.Add(map.Split(vaAligned)); + } + + if (map.EndAddress > endAddressAligned) + { + PrivateMapping newMap = map.Split(endAddressAligned); + _privateTree.Add(newMap); + map = newMap; + } + + map.Map(_baseMemory, Address, _privateMemoryAllocator.Allocate(map.Size, _hostPageSize)); + } + + if (map.EndAddress >= endAddressAligned) + { + break; + } + } + } + + private void UnmapPrivate(ulong va, ulong size, bool unmappedBefore, bool unmappedAfter) + { + ulong endAddress = va + size; + + ulong alignment = _hostPageSize; + + // If the adjacent mappings are unmapped, expand the range outwards, + // otherwise shrink it inwards. We must ensure we won't unmap pages that might still be in use. + ulong vaAligned = unmappedBefore ? BitUtils.AlignDown(va, alignment) : BitUtils.AlignUp(va, alignment); + ulong endAddressAligned = unmappedAfter ? BitUtils.AlignUp(endAddress, alignment) : BitUtils.AlignDown(endAddress, alignment); + + if (endAddressAligned <= vaAligned) + { + return; + } + + PrivateMapping map = _privateTree.GetNode(vaAligned); + + for (; map != null; map = map.Successor) + { + if (map.PrivateAllocation.IsValid) + { + if (map.Address < vaAligned) + { + _privateTree.Add(map.Split(vaAligned)); + } + + if (map.EndAddress > endAddressAligned) + { + PrivateMapping newMap = map.Split(endAddressAligned); + _privateTree.Add(newMap); + map = newMap; + } + + map.Unmap(_baseMemory, Address); + map = TryCoalesce(map); + } + + if (map.EndAddress >= endAddressAligned) + { + break; + } + } + } + + private PrivateMapping TryCoalesce(PrivateMapping map) + { + PrivateMapping previousMap = map.Predecessor; + PrivateMapping nextMap = map.Successor; + + if (previousMap != null && CanCoalesce(previousMap, map)) + { + previousMap.Extend(map.Size); + _privateTree.Remove(map); + map = previousMap; + } + + if (nextMap != null && CanCoalesce(map, nextMap)) + { + map.Extend(nextMap.Size); + _privateTree.Remove(nextMap); + } + + return map; + } + + private static bool CanCoalesce(PrivateMapping left, PrivateMapping right) + { + return !left.PrivateAllocation.IsValid && !right.PrivateAllocation.IsValid; + } + + private void LateMap() + { + // Map all existing private allocations. + // This is necessary to ensure mirrors that are lazily created have the same mappings as the main one. + + PrivateMapping map = _privateTree.GetNode(Address); + + for (; map != null; map = map.Successor) + { + if (map.PrivateAllocation.IsValid) + { + _baseMemory.LateMapView(map.PrivateAllocation.Memory, map.PrivateAllocation.Offset, map.Address - Address, map.Size); + } + } + + MemoryBlock firstPageMemory = _firstPageMemoryForUnmap; + ulong firstPageOffset = _firstPageOffsetForLateMap; + + if (firstPageMemory != null) + { + _baseMemory.LateMapView(firstPageMemory, firstPageOffset, Size, _hostPageSize); + } + } + + public PrivateRange GetFirstPrivateAllocation(ulong va, ulong size, out ulong nextVa) + { + _treeLock.EnterReadLock(); + + try + { + PrivateMapping map = _privateTree.GetNode(va); + + nextVa = map.EndAddress; + + if (map != null && map.PrivateAllocation.IsValid) + { + ulong startOffset = va - map.Address; + + return new( + map.PrivateAllocation.Memory, + map.PrivateAllocation.Offset + startOffset, + Math.Min(map.PrivateAllocation.Size - startOffset, size)); + } + } + finally + { + _treeLock.ExitReadLock(); + } + + return PrivateRange.Empty; + } + + public bool HasPrivateAllocation(ulong va, ulong size, ulong startVa, ulong startSize, ref PrivateRange range) + { + ulong endVa = va + size; + + _treeLock.EnterReadLock(); + + try + { + for (PrivateMapping map = _privateTree.GetNode(va); map != null && map.Address < endVa; map = map.Successor) + { + if (map.PrivateAllocation.IsValid) + { + if (map.Address <= startVa && map.EndAddress >= startVa + startSize) + { + ulong startOffset = startVa - map.Address; + + range = new( + map.PrivateAllocation.Memory, + map.PrivateAllocation.Offset + startOffset, + Math.Min(map.PrivateAllocation.Size - startOffset, startSize)); + } + + return true; + } + } + } + finally + { + _treeLock.ExitReadLock(); + } + + return false; + } + + public void Dispose() + { + GC.SuppressFinalize(this); + + _privateMemoryAllocator.Dispose(); + _baseMemory.Dispose(); + } + } +} diff --git a/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionAllocator.cs b/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionAllocator.cs new file mode 100644 index 000000000..fc3c198ab --- /dev/null +++ b/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionAllocator.cs @@ -0,0 +1,202 @@ +using Ryujinx.Common; +using Ryujinx.Common.Collections; +using Ryujinx.Memory; +using Ryujinx.Memory.Tracking; +using System; + +namespace Ryujinx.Cpu.Jit.HostTracked +{ + readonly struct AddressSpacePartitionAllocation : IDisposable + { + private readonly AddressSpacePartitionAllocator _owner; + private readonly PrivateMemoryAllocatorImpl.Allocation _allocation; + + public IntPtr Pointer => (IntPtr)((ulong)_allocation.Block.Memory.Pointer + _allocation.Offset); + + public bool IsValid => _owner != null; + + public AddressSpacePartitionAllocation( + AddressSpacePartitionAllocator owner, + PrivateMemoryAllocatorImpl.Allocation allocation) + { + _owner = owner; + _allocation = allocation; + } + + public void RegisterMapping(ulong va, ulong endVa) + { + _allocation.Block.AddMapping(_allocation.Offset, _allocation.Size, va, endVa); + } + + public void MapView(MemoryBlock srcBlock, ulong srcOffset, ulong dstOffset, ulong size) + { + _allocation.Block.Memory.MapView(srcBlock, srcOffset, _allocation.Offset + dstOffset, size); + } + + public void UnmapView(MemoryBlock srcBlock, ulong offset, ulong size) + { + _allocation.Block.Memory.UnmapView(srcBlock, _allocation.Offset + offset, size); + } + + public void Reprotect(ulong offset, ulong size, MemoryPermission permission, bool throwOnFail) + { + _allocation.Block.Memory.Reprotect(_allocation.Offset + offset, size, permission, throwOnFail); + } + + public IntPtr GetPointer(ulong offset, ulong size) + { + return _allocation.Block.Memory.GetPointer(_allocation.Offset + offset, size); + } + + public void Dispose() + { + _allocation.Block.RemoveMapping(_allocation.Offset, _allocation.Size); + _owner.Free(_allocation.Block, _allocation.Offset, _allocation.Size); + } + } + + class AddressSpacePartitionAllocator : PrivateMemoryAllocatorImpl + { + private const ulong DefaultBlockAlignment = 1UL << 32; // 4GB + + public class Block : PrivateMemoryAllocator.Block + { + private readonly MemoryTracking _tracking; + private readonly Func _readPtCallback; + private readonly MemoryEhMeilleure _memoryEh; + + private class Mapping : IntrusiveRedBlackTreeNode, IComparable, IComparable + { + public ulong Address { get; } + public ulong Size { get; } + public ulong EndAddress => Address + Size; + public ulong Va { get; } + public ulong EndVa { get; } + + public Mapping(ulong address, ulong size, ulong va, ulong endVa) + { + Address = address; + Size = size; + Va = va; + EndVa = endVa; + } + + public int CompareTo(Mapping other) + { + if (Address < other.Address) + { + return -1; + } + else if (Address <= other.EndAddress - 1UL) + { + return 0; + } + else + { + return 1; + } + } + + public int CompareTo(ulong address) + { + if (address < Address) + { + return -1; + } + else if (address <= EndAddress - 1UL) + { + return 0; + } + else + { + return 1; + } + } + } + + private readonly AddressIntrusiveRedBlackTree _mappingTree; + private readonly object _lock; + + public Block(MemoryTracking tracking, Func readPtCallback, MemoryBlock memory, ulong size, object locker) : base(memory, size) + { + _tracking = tracking; + _readPtCallback = readPtCallback; + _memoryEh = new(memory, null, tracking, VirtualMemoryEvent); + _mappingTree = new(); + _lock = locker; + } + + public void AddMapping(ulong offset, ulong size, ulong va, ulong endVa) + { + _mappingTree.Add(new(offset, size, va, endVa)); + } + + public void RemoveMapping(ulong offset, ulong size) + { + _mappingTree.Remove(_mappingTree.GetNode(offset)); + } + + private ulong VirtualMemoryEvent(ulong address, ulong size, bool write) + { + Mapping map; + + lock (_lock) + { + map = _mappingTree.GetNode(address); + } + + if (map == null) + { + return 0; + } + + address -= map.Address; + + ulong addressAligned = BitUtils.AlignDown(address, AddressSpacePartition.GuestPageSize); + ulong endAddressAligned = BitUtils.AlignUp(address + size, AddressSpacePartition.GuestPageSize); + ulong sizeAligned = endAddressAligned - addressAligned; + + if (!_tracking.VirtualMemoryEvent(map.Va + addressAligned, sizeAligned, write)) + { + return 0; + } + + return _readPtCallback(map.Va + address); + } + + public override void Destroy() + { + _memoryEh.Dispose(); + + base.Destroy(); + } + } + + private readonly MemoryTracking _tracking; + private readonly Func _readPtCallback; + private readonly object _lock; + + public AddressSpacePartitionAllocator( + MemoryTracking tracking, + Func readPtCallback, + object locker) : base(DefaultBlockAlignment, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible) + { + _tracking = tracking; + _readPtCallback = readPtCallback; + _lock = locker; + } + + public AddressSpacePartitionAllocation Allocate(ulong va, ulong size) + { + AddressSpacePartitionAllocation allocation = new(this, Allocate(size, MemoryBlock.GetPageSize(), CreateBlock)); + allocation.RegisterMapping(va, va + size); + + return allocation; + } + + private Block CreateBlock(MemoryBlock memory, ulong size) + { + return new Block(_tracking, _readPtCallback, memory, size, _lock); + } + } +} diff --git a/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionMultiAllocation.cs b/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionMultiAllocation.cs new file mode 100644 index 000000000..3b065583f --- /dev/null +++ b/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionMultiAllocation.cs @@ -0,0 +1,101 @@ +using Ryujinx.Memory; +using System; +using System.Diagnostics; + +namespace Ryujinx.Cpu.Jit.HostTracked +{ + class AddressSpacePartitionMultiAllocation : IDisposable + { + private readonly AddressSpacePartitionAllocation _baseMemory; + private AddressSpacePartitionAllocation _baseMemoryRo; + private AddressSpacePartitionAllocation _baseMemoryNone; + + public AddressSpacePartitionMultiAllocation(AddressSpacePartitionAllocation baseMemory) + { + _baseMemory = baseMemory; + } + + public void MapView(MemoryBlock srcBlock, ulong srcOffset, ulong dstOffset, ulong size) + { + _baseMemory.MapView(srcBlock, srcOffset, dstOffset, size); + + if (_baseMemoryRo.IsValid) + { + _baseMemoryRo.MapView(srcBlock, srcOffset, dstOffset, size); + _baseMemoryRo.Reprotect(dstOffset, size, MemoryPermission.Read, false); + } + } + + public void LateMapView(MemoryBlock srcBlock, ulong srcOffset, ulong dstOffset, ulong size) + { + _baseMemoryRo.MapView(srcBlock, srcOffset, dstOffset, size); + _baseMemoryRo.Reprotect(dstOffset, size, MemoryPermission.Read, false); + } + + public void UnmapView(MemoryBlock srcBlock, ulong offset, ulong size) + { + _baseMemory.UnmapView(srcBlock, offset, size); + + if (_baseMemoryRo.IsValid) + { + _baseMemoryRo.UnmapView(srcBlock, offset, size); + } + } + + public void Reprotect(ulong offset, ulong size, MemoryPermission permission, bool throwOnFail) + { + _baseMemory.Reprotect(offset, size, permission, throwOnFail); + } + + public IntPtr GetPointer(ulong offset, ulong size) + { + return _baseMemory.GetPointer(offset, size); + } + + public bool LazyInitMirrorForProtection(AddressSpacePartitioned addressSpace, ulong blockAddress, ulong blockSize, MemoryPermission permission) + { + if (permission == MemoryPermission.None && !_baseMemoryNone.IsValid) + { + _baseMemoryNone = addressSpace.CreateAsPartitionAllocation(blockAddress, blockSize); + } + else if (permission == MemoryPermission.Read && !_baseMemoryRo.IsValid) + { + _baseMemoryRo = addressSpace.CreateAsPartitionAllocation(blockAddress, blockSize); + + return true; + } + + return false; + } + + public IntPtr GetPointerForProtection(ulong offset, ulong size, MemoryPermission permission) + { + AddressSpacePartitionAllocation allocation = permission switch + { + MemoryPermission.ReadAndWrite => _baseMemory, + MemoryPermission.Read => _baseMemoryRo, + MemoryPermission.None => _baseMemoryNone, + _ => throw new ArgumentException($"Invalid protection \"{permission}\"."), + }; + + Debug.Assert(allocation.IsValid); + + return allocation.GetPointer(offset, size); + } + + public void Dispose() + { + _baseMemory.Dispose(); + + if (_baseMemoryRo.IsValid) + { + _baseMemoryRo.Dispose(); + } + + if (_baseMemoryNone.IsValid) + { + _baseMemoryNone.Dispose(); + } + } + } +} diff --git a/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitioned.cs b/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitioned.cs new file mode 100644 index 000000000..2cf2c248b --- /dev/null +++ b/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitioned.cs @@ -0,0 +1,407 @@ +using Ryujinx.Common; +using Ryujinx.Memory; +using Ryujinx.Memory.Tracking; +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Ryujinx.Cpu.Jit.HostTracked +{ + class AddressSpacePartitioned : IDisposable + { + private const int PartitionBits = 25; + private const ulong PartitionSize = 1UL << PartitionBits; + + private readonly MemoryBlock _backingMemory; + private readonly List _partitions; + private readonly AddressSpacePartitionAllocator _asAllocator; + private readonly Action _updatePtCallback; + private readonly bool _useProtectionMirrors; + + public AddressSpacePartitioned(MemoryTracking tracking, MemoryBlock backingMemory, NativePageTable nativePageTable, bool useProtectionMirrors) + { + _backingMemory = backingMemory; + _partitions = new(); + _asAllocator = new(tracking, nativePageTable.Read, _partitions); + _updatePtCallback = nativePageTable.Update; + _useProtectionMirrors = useProtectionMirrors; + } + + public void Map(ulong va, ulong pa, ulong size) + { + ulong endVa = va + size; + + lock (_partitions) + { + EnsurePartitionsLocked(va, size); + + while (va < endVa) + { + int partitionIndex = FindPartitionIndexLocked(va); + AddressSpacePartition partition = _partitions[partitionIndex]; + + (ulong clampedVa, ulong clampedEndVa) = ClampRange(partition, va, endVa); + + partition.Map(clampedVa, pa, clampedEndVa - clampedVa); + + ulong currentSize = clampedEndVa - clampedVa; + + va += currentSize; + pa += currentSize; + + InsertOrRemoveBridgeIfNeeded(partitionIndex); + } + } + } + + public void Unmap(ulong va, ulong size) + { + ulong endVa = va + size; + + while (va < endVa) + { + AddressSpacePartition partition; + + lock (_partitions) + { + int partitionIndex = FindPartitionIndexLocked(va); + if (partitionIndex < 0) + { + va += PartitionSize - (va & (PartitionSize - 1)); + + continue; + } + + partition = _partitions[partitionIndex]; + + (ulong clampedVa, ulong clampedEndVa) = ClampRange(partition, va, endVa); + + partition.Unmap(clampedVa, clampedEndVa - clampedVa); + + va += clampedEndVa - clampedVa; + + InsertOrRemoveBridgeIfNeeded(partitionIndex); + + if (partition.IsEmpty()) + { + _partitions.Remove(partition); + partition.Dispose(); + } + } + } + } + + public void Reprotect(ulong va, ulong size, MemoryPermission protection) + { + ulong endVa = va + size; + + lock (_partitions) + { + while (va < endVa) + { + AddressSpacePartition partition = FindPartitionWithIndex(va, out int partitionIndex); + + if (partition == null) + { + va += PartitionSize - (va & (PartitionSize - 1)); + + continue; + } + + (ulong clampedVa, ulong clampedEndVa) = ClampRange(partition, va, endVa); + + if (_useProtectionMirrors) + { + partition.Reprotect(clampedVa, clampedEndVa - clampedVa, protection, this, _updatePtCallback); + } + else + { + partition.ReprotectAligned(clampedVa, clampedEndVa - clampedVa, protection); + + if (clampedVa == partition.Address && + partitionIndex > 0 && + _partitions[partitionIndex - 1].EndAddress == partition.Address) + { + _partitions[partitionIndex - 1].ReprotectBridge(protection); + } + } + + va += clampedEndVa - clampedVa; + } + } + } + + public PrivateRange GetPrivateAllocation(ulong va) + { + AddressSpacePartition partition = FindPartition(va); + + if (partition == null) + { + return PrivateRange.Empty; + } + + return partition.GetPrivateAllocation(va); + } + + public PrivateRange GetFirstPrivateAllocation(ulong va, ulong size, out ulong nextVa) + { + AddressSpacePartition partition = FindPartition(va); + + if (partition == null) + { + nextVa = (va & ~(PartitionSize - 1)) + PartitionSize; + + return PrivateRange.Empty; + } + + return partition.GetFirstPrivateAllocation(va, size, out nextVa); + } + + public bool HasAnyPrivateAllocation(ulong va, ulong size, out PrivateRange range) + { + range = PrivateRange.Empty; + + ulong startVa = va; + ulong endVa = va + size; + + while (va < endVa) + { + AddressSpacePartition partition = FindPartition(va); + + if (partition == null) + { + va += PartitionSize - (va & (PartitionSize - 1)); + + continue; + } + + (ulong clampedVa, ulong clampedEndVa) = ClampRange(partition, va, endVa); + + if (partition.HasPrivateAllocation(clampedVa, clampedEndVa - clampedVa, startVa, size, ref range)) + { + return true; + } + + va += clampedEndVa - clampedVa; + } + + return false; + } + + private void InsertOrRemoveBridgeIfNeeded(int partitionIndex) + { + if (partitionIndex > 0) + { + if (_partitions[partitionIndex - 1].EndAddress == _partitions[partitionIndex].Address) + { + _partitions[partitionIndex - 1].InsertBridgeAtEnd(_partitions[partitionIndex], _useProtectionMirrors); + } + else + { + _partitions[partitionIndex - 1].InsertBridgeAtEnd(null, _useProtectionMirrors); + } + } + + if (partitionIndex + 1 < _partitions.Count && _partitions[partitionIndex].EndAddress == _partitions[partitionIndex + 1].Address) + { + _partitions[partitionIndex].InsertBridgeAtEnd(_partitions[partitionIndex + 1], _useProtectionMirrors); + } + else + { + _partitions[partitionIndex].InsertBridgeAtEnd(null, _useProtectionMirrors); + } + } + + public IntPtr GetPointer(ulong va, ulong size) + { + AddressSpacePartition partition = FindPartition(va); + + return partition.GetPointer(va, size); + } + + private static (ulong, ulong) ClampRange(AddressSpacePartition partition, ulong va, ulong endVa) + { + if (va < partition.Address) + { + va = partition.Address; + } + + if (endVa > partition.EndAddress) + { + endVa = partition.EndAddress; + } + + return (va, endVa); + } + + private AddressSpacePartition FindPartition(ulong va) + { + lock (_partitions) + { + int index = FindPartitionIndexLocked(va); + if (index >= 0) + { + return _partitions[index]; + } + } + + return null; + } + + private AddressSpacePartition FindPartitionWithIndex(ulong va, out int index) + { + lock (_partitions) + { + index = FindPartitionIndexLocked(va); + if (index >= 0) + { + return _partitions[index]; + } + } + + return null; + } + + private int FindPartitionIndexLocked(ulong va) + { + int left = 0; + int middle; + int right = _partitions.Count - 1; + + while (left <= right) + { + middle = left + ((right - left) >> 1); + + AddressSpacePartition partition = _partitions[middle]; + + if (partition.Address <= va && partition.EndAddress > va) + { + return middle; + } + + if (partition.Address >= va) + { + right = middle - 1; + } + else + { + left = middle + 1; + } + } + + return -1; + } + + private void EnsurePartitionsLocked(ulong va, ulong size) + { + ulong endVa = BitUtils.AlignUp(va + size, PartitionSize); + va = BitUtils.AlignDown(va, PartitionSize); + + for (int i = 0; i < _partitions.Count && va < endVa; i++) + { + AddressSpacePartition partition = _partitions[i]; + + if (partition.Address <= va && partition.EndAddress > va) + { + if (partition.EndAddress >= endVa) + { + // Fully mapped already. + va = endVa; + + break; + } + + ulong gapSize; + + if (i + 1 < _partitions.Count) + { + AddressSpacePartition nextPartition = _partitions[i + 1]; + + if (partition.EndAddress == nextPartition.Address) + { + va = partition.EndAddress; + + continue; + } + + gapSize = Math.Min(endVa, nextPartition.Address) - partition.EndAddress; + } + else + { + gapSize = endVa - partition.EndAddress; + } + + _partitions.Insert(i + 1, CreateAsPartition(partition.EndAddress, gapSize)); + va = partition.EndAddress + gapSize; + i++; + } + else if (partition.EndAddress > va) + { + Debug.Assert(partition.Address > va); + + ulong gapSize; + + if (partition.Address < endVa) + { + gapSize = partition.Address - va; + } + else + { + gapSize = endVa - va; + } + + _partitions.Insert(i, CreateAsPartition(va, gapSize)); + va = Math.Min(partition.EndAddress, endVa); + i++; + } + } + + if (va < endVa) + { + _partitions.Add(CreateAsPartition(va, endVa - va)); + } + + ValidatePartitionList(); + } + + [Conditional("DEBUG")] + private void ValidatePartitionList() + { + for (int i = 1; i < _partitions.Count; i++) + { + Debug.Assert(_partitions[i].Address > _partitions[i - 1].Address); + Debug.Assert(_partitions[i].EndAddress > _partitions[i - 1].EndAddress); + } + } + + private AddressSpacePartition CreateAsPartition(ulong va, ulong size) + { + return new(CreateAsPartitionAllocation(va, size), _backingMemory, va, size); + } + + public AddressSpacePartitionAllocation CreateAsPartitionAllocation(ulong va, ulong size) + { + return _asAllocator.Allocate(va, size + MemoryBlock.GetPageSize()); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + foreach (AddressSpacePartition partition in _partitions) + { + partition.Dispose(); + } + + _partitions.Clear(); + _asAllocator.Dispose(); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Cpu/Jit/HostTracked/NativePageTable.cs b/src/Ryujinx.Cpu/Jit/HostTracked/NativePageTable.cs new file mode 100644 index 000000000..e3174e3fc --- /dev/null +++ b/src/Ryujinx.Cpu/Jit/HostTracked/NativePageTable.cs @@ -0,0 +1,223 @@ +using Ryujinx.Cpu.Signal; +using Ryujinx.Memory; +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.Jit.HostTracked +{ + sealed class NativePageTable : IDisposable + { + private delegate ulong TrackingEventDelegate(ulong address, ulong size, bool write); + + private const int PageBits = 12; + private const int PageSize = 1 << PageBits; + private const int PageMask = PageSize - 1; + + private const int PteSize = 8; + + private readonly int _bitsPerPtPage; + private readonly int _entriesPerPtPage; + private readonly int _pageCommitmentBits; + + private readonly PageTable _pageTable; + private readonly MemoryBlock _nativePageTable; + private readonly ulong[] _pageCommitmentBitmap; + private readonly ulong _hostPageSize; + + private readonly TrackingEventDelegate _trackingEvent; + + private bool _disposed; + + public IntPtr PageTablePointer => _nativePageTable.Pointer; + + public NativePageTable(ulong asSize) + { + ulong hostPageSize = MemoryBlock.GetPageSize(); + + _entriesPerPtPage = (int)(hostPageSize / sizeof(ulong)); + _bitsPerPtPage = BitOperations.Log2((uint)_entriesPerPtPage); + _pageCommitmentBits = PageBits + _bitsPerPtPage; + + _hostPageSize = hostPageSize; + _pageTable = new PageTable(); + _nativePageTable = new MemoryBlock((asSize / PageSize) * PteSize + _hostPageSize, MemoryAllocationFlags.Reserve); + _pageCommitmentBitmap = new ulong[(asSize >> _pageCommitmentBits) / (sizeof(ulong) * 8)]; + + ulong ptStart = (ulong)_nativePageTable.Pointer; + ulong ptEnd = ptStart + _nativePageTable.Size; + + _trackingEvent = VirtualMemoryEvent; + + bool added = NativeSignalHandler.AddTrackedRegion((nuint)ptStart, (nuint)ptEnd, Marshal.GetFunctionPointerForDelegate(_trackingEvent)); + + if (!added) + { + throw new InvalidOperationException("Number of allowed tracked regions exceeded."); + } + } + + public void Map(ulong va, ulong pa, ulong size, AddressSpacePartitioned addressSpace, MemoryBlock backingMemory, bool privateMap) + { + while (size != 0) + { + _pageTable.Map(va, pa); + + EnsureCommitment(va); + + if (privateMap) + { + _nativePageTable.Write((va / PageSize) * PteSize, GetPte(va, addressSpace.GetPointer(va, PageSize))); + } + else + { + _nativePageTable.Write((va / PageSize) * PteSize, GetPte(va, backingMemory.GetPointer(pa, PageSize))); + } + + va += PageSize; + pa += PageSize; + size -= PageSize; + } + } + + public void Unmap(ulong va, ulong size) + { + IntPtr guardPagePtr = GetGuardPagePointer(); + + while (size != 0) + { + _pageTable.Unmap(va); + _nativePageTable.Write((va / PageSize) * PteSize, GetPte(va, guardPagePtr)); + + va += PageSize; + size -= PageSize; + } + } + + public ulong Read(ulong va) + { + ulong pte = _nativePageTable.Read((va / PageSize) * PteSize); + + pte += va & ~(ulong)PageMask; + + return pte + (va & PageMask); + } + + public void Update(ulong va, IntPtr ptr, ulong size) + { + ulong remainingSize = size; + + while (remainingSize != 0) + { + EnsureCommitment(va); + + _nativePageTable.Write((va / PageSize) * PteSize, GetPte(va, ptr)); + + va += PageSize; + ptr += PageSize; + remainingSize -= PageSize; + } + } + + private void EnsureCommitment(ulong va) + { + ulong bit = va >> _pageCommitmentBits; + + int index = (int)(bit / (sizeof(ulong) * 8)); + int shift = (int)(bit % (sizeof(ulong) * 8)); + + ulong mask = 1UL << shift; + + ulong oldMask = _pageCommitmentBitmap[index]; + + if ((oldMask & mask) == 0) + { + lock (_pageCommitmentBitmap) + { + oldMask = _pageCommitmentBitmap[index]; + + if ((oldMask & mask) != 0) + { + return; + } + + _nativePageTable.Commit(bit * _hostPageSize, _hostPageSize); + + Span pageSpan = MemoryMarshal.Cast(_nativePageTable.GetSpan(bit * _hostPageSize, (int)_hostPageSize)); + + Debug.Assert(pageSpan.Length == _entriesPerPtPage); + + IntPtr guardPagePtr = GetGuardPagePointer(); + + for (int i = 0; i < pageSpan.Length; i++) + { + pageSpan[i] = GetPte((bit << _pageCommitmentBits) | ((ulong)i * PageSize), guardPagePtr); + } + + _pageCommitmentBitmap[index] = oldMask | mask; + } + } + } + + private IntPtr GetGuardPagePointer() + { + return _nativePageTable.GetPointer(_nativePageTable.Size - _hostPageSize, _hostPageSize); + } + + private static ulong GetPte(ulong va, IntPtr ptr) + { + Debug.Assert((va & PageMask) == 0); + + return (ulong)ptr - va; + } + + public ulong GetPhysicalAddress(ulong va) + { + return _pageTable.Read(va) + (va & PageMask); + } + + private ulong VirtualMemoryEvent(ulong address, ulong size, bool write) + { + if (address < _nativePageTable.Size - _hostPageSize) + { + // Some prefetch instructions do not cause faults with invalid addresses. + // Retry if we are hitting a case where the page table is unmapped, the next + // run will execute the actual instruction. + // The address loaded from the page table will be invalid, and it should hit the else case + // if the instruction faults on unmapped or protected memory. + + ulong va = address * (PageSize / sizeof(ulong)); + + EnsureCommitment(va); + + return (ulong)_nativePageTable.Pointer + address; + } + else + { + throw new InvalidMemoryRegionException(); + } + } + + private void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + NativeSignalHandler.RemoveTrackedRegion((nuint)_nativePageTable.Pointer); + + _nativePageTable.Dispose(); + } + + _disposed = true; + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs index a5944097d..9893c59b2 100644 --- a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs +++ b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs @@ -1,5 +1,7 @@ using ARMeilleure.Memory; using ARMeilleure.Translation; +using Ryujinx.Cpu.Signal; +using Ryujinx.Memory; namespace Ryujinx.Cpu.Jit { @@ -12,6 +14,12 @@ namespace Ryujinx.Cpu.Jit { _tickSource = tickSource; _translator = new Translator(new JitMemoryAllocator(forJit: true), memory, for64Bit); + + if (memory.Type.IsHostMappedOrTracked()) + { + NativeSignalHandler.InitializeSignalHandler(); + } + memory.UnmapEvent += UnmapHandler; } diff --git a/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs b/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs index 926dd8a0c..06c11b7b9 100644 --- a/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs +++ b/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs @@ -14,7 +14,5 @@ namespace Ryujinx.Cpu.Jit public IJitMemoryBlock Allocate(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.None); public IJitMemoryBlock Reserve(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.Reserve | _jitFlag); - - public ulong GetPageSize() => MemoryBlock.GetPageSize(); } } diff --git a/src/Ryujinx.Cpu/Jit/MemoryManager.cs b/src/Ryujinx.Cpu/Jit/MemoryManager.cs index b9a547025..6f594ec2f 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManager.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManager.cs @@ -3,6 +3,7 @@ using Ryujinx.Memory; using Ryujinx.Memory.Range; using Ryujinx.Memory.Tracking; using System; +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; @@ -14,12 +15,8 @@ namespace Ryujinx.Cpu.Jit /// /// Represents a CPU memory manager. /// - public sealed class MemoryManager : MemoryManagerBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock + public sealed class MemoryManager : VirtualMemoryManagerRefCountedBase, IMemoryManager, IVirtualMemoryManagerTracked { - public const int PageBits = 12; - public const int PageSize = 1 << PageBits; - public const int PageMask = PageSize - 1; - private const int PteSize = 8; private const int PointerTagBit = 62; @@ -28,17 +25,17 @@ namespace Ryujinx.Cpu.Jit private readonly InvalidAccessHandler _invalidAccessHandler; /// - public bool Supports4KBPages => true; + public bool UsesPrivateAllocations => false; /// /// Address space width in bits. /// public int AddressSpaceBits { get; } - private readonly ulong _addressSpaceSize; - private readonly MemoryBlock _pageTable; + private readonly ManagedPageFlags _pages; + /// /// Page table base pointer. /// @@ -50,6 +47,8 @@ namespace Ryujinx.Cpu.Jit public event Action UnmapEvent; + protected override ulong AddressSpaceSize { get; } + /// /// Creates a new instance of the memory manager. /// @@ -71,9 +70,11 @@ namespace Ryujinx.Cpu.Jit } AddressSpaceBits = asBits; - _addressSpaceSize = asSize; + AddressSpaceSize = asSize; _pageTable = new MemoryBlock((asSize / PageSize) * PteSize); + _pages = new ManagedPageFlags(AddressSpaceBits); + Tracking = new MemoryTracking(this, PageSize); } @@ -93,15 +94,10 @@ namespace Ryujinx.Cpu.Jit remainingSize -= PageSize; } + _pages.AddMapping(oVa, size); Tracking.Map(oVa, size); } - /// - public void MapForeign(ulong va, nuint hostPointer, ulong size) - { - throw new NotSupportedException(); - } - /// public void Unmap(ulong va, ulong size) { @@ -115,6 +111,7 @@ namespace Ryujinx.Cpu.Jit UnmapEvent?.Invoke(va, size); Tracking.Unmap(va, size); + _pages.RemoveMapping(va, size); ulong remainingSize = size; while (remainingSize != 0) @@ -126,18 +123,29 @@ namespace Ryujinx.Cpu.Jit } } - /// - public T Read(ulong va) where T : unmanaged - { - return MemoryMarshal.Cast(GetSpan(va, Unsafe.SizeOf()))[0]; - } - - /// - public T ReadTracked(ulong va) where T : unmanaged + public override T ReadTracked(ulong va) { try { - SignalMemoryTracking(va, (ulong)Unsafe.SizeOf(), false); + return base.ReadTracked(va); + } + catch (InvalidMemoryRegionException) + { + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } + + return default; + } + } + + /// + public T ReadGuest(ulong va) where T : unmanaged + { + try + { + SignalMemoryTrackingImpl(va, (ulong)Unsafe.SizeOf(), false, true); return Read(va); } @@ -153,112 +161,26 @@ namespace Ryujinx.Cpu.Jit } /// - public void Read(ulong va, Span data) - { - ReadImpl(va, data); - } - - /// - public void Write(ulong va, T value) where T : unmanaged - { - Write(va, MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref value, 1))); - } - - /// - public void Write(ulong va, ReadOnlySpan data) - { - if (data.Length == 0) - { - return; - } - - SignalMemoryTracking(va, (ulong)data.Length, true); - - WriteImpl(va, data); - } - - /// - public void WriteUntracked(ulong va, ReadOnlySpan data) - { - if (data.Length == 0) - { - return; - } - - WriteImpl(va, data); - } - - /// - public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan data) - { - if (data.Length == 0) - { - return false; - } - - SignalMemoryTracking(va, (ulong)data.Length, false); - - if (IsContiguousAndMapped(va, data.Length)) - { - var target = _backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length); - - bool changed = !data.SequenceEqual(target); - - if (changed) - { - data.CopyTo(target); - } - - return changed; - } - else - { - WriteImpl(va, data); - - return true; - } - } - - /// - /// Writes data to CPU mapped memory. - /// - /// Virtual address to write the data into - /// Data to be written - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WriteImpl(ulong va, ReadOnlySpan data) + public override void Read(ulong va, Span data) { try { - AssertValidAddressAndSize(va, (ulong)data.Length); - - if (IsContiguousAndMapped(va, data.Length)) + base.Read(va, data); + } + catch (InvalidMemoryRegionException) + { + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) { - data.CopyTo(_backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length)); + throw; } - else - { - int offset = 0, size; + } + } - if ((va & PageMask) != 0) - { - ulong pa = GetPhysicalAddressInternal(va); - - size = Math.Min(data.Length, PageSize - (int)(va & PageMask)); - - data[..size].CopyTo(_backingMemory.GetSpan(pa, size)); - - offset += size; - } - - for (; offset < data.Length; offset += size) - { - ulong pa = GetPhysicalAddressInternal(va + (ulong)offset); - - size = Math.Min(data.Length - offset, PageSize); - - data.Slice(offset, size).CopyTo(_backingMemory.GetSpan(pa, size)); - } - } + public override void Write(ulong va, ReadOnlySpan data) + { + try + { + base.Write(va, data); } catch (InvalidMemoryRegionException) { @@ -270,60 +192,47 @@ namespace Ryujinx.Cpu.Jit } /// - public ReadOnlySpan GetSpan(ulong va, int size, bool tracked = false) + public void WriteGuest(ulong va, T value) where T : unmanaged { - if (size == 0) + Span data = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref value, 1)); + + SignalMemoryTrackingImpl(va, (ulong)data.Length, true, true); + + Write(va, data); + } + + public override void WriteUntracked(ulong va, ReadOnlySpan data) + { + try { - return ReadOnlySpan.Empty; + base.WriteUntracked(va, data); } - - if (tracked) + catch (InvalidMemoryRegionException) { - SignalMemoryTracking(va, (ulong)size, false); - } - - if (IsContiguousAndMapped(va, size)) - { - return _backingMemory.GetSpan(GetPhysicalAddressInternal(va), size); - } - else - { - Span data = new byte[size]; - - ReadImpl(va, data); - - return data; + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } } } - /// - public WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) + public override ReadOnlySequence GetReadOnlySequence(ulong va, int size, bool tracked = false) { - if (size == 0) + try { - return new WritableRegion(null, va, Memory.Empty); + return base.GetReadOnlySequence(va, size, tracked); } - - if (IsContiguousAndMapped(va, size)) + catch (InvalidMemoryRegionException) { - if (tracked) + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) { - SignalMemoryTracking(va, (ulong)size, true); + throw; } - return new WritableRegion(null, va, _backingMemory.GetMemory(GetPhysicalAddressInternal(va), size)); - } - else - { - Memory memory = new byte[size]; - - GetSpan(va, size).CopyTo(memory.Span); - - return new WritableRegion(this, va, memory, tracked); + return ReadOnlySequence.Empty; } } - /// public ref T GetRef(ulong va) where T : unmanaged { if (!IsContiguous(va, Unsafe.SizeOf())) @@ -336,56 +245,6 @@ namespace Ryujinx.Cpu.Jit return ref _backingMemory.GetRef(GetPhysicalAddressInternal(va)); } - /// - /// Computes the number of pages in a virtual address range. - /// - /// Virtual address of the range - /// Size of the range - /// The virtual address of the beginning of the first page - /// This function does not differentiate between allocated and unallocated pages. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetPagesCount(ulong va, uint size, out ulong startVa) - { - // WARNING: Always check if ulong does not overflow during the operations. - startVa = va & ~(ulong)PageMask; - ulong vaSpan = (va - startVa + size + PageMask) & ~(ulong)PageMask; - - return (int)(vaSpan / PageSize); - } - - private static void ThrowMemoryNotContiguous() => throw new MemoryNotContiguousException(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsContiguousAndMapped(ulong va, int size) => IsContiguous(va, size) && IsMapped(va); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsContiguous(ulong va, int size) - { - if (!ValidateAddress(va) || !ValidateAddressAndSize(va, (ulong)size)) - { - return false; - } - - int pages = GetPagesCount(va, (uint)size, out va); - - for (int page = 0; page < pages - 1; page++) - { - if (!ValidateAddress(va + PageSize)) - { - return false; - } - - if (GetPhysicalAddressInternal(va) + PageSize != GetPhysicalAddressInternal(va + PageSize)) - { - return false; - } - - va += PageSize; - } - - return true; - } - /// public IEnumerable GetHostRegions(ulong va, ulong size) { @@ -462,48 +321,6 @@ namespace Ryujinx.Cpu.Jit return regions; } - private void ReadImpl(ulong va, Span data) - { - if (data.Length == 0) - { - return; - } - - try - { - AssertValidAddressAndSize(va, (ulong)data.Length); - - int offset = 0, size; - - if ((va & PageMask) != 0) - { - ulong pa = GetPhysicalAddressInternal(va); - - size = Math.Min(data.Length, PageSize - (int)(va & PageMask)); - - _backingMemory.GetSpan(pa, size).CopyTo(data[..size]); - - offset += size; - } - - for (; offset < data.Length; offset += size) - { - ulong pa = GetPhysicalAddressInternal(va + (ulong)offset); - - size = Math.Min(data.Length - offset, PageSize); - - _backingMemory.GetSpan(pa, size).CopyTo(data.Slice(offset, size)); - } - } - catch (InvalidMemoryRegionException) - { - if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) - { - throw; - } - } - } - /// public bool IsRangeMapped(ulong va, ulong size) { @@ -532,9 +349,8 @@ namespace Ryujinx.Cpu.Jit return true; } - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsMapped(ulong va) + public override bool IsMapped(ulong va) { if (!ValidateAddress(va)) { @@ -544,40 +360,9 @@ namespace Ryujinx.Cpu.Jit return _pageTable.Read((va / PageSize) * PteSize) != 0; } - private bool ValidateAddress(ulong va) + private nuint GetPhysicalAddressInternal(ulong va) { - return va < _addressSpaceSize; - } - - /// - /// Checks if the combination of virtual address and size is part of the addressable space. - /// - /// Virtual address of the range - /// Size of the range in bytes - /// True if the combination of virtual address and size is part of the addressable space - private bool ValidateAddressAndSize(ulong va, ulong size) - { - ulong endVa = va + size; - return endVa >= va && endVa >= size && endVa <= _addressSpaceSize; - } - - /// - /// Ensures the combination of virtual address and size is part of the addressable space. - /// - /// Virtual address of the range - /// Size of the range in bytes - /// Throw when the memory region specified outside the addressable space - private void AssertValidAddressAndSize(ulong va, ulong size) - { - if (!ValidateAddressAndSize(va, size)) - { - throw new InvalidMemoryRegionException($"va=0x{va:X16}, size=0x{size:X16}"); - } - } - - private ulong GetPhysicalAddressInternal(ulong va) - { - return PteToPa(_pageTable.Read((va / PageSize) * PteSize) & ~(0xffffUL << 48)) + (va & PageMask); + return (nuint)(PteToPa(_pageTable.Read((va / PageSize) * PteSize) & ~(0xffffUL << 48)) + (va & PageMask)); } /// @@ -587,50 +372,57 @@ namespace Ryujinx.Cpu.Jit } /// - public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection) + public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection, bool guest) { AssertValidAddressAndSize(va, size); - // Protection is inverted on software pages, since the default value is 0. - protection = (~protection) & MemoryPermission.ReadAndWrite; - - long tag = protection switch + if (guest) { - MemoryPermission.None => 0L, - MemoryPermission.Write => 2L << PointerTagBit, - _ => 3L << PointerTagBit, - }; + // Protection is inverted on software pages, since the default value is 0. + protection = (~protection) & MemoryPermission.ReadAndWrite; - int pages = GetPagesCount(va, (uint)size, out va); - ulong pageStart = va >> PageBits; - long invTagMask = ~(0xffffL << 48); - - for (int page = 0; page < pages; page++) - { - ref long pageRef = ref _pageTable.GetRef(pageStart * PteSize); - - long pte; - - do + long tag = protection switch { - pte = Volatile.Read(ref pageRef); - } - while (pte != 0 && Interlocked.CompareExchange(ref pageRef, (pte & invTagMask) | tag, pte) != pte); + MemoryPermission.None => 0L, + MemoryPermission.Write => 2L << PointerTagBit, + _ => 3L << PointerTagBit, + }; - pageStart++; + int pages = GetPagesCount(va, (uint)size, out va); + ulong pageStart = va >> PageBits; + long invTagMask = ~(0xffffL << 48); + + for (int page = 0; page < pages; page++) + { + ref long pageRef = ref _pageTable.GetRef(pageStart * PteSize); + + long pte; + + do + { + pte = Volatile.Read(ref pageRef); + } + while (pte != 0 && Interlocked.CompareExchange(ref pageRef, (pte & invTagMask) | tag, pte) != pte); + + pageStart++; + } + } + else + { + _pages.TrackingReprotect(va, size, protection); } } /// - public RegionHandle BeginTracking(ulong address, ulong size, int id) + public RegionHandle BeginTracking(ulong address, ulong size, int id, RegionFlags flags = RegionFlags.None) { - return Tracking.BeginTracking(address, size, id); + return Tracking.BeginTracking(address, size, id, flags); } /// - public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id) + public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id, RegionFlags flags = RegionFlags.None) { - return Tracking.BeginGranularTracking(address, size, handles, granularity, id); + return Tracking.BeginGranularTracking(address, size, handles, granularity, id, flags); } /// @@ -639,8 +431,7 @@ namespace Ryujinx.Cpu.Jit return Tracking.BeginSmartGranularTracking(address, size, granularity, id); } - /// - public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) + private void SignalMemoryTrackingImpl(ulong va, ulong size, bool write, bool guest, bool precise = false, int? exemptId = null) { AssertValidAddressAndSize(va, size); @@ -650,31 +441,45 @@ namespace Ryujinx.Cpu.Jit return; } - // We emulate guard pages for software memory access. This makes for an easy transition to - // tracking using host guard pages in future, but also supporting platforms where this is not possible. + // If the memory tracking is coming from the guest, use the tag bits in the page table entry. + // Otherwise, use the managed page flags. - // Write tag includes read protection, since we don't have any read actions that aren't performed before write too. - long tag = (write ? 3L : 1L) << PointerTagBit; - - int pages = GetPagesCount(va, (uint)size, out _); - ulong pageStart = va >> PageBits; - - for (int page = 0; page < pages; page++) + if (guest) { - ref long pageRef = ref _pageTable.GetRef(pageStart * PteSize); + // We emulate guard pages for software memory access. This makes for an easy transition to + // tracking using host guard pages in future, but also supporting platforms where this is not possible. - long pte; + // Write tag includes read protection, since we don't have any read actions that aren't performed before write too. + long tag = (write ? 3L : 1L) << PointerTagBit; - pte = Volatile.Read(ref pageRef); + int pages = GetPagesCount(va, (uint)size, out _); + ulong pageStart = va >> PageBits; - if ((pte & tag) != 0) + for (int page = 0; page < pages; page++) { - Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId); - break; - } + ref long pageRef = ref _pageTable.GetRef(pageStart * PteSize); - pageStart++; + long pte = Volatile.Read(ref pageRef); + + if ((pte & tag) != 0) + { + Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId, true); + break; + } + + pageStart++; + } } + else + { + _pages.SignalMemoryTracking(Tracking, va, size, write, exemptId); + } + } + + /// + public override void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) + { + SignalMemoryTrackingImpl(va, size, write, false, precise, exemptId); } private ulong PaToPte(ulong pa) @@ -691,5 +496,17 @@ namespace Ryujinx.Cpu.Jit /// Disposes of resources used by the memory manager. /// protected override void Destroy() => _pageTable.Dispose(); + + protected override Memory GetPhysicalAddressMemory(nuint pa, int size) + => _backingMemory.GetMemory(pa, size); + + protected override Span GetPhysicalAddressSpan(nuint pa, int size) + => _backingMemory.GetSpan(pa, size); + + protected override nuint TranslateVirtualAddressChecked(ulong va) + => GetPhysicalAddressInternal(va); + + protected override nuint TranslateVirtualAddressUnchecked(ulong va) + => GetPhysicalAddressInternal(va); } } diff --git a/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs b/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs index 6d32787ac..d701ff722 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs @@ -3,52 +3,31 @@ using Ryujinx.Memory; using Ryujinx.Memory.Range; using Ryujinx.Memory.Tracking; using System; +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using System.Threading; namespace Ryujinx.Cpu.Jit { /// /// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region. /// - public sealed class MemoryManagerHostMapped : MemoryManagerBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock + public sealed class MemoryManagerHostMapped : VirtualMemoryManagerRefCountedBase, IMemoryManager, IVirtualMemoryManagerTracked { - public const int PageBits = 12; - public const int PageSize = 1 << PageBits; - public const int PageMask = PageSize - 1; - - public const int PageToPteShift = 5; // 32 pages (2 bits each) in one ulong page table entry. - public const ulong BlockMappedMask = 0x5555555555555555; // First bit of each table entry set. - - private enum HostMappedPtBits : ulong - { - Unmapped = 0, - Mapped, - WriteTracked, - ReadWriteTracked, - - MappedReplicated = 0x5555555555555555, - WriteTrackedReplicated = 0xaaaaaaaaaaaaaaaa, - ReadWriteTrackedReplicated = ulong.MaxValue, - } - private readonly InvalidAccessHandler _invalidAccessHandler; private readonly bool _unsafeMode; private readonly AddressSpace _addressSpace; - public ulong AddressSpaceSize { get; } - private readonly PageTable _pageTable; private readonly MemoryEhMeilleure _memoryEh; - private readonly ulong[] _pageBitmap; + private readonly ManagedPageFlags _pages; /// - public bool Supports4KBPages => MemoryBlock.GetPageSize() == PageSize; + public bool UsesPrivateAllocations => false; public int AddressSpaceBits { get; } @@ -60,6 +39,8 @@ namespace Ryujinx.Cpu.Jit public event Action UnmapEvent; + protected override ulong AddressSpaceSize { get; } + /// /// Creates a new instance of the host mapped memory manager. /// @@ -85,48 +66,12 @@ namespace Ryujinx.Cpu.Jit AddressSpaceBits = asBits; - _pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))]; + _pages = new ManagedPageFlags(AddressSpaceBits); Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler); _memoryEh = new MemoryEhMeilleure(_addressSpace.Base, _addressSpace.Mirror, Tracking); } - /// - /// Checks if the virtual address is part of the addressable space. - /// - /// Virtual address - /// True if the virtual address is part of the addressable space - private bool ValidateAddress(ulong va) - { - return va < AddressSpaceSize; - } - - /// - /// Checks if the combination of virtual address and size is part of the addressable space. - /// - /// Virtual address of the range - /// Size of the range in bytes - /// True if the combination of virtual address and size is part of the addressable space - private bool ValidateAddressAndSize(ulong va, ulong size) - { - ulong endVa = va + size; - return endVa >= va && endVa >= size && endVa <= AddressSpaceSize; - } - - /// - /// Ensures the combination of virtual address and size is part of the addressable space. - /// - /// Virtual address of the range - /// Size of the range in bytes - /// Throw when the memory region specified outside the addressable space - private void AssertValidAddressAndSize(ulong va, ulong size) - { - if (!ValidateAddressAndSize(va, size)) - { - throw new InvalidMemoryRegionException($"va=0x{va:X16}, size=0x{size:X16}"); - } - } - /// /// Ensures the combination of virtual address and size is part of the addressable space and fully mapped. /// @@ -134,7 +79,7 @@ namespace Ryujinx.Cpu.Jit /// Size of the range in bytes private void AssertMapped(ulong va, ulong size) { - if (!ValidateAddressAndSize(va, size) || !IsRangeMappedImpl(va, size)) + if (!ValidateAddressAndSize(va, size) || !_pages.IsRangeMapped(va, size)) { throw new InvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}"); } @@ -146,18 +91,12 @@ namespace Ryujinx.Cpu.Jit AssertValidAddressAndSize(va, size); _addressSpace.Map(va, pa, size, flags); - AddMapping(va, size); + _pages.AddMapping(va, size); PtMap(va, pa, size); Tracking.Map(va, size); } - /// - public void MapForeign(ulong va, nuint hostPointer, ulong size) - { - throw new NotSupportedException(); - } - /// public void Unmap(ulong va, ulong size) { @@ -166,7 +105,7 @@ namespace Ryujinx.Cpu.Jit UnmapEvent?.Invoke(va, size); Tracking.Unmap(va, size); - RemoveMapping(va, size); + _pages.RemoveMapping(va, size); PtUnmap(va, size); _addressSpace.Unmap(va, size); } @@ -194,8 +133,7 @@ namespace Ryujinx.Cpu.Jit } } - /// - public T Read(ulong va) where T : unmanaged + public override T Read(ulong va) { try { @@ -214,14 +152,11 @@ namespace Ryujinx.Cpu.Jit } } - /// - public T ReadTracked(ulong va) where T : unmanaged + public override T ReadTracked(ulong va) { try { - SignalMemoryTracking(va, (ulong)Unsafe.SizeOf(), false); - - return Read(va); + return base.ReadTracked(va); } catch (InvalidMemoryRegionException) { @@ -234,8 +169,7 @@ namespace Ryujinx.Cpu.Jit } } - /// - public void Read(ulong va, Span data) + public override void Read(ulong va, Span data) { try { @@ -252,9 +186,7 @@ namespace Ryujinx.Cpu.Jit } } - - /// - public void Write(ulong va, T value) where T : unmanaged + public override void Write(ulong va, T value) { try { @@ -271,8 +203,7 @@ namespace Ryujinx.Cpu.Jit } } - /// - public void Write(ulong va, ReadOnlySpan data) + public override void Write(ulong va, ReadOnlySpan data) { try { @@ -289,8 +220,7 @@ namespace Ryujinx.Cpu.Jit } } - /// - public void WriteUntracked(ulong va, ReadOnlySpan data) + public override void WriteUntracked(ulong va, ReadOnlySpan data) { try { @@ -307,8 +237,7 @@ namespace Ryujinx.Cpu.Jit } } - /// - public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan data) + public override bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan data) { try { @@ -335,8 +264,21 @@ namespace Ryujinx.Cpu.Jit } } - /// - public ReadOnlySpan GetSpan(ulong va, int size, bool tracked = false) + public override ReadOnlySequence GetReadOnlySequence(ulong va, int size, bool tracked = false) + { + if (tracked) + { + SignalMemoryTracking(va, (ulong)size, write: false); + } + else + { + AssertMapped(va, (ulong)size); + } + + return new ReadOnlySequence(_addressSpace.Mirror.GetMemory(va, size)); + } + + public override ReadOnlySpan GetSpan(ulong va, int size, bool tracked = false) { if (tracked) { @@ -350,8 +292,7 @@ namespace Ryujinx.Cpu.Jit return _addressSpace.Mirror.GetSpan(va, size); } - /// - public WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) + public override WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) { if (tracked) { @@ -365,7 +306,6 @@ namespace Ryujinx.Cpu.Jit return _addressSpace.Mirror.GetWritableRegion(va, size); } - /// public ref T GetRef(ulong va) where T : unmanaged { SignalMemoryTracking(va, (ulong)Unsafe.SizeOf(), true); @@ -373,26 +313,10 @@ namespace Ryujinx.Cpu.Jit return ref _addressSpace.Mirror.GetRef(va); } - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsMapped(ulong va) + public override bool IsMapped(ulong va) { - return ValidateAddress(va) && IsMappedImpl(va); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsMappedImpl(ulong va) - { - ulong page = va >> PageBits; - - int bit = (int)((page & 31) << 1); - - int pageIndex = (int)(page >> PageToPteShift); - ref ulong pageRef = ref _pageBitmap[pageIndex]; - - ulong pte = Volatile.Read(ref pageRef); - - return ((pte >> bit) & 3) != 0; + return ValidateAddress(va) && _pages.IsMapped(va); } /// @@ -400,58 +324,7 @@ namespace Ryujinx.Cpu.Jit { AssertValidAddressAndSize(va, size); - return IsRangeMappedImpl(va, size); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void GetPageBlockRange(ulong pageStart, ulong pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex) - { - startMask = ulong.MaxValue << ((int)(pageStart & 31) << 1); - endMask = ulong.MaxValue >> (64 - ((int)(pageEnd & 31) << 1)); - - pageIndex = (int)(pageStart >> PageToPteShift); - pageEndIndex = (int)((pageEnd - 1) >> PageToPteShift); - } - - private bool IsRangeMappedImpl(ulong va, ulong size) - { - int pages = GetPagesCount(va, size, out _); - - if (pages == 1) - { - return IsMappedImpl(va); - } - - ulong pageStart = va >> PageBits; - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - // Check if either bit in each 2 bit page entry is set. - // OR the block with itself shifted down by 1, and check the first bit of each entry. - - ulong mask = BlockMappedMask & startMask; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - ulong pte = Volatile.Read(ref pageRef); - - pte |= pte >> 1; - if ((pte & mask) != mask) - { - return false; - } - - mask = BlockMappedMask; - } - - return true; + return _pages.IsRangeMapped(va, size); } /// @@ -512,11 +385,10 @@ namespace Ryujinx.Cpu.Jit return _pageTable.Read(va) + (va & PageMask); } - /// /// /// This function also validates that the given range is both valid and mapped, and will throw if it is not. /// - public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) + public override void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) { AssertValidAddressAndSize(va, size); @@ -526,93 +398,7 @@ namespace Ryujinx.Cpu.Jit return; } - // Software table, used for managed memory tracking. - - int pages = GetPagesCount(va, size, out _); - ulong pageStart = va >> PageBits; - - if (pages == 1) - { - ulong tag = (ulong)(write ? HostMappedPtBits.WriteTracked : HostMappedPtBits.ReadWriteTracked); - - int bit = (int)((pageStart & 31) << 1); - - int pageIndex = (int)(pageStart >> PageToPteShift); - ref ulong pageRef = ref _pageBitmap[pageIndex]; - - ulong pte = Volatile.Read(ref pageRef); - ulong state = ((pte >> bit) & 3); - - if (state >= tag) - { - Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId); - return; - } - else if (state == 0) - { - ThrowInvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}"); - } - } - else - { - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - ulong mask = startMask; - - ulong anyTrackingTag = (ulong)HostMappedPtBits.WriteTrackedReplicated; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - - ulong pte = Volatile.Read(ref pageRef); - ulong mappedMask = mask & BlockMappedMask; - - ulong mappedPte = pte | (pte >> 1); - if ((mappedPte & mappedMask) != mappedMask) - { - ThrowInvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}"); - } - - pte &= mask; - if ((pte & anyTrackingTag) != 0) // Search for any tracking. - { - // Writes trigger any tracking. - // Only trigger tracking from reads if both bits are set on any page. - if (write || (pte & (pte >> 1) & BlockMappedMask) != 0) - { - Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId); - break; - } - } - - mask = ulong.MaxValue; - } - } - } - - /// - /// Computes the number of pages in a virtual address range. - /// - /// Virtual address of the range - /// Size of the range - /// The virtual address of the beginning of the first page - /// This function does not differentiate between allocated and unallocated pages. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetPagesCount(ulong va, ulong size, out ulong startVa) - { - // WARNING: Always check if ulong does not overflow during the operations. - startVa = va & ~(ulong)PageMask; - ulong vaSpan = (va - startVa + size + PageMask) & ~(ulong)PageMask; - - return (int)(vaSpan / PageSize); + _pages.SignalMemoryTracking(Tracking, va, size, write, exemptId); } /// @@ -622,103 +408,28 @@ namespace Ryujinx.Cpu.Jit } /// - public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection) + public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection, bool guest) { - // Protection is inverted on software pages, since the default value is 0. - protection = (~protection) & MemoryPermission.ReadAndWrite; - - int pages = GetPagesCount(va, size, out va); - ulong pageStart = va >> PageBits; - - if (pages == 1) + if (guest) { - ulong protTag = protection switch - { - MemoryPermission.None => (ulong)HostMappedPtBits.Mapped, - MemoryPermission.Write => (ulong)HostMappedPtBits.WriteTracked, - _ => (ulong)HostMappedPtBits.ReadWriteTracked, - }; - - int bit = (int)((pageStart & 31) << 1); - - ulong tagMask = 3UL << bit; - ulong invTagMask = ~tagMask; - - ulong tag = protTag << bit; - - int pageIndex = (int)(pageStart >> PageToPteShift); - ref ulong pageRef = ref _pageBitmap[pageIndex]; - - ulong pte; - - do - { - pte = Volatile.Read(ref pageRef); - } - while ((pte & tagMask) != 0 && Interlocked.CompareExchange(ref pageRef, (pte & invTagMask) | tag, pte) != pte); + _addressSpace.Base.Reprotect(va, size, protection, false); } else { - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - ulong mask = startMask; - - ulong protTag = protection switch - { - MemoryPermission.None => (ulong)HostMappedPtBits.MappedReplicated, - MemoryPermission.Write => (ulong)HostMappedPtBits.WriteTrackedReplicated, - _ => (ulong)HostMappedPtBits.ReadWriteTrackedReplicated, - }; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - - ulong pte; - ulong mappedMask; - - // Change the protection of all 2 bit entries that are mapped. - do - { - pte = Volatile.Read(ref pageRef); - - mappedMask = pte | (pte >> 1); - mappedMask |= (mappedMask & BlockMappedMask) << 1; - mappedMask &= mask; // Only update mapped pages within the given range. - } - while (Interlocked.CompareExchange(ref pageRef, (pte & (~mappedMask)) | (protTag & mappedMask), pte) != pte); - - mask = ulong.MaxValue; - } + _pages.TrackingReprotect(va, size, protection); } - - protection = protection switch - { - MemoryPermission.None => MemoryPermission.ReadAndWrite, - MemoryPermission.Write => MemoryPermission.Read, - _ => MemoryPermission.None, - }; - - _addressSpace.Base.Reprotect(va, size, protection, false); } /// - public RegionHandle BeginTracking(ulong address, ulong size, int id) + public RegionHandle BeginTracking(ulong address, ulong size, int id, RegionFlags flags = RegionFlags.None) { - return Tracking.BeginTracking(address, size, id); + return Tracking.BeginTracking(address, size, id, flags); } /// - public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id) + public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id, RegionFlags flags = RegionFlags.None) { - return Tracking.BeginGranularTracking(address, size, handles, granularity, id); + return Tracking.BeginGranularTracking(address, size, handles, granularity, id, flags); } /// @@ -727,86 +438,6 @@ namespace Ryujinx.Cpu.Jit return Tracking.BeginSmartGranularTracking(address, size, granularity, id); } - /// - /// Adds the given address mapping to the page table. - /// - /// Virtual memory address - /// Size to be mapped - private void AddMapping(ulong va, ulong size) - { - int pages = GetPagesCount(va, size, out _); - ulong pageStart = va >> PageBits; - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - ulong mask = startMask; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - - ulong pte; - ulong mappedMask; - - // Map all 2-bit entries that are unmapped. - do - { - pte = Volatile.Read(ref pageRef); - - mappedMask = pte | (pte >> 1); - mappedMask |= (mappedMask & BlockMappedMask) << 1; - mappedMask |= ~mask; // Treat everything outside the range as mapped, thus unchanged. - } - while (Interlocked.CompareExchange(ref pageRef, (pte & mappedMask) | (BlockMappedMask & (~mappedMask)), pte) != pte); - - mask = ulong.MaxValue; - } - } - - /// - /// Removes the given address mapping from the page table. - /// - /// Virtual memory address - /// Size to be unmapped - private void RemoveMapping(ulong va, ulong size) - { - int pages = GetPagesCount(va, size, out _); - ulong pageStart = va >> PageBits; - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - startMask = ~startMask; - endMask = ~endMask; - - ulong mask = startMask; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask |= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - ulong pte; - - do - { - pte = Volatile.Read(ref pageRef); - } - while (Interlocked.CompareExchange(ref pageRef, pte & mask, pte) != pte); - - mask = 0; - } - } - /// /// Disposes of resources used by the memory manager. /// @@ -816,6 +447,16 @@ namespace Ryujinx.Cpu.Jit _memoryEh.Dispose(); } - private static void ThrowInvalidMemoryRegionException(string message) => throw new InvalidMemoryRegionException(message); + protected override Memory GetPhysicalAddressMemory(nuint pa, int size) + => _addressSpace.Mirror.GetMemory(pa, size); + + protected override Span GetPhysicalAddressSpan(nuint pa, int size) + => _addressSpace.Mirror.GetSpan(pa, size); + + protected override nuint TranslateVirtualAddressChecked(ulong va) + => (nuint)GetPhysicalAddressChecked(va); + + protected override nuint TranslateVirtualAddressUnchecked(ulong va) + => (nuint)GetPhysicalAddressInternal(va); } } diff --git a/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs b/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs index 03befa088..13382cbb3 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs @@ -1,82 +1,64 @@ using ARMeilleure.Memory; +using Ryujinx.Common.Memory; +using Ryujinx.Cpu.Jit.HostTracked; +using Ryujinx.Cpu.Signal; using Ryujinx.Memory; using Ryujinx.Memory.Range; using Ryujinx.Memory.Tracking; using System; +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Threading; namespace Ryujinx.Cpu.Jit { /// /// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region. /// - public sealed class MemoryManagerHostTracked : MemoryManagerBase, IWritableBlock, IMemoryManager, IVirtualMemoryManagerTracked + public sealed class MemoryManagerHostTracked : VirtualMemoryManagerRefCountedBase, IMemoryManager, IVirtualMemoryManagerTracked { - public const int PageBits = 12; - public const int PageSize = 1 << PageBits; - public const int PageMask = PageSize - 1; - - public const int PageToPteShift = 5; // 32 pages (2 bits each) in one ulong page table entry. - public const ulong BlockMappedMask = 0x5555555555555555; // First bit of each table entry set. - - private enum HostMappedPtBits : ulong - { - Unmapped = 0, - Mapped, - WriteTracked, - ReadWriteTracked, - - MappedReplicated = 0x5555555555555555, - WriteTrackedReplicated = 0xaaaaaaaaaaaaaaaa, - ReadWriteTrackedReplicated = ulong.MaxValue - } - private readonly InvalidAccessHandler _invalidAccessHandler; + private readonly bool _unsafeMode; private readonly MemoryBlock _backingMemory; - private readonly PageTable _pageTable; - - private readonly ulong[] _pageBitmap; public int AddressSpaceBits { get; } - public MemoryTracking Tracking { get; private set; } + public MemoryTracking Tracking { get; } - private const int PteSize = 8; + private readonly NativePageTable _nativePageTable; + private readonly Ryujinx.Cpu.Jit.HostTracked.AddressSpacePartitioned _addressSpace; - private readonly AddressSpacePartitioned _addressSpace; + private readonly ManagedPageFlags _pages; - public ulong AddressSpaceSize { get; } - - private readonly MemoryBlock _flatPageTable; + protected override ulong AddressSpaceSize { get; } /// - public bool Supports4KBPages => false; + public bool UsesPrivateAllocations => true; - public IntPtr PageTablePointer => _flatPageTable.Pointer; + public IntPtr PageTablePointer => _nativePageTable.PageTablePointer; - public MemoryManagerType Type => MemoryManagerType.HostTracked; + public MemoryManagerType Type => _unsafeMode ? MemoryManagerType.HostTrackedUnsafe : MemoryManagerType.HostTracked; public event Action UnmapEvent; /// - /// Creates a new instance of the host mapped memory manager. + /// Creates a new instance of the host tracked memory manager. /// /// Physical backing memory where virtual memory will be mapped to /// Size of the address space + /// True if unmanaged access should not be masked (unsafe), false otherwise. /// Optional function to handle invalid memory accesses - public MemoryManagerHostTracked(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler) + public MemoryManagerHostTracked(MemoryBlock backingMemory, ulong addressSpaceSize, bool unsafeMode, InvalidAccessHandler invalidAccessHandler) { - Tracking = new MemoryTracking(this, AddressSpacePartitioned.Use4KBProtection ? PageSize : (int)MemoryBlock.GetPageSize(), invalidAccessHandler); + bool useProtectionMirrors = MemoryBlock.GetPageSize() > PageSize; + + Tracking = new MemoryTracking(this, PageSize, invalidAccessHandler, useProtectionMirrors); _backingMemory = backingMemory; - _pageTable = new PageTable(); _invalidAccessHandler = invalidAccessHandler; - _addressSpace = new(Tracking, backingMemory, UpdatePt); + _unsafeMode = unsafeMode; AddressSpaceSize = addressSpaceSize; ulong asSize = PageSize; @@ -90,8 +72,81 @@ namespace Ryujinx.Cpu.Jit AddressSpaceBits = asBits; - _pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))]; - _flatPageTable = new MemoryBlock((asSize / PageSize) * PteSize); + if (useProtectionMirrors && !NativeSignalHandler.SupportsFaultAddressPatching()) + { + // Currently we require being able to change the fault address to something else + // in order to "emulate" 4KB granularity protection on systems with larger page size. + + throw new PlatformNotSupportedException(); + } + + _pages = new ManagedPageFlags(asBits); + _nativePageTable = new(asSize); + _addressSpace = new(Tracking, backingMemory, _nativePageTable, useProtectionMirrors); + } + + public override ReadOnlySequence GetReadOnlySequence(ulong va, int size, bool tracked = false) + { + if (size == 0) + { + return ReadOnlySequence.Empty; + } + + try + { + if (tracked) + { + SignalMemoryTracking(va, (ulong)size, false); + } + else + { + AssertValidAddressAndSize(va, (ulong)size); + } + + ulong endVa = va + (ulong)size; + int offset = 0; + + BytesReadOnlySequenceSegment first = null, last = null; + + while (va < endVa) + { + (MemoryBlock memory, ulong rangeOffset, ulong copySize) = GetMemoryOffsetAndSize(va, (ulong)(size - offset)); + + Memory physicalMemory = memory.GetMemory(rangeOffset, (int)copySize); + + if (first is null) + { + first = last = new BytesReadOnlySequenceSegment(physicalMemory); + } + else + { + if (last.IsContiguousWith(physicalMemory, out nuint contiguousStart, out int contiguousSize)) + { + Memory contiguousPhysicalMemory = new NativeMemoryManager(contiguousStart, contiguousSize).Memory; + + last.Replace(contiguousPhysicalMemory); + } + else + { + last = last.Append(physicalMemory); + } + } + + va += copySize; + offset += (int)copySize; + } + + return new ReadOnlySequence(first, 0, last, (int)(size - last.RunningIndex)); + } + catch (InvalidMemoryRegionException) + { + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } + + return ReadOnlySequence.Empty; + } } /// @@ -104,52 +159,12 @@ namespace Ryujinx.Cpu.Jit _addressSpace.Map(va, pa, size); } - AddMapping(va, size); - PtMap(va, pa, size, flags.HasFlag(MemoryMapFlags.Private)); + _pages.AddMapping(va, size); + _nativePageTable.Map(va, pa, size, _addressSpace, _backingMemory, flags.HasFlag(MemoryMapFlags.Private)); Tracking.Map(va, size); } - private void PtMap(ulong va, ulong pa, ulong size, bool privateMap) - { - while (size != 0) - { - _pageTable.Map(va, pa); - - if (privateMap) - { - _flatPageTable.Write((va / PageSize) * PteSize, (ulong)_addressSpace.GetPointer(va, PageSize) - va); - } - else - { - _flatPageTable.Write((va / PageSize) * PteSize, (ulong)_backingMemory.GetPointer(pa, PageSize) - va); - } - - va += PageSize; - pa += PageSize; - size -= PageSize; - } - } - - private void UpdatePt(ulong va, IntPtr ptr, ulong size) - { - ulong remainingSize = size; - while (remainingSize != 0) - { - _flatPageTable.Write((va / PageSize) * PteSize, (ulong)ptr - va); - - va += PageSize; - ptr += PageSize; - remainingSize -= PageSize; - } - } - - /// - public void MapForeign(ulong va, nuint hostPointer, ulong size) - { - throw new NotSupportedException(); - } - /// public void Unmap(ulong va, ulong size) { @@ -160,70 +175,15 @@ namespace Ryujinx.Cpu.Jit UnmapEvent?.Invoke(va, size); Tracking.Unmap(va, size); - RemoveMapping(va, size); - PtUnmap(va, size); + _pages.RemoveMapping(va, size); + _nativePageTable.Unmap(va, size); } - private void PtUnmap(ulong va, ulong size) - { - while (size != 0) - { - _pageTable.Unmap(va); - _flatPageTable.Write((va / PageSize) * PteSize, 0UL); - - va += PageSize; - size -= PageSize; - } - } - - /// - /// Checks if the virtual address is part of the addressable space. - /// - /// Virtual address - /// True if the virtual address is part of the addressable space - private bool ValidateAddress(ulong va) - { - return va < AddressSpaceSize; - } - - /// - /// Checks if the combination of virtual address and size is part of the addressable space. - /// - /// Virtual address of the range - /// Size of the range in bytes - /// True if the combination of virtual address and size is part of the addressable space - private bool ValidateAddressAndSize(ulong va, ulong size) - { - ulong endVa = va + size; - return endVa >= va && endVa >= size && endVa <= AddressSpaceSize; - } - - /// - /// Ensures the combination of virtual address and size is part of the addressable space. - /// - /// Virtual address of the range - /// Size of the range in bytes - /// Throw when the memory region specified outside the addressable space - private void AssertValidAddressAndSize(ulong va, ulong size) - { - if (!ValidateAddressAndSize(va, size)) - { - throw new InvalidMemoryRegionException($"va=0x{va:X16}, size=0x{size:X16}"); - } - } - - public T Read(ulong va) where T : unmanaged - { - return MemoryMarshal.Cast(GetSpan(va, Unsafe.SizeOf()))[0]; - } - - public T ReadTracked(ulong va) where T : unmanaged + public override T ReadTracked(ulong va) { try { - SignalMemoryTracking(va, (ulong)Unsafe.SizeOf(), false); - - return Read(va); + return base.ReadTracked(va); } catch (InvalidMemoryRegionException) { @@ -236,39 +196,40 @@ namespace Ryujinx.Cpu.Jit } } - public void Read(ulong va, Span data) - { - ReadImpl(va, data); - } - - public void Write(ulong va, T value) where T : unmanaged - { - Write(va, MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref value, 1))); - } - - public void Write(ulong va, ReadOnlySpan data) + public override void Read(ulong va, Span data) { if (data.Length == 0) { return; } - SignalMemoryTracking(va, (ulong)data.Length, true); - - WriteImpl(va, data); - } - - public void WriteUntracked(ulong va, ReadOnlySpan data) - { - if (data.Length == 0) + try { - return; - } + AssertValidAddressAndSize(va, (ulong)data.Length); - WriteImpl(va, data); + ulong endVa = va + (ulong)data.Length; + int offset = 0; + + while (va < endVa) + { + (MemoryBlock memory, ulong rangeOffset, ulong copySize) = GetMemoryOffsetAndSize(va, (ulong)(data.Length - offset)); + + memory.GetSpan(rangeOffset, (int)copySize).CopyTo(data.Slice(offset, (int)copySize)); + + va += copySize; + offset += (int)copySize; + } + } + catch (InvalidMemoryRegionException) + { + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } + } } - public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan data) + public override bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan data) { if (data.Length == 0) { @@ -298,35 +259,7 @@ namespace Ryujinx.Cpu.Jit } } - private void WriteImpl(ulong va, ReadOnlySpan data) - { - try - { - AssertValidAddressAndSize(va, (ulong)data.Length); - - ulong endVa = va + (ulong)data.Length; - int offset = 0; - - while (va < endVa) - { - (MemoryBlock memory, ulong rangeOffset, ulong copySize) = GetMemoryOffsetAndSize(va, (ulong)(data.Length - offset)); - - data.Slice(offset, (int)copySize).CopyTo(memory.GetSpan(rangeOffset, (int)copySize)); - - va += copySize; - offset += (int)copySize; - } - } - catch (InvalidMemoryRegionException) - { - if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) - { - throw; - } - } - } - - public ReadOnlySpan GetSpan(ulong va, int size, bool tracked = false) + public override ReadOnlySpan GetSpan(ulong va, int size, bool tracked = false) { if (size == 0) { @@ -346,13 +279,13 @@ namespace Ryujinx.Cpu.Jit { Span data = new byte[size]; - ReadImpl(va, data); + Read(va, data); return data; } } - public WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) + public override WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) { if (size == 0) { @@ -370,11 +303,11 @@ namespace Ryujinx.Cpu.Jit } else { - Memory memory = new byte[size]; + MemoryOwner memoryOwner = MemoryOwner.Rent(size); - ReadImpl(va, memory.Span); + Read(va, memoryOwner.Span); - return new WritableRegion(this, va, memory); + return new WritableRegion(this, va, memoryOwner); } } @@ -391,92 +324,24 @@ namespace Ryujinx.Cpu.Jit } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsMapped(ulong va) + public override bool IsMapped(ulong va) { - return ValidateAddress(va) && IsMappedImpl(va); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsMappedImpl(ulong va) - { - ulong page = va >> PageBits; - - int bit = (int)((page & 31) << 1); - - int pageIndex = (int)(page >> PageToPteShift); - ref ulong pageRef = ref _pageBitmap[pageIndex]; - - ulong pte = Volatile.Read(ref pageRef); - - return ((pte >> bit) & 3) != 0; + return ValidateAddress(va) && _pages.IsMapped(va); } public bool IsRangeMapped(ulong va, ulong size) { AssertValidAddressAndSize(va, size); - return IsRangeMappedImpl(va, size); + return _pages.IsRangeMapped(va, size); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void GetPageBlockRange(ulong pageStart, ulong pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex) - { - startMask = ulong.MaxValue << ((int)(pageStart & 31) << 1); - endMask = ulong.MaxValue >> (64 - ((int)(pageEnd & 31) << 1)); - - pageIndex = (int)(pageStart >> PageToPteShift); - pageEndIndex = (int)((pageEnd - 1) >> PageToPteShift); - } - - private bool IsRangeMappedImpl(ulong va, ulong size) - { - int pages = GetPagesCount(va, size, out _); - - if (pages == 1) - { - return IsMappedImpl(va); - } - - ulong pageStart = va >> PageBits; - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - // Check if either bit in each 2 bit page entry is set. - // OR the block with itself shifted down by 1, and check the first bit of each entry. - - ulong mask = BlockMappedMask & startMask; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - ulong pte = Volatile.Read(ref pageRef); - - pte |= pte >> 1; - if ((pte & mask) != mask) - { - return false; - } - - mask = BlockMappedMask; - } - - return true; - } - - private static void ThrowMemoryNotContiguous() => throw new MemoryNotContiguousException(); - private bool TryGetVirtualContiguous(ulong va, int size, out MemoryBlock memory, out ulong offset) { - if (_addressSpace.HasAnyPrivateAllocation(va, (ulong)size, out PrivateRange range)) + if (_addressSpace.HasAnyPrivateAllocation(va, (ulong)size, out Ryujinx.Cpu.Jit.HostTracked.PrivateRange range)) { // If we have a private allocation overlapping the range, - // this the access is only considered contiguous if it covers the entire range. + // then the access is only considered contiguous if it covers the entire range. if (range.Memory != null) { @@ -559,9 +424,7 @@ namespace Ryujinx.Cpu.Jit private (MemoryBlock, ulong, ulong) GetMemoryOffsetAndSize(ulong va, ulong size) { - ulong endVa = va + size; - - PrivateRange privateRange = _addressSpace.GetFirstPrivateAllocation(va, size, out ulong nextVa); + Ryujinx.Cpu.Jit.HostTracked.PrivateRange privateRange = _addressSpace.GetFirstPrivateAllocation(va, size, out ulong nextVa); if (privateRange.Memory != null) { @@ -570,7 +433,7 @@ namespace Ryujinx.Cpu.Jit ulong physSize = GetContiguousSize(va, Math.Min(size, nextVa - va)); - return new(_backingMemory, GetPhysicalAddressChecked(va), physSize); + return (_backingMemory, GetPhysicalAddressChecked(va), physSize); } public IEnumerable GetHostRegions(ulong va, ulong size) @@ -651,44 +514,11 @@ namespace Ryujinx.Cpu.Jit return regions; } - private void ReadImpl(ulong va, Span data) - { - if (data.Length == 0) - { - return; - } - - try - { - AssertValidAddressAndSize(va, (ulong)data.Length); - - ulong endVa = va + (ulong)data.Length; - int offset = 0; - - while (va < endVa) - { - (MemoryBlock memory, ulong rangeOffset, ulong copySize) = GetMemoryOffsetAndSize(va, (ulong)(data.Length - offset)); - - memory.GetSpan(rangeOffset, (int)copySize).CopyTo(data.Slice(offset, (int)copySize)); - - va += copySize; - offset += (int)copySize; - } - } - catch (InvalidMemoryRegionException) - { - if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) - { - throw; - } - } - } - /// /// /// This function also validates that the given range is both valid and mapped, and will throw if it is not. /// - public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) + public override void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) { AssertValidAddressAndSize(va, size); @@ -700,101 +530,17 @@ namespace Ryujinx.Cpu.Jit // Software table, used for managed memory tracking. - int pages = GetPagesCount(va, size, out _); - ulong pageStart = va >> PageBits; - - if (pages == 1) - { - ulong tag = (ulong)(write ? HostMappedPtBits.WriteTracked : HostMappedPtBits.ReadWriteTracked); - - int bit = (int)((pageStart & 31) << 1); - - int pageIndex = (int)(pageStart >> PageToPteShift); - ref ulong pageRef = ref _pageBitmap[pageIndex]; - - ulong pte = Volatile.Read(ref pageRef); - ulong state = ((pte >> bit) & 3); - - if (state >= tag) - { - Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId); - return; - } - else if (state == 0) - { - ThrowInvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}"); - } - } - else - { - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - ulong mask = startMask; - - ulong anyTrackingTag = (ulong)HostMappedPtBits.WriteTrackedReplicated; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - - ulong pte = Volatile.Read(ref pageRef); - ulong mappedMask = mask & BlockMappedMask; - - ulong mappedPte = pte | (pte >> 1); - if ((mappedPte & mappedMask) != mappedMask) - { - ThrowInvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}"); - } - - pte &= mask; - if ((pte & anyTrackingTag) != 0) // Search for any tracking. - { - // Writes trigger any tracking. - // Only trigger tracking from reads if both bits are set on any page. - if (write || (pte & (pte >> 1) & BlockMappedMask) != 0) - { - Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId); - break; - } - } - - mask = ulong.MaxValue; - } - } + _pages.SignalMemoryTracking(Tracking, va, size, write, exemptId); } - /// - /// Computes the number of pages in a virtual address range. - /// - /// Virtual address of the range - /// Size of the range - /// The virtual address of the beginning of the first page - /// This function does not differentiate between allocated and unallocated pages. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int GetPagesCount(ulong va, ulong size, out ulong startVa) + public RegionHandle BeginTracking(ulong address, ulong size, int id, RegionFlags flags = RegionFlags.None) { - // WARNING: Always check if ulong does not overflow during the operations. - startVa = va & ~(ulong)PageMask; - ulong vaSpan = (va - startVa + size + PageMask) & ~(ulong)PageMask; - - return (int)(vaSpan / PageSize); + return Tracking.BeginTracking(address, size, id, flags); } - public RegionHandle BeginTracking(ulong address, ulong size, int id) + public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id, RegionFlags flags = RegionFlags.None) { - return Tracking.BeginTracking(address, size, id); - } - - public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id) - { - return Tracking.BeginGranularTracking(address, size, handles, granularity, id); + return Tracking.BeginGranularTracking(address, size, handles, granularity, id, flags); } public SmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity, int id) @@ -802,86 +548,6 @@ namespace Ryujinx.Cpu.Jit return Tracking.BeginSmartGranularTracking(address, size, granularity, id); } - /// - /// Adds the given address mapping to the page table. - /// - /// Virtual memory address - /// Size to be mapped - private void AddMapping(ulong va, ulong size) - { - int pages = GetPagesCount(va, size, out _); - ulong pageStart = va >> PageBits; - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - ulong mask = startMask; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - - ulong pte; - ulong mappedMask; - - // Map all 2-bit entries that are unmapped. - do - { - pte = Volatile.Read(ref pageRef); - - mappedMask = pte | (pte >> 1); - mappedMask |= (mappedMask & BlockMappedMask) << 1; - mappedMask |= ~mask; // Treat everything outside the range as mapped, thus unchanged. - } - while (Interlocked.CompareExchange(ref pageRef, (pte & mappedMask) | (BlockMappedMask & (~mappedMask)), pte) != pte); - - mask = ulong.MaxValue; - } - } - - /// - /// Removes the given address mapping from the page table. - /// - /// Virtual memory address - /// Size to be unmapped - private void RemoveMapping(ulong va, ulong size) - { - int pages = GetPagesCount(va, size, out _); - ulong pageStart = va >> PageBits; - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - startMask = ~startMask; - endMask = ~endMask; - - ulong mask = startMask; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask |= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - ulong pte; - - do - { - pte = Volatile.Read(ref pageRef); - } - while (Interlocked.CompareExchange(ref pageRef, pte & mask, pte) != pte); - - mask = 0; - } - } - private ulong GetPhysicalAddressChecked(ulong va) { if (!IsMapped(va)) @@ -894,11 +560,9 @@ namespace Ryujinx.Cpu.Jit private ulong GetPhysicalAddressInternal(ulong va) { - return _pageTable.Read(va) + (va & PageMask); + return _nativePageTable.GetPhysicalAddress(va); } - private static void ThrowInvalidMemoryRegionException(string message) => throw new InvalidMemoryRegionException(message); - /// public void Reprotect(ulong va, ulong size, MemoryPermission protection) { @@ -906,91 +570,16 @@ namespace Ryujinx.Cpu.Jit } /// - public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection) + public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection, bool guest) { - // Protection is inverted on software pages, since the default value is 0. - protection = (~protection) & MemoryPermission.ReadAndWrite; - - int pages = GetPagesCount(va, size, out va); - ulong pageStart = va >> PageBits; - - if (pages == 1) + if (guest) { - ulong protTag = protection switch - { - MemoryPermission.None => (ulong)HostMappedPtBits.Mapped, - MemoryPermission.Write => (ulong)HostMappedPtBits.WriteTracked, - _ => (ulong)HostMappedPtBits.ReadWriteTracked, - }; - - int bit = (int)((pageStart & 31) << 1); - - ulong tagMask = 3UL << bit; - ulong invTagMask = ~tagMask; - - ulong tag = protTag << bit; - - int pageIndex = (int)(pageStart >> PageToPteShift); - ref ulong pageRef = ref _pageBitmap[pageIndex]; - - ulong pte; - - do - { - pte = Volatile.Read(ref pageRef); - } - while ((pte & tagMask) != 0 && Interlocked.CompareExchange(ref pageRef, (pte & invTagMask) | tag, pte) != pte); + _addressSpace.Reprotect(va, size, protection); } else { - ulong pageEnd = pageStart + (ulong)pages; - - GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); - - ulong mask = startMask; - - ulong protTag = protection switch - { - MemoryPermission.None => (ulong)HostMappedPtBits.MappedReplicated, - MemoryPermission.Write => (ulong)HostMappedPtBits.WriteTrackedReplicated, - _ => (ulong)HostMappedPtBits.ReadWriteTrackedReplicated, - }; - - while (pageIndex <= pageEndIndex) - { - if (pageIndex == pageEndIndex) - { - mask &= endMask; - } - - ref ulong pageRef = ref _pageBitmap[pageIndex++]; - - ulong pte; - ulong mappedMask; - - // Change the protection of all 2 bit entries that are mapped. - do - { - pte = Volatile.Read(ref pageRef); - - mappedMask = pte | (pte >> 1); - mappedMask |= (mappedMask & BlockMappedMask) << 1; - mappedMask &= mask; // Only update mapped pages within the given range. - } - while (Interlocked.CompareExchange(ref pageRef, (pte & (~mappedMask)) | (protTag & mappedMask), pte) != pte); - - mask = ulong.MaxValue; - } + _pages.TrackingReprotect(va, size, protection); } - - protection = protection switch - { - MemoryPermission.None => MemoryPermission.ReadAndWrite, - MemoryPermission.Write => MemoryPermission.Read, - _ => MemoryPermission.None, - }; - - _addressSpace.Reprotect(va, size, protection); } /// @@ -999,6 +588,47 @@ namespace Ryujinx.Cpu.Jit protected override void Destroy() { _addressSpace.Dispose(); + _nativePageTable.Dispose(); } + + protected override Memory GetPhysicalAddressMemory(nuint pa, int size) + => _backingMemory.GetMemory(pa, size); + + protected override Span GetPhysicalAddressSpan(nuint pa, int size) + => _backingMemory.GetSpan(pa, size); + + protected override void WriteImpl(ulong va, ReadOnlySpan data) + { + try + { + AssertValidAddressAndSize(va, (ulong)data.Length); + + ulong endVa = va + (ulong)data.Length; + int offset = 0; + + while (va < endVa) + { + (MemoryBlock memory, ulong rangeOffset, ulong copySize) = GetMemoryOffsetAndSize(va, (ulong)(data.Length - offset)); + + data.Slice(offset, (int)copySize).CopyTo(memory.GetSpan(rangeOffset, (int)copySize)); + + va += copySize; + offset += (int)copySize; + } + } + catch (InvalidMemoryRegionException) + { + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } + } + } + + protected override nuint TranslateVirtualAddressChecked(ulong va) + => (nuint)GetPhysicalAddressChecked(va); + + protected override nuint TranslateVirtualAddressUnchecked(ulong va) + => (nuint)GetPhysicalAddressInternal(va); } } diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Block.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Block.cs index 4729f6940..c4568995c 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Block.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Block.cs @@ -10,6 +10,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 public readonly List Instructions; public readonly bool EndsWithBranch; public readonly bool HasHostCall; + public readonly bool HasHostCallSkipContext; public readonly bool IsTruncated; public readonly bool IsLoopEnd; public readonly bool IsThumb; @@ -20,6 +21,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 List instructions, bool endsWithBranch, bool hasHostCall, + bool hasHostCallSkipContext, bool isTruncated, bool isLoopEnd, bool isThumb) @@ -31,6 +33,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 Instructions = instructions; EndsWithBranch = endsWithBranch; HasHostCall = hasHostCall; + HasHostCallSkipContext = hasHostCallSkipContext; IsTruncated = isTruncated; IsLoopEnd = isLoopEnd; IsThumb = isThumb; @@ -57,6 +60,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 Instructions.GetRange(0, splitIndex), false, HasHostCall, + HasHostCallSkipContext, false, false, IsThumb); @@ -67,6 +71,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 Instructions.GetRange(splitIndex, splitCount), EndsWithBranch, HasHostCall, + HasHostCallSkipContext, IsTruncated, IsLoopEnd, IsThumb); diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs index afd2c021f..8a2b389ad 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs @@ -208,6 +208,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 InstMeta meta; InstFlags extraFlags = InstFlags.None; bool hasHostCall = false; + bool hasHostCallSkipContext = false; bool isTruncated = false; do @@ -246,9 +247,17 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 meta = InstTableA32.GetMeta(encoding, cpuPreset.Version, cpuPreset.Features); } - if (meta.Name.IsSystemOrCall() && !hasHostCall) + if (meta.Name.IsSystemOrCall()) { - hasHostCall = meta.Name.IsCall() || InstEmitSystem.NeedsCall(meta.Name); + if (!hasHostCall) + { + hasHostCall = InstEmitSystem.NeedsCall(meta.Name); + } + + if (!hasHostCallSkipContext) + { + hasHostCallSkipContext = meta.Name.IsCall() || InstEmitSystem.NeedsCallSkipContext(meta.Name); + } } insts.Add(new(encoding, meta.Name, meta.EmitFunc, meta.Flags | extraFlags)); @@ -259,8 +268,8 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 if (!isTruncated && IsBackwardsBranch(meta.Name, encoding)) { - hasHostCall = true; isLoopEnd = true; + hasHostCallSkipContext = true; } return new( @@ -269,6 +278,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 insts, !isTruncated, hasHostCall, + hasHostCallSkipContext, isTruncated, isLoopEnd, isThumb); @@ -415,7 +425,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 private static bool IsRtWrite(InstName name, uint encoding) { - // Some instruction can move GPR to FP/SIMD or FP/SIMD to GPR depending on the encoding. + // Some instructions can move GPR to FP/SIMD or FP/SIMD to GPR depending on the encoding. // Detect those cases so that we can tell if we're actually doing a register write. switch (name) diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/MultiBlock.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/MultiBlock.cs index a213c222c..ca25057fe 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/MultiBlock.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/MultiBlock.cs @@ -6,6 +6,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 { public readonly List Blocks; public readonly bool HasHostCall; + public readonly bool HasHostCallSkipContext; public readonly bool IsTruncated; public MultiBlock(List blocks) @@ -15,12 +16,14 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 Block block = blocks[0]; HasHostCall = block.HasHostCall; + HasHostCallSkipContext = block.HasHostCallSkipContext; for (int index = 1; index < blocks.Count; index++) { block = blocks[index]; HasHostCall |= block.HasHostCall; + HasHostCallSkipContext |= block.HasHostCallSkipContext; } block = blocks[^1]; diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterAllocator.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterAllocator.cs index 6c7057229..4a3f03b8a 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterAllocator.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterAllocator.cs @@ -106,6 +106,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 if ((regMask & AbiConstants.ReservedRegsMask) == 0) { _gprMask |= regMask; + UsedGprsMask |= regMask; return firstCalleeSaved; } diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs index 1e8a89157..a668b5777 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs @@ -305,12 +305,23 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 ForceConditionalEnd(cgContext, ref lastCondition, lastConditionIp); } + int reservedStackSize = 0; + + if (multiBlock.HasHostCall) + { + reservedStackSize = CalculateStackSizeForCallSpill(regAlloc.UsedGprsMask, regAlloc.UsedFpSimdMask, UsablePStateMask); + } + else if (multiBlock.HasHostCallSkipContext) + { + reservedStackSize = 2 * sizeof(ulong); // Context and page table pointers. + } + RegisterSaveRestore rsr = new( regAlloc.UsedGprsMask & AbiConstants.GprCalleeSavedRegsMask, regAlloc.UsedFpSimdMask & AbiConstants.FpSimdCalleeSavedRegsMask, OperandType.FP64, - multiBlock.HasHostCall, - multiBlock.HasHostCall ? CalculateStackSizeForCallSpill(regAlloc.UsedGprsMask, regAlloc.UsedFpSimdMask, UsablePStateMask) : 0); + multiBlock.HasHostCall || multiBlock.HasHostCallSkipContext, + reservedStackSize); TailMerger tailMerger = new(); @@ -596,7 +607,8 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 name == InstName.Ldm || name == InstName.Ldmda || name == InstName.Ldmdb || - name == InstName.Ldmib) + name == InstName.Ldmib || + name == InstName.Pop) { // Arm32 does not have a return instruction, instead returns are implemented // either using BX LR (for leaf functions), or POP { ... PC }. @@ -711,7 +723,14 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 switch (type) { case BranchType.SyncPoint: - InstEmitSystem.WriteSyncPoint(context.Writer, context.RegisterAllocator, context.TailMerger, context.GetReservedStackOffset()); + InstEmitSystem.WriteSyncPoint( + context.Writer, + ref asm, + context.RegisterAllocator, + context.TailMerger, + context.GetReservedStackOffset(), + context.StoreToContext, + context.LoadFromContext); break; case BranchType.SoftwareInterrupt: context.StoreToContext(); diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs index 81e44ba00..3b1ff5a2a 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs @@ -199,12 +199,12 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 } } - private static void WriteSpillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) + public static void WriteSpillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) { WriteSpillOrFillSkipContext(ref asm, regAlloc, spillOffset, spill: true); } - private static void WriteFillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) + public static void WriteFillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) { WriteSpillOrFillSkipContext(ref asm, regAlloc, spillOffset, spill: false); } diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs index 54e156d74..d8caee6e7 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs @@ -1126,7 +1126,10 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 Operand destination64 = new(destination.Kind, OperandType.I64, destination.Value); Operand basePointer = new(regAlloc.FixedPageTableRegister, RegisterType.Integer, OperandType.I64); - if (mmType == MemoryManagerType.HostTracked) + // We don't need to mask the address for the safe mode, since it is already naturally limited to 32-bit + // and can never reach out of the guest address space. + + if (mmType.IsHostTracked()) { int tempRegister = regAlloc.AllocateTempGprRegister(); @@ -1138,7 +1141,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 regAlloc.FreeTempGprRegister(tempRegister); } - else if (mmType == MemoryManagerType.HostMapped || mmType == MemoryManagerType.HostMappedUnsafe) + else if (mmType.IsHostMapped()) { asm.Add(destination64, basePointer, guestAddress); } diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMove.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMove.cs index 88850cb33..d57750fc1 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMove.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMove.cs @@ -1,6 +1,5 @@ using Ryujinx.Cpu.LightningJit.CodeGen; using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; -using System.Diagnostics; namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 { diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMemory.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMemory.cs index 7f997b604..e77dc0a29 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMemory.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMemory.cs @@ -717,6 +717,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 } } + [Conditional("DEBUG")] private static void AssertSequentialRegisters(ReadOnlySpan registers) { for (int index = 1; index < registers.Length; index++) diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSaturate.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSaturate.cs index e2354f448..f1b6e395b 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSaturate.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSaturate.cs @@ -114,7 +114,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 InstEmitCommon.EmitUnsigned16BitPair(context, rd, rn, rm, (d, n, m) => { context.Arm64Assembler.Add(d, n, m); - EmitSaturateUnsignedRange(context, d, 16); + EmitSaturateUqadd(context, d, 16); }); } @@ -123,7 +123,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 InstEmitCommon.EmitUnsigned8BitPair(context, rd, rn, rm, (d, n, m) => { context.Arm64Assembler.Add(d, n, m); - EmitSaturateUnsignedRange(context, d, 8); + EmitSaturateUqadd(context, d, 8); }); } @@ -140,7 +140,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 context.Arm64Assembler.Add(d, n, m); } - EmitSaturateUnsignedRange(context, d, 16); + EmitSaturateUq(context, d, 16, e == 0); }); } @@ -157,25 +157,25 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 context.Arm64Assembler.Sub(d, n, m); } - EmitSaturateUnsignedRange(context, d, 16); + EmitSaturateUq(context, d, 16, e != 0); }); } public static void Uqsub16(CodeGenContext context, uint rd, uint rn, uint rm) { - InstEmitCommon.EmitSigned16BitPair(context, rd, rn, rm, (d, n, m) => + InstEmitCommon.EmitUnsigned16BitPair(context, rd, rn, rm, (d, n, m) => { context.Arm64Assembler.Sub(d, n, m); - EmitSaturateUnsignedRange(context, d, 16); + EmitSaturateUqsub(context, d, 16); }); } public static void Uqsub8(CodeGenContext context, uint rd, uint rn, uint rm) { - InstEmitCommon.EmitSigned8BitPair(context, rd, rn, rm, (d, n, m) => + InstEmitCommon.EmitUnsigned8BitPair(context, rd, rn, rm, (d, n, m) => { context.Arm64Assembler.Sub(d, n, m); - EmitSaturateUnsignedRange(context, d, 8); + EmitSaturateUqsub(context, d, 8); }); } @@ -358,7 +358,17 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 } } - private static void EmitSaturateUnsignedRange(CodeGenContext context, Operand value, uint saturateTo) + private static void EmitSaturateUqadd(CodeGenContext context, Operand value, uint saturateTo) + { + EmitSaturateUq(context, value, saturateTo, isSub: false); + } + + private static void EmitSaturateUqsub(CodeGenContext context, Operand value, uint saturateTo) + { + EmitSaturateUq(context, value, saturateTo, isSub: true); + } + + private static void EmitSaturateUq(CodeGenContext context, Operand value, uint saturateTo, bool isSub) { Debug.Assert(saturateTo <= 32); @@ -379,7 +389,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 return; } - context.Arm64Assembler.Lsr(tempRegister.Operand, value, InstEmitCommon.Const(32 - (int)saturateTo)); + context.Arm64Assembler.Lsr(tempRegister.Operand, value, InstEmitCommon.Const((int)saturateTo)); int branchIndex = context.CodeWriter.InstructionPointer; @@ -387,7 +397,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 context.Arm64Assembler.Cbz(tempRegister.Operand, 0); // Saturate. - context.Arm64Assembler.Mov(value, uint.MaxValue >> (32 - (int)saturateTo)); + context.Arm64Assembler.Mov(value, isSub ? 0u : uint.MaxValue >> (32 - (int)saturateTo)); int delta = context.CodeWriter.InstructionPointer - branchIndex; context.CodeWriter.WriteInstructionAt(branchIndex, context.CodeWriter.ReadInstructionAt(branchIndex) | (uint)((delta & 0x7ffff) << 5)); diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs index 220f35d4b..07f9f86a8 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs @@ -354,11 +354,18 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 // All instructions that might do a host call should be included here. // That is required to reserve space on the stack for caller saved registers. + return name == InstName.Mrrc; + } + + public static bool NeedsCallSkipContext(InstName name) + { + // All instructions that might do a host call should be included here. + // That is required to reserve space on the stack for caller saved registers. + switch (name) { case InstName.Mcr: case InstName.Mrc: - case InstName.Mrrc: case InstName.Svc: case InstName.Udf: return true; @@ -372,7 +379,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 Assembler asm = new(writer); WriteCall(ref asm, regAlloc, GetBkptHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, imm); - WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: true, spillBaseOffset); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); } public static void WriteSvc(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset, uint pc, uint svcId) @@ -380,7 +387,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 Assembler asm = new(writer); WriteCall(ref asm, regAlloc, GetSvcHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, svcId); - WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: true, spillBaseOffset); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); } public static void WriteUdf(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset, uint pc, uint imm) @@ -388,7 +395,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 Assembler asm = new(writer); WriteCall(ref asm, regAlloc, GetUdfHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, imm); - WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: true, spillBaseOffset); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); } public static void WriteReadCntpct(CodeWriter writer, RegisterAllocator regAlloc, int spillBaseOffset, int rt, int rt2) @@ -422,14 +429,14 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 WriteFill(ref asm, regAlloc, resultMask, skipContext: false, spillBaseOffset, tempRegister); } - public static void WriteSyncPoint(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset) - { - Assembler asm = new(writer); - - WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: false, spillBaseOffset); - } - - private static void WriteSyncPoint(CodeWriter writer, ref Assembler asm, RegisterAllocator regAlloc, TailMerger tailMerger, bool skipContext, int spillBaseOffset) + public static void WriteSyncPoint( + CodeWriter writer, + ref Assembler asm, + RegisterAllocator regAlloc, + TailMerger tailMerger, + int spillBaseOffset, + Action storeToContext = null, + Action loadFromContext = null) { int tempRegister = regAlloc.AllocateTempGprRegister(); @@ -440,7 +447,8 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 int branchIndex = writer.InstructionPointer; asm.Cbnz(rt, 0); - WriteSpill(ref asm, regAlloc, 1u << tempRegister, skipContext, spillBaseOffset, tempRegister); + storeToContext?.Invoke(); + WriteSpill(ref asm, regAlloc, 1u << tempRegister, skipContext: true, spillBaseOffset, tempRegister); Operand rn = Register(tempRegister == 0 ? 1 : 0); @@ -449,7 +457,8 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 tailMerger.AddConditionalZeroReturn(writer, asm, Register(0, OperandType.I32)); - WriteFill(ref asm, regAlloc, 1u << tempRegister, skipContext, spillBaseOffset, tempRegister); + WriteFill(ref asm, regAlloc, 1u << tempRegister, skipContext: true, spillBaseOffset, tempRegister); + loadFromContext?.Invoke(); asm.LdrRiUn(rt, Register(regAlloc.FixedContextRegister), NativeContextOffsets.CounterOffset); @@ -489,8 +498,8 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 // We only support up to 7 arguments right now. // ABI defines the first 8 integer arguments to be passed on registers X0-X7. - // We need at least one regiser to put the function address on, so that reduces the amount of - // register we can use for that by one. + // We need at least one register to put the function address on, so that reduces the number of + // registers we can use for that by one. Debug.Assert(callArgs.Length < 8); @@ -514,18 +523,31 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 private static void WriteSpill(ref Assembler asm, RegisterAllocator regAlloc, uint exceptMask, bool skipContext, int spillOffset, int tempRegister) { - WriteSpillOrFill(ref asm, regAlloc, skipContext, exceptMask, spillOffset, tempRegister, spill: true); + if (skipContext) + { + InstEmitFlow.WriteSpillSkipContext(ref asm, regAlloc, spillOffset); + } + else + { + WriteSpillOrFill(ref asm, regAlloc, exceptMask, spillOffset, tempRegister, spill: true); + } } private static void WriteFill(ref Assembler asm, RegisterAllocator regAlloc, uint exceptMask, bool skipContext, int spillOffset, int tempRegister) { - WriteSpillOrFill(ref asm, regAlloc, skipContext, exceptMask, spillOffset, tempRegister, spill: false); + if (skipContext) + { + InstEmitFlow.WriteFillSkipContext(ref asm, regAlloc, spillOffset); + } + else + { + WriteSpillOrFill(ref asm, regAlloc, exceptMask, spillOffset, tempRegister, spill: false); + } } private static void WriteSpillOrFill( ref Assembler asm, RegisterAllocator regAlloc, - bool skipContext, uint exceptMask, int spillOffset, int tempRegister, @@ -533,11 +555,6 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 { uint gprMask = regAlloc.UsedGprsMask & ~(AbiConstants.GprCalleeSavedRegsMask | exceptMask); - if (skipContext) - { - gprMask &= ~Compiler.UsableGprsMask; - } - if (!spill) { // We must reload the status register before reloading the GPRs, @@ -600,11 +617,6 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 uint fpSimdMask = regAlloc.UsedFpSimdMask; - if (skipContext) - { - fpSimdMask &= ~Compiler.UsableFpSimdMask; - } - while (fpSimdMask != 0) { int reg = BitOperations.TrailingZeroCount(fpSimdMask); diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/InstName.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/InstName.cs index 58d78ae6e..3391a2c14 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm64/InstName.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/InstName.cs @@ -1106,6 +1106,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64 case InstName.Mrs: case InstName.MsrImm: case InstName.MsrReg: + case InstName.Sysl: return true; } @@ -1130,5 +1131,37 @@ namespace Ryujinx.Cpu.LightningJit.Arm64 return false; } + + public static bool IsPartialRegisterUpdateMemory(this InstName name) + { + switch (name) + { + case InstName.Ld1AdvsimdSnglAsNoPostIndex: + case InstName.Ld1AdvsimdSnglAsPostIndex: + case InstName.Ld2AdvsimdSnglAsNoPostIndex: + case InstName.Ld2AdvsimdSnglAsPostIndex: + case InstName.Ld3AdvsimdSnglAsNoPostIndex: + case InstName.Ld3AdvsimdSnglAsPostIndex: + case InstName.Ld4AdvsimdSnglAsNoPostIndex: + case InstName.Ld4AdvsimdSnglAsPostIndex: + return true; + } + + return false; + } + + public static bool IsPrefetchMemory(this InstName name) + { + switch (name) + { + case InstName.PrfmImm: + case InstName.PrfmLit: + case InstName.PrfmReg: + case InstName.Prfum: + return true; + } + + return false; + } } } diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterAllocator.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterAllocator.cs index 0a2b4f7aa..1c6eab0de 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterAllocator.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterAllocator.cs @@ -1,15 +1,12 @@ +using ARMeilleure.Memory; using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; using System; -using System.Diagnostics; using System.Numerics; namespace Ryujinx.Cpu.LightningJit.Arm64 { class RegisterAllocator { - public const int MaxTemps = 2; - public const int MaxTempsInclFixed = MaxTemps + 2; - private uint _gprMask; private readonly uint _fpSimdMask; private readonly uint _pStateMask; @@ -25,7 +22,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64 public uint AllFpSimdMask => _fpSimdMask; public uint AllPStateMask => _pStateMask; - public RegisterAllocator(uint gprMask, uint fpSimdMask, uint pStateMask, bool hasHostCall) + public RegisterAllocator(MemoryManagerType mmType, uint gprMask, uint fpSimdMask, uint pStateMask, bool hasHostCall) { _gprMask = gprMask; _fpSimdMask = fpSimdMask; @@ -56,7 +53,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64 BuildRegisterMap(_registerMap); - Span tempRegisters = stackalloc int[MaxTemps]; + Span tempRegisters = stackalloc int[CalculateMaxTemps(mmType)]; for (int index = 0; index < tempRegisters.Length; index++) { @@ -150,5 +147,15 @@ namespace Ryujinx.Cpu.LightningJit.Arm64 { mask &= ~(1u << index); } + + public static int CalculateMaxTemps(MemoryManagerType mmType) + { + return mmType.IsHostMapped() ? 1 : 2; + } + + public static int CalculateMaxTempsInclFixed(MemoryManagerType mmType) + { + return CalculateMaxTemps(mmType) + 2; + } } } diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterUtils.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterUtils.cs index eb3fc229f..191e03e7b 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterUtils.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterUtils.cs @@ -247,7 +247,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64 } } - if (!flags.HasFlag(InstFlags.ReadRt)) + if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory()) { if (flags.HasFlag(InstFlags.Rt)) { @@ -281,7 +281,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64 gprMask |= MaskFromIndex(ExtractRd(flags, encoding)); } - if (!flags.HasFlag(InstFlags.ReadRt)) + if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory()) { if (flags.HasFlag(InstFlags.Rt)) { diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/SysUtils.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/SysUtils.cs new file mode 100644 index 000000000..69689a391 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/SysUtils.cs @@ -0,0 +1,48 @@ +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm64 +{ + static class SysUtils + { + public static (uint, uint, uint, uint) UnpackOp1CRnCRmOp2(uint encoding) + { + uint op1 = (encoding >> 16) & 7; + uint crn = (encoding >> 12) & 0xf; + uint crm = (encoding >> 8) & 0xf; + uint op2 = (encoding >> 5) & 7; + + return (op1, crn, crm, op2); + } + + public static bool IsCacheInstEl0(uint encoding) + { + (uint op1, uint crn, uint crm, uint op2) = UnpackOp1CRnCRmOp2(encoding); + + return ((op1 << 11) | (crn << 7) | (crm << 3) | op2) switch + { + 0b011_0111_0100_001 => true, // DC ZVA + 0b011_0111_1010_001 => true, // DC CVAC + 0b011_0111_1100_001 => true, // DC CVAP + 0b011_0111_1011_001 => true, // DC CVAU + 0b011_0111_1110_001 => true, // DC CIVAC + 0b011_0111_0101_001 => true, // IC IVAU + _ => false, + }; + } + + public static bool IsCacheInstUciTrapped(uint encoding) + { + (uint op1, uint crn, uint crm, uint op2) = UnpackOp1CRnCRmOp2(encoding); + + return ((op1 << 11) | (crn << 7) | (crm << 3) | op2) switch + { + 0b011_0111_1010_001 => true, // DC CVAC + 0b011_0111_1100_001 => true, // DC CVAP + 0b011_0111_1011_001 => true, // DC CVAU + 0b011_0111_1110_001 => true, // DC CIVAC + 0b011_0111_0101_001 => true, // IC IVAU + _ => false, + }; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Compiler.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Compiler.cs index babe2cb41..7a6d761e8 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Compiler.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Compiler.cs @@ -316,7 +316,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 uint pStateUseMask = multiBlock.GlobalUseMask.PStateMask; CodeWriter writer = new(); - RegisterAllocator regAlloc = new(gprUseMask, fpSimdUseMask, pStateUseMask, multiBlock.HasHostCall); + RegisterAllocator regAlloc = new(memoryManager.Type, gprUseMask, fpSimdUseMask, pStateUseMask, multiBlock.HasHostCall); RegisterSaveRestore rsr = new( regAlloc.AllGprMask & AbiConstants.GprCalleeSavedRegsMask, regAlloc.AllFpSimdMask & AbiConstants.FpSimdCalleeSavedRegsMask, @@ -350,11 +350,20 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 if (instInfo.AddressForm != AddressForm.None) { - InstEmitMemory.RewriteInstruction(memoryManager.Type, writer, regAlloc, instInfo.Name, instInfo.Flags, instInfo.AddressForm, pc, encoding); + InstEmitMemory.RewriteInstruction( + memoryManager.AddressSpaceBits, + memoryManager.Type, + writer, + regAlloc, + instInfo.Name, + instInfo.Flags, + instInfo.AddressForm, + pc, + encoding); } else if (instInfo.Name == InstName.Sys) { - InstEmitMemory.RewriteSysInstruction(memoryManager.Type, writer, regAlloc, encoding); + InstEmitMemory.RewriteSysInstruction(memoryManager.AddressSpaceBits, memoryManager.Type, writer, regAlloc, encoding); } else if (instInfo.Name.IsSystem()) { diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Decoder.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Decoder.cs index 738b8a32d..d5e1eb19c 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Decoder.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Decoder.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 { static class Decoder { - private const int MaxInstructionsPerBlock = 1000; + private const int MaxInstructionsPerFunction = 10000; private const uint NzcvFlags = 0xfu << 28; private const uint CFlag = 0x1u << 29; @@ -22,10 +22,11 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 bool hasHostCall = false; bool hasMemoryInstruction = false; + int totalInsts = 0; while (true) { - Block block = Decode(cpuPreset, memoryManager, address, ref useMask, ref hasHostCall, ref hasMemoryInstruction); + Block block = Decode(cpuPreset, memoryManager, address, ref totalInsts, ref useMask, ref hasHostCall, ref hasMemoryInstruction); if (!block.IsTruncated && TryGetBranchTarget(block, out ulong targetAddress)) { @@ -230,6 +231,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, + ref int totalInsts, ref RegisterMask useMask, ref bool hasHostCall, ref bool hasMemoryInstruction) @@ -255,7 +257,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 (name, flags, AddressForm addressForm) = InstTable.GetInstNameAndFlags(encoding, cpuPreset.Version, cpuPreset.Features); - if (name.IsPrivileged()) + if (name.IsPrivileged() || (name == InstName.Sys && IsPrivilegedSys(encoding))) { name = InstName.UdfPermUndef; flags = InstFlags.None; @@ -272,7 +274,8 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 uint tempGprUseMask = gprUseMask | instGprReadMask | instGprWriteMask; - if (CalculateAvailableTemps(tempGprUseMask) < CalculateRequiredGprTemps(tempGprUseMask) || insts.Count >= MaxInstructionsPerBlock) + if (CalculateAvailableTemps(tempGprUseMask) < CalculateRequiredGprTemps(memoryManager.Type, tempGprUseMask) || + totalInsts++ >= MaxInstructionsPerFunction) { isTruncated = true; address -= 4UL; @@ -339,6 +342,11 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 return new(startAddress, address, insts, !isTruncated && !name.IsException(), isTruncated, isLoopEnd); } + private static bool IsPrivilegedSys(uint encoding) + { + return !SysUtils.IsCacheInstEl0(encoding); + } + private static bool IsMrsNzcv(uint encoding) { return (encoding & ~0x1fu) == 0xd53b4200u; @@ -371,9 +379,9 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 return false; } - private static int CalculateRequiredGprTemps(uint gprUseMask) + private static int CalculateRequiredGprTemps(MemoryManagerType mmType, uint gprUseMask) { - return BitOperations.PopCount(gprUseMask & RegisterUtils.ReservedRegsMask) + RegisterAllocator.MaxTempsInclFixed; + return BitOperations.PopCount(gprUseMask & RegisterUtils.ReservedRegsMask) + RegisterAllocator.CalculateMaxTempsInclFixed(mmType); } private static int CalculateAvailableTemps(uint gprUseMask) diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitMemory.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitMemory.cs index c9c1c86f2..790a7de95 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitMemory.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitMemory.cs @@ -11,8 +11,16 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 private const uint XMask = 0x3f808000u; private const uint XValue = 0x8000000u; - public static void RewriteSysInstruction(MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) + public static void RewriteSysInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) { + // TODO: Handle IC instruction, it should invalidate the JIT cache. + + if (InstEmitSystem.IsCacheInstForbidden(encoding)) + { + // Current OS does not allow cache maintenance instructions from user mode, just do nothing. + return; + } + int rtIndex = RegisterUtils.ExtractRt(encoding); if (rtIndex == RegisterUtils.ZrIndex) { @@ -27,7 +35,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 Assembler asm = new(writer); - WriteAddressTranslation(mmType, regAlloc, ref asm, rt, guestAddress); + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rt, guestAddress); encoding = RegisterUtils.ReplaceRt(encoding, tempRegister); @@ -37,6 +45,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 } public static void RewriteInstruction( + int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, @@ -46,22 +55,32 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 ulong pc, uint encoding) { + if (name.IsPrefetchMemory() && mmType == MemoryManagerType.HostTrackedUnsafe) + { + // Prefetch to invalid addresses do not cause faults, so for memory manager + // types where we need to access the page table before doing the prefetch, + // we should make sure we won't try to access an out of bounds page table region. + // To do this, we force the masked memory manager variant to be used. + + mmType = MemoryManagerType.HostTracked; + } + switch (addressForm) { case AddressForm.OffsetReg: - RewriteOffsetRegMemoryInstruction(mmType, writer, regAlloc, flags, encoding); + RewriteOffsetRegMemoryInstruction(asBits, mmType, writer, regAlloc, flags, encoding); break; case AddressForm.PostIndexed: - RewritePostIndexedMemoryInstruction(mmType, writer, regAlloc, flags, encoding); + RewritePostIndexedMemoryInstruction(asBits, mmType, writer, regAlloc, flags, encoding); break; case AddressForm.PreIndexed: - RewritePreIndexedMemoryInstruction(mmType, writer, regAlloc, flags, encoding); + RewritePreIndexedMemoryInstruction(asBits, mmType, writer, regAlloc, flags, encoding); break; case AddressForm.SignedScaled: - RewriteSignedScaledMemoryInstruction(mmType, writer, regAlloc, flags, encoding); + RewriteSignedScaledMemoryInstruction(asBits, mmType, writer, regAlloc, flags, encoding); break; case AddressForm.UnsignedScaled: - RewriteUnsignedScaledMemoryInstruction(mmType, writer, regAlloc, flags, encoding); + RewriteUnsignedScaledMemoryInstruction(asBits, mmType, writer, regAlloc, flags, encoding); break; case AddressForm.BaseRegister: // Some applications uses unordered memory instructions in places where @@ -74,19 +93,19 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 encoding |= 1u << 15; } - RewriteBaseRegisterMemoryInstruction(mmType, writer, regAlloc, encoding); + RewriteBaseRegisterMemoryInstruction(asBits, mmType, writer, regAlloc, encoding); break; case AddressForm.StructNoOffset: - RewriteBaseRegisterMemoryInstruction(mmType, writer, regAlloc, encoding); + RewriteBaseRegisterMemoryInstruction(asBits, mmType, writer, regAlloc, encoding); break; case AddressForm.BasePlusOffset: - RewriteBasePlusOffsetMemoryInstruction(mmType, writer, regAlloc, encoding); + RewriteBasePlusOffsetMemoryInstruction(asBits, mmType, writer, regAlloc, encoding); break; case AddressForm.Literal: - RewriteLiteralMemoryInstruction(mmType, writer, regAlloc, name, pc, encoding); + RewriteLiteralMemoryInstruction(asBits, mmType, writer, regAlloc, name, pc, encoding); break; case AddressForm.StructPostIndexedReg: - RewriteStructPostIndexedRegMemoryInstruction(mmType, writer, regAlloc, encoding); + RewriteStructPostIndexedRegMemoryInstruction(asBits, mmType, writer, regAlloc, encoding); break; default: writer.WriteInstruction(encoding); @@ -94,7 +113,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 } } - private static void RewriteOffsetRegMemoryInstruction(MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) + private static void RewriteOffsetRegMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) { // TODO: Some unallocated encoding cases. @@ -118,7 +137,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 asm.Add(rn, guestAddress, guestOffset, extensionType, shift); - WriteAddressTranslation(mmType, regAlloc, ref asm, rn, rn); + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, rn); encoding = RegisterUtils.ReplaceRn(encoding, tempRegister); encoding = (encoding & ~(0xfffu << 10)) | (1u << 24); // Register -> Unsigned offset @@ -128,7 +147,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 regAlloc.FreeTempGprRegister(tempRegister); } - private static void RewritePostIndexedMemoryInstruction(MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) + private static void RewritePostIndexedMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) { bool isPair = flags.HasFlag(InstFlags.Rt2); int imm = isPair ? ExtractSImm7Scaled(flags, encoding) : ExtractSImm9(encoding); @@ -139,7 +158,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 Assembler asm = new(writer); - WriteAddressTranslation(mmType, regAlloc, ref asm, rn, guestAddress); + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, guestAddress); encoding = RegisterUtils.ReplaceRn(encoding, tempRegister); @@ -162,7 +181,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 regAlloc.FreeTempGprRegister(tempRegister); } - private static void RewritePreIndexedMemoryInstruction(MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) + private static void RewritePreIndexedMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) { bool isPair = flags.HasFlag(InstFlags.Rt2); int imm = isPair ? ExtractSImm7Scaled(flags, encoding) : ExtractSImm9(encoding); @@ -174,7 +193,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 Assembler asm = new(writer); WriteAddConstant(ref asm, guestAddress, guestAddress, imm); - WriteAddressTranslation(mmType, regAlloc, ref asm, rn, guestAddress); + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, guestAddress); encoding = RegisterUtils.ReplaceRn(encoding, tempRegister); @@ -195,27 +214,27 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 regAlloc.FreeTempGprRegister(tempRegister); } - private static void RewriteSignedScaledMemoryInstruction(MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) + private static void RewriteSignedScaledMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) { - RewriteMemoryInstruction(mmType, writer, regAlloc, encoding, ExtractSImm7Scaled(flags, encoding), 0x7fu << 15); + RewriteMemoryInstruction(asBits, mmType, writer, regAlloc, encoding, ExtractSImm7Scaled(flags, encoding), 0x7fu << 15); } - private static void RewriteUnsignedScaledMemoryInstruction(MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) + private static void RewriteUnsignedScaledMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) { - RewriteMemoryInstruction(mmType, writer, regAlloc, encoding, ExtractUImm12Scaled(flags, encoding), 0xfffu << 10); + RewriteMemoryInstruction(asBits, mmType, writer, regAlloc, encoding, ExtractUImm12Scaled(flags, encoding), 0xfffu << 10); } - private static void RewriteBaseRegisterMemoryInstruction(MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) + private static void RewriteBaseRegisterMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) { - RewriteMemoryInstruction(mmType, writer, regAlloc, encoding, 0, 0u); + RewriteMemoryInstruction(asBits, mmType, writer, regAlloc, encoding, 0, 0u); } - private static void RewriteBasePlusOffsetMemoryInstruction(MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) + private static void RewriteBasePlusOffsetMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) { - RewriteMemoryInstruction(mmType, writer, regAlloc, encoding, ExtractSImm9(encoding), 0x1ffu << 12); + RewriteMemoryInstruction(asBits, mmType, writer, regAlloc, encoding, ExtractSImm9(encoding), 0x1ffu << 12); } - private static void RewriteMemoryInstruction(MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding, int imm, uint immMask) + private static void RewriteMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding, int imm, uint immMask) { int tempRegister = regAlloc.AllocateTempGprRegister(); Operand rn = new(tempRegister, RegisterType.Integer, OperandType.I64); @@ -229,7 +248,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 imm = 0; } - WriteAddressTranslation(mmType, regAlloc, ref asm, rn, guestAddress, imm); + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, guestAddress, imm); encoding = RegisterUtils.ReplaceRn(encoding, tempRegister); @@ -243,7 +262,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 regAlloc.FreeTempGprRegister(tempRegister); } - private static void RewriteLiteralMemoryInstruction(MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstName name, ulong pc, uint encoding) + private static void RewriteLiteralMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstName name, ulong pc, uint encoding) { Assembler asm = new(writer); @@ -308,7 +327,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 int tempRegister = regAlloc.AllocateTempGprRegister(); Operand rn = new(tempRegister, RegisterType.Integer, OperandType.I64); - WriteAddressTranslation(mmType, regAlloc, ref asm, rn, targetAddress); + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, targetAddress); switch (name) { @@ -332,7 +351,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 } } - private static void RewriteStructPostIndexedRegMemoryInstruction(MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) + private static void RewriteStructPostIndexedRegMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) { // TODO: Some unallocated encoding cases. @@ -344,7 +363,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 Assembler asm = new(writer); - WriteAddressTranslation(mmType, regAlloc, ref asm, rn, guestAddress); + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, guestAddress); encoding = RegisterUtils.ReplaceRn(encoding, tempRegister); encoding &= ~((0x1fu << 16) | (1u << 23)); // Post-index -> No offset @@ -471,6 +490,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 } private static void WriteAddressTranslation( + int asBits, MemoryManagerType mmType, RegisterAllocator regAlloc, ref Assembler asm, @@ -498,34 +518,58 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 guestAddress = destination; } - WriteAddressTranslation(mmType, regAlloc, ref asm, destination, guestAddress); + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, destination, guestAddress); } - private static void WriteAddressTranslation(MemoryManagerType mmType, RegisterAllocator regAlloc, ref Assembler asm, Operand destination, ulong guestAddress) + private static void WriteAddressTranslation( + int asBits, + MemoryManagerType mmType, + RegisterAllocator regAlloc, + ref Assembler asm, + Operand destination, + ulong guestAddress) { asm.Mov(destination, guestAddress); - WriteAddressTranslation(mmType, regAlloc, ref asm, destination, destination); + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, destination, destination); } - private static void WriteAddressTranslation(MemoryManagerType mmType, RegisterAllocator regAlloc, ref Assembler asm, Operand destination, Operand guestAddress) + private static void WriteAddressTranslation( + int asBits, + MemoryManagerType mmType, + RegisterAllocator regAlloc, + ref Assembler asm, + Operand destination, + Operand guestAddress) { Operand basePointer = new(regAlloc.FixedPageTableRegister, RegisterType.Integer, OperandType.I64); - if (mmType == MemoryManagerType.HostTracked) + if (mmType.IsHostTracked()) { int tempRegister = regAlloc.AllocateTempGprRegister(); Operand pte = new(tempRegister, RegisterType.Integer, OperandType.I64); asm.Lsr(pte, guestAddress, new Operand(OperandKind.Constant, OperandType.I32, 12)); + + if (mmType == MemoryManagerType.HostTracked) + { + asm.And(pte, pte, new Operand(OperandKind.Constant, OperandType.I64, ulong.MaxValue >> (64 - (asBits - 12)))); + } + asm.LdrRr(pte, basePointer, pte, ArmExtensionType.Uxtx, true); asm.Add(destination, pte, guestAddress); regAlloc.FreeTempGprRegister(tempRegister); } - else if (mmType == MemoryManagerType.HostMapped || mmType == MemoryManagerType.HostMappedUnsafe) + else if (mmType.IsHostMapped()) { + if (mmType == MemoryManagerType.HostMapped) + { + asm.And(destination, guestAddress, new Operand(OperandKind.Constant, OperandType.I64, ulong.MaxValue >> (64 - asBits))); + guestAddress = destination; + } + asm.Add(destination, basePointer, guestAddress); } else diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs index 8005ecd2b..3eac5b63f 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs @@ -69,7 +69,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 asm.LdrRiUn(Register((int)rd), Register(regAlloc.FixedContextRegister), NativeContextOffsets.TpidrEl0Offset); } } - else if ((encoding & ~0x1f) == 0xd53b0020 && (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())) // mrs x0, ctr_el0 + else if ((encoding & ~0x1f) == 0xd53b0020 && IsCtrEl0AccessForbidden()) // mrs x0, ctr_el0 { uint rd = encoding & 0x1f; @@ -115,7 +115,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 { return true; } - else if ((encoding & ~0x1f) == 0xd53b0020 && (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())) // mrs x0, ctr_el0 + else if ((encoding & ~0x1f) == 0xd53b0020 && IsCtrEl0AccessForbidden()) // mrs x0, ctr_el0 { return true; } @@ -127,6 +127,18 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 return false; } + private static bool IsCtrEl0AccessForbidden() + { + // Only Linux allows accessing CTR_EL0 from user mode. + return OperatingSystem.IsWindows() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS(); + } + + public static bool IsCacheInstForbidden(uint encoding) + { + // Windows does not allow the cache maintenance instructions to be used from user mode. + return OperatingSystem.IsWindows() && SysUtils.IsCacheInstUciTrapped(encoding); + } + public static bool NeedsContextStoreLoad(InstName name) { return name == InstName.Svc; diff --git a/src/Ryujinx.Cpu/LightningJit/Cache/CacheEntry.cs b/src/Ryujinx.Cpu/LightningJit/Cache/CacheEntry.cs index b3bb6e31b..0249e24b8 100644 --- a/src/Ryujinx.Cpu/LightningJit/Cache/CacheEntry.cs +++ b/src/Ryujinx.Cpu/LightningJit/Cache/CacheEntry.cs @@ -8,7 +8,6 @@ namespace Ryujinx.Cpu.LightningJit.Cache public int Offset { get; } public int Size { get; } - public CacheEntry(int offset, int size) { Offset = offset; diff --git a/src/Ryujinx.Cpu/LightningJit/Cache/NoWxCache.cs b/src/Ryujinx.Cpu/LightningJit/Cache/NoWxCache.cs index 16e8fdd4a..a71074995 100644 --- a/src/Ryujinx.Cpu/LightningJit/Cache/NoWxCache.cs +++ b/src/Ryujinx.Cpu/LightningJit/Cache/NoWxCache.cs @@ -10,7 +10,7 @@ namespace Ryujinx.Cpu.LightningJit.Cache class NoWxCache : IDisposable { private const int CodeAlignment = 4; // Bytes. - private const int SharedCacheSize = 192 * 1024 * 1024; + private const int SharedCacheSize = 2047 * 1024 * 1024; private const int LocalCacheSize = 128 * 1024 * 1024; // How many calls to the same function we allow until we pad the shared cache to force the function to become available there diff --git a/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs b/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs index c53b2d96e..b63636e39 100644 --- a/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs +++ b/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Cpu.LightningJit public LightningJitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit) { _tickSource = tickSource; - _translator = new Translator(new JitMemoryAllocator(forJit: true), memory, for64Bit); + _translator = new Translator(memory, for64Bit); memory.UnmapEvent += UnmapHandler; } diff --git a/src/Ryujinx.Cpu/LightningJit/Translator.cs b/src/Ryujinx.Cpu/LightningJit/Translator.cs index f59f64fb7..bbacecef7 100644 --- a/src/Ryujinx.Cpu/LightningJit/Translator.cs +++ b/src/Ryujinx.Cpu/LightningJit/Translator.cs @@ -1,10 +1,11 @@ using ARMeilleure.Common; using ARMeilleure.Memory; -using ARMeilleure.Signal; using Ryujinx.Cpu.Jit; using Ryujinx.Cpu.LightningJit.Cache; using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; using Ryujinx.Cpu.LightningJit.State; +using Ryujinx.Cpu.Signal; +using Ryujinx.Memory; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -46,7 +47,7 @@ namespace Ryujinx.Cpu.LightningJit internal TranslatorStubs Stubs { get; } internal IMemoryManager Memory { get; } - public Translator(IJitMemoryAllocator allocator, IMemoryManager memory, bool for64Bits) + public Translator(IMemoryManager memory, bool for64Bits) { Memory = memory; @@ -58,22 +59,18 @@ namespace Ryujinx.Cpu.LightningJit } else { - JitCache.Initialize(allocator); + JitCache.Initialize(new JitMemoryAllocator(forJit: true)); } - NativeSignalHandler.Initialize(allocator); - Functions = new TranslatorCache(); FunctionTable = new AddressTable(for64Bits ? _levels64Bit : _levels32Bit); Stubs = new TranslatorStubs(FunctionTable, _noWxCache); FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub; - if (memory.Type == MemoryManagerType.HostTracked || - memory.Type == MemoryManagerType.HostMapped || - memory.Type == MemoryManagerType.HostMappedUnsafe) + if (memory.Type.IsHostMappedOrTracked()) { - NativeSignalHandler.InitializeSignalHandler(allocator.GetPageSize()); + NativeSignalHandler.InitializeSignalHandler(); } } @@ -141,7 +138,7 @@ namespace Ryujinx.Cpu.LightningJit } } - internal TranslatedFunction Translate(ulong address, ExecutionMode mode) + private TranslatedFunction Translate(ulong address, ExecutionMode mode) { CompiledFunction func = Compile(address, mode); IntPtr funcPointer = JitCache.Map(func.Code); @@ -149,7 +146,7 @@ namespace Ryujinx.Cpu.LightningJit return new TranslatedFunction(funcPointer, (ulong)func.GuestCodeLength); } - internal CompiledFunction Compile(ulong address, ExecutionMode mode) + private CompiledFunction Compile(ulong address, ExecutionMode mode) { return AarchCompiler.Compile(CpuPresets.CortexA57, Memory, address, FunctionTable, Stubs.DispatchStub, mode, RuntimeInformation.ProcessArchitecture); } diff --git a/src/Ryujinx.Cpu/ManagedPageFlags.cs b/src/Ryujinx.Cpu/ManagedPageFlags.cs new file mode 100644 index 000000000..a839dae67 --- /dev/null +++ b/src/Ryujinx.Cpu/ManagedPageFlags.cs @@ -0,0 +1,389 @@ +using Ryujinx.Memory; +using Ryujinx.Memory.Tracking; +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace Ryujinx.Cpu +{ + /// + /// A page bitmap that keeps track of mapped state and tracking protection + /// for managed memory accesses (not using host page protection). + /// + internal readonly struct ManagedPageFlags + { + public const int PageBits = 12; + public const int PageSize = 1 << PageBits; + public const int PageMask = PageSize - 1; + + private readonly ulong[] _pageBitmap; + + public const int PageToPteShift = 5; // 32 pages (2 bits each) in one ulong page table entry. + public const ulong BlockMappedMask = 0x5555555555555555; // First bit of each table entry set. + + private enum ManagedPtBits : ulong + { + Unmapped = 0, + Mapped, + WriteTracked, + ReadWriteTracked, + + MappedReplicated = 0x5555555555555555, + WriteTrackedReplicated = 0xaaaaaaaaaaaaaaaa, + ReadWriteTrackedReplicated = ulong.MaxValue, + } + + public ManagedPageFlags(int addressSpaceBits) + { + int bits = Math.Max(0, addressSpaceBits - (PageBits + PageToPteShift)); + _pageBitmap = new ulong[1 << bits]; + } + + /// + /// Computes the number of pages in a virtual address range. + /// + /// Virtual address of the range + /// Size of the range + /// The virtual address of the beginning of the first page + /// This function does not differentiate between allocated and unallocated pages. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetPagesCount(ulong va, ulong size, out ulong startVa) + { + // WARNING: Always check if ulong does not overflow during the operations. + startVa = va & ~(ulong)PageMask; + ulong vaSpan = (va - startVa + size + PageMask) & ~(ulong)PageMask; + + return (int)(vaSpan / PageSize); + } + + /// + /// Checks if the page at a given CPU virtual address is mapped. + /// + /// Virtual address to check + /// True if the address is mapped, false otherwise + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly bool IsMapped(ulong va) + { + ulong page = va >> PageBits; + + int bit = (int)((page & 31) << 1); + + int pageIndex = (int)(page >> PageToPteShift); + ref ulong pageRef = ref _pageBitmap[pageIndex]; + + ulong pte = Volatile.Read(ref pageRef); + + return ((pte >> bit) & 3) != 0; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void GetPageBlockRange(ulong pageStart, ulong pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex) + { + startMask = ulong.MaxValue << ((int)(pageStart & 31) << 1); + endMask = ulong.MaxValue >> (64 - ((int)(pageEnd & 31) << 1)); + + pageIndex = (int)(pageStart >> PageToPteShift); + pageEndIndex = (int)((pageEnd - 1) >> PageToPteShift); + } + + /// + /// Checks if a memory range is mapped. + /// + /// Virtual address of the range + /// Size of the range in bytes + /// True if the entire range is mapped, false otherwise + public readonly bool IsRangeMapped(ulong va, ulong size) + { + int pages = GetPagesCount(va, size, out _); + + if (pages == 1) + { + return IsMapped(va); + } + + ulong pageStart = va >> PageBits; + ulong pageEnd = pageStart + (ulong)pages; + + GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); + + // Check if either bit in each 2 bit page entry is set. + // OR the block with itself shifted down by 1, and check the first bit of each entry. + + ulong mask = BlockMappedMask & startMask; + + while (pageIndex <= pageEndIndex) + { + if (pageIndex == pageEndIndex) + { + mask &= endMask; + } + + ref ulong pageRef = ref _pageBitmap[pageIndex++]; + ulong pte = Volatile.Read(ref pageRef); + + pte |= pte >> 1; + if ((pte & mask) != mask) + { + return false; + } + + mask = BlockMappedMask; + } + + return true; + } + + /// + /// Reprotect a region of virtual memory for tracking. + /// + /// Virtual address base + /// Size of the region to protect + /// Memory protection to set + public readonly void TrackingReprotect(ulong va, ulong size, MemoryPermission protection) + { + // Protection is inverted on software pages, since the default value is 0. + protection = (~protection) & MemoryPermission.ReadAndWrite; + + int pages = GetPagesCount(va, size, out va); + ulong pageStart = va >> PageBits; + + if (pages == 1) + { + ulong protTag = protection switch + { + MemoryPermission.None => (ulong)ManagedPtBits.Mapped, + MemoryPermission.Write => (ulong)ManagedPtBits.WriteTracked, + _ => (ulong)ManagedPtBits.ReadWriteTracked, + }; + + int bit = (int)((pageStart & 31) << 1); + + ulong tagMask = 3UL << bit; + ulong invTagMask = ~tagMask; + + ulong tag = protTag << bit; + + int pageIndex = (int)(pageStart >> PageToPteShift); + ref ulong pageRef = ref _pageBitmap[pageIndex]; + + ulong pte; + + do + { + pte = Volatile.Read(ref pageRef); + } + while ((pte & tagMask) != 0 && Interlocked.CompareExchange(ref pageRef, (pte & invTagMask) | tag, pte) != pte); + } + else + { + ulong pageEnd = pageStart + (ulong)pages; + + GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); + + ulong mask = startMask; + + ulong protTag = protection switch + { + MemoryPermission.None => (ulong)ManagedPtBits.MappedReplicated, + MemoryPermission.Write => (ulong)ManagedPtBits.WriteTrackedReplicated, + _ => (ulong)ManagedPtBits.ReadWriteTrackedReplicated, + }; + + while (pageIndex <= pageEndIndex) + { + if (pageIndex == pageEndIndex) + { + mask &= endMask; + } + + ref ulong pageRef = ref _pageBitmap[pageIndex++]; + + ulong pte; + ulong mappedMask; + + // Change the protection of all 2 bit entries that are mapped. + do + { + pte = Volatile.Read(ref pageRef); + + mappedMask = pte | (pte >> 1); + mappedMask |= (mappedMask & BlockMappedMask) << 1; + mappedMask &= mask; // Only update mapped pages within the given range. + } + while (Interlocked.CompareExchange(ref pageRef, (pte & (~mappedMask)) | (protTag & mappedMask), pte) != pte); + + mask = ulong.MaxValue; + } + } + } + + /// + /// Alerts the memory tracking that a given region has been read from or written to. + /// This should be called before read/write is performed. + /// + /// Memory tracking structure to call when pages are protected + /// Virtual address of the region + /// Size of the region + /// True if the region was written, false if read + /// Optional ID of the handles that should not be signalled + /// + /// This function also validates that the given range is both valid and mapped, and will throw if it is not. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void SignalMemoryTracking(MemoryTracking tracking, ulong va, ulong size, bool write, int? exemptId = null) + { + // Software table, used for managed memory tracking. + + int pages = GetPagesCount(va, size, out _); + ulong pageStart = va >> PageBits; + + if (pages == 1) + { + ulong tag = (ulong)(write ? ManagedPtBits.WriteTracked : ManagedPtBits.ReadWriteTracked); + + int bit = (int)((pageStart & 31) << 1); + + int pageIndex = (int)(pageStart >> PageToPteShift); + ref ulong pageRef = ref _pageBitmap[pageIndex]; + + ulong pte = Volatile.Read(ref pageRef); + ulong state = ((pte >> bit) & 3); + + if (state >= tag) + { + tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId); + return; + } + else if (state == 0) + { + ThrowInvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}"); + } + } + else + { + ulong pageEnd = pageStart + (ulong)pages; + + GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); + + ulong mask = startMask; + + ulong anyTrackingTag = (ulong)ManagedPtBits.WriteTrackedReplicated; + + while (pageIndex <= pageEndIndex) + { + if (pageIndex == pageEndIndex) + { + mask &= endMask; + } + + ref ulong pageRef = ref _pageBitmap[pageIndex++]; + + ulong pte = Volatile.Read(ref pageRef); + ulong mappedMask = mask & BlockMappedMask; + + ulong mappedPte = pte | (pte >> 1); + if ((mappedPte & mappedMask) != mappedMask) + { + ThrowInvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}"); + } + + pte &= mask; + if ((pte & anyTrackingTag) != 0) // Search for any tracking. + { + // Writes trigger any tracking. + // Only trigger tracking from reads if both bits are set on any page. + if (write || (pte & (pte >> 1) & BlockMappedMask) != 0) + { + tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId); + break; + } + } + + mask = ulong.MaxValue; + } + } + } + + /// + /// Adds the given address mapping to the page table. + /// + /// Virtual memory address + /// Size to be mapped + public readonly void AddMapping(ulong va, ulong size) + { + int pages = GetPagesCount(va, size, out _); + ulong pageStart = va >> PageBits; + ulong pageEnd = pageStart + (ulong)pages; + + GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); + + ulong mask = startMask; + + while (pageIndex <= pageEndIndex) + { + if (pageIndex == pageEndIndex) + { + mask &= endMask; + } + + ref ulong pageRef = ref _pageBitmap[pageIndex++]; + + ulong pte; + ulong mappedMask; + + // Map all 2-bit entries that are unmapped. + do + { + pte = Volatile.Read(ref pageRef); + + mappedMask = pte | (pte >> 1); + mappedMask |= (mappedMask & BlockMappedMask) << 1; + mappedMask |= ~mask; // Treat everything outside the range as mapped, thus unchanged. + } + while (Interlocked.CompareExchange(ref pageRef, (pte & mappedMask) | (BlockMappedMask & (~mappedMask)), pte) != pte); + + mask = ulong.MaxValue; + } + } + + /// + /// Removes the given address mapping from the page table. + /// + /// Virtual memory address + /// Size to be unmapped + public readonly void RemoveMapping(ulong va, ulong size) + { + int pages = GetPagesCount(va, size, out _); + ulong pageStart = va >> PageBits; + ulong pageEnd = pageStart + (ulong)pages; + + GetPageBlockRange(pageStart, pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex); + + startMask = ~startMask; + endMask = ~endMask; + + ulong mask = startMask; + + while (pageIndex <= pageEndIndex) + { + if (pageIndex == pageEndIndex) + { + mask |= endMask; + } + + ref ulong pageRef = ref _pageBitmap[pageIndex++]; + ulong pte; + + do + { + pte = Volatile.Read(ref pageRef); + } + while (Interlocked.CompareExchange(ref pageRef, pte & mask, pte) != pte); + + mask = 0; + } + } + + private static void ThrowInvalidMemoryRegionException(string message) => throw new InvalidMemoryRegionException(message); + } +} diff --git a/src/Ryujinx.Cpu/MemoryEhMeilleure.cs b/src/Ryujinx.Cpu/MemoryEhMeilleure.cs index d3763c777..379ace941 100644 --- a/src/Ryujinx.Cpu/MemoryEhMeilleure.cs +++ b/src/Ryujinx.Cpu/MemoryEhMeilleure.cs @@ -1,4 +1,5 @@ -using ARMeilleure.Signal; +using Ryujinx.Common; +using Ryujinx.Cpu.Signal; using Ryujinx.Memory; using Ryujinx.Memory.Tracking; using System; @@ -8,10 +9,13 @@ namespace Ryujinx.Cpu { public class MemoryEhMeilleure : IDisposable { - public delegate bool TrackingEventDelegate(ulong address, ulong size, bool write); + public delegate ulong TrackingEventDelegate(ulong address, ulong size, bool write); + private readonly MemoryTracking _tracking; private readonly TrackingEventDelegate _trackingEvent; + private readonly ulong _pageSize; + private readonly ulong _baseAddress; private readonly ulong _mirrorAddress; @@ -21,7 +25,10 @@ namespace Ryujinx.Cpu ulong endAddress = _baseAddress + addressSpace.Size; - _trackingEvent = trackingEvent ?? tracking.VirtualMemoryEvent; + _tracking = tracking; + _trackingEvent = trackingEvent ?? VirtualMemoryEvent; + + _pageSize = MemoryBlock.GetPageSize(); bool added = NativeSignalHandler.AddTrackedRegion((nuint)_baseAddress, (nuint)endAddress, Marshal.GetFunctionPointerForDelegate(_trackingEvent)); @@ -48,6 +55,21 @@ namespace Ryujinx.Cpu } } + private ulong VirtualMemoryEvent(ulong address, ulong size, bool write) + { + ulong pageSize = _pageSize; + ulong addressAligned = BitUtils.AlignDown(address, pageSize); + ulong endAddressAligned = BitUtils.AlignUp(address + size, pageSize); + ulong sizeAligned = endAddressAligned - addressAligned; + + if (_tracking.VirtualMemoryEvent(addressAligned, sizeAligned, write)) + { + return _baseAddress + address; + } + + return 0; + } + public void Dispose() { GC.SuppressFinalize(this); diff --git a/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs new file mode 100644 index 000000000..48f13c0cd --- /dev/null +++ b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs @@ -0,0 +1,184 @@ +using ARMeilleure.Signal; +using Ryujinx.Common; +using Ryujinx.Memory; +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.Signal +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SignalHandlerRange + { + public int IsActive; + public nuint RangeAddress; + public nuint RangeEndAddress; + public IntPtr ActionPointer; + } + + [InlineArray(NativeSignalHandlerGenerator.MaxTrackedRanges)] + struct SignalHandlerRangeArray + { + public SignalHandlerRange Range0; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SignalHandlerConfig + { + /// + /// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct. + /// + public int StructAddressOffset; + + /// + /// The byte offset of the write flag in the SigInfo or ExceptionRecord struct. + /// + public int StructWriteOffset; + + /// + /// The sigaction handler that was registered before this one. (unix only) + /// + public nuint UnixOldSigaction; + + /// + /// The type of the previous sigaction. True for the 3 argument variant. (unix only) + /// + public int UnixOldSigaction3Arg; + + /// + /// Fixed size array of tracked ranges. + /// + public SignalHandlerRangeArray Ranges; + } + + static class NativeSignalHandler + { + private static readonly IntPtr _handlerConfig; + private static IntPtr _signalHandlerPtr; + + private static MemoryBlock _codeBlock; + + private static readonly object _lock = new(); + private static bool _initialized; + + static NativeSignalHandler() + { + _handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf()); + ref SignalHandlerConfig config = ref GetConfigRef(); + + config = new SignalHandlerConfig(); + } + + public static void InitializeSignalHandler(Func customSignalHandlerFactory = null) + { + if (_initialized) + { + return; + } + + lock (_lock) + { + if (_initialized) + { + return; + } + + int rangeStructSize = Unsafe.SizeOf(); + + ref SignalHandlerConfig config = ref GetConfigRef(); + + if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) + { + _signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateUnixSignalHandler(_handlerConfig, rangeStructSize)); + + if (customSignalHandlerFactory != null) + { + _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr); + } + + var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr); + + config.UnixOldSigaction = (nuint)(ulong)old.sa_handler; + config.UnixOldSigaction3Arg = old.sa_flags & 4; + } + else + { + config.StructAddressOffset = 40; // ExceptionInformation1 + config.StructWriteOffset = 32; // ExceptionInformation0 + + _signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateWindowsSignalHandler(_handlerConfig, rangeStructSize)); + + if (customSignalHandlerFactory != null) + { + _signalHandlerPtr = customSignalHandlerFactory(IntPtr.Zero, _signalHandlerPtr); + } + + WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr); + } + + _initialized = true; + } + } + + private static IntPtr MapCode(ReadOnlySpan code) + { + Debug.Assert(_codeBlock == null); + + ulong codeSizeAligned = BitUtils.AlignUp((ulong)code.Length, MemoryBlock.GetPageSize()); + + _codeBlock = new MemoryBlock(codeSizeAligned); + _codeBlock.Write(0, code); + _codeBlock.Reprotect(0, codeSizeAligned, MemoryPermission.ReadAndExecute); + + return _codeBlock.Pointer; + } + + private static unsafe ref SignalHandlerConfig GetConfigRef() + { + return ref Unsafe.AsRef((void*)_handlerConfig); + } + + public static bool AddTrackedRegion(nuint address, nuint endAddress, IntPtr action) + { + Span ranges = GetConfigRef().Ranges; + + for (int i = 0; i < NativeSignalHandlerGenerator.MaxTrackedRanges; i++) + { + if (ranges[i].IsActive == 0) + { + ranges[i].RangeAddress = address; + ranges[i].RangeEndAddress = endAddress; + ranges[i].ActionPointer = action; + ranges[i].IsActive = 1; + + return true; + } + } + + return false; + } + + public static bool RemoveTrackedRegion(nuint address) + { + Span ranges = GetConfigRef().Ranges; + + for (int i = 0; i < NativeSignalHandlerGenerator.MaxTrackedRanges; i++) + { + if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address) + { + ranges[i].IsActive = 0; + + return true; + } + } + + return false; + } + + public static bool SupportsFaultAddressPatching() + { + return NativeSignalHandlerGenerator.SupportsFaultAddressPatchingForHost(); + } + } +} diff --git a/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs similarity index 98% rename from src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs rename to src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs index 433aab636..5f57a75ef 100644 --- a/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs +++ b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace ARMeilleure.Signal +namespace Ryujinx.Cpu.Signal { static partial class UnixSignalHandlerRegistration { diff --git a/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs b/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs new file mode 100644 index 000000000..1fbce0f72 --- /dev/null +++ b/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.Signal +{ + static partial class WindowsSignalHandlerRegistration + { + [LibraryImport("kernel32.dll")] + private static partial IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler); + + [LibraryImport("kernel32.dll")] + private static partial ulong RemoveVectoredExceptionHandler(IntPtr handle); + + public static IntPtr RegisterExceptionHandler(IntPtr action) + { + return AddVectoredExceptionHandler(1, action); + } + + public static bool RemoveExceptionHandler(IntPtr handle) + { + return RemoveVectoredExceptionHandler(handle) != 0; + } + } +} diff --git a/src/Ryujinx.Cpu/MemoryManagerBase.cs b/src/Ryujinx.Cpu/VirtualMemoryManagerRefCountedBase.cs similarity index 86% rename from src/Ryujinx.Cpu/MemoryManagerBase.cs rename to src/Ryujinx.Cpu/VirtualMemoryManagerRefCountedBase.cs index 3288e3a49..3c7b33805 100644 --- a/src/Ryujinx.Cpu/MemoryManagerBase.cs +++ b/src/Ryujinx.Cpu/VirtualMemoryManagerRefCountedBase.cs @@ -4,7 +4,7 @@ using System.Threading; namespace Ryujinx.Cpu { - public abstract class MemoryManagerBase : IRefCounted + public abstract class VirtualMemoryManagerRefCountedBase : VirtualMemoryManagerBase, IRefCounted { private int _referenceCount; diff --git a/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs b/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs new file mode 100644 index 000000000..cb1a7c3ab --- /dev/null +++ b/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs @@ -0,0 +1,396 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Memory; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Device +{ + /// + /// Device memory manager. + /// + public class DeviceMemoryManager : IWritableBlock + { + private const int PtLvl0Bits = 10; + private const int PtLvl1Bits = 10; + public const int PtPageBits = 12; + + private const ulong PtLvl0Size = 1UL << PtLvl0Bits; + private const ulong PtLvl1Size = 1UL << PtLvl1Bits; + public const ulong PageSize = 1UL << PtPageBits; + + private const ulong PtLvl0Mask = PtLvl0Size - 1; + private const ulong PtLvl1Mask = PtLvl1Size - 1; + public const ulong PageMask = PageSize - 1; + + private const int PtLvl0Bit = PtPageBits + PtLvl1Bits; + private const int PtLvl1Bit = PtPageBits; + private const int AddressSpaceBits = PtPageBits + PtLvl1Bits + PtLvl0Bits; + + public const ulong PteUnmapped = ulong.MaxValue; + + private readonly ulong[][] _pageTable; + + private readonly IVirtualMemoryManager _physical; + + /// + /// Creates a new instance of the GPU memory manager. + /// + /// Physical memory that this memory manager will map into + public DeviceMemoryManager(IVirtualMemoryManager physicalMemory) + { + _physical = physicalMemory; + _pageTable = new ulong[PtLvl0Size][]; + } + + /// + /// Reads data from GPU mapped memory. + /// + /// Type of the data + /// GPU virtual address where the data is located + /// The data at the specified memory location + public T Read(ulong va) where T : unmanaged + { + int size = Unsafe.SizeOf(); + + if (IsContiguous(va, size)) + { + return _physical.Read(Translate(va)); + } + else + { + Span data = new byte[size]; + + ReadImpl(va, data); + + return MemoryMarshal.Cast(data)[0]; + } + } + + /// + /// Gets a read-only span of data from GPU mapped memory. + /// + /// GPU virtual address where the data is located + /// Size of the data + /// The span of the data at the specified memory location + public ReadOnlySpan GetSpan(ulong va, int size) + { + if (IsContiguous(va, size)) + { + return _physical.GetSpan(Translate(va), size); + } + else + { + Span data = new byte[size]; + + ReadImpl(va, data); + + return data; + } + } + + /// + /// Reads data from a possibly non-contiguous region of GPU mapped memory. + /// + /// GPU virtual address of the data + /// Span to write the read data into + private void ReadImpl(ulong va, Span data) + { + if (data.Length == 0) + { + return; + } + + int offset = 0, size; + + if ((va & PageMask) != 0) + { + ulong pa = Translate(va); + + size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask)); + + if (pa != PteUnmapped && _physical.IsMapped(pa)) + { + _physical.GetSpan(pa, size).CopyTo(data[..size]); + } + + offset += size; + } + + for (; offset < data.Length; offset += size) + { + ulong pa = Translate(va + (ulong)offset); + + size = Math.Min(data.Length - offset, (int)PageSize); + + if (pa != PteUnmapped && _physical.IsMapped(pa)) + { + _physical.GetSpan(pa, size).CopyTo(data.Slice(offset, size)); + } + } + } + + /// + /// Gets a writable region from GPU mapped memory. + /// + /// Start address of the range + /// Size in bytes to be range + /// A writable region with the data at the specified memory location + public WritableRegion GetWritableRegion(ulong va, int size) + { + if (IsContiguous(va, size)) + { + return _physical.GetWritableRegion(Translate(va), size, tracked: true); + } + else + { + MemoryOwner memoryOwner = MemoryOwner.Rent(size); + + ReadImpl(va, memoryOwner.Span); + + return new WritableRegion(this, va, memoryOwner, tracked: true); + } + } + + /// + /// Writes data to GPU mapped memory. + /// + /// Type of the data + /// GPU virtual address to write the value into + /// The value to be written + public void Write(ulong va, T value) where T : unmanaged + { + Write(va, MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref value, 1))); + } + + /// + /// Writes data to GPU mapped memory. + /// + /// GPU virtual address to write the data into + /// The data to be written + public void Write(ulong va, ReadOnlySpan data) + { + if (IsContiguous(va, data.Length)) + { + _physical.Write(Translate(va), data); + } + else + { + int offset = 0, size; + + if ((va & PageMask) != 0) + { + ulong pa = Translate(va); + + size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask)); + + if (pa != PteUnmapped && _physical.IsMapped(pa)) + { + _physical.Write(pa, data[..size]); + } + + offset += size; + } + + for (; offset < data.Length; offset += size) + { + ulong pa = Translate(va + (ulong)offset); + + size = Math.Min(data.Length - offset, (int)PageSize); + + if (pa != PteUnmapped && _physical.IsMapped(pa)) + { + _physical.Write(pa, data.Slice(offset, size)); + } + } + } + } + + /// + /// Writes data to GPU mapped memory without write tracking. + /// + /// GPU virtual address to write the data into + /// The data to be written + public void WriteUntracked(ulong va, ReadOnlySpan data) + { + throw new NotSupportedException(); + } + + /// + /// Maps a given range of pages to the specified CPU virtual address. + /// + /// + /// All addresses and sizes must be page aligned. + /// + /// CPU virtual address to map into + /// GPU virtual address to be mapped + /// Kind of the resource located at the mapping + public void Map(ulong pa, ulong va, ulong size) + { + lock (_pageTable) + { + for (ulong offset = 0; offset < size; offset += PageSize) + { + SetPte(va + offset, PackPte(pa + offset)); + } + } + } + + /// + /// Unmaps a given range of pages at the specified GPU virtual memory region. + /// + /// GPU virtual address to unmap + /// Size in bytes of the region being unmapped + public void Unmap(ulong va, ulong size) + { + lock (_pageTable) + { + for (ulong offset = 0; offset < size; offset += PageSize) + { + SetPte(va + offset, PteUnmapped); + } + } + } + + /// + /// Checks if a region of GPU mapped memory is contiguous. + /// + /// GPU virtual address of the region + /// Size of the region + /// True if the region is contiguous, false otherwise + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsContiguous(ulong va, int size) + { + if (!ValidateAddress(va) || GetPte(va) == PteUnmapped) + { + return false; + } + + ulong endVa = (va + (ulong)size + PageMask) & ~PageMask; + + va &= ~PageMask; + + int pages = (int)((endVa - va) / PageSize); + + for (int page = 0; page < pages - 1; page++) + { + if (!ValidateAddress(va + PageSize) || GetPte(va + PageSize) == PteUnmapped) + { + return false; + } + + if (Translate(va) + PageSize != Translate(va + PageSize)) + { + return false; + } + + va += PageSize; + } + + return true; + } + + /// + /// Validates a GPU virtual address. + /// + /// Address to validate + /// True if the address is valid, false otherwise + private static bool ValidateAddress(ulong va) + { + return va < (1UL << AddressSpaceBits); + } + + /// + /// Checks if a given page is mapped. + /// + /// GPU virtual address of the page to check + /// True if the page is mapped, false otherwise + public bool IsMapped(ulong va) + { + return Translate(va) != PteUnmapped; + } + + /// + /// Translates a GPU virtual address to a CPU virtual address. + /// + /// GPU virtual address to be translated + /// CPU virtual address, or if unmapped + public ulong Translate(ulong va) + { + if (!ValidateAddress(va)) + { + return PteUnmapped; + } + + ulong pte = GetPte(va); + + if (pte == PteUnmapped) + { + return PteUnmapped; + } + + return UnpackPaFromPte(pte) + (va & PageMask); + } + + /// + /// Gets the Page Table entry for a given GPU virtual address. + /// + /// GPU virtual address + /// Page table entry (CPU virtual address) + private ulong GetPte(ulong va) + { + ulong l0 = (va >> PtLvl0Bit) & PtLvl0Mask; + ulong l1 = (va >> PtLvl1Bit) & PtLvl1Mask; + + if (_pageTable[l0] == null) + { + return PteUnmapped; + } + + return _pageTable[l0][l1]; + } + + /// + /// Sets a Page Table entry at a given GPU virtual address. + /// + /// GPU virtual address + /// Page table entry (CPU virtual address) + private void SetPte(ulong va, ulong pte) + { + ulong l0 = (va >> PtLvl0Bit) & PtLvl0Mask; + ulong l1 = (va >> PtLvl1Bit) & PtLvl1Mask; + + if (_pageTable[l0] == null) + { + _pageTable[l0] = new ulong[PtLvl1Size]; + + for (ulong index = 0; index < PtLvl1Size; index++) + { + _pageTable[l0][index] = PteUnmapped; + } + } + + _pageTable[l0][l1] = pte; + } + + /// + /// Creates a page table entry from a physical address and kind. + /// + /// Physical address + /// Page table entry + private static ulong PackPte(ulong pa) + { + return pa; + } + + /// + /// Unpacks physical address from a page table entry. + /// + /// Page table entry + /// Physical address + private static ulong UnpackPaFromPte(ulong pte) + { + return pte; + } + } +} diff --git a/src/Ryujinx.Graphics.Device/DeviceState.cs b/src/Ryujinx.Graphics.Device/DeviceState.cs index f5b30836b..d001995ef 100644 --- a/src/Ryujinx.Graphics.Device/DeviceState.cs +++ b/src/Ryujinx.Graphics.Device/DeviceState.cs @@ -40,15 +40,10 @@ namespace Ryujinx.Graphics.Device { var field = fields[fieldIndex]; - var cuurentFieldOffset = (int)Marshal.OffsetOf(field.Name); + var currentFieldOffset = (int)Marshal.OffsetOf(field.Name); var nextFieldOffset = fieldIndex + 1 == fields.Length ? Unsafe.SizeOf() : (int)Marshal.OffsetOf(fields[fieldIndex + 1].Name); - int sizeOfField = nextFieldOffset - cuurentFieldOffset; - - if(sizeOfField == 0) - { - - } + int sizeOfField = nextFieldOffset - currentFieldOffset; for (int i = 0; i < ((sizeOfField + 3) & ~3); i += 4) { diff --git a/src/Ryujinx.Graphics.Device/ISynchronizationManager.cs b/src/Ryujinx.Graphics.Device/ISynchronizationManager.cs new file mode 100644 index 000000000..2a8d1d9b7 --- /dev/null +++ b/src/Ryujinx.Graphics.Device/ISynchronizationManager.cs @@ -0,0 +1,39 @@ +using Ryujinx.Common.Logging; +using System; +using System.Threading; + +namespace Ryujinx.Graphics.Device +{ + /// + /// Synchronization manager interface. + /// + public interface ISynchronizationManager + { + /// + /// Increment the value of a syncpoint with a given id. + /// + /// The id of the syncpoint + /// Thrown when id >= MaxHardwareSyncpoints + /// The incremented value of the syncpoint + uint IncrementSyncpoint(uint id); + + /// + /// Get the value of a syncpoint with a given id. + /// + /// The id of the syncpoint + /// Thrown when id >= MaxHardwareSyncpoints + /// The value of the syncpoint + uint GetSyncpointValue(uint id); + + /// + /// Wait on a syncpoint with a given id at a target threshold. + /// The callback will be called once the threshold is reached and will automatically be unregistered. + /// + /// The id of the syncpoint + /// The target threshold + /// The timeout + /// Thrown when id >= MaxHardwareSyncpoints + /// True if timed out + bool WaitOnSyncpoint(uint id, uint threshold, TimeSpan timeout); + } +} diff --git a/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj b/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj index ae2821edb..973a9e260 100644 --- a/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj +++ b/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj @@ -4,4 +4,8 @@ net8.0 + + + + diff --git a/src/Ryujinx.Graphics.GAL/BufferAccess.cs b/src/Ryujinx.Graphics.GAL/BufferAccess.cs index faefa5188..1e7736f8f 100644 --- a/src/Ryujinx.Graphics.GAL/BufferAccess.cs +++ b/src/Ryujinx.Graphics.GAL/BufferAccess.cs @@ -6,8 +6,13 @@ namespace Ryujinx.Graphics.GAL public enum BufferAccess { Default = 0, - FlushPersistent = 1 << 0, - Stream = 1 << 1, - SparseCompatible = 1 << 2, + HostMemory = 1, + DeviceMemory = 2, + DeviceMemoryMapped = 3, + + MemoryTypeMask = 0xf, + + Stream = 1 << 4, + SparseCompatible = 1 << 5, } } diff --git a/src/Ryujinx.Graphics.GAL/Capabilities.cs b/src/Ryujinx.Graphics.GAL/Capabilities.cs index dc927eaba..1eec80e51 100644 --- a/src/Ryujinx.Graphics.GAL/Capabilities.cs +++ b/src/Ryujinx.Graphics.GAL/Capabilities.cs @@ -6,6 +6,7 @@ namespace Ryujinx.Graphics.GAL { public readonly TargetApi Api; public readonly string VendorName; + public readonly SystemMemoryType MemoryType; public readonly bool HasFrontFacingBug; public readonly bool HasVectorIndexingBug; @@ -36,6 +37,8 @@ namespace Ryujinx.Graphics.GAL public readonly bool SupportsMismatchingViewFormat; public readonly bool SupportsCubemapView; public readonly bool SupportsNonConstantTextureOffset; + public readonly bool SupportsQuads; + public readonly bool SupportsSeparateSampler; public readonly bool SupportsShaderBallot; public readonly bool SupportsShaderBarrierDivergence; public readonly bool SupportsShaderFloat64; @@ -48,6 +51,13 @@ namespace Ryujinx.Graphics.GAL public readonly bool SupportsIndirectParameters; public readonly bool SupportsDepthClipControl; + public readonly int UniformBufferSetIndex; + public readonly int StorageBufferSetIndex; + public readonly int TextureSetIndex; + public readonly int ImageSetIndex; + public readonly int ExtraSetBaseIndex; + public readonly int MaximumExtraSets; + public readonly uint MaximumUniformBuffersPerStage; public readonly uint MaximumStorageBuffersPerStage; public readonly uint MaximumTexturesPerStage; @@ -61,9 +71,12 @@ namespace Ryujinx.Graphics.GAL public readonly int GatherBiasPrecision; + public readonly ulong MaximumGpuMemory; + public Capabilities( TargetApi api, string vendorName, + SystemMemoryType memoryType, bool hasFrontFacingBug, bool hasVectorIndexingBug, bool needsFragmentOutputSpecialization, @@ -92,6 +105,8 @@ namespace Ryujinx.Graphics.GAL bool supportsMismatchingViewFormat, bool supportsCubemapView, bool supportsNonConstantTextureOffset, + bool supportsQuads, + bool supportsSeparateSampler, bool supportsShaderBallot, bool supportsShaderBarrierDivergence, bool supportsShaderFloat64, @@ -103,6 +118,12 @@ namespace Ryujinx.Graphics.GAL bool supportsViewportSwizzle, bool supportsIndirectParameters, bool supportsDepthClipControl, + int uniformBufferSetIndex, + int storageBufferSetIndex, + int textureSetIndex, + int imageSetIndex, + int extraSetBaseIndex, + int maximumExtraSets, uint maximumUniformBuffersPerStage, uint maximumStorageBuffersPerStage, uint maximumTexturesPerStage, @@ -112,10 +133,12 @@ namespace Ryujinx.Graphics.GAL int shaderSubgroupSize, int storageBufferOffsetAlignment, int textureBufferOffsetAlignment, - int gatherBiasPrecision) + int gatherBiasPrecision, + ulong maximumGpuMemory) { Api = api; VendorName = vendorName; + MemoryType = memoryType; HasFrontFacingBug = hasFrontFacingBug; HasVectorIndexingBug = hasVectorIndexingBug; NeedsFragmentOutputSpecialization = needsFragmentOutputSpecialization; @@ -144,6 +167,8 @@ namespace Ryujinx.Graphics.GAL SupportsMismatchingViewFormat = supportsMismatchingViewFormat; SupportsCubemapView = supportsCubemapView; SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset; + SupportsQuads = supportsQuads; + SupportsSeparateSampler = supportsSeparateSampler; SupportsShaderBallot = supportsShaderBallot; SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence; SupportsShaderFloat64 = supportsShaderFloat64; @@ -155,6 +180,12 @@ namespace Ryujinx.Graphics.GAL SupportsViewportSwizzle = supportsViewportSwizzle; SupportsIndirectParameters = supportsIndirectParameters; SupportsDepthClipControl = supportsDepthClipControl; + UniformBufferSetIndex = uniformBufferSetIndex; + StorageBufferSetIndex = storageBufferSetIndex; + TextureSetIndex = textureSetIndex; + ImageSetIndex = imageSetIndex; + ExtraSetBaseIndex = extraSetBaseIndex; + MaximumExtraSets = maximumExtraSets; MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage; MaximumStorageBuffersPerStage = maximumStorageBuffersPerStage; MaximumTexturesPerStage = maximumTexturesPerStage; @@ -165,6 +196,7 @@ namespace Ryujinx.Graphics.GAL StorageBufferOffsetAlignment = storageBufferOffsetAlignment; TextureBufferOffsetAlignment = textureBufferOffsetAlignment; GatherBiasPrecision = gatherBiasPrecision; + MaximumGpuMemory = maximumGpuMemory; } } } diff --git a/src/Ryujinx.Graphics.GAL/Format.cs b/src/Ryujinx.Graphics.GAL/Format.cs index 99c89dcec..17c42d2d4 100644 --- a/src/Ryujinx.Graphics.GAL/Format.cs +++ b/src/Ryujinx.Graphics.GAL/Format.cs @@ -147,6 +147,8 @@ namespace Ryujinx.Graphics.GAL A1B5G5R5Unorm, B8G8R8A8Unorm, B8G8R8A8Srgb, + B10G10R10A2Unorm, + X8UintD24Unorm, } public static class FormatExtensions @@ -260,6 +262,7 @@ namespace Ryujinx.Graphics.GAL case Format.R10G10B10A2Sint: case Format.R10G10B10A2Uscaled: case Format.R10G10B10A2Sscaled: + case Format.B10G10R10A2Unorm: return 4; case Format.S8Uint: @@ -267,6 +270,7 @@ namespace Ryujinx.Graphics.GAL case Format.D16Unorm: return 2; case Format.S8UintD24Unorm: + case Format.X8UintD24Unorm: case Format.D32Float: case Format.D24UnormS8Uint: return 4; @@ -347,6 +351,7 @@ namespace Ryujinx.Graphics.GAL case Format.D16Unorm: case Format.D24UnormS8Uint: case Format.S8UintD24Unorm: + case Format.X8UintD24Unorm: case Format.D32Float: case Format.D32FloatS8Uint: return true; @@ -451,6 +456,7 @@ namespace Ryujinx.Graphics.GAL case Format.R32G32Uint: case Format.B8G8R8A8Unorm: case Format.B8G8R8A8Srgb: + case Format.B10G10R10A2Unorm: case Format.R10G10B10A2Unorm: case Format.R10G10B10A2Uint: case Format.R8G8B8A8Unorm: @@ -611,6 +617,7 @@ namespace Ryujinx.Graphics.GAL case Format.B5G5R5A1Unorm: case Format.B8G8R8A8Unorm: case Format.B8G8R8A8Srgb: + case Format.B10G10R10A2Unorm: return true; } @@ -629,6 +636,7 @@ namespace Ryujinx.Graphics.GAL case Format.D16Unorm: case Format.D24UnormS8Uint: case Format.S8UintD24Unorm: + case Format.X8UintD24Unorm: case Format.D32Float: case Format.D32FloatS8Uint: case Format.S8Uint: @@ -703,5 +711,36 @@ namespace Ryujinx.Graphics.GAL { return format.IsUint() || format.IsSint(); } + + /// + /// Checks if the texture format is a float or sRGB color format. + /// + /// + /// Does not include normalized, compressed or depth formats. + /// Float and sRGB formats do not participate in logical operations. + /// + /// Texture format + /// True if the format is a float or sRGB color format, false otherwise + public static bool IsFloatOrSrgb(this Format format) + { + switch (format) + { + case Format.R8G8B8A8Srgb: + case Format.B8G8R8A8Srgb: + case Format.R16Float: + case Format.R16G16Float: + case Format.R16G16B16Float: + case Format.R16G16B16A16Float: + case Format.R32Float: + case Format.R32G32Float: + case Format.R32G32B32Float: + case Format.R32G32B32A32Float: + case Format.R11G11B10Float: + case Format.R9G9B9E5Float: + return true; + } + + return false; + } } } diff --git a/src/Ryujinx.Graphics.GAL/HardwareInfo.cs b/src/Ryujinx.Graphics.GAL/HardwareInfo.cs index d8f7d1f71..c2546fa46 100644 --- a/src/Ryujinx.Graphics.GAL/HardwareInfo.cs +++ b/src/Ryujinx.Graphics.GAL/HardwareInfo.cs @@ -4,11 +4,13 @@ namespace Ryujinx.Graphics.GAL { public string GpuVendor { get; } public string GpuModel { get; } + public string GpuDriver { get; } - public HardwareInfo(string gpuVendor, string gpuModel) + public HardwareInfo(string gpuVendor, string gpuModel, string gpuDriver) { GpuVendor = gpuVendor; GpuModel = gpuModel; + GpuDriver = gpuDriver; } } } diff --git a/src/Ryujinx.Graphics.GAL/IImageArray.cs b/src/Ryujinx.Graphics.GAL/IImageArray.cs new file mode 100644 index 000000000..d87314eb8 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/IImageArray.cs @@ -0,0 +1,9 @@ +using System; + +namespace Ryujinx.Graphics.GAL +{ + public interface IImageArray : IDisposable + { + void SetImages(int index, ITexture[] images); + } +} diff --git a/src/Ryujinx.Graphics.GAL/IPipeline.cs b/src/Ryujinx.Graphics.GAL/IPipeline.cs index f5978cefa..b8409a573 100644 --- a/src/Ryujinx.Graphics.GAL/IPipeline.cs +++ b/src/Ryujinx.Graphics.GAL/IPipeline.cs @@ -58,7 +58,9 @@ namespace Ryujinx.Graphics.GAL void SetIndexBuffer(BufferRange buffer, IndexType type); - void SetImage(int binding, ITexture texture, Format imageFormat); + void SetImage(ShaderStage stage, int binding, ITexture texture); + void SetImageArray(ShaderStage stage, int binding, IImageArray array); + void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array); void SetLineParameters(float width, bool smooth); @@ -89,6 +91,8 @@ namespace Ryujinx.Graphics.GAL void SetStorageBuffers(ReadOnlySpan buffers); void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler); + void SetTextureArray(ShaderStage stage, int binding, ITextureArray array); + void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array); void SetTransformFeedbackBuffers(ReadOnlySpan buffers); void SetUniformBuffers(ReadOnlySpan buffers); diff --git a/src/Ryujinx.Graphics.GAL/IRenderer.cs b/src/Ryujinx.Graphics.GAL/IRenderer.cs index 3bf56465e..85d0bd729 100644 --- a/src/Ryujinx.Graphics.GAL/IRenderer.cs +++ b/src/Ryujinx.Graphics.GAL/IRenderer.cs @@ -17,14 +17,17 @@ namespace Ryujinx.Graphics.GAL void BackgroundContextAction(Action action, bool alwaysBackground = false); BufferHandle CreateBuffer(int size, BufferAccess access = BufferAccess.Default); - BufferHandle CreateBuffer(int size, BufferAccess access, BufferHandle storageHint); BufferHandle CreateBuffer(nint pointer, int size); BufferHandle CreateBufferSparse(ReadOnlySpan storageBuffers); + IImageArray CreateImageArray(int size, bool isBuffer); + IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info); ISampler CreateSampler(SamplerCreateInfo info); ITexture CreateTexture(TextureCreateInfo info); + ITextureArray CreateTextureArray(int size, bool isBuffer); + bool PrepareHostMapping(nint address, ulong size); void CreateSync(ulong id, bool strict); diff --git a/src/Ryujinx.Graphics.GAL/ITexture.cs b/src/Ryujinx.Graphics.GAL/ITexture.cs index ea8d68649..ed705de97 100644 --- a/src/Ryujinx.Graphics.GAL/ITexture.cs +++ b/src/Ryujinx.Graphics.GAL/ITexture.cs @@ -19,29 +19,33 @@ namespace Ryujinx.Graphics.GAL PinnedSpan GetData(int layer, int level); /// - /// Sets the texture data. The data passed as a will be disposed when the operation completes. + /// Sets the texture data. The data passed as a will be disposed when + /// the operation completes. /// /// Texture data bytes - void SetData(IMemoryOwner data); + void SetData(MemoryOwner data); /// - /// Sets the texture data. The data passed as a will be disposed when the operation completes. + /// Sets the texture data. The data passed as a will be disposed when + /// the operation completes. /// /// Texture data bytes /// Target layer /// Target level - void SetData(IMemoryOwner data, int layer, int level); + void SetData(MemoryOwner data, int layer, int level); /// - /// Sets the texture data. The data passed as a will be disposed when the operation completes. + /// Sets the texture data. The data passed as a will be disposed when + /// the operation completes. /// /// Texture data bytes /// Target layer /// Target level /// Target sub-region of the texture to update - void SetData(IMemoryOwner data, int layer, int level, Rectangle region); + void SetData(MemoryOwner data, int layer, int level, Rectangle region); void SetStorage(BufferRange buffer); + void Release(); } } diff --git a/src/Ryujinx.Graphics.GAL/ITextureArray.cs b/src/Ryujinx.Graphics.GAL/ITextureArray.cs new file mode 100644 index 000000000..9ee79dacb --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/ITextureArray.cs @@ -0,0 +1,10 @@ +using System; + +namespace Ryujinx.Graphics.GAL +{ + public interface ITextureArray : IDisposable + { + void SetSamplers(int index, ISampler[] samplers); + void SetTextures(int index, ITexture[] textures); + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs b/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs index 5bf3d3283..a1e6db971 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs @@ -1,10 +1,12 @@ using Ryujinx.Graphics.GAL.Multithreading.Commands; using Ryujinx.Graphics.GAL.Multithreading.Commands.Buffer; using Ryujinx.Graphics.GAL.Multithreading.Commands.CounterEvent; +using Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray; using Ryujinx.Graphics.GAL.Multithreading.Commands.Program; using Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer; using Ryujinx.Graphics.GAL.Multithreading.Commands.Sampler; using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture; +using Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray; using Ryujinx.Graphics.GAL.Multithreading.Commands.Window; using System; using System.Linq; @@ -42,14 +44,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading } Register(CommandType.Action); - Register(CommandType.CreateBuffer); Register(CommandType.CreateBufferAccess); Register(CommandType.CreateBufferSparse); Register(CommandType.CreateHostBuffer); + Register(CommandType.CreateImageArray); Register(CommandType.CreateProgram); Register(CommandType.CreateSampler); Register(CommandType.CreateSync); Register(CommandType.CreateTexture); + Register(CommandType.CreateTextureArray); Register(CommandType.GetCapabilities); Register(CommandType.PreFrame); Register(CommandType.ReportCounter); @@ -63,6 +66,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading Register(CommandType.CounterEventDispose); Register(CommandType.CounterEventFlush); + Register(CommandType.ImageArrayDispose); + Register(CommandType.ImageArraySetImages); + Register(CommandType.ProgramDispose); Register(CommandType.ProgramGetBinary); Register(CommandType.ProgramCheckLink); @@ -82,6 +88,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading Register(CommandType.TextureSetDataSliceRegion); Register(CommandType.TextureSetStorage); + Register(CommandType.TextureArrayDispose); + Register(CommandType.TextureArraySetSamplers); + Register(CommandType.TextureArraySetTextures); + Register(CommandType.WindowPresent); Register(CommandType.Barrier); @@ -114,6 +124,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading Register(CommandType.SetTransformFeedbackBuffers); Register(CommandType.SetUniformBuffers); Register(CommandType.SetImage); + Register(CommandType.SetImageArray); + Register(CommandType.SetImageArraySeparate); Register(CommandType.SetIndexBuffer); Register(CommandType.SetLineParameters); Register(CommandType.SetLogicOpState); @@ -130,6 +142,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading Register(CommandType.SetScissor); Register(CommandType.SetStencilTest); Register(CommandType.SetTextureAndSampler); + Register(CommandType.SetTextureArray); + Register(CommandType.SetTextureArraySeparate); Register(CommandType.SetUserClipDistance); Register(CommandType.SetVertexAttribs); Register(CommandType.SetVertexBuffers); diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs b/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs index 6be639253..348c8e462 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs @@ -3,14 +3,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading enum CommandType : byte { Action, - CreateBuffer, CreateBufferAccess, CreateBufferSparse, CreateHostBuffer, + CreateImageArray, CreateProgram, CreateSampler, CreateSync, CreateTexture, + CreateTextureArray, GetCapabilities, Unused, PreFrame, @@ -25,6 +26,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading CounterEventDispose, CounterEventFlush, + ImageArrayDispose, + ImageArraySetImages, + ProgramDispose, ProgramGetBinary, ProgramCheckLink, @@ -44,6 +48,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading TextureSetDataSliceRegion, TextureSetStorage, + TextureArrayDispose, + TextureArraySetSamplers, + TextureArraySetTextures, + WindowPresent, Barrier, @@ -76,6 +84,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading SetTransformFeedbackBuffers, SetUniformBuffers, SetImage, + SetImageArray, + SetImageArraySeparate, SetIndexBuffer, SetLineParameters, SetLogicOpState, @@ -92,6 +102,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading SetScissor, SetStencilTest, SetTextureAndSampler, + SetTextureArray, + SetTextureArraySeparate, SetUserClipDistance, SetVertexAttribs, SetVertexBuffers, diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArrayDisposeCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArrayDisposeCommand.cs new file mode 100644 index 000000000..ac2ac933b --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArrayDisposeCommand.cs @@ -0,0 +1,21 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray +{ + struct ImageArrayDisposeCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.ImageArrayDispose; + private TableRef _imageArray; + + public void Set(TableRef imageArray) + { + _imageArray = imageArray; + } + + public static void Run(ref ImageArrayDisposeCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + command._imageArray.Get(threaded).Base.Dispose(); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArraySetImagesCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArraySetImagesCommand.cs new file mode 100644 index 000000000..cc28d585c --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArraySetImagesCommand.cs @@ -0,0 +1,27 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; +using System.Linq; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray +{ + struct ImageArraySetImagesCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.ImageArraySetImages; + private TableRef _imageArray; + private int _index; + private TableRef _images; + + public void Set(TableRef imageArray, int index, TableRef images) + { + _imageArray = imageArray; + _index = index; + _images = images; + } + + public static void Run(ref ImageArraySetImagesCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + ThreadedImageArray imageArray = command._imageArray.Get(threaded); + imageArray.Base.SetImages(command._index, command._images.Get(threaded).Select(texture => ((ThreadedTexture)texture)?.Base).ToArray()); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateBufferCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateBufferCommand.cs deleted file mode 100644 index 60a6e4bf4..000000000 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateBufferCommand.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer -{ - struct CreateBufferCommand : IGALCommand, IGALCommand - { - public readonly CommandType CommandType => CommandType.CreateBuffer; - private BufferHandle _threadedHandle; - private int _size; - private BufferAccess _access; - private BufferHandle _storageHint; - - public void Set(BufferHandle threadedHandle, int size, BufferAccess access, BufferHandle storageHint) - { - _threadedHandle = threadedHandle; - _size = size; - _access = access; - _storageHint = storageHint; - } - - public static void Run(ref CreateBufferCommand command, ThreadedRenderer threaded, IRenderer renderer) - { - BufferHandle hint = BufferHandle.Null; - - if (command._storageHint != BufferHandle.Null) - { - hint = threaded.Buffers.MapBuffer(command._storageHint); - } - - threaded.Buffers.AssignBuffer(command._threadedHandle, renderer.CreateBuffer(command._size, command._access, hint)); - } - } -} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateImageArrayCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateImageArrayCommand.cs new file mode 100644 index 000000000..1c3fb8120 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateImageArrayCommand.cs @@ -0,0 +1,25 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer +{ + struct CreateImageArrayCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.CreateImageArray; + private TableRef _imageArray; + private int _size; + private bool _isBuffer; + + public void Set(TableRef imageArray, int size, bool isBuffer) + { + _imageArray = imageArray; + _size = size; + _isBuffer = isBuffer; + } + + public static void Run(ref CreateImageArrayCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + command._imageArray.Get(threaded).Base = renderer.CreateImageArray(command._size, command._isBuffer); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateTextureArrayCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateTextureArrayCommand.cs new file mode 100644 index 000000000..9bd891e68 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateTextureArrayCommand.cs @@ -0,0 +1,25 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer +{ + struct CreateTextureArrayCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.CreateTextureArray; + private TableRef _textureArray; + private int _size; + private bool _isBuffer; + + public void Set(TableRef textureArray, int size, bool isBuffer) + { + _textureArray = textureArray; + _size = size; + _isBuffer = isBuffer; + } + + public static void Run(ref CreateTextureArrayCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + command._textureArray.Get(threaded).Base = renderer.CreateTextureArray(command._size, command._isBuffer); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArrayCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArrayCommand.cs new file mode 100644 index 000000000..b8d3c7ac5 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArrayCommand.cs @@ -0,0 +1,26 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; +using Ryujinx.Graphics.Shader; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands +{ + struct SetImageArrayCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.SetImageArray; + private ShaderStage _stage; + private int _binding; + private TableRef _array; + + public void Set(ShaderStage stage, int binding, TableRef array) + { + _stage = stage; + _binding = binding; + _array = array; + } + + public static void Run(ref SetImageArrayCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + renderer.Pipeline.SetImageArray(command._stage, command._binding, command._array.GetAs(threaded)?.Base); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArraySeparateCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArraySeparateCommand.cs new file mode 100644 index 000000000..abeb58a06 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArraySeparateCommand.cs @@ -0,0 +1,26 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; +using Ryujinx.Graphics.Shader; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands +{ + struct SetImageArraySeparateCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.SetImageArraySeparate; + private ShaderStage _stage; + private int _setIndex; + private TableRef _array; + + public void Set(ShaderStage stage, int setIndex, TableRef array) + { + _stage = stage; + _setIndex = setIndex; + _array = array; + } + + public static void Run(ref SetImageArraySeparateCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + renderer.Pipeline.SetImageArraySeparate(command._stage, command._setIndex, command._array.GetAs(threaded)?.Base); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs index b4e966ca8..2ba9db527 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs @@ -1,25 +1,26 @@ using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Resources; +using Ryujinx.Graphics.Shader; namespace Ryujinx.Graphics.GAL.Multithreading.Commands { struct SetImageCommand : IGALCommand, IGALCommand { public readonly CommandType CommandType => CommandType.SetImage; + private ShaderStage _stage; private int _binding; private TableRef _texture; - private Format _imageFormat; - public void Set(int binding, TableRef texture, Format imageFormat) + public void Set(ShaderStage stage, int binding, TableRef texture) { + _stage = stage; _binding = binding; _texture = texture; - _imageFormat = imageFormat; } public static void Run(ref SetImageCommand command, ThreadedRenderer threaded, IRenderer renderer) { - renderer.Pipeline.SetImage(command._binding, command._texture.GetAs(threaded)?.Base, command._imageFormat); + renderer.Pipeline.SetImage(command._stage, command._binding, command._texture.GetAs(threaded)?.Base); } } } diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArrayCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArrayCommand.cs new file mode 100644 index 000000000..45e28aa65 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArrayCommand.cs @@ -0,0 +1,26 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; +using Ryujinx.Graphics.Shader; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands +{ + struct SetTextureArrayCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.SetTextureArray; + private ShaderStage _stage; + private int _binding; + private TableRef _array; + + public void Set(ShaderStage stage, int binding, TableRef array) + { + _stage = stage; + _binding = binding; + _array = array; + } + + public static void Run(ref SetTextureArrayCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + renderer.Pipeline.SetTextureArray(command._stage, command._binding, command._array.GetAs(threaded)?.Base); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArraySeparateCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArraySeparateCommand.cs new file mode 100644 index 000000000..b179f2e70 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArraySeparateCommand.cs @@ -0,0 +1,26 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; +using Ryujinx.Graphics.Shader; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands +{ + struct SetTextureArraySeparateCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.SetTextureArraySeparate; + private ShaderStage _stage; + private int _setIndex; + private TableRef _array; + + public void Set(ShaderStage stage, int setIndex, TableRef array) + { + _stage = stage; + _setIndex = setIndex; + _array = array; + } + + public static void Run(ref SetTextureArraySeparateCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + renderer.Pipeline.SetTextureArraySeparate(command._stage, command._setIndex, command._array.GetAs(threaded)?.Base); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs index a7a8846e4..4449566a7 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs @@ -1,7 +1,6 @@ +using Ryujinx.Common.Memory; using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Resources; -using System; -using System.Buffers; namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture { @@ -9,9 +8,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture { public readonly CommandType CommandType => CommandType.TextureSetData; private TableRef _texture; - private TableRef> _data; + private TableRef> _data; - public void Set(TableRef texture, TableRef> data) + public void Set(TableRef texture, TableRef> data) { _texture = texture; _data = data; diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs index bb24ee140..3619149e9 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs @@ -1,7 +1,6 @@ +using Ryujinx.Common.Memory; using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Resources; -using System; -using System.Buffers; namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture { @@ -9,11 +8,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture { public readonly CommandType CommandType => CommandType.TextureSetDataSlice; private TableRef _texture; - private TableRef> _data; + private TableRef> _data; private int _layer; private int _level; - public void Set(TableRef texture, TableRef> data, int layer, int level) + public void Set(TableRef texture, TableRef> data, int layer, int level) { _texture = texture; _data = data; diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs index 93631267b..6c6a53636 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs @@ -1,7 +1,6 @@ +using Ryujinx.Common.Memory; using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Resources; -using System; -using System.Buffers; namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture { @@ -9,12 +8,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture { public readonly CommandType CommandType => CommandType.TextureSetDataSliceRegion; private TableRef _texture; - private TableRef> _data; + private TableRef> _data; private int _layer; private int _level; private Rectangle _region; - public void Set(TableRef texture, TableRef> data, int layer, int level, Rectangle region) + public void Set(TableRef texture, TableRef> data, int layer, int level, Rectangle region) { _texture = texture; _data = data; diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArrayDisposeCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArrayDisposeCommand.cs new file mode 100644 index 000000000..fec1c48f0 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArrayDisposeCommand.cs @@ -0,0 +1,21 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray +{ + struct TextureArrayDisposeCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.TextureArrayDispose; + private TableRef _textureArray; + + public void Set(TableRef textureArray) + { + _textureArray = textureArray; + } + + public static void Run(ref TextureArrayDisposeCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + command._textureArray.Get(threaded).Base.Dispose(); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArraySetSamplersCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArraySetSamplersCommand.cs new file mode 100644 index 000000000..204ee32da --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArraySetSamplersCommand.cs @@ -0,0 +1,27 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; +using System.Linq; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray +{ + struct TextureArraySetSamplersCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.TextureArraySetSamplers; + private TableRef _textureArray; + private int _index; + private TableRef _samplers; + + public void Set(TableRef textureArray, int index, TableRef samplers) + { + _textureArray = textureArray; + _index = index; + _samplers = samplers; + } + + public static void Run(ref TextureArraySetSamplersCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + ThreadedTextureArray textureArray = command._textureArray.Get(threaded); + textureArray.Base.SetSamplers(command._index, command._samplers.Get(threaded).Select(sampler => ((ThreadedSampler)sampler)?.Base).ToArray()); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArraySetTexturesCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArraySetTexturesCommand.cs new file mode 100644 index 000000000..cc94d1b6d --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureArray/TextureArraySetTexturesCommand.cs @@ -0,0 +1,27 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; +using System.Linq; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray +{ + struct TextureArraySetTexturesCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.TextureArraySetTextures; + private TableRef _textureArray; + private int _index; + private TableRef _textures; + + public void Set(TableRef textureArray, int index, TableRef textures) + { + _textureArray = textureArray; + _index = index; + _textures = textures; + } + + public static void Run(ref TextureArraySetTexturesCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + ThreadedTextureArray textureArray = command._textureArray.Get(threaded); + textureArray.Base.SetTextures(command._index, command._textures.Get(threaded).Select(texture => ((ThreadedTexture)texture)?.Base).ToArray()); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs new file mode 100644 index 000000000..82587c189 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs @@ -0,0 +1,36 @@ +using Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray; +using Ryujinx.Graphics.GAL.Multithreading.Model; + +namespace Ryujinx.Graphics.GAL.Multithreading.Resources +{ + /// + /// Threaded representation of a image array. + /// + class ThreadedImageArray : IImageArray + { + private readonly ThreadedRenderer _renderer; + public IImageArray Base; + + public ThreadedImageArray(ThreadedRenderer renderer) + { + _renderer = renderer; + } + + private TableRef Ref(T reference) + { + return new TableRef(_renderer, reference); + } + + public void Dispose() + { + _renderer.New().Set(Ref(this)); + _renderer.QueueCommand(); + } + + public void SetImages(int index, ITexture[] images) + { + _renderer.New().Set(Ref(this), index, Ref(images)); + _renderer.QueueCommand(); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs index b674930e1..0d545db94 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs @@ -111,19 +111,22 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources _renderer.QueueCommand(); } - public void SetData(IMemoryOwner data) + /// + public void SetData(MemoryOwner data) { _renderer.New().Set(Ref(this), Ref(data)); _renderer.QueueCommand(); } - public void SetData(IMemoryOwner data, int layer, int level) + /// + public void SetData(MemoryOwner data, int layer, int level) { _renderer.New().Set(Ref(this), Ref(data), layer, level); _renderer.QueueCommand(); } - public void SetData(IMemoryOwner data, int layer, int level, Rectangle region) + /// + public void SetData(MemoryOwner data, int layer, int level, Rectangle region) { _renderer.New().Set(Ref(this), Ref(data), layer, level, region); _renderer.QueueCommand(); diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTextureArray.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTextureArray.cs new file mode 100644 index 000000000..4334c7048 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTextureArray.cs @@ -0,0 +1,43 @@ +using Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray; +using Ryujinx.Graphics.GAL.Multithreading.Model; +using System.Linq; + +namespace Ryujinx.Graphics.GAL.Multithreading.Resources +{ + /// + /// Threaded representation of a texture and sampler array. + /// + class ThreadedTextureArray : ITextureArray + { + private readonly ThreadedRenderer _renderer; + public ITextureArray Base; + + public ThreadedTextureArray(ThreadedRenderer renderer) + { + _renderer = renderer; + } + + private TableRef Ref(T reference) + { + return new TableRef(_renderer, reference); + } + + public void Dispose() + { + _renderer.New().Set(Ref(this)); + _renderer.QueueCommand(); + } + + public void SetSamplers(int index, ISampler[] samplers) + { + _renderer.New().Set(Ref(this), index, Ref(samplers.ToArray())); + _renderer.QueueCommand(); + } + + public void SetTextures(int index, ITexture[] textures) + { + _renderer.New().Set(Ref(this), index, Ref(textures.ToArray())); + _renderer.QueueCommand(); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs index f40d9896c..deec36648 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs @@ -177,9 +177,21 @@ namespace Ryujinx.Graphics.GAL.Multithreading _renderer.QueueCommand(); } - public void SetImage(int binding, ITexture texture, Format imageFormat) + public void SetImage(ShaderStage stage, int binding, ITexture texture) { - _renderer.New().Set(binding, Ref(texture), imageFormat); + _renderer.New().Set(stage, binding, Ref(texture)); + _renderer.QueueCommand(); + } + + public void SetImageArray(ShaderStage stage, int binding, IImageArray array) + { + _renderer.New().Set(stage, binding, Ref(array)); + _renderer.QueueCommand(); + } + + public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array) + { + _renderer.New().Set(stage, setIndex, Ref(array)); _renderer.QueueCommand(); } @@ -285,6 +297,18 @@ namespace Ryujinx.Graphics.GAL.Multithreading _renderer.QueueCommand(); } + public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array) + { + _renderer.New().Set(stage, binding, Ref(array)); + _renderer.QueueCommand(); + } + + public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array) + { + _renderer.New().Set(stage, setIndex, Ref(array)); + _renderer.QueueCommand(); + } + public void SetTransformFeedbackBuffers(ReadOnlySpan buffers) { _renderer.New().Set(_renderer.CopySpan(buffers)); diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs index 830fbf2d9..cc3d2e5c1 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs @@ -272,15 +272,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading return handle; } - public BufferHandle CreateBuffer(int size, BufferAccess access, BufferHandle storageHint) - { - BufferHandle handle = Buffers.CreateBufferHandle(); - New().Set(handle, size, access, storageHint); - QueueCommand(); - - return handle; - } - public BufferHandle CreateBuffer(nint pointer, int size) { BufferHandle handle = Buffers.CreateBufferHandle(); @@ -299,6 +290,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading return handle; } + public IImageArray CreateImageArray(int size, bool isBuffer) + { + var imageArray = new ThreadedImageArray(this); + New().Set(Ref(imageArray), size, isBuffer); + QueueCommand(); + + return imageArray; + } + public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info) { var program = new ThreadedProgram(this); @@ -349,6 +349,14 @@ namespace Ryujinx.Graphics.GAL.Multithreading return texture; } } + public ITextureArray CreateTextureArray(int size, bool isBuffer) + { + var textureArray = new ThreadedTextureArray(this); + New().Set(Ref(textureArray), size, isBuffer); + QueueCommand(); + + return textureArray; + } public void DeleteBuffer(BufferHandle buffer) { diff --git a/src/Ryujinx.Graphics.GAL/ResourceLayout.cs b/src/Ryujinx.Graphics.GAL/ResourceLayout.cs index 84bca5b41..b7464ee12 100644 --- a/src/Ryujinx.Graphics.GAL/ResourceLayout.cs +++ b/src/Ryujinx.Graphics.GAL/ResourceLayout.cs @@ -71,19 +71,23 @@ namespace Ryujinx.Graphics.GAL public readonly struct ResourceUsage : IEquatable { public int Binding { get; } + public int ArrayLength { get; } public ResourceType Type { get; } public ResourceStages Stages { get; } + public bool Write { get; } - public ResourceUsage(int binding, ResourceType type, ResourceStages stages) + public ResourceUsage(int binding, int arrayLength, ResourceType type, ResourceStages stages, bool write) { Binding = binding; + ArrayLength = arrayLength; Type = type; Stages = stages; + Write = write; } public override int GetHashCode() { - return HashCode.Combine(Binding, Type, Stages); + return HashCode.Combine(Binding, ArrayLength, Type, Stages); } public override bool Equals(object obj) @@ -93,7 +97,7 @@ namespace Ryujinx.Graphics.GAL public bool Equals(ResourceUsage other) { - return Binding == other.Binding && Type == other.Type && Stages == other.Stages; + return Binding == other.Binding && ArrayLength == other.ArrayLength && Type == other.Type && Stages == other.Stages; } public static bool operator ==(ResourceUsage left, ResourceUsage right) diff --git a/src/Ryujinx.Graphics.GAL/SystemMemoryType.cs b/src/Ryujinx.Graphics.GAL/SystemMemoryType.cs new file mode 100644 index 000000000..532921298 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/SystemMemoryType.cs @@ -0,0 +1,29 @@ +namespace Ryujinx.Graphics.GAL +{ + public enum SystemMemoryType + { + /// + /// The backend manages the ownership of memory. This mode never supports host imported memory. + /// + BackendManaged, + + /// + /// Device memory has similar performance to host memory, usually because it's shared between CPU/GPU. + /// Use host memory whenever possible. + /// + UnifiedMemory, + + /// + /// GPU storage to host memory goes though a slow interconnect, but it would still be preferable to use it if the data is flushed back often. + /// Assumes constant buffer access to host memory is rather fast. + /// + DedicatedMemory, + + /// + /// GPU storage to host memory goes though a slow interconnect, that is very slow when doing access from storage. + /// When frequently accessed, copy buffers to host memory using DMA. + /// Assumes constant buffer access to host memory is rather fast. + /// + DedicatedMemorySlowStorage + } +} diff --git a/src/Ryujinx.Graphics.GAL/TextureCreateInfo.cs b/src/Ryujinx.Graphics.GAL/TextureCreateInfo.cs index 44090291d..79c84db01 100644 --- a/src/Ryujinx.Graphics.GAL/TextureCreateInfo.cs +++ b/src/Ryujinx.Graphics.GAL/TextureCreateInfo.cs @@ -1,6 +1,5 @@ using Ryujinx.Common; using System; -using System.Numerics; namespace Ryujinx.Graphics.GAL { @@ -113,25 +112,6 @@ namespace Ryujinx.Graphics.GAL return 1; } - public int GetLevelsClamped() - { - int maxSize = Width; - - if (Target != Target.Texture1D && - Target != Target.Texture1DArray) - { - maxSize = Math.Max(maxSize, Height); - } - - if (Target == Target.Texture3D) - { - maxSize = Math.Max(maxSize, Depth); - } - - int maxLevels = BitOperations.Log2((uint)maxSize) + 1; - return Math.Min(Levels, maxLevels); - } - private static int GetLevelSize(int size, int level) { return Math.Max(1, size >> level); diff --git a/src/Ryujinx.Graphics.GAL/UpscaleType.cs b/src/Ryujinx.Graphics.GAL/UpscaleType.cs index ca24199c4..e2482faef 100644 --- a/src/Ryujinx.Graphics.GAL/UpscaleType.cs +++ b/src/Ryujinx.Graphics.GAL/UpscaleType.cs @@ -5,5 +5,6 @@ namespace Ryujinx.Graphics.GAL Bilinear, Nearest, Fsr, + Area, } } diff --git a/src/Ryujinx.Graphics.Gpu/Constants.cs b/src/Ryujinx.Graphics.Gpu/Constants.cs index c553d988e..23b9be5ca 100644 --- a/src/Ryujinx.Graphics.Gpu/Constants.cs +++ b/src/Ryujinx.Graphics.Gpu/Constants.cs @@ -89,5 +89,10 @@ namespace Ryujinx.Graphics.Gpu /// Maximum size that an storage buffer is assumed to have when the correct size is unknown. /// public const ulong MaxUnknownStorageSize = 0x100000; + + /// + /// Size of a bindless texture handle as exposed by guest graphics APIs. + /// + public const int TextureHandleSizeInBytes = sizeof(ulong); } } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs index ccdbe4748..cd8144724 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs @@ -126,6 +126,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute ulong samplerPoolGpuVa = ((ulong)_state.State.SetTexSamplerPoolAOffsetUpper << 32) | _state.State.SetTexSamplerPoolB; ulong texturePoolGpuVa = ((ulong)_state.State.SetTexHeaderPoolAOffsetUpper << 32) | _state.State.SetTexHeaderPoolB; + int samplerPoolMaximumId = _state.State.SetTexSamplerPoolCMaximumIndex; + GpuChannelPoolState poolState = new( texturePoolGpuVa, _state.State.SetTexHeaderPoolCMaximumIndex, @@ -139,7 +141,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute sharedMemorySize, _channel.BufferManager.HasUnalignedStorageBuffers); - CachedShaderProgram cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa); + CachedShaderProgram cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, samplerPoolMaximumId, poolState, computeState, shaderGpuVa); _context.Renderer.Pipeline.SetProgram(cs.HostProgram); @@ -184,7 +186,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute sharedMemorySize, _channel.BufferManager.HasUnalignedStorageBuffers); - cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa); + cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, samplerPoolMaximumId, poolState, computeState, shaderGpuVa); _context.Renderer.Pipeline.SetProgram(cs.HostProgram); } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs index 0fc10ff49..63e150150 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Common.Memory; using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Gpu.Engine.Threed; using Ryujinx.Graphics.Gpu.Memory; @@ -276,16 +277,68 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma dstBaseOffset += dstStride * (yCount - 1); } - ReadOnlySpan srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true); + // If remapping is disabled, we always copy the components directly, in order. + // If it's enabled, but the mapping is just XYZW, we also copy them in order. + bool isIdentityRemap = !remap || + (_state.State.SetRemapComponentsDstX == SetRemapComponentsDst.SrcX && + (dstComponents < 2 || _state.State.SetRemapComponentsDstY == SetRemapComponentsDst.SrcY) && + (dstComponents < 3 || _state.State.SetRemapComponentsDstZ == SetRemapComponentsDst.SrcZ) && + (dstComponents < 4 || _state.State.SetRemapComponentsDstW == SetRemapComponentsDst.SrcW)); bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount); bool completeDest = IsTextureCopyComplete(dst, dstLinear, dstBpp, dstStride, xCount, yCount); + // Check if the source texture exists on the GPU, if it does, do a GPU side copy. + // Otherwise, we would need to flush the source texture which is costly. + // We don't expect the source to be linear in such cases, as linear source usually indicates buffer or CPU written data. + + if (completeSource && completeDest && !srcLinear && isIdentityRemap) + { + var source = memoryManager.Physical.TextureCache.FindTexture( + memoryManager, + srcGpuVa, + srcBpp, + srcStride, + src.Height, + xCount, + yCount, + srcLinear, + src.MemoryLayout.UnpackGobBlocksInY(), + src.MemoryLayout.UnpackGobBlocksInZ()); + + if (source != null && source.Height == yCount) + { + source.SynchronizeMemory(); + + var target = memoryManager.Physical.TextureCache.FindOrCreateTexture( + memoryManager, + source.Info.FormatInfo, + dstGpuVa, + xCount, + yCount, + dstStride, + dstLinear, + dst.MemoryLayout.UnpackGobBlocksInY(), + dst.MemoryLayout.UnpackGobBlocksInZ()); + + if (source.ScaleFactor != target.ScaleFactor) + { + target.PropagateScale(source); + } + + source.HostTexture.CopyTo(target.HostTexture, 0, 0); + target.SignalModified(); + return; + } + } + + ReadOnlySpan srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true); + // Try to set the texture data directly, // but only if we are doing a complete copy, // and not for block linear to linear copies, since those are typically accessed from the CPU. - if (completeSource && completeDest && !(dstLinear && !srcLinear)) + if (completeSource && completeDest && !(dstLinear && !srcLinear) && isIdentityRemap) { var target = memoryManager.Physical.TextureCache.FindTexture( memoryManager, @@ -301,7 +354,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma if (target != null) { - IMemoryOwner data; + MemoryOwner data; if (srcLinear) { data = LayoutConverter.ConvertLinearStridedToLinear( @@ -354,14 +407,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma TextureParams srcParams = new(srcRegionX, srcRegionY, srcBaseOffset, srcBpp, srcLinear, srcCalculator); TextureParams dstParams = new(dstRegionX, dstRegionY, dstBaseOffset, dstBpp, dstLinear, dstCalculator); - // If remapping is enabled, we always copy the components directly, in order. - // If it's enabled, but the mapping is just XYZW, we also copy them in order. - bool isIdentityRemap = !remap || - (_state.State.SetRemapComponentsDstX == SetRemapComponentsDst.SrcX && - (dstComponents < 2 || _state.State.SetRemapComponentsDstY == SetRemapComponentsDst.SrcY) && - (dstComponents < 3 || _state.State.SetRemapComponentsDstZ == SetRemapComponentsDst.SrcZ) && - (dstComponents < 4 || _state.State.SetRemapComponentsDstW == SetRemapComponentsDst.SrcW)); - if (isIdentityRemap) { // The order of the components doesn't change, so we can just copy directly diff --git a/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs index 5bd8ec728..cedd824a1 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs @@ -157,6 +157,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo } else if (operation == SyncpointbOperation.Incr) { + // "Unbind" render targets since a syncpoint increment might indicate future CPU access for the textures. + _parent.TextureManager.RefreshModifiedTextures(); + _context.CreateHostSyncIfNeeded(HostSyncFlags.StrictSyncpoint); _context.Synchronization.IncrementSyncpoint(syncpointId); } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs b/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs index b57109c7d..984a9cff8 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs @@ -4,6 +4,7 @@ using Ryujinx.Graphics.Gpu.Engine.Dma; using Ryujinx.Graphics.Gpu.Engine.InlineToMemory; using Ryujinx.Graphics.Gpu.Engine.Threed; using Ryujinx.Graphics.Gpu.Engine.Twod; +using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Gpu.Memory; using System; using System.Runtime.CompilerServices; @@ -28,6 +29,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo /// public MemoryManager MemoryManager => _channel.MemoryManager; + /// + /// Channel texture manager. + /// + public TextureManager TextureManager => _channel.TextureManager; + /// /// 3D Engine. /// diff --git a/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs index 576ef3266..78099f74a 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs @@ -198,11 +198,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory if (target != null) { - var memory = ByteMemoryPool.Rent(data.Length); - data.CopyTo(memory.Memory.Span); - target.SynchronizeMemory(); - target.SetData(memory, 0, 0, new GAL.Rectangle(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount)); + var dataCopy = MemoryOwner.RentCopy(data); + target.SetData(dataCopy, 0, 0, new GAL.Rectangle(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount)); target.SignalModified(); return; diff --git a/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs b/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs index 7f3772f44..475d1ee4e 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs @@ -5,6 +5,7 @@ using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.Engine.GPFifo; using Ryujinx.Graphics.Gpu.Engine.Threed; using Ryujinx.Graphics.Gpu.Engine.Types; +using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Memory.Range; using System; using System.Collections.Generic; @@ -495,8 +496,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME ulong indirectBufferSize = (ulong)maxDrawCount * (ulong)stride; - MultiRange indirectBufferRange = bufferCache.TranslateAndCreateMultiBuffers(_processor.MemoryManager, indirectBufferGpuVa, indirectBufferSize); - MultiRange parameterBufferRange = bufferCache.TranslateAndCreateMultiBuffers(_processor.MemoryManager, parameterBufferGpuVa, 4); + MultiRange indirectBufferRange = bufferCache.TranslateAndCreateMultiBuffers(_processor.MemoryManager, indirectBufferGpuVa, indirectBufferSize, BufferStage.Indirect); + MultiRange parameterBufferRange = bufferCache.TranslateAndCreateMultiBuffers(_processor.MemoryManager, parameterBufferGpuVa, 4, BufferStage.Indirect); _processor.ThreedClass.DrawIndirect( topology, diff --git a/src/Ryujinx.Graphics.Gpu/Engine/ShaderTexture.cs b/src/Ryujinx.Graphics.Gpu/Engine/ShaderTexture.cs index 492c6ee60..bdb34180e 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/ShaderTexture.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/ShaderTexture.cs @@ -1,5 +1,6 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Shader; namespace Ryujinx.Graphics.Gpu.Engine @@ -16,7 +17,7 @@ namespace Ryujinx.Graphics.Gpu.Engine /// Texture target value public static Target GetTarget(SamplerType type) { - type &= ~(SamplerType.Indexed | SamplerType.Shadow); + type &= ~SamplerType.Shadow; switch (type) { @@ -61,51 +62,51 @@ namespace Ryujinx.Graphics.Gpu.Engine /// /// Shader image format /// Texture format - public static Format GetFormat(TextureFormat format) + public static FormatInfo GetFormatInfo(TextureFormat format) { return format switch { #pragma warning disable IDE0055 // Disable formatting - TextureFormat.R8Unorm => Format.R8Unorm, - TextureFormat.R8Snorm => Format.R8Snorm, - TextureFormat.R8Uint => Format.R8Uint, - TextureFormat.R8Sint => Format.R8Sint, - TextureFormat.R16Float => Format.R16Float, - TextureFormat.R16Unorm => Format.R16Unorm, - TextureFormat.R16Snorm => Format.R16Snorm, - TextureFormat.R16Uint => Format.R16Uint, - TextureFormat.R16Sint => Format.R16Sint, - TextureFormat.R32Float => Format.R32Float, - TextureFormat.R32Uint => Format.R32Uint, - TextureFormat.R32Sint => Format.R32Sint, - TextureFormat.R8G8Unorm => Format.R8G8Unorm, - TextureFormat.R8G8Snorm => Format.R8G8Snorm, - TextureFormat.R8G8Uint => Format.R8G8Uint, - TextureFormat.R8G8Sint => Format.R8G8Sint, - TextureFormat.R16G16Float => Format.R16G16Float, - TextureFormat.R16G16Unorm => Format.R16G16Unorm, - TextureFormat.R16G16Snorm => Format.R16G16Snorm, - TextureFormat.R16G16Uint => Format.R16G16Uint, - TextureFormat.R16G16Sint => Format.R16G16Sint, - TextureFormat.R32G32Float => Format.R32G32Float, - TextureFormat.R32G32Uint => Format.R32G32Uint, - TextureFormat.R32G32Sint => Format.R32G32Sint, - TextureFormat.R8G8B8A8Unorm => Format.R8G8B8A8Unorm, - TextureFormat.R8G8B8A8Snorm => Format.R8G8B8A8Snorm, - TextureFormat.R8G8B8A8Uint => Format.R8G8B8A8Uint, - TextureFormat.R8G8B8A8Sint => Format.R8G8B8A8Sint, - TextureFormat.R16G16B16A16Float => Format.R16G16B16A16Float, - TextureFormat.R16G16B16A16Unorm => Format.R16G16B16A16Unorm, - TextureFormat.R16G16B16A16Snorm => Format.R16G16B16A16Snorm, - TextureFormat.R16G16B16A16Uint => Format.R16G16B16A16Uint, - TextureFormat.R16G16B16A16Sint => Format.R16G16B16A16Sint, - TextureFormat.R32G32B32A32Float => Format.R32G32B32A32Float, - TextureFormat.R32G32B32A32Uint => Format.R32G32B32A32Uint, - TextureFormat.R32G32B32A32Sint => Format.R32G32B32A32Sint, - TextureFormat.R10G10B10A2Unorm => Format.R10G10B10A2Unorm, - TextureFormat.R10G10B10A2Uint => Format.R10G10B10A2Uint, - TextureFormat.R11G11B10Float => Format.R11G11B10Float, - _ => 0, + TextureFormat.R8Unorm => new(Format.R8Unorm, 1, 1, 1, 1), + TextureFormat.R8Snorm => new(Format.R8Snorm, 1, 1, 1, 1), + TextureFormat.R8Uint => new(Format.R8Uint, 1, 1, 1, 1), + TextureFormat.R8Sint => new(Format.R8Sint, 1, 1, 1, 1), + TextureFormat.R16Float => new(Format.R16Float, 1, 1, 2, 1), + TextureFormat.R16Unorm => new(Format.R16Unorm, 1, 1, 2, 1), + TextureFormat.R16Snorm => new(Format.R16Snorm, 1, 1, 2, 1), + TextureFormat.R16Uint => new(Format.R16Uint, 1, 1, 2, 1), + TextureFormat.R16Sint => new(Format.R16Sint, 1, 1, 2, 1), + TextureFormat.R32Float => new(Format.R32Float, 1, 1, 4, 1), + TextureFormat.R32Uint => new(Format.R32Uint, 1, 1, 4, 1), + TextureFormat.R32Sint => new(Format.R32Sint, 1, 1, 4, 1), + TextureFormat.R8G8Unorm => new(Format.R8G8Unorm, 1, 1, 2, 2), + TextureFormat.R8G8Snorm => new(Format.R8G8Snorm, 1, 1, 2, 2), + TextureFormat.R8G8Uint => new(Format.R8G8Uint, 1, 1, 2, 2), + TextureFormat.R8G8Sint => new(Format.R8G8Sint, 1, 1, 2, 2), + TextureFormat.R16G16Float => new(Format.R16G16Float, 1, 1, 4, 2), + TextureFormat.R16G16Unorm => new(Format.R16G16Unorm, 1, 1, 4, 2), + TextureFormat.R16G16Snorm => new(Format.R16G16Snorm, 1, 1, 4, 2), + TextureFormat.R16G16Uint => new(Format.R16G16Uint, 1, 1, 4, 2), + TextureFormat.R16G16Sint => new(Format.R16G16Sint, 1, 1, 4, 2), + TextureFormat.R32G32Float => new(Format.R32G32Float, 1, 1, 8, 2), + TextureFormat.R32G32Uint => new(Format.R32G32Uint, 1, 1, 8, 2), + TextureFormat.R32G32Sint => new(Format.R32G32Sint, 1, 1, 8, 2), + TextureFormat.R8G8B8A8Unorm => new(Format.R8G8B8A8Unorm, 1, 1, 4, 4), + TextureFormat.R8G8B8A8Snorm => new(Format.R8G8B8A8Snorm, 1, 1, 4, 4), + TextureFormat.R8G8B8A8Uint => new(Format.R8G8B8A8Uint, 1, 1, 4, 4), + TextureFormat.R8G8B8A8Sint => new(Format.R8G8B8A8Sint, 1, 1, 4, 4), + TextureFormat.R16G16B16A16Float => new(Format.R16G16B16A16Float, 1, 1, 8, 4), + TextureFormat.R16G16B16A16Unorm => new(Format.R16G16B16A16Unorm, 1, 1, 8, 4), + TextureFormat.R16G16B16A16Snorm => new(Format.R16G16B16A16Snorm, 1, 1, 8, 4), + TextureFormat.R16G16B16A16Uint => new(Format.R16G16B16A16Uint, 1, 1, 8, 4), + TextureFormat.R16G16B16A16Sint => new(Format.R16G16B16A16Sint, 1, 1, 8, 4), + TextureFormat.R32G32B32A32Float => new(Format.R32G32B32A32Float, 1, 1, 16, 4), + TextureFormat.R32G32B32A32Uint => new(Format.R32G32B32A32Uint, 1, 1, 16, 4), + TextureFormat.R32G32B32A32Sint => new(Format.R32G32B32A32Sint, 1, 1, 16, 4), + TextureFormat.R10G10B10A2Unorm => new(Format.R10G10B10A2Unorm, 1, 1, 4, 4), + TextureFormat.R10G10B10A2Uint => new(Format.R10G10B10A2Uint, 1, 1, 4, 4), + TextureFormat.R11G11B10Float => new(Format.R11G11B10Float, 1, 1, 4, 3), + _ => FormatInfo.Invalid, #pragma warning restore IDE0055 }; } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs index f9cb40b0d..6de50fb2e 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs @@ -438,7 +438,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw ReadOnlySpan dataBytes = MemoryMarshal.Cast(data); - BufferHandle buffer = _context.Renderer.CreateBuffer(dataBytes.Length); + BufferHandle buffer = _context.Renderer.CreateBuffer(dataBytes.Length, BufferAccess.DeviceMemory); _context.Renderer.SetBufferData(buffer, 0, dataBytes); return new IndexBuffer(buffer, count, dataBytes.Length); @@ -529,7 +529,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw { if (_dummyBuffer == BufferHandle.Null) { - _dummyBuffer = _context.Renderer.CreateBuffer(DummyBufferSize); + _dummyBuffer = _context.Renderer.CreateBuffer(DummyBufferSize, BufferAccess.DeviceMemory); _context.Renderer.Pipeline.ClearBuffer(_dummyBuffer, 0, DummyBufferSize, 0); } @@ -550,7 +550,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw _context.Renderer.DeleteBuffer(_sequentialIndexBuffer); } - _sequentialIndexBuffer = _context.Renderer.CreateBuffer(count * sizeof(uint)); + _sequentialIndexBuffer = _context.Renderer.CreateBuffer(count * sizeof(uint), BufferAccess.DeviceMemory); _sequentialIndexBufferCount = count; Span data = new int[count]; @@ -583,7 +583,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw _context.Renderer.DeleteBuffer(buffer.Handle); } - buffer.Handle = _context.Renderer.CreateBuffer(newSize); + buffer.Handle = _context.Renderer.CreateBuffer(newSize, BufferAccess.DeviceMemory); buffer.Size = newSize; } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs index 6324e6a15..73682866b 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs @@ -3,6 +3,7 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.Engine.Types; using Ryujinx.Graphics.Gpu.Image; +using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Shader; using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader.Translation; @@ -370,7 +371,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw { var memoryManager = _channel.MemoryManager; - BufferRange range = memoryManager.Physical.BufferCache.GetBufferRange(memoryManager.GetPhysicalRegions(address, size)); + BufferRange range = memoryManager.Physical.BufferCache.GetBufferRange(memoryManager.GetPhysicalRegions(address, size), BufferStage.VertexBuffer); ITexture bufferTexture = _vacContext.EnsureBufferTexture(index + 2, format); bufferTexture.SetStorage(range); @@ -412,7 +413,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw var memoryManager = _channel.MemoryManager; ulong misalign = address & ((ulong)_context.Capabilities.TextureBufferOffsetAlignment - 1); - BufferRange range = memoryManager.Physical.BufferCache.GetBufferRange(memoryManager.GetPhysicalRegions(address + indexOffset - misalign, size + misalign)); + BufferRange range = memoryManager.Physical.BufferCache.GetBufferRange( + memoryManager.GetPhysicalRegions(address + indexOffset - misalign, size + misalign), + BufferStage.IndexBuffer); misalignedOffset = (int)misalign >> shift; SetIndexBufferTexture(reservations, range, format); diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs index 8c72663f1..56ef64c6e 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs @@ -103,6 +103,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// Method call argument public void DrawEnd(ThreedClass engine, int argument) { + _drawState.DrawUsesEngineState = true; + DrawEnd( engine, _state.State.IndexBufferState.First, @@ -205,10 +207,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed } else { -#pragma warning disable IDE0059 // Remove unnecessary value assignment - var drawState = _state.State.VertexBufferDrawState; -#pragma warning restore IDE0059 - DrawImpl(engine, drawVertexCount, 1, 0, drawFirstVertex, firstInstance, indexed: false); } @@ -379,6 +377,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed bool oldDrawIndexed = _drawState.DrawIndexed; _drawState.DrawIndexed = true; + _drawState.DrawUsesEngineState = false; engine.ForceStateDirty(IndexBufferCountMethodOffset * 4); DrawEnd(engine, firstIndex, indexCount, 0, 0); @@ -424,6 +423,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed bool oldDrawIndexed = _drawState.DrawIndexed; _drawState.DrawIndexed = false; + _drawState.DrawUsesEngineState = false; engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4); DrawEnd(engine, 0, 0, firstVertex, vertexCount); @@ -544,6 +544,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _state.State.FirstInstance = (uint)firstInstance; _drawState.DrawIndexed = indexed; + _drawState.DrawUsesEngineState = true; _currentSpecState.SetHasConstantBufferDrawParameters(true); engine.UpdateState(); @@ -676,14 +677,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _drawState.DrawIndexed = indexed; _drawState.DrawIndirect = true; + _drawState.DrawUsesEngineState = true; _currentSpecState.SetHasConstantBufferDrawParameters(true); engine.UpdateState(); if (hasCount) { - var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferRange); - var parameterBuffer = memory.BufferCache.GetBufferRange(parameterBufferRange); + var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferRange, BufferStage.Indirect); + var parameterBuffer = memory.BufferCache.GetBufferRange(parameterBufferRange, BufferStage.Indirect); if (indexed) { @@ -696,7 +698,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed } else { - var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferRange); + var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferRange, BufferStage.Indirect); if (indexed) { diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawState.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawState.cs index 8113c1827..03b5e3f3b 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawState.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawState.cs @@ -38,6 +38,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// public bool DrawIndirect; + /// + /// Indicates that the draw is using the draw parameters on the 3D engine state, rather than inline parameters submitted with the draw command. + /// + public bool DrawUsesEngineState; + /// /// Indicates if any of the currently used vertex shaders reads the instance ID. /// @@ -48,11 +53,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// public bool IsAnyVbInstanced; - /// - /// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0. - /// - public bool HasConstantBufferDrawParameters; - /// /// Primitive topology for the next draw. /// diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs index c8c44d8e5..effcb7bbb 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs @@ -79,10 +79,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed { var field = fields[fieldIndex]; - var cuurentFieldOffset = (int)Marshal.OffsetOf(field.Name); + var currentFieldOffset = (int)Marshal.OffsetOf(field.Name); var nextFieldOffset = fieldIndex + 1 == fields.Length ? Unsafe.SizeOf() : (int)Marshal.OffsetOf(fields[fieldIndex + 1].Name); - int sizeOfField = nextFieldOffset - cuurentFieldOffset; + int sizeOfField = nextFieldOffset - currentFieldOffset; if (fieldToDelegate.TryGetValue(field.Name, out int entryIndex)) { diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index 24a4d58c7..1dc77b52d 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -26,6 +26,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed public const int PrimitiveRestartStateIndex = 12; public const int RenderTargetStateIndex = 27; + // Vertex buffers larger than this size will be clamped to the mapped size. + private const ulong VertexBufferSizeToMappedSizeThreshold = 256 * 1024 * 1024; // 256 MB + private readonly GpuContext _context; private readonly GpuChannel _channel; private readonly DeviceStateWithShadow _state; @@ -47,7 +50,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed private uint _vbEnableMask; private bool _prevDrawIndexed; - private readonly bool _prevDrawIndirect; + private bool _prevDrawIndirect; + private bool _prevDrawUsesEngineState; private IndexType _prevIndexType; private uint _prevFirstVertex; private bool _prevTfEnable; @@ -236,7 +240,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed // method when doing indexed draws, so we need to make sure // to update the vertex buffers if we are doing a regular // draw after a indexed one and vice-versa. - if (_drawState.DrawIndexed != _prevDrawIndexed) + // Some draws also do not update the engine state, so it is possible for it + // to not be dirty even if the vertex counts or other state changed. We need to force it to be dirty in this case. + if (_drawState.DrawIndexed != _prevDrawIndexed || _drawState.DrawUsesEngineState != _prevDrawUsesEngineState) { _updateTracker.ForceDirty(VertexBufferStateIndex); @@ -251,6 +257,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed } _prevDrawIndexed = _drawState.DrawIndexed; + _prevDrawUsesEngineState = _drawState.DrawUsesEngineState; } // Some draw parameters are used to restrict the vertex buffer size, @@ -260,6 +267,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed if (_drawState.DrawIndirect != _prevDrawIndirect) { _updateTracker.ForceDirty(VertexBufferStateIndex); + + _prevDrawIndirect = _drawState.DrawIndirect; } // In some cases, the index type is also used to guess the @@ -334,11 +343,22 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed bool unalignedChanged = _currentSpecState.SetHasUnalignedStorageBuffer(_channel.BufferManager.HasUnalignedStorageBuffers); - if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || unalignedChanged) + bool scaleMismatch; + do { - // Shader must be reloaded. _vtgWritesRtLayer should not change. - UpdateShaderState(); + if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState, out scaleMismatch) || unalignedChanged) + { + // Shader must be reloaded. _vtgWritesRtLayer should not change. + UpdateShaderState(); + } + + if (scaleMismatch) + { + // Binding textures changed scale of the bound render targets, correct the render target scale and rebind. + UpdateRenderTargetState(); + } } + while (scaleMismatch); _channel.BufferManager.CommitGraphicsBindings(_drawState.DrawIndexed); } @@ -1138,6 +1158,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed size = Math.Min(size, maxVertexBufferSize); } + else if (size > VertexBufferSizeToMappedSizeThreshold) + { + // Make sure we have a sane vertex buffer size, since in some cases applications + // might set the "end address" of the vertex buffer to the end of the GPU address space, + // which would result in a several GBs large buffer. + + size = _channel.MemoryManager.GetMappedSize(address, size); + } } else { @@ -1401,7 +1429,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed addressesSpan[index] = baseAddress + shader.Offset; } - CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), addresses); + int samplerPoolMaximumId = _state.State.SamplerIndex == SamplerIndex.ViaHeaderIndex + ? _state.State.TexturePoolState.MaximumId + : _state.State.SamplerPoolState.MaximumId; + + CachedShaderProgram gs = shaderCache.GetGraphicsShader( + ref _state.State, + ref _pipeline, + _channel, + samplerPoolMaximumId, + ref _currentSpecState.GetPoolState(), + ref _currentSpecState.GetGraphicsState(), + addresses); // Consume the modified flag for spec state so that it isn't checked again. _currentSpecState.SetShader(gs); diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs index dd55e7d1d..35051c6e0 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs @@ -415,7 +415,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed #pragma warning disable CS0649 // Field is never assigned to public int Width; public int Height; - public int Depth; + public ushort Depth; + public ushort Flags; + + public readonly bool UnpackIsLayered() + { + return (Flags & 1) == 0; + } #pragma warning restore CS0649 } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs b/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs index c798384f0..273438a67 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs @@ -37,6 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Types R16G16Sint = 0xdc, R16G16Uint = 0xdd, R16G16Float = 0xde, + B10G10R10A2Unorm = 0xdf, R11G11B10Float = 0xe0, R32Sint = 0xe3, R32Uint = 0xe4, @@ -104,6 +105,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Types ColorFormat.R16G16Sint => new FormatInfo(Format.R16G16Sint, 1, 1, 4, 2), ColorFormat.R16G16Uint => new FormatInfo(Format.R16G16Uint, 1, 1, 4, 2), ColorFormat.R16G16Float => new FormatInfo(Format.R16G16Float, 1, 1, 4, 2), + ColorFormat.B10G10R10A2Unorm => new FormatInfo(Format.B10G10R10A2Unorm, 1, 1, 4, 4), ColorFormat.R11G11B10Float => new FormatInfo(Format.R11G11B10Float, 1, 1, 4, 3), ColorFormat.R32Sint => new FormatInfo(Format.R32Sint, 1, 1, 4, 1), ColorFormat.R32Uint => new FormatInfo(Format.R32Uint, 1, 1, 4, 1), diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Types/ZetaFormat.cs b/src/Ryujinx.Graphics.Gpu/Engine/Types/ZetaFormat.cs index e2a044e72..88fbe88f9 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Types/ZetaFormat.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Types/ZetaFormat.cs @@ -8,13 +8,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Types /// enum ZetaFormat { - D32Float = 0xa, - D16Unorm = 0x13, - D24UnormS8Uint = 0x14, - D24Unorm = 0x15, - S8UintD24Unorm = 0x16, + Zf32 = 0xa, + Z16 = 0x13, + Z24S8 = 0x14, + X8Z24 = 0x15, + S8Z24 = 0x16, S8Uint = 0x17, - D32FloatS8Uint = 0x19, + Zf32X24S8 = 0x19, } static class ZetaFormatConverter @@ -29,14 +29,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Types return format switch { #pragma warning disable IDE0055 // Disable formatting - ZetaFormat.D32Float => new FormatInfo(Format.D32Float, 1, 1, 4, 1), - ZetaFormat.D16Unorm => new FormatInfo(Format.D16Unorm, 1, 1, 2, 1), - ZetaFormat.D24UnormS8Uint => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 2), - ZetaFormat.D24Unorm => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 1), - ZetaFormat.S8UintD24Unorm => new FormatInfo(Format.S8UintD24Unorm, 1, 1, 4, 2), - ZetaFormat.S8Uint => new FormatInfo(Format.S8Uint, 1, 1, 1, 1), - ZetaFormat.D32FloatS8Uint => new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8, 2), - _ => FormatInfo.Default, + ZetaFormat.Zf32 => new FormatInfo(Format.D32Float, 1, 1, 4, 1), + ZetaFormat.Z16 => new FormatInfo(Format.D16Unorm, 1, 1, 2, 1), + ZetaFormat.Z24S8 => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 2), + ZetaFormat.X8Z24 => new FormatInfo(Format.X8UintD24Unorm, 1, 1, 4, 1), + ZetaFormat.S8Z24 => new FormatInfo(Format.S8UintD24Unorm, 1, 1, 4, 2), + ZetaFormat.S8Uint => new FormatInfo(Format.S8Uint, 1, 1, 1, 1), + ZetaFormat.Zf32X24S8 => new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8, 2), + _ => FormatInfo.Default, #pragma warning restore IDE0055 }; } diff --git a/src/Ryujinx.Graphics.Gpu/GpuContext.cs b/src/Ryujinx.Graphics.Gpu/GpuContext.cs index a50852b05..048d32fb7 100644 --- a/src/Ryujinx.Graphics.Gpu/GpuContext.cs +++ b/src/Ryujinx.Graphics.Gpu/GpuContext.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.Engine.GPFifo; using Ryujinx.Graphics.Gpu.Memory; @@ -106,6 +107,8 @@ namespace Ryujinx.Graphics.Gpu private long _modifiedSequence; private readonly ulong _firstTimestamp; + private readonly ManualResetEvent _gpuReadyEvent; + /// /// Creates a new instance of the GPU emulation context. /// @@ -121,6 +124,7 @@ namespace Ryujinx.Graphics.Gpu Window = new Window(this); HostInitalized = new ManualResetEvent(false); + _gpuReadyEvent = new ManualResetEvent(false); SyncActions = new List(); SyncpointActions = new List(); @@ -160,6 +164,22 @@ namespace Ryujinx.Graphics.Gpu return new MemoryManager(physicalMemory); } + /// + /// Creates a new device memory manager. + /// + /// ID of the process that owns the memory manager + /// The memory manager + /// Thrown when is invalid + public DeviceMemoryManager CreateDeviceMemoryManager(ulong pid) + { + if (!PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory)) + { + throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid)); + } + + return physicalMemory.CreateDeviceMemoryManager(); + } + /// /// Registers virtual memory used by a process for GPU memory access, caching and read/write tracking. /// @@ -216,7 +236,7 @@ namespace Ryujinx.Graphics.Gpu /// Gets a sequence number for resource modification ordering. This increments on each call. /// /// A sequence number for resource modification ordering - public long GetModifiedSequence() + internal long GetModifiedSequence() { return _modifiedSequence++; } @@ -225,7 +245,7 @@ namespace Ryujinx.Graphics.Gpu /// Gets the value of the GPU timer. /// /// The current GPU timestamp - public ulong GetTimestamp() + internal ulong GetTimestamp() { // Guest timestamp will start at 0, instead of host value. ulong ticks = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds) - _firstTimestamp; @@ -262,6 +282,16 @@ namespace Ryujinx.Graphics.Gpu { physicalMemory.ShaderCache.Initialize(cancellationToken); } + + _gpuReadyEvent.Set(); + } + + /// + /// Waits until the GPU is ready to receive commands. + /// + public void WaitUntilGpuReady() + { + _gpuReadyEvent.WaitOne(); } /// @@ -363,10 +393,17 @@ namespace Ryujinx.Graphics.Gpu if (force || _pendingSync || (syncpoint && SyncpointActions.Count > 0)) { - Renderer.CreateSync(SyncNumber, strict); + foreach (var action in SyncActions) + { + action.SyncPreAction(syncpoint); + } - SyncActions.ForEach(action => action.SyncPreAction(syncpoint)); - SyncpointActions.ForEach(action => action.SyncPreAction(syncpoint)); + foreach (var action in SyncpointActions) + { + action.SyncPreAction(syncpoint); + } + + Renderer.CreateSync(SyncNumber, strict); SyncNumber++; @@ -399,6 +436,7 @@ namespace Ryujinx.Graphics.Gpu { GPFifo.Dispose(); HostInitalized.Dispose(); + _gpuReadyEvent.Dispose(); // Has to be disposed before processing deferred actions, as it will produce some. foreach (var physicalMemory in PhysicalMemoryRegistry.Values) diff --git a/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs b/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs index 05782605b..ad6c1fecb 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; @@ -46,7 +47,11 @@ namespace Ryujinx.Graphics.Gpu.Image { private const int MinCountForDeletion = 32; private const int MaxCapacity = 2048; - private const ulong MaxTextureSizeCapacity = 512 * 1024 * 1024; // MB; + private const ulong MinTextureSizeCapacity = 512 * 1024 * 1024; + private const ulong MaxTextureSizeCapacity = 4UL * 1024 * 1024 * 1024; + private const ulong DefaultTextureSizeCapacity = 1UL * 1024 * 1024 * 1024; + private const float MemoryScaleFactor = 0.50f; + private ulong _maxCacheMemoryUsage = 0; private readonly LinkedList _textures; private ulong _totalSize; @@ -56,6 +61,25 @@ namespace Ryujinx.Graphics.Gpu.Image private readonly Dictionary _shortCacheLookup; + /// + /// Initializes the cache, setting the maximum texture capacity for the specified GPU context. + /// + /// + /// If the backend GPU has 0 memory capacity, the cache size defaults to `DefaultTextureSizeCapacity`. + /// + /// The GPU context that the cache belongs to + public void Initialize(GpuContext context) + { + var cacheMemory = (ulong)(context.Capabilities.MaximumGpuMemory * MemoryScaleFactor); + + _maxCacheMemoryUsage = Math.Clamp(cacheMemory, MinTextureSizeCapacity, MaxTextureSizeCapacity); + + if (context.Capabilities.MaximumGpuMemory == 0) + { + _maxCacheMemoryUsage = DefaultTextureSizeCapacity; + } + } + /// /// Creates a new instance of the automatic deletion cache. /// @@ -85,7 +109,7 @@ namespace Ryujinx.Graphics.Gpu.Image texture.CacheNode = _textures.AddLast(texture); if (_textures.Count > MaxCapacity || - (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion)) + (_totalSize > _maxCacheMemoryUsage && _textures.Count >= MinCountForDeletion)) { RemoveLeastUsedTexture(); } @@ -107,11 +131,10 @@ namespace Ryujinx.Graphics.Gpu.Image if (texture.CacheNode != _textures.Last) { _textures.Remove(texture.CacheNode); - - texture.CacheNode = _textures.AddLast(texture); + _textures.AddLast(texture.CacheNode); } - if (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion) + if (_totalSize > _maxCacheMemoryUsage && _textures.Count >= MinCountForDeletion) { RemoveLeastUsedTexture(); } diff --git a/src/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs b/src/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs index 8a9f37bb0..b95c684e4 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs @@ -7,6 +7,11 @@ namespace Ryujinx.Graphics.Gpu.Image /// readonly struct FormatInfo { + /// + /// An invalid texture format. + /// + public static FormatInfo Invalid { get; } = new(0, 0, 0, 0, 0); + /// /// A default, generic RGBA8 texture format. /// @@ -23,7 +28,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Must be 1 for non-compressed formats. /// - public int BlockWidth { get; } + public byte BlockWidth { get; } /// /// The block height for compressed formats. @@ -31,17 +36,17 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Must be 1 for non-compressed formats. /// - public int BlockHeight { get; } + public byte BlockHeight { get; } /// /// The number of bytes occupied by a single pixel in memory of the texture data. /// - public int BytesPerPixel { get; } + public byte BytesPerPixel { get; } /// /// The maximum number of components this format has defined (in RGBA order). /// - public int Components { get; } + public byte Components { get; } /// /// Whenever or not the texture format is a compressed format. Determined from block size. @@ -57,10 +62,10 @@ namespace Ryujinx.Graphics.Gpu.Image /// The number of bytes occupied by a single pixel in memory of the texture data public FormatInfo( Format format, - int blockWidth, - int blockHeight, - int bytesPerPixel, - int components) + byte blockWidth, + byte blockHeight, + byte bytesPerPixel, + byte components) { Format = format; BlockWidth = blockWidth; diff --git a/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs b/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs index 0af0725a2..da9e5c3a9 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs @@ -185,6 +185,7 @@ namespace Ryujinx.Graphics.Gpu.Image G24R8RUintGUnormBUnormAUnorm = G24R8 | RUint | GUnorm | BUnorm | AUnorm, // 0x24a0e Z24S8RUintGUnormBUnormAUnorm = Z24S8 | RUint | GUnorm | BUnorm | AUnorm, // 0x24a29 Z24S8RUintGUnormBUintAUint = Z24S8 | RUint | GUnorm | BUint | AUint, // 0x48a29 + X8Z24RUnormGUintBUintAUint = X8Z24 | RUnorm | GUint | BUint | AUint, // 0x4912a S8Z24RUnormGUintBUintAUint = S8Z24 | RUnorm | GUint | BUint | AUint, // 0x4912b R32B24G8RFloatGUintBUnormAUnorm = R32B24G8 | RFloat | GUint | BUnorm | AUnorm, // 0x25385 Zf32X24S8RFloatGUintBUnormAUnorm = Zf32X24S8 | RFloat | GUint | BUnorm | AUnorm, // 0x253b0 @@ -410,6 +411,7 @@ namespace Ryujinx.Graphics.Gpu.Image { TextureFormat.G24R8RUintGUnormBUnormAUnorm, new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 2) }, { TextureFormat.Z24S8RUintGUnormBUnormAUnorm, new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 2) }, { TextureFormat.Z24S8RUintGUnormBUintAUint, new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 2) }, + { TextureFormat.X8Z24RUnormGUintBUintAUint, new FormatInfo(Format.X8UintD24Unorm, 1, 1, 4, 2) }, { TextureFormat.S8Z24RUnormGUintBUintAUint, new FormatInfo(Format.S8UintD24Unorm, 1, 1, 4, 2) }, { TextureFormat.R32B24G8RFloatGUintBUnormAUnorm, new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8, 2) }, { TextureFormat.Zf32X24S8RFloatGUintBUnormAUnorm, new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8, 2) }, @@ -672,9 +674,9 @@ namespace Ryujinx.Graphics.Gpu.Image { 1 => new FormatInfo(Format.R8Unorm, 1, 1, 1, 1), 2 => new FormatInfo(Format.R16Unorm, 1, 1, 2, 1), - 4 => new FormatInfo(Format.R32Float, 1, 1, 4, 1), - 8 => new FormatInfo(Format.R32G32Float, 1, 1, 8, 2), - 16 => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16, 4), + 4 => new FormatInfo(Format.R32Uint, 1, 1, 4, 1), + 8 => new FormatInfo(Format.R32G32Uint, 1, 1, 8, 2), + 16 => new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16, 4), _ => format, }; } diff --git a/src/Ryujinx.Graphics.Gpu/Image/Pool.cs b/src/Ryujinx.Graphics.Gpu/Image/Pool.cs index 0c3a219de..e12fedc74 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/Pool.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/Pool.cs @@ -69,7 +69,7 @@ namespace Ryujinx.Graphics.Gpu.Image Address = address; Size = size; - _memoryTracking = physicalMemory.BeginGranularTracking(address, size, ResourceKind.Pool); + _memoryTracking = physicalMemory.BeginGranularTracking(address, size, ResourceKind.Pool, RegionFlags.None); _memoryTracking.RegisterPreciseAction(address, size, PreciseAction); _modifiedDelegate = RegionModified; } @@ -111,6 +111,21 @@ namespace Ryujinx.Graphics.Gpu.Image /// The GPU resource with the given ID public abstract T1 Get(int id); + /// + /// Gets the cached item with the given ID, or null if there is no cached item for the specified ID. + /// + /// ID of the item. This is effectively a zero-based index + /// The cached item with the given ID + public T1 GetCachedItem(int id) + { + if (!IsValidId(id)) + { + return default; + } + + return Items[id]; + } + /// /// Checks if a given ID is valid and inside the range of the pool. /// @@ -197,6 +212,23 @@ namespace Ryujinx.Graphics.Gpu.Image return false; } + /// + /// Checks if the pool was modified by comparing the current with a cached one. + /// + /// Cached modified sequence number + /// True if the pool was modified, false otherwise + public bool WasModified(ref int sequenceNumber) + { + if (sequenceNumber != ModifiedSequenceNumber) + { + sequenceNumber = ModifiedSequenceNumber; + + return true; + } + + return false; + } + protected abstract void InvalidateRangeImpl(ulong address, ulong size); protected abstract void Delete(T1 item); diff --git a/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs b/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs index d9881f897..50872ab63 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs @@ -62,8 +62,9 @@ namespace Ryujinx.Graphics.Gpu.Image /// GPU channel that the texture pool cache belongs to /// Start address of the texture pool /// Maximum ID of the texture pool + /// Cache of texture array bindings /// The found or newly created texture pool - public T FindOrCreate(GpuChannel channel, ulong address, int maximumId) + public T FindOrCreate(GpuChannel channel, ulong address, int maximumId, TextureBindingsArrayCache bindingsArrayCache) { // Remove old entries from the cache, if possible. while (_pools.Count > MaxCapacity && (_currentTimestamp - _pools.First.Value.CacheTimestamp) >= MinDeltaForRemoval) @@ -73,6 +74,7 @@ namespace Ryujinx.Graphics.Gpu.Image _pools.RemoveFirst(); oldestPool.Dispose(); oldestPool.CacheNode = null; + bindingsArrayCache.RemoveAllWithPool(oldestPool); } T pool; @@ -87,8 +89,7 @@ namespace Ryujinx.Graphics.Gpu.Image if (pool.CacheNode != _pools.Last) { _pools.Remove(pool.CacheNode); - - pool.CacheNode = _pools.AddLast(pool); + _pools.AddLast(pool.CacheNode); } pool.CacheTimestamp = _currentTimestamp; diff --git a/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs b/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs index d6a3d975b..b007c1591 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs @@ -13,6 +13,11 @@ namespace Ryujinx.Graphics.Gpu.Image /// public bool IsDisposed { get; private set; } + /// + /// True if the sampler has sRGB conversion enabled, false otherwise. + /// + public bool IsSrgb { get; } + /// /// Host sampler object. /// @@ -30,6 +35,8 @@ namespace Ryujinx.Graphics.Gpu.Image /// The Maxwell sampler descriptor public Sampler(GpuContext context, SamplerDescriptor descriptor) { + IsSrgb = descriptor.UnpackSrgb(); + MinFilter minFilter = descriptor.UnpackMinFilter(); MagFilter magFilter = descriptor.UnpackMagFilter(); diff --git a/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs b/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs index e04c31dfa..836a3260c 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs @@ -113,6 +113,15 @@ namespace Ryujinx.Graphics.Gpu.Image return (CompareOp)(((Word0 >> 10) & 7) + 1); } + /// + /// Unpacks the sampler sRGB format flag. + /// + /// True if the has sampler is sRGB conversion enabled, false otherwise + public readonly bool UnpackSrgb() + { + return (Word0 & (1 << 13)) != 0; + } + /// /// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering. /// diff --git a/src/Ryujinx.Graphics.Gpu/Image/Texture.cs b/src/Ryujinx.Graphics.Gpu/Image/Texture.cs index 195d13084..1e59d4fee 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -391,7 +391,7 @@ namespace Ryujinx.Graphics.Gpu.Image { _views.Remove(texture); - Group.RemoveView(texture); + Group.RemoveView(_views, texture); texture._viewStorage = texture; @@ -574,7 +574,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Discards all data for this texture. - /// This clears all dirty flags, modified flags, and pending copies from other textures. + /// This clears all dirty flags and pending copies from other textures. /// It should be used if the texture data will be fully overwritten by the next use. /// public void DiscardData() @@ -662,7 +662,7 @@ namespace Ryujinx.Graphics.Gpu.Image } } - IMemoryOwner result = ConvertToHostCompatibleFormat(data); + MemoryOwner result = ConvertToHostCompatibleFormat(data); if (ScaleFactor != 1f && AllowScaledSetData()) { @@ -685,7 +685,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// Uploads new texture data to the host GPU. The data passed as a will be disposed when the operation completes. /// /// New data - public void SetData(IMemoryOwner data) + public void SetData(MemoryOwner data) { BlacklistScale(); @@ -704,7 +704,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// New data /// Target layer /// Target level - public void SetData(IMemoryOwner data, int layer, int level) + public void SetData(MemoryOwner data, int layer, int level) { BlacklistScale(); @@ -722,7 +722,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// Target layer /// Target level /// Target sub-region of the texture to update - public void SetData(IMemoryOwner data, int layer, int level, Rectangle region) + public void SetData(MemoryOwner data, int layer, int level, Rectangle region) { BlacklistScale(); @@ -740,7 +740,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// Mip level to convert /// True to convert a single slice /// Converted data - public IMemoryOwner ConvertToHostCompatibleFormat(ReadOnlySpan data, int level = 0, bool single = false) + public MemoryOwner ConvertToHostCompatibleFormat(ReadOnlySpan data, int level = 0, bool single = false) { int width = Info.Width; int height = Info.Height; @@ -755,7 +755,7 @@ namespace Ryujinx.Graphics.Gpu.Image int sliceDepth = single ? 1 : depth; - IMemoryOwner linear; + MemoryOwner linear; if (Info.IsLinear) { @@ -788,39 +788,40 @@ namespace Ryujinx.Graphics.Gpu.Image data); } - IMemoryOwner result = linear; + MemoryOwner result = linear; // Handle compressed cases not supported by the host: // - ASTC is usually not supported on desktop cards. // - BC4/BC5 is not supported on 3D textures. if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc()) { - if (!AstcDecoder.TryDecodeToRgba8P( - result.Memory, - Info.FormatInfo.BlockWidth, - Info.FormatInfo.BlockHeight, - width, - height, - sliceDepth, - levels, - layers, - out IMemoryOwner decoded)) + using (result) { - string texInfo = $"{Info.Target} {Info.FormatInfo.Format} {Info.Width}x{Info.Height}x{Info.DepthOrLayers} levels {Info.Levels}"; - - Logger.Debug?.Print(LogClass.Gpu, $"Invalid ASTC texture at 0x{Info.GpuAddress:X} ({texInfo})."); - } - - if (GraphicsConfig.EnableTextureRecompression) - { - using (decoded) + if (!AstcDecoder.TryDecodeToRgba8P( + result.Memory, + Info.FormatInfo.BlockWidth, + Info.FormatInfo.BlockHeight, + width, + height, + sliceDepth, + levels, + layers, + out MemoryOwner decoded)) { - result = BCnEncoder.EncodeBC7(decoded.Memory, width, height, sliceDepth, levels, layers); + string texInfo = $"{Info.Target} {Info.FormatInfo.Format} {Info.Width}x{Info.Height}x{Info.DepthOrLayers} levels {Info.Levels}"; + + Logger.Debug?.Print(LogClass.Gpu, $"Invalid ASTC texture at 0x{Info.GpuAddress:X} ({texInfo})."); } - } - else - { - result = decoded; + + if (GraphicsConfig.EnableTextureRecompression) + { + using (decoded) + { + return BCnEncoder.EncodeBC7(decoded.Memory, width, height, sliceDepth, levels, layers); + } + } + + return decoded; } } else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2()) @@ -829,16 +830,22 @@ namespace Ryujinx.Graphics.Gpu.Image { case Format.Etc2RgbaSrgb: case Format.Etc2RgbaUnorm: - result = ETC2Decoder.DecodeRgba(result.Memory.Span, width, height, sliceDepth, levels, layers); - break; + using (result) + { + return ETC2Decoder.DecodeRgba(result.Span, width, height, sliceDepth, levels, layers); + } case Format.Etc2RgbPtaSrgb: case Format.Etc2RgbPtaUnorm: - result = ETC2Decoder.DecodePta(result.Memory.Span, width, height, sliceDepth, levels, layers); - break; + using (result) + { + return ETC2Decoder.DecodePta(result.Span, width, height, sliceDepth, levels, layers); + } case Format.Etc2RgbSrgb: case Format.Etc2RgbUnorm: - result = ETC2Decoder.DecodeRgb(result.Memory.Span, width, height, sliceDepth, levels, layers); - break; + using (result) + { + return ETC2Decoder.DecodeRgb(result.Span, width, height, sliceDepth, levels, layers); + } } } else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities)) @@ -847,55 +854,75 @@ namespace Ryujinx.Graphics.Gpu.Image { case Format.Bc1RgbaSrgb: case Format.Bc1RgbaUnorm: - result = BCnDecoder.DecodeBC1(result.Memory.Span, width, height, sliceDepth, levels, layers); - break; + using (result) + { + return BCnDecoder.DecodeBC1(result.Span, width, height, sliceDepth, levels, layers); + } case Format.Bc2Srgb: case Format.Bc2Unorm: - result = BCnDecoder.DecodeBC2(result.Memory.Span, width, height, sliceDepth, levels, layers); - break; + using (result) + { + return BCnDecoder.DecodeBC2(result.Span, width, height, sliceDepth, levels, layers); + } case Format.Bc3Srgb: case Format.Bc3Unorm: - result = BCnDecoder.DecodeBC3(result.Memory.Span, width, height, sliceDepth, levels, layers); - break; + using (result) + { + return BCnDecoder.DecodeBC3(result.Span, width, height, sliceDepth, levels, layers); + } case Format.Bc4Snorm: case Format.Bc4Unorm: - result = BCnDecoder.DecodeBC4(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm); - break; + using (result) + { + return BCnDecoder.DecodeBC4(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm); + } case Format.Bc5Snorm: case Format.Bc5Unorm: - result = BCnDecoder.DecodeBC5(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm); - break; + using (result) + { + return BCnDecoder.DecodeBC5(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm); + } case Format.Bc6HSfloat: case Format.Bc6HUfloat: - result = BCnDecoder.DecodeBC6(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat); - break; + using (result) + { + return BCnDecoder.DecodeBC6(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat); + } case Format.Bc7Srgb: case Format.Bc7Unorm: - result = BCnDecoder.DecodeBC7(result.Memory.Span, width, height, sliceDepth, levels, layers); - break; + using (result) + { + return BCnDecoder.DecodeBC7(result.Span, width, height, sliceDepth, levels, layers); + } } } else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm) { - var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Memory.Span, width); + using (result) + { + var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Span, width); - if (!_context.Capabilities.SupportsR4G4B4A4Format) - { - using (converted) + if (_context.Capabilities.SupportsR4G4B4A4Format) { - result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Memory.Span, width); + return converted; + } + else + { + using (converted) + { + return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Span, width); + } } - } - else - { - result = converted; } } else if (Format == Format.R4G4B4A4Unorm) { if (!_context.Capabilities.SupportsR4G4B4A4Format) { - result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width); + using (result) + { + return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Span, width); + } } } else if (!_context.Capabilities.Supports5BitComponentFormat && Format.Is16BitPacked()) @@ -904,19 +931,27 @@ namespace Ryujinx.Graphics.Gpu.Image { case Format.B5G6R5Unorm: case Format.R5G6B5Unorm: - result = PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Memory.Span, width); - break; + using (result) + { + return PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Span, width); + } case Format.B5G5R5A1Unorm: case Format.R5G5B5X1Unorm: case Format.R5G5B5A1Unorm: - result = PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Memory.Span, width, Format == Format.R5G5B5X1Unorm); - break; + using (result) + { + return PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Span, width, Format == Format.R5G5B5X1Unorm); + } case Format.A1B5G5R5Unorm: - result = PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Memory.Span, width); - break; + using (result) + { + return PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Span, width); + } case Format.R4G4B4A4Unorm: - result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width); - break; + using (result) + { + return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Span, width); + } } } diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs index 606842d6d..e9930405b 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs @@ -17,13 +17,23 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// For images, indicates the format specified on the shader. /// - public Format Format { get; } + public FormatInfo FormatInfo { get; } + + /// + /// Shader texture host set index. + /// + public int Set { get; } /// /// Shader texture host binding point. /// public int Binding { get; } + /// + /// For array of textures, this indicates the length of the array. A value of one indicates it is not an array. + /// + public int ArrayLength { get; } + /// /// Constant buffer slot with the texture handle. /// @@ -39,20 +49,29 @@ namespace Ryujinx.Graphics.Gpu.Image /// public TextureUsageFlags Flags { get; } + /// + /// Indicates that the binding is for a sampler. + /// + public bool IsSamplerOnly { get; } + /// /// Constructs the texture binding information structure. /// /// The shader sampler target type - /// Format of the image as declared on the shader + /// Format of the image as declared on the shader + /// Shader texture host set index /// The shader texture binding point + /// For array of textures, this indicates the length of the array. A value of one indicates it is not an array /// Constant buffer slot where the texture handle is located /// The shader texture handle (read index into the texture constant buffer) /// The texture's usage flags, indicating how it is used in the shader - public TextureBindingInfo(Target target, Format format, int binding, int cbufSlot, int handle, TextureUsageFlags flags) + public TextureBindingInfo(Target target, FormatInfo formatInfo, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags) { Target = target; - Format = format; + FormatInfo = formatInfo; + Set = set; Binding = binding; + ArrayLength = arrayLength; CbufSlot = cbufSlot; Handle = handle; Flags = flags; @@ -62,12 +81,24 @@ namespace Ryujinx.Graphics.Gpu.Image /// Constructs the texture binding information structure. /// /// The shader sampler target type + /// Shader texture host set index /// The shader texture binding point + /// For array of textures, this indicates the length of the array. A value of one indicates it is not an array /// Constant buffer slot where the texture handle is located /// The shader texture handle (read index into the texture constant buffer) /// The texture's usage flags, indicating how it is used in the shader - public TextureBindingInfo(Target target, int binding, int cbufSlot, int handle, TextureUsageFlags flags) : this(target, (Format)0, binding, cbufSlot, handle, flags) + /// Indicates that the binding is for a sampler + public TextureBindingInfo( + Target target, + int set, + int binding, + int arrayLength, + int cbufSlot, + int handle, + TextureUsageFlags flags, + bool isSamplerOnly) : this(target, FormatInfo.Invalid, set, binding, arrayLength, cbufSlot, handle, flags) { + IsSamplerOnly = isSamplerOnly; } } } diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs new file mode 100644 index 000000000..72bac75e5 --- /dev/null +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs @@ -0,0 +1,1153 @@ +using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Gpu.Engine.Types; +using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Shader; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Image +{ + /// + /// Texture bindings array cache. + /// + class TextureBindingsArrayCache + { + /// + /// Minimum timestamp delta until texture array can be removed from the cache. + /// + private const int MinDeltaForRemoval = 20000; + + private readonly GpuContext _context; + private readonly GpuChannel _channel; + + /// + /// Array cache entry key. + /// + private readonly struct CacheEntryFromPoolKey : IEquatable + { + /// + /// Whether the entry is for an image. + /// + public readonly bool IsImage; + + /// + /// Whether the entry is for a sampler. + /// + public readonly bool IsSampler; + + /// + /// Texture or image target type. + /// + public readonly Target Target; + + /// + /// Number of entries of the array. + /// + public readonly int ArrayLength; + + private readonly TexturePool _texturePool; + private readonly SamplerPool _samplerPool; + + /// + /// Creates a new array cache entry. + /// + /// Whether the entry is for an image + /// Binding information for the array + /// Texture pool where the array textures are located + /// Sampler pool where the array samplers are located + public CacheEntryFromPoolKey(bool isImage, TextureBindingInfo bindingInfo, TexturePool texturePool, SamplerPool samplerPool) + { + IsImage = isImage; + IsSampler = bindingInfo.IsSamplerOnly; + Target = bindingInfo.Target; + ArrayLength = bindingInfo.ArrayLength; + + _texturePool = texturePool; + _samplerPool = samplerPool; + } + + /// + /// Checks if the pool matches the cached pool. + /// + /// Texture or sampler pool instance + /// True if the pool matches, false otherwise + public bool MatchesPool(IPool pool) + { + return _texturePool == pool || _samplerPool == pool; + } + + /// + /// Checks if the texture and sampler pools matches the cached pools. + /// + /// Texture pool instance + /// Sampler pool instance + /// True if the pools match, false otherwise + private bool MatchesPools(TexturePool texturePool, SamplerPool samplerPool) + { + return _texturePool == texturePool && _samplerPool == samplerPool; + } + + public bool Equals(CacheEntryFromPoolKey other) + { + return IsImage == other.IsImage && + IsSampler == other.IsSampler && + Target == other.Target && + ArrayLength == other.ArrayLength && + MatchesPools(other._texturePool, other._samplerPool); + } + + public override bool Equals(object obj) + { + return obj is CacheEntryFromBufferKey other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(_texturePool, _samplerPool, IsSampler); + } + } + + /// + /// Array cache entry key. + /// + private readonly struct CacheEntryFromBufferKey : IEquatable + { + /// + /// Whether the entry is for an image. + /// + public readonly bool IsImage; + + /// + /// Texture or image target type. + /// + public readonly Target Target; + + /// + /// Word offset of the first handle on the constant buffer. + /// + public readonly int HandleIndex; + + /// + /// Number of entries of the array. + /// + public readonly int ArrayLength; + + private readonly TexturePool _texturePool; + private readonly SamplerPool _samplerPool; + + private readonly BufferBounds _textureBufferBounds; + + /// + /// Creates a new array cache entry. + /// + /// Whether the entry is for an image + /// Binding information for the array + /// Texture pool where the array textures are located + /// Sampler pool where the array samplers are located + /// Constant buffer bounds with the texture handles + public CacheEntryFromBufferKey( + bool isImage, + TextureBindingInfo bindingInfo, + TexturePool texturePool, + SamplerPool samplerPool, + ref BufferBounds textureBufferBounds) + { + IsImage = isImage; + Target = bindingInfo.Target; + HandleIndex = bindingInfo.Handle; + ArrayLength = bindingInfo.ArrayLength; + + _texturePool = texturePool; + _samplerPool = samplerPool; + + _textureBufferBounds = textureBufferBounds; + } + + /// + /// Checks if the texture and sampler pools matches the cached pools. + /// + /// Texture pool instance + /// Sampler pool instance + /// True if the pools match, false otherwise + private bool MatchesPools(TexturePool texturePool, SamplerPool samplerPool) + { + return _texturePool == texturePool && _samplerPool == samplerPool; + } + + /// + /// Checks if the cached constant buffer address and size matches. + /// + /// New buffer address and size + /// True if the address and size matches, false otherwise + private bool MatchesBufferBounds(BufferBounds textureBufferBounds) + { + return _textureBufferBounds.Equals(textureBufferBounds); + } + + public bool Equals(CacheEntryFromBufferKey other) + { + return IsImage == other.IsImage && + Target == other.Target && + HandleIndex == other.HandleIndex && + ArrayLength == other.ArrayLength && + MatchesPools(other._texturePool, other._samplerPool) && + MatchesBufferBounds(other._textureBufferBounds); + } + + public override bool Equals(object obj) + { + return obj is CacheEntryFromBufferKey other && Equals(other); + } + + public override int GetHashCode() + { + return _textureBufferBounds.Range.GetHashCode(); + } + } + + /// + /// Array cache entry from pool. + /// + private class CacheEntry + { + /// + /// All cached textures, along with their invalidated sequence number as value. + /// + public readonly Dictionary Textures; + + /// + /// Backend texture array if the entry is for a texture, otherwise null. + /// + public readonly ITextureArray TextureArray; + + /// + /// Backend image array if the entry is for an image, otherwise null. + /// + public readonly IImageArray ImageArray; + + /// + /// Texture pool where the array textures are located. + /// + protected readonly TexturePool TexturePool; + + /// + /// Sampler pool where the array samplers are located. + /// + protected readonly SamplerPool SamplerPool; + + private int _texturePoolSequence; + private int _samplerPoolSequence; + + /// + /// Creates a new array cache entry. + /// + /// Texture pool where the array textures are located + /// Sampler pool where the array samplers are located + private CacheEntry(TexturePool texturePool, SamplerPool samplerPool) + { + Textures = new Dictionary(); + + TexturePool = texturePool; + SamplerPool = samplerPool; + } + + /// + /// Creates a new array cache entry. + /// + /// Backend texture array + /// Texture pool where the array textures are located + /// Sampler pool where the array samplers are located + public CacheEntry(ITextureArray array, TexturePool texturePool, SamplerPool samplerPool) : this(texturePool, samplerPool) + { + TextureArray = array; + } + + /// + /// Creates a new array cache entry. + /// + /// Backend image array + /// Texture pool where the array textures are located + /// Sampler pool where the array samplers are located + public CacheEntry(IImageArray array, TexturePool texturePool, SamplerPool samplerPool) : this(texturePool, samplerPool) + { + ImageArray = array; + } + + /// + /// Synchronizes memory for all textures in the array. + /// + /// Indicates if the texture may be modified by the access + /// Indicates if the texture should be blacklisted for scaling + public void SynchronizeMemory(bool isStore, bool blacklistScale) + { + foreach (Texture texture in Textures.Keys) + { + texture.SynchronizeMemory(); + + if (isStore) + { + texture.SignalModified(); + } + + if (blacklistScale && texture.ScaleMode != TextureScaleMode.Blacklisted) + { + // Scaling textures used on arrays is currently not supported. + + texture.BlacklistScale(); + } + } + } + + /// + /// Clears all cached texture instances. + /// + public virtual void Reset() + { + Textures.Clear(); + } + + /// + /// Checks if any texture has been deleted since the last call to this method. + /// + /// True if one or more textures have been deleted, false otherwise + public bool ValidateTextures() + { + foreach ((Texture texture, int invalidatedSequence) in Textures) + { + if (texture.InvalidatedSequence != invalidatedSequence) + { + return false; + } + } + + return true; + } + + /// + /// Checks if the cached texture or sampler pool has been modified since the last call to this method. + /// + /// True if any used entries of the pool might have been modified, false otherwise + public bool TexturePoolModified() + { + return TexturePool.WasModified(ref _texturePoolSequence); + } + + /// + /// Checks if the cached texture or sampler pool has been modified since the last call to this method. + /// + /// True if any used entries of the pool might have been modified, false otherwise + public bool SamplerPoolModified() + { + return SamplerPool != null && SamplerPool.WasModified(ref _samplerPoolSequence); + } + } + + /// + /// Array cache entry from constant buffer. + /// + private class CacheEntryFromBuffer : CacheEntry + { + /// + /// Key for this entry on the cache. + /// + public readonly CacheEntryFromBufferKey Key; + + /// + /// Linked list node used on the texture bindings array cache. + /// + public LinkedListNode CacheNode; + + /// + /// Timestamp set on the last use of the array by the cache. + /// + public int CacheTimestamp; + + /// + /// All pool texture IDs along with their textures. + /// + public readonly Dictionary TextureIds; + + /// + /// All pool sampler IDs along with their samplers. + /// + public readonly Dictionary SamplerIds; + + private int[] _cachedTextureBuffer; + private int[] _cachedSamplerBuffer; + + private int _lastSequenceNumber; + + /// + /// Creates a new array cache entry. + /// + /// Key for this entry on the cache + /// Backend texture array + /// Texture pool where the array textures are located + /// Sampler pool where the array samplers are located + public CacheEntryFromBuffer(ref CacheEntryFromBufferKey key, ITextureArray array, TexturePool texturePool, SamplerPool samplerPool) : base(array, texturePool, samplerPool) + { + Key = key; + _lastSequenceNumber = -1; + TextureIds = new Dictionary(); + SamplerIds = new Dictionary(); + } + + /// + /// Creates a new array cache entry. + /// + /// Key for this entry on the cache + /// Backend image array + /// Texture pool where the array textures are located + /// Sampler pool where the array samplers are located + public CacheEntryFromBuffer(ref CacheEntryFromBufferKey key, IImageArray array, TexturePool texturePool, SamplerPool samplerPool) : base(array, texturePool, samplerPool) + { + Key = key; + _lastSequenceNumber = -1; + TextureIds = new Dictionary(); + SamplerIds = new Dictionary(); + } + + /// + public override void Reset() + { + base.Reset(); + TextureIds.Clear(); + SamplerIds.Clear(); + } + + /// + /// Updates the cached constant buffer data. + /// + /// Constant buffer data with the texture handles (and sampler handles, if they are combined) + /// Constant buffer data with the sampler handles + /// Whether and comes from different buffers + public void UpdateData(ReadOnlySpan cachedTextureBuffer, ReadOnlySpan cachedSamplerBuffer, bool separateSamplerBuffer) + { + _cachedTextureBuffer = cachedTextureBuffer.ToArray(); + _cachedSamplerBuffer = separateSamplerBuffer ? cachedSamplerBuffer.ToArray() : _cachedTextureBuffer; + } + + /// + /// Checks if the sequence number matches the one used on the last call to this method. + /// + /// Current sequence number + /// True if the sequence numbers match, false otherwise + public bool MatchesSequenceNumber(int currentSequenceNumber) + { + if (_lastSequenceNumber == currentSequenceNumber) + { + return true; + } + + _lastSequenceNumber = currentSequenceNumber; + + return false; + } + + /// + /// Checks if the buffer data matches the cached data. + /// + /// New texture buffer data + /// New sampler buffer data + /// Whether and comes from different buffers + /// Word offset of the sampler constant buffer handle that is used + /// True if the data matches, false otherwise + public bool MatchesBufferData( + ReadOnlySpan cachedTextureBuffer, + ReadOnlySpan cachedSamplerBuffer, + bool separateSamplerBuffer, + int samplerWordOffset) + { + if (_cachedTextureBuffer != null && cachedTextureBuffer.Length > _cachedTextureBuffer.Length) + { + cachedTextureBuffer = cachedTextureBuffer[.._cachedTextureBuffer.Length]; + } + + if (!_cachedTextureBuffer.AsSpan().SequenceEqual(cachedTextureBuffer)) + { + return false; + } + + if (separateSamplerBuffer) + { + if (_cachedSamplerBuffer == null || + _cachedSamplerBuffer.Length <= samplerWordOffset || + cachedSamplerBuffer.Length <= samplerWordOffset) + { + return false; + } + + int oldValue = _cachedSamplerBuffer[samplerWordOffset]; + int newValue = cachedSamplerBuffer[samplerWordOffset]; + + return oldValue == newValue; + } + + return true; + } + + /// + /// Checks if the cached texture or sampler pool has been modified since the last call to this method. + /// + /// True if any used entries of the pools might have been modified, false otherwise + public bool PoolsModified() + { + bool texturePoolModified = TexturePoolModified(); + bool samplerPoolModified = SamplerPoolModified(); + + // If both pools were not modified since the last check, we have nothing else to check. + if (!texturePoolModified && !samplerPoolModified) + { + return false; + } + + // If the pools were modified, let's check if any of the entries we care about changed. + + // Check if any of our cached textures changed on the pool. + foreach ((int textureId, (Texture texture, TextureDescriptor descriptor)) in TextureIds) + { + if (TexturePool.GetCachedItem(textureId) != texture || + (texture == null && TexturePool.IsValidId(textureId) && !TexturePool.GetDescriptorRef(textureId).Equals(descriptor))) + { + return true; + } + } + + // Check if any of our cached samplers changed on the pool. + if (SamplerPool != null) + { + foreach ((int samplerId, (Sampler sampler, SamplerDescriptor descriptor)) in SamplerIds) + { + if (SamplerPool.GetCachedItem(samplerId) != sampler || + (sampler == null && SamplerPool.IsValidId(samplerId) && !SamplerPool.GetDescriptorRef(samplerId).Equals(descriptor))) + { + return true; + } + } + } + + return false; + } + } + + private readonly Dictionary _cacheFromBuffer; + private readonly Dictionary _cacheFromPool; + private readonly LinkedList _lruCache; + + private int _currentTimestamp; + + /// + /// Creates a new instance of the texture bindings array cache. + /// + /// GPU context + /// GPU channel + public TextureBindingsArrayCache(GpuContext context, GpuChannel channel) + { + _context = context; + _channel = channel; + _cacheFromBuffer = new Dictionary(); + _cacheFromPool = new Dictionary(); + _lruCache = new LinkedList(); + } + + /// + /// Updates a texture array bindings and textures. + /// + /// Texture pool + /// Sampler pool + /// Shader stage where the array is used + /// Shader stage index where the array is used + /// Texture constant buffer index + /// Sampler handles source + /// Array binding information + public void UpdateTextureArray( + TexturePool texturePool, + SamplerPool samplerPool, + ShaderStage stage, + int stageIndex, + int textureBufferIndex, + SamplerIndex samplerIndex, + in TextureBindingInfo bindingInfo) + { + Update(texturePool, samplerPool, stage, stageIndex, textureBufferIndex, isImage: false, samplerIndex, bindingInfo); + } + + /// + /// Updates a image array bindings and textures. + /// + /// Texture pool + /// Shader stage where the array is used + /// Shader stage index where the array is used + /// Texture constant buffer index + /// Array binding information + public void UpdateImageArray(TexturePool texturePool, ShaderStage stage, int stageIndex, int textureBufferIndex, in TextureBindingInfo bindingInfo) + { + Update(texturePool, null, stage, stageIndex, textureBufferIndex, isImage: true, SamplerIndex.ViaHeaderIndex, bindingInfo); + } + + /// + /// Updates a texture or image array bindings and textures. + /// + /// Texture pool + /// Sampler pool + /// Shader stage where the array is used + /// Shader stage index where the array is used + /// Texture constant buffer index + /// Whether the array is a image or texture array + /// Sampler handles source + /// Array binding information + private void Update( + TexturePool texturePool, + SamplerPool samplerPool, + ShaderStage stage, + int stageIndex, + int textureBufferIndex, + bool isImage, + SamplerIndex samplerIndex, + in TextureBindingInfo bindingInfo) + { + if (IsDirectHandleType(bindingInfo.Handle)) + { + UpdateFromPool(texturePool, samplerPool, stage, isImage, bindingInfo); + } + else + { + UpdateFromBuffer(texturePool, samplerPool, stage, stageIndex, textureBufferIndex, isImage, samplerIndex, bindingInfo); + } + } + + /// + /// Updates a texture or image array bindings and textures from a texture or sampler pool. + /// + /// Texture pool + /// Sampler pool + /// Shader stage where the array is used + /// Whether the array is a image or texture array + /// Array binding information + private void UpdateFromPool(TexturePool texturePool, SamplerPool samplerPool, ShaderStage stage, bool isImage, in TextureBindingInfo bindingInfo) + { + CacheEntry entry = GetOrAddEntry(texturePool, samplerPool, bindingInfo, isImage, out bool isNewEntry); + + bool isSampler = bindingInfo.IsSamplerOnly; + bool poolModified = isSampler ? entry.SamplerPoolModified() : entry.TexturePoolModified(); + bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore); + bool resScaleUnsupported = bindingInfo.Flags.HasFlag(TextureUsageFlags.ResScaleUnsupported); + + if (!poolModified && !isNewEntry && entry.ValidateTextures()) + { + entry.SynchronizeMemory(isStore, resScaleUnsupported); + + if (isImage) + { + SetImageArray(stage, bindingInfo, entry.ImageArray); + } + else + { + SetTextureArray(stage, bindingInfo, entry.TextureArray); + } + + return; + } + + if (!isNewEntry) + { + entry.Reset(); + } + + int length = (isSampler ? samplerPool.MaximumId : texturePool.MaximumId) + 1; + length = Math.Min(length, bindingInfo.ArrayLength); + + ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength]; + ITexture[] textures = new ITexture[bindingInfo.ArrayLength]; + + for (int index = 0; index < length; index++) + { + Texture texture = null; + Sampler sampler = null; + + if (isSampler) + { + sampler = samplerPool?.Get(index); + } + else + { + ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, bindingInfo.FormatInfo, out texture); + + if (texture != null) + { + entry.Textures[texture] = texture.InvalidatedSequence; + + if (isStore) + { + texture.SignalModified(); + } + + if (resScaleUnsupported && texture.ScaleMode != TextureScaleMode.Blacklisted) + { + // Scaling textures used on arrays is currently not supported. + + texture.BlacklistScale(); + } + } + } + + ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); + ISampler hostSampler = sampler?.GetHostSampler(texture); + + if (hostTexture != null && texture.Target == Target.TextureBuffer) + { + // Ensure that the buffer texture is using the correct buffer as storage. + // Buffers are frequently re-created to accommodate larger data, so we need to re-bind + // to ensure we're not using a old buffer that was already deleted. + if (isImage) + { + _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index); + } + else + { + _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index); + } + } + else if (isImage) + { + textures[index] = hostTexture; + } + else + { + samplers[index] = hostSampler; + textures[index] = hostTexture; + } + } + + if (isImage) + { + entry.ImageArray.SetImages(0, textures); + + SetImageArray(stage, bindingInfo, entry.ImageArray); + } + else + { + entry.TextureArray.SetSamplers(0, samplers); + entry.TextureArray.SetTextures(0, textures); + + SetTextureArray(stage, bindingInfo, entry.TextureArray); + } + } + + /// + /// Updates a texture or image array bindings and textures from constant buffer handles. + /// + /// Texture pool + /// Sampler pool + /// Shader stage where the array is used + /// Shader stage index where the array is used + /// Texture constant buffer index + /// Whether the array is a image or texture array + /// Sampler handles source + /// Array binding information + private void UpdateFromBuffer( + TexturePool texturePool, + SamplerPool samplerPool, + ShaderStage stage, + int stageIndex, + int textureBufferIndex, + bool isImage, + SamplerIndex samplerIndex, + in TextureBindingInfo bindingInfo) + { + (textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex); + + bool separateSamplerBuffer = textureBufferIndex != samplerBufferIndex; + bool isCompute = stage == ShaderStage.Compute; + + ref BufferBounds textureBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, textureBufferIndex); + ref BufferBounds samplerBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, samplerBufferIndex); + + CacheEntryFromBuffer entry = GetOrAddEntry( + texturePool, + samplerPool, + bindingInfo, + isImage, + ref textureBufferBounds, + out bool isNewEntry); + + bool poolsModified = entry.PoolsModified(); + bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore); + bool resScaleUnsupported = bindingInfo.Flags.HasFlag(TextureUsageFlags.ResScaleUnsupported); + + ReadOnlySpan cachedTextureBuffer; + ReadOnlySpan cachedSamplerBuffer; + + if (!poolsModified && !isNewEntry && entry.ValidateTextures()) + { + if (entry.MatchesSequenceNumber(_context.SequenceNumber)) + { + entry.SynchronizeMemory(isStore, resScaleUnsupported); + + if (isImage) + { + SetImageArray(stage, bindingInfo, entry.ImageArray); + } + else + { + SetTextureArray(stage, bindingInfo, entry.TextureArray); + } + + return; + } + + cachedTextureBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(textureBufferBounds.Range)); + + if (separateSamplerBuffer) + { + cachedSamplerBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(samplerBufferBounds.Range)); + } + else + { + cachedSamplerBuffer = cachedTextureBuffer; + } + + (_, int samplerWordOffset, _) = TextureHandle.UnpackOffsets(bindingInfo.Handle); + + if (entry.MatchesBufferData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer, samplerWordOffset)) + { + entry.SynchronizeMemory(isStore, resScaleUnsupported); + + if (isImage) + { + SetImageArray(stage, bindingInfo, entry.ImageArray); + } + else + { + SetTextureArray(stage, bindingInfo, entry.TextureArray); + } + + return; + } + } + else + { + cachedTextureBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(textureBufferBounds.Range)); + + if (separateSamplerBuffer) + { + cachedSamplerBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(samplerBufferBounds.Range)); + } + else + { + cachedSamplerBuffer = cachedTextureBuffer; + } + } + + if (!isNewEntry) + { + entry.Reset(); + } + + entry.UpdateData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer); + + ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength]; + ITexture[] textures = new ITexture[bindingInfo.ArrayLength]; + + for (int index = 0; index < bindingInfo.ArrayLength; index++) + { + int handleIndex = bindingInfo.Handle + index * (Constants.TextureHandleSizeInBytes / sizeof(int)); + int packedId = TextureHandle.ReadPackedId(handleIndex, cachedTextureBuffer, cachedSamplerBuffer); + int textureId = TextureHandle.UnpackTextureId(packedId); + int samplerId; + + if (samplerIndex == SamplerIndex.ViaHeaderIndex) + { + samplerId = textureId; + } + else + { + samplerId = TextureHandle.UnpackSamplerId(packedId); + } + + ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture); + + if (texture != null) + { + entry.Textures[texture] = texture.InvalidatedSequence; + + if (isStore) + { + texture.SignalModified(); + } + + if (resScaleUnsupported && texture.ScaleMode != TextureScaleMode.Blacklisted) + { + // Scaling textures used on arrays is currently not supported. + + texture.BlacklistScale(); + } + } + + entry.TextureIds[textureId] = (texture, descriptor); + + ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); + ISampler hostSampler = null; + + if (!isImage && bindingInfo.Target != Target.TextureBuffer) + { + Sampler sampler = samplerPool?.Get(samplerId); + + entry.SamplerIds[samplerId] = (sampler, samplerPool?.GetDescriptorRef(samplerId) ?? default); + + hostSampler = sampler?.GetHostSampler(texture); + } + + if (hostTexture != null && texture.Target == Target.TextureBuffer) + { + // Ensure that the buffer texture is using the correct buffer as storage. + // Buffers are frequently re-created to accommodate larger data, so we need to re-bind + // to ensure we're not using a old buffer that was already deleted. + if (isImage) + { + _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index); + } + else + { + _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index); + } + } + else if (isImage) + { + textures[index] = hostTexture; + } + else + { + samplers[index] = hostSampler; + textures[index] = hostTexture; + } + } + + if (isImage) + { + entry.ImageArray.SetImages(0, textures); + + SetImageArray(stage, bindingInfo, entry.ImageArray); + } + else + { + entry.TextureArray.SetSamplers(0, samplers); + entry.TextureArray.SetTextures(0, textures); + + SetTextureArray(stage, bindingInfo, entry.TextureArray); + } + } + + /// + /// Updates a texture array binding on the host. + /// + /// Shader stage where the array is used + /// Array binding information + /// Texture array + private void SetTextureArray(ShaderStage stage, in TextureBindingInfo bindingInfo, ITextureArray array) + { + if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex && _context.Capabilities.MaximumExtraSets != 0) + { + _context.Renderer.Pipeline.SetTextureArraySeparate(stage, bindingInfo.Set, array); + } + else + { + _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, array); + } + } + + /// + /// Updates a image array binding on the host. + /// + /// Shader stage where the array is used + /// Array binding information + /// Image array + private void SetImageArray(ShaderStage stage, in TextureBindingInfo bindingInfo, IImageArray array) + { + if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex && _context.Capabilities.MaximumExtraSets != 0) + { + _context.Renderer.Pipeline.SetImageArraySeparate(stage, bindingInfo.Set, array); + } + else + { + _context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, array); + } + } + + /// + /// Gets a cached texture entry from pool, or creates a new one if not found. + /// + /// Texture pool + /// Sampler pool + /// Array binding information + /// Whether the array is a image or texture array + /// Whether a new entry was created, or an existing one was returned + /// Cache entry + private CacheEntry GetOrAddEntry( + TexturePool texturePool, + SamplerPool samplerPool, + in TextureBindingInfo bindingInfo, + bool isImage, + out bool isNew) + { + CacheEntryFromPoolKey key = new CacheEntryFromPoolKey(isImage, bindingInfo, texturePool, samplerPool); + + isNew = !_cacheFromPool.TryGetValue(key, out CacheEntry entry); + + if (isNew) + { + int arrayLength = bindingInfo.ArrayLength; + + if (isImage) + { + IImageArray array = _context.Renderer.CreateImageArray(arrayLength, bindingInfo.Target == Target.TextureBuffer); + + _cacheFromPool.Add(key, entry = new CacheEntry(array, texturePool, samplerPool)); + } + else + { + ITextureArray array = _context.Renderer.CreateTextureArray(arrayLength, bindingInfo.Target == Target.TextureBuffer); + + _cacheFromPool.Add(key, entry = new CacheEntry(array, texturePool, samplerPool)); + } + } + + return entry; + } + + /// + /// Gets a cached texture entry from constant buffer, or creates a new one if not found. + /// + /// Texture pool + /// Sampler pool + /// Array binding information + /// Whether the array is a image or texture array + /// Constant buffer bounds with the texture handles + /// Whether a new entry was created, or an existing one was returned + /// Cache entry + private CacheEntryFromBuffer GetOrAddEntry( + TexturePool texturePool, + SamplerPool samplerPool, + in TextureBindingInfo bindingInfo, + bool isImage, + ref BufferBounds textureBufferBounds, + out bool isNew) + { + CacheEntryFromBufferKey key = new CacheEntryFromBufferKey( + isImage, + bindingInfo, + texturePool, + samplerPool, + ref textureBufferBounds); + + isNew = !_cacheFromBuffer.TryGetValue(key, out CacheEntryFromBuffer entry); + + if (isNew) + { + int arrayLength = bindingInfo.ArrayLength; + + if (isImage) + { + IImageArray array = _context.Renderer.CreateImageArray(arrayLength, bindingInfo.Target == Target.TextureBuffer); + + _cacheFromBuffer.Add(key, entry = new CacheEntryFromBuffer(ref key, array, texturePool, samplerPool)); + } + else + { + ITextureArray array = _context.Renderer.CreateTextureArray(arrayLength, bindingInfo.Target == Target.TextureBuffer); + + _cacheFromBuffer.Add(key, entry = new CacheEntryFromBuffer(ref key, array, texturePool, samplerPool)); + } + } + + if (entry.CacheNode != null) + { + _lruCache.Remove(entry.CacheNode); + _lruCache.AddLast(entry.CacheNode); + } + else + { + entry.CacheNode = _lruCache.AddLast(entry); + } + + entry.CacheTimestamp = ++_currentTimestamp; + + RemoveLeastUsedEntries(); + + return entry; + } + + /// + /// Remove entries from the cache that have not been used for some time. + /// + private void RemoveLeastUsedEntries() + { + LinkedListNode nextNode = _lruCache.First; + + while (nextNode != null && _currentTimestamp - nextNode.Value.CacheTimestamp >= MinDeltaForRemoval) + { + LinkedListNode toRemove = nextNode; + nextNode = nextNode.Next; + _cacheFromBuffer.Remove(toRemove.Value.Key); + _lruCache.Remove(toRemove); + + if (toRemove.Value.Key.IsImage) + { + toRemove.Value.ImageArray.Dispose(); + } + else + { + toRemove.Value.TextureArray.Dispose(); + } + } + } + + /// + /// Removes all cached texture arrays matching the specified texture pool. + /// + /// Texture pool + public void RemoveAllWithPool(IPool pool) + { + List keysToRemove = null; + + foreach ((CacheEntryFromPoolKey key, CacheEntry entry) in _cacheFromPool) + { + if (key.MatchesPool(pool)) + { + (keysToRemove ??= new()).Add(key); + + if (key.IsImage) + { + entry.ImageArray.Dispose(); + } + else + { + entry.TextureArray.Dispose(); + } + } + } + + if (keysToRemove != null) + { + foreach (CacheEntryFromPoolKey key in keysToRemove) + { + _cacheFromPool.Remove(key); + } + } + } + + /// + /// Checks if a handle indicates the binding should have all its textures sourced directly from a pool. + /// + /// Handle to check + /// True if the handle represents direct pool access, false otherwise + private static bool IsDirectHandleType(int handle) + { + (_, _, TextureHandleType type) = TextureHandle.UnpackOffsets(handle); + + return type == TextureHandleType.Direct; + } + } +} diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs index 963bd947d..f96ddfb1b 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs @@ -34,6 +34,8 @@ namespace Ryujinx.Graphics.Gpu.Image private readonly TexturePoolCache _texturePoolCache; private readonly SamplerPoolCache _samplerPoolCache; + private readonly TextureBindingsArrayCache _bindingsArrayCache; + private TexturePool _cachedTexturePool; private SamplerPool _cachedSamplerPool; @@ -56,6 +58,8 @@ namespace Ryujinx.Graphics.Gpu.Image private TextureState[] _textureState; private TextureState[] _imageState; + private int[] _textureCounts; + private int _texturePoolSequence; private int _samplerPoolSequence; @@ -68,12 +72,14 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// The GPU context that the texture bindings manager belongs to /// The GPU channel that the texture bindings manager belongs to + /// Cache of texture array bindings /// Texture pools cache used to get texture pools from /// Sampler pools cache used to get sampler pools from /// True if the bindings manager is used for the compute engine public TextureBindingsManager( GpuContext context, GpuChannel channel, + TextureBindingsArrayCache bindingsArrayCache, TexturePoolCache texturePoolCache, SamplerPoolCache samplerPoolCache, bool isCompute) @@ -85,6 +91,8 @@ namespace Ryujinx.Graphics.Gpu.Image _isCompute = isCompute; + _bindingsArrayCache = bindingsArrayCache; + int stages = isCompute ? 1 : Constants.ShaderStages; _textureBindings = new TextureBindingInfo[stages][]; @@ -95,9 +103,11 @@ namespace Ryujinx.Graphics.Gpu.Image for (int stage = 0; stage < stages; stage++) { - _textureBindings[stage] = new TextureBindingInfo[InitialTextureStateSize]; - _imageBindings[stage] = new TextureBindingInfo[InitialImageStateSize]; + _textureBindings[stage] = Array.Empty(); + _imageBindings[stage] = Array.Empty(); } + + _textureCounts = Array.Empty(); } /// @@ -109,6 +119,8 @@ namespace Ryujinx.Graphics.Gpu.Image _textureBindings = bindings.TextureBindings; _imageBindings = bindings.ImageBindings; + _textureCounts = bindings.TextureCounts; + SetMaxBindings(bindings.MaxTextureBinding, bindings.MaxImageBinding); } @@ -175,7 +187,9 @@ namespace Ryujinx.Graphics.Gpu.Image { (TexturePool texturePool, SamplerPool samplerPool) = GetPools(); - return (texturePool.Get(textureId), samplerPool.Get(samplerId)); + Sampler sampler = samplerPool?.Get(samplerId); + + return (texturePool.Get(textureId, sampler?.IsSrgb ?? true), sampler); } /// @@ -401,27 +415,6 @@ namespace Ryujinx.Graphics.Gpu.Image } } -#pragma warning disable IDE0051 // Remove unused private member - /// - /// Counts the total number of texture bindings used by all shader stages. - /// - /// The total amount of textures used - private int GetTextureBindingsCount() - { - int count = 0; - - foreach (TextureBindingInfo[] textureInfo in _textureBindings) - { - if (textureInfo != null) - { - count += textureInfo.Length; - } - } - - return count; - } -#pragma warning restore IDE0051 - /// /// Ensures that the texture bindings are visible to the host GPU. /// Note: this actually performs the binding using the host graphics API. @@ -465,6 +458,13 @@ namespace Ryujinx.Graphics.Gpu.Image TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index]; TextureUsageFlags usageFlags = bindingInfo.Flags; + if (bindingInfo.ArrayLength > 1) + { + _bindingsArrayCache.UpdateTextureArray(texturePool, samplerPool, stage, stageIndex, _textureBufferIndex, _samplerIndex, bindingInfo); + + continue; + } + (int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, _textureBufferIndex); UpdateCachedBuffer(stageIndex, ref cachedTextureBufferIndex, ref cachedSamplerBufferIndex, ref cachedTextureBuffer, ref cachedSamplerBuffer, textureBufferIndex, samplerBufferIndex); @@ -510,12 +510,12 @@ namespace Ryujinx.Graphics.Gpu.Image state.TextureHandle = textureId; state.SamplerHandle = samplerId; - ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture); + Sampler sampler = samplerPool?.Get(samplerId); + + ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, sampler?.IsSrgb ?? true, out Texture texture); specStateMatches &= specState.MatchesTexture(stage, index, descriptor); - Sampler sampler = samplerPool?.Get(samplerId); - ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); ISampler hostSampler = sampler?.GetHostSampler(texture); @@ -524,7 +524,7 @@ namespace Ryujinx.Graphics.Gpu.Image // Ensure that the buffer texture is using the correct buffer as storage. // Buffers are frequently re-created to accommodate larger data, so we need to re-bind // to ensure we're not using a old buffer that was already deleted. - _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, bindingInfo.Format, false); + _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, false); // Cache is not used for buffer texture, it must always rebind. state.CachedTexture = null; @@ -582,7 +582,7 @@ namespace Ryujinx.Graphics.Gpu.Image } // Scales for images appear after the texture ones. - int baseScaleIndex = _textureBindings[stageIndex].Length; + int baseScaleIndex = _textureCounts[stageIndex]; int cachedTextureBufferIndex = -1; int cachedSamplerBufferIndex = -1; @@ -595,6 +595,14 @@ namespace Ryujinx.Graphics.Gpu.Image { TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index]; TextureUsageFlags usageFlags = bindingInfo.Flags; + + if (bindingInfo.ArrayLength > 1) + { + _bindingsArrayCache.UpdateImageArray(pool, stage, stageIndex, _textureBufferIndex, bindingInfo); + + continue; + } + int scaleIndex = baseScaleIndex + index; (int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, _textureBufferIndex); @@ -610,6 +618,7 @@ namespace Ryujinx.Graphics.Gpu.Image if (!poolModified && state.TextureHandle == textureId && + state.ImageFormat == bindingInfo.FormatInfo.Format && state.CachedTexture != null && state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence) { @@ -620,29 +629,25 @@ namespace Ryujinx.Graphics.Gpu.Image if (isStore) { - cachedTexture?.SignalModified(); + cachedTexture.SignalModified(); } - Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format; - - if (state.ImageFormat != format || - ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 && - UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage))) + if ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 && UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage)) { ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target); state.Texture = hostTextureRebind; - state.ImageFormat = format; - _context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTextureRebind, format); + _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind); } continue; } state.TextureHandle = textureId; + state.ImageFormat = bindingInfo.FormatInfo.Format; - ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, out Texture texture); + ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture); specStateMatches &= specState.MatchesImage(stage, index, descriptor); @@ -654,14 +659,7 @@ namespace Ryujinx.Graphics.Gpu.Image // Buffers are frequently re-created to accommodate larger data, so we need to re-bind // to ensure we're not using a old buffer that was already deleted. - Format format = bindingInfo.Format; - - if (format == 0 && texture != null) - { - format = texture.Format; - } - - _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, format, true); + _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, true); // Cache is not used for buffer texture, it must always rebind. state.CachedTexture = null; @@ -683,16 +681,7 @@ namespace Ryujinx.Graphics.Gpu.Image { state.Texture = hostTexture; - Format format = bindingInfo.Format; - - if (format == 0 && texture != null) - { - format = texture.Format; - } - - state.ImageFormat = format; - - _context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTexture, format); + _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTexture); } state.CachedTexture = texture; @@ -728,7 +717,7 @@ namespace Ryujinx.Graphics.Gpu.Image ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); - TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); + TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId, _bindingsArrayCache); TextureDescriptor descriptor; @@ -766,7 +755,7 @@ namespace Ryujinx.Graphics.Gpu.Image ? _channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex) : _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex); - int handle = textureBufferAddress != 0 + int handle = textureBufferAddress != MemoryManager.PteUnmapped ? _channel.MemoryManager.Physical.Read(textureBufferAddress + (uint)textureWordOffset * 4) : 0; @@ -786,7 +775,7 @@ namespace Ryujinx.Graphics.Gpu.Image ? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex) : _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex); - samplerHandle = samplerBufferAddress != 0 + samplerHandle = samplerBufferAddress != MemoryManager.PteUnmapped ? _channel.MemoryManager.Physical.Read(samplerBufferAddress + (uint)samplerWordOffset * 4) : 0; } @@ -824,7 +813,7 @@ namespace Ryujinx.Graphics.Gpu.Image if (poolAddress != MemoryManager.PteUnmapped) { - texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, _texturePoolMaximumId); + texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, _texturePoolMaximumId, _bindingsArrayCache); _texturePool = texturePool; } } @@ -835,7 +824,7 @@ namespace Ryujinx.Graphics.Gpu.Image if (poolAddress != MemoryManager.PteUnmapped) { - samplerPool = _samplerPoolCache.FindOrCreate(_channel, poolAddress, _samplerPoolMaximumId); + samplerPool = _samplerPoolCache.FindOrCreate(_channel, poolAddress, _samplerPoolMaximumId, _bindingsArrayCache); _samplerPool = samplerPool; } } diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index 6b92c0aaf..1587e2018 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -8,6 +8,7 @@ using Ryujinx.Graphics.Texture; using Ryujinx.Memory.Range; using System; using System.Collections.Generic; +using System.Threading; namespace Ryujinx.Graphics.Gpu.Image { @@ -39,6 +40,8 @@ namespace Ryujinx.Graphics.Gpu.Image private readonly MultiRangeList _textures; private readonly HashSet _partiallyMappedTextures; + private readonly ReaderWriterLockSlim _texturesLock; + private Texture[] _textureOverlaps; private OverlapInfo[] _overlapInfo; @@ -57,12 +60,22 @@ namespace Ryujinx.Graphics.Gpu.Image _textures = new MultiRangeList(); _partiallyMappedTextures = new HashSet(); + _texturesLock = new ReaderWriterLockSlim(); + _textureOverlaps = new Texture[OverlapsBufferInitialCapacity]; _overlapInfo = new OverlapInfo[OverlapsBufferInitialCapacity]; _cache = new AutoDeleteCache(); } + /// + /// Initializes the cache, setting the maximum texture capacity for the specified GPU context. + /// + public void Initialize() + { + _cache.Initialize(_context); + } + /// /// Handles marking of textures written to a memory region being (partially) remapped. /// @@ -75,10 +88,16 @@ namespace Ryujinx.Graphics.Gpu.Image MultiRange unmapped = ((MemoryManager)sender).GetPhysicalRegions(e.Address, e.Size); - lock (_textures) + _texturesLock.EnterReadLock(); + + try { overlapCount = _textures.FindOverlaps(unmapped, ref overlaps); } + finally + { + _texturesLock.ExitReadLock(); + } if (overlapCount > 0) { @@ -217,7 +236,18 @@ namespace Ryujinx.Graphics.Gpu.Image public bool UpdateMapping(Texture texture, MultiRange range) { // There cannot be an existing texture compatible with this mapping in the texture cache already. - int overlapCount = _textures.FindOverlaps(range, ref _textureOverlaps); + int overlapCount; + + _texturesLock.EnterReadLock(); + + try + { + overlapCount = _textures.FindOverlaps(range, ref _textureOverlaps); + } + finally + { + _texturesLock.ExitReadLock(); + } for (int i = 0; i < overlapCount; i++) { @@ -231,11 +261,20 @@ namespace Ryujinx.Graphics.Gpu.Image } } - _textures.Remove(texture); + _texturesLock.EnterWriteLock(); - texture.ReplaceRange(range); + try + { + _textures.Remove(texture); - _textures.Add(texture); + texture.ReplaceRange(range); + + _textures.Add(texture); + } + finally + { + _texturesLock.ExitWriteLock(); + } return true; } @@ -316,6 +355,53 @@ namespace Ryujinx.Graphics.Gpu.Image return texture; } + /// + /// Tries to find an existing texture, or create a new one if not found. + /// + /// GPU memory manager where the texture is mapped + /// Format of the texture + /// GPU virtual address of the texture + /// Texture width in bytes + /// Texture height + /// Texture stride if linear, otherwise ignored + /// Indicates if the texture is linear or block linear + /// GOB blocks in Y for block linear textures + /// GOB blocks in Z for 3D block linear textures + /// The texture + public Texture FindOrCreateTexture( + MemoryManager memoryManager, + FormatInfo formatInfo, + ulong gpuAddress, + int xCount, + int yCount, + int stride, + bool isLinear, + int gobBlocksInY, + int gobBlocksInZ) + { + TextureInfo info = new( + gpuAddress, + xCount / formatInfo.BytesPerPixel, + yCount, + 1, + 1, + 1, + 1, + stride, + isLinear, + gobBlocksInY, + gobBlocksInZ, + 1, + Target.Texture2D, + formatInfo); + + Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.ForCopy, info, 0, sizeHint: new Size(xCount, yCount, 1)); + + texture?.SynchronizeMemory(); + + return texture; + } + /// /// Tries to find an existing texture, or create a new one if not found. /// @@ -437,13 +523,11 @@ namespace Ryujinx.Graphics.Gpu.Image int gobBlocksInY = dsState.MemoryLayout.UnpackGobBlocksInY(); int gobBlocksInZ = dsState.MemoryLayout.UnpackGobBlocksInZ(); + layered &= size.UnpackIsLayered(); + Target target; - if (dsState.MemoryLayout.UnpackIsTarget3D()) - { - target = Target.Texture3D; - } - else if ((samplesInX | samplesInY) != 1) + if ((samplesInX | samplesInY) != 1) { target = size.Depth > 1 && layered ? Target.Texture2DMultisampleArray @@ -611,11 +695,17 @@ namespace Ryujinx.Graphics.Gpu.Image int sameAddressOverlapsCount; - lock (_textures) + _texturesLock.EnterReadLock(); + + try { // Try to find a perfect texture match, with the same address and parameters. sameAddressOverlapsCount = _textures.FindOverlaps(address, ref _textureOverlaps); } + finally + { + _texturesLock.ExitReadLock(); + } Texture texture = null; @@ -698,10 +788,16 @@ namespace Ryujinx.Graphics.Gpu.Image if (info.Target != Target.TextureBuffer) { - lock (_textures) + _texturesLock.EnterReadLock(); + + try { overlapsCount = _textures.FindOverlaps(range.Value, ref _textureOverlaps); } + finally + { + _texturesLock.ExitReadLock(); + } } if (_overlapInfo.Length != _textureOverlaps.Length) @@ -790,8 +886,12 @@ namespace Ryujinx.Graphics.Gpu.Image texture = new Texture(_context, _physicalMemory, info, sizeInfo, range.Value, scaleMode); + // If the new texture is larger than the existing one, we need to fill the remaining space with CPU data, + // otherwise we only need the data that is copied from the existing texture, without loading the CPU data. + bool updateNewTexture = texture.Width > overlap.Width || texture.Height > overlap.Height; + texture.InitializeGroup(true, true, new List()); - texture.InitializeData(false, false); + texture.InitializeData(false, updateNewTexture); overlap.SynchronizeMemory(); overlap.CreateCopyDependency(texture, oInfo.FirstLayer, oInfo.FirstLevel, true); @@ -1021,10 +1121,16 @@ namespace Ryujinx.Graphics.Gpu.Image _cache.Add(texture); } - lock (_textures) + _texturesLock.EnterWriteLock(); + + try { _textures.Add(texture); } + finally + { + _texturesLock.ExitWriteLock(); + } if (partiallyMapped) { @@ -1087,7 +1193,19 @@ namespace Ryujinx.Graphics.Gpu.Image return null; } - int addressMatches = _textures.FindOverlaps(address, ref _textureOverlaps); + int addressMatches; + + _texturesLock.EnterReadLock(); + + try + { + addressMatches = _textures.FindOverlaps(address, ref _textureOverlaps); + } + finally + { + _texturesLock.ExitReadLock(); + } + Texture textureMatch = null; for (int i = 0; i < addressMatches; i++) @@ -1228,10 +1346,16 @@ namespace Ryujinx.Graphics.Gpu.Image /// The texture to be removed public void RemoveTextureFromCache(Texture texture) { - lock (_textures) + _texturesLock.EnterWriteLock(); + + try { _textures.Remove(texture); } + finally + { + _texturesLock.ExitWriteLock(); + } lock (_partiallyMappedTextures) { @@ -1320,13 +1444,19 @@ namespace Ryujinx.Graphics.Gpu.Image /// public void Dispose() { - lock (_textures) + _texturesLock.EnterReadLock(); + + try { foreach (Texture texture in _textures) { texture.Dispose(); } } + finally + { + _texturesLock.ExitReadLock(); + } } } } diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs index eef38948d..8bed6363b 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs @@ -242,7 +242,12 @@ namespace Ryujinx.Graphics.Gpu.Image return TextureMatchQuality.FormatAlias; } else if ((lhs.FormatInfo.Format == Format.D24UnormS8Uint || - lhs.FormatInfo.Format == Format.S8UintD24Unorm) && rhs.FormatInfo.Format == Format.B8G8R8A8Unorm) + lhs.FormatInfo.Format == Format.S8UintD24Unorm || + lhs.FormatInfo.Format == Format.X8UintD24Unorm) && rhs.FormatInfo.Format == Format.B8G8R8A8Unorm) + { + return TextureMatchQuality.FormatAlias; + } + else if (lhs.FormatInfo.Format == Format.D32FloatS8Uint && rhs.FormatInfo.Format == Format.R32G32Float) { return TextureMatchQuality.FormatAlias; } @@ -734,7 +739,8 @@ namespace Ryujinx.Graphics.Gpu.Image } return (lhsFormat.Format == Format.R8G8B8A8Unorm && rhsFormat.Format == Format.R32G32B32A32Float) || - (lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm); + (lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm) || + (lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R32Uint); } /// diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs index e45c36528..afa0b1cca 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs @@ -89,9 +89,9 @@ namespace Ryujinx.Graphics.Gpu.Image private MultiRange TextureRange => Storage.Range; /// - /// The views list from the storage texture. + /// The views array from the storage texture. /// - private List _views; + private Texture[] _views; private TextureGroupHandle[] _handles; private bool[] _loadNeeded; @@ -283,7 +283,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Discards all data for a given texture. - /// This clears all dirty flags, modified flags, and pending copies from other textures. + /// This clears all dirty flags and pending copies from other textures. /// /// The texture being discarded public void DiscardData(Texture texture) @@ -446,7 +446,7 @@ namespace Ryujinx.Graphics.Gpu.Image ReadOnlySpan data = dataSpan[(offset - spanBase)..]; - IMemoryOwner result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true); + MemoryOwner result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true); Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level); } @@ -646,7 +646,7 @@ namespace Ryujinx.Graphics.Gpu.Image } else { - _flushBuffer = _context.Renderer.CreateBuffer((int)Storage.Size, BufferAccess.FlushPersistent); + _flushBuffer = _context.Renderer.CreateBuffer((int)Storage.Size, BufferAccess.HostMemory); _flushBufferImported = false; } @@ -1075,7 +1075,7 @@ namespace Ryujinx.Graphics.Gpu.Image public void UpdateViews(List views, Texture texture) { // This is saved to calculate overlapping views for each handle. - _views = views; + _views = views.ToArray(); bool layerViews = _hasLayerViews; bool mipViews = _hasMipViews; @@ -1137,9 +1137,13 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Removes a view from the group, removing it from all overlap lists. /// + /// The views list of the storage texture /// View to remove from the group - public void RemoveView(Texture view) + public void RemoveView(List views, Texture view) { + // This is saved to calculate overlapping views for each handle. + _views = views.ToArray(); + int offset = FindOffset(view); foreach (TextureGroupHandle handle in _handles) @@ -1606,9 +1610,11 @@ namespace Ryujinx.Graphics.Gpu.Image Storage.SignalModifiedDirty(); - if (_views != null) + Texture[] views = _views; + + if (views != null) { - foreach (Texture texture in _views) + foreach (Texture texture in views) { texture.SignalModifiedDirty(); } @@ -1623,20 +1629,6 @@ namespace Ryujinx.Graphics.Gpu.Image /// The size of the flushing memory access public void FlushAction(TextureGroupHandle handle, ulong address, ulong size) { - // If the page size is larger than 4KB, we will have a lot of false positives for flushing. - // Let's avoid flushing textures that are unlikely to be read from CPU to improve performance - // on those platforms. - if (!_physicalMemory.Supports4KBPages && !Storage.Info.IsLinear && !_context.IsGpuThread()) - { - //return; - } - - // If size is zero, we have nothing to flush. - if (size == 0) - { - return; - } - // There is a small gap here where the action is removed but _actionRegistered is still 1. // In this case it will skip registering the action, but here we are already handling it, // so there shouldn't be any issue as it's the same handler for all actions. diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs index d345ec2db..860922d59 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs @@ -121,7 +121,7 @@ namespace Ryujinx.Graphics.Gpu.Image public TextureGroupHandle(TextureGroup group, int offset, ulong size, - List views, + IEnumerable views, int firstLayer, int firstLevel, int baseSlice, @@ -182,11 +182,10 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Discards all data for this handle. - /// This clears all dirty flags, modified flags, and pending copies from other handles. + /// This clears all dirty flags and pending copies from other handles. /// public void DiscardData() { - Modified = false; DeferredCopy = null; foreach (RegionHandle handle in Handles) @@ -202,8 +201,8 @@ namespace Ryujinx.Graphics.Gpu.Image /// Calculate a list of which views overlap this handle. /// /// The parent texture group, used to find a view's base CPU VA offset - /// The list of views to search for overlaps - public void RecalculateOverlaps(TextureGroup group, List views) + /// The views to search for overlaps + public void RecalculateOverlaps(TextureGroup group, IEnumerable views) { // Overlaps can be accessed from the memory tracking signal handler, so access must be atomic. lock (Overlaps) diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index 3bf0beefd..db2921468 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs @@ -15,6 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Image private readonly TextureBindingsManager _cpBindingsManager; private readonly TextureBindingsManager _gpBindingsManager; + private readonly TextureBindingsArrayCache _bindingsArrayCache; private readonly TexturePoolCache _texturePoolCache; private readonly SamplerPoolCache _samplerPoolCache; @@ -46,8 +47,9 @@ namespace Ryujinx.Graphics.Gpu.Image TexturePoolCache texturePoolCache = new(context); SamplerPoolCache samplerPoolCache = new(context); - _cpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, samplerPoolCache, isCompute: true); - _gpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, samplerPoolCache, isCompute: false); + _bindingsArrayCache = new TextureBindingsArrayCache(context, channel); + _cpBindingsManager = new TextureBindingsManager(context, channel, _bindingsArrayCache, texturePoolCache, samplerPoolCache, isCompute: true); + _gpBindingsManager = new TextureBindingsManager(context, channel, _bindingsArrayCache, texturePoolCache, samplerPoolCache, isCompute: false); _texturePoolCache = texturePoolCache; _samplerPoolCache = samplerPoolCache; @@ -360,15 +362,16 @@ namespace Ryujinx.Graphics.Gpu.Image /// Commits bindings on the graphics pipeline. /// /// Specialization state for the bound shader + /// True if there is a scale mismatch in the render targets, indicating they must be re-evaluated /// True if all bound textures match the current shader specialization state, false otherwise - public bool CommitGraphicsBindings(ShaderSpecializationState specState) + public bool CommitGraphicsBindings(ShaderSpecializationState specState, out bool scaleMismatch) { _texturePoolCache.Tick(); _samplerPoolCache.Tick(); bool result = _gpBindingsManager.CommitBindings(specState); - UpdateRenderTargets(); + scaleMismatch = UpdateRenderTargets(); return result; } @@ -383,7 +386,7 @@ namespace Ryujinx.Graphics.Gpu.Image { ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); - TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); + TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId, _bindingsArrayCache); return texturePool; } @@ -426,9 +429,12 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Update host framebuffer attachments based on currently bound render target buffers. /// - public void UpdateRenderTargets() + /// True if there is a scale mismatch in the render targets, indicating they must be re-evaluated + public bool UpdateRenderTargets() { bool anyChanged = false; + float expectedScale = RenderTargetScale; + bool scaleMismatch = false; Texture dsTexture = _rtDepthStencil; ITexture hostDsTexture = null; @@ -448,6 +454,11 @@ namespace Ryujinx.Graphics.Gpu.Image { _rtHostDs = hostDsTexture; anyChanged = true; + + if (dsTexture != null && dsTexture.ScaleFactor != expectedScale) + { + scaleMismatch = true; + } } for (int index = 0; index < _rtColors.Length; index++) @@ -470,6 +481,11 @@ namespace Ryujinx.Graphics.Gpu.Image { _rtHostColors[index] = hostTexture; anyChanged = true; + + if (texture != null && texture.ScaleFactor != expectedScale) + { + scaleMismatch = true; + } } } @@ -477,6 +493,8 @@ namespace Ryujinx.Graphics.Gpu.Image { _context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, _rtHostDs); } + + return scaleMismatch; } /// diff --git a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs index a4035577d..be7cb0b89 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs @@ -6,6 +6,7 @@ using Ryujinx.Memory.Range; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Numerics; using System.Threading; namespace Ryujinx.Graphics.Gpu.Image @@ -74,6 +75,76 @@ namespace Ryujinx.Graphics.Gpu.Image private readonly ConcurrentQueue _dereferenceQueue = new(); private TextureDescriptor _defaultDescriptor; + /// + /// List of textures that shares the same memory region, but have different formats. + /// + private class TextureAliasList + { + /// + /// Alias texture. + /// + /// Texture format + /// Texture + private readonly record struct Alias(Format Format, Texture Texture); + + /// + /// List of texture aliases. + /// + private readonly List _aliases; + + /// + /// Creates a new instance of the texture alias list. + /// + public TextureAliasList() + { + _aliases = new List(); + } + + /// + /// Adds a new texture alias. + /// + /// Alias format + /// Alias texture + public void Add(Format format, Texture texture) + { + _aliases.Add(new Alias(format, texture)); + texture.IncrementReferenceCount(); + } + + /// + /// Finds a texture with the requested format, or returns null if not found. + /// + /// Format to find + /// Texture with the requested format, or null if not found + public Texture Find(Format format) + { + foreach (var alias in _aliases) + { + if (alias.Format == format) + { + return alias.Texture; + } + } + + return null; + } + + /// + /// Removes all alias textures. + /// + public void Destroy() + { + foreach (var entry in _aliases) + { + entry.Texture.DecrementReferenceCount(); + } + + _aliases.Clear(); + } + } + + private readonly Dictionary _aliasLists; + /// /// Linked list node used on the texture pool cache. /// @@ -94,6 +165,7 @@ namespace Ryujinx.Graphics.Gpu.Image public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId) { _channel = channel; + _aliasLists = new Dictionary(); } /// @@ -114,14 +186,13 @@ namespace Ryujinx.Graphics.Gpu.Image if (texture == null) { - TextureInfo info = GetInfo(descriptor, out int layerSize); - // The dereference queue can put our texture back on the cache. if ((texture = ProcessDereferenceQueue(id)) != null) { return ref descriptor; } + TextureInfo info = GetInfo(descriptor, out int layerSize); texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize); // If this happens, then the texture address is invalid, we can't add it to the cache. @@ -156,6 +227,17 @@ namespace Ryujinx.Graphics.Gpu.Image /// ID of the texture. This is effectively a zero-based index /// The texture with the given ID public override Texture Get(int id) + { + return Get(id, srgbSampler: true); + } + + /// + /// Gets the texture with the given ID. + /// + /// ID of the texture. This is effectively a zero-based index + /// Whether the texture is being accessed with a sampler that has sRGB conversion enabled + /// The texture with the given ID + public Texture Get(int id, bool srgbSampler) { if ((uint)id >= Items.Length) { @@ -169,7 +251,7 @@ namespace Ryujinx.Graphics.Gpu.Image SynchronizeMemory(); } - GetInternal(id, out Texture texture); + GetForBinding(id, srgbSampler, out Texture texture); return texture; } @@ -181,9 +263,10 @@ namespace Ryujinx.Graphics.Gpu.Image /// This method assumes that the pool has been manually synchronized before doing binding. /// /// ID of the texture. This is effectively a zero-based index + /// Whether the texture is being accessed with a sampler that has sRGB conversion enabled /// The texture with the given ID /// The texture descriptor with the given ID - public ref readonly TextureDescriptor GetForBinding(int id, out Texture texture) + public ref readonly TextureDescriptor GetForBinding(int id, bool srgbSampler, out Texture texture) { if ((uint)id >= Items.Length) { @@ -193,9 +276,66 @@ namespace Ryujinx.Graphics.Gpu.Image // When getting for binding, assume the pool has already been synchronized. + if (!srgbSampler) + { + // If the sampler does not have the sRGB bit enabled, then the texture can't use a sRGB format. + ref readonly TextureDescriptor tempDescriptor = ref GetDescriptorRef(id); + + if (tempDescriptor.UnpackSrgb() && FormatTable.TryGetTextureFormat(tempDescriptor.UnpackFormat(), isSrgb: false, out FormatInfo formatInfo)) + { + // Get a view of the texture with the right format. + return ref GetForBinding(id, formatInfo, out texture); + } + } + return ref GetInternal(id, out texture); } + /// + /// Gets the texture descriptor and texture with the given ID. + /// + /// + /// This method assumes that the pool has been manually synchronized before doing binding. + /// + /// ID of the texture. This is effectively a zero-based index + /// Texture format information + /// The texture with the given ID + /// The texture descriptor with the given ID + public ref readonly TextureDescriptor GetForBinding(int id, FormatInfo formatInfo, out Texture texture) + { + if ((uint)id >= Items.Length) + { + texture = null; + return ref _defaultDescriptor; + } + + ref readonly TextureDescriptor descriptor = ref GetInternal(id, out texture); + + if (texture != null && formatInfo.Format != 0 && texture.Format != formatInfo.Format) + { + if (!_aliasLists.TryGetValue(texture, out TextureAliasList aliasList)) + { + _aliasLists.Add(texture, aliasList = new TextureAliasList()); + } + + texture = aliasList.Find(formatInfo.Format); + + if (texture == null) + { + TextureInfo info = GetInfo(descriptor, out int layerSize); + info = ChangeFormat(info, formatInfo); + texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize); + + if (texture != null) + { + aliasList.Add(formatInfo.Format, texture); + } + } + } + + return ref descriptor; + } + /// /// Checks if the pool was modified, and returns the last sequence number where a modification was detected. /// @@ -233,6 +373,7 @@ namespace Ryujinx.Graphics.Gpu.Image else { texture.DecrementReferenceCount(); + RemoveAliasList(texture); } } @@ -326,6 +467,8 @@ namespace Ryujinx.Graphics.Gpu.Image { texture.DecrementReferenceCount(); } + + RemoveAliasList(texture); } return null; @@ -368,6 +511,7 @@ namespace Ryujinx.Graphics.Gpu.Image if (Interlocked.Exchange(ref Items[id], null) != null) { texture.DecrementReferenceCount(this, id); + RemoveAliasList(texture); } } } @@ -490,6 +634,8 @@ namespace Ryujinx.Graphics.Gpu.Image levels = (maxLod - minLod) + 1; } + levels = ClampLevels(target, width, height, depthOrLayers, levels); + SwizzleComponent swizzleR = descriptor.UnpackSwizzleR().Convert(); SwizzleComponent swizzleG = descriptor.UnpackSwizzleG().Convert(); SwizzleComponent swizzleB = descriptor.UnpackSwizzleB().Convert(); @@ -540,6 +686,34 @@ namespace Ryujinx.Graphics.Gpu.Image swizzleA); } + /// + /// Clamps the amount of mipmap levels to the maximum allowed for the given texture dimensions. + /// + /// Number of texture dimensions (1D, 2D, 3D, Cube, etc) + /// Width of the texture + /// Height of the texture, ignored for 1D textures + /// Depth of the texture for 3D textures, otherwise ignored + /// Original amount of mipmap levels + /// Clamped mipmap levels + private static int ClampLevels(Target target, int width, int height, int depthOrLayers, int levels) + { + int maxSize = width; + + if (target != Target.Texture1D && + target != Target.Texture1DArray) + { + maxSize = Math.Max(maxSize, height); + } + + if (target == Target.Texture3D) + { + maxSize = Math.Max(maxSize, depthOrLayers); + } + + int maxLevels = BitOperations.Log2((uint)maxSize) + 1; + return Math.Min(levels, maxLevels); + } + /// /// Gets the texture depth-stencil mode, based on the swizzle components of each color channel. /// The depth-stencil mode is determined based on how the driver sets those parameters. @@ -591,6 +765,57 @@ namespace Ryujinx.Graphics.Gpu.Image component == SwizzleComponent.Green; } + /// + /// Changes the format on the texture information structure, and also adjusts the width for the new format if needed. + /// + /// Texture information + /// New format + /// Texture information with the new format + private static TextureInfo ChangeFormat(in TextureInfo info, FormatInfo dstFormat) + { + int width = info.Width; + + if (info.FormatInfo.BytesPerPixel != dstFormat.BytesPerPixel) + { + int stride = width * info.FormatInfo.BytesPerPixel; + width = stride / dstFormat.BytesPerPixel; + } + + return new TextureInfo( + info.GpuAddress, + width, + info.Height, + info.DepthOrLayers, + info.Levels, + info.SamplesInX, + info.SamplesInY, + info.Stride, + info.IsLinear, + info.GobBlocksInY, + info.GobBlocksInZ, + info.GobBlocksInTileX, + info.Target, + dstFormat, + info.DepthStencilMode, + info.SwizzleR, + info.SwizzleG, + info.SwizzleB, + info.SwizzleA); + } + + /// + /// Removes all aliases for a texture. + /// + /// Texture to have the aliases removed + private void RemoveAliasList(Texture texture) + { + if (_aliasLists.TryGetValue(texture, out TextureAliasList aliasList)) + { + _aliasLists.Remove(texture); + aliasList.Destroy(); + } + } + /// /// Decrements the reference count of the texture. /// This indicates that the texture pool is not using it anymore. @@ -598,7 +823,11 @@ namespace Ryujinx.Graphics.Gpu.Image /// The texture to be deleted protected override void Delete(Texture item) { - item?.DecrementReferenceCount(this); + if (item != null) + { + item.DecrementReferenceCount(this); + RemoveAliasList(item); + } } public override void Dispose() diff --git a/src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs b/src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs index adaacd915..55575c20c 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs @@ -5,9 +5,13 @@ using Ryujinx.Memory.Tracking; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; namespace Ryujinx.Graphics.Gpu.Memory { + delegate void BufferFlushAction(ulong address, ulong size, ulong syncNumber); + /// /// Buffer, used to store vertex and index data, uniform and storage buffers, and others. /// @@ -21,7 +25,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Host buffer handle. /// - public BufferHandle Handle { get; } + public BufferHandle Handle { get; private set; } /// /// Start address of the buffer in guest memory. @@ -58,6 +62,17 @@ namespace Ryujinx.Graphics.Gpu.Memory /// private BufferModifiedRangeList _modifiedRanges = null; + /// + /// A structure that is used to flush buffer data back to a host mapped buffer for cached readback. + /// Only used if the buffer data is explicitly owned by device local memory. + /// + private BufferPreFlush _preFlush = null; + + /// + /// Usage tracking state that determines what type of backing the buffer should use. + /// + public BufferBackingState BackingState; + private readonly MultiRegionHandle _memoryTrackingGranular; private readonly RegionHandle _memoryTracking; @@ -65,6 +80,9 @@ namespace Ryujinx.Graphics.Gpu.Memory private readonly Action _loadDelegate; private readonly Action _modifiedDelegate; + private HashSet _virtualDependencies; + private readonly ReaderWriterLockSlim _virtualDependenciesLock; + private int _sequenceNumber; private readonly bool _useGranular; @@ -82,6 +100,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Physical memory where the buffer is mapped /// Start address of the buffer /// Size of the buffer in bytes + /// The type of usage that created the buffer /// Indicates if the buffer can be used in a sparse buffer mapping /// Buffers which this buffer contains, and will inherit tracking handles from public Buffer( @@ -89,6 +108,7 @@ namespace Ryujinx.Graphics.Gpu.Memory PhysicalMemory physicalMemory, ulong address, ulong size, + BufferStage stage, bool sparseCompatible, IEnumerable baseBuffers = null) { @@ -98,9 +118,11 @@ namespace Ryujinx.Graphics.Gpu.Memory Size = size; SparseCompatible = sparseCompatible; - BufferAccess access = sparseCompatible ? BufferAccess.SparseCompatible : BufferAccess.Default; + BackingState = new BufferBackingState(_context, this, stage, baseBuffers); - Handle = context.Renderer.CreateBuffer((int)size, access, baseBuffers?.MaxBy(x => x.Size).Handle ?? BufferHandle.Null); + BufferAccess access = BackingState.SwitchAccess(this); + + Handle = context.Renderer.CreateBuffer((int)size, access); _useGranular = size > GranularBufferThreshold; @@ -123,13 +145,13 @@ namespace Ryujinx.Graphics.Gpu.Memory if (_useGranular) { - _memoryTrackingGranular = physicalMemory.BeginGranularTracking(address, size, ResourceKind.Buffer, baseHandles); + _memoryTrackingGranular = physicalMemory.BeginGranularTracking(address, size, ResourceKind.Buffer, RegionFlags.UnalignedAccess, baseHandles); _memoryTrackingGranular.RegisterPreciseAction(address, size, PreciseAction); } else { - _memoryTracking = physicalMemory.BeginTracking(address, size, ResourceKind.Buffer); + _memoryTracking = physicalMemory.BeginTracking(address, size, ResourceKind.Buffer, RegionFlags.UnalignedAccess); if (baseHandles != null) { @@ -152,6 +174,31 @@ namespace Ryujinx.Graphics.Gpu.Memory _externalFlushDelegate = new RegionSignal(ExternalFlush); _loadDelegate = new Action(LoadRegion); _modifiedDelegate = new Action(RegionModified); + + _virtualDependenciesLock = new ReaderWriterLockSlim(); + } + + /// + /// Recreates the backing buffer based on the desired access type + /// reported by the backing state struct. + /// + private void ChangeBacking() + { + BufferAccess access = BackingState.SwitchAccess(this); + + BufferHandle newHandle = _context.Renderer.CreateBuffer((int)Size, access); + + _context.Renderer.Pipeline.CopyBuffer(Handle, newHandle, 0, 0, (int)Size); + + _modifiedRanges?.SelfMigration(); + + // If swtiching from device local to host mapped, pre-flushing data no longer makes sense. + // This is set to null and disposed when the migration fully completes. + _preFlush = null; + + Handle = newHandle; + + _physicalMemory.BufferCache.BufferBackingChanged(this); } /// @@ -220,6 +267,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Start address of the range to synchronize /// Size in bytes of the range to synchronize + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SynchronizeMemory(ulong address, ulong size) { if (_useGranular) @@ -238,7 +286,9 @@ namespace Ryujinx.Graphics.Gpu.Memory } else { + BackingState.RecordSet(); _context.Renderer.SetBufferData(Handle, 0, _physicalMemory.GetSpan(Address, (int)Size)); + CopyToDependantVirtualBuffers(); } _sequenceNumber = _context.SequenceNumber; @@ -274,15 +324,35 @@ namespace Ryujinx.Graphics.Gpu.Memory _modifiedRanges ??= new BufferModifiedRangeList(_context, this, Flush); } + /// + /// Checks if a backing change is deemed necessary from the given usage. + /// If it is, queues a backing change to happen on the next sync action. + /// + /// Buffer stage that can change backing type + private void TryQueueBackingChange(BufferStage stage) + { + if (BackingState.ShouldChangeBacking(stage)) + { + if (!_syncActionRegistered) + { + _context.RegisterSyncAction(this); + _syncActionRegistered = true; + } + } + } + /// /// Signal that the given region of the buffer has been modified. /// /// The start address of the modified region /// The size of the modified region - public void SignalModified(ulong address, ulong size) + /// Buffer stage that triggered the modification + public void SignalModified(ulong address, ulong size, BufferStage stage) { EnsureRangeList(); + TryQueueBackingChange(stage); + _modifiedRanges.SignalModified(address, size); if (!_syncActionRegistered) @@ -302,6 +372,37 @@ namespace Ryujinx.Graphics.Gpu.Memory _modifiedRanges?.Clear(address, size); } + /// + /// Action to be performed immediately before sync is created. + /// This will copy any buffer ranges designated for pre-flushing. + /// + /// True if the action is a guest syncpoint + public void SyncPreAction(bool syncpoint) + { + if (_referenceCount == 0) + { + return; + } + + if (BackingState.ShouldChangeBacking()) + { + ChangeBacking(); + } + + if (BackingState.IsDeviceLocal) + { + _preFlush ??= new BufferPreFlush(_context, this, FlushImpl); + + if (_preFlush.ShouldCopy) + { + _modifiedRanges?.GetRangesAtSync(Address, Size, _context.SyncNumber, (address, size) => + { + _preFlush.CopyModified(address, size); + }); + } + } + } + /// /// Action to be performed when a syncpoint is reached after modification. /// This will register read/write tracking to flush the buffer from GPU when its memory is used. @@ -457,9 +558,13 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Size of the modified region private void LoadRegion(ulong mAddress, ulong mSize) { + BackingState.RecordSet(); + int offset = (int)(mAddress - Address); _context.Renderer.SetBufferData(Handle, offset, _physicalMemory.GetSpan(mAddress, (int)mSize)); + + CopyToDependantVirtualBuffers(mAddress, mSize); } /// @@ -520,23 +625,90 @@ namespace Ryujinx.Graphics.Gpu.Memory /// The offset of the destination buffer to copy into public void CopyTo(Buffer destination, int dstOffset) { + CopyFromDependantVirtualBuffers(); _context.Renderer.Pipeline.CopyBuffer(Handle, destination.Handle, 0, dstOffset, (int)Size); } + /// + /// Flushes a range of the buffer. + /// This writes the range data back into guest memory. + /// + /// Buffer handle to flush data from + /// Start address of the range + /// Size in bytes of the range + private void FlushImpl(BufferHandle handle, ulong address, ulong size) + { + int offset = (int)(address - Address); + + using PinnedSpan data = _context.Renderer.GetBufferData(handle, offset, (int)size); + + // TODO: When write tracking shaders, they will need to be aware of changes in overlapping buffers. + _physicalMemory.WriteUntracked(address, CopyFromDependantVirtualBuffers(data.Get(), address, size)); + } + /// /// Flushes a range of the buffer. /// This writes the range data back into guest memory. /// /// Start address of the range /// Size in bytes of the range - public void Flush(ulong address, ulong size) + private void FlushImpl(ulong address, ulong size) { - int offset = (int)(address - Address); + FlushImpl(Handle, address, size); + } - using PinnedSpan data = _context.Renderer.GetBufferData(Handle, offset, (int)size); + /// + /// Flushes a range of the buffer from the most optimal source. + /// This writes the range data back into guest memory. + /// + /// Start address of the range + /// Size in bytes of the range + /// Sync number waited for before flushing the data + public void Flush(ulong address, ulong size, ulong syncNumber) + { + BackingState.RecordFlush(); - // TODO: When write tracking shaders, they will need to be aware of changes in overlapping buffers. - _physicalMemory.WriteUntracked(address, data.Get()); + BufferPreFlush preFlush = _preFlush; + + if (preFlush != null) + { + preFlush.FlushWithAction(address, size, syncNumber); + } + else + { + FlushImpl(address, size); + } + } + /// + /// Gets an action that disposes the backing buffer using its current handle. + /// Useful for deleting an old copy of the buffer after the handle changes. + /// + /// An action that flushes data from the specified range, using the buffer handle at the time the method is generated + public Action GetSnapshotDisposeAction() + { + BufferHandle handle = Handle; + BufferPreFlush preFlush = _preFlush; + + return () => + { + _context.Renderer.DeleteBuffer(handle); + preFlush?.Dispose(); + }; + } + + /// + /// Gets an action that flushes a range of the buffer using its current handle. + /// Useful for flushing data from old copies of the buffer after the handle changes. + /// + /// An action that flushes data from the specified range, using the buffer handle at the time the method is generated + public BufferFlushAction GetSnapshotFlushAction() + { + BufferHandle handle = Handle; + + return (ulong address, ulong size, ulong _) => + { + FlushImpl(handle, address, size); + }; } /// @@ -629,6 +801,207 @@ namespace Ryujinx.Graphics.Gpu.Memory UnmappedSequence++; } + /// + /// Adds a virtual buffer dependency, indicating that a virtual buffer depends on data from this buffer. + /// + /// Dependant virtual buffer + public void AddVirtualDependency(MultiRangeBuffer virtualBuffer) + { + _virtualDependenciesLock.EnterWriteLock(); + + try + { + (_virtualDependencies ??= new()).Add(virtualBuffer); + } + finally + { + _virtualDependenciesLock.ExitWriteLock(); + } + } + + /// + /// Removes a virtual buffer dependency, indicating that a virtual buffer no longer depends on data from this buffer. + /// + /// Dependant virtual buffer + public void RemoveVirtualDependency(MultiRangeBuffer virtualBuffer) + { + _virtualDependenciesLock.EnterWriteLock(); + + try + { + if (_virtualDependencies != null) + { + _virtualDependencies.Remove(virtualBuffer); + + if (_virtualDependencies.Count == 0) + { + _virtualDependencies = null; + } + } + } + finally + { + _virtualDependenciesLock.ExitWriteLock(); + } + } + + /// + /// Copies the buffer data to all virtual buffers that depends on it. + /// + public void CopyToDependantVirtualBuffers() + { + CopyToDependantVirtualBuffers(Address, Size); + } + + /// + /// Copies the buffer data inside the specifide range to all virtual buffers that depends on it. + /// + /// Address of the range + /// Size of the range in bytes + public void CopyToDependantVirtualBuffers(ulong address, ulong size) + { + if (_virtualDependencies != null) + { + foreach (var virtualBuffer in _virtualDependencies) + { + CopyToDependantVirtualBuffer(virtualBuffer, address, size); + } + } + } + + /// + /// Copies all modified ranges from all virtual buffers back into this buffer. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyFromDependantVirtualBuffers() + { + if (_virtualDependencies != null) + { + CopyFromDependantVirtualBuffersImpl(); + } + } + + /// + /// Copies all modified ranges from all virtual buffers back into this buffer. + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private void CopyFromDependantVirtualBuffersImpl() + { + foreach (var virtualBuffer in _virtualDependencies.OrderBy(x => x.ModificationSequenceNumber)) + { + virtualBuffer.ConsumeModifiedRegion(this, (mAddress, mSize) => + { + // Get offset inside both this and the virtual buffer. + // Note that sometimes there is no right answer for the virtual offset, + // as the same physical range might be mapped multiple times inside a virtual buffer. + // We just assume it does not happen in practice as it can only be implemented correctly + // when the host has support for proper sparse mapping. + + ulong mEndAddress = mAddress + mSize; + mAddress = Math.Max(mAddress, Address); + mSize = Math.Min(mEndAddress, EndAddress) - mAddress; + + int physicalOffset = (int)(mAddress - Address); + int virtualOffset = virtualBuffer.Range.FindOffset(new(mAddress, mSize)); + + _context.Renderer.Pipeline.CopyBuffer(virtualBuffer.Handle, Handle, virtualOffset, physicalOffset, (int)mSize); + }); + } + } + + /// + /// Copies all overlapping modified ranges from all virtual buffers back into this buffer, and returns an updated span with the data. + /// + /// Span where the unmodified data will be taken from for the output + /// Address of the region to copy + /// Size of the region to copy in bytes + /// A span with , and the data for all modified ranges if any + private ReadOnlySpan CopyFromDependantVirtualBuffers(ReadOnlySpan dataSpan, ulong address, ulong size) + { + _virtualDependenciesLock.EnterReadLock(); + + try + { + if (_virtualDependencies != null) + { + byte[] storage = dataSpan.ToArray(); + + foreach (var virtualBuffer in _virtualDependencies.OrderBy(x => x.ModificationSequenceNumber)) + { + virtualBuffer.ConsumeModifiedRegion(address, size, (mAddress, mSize) => + { + // Get offset inside both this and the virtual buffer. + // Note that sometimes there is no right answer for the virtual offset, + // as the same physical range might be mapped multiple times inside a virtual buffer. + // We just assume it does not happen in practice as it can only be implemented correctly + // when the host has support for proper sparse mapping. + + ulong mEndAddress = mAddress + mSize; + mAddress = Math.Max(mAddress, address); + mSize = Math.Min(mEndAddress, address + size) - mAddress; + + int physicalOffset = (int)(mAddress - Address); + int virtualOffset = virtualBuffer.Range.FindOffset(new(mAddress, mSize)); + + _context.Renderer.Pipeline.CopyBuffer(virtualBuffer.Handle, Handle, virtualOffset, physicalOffset, (int)size); + virtualBuffer.GetData(storage.AsSpan().Slice((int)(mAddress - address), (int)mSize), virtualOffset, (int)mSize); + }); + } + + dataSpan = storage; + } + } + finally + { + _virtualDependenciesLock.ExitReadLock(); + } + + return dataSpan; + } + + /// + /// Copies the buffer data to the specified virtual buffer. + /// + /// Virtual buffer to copy the data into + public void CopyToDependantVirtualBuffer(MultiRangeBuffer virtualBuffer) + { + CopyToDependantVirtualBuffer(virtualBuffer, Address, Size); + } + + /// + /// Copies the buffer data inside the given range to the specified virtual buffer. + /// + /// Virtual buffer to copy the data into + /// Address of the range + /// Size of the range in bytes + public void CopyToDependantVirtualBuffer(MultiRangeBuffer virtualBuffer, ulong address, ulong size) + { + // Broadcast data to all ranges of the virtual buffer that are contained inside this buffer. + + ulong lastOffset = 0; + + while (virtualBuffer.TryGetPhysicalOffset(this, lastOffset, out ulong srcOffset, out ulong dstOffset, out ulong copySize)) + { + ulong innerOffset = address - Address; + ulong innerEndOffset = (address + size) - Address; + + lastOffset = dstOffset + copySize; + + // Clamp range to the specified range. + ulong copySrcOffset = Math.Max(srcOffset, innerOffset); + ulong copySrcEndOffset = Math.Min(innerEndOffset, srcOffset + copySize); + + if (copySrcEndOffset > copySrcOffset) + { + copySize = copySrcEndOffset - copySrcOffset; + dstOffset += copySrcOffset - srcOffset; + srcOffset = copySrcOffset; + + _context.Renderer.Pipeline.CopyBuffer(Handle, virtualBuffer.Handle, (int)srcOffset, (int)dstOffset, (int)copySize); + } + } + } + /// /// Increments the buffer reference count. /// @@ -656,6 +1029,8 @@ namespace Ryujinx.Graphics.Gpu.Memory _modifiedRanges?.Clear(); _context.Renderer.DeleteBuffer(Handle); + _preFlush?.Dispose(); + _preFlush = null; UnmappedSequence++; } diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferBackingState.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferBackingState.cs new file mode 100644 index 000000000..3f65131e6 --- /dev/null +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferBackingState.cs @@ -0,0 +1,294 @@ +using Ryujinx.Graphics.GAL; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Gpu.Memory +{ + /// + /// Type of backing memory. + /// In ascending order of priority when merging multiple buffer backing states. + /// + internal enum BufferBackingType + { + HostMemory, + DeviceMemory, + DeviceMemoryWithFlush + } + + /// + /// Keeps track of buffer usage to decide what memory heap that buffer memory is placed on. + /// Dedicated GPUs prefer certain types of resources to be device local, + /// and if we need data to be read back, we might prefer that they're in host memory. + /// + /// The measurements recorded here compare to a set of heruristics (thresholds and conditions) + /// that appear to produce good performance in most software. + /// + internal struct BufferBackingState + { + private const int DeviceLocalSizeThreshold = 256 * 1024; // 256kb + + private const int SetCountThreshold = 100; + private const int WriteCountThreshold = 50; + private const int FlushCountThreshold = 5; + private const int DeviceLocalForceExpiry = 100; + + public readonly bool IsDeviceLocal => _activeType != BufferBackingType.HostMemory; + + private readonly SystemMemoryType _systemMemoryType; + private BufferBackingType _activeType; + private BufferBackingType _desiredType; + + private bool _canSwap; + + private int _setCount; + private int _writeCount; + private int _flushCount; + private int _flushTemp; + private int _lastFlushWrite; + private int _deviceLocalForceCount; + + private readonly int _size; + + /// + /// Initialize the buffer backing state for a given parent buffer. + /// + /// GPU context + /// Parent buffer + /// Initial buffer stage + /// Buffers to inherit state from + public BufferBackingState(GpuContext context, Buffer parent, BufferStage stage, IEnumerable baseBuffers = null) + { + _size = (int)parent.Size; + _systemMemoryType = context.Capabilities.MemoryType; + + // Backend managed is always auto, unified memory is always host. + _desiredType = BufferBackingType.HostMemory; + _canSwap = _systemMemoryType != SystemMemoryType.BackendManaged && _systemMemoryType != SystemMemoryType.UnifiedMemory; + + if (_canSwap) + { + // Might want to start certain buffers as being device local, + // and the usage might also lock those buffers into being device local. + + BufferStage storageFlags = stage & BufferStage.StorageMask; + + if (parent.Size > DeviceLocalSizeThreshold && baseBuffers == null) + { + _desiredType = BufferBackingType.DeviceMemory; + } + + if (storageFlags != 0) + { + // Storage buffer bindings may require special treatment. + + var rawStage = stage & BufferStage.StageMask; + + if (rawStage == BufferStage.Fragment) + { + // Fragment read should start device local. + + _desiredType = BufferBackingType.DeviceMemory; + + if (storageFlags != BufferStage.StorageRead) + { + // Fragment write should stay device local until the use doesn't happen anymore. + + _deviceLocalForceCount = DeviceLocalForceExpiry; + } + } + + // TODO: Might be nice to force atomic access to be device local for any stage. + } + + if (baseBuffers != null) + { + foreach (Buffer buffer in baseBuffers) + { + CombineState(buffer.BackingState); + } + } + } + } + + /// + /// Combine buffer backing types, selecting the one with highest priority. + /// + /// First buffer backing type + /// Second buffer backing type + /// Combined buffer backing type + private static BufferBackingType CombineTypes(BufferBackingType left, BufferBackingType right) + { + return (BufferBackingType)Math.Max((int)left, (int)right); + } + + /// + /// Combine the state from the given buffer backing state with this one, + /// so that the state isn't lost when migrating buffers. + /// + /// Buffer state to combine into this state + private void CombineState(BufferBackingState oldState) + { + _setCount += oldState._setCount; + _writeCount += oldState._writeCount; + _flushCount += oldState._flushCount; + _flushTemp += oldState._flushTemp; + _lastFlushWrite = -1; + _deviceLocalForceCount = Math.Max(_deviceLocalForceCount, oldState._deviceLocalForceCount); + + _canSwap &= oldState._canSwap; + + _desiredType = CombineTypes(_desiredType, oldState._desiredType); + } + + /// + /// Get the buffer access for the desired backing type, and record that type as now being active. + /// + /// Parent buffer + /// Buffer access + public BufferAccess SwitchAccess(Buffer parent) + { + BufferAccess access = parent.SparseCompatible ? BufferAccess.SparseCompatible : BufferAccess.Default; + + bool isBackendManaged = _systemMemoryType == SystemMemoryType.BackendManaged; + + if (!isBackendManaged) + { + switch (_desiredType) + { + case BufferBackingType.HostMemory: + access |= BufferAccess.HostMemory; + break; + case BufferBackingType.DeviceMemory: + access |= BufferAccess.DeviceMemory; + break; + case BufferBackingType.DeviceMemoryWithFlush: + access |= BufferAccess.DeviceMemoryMapped; + break; + } + } + + _activeType = _desiredType; + + return access; + } + + /// + /// Record when data has been uploaded to the buffer. + /// + public void RecordSet() + { + _setCount++; + + ConsiderUseCounts(); + } + + /// + /// Record when data has been flushed from the buffer. + /// + public void RecordFlush() + { + if (_lastFlushWrite != _writeCount) + { + // If it's on the same page as the last flush, ignore it. + _lastFlushWrite = _writeCount; + _flushCount++; + } + } + + /// + /// Determine if the buffer backing should be changed. + /// + /// True if the desired backing type is different from the current type + public readonly bool ShouldChangeBacking() + { + return _desiredType != _activeType; + } + + /// + /// Determine if the buffer backing should be changed, considering a new use with the given buffer stage. + /// + /// Buffer stage for the use + /// True if the desired backing type is different from the current type + public bool ShouldChangeBacking(BufferStage stage) + { + if (!_canSwap) + { + return false; + } + + BufferStage storageFlags = stage & BufferStage.StorageMask; + + if (storageFlags != 0) + { + if (storageFlags != BufferStage.StorageRead) + { + // Storage write. + _writeCount++; + + var rawStage = stage & BufferStage.StageMask; + + if (rawStage == BufferStage.Fragment) + { + // Switch to device memory, swap back only if this use disappears. + + _desiredType = CombineTypes(_desiredType, BufferBackingType.DeviceMemory); + _deviceLocalForceCount = DeviceLocalForceExpiry; + + // TODO: Might be nice to force atomic access to be device local for any stage. + } + } + + ConsiderUseCounts(); + } + + return _desiredType != _activeType; + } + + /// + /// Evaluate the current counts to determine what the buffer's desired backing type is. + /// This method depends on heuristics devised by testing a variety of software. + /// + private void ConsiderUseCounts() + { + if (_canSwap) + { + if (_writeCount >= WriteCountThreshold || _setCount >= SetCountThreshold || _flushCount >= FlushCountThreshold) + { + if (_deviceLocalForceCount > 0 && --_deviceLocalForceCount != 0) + { + // Some buffer usage demanded that the buffer stay device local. + // The desired type was selected when this counter was set. + } + else if (_flushCount > 0 || _flushTemp-- > 0) + { + // Buffers that flush should ideally be mapped in host address space for easy copies. + // If the buffer is large it will do better on GPU memory, as there will be more writes than data flushes (typically individual pages). + // If it is small, then it's likely most of the buffer will be flushed so we want it on host memory, as access is cached. + _desiredType = _size > DeviceLocalSizeThreshold ? BufferBackingType.DeviceMemoryWithFlush : BufferBackingType.HostMemory; + } + else if (_writeCount >= WriteCountThreshold) + { + // Buffers that are written often should ideally be in the device local heap. (Storage buffers) + _desiredType = BufferBackingType.DeviceMemory; + } + else if (_setCount > SetCountThreshold) + { + // Buffers that have their data set often should ideally be host mapped. (Constant buffers) + _desiredType = BufferBackingType.HostMemory; + } + + // It's harder for a buffer that is flushed to revert to another type of mapping. + if (_flushCount > 0) + { + _flushTemp = 1000; + } + + _lastFlushWrite = -1; + _flushCount = 0; + _writeCount = 0; + _setCount = 0; + } + } + } + } +} diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs index aed3268ae..cf783ef2f 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs @@ -1,12 +1,13 @@ using Ryujinx.Graphics.Shader; using Ryujinx.Memory.Range; +using System; namespace Ryujinx.Graphics.Gpu.Memory { /// /// Memory range used for buffers. /// - readonly struct BufferBounds + readonly struct BufferBounds : IEquatable { /// /// Physical memory ranges where the buffer is mapped. @@ -33,5 +34,25 @@ namespace Ryujinx.Graphics.Gpu.Memory Range = range; Flags = flags; } + + public override bool Equals(object obj) + { + return obj is BufferBounds bounds && Equals(bounds); + } + + public bool Equals(BufferBounds bounds) + { + return Range == bounds.Range && Flags == bounds.Flags; + } + + public bool Equals(ref BufferBounds bounds) + { + return Range == bounds.Range && Flags == bounds.Flags; + } + + public override int GetHashCode() + { + return HashCode.Combine(Range, Flags); + } } } diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs index bd9aa39c8..66d2cdb62 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs @@ -3,6 +3,7 @@ using Ryujinx.Memory.Range; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; namespace Ryujinx.Graphics.Gpu.Memory { @@ -46,6 +47,7 @@ namespace Ryujinx.Graphics.Gpu.Memory private readonly Dictionary _dirtyCache; private readonly Dictionary _modifiedCache; private bool _pruneCaches; + private int _virtualModifiedSequenceNumber; public event Action NotifyBuffersModified; @@ -105,8 +107,9 @@ namespace Ryujinx.Graphics.Gpu.Memory /// GPU memory manager where the buffer is mapped /// Start GPU virtual address of the buffer /// Size in bytes of the buffer + /// The type of usage that created the buffer /// Contiguous physical range of the buffer, after address translation - public MultiRange TranslateAndCreateBuffer(MemoryManager memoryManager, ulong gpuVa, ulong size) + public MultiRange TranslateAndCreateBuffer(MemoryManager memoryManager, ulong gpuVa, ulong size, BufferStage stage) { if (gpuVa == 0) { @@ -117,7 +120,7 @@ namespace Ryujinx.Graphics.Gpu.Memory if (address != MemoryManager.PteUnmapped) { - CreateBuffer(address, size); + CreateBuffer(address, size, stage); } return new MultiRange(address, size); @@ -125,31 +128,75 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Performs address translation of the GPU virtual address, and creates - /// new buffers, if needed, for the specified range. + /// new physical and virtual buffers, if needed, for the specified range. /// /// GPU memory manager where the buffer is mapped /// Start GPU virtual address of the buffer /// Size in bytes of the buffer + /// The type of usage that created the buffer /// Physical ranges of the buffer, after address translation - public MultiRange TranslateAndCreateMultiBuffers(MemoryManager memoryManager, ulong gpuVa, ulong size) + public MultiRange TranslateAndCreateMultiBuffers(MemoryManager memoryManager, ulong gpuVa, ulong size, BufferStage stage) { if (gpuVa == 0) { return new MultiRange(MemoryManager.PteUnmapped, size); } - bool supportsSparse = _context.Capabilities.SupportsSparseBuffer; - // Fast path not taken for non-contiguous ranges, // since multi-range buffers are not coalesced, so a buffer that covers // the entire cached range might not actually exist. - if (memoryManager.VirtualBufferCache.TryGetOrAddRange(gpuVa, size, supportsSparse, out MultiRange range) && + if (memoryManager.VirtualRangeCache.TryGetOrAddRange(gpuVa, size, out MultiRange range) && range.Count == 1) { return range; } - CreateBuffer(range); + CreateBuffer(range, stage); + + return range; + } + + /// + /// Performs address translation of the GPU virtual address, and creates + /// new physical buffers, if needed, for the specified range. + /// + /// GPU memory manager where the buffer is mapped + /// Start GPU virtual address of the buffer + /// Size in bytes of the buffer + /// The type of usage that created the buffer + /// Physical ranges of the buffer, after address translation + public MultiRange TranslateAndCreateMultiBuffersPhysicalOnly(MemoryManager memoryManager, ulong gpuVa, ulong size, BufferStage stage) + { + if (gpuVa == 0) + { + return new MultiRange(MemoryManager.PteUnmapped, size); + } + + // Fast path not taken for non-contiguous ranges, + // since multi-range buffers are not coalesced, so a buffer that covers + // the entire cached range might not actually exist. + if (memoryManager.VirtualRangeCache.TryGetOrAddRange(gpuVa, size, out MultiRange range) && + range.Count == 1) + { + return range; + } + + for (int i = 0; i < range.Count; i++) + { + MemoryRange subRange = range.GetSubRange(i); + + if (subRange.Address != MemoryManager.PteUnmapped) + { + if (range.Count > 1) + { + CreateBuffer(subRange.Address, subRange.Size, stage, SparseBufferAlignmentSize); + } + else + { + CreateBuffer(subRange.Address, subRange.Size, stage); + } + } + } return range; } @@ -159,11 +206,12 @@ namespace Ryujinx.Graphics.Gpu.Memory /// This can be used to ensure the existance of a buffer. /// /// Physical ranges of memory where the buffer data is located - public void CreateBuffer(MultiRange range) + /// The type of usage that created the buffer + public void CreateBuffer(MultiRange range, BufferStage stage) { if (range.Count > 1) { - CreateMultiRangeBuffer(range); + CreateMultiRangeBuffer(range, stage); } else { @@ -171,7 +219,7 @@ namespace Ryujinx.Graphics.Gpu.Memory if (subRange.Address != MemoryManager.PteUnmapped) { - CreateBuffer(subRange.Address, subRange.Size); + CreateBuffer(subRange.Address, subRange.Size, stage); } } } @@ -182,7 +230,8 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Address of the buffer in memory /// Size of the buffer in bytes - public void CreateBuffer(ulong address, ulong size) + /// The type of usage that created the buffer + public void CreateBuffer(ulong address, ulong size, BufferStage stage) { ulong endAddress = address + size; @@ -195,7 +244,7 @@ namespace Ryujinx.Graphics.Gpu.Memory alignedEndAddress += BufferAlignmentSize; } - CreateBufferAligned(alignedAddress, alignedEndAddress - alignedAddress); + CreateBufferAligned(alignedAddress, alignedEndAddress - alignedAddress, stage); } /// @@ -204,8 +253,9 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Address of the buffer in memory /// Size of the buffer in bytes + /// The type of usage that created the buffer /// Alignment of the start address of the buffer in bytes - public void CreateBuffer(ulong address, ulong size, ulong alignment) + public void CreateBuffer(ulong address, ulong size, BufferStage stage, ulong alignment) { ulong alignmentMask = alignment - 1; ulong pageAlignmentMask = BufferAlignmentMask; @@ -220,7 +270,7 @@ namespace Ryujinx.Graphics.Gpu.Memory alignedEndAddress += pageAlignmentMask; } - CreateBufferAligned(alignedAddress, alignedEndAddress - alignedAddress, alignment); + CreateBufferAligned(alignedAddress, alignedEndAddress - alignedAddress, stage, alignment); } /// @@ -228,7 +278,8 @@ namespace Ryujinx.Graphics.Gpu.Memory /// if it does not exist yet. /// /// Physical ranges of memory - private void CreateMultiRangeBuffer(MultiRange range) + /// The type of usage that created the buffer + private void CreateMultiRangeBuffer(MultiRange range, BufferStage stage) { // Ensure all non-contiguous buffer we might use are sparse aligned. for (int i = 0; i < range.Count; i++) @@ -237,7 +288,7 @@ namespace Ryujinx.Graphics.Gpu.Memory if (subRange.Address != MemoryManager.PteUnmapped) { - CreateBuffer(subRange.Address, subRange.Size, SparseBufferAlignmentSize); + CreateBuffer(subRange.Address, subRange.Size, stage, SparseBufferAlignmentSize); } } @@ -263,41 +314,108 @@ namespace Ryujinx.Graphics.Gpu.Memory } } - BufferRange[] storages = new BufferRange[range.Count]; + MultiRangeBuffer multiRangeBuffer; + MemoryRange[] alignedSubRanges = new MemoryRange[range.Count]; ulong alignmentMask = SparseBufferAlignmentSize - 1; - for (int i = 0; i < range.Count; i++) + if (_context.Capabilities.SupportsSparseBuffer) { - MemoryRange subRange = range.GetSubRange(i); + BufferRange[] storages = new BufferRange[range.Count]; + + for (int i = 0; i < range.Count; i++) + { + MemoryRange subRange = range.GetSubRange(i); + + if (subRange.Address != MemoryManager.PteUnmapped) + { + ulong endAddress = subRange.Address + subRange.Size; + + ulong alignedAddress = subRange.Address & ~alignmentMask; + ulong alignedEndAddress = (endAddress + alignmentMask) & ~alignmentMask; + ulong alignedSize = alignedEndAddress - alignedAddress; + + Buffer buffer = _buffers.FindFirstOverlap(alignedAddress, alignedSize); + BufferRange bufferRange = buffer.GetRange(alignedAddress, alignedSize, false); + + alignedSubRanges[i] = new MemoryRange(alignedAddress, alignedSize); + storages[i] = bufferRange; + } + else + { + ulong alignedSize = (subRange.Size + alignmentMask) & ~alignmentMask; + + alignedSubRanges[i] = new MemoryRange(MemoryManager.PteUnmapped, alignedSize); + storages[i] = new BufferRange(BufferHandle.Null, 0, (int)alignedSize); + } + } + + multiRangeBuffer = new(_context, new MultiRange(alignedSubRanges), storages); + } + else + { + for (int i = 0; i < range.Count; i++) + { + MemoryRange subRange = range.GetSubRange(i); + + if (subRange.Address != MemoryManager.PteUnmapped) + { + ulong endAddress = subRange.Address + subRange.Size; + + ulong alignedAddress = subRange.Address & ~alignmentMask; + ulong alignedEndAddress = (endAddress + alignmentMask) & ~alignmentMask; + ulong alignedSize = alignedEndAddress - alignedAddress; + + alignedSubRanges[i] = new MemoryRange(alignedAddress, alignedSize); + } + else + { + ulong alignedSize = (subRange.Size + alignmentMask) & ~alignmentMask; + + alignedSubRanges[i] = new MemoryRange(MemoryManager.PteUnmapped, alignedSize); + } + } + + multiRangeBuffer = new(_context, new MultiRange(alignedSubRanges)); + + UpdateVirtualBufferDependencies(multiRangeBuffer); + } + + _multiRangeBuffers.Add(multiRangeBuffer); + } + + /// + /// Adds two-way dependencies to all physical buffers contained within a given virtual buffer. + /// + /// Virtual buffer to have dependencies added + private void UpdateVirtualBufferDependencies(MultiRangeBuffer virtualBuffer) + { + virtualBuffer.ClearPhysicalDependencies(); + + ulong dstOffset = 0; + + HashSet physicalBuffers = new(); + + for (int i = 0; i < virtualBuffer.Range.Count; i++) + { + MemoryRange subRange = virtualBuffer.Range.GetSubRange(i); if (subRange.Address != MemoryManager.PteUnmapped) { - ulong endAddress = subRange.Address + subRange.Size; + Buffer buffer = _buffers.FindFirstOverlap(subRange.Address, subRange.Size); - ulong alignedAddress = subRange.Address & ~alignmentMask; - ulong alignedEndAddress = (endAddress + alignmentMask) & ~alignmentMask; - ulong alignedSize = alignedEndAddress - alignedAddress; - - Buffer buffer = _buffers.FindFirstOverlap(alignedAddress, alignedSize); - BufferRange bufferRange = buffer.GetRange(alignedAddress, alignedSize, false); - - storages[i] = bufferRange; - alignedSubRanges[i] = new MemoryRange(alignedAddress, alignedSize); + virtualBuffer.AddPhysicalDependency(buffer, subRange.Address, dstOffset, subRange.Size); + physicalBuffers.Add(buffer); } - else - { - ulong alignedSize = (subRange.Size + alignmentMask) & ~alignmentMask; - storages[i] = new BufferRange(BufferHandle.Null, 0, (int)alignedSize); - alignedSubRanges[i] = new MemoryRange(MemoryManager.PteUnmapped, alignedSize); - } + dstOffset += subRange.Size; } - MultiRangeBuffer multiRangeBuffer = new(_context, new MultiRange(alignedSubRanges), storages); - - _multiRangeBuffers.Add(multiRangeBuffer); + foreach (var buffer in physicalBuffers) + { + buffer.CopyToDependantVirtualBuffer(virtualBuffer); + } } /// @@ -320,9 +438,9 @@ namespace Ryujinx.Graphics.Gpu.Memory result.EndGpuAddress < gpuVa + size || result.UnmappedSequence != result.Buffer.UnmappedSequence) { - MultiRange range = TranslateAndCreateBuffer(memoryManager, gpuVa, size); + MultiRange range = TranslateAndCreateBuffer(memoryManager, gpuVa, size, BufferStage.Internal); ulong address = range.GetSubRange(0).Address; - result = new BufferCacheEntry(address, gpuVa, GetBuffer(address, size)); + result = new BufferCacheEntry(address, gpuVa, GetBuffer(address, size, BufferStage.Internal)); _dirtyCache[gpuVa] = result; } @@ -355,9 +473,9 @@ namespace Ryujinx.Graphics.Gpu.Memory result.EndGpuAddress < alignedEndGpuVa || result.UnmappedSequence != result.Buffer.UnmappedSequence) { - MultiRange range = TranslateAndCreateBuffer(memoryManager, alignedGpuVa, size); + MultiRange range = TranslateAndCreateBuffer(memoryManager, alignedGpuVa, size, BufferStage.None); ulong address = range.GetSubRange(0).Address; - result = new BufferCacheEntry(address, alignedGpuVa, GetBuffer(address, size)); + result = new BufferCacheEntry(address, alignedGpuVa, GetBuffer(address, size, BufferStage.None)); _modifiedCache[alignedGpuVa] = result; } @@ -374,7 +492,8 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Address of the buffer in guest memory /// Size in bytes of the buffer - private void CreateBufferAligned(ulong address, ulong size) + /// The type of usage that created the buffer + private void CreateBufferAligned(ulong address, ulong size, BufferStage stage) { Buffer[] overlaps = _bufferOverlaps; int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps); @@ -435,13 +554,13 @@ namespace Ryujinx.Graphics.Gpu.Memory ulong newSize = endAddress - address; - CreateBufferAligned(address, newSize, anySparseCompatible, overlaps, overlapsCount); + CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlaps, overlapsCount); } } else { // No overlap, just create a new buffer. - Buffer buffer = new(_context, _physicalMemory, address, size, sparseCompatible: false); + Buffer buffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible: false); lock (_buffers) { @@ -459,8 +578,9 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Address of the buffer in guest memory /// Size in bytes of the buffer + /// The type of usage that created the buffer /// Alignment of the start address of the buffer - private void CreateBufferAligned(ulong address, ulong size, ulong alignment) + private void CreateBufferAligned(ulong address, ulong size, BufferStage stage, ulong alignment) { Buffer[] overlaps = _bufferOverlaps; int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps); @@ -513,13 +633,13 @@ namespace Ryujinx.Graphics.Gpu.Memory ulong newSize = endAddress - address; - CreateBufferAligned(address, newSize, sparseAligned, overlaps, overlapsCount); + CreateBufferAligned(address, newSize, stage, sparseAligned, overlaps, overlapsCount); } } else { // No overlap, just create a new buffer. - Buffer buffer = new(_context, _physicalMemory, address, size, sparseAligned); + Buffer buffer = new(_context, _physicalMemory, address, size, stage, sparseAligned); lock (_buffers) { @@ -537,12 +657,13 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Address of the buffer in guest memory /// Size in bytes of the buffer + /// The type of usage that created the buffer /// Indicates if the buffer can be used in a sparse buffer mapping /// Buffers overlapping the range /// Total of overlaps - private void CreateBufferAligned(ulong address, ulong size, bool sparseCompatible, Buffer[] overlaps, int overlapsCount) + private void CreateBufferAligned(ulong address, ulong size, BufferStage stage, bool sparseCompatible, Buffer[] overlaps, int overlapsCount) { - Buffer newBuffer = new Buffer(_context, _physicalMemory, address, size, sparseCompatible, overlaps.Take(overlapsCount)); + Buffer newBuffer = new Buffer(_context, _physicalMemory, address, size, stage, sparseCompatible, overlaps.Take(overlapsCount)); lock (_buffers) { @@ -593,7 +714,7 @@ namespace Ryujinx.Graphics.Gpu.Memory for (int index = 0; index < overlapCount; index++) { - CreateMultiRangeBuffer(overlaps[index].Range); + CreateMultiRangeBuffer(overlaps[index].Range, BufferStage.None); } } @@ -620,8 +741,8 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Size in bytes of the copy public void CopyBuffer(MemoryManager memoryManager, ulong srcVa, ulong dstVa, ulong size) { - MultiRange srcRange = TranslateAndCreateMultiBuffers(memoryManager, srcVa, size); - MultiRange dstRange = TranslateAndCreateMultiBuffers(memoryManager, dstVa, size); + MultiRange srcRange = TranslateAndCreateMultiBuffersPhysicalOnly(memoryManager, srcVa, size, BufferStage.Copy); + MultiRange dstRange = TranslateAndCreateMultiBuffersPhysicalOnly(memoryManager, dstVa, size, BufferStage.Copy); if (srcRange.Count == 1 && dstRange.Count == 1) { @@ -677,8 +798,8 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Size in bytes of the copy private void CopyBufferSingleRange(MemoryManager memoryManager, ulong srcAddress, ulong dstAddress, ulong size) { - Buffer srcBuffer = GetBuffer(srcAddress, size); - Buffer dstBuffer = GetBuffer(dstAddress, size); + Buffer srcBuffer = GetBuffer(srcAddress, size, BufferStage.Copy); + Buffer dstBuffer = GetBuffer(dstAddress, size, BufferStage.Copy); int srcOffset = (int)(srcAddress - srcBuffer.Address); int dstOffset = (int)(dstAddress - dstBuffer.Address); @@ -692,7 +813,7 @@ namespace Ryujinx.Graphics.Gpu.Memory if (srcBuffer.IsModified(srcAddress, size)) { - dstBuffer.SignalModified(dstAddress, size); + dstBuffer.SignalModified(dstAddress, size, BufferStage.Copy); } else { @@ -701,6 +822,8 @@ namespace Ryujinx.Graphics.Gpu.Memory dstBuffer.ClearModified(dstAddress, size); memoryManager.Physical.WriteTrackedResource(dstAddress, memoryManager.Physical.GetSpan(srcAddress, (int)size), ResourceKind.Buffer); } + + dstBuffer.CopyToDependantVirtualBuffers(dstAddress, size); } /// @@ -715,18 +838,20 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Value to be written into the buffer public void ClearBuffer(MemoryManager memoryManager, ulong gpuVa, ulong size, uint value) { - MultiRange range = TranslateAndCreateMultiBuffers(memoryManager, gpuVa, size); + MultiRange range = TranslateAndCreateMultiBuffersPhysicalOnly(memoryManager, gpuVa, size, BufferStage.Copy); for (int index = 0; index < range.Count; index++) { MemoryRange subRange = range.GetSubRange(index); - Buffer buffer = GetBuffer(subRange.Address, subRange.Size); + Buffer buffer = GetBuffer(subRange.Address, subRange.Size, BufferStage.Copy); int offset = (int)(subRange.Address - buffer.Address); _context.Renderer.Pipeline.ClearBuffer(buffer.Handle, offset, (int)subRange.Size, value); memoryManager.Physical.FillTrackedResource(subRange.Address, subRange.Size, value, ResourceKind.Buffer); + + buffer.CopyToDependantVirtualBuffers(subRange.Address, subRange.Size); } } @@ -734,18 +859,19 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Gets a buffer sub-range starting at a given memory address, aligned to the next page boundary. /// /// Physical regions of memory where the buffer is mapped + /// Buffer stage that triggered the access /// Whether the buffer will be written to by this use /// The buffer sub-range starting at the given memory address - public BufferRange GetBufferRangeAligned(MultiRange range, bool write = false) + public BufferRange GetBufferRangeAligned(MultiRange range, BufferStage stage, bool write = false) { if (range.Count > 1) { - return GetBuffer(range, write).GetRange(range); + return GetBuffer(range, stage, write).GetRange(range); } else { MemoryRange subRange = range.GetSubRange(0); - return GetBuffer(subRange.Address, subRange.Size, write).GetRangeAligned(subRange.Address, subRange.Size, write); + return GetBuffer(subRange.Address, subRange.Size, stage, write).GetRangeAligned(subRange.Address, subRange.Size, write); } } @@ -753,18 +879,19 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Gets a buffer sub-range for a given memory range. /// /// Physical regions of memory where the buffer is mapped + /// Buffer stage that triggered the access /// Whether the buffer will be written to by this use /// The buffer sub-range for the given range - public BufferRange GetBufferRange(MultiRange range, bool write = false) + public BufferRange GetBufferRange(MultiRange range, BufferStage stage, bool write = false) { if (range.Count > 1) { - return GetBuffer(range, write).GetRange(range); + return GetBuffer(range, stage, write).GetRange(range); } else { MemoryRange subRange = range.GetSubRange(0); - return GetBuffer(subRange.Address, subRange.Size, write).GetRange(subRange.Address, subRange.Size, write); + return GetBuffer(subRange.Address, subRange.Size, stage, write).GetRange(subRange.Address, subRange.Size, write); } } @@ -773,9 +900,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// A buffer overlapping with the specified range is assumed to already exist on the cache. /// /// Physical regions of memory where the buffer is mapped + /// Buffer stage that triggered the access /// Whether the buffer will be written to by this use /// The buffer where the range is fully contained - private MultiRangeBuffer GetBuffer(MultiRange range, bool write = false) + private MultiRangeBuffer GetBuffer(MultiRange range, BufferStage stage, bool write = false) { for (int i = 0; i < range.Count; i++) { @@ -787,7 +915,7 @@ namespace Ryujinx.Graphics.Gpu.Memory if (write) { - subBuffer.SignalModified(subRange.Address, subRange.Size); + subBuffer.SignalModified(subRange.Address, subRange.Size, stage); } } @@ -806,6 +934,11 @@ namespace Ryujinx.Graphics.Gpu.Memory } } + if (write && buffer != null && !_context.Capabilities.SupportsSparseBuffer) + { + buffer.AddModifiedRegion(range, ++_virtualModifiedSequenceNumber); + } + return buffer; } @@ -815,9 +948,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Start address of the memory range /// Size in bytes of the memory range + /// Buffer stage that triggered the access /// Whether the buffer will be written to by this use /// The buffer where the range is fully contained - private Buffer GetBuffer(ulong address, ulong size, bool write = false) + private Buffer GetBuffer(ulong address, ulong size, BufferStage stage, bool write = false) { Buffer buffer; @@ -825,11 +959,12 @@ namespace Ryujinx.Graphics.Gpu.Memory { buffer = _buffers.FindFirstOverlap(address, size); + buffer.CopyFromDependantVirtualBuffers(); buffer.SynchronizeMemory(address, size); if (write) { - buffer.SignalModified(address, size); + buffer.SignalModified(address, size, stage); } } else @@ -849,14 +984,14 @@ namespace Ryujinx.Graphics.Gpu.Memory if (range.Count == 1) { MemoryRange subRange = range.GetSubRange(0); - SynchronizeBufferRange(subRange.Address, subRange.Size); + SynchronizeBufferRange(subRange.Address, subRange.Size, copyBackVirtual: true); } else { for (int index = 0; index < range.Count; index++) { MemoryRange subRange = range.GetSubRange(index); - SynchronizeBufferRange(subRange.Address, subRange.Size); + SynchronizeBufferRange(subRange.Address, subRange.Size, copyBackVirtual: false); } } } @@ -866,16 +1001,35 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Start address of the memory range /// Size in bytes of the memory range - private void SynchronizeBufferRange(ulong address, ulong size) + /// Whether virtual buffers that uses this buffer as backing memory should have its data copied back if modified + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SynchronizeBufferRange(ulong address, ulong size, bool copyBackVirtual) { if (size != 0) { Buffer buffer = _buffers.FindFirstOverlap(address, size); + if (copyBackVirtual) + { + buffer.CopyFromDependantVirtualBuffers(); + } + buffer.SynchronizeMemory(address, size); } } + /// + /// Signal that the given buffer's handle has changed, + /// forcing rebind and any overlapping multi-range buffers to be recreated. + /// + /// The buffer that has changed handle + public void BufferBackingChanged(Buffer buffer) + { + NotifyBuffersModified?.Invoke(); + + RecreateMultiRangeBuffers(buffer.Address, buffer.Size); + } + /// /// Prune any invalid entries from a quick access dictionary. /// diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs index c65602b5b..409867e09 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs @@ -27,6 +27,8 @@ namespace Ryujinx.Graphics.Gpu.Memory private readonly VertexBuffer[] _vertexBuffers; private readonly BufferBounds[] _transformFeedbackBuffers; private readonly List _bufferTextures; + private readonly List> _bufferTextureArrays; + private readonly List> _bufferImageArrays; private readonly BufferAssignment[] _ranges; /// @@ -140,11 +142,12 @@ namespace Ryujinx.Graphics.Gpu.Memory } _bufferTextures = new List(); + _bufferTextureArrays = new List>(); + _bufferImageArrays = new List>(); _ranges = new BufferAssignment[Constants.TotalGpUniformBuffers * Constants.ShaderStages]; } - /// /// Sets the memory range with the index buffer data, to be used for subsequent draw calls. /// @@ -153,7 +156,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Type of each index buffer element public void SetIndexBuffer(ulong gpuVa, ulong size, IndexType type) { - MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size, BufferStage.IndexBuffer); _indexBuffer.Range = range; _indexBuffer.Type = type; @@ -183,7 +186,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Vertex divisor of the buffer, for instanced draws public void SetVertexBuffer(int index, ulong gpuVa, ulong size, int stride, int divisor) { - MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size, BufferStage.VertexBuffer); _vertexBuffers[index].Range = range; _vertexBuffers[index].Stride = stride; @@ -210,7 +213,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Size in bytes of the transform feedback buffer public void SetTransformFeedbackBuffer(int index, ulong gpuVa, ulong size) { - MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateMultiBuffers(_channel.MemoryManager, gpuVa, size); + MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateMultiBuffers(_channel.MemoryManager, gpuVa, size, BufferStage.TransformFeedback); _transformFeedbackBuffers[index] = new BufferBounds(range); _transformFeedbackBuffersDirty = true; @@ -257,7 +260,7 @@ namespace Ryujinx.Graphics.Gpu.Memory gpuVa = BitUtils.AlignDown(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment); - MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateMultiBuffers(_channel.MemoryManager, gpuVa, size); + MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateMultiBuffers(_channel.MemoryManager, gpuVa, size, BufferStageUtils.ComputeStorage(flags)); _cpStorageBuffers.SetBounds(index, range, flags); } @@ -281,7 +284,7 @@ namespace Ryujinx.Graphics.Gpu.Memory gpuVa = BitUtils.AlignDown(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment); - MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateMultiBuffers(_channel.MemoryManager, gpuVa, size); + MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateMultiBuffers(_channel.MemoryManager, gpuVa, size, BufferStageUtils.GraphicsStorage(stage, flags)); if (!buffers.Buffers[index].Range.Equals(range)) { @@ -300,7 +303,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Size in bytes of the storage buffer public void SetComputeUniformBuffer(int index, ulong gpuVa, ulong size) { - MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size, BufferStage.Compute); _cpUniformBuffers.SetBounds(index, range); } @@ -315,7 +318,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Size in bytes of the storage buffer public void SetGraphicsUniformBuffer(int stage, int index, ulong gpuVa, ulong size) { - MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size, BufferStageUtils.FromShaderStage(stage)); _gpUniformBuffers[stage].SetBounds(index, range); _gpUniformBuffersDirty = true; @@ -418,6 +421,16 @@ namespace Ryujinx.Graphics.Gpu.Memory return _cpUniformBuffers.Buffers[index].Range.GetSubRange(0).Address; } + /// + /// Gets the size of the compute uniform buffer currently bound at the given index. + /// + /// Index of the uniform buffer binding + /// The uniform buffer size, or an undefined value if the buffer is not currently bound + public int GetComputeUniformBufferSize(int index) + { + return (int)_cpUniformBuffers.Buffers[index].Range.GetSubRange(0).Size; + } + /// /// Gets the address of the graphics uniform buffer currently bound at the given index. /// @@ -429,6 +442,17 @@ namespace Ryujinx.Graphics.Gpu.Memory return _gpUniformBuffers[stage].Buffers[index].Range.GetSubRange(0).Address; } + /// + /// Gets the size of the graphics uniform buffer currently bound at the given index. + /// + /// Index of the shader stage + /// Index of the uniform buffer binding + /// The uniform buffer size, or an undefined value if the buffer is not currently bound + public int GetGraphicsUniformBufferSize(int stage, int index) + { + return (int)_gpUniformBuffers[stage].Buffers[index].Range.GetSubRange(0).Size; + } + /// /// Gets the bounds of the uniform buffer currently bound at the given index. /// @@ -459,7 +483,7 @@ namespace Ryujinx.Graphics.Gpu.Memory BindBuffers(bufferCache, _cpStorageBuffers, isStorage: true); BindBuffers(bufferCache, _cpUniformBuffers, isStorage: false); - CommitBufferTextureBindings(); + CommitBufferTextureBindings(bufferCache); // Force rebind after doing compute work. Rebind(); @@ -470,21 +494,22 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Commit any queued buffer texture bindings. /// - private void CommitBufferTextureBindings() + /// Buffer cache + private void CommitBufferTextureBindings(BufferCache bufferCache) { if (_bufferTextures.Count > 0) { foreach (var binding in _bufferTextures) { var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore); - var range = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(binding.Range, isStore); + var range = bufferCache.GetBufferRange(binding.Range, BufferStageUtils.TextureBuffer(binding.Stage, binding.BindingInfo.Flags), isStore); binding.Texture.SetStorage(range); // The texture must be rebound to use the new storage if it was updated. if (binding.IsImage) { - _context.Renderer.Pipeline.SetImage(binding.BindingInfo.Binding, binding.Texture, binding.Format); + _context.Renderer.Pipeline.SetImage(binding.Stage, binding.BindingInfo.Binding, binding.Texture); } else { @@ -494,6 +519,33 @@ namespace Ryujinx.Graphics.Gpu.Memory _bufferTextures.Clear(); } + + if (_bufferTextureArrays.Count > 0 || _bufferImageArrays.Count > 0) + { + ITexture[] textureArray = new ITexture[1]; + + foreach (var binding in _bufferTextureArrays) + { + var range = bufferCache.GetBufferRange(binding.Range, BufferStage.None); + binding.Texture.SetStorage(range); + + textureArray[0] = binding.Texture; + binding.Array.SetTextures(binding.Index, textureArray); + } + + foreach (var binding in _bufferImageArrays) + { + var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore); + var range = bufferCache.GetBufferRange(binding.Range, BufferStage.None, isStore); + binding.Texture.SetStorage(range); + + textureArray[0] = binding.Texture; + binding.Array.SetImages(binding.Index, textureArray); + } + + _bufferTextureArrays.Clear(); + _bufferImageArrays.Clear(); + } } /// @@ -513,7 +565,7 @@ namespace Ryujinx.Graphics.Gpu.Memory if (!_indexBuffer.Range.IsUnmapped) { - BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Range); + BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Range, BufferStage.IndexBuffer); _context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type); } @@ -545,7 +597,7 @@ namespace Ryujinx.Graphics.Gpu.Memory continue; } - BufferRange buffer = bufferCache.GetBufferRange(vb.Range); + BufferRange buffer = bufferCache.GetBufferRange(vb.Range, BufferStage.VertexBuffer); vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor); } @@ -585,7 +637,7 @@ namespace Ryujinx.Graphics.Gpu.Memory continue; } - tfbs[index] = bufferCache.GetBufferRange(tfb.Range, write: true); + tfbs[index] = bufferCache.GetBufferRange(tfb.Range, BufferStage.TransformFeedback, write: true); } _context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs); @@ -632,7 +684,7 @@ namespace Ryujinx.Graphics.Gpu.Memory _context.SupportBufferUpdater.SetTfeOffset(index, tfeOffset); - buffers[index] = new BufferAssignment(index, bufferCache.GetBufferRange(range, write: true)); + buffers[index] = new BufferAssignment(index, bufferCache.GetBufferRange(range, BufferStage.TransformFeedback, write: true)); } } @@ -676,7 +728,7 @@ namespace Ryujinx.Graphics.Gpu.Memory UpdateBuffers(_gpUniformBuffers); } - CommitBufferTextureBindings(); + CommitBufferTextureBindings(bufferCache); _rebind = false; @@ -699,6 +751,7 @@ namespace Ryujinx.Graphics.Gpu.Memory for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++) { ref var buffers = ref bindings[(int)stage - 1]; + BufferStage bufferStage = BufferStageUtils.FromShaderStage(stage); for (int index = 0; index < buffers.Count; index++) { @@ -710,8 +763,8 @@ namespace Ryujinx.Graphics.Gpu.Memory { var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write); var range = isStorage - ? bufferCache.GetBufferRangeAligned(bounds.Range, isWrite) - : bufferCache.GetBufferRange(bounds.Range); + ? bufferCache.GetBufferRangeAligned(bounds.Range, bufferStage | BufferStageUtils.FromUsage(bounds.Flags), isWrite) + : bufferCache.GetBufferRange(bounds.Range, bufferStage); ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range); } @@ -747,8 +800,8 @@ namespace Ryujinx.Graphics.Gpu.Memory { var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write); var range = isStorage - ? bufferCache.GetBufferRangeAligned(bounds.Range, isWrite) - : bufferCache.GetBufferRange(bounds.Range); + ? bufferCache.GetBufferRangeAligned(bounds.Range, BufferStageUtils.ComputeStorage(bounds.Flags), isWrite) + : bufferCache.GetBufferRange(bounds.Range, BufferStage.Compute); ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range); } @@ -820,12 +873,57 @@ namespace Ryujinx.Graphics.Gpu.Memory ITexture texture, MultiRange range, TextureBindingInfo bindingInfo, - Format format, bool isImage) { - _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range); + _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags)); - _bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, format, isImage)); + _bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, isImage)); + } + + /// + /// Sets the buffer storage of a buffer texture array element. This will be bound when the buffer manager commits bindings. + /// + /// Shader stage accessing the texture + /// Texture array where the element will be inserted + /// Buffer texture + /// Physical ranges of memory where the buffer texture data is located + /// Binding info for the buffer texture + /// Index of the binding on the array + /// Format of the buffer texture + public void SetBufferTextureStorage( + ShaderStage stage, + ITextureArray array, + ITexture texture, + MultiRange range, + TextureBindingInfo bindingInfo, + int index) + { + _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags)); + + _bufferTextureArrays.Add(new BufferTextureArrayBinding(array, texture, range, bindingInfo, index)); + } + + /// + /// Sets the buffer storage of a buffer image array element. This will be bound when the buffer manager commits bindings. + /// + /// Shader stage accessing the texture + /// Image array where the element will be inserted + /// Buffer texture + /// Physical ranges of memory where the buffer texture data is located + /// Binding info for the buffer texture + /// Index of the binding on the array + /// Format of the buffer texture + public void SetBufferTextureStorage( + ShaderStage stage, + IImageArray array, + ITexture texture, + MultiRange range, + TextureBindingInfo bindingInfo, + int index) + { + _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags)); + + _bufferImageArrays.Add(new BufferTextureArrayBinding(array, texture, range, bindingInfo, index)); } /// diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferMigration.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferMigration.cs index 0a5268031..ce9985318 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferMigration.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferMigration.cs @@ -1,37 +1,21 @@ using System; +using System.Threading; namespace Ryujinx.Graphics.Gpu.Memory { /// - /// A record of when buffer data was copied from one buffer to another, along with the SyncNumber when the migration will be complete. - /// Keeps the source buffer alive for data flushes until the migration is complete. + /// A record of when buffer data was copied from multiple buffers to one migration target, + /// along with the SyncNumber when the migration will be complete. + /// Keeps the source buffers alive for data flushes until the migration is complete. + /// All spans cover the full range of the "destination" buffer. /// internal class BufferMigration : IDisposable { /// - /// The offset for the migrated region. + /// Ranges from source buffers that were copied as part of this migration. + /// Ordered by increasing base address. /// - private readonly ulong _offset; - - /// - /// The size for the migrated region. - /// - private readonly ulong _size; - - /// - /// The buffer that was migrated from. - /// - private readonly Buffer _buffer; - - /// - /// The source range action, to be called on overlap with an unreached sync number. - /// - private readonly Action _sourceRangeAction; - - /// - /// The source range list. - /// - private readonly BufferModifiedRangeList _source; + public BufferMigrationSpan[] Spans { get; private set; } /// /// The destination range list. This range list must be updated when flushing the source. @@ -43,55 +27,193 @@ namespace Ryujinx.Graphics.Gpu.Memory /// public readonly ulong SyncNumber; + /// + /// Number of active users there are traversing this migration's spans. + /// + private int _refCount; + + /// + /// Create a new buffer migration. + /// + /// Source spans for the migration + /// Destination buffer range list + /// Sync number where this migration will be complete + public BufferMigration(BufferMigrationSpan[] spans, BufferModifiedRangeList destination, ulong syncNumber) + { + Spans = spans; + Destination = destination; + SyncNumber = syncNumber; + } + + /// + /// Add a span to the migration. Allocates a new array with the target size, and replaces it. + /// + /// + /// The base address for the span is assumed to be higher than all other spans in the migration, + /// to keep the span array ordered. + /// + public void AddSpanToEnd(BufferMigrationSpan span) + { + BufferMigrationSpan[] oldSpans = Spans; + + BufferMigrationSpan[] newSpans = new BufferMigrationSpan[oldSpans.Length + 1]; + + oldSpans.CopyTo(newSpans, 0); + + newSpans[oldSpans.Length] = span; + + Spans = newSpans; + } + + /// + /// Performs the given range action, or one from a migration that overlaps and has not synced yet. + /// + /// The offset to pass to the action + /// The size to pass to the action + /// The sync number that has been reached + /// The action to perform + public void RangeActionWithMigration(ulong offset, ulong size, ulong syncNumber, BufferFlushAction rangeAction) + { + long syncDiff = (long)(syncNumber - SyncNumber); + + if (syncDiff >= 0) + { + // The migration has completed. Run the parent action. + rangeAction(offset, size, syncNumber); + } + else + { + Interlocked.Increment(ref _refCount); + + ulong prevAddress = offset; + ulong endAddress = offset + size; + + foreach (BufferMigrationSpan span in Spans) + { + if (!span.Overlaps(offset, size)) + { + continue; + } + + if (span.Address > prevAddress) + { + // There's a gap between this span and the last (or the start address). Flush the range using the parent action. + + rangeAction(prevAddress, span.Address - prevAddress, syncNumber); + } + + span.RangeActionWithMigration(offset, size, syncNumber); + + prevAddress = span.Address + span.Size; + } + + if (endAddress > prevAddress) + { + // There's a gap at the end of the range with no migration. Flush the range using the parent action. + rangeAction(prevAddress, endAddress - prevAddress, syncNumber); + } + + Interlocked.Decrement(ref _refCount); + } + } + + /// + /// Dispose the buffer migration. This removes the reference from the destination range list, + /// and runs all the dispose buffers for the migration spans. (typically disposes the source buffer) + /// + public void Dispose() + { + while (Volatile.Read(ref _refCount) > 0) + { + // Coming into this method, the sync for the migration will be met, so nothing can increment the ref count. + // However, an existing traversal of the spans for data flush could still be in progress. + // Spin if this is ever the case, so they don't get disposed before the operation is complete. + } + + Destination.RemoveMigration(this); + + foreach (BufferMigrationSpan span in Spans) + { + span.Dispose(); + } + } + } + + /// + /// A record of when buffer data was copied from one buffer to another, for a specific range in a source buffer. + /// Keeps the source buffer alive for data flushes until the migration is complete. + /// + internal readonly struct BufferMigrationSpan : IDisposable + { + /// + /// The offset for the migrated region. + /// + public readonly ulong Address; + + /// + /// The size for the migrated region. + /// + public readonly ulong Size; + + /// + /// The action to perform when the migration isn't needed anymore. + /// + private readonly Action _disposeAction; + + /// + /// The source range action, to be called on overlap with an unreached sync number. + /// + private readonly BufferFlushAction _sourceRangeAction; + + /// + /// Optional migration for the source data. Can chain together if many migrations happen in a short time. + /// If this is null, then _sourceRangeAction will always provide up to date data. + /// + private readonly BufferMigration _source; + /// /// Creates a record for a buffer migration. /// /// The source buffer for this migration + /// The action to perform when the migration isn't needed anymore /// The flush action for the source buffer - /// The modified range list for the source buffer - /// The modified range list for the destination buffer - /// The sync number for when the migration is complete - public BufferMigration( + /// Pending migration for the source buffer + public BufferMigrationSpan( Buffer buffer, - Action sourceRangeAction, - BufferModifiedRangeList source, - BufferModifiedRangeList dest, - ulong syncNumber) + Action disposeAction, + BufferFlushAction sourceRangeAction, + BufferMigration source) { - _offset = buffer.Address; - _size = buffer.Size; - _buffer = buffer; + Address = buffer.Address; + Size = buffer.Size; + _disposeAction = disposeAction; _sourceRangeAction = sourceRangeAction; _source = source; - Destination = dest; - SyncNumber = syncNumber; } + /// + /// Creates a record for a buffer migration, using the default buffer dispose action. + /// + /// The source buffer for this migration + /// The flush action for the source buffer + /// Pending migration for the source buffer + public BufferMigrationSpan( + Buffer buffer, + BufferFlushAction sourceRangeAction, + BufferMigration source) : this(buffer, buffer.DecrementReferenceCount, sourceRangeAction, source) { } + /// /// Determine if the given range overlaps this migration, and has not been completed yet. /// /// Start offset /// Range size - /// The sync number that was waited on /// True if overlapping and in progress, false otherwise - public bool Overlaps(ulong offset, ulong size, ulong syncNumber) + public bool Overlaps(ulong offset, ulong size) { ulong end = offset + size; - ulong destEnd = _offset + _size; - long syncDiff = (long)(syncNumber - SyncNumber); // syncNumber is less if the copy has not completed. + ulong destEnd = Address + Size; - return !(end <= _offset || offset >= destEnd) && syncDiff < 0; - } - - /// - /// Determine if the given range matches this migration. - /// - /// Start offset - /// Range size - /// True if the range exactly matches, false otherwise - public bool FullyMatches(ulong offset, ulong size) - { - return _offset == offset && _size == size; + return !(end <= Address || offset >= destEnd); } /// @@ -100,26 +222,30 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Start offset /// Range size /// Current sync number - /// The modified range list that originally owned this range - public void RangeActionWithMigration(ulong offset, ulong size, ulong syncNumber, BufferModifiedRangeList parent) + public void RangeActionWithMigration(ulong offset, ulong size, ulong syncNumber) { ulong end = offset + size; - end = Math.Min(_offset + _size, end); - offset = Math.Max(_offset, offset); + end = Math.Min(Address + Size, end); + offset = Math.Max(Address, offset); size = end - offset; - _source.RangeActionWithMigration(offset, size, syncNumber, parent, _sourceRangeAction); + if (_source != null) + { + _source.RangeActionWithMigration(offset, size, syncNumber, _sourceRangeAction); + } + else + { + _sourceRangeAction(offset, size, syncNumber); + } } /// - /// Removes this reference to the range list, potentially allowing for the source buffer to be disposed. + /// Removes this migration span, potentially allowing for the source buffer to be disposed. /// public void Dispose() { - Destination.RemoveMigration(this); - - _buffer.DecrementReferenceCount(); + _disposeAction(); } } } diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs index 6ada8a4b2..d330de638 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs @@ -1,7 +1,6 @@ using Ryujinx.Common.Pools; using Ryujinx.Memory.Range; using System; -using System.Collections.Generic; using System.Linq; namespace Ryujinx.Graphics.Gpu.Memory @@ -72,10 +71,10 @@ namespace Ryujinx.Graphics.Gpu.Memory private readonly GpuContext _context; private readonly Buffer _parent; - private readonly Action _flushAction; + private readonly BufferFlushAction _flushAction; - private List _sources; - private BufferMigration _migrationTarget; + private BufferMigration _source; + private BufferModifiedRangeList _migrationTarget; private readonly object _lock = new(); @@ -99,7 +98,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// GPU context that the buffer range list belongs to /// The parent buffer that owns this range list /// The flush action for the parent buffer - public BufferModifiedRangeList(GpuContext context, Buffer parent, Action flushAction) : base(BackingInitialSize) + public BufferModifiedRangeList(GpuContext context, Buffer parent, BufferFlushAction flushAction) : base(BackingInitialSize) { _context = context; _parent = parent; @@ -199,6 +198,36 @@ namespace Ryujinx.Graphics.Gpu.Memory } } + /// + /// Gets modified ranges within the specified region, and then fires the given action for each range individually. + /// + /// Start address to query + /// Size to query + /// Sync number required for a range to be signalled + /// The action to call for each modified range + public void GetRangesAtSync(ulong address, ulong size, ulong syncNumber, Action rangeAction) + { + int count = 0; + + ref var overlaps = ref ThreadStaticArray.Get(); + + // Range list must be consistent for this operation. + lock (_lock) + { + count = FindOverlapsNonOverlapping(address, size, ref overlaps); + } + + for (int i = 0; i < count; i++) + { + BufferModifiedRange overlap = overlaps[i]; + + if (overlap.SyncNumber == syncNumber) + { + rangeAction(overlap.Address, overlap.Size); + } + } + } + /// /// Gets modified ranges within the specified region, and then fires the given action for each range individually. /// @@ -245,41 +274,16 @@ namespace Ryujinx.Graphics.Gpu.Memory /// The offset to pass to the action /// The size to pass to the action /// The sync number that has been reached - /// The modified range list that originally owned this range /// The action to perform - public void RangeActionWithMigration(ulong offset, ulong size, ulong syncNumber, BufferModifiedRangeList parent, Action rangeAction) + public void RangeActionWithMigration(ulong offset, ulong size, ulong syncNumber, BufferFlushAction rangeAction) { - bool firstSource = true; - - if (parent != this) + if (_source != null) { - lock (_lock) - { - if (_sources != null) - { - foreach (BufferMigration source in _sources) - { - if (source.Overlaps(offset, size, syncNumber)) - { - if (firstSource && !source.FullyMatches(offset, size)) - { - // Perform this buffer's action first. The migrations will run after. - rangeAction(offset, size); - } - - source.RangeActionWithMigration(offset, size, syncNumber, parent); - - firstSource = false; - } - } - } - } + _source.RangeActionWithMigration(offset, size, syncNumber, rangeAction); } - - if (firstSource) + else { - // No overlapping migrations, or they are not meant for this range, flush the data using the given action. - rangeAction(offset, size); + rangeAction(offset, size, syncNumber); } } @@ -319,7 +323,7 @@ namespace Ryujinx.Graphics.Gpu.Memory ClearPart(overlap, clampAddress, clampEnd); - RangeActionWithMigration(clampAddress, clampEnd - clampAddress, waitSync, overlap.Parent, _flushAction); + RangeActionWithMigration(clampAddress, clampEnd - clampAddress, waitSync, _flushAction); } } @@ -329,7 +333,7 @@ namespace Ryujinx.Graphics.Gpu.Memory // There is a migration target to call instead. This can't be changed after set so accessing it outside the lock is fine. - _migrationTarget.Destination.RemoveRangesAndFlush(overlaps, rangeCount, highestDiff, currentSync, address, endAddress); + _migrationTarget.RemoveRangesAndFlush(overlaps, rangeCount, highestDiff, currentSync, address, endAddress); } /// @@ -367,7 +371,7 @@ namespace Ryujinx.Graphics.Gpu.Memory if (rangeCount == -1) { - _migrationTarget.Destination.WaitForAndFlushRanges(address, size); + _migrationTarget.WaitForAndFlushRanges(address, size); return; } @@ -407,6 +411,9 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Inherit ranges from another modified range list. /// + /// + /// Assumes that ranges will be inherited in address ascending order. + /// /// The range list to inherit from /// The action to call for each modified range public void InheritRanges(BufferModifiedRangeList ranges, Action registerRangeAction) @@ -415,18 +422,31 @@ namespace Ryujinx.Graphics.Gpu.Memory lock (ranges._lock) { - BufferMigration migration = new(ranges._parent, ranges._flushAction, ranges, this, _context.SyncNumber); - - ranges._parent.IncrementReferenceCount(); - ranges._migrationTarget = migration; - - _context.RegisterBufferMigration(migration); - inheritRanges = ranges.ToArray(); lock (_lock) { - (_sources ??= new List()).Add(migration); + // Copy over the migration from the previous range list + + BufferMigration oldMigration = ranges._source; + + BufferMigrationSpan span = new BufferMigrationSpan(ranges._parent, ranges._flushAction, oldMigration); + ranges._parent.IncrementReferenceCount(); + + if (_source == null) + { + // Create a new migration. + _source = new BufferMigration(new BufferMigrationSpan[] { span }, this, _context.SyncNumber); + + _context.RegisterBufferMigration(_source); + } + else + { + // Extend the migration + _source.AddSpanToEnd(span); + } + + ranges._migrationTarget = this; foreach (BufferModifiedRange range in inheritRanges) { @@ -445,6 +465,27 @@ namespace Ryujinx.Graphics.Gpu.Memory } } + /// + /// Register a migration from previous buffer storage. This migration is from a snapshot of the buffer's + /// current handle to its handle in the future, and is assumed to be complete when the sync action completes. + /// When the migration completes, the handle is disposed. + /// + public void SelfMigration() + { + lock (_lock) + { + BufferMigrationSpan span = new(_parent, _parent.GetSnapshotDisposeAction(), _parent.GetSnapshotFlushAction(), _source); + BufferMigration migration = new(new BufferMigrationSpan[] { span }, this, _context.SyncNumber); + + // Migration target is used to redirect flush actions to the latest range list, + // so we don't need to set it here. (this range list is still the latest) + + _context.RegisterBufferMigration(migration); + + _source = migration; + } + } + /// /// Removes a source buffer migration, indicating its copy has completed. /// @@ -453,7 +494,10 @@ namespace Ryujinx.Graphics.Gpu.Memory { lock (_lock) { - _sources.Remove(migration); + if (_source == migration) + { + _source = null; + } } } diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferPreFlush.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferPreFlush.cs new file mode 100644 index 000000000..d58b9ea66 --- /dev/null +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferPreFlush.cs @@ -0,0 +1,295 @@ +using Ryujinx.Common; +using Ryujinx.Graphics.GAL; +using System; + +namespace Ryujinx.Graphics.Gpu.Memory +{ + /// + /// Manages flushing ranges from buffers in advance for easy access, if they are flushed often. + /// Typically, from device local memory to a host mapped target for cached access. + /// + internal class BufferPreFlush : IDisposable + { + private const ulong PageSize = MemoryManager.PageSize; + + /// + /// Threshold for the number of copies without a flush required to disable preflush on a page. + /// + private const int DeactivateCopyThreshold = 200; + + /// + /// Value that indicates whether a page has been flushed or copied before. + /// + private enum PreFlushState + { + None, + HasFlushed, + HasCopied + } + + /// + /// Flush state for each page of the buffer. + /// Controls whether data should be copied to the flush buffer, what sync is expected + /// and unflushed copy counting for stopping copies that are no longer needed. + /// + private struct PreFlushPage + { + public PreFlushState State; + public ulong FirstActivatedSync; + public ulong LastCopiedSync; + public int CopyCount; + } + + /// + /// True if there are ranges that should copy to the flush buffer, false otherwise. + /// + public bool ShouldCopy { get; private set; } + + private readonly GpuContext _context; + private readonly Buffer _buffer; + private readonly PreFlushPage[] _pages; + private readonly ulong _address; + private readonly ulong _size; + private readonly ulong _misalignment; + private readonly Action _flushAction; + + private BufferHandle _flushBuffer; + + public BufferPreFlush(GpuContext context, Buffer parent, Action flushAction) + { + _context = context; + _buffer = parent; + _address = parent.Address; + _size = parent.Size; + _pages = new PreFlushPage[BitUtils.DivRoundUp(_size, PageSize)]; + _misalignment = _address & (PageSize - 1); + + _flushAction = flushAction; + } + + /// + /// Ensure that the flush buffer exists. + /// + private void EnsureFlushBuffer() + { + if (_flushBuffer == BufferHandle.Null) + { + _flushBuffer = _context.Renderer.CreateBuffer((int)_size, BufferAccess.HostMemory); + } + } + + /// + /// Gets a page range from an address and size byte range. + /// + /// Range address + /// Range size + /// A page index and count + private (int index, int count) GetPageRange(ulong address, ulong size) + { + ulong offset = address - _address; + ulong endOffset = offset + size; + + int basePage = (int)(offset / PageSize); + int endPage = (int)((endOffset - 1) / PageSize); + + return (basePage, 1 + endPage - basePage); + } + + /// + /// Gets an offset and size range in the parent buffer from a page index and count. + /// + /// Range start page + /// Range page count + /// Offset and size range + private (int offset, int size) GetOffset(int startPage, int count) + { + int offset = (int)((ulong)startPage * PageSize - _misalignment); + int endOffset = (int)((ulong)(startPage + count) * PageSize - _misalignment); + + offset = Math.Max(0, offset); + endOffset = Math.Min((int)_size, endOffset); + + return (offset, endOffset - offset); + } + + /// + /// Copy a range of pages from the parent buffer into the flush buffer. + /// + /// Range start page + /// Range page count + private void CopyPageRange(int startPage, int count) + { + (int offset, int size) = GetOffset(startPage, count); + + EnsureFlushBuffer(); + + _context.Renderer.Pipeline.CopyBuffer(_buffer.Handle, _flushBuffer, offset, offset, size); + } + + /// + /// Copy a modified range into the flush buffer if it's marked as flushed. + /// Any pages the range overlaps are copied, and copies aren't repeated in the same sync number. + /// + /// Range address + /// Range size + public void CopyModified(ulong address, ulong size) + { + (int baseIndex, int count) = GetPageRange(address, size); + ulong syncNumber = _context.SyncNumber; + + int startPage = -1; + + for (int i = 0; i < count; i++) + { + int pageIndex = baseIndex + i; + ref PreFlushPage page = ref _pages[pageIndex]; + + if (page.State > PreFlushState.None) + { + // Perform the copy, and update the state of each page. + if (startPage == -1) + { + startPage = pageIndex; + } + + if (page.State != PreFlushState.HasCopied) + { + page.FirstActivatedSync = syncNumber; + page.State = PreFlushState.HasCopied; + } + else if (page.CopyCount++ >= DeactivateCopyThreshold) + { + page.CopyCount = 0; + page.State = PreFlushState.None; + } + + if (page.LastCopiedSync != syncNumber) + { + page.LastCopiedSync = syncNumber; + } + } + else if (startPage != -1) + { + CopyPageRange(startPage, pageIndex - startPage); + + startPage = -1; + } + } + + if (startPage != -1) + { + CopyPageRange(startPage, (baseIndex + count) - startPage); + } + } + + /// + /// Flush the given page range back into guest memory, optionally using data from the flush buffer. + /// The actual flushed range is an intersection of the page range and the address range. + /// + /// Address range start + /// Address range size + /// Page range start + /// Page range count + /// True if the data should come from the flush buffer + private void FlushPageRange(ulong address, ulong size, int startPage, int count, bool preFlush) + { + (int pageOffset, int pageSize) = GetOffset(startPage, count); + + int offset = (int)(address - _address); + int end = offset + (int)size; + + offset = Math.Max(offset, pageOffset); + end = Math.Min(end, pageOffset + pageSize); + + if (end >= offset) + { + BufferHandle handle = preFlush ? _flushBuffer : _buffer.Handle; + _flushAction(handle, _address + (ulong)offset, (ulong)(end - offset)); + } + } + + /// + /// Flush the given address range back into guest memory, optionally using data from the flush buffer. + /// When a copy has been performed on or before the waited sync number, the data can come from the flush buffer. + /// Otherwise, it flushes the parent buffer directly. + /// + /// Range address + /// Range size + /// Sync number that has been waited for + public void FlushWithAction(ulong address, ulong size, ulong syncNumber) + { + // Copy the parts of the range that have pre-flush copies that have been completed. + // Run the flush action for ranges that don't have pre-flush copies. + + // If a range doesn't have a pre-flush copy, consider adding one. + + (int baseIndex, int count) = GetPageRange(address, size); + + bool rangePreFlushed = false; + int startPage = -1; + + for (int i = 0; i < count; i++) + { + int pageIndex = baseIndex + i; + ref PreFlushPage page = ref _pages[pageIndex]; + + bool flushPage = false; + page.CopyCount = 0; + + if (page.State == PreFlushState.HasCopied) + { + if (syncNumber >= page.FirstActivatedSync) + { + // After the range is first activated, its data will always be copied to the preflush buffer on each sync. + flushPage = true; + } + } + else if (page.State == PreFlushState.None) + { + page.State = PreFlushState.HasFlushed; + ShouldCopy = true; + } + + if (flushPage) + { + if (!rangePreFlushed || startPage == -1) + { + if (startPage != -1) + { + FlushPageRange(address, size, startPage, pageIndex - startPage, false); + } + + rangePreFlushed = true; + startPage = pageIndex; + } + } + else if (rangePreFlushed || startPage == -1) + { + if (startPage != -1) + { + FlushPageRange(address, size, startPage, pageIndex - startPage, true); + } + + rangePreFlushed = false; + startPage = pageIndex; + } + } + + if (startPage != -1) + { + FlushPageRange(address, size, startPage, (baseIndex + count) - startPage, rangePreFlushed); + } + } + + /// + /// Dispose the flush buffer, if present. + /// + public void Dispose() + { + if (_flushBuffer != BufferHandle.Null) + { + _context.Renderer.DeleteBuffer(_flushBuffer); + } + } + } +} diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferStage.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferStage.cs new file mode 100644 index 000000000..d56abda28 --- /dev/null +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferStage.cs @@ -0,0 +1,99 @@ +using Ryujinx.Graphics.Shader; +using System.Runtime.CompilerServices; + +namespace Ryujinx.Graphics.Gpu.Memory +{ + /// + /// Pipeline stages that can modify buffer data, as well as flags indicating storage usage. + /// Must match ShaderStage for the shader stages, though anything after that can be in any order. + /// + internal enum BufferStage : byte + { + Compute, + Vertex, + TessellationControl, + TessellationEvaluation, + Geometry, + Fragment, + + Indirect, + VertexBuffer, + IndexBuffer, + Copy, + TransformFeedback, + Internal, + None, + + StageMask = 0x3f, + StorageMask = 0xc0, + + StorageRead = 0x40, + StorageWrite = 0x80, + +#pragma warning disable CA1069 // Enums values should not be duplicated + StorageAtomic = 0xc0 +#pragma warning restore CA1069 // Enums values should not be duplicated + } + + /// + /// Utility methods to convert shader stages and binding flags into buffer stages. + /// + internal static class BufferStageUtils + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BufferStage FromShaderStage(ShaderStage stage) + { + return (BufferStage)stage; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BufferStage FromShaderStage(int stageIndex) + { + return (BufferStage)(stageIndex + 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BufferStage FromUsage(BufferUsageFlags flags) + { + if (flags.HasFlag(BufferUsageFlags.Write)) + { + return BufferStage.StorageWrite; + } + else + { + return BufferStage.StorageRead; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BufferStage FromUsage(TextureUsageFlags flags) + { + if (flags.HasFlag(TextureUsageFlags.ImageStore)) + { + return BufferStage.StorageWrite; + } + else + { + return BufferStage.StorageRead; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BufferStage TextureBuffer(ShaderStage shaderStage, TextureUsageFlags flags) + { + return FromShaderStage(shaderStage) | FromUsage(flags); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BufferStage GraphicsStorage(int stageIndex, BufferUsageFlags flags) + { + return FromShaderStage(stageIndex) | FromUsage(flags); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BufferStage ComputeStorage(BufferUsageFlags flags) + { + return BufferStage.Compute | FromUsage(flags); + } + } +} diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureArrayBinding.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureArrayBinding.cs new file mode 100644 index 000000000..a5338fa55 --- /dev/null +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureArrayBinding.cs @@ -0,0 +1,59 @@ +using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Gpu.Image; +using Ryujinx.Memory.Range; + +namespace Ryujinx.Graphics.Gpu.Memory +{ + /// + /// A buffer binding to apply to a buffer texture array element. + /// + readonly struct BufferTextureArrayBinding + { + /// + /// Backend texture or image array. + /// + public T Array { get; } + + /// + /// The buffer texture. + /// + public ITexture Texture { get; } + + /// + /// Physical ranges of memory where the buffer texture data is located. + /// + public MultiRange Range { get; } + + /// + /// The image or sampler binding info for the buffer texture. + /// + public TextureBindingInfo BindingInfo { get; } + + /// + /// Index of the binding on the array. + /// + public int Index { get; } + + /// + /// Create a new buffer texture binding. + /// + /// Array + /// Buffer texture + /// Physical ranges of memory where the buffer texture data is located + /// Binding info + /// Index of the binding on the array + public BufferTextureArrayBinding( + T array, + ITexture texture, + MultiRange range, + TextureBindingInfo bindingInfo, + int index) + { + Array = array; + Texture = texture; + Range = range; + BindingInfo = bindingInfo; + Index = index; + } + } +} diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs index bf0beffa2..1a3fde5b6 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs @@ -30,11 +30,6 @@ namespace Ryujinx.Graphics.Gpu.Memory /// public TextureBindingInfo BindingInfo { get; } - /// - /// The image format for the binding. - /// - public Format Format { get; } - /// /// Whether the binding is for an image or a sampler. /// @@ -47,21 +42,18 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Buffer texture /// Physical ranges of memory where the buffer texture data is located /// Binding info - /// Binding format /// Whether the binding is for an image or a sampler public BufferTextureBinding( ShaderStage stage, ITexture texture, MultiRange range, TextureBindingInfo bindingInfo, - Format format, bool isImage) { Stage = stage; Texture = texture; Range = range; BindingInfo = bindingInfo; - Format = format; IsImage = isImage; } } diff --git a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs index 5e19bddc3..d1065431d 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs @@ -1,3 +1,5 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Memory; using Ryujinx.Memory.Range; using System; @@ -40,9 +42,9 @@ namespace Ryujinx.Graphics.Gpu.Memory internal PhysicalMemory Physical { get; } /// - /// Virtual buffer cache. + /// Virtual range cache. /// - internal VirtualBufferCache VirtualBufferCache { get; } + internal VirtualRangeCache VirtualRangeCache { get; } /// /// Cache of GPU counters. @@ -56,13 +58,14 @@ namespace Ryujinx.Graphics.Gpu.Memory internal MemoryManager(PhysicalMemory physicalMemory) { Physical = physicalMemory; - VirtualBufferCache = new VirtualBufferCache(this); + VirtualRangeCache = new VirtualRangeCache(this); CounterCache = new CounterCache(); _pageTable = new ulong[PtLvl0Size][]; MemoryUnmapped += Physical.TextureCache.MemoryUnmappedHandler; MemoryUnmapped += Physical.BufferCache.MemoryUnmappedHandler; - MemoryUnmapped += VirtualBufferCache.MemoryUnmappedHandler; + MemoryUnmapped += VirtualRangeCache.MemoryUnmappedHandler; MemoryUnmapped += CounterCache.MemoryUnmappedHandler; + Physical.TextureCache.Initialize(); } /// @@ -240,11 +243,11 @@ namespace Ryujinx.Graphics.Gpu.Memory } else { - Memory memory = new byte[size]; + MemoryOwner memoryOwner = MemoryOwner.Rent(size); - GetSpan(va, size).CopyTo(memory.Span); + ReadImpl(va, memoryOwner.Span, tracked); - return new WritableRegion(this, va, memory, tracked); + return new WritableRegion(this, va, memoryOwner, tracked); } } @@ -329,49 +332,6 @@ namespace Ryujinx.Graphics.Gpu.Memory } } - /// - /// Writes data to GPU mapped memory, stopping at the first unmapped page at the memory region, if any. - /// - /// GPU virtual address to write the data into - /// The data to be written - public void WriteMapped(ulong va, ReadOnlySpan data) - { - if (IsContiguous(va, data.Length)) - { - Physical.Write(Translate(va), data); - } - else - { - int offset = 0, size; - - if ((va & PageMask) != 0) - { - ulong pa = Translate(va); - - size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask)); - - if (pa != PteUnmapped && Physical.IsMapped(pa)) - { - Physical.Write(pa, data[..size]); - } - - offset += size; - } - - for (; offset < data.Length; offset += size) - { - ulong pa = Translate(va + (ulong)offset); - - size = Math.Min(data.Length - offset, (int)PageSize); - - if (pa != PteUnmapped && Physical.IsMapped(pa)) - { - Physical.Write(pa, data.Slice(offset, size)); - } - } - } - } - /// /// Runs remap actions that are added to an unmap event. /// These must run after the mapping completes. diff --git a/src/Ryujinx.Graphics.Gpu/Memory/MultiRangeBuffer.cs b/src/Ryujinx.Graphics.Gpu/Memory/MultiRangeBuffer.cs index e039a7a43..d92b0836e 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/MultiRangeBuffer.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/MultiRangeBuffer.cs @@ -1,6 +1,7 @@ using Ryujinx.Graphics.GAL; using Ryujinx.Memory.Range; using System; +using System.Collections.Generic; namespace Ryujinx.Graphics.Gpu.Memory { @@ -21,12 +22,73 @@ namespace Ryujinx.Graphics.Gpu.Memory /// public MultiRange Range { get; } + /// + /// Ever increasing counter value indicating when the buffer was modified relative to other buffers. + /// + public int ModificationSequenceNumber { get; private set; } + + /// + /// Physical buffer dependency entry. + /// + private readonly struct PhysicalDependency + { + /// + /// Physical buffer. + /// + public readonly Buffer PhysicalBuffer; + + /// + /// Offset of the range on the physical buffer. + /// + public readonly ulong PhysicalOffset; + + /// + /// Offset of the range on the virtual buffer. + /// + public readonly ulong VirtualOffset; + + /// + /// Size of the range. + /// + public readonly ulong Size; + + /// + /// Creates a new physical dependency. + /// + /// Physical buffer + /// Offset of the range on the physical buffer + /// Offset of the range on the virtual buffer + /// Size of the range + public PhysicalDependency(Buffer physicalBuffer, ulong physicalOffset, ulong virtualOffset, ulong size) + { + PhysicalBuffer = physicalBuffer; + PhysicalOffset = physicalOffset; + VirtualOffset = virtualOffset; + Size = size; + } + } + + private List _dependencies; + private BufferModifiedRangeList _modifiedRanges = null; + /// /// Creates a new instance of the buffer. /// /// GPU context that the buffer belongs to /// Range of memory where the data is mapped - /// Backing memory for the buffers + public MultiRangeBuffer(GpuContext context, MultiRange range) + { + _context = context; + Range = range; + Handle = context.Renderer.CreateBuffer((int)range.GetSize()); + } + + /// + /// Creates a new instance of the buffer. + /// + /// GPU context that the buffer belongs to + /// Range of memory where the data is mapped + /// Backing memory for the buffer public MultiRangeBuffer(GpuContext context, MultiRange range, ReadOnlySpan storages) { _context = context; @@ -49,11 +111,134 @@ namespace Ryujinx.Graphics.Gpu.Memory return new BufferRange(Handle, offset, (int)range.GetSize()); } + /// + /// Removes all physical buffer dependencies. + /// + public void ClearPhysicalDependencies() + { + _dependencies?.Clear(); + } + + /// + /// Adds a physical buffer dependency. + /// + /// Physical buffer to be added + /// Address inside the physical buffer where the virtual buffer range is located + /// Offset inside the virtual buffer where the physical range is located + /// Size of the range in bytes + public void AddPhysicalDependency(Buffer buffer, ulong rangeAddress, ulong dstOffset, ulong rangeSize) + { + (_dependencies ??= new()).Add(new(buffer, rangeAddress - buffer.Address, dstOffset, rangeSize)); + buffer.AddVirtualDependency(this); + } + + /// + /// Tries to get the physical range corresponding to the given physical buffer. + /// + /// Physical buffer + /// Minimum virtual offset that a range match can have + /// Physical offset of the match + /// Virtual offset of the match, always greater than or equal + /// Size of the range match + /// True if a match was found for the given parameters, false otherwise + public bool TryGetPhysicalOffset(Buffer buffer, ulong minimumVirtOffset, out ulong physicalOffset, out ulong virtualOffset, out ulong size) + { + physicalOffset = 0; + virtualOffset = 0; + size = 0; + + if (_dependencies != null) + { + foreach (var dependency in _dependencies) + { + if (dependency.PhysicalBuffer == buffer && dependency.VirtualOffset >= minimumVirtOffset) + { + physicalOffset = dependency.PhysicalOffset; + virtualOffset = dependency.VirtualOffset; + size = dependency.Size; + + return true; + } + } + } + + return false; + } + + /// + /// Adds a modified virtual memory range. + /// + /// + /// This is only required when the host does not support sparse buffers, otherwise only physical buffers need to track modification. + /// + /// Modified range + /// ModificationSequenceNumber + public void AddModifiedRegion(MultiRange range, int modifiedSequenceNumber) + { + _modifiedRanges ??= new(_context, null, null); + + for (int i = 0; i < range.Count; i++) + { + MemoryRange subRange = range.GetSubRange(i); + + _modifiedRanges.SignalModified(subRange.Address, subRange.Size); + } + + ModificationSequenceNumber = modifiedSequenceNumber; + } + + /// + /// Calls the specified for all modified ranges that overlaps with . + /// + /// Buffer to have its range checked + /// Action to perform for modified ranges + public void ConsumeModifiedRegion(Buffer buffer, Action rangeAction) + { + ConsumeModifiedRegion(buffer.Address, buffer.Size, rangeAction); + } + + /// + /// Calls the specified for all modified ranges that overlaps with and . + /// + /// Address of the region to consume + /// Size of the region to consume + /// Action to perform for modified ranges + public void ConsumeModifiedRegion(ulong address, ulong size, Action rangeAction) + { + if (_modifiedRanges != null) + { + _modifiedRanges.GetRanges(address, size, rangeAction); + _modifiedRanges.Clear(address, size); + } + } + + /// + /// Gets data from the specified region of the buffer, and places it on . + /// + /// Span to put the data into + /// Offset of the buffer to get the data from + /// Size of the data in bytes + public void GetData(Span output, int offset, int size) + { + using PinnedSpan data = _context.Renderer.GetBufferData(Handle, offset, size); + data.Get().CopyTo(output); + } + /// /// Disposes the host buffer. /// public void Dispose() { + if (_dependencies != null) + { + foreach (var dependency in _dependencies) + { + dependency.PhysicalBuffer.RemoveVirtualDependency(this); + } + + _dependencies = null; + } + _context.Renderer.DeleteBuffer(Handle); } } diff --git a/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs index 1ca6071bd..b22cc01b8 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs @@ -1,10 +1,13 @@ +using Ryujinx.Common.Memory; using Ryujinx.Cpu; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Gpu.Shader; using Ryujinx.Memory; using Ryujinx.Memory.Range; using Ryujinx.Memory.Tracking; using System; +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; @@ -22,11 +25,6 @@ namespace Ryujinx.Graphics.Gpu.Memory private readonly IVirtualMemoryManagerTracked _cpuMemory; private int _referenceCount; - /// - /// Indicates whenever the memory manager supports 4KB pages. - /// - public bool Supports4KBPages => _cpuMemory.Supports4KBPages; - /// /// In-memory shader cache. /// @@ -82,6 +80,15 @@ namespace Ryujinx.Graphics.Gpu.Memory } } + /// + /// Creates a new device memory manager. + /// + /// The memory manager + public DeviceMemoryManager CreateDeviceMemoryManager() + { + return new DeviceMemoryManager(_cpuMemory); + } + /// /// Gets a host pointer for a given range of application memory. /// If the memory region is not a single contiguous block, this method returns 0. @@ -185,7 +192,9 @@ namespace Ryujinx.Graphics.Gpu.Memory } else { - Memory memory = new byte[range.GetSize()]; + MemoryOwner memoryOwner = MemoryOwner.Rent(checked((int)range.GetSize())); + + Span memorySpan = memoryOwner.Span; int offset = 0; for (int i = 0; i < range.Count; i++) @@ -194,12 +203,12 @@ namespace Ryujinx.Graphics.Gpu.Memory int size = (int)currentRange.Size; if (currentRange.Address != MemoryManager.PteUnmapped) { - GetSpan(currentRange.Address, size).CopyTo(memory.Span.Slice(offset, size)); + GetSpan(currentRange.Address, size).CopyTo(memorySpan.Slice(offset, size)); } offset += size; } - return new WritableRegion(new MultiRangeWritableBlock(range, this), 0, memory, tracked); + return new WritableRegion(new MultiRangeWritableBlock(range, this), 0, memoryOwner, tracked); } } @@ -358,10 +367,11 @@ namespace Ryujinx.Graphics.Gpu.Memory /// CPU virtual address of the region /// Size of the region /// Kind of the resource being tracked + /// Region flags /// The memory tracking handle - public RegionHandle BeginTracking(ulong address, ulong size, ResourceKind kind) + public RegionHandle BeginTracking(ulong address, ulong size, ResourceKind kind, RegionFlags flags = RegionFlags.None) { - return _cpuMemory.BeginTracking(address, size, (int)kind); + return _cpuMemory.BeginTracking(address, size, (int)kind, flags); } /// @@ -398,12 +408,19 @@ namespace Ryujinx.Graphics.Gpu.Memory /// CPU virtual address of the region /// Size of the region /// Kind of the resource being tracked + /// Region flags /// Handles to inherit state from or reuse /// Desired granularity of write tracking /// The memory tracking handle - public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, ResourceKind kind, IEnumerable handles = null, ulong granularity = 4096) + public MultiRegionHandle BeginGranularTracking( + ulong address, + ulong size, + ResourceKind kind, + RegionFlags flags = RegionFlags.None, + IEnumerable handles = null, + ulong granularity = 4096) { - return _cpuMemory.BeginGranularTracking(address, size, handles, granularity, (int)kind); + return _cpuMemory.BeginGranularTracking(address, size, handles, granularity, (int)kind, flags); } /// diff --git a/src/Ryujinx.Graphics.Gpu/Memory/VirtualBufferCache.cs b/src/Ryujinx.Graphics.Gpu/Memory/VirtualRangeCache.cs similarity index 92% rename from src/Ryujinx.Graphics.Gpu/Memory/VirtualBufferCache.cs rename to src/Ryujinx.Graphics.Gpu/Memory/VirtualRangeCache.cs index 858c5e3b0..964507a21 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/VirtualBufferCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/VirtualRangeCache.cs @@ -6,9 +6,9 @@ using System.Threading; namespace Ryujinx.Graphics.Gpu.Memory { /// - /// Virtual buffer cache. + /// Virtual range cache. /// - class VirtualBufferCache + class VirtualRangeCache { private readonly MemoryManager _memoryManager; @@ -68,10 +68,10 @@ namespace Ryujinx.Graphics.Gpu.Memory private int _hasDeferredUnmaps; /// - /// Creates a new instance of the virtual buffer cache. + /// Creates a new instance of the virtual range cache. /// - /// Memory manager that the virtual buffer cache belongs to - public VirtualBufferCache(MemoryManager memoryManager) + /// Memory manager that the virtual range cache belongs to + public VirtualRangeCache(MemoryManager memoryManager) { _memoryManager = memoryManager; _virtualRanges = new RangeList(); @@ -102,10 +102,9 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// GPU virtual address to get the physical range from /// Size in bytes of the region - /// Indicates host support for sparse buffer mapping of non-contiguous ranges /// Physical range for the specified GPU virtual region /// True if the range already existed, false if a new one was created and added - public bool TryGetOrAddRange(ulong gpuVa, ulong size, bool supportsSparse, out MultiRange range) + public bool TryGetOrAddRange(ulong gpuVa, ulong size, out MultiRange range) { VirtualRange[] overlaps = _virtualRangeOverlaps; int overlapsCount; @@ -158,7 +157,7 @@ namespace Ryujinx.Graphics.Gpu.Memory } else { - found = true; + found = overlap0.Range.Count == 1 || IsSparseAligned(overlap0.Range); range = overlap0.Range.Slice(gpuVa - overlap0.Address, size); } } @@ -174,12 +173,11 @@ namespace Ryujinx.Graphics.Gpu.Memory ShrinkOverlapsBufferIfNeeded(); - // If the the range is not properly aligned for sparse mapping, - // or if the host does not support sparse mapping, let's just - // force it to a single range. + // If the range is not properly aligned for sparse mapping, + // let's just force it to a single range. // This might cause issues in some applications that uses sparse // mappings. - if (!IsSparseAligned(range) || !supportsSparse) + if (!IsSparseAligned(range)) { range = new MultiRange(range.GetSubRange(0).Address, size); } diff --git a/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs b/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs index 4e1cb4e12..018c5fdc0 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs @@ -17,6 +17,8 @@ namespace Ryujinx.Graphics.Gpu.Shader public BufferDescriptor[][] ConstantBufferBindings { get; } public BufferDescriptor[][] StorageBufferBindings { get; } + public int[] TextureCounts { get; } + public int MaxTextureBinding { get; } public int MaxImageBinding { get; } @@ -34,6 +36,8 @@ namespace Ryujinx.Graphics.Gpu.Shader ConstantBufferBindings = new BufferDescriptor[stageCount][]; StorageBufferBindings = new BufferDescriptor[stageCount][]; + TextureCounts = new int[stageCount]; + int maxTextureBinding = -1; int maxImageBinding = -1; int offset = isCompute ? 0 : 1; @@ -54,18 +58,26 @@ namespace Ryujinx.Graphics.Gpu.Shader TextureBindings[i] = stage.Info.Textures.Select(descriptor => { - Target target = ShaderTexture.GetTarget(descriptor.Type); + Target target = descriptor.Type != SamplerType.None ? ShaderTexture.GetTarget(descriptor.Type) : default; var result = new TextureBindingInfo( target, + descriptor.Set, descriptor.Binding, + descriptor.ArrayLength, descriptor.CbufSlot, descriptor.HandleIndex, - descriptor.Flags); + descriptor.Flags, + descriptor.Type == SamplerType.None); - if (descriptor.Binding > maxTextureBinding) + if (descriptor.ArrayLength <= 1) { - maxTextureBinding = descriptor.Binding; + if (descriptor.Binding > maxTextureBinding) + { + maxTextureBinding = descriptor.Binding; + } + + TextureCounts[i]++; } return result; @@ -74,17 +86,19 @@ namespace Ryujinx.Graphics.Gpu.Shader ImageBindings[i] = stage.Info.Images.Select(descriptor => { Target target = ShaderTexture.GetTarget(descriptor.Type); - Format format = ShaderTexture.GetFormat(descriptor.Format); + FormatInfo formatInfo = ShaderTexture.GetFormatInfo(descriptor.Format); var result = new TextureBindingInfo( target, - format, + formatInfo, + descriptor.Set, descriptor.Binding, + descriptor.ArrayLength, descriptor.CbufSlot, descriptor.HandleIndex, descriptor.Flags); - if (descriptor.Binding > maxImageBinding) + if (descriptor.ArrayLength <= 1 && descriptor.Binding > maxImageBinding) { maxImageBinding = descriptor.Binding; } diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/BinarySerializer.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/BinarySerializer.cs index b08c44d67..3837092c9 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/BinarySerializer.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/BinarySerializer.cs @@ -125,9 +125,18 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache CompressionAlgorithm algorithm = CompressionAlgorithm.None; Read(ref algorithm); - if (algorithm == CompressionAlgorithm.Deflate) + switch (algorithm) { - _activeStream = new DeflateStream(_stream, CompressionMode.Decompress, true); + case CompressionAlgorithm.None: + break; + case CompressionAlgorithm.Deflate: + _activeStream = new DeflateStream(_stream, CompressionMode.Decompress, true); + break; + case CompressionAlgorithm.Brotli: + _activeStream = new BrotliStream(_stream, CompressionMode.Decompress, true); + break; + default: + throw new ArgumentException($"Invalid compression algorithm \"{algorithm}\""); } } @@ -139,9 +148,18 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache { Write(ref algorithm); - if (algorithm == CompressionAlgorithm.Deflate) + switch (algorithm) { - _activeStream = new DeflateStream(_stream, CompressionLevel.SmallestSize, true); + case CompressionAlgorithm.None: + break; + case CompressionAlgorithm.Deflate: + _activeStream = new DeflateStream(_stream, CompressionLevel.Fastest, true); + break; + case CompressionAlgorithm.Brotli: + _activeStream = new BrotliStream(_stream, CompressionLevel.Fastest, true); + break; + default: + throw new ArgumentException($"Invalid compression algorithm \"{algorithm}\""); } } @@ -177,7 +195,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache switch (algorithm) { case CompressionAlgorithm.None: - stream.Read(data); + stream.ReadExactly(data); break; case CompressionAlgorithm.Deflate: stream = new DeflateStream(stream, CompressionMode.Decompress, true); @@ -187,6 +205,14 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache } stream.Dispose(); break; + case CompressionAlgorithm.Brotli: + stream = new BrotliStream(stream, CompressionMode.Decompress, true); + for (int offset = 0; offset < data.Length;) + { + offset += stream.Read(data[offset..]); + } + stream.Dispose(); + break; } } @@ -206,7 +232,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache stream.Write(data); break; case CompressionAlgorithm.Deflate: - stream = new DeflateStream(stream, CompressionLevel.SmallestSize, true); + stream = new DeflateStream(stream, CompressionLevel.Fastest, true); + stream.Write(data); + stream.Dispose(); + break; + case CompressionAlgorithm.Brotli: + stream = new BrotliStream(stream, CompressionLevel.Fastest, true); stream.Write(data); stream.Dispose(); break; diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/CompressionAlgorithm.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/CompressionAlgorithm.cs index 96ddbb513..86d3de07d 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/CompressionAlgorithm.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/CompressionAlgorithm.cs @@ -14,5 +14,10 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache /// Deflate compression (RFC 1951). /// Deflate, + + /// + /// Brotli compression (RFC 7932). + /// + Brotli, } } diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheCommon.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheCommon.cs index c4ce0b870..cecfe9acf 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheCommon.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheCommon.cs @@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache /// Compression algorithm public static CompressionAlgorithm GetCompressionAlgorithm() { - return CompressionAlgorithm.Deflate; + return CompressionAlgorithm.Brotli; } } } diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs index de6432bc1..3c7664b77 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs @@ -18,6 +18,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache private readonly ShaderSpecializationState _newSpecState; private readonly int _stageIndex; private readonly bool _isVulkan; + private readonly bool _hasGeometryShader; + private readonly bool _supportsQuads; /// /// Creates a new instance of the cached GPU state accessor for shader translation. @@ -27,7 +29,9 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache /// The constant buffer 1 data of the shader /// Shader specialization state of the cached shader /// Shader specialization state of the recompiled shader + /// Resource counts shared across all shader stages /// Shader stage index + /// Indicates if a geometry shader is present public DiskCacheGpuAccessor( GpuContext context, ReadOnlyMemory data, @@ -35,7 +39,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache ShaderSpecializationState oldSpecState, ShaderSpecializationState newSpecState, ResourceCounts counts, - int stageIndex) : base(context, counts, stageIndex) + int stageIndex, + bool hasGeometryShader) : base(context, counts, stageIndex) { _data = data; _cb1Data = cb1Data; @@ -43,6 +48,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache _newSpecState = newSpecState; _stageIndex = stageIndex; _isVulkan = context.Capabilities.Api == TargetApi.Vulkan; + _hasGeometryShader = hasGeometryShader; + _supportsQuads = context.Capabilities.SupportsQuads; if (stageIndex == (int)ShaderStage.Geometry - 1) { @@ -99,7 +106,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache /// public GpuGraphicsState QueryGraphicsState() { - return _oldSpecState.GraphicsState.CreateShaderGraphicsState(!_isVulkan, _isVulkan || _oldSpecState.GraphicsState.YNegateEnabled); + return _oldSpecState.GraphicsState.CreateShaderGraphicsState( + !_isVulkan, + _supportsQuads, + _hasGeometryShader, + _isVulkan || _oldSpecState.GraphicsState.YNegateEnabled); } /// @@ -109,11 +120,10 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache } /// - public TextureFormat QueryTextureFormat(int handle, int cbufSlot) + /// Pool length is not available on the cache + public int QuerySamplerArrayLengthFromPool() { - _newSpecState.RecordTextureFormat(_stageIndex, handle, cbufSlot); - (uint format, bool formatSrgb) = _oldSpecState.GetFormat(_stageIndex, handle, cbufSlot); - return ConvertToTextureFormat(format, formatSrgb); + return QueryArrayLengthFromPool(isSampler: true); } /// @@ -123,6 +133,36 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache return _oldSpecState.GetTextureTarget(_stageIndex, handle, cbufSlot).ConvertSamplerType(); } + /// + /// Constant buffer derived length is not available on the cache + public int QueryTextureArrayLengthFromBuffer(int slot) + { + if (!_oldSpecState.TextureArrayFromBufferRegistered(_stageIndex, 0, slot)) + { + throw new DiskCacheLoadException(DiskCacheLoadResult.MissingTextureArrayLength); + } + + int arrayLength = _oldSpecState.GetTextureArrayFromBufferLength(_stageIndex, 0, slot); + _newSpecState.RegisterTextureArrayLengthFromBuffer(_stageIndex, 0, slot, arrayLength); + + return arrayLength; + } + + /// + /// Pool length is not available on the cache + public int QueryTextureArrayLengthFromPool() + { + return QueryArrayLengthFromPool(isSampler: false); + } + + /// + public TextureFormat QueryTextureFormat(int handle, int cbufSlot) + { + _newSpecState.RecordTextureFormat(_stageIndex, handle, cbufSlot); + (uint format, bool formatSrgb) = _oldSpecState.GetFormat(_stageIndex, handle, cbufSlot); + return ConvertToTextureFormat(format, formatSrgb); + } + /// public bool QueryTextureCoordNormalized(int handle, int cbufSlot) { @@ -155,6 +195,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache } /// + /// Texture information is not available on the cache public void RegisterTexture(int handle, int cbufSlot) { if (!_oldSpecState.TextureRegistered(_stageIndex, handle, cbufSlot)) @@ -167,5 +208,24 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache bool coordNormalized = _oldSpecState.GetCoordNormalized(_stageIndex, handle, cbufSlot); _newSpecState.RegisterTexture(_stageIndex, handle, cbufSlot, format, formatSrgb, target, coordNormalized); } + + /// + /// Gets the cached texture or sampler pool capacity. + /// + /// True to get sampler pool length, false for texture pool length + /// Pool length + /// Pool length is not available on the cache + private int QueryArrayLengthFromPool(bool isSampler) + { + if (!_oldSpecState.TextureArrayFromPoolRegistered(isSampler)) + { + throw new DiskCacheLoadException(DiskCacheLoadResult.MissingTextureArrayLength); + } + + int arrayLength = _oldSpecState.GetTextureArrayFromPoolLength(isSampler); + _newSpecState.RegisterTextureArrayLengthFromPool(isSampler, arrayLength); + + return arrayLength; + } } } diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs index 59d2cfb3f..08cd3bb02 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs @@ -220,7 +220,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache } dataFileStream.Seek((long)entry.Offset, SeekOrigin.Begin); - dataFileStream.Read(cb1Data); + dataFileStream.ReadExactly(cb1Data); BinarySerializer.ReadCompressed(dataFileStream, guestCode); _cache[index] = (guestCode, cb1Data); @@ -279,7 +279,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache dataFileStream.Seek((long)entry.Offset, SeekOrigin.Begin); byte[] cachedCode = new byte[entry.CodeSize]; byte[] cachedCb1Data = new byte[entry.Cb1DataSize]; - dataFileStream.Read(cachedCb1Data); + dataFileStream.ReadExactly(cachedCb1Data); BinarySerializer.ReadCompressed(dataFileStream, cachedCode); if (data.SequenceEqual(cachedCode) && cb1Data.SequenceEqual(cachedCb1Data)) diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs index 125ab8993..c36fc0ada 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMinor = 2; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; - private const uint CodeGenVersion = 5958; + private const uint CodeGenVersion = 7353; private const string SharedTocFileName = "shared.toc"; private const string SharedDataFileName = "shared.data"; diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheLoadResult.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheLoadResult.cs index ba23f70ee..d5abb9e55 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheLoadResult.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheLoadResult.cs @@ -20,6 +20,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache /// InvalidCb1DataLength, + /// + /// The cache is missing the length of a texture array used by the shader. + /// + MissingTextureArrayLength, + /// /// The cache is missing the descriptor of a texture used by the shader. /// @@ -60,6 +65,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache DiskCacheLoadResult.Success => "No error.", DiskCacheLoadResult.NoAccess => "Could not access the cache file.", DiskCacheLoadResult.InvalidCb1DataLength => "Constant buffer 1 data length is too low.", + DiskCacheLoadResult.MissingTextureArrayLength => "Texture array length missing from the cache file.", DiskCacheLoadResult.MissingTextureDescriptor => "Texture descriptor missing from the cache file.", DiskCacheLoadResult.FileCorruptedGeneric => "The cache file is corrupted.", DiskCacheLoadResult.FileCorruptedInvalidMagic => "Magic check failed, the cache file is corrupted.", diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs index 153fc4427..20f96462e 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs @@ -601,6 +601,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache TargetApi api = _context.Capabilities.Api; + bool hasCachedGs = guestShaders[4].HasValue; + for (int stageIndex = Constants.ShaderStages - 1; stageIndex >= 0; stageIndex--) { if (guestShaders[stageIndex + 1].HasValue) @@ -610,7 +612,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache byte[] guestCode = shader.Code; byte[] cb1Data = shader.Cb1Data; - DiskCacheGpuAccessor gpuAccessor = new(_context, guestCode, cb1Data, specState, newSpecState, counts, stageIndex); + DiskCacheGpuAccessor gpuAccessor = new(_context, guestCode, cb1Data, specState, newSpecState, counts, stageIndex, hasCachedGs); TranslatorContext currentStage = DecodeGraphicsShader(gpuAccessor, api, DefaultFlags, 0); if (nextStage != null) @@ -623,7 +625,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache byte[] guestCodeA = guestShaders[0].Value.Code; byte[] cb1DataA = guestShaders[0].Value.Cb1Data; - DiskCacheGpuAccessor gpuAccessorA = new(_context, guestCodeA, cb1DataA, specState, newSpecState, counts, 0); + DiskCacheGpuAccessor gpuAccessorA = new(_context, guestCodeA, cb1DataA, specState, newSpecState, counts, 0, hasCachedGs); translatorContexts[0] = DecodeGraphicsShader(gpuAccessorA, api, DefaultFlags | TranslationFlags.VertexA, 0); } @@ -711,7 +713,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache GuestCodeAndCbData shader = guestShaders[0].Value; ResourceCounts counts = new(); ShaderSpecializationState newSpecState = new(ref specState.ComputeState); - DiskCacheGpuAccessor gpuAccessor = new(_context, shader.Code, shader.Cb1Data, specState, newSpecState, counts, 0); + DiskCacheGpuAccessor gpuAccessor = new(_context, shader.Code, shader.Cb1Data, specState, newSpecState, counts, 0, false); gpuAccessor.InitializeReservedCounts(tfEnabled: false, vertexAsCompute: false); TranslatorContext translatorContext = DecodeComputeShader(gpuAccessor, _context.Capabilities.Api, 0); diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs index 95763f31d..1be75f242 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs @@ -17,6 +17,8 @@ namespace Ryujinx.Graphics.Gpu.Shader private readonly int _stageIndex; private readonly bool _compute; private readonly bool _isVulkan; + private readonly bool _hasGeometryShader; + private readonly bool _supportsQuads; /// /// Creates a new instance of the GPU state accessor for graphics shader translation. @@ -25,12 +27,20 @@ namespace Ryujinx.Graphics.Gpu.Shader /// GPU channel /// Current GPU state /// Graphics shader stage index (0 = Vertex, 4 = Fragment) - public GpuAccessor(GpuContext context, GpuChannel channel, GpuAccessorState state, int stageIndex) : base(context, state.ResourceCounts, stageIndex) + /// Indicates if a geometry shader is present + public GpuAccessor( + GpuContext context, + GpuChannel channel, + GpuAccessorState state, + int stageIndex, + bool hasGeometryShader) : base(context, state.ResourceCounts, stageIndex) { - _isVulkan = context.Capabilities.Api == TargetApi.Vulkan; _channel = channel; _state = state; _stageIndex = stageIndex; + _isVulkan = context.Capabilities.Api == TargetApi.Vulkan; + _hasGeometryShader = hasGeometryShader; + _supportsQuads = context.Capabilities.SupportsQuads; if (stageIndex == (int)ShaderStage.Geometry - 1) { @@ -72,6 +82,7 @@ namespace Ryujinx.Graphics.Gpu.Shader public ReadOnlySpan GetCode(ulong address, int minimumSize) { int size = Math.Max(minimumSize, 0x1000 - (int)(address & 0xfff)); + return MemoryMarshal.Cast(_channel.MemoryManager.GetSpan(address, size)); } @@ -104,7 +115,11 @@ namespace Ryujinx.Graphics.Gpu.Shader /// public GpuGraphicsState QueryGraphicsState() { - return _state.GraphicsState.CreateShaderGraphicsState(!_isVulkan, _isVulkan || _state.GraphicsState.YNegateEnabled); + return _state.GraphicsState.CreateShaderGraphicsState( + !_isVulkan, + _supportsQuads, + _hasGeometryShader, + _isVulkan || _state.GraphicsState.YNegateEnabled); } /// @@ -119,12 +134,13 @@ namespace Ryujinx.Graphics.Gpu.Shader return _state.GraphicsState.HasUnalignedStorageBuffer || _state.ComputeState.HasUnalignedStorageBuffer; } - //// - public TextureFormat QueryTextureFormat(int handle, int cbufSlot) + /// + public int QuerySamplerArrayLengthFromPool() { - _state.SpecializationState?.RecordTextureFormat(_stageIndex, handle, cbufSlot); - var descriptor = GetTextureDescriptor(handle, cbufSlot); - return ConvertToTextureFormat(descriptor.UnpackFormat(), descriptor.UnpackSrgb()); + int length = _state.SamplerPoolMaximumId + 1; + _state.SpecializationState?.RegisterTextureArrayLengthFromPool(isSampler: true, length); + + return length; } /// @@ -134,6 +150,37 @@ namespace Ryujinx.Graphics.Gpu.Shader return GetTextureDescriptor(handle, cbufSlot).UnpackTextureTarget().ConvertSamplerType(); } + /// + public int QueryTextureArrayLengthFromBuffer(int slot) + { + int size = _compute + ? _channel.BufferManager.GetComputeUniformBufferSize(slot) + : _channel.BufferManager.GetGraphicsUniformBufferSize(_stageIndex, slot); + + int arrayLength = size / Constants.TextureHandleSizeInBytes; + + _state.SpecializationState?.RegisterTextureArrayLengthFromBuffer(_stageIndex, 0, slot, arrayLength); + + return arrayLength; + } + + /// + public int QueryTextureArrayLengthFromPool() + { + int length = _state.PoolState.TexturePoolMaximumId + 1; + _state.SpecializationState?.RegisterTextureArrayLengthFromPool(isSampler: false, length); + + return length; + } + + //// + public TextureFormat QueryTextureFormat(int handle, int cbufSlot) + { + _state.SpecializationState?.RecordTextureFormat(_stageIndex, handle, cbufSlot); + var descriptor = GetTextureDescriptor(handle, cbufSlot); + return ConvertToTextureFormat(descriptor.UnpackFormat(), descriptor.UnpackSrgb()); + } + /// public bool QueryTextureCoordNormalized(int handle, int cbufSlot) { diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs index a5b31363b..d89eebabf 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs @@ -20,6 +20,9 @@ namespace Ryujinx.Graphics.Gpu.Shader private int _reservedTextures; private int _reservedImages; + private int _staticTexturesCount; + private int _staticImagesCount; + /// /// Creates a new GPU accessor. /// @@ -48,7 +51,7 @@ namespace Ryujinx.Graphics.Gpu.Shader _reservedImages = rrc.ReservedImages; } - public int QueryBindingConstantBuffer(int index) + public SetBindingPair CreateConstantBufferBinding(int index) { int binding; @@ -61,10 +64,42 @@ namespace Ryujinx.Graphics.Gpu.Shader binding = _resourceCounts.UniformBuffersCount++; } - return binding + _reservedConstantBuffers; + return new SetBindingPair(_context.Capabilities.UniformBufferSetIndex, binding + _reservedConstantBuffers); } - public int QueryBindingStorageBuffer(int index) + public SetBindingPair CreateImageBinding(int count, bool isBuffer) + { + int binding; + + if (_context.Capabilities.Api == TargetApi.Vulkan) + { + if (count == 1) + { + int index = _staticImagesCount++; + + if (isBuffer) + { + index += (int)_context.Capabilities.MaximumImagesPerStage; + } + + binding = GetBindingFromIndex(index, _context.Capabilities.MaximumImagesPerStage * 2, "Image"); + } + else + { + binding = (int)GetDynamicBaseIndexDual(_context.Capabilities.MaximumImagesPerStage) + _resourceCounts.ImagesCount++; + } + } + else + { + binding = _resourceCounts.ImagesCount; + + _resourceCounts.ImagesCount += count; + } + + return new SetBindingPair(_context.Capabilities.ImageSetIndex, binding + _reservedImages); + } + + public SetBindingPair CreateStorageBufferBinding(int index) { int binding; @@ -77,49 +112,39 @@ namespace Ryujinx.Graphics.Gpu.Shader binding = _resourceCounts.StorageBuffersCount++; } - return binding + _reservedStorageBuffers; + return new SetBindingPair(_context.Capabilities.StorageBufferSetIndex, binding + _reservedStorageBuffers); } - public int QueryBindingTexture(int index, bool isBuffer) + public SetBindingPair CreateTextureBinding(int count, bool isBuffer) { int binding; if (_context.Capabilities.Api == TargetApi.Vulkan) { - if (isBuffer) + if (count == 1) { - index += (int)_context.Capabilities.MaximumTexturesPerStage; - } + int index = _staticTexturesCount++; - binding = GetBindingFromIndex(index, _context.Capabilities.MaximumTexturesPerStage * 2, "Texture"); + if (isBuffer) + { + index += (int)_context.Capabilities.MaximumTexturesPerStage; + } + + binding = GetBindingFromIndex(index, _context.Capabilities.MaximumTexturesPerStage * 2, "Texture"); + } + else + { + binding = (int)GetDynamicBaseIndexDual(_context.Capabilities.MaximumTexturesPerStage) + _resourceCounts.TexturesCount++; + } } else { - binding = _resourceCounts.TexturesCount++; + binding = _resourceCounts.TexturesCount; + + _resourceCounts.TexturesCount += count; } - return binding + _reservedTextures; - } - - public int QueryBindingImage(int index, bool isBuffer) - { - int binding; - - if (_context.Capabilities.Api == TargetApi.Vulkan) - { - if (isBuffer) - { - index += (int)_context.Capabilities.MaximumImagesPerStage; - } - - binding = GetBindingFromIndex(index, _context.Capabilities.MaximumImagesPerStage * 2, "Image"); - } - else - { - binding = _resourceCounts.ImagesCount++; - } - - return binding + _reservedImages; + return new SetBindingPair(_context.Capabilities.TextureSetIndex, binding + _reservedTextures); } private int GetBindingFromIndex(int index, uint maxPerStage, string resourceName) @@ -148,6 +173,26 @@ namespace Ryujinx.Graphics.Gpu.Shader }; } + private static uint GetDynamicBaseIndexDual(uint maxPerStage) + { + return GetDynamicBaseIndex(maxPerStage) * 2; + } + + private static uint GetDynamicBaseIndex(uint maxPerStage) + { + return maxPerStage * Constants.ShaderStages; + } + + public int CreateExtraSet() + { + if (_resourceCounts.SetsCount >= _context.Capabilities.MaximumExtraSets) + { + return -1; + } + + return _context.Capabilities.ExtraSetBaseIndex + _resourceCounts.SetsCount++; + } + public int QueryHostGatherBiasPrecision() => _context.Capabilities.GatherBiasPrecision; public bool QueryHostReducedPrecision() => _context.Capabilities.ReduceShaderPrecision; @@ -178,6 +223,8 @@ namespace Ryujinx.Graphics.Gpu.Shader public bool QueryHostSupportsScaledVertexFormats() => _context.Capabilities.SupportsScaledVertexFormats; + public bool QueryHostSupportsSeparateSampler() => _context.Capabilities.SupportsSeparateSampler; + public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot; public bool QueryHostSupportsShaderBarrierDivergence() => _context.Capabilities.SupportsShaderBarrierDivergence; diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs index cfc4a2ccc..808bf1851 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs @@ -5,6 +5,11 @@ namespace Ryujinx.Graphics.Gpu.Shader /// class GpuAccessorState { + /// + /// Maximum ID that a sampler pool entry may have. + /// + public readonly int SamplerPoolMaximumId; + /// /// GPU texture pool state. /// @@ -38,18 +43,21 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Creates a new GPU accessor state. /// + /// Maximum ID that a sampler pool entry may have /// GPU texture pool state /// GPU compute state, for compute shaders /// GPU graphics state, for vertex, tessellation, geometry and fragment shaders /// Shader specialization state (shared by all stages) /// Transform feedback information, if the shader uses transform feedback. Otherwise, should be null public GpuAccessorState( + int samplerPoolMaximumId, GpuChannelPoolState poolState, GpuChannelComputeState computeState, GpuChannelGraphicsState graphicsState, ShaderSpecializationState specializationState, TransformFeedbackDescriptor[] transformFeedbackDescriptors = null) { + SamplerPoolMaximumId = samplerPoolMaximumId; PoolState = poolState; GraphicsState = graphicsState; ComputeState = computeState; diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs index b5bc4df3c..765bef7d4 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs @@ -106,8 +106,11 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Creates a new graphics state from this state that can be used for shader generation. /// /// Indicates if the host API supports alpha test operations + /// Indicates if the host API supports quad primitives + /// Indicates if a geometry shader is used + /// If true, indicates that the fragment origin is the upper left corner of the viewport, otherwise it is the lower left corner /// GPU graphics state that can be used for shader translation - public readonly GpuGraphicsState CreateShaderGraphicsState(bool hostSupportsAlphaTest, bool originUpperLeft) + public readonly GpuGraphicsState CreateShaderGraphicsState(bool hostSupportsAlphaTest, bool hostSupportsQuads, bool hasGeometryShader, bool originUpperLeft) { AlphaTestOp alphaTestOp; @@ -130,6 +133,9 @@ namespace Ryujinx.Graphics.Gpu.Shader }; } + bool isQuad = Topology == PrimitiveTopology.Quads || Topology == PrimitiveTopology.QuadStrip; + bool halvePrimitiveId = !hostSupportsQuads && !hasGeometryShader && isQuad; + return new GpuGraphicsState( EarlyZForce, ConvertToInputTopology(Topology, TessellationMode), @@ -149,7 +155,8 @@ namespace Ryujinx.Graphics.Gpu.Shader in FragmentOutputTypes, DualSourceBlendEnable, YNegateEnabled, - originUpperLeft); + originUpperLeft, + halvePrimitiveId); } /// diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs index ddb45152e..a2ab99335 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs @@ -2,7 +2,6 @@ using System; namespace Ryujinx.Graphics.Gpu.Shader { -#pragma warning disable CS0659 // Class overrides Object.Equals(object o) but does not override Object.GetHashCode() /// /// State used by the . /// @@ -52,6 +51,10 @@ namespace Ryujinx.Graphics.Gpu.Shader { return obj is GpuChannelPoolState state && Equals(state); } + + public override int GetHashCode() + { + return HashCode.Combine(TexturePoolGpuVa, TexturePoolMaximumId, TextureBufferIndex); + } } -#pragma warning restore CS0659 } diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ResourceCounts.cs b/src/Ryujinx.Graphics.Gpu/Shader/ResourceCounts.cs index 126e3249c..59ab378cf 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ResourceCounts.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ResourceCounts.cs @@ -24,5 +24,10 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Total of images used by the shaders. /// public int ImagesCount; + + /// + /// Total of extra sets used by the shaders. + /// + public int SetsCount; } } diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index af682e422..4fc66c4c0 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -161,7 +161,8 @@ namespace Ryujinx.Graphics.Gpu.Shader _graphicsShaderCache, _computeShaderCache, _diskCacheHostStorage, - ShaderCacheStateUpdate, cancellationToken); + ShaderCacheStateUpdate, + cancellationToken); loader.LoadShaders(); @@ -191,12 +192,14 @@ namespace Ryujinx.Graphics.Gpu.Shader /// This automatically translates, compiles and adds the code to the cache if not present. /// /// GPU channel + /// Maximum ID that an entry in the sampler pool may have /// Texture pool state /// Compute engine state /// GPU virtual address of the binary shader code /// Compiled compute shader code public CachedShaderProgram GetComputeShader( GpuChannel channel, + int samplerPoolMaximumId, GpuChannelPoolState poolState, GpuChannelComputeState computeState, ulong gpuVa) @@ -213,7 +216,7 @@ namespace Ryujinx.Graphics.Gpu.Shader } ShaderSpecializationState specState = new(ref computeState); - GpuAccessorState gpuAccessorState = new(poolState, computeState, default, specState); + GpuAccessorState gpuAccessorState = new(samplerPoolMaximumId, poolState, computeState, default, specState); GpuAccessor gpuAccessor = new(_context, channel, gpuAccessorState); gpuAccessor.InitializeReservedCounts(tfEnabled: false, vertexAsCompute: false); @@ -290,6 +293,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// GPU state /// Pipeline state /// GPU channel + /// Maximum ID that an entry in the sampler pool may have /// Texture pool state /// 3D engine state /// Addresses of the shaders for each stage @@ -298,6 +302,7 @@ namespace Ryujinx.Graphics.Gpu.Shader ref ThreedClassState state, ref ProgramPipelineState pipeline, GpuChannel channel, + int samplerPoolMaximumId, ref GpuChannelPoolState poolState, ref GpuChannelGraphicsState graphicsState, ShaderAddresses addresses) @@ -318,7 +323,7 @@ namespace Ryujinx.Graphics.Gpu.Shader UpdatePipelineInfo(ref state, ref pipeline, graphicsState, channel); ShaderSpecializationState specState = new(ref graphicsState, ref pipeline, transformFeedbackDescriptors); - GpuAccessorState gpuAccessorState = new(poolState, default, graphicsState, specState, transformFeedbackDescriptors); + GpuAccessorState gpuAccessorState = new(samplerPoolMaximumId, poolState, default, graphicsState, specState, transformFeedbackDescriptors); ReadOnlySpan addressesSpan = addresses.AsSpan(); @@ -334,7 +339,7 @@ namespace Ryujinx.Graphics.Gpu.Shader if (gpuVa != 0) { - GpuAccessor gpuAccessor = new(_context, channel, gpuAccessorState, stageIndex); + GpuAccessor gpuAccessor = new(_context, channel, gpuAccessorState, stageIndex, addresses.Geometry != 0); TranslatorContext currentStage = DecodeGraphicsShader(gpuAccessor, api, DefaultFlags, gpuVa); if (nextStage != null) diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs index c2258026c..49823562f 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs @@ -1,5 +1,6 @@ using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Shader; +using System; using System.Collections.Generic; namespace Ryujinx.Graphics.Gpu.Shader @@ -9,13 +10,6 @@ namespace Ryujinx.Graphics.Gpu.Shader /// class ShaderInfoBuilder { - private const int TotalSets = 4; - - private const int UniformSetIndex = 0; - private const int StorageSetIndex = 1; - private const int TextureSetIndex = 2; - private const int ImageSetIndex = 3; - private const ResourceStages SupportBufferStages = ResourceStages.Compute | ResourceStages.Vertex | @@ -36,8 +30,8 @@ namespace Ryujinx.Graphics.Gpu.Shader private readonly int _reservedTextures; private readonly int _reservedImages; - private readonly List[] _resourceDescriptors; - private readonly List[] _resourceUsages; + private List[] _resourceDescriptors; + private List[] _resourceUsages; /// /// Creates a new shader info builder. @@ -51,17 +45,27 @@ namespace Ryujinx.Graphics.Gpu.Shader _fragmentOutputMap = -1; - _resourceDescriptors = new List[TotalSets]; - _resourceUsages = new List[TotalSets]; + int uniformSetIndex = context.Capabilities.UniformBufferSetIndex; + int storageSetIndex = context.Capabilities.StorageBufferSetIndex; + int textureSetIndex = context.Capabilities.TextureSetIndex; + int imageSetIndex = context.Capabilities.ImageSetIndex; - for (int index = 0; index < TotalSets; index++) + int totalSets = Math.Max(uniformSetIndex, storageSetIndex); + totalSets = Math.Max(totalSets, textureSetIndex); + totalSets = Math.Max(totalSets, imageSetIndex); + totalSets++; + + _resourceDescriptors = new List[totalSets]; + _resourceUsages = new List[totalSets]; + + for (int index = 0; index < totalSets; index++) { _resourceDescriptors[index] = new(); _resourceUsages[index] = new(); } - AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1); - AddUsage(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1); + AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, uniformSetIndex, 0, 1); + AddUsage(SupportBufferStages, ResourceType.UniformBuffer, uniformSetIndex, 0, 1); ResourceReservationCounts rrc = new(!context.Capabilities.SupportsTransformFeedback && tfEnabled, vertexAsCompute); @@ -73,16 +77,25 @@ namespace Ryujinx.Graphics.Gpu.Shader // TODO: Handle that better? Maybe we should only set the binding that are really needed on each shader. ResourceStages stages = vertexAsCompute ? ResourceStages.Compute | ResourceStages.Vertex : VtgStages; - PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, UniformSetIndex, 1, rrc.ReservedConstantBuffers - 1); - PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, StorageSetIndex, 0, rrc.ReservedStorageBuffers); - PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, TextureSetIndex, 0, rrc.ReservedTextures); - PopulateDescriptorAndUsages(stages, ResourceType.BufferImage, ImageSetIndex, 0, rrc.ReservedImages); + PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, uniformSetIndex, 1, rrc.ReservedConstantBuffers - 1); + PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, storageSetIndex, 0, rrc.ReservedStorageBuffers, true); + PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, textureSetIndex, 0, rrc.ReservedTextures); + PopulateDescriptorAndUsages(stages, ResourceType.BufferImage, imageSetIndex, 0, rrc.ReservedImages, true); } - private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count) + /// + /// Populates descriptors and usages for vertex as compute and transform feedback emulation reserved resources. + /// + /// Shader stages where the resources are used + /// Resource type + /// Resource set index where the resources are used + /// First binding number + /// Amount of bindings + /// True if the binding is written from the shader, false otherwise + private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count, bool write = false) { AddDescriptor(stages, type, setIndex, start, count); - AddUsage(stages, type, setIndex, start, count); + AddUsage(stages, type, setIndex, start, count, write); } /// @@ -127,15 +140,23 @@ namespace Ryujinx.Graphics.Gpu.Shader int textureBinding = _reservedTextures + stageIndex * texturesPerStage * 2; int imageBinding = _reservedImages + stageIndex * imagesPerStage * 2; - AddDescriptor(stages, ResourceType.UniformBuffer, UniformSetIndex, uniformBinding, uniformsPerStage); - AddDescriptor(stages, ResourceType.StorageBuffer, StorageSetIndex, storageBinding, storagesPerStage); - AddDualDescriptor(stages, ResourceType.TextureAndSampler, ResourceType.BufferTexture, TextureSetIndex, textureBinding, texturesPerStage); - AddDualDescriptor(stages, ResourceType.Image, ResourceType.BufferImage, ImageSetIndex, imageBinding, imagesPerStage); + int uniformSetIndex = _context.Capabilities.UniformBufferSetIndex; + int storageSetIndex = _context.Capabilities.StorageBufferSetIndex; + int textureSetIndex = _context.Capabilities.TextureSetIndex; + int imageSetIndex = _context.Capabilities.ImageSetIndex; - AddUsage(info.CBuffers, stages, UniformSetIndex, isStorage: false); - AddUsage(info.SBuffers, stages, StorageSetIndex, isStorage: true); - AddUsage(info.Textures, stages, TextureSetIndex, isImage: false); - AddUsage(info.Images, stages, ImageSetIndex, isImage: true); + AddDescriptor(stages, ResourceType.UniformBuffer, uniformSetIndex, uniformBinding, uniformsPerStage); + AddDescriptor(stages, ResourceType.StorageBuffer, storageSetIndex, storageBinding, storagesPerStage); + AddDualDescriptor(stages, ResourceType.TextureAndSampler, ResourceType.BufferTexture, textureSetIndex, textureBinding, texturesPerStage); + AddDualDescriptor(stages, ResourceType.Image, ResourceType.BufferImage, imageSetIndex, imageBinding, imagesPerStage); + + AddArrayDescriptors(info.Textures, stages, isImage: false); + AddArrayDescriptors(info.Images, stages, isImage: true); + + AddUsage(info.CBuffers, stages, isStorage: false); + AddUsage(info.SBuffers, stages, isStorage: true); + AddUsage(info.Textures, stages, isImage: false); + AddUsage(info.Images, stages, isImage: true); } /// @@ -169,6 +190,25 @@ namespace Ryujinx.Graphics.Gpu.Shader AddDescriptor(stages, type2, setIndex, binding + count, count); } + /// + /// Adds all array descriptors (those with an array length greater than one). + /// + /// Textures to be added + /// Stages where the textures are used + /// True for images, false for textures + private void AddArrayDescriptors(IEnumerable textures, ResourceStages stages, bool isImage) + { + foreach (TextureDescriptor texture in textures) + { + if (texture.ArrayLength > 1) + { + ResourceType type = GetTextureResourceType(texture, isImage); + + GetDescriptors(texture.Set).Add(new ResourceDescriptor(texture.Binding, texture.ArrayLength, type, stages)); + } + } + } + /// /// Adds buffer usage information to the list of usages. /// @@ -177,11 +217,12 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Descriptor set number where the resource will be bound /// Binding number where the resource will be bound /// Number of resources bound at the binding location - private void AddUsage(ResourceStages stages, ResourceType type, int setIndex, int binding, int count) + /// True if the binding is written from the shader, false otherwise + private void AddUsage(ResourceStages stages, ResourceType type, int setIndex, int binding, int count, bool write = false) { for (int index = 0; index < count; index++) { - _resourceUsages[setIndex].Add(new ResourceUsage(binding + index, type, stages)); + _resourceUsages[setIndex].Add(new ResourceUsage(binding + index, 1, type, stages, write)); } } @@ -190,16 +231,17 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Buffers to be added /// Stages where the buffers are used - /// Descriptor set index where the buffers will be bound /// True for storage buffers, false for uniform buffers - private void AddUsage(IEnumerable buffers, ResourceStages stages, int setIndex, bool isStorage) + private void AddUsage(IEnumerable buffers, ResourceStages stages, bool isStorage) { foreach (BufferDescriptor buffer in buffers) { - _resourceUsages[setIndex].Add(new ResourceUsage( + GetUsages(buffer.Set).Add(new ResourceUsage( buffer.Binding, + 1, isStorage ? ResourceType.StorageBuffer : ResourceType.UniformBuffer, - stages)); + stages, + buffer.Flags.HasFlag(BufferUsageFlags.Write))); } } @@ -208,22 +250,93 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Textures to be added /// Stages where the textures are used - /// Descriptor set index where the textures will be bound /// True for images, false for textures - private void AddUsage(IEnumerable textures, ResourceStages stages, int setIndex, bool isImage) + private void AddUsage(IEnumerable textures, ResourceStages stages, bool isImage) { foreach (TextureDescriptor texture in textures) { - bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer; + ResourceType type = GetTextureResourceType(texture, isImage); - ResourceType type = isBuffer - ? (isImage ? ResourceType.BufferImage : ResourceType.BufferTexture) - : (isImage ? ResourceType.Image : ResourceType.TextureAndSampler); - - _resourceUsages[setIndex].Add(new ResourceUsage( + GetUsages(texture.Set).Add(new ResourceUsage( texture.Binding, + texture.ArrayLength, type, - stages)); + stages, + texture.Flags.HasFlag(TextureUsageFlags.ImageStore))); + } + } + + /// + /// Gets the list of resource descriptors for a given set index. A new list will be created if needed. + /// + /// Resource set index + /// List of resource descriptors + private List GetDescriptors(int setIndex) + { + if (_resourceDescriptors.Length <= setIndex) + { + int oldLength = _resourceDescriptors.Length; + Array.Resize(ref _resourceDescriptors, setIndex + 1); + + for (int index = oldLength; index <= setIndex; index++) + { + _resourceDescriptors[index] = new(); + } + } + + return _resourceDescriptors[setIndex]; + } + + /// + /// Gets the list of resource usages for a given set index. A new list will be created if needed. + /// + /// Resource set index + /// List of resource usages + private List GetUsages(int setIndex) + { + if (_resourceUsages.Length <= setIndex) + { + int oldLength = _resourceUsages.Length; + Array.Resize(ref _resourceUsages, setIndex + 1); + + for (int index = oldLength; index <= setIndex; index++) + { + _resourceUsages[index] = new(); + } + } + + return _resourceUsages[setIndex]; + } + + /// + /// Gets a resource type from a texture descriptor. + /// + /// Texture descriptor + /// Whether the texture is a image texture (writable) or not (sampled) + /// Resource type + private static ResourceType GetTextureResourceType(TextureDescriptor texture, bool isImage) + { + bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer; + + if (isBuffer) + { + return isImage ? ResourceType.BufferImage : ResourceType.BufferTexture; + } + else if (isImage) + { + return ResourceType.Image; + } + else if (texture.Type == SamplerType.None) + { + return ResourceType.Sampler; + } + else if (texture.Separate) + { + return ResourceType.Texture; + } + else + { + return ResourceType.TextureAndSampler; } } @@ -235,10 +348,12 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Shader information public ShaderInfo Build(ProgramPipelineState? pipeline, bool fromCache = false) { - var descriptors = new ResourceDescriptorCollection[TotalSets]; - var usages = new ResourceUsageCollection[TotalSets]; + int totalSets = _resourceDescriptors.Length; - for (int index = 0; index < TotalSets; index++) + var descriptors = new ResourceDescriptorCollection[totalSets]; + var usages = new ResourceUsageCollection[totalSets]; + + for (int index = 0; index < totalSets; index++) { descriptors[index] = new ResourceDescriptorCollection(_resourceDescriptors[index].ToArray().AsReadOnly()); usages[index] = new ResourceUsageCollection(_resourceUsages[index].ToArray().AsReadOnly()); diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs index 1477b7382..1230c0580 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs @@ -30,6 +30,8 @@ namespace Ryujinx.Graphics.Gpu.Shader { PrimitiveTopology = 1 << 1, TransformFeedback = 1 << 3, + TextureArrayFromBuffer = 1 << 4, + TextureArrayFromPool = 1 << 5, } private QueriedStateFlags _queriedState; @@ -153,6 +155,8 @@ namespace Ryujinx.Graphics.Gpu.Shader } private readonly Dictionary> _textureSpecialization; + private readonly Dictionary _textureArrayFromBufferSpecialization; + private readonly Dictionary _textureArrayFromPoolSpecialization; private KeyValuePair>[] _allTextures; private Box[][] _textureByBinding; private Box[][] _imageByBinding; @@ -163,6 +167,8 @@ namespace Ryujinx.Graphics.Gpu.Shader private ShaderSpecializationState() { _textureSpecialization = new Dictionary>(); + _textureArrayFromBufferSpecialization = new Dictionary(); + _textureArrayFromPoolSpecialization = new Dictionary(); } /// @@ -323,6 +329,30 @@ namespace Ryujinx.Graphics.Gpu.Shader state.Value.CoordNormalized = coordNormalized; } + /// + /// Registers the length of a texture array calculated from a constant buffer size. + /// + /// Shader stage where the texture is used + /// Offset in words of the texture handle on the texture buffer + /// Slot of the texture buffer constant buffer + /// Number of elements in the texture array + public void RegisterTextureArrayLengthFromBuffer(int stageIndex, int handle, int cbufSlot, int length) + { + _textureArrayFromBufferSpecialization[new TextureKey(stageIndex, handle, cbufSlot)] = length; + _queriedState |= QueriedStateFlags.TextureArrayFromBuffer; + } + + /// + /// Registers the length of a texture array calculated from a texture or sampler pool capacity. + /// + /// True for sampler pool, false for texture pool + /// Number of elements in the texture array + public void RegisterTextureArrayLengthFromPool(bool isSampler, int length) + { + _textureArrayFromPoolSpecialization[isSampler] = length; + _queriedState |= QueriedStateFlags.TextureArrayFromPool; + } + /// /// Indicates that the format of a given texture was used during the shader translation process. /// @@ -369,7 +399,7 @@ namespace Ryujinx.Graphics.Gpu.Shader } /// - /// Checks if a given texture was registerd on this specialization state. + /// Checks if a given texture was registered on this specialization state. /// /// Shader stage where the texture is used /// Offset in words of the texture handle on the texture buffer @@ -379,12 +409,35 @@ namespace Ryujinx.Graphics.Gpu.Shader return GetTextureSpecState(stageIndex, handle, cbufSlot) != null; } + /// + /// Checks if a given texture array (from constant buffer) was registered on this specialization state. + /// + /// Shader stage where the texture is used + /// Offset in words of the texture handle on the texture buffer + /// Slot of the texture buffer constant buffer + /// True if the length for the given buffer and stage exists, false otherwise + public bool TextureArrayFromBufferRegistered(int stageIndex, int handle, int cbufSlot) + { + return _textureArrayFromBufferSpecialization.ContainsKey(new TextureKey(stageIndex, handle, cbufSlot)); + } + + /// + /// Checks if a given texture array (from a sampler pool or texture pool) was registered on this specialization state. + /// + /// True for sampler pool, false for texture pool + /// True if the length for the given pool, false otherwise + public bool TextureArrayFromPoolRegistered(bool isSampler) + { + return _textureArrayFromPoolSpecialization.ContainsKey(isSampler); + } + /// /// Gets the recorded format of a given texture. /// /// Shader stage where the texture is used /// Offset in words of the texture handle on the texture buffer /// Slot of the texture buffer constant buffer + /// Format and sRGB tuple public (uint, bool) GetFormat(int stageIndex, int handle, int cbufSlot) { TextureSpecializationState state = GetTextureSpecState(stageIndex, handle, cbufSlot).Value; @@ -397,6 +450,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Shader stage where the texture is used /// Offset in words of the texture handle on the texture buffer /// Slot of the texture buffer constant buffer + /// Texture target public TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot) { return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.TextureTarget; @@ -408,11 +462,34 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Shader stage where the texture is used /// Offset in words of the texture handle on the texture buffer /// Slot of the texture buffer constant buffer + /// True if coordinates are normalized, false otherwise public bool GetCoordNormalized(int stageIndex, int handle, int cbufSlot) { return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.CoordNormalized; } + /// + /// Gets the recorded length of a given texture array (from constant buffer). + /// + /// Shader stage where the texture is used + /// Offset in words of the texture handle on the texture buffer + /// Slot of the texture buffer constant buffer + /// Texture array length + public int GetTextureArrayFromBufferLength(int stageIndex, int handle, int cbufSlot) + { + return _textureArrayFromBufferSpecialization[new TextureKey(stageIndex, handle, cbufSlot)]; + } + + /// + /// Gets the recorded length of a given texture array (from a sampler or texture pool). + /// + /// True to get the sampler pool length, false to get the texture pool length + /// Texture array length + public int GetTextureArrayFromPoolLength(bool isSampler) + { + return _textureArrayFromPoolSpecialization[isSampler]; + } + /// /// Gets texture specialization state for a given texture, or create a new one if not present. /// @@ -548,6 +625,12 @@ namespace Ryujinx.Graphics.Gpu.Shader return Matches(channel, ref poolState, checkTextures, isCompute: false); } + /// + /// Converts special vertex attribute groups to their generic equivalents, for comparison purposes. + /// + /// GPU channel + /// Vertex attribute type + /// Filtered attribute private static AttributeType FilterAttributeType(GpuChannel channel, AttributeType type) { type &= ~(AttributeType.Packed | AttributeType.PackedRgb10A2Signed); @@ -660,7 +743,7 @@ namespace Ryujinx.Graphics.Gpu.Shader constantBufferUsePerStageMask &= ~(1 << index); } - if (checkTextures) + if (checkTextures && _allTextures.Length > 0) { TexturePool pool = channel.TextureManager.GetTexturePool(poolState.TexturePoolGpuVa, poolState.TexturePoolMaximumId); @@ -838,6 +921,38 @@ namespace Ryujinx.Graphics.Gpu.Shader specState._textureSpecialization[textureKey] = textureState; } + if (specState._queriedState.HasFlag(QueriedStateFlags.TextureArrayFromBuffer)) + { + dataReader.Read(ref count); + + for (int index = 0; index < count; index++) + { + TextureKey textureKey = default; + int length = 0; + + dataReader.ReadWithMagicAndSize(ref textureKey, TexkMagic); + dataReader.Read(ref length); + + specState._textureArrayFromBufferSpecialization[textureKey] = length; + } + } + + if (specState._queriedState.HasFlag(QueriedStateFlags.TextureArrayFromPool)) + { + dataReader.Read(ref count); + + for (int index = 0; index < count; index++) + { + bool textureKey = default; + int length = 0; + + dataReader.ReadWithMagicAndSize(ref textureKey, TexkMagic); + dataReader.Read(ref length); + + specState._textureArrayFromPoolSpecialization[textureKey] = length; + } + } + return specState; } @@ -902,6 +1017,36 @@ namespace Ryujinx.Graphics.Gpu.Shader dataWriter.WriteWithMagicAndSize(ref textureKey, TexkMagic); dataWriter.WriteWithMagicAndSize(ref textureState.Value, TexsMagic); } + + if (_queriedState.HasFlag(QueriedStateFlags.TextureArrayFromBuffer)) + { + count = (ushort)_textureArrayFromBufferSpecialization.Count; + dataWriter.Write(ref count); + + foreach (var kv in _textureArrayFromBufferSpecialization) + { + var textureKey = kv.Key; + var length = kv.Value; + + dataWriter.WriteWithMagicAndSize(ref textureKey, TexkMagic); + dataWriter.Write(ref length); + } + } + + if (_queriedState.HasFlag(QueriedStateFlags.TextureArrayFromPool)) + { + count = (ushort)_textureArrayFromPoolSpecialization.Count; + dataWriter.Write(ref count); + + foreach (var kv in _textureArrayFromPoolSpecialization) + { + var textureKey = kv.Key; + var length = kv.Value; + + dataWriter.WriteWithMagicAndSize(ref textureKey, TexkMagic); + dataWriter.Write(ref length); + } + } } } } diff --git a/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs b/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs index c2fa4c248..1042a4db8 100644 --- a/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs @@ -1,4 +1,5 @@ using Ryujinx.Common.Logging; +using Ryujinx.Graphics.Device; using System; using System.Threading; @@ -7,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization /// /// GPU synchronization manager. /// - public class SynchronizationManager + public class SynchronizationManager : ISynchronizationManager { /// /// The maximum number of syncpoints supported by the GM20B. @@ -29,12 +30,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization } } - /// - /// Increment the value of a syncpoint with a given id. - /// - /// The id of the syncpoint - /// Thrown when id >= MaxHardwareSyncpoints - /// The incremented value of the syncpoint + /// public uint IncrementSyncpoint(uint id) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(id, (uint)MaxHardwareSyncpoints); @@ -42,12 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization return _syncpoints[id].Increment(); } - /// - /// Get the value of a syncpoint with a given id. - /// - /// The id of the syncpoint - /// Thrown when id >= MaxHardwareSyncpoints - /// The value of the syncpoint + /// public uint GetSyncpointValue(uint id) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(id, (uint)MaxHardwareSyncpoints); @@ -84,15 +75,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization _syncpoints[id].UnregisterCallback(waiterInformation); } - /// - /// Wait on a syncpoint with a given id at a target threshold. - /// The callback will be called once the threshold is reached and will automatically be unregistered. - /// - /// The id of the syncpoint - /// The target threshold - /// The timeout - /// Thrown when id >= MaxHardwareSyncpoints - /// True if timed out + /// public bool WaitOnSyncpoint(uint id, uint threshold, TimeSpan timeout) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(id, (uint)MaxHardwareSyncpoints); diff --git a/src/Ryujinx.Graphics.Gpu/Window.cs b/src/Ryujinx.Graphics.Gpu/Window.cs index 3b2368537..59cd4c8a6 100644 --- a/src/Ryujinx.Graphics.Gpu/Window.cs +++ b/src/Ryujinx.Graphics.Gpu/Window.cs @@ -131,7 +131,7 @@ namespace Ryujinx.Graphics.Gpu bool isLinear, int gobBlocksInY, Format format, - int bytesPerPixel, + byte bytesPerPixel, ImageCrop crop, Action acquireCallback, Action releaseCallback, diff --git a/src/Ryujinx.Graphics.Host1x/Host1xClass.cs b/src/Ryujinx.Graphics.Host1x/Host1xClass.cs index 4327b93c2..3ffc87ba5 100644 --- a/src/Ryujinx.Graphics.Host1x/Host1xClass.cs +++ b/src/Ryujinx.Graphics.Host1x/Host1xClass.cs @@ -1,5 +1,4 @@ using Ryujinx.Graphics.Device; -using Ryujinx.Graphics.Gpu.Synchronization; using System.Collections.Generic; using System.Threading; @@ -7,10 +6,10 @@ namespace Ryujinx.Graphics.Host1x { public class Host1xClass : IDeviceState { - private readonly SynchronizationManager _syncMgr; + private readonly ISynchronizationManager _syncMgr; private readonly DeviceState _state; - public Host1xClass(SynchronizationManager syncMgr) + public Host1xClass(ISynchronizationManager syncMgr) { _syncMgr = syncMgr; _state = new DeviceState(new Dictionary diff --git a/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs b/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs index 6733b32aa..2db74ce5e 100644 --- a/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs +++ b/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs @@ -1,7 +1,6 @@ using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.Graphics.Device; -using Ryujinx.Graphics.Gpu.Synchronization; using System; using System.Numerics; @@ -35,7 +34,7 @@ namespace Ryujinx.Graphics.Host1x private int _mask; private bool _incrementing; - public Host1xDevice(SynchronizationManager syncMgr) + public Host1xDevice(ISynchronizationManager syncMgr) { _syncptIncrMgr = new SyncptIncrManager(syncMgr); _commandQueue = new AsyncWorkQueue(Process, "Ryujinx.Host1xProcessor"); diff --git a/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj b/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj index 22959fad8..d631d039f 100644 --- a/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj +++ b/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj @@ -6,7 +6,6 @@ - diff --git a/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs b/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs index 164d15ec2..a5ee1198c 100644 --- a/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs +++ b/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs @@ -1,11 +1,11 @@ -using Ryujinx.Graphics.Gpu.Synchronization; +using Ryujinx.Graphics.Device; using System.Collections.Generic; namespace Ryujinx.Graphics.Host1x { class SyncptIncrManager { - private readonly SynchronizationManager _syncMgr; + private readonly ISynchronizationManager _syncMgr; private readonly struct SyncptIncr { @@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Host1x private uint _currentId; - public SyncptIncrManager(SynchronizationManager syncMgr) + public SyncptIncrManager(ISynchronizationManager syncMgr) { _syncMgr = syncMgr; } diff --git a/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs b/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs index ef8ab9086..6058f72d6 100644 --- a/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs +++ b/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs @@ -12,10 +12,10 @@ namespace Ryujinx.Graphics.Nvdec public static void Decode(NvdecDecoderContext context, ResourceManager rm, ref NvdecRegisters state) { - PictureInfo pictureInfo = rm.Gmm.DeviceRead(state.SetDrvPicSetupOffset); + PictureInfo pictureInfo = rm.MemoryManager.DeviceRead(state.SetDrvPicSetupOffset); H264PictureInfo info = pictureInfo.Convert(); - ReadOnlySpan bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize); + ReadOnlySpan bitstream = rm.MemoryManager.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize); int width = (int)pictureInfo.PicWidthInMbs * MbSizeInPixels; int height = (int)pictureInfo.PicHeightInMbs * MbSizeInPixels; @@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Nvdec if (outputSurface.Field == FrameField.Progressive) { SurfaceWriter.Write( - rm.Gmm, + rm.MemoryManager, outputSurface, lumaOffset + pictureInfo.LumaFrameOffset, chromaOffset + pictureInfo.ChromaFrameOffset); @@ -42,7 +42,7 @@ namespace Ryujinx.Graphics.Nvdec else { SurfaceWriter.WriteInterlaced( - rm.Gmm, + rm.MemoryManager, outputSurface, lumaOffset + pictureInfo.LumaTopFieldOffset, chromaOffset + pictureInfo.ChromaTopFieldOffset, diff --git a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs index 4a4e1a3f6..7359b3309 100644 --- a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs +++ b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs @@ -1,4 +1,4 @@ -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Video; using System; using System.Diagnostics; @@ -27,11 +27,11 @@ namespace Ryujinx.Graphics.Nvdec.Image private readonly CacheItem[] _pool = new CacheItem[MaxItems]; - private readonly MemoryManager _gmm; + private readonly DeviceMemoryManager _mm; - public SurfaceCache(MemoryManager gmm) + public SurfaceCache(DeviceMemoryManager mm) { - _gmm = gmm; + _mm = mm; } public ISurface Get(IDecoder decoder, uint lumaOffset, uint chromaOffset, int width, int height) @@ -77,7 +77,7 @@ namespace Ryujinx.Graphics.Nvdec.Image if ((lumaOffset | chromaOffset) != 0) { - SurfaceReader.Read(_gmm, surface, lumaOffset, chromaOffset); + SurfaceReader.Read(_mm, surface, lumaOffset, chromaOffset); } MoveToFront(i); @@ -100,7 +100,7 @@ namespace Ryujinx.Graphics.Nvdec.Image if ((lumaOffset | chromaOffset) != 0) { - SurfaceReader.Read(_gmm, surface, lumaOffset, chromaOffset); + SurfaceReader.Read(_mm, surface, lumaOffset, chromaOffset); } MoveToFront(MaxItems - 1); diff --git a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs index e87956852..f510c128d 100644 --- a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs +++ b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs @@ -1,5 +1,5 @@ using Ryujinx.Common; -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Video; using System; @@ -11,13 +11,13 @@ namespace Ryujinx.Graphics.Nvdec.Image { static class SurfaceReader { - public static void Read(MemoryManager gmm, ISurface surface, uint lumaOffset, uint chromaOffset) + public static void Read(DeviceMemoryManager mm, ISurface surface, uint lumaOffset, uint chromaOffset) { int width = surface.Width; int height = surface.Height; int stride = surface.Stride; - ReadOnlySpan luma = gmm.DeviceGetSpan(lumaOffset, GetBlockLinearSize(width, height, 1)); + ReadOnlySpan luma = mm.DeviceGetSpan(lumaOffset, GetBlockLinearSize(width, height, 1)); ReadLuma(surface.YPlane.AsSpan(), luma, stride, width, height); @@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Nvdec.Image int uvHeight = surface.UvHeight; int uvStride = surface.UvStride; - ReadOnlySpan chroma = gmm.DeviceGetSpan(chromaOffset, GetBlockLinearSize(uvWidth, uvHeight, 2)); + ReadOnlySpan chroma = mm.DeviceGetSpan(chromaOffset, GetBlockLinearSize(uvWidth, uvHeight, 2)); ReadChroma(surface.UPlane.AsSpan(), surface.VPlane.AsSpan(), chroma, uvStride, uvWidth, uvHeight); } diff --git a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs index b4f028998..043be1f2b 100644 --- a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs +++ b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs @@ -1,5 +1,5 @@ using Ryujinx.Common; -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Video; using System; @@ -12,11 +12,11 @@ namespace Ryujinx.Graphics.Nvdec.Image { static class SurfaceWriter { - public static void Write(MemoryManager gmm, ISurface surface, uint lumaOffset, uint chromaOffset) + public static void Write(DeviceMemoryManager mm, ISurface surface, uint lumaOffset, uint chromaOffset) { int lumaSize = GetBlockLinearSize(surface.Width, surface.Height, 1); - using var luma = gmm.GetWritableRegion(ExtendOffset(lumaOffset), lumaSize); + using var luma = mm.GetWritableRegion(ExtendOffset(lumaOffset), lumaSize); WriteLuma( luma.Memory.Span, @@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Nvdec.Image int chromaSize = GetBlockLinearSize(surface.UvWidth, surface.UvHeight, 2); - using var chroma = gmm.GetWritableRegion(ExtendOffset(chromaOffset), chromaSize); + using var chroma = mm.GetWritableRegion(ExtendOffset(chromaOffset), chromaSize); WriteChroma( chroma.Memory.Span, @@ -39,7 +39,7 @@ namespace Ryujinx.Graphics.Nvdec.Image } public static void WriteInterlaced( - MemoryManager gmm, + DeviceMemoryManager mm, ISurface surface, uint lumaTopOffset, uint chromaTopOffset, @@ -48,8 +48,8 @@ namespace Ryujinx.Graphics.Nvdec.Image { int lumaSize = GetBlockLinearSize(surface.Width, surface.Height / 2, 1); - using var lumaTop = gmm.GetWritableRegion(ExtendOffset(lumaTopOffset), lumaSize); - using var lumaBottom = gmm.GetWritableRegion(ExtendOffset(lumaBottomOffset), lumaSize); + using var lumaTop = mm.GetWritableRegion(ExtendOffset(lumaTopOffset), lumaSize); + using var lumaBottom = mm.GetWritableRegion(ExtendOffset(lumaBottomOffset), lumaSize); WriteLuma( lumaTop.Memory.Span, @@ -67,8 +67,8 @@ namespace Ryujinx.Graphics.Nvdec.Image int chromaSize = GetBlockLinearSize(surface.UvWidth, surface.UvHeight / 2, 2); - using var chromaTop = gmm.GetWritableRegion(ExtendOffset(chromaTopOffset), chromaSize); - using var chromaBottom = gmm.GetWritableRegion(ExtendOffset(chromaBottomOffset), chromaSize); + using var chromaTop = mm.GetWritableRegion(ExtendOffset(chromaTopOffset), chromaSize); + using var chromaBottom = mm.GetWritableRegion(ExtendOffset(chromaBottomOffset), chromaSize); WriteChroma( chromaTop.Memory.Span, diff --git a/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs b/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs index 28d42a8b4..1477ed914 100644 --- a/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs +++ b/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs @@ -1,23 +1,23 @@ -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using System; namespace Ryujinx.Graphics.Nvdec { static class MemoryExtensions { - public static T DeviceRead(this MemoryManager gmm, uint offset) where T : unmanaged + public static T DeviceRead(this DeviceMemoryManager gmm, uint offset) where T : unmanaged { - return gmm.Read((ulong)offset << 8); + return gmm.Read(ExtendOffset(offset)); } - public static ReadOnlySpan DeviceGetSpan(this MemoryManager gmm, uint offset, int size) + public static ReadOnlySpan DeviceGetSpan(this DeviceMemoryManager gmm, uint offset, int size) { - return gmm.GetSpan((ulong)offset << 8, size); + return gmm.GetSpan(ExtendOffset(offset), size); } - public static void DeviceWrite(this MemoryManager gmm, uint offset, ReadOnlySpan data) + public static void DeviceWrite(this DeviceMemoryManager gmm, uint offset, ReadOnlySpan data) { - gmm.Write((ulong)offset << 8, data); + gmm.Write(ExtendOffset(offset), data); } public static ulong ExtendOffset(uint offset) diff --git a/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs b/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs index 77e295544..29e260d63 100644 --- a/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs +++ b/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs @@ -1,6 +1,5 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.Device; -using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Nvdec.Image; using System.Collections.Concurrent; using System.Collections.Generic; @@ -17,9 +16,9 @@ namespace Ryujinx.Graphics.Nvdec private readonly ConcurrentDictionary _contexts; private NvdecDecoderContext _currentContext; - public NvdecDevice(MemoryManager gmm) + public NvdecDevice(DeviceMemoryManager mm) { - _rm = new ResourceManager(gmm, new SurfaceCache(gmm)); + _rm = new ResourceManager(mm, new SurfaceCache(mm)); _state = new DeviceState(new Dictionary { { nameof(NvdecRegisters.Execute), new RwCallback(Execute, null) }, diff --git a/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs b/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs index 200d3a1bd..da0ded912 100644 --- a/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs +++ b/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs @@ -1,16 +1,16 @@ -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Nvdec.Image; namespace Ryujinx.Graphics.Nvdec { readonly struct ResourceManager { - public MemoryManager Gmm { get; } + public DeviceMemoryManager MemoryManager { get; } public SurfaceCache Cache { get; } - public ResourceManager(MemoryManager gmm, SurfaceCache cache) + public ResourceManager(DeviceMemoryManager mm, SurfaceCache cache) { - Gmm = gmm; + MemoryManager = mm; Cache = cache; } } diff --git a/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj b/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj index fd49a7c80..6c00e9a7c 100644 --- a/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj +++ b/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj @@ -8,7 +8,6 @@ - diff --git a/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs b/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs index 0a7d5840e..3d2543c49 100644 --- a/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs +++ b/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs @@ -10,8 +10,8 @@ namespace Ryujinx.Graphics.Nvdec { public static void Decode(NvdecDecoderContext context, ResourceManager rm, ref NvdecRegisters state) { - PictureInfo pictureInfo = rm.Gmm.DeviceRead(state.SetDrvPicSetupOffset); - ReadOnlySpan bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.VLDBufferSize); + PictureInfo pictureInfo = rm.MemoryManager.DeviceRead(state.SetDrvPicSetupOffset); + ReadOnlySpan bitstream = rm.MemoryManager.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.VLDBufferSize); Decoder decoder = context.GetVp8Decoder(); @@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Nvdec if (decoder.Decode(ref info, outputSurface, bitstream)) { - SurfaceWriter.Write(rm.Gmm, outputSurface, lumaOffset, chromaOffset); + SurfaceWriter.Write(rm.MemoryManager, outputSurface, lumaOffset, chromaOffset); } rm.Cache.Put(outputSurface); diff --git a/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs b/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs index 037950562..5ed508647 100644 --- a/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs +++ b/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs @@ -1,5 +1,5 @@ using Ryujinx.Common; -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Nvdec.Image; using Ryujinx.Graphics.Nvdec.Types.Vp9; using Ryujinx.Graphics.Nvdec.Vp9; @@ -17,8 +17,8 @@ namespace Ryujinx.Graphics.Nvdec public unsafe static void Decode(ResourceManager rm, ref NvdecRegisters state) { - PictureInfo pictureInfo = rm.Gmm.DeviceRead(state.SetDrvPicSetupOffset); - EntropyProbs entropy = rm.Gmm.DeviceRead(state.Vp9SetProbTabBufOffset); + PictureInfo pictureInfo = rm.MemoryManager.DeviceRead(state.SetDrvPicSetupOffset); + EntropyProbs entropy = rm.MemoryManager.DeviceRead(state.Vp9SetProbTabBufOffset); ISurface Rent(uint lumaOffset, uint chromaOffset, FrameSize size) { @@ -38,19 +38,19 @@ namespace Ryujinx.Graphics.Nvdec entropy.Convert(ref info.Entropy); - ReadOnlySpan bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize); + ReadOnlySpan bitstream = rm.MemoryManager.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize); ReadOnlySpan mvsIn = ReadOnlySpan.Empty; if (info.UsePrevInFindMvRefs) { - mvsIn = GetMvsInput(rm.Gmm, pictureInfo.CurrentFrameSize, state.Vp9SetColMvReadBufOffset); + mvsIn = GetMvsInput(rm.MemoryManager, pictureInfo.CurrentFrameSize, state.Vp9SetColMvReadBufOffset); } int miCols = BitUtils.DivRoundUp(pictureInfo.CurrentFrameSize.Width, 8); int miRows = BitUtils.DivRoundUp(pictureInfo.CurrentFrameSize.Height, 8); - using var mvsRegion = rm.Gmm.GetWritableRegion(ExtendOffset(state.Vp9SetColMvWriteBufOffset), miRows * miCols * 16); + using var mvsRegion = rm.MemoryManager.GetWritableRegion(ExtendOffset(state.Vp9SetColMvWriteBufOffset), miRows * miCols * 16); Span mvsOut = MemoryMarshal.Cast(mvsRegion.Memory.Span); @@ -59,10 +59,10 @@ namespace Ryujinx.Graphics.Nvdec if (_decoder.Decode(ref info, currentSurface, bitstream, mvsIn, mvsOut)) { - SurfaceWriter.Write(rm.Gmm, currentSurface, lumaOffset, chromaOffset); + SurfaceWriter.Write(rm.MemoryManager, currentSurface, lumaOffset, chromaOffset); } - WriteBackwardUpdates(rm.Gmm, state.Vp9SetCtxCounterBufOffset, ref info.BackwardUpdateCounts); + WriteBackwardUpdates(rm.MemoryManager, state.Vp9SetCtxCounterBufOffset, ref info.BackwardUpdateCounts); rm.Cache.Put(lastSurface); rm.Cache.Put(goldenSurface); @@ -70,17 +70,17 @@ namespace Ryujinx.Graphics.Nvdec rm.Cache.Put(currentSurface); } - private static ReadOnlySpan GetMvsInput(MemoryManager gmm, FrameSize size, uint offset) + private static ReadOnlySpan GetMvsInput(DeviceMemoryManager mm, FrameSize size, uint offset) { int miCols = BitUtils.DivRoundUp(size.Width, 8); int miRows = BitUtils.DivRoundUp(size.Height, 8); - return MemoryMarshal.Cast(gmm.DeviceGetSpan(offset, miRows * miCols * 16)); + return MemoryMarshal.Cast(mm.DeviceGetSpan(offset, miRows * miCols * 16)); } - private static void WriteBackwardUpdates(MemoryManager gmm, uint offset, ref Vp9BackwardUpdates counts) + private static void WriteBackwardUpdates(DeviceMemoryManager mm, uint offset, ref Vp9BackwardUpdates counts) { - using var backwardUpdatesRegion = gmm.GetWritableRegion(ExtendOffset(offset), Unsafe.SizeOf()); + using var backwardUpdatesRegion = mm.GetWritableRegion(ExtendOffset(offset), Unsafe.SizeOf()); ref var backwardUpdates = ref MemoryMarshal.Cast(backwardUpdatesRegion.Memory.Span)[0]; diff --git a/src/Ryujinx.Graphics.OpenGL/BackgroundContextWorker.cs b/src/Ryujinx.Graphics.OpenGL/BackgroundContextWorker.cs index ae647e388..f22e0df57 100644 --- a/src/Ryujinx.Graphics.OpenGL/BackgroundContextWorker.cs +++ b/src/Ryujinx.Graphics.OpenGL/BackgroundContextWorker.cs @@ -30,6 +30,8 @@ namespace Ryujinx.Graphics.OpenGL _thread.Start(); } + public bool HasContext() => _backgroundContext.HasContext(); + private void Run() { InBackground = true; diff --git a/src/Ryujinx.Graphics.OpenGL/Effects/AreaScalingFilter.cs b/src/Ryujinx.Graphics.OpenGL/Effects/AreaScalingFilter.cs new file mode 100644 index 000000000..9b19f2f26 --- /dev/null +++ b/src/Ryujinx.Graphics.OpenGL/Effects/AreaScalingFilter.cs @@ -0,0 +1,106 @@ +using OpenTK.Graphics.OpenGL; +using Ryujinx.Common; +using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.OpenGL.Image; +using System; +using static Ryujinx.Graphics.OpenGL.Effects.ShaderHelper; + +namespace Ryujinx.Graphics.OpenGL.Effects +{ + internal class AreaScalingFilter : IScalingFilter + { + private readonly OpenGLRenderer _renderer; + private int _inputUniform; + private int _outputUniform; + private int _srcX0Uniform; + private int _srcX1Uniform; + private int _srcY0Uniform; + private int _scalingShaderProgram; + private int _srcY1Uniform; + private int _dstX0Uniform; + private int _dstX1Uniform; + private int _dstY0Uniform; + private int _dstY1Uniform; + + public float Level { get; set; } + + public AreaScalingFilter(OpenGLRenderer renderer) + { + Initialize(); + + _renderer = renderer; + } + + public void Dispose() + { + if (_scalingShaderProgram != 0) + { + GL.DeleteProgram(_scalingShaderProgram); + } + } + + private void Initialize() + { + var scalingShader = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl"); + + _scalingShaderProgram = CompileProgram(scalingShader, ShaderType.ComputeShader); + + _inputUniform = GL.GetUniformLocation(_scalingShaderProgram, "Source"); + _outputUniform = GL.GetUniformLocation(_scalingShaderProgram, "imgOutput"); + + _srcX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX0"); + _srcX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX1"); + _srcY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY0"); + _srcY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY1"); + _dstX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX0"); + _dstX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX1"); + _dstY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY0"); + _dstY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY1"); + } + + public void Run( + TextureView view, + TextureView destinationTexture, + int width, + int height, + Extents2D source, + Extents2D destination) + { + int previousProgram = GL.GetInteger(GetPName.CurrentProgram); + int previousUnit = GL.GetInteger(GetPName.ActiveTexture); + GL.ActiveTexture(TextureUnit.Texture0); + int previousTextureBinding = GL.GetInteger(GetPName.TextureBinding2D); + + GL.BindImageTexture(0, destinationTexture.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8); + + int threadGroupWorkRegionDim = 16; + int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; + int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; + + // Scaling pass + GL.UseProgram(_scalingShaderProgram); + view.Bind(0); + GL.Uniform1(_inputUniform, 0); + GL.Uniform1(_outputUniform, 0); + GL.Uniform1(_srcX0Uniform, (float)source.X1); + GL.Uniform1(_srcX1Uniform, (float)source.X2); + GL.Uniform1(_srcY0Uniform, (float)source.Y1); + GL.Uniform1(_srcY1Uniform, (float)source.Y2); + GL.Uniform1(_dstX0Uniform, (float)destination.X1); + GL.Uniform1(_dstX1Uniform, (float)destination.X2); + GL.Uniform1(_dstY0Uniform, (float)destination.Y1); + GL.Uniform1(_dstY1Uniform, (float)destination.Y2); + GL.DispatchCompute(dispatchX, dispatchY, 1); + + GL.UseProgram(previousProgram); + GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit); + + (_renderer.Pipeline as Pipeline).RestoreImages1And2(); + + GL.ActiveTexture(TextureUnit.Texture0); + GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding); + + GL.ActiveTexture((TextureUnit)previousUnit); + } + } +} diff --git a/src/Ryujinx.Graphics.OpenGL/Effects/FsrScalingFilter.cs b/src/Ryujinx.Graphics.OpenGL/Effects/FsrScalingFilter.cs index 1a130bebb..0522e28e0 100644 --- a/src/Ryujinx.Graphics.OpenGL/Effects/FsrScalingFilter.cs +++ b/src/Ryujinx.Graphics.OpenGL/Effects/FsrScalingFilter.cs @@ -18,7 +18,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects private int _srcY0Uniform; private int _scalingShaderProgram; private int _sharpeningShaderProgram; - private float _scale = 1; + private float _sharpeningLevel = 1; private int _srcY1Uniform; private int _dstX0Uniform; private int _dstX1Uniform; @@ -30,10 +30,10 @@ namespace Ryujinx.Graphics.OpenGL.Effects public float Level { - get => _scale; + get => _sharpeningLevel; set { - _scale = MathF.Max(0.01f, value); + _sharpeningLevel = MathF.Max(0.01f, value); } } diff --git a/src/Ryujinx.Graphics.OpenGL/Effects/ShaderHelper.cs b/src/Ryujinx.Graphics.OpenGL/Effects/ShaderHelper.cs index c25fe5b25..637b2fba8 100644 --- a/src/Ryujinx.Graphics.OpenGL/Effects/ShaderHelper.cs +++ b/src/Ryujinx.Graphics.OpenGL/Effects/ShaderHelper.cs @@ -1,4 +1,5 @@ using OpenTK.Graphics.OpenGL; +using Ryujinx.Common.Logging; namespace Ryujinx.Graphics.OpenGL.Effects { @@ -6,18 +7,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects { public static int CompileProgram(string shaderCode, ShaderType shaderType) { - var shader = GL.CreateShader(shaderType); - GL.ShaderSource(shader, shaderCode); - GL.CompileShader(shader); - - var program = GL.CreateProgram(); - GL.AttachShader(program, shader); - GL.LinkProgram(program); - - GL.DetachShader(program, shader); - GL.DeleteShader(shader); - - return program; + return CompileProgram(new string[] { shaderCode }, shaderType); } public static int CompileProgram(string[] shaders, ShaderType shaderType) @@ -26,6 +16,15 @@ namespace Ryujinx.Graphics.OpenGL.Effects GL.ShaderSource(shader, shaders.Length, shaders, (int[])null); GL.CompileShader(shader); + GL.GetShader(shader, ShaderParameter.CompileStatus, out int isCompiled); + if (isCompiled == 0) + { + string log = GL.GetShaderInfoLog(shader); + Logger.Error?.Print(LogClass.Gpu, $"Failed to compile effect shader:\n\n{log}\n"); + GL.DeleteShader(shader); + return 0; + } + var program = GL.CreateProgram(); GL.AttachShader(program, shader); GL.LinkProgram(program); diff --git a/src/Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl b/src/Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl new file mode 100644 index 000000000..0fe20d3f9 --- /dev/null +++ b/src/Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl @@ -0,0 +1,119 @@ +#version 430 core +precision mediump float; +layout (local_size_x = 16, local_size_y = 16) in; +layout(rgba8, binding = 0, location=0) uniform image2D imgOutput; +layout( location=1 ) uniform sampler2D Source; +layout( location=2 ) uniform float srcX0; +layout( location=3 ) uniform float srcX1; +layout( location=4 ) uniform float srcY0; +layout( location=5 ) uniform float srcY1; +layout( location=6 ) uniform float dstX0; +layout( location=7 ) uniform float dstX1; +layout( location=8 ) uniform float dstY0; +layout( location=9 ) uniform float dstY1; + +/***** Area Sampling *****/ + +// By Sam Belliveau and Filippo Tarpini. Public Domain license. +// Effectively a more accurate sharp bilinear filter when upscaling, +// that also works as a mathematically perfect downscale filter. +// https://entropymine.com/imageworsener/pixelmixing/ +// https://github.com/obsproject/obs-studio/pull/1715 +// https://legacy.imagemagick.org/Usage/filter/ +vec4 AreaSampling(vec2 xy) +{ + // Determine the sizes of the source and target images. + vec2 source_size = vec2(abs(srcX1 - srcX0), abs(srcY1 - srcY0)); + vec2 target_size = vec2(abs(dstX1 - dstX0), abs(dstY1 - dstY0)); + vec2 inverted_target_size = vec2(1.0) / target_size; + + // Compute the top-left and bottom-right corners of the target pixel box. + vec2 t_beg = floor(xy - vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1)); + vec2 t_end = t_beg + vec2(1.0, 1.0); + + // Convert the target pixel box to source pixel box. + vec2 beg = t_beg * inverted_target_size * source_size; + vec2 end = t_end * inverted_target_size * source_size; + + // Compute the top-left and bottom-right corners of the pixel box. + ivec2 f_beg = ivec2(beg); + ivec2 f_end = ivec2(end); + + // Compute how much of the start and end pixels are covered horizontally & vertically. + float area_w = 1.0 - fract(beg.x); + float area_n = 1.0 - fract(beg.y); + float area_e = fract(end.x); + float area_s = fract(end.y); + + // Compute the areas of the corner pixels in the pixel box. + float area_nw = area_n * area_w; + float area_ne = area_n * area_e; + float area_sw = area_s * area_w; + float area_se = area_s * area_e; + + // Initialize the color accumulator. + vec4 avg_color = vec4(0.0, 0.0, 0.0, 0.0); + + // Accumulate corner pixels. + avg_color += area_nw * texelFetch(Source, ivec2(f_beg.x, f_beg.y), 0); + avg_color += area_ne * texelFetch(Source, ivec2(f_end.x, f_beg.y), 0); + avg_color += area_sw * texelFetch(Source, ivec2(f_beg.x, f_end.y), 0); + avg_color += area_se * texelFetch(Source, ivec2(f_end.x, f_end.y), 0); + + // Determine the size of the pixel box. + int x_range = int(f_end.x - f_beg.x - 0.5); + int y_range = int(f_end.y - f_beg.y - 0.5); + + // Accumulate top and bottom edge pixels. + for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) + { + avg_color += area_n * texelFetch(Source, ivec2(x, f_beg.y), 0); + avg_color += area_s * texelFetch(Source, ivec2(x, f_end.y), 0); + } + + // Accumulate left and right edge pixels and all the pixels in between. + for (int y = f_beg.y + 1; y <= f_beg.y + y_range; ++y) + { + avg_color += area_w * texelFetch(Source, ivec2(f_beg.x, y), 0); + avg_color += area_e * texelFetch(Source, ivec2(f_end.x, y), 0); + + for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) + { + avg_color += texelFetch(Source, ivec2(x, y), 0); + } + } + + // Compute the area of the pixel box that was sampled. + float area_corners = area_nw + area_ne + area_sw + area_se; + float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e); + float area_center = float(x_range) * float(y_range); + + // Return the normalized average color. + return avg_color / (area_corners + area_edges + area_center); +} + +float insideBox(vec2 v, vec2 bLeft, vec2 tRight) { + vec2 s = step(bLeft, v) - step(tRight, v); + return s.x * s.y; +} + +vec2 translateDest(vec2 pos) { + vec2 translatedPos = vec2(pos.x, pos.y); + translatedPos.x = dstX1 < dstX0 ? dstX1 - translatedPos.x : translatedPos.x; + translatedPos.y = dstY0 > dstY1 ? dstY0 + dstY1 - translatedPos.y - 1 : translatedPos.y; + return translatedPos; +} + +void main() +{ + vec2 bLeft = vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1); + vec2 tRight = vec2(dstX1 > dstX0 ? dstX1 : dstX0, dstY1 > dstY0 ? dstY1 : dstY0); + ivec2 loc = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y); + if (insideBox(loc, bLeft, tRight) == 0) { + imageStore(imgOutput, loc, vec4(0, 0, 0, 1)); + return; + } + + vec4 outColor = AreaSampling(loc); + imageStore(imgOutput, ivec2(translateDest(loc)), vec4(outColor.rgb, 1)); +} diff --git a/src/Ryujinx.Graphics.OpenGL/Effects/Shaders/fsr_scaling.glsl b/src/Ryujinx.Graphics.OpenGL/Effects/Shaders/fsr_scaling.glsl index 8e8755db2..3c7d485b1 100644 --- a/src/Ryujinx.Graphics.OpenGL/Effects/Shaders/fsr_scaling.glsl +++ b/src/Ryujinx.Graphics.OpenGL/Effects/Shaders/fsr_scaling.glsl @@ -85,4 +85,4 @@ void main() { CurrFilter(gxy); gxy.x -= 8u; CurrFilter(gxy); -} \ No newline at end of file +} diff --git a/src/Ryujinx.Graphics.OpenGL/Effects/SmaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.OpenGL/Effects/SmaaPostProcessingEffect.cs index 46dda13f2..a6c5e4aca 100644 --- a/src/Ryujinx.Graphics.OpenGL/Effects/SmaaPostProcessingEffect.cs +++ b/src/Ryujinx.Graphics.OpenGL/Effects/SmaaPostProcessingEffect.cs @@ -33,7 +33,8 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa public int Quality { - get => _quality; set + get => _quality; + set { _quality = Math.Clamp(value, 0, _qualities.Length - 1); } @@ -150,8 +151,8 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa _areaTexture = new TextureStorage(_renderer, areaInfo); _searchTexture = new TextureStorage(_renderer, searchInfo); - var areaTexture = EmbeddedResources.Read("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaAreaTexture.bin"); - var searchTexture = EmbeddedResources.Read("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaSearchTexture.bin"); + var areaTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaAreaTexture.bin"); + var searchTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaSearchTexture.bin"); var areaView = _areaTexture.CreateDefaultView(); var searchView = _searchTexture.CreateDefaultView(); diff --git a/src/Ryujinx.Graphics.OpenGL/FormatTable.cs b/src/Ryujinx.Graphics.OpenGL/FormatTable.cs index 3dac33b94..4cf4dc760 100644 --- a/src/Ryujinx.Graphics.OpenGL/FormatTable.cs +++ b/src/Ryujinx.Graphics.OpenGL/FormatTable.cs @@ -68,6 +68,7 @@ namespace Ryujinx.Graphics.OpenGL Add(Format.S8Uint, new FormatInfo(1, false, false, All.StencilIndex8, PixelFormat.StencilIndex, PixelType.UnsignedByte)); Add(Format.D16Unorm, new FormatInfo(1, false, false, All.DepthComponent16, PixelFormat.DepthComponent, PixelType.UnsignedShort)); Add(Format.S8UintD24Unorm, new FormatInfo(1, false, false, All.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248)); + Add(Format.X8UintD24Unorm, new FormatInfo(1, false, false, All.DepthComponent24, PixelFormat.DepthComponent, PixelType.UnsignedInt)); Add(Format.D32Float, new FormatInfo(1, false, false, All.DepthComponent32f, PixelFormat.DepthComponent, PixelType.Float)); Add(Format.D24UnormS8Uint, new FormatInfo(1, false, false, All.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248)); Add(Format.D32FloatS8Uint, new FormatInfo(1, false, false, All.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev)); @@ -161,6 +162,7 @@ namespace Ryujinx.Graphics.OpenGL Add(Format.A1B5G5R5Unorm, new FormatInfo(4, true, false, All.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551)); Add(Format.B8G8R8A8Unorm, new FormatInfo(4, true, false, All.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte)); Add(Format.B8G8R8A8Srgb, new FormatInfo(4, false, false, All.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte)); + Add(Format.B10G10R10A2Unorm, new FormatInfo(4, false, false, All.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed)); Add(Format.R8Unorm, SizedInternalFormat.R8); Add(Format.R8Uint, SizedInternalFormat.R8ui); @@ -223,5 +225,17 @@ namespace Ryujinx.Graphics.OpenGL { return _tableImage[(int)format]; } + + public static bool IsPackedDepthStencil(Format format) + { + return format == Format.D24UnormS8Uint || + format == Format.D32FloatS8Uint || + format == Format.S8UintD24Unorm; + } + + public static bool IsDepthOnly(Format format) + { + return format == Format.D16Unorm || format == Format.D32Float || format == Format.X8UintD24Unorm; + } } } diff --git a/src/Ryujinx.Graphics.OpenGL/Framebuffer.cs b/src/Ryujinx.Graphics.OpenGL/Framebuffer.cs index 3b79c5d6b..394b8bc76 100644 --- a/src/Ryujinx.Graphics.OpenGL/Framebuffer.cs +++ b/src/Ryujinx.Graphics.OpenGL/Framebuffer.cs @@ -119,11 +119,11 @@ namespace Ryujinx.Graphics.OpenGL private static FramebufferAttachment GetAttachment(Format format) { - if (IsPackedDepthStencilFormat(format)) + if (FormatTable.IsPackedDepthStencil(format)) { return FramebufferAttachment.DepthStencilAttachment; } - else if (IsDepthOnlyFormat(format)) + else if (FormatTable.IsDepthOnly(format)) { return FramebufferAttachment.DepthAttachment; } @@ -133,18 +133,6 @@ namespace Ryujinx.Graphics.OpenGL } } - private static bool IsPackedDepthStencilFormat(Format format) - { - return format == Format.D24UnormS8Uint || - format == Format.D32FloatS8Uint || - format == Format.S8UintD24Unorm; - } - - private static bool IsDepthOnlyFormat(Format format) - { - return format == Format.D16Unorm || format == Format.D32Float; - } - public int GetColorLayerCount(int index) { return _colors[index]?.Info.GetDepthOrLayers() ?? 0; diff --git a/src/Ryujinx.Graphics.OpenGL/IOpenGLContext.cs b/src/Ryujinx.Graphics.OpenGL/IOpenGLContext.cs index a11b9cb29..525418d74 100644 --- a/src/Ryujinx.Graphics.OpenGL/IOpenGLContext.cs +++ b/src/Ryujinx.Graphics.OpenGL/IOpenGLContext.cs @@ -7,21 +7,6 @@ namespace Ryujinx.Graphics.OpenGL { void MakeCurrent(); - // TODO: Support more APIs per platform. - static bool HasContext() - { - if (OperatingSystem.IsWindows()) - { - return WGLHelper.GetCurrentContext() != IntPtr.Zero; - } - else if (OperatingSystem.IsLinux()) - { - return GLXHelper.GetCurrentContext() != IntPtr.Zero; - } - else - { - return false; - } - } + bool HasContext(); } } diff --git a/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs b/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs index c4bbf7456..490c0c585 100644 --- a/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs +++ b/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Memory; using System; using System.Numerics; using System.Runtime.InteropServices; @@ -8,9 +9,11 @@ namespace Ryujinx.Graphics.OpenGL.Image { static class FormatConverter { - public unsafe static byte[] ConvertS8D24ToD24S8(ReadOnlySpan data) + public unsafe static MemoryOwner ConvertS8D24ToD24S8(ReadOnlySpan data) { - byte[] output = new byte[data.Length]; + MemoryOwner outputMemory = MemoryOwner.Rent(data.Length); + + Span output = outputMemory.Span; int start = 0; @@ -74,7 +77,7 @@ namespace Ryujinx.Graphics.OpenGL.Image outSpan[i] = BitOperations.RotateLeft(dataSpan[i], 8); } - return output; + return outputMemory; } public unsafe static byte[] ConvertD24S8ToS8D24(ReadOnlySpan data) diff --git a/src/Ryujinx.Graphics.OpenGL/Image/ImageArray.cs b/src/Ryujinx.Graphics.OpenGL/Image/ImageArray.cs new file mode 100644 index 000000000..3486f29df --- /dev/null +++ b/src/Ryujinx.Graphics.OpenGL/Image/ImageArray.cs @@ -0,0 +1,63 @@ +using OpenTK.Graphics.OpenGL; +using Ryujinx.Graphics.GAL; + +namespace Ryujinx.Graphics.OpenGL.Image +{ + class ImageArray : IImageArray + { + private record struct TextureRef + { + public int Handle; + public Format Format; + } + + private readonly TextureRef[] _images; + + public ImageArray(int size) + { + _images = new TextureRef[size]; + } + + public void SetImages(int index, ITexture[] images) + { + for (int i = 0; i < images.Length; i++) + { + ITexture image = images[i]; + + if (image is TextureBase imageBase) + { + _images[index + i].Handle = imageBase.Handle; + _images[index + i].Format = imageBase.Format; + } + else + { + _images[index + i].Handle = 0; + } + } + } + + public void Bind(int baseBinding) + { + for (int i = 0; i < _images.Length; i++) + { + if (_images[i].Handle == 0) + { + GL.BindImageTexture(baseBinding + i, 0, 0, true, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8); + } + else + { + SizedInternalFormat format = FormatTable.GetImageFormat(_images[i].Format); + + if (format != 0) + { + GL.BindImageTexture(baseBinding + i, _images[i].Handle, 0, true, 0, TextureAccess.ReadWrite, format); + } + } + } + } + + public void Dispose() + { + } + } +} diff --git a/src/Ryujinx.Graphics.OpenGL/Image/TextureArray.cs b/src/Ryujinx.Graphics.OpenGL/Image/TextureArray.cs new file mode 100644 index 000000000..41ac058c1 --- /dev/null +++ b/src/Ryujinx.Graphics.OpenGL/Image/TextureArray.cs @@ -0,0 +1,56 @@ +using Ryujinx.Graphics.GAL; + +namespace Ryujinx.Graphics.OpenGL.Image +{ + class TextureArray : ITextureArray + { + private record struct TextureRef + { + public TextureBase Texture; + public Sampler Sampler; + } + + private readonly TextureRef[] _textureRefs; + + public TextureArray(int size) + { + _textureRefs = new TextureRef[size]; + } + + public void SetSamplers(int index, ISampler[] samplers) + { + for (int i = 0; i < samplers.Length; i++) + { + _textureRefs[index + i].Sampler = samplers[i] as Sampler; + } + } + + public void SetTextures(int index, ITexture[] textures) + { + for (int i = 0; i < textures.Length; i++) + { + _textureRefs[index + i].Texture = textures[i] as TextureBase; + } + } + + public void Bind(int baseBinding) + { + for (int i = 0; i < _textureRefs.Length; i++) + { + if (_textureRefs[i].Texture != null) + { + _textureRefs[i].Texture.Bind(baseBinding + i); + _textureRefs[i].Sampler?.Bind(baseBinding + i); + } + else + { + TextureBase.ClearBinding(baseBinding + i); + } + } + } + + public void Dispose() + { + } + } +} diff --git a/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs b/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs index e8f6d9a26..b8467209b 100644 --- a/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs +++ b/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs @@ -55,22 +55,25 @@ namespace Ryujinx.Graphics.OpenGL.Image throw new NotImplementedException(); } - public void SetData(IMemoryOwner data) + /// + public void SetData(MemoryOwner data) { - var dataSpan = data.Memory.Span; + var dataSpan = data.Span; Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]); data.Dispose(); } - public void SetData(IMemoryOwner data, int layer, int level) + /// + public void SetData(MemoryOwner data, int layer, int level) { data.Dispose(); throw new NotSupportedException(); } - public void SetData(IMemoryOwner data, int layer, int level, Rectangle region) + /// + public void SetData(MemoryOwner data, int layer, int level, Rectangle region) { data.Dispose(); throw new NotSupportedException(); diff --git a/src/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs b/src/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs index 128f481f6..89bd5e4ff 100644 --- a/src/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs +++ b/src/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs @@ -294,7 +294,7 @@ namespace Ryujinx.Graphics.OpenGL.Image { return FramebufferAttachment.DepthStencilAttachment; } - else if (IsDepthOnly(format)) + else if (FormatTable.IsDepthOnly(format)) { return FramebufferAttachment.DepthAttachment; } @@ -324,11 +324,11 @@ namespace Ryujinx.Graphics.OpenGL.Image private static ClearBufferMask GetMask(Format format) { - if (format == Format.D24UnormS8Uint || format == Format.D32FloatS8Uint || format == Format.S8UintD24Unorm) + if (FormatTable.IsPackedDepthStencil(format)) { return ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit; } - else if (IsDepthOnly(format)) + else if (FormatTable.IsDepthOnly(format)) { return ClearBufferMask.DepthBufferBit; } @@ -342,11 +342,6 @@ namespace Ryujinx.Graphics.OpenGL.Image } } - private static bool IsDepthOnly(Format format) - { - return format == Format.D16Unorm || format == Format.D32Float; - } - public TextureView BgraSwap(TextureView from) { TextureView to = (TextureView)_renderer.CreateTexture(from.Info); diff --git a/src/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs b/src/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs index adaa82572..2511d2f8e 100644 --- a/src/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs +++ b/src/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs @@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.OpenGL.Image internalFormat = (SizedInternalFormat)format.PixelInternalFormat; } - int levels = Info.GetLevelsClamped(); + int levels = Info.Levels; switch (Info.Target) { diff --git a/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs b/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs index 7451fc1d4..c9498fc41 100644 --- a/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs +++ b/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs @@ -52,7 +52,7 @@ namespace Ryujinx.Graphics.OpenGL.Image pixelInternalFormat = format.PixelInternalFormat; } - int levels = Info.GetLevelsClamped(); + int levels = Info.Levels; GL.TextureView( Handle, @@ -268,7 +268,7 @@ namespace Ryujinx.Graphics.OpenGL.Image public unsafe PinnedSpan GetData() { int size = 0; - int levels = Info.GetLevelsClamped(); + int levels = Info.Levels; for (int level = 0; level < levels; level++) { @@ -427,7 +427,7 @@ namespace Ryujinx.Graphics.OpenGL.Image faces = 6; } - int levels = Info.GetLevelsClamped(); + int levels = Info.Levels; for (int level = 0; level < levels; level++) { @@ -449,77 +449,61 @@ namespace Ryujinx.Graphics.OpenGL.Image } } - public void SetData(ReadOnlySpan dataSpan) + public void SetData(MemoryOwner data) { - if (Format == Format.S8UintD24Unorm) + using (data = EnsureDataFormat(data)) { - dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan); - } - - unsafe - { - fixed (byte* ptr = dataSpan) + unsafe { - ReadFrom((IntPtr)ptr, dataSpan.Length); + var dataSpan = data.Span; + fixed (byte* ptr = dataSpan) + { + ReadFrom((IntPtr)ptr, dataSpan.Length); + } } } } - public void SetData(IMemoryOwner data) + public void SetData(MemoryOwner data, int layer, int level) { - SetData(data.Memory.Span); - - data.Dispose(); - } - - public void SetData(IMemoryOwner data, int layer, int level) - { - var dataSpan = data.Memory.Span; - - if (Format == Format.S8UintD24Unorm) + using (data = EnsureDataFormat(data)) { - dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan); - } - - unsafe - { - fixed (byte* ptr = dataSpan) + unsafe { - int width = Math.Max(Info.Width >> level, 1); - int height = Math.Max(Info.Height >> level, 1); + fixed (byte* ptr = data.Span) + { + int width = Math.Max(Info.Width >> level, 1); + int height = Math.Max(Info.Height >> level, 1); - ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height); + ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height); + } } } data.Dispose(); } - public void SetData(IMemoryOwner data, int layer, int level, Rectangle region) + public void SetData(MemoryOwner data, int layer, int level, Rectangle region) { - var dataSpan = data.Memory.Span; - - if (Format == Format.S8UintD24Unorm) + using (data = EnsureDataFormat(data)) { - dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan); - } + int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth); + int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight); - int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth); - int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight); - - unsafe - { - fixed (byte* ptr = dataSpan) + unsafe { - ReadFrom2D( - (IntPtr)ptr, - layer, - level, - region.X, - region.Y, - region.Width, - region.Height, - BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks); + fixed (byte* ptr = data.Span) + { + ReadFrom2D( + (IntPtr)ptr, + layer, + level, + region.X, + region.Y, + region.Width, + region.Height, + BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks); + } } } @@ -543,6 +527,19 @@ namespace Ryujinx.Graphics.OpenGL.Image ReadFrom2D(data, layer, level, x, y, width, height, mipSize); } + private MemoryOwner EnsureDataFormat(MemoryOwner data) + { + if (Format == Format.S8UintD24Unorm) + { + using (data) + { + return FormatConverter.ConvertS8D24ToD24S8(data.Span); + } + } + + return data; + } + private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height, int mipSize) { TextureTarget target = Target.Convert(); @@ -724,7 +721,7 @@ namespace Ryujinx.Graphics.OpenGL.Image int width = Info.Width; int height = Info.Height; int depth = Info.Depth; - int levels = Info.GetLevelsClamped(); + int levels = Info.Levels; int offset = 0; diff --git a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs index 64ba4e3ee..9fcdf1ad7 100644 --- a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs +++ b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs @@ -61,7 +61,9 @@ namespace Ryujinx.Graphics.OpenGL { BufferCount++; - if (access.HasFlag(GAL.BufferAccess.FlushPersistent)) + var memType = access & GAL.BufferAccess.MemoryTypeMask; + + if (memType == GAL.BufferAccess.HostMemory) { BufferHandle handle = Buffer.CreatePersistent(size); @@ -75,11 +77,6 @@ namespace Ryujinx.Graphics.OpenGL } } - public BufferHandle CreateBuffer(int size, GAL.BufferAccess access, BufferHandle storageHint) - { - return CreateBuffer(size, access); - } - public BufferHandle CreateBuffer(nint pointer, int size) { throw new NotSupportedException(); @@ -90,6 +87,11 @@ namespace Ryujinx.Graphics.OpenGL throw new NotSupportedException(); } + public IImageArray CreateImageArray(int size, bool isBuffer) + { + return new ImageArray(size); + } + public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info) { return new Program(shaders, info.FragmentOutputMap); @@ -112,6 +114,11 @@ namespace Ryujinx.Graphics.OpenGL } } + public ITextureArray CreateTextureArray(int size, bool isBuffer) + { + return new TextureArray(size); + } + public void DeleteBuffer(BufferHandle buffer) { PersistentBuffers.Unmap(buffer); @@ -121,7 +128,7 @@ namespace Ryujinx.Graphics.OpenGL public HardwareInfo GetHardwareInfo() { - return new HardwareInfo(GpuVendor, GpuRenderer); + return new HardwareInfo(GpuVendor, GpuRenderer, GpuVendor); // OpenGL does not provide a driver name, vendor name is closest analogue. } public PinnedSpan GetBufferData(BufferHandle buffer, int offset, int size) @@ -138,6 +145,7 @@ namespace Ryujinx.Graphics.OpenGL return new Capabilities( api: TargetApi.OpenGL, vendorName: GpuVendor, + memoryType: SystemMemoryType.BackendManaged, hasFrontFacingBug: intelWindows, hasVectorIndexingBug: amdWindows, needsFragmentOutputSpecialization: false, @@ -151,6 +159,7 @@ namespace Ryujinx.Graphics.OpenGL supportsBgraFormat: false, supportsR4G4Format: false, supportsR4G4B4A4Format: true, + supportsScaledVertexFormats: true, supportsSnormBufferTextureFormat: false, supports5BitComponentFormat: true, supportsSparseBuffer: false, @@ -165,7 +174,8 @@ namespace Ryujinx.Graphics.OpenGL supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat, supportsCubemapView: true, supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset, - supportsScaledVertexFormats: true, + supportsQuads: HwCapabilities.SupportsQuads, + supportsSeparateSampler: false, supportsShaderBallot: HwCapabilities.SupportsShaderBallot, supportsShaderBarrierDivergence: !(intelWindows || intelUnix), supportsShaderFloat64: true, @@ -177,6 +187,12 @@ namespace Ryujinx.Graphics.OpenGL supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle, supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters, supportsDepthClipControl: true, + uniformBufferSetIndex: 0, + storageBufferSetIndex: 1, + textureSetIndex: 2, + imageSetIndex: 3, + extraSetBaseIndex: 0, + maximumExtraSets: 0, maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver? maximumStorageBuffersPerStage: 16, maximumTexturesPerStage: 32, @@ -186,7 +202,8 @@ namespace Ryujinx.Graphics.OpenGL shaderSubgroupSize: Constants.MaxSubgroupSize, storageBufferOffsetAlignment: HwCapabilities.StorageBufferOffsetAlignment, textureBufferOffsetAlignment: HwCapabilities.TextureBufferOffsetAlignment, - gatherBiasPrecision: intelWindows || amdWindows ? 8 : 0); // Precision is 8 for these vendors on Vulkan. + gatherBiasPrecision: intelWindows || amdWindows ? 8 : 0, // Precision is 8 for these vendors on Vulkan. + maximumGpuMemory: 0); } public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan data) @@ -248,7 +265,7 @@ namespace Ryujinx.Graphics.OpenGL { // alwaysBackground is ignored, since we cannot switch from the current context. - if (IOpenGLContext.HasContext()) + if (_window.BackgroundContext.HasContext()) { action(); // We have a context already - use that (assuming it is the main one). } diff --git a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs index 923c85d7e..27aacac15 100644 --- a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.OpenGL private readonly Vector4[] _fpIsBgra = new Vector4[SupportBuffer.FragmentIsBgraCount]; - private readonly (TextureBase, Format)[] _images; + private readonly TextureBase[] _images; private TextureBase _unit0Texture; private Sampler _unit0Sampler; @@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.OpenGL _fragmentOutputMap = uint.MaxValue; _componentMasks = uint.MaxValue; - _images = new (TextureBase, Format)[SavedImages]; + _images = new TextureBase[SavedImages]; _tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers]; _tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers]; @@ -935,11 +935,11 @@ namespace Ryujinx.Graphics.OpenGL SetFrontFace(_frontFace = frontFace.Convert()); } - public void SetImage(int binding, ITexture texture, Format imageFormat) + public void SetImage(ShaderStage stage, int binding, ITexture texture) { if ((uint)binding < SavedImages) { - _images[binding] = (texture as TextureBase, imageFormat); + _images[binding] = texture as TextureBase; } if (texture == null) @@ -950,7 +950,7 @@ namespace Ryujinx.Graphics.OpenGL TextureBase texBase = (TextureBase)texture; - SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat); + SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format); if (format != 0) { @@ -958,6 +958,16 @@ namespace Ryujinx.Graphics.OpenGL } } + public void SetImageArray(ShaderStage stage, int binding, IImageArray array) + { + (array as ImageArray).Bind(binding); + } + + public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array) + { + throw new NotSupportedException("OpenGL does not support descriptor sets."); + } + public void SetIndexBuffer(BufferRange buffer, IndexType type) { _elementsType = type.Convert(); @@ -1117,7 +1127,7 @@ namespace Ryujinx.Graphics.OpenGL prg.Bind(); } - if (prg.HasFragmentShader && _fragmentOutputMap != (uint)prg.FragmentOutputMap) + if (_fragmentOutputMap != (uint)prg.FragmentOutputMap) { _fragmentOutputMap = (uint)prg.FragmentOutputMap; @@ -1302,6 +1312,15 @@ namespace Ryujinx.Graphics.OpenGL } } + public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array) + { + (array as TextureArray).Bind(binding); + } + + public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array) + { + throw new NotSupportedException("OpenGL does not support descriptor sets."); + } public void SetTransformFeedbackBuffers(ReadOnlySpan buffers) { @@ -1603,11 +1622,11 @@ namespace Ryujinx.Graphics.OpenGL { for (int i = 0; i < SavedImages; i++) { - (TextureBase texBase, Format imageFormat) = _images[i]; + TextureBase texBase = _images[i]; if (texBase != null) { - SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat); + SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format); if (format != 0) { diff --git a/src/Ryujinx.Graphics.OpenGL/Program.cs b/src/Ryujinx.Graphics.OpenGL/Program.cs index cc9120c7c..19de06f8f 100644 --- a/src/Ryujinx.Graphics.OpenGL/Program.cs +++ b/src/Ryujinx.Graphics.OpenGL/Program.cs @@ -30,7 +30,6 @@ namespace Ryujinx.Graphics.OpenGL private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete; private int[] _shaderHandles; - public bool HasFragmentShader; public int FragmentOutputMap { get; } public Program(ShaderSource[] shaders, int fragmentOutputMap) @@ -40,6 +39,7 @@ namespace Ryujinx.Graphics.OpenGL GL.ProgramParameter(Handle, ProgramParameterName.ProgramBinaryRetrievableHint, 1); _shaderHandles = new int[shaders.Length]; + bool hasFragmentShader = false; for (int index = 0; index < shaders.Length; index++) { @@ -47,7 +47,7 @@ namespace Ryujinx.Graphics.OpenGL if (shader.Stage == ShaderStage.Fragment) { - HasFragmentShader = true; + hasFragmentShader = true; } int shaderHandle = GL.CreateShader(shader.Stage.Convert()); @@ -71,7 +71,7 @@ namespace Ryujinx.Graphics.OpenGL GL.LinkProgram(Handle); - FragmentOutputMap = fragmentOutputMap; + FragmentOutputMap = hasFragmentShader ? fragmentOutputMap : 0; } public Program(ReadOnlySpan code, bool hasFragmentShader, int fragmentOutputMap) @@ -91,8 +91,7 @@ namespace Ryujinx.Graphics.OpenGL } } - HasFragmentShader = hasFragmentShader; - FragmentOutputMap = fragmentOutputMap; + FragmentOutputMap = hasFragmentShader ? fragmentOutputMap : 0; } public void Bind() diff --git a/src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj b/src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj index 3d64da99b..f3071f486 100644 --- a/src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj +++ b/src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj @@ -21,6 +21,7 @@ + diff --git a/src/Ryujinx.Graphics.OpenGL/Window.cs b/src/Ryujinx.Graphics.OpenGL/Window.cs index 6bcfefa4e..285ab725e 100644 --- a/src/Ryujinx.Graphics.OpenGL/Window.cs +++ b/src/Ryujinx.Graphics.OpenGL/Window.cs @@ -373,6 +373,16 @@ namespace Ryujinx.Graphics.OpenGL _isLinear = false; _scalingFilter.Level = _scalingFilterLevel; + RecreateUpscalingTexture(); + break; + case ScalingFilter.Area: + if (_scalingFilter is not AreaScalingFilter) + { + _scalingFilter?.Dispose(); + _scalingFilter = new AreaScalingFilter(_renderer); + } + _isLinear = false; + RecreateUpscalingTexture(); break; } diff --git a/src/Ryujinx.Graphics.Shader/BufferDescriptor.cs b/src/Ryujinx.Graphics.Shader/BufferDescriptor.cs index ead1c5e67..11d4e3c11 100644 --- a/src/Ryujinx.Graphics.Shader/BufferDescriptor.cs +++ b/src/Ryujinx.Graphics.Shader/BufferDescriptor.cs @@ -4,14 +4,16 @@ namespace Ryujinx.Graphics.Shader { // New fields should be added to the end of the struct to keep disk shader cache compatibility. + public readonly int Set; public readonly int Binding; public readonly byte Slot; public readonly byte SbCbSlot; public readonly ushort SbCbOffset; public readonly BufferUsageFlags Flags; - public BufferDescriptor(int binding, int slot) + public BufferDescriptor(int set, int binding, int slot) { + Set = set; Binding = binding; Slot = (byte)slot; SbCbSlot = 0; @@ -19,8 +21,9 @@ namespace Ryujinx.Graphics.Shader Flags = BufferUsageFlags.None; } - public BufferDescriptor(int binding, int slot, int sbCbSlot, int sbCbOffset, BufferUsageFlags flags) + public BufferDescriptor(int set, int binding, int slot, int sbCbSlot, int sbCbOffset, BufferUsageFlags flags) { + Set = set; Binding = binding; Slot = (byte)slot; SbCbSlot = (byte)sbCbSlot; diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs index 500de71f6..eb6c689b8 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Numerics; namespace Ryujinx.Graphics.Shader.CodeGen.Glsl { @@ -339,27 +338,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl private static void DeclareSamplers(CodeGenContext context, IEnumerable definitions) { - int arraySize = 0; - foreach (var definition in definitions) { - string indexExpr = string.Empty; + string arrayDecl = string.Empty; - if (definition.Type.HasFlag(SamplerType.Indexed)) + if (definition.ArrayLength > 1) { - if (arraySize == 0) - { - arraySize = ResourceManager.SamplerArraySize; - } - else if (--arraySize != 0) - { - continue; - } - - indexExpr = $"[{NumberFormatter.FormatInt(arraySize)}]"; + arrayDecl = $"[{NumberFormatter.FormatInt(definition.ArrayLength)}]"; + } + else if (definition.ArrayLength == 0) + { + arrayDecl = "[]"; } - string samplerTypeName = definition.Type.ToGlslSamplerType(); + string samplerTypeName = definition.Separate ? definition.Type.ToGlslTextureType() : definition.Type.ToGlslSamplerType(); string layout = string.Empty; @@ -368,30 +360,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl layout = $", set = {definition.Set}"; } - context.AppendLine($"layout (binding = {definition.Binding}{layout}) uniform {samplerTypeName} {definition.Name}{indexExpr};"); + context.AppendLine($"layout (binding = {definition.Binding}{layout}) uniform {samplerTypeName} {definition.Name}{arrayDecl};"); } } private static void DeclareImages(CodeGenContext context, IEnumerable definitions) { - int arraySize = 0; - foreach (var definition in definitions) { - string indexExpr = string.Empty; + string arrayDecl = string.Empty; - if (definition.Type.HasFlag(SamplerType.Indexed)) + if (definition.ArrayLength > 1) { - if (arraySize == 0) - { - arraySize = ResourceManager.SamplerArraySize; - } - else if (--arraySize != 0) - { - continue; - } - - indexExpr = $"[{NumberFormatter.FormatInt(arraySize)}]"; + arrayDecl = $"[{NumberFormatter.FormatInt(definition.ArrayLength)}]"; + } + else if (definition.ArrayLength == 0) + { + arrayDecl = "[]"; } string imageTypeName = definition.Type.ToGlslImageType(definition.Format.GetComponentType()); @@ -413,7 +398,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl layout = $", set = {definition.Set}{layout}"; } - context.AppendLine($"layout (binding = {definition.Binding}{layout}) uniform {imageTypeName} {definition.Name}{indexExpr};"); + context.AppendLine($"layout (binding = {definition.Binding}{layout}) uniform {imageTypeName} {definition.Name}{arrayDecl};"); } } diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs index eb0cb92db..9e7f64b0e 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs @@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions AggregateType type = GetSrcVarType(operation.Inst, 0); - string srcExpr = GetSoureExpr(context, src, type); + string srcExpr = GetSourceExpr(context, src, type); string zero; if (type == AggregateType.FP64) @@ -80,7 +80,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions for (int argIndex = operation.SourcesCount - arity + 2; argIndex < operation.SourcesCount; argIndex++) { - builder.Append($", {GetSoureExpr(context, operation.GetSource(argIndex), dstType)}"); + builder.Append($", {GetSourceExpr(context, operation.GetSource(argIndex), dstType)}"); } } else @@ -94,7 +94,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions AggregateType dstType = GetSrcVarType(inst, argIndex); - builder.Append(GetSoureExpr(context, operation.GetSource(argIndex), dstType)); + builder.Append(GetSourceExpr(context, operation.GetSource(argIndex), dstType)); } } @@ -107,7 +107,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions // Return may optionally have a return value (and in this case it is unary). if (inst == Instruction.Return && operation.SourcesCount != 0) { - return $"{op} {GetSoureExpr(context, operation.GetSource(0), context.CurrentFunction.ReturnType)}"; + return $"{op} {GetSourceExpr(context, operation.GetSource(0), context.CurrentFunction.ReturnType)}"; } int arity = (int)(info.Type & InstType.ArityMask); @@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { IAstNode src = operation.GetSource(index); - string srcExpr = GetSoureExpr(context, src, GetSrcVarType(inst, index)); + string srcExpr = GetSourceExpr(context, src, GetSrcVarType(inst, index)); bool isLhs = arity == 2 && index == 0; diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenBallot.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenBallot.cs index 6cc7048bd..000d7f797 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenBallot.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenBallot.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { AggregateType dstType = GetSrcVarType(operation.Inst, 0); - string arg = GetSoureExpr(context, operation.GetSource(0), dstType); + string arg = GetSourceExpr(context, operation.GetSource(0), dstType); char component = "xyzw"[operation.Index]; if (context.HostCapabilities.SupportsShaderBallot) diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenCall.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenCall.cs index 0618ba8a3..d5448856d 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenCall.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenCall.cs @@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions for (int i = 0; i < args.Length; i++) { - args[i] = GetSoureExpr(context, operation.GetSource(i + 1), function.GetArgumentType(i)); + args[i] = GetSourceExpr(context, operation.GetSource(i + 1), function.GetArgumentType(i)); } return $"{function.Name}({string.Join(", ", args)})"; diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs index 5c2d16f4c..4b28f3878 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs @@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions return _infoTable[(int)(inst & Instruction.Mask)]; } - public static string GetSoureExpr(CodeGenContext context, IAstNode node, AggregateType dstType) + public static string GetSourceExpr(CodeGenContext context, IAstNode node, AggregateType dstType) { return ReinterpretCast(context, node, OperandManager.GetNodeDestType(context, node), dstType); } diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs index 2e90bd16d..4308b08f8 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs @@ -14,35 +14,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { AstTextureOperation texOp = (AstTextureOperation)operation; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; - - // TODO: Bindless texture support. For now we just return 0/do nothing. - if (isBindless) - { - switch (texOp.Inst) - { - case Instruction.ImageStore: - return "// imageStore(bindless)"; - case Instruction.ImageLoad: - AggregateType componentType = texOp.Format.GetComponentType(); - - NumberFormatter.TryFormat(0, componentType, out string imageConst); - - AggregateType outputType = texOp.GetVectorType(componentType); - - if ((outputType & AggregateType.ElementCountMask) != 0) - { - return $"{Declarations.GetVarTypeName(context, outputType, precise: false)}({imageConst})"; - } - - return imageConst; - default: - return NumberFormatter.FormatInt(0); - } - } - bool isArray = (texOp.Type & SamplerType.Array) != 0; - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; var texCallBuilder = new StringBuilder(); @@ -70,21 +42,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions texCallBuilder.Append(texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore"); } - int srcIndex = isBindless ? 1 : 0; + int srcIndex = 0; string Src(AggregateType type) { - return GetSoureExpr(context, texOp.GetSource(srcIndex++), type); + return GetSourceExpr(context, texOp.GetSource(srcIndex++), type); } - string indexExpr = null; - - if (isIndexed) - { - indexExpr = Src(AggregateType.S32); - } - - string imageName = GetImageName(context.Properties, texOp, indexExpr); + string imageName = GetImageName(context, texOp, ref srcIndex); texCallBuilder.Append('('); texCallBuilder.Append(imageName); @@ -198,27 +163,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions AstTextureOperation texOp = (AstTextureOperation)operation; int coordsCount = texOp.Type.GetDimensions(); + int coordsIndex = 0; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; - - // TODO: Bindless texture support. For now we just return 0. - if (isBindless) - { - return NumberFormatter.FormatFloat(0); - } - - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - - string indexExpr = null; - - if (isIndexed) - { - indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32); - } - - string samplerName = GetSamplerName(context.Properties, texOp, indexExpr); - - int coordsIndex = isBindless || isIndexed ? 1 : 0; + string samplerName = GetSamplerName(context, texOp, ref coordsIndex); string coordsExpr; @@ -228,14 +175,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions for (int index = 0; index < coordsCount; index++) { - elems[index] = GetSoureExpr(context, texOp.GetSource(coordsIndex + index), AggregateType.FP32); + elems[index] = GetSourceExpr(context, texOp.GetSource(coordsIndex + index), AggregateType.FP32); } coordsExpr = "vec" + coordsCount + "(" + string.Join(", ", elems) + ")"; } else { - coordsExpr = GetSoureExpr(context, texOp.GetSource(coordsIndex), AggregateType.FP32); + coordsExpr = GetSourceExpr(context, texOp.GetSource(coordsIndex), AggregateType.FP32); } return $"textureQueryLod({samplerName}, {coordsExpr}){GetMask(texOp.Index)}"; @@ -250,7 +197,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { AstTextureOperation texOp = (AstTextureOperation)operation; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isGather = (texOp.Flags & TextureFlags.Gather) != 0; bool hasDerivatives = (texOp.Flags & TextureFlags.Derivatives) != 0; bool intCoords = (texOp.Flags & TextureFlags.IntCoords) != 0; @@ -260,12 +206,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0; bool isArray = (texOp.Type & SamplerType.Array) != 0; - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0; bool isShadow = (texOp.Type & SamplerType.Shadow) != 0; - bool colorIsVector = isGather || !isShadow; - SamplerType type = texOp.Type & SamplerType.Mask; bool is2D = type == SamplerType.Texture2D; @@ -286,24 +229,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions hasLodLevel = false; } - // TODO: Bindless texture support. For now we just return 0. - if (isBindless) - { - string scalarValue = NumberFormatter.FormatFloat(0); - - if (colorIsVector) - { - AggregateType outputType = texOp.GetVectorType(AggregateType.FP32); - - if ((outputType & AggregateType.ElementCountMask) != 0) - { - return $"{Declarations.GetVarTypeName(context, outputType, precise: false)}({scalarValue})"; - } - } - - return scalarValue; - } - string texCall = intCoords ? "texelFetch" : "texture"; if (isGather) @@ -328,21 +253,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions texCall += "Offsets"; } - int srcIndex = isBindless ? 1 : 0; + int srcIndex = 0; string Src(AggregateType type) { - return GetSoureExpr(context, texOp.GetSource(srcIndex++), type); + return GetSourceExpr(context, texOp.GetSource(srcIndex++), type); } - string indexExpr = null; - - if (isIndexed) - { - indexExpr = Src(AggregateType.S32); - } - - string samplerName = GetSamplerName(context.Properties, texOp, indexExpr); + string samplerName = GetSamplerName(context, texOp, ref srcIndex); texCall += "(" + samplerName; @@ -512,6 +430,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions Append(Src(AggregateType.S32)); } + bool colorIsVector = isGather || !isShadow; + texCall += ")" + (colorIsVector ? GetMaskMultiDest(texOp.Index) : ""); return texCall; @@ -521,24 +441,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { AstTextureOperation texOp = (AstTextureOperation)operation; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; + int srcIndex = 0; - // TODO: Bindless texture support. For now we just return 0. - if (isBindless) - { - return NumberFormatter.FormatInt(0); - } - - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - - string indexExpr = null; - - if (isIndexed) - { - indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32); - } - - string samplerName = GetSamplerName(context.Properties, texOp, indexExpr); + string samplerName = GetSamplerName(context, texOp, ref srcIndex); return $"textureSamples({samplerName})"; } @@ -547,24 +452,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { AstTextureOperation texOp = (AstTextureOperation)operation; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; + int srcIndex = 0; - // TODO: Bindless texture support. For now we just return 0. - if (isBindless) - { - return NumberFormatter.FormatInt(0); - } - - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - - string indexExpr = null; - - if (isIndexed) - { - indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32); - } - - string samplerName = GetSamplerName(context.Properties, texOp, indexExpr); + string samplerName = GetSamplerName(context, texOp, ref srcIndex); if (texOp.Index == 3) { @@ -572,15 +462,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions } else { - context.Properties.Textures.TryGetValue(texOp.Binding, out TextureDefinition definition); + context.Properties.Textures.TryGetValue(texOp.GetTextureSetAndBinding(), out TextureDefinition definition); bool hasLod = !definition.Type.HasFlag(SamplerType.Multisample) && (definition.Type & SamplerType.Mask) != SamplerType.TextureBuffer; string texCall; if (hasLod) { - int lodSrcIndex = isBindless || isIndexed ? 1 : 0; - IAstNode lod = operation.GetSource(lodSrcIndex); - string lodExpr = GetSoureExpr(context, lod, GetSrcVarType(operation.Inst, lodSrcIndex)); + IAstNode lod = operation.GetSource(srcIndex); + string lodExpr = GetSourceExpr(context, lod, GetSrcVarType(operation.Inst, srcIndex)); texCall = $"textureSize({samplerName}, {lodExpr}){GetMask(texOp.Index)}"; } @@ -697,12 +586,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions if (storageKind == StorageKind.Input) { - string expr = GetSoureExpr(context, operation.GetSource(srcIndex++), AggregateType.S32); + string expr = GetSourceExpr(context, operation.GetSource(srcIndex++), AggregateType.S32); varName = $"gl_in[{expr}].{varName}"; } else if (storageKind == StorageKind.Output) { - string expr = GetSoureExpr(context, operation.GetSource(srcIndex++), AggregateType.S32); + string expr = GetSourceExpr(context, operation.GetSource(srcIndex++), AggregateType.S32); varName = $"gl_out[{expr}].{varName}"; } } @@ -735,38 +624,53 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions } else { - varName += $"[{GetSoureExpr(context, src, AggregateType.S32)}]"; + varName += $"[{GetSourceExpr(context, src, AggregateType.S32)}]"; } } if (isStore) { varType &= AggregateType.ElementTypeMask; - varName = $"{varName} = {GetSoureExpr(context, operation.GetSource(srcIndex), varType)}"; + varName = $"{varName} = {GetSourceExpr(context, operation.GetSource(srcIndex), varType)}"; } return varName; } - private static string GetSamplerName(ShaderProperties resourceDefinitions, AstTextureOperation texOp, string indexExpr) + private static string GetSamplerName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex) { - string name = resourceDefinitions.Textures[texOp.Binding].Name; + TextureDefinition textureDefinition = context.Properties.Textures[texOp.GetTextureSetAndBinding()]; + string name = textureDefinition.Name; - if (texOp.Type.HasFlag(SamplerType.Indexed)) + if (textureDefinition.ArrayLength != 1) { - name = $"{name}[{indexExpr}]"; + name = $"{name}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]"; + } + + if (texOp.IsSeparate) + { + TextureDefinition samplerDefinition = context.Properties.Textures[texOp.GetSamplerSetAndBinding()]; + string samplerName = samplerDefinition.Name; + + if (samplerDefinition.ArrayLength != 1) + { + samplerName = $"{samplerName}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]"; + } + + name = $"{texOp.Type.ToGlslSamplerType()}({name}, {samplerName})"; } return name; } - private static string GetImageName(ShaderProperties resourceDefinitions, AstTextureOperation texOp, string indexExpr) + private static string GetImageName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex) { - string name = resourceDefinitions.Images[texOp.Binding].Name; + TextureDefinition definition = context.Properties.Images[texOp.GetTextureSetAndBinding()]; + string name = definition.Name; - if (texOp.Type.HasFlag(SamplerType.Indexed)) + if (definition.ArrayLength != 1) { - name = $"{name}[{indexExpr}]"; + name = $"{name}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]"; } return name; diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs index ad84c4850..4469785d2 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs @@ -13,8 +13,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions IAstNode src0 = operation.GetSource(0); IAstNode src1 = operation.GetSource(1); - string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0)); - string src1Expr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 1)); + string src0Expr = GetSourceExpr(context, src0, GetSrcVarType(operation.Inst, 0)); + string src1Expr = GetSourceExpr(context, src1, GetSrcVarType(operation.Inst, 1)); return $"packDouble2x32(uvec2({src0Expr}, {src1Expr}))"; } @@ -24,8 +24,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions IAstNode src0 = operation.GetSource(0); IAstNode src1 = operation.GetSource(1); - string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0)); - string src1Expr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 1)); + string src0Expr = GetSourceExpr(context, src0, GetSrcVarType(operation.Inst, 0)); + string src1Expr = GetSourceExpr(context, src1, GetSrcVarType(operation.Inst, 1)); return $"packHalf2x16(vec2({src0Expr}, {src1Expr}))"; } @@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { IAstNode src = operation.GetSource(0); - string srcExpr = GetSoureExpr(context, src, GetSrcVarType(operation.Inst, 0)); + string srcExpr = GetSourceExpr(context, src, GetSrcVarType(operation.Inst, 0)); return $"unpackDouble2x32({srcExpr}){GetMask(operation.Index)}"; } @@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { IAstNode src = operation.GetSource(0); - string srcExpr = GetSoureExpr(context, src, GetSrcVarType(operation.Inst, 0)); + string srcExpr = GetSourceExpr(context, src, GetSrcVarType(operation.Inst, 0)); return $"unpackHalf2x16({srcExpr}){GetMask(operation.Index)}"; } diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenShuffle.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenShuffle.cs index 6d3859efd..b72b94d90 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenShuffle.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenShuffle.cs @@ -9,8 +9,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { public static string Shuffle(CodeGenContext context, AstOperation operation) { - string value = GetSoureExpr(context, operation.GetSource(0), AggregateType.FP32); - string index = GetSoureExpr(context, operation.GetSource(1), AggregateType.U32); + string value = GetSourceExpr(context, operation.GetSource(0), AggregateType.FP32); + string index = GetSourceExpr(context, operation.GetSource(1), AggregateType.U32); if (context.HostCapabilities.SupportsShaderBallot) { diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenVector.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenVector.cs index 70174a5ba..a300c7750 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenVector.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenVector.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions IAstNode vector = operation.GetSource(0); IAstNode index = operation.GetSource(1); - string vectorExpr = GetSoureExpr(context, vector, OperandManager.GetNodeDestType(context, vector)); + string vectorExpr = GetSourceExpr(context, vector, OperandManager.GetNodeDestType(context, vector)); if (index is AstOperand indexOperand && indexOperand.Type == OperandType.Constant) { @@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions } else { - string indexExpr = GetSoureExpr(context, index, GetSrcVarType(operation.Inst, 1)); + string indexExpr = GetSourceExpr(context, index, GetSrcVarType(operation.Inst, 1)); return $"{vectorExpr}[{indexExpr}]"; } diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs index 53ecc4531..a350b089c 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs @@ -146,9 +146,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl } else if (operation is AstTextureOperation texOp) { - if (texOp.Inst == Instruction.ImageLoad || - texOp.Inst == Instruction.ImageStore || - texOp.Inst == Instruction.ImageAtomic) + if (texOp.Inst.IsImage()) { return texOp.GetVectorType(texOp.Format.GetComponentType()); } diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs index 17c3eefe3..cc7977f84 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs @@ -33,9 +33,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv public Dictionary LocalMemories { get; } = new(); public Dictionary SharedMemories { get; } = new(); - public Dictionary SamplersTypes { get; } = new(); - public Dictionary Samplers { get; } = new(); - public Dictionary Images { get; } = new(); + public Dictionary SamplersTypes { get; } = new(); + public Dictionary Samplers { get; } = new(); + public Dictionary Images { get; } = new(); public Dictionary Inputs { get; } = new(); public Dictionary Outputs { get; } = new(); @@ -98,11 +98,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv Logger = parameters.Logger; TargetApi = parameters.TargetApi; - AddCapability(Capability.Shader); - AddCapability(Capability.Float64); - - SetMemoryModel(AddressingModel.Logical, MemoryModel.GLSL450); - Delegates = new SpirvDelegates(this); } diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs index 4ff61d9f2..55d35bf0d 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs @@ -160,31 +160,61 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { int setIndex = context.TargetApi == TargetApi.Vulkan ? sampler.Set : 0; - var dim = (sampler.Type & SamplerType.Mask) switch + SpvInstruction imageType; + SpvInstruction sampledImageType; + + if (sampler.Type != SamplerType.None) { - SamplerType.Texture1D => Dim.Dim1D, - SamplerType.Texture2D => Dim.Dim2D, - SamplerType.Texture3D => Dim.Dim3D, - SamplerType.TextureCube => Dim.Cube, - SamplerType.TextureBuffer => Dim.Buffer, - _ => throw new InvalidOperationException($"Invalid sampler type \"{sampler.Type & SamplerType.Mask}\"."), - }; + var dim = (sampler.Type & SamplerType.Mask) switch + { + SamplerType.Texture1D => Dim.Dim1D, + SamplerType.Texture2D => Dim.Dim2D, + SamplerType.Texture3D => Dim.Dim3D, + SamplerType.TextureCube => Dim.Cube, + SamplerType.TextureBuffer => Dim.Buffer, + _ => throw new InvalidOperationException($"Invalid sampler type \"{sampler.Type & SamplerType.Mask}\"."), + }; - var imageType = context.TypeImage( - context.TypeFP32(), - dim, - sampler.Type.HasFlag(SamplerType.Shadow), - sampler.Type.HasFlag(SamplerType.Array), - sampler.Type.HasFlag(SamplerType.Multisample), - 1, - ImageFormat.Unknown); + imageType = context.TypeImage( + context.TypeFP32(), + dim, + sampler.Type.HasFlag(SamplerType.Shadow), + sampler.Type.HasFlag(SamplerType.Array), + sampler.Type.HasFlag(SamplerType.Multisample), + 1, + ImageFormat.Unknown); - var sampledImageType = context.TypeSampledImage(imageType); - var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageType); - var sampledImageVariable = context.Variable(sampledImagePointerType, StorageClass.UniformConstant); + sampledImageType = context.TypeSampledImage(imageType); + } + else + { + imageType = sampledImageType = context.TypeSampler(); + } - context.Samplers.Add(sampler.Binding, (imageType, sampledImageType, sampledImageVariable)); - context.SamplersTypes.Add(sampler.Binding, sampler.Type); + var sampledOrSeparateImageType = sampler.Separate ? imageType : sampledImageType; + var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledOrSeparateImageType); + var sampledImageArrayPointerType = sampledImagePointerType; + + if (sampler.ArrayLength == 0) + { + var sampledImageArrayType = context.TypeRuntimeArray(sampledOrSeparateImageType); + sampledImageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageArrayType); + } + else if (sampler.ArrayLength != 1) + { + var sampledImageArrayType = context.TypeArray(sampledOrSeparateImageType, context.Constant(context.TypeU32(), sampler.ArrayLength)); + sampledImageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageArrayType); + } + + var sampledImageVariable = context.Variable(sampledImageArrayPointerType, StorageClass.UniformConstant); + + context.Samplers.Add(new(sampler.Set, sampler.Binding), new SamplerDeclaration( + imageType, + sampledImageType, + sampledImagePointerType, + sampledImageVariable, + sampler.ArrayLength != 1)); + context.SamplersTypes.Add(new(sampler.Set, sampler.Binding), sampler.Type); context.Name(sampledImageVariable, sampler.Name); context.Decorate(sampledImageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex); @@ -211,9 +241,22 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv GetImageFormat(image.Format)); var imagePointerType = context.TypePointer(StorageClass.UniformConstant, imageType); - var imageVariable = context.Variable(imagePointerType, StorageClass.UniformConstant); + var imageArrayPointerType = imagePointerType; - context.Images.Add(image.Binding, (imageType, imageVariable)); + if (image.ArrayLength == 0) + { + var imageArrayType = context.TypeRuntimeArray(imageType); + imageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, imageArrayType); + } + else if (image.ArrayLength != 1) + { + var imageArrayType = context.TypeArray(imageType, context.Constant(context.TypeU32(), image.ArrayLength)); + imageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, imageArrayType); + } + + var imageVariable = context.Variable(imageArrayPointerType, StorageClass.UniformConstant); + + context.Images.Add(new(image.Set, image.Binding), new ImageDeclaration(imageType, imagePointerType, imageVariable, image.ArrayLength != 1)); context.Name(imageVariable, image.Name); context.Decorate(imageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex); @@ -356,6 +399,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv context.AddGlobalVariable(perVertexInputVariable); context.Inputs.Add(new IoDefinition(StorageKind.Input, IoVariable.Position), perVertexInputVariable); + + if (context.Definitions.Stage == ShaderStage.Geometry && + context.Definitions.GpPassthrough && + context.HostCapabilities.SupportsGeometryShaderPassthrough) + { + context.MemberDecorate(perVertexInputStructType, 0, Decoration.PassthroughNV); + context.MemberDecorate(perVertexInputStructType, 1, Decoration.PassthroughNV); + context.MemberDecorate(perVertexInputStructType, 2, Decoration.PassthroughNV); + context.MemberDecorate(perVertexInputStructType, 3, Decoration.PassthroughNV); + } } var perVertexOutputStructType = CreatePerVertexStructType(context); diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/ImageDeclaration.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/ImageDeclaration.cs new file mode 100644 index 000000000..1e0aee734 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/ImageDeclaration.cs @@ -0,0 +1,20 @@ +using Spv.Generator; + +namespace Ryujinx.Graphics.Shader.CodeGen.Spirv +{ + readonly struct ImageDeclaration + { + public readonly Instruction ImageType; + public readonly Instruction ImagePointerType; + public readonly Instruction Image; + public readonly bool IsIndexed; + + public ImageDeclaration(Instruction imageType, Instruction imagePointerType, Instruction image, bool isIndexed) + { + ImageType = imageType; + ImagePointerType = imagePointerType; + Image = image; + IsIndexed = isIndexed; + } + } +} diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs index 601753cb0..6206985d8 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs @@ -591,34 +591,28 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { AstTextureOperation texOp = (AstTextureOperation)operation; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; - var componentType = texOp.Format.GetComponentType(); - // TODO: Bindless texture support. For now we just return 0/do nothing. - if (isBindless) - { - return new OperationResult(componentType, componentType switch - { - AggregateType.S32 => context.Constant(context.TypeS32(), 0), - AggregateType.U32 => context.Constant(context.TypeU32(), 0u), - _ => context.Constant(context.TypeFP32(), 0f), - }); - } - bool isArray = (texOp.Type & SamplerType.Array) != 0; - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - int srcIndex = isBindless ? 1 : 0; + int srcIndex = 0; SpvInstruction Src(AggregateType type) { return context.Get(type, texOp.GetSource(srcIndex++)); } - if (isIndexed) + ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()]; + SpvInstruction image = declaration.Image; + + SpvInstruction resultType = context.GetType(componentType); + SpvInstruction imagePointerType = context.TypePointer(StorageClass.Image, resultType); + + if (declaration.IsIndexed) { - Src(AggregateType.S32); + SpvInstruction textureIndex = Src(AggregateType.S32); + + image = context.AccessChain(imagePointerType, image, textureIndex); } int coordsCount = texOp.Type.GetDimensions(); @@ -646,14 +640,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv SpvInstruction value = Src(componentType); - (var imageType, var imageVariable) = context.Images[texOp.Binding]; - - context.Load(imageType, imageVariable); - - SpvInstruction resultType = context.GetType(componentType); - SpvInstruction imagePointerType = context.TypePointer(StorageClass.Image, resultType); - - var pointer = context.ImageTexelPointer(imagePointerType, imageVariable, pCoords, context.Constant(context.TypeU32(), 0)); + var pointer = context.ImageTexelPointer(imagePointerType, image, pCoords, context.Constant(context.TypeU32(), 0)); var one = context.Constant(context.TypeU32(), 1); var zero = context.Constant(context.TypeU32(), 0); @@ -683,31 +670,29 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { AstTextureOperation texOp = (AstTextureOperation)operation; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; - var componentType = texOp.Format.GetComponentType(); - // TODO: Bindless texture support. For now we just return 0/do nothing. - if (isBindless) - { - return GetZeroOperationResult(context, texOp, componentType, isVector: true); - } - bool isArray = (texOp.Type & SamplerType.Array) != 0; - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - int srcIndex = isBindless ? 1 : 0; + int srcIndex = 0; SpvInstruction Src(AggregateType type) { return context.Get(type, texOp.GetSource(srcIndex++)); } - if (isIndexed) + ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()]; + SpvInstruction image = declaration.Image; + + if (declaration.IsIndexed) { - Src(AggregateType.S32); + SpvInstruction textureIndex = Src(AggregateType.S32); + + image = context.AccessChain(declaration.ImagePointerType, image, textureIndex); } + image = context.Load(declaration.ImageType, image); + int coordsCount = texOp.Type.GetDimensions(); int pCount = coordsCount + (isArray ? 1 : 0); @@ -731,9 +716,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv pCoords = Src(AggregateType.S32); } - (var imageType, var imageVariable) = context.Images[texOp.Binding]; - - var image = context.Load(imageType, imageVariable); var imageComponentType = context.GetType(componentType); var swizzledResultType = texOp.GetVectorType(componentType); @@ -747,29 +729,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { AstTextureOperation texOp = (AstTextureOperation)operation; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; - - // TODO: Bindless texture support. For now we just return 0/do nothing. - if (isBindless) - { - return OperationResult.Invalid; - } - bool isArray = (texOp.Type & SamplerType.Array) != 0; - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - int srcIndex = isBindless ? 1 : 0; + int srcIndex = 0; SpvInstruction Src(AggregateType type) { return context.Get(type, texOp.GetSource(srcIndex++)); } - if (isIndexed) + ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()]; + SpvInstruction image = declaration.Image; + + if (declaration.IsIndexed) { - Src(AggregateType.S32); + SpvInstruction textureIndex = Src(AggregateType.S32); + + image = context.AccessChain(declaration.ImagePointerType, image, textureIndex); } + image = context.Load(declaration.ImageType, image); + int coordsCount = texOp.Type.GetDimensions(); int pCount = coordsCount + (isArray ? 1 : 0); @@ -818,10 +798,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv var texel = context.CompositeConstruct(context.TypeVector(context.GetType(componentType), ComponentsCount), cElems); - (var imageType, var imageVariable) = context.Images[texOp.Binding]; - - var image = context.Load(imageType, imageVariable); - context.ImageWrite(image, pCoords, texel, ImageOperandsMask.MaskNone); return OperationResult.Invalid; @@ -854,16 +830,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { AstTextureOperation texOp = (AstTextureOperation)operation; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; - - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - - // TODO: Bindless texture support. For now we just return 0. - if (isBindless) - { - return new OperationResult(AggregateType.S32, context.Constant(context.TypeS32(), 0)); - } - int srcIndex = 0; SpvInstruction Src(AggregateType type) @@ -871,10 +837,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv return context.Get(type, texOp.GetSource(srcIndex++)); } - if (isIndexed) - { - Src(AggregateType.S32); - } + SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()]; + SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex); int pCount = texOp.Type.GetDimensions(); @@ -897,10 +861,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv pCoords = Src(AggregateType.FP32); } - (_, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding]; - - var image = context.Load(sampledImageType, sampledImageVariable); - var resultType = context.TypeVector(context.TypeFP32(), 2); var packed = context.ImageQueryLod(resultType, image, pCoords); var result = context.CompositeExtract(context.TypeFP32(), packed, (SpvLiteralInteger)texOp.Index); @@ -1182,7 +1142,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { AstTextureOperation texOp = (AstTextureOperation)operation; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isGather = (texOp.Flags & TextureFlags.Gather) != 0; bool hasDerivatives = (texOp.Flags & TextureFlags.Derivatives) != 0; bool intCoords = (texOp.Flags & TextureFlags.IntCoords) != 0; @@ -1192,29 +1151,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0; bool isArray = (texOp.Type & SamplerType.Array) != 0; - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0; bool isShadow = (texOp.Type & SamplerType.Shadow) != 0; - bool colorIsVector = isGather || !isShadow; - - // TODO: Bindless texture support. For now we just return 0. - if (isBindless) - { - return GetZeroOperationResult(context, texOp, AggregateType.FP32, colorIsVector); - } - - int srcIndex = isBindless ? 1 : 0; + int srcIndex = 0; SpvInstruction Src(AggregateType type) { return context.Get(type, texOp.GetSource(srcIndex++)); } - if (isIndexed) - { - Src(AggregateType.S32); - } + SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()]; + SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex); int coordsCount = texOp.Type.GetDimensions(); @@ -1419,15 +1367,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv operandsList.Add(sample); } + bool colorIsVector = isGather || !isShadow; + var resultType = colorIsVector ? context.TypeVector(context.TypeFP32(), 4) : context.TypeFP32(); - (var imageType, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding]; - - var image = context.Load(sampledImageType, sampledImageVariable); - if (intCoords) { - image = context.Image(imageType, image); + image = context.Image(declaration.ImageType, image); } var operands = operandsList.ToArray(); @@ -1485,25 +1431,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { AstTextureOperation texOp = (AstTextureOperation)operation; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; + int srcIndex = 0; - // TODO: Bindless texture support. For now we just return 0. - if (isBindless) - { - return new OperationResult(AggregateType.S32, context.Constant(context.TypeS32(), 0)); - } + SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()]; + SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex); - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - - if (isIndexed) - { - context.GetS32(texOp.GetSource(0)); - } - - (var imageType, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding]; - - var image = context.Load(sampledImageType, sampledImageVariable); - image = context.Image(imageType, image); + image = context.Image(declaration.ImageType, image); SpvInstruction result = context.ImageQuerySamples(context.TypeS32(), image); @@ -1514,25 +1447,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { AstTextureOperation texOp = (AstTextureOperation)operation; - bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; + int srcIndex = 0; - // TODO: Bindless texture support. For now we just return 0. - if (isBindless) - { - return new OperationResult(AggregateType.S32, context.Constant(context.TypeS32(), 0)); - } + SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()]; + SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex); - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - - if (isIndexed) - { - context.GetS32(texOp.GetSource(0)); - } - - (var imageType, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding]; - - var image = context.Load(sampledImageType, sampledImageVariable); - image = context.Image(imageType, image); + image = context.Image(declaration.ImageType, image); if (texOp.Index == 3) { @@ -1540,7 +1460,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv } else { - var type = context.SamplersTypes[texOp.Binding]; + var type = context.SamplersTypes[texOp.GetTextureSetAndBinding()]; bool hasLod = !type.HasFlag(SamplerType.Multisample) && type != SamplerType.TextureBuffer; int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.GetDimensions(); @@ -1556,8 +1476,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv if (hasLod) { - int lodSrcIndex = isBindless || isIndexed ? 1 : 0; - var lod = context.GetS32(operation.GetSource(lodSrcIndex)); + var lod = context.GetS32(operation.GetSource(srcIndex)); result = context.ImageQuerySizeLod(resultType, image, lod); } else @@ -1929,38 +1848,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv return context.Load(context.GetType(varType), context.Inputs[ioDefinition]); } - private static OperationResult GetZeroOperationResult( - CodeGenContext context, - AstTextureOperation texOp, - AggregateType scalarType, - bool isVector) - { - var zero = scalarType switch - { - AggregateType.S32 => context.Constant(context.TypeS32(), 0), - AggregateType.U32 => context.Constant(context.TypeU32(), 0u), - _ => context.Constant(context.TypeFP32(), 0f), - }; - - if (isVector) - { - AggregateType outputType = texOp.GetVectorType(scalarType); - - if ((outputType & AggregateType.ElementCountMask) != 0) - { - int componentsCount = BitOperations.PopCount((uint)texOp.Index); - - SpvInstruction[] values = new SpvInstruction[componentsCount]; - - values.AsSpan().Fill(zero); - - return new OperationResult(outputType, context.ConstantComposite(context.GetType(outputType), values)); - } - } - - return new OperationResult(scalarType, zero); - } - private static SpvInstruction GetSwizzledResult(CodeGenContext context, SpvInstruction vector, AggregateType swizzledResultType, int mask) { if ((swizzledResultType & AggregateType.ElementCountMask) != 0) @@ -1987,6 +1874,43 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv } } + private static SpvInstruction GenerateSampledImageLoad(CodeGenContext context, AstTextureOperation texOp, SamplerDeclaration declaration, ref int srcIndex) + { + SpvInstruction image = declaration.Image; + + if (declaration.IsIndexed) + { + SpvInstruction textureIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++)); + + image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex); + } + + if (texOp.IsSeparate) + { + image = context.Load(declaration.ImageType, image); + + SamplerDeclaration samplerDeclaration = context.Samplers[texOp.GetSamplerSetAndBinding()]; + + SpvInstruction sampler = samplerDeclaration.Image; + + if (samplerDeclaration.IsIndexed) + { + SpvInstruction samplerIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++)); + + sampler = context.AccessChain(samplerDeclaration.SampledImagePointerType, sampler, samplerIndex); + } + + sampler = context.Load(samplerDeclaration.ImageType, sampler); + image = context.SampledImage(declaration.SampledImageType, image, sampler); + } + else + { + image = context.Load(declaration.SampledImageType, image); + } + + return image; + } + private static OperationResult GenerateUnary( CodeGenContext context, AstOperation operation, diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SamplerDeclaration.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SamplerDeclaration.cs new file mode 100644 index 000000000..9e0ecd794 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SamplerDeclaration.cs @@ -0,0 +1,27 @@ +using Spv.Generator; + +namespace Ryujinx.Graphics.Shader.CodeGen.Spirv +{ + readonly struct SamplerDeclaration + { + public readonly Instruction ImageType; + public readonly Instruction SampledImageType; + public readonly Instruction SampledImagePointerType; + public readonly Instruction Image; + public readonly bool IsIndexed; + + public SamplerDeclaration( + Instruction imageType, + Instruction sampledImageType, + Instruction sampledImagePointerType, + Instruction image, + bool isIndexed) + { + ImageType = imageType; + SampledImageType = sampledImageType; + SampledImagePointerType = sampledImagePointerType; + Image = image; + IsIndexed = isIndexed; + } + } +} diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs index ccfdc46d0..b259dde28 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs @@ -43,6 +43,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv CodeGenContext context = new(info, parameters, instPool, integerPool); + context.AddCapability(Capability.Shader); + + context.SetMemoryModel(AddressingModel.Logical, MemoryModel.GLSL450); + context.AddCapability(Capability.GroupNonUniformBallot); context.AddCapability(Capability.GroupNonUniformShuffle); context.AddCapability(Capability.GroupNonUniformVote); @@ -51,6 +55,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv context.AddCapability(Capability.ImageQuery); context.AddCapability(Capability.SampledBuffer); + if (parameters.HostCapabilities.SupportsShaderFloat64) + { + context.AddCapability(Capability.Float64); + } + if (parameters.Definitions.TransformFeedbackEnabled && parameters.Definitions.LastInVertexPipeline) { context.AddCapability(Capability.TransformFeedback); @@ -58,7 +67,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv if (parameters.Definitions.Stage == ShaderStage.Fragment) { - if (context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Input, IoVariable.Layer))) + if (context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Input, IoVariable.Layer)) || + context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Input, IoVariable.PrimitiveId))) { context.AddCapability(Capability.Geometry); } diff --git a/src/Ryujinx.Graphics.Shader/GpuGraphicsState.cs b/src/Ryujinx.Graphics.Shader/GpuGraphicsState.cs index f16c71d55..38684002c 100644 --- a/src/Ryujinx.Graphics.Shader/GpuGraphicsState.cs +++ b/src/Ryujinx.Graphics.Shader/GpuGraphicsState.cs @@ -102,6 +102,11 @@ namespace Ryujinx.Graphics.Shader /// public readonly bool OriginUpperLeft; + /// + /// Indicates that the primitive ID values on the shader should be halved due to quad to triangles conversion. + /// + public readonly bool HalvePrimitiveId; + /// /// Creates a new GPU graphics state. /// @@ -124,6 +129,7 @@ namespace Ryujinx.Graphics.Shader /// Indicates whether dual source blend is enabled /// Indicates if negation of the viewport Y axis is enabled /// If true, indicates that the fragment origin is the upper left corner of the viewport, otherwise it is the lower left corner + /// Indicates that the primitive ID values on the shader should be halved due to quad to triangles conversion public GpuGraphicsState( bool earlyZForce, InputTopology topology, @@ -143,7 +149,8 @@ namespace Ryujinx.Graphics.Shader in Array8 fragmentOutputTypes, bool dualSourceBlendEnable, bool yNegateEnabled, - bool originUpperLeft) + bool originUpperLeft, + bool halvePrimitiveId) { EarlyZForce = earlyZForce; Topology = topology; @@ -164,6 +171,7 @@ namespace Ryujinx.Graphics.Shader DualSourceBlendEnable = dualSourceBlendEnable; YNegateEnabled = yNegateEnabled; OriginUpperLeft = originUpperLeft; + HalvePrimitiveId = halvePrimitiveId; } } } diff --git a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs index df6d29dc5..4e6d6edf9 100644 --- a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs +++ b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs @@ -27,45 +27,42 @@ namespace Ryujinx.Graphics.Shader ReadOnlySpan GetCode(ulong address, int minimumSize); /// - /// Queries the binding number of a constant buffer. + /// Gets the binding number of a constant buffer. /// /// Constant buffer index /// Binding number - int QueryBindingConstantBuffer(int index) - { - return index + 1; - } + SetBindingPair CreateConstantBufferBinding(int index); /// - /// Queries the binding number of a storage buffer. + /// Gets the binding number of an image. + /// + /// For array of images, the number of elements of the array, otherwise it should be 1 + /// Indicates if the image is a buffer image + /// Binding number + SetBindingPair CreateImageBinding(int count, bool isBuffer); + + /// + /// Gets the binding number of a storage buffer. /// /// Storage buffer index /// Binding number - int QueryBindingStorageBuffer(int index) - { - return index; - } + SetBindingPair CreateStorageBufferBinding(int index); /// - /// Queries the binding number of a texture. + /// Gets the binding number of a texture. /// - /// Texture index + /// For array of textures, the number of elements of the array, otherwise it should be 1 /// Indicates if the texture is a buffer texture /// Binding number - int QueryBindingTexture(int index, bool isBuffer) - { - return index; - } + SetBindingPair CreateTextureBinding(int count, bool isBuffer); /// - /// Queries the binding number of an image. + /// Gets the set index for an additional set, or -1 if there's no extra set available. /// - /// Image index - /// Indicates if the image is a buffer image - /// Binding number - int QueryBindingImage(int index, bool isBuffer) + /// Extra set index, or -1 if not available + int CreateExtraSet() { - return index; + return -1; } /// @@ -147,6 +144,7 @@ namespace Ryujinx.Graphics.Shader default, false, false, + false, false); } @@ -303,6 +301,15 @@ namespace Ryujinx.Graphics.Shader return true; } + /// + /// Queries host API support for separate textures and samplers. + /// + /// True if the API supports samplers and textures to be combined on the shader, false otherwise + bool QueryHostSupportsSeparateSampler() + { + return true; + } + /// /// Queries host GPU shader ballot support. /// @@ -393,6 +400,12 @@ namespace Ryujinx.Graphics.Shader return true; } + /// + /// Gets the maximum number of samplers that the bound texture pool may have. + /// + /// Maximum amount of samplers that the pool may have + int QuerySamplerArrayLengthFromPool(); + /// /// Queries sampler type information. /// @@ -404,6 +417,19 @@ namespace Ryujinx.Graphics.Shader return SamplerType.Texture2D; } + /// + /// Gets the size in bytes of a bound constant buffer for the current shader stage. + /// + /// The number of the constant buffer to get the size from + /// Size in bytes + int QueryTextureArrayLengthFromBuffer(int slot); + + /// + /// Gets the maximum number of textures that the bound texture pool may have. + /// + /// Maximum amount of textures that the pool may have + int QueryTextureArrayLengthFromPool(); + /// /// Queries texture coordinate normalization information. /// diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs index 63ce38e25..c704156bc 100644 --- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs +++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs @@ -84,6 +84,10 @@ namespace Ryujinx.Graphics.Shader.Instructions value = context.IConvertU32ToFP32(value); } } + else if (offset == AttributeConsts.PrimitiveId && context.TranslatorContext.Definitions.HalvePrimitiveId) + { + value = context.ShiftRightS32(value, Const(1)); + } context.Copy(Register(rd), value); } @@ -187,6 +191,12 @@ namespace Ryujinx.Graphics.Shader.Instructions } } } + else if (op.Imm10 == AttributeConsts.PrimitiveId && context.TranslatorContext.Definitions.HalvePrimitiveId) + { + // If quads are used, but the host does not support them, they need to be converted to triangles. + // Since each quad becomes 2 triangles, we need to compensate here and divide primitive ID by 2. + res = context.ShiftRightS32(res, Const(1)); + } else if (op.Imm10 == AttributeConsts.FrontFacing && context.TranslatorContext.GpuAccessor.QueryHostHasFrontFacingBug()) { // gl_FrontFacing sometimes has incorrect (flipped) values depending how it is accessed on Intel GPUs. diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs index 40129252a..3fcb821d3 100644 --- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs +++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs @@ -222,30 +222,14 @@ namespace Ryujinx.Graphics.Shader.Instructions context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); } break; - case AtomOp.And: - if (type == AtomSize.S32 || type == AtomSize.U32) + case AtomOp.Min: + if (type == AtomSize.S32) { - res = context.AtomicAnd(storageKind, e0, e1, value); + res = context.AtomicMinS32(storageKind, e0, e1, value); } - else + else if (type == AtomSize.U32) { - context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); - } - break; - case AtomOp.Xor: - if (type == AtomSize.S32 || type == AtomSize.U32) - { - res = context.AtomicXor(storageKind, e0, e1, value); - } - else - { - context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); - } - break; - case AtomOp.Or: - if (type == AtomSize.S32 || type == AtomSize.U32) - { - res = context.AtomicOr(storageKind, e0, e1, value); + res = context.AtomicMinU32(storageKind, e0, e1, value); } else { @@ -266,20 +250,49 @@ namespace Ryujinx.Graphics.Shader.Instructions context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); } break; - case AtomOp.Min: - if (type == AtomSize.S32) + case AtomOp.And: + if (type == AtomSize.S32 || type == AtomSize.U32) { - res = context.AtomicMinS32(storageKind, e0, e1, value); - } - else if (type == AtomSize.U32) - { - res = context.AtomicMinU32(storageKind, e0, e1, value); + res = context.AtomicAnd(storageKind, e0, e1, value); } else { context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); } break; + case AtomOp.Or: + if (type == AtomSize.S32 || type == AtomSize.U32) + { + res = context.AtomicOr(storageKind, e0, e1, value); + } + else + { + context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); + } + break; + case AtomOp.Xor: + if (type == AtomSize.S32 || type == AtomSize.U32) + { + res = context.AtomicXor(storageKind, e0, e1, value); + } + else + { + context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); + } + break; + case AtomOp.Exch: + if (type == AtomSize.S32 || type == AtomSize.U32) + { + res = context.AtomicSwap(storageKind, e0, e1, value); + } + else + { + context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); + } + break; + default: + context.TranslatorContext.GpuAccessor.Log($"Invalid atomic operation: {op}."); + break; } return res; diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitPredicate.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitPredicate.cs index 630162ade..1d8651254 100644 --- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitPredicate.cs +++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitPredicate.cs @@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Shader.Instructions if (op.BVal) { - context.Copy(dest, context.ConditionalSelect(res, ConstF(1), Const(0))); + context.Copy(dest, context.ConditionalSelect(res, ConstF(1), ConstF(0))); } else { diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs index 0aac0ffa8..383e82c69 100644 --- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs +++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs @@ -278,7 +278,7 @@ namespace Ryujinx.Graphics.Shader.Instructions flags |= TextureFlags.Bindless; } - int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding( + SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding( Instruction.ImageAtomic, type, format, @@ -286,7 +286,7 @@ namespace Ryujinx.Graphics.Shader.Instructions TextureOperation.DefaultCbufSlot, imm); - Operand res = context.ImageAtomic(type, format, flags, binding, sources); + Operand res = context.ImageAtomic(type, format, flags, setAndBinding, sources); context.Copy(d, res); } @@ -389,7 +389,7 @@ namespace Ryujinx.Graphics.Shader.Instructions TextureFormat format = isBindless ? TextureFormat.Unknown : ShaderProperties.GetTextureFormat(context.TranslatorContext.GpuAccessor, handle); - int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding( + SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding( Instruction.ImageLoad, type, format, @@ -397,7 +397,7 @@ namespace Ryujinx.Graphics.Shader.Instructions TextureOperation.DefaultCbufSlot, handle); - context.ImageLoad(type, format, flags, binding, (int)componentMask, dests, sources); + context.ImageLoad(type, format, flags, setAndBinding, (int)componentMask, dests, sources); } else { @@ -432,7 +432,7 @@ namespace Ryujinx.Graphics.Shader.Instructions TextureFormat format = GetTextureFormat(size); - int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding( + SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding( Instruction.ImageLoad, type, format, @@ -440,7 +440,7 @@ namespace Ryujinx.Graphics.Shader.Instructions TextureOperation.DefaultCbufSlot, handle); - context.ImageLoad(type, format, flags, binding, compMask, dests, sources); + context.ImageLoad(type, format, flags, setAndBinding, compMask, dests, sources); switch (size) { @@ -552,7 +552,7 @@ namespace Ryujinx.Graphics.Shader.Instructions flags |= TextureFlags.Bindless; } - int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding( + SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding( Instruction.ImageAtomic, type, format, @@ -560,7 +560,7 @@ namespace Ryujinx.Graphics.Shader.Instructions TextureOperation.DefaultCbufSlot, imm); - context.ImageAtomic(type, format, flags, binding, sources); + context.ImageAtomic(type, format, flags, setAndBinding, sources); } private static void EmitSust( @@ -679,7 +679,7 @@ namespace Ryujinx.Graphics.Shader.Instructions flags |= TextureFlags.Coherent; } - int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding( + SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding( Instruction.ImageStore, type, format, @@ -687,7 +687,7 @@ namespace Ryujinx.Graphics.Shader.Instructions TextureOperation.DefaultCbufSlot, handle); - context.ImageStore(type, format, flags, binding, sources); + context.ImageStore(type, format, flags, setAndBinding, sources); } private static int GetComponentSizeInBytesLog2(SuatomSize size) diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs index 55f7d5778..2076262da 100644 --- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs +++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs @@ -578,12 +578,7 @@ namespace Ryujinx.Graphics.Shader.Instructions type = SamplerType.Texture2D; flags = TextureFlags.Gather; - if (tld4sOp.Dc) - { - sourcesList.Add(Rb()); - - type |= SamplerType.Shadow; - } + int depthCompareIndex = sourcesList.Count; if (tld4sOp.Aoffi) { @@ -592,7 +587,16 @@ namespace Ryujinx.Graphics.Shader.Instructions flags |= TextureFlags.Offset; } - sourcesList.Add(Const((int)tld4sOp.TexComp)); + if (tld4sOp.Dc) + { + sourcesList.Insert(depthCompareIndex, Rb()); + + type |= SamplerType.Shadow; + } + else + { + sourcesList.Add(Const((int)tld4sOp.TexComp)); + } } else { @@ -881,7 +885,7 @@ namespace Ryujinx.Graphics.Shader.Instructions return Register(dest++, RegisterType.Gpr); } - int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding( + SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding( Instruction.Lod, type, TextureFormat.Unknown, @@ -909,7 +913,7 @@ namespace Ryujinx.Graphics.Shader.Instructions else { // The instruction component order is the inverse of GLSL's. - Operand res = context.Lod(type, flags, binding, compIndex ^ 1, sources); + Operand res = context.Lod(type, flags, setAndBinding, compIndex ^ 1, sources); res = context.FPMultiply(res, ConstF(256.0f)); @@ -1112,12 +1116,12 @@ namespace Ryujinx.Graphics.Shader.Instructions } TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None; - int binding; + SetBindingPair setAndBinding; switch (query) { case TexQuery.TexHeaderDimension: - binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding( + setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding( Instruction.TextureQuerySize, type, TextureFormat.Unknown, @@ -1136,13 +1140,13 @@ namespace Ryujinx.Graphics.Shader.Instructions break; } - context.Copy(d, context.TextureQuerySize(type, flags, binding, compIndex, sources)); + context.Copy(d, context.TextureQuerySize(type, flags, setAndBinding, compIndex, sources)); } } break; case TexQuery.TexHeaderTextureType: - binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding( + setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding( Instruction.TextureQuerySamples, type, TextureFormat.Unknown, @@ -1167,7 +1171,7 @@ namespace Ryujinx.Graphics.Shader.Instructions if (d != null) { - context.Copy(d, context.TextureQuerySamples(type, flags, binding, sources)); + context.Copy(d, context.TextureQuerySamples(type, flags, setAndBinding, sources)); } } break; @@ -1187,7 +1191,7 @@ namespace Ryujinx.Graphics.Shader.Instructions Operand[] dests, Operand[] sources) { - int binding = flags.HasFlag(TextureFlags.Bindless) ? 0 : context.ResourceManager.GetTextureOrImageBinding( + SetBindingPair setAndBinding = flags.HasFlag(TextureFlags.Bindless) ? default : context.ResourceManager.GetTextureOrImageBinding( Instruction.TextureSample, type, TextureFormat.Unknown, @@ -1195,7 +1199,7 @@ namespace Ryujinx.Graphics.Shader.Instructions TextureOperation.DefaultCbufSlot, handle); - context.TextureSample(type, flags, binding, componentMask, dests, sources); + context.TextureSample(type, flags, setAndBinding, componentMask, dests, sources); } private static SamplerType ConvertSamplerType(TexDim dimensions) diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs index e5695ebc2..273a38a5b 100644 --- a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs @@ -156,10 +156,42 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation return false; } + public static bool IsComparison(this Instruction inst) + { + switch (inst & Instruction.Mask) + { + case Instruction.CompareEqual: + case Instruction.CompareGreater: + case Instruction.CompareGreaterOrEqual: + case Instruction.CompareGreaterOrEqualU32: + case Instruction.CompareGreaterU32: + case Instruction.CompareLess: + case Instruction.CompareLessOrEqual: + case Instruction.CompareLessOrEqualU32: + case Instruction.CompareLessU32: + case Instruction.CompareNotEqual: + return true; + } + + return false; + } + public static bool IsTextureQuery(this Instruction inst) { inst &= Instruction.Mask; return inst == Instruction.Lod || inst == Instruction.TextureQuerySamples || inst == Instruction.TextureQuerySize; } + + public static bool IsImage(this Instruction inst) + { + inst &= Instruction.Mask; + return inst == Instruction.ImageAtomic || inst == Instruction.ImageLoad || inst == Instruction.ImageStore; + } + + public static bool IsImageStore(this Instruction inst) + { + inst &= Instruction.Mask; + return inst == Instruction.ImageAtomic || inst == Instruction.ImageStore; + } } } diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs index f5396a884..713e8a4fb 100644 --- a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs @@ -20,13 +20,13 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation } set { - if (value != null && value.Type == OperandType.LocalVariable) - { - value.AsgOp = this; - } - if (value != null) { + if (value.Type == OperandType.LocalVariable) + { + value.AsgOp = this; + } + _dests = new[] { value }; } else @@ -216,6 +216,11 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation newSources[index] = source; + if (source != null && source.Type == OperandType.LocalVariable) + { + source.UseOps.Add(this); + } + _sources = newSources; } diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs index fa5550a64..7eee8f2e9 100644 --- a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs @@ -8,13 +8,17 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation public TextureFormat Format { get; set; } public TextureFlags Flags { get; private set; } + public int Set { get; private set; } public int Binding { get; private set; } + public int SamplerSet { get; private set; } + public int SamplerBinding { get; private set; } public TextureOperation( Instruction inst, SamplerType type, TextureFormat format, TextureFlags flags, + int set, int binding, int compIndex, Operand[] dests, @@ -23,17 +27,28 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation Type = type; Format = format; Flags = flags; + Set = set; Binding = binding; + SamplerSet = -1; + SamplerBinding = -1; } - public void TurnIntoIndexed(int binding) + public void TurnIntoArray(SetBindingPair setAndBinding) { - Type |= SamplerType.Indexed; Flags &= ~TextureFlags.Bindless; - Binding = binding; + Set = setAndBinding.SetIndex; + Binding = setAndBinding.Binding; } - public void SetBinding(int binding) + public void TurnIntoArray(SetBindingPair textureSetAndBinding, SetBindingPair samplerSetAndBinding) + { + TurnIntoArray(textureSetAndBinding); + + SamplerSet = samplerSetAndBinding.SetIndex; + SamplerBinding = samplerSetAndBinding.Binding; + } + + public void SetBinding(SetBindingPair setAndBinding) { if ((Flags & TextureFlags.Bindless) != 0) { @@ -42,7 +57,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation RemoveSource(0); } - Binding = binding; + Set = setAndBinding.SetIndex; + Binding = setAndBinding.Binding; } public void SetLodLevelFlag() diff --git a/src/Ryujinx.Graphics.Shader/SamplerType.cs b/src/Ryujinx.Graphics.Shader/SamplerType.cs index 85e97368f..a693495fa 100644 --- a/src/Ryujinx.Graphics.Shader/SamplerType.cs +++ b/src/Ryujinx.Graphics.Shader/SamplerType.cs @@ -16,9 +16,8 @@ namespace Ryujinx.Graphics.Shader Mask = 0xff, Array = 1 << 8, - Indexed = 1 << 9, - Multisample = 1 << 10, - Shadow = 1 << 11, + Multisample = 1 << 9, + Shadow = 1 << 10, } static class SamplerTypeExtensions @@ -36,10 +35,41 @@ namespace Ryujinx.Graphics.Shader }; } + public static string ToShortSamplerType(this SamplerType type) + { + string typeName = (type & SamplerType.Mask) switch + { + SamplerType.Texture1D => "1d", + SamplerType.TextureBuffer => "b", + SamplerType.Texture2D => "2d", + SamplerType.Texture3D => "3d", + SamplerType.TextureCube => "cube", + _ => throw new ArgumentException($"Invalid sampler type \"{type}\"."), + }; + + if ((type & SamplerType.Multisample) != 0) + { + typeName += "ms"; + } + + if ((type & SamplerType.Array) != 0) + { + typeName += "a"; + } + + if ((type & SamplerType.Shadow) != 0) + { + typeName += "s"; + } + + return typeName; + } + public static string ToGlslSamplerType(this SamplerType type) { string typeName = (type & SamplerType.Mask) switch { + SamplerType.None => "sampler", SamplerType.Texture1D => "sampler1D", SamplerType.TextureBuffer => "samplerBuffer", SamplerType.Texture2D => "sampler2D", @@ -66,6 +96,31 @@ namespace Ryujinx.Graphics.Shader return typeName; } + public static string ToGlslTextureType(this SamplerType type) + { + string typeName = (type & SamplerType.Mask) switch + { + SamplerType.Texture1D => "texture1D", + SamplerType.TextureBuffer => "textureBuffer", + SamplerType.Texture2D => "texture2D", + SamplerType.Texture3D => "texture3D", + SamplerType.TextureCube => "textureCube", + _ => throw new ArgumentException($"Invalid texture type \"{type}\"."), + }; + + if ((type & SamplerType.Multisample) != 0) + { + typeName += "MS"; + } + + if ((type & SamplerType.Array) != 0) + { + typeName += "Array"; + } + + return typeName; + } + public static string ToGlslImageType(this SamplerType type, AggregateType componentType) { string typeName = (type & SamplerType.Mask) switch diff --git a/src/Ryujinx.Graphics.Shader/SetBindingPair.cs b/src/Ryujinx.Graphics.Shader/SetBindingPair.cs new file mode 100644 index 000000000..1e8a4f9c6 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/SetBindingPair.cs @@ -0,0 +1,4 @@ +namespace Ryujinx.Graphics.Shader +{ + public readonly record struct SetBindingPair(int SetIndex, int Binding); +} diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs index 3970df1e9..867cae853 100644 --- a/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs +++ b/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs @@ -8,21 +8,42 @@ namespace Ryujinx.Graphics.Shader.StructuredIr public TextureFormat Format { get; } public TextureFlags Flags { get; } + public int Set { get; } public int Binding { get; } + public int SamplerSet { get; } + public int SamplerBinding { get; } + + public bool IsSeparate => SamplerBinding >= 0; public AstTextureOperation( Instruction inst, SamplerType type, TextureFormat format, TextureFlags flags, + int set, int binding, + int samplerSet, + int samplerBinding, int index, params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length) { Type = type; Format = format; Flags = flags; + Set = set; Binding = binding; + SamplerSet = samplerSet; + SamplerBinding = samplerBinding; + } + + public SetBindingPair GetTextureSetAndBinding() + { + return new SetBindingPair(Set, Binding); + } + + public SetBindingPair GetSamplerSetAndBinding() + { + return new SetBindingPair(SamplerSet, SamplerBinding); } } } diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/PhiFunctions.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/PhiFunctions.cs index 8b1cb9c56..90f1f2f6d 100644 --- a/src/Ryujinx.Graphics.Shader/StructuredIr/PhiFunctions.cs +++ b/src/Ryujinx.Graphics.Shader/StructuredIr/PhiFunctions.cs @@ -24,17 +24,21 @@ namespace Ryujinx.Graphics.Shader.StructuredIr continue; } + Operand temp = OperandHelper.Local(); + for (int index = 0; index < phi.SourcesCount; index++) { Operand src = phi.GetSource(index); - BasicBlock srcBlock = phi.GetBlock(index); - Operation copyOp = new(Instruction.Copy, phi.Dest, src); + Operation copyOp = new(Instruction.Copy, temp, src); srcBlock.Append(copyOp); } + Operation copyOp2 = new(Instruction.Copy, phi.Dest, temp); + + nextNode = block.Operations.AddAfter(node, copyOp2).Next; block.Operations.Remove(node); node = nextNode; diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs index 8c12c2aaf..53ed6bfcc 100644 --- a/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs +++ b/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs @@ -6,15 +6,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr { private readonly Dictionary _constantBuffers; private readonly Dictionary _storageBuffers; - private readonly Dictionary _textures; - private readonly Dictionary _images; + private readonly Dictionary _textures; + private readonly Dictionary _images; private readonly Dictionary _localMemories; private readonly Dictionary _sharedMemories; public IReadOnlyDictionary ConstantBuffers => _constantBuffers; public IReadOnlyDictionary StorageBuffers => _storageBuffers; - public IReadOnlyDictionary Textures => _textures; - public IReadOnlyDictionary Images => _images; + public IReadOnlyDictionary Textures => _textures; + public IReadOnlyDictionary Images => _images; public IReadOnlyDictionary LocalMemories => _localMemories; public IReadOnlyDictionary SharedMemories => _sharedMemories; @@ -22,8 +22,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr { _constantBuffers = new Dictionary(); _storageBuffers = new Dictionary(); - _textures = new Dictionary(); - _images = new Dictionary(); + _textures = new Dictionary(); + _images = new Dictionary(); _localMemories = new Dictionary(); _sharedMemories = new Dictionary(); } @@ -40,12 +40,12 @@ namespace Ryujinx.Graphics.Shader.StructuredIr public void AddOrUpdateTexture(TextureDefinition definition) { - _textures[definition.Binding] = definition; + _textures[new(definition.Set, definition.Binding)] = definition; } public void AddOrUpdateImage(TextureDefinition definition) { - _images[definition.Binding] = definition; + _images[new(definition.Set, definition.Binding)] = definition; } public int AddLocalMemory(MemoryDefinition definition) diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs index 2e2df7546..88053658d 100644 --- a/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs +++ b/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs @@ -169,7 +169,17 @@ namespace Ryujinx.Graphics.Shader.StructuredIr AstTextureOperation GetAstTextureOperation(TextureOperation texOp) { - return new AstTextureOperation(inst, texOp.Type, texOp.Format, texOp.Flags, texOp.Binding, texOp.Index, sources); + return new AstTextureOperation( + inst, + texOp.Type, + texOp.Format, + texOp.Flags, + texOp.Set, + texOp.Binding, + texOp.SamplerSet, + texOp.SamplerBinding, + texOp.Index, + sources); } int componentsCount = BitOperations.PopCount((uint)operation.Index); diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs index e45c82854..1021dff0e 100644 --- a/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs +++ b/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs @@ -4,24 +4,40 @@ namespace Ryujinx.Graphics.Shader { public int Set { get; } public int Binding { get; } + public int ArrayLength { get; } + public bool Separate { get; } public string Name { get; } public SamplerType Type { get; } public TextureFormat Format { get; } public TextureUsageFlags Flags { get; } - public TextureDefinition(int set, int binding, string name, SamplerType type, TextureFormat format, TextureUsageFlags flags) + public TextureDefinition( + int set, + int binding, + int arrayLength, + bool separate, + string name, + SamplerType type, + TextureFormat format, + TextureUsageFlags flags) { Set = set; Binding = binding; + ArrayLength = arrayLength; + Separate = separate; Name = name; Type = type; Format = format; Flags = flags; } + public TextureDefinition(int set, int binding, string name, SamplerType type) : this(set, binding, 1, false, name, type, TextureFormat.Unknown, TextureUsageFlags.None) + { + } + public TextureDefinition SetFlag(TextureUsageFlags flag) { - return new TextureDefinition(Set, Binding, Name, Type, Format, Flags | flag); + return new TextureDefinition(Set, Binding, ArrayLength, Separate, Name, Type, Format, Flags | flag); } } } diff --git a/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs b/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs index 1130b63b8..1e387407d 100644 --- a/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs +++ b/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs @@ -4,6 +4,7 @@ namespace Ryujinx.Graphics.Shader { // New fields should be added to the end of the struct to keep disk shader cache compatibility. + public readonly int Set; public readonly int Binding; public readonly SamplerType Type; @@ -11,16 +12,31 @@ namespace Ryujinx.Graphics.Shader public readonly int CbufSlot; public readonly int HandleIndex; + public readonly int ArrayLength; + + public readonly bool Separate; public readonly TextureUsageFlags Flags; - public TextureDescriptor(int binding, SamplerType type, TextureFormat format, int cbufSlot, int handleIndex, TextureUsageFlags flags) + public TextureDescriptor( + int set, + int binding, + SamplerType type, + TextureFormat format, + int cbufSlot, + int handleIndex, + int arrayLength, + bool separate, + TextureUsageFlags flags) { + Set = set; Binding = binding; Type = type; Format = format; CbufSlot = cbufSlot; HandleIndex = handleIndex; + ArrayLength = arrayLength; + Separate = separate; Flags = flags; } } diff --git a/src/Ryujinx.Graphics.Shader/TextureHandle.cs b/src/Ryujinx.Graphics.Shader/TextureHandle.cs index fc9ab2d67..3aaceac48 100644 --- a/src/Ryujinx.Graphics.Shader/TextureHandle.cs +++ b/src/Ryujinx.Graphics.Shader/TextureHandle.cs @@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Shader SeparateSamplerHandle = 1, SeparateSamplerId = 2, SeparateConstantSamplerHandle = 3, + Direct = 4, } public static class TextureHandle @@ -88,7 +89,7 @@ namespace Ryujinx.Graphics.Shader { (int textureWordOffset, int samplerWordOffset, TextureHandleType handleType) = UnpackOffsets(wordOffset); - int handle = cachedTextureBuffer.Length != 0 ? cachedTextureBuffer[textureWordOffset] : 0; + int handle = textureWordOffset < cachedTextureBuffer.Length ? cachedTextureBuffer[textureWordOffset] : 0; // The "wordOffset" (which is really the immediate value used on texture instructions on the shader) // is a 13-bit value. However, in order to also support separate samplers and textures (which uses @@ -102,7 +103,7 @@ namespace Ryujinx.Graphics.Shader if (handleType != TextureHandleType.SeparateConstantSamplerHandle) { - samplerHandle = cachedSamplerBuffer.Length != 0 ? cachedSamplerBuffer[samplerWordOffset] : 0; + samplerHandle = samplerWordOffset < cachedSamplerBuffer.Length ? cachedSamplerBuffer[samplerWordOffset] : 0; } else { diff --git a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs index f1dffb351..5e07b39f1 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs @@ -80,9 +80,10 @@ namespace Ryujinx.Graphics.Shader.Translation return; } - if (TranslatorContext.Definitions.Stage == ShaderStage.Vertex && TranslatorContext.Options.TargetApi == TargetApi.Vulkan) + // Vulkan requires the point size to be always written on the shader if the primitive topology is points. + // OpenGL requires the point size to be always written on the shader if PROGRAM_POINT_SIZE is set. + if (TranslatorContext.Definitions.Stage == ShaderStage.Vertex) { - // Vulkan requires the point size to be always written on the shader if the primitive topology is points. this.Store(StorageKind.Output, IoVariable.PointSize, null, ConstF(TranslatorContext.Definitions.PointSize)); } @@ -123,7 +124,7 @@ namespace Ryujinx.Graphics.Shader.Translation this.TextureSample( SamplerType.TextureBuffer, TextureFlags.IntCoords, - ResourceManager.Reservations.IndexBufferTextureBinding, + ResourceManager.Reservations.GetIndexBufferTextureSetAndBinding(), 1, new[] { vertexIndexVr }, new[] { this.IAdd(ibBaseOffset, outputVertexOffset) }); @@ -144,7 +145,7 @@ namespace Ryujinx.Graphics.Shader.Translation this.TextureSample( SamplerType.TextureBuffer, TextureFlags.IntCoords, - ResourceManager.Reservations.TopologyRemapBufferTextureBinding, + ResourceManager.Reservations.GetTopologyRemapBufferTextureSetAndBinding(), 1, new[] { vertexIndex }, new[] { this.IAdd(baseVertex, Const(index)) }); diff --git a/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs b/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs index 9e314c620..5bdbb0025 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs @@ -618,12 +618,21 @@ namespace Ryujinx.Graphics.Shader.Translation SamplerType type, TextureFormat format, TextureFlags flags, - int binding, + SetBindingPair setAndBinding, Operand[] sources) { Operand dest = Local(); - context.Add(new TextureOperation(Instruction.ImageAtomic, type, format, flags, binding, 0, new[] { dest }, sources)); + context.Add(new TextureOperation( + Instruction.ImageAtomic, + type, + format, + flags, + setAndBinding.SetIndex, + setAndBinding.Binding, + 0, + new[] { dest }, + sources)); return dest; } @@ -633,12 +642,21 @@ namespace Ryujinx.Graphics.Shader.Translation SamplerType type, TextureFormat format, TextureFlags flags, - int binding, + SetBindingPair setAndBinding, int compMask, Operand[] dests, Operand[] sources) { - context.Add(new TextureOperation(Instruction.ImageLoad, type, format, flags, binding, compMask, dests, sources)); + context.Add(new TextureOperation( + Instruction.ImageLoad, + type, + format, + flags, + setAndBinding.SetIndex, + setAndBinding.Binding, + compMask, + dests, + sources)); } public static void ImageStore( @@ -646,10 +664,19 @@ namespace Ryujinx.Graphics.Shader.Translation SamplerType type, TextureFormat format, TextureFlags flags, - int binding, + SetBindingPair setAndBinding, Operand[] sources) { - context.Add(new TextureOperation(Instruction.ImageStore, type, format, flags, binding, 0, null, sources)); + context.Add(new TextureOperation( + Instruction.ImageStore, + type, + format, + flags, + setAndBinding.SetIndex, + setAndBinding.Binding, + 0, + null, + sources)); } public static Operand IsNan(this EmitterContext context, Operand a, Instruction fpType = Instruction.FP32) @@ -718,13 +745,22 @@ namespace Ryujinx.Graphics.Shader.Translation this EmitterContext context, SamplerType type, TextureFlags flags, - int binding, + SetBindingPair setAndBinding, int compIndex, Operand[] sources) { Operand dest = Local(); - context.Add(new TextureOperation(Instruction.Lod, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources)); + context.Add(new TextureOperation( + Instruction.Lod, + type, + TextureFormat.Unknown, + flags, + setAndBinding.SetIndex, + setAndBinding.Binding, + compIndex, + new[] { dest }, + sources)); return dest; } @@ -889,24 +925,42 @@ namespace Ryujinx.Graphics.Shader.Translation this EmitterContext context, SamplerType type, TextureFlags flags, - int binding, + SetBindingPair setAndBinding, int compMask, Operand[] dests, Operand[] sources) { - context.Add(new TextureOperation(Instruction.TextureSample, type, TextureFormat.Unknown, flags, binding, compMask, dests, sources)); + context.Add(new TextureOperation( + Instruction.TextureSample, + type, + TextureFormat.Unknown, + flags, + setAndBinding.SetIndex, + setAndBinding.Binding, + compMask, + dests, + sources)); } public static Operand TextureQuerySamples( this EmitterContext context, SamplerType type, TextureFlags flags, - int binding, + SetBindingPair setAndBinding, Operand[] sources) { Operand dest = Local(); - context.Add(new TextureOperation(Instruction.TextureQuerySamples, type, TextureFormat.Unknown, flags, binding, 0, new[] { dest }, sources)); + context.Add(new TextureOperation( + Instruction.TextureQuerySamples, + type, + TextureFormat.Unknown, + flags, + setAndBinding.SetIndex, + setAndBinding.Binding, + 0, + new[] { dest }, + sources)); return dest; } @@ -915,13 +969,22 @@ namespace Ryujinx.Graphics.Shader.Translation this EmitterContext context, SamplerType type, TextureFlags flags, - int binding, + SetBindingPair setAndBinding, int compIndex, Operand[] sources) { Operand dest = Local(); - context.Add(new TextureOperation(Instruction.TextureQuerySize, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources)); + context.Add(new TextureOperation( + Instruction.TextureQuerySize, + type, + TextureFormat.Unknown, + flags, + setAndBinding.SetIndex, + setAndBinding.Binding, + compIndex, + new[] { dest }, + sources)); return dest; } diff --git a/src/Ryujinx.Graphics.Shader/Translation/HostCapabilities.cs b/src/Ryujinx.Graphics.Shader/Translation/HostCapabilities.cs index 2523272b0..11fe6599d 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/HostCapabilities.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/HostCapabilities.cs @@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Shader.Translation public readonly bool SupportsGeometryShaderPassthrough; public readonly bool SupportsShaderBallot; public readonly bool SupportsShaderBarrierDivergence; + public readonly bool SupportsShaderFloat64; public readonly bool SupportsTextureShadowLod; public readonly bool SupportsViewportMask; @@ -18,6 +19,7 @@ namespace Ryujinx.Graphics.Shader.Translation bool supportsGeometryShaderPassthrough, bool supportsShaderBallot, bool supportsShaderBarrierDivergence, + bool supportsShaderFloat64, bool supportsTextureShadowLod, bool supportsViewportMask) { @@ -27,6 +29,7 @@ namespace Ryujinx.Graphics.Shader.Translation SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough; SupportsShaderBallot = supportsShaderBallot; SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence; + SupportsShaderFloat64 = supportsShaderFloat64; SupportsTextureShadowLod = supportsTextureShadowLod; SupportsViewportMask = supportsViewportMask; } diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs index a88903274..1f2f79a2d 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs @@ -1,6 +1,7 @@ using Ryujinx.Graphics.Shader.Instructions; using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.StructuredIr; +using System; using System.Collections.Generic; namespace Ryujinx.Graphics.Shader.Translation.Optimizations @@ -15,8 +16,12 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations // - The handle is a constant buffer value. // - The handle is the result of a bitwise OR logical operation. // - Both sources of the OR operation comes from a constant buffer. - for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) + LinkedListNode nextNode; + + for (LinkedListNode node = block.Operations.First; node != null; node = nextNode) { + nextNode = node.Next; + if (node.Value is not TextureOperation texOp) { continue; @@ -27,185 +32,325 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations continue; } - if (texOp.Inst == Instruction.TextureSample || texOp.Inst.IsTextureQuery()) + if (!TryConvertBindless(block, resourceManager, gpuAccessor, texOp) && + !GenerateBindlessAccess(block, resourceManager, gpuAccessor, texOp, node)) { - Operand bindlessHandle = texOp.GetSource(0); + // If we can't do bindless elimination, remove the texture operation. + // Set any destination variables to zero. - // In some cases the compiler uses a shuffle operation to get the handle, - // for some textureGrad implementations. In those cases, we can skip the shuffle. - if (bindlessHandle.AsgOp is Operation shuffleOp && shuffleOp.Inst == Instruction.Shuffle) + string typeName = texOp.Inst.IsImage() + ? texOp.Type.ToGlslImageType(texOp.Format.GetComponentType()) + : texOp.Type.ToGlslTextureType(); + + gpuAccessor.Log($"Failed to find handle source for bindless access of type \"{typeName}\"."); + + for (int destIndex = 0; destIndex < texOp.DestsCount; destIndex++) { - bindlessHandle = shuffleOp.GetSource(0); + block.Operations.AddBefore(node, new Operation(Instruction.Copy, texOp.GetDest(destIndex), OperandHelper.Const(0))); } - bindlessHandle = Utils.FindLastOperation(bindlessHandle, block); - - // Some instructions do not encode an accurate sampler type: - // - Most instructions uses the same type for 1D and Buffer. - // - Query instructions may not have any type. - // For those cases, we need to try getting the type from current GPU state, - // as long bindless elimination is successful and we know where the texture descriptor is located. - bool rewriteSamplerType = - texOp.Type == SamplerType.TextureBuffer || - texOp.Inst == Instruction.TextureQuerySamples || - texOp.Inst == Instruction.TextureQuerySize; - - if (bindlessHandle.Type == OperandType.ConstantBuffer) - { - SetHandle( - resourceManager, - gpuAccessor, - texOp, - bindlessHandle.GetCbufOffset(), - bindlessHandle.GetCbufSlot(), - rewriteSamplerType, - isImage: false); - - continue; - } - - if (!TryGetOperation(bindlessHandle.AsgOp, out Operation handleCombineOp)) - { - continue; - } - - if (handleCombineOp.Inst != Instruction.BitwiseOr) - { - continue; - } - - Operand src0 = Utils.FindLastOperation(handleCombineOp.GetSource(0), block); - Operand src1 = Utils.FindLastOperation(handleCombineOp.GetSource(1), block); - - // For cases where we have a constant, ensure that the constant is always - // the second operand. - // Since this is a commutative operation, both are fine, - // and having a "canonical" representation simplifies some checks below. - if (src0.Type == OperandType.Constant && src1.Type != OperandType.Constant) - { - (src0, src1) = (src1, src0); - } - - TextureHandleType handleType = TextureHandleType.SeparateSamplerHandle; - - // Try to match the following patterns: - // Masked pattern: - // - samplerHandle = samplerHandle & 0xFFF00000; - // - textureHandle = textureHandle & 0xFFFFF; - // - combinedHandle = samplerHandle | textureHandle; - // Where samplerHandle and textureHandle comes from a constant buffer. - // Shifted pattern: - // - samplerHandle = samplerId << 20; - // - combinedHandle = samplerHandle | textureHandle; - // Where samplerId and textureHandle comes from a constant buffer. - // Constant pattern: - // - combinedHandle = samplerHandleConstant | textureHandle; - // Where samplerHandleConstant is a constant value, and textureHandle comes from a constant buffer. - if (src0.AsgOp is Operation src0AsgOp) - { - if (src1.AsgOp is Operation src1AsgOp && - src0AsgOp.Inst == Instruction.BitwiseAnd && - src1AsgOp.Inst == Instruction.BitwiseAnd) - { - src0 = GetSourceForMaskedHandle(src0AsgOp, 0xFFFFF); - src1 = GetSourceForMaskedHandle(src1AsgOp, 0xFFF00000); - - // The OR operation is commutative, so we can also try to swap the operands to get a match. - if (src0 == null || src1 == null) - { - src0 = GetSourceForMaskedHandle(src1AsgOp, 0xFFFFF); - src1 = GetSourceForMaskedHandle(src0AsgOp, 0xFFF00000); - } - - if (src0 == null || src1 == null) - { - continue; - } - } - else if (src0AsgOp.Inst == Instruction.ShiftLeft) - { - Operand shift = src0AsgOp.GetSource(1); - - if (shift.Type == OperandType.Constant && shift.Value == 20) - { - src0 = src1; - src1 = src0AsgOp.GetSource(0); - handleType = TextureHandleType.SeparateSamplerId; - } - } - } - else if (src1.AsgOp is Operation src1AsgOp && src1AsgOp.Inst == Instruction.ShiftLeft) - { - Operand shift = src1AsgOp.GetSource(1); - - if (shift.Type == OperandType.Constant && shift.Value == 20) - { - src1 = src1AsgOp.GetSource(0); - handleType = TextureHandleType.SeparateSamplerId; - } - } - else if (src1.Type == OperandType.Constant && (src1.Value & 0xfffff) == 0) - { - handleType = TextureHandleType.SeparateConstantSamplerHandle; - } - - if (src0.Type != OperandType.ConstantBuffer) - { - continue; - } - - if (handleType == TextureHandleType.SeparateConstantSamplerHandle) - { - SetHandle( - resourceManager, - gpuAccessor, - texOp, - TextureHandle.PackOffsets(src0.GetCbufOffset(), ((src1.Value >> 20) & 0xfff), handleType), - TextureHandle.PackSlots(src0.GetCbufSlot(), 0), - rewriteSamplerType, - isImage: false); - } - else if (src1.Type == OperandType.ConstantBuffer) - { - SetHandle( - resourceManager, - gpuAccessor, - texOp, - TextureHandle.PackOffsets(src0.GetCbufOffset(), src1.GetCbufOffset(), handleType), - TextureHandle.PackSlots(src0.GetCbufSlot(), src1.GetCbufSlot()), - rewriteSamplerType, - isImage: false); - } + Utils.DeleteNode(node, texOp); } - else if (texOp.Inst == Instruction.ImageLoad || - texOp.Inst == Instruction.ImageStore || - texOp.Inst == Instruction.ImageAtomic) + } + } + + private static bool GenerateBindlessAccess( + BasicBlock block, + ResourceManager resourceManager, + IGpuAccessor gpuAccessor, + TextureOperation texOp, + LinkedListNode node) + { + if (!gpuAccessor.QueryHostSupportsSeparateSampler()) + { + // We depend on combining samplers and textures in the shader being supported for this. + + return false; + } + + Operand bindlessHandle = texOp.GetSource(0); + + if (bindlessHandle.AsgOp is PhiNode phi) + { + for (int srcIndex = 0; srcIndex < phi.SourcesCount; srcIndex++) { - Operand src0 = Utils.FindLastOperation(texOp.GetSource(0), block); + Operand phiSource = phi.GetSource(srcIndex); - if (src0.Type == OperandType.ConstantBuffer) + if (phiSource.AsgOp is not PhiNode && !IsBindlessAccessAllowed(phiSource)) { - int cbufOffset = src0.GetCbufOffset(); - int cbufSlot = src0.GetCbufSlot(); - - if (texOp.Format == TextureFormat.Unknown) - { - if (texOp.Inst == Instruction.ImageAtomic) - { - texOp.Format = ShaderProperties.GetTextureFormatAtomic(gpuAccessor, cbufOffset, cbufSlot); - } - else - { - texOp.Format = ShaderProperties.GetTextureFormat(gpuAccessor, cbufOffset, cbufSlot); - } - } - - bool rewriteSamplerType = texOp.Type == SamplerType.TextureBuffer; - - SetHandle(resourceManager, gpuAccessor, texOp, cbufOffset, cbufSlot, rewriteSamplerType, isImage: true); + return false; } } } + else if (!IsBindlessAccessAllowed(bindlessHandle)) + { + return false; + } + + Operand textureHandle = OperandHelper.Local(); + Operand samplerHandle = OperandHelper.Local(); + Operand textureIndex = OperandHelper.Local(); + + block.Operations.AddBefore(node, new Operation(Instruction.BitwiseAnd, textureHandle, bindlessHandle, OperandHelper.Const(0xfffff))); + block.Operations.AddBefore(node, new Operation(Instruction.ShiftRightU32, samplerHandle, bindlessHandle, OperandHelper.Const(20))); + + int texturePoolLength = Math.Max(BindlessToArray.MinimumArrayLength, gpuAccessor.QueryTextureArrayLengthFromPool()); + + block.Operations.AddBefore(node, new Operation(Instruction.MinimumU32, textureIndex, textureHandle, OperandHelper.Const(texturePoolLength - 1))); + + texOp.SetSource(0, textureIndex); + + bool hasSampler = !texOp.Inst.IsImage(); + + SetBindingPair textureSetAndBinding = resourceManager.GetTextureOrImageBinding( + texOp.Inst, + texOp.Type, + texOp.Format, + texOp.Flags & ~TextureFlags.Bindless, + 0, + TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct), + texturePoolLength, + hasSampler); + + if (hasSampler) + { + Operand samplerIndex = OperandHelper.Local(); + + int samplerPoolLength = Math.Max(BindlessToArray.MinimumArrayLength, gpuAccessor.QuerySamplerArrayLengthFromPool()); + + block.Operations.AddBefore(node, new Operation(Instruction.MinimumU32, samplerIndex, samplerHandle, OperandHelper.Const(samplerPoolLength - 1))); + + texOp.InsertSource(1, samplerIndex); + + SetBindingPair samplerSetAndBinding = resourceManager.GetTextureOrImageBinding( + texOp.Inst, + SamplerType.None, + texOp.Format, + TextureFlags.None, + 0, + TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct), + samplerPoolLength); + + texOp.TurnIntoArray(textureSetAndBinding, samplerSetAndBinding); + } + else + { + texOp.TurnIntoArray(textureSetAndBinding); + } + + return true; + } + + private static bool IsBindlessAccessAllowed(Operand bindlessHandle) + { + if (bindlessHandle.Type == OperandType.ConstantBuffer) + { + // Bindless access with handles from constant buffer is allowed. + + return true; + } + + if (bindlessHandle.AsgOp is not Operation handleOp || + handleOp.Inst != Instruction.Load || + (handleOp.StorageKind != StorageKind.Input && handleOp.StorageKind != StorageKind.StorageBuffer)) + { + // Right now, we only allow bindless access when the handle comes from a shader input or storage buffer. + // This is an artificial limitation to prevent it from being used in cases where it + // would have a large performance impact of loading all textures in the pool. + // It might be removed in the future, if we can mitigate the performance impact. + + return false; + } + + return true; + } + + private static bool TryConvertBindless(BasicBlock block, ResourceManager resourceManager, IGpuAccessor gpuAccessor, TextureOperation texOp) + { + if (texOp.Inst == Instruction.TextureSample || texOp.Inst.IsTextureQuery()) + { + Operand bindlessHandle = texOp.GetSource(0); + + // In some cases the compiler uses a shuffle operation to get the handle, + // for some textureGrad implementations. In those cases, we can skip the shuffle. + if (bindlessHandle.AsgOp is Operation shuffleOp && shuffleOp.Inst == Instruction.Shuffle) + { + bindlessHandle = shuffleOp.GetSource(0); + } + + bindlessHandle = Utils.FindLastOperation(bindlessHandle, block); + + // Some instructions do not encode an accurate sampler type: + // - Most instructions uses the same type for 1D and Buffer. + // - Query instructions may not have any type. + // For those cases, we need to try getting the type from current GPU state, + // as long bindless elimination is successful and we know where the texture descriptor is located. + bool rewriteSamplerType = + texOp.Type == SamplerType.TextureBuffer || + texOp.Inst == Instruction.TextureQuerySamples || + texOp.Inst == Instruction.TextureQuerySize; + + if (bindlessHandle.Type == OperandType.ConstantBuffer) + { + SetHandle( + resourceManager, + gpuAccessor, + texOp, + bindlessHandle.GetCbufOffset(), + bindlessHandle.GetCbufSlot(), + rewriteSamplerType, + isImage: false); + + return true; + } + + if (!TryGetOperation(bindlessHandle.AsgOp, out Operation handleCombineOp)) + { + return false; + } + + if (handleCombineOp.Inst != Instruction.BitwiseOr) + { + return false; + } + + Operand src0 = Utils.FindLastOperation(handleCombineOp.GetSource(0), block); + Operand src1 = Utils.FindLastOperation(handleCombineOp.GetSource(1), block); + + // For cases where we have a constant, ensure that the constant is always + // the second operand. + // Since this is a commutative operation, both are fine, + // and having a "canonical" representation simplifies some checks below. + if (src0.Type == OperandType.Constant && src1.Type != OperandType.Constant) + { + (src0, src1) = (src1, src0); + } + + TextureHandleType handleType = TextureHandleType.SeparateSamplerHandle; + + // Try to match the following patterns: + // Masked pattern: + // - samplerHandle = samplerHandle & 0xFFF00000; + // - textureHandle = textureHandle & 0xFFFFF; + // - combinedHandle = samplerHandle | textureHandle; + // Where samplerHandle and textureHandle comes from a constant buffer. + // Shifted pattern: + // - samplerHandle = samplerId << 20; + // - combinedHandle = samplerHandle | textureHandle; + // Where samplerId and textureHandle comes from a constant buffer. + // Constant pattern: + // - combinedHandle = samplerHandleConstant | textureHandle; + // Where samplerHandleConstant is a constant value, and textureHandle comes from a constant buffer. + if (src0.AsgOp is Operation src0AsgOp) + { + if (src1.AsgOp is Operation src1AsgOp && + src0AsgOp.Inst == Instruction.BitwiseAnd && + src1AsgOp.Inst == Instruction.BitwiseAnd) + { + src0 = GetSourceForMaskedHandle(src0AsgOp, 0xFFFFF); + src1 = GetSourceForMaskedHandle(src1AsgOp, 0xFFF00000); + + // The OR operation is commutative, so we can also try to swap the operands to get a match. + if (src0 == null || src1 == null) + { + src0 = GetSourceForMaskedHandle(src1AsgOp, 0xFFFFF); + src1 = GetSourceForMaskedHandle(src0AsgOp, 0xFFF00000); + } + + if (src0 == null || src1 == null) + { + return false; + } + } + else if (src0AsgOp.Inst == Instruction.ShiftLeft) + { + Operand shift = src0AsgOp.GetSource(1); + + if (shift.Type == OperandType.Constant && shift.Value == 20) + { + src0 = src1; + src1 = src0AsgOp.GetSource(0); + handleType = TextureHandleType.SeparateSamplerId; + } + } + } + else if (src1.AsgOp is Operation src1AsgOp && src1AsgOp.Inst == Instruction.ShiftLeft) + { + Operand shift = src1AsgOp.GetSource(1); + + if (shift.Type == OperandType.Constant && shift.Value == 20) + { + src1 = src1AsgOp.GetSource(0); + handleType = TextureHandleType.SeparateSamplerId; + } + } + else if (src1.Type == OperandType.Constant && (src1.Value & 0xfffff) == 0) + { + handleType = TextureHandleType.SeparateConstantSamplerHandle; + } + + if (src0.Type != OperandType.ConstantBuffer) + { + return false; + } + + if (handleType == TextureHandleType.SeparateConstantSamplerHandle) + { + SetHandle( + resourceManager, + gpuAccessor, + texOp, + TextureHandle.PackOffsets(src0.GetCbufOffset(), (src1.Value >> 20) & 0xfff, handleType), + TextureHandle.PackSlots(src0.GetCbufSlot(), 0), + rewriteSamplerType, + isImage: false); + + return true; + } + else if (src1.Type == OperandType.ConstantBuffer) + { + SetHandle( + resourceManager, + gpuAccessor, + texOp, + TextureHandle.PackOffsets(src0.GetCbufOffset(), src1.GetCbufOffset(), handleType), + TextureHandle.PackSlots(src0.GetCbufSlot(), src1.GetCbufSlot()), + rewriteSamplerType, + isImage: false); + + return true; + } + } + else if (texOp.Inst.IsImage()) + { + Operand src0 = Utils.FindLastOperation(texOp.GetSource(0), block); + + if (src0.Type == OperandType.ConstantBuffer) + { + int cbufOffset = src0.GetCbufOffset(); + int cbufSlot = src0.GetCbufSlot(); + + if (texOp.Format == TextureFormat.Unknown) + { + if (texOp.Inst == Instruction.ImageAtomic) + { + texOp.Format = ShaderProperties.GetTextureFormatAtomic(gpuAccessor, cbufOffset, cbufSlot); + } + else + { + texOp.Format = ShaderProperties.GetTextureFormat(gpuAccessor, cbufOffset, cbufSlot); + } + } + + bool rewriteSamplerType = texOp.Type == SamplerType.TextureBuffer; + + SetHandle(resourceManager, gpuAccessor, texOp, cbufOffset, cbufSlot, rewriteSamplerType, isImage: true); + + return true; + } + } + + return false; } private static bool TryGetOperation(INode asgOp, out Operation outOperation) @@ -335,7 +480,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations } } - int binding = resourceManager.GetTextureOrImageBinding( + SetBindingPair setAndBinding = resourceManager.GetTextureOrImageBinding( texOp.Inst, texOp.Type, texOp.Format, @@ -343,7 +488,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations cbufSlot, cbufOffset); - texOp.SetBinding(binding); + texOp.SetBinding(setAndBinding); } } } diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs new file mode 100644 index 000000000..1e0b3b645 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs @@ -0,0 +1,238 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System; +using System.Collections.Generic; +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Translation.Optimizations +{ + static class BindlessToArray + { + private const int NvnTextureBufferIndex = 2; + private const int HardcodedArrayLengthOgl = 4; + + // 1 and 0 elements are not considered arrays anymore. + public const int MinimumArrayLength = 2; + + public static void RunPassOgl(BasicBlock block, ResourceManager resourceManager) + { + // We can turn a bindless texture access into a indexed access, + // as long the following conditions are true: + // - The handle is loaded using a LDC instruction. + // - The handle is loaded from the constant buffer with the handles (CB2 for NVN). + // - The load has a constant offset. + // The base offset of the array of handles on the constant buffer is the constant offset. + for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) + { + if (node.Value is not TextureOperation texOp) + { + continue; + } + + if ((texOp.Flags & TextureFlags.Bindless) == 0) + { + continue; + } + + if (texOp.GetSource(0).AsgOp is not Operation handleAsgOp) + { + continue; + } + + if (handleAsgOp.Inst != Instruction.Load || + handleAsgOp.StorageKind != StorageKind.ConstantBuffer || + handleAsgOp.SourcesCount != 4) + { + continue; + } + + Operand ldcSrc0 = handleAsgOp.GetSource(0); + + if (ldcSrc0.Type != OperandType.Constant || + !resourceManager.TryGetConstantBufferSlot(ldcSrc0.Value, out int src0CbufSlot) || + src0CbufSlot != NvnTextureBufferIndex) + { + continue; + } + + Operand ldcSrc1 = handleAsgOp.GetSource(1); + + // We expect field index 0 to be accessed. + if (ldcSrc1.Type != OperandType.Constant || ldcSrc1.Value != 0) + { + continue; + } + + Operand ldcSrc2 = handleAsgOp.GetSource(2); + + // FIXME: This is missing some checks, for example, a check to ensure that the shift value is 2. + // Might be not worth fixing since if that doesn't kick in, the result will be no texture + // to access anyway which is also wrong. + // Plus this whole transform is fundamentally flawed as-is since we have no way to know the array size. + // Eventually, this should be entirely removed in favor of a implementation that supports true bindless + // texture access. + if (ldcSrc2.AsgOp is not Operation shrOp || shrOp.Inst != Instruction.ShiftRightU32) + { + continue; + } + + if (shrOp.GetSource(0).AsgOp is not Operation shrOp2 || shrOp2.Inst != Instruction.ShiftRightU32) + { + continue; + } + + if (shrOp2.GetSource(0).AsgOp is not Operation addOp || addOp.Inst != Instruction.Add) + { + continue; + } + + Operand addSrc1 = addOp.GetSource(1); + + if (addSrc1.Type != OperandType.Constant) + { + continue; + } + + TurnIntoArray(resourceManager, texOp, NvnTextureBufferIndex, addSrc1.Value / 4, HardcodedArrayLengthOgl); + + Operand index = Local(); + + Operand source = addOp.GetSource(0); + + Operation shrBy3 = new(Instruction.ShiftRightU32, index, source, Const(3)); + + block.Operations.AddBefore(node, shrBy3); + + texOp.SetSource(0, index); + } + } + + public static void RunPass(BasicBlock block, ResourceManager resourceManager, IGpuAccessor gpuAccessor) + { + // We can turn a bindless texture access into a indexed access, + // as long the following conditions are true: + // - The handle is loaded using a LDC instruction. + // - The handle is loaded from the constant buffer with the handles (CB2 for NVN). + // - The load has a constant offset. + // The base offset of the array of handles on the constant buffer is the constant offset. + for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) + { + if (node.Value is not TextureOperation texOp) + { + continue; + } + + if ((texOp.Flags & TextureFlags.Bindless) == 0) + { + continue; + } + + Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block); + + if (bindlessHandle.AsgOp is not Operation handleAsgOp) + { + continue; + } + + int secondaryCbufSlot = 0; + int secondaryCbufOffset = 0; + bool hasSecondaryHandle = false; + + if (handleAsgOp.Inst == Instruction.BitwiseOr) + { + Operand src0 = Utils.FindLastOperation(handleAsgOp.GetSource(0), block); + Operand src1 = Utils.FindLastOperation(handleAsgOp.GetSource(1), block); + + if (src0.Type == OperandType.ConstantBuffer && src1.AsgOp is Operation) + { + handleAsgOp = src1.AsgOp as Operation; + secondaryCbufSlot = src0.GetCbufSlot(); + secondaryCbufOffset = src0.GetCbufOffset(); + hasSecondaryHandle = true; + } + else if (src0.AsgOp is Operation && src1.Type == OperandType.ConstantBuffer) + { + handleAsgOp = src0.AsgOp as Operation; + secondaryCbufSlot = src1.GetCbufSlot(); + secondaryCbufOffset = src1.GetCbufOffset(); + hasSecondaryHandle = true; + } + } + + if (handleAsgOp.Inst != Instruction.Load || + handleAsgOp.StorageKind != StorageKind.ConstantBuffer || + handleAsgOp.SourcesCount != 4) + { + continue; + } + + Operand ldcSrc0 = handleAsgOp.GetSource(0); + + if (ldcSrc0.Type != OperandType.Constant || + !resourceManager.TryGetConstantBufferSlot(ldcSrc0.Value, out int src0CbufSlot)) + { + continue; + } + + Operand ldcSrc1 = handleAsgOp.GetSource(1); + + // We expect field index 0 to be accessed. + if (ldcSrc1.Type != OperandType.Constant || ldcSrc1.Value != 0) + { + continue; + } + + Operand ldcVecIndex = handleAsgOp.GetSource(2); + Operand ldcElemIndex = handleAsgOp.GetSource(3); + + if (ldcVecIndex.Type != OperandType.LocalVariable || ldcElemIndex.Type != OperandType.LocalVariable) + { + continue; + } + + int cbufSlot; + int handleIndex; + + if (hasSecondaryHandle) + { + cbufSlot = TextureHandle.PackSlots(src0CbufSlot, secondaryCbufSlot); + handleIndex = TextureHandle.PackOffsets(0, secondaryCbufOffset, TextureHandleType.SeparateSamplerHandle); + } + else + { + cbufSlot = src0CbufSlot; + handleIndex = 0; + } + + int length = Math.Max(MinimumArrayLength, gpuAccessor.QueryTextureArrayLengthFromBuffer(src0CbufSlot)); + + TurnIntoArray(resourceManager, texOp, cbufSlot, handleIndex, length); + + Operand vecIndex = Local(); + Operand elemIndex = Local(); + Operand index = Local(); + Operand indexMin = Local(); + + block.Operations.AddBefore(node, new Operation(Instruction.ShiftLeft, vecIndex, ldcVecIndex, Const(1))); + block.Operations.AddBefore(node, new Operation(Instruction.ShiftRightU32, elemIndex, ldcElemIndex, Const(1))); + block.Operations.AddBefore(node, new Operation(Instruction.Add, index, vecIndex, elemIndex)); + block.Operations.AddBefore(node, new Operation(Instruction.MinimumU32, indexMin, index, Const(length - 1))); + + texOp.SetSource(0, indexMin); + } + } + + private static void TurnIntoArray(ResourceManager resourceManager, TextureOperation texOp, int cbufSlot, int handleIndex, int length) + { + SetBindingPair setAndBinding = resourceManager.GetTextureOrImageBinding( + texOp.Inst, + texOp.Type, + texOp.Format, + texOp.Flags & ~TextureFlags.Bindless, + cbufSlot, + handleIndex, + length); + + texOp.TurnIntoArray(setAndBinding); + } + } +} diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs deleted file mode 100644 index 2bd31fe1b..000000000 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs +++ /dev/null @@ -1,118 +0,0 @@ -using Ryujinx.Graphics.Shader.IntermediateRepresentation; -using System.Collections.Generic; - -using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; - -namespace Ryujinx.Graphics.Shader.Translation.Optimizations -{ - static class BindlessToIndexed - { - private const int NvnTextureBufferIndex = 2; - - public static void RunPass(BasicBlock block, ResourceManager resourceManager) - { - // We can turn a bindless texture access into a indexed access, - // as long the following conditions are true: - // - The handle is loaded using a LDC instruction. - // - The handle is loaded from the constant buffer with the handles (CB2 for NVN). - // - The load has a constant offset. - // The base offset of the array of handles on the constant buffer is the constant offset. - for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) - { - if (node.Value is not TextureOperation texOp) - { - continue; - } - - if ((texOp.Flags & TextureFlags.Bindless) == 0) - { - continue; - } - - if (texOp.GetSource(0).AsgOp is not Operation handleAsgOp) - { - continue; - } - - if (handleAsgOp.Inst != Instruction.Load || - handleAsgOp.StorageKind != StorageKind.ConstantBuffer || - handleAsgOp.SourcesCount != 4) - { - continue; - } - - Operand ldcSrc0 = handleAsgOp.GetSource(0); - - if (ldcSrc0.Type != OperandType.Constant || - !resourceManager.TryGetConstantBufferSlot(ldcSrc0.Value, out int src0CbufSlot) || - src0CbufSlot != NvnTextureBufferIndex) - { - continue; - } - - Operand ldcSrc1 = handleAsgOp.GetSource(1); - - // We expect field index 0 to be accessed. - if (ldcSrc1.Type != OperandType.Constant || ldcSrc1.Value != 0) - { - continue; - } - - Operand ldcSrc2 = handleAsgOp.GetSource(2); - - // FIXME: This is missing some checks, for example, a check to ensure that the shift value is 2. - // Might be not worth fixing since if that doesn't kick in, the result will be no texture - // to access anyway which is also wrong. - // Plus this whole transform is fundamentally flawed as-is since we have no way to know the array size. - // Eventually, this should be entirely removed in favor of a implementation that supports true bindless - // texture access. - if (ldcSrc2.AsgOp is not Operation shrOp || shrOp.Inst != Instruction.ShiftRightU32) - { - continue; - } - - if (shrOp.GetSource(0).AsgOp is not Operation shrOp2 || shrOp2.Inst != Instruction.ShiftRightU32) - { - continue; - } - - if (shrOp2.GetSource(0).AsgOp is not Operation addOp || addOp.Inst != Instruction.Add) - { - continue; - } - - Operand addSrc1 = addOp.GetSource(1); - - if (addSrc1.Type != OperandType.Constant) - { - continue; - } - - TurnIntoIndexed(resourceManager, texOp, addSrc1.Value / 4); - - Operand index = Local(); - - Operand source = addOp.GetSource(0); - - Operation shrBy3 = new(Instruction.ShiftRightU32, index, source, Const(3)); - - block.Operations.AddBefore(node, shrBy3); - - texOp.SetSource(0, index); - } - } - - private static void TurnIntoIndexed(ResourceManager resourceManager, TextureOperation texOp, int handle) - { - int binding = resourceManager.GetTextureOrImageBinding( - texOp.Inst, - texOp.Type | SamplerType.Indexed, - texOp.Format, - texOp.Flags & ~TextureFlags.Bindless, - NvnTextureBufferIndex, - handle); - - texOp.TurnIntoIndexed(binding); - } - } -} diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs index 17427a5f9..1be7c5c52 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs @@ -20,7 +20,15 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations // Those passes are looking for specific patterns and only needs to run once. for (int blkIndex = 0; blkIndex < context.Blocks.Length; blkIndex++) { - BindlessToIndexed.RunPass(context.Blocks[blkIndex], context.ResourceManager); + if (context.TargetApi == TargetApi.OpenGL) + { + BindlessToArray.RunPassOgl(context.Blocks[blkIndex], context.ResourceManager); + } + else + { + BindlessToArray.RunPass(context.Blocks[blkIndex], context.ResourceManager, context.GpuAccessor); + } + BindlessElimination.RunPass(context.Blocks[blkIndex], context.ResourceManager, context.GpuAccessor); // FragmentCoord only exists on fragment shaders, so we don't need to check other stages. @@ -144,18 +152,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations { // If all phi sources are the same, we can propagate it and remove the phi. - Operand firstSrc = phi.GetSource(0); - - for (int index = 1; index < phi.SourcesCount; index++) + if (!Utils.AreAllSourcesTheSameOperand(phi)) { - if (!IsSameOperand(firstSrc, phi.GetSource(index))) - { - return false; - } + return false; } // All sources are equal, we can propagate the value. + Operand firstSrc = phi.GetSource(0); Operand dest = phi.Dest; INode[] uses = dest.UseOps.ToArray(); @@ -174,17 +178,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations return true; } - private static bool IsSameOperand(Operand x, Operand y) - { - if (x.Type != y.Type || x.Value != y.Value) - { - return false; - } - - // TODO: Handle Load operations with the same storage and the same constant parameters. - return x.Type == OperandType.Constant || x.Type == OperandType.ConstantBuffer; - } - private static bool PropagatePack(Operation packOp) { // Propagate pack source operands to uses by unpack @@ -322,7 +315,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations Operand lhs = operation.GetSource(0); Operand rhs = operation.GetSource(1); - // Check LHS of the the main multiplication operation. We expect an input being multiplied by gl_FragCoord.w. + // Check LHS of the main multiplication operation. We expect an input being multiplied by gl_FragCoord.w. if (lhs.AsgOp is not Operation attrMulOp || attrMulOp.Inst != (Instruction.FP32 | Instruction.Multiply)) { return; diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs index a509fcb42..097c8aa88 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs @@ -31,6 +31,10 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations TryEliminateBitwiseOr(operation); break; + case Instruction.CompareNotEqual: + TryEliminateCompareNotEqual(operation); + break; + case Instruction.ConditionalSelect: TryEliminateConditionalSelect(operation); break; @@ -174,6 +178,32 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations } } + private static void TryEliminateCompareNotEqual(Operation operation) + { + // Comparison instruction returns 0 if the result is false, and -1 if true. + // Doing a not equal zero comparison on the result is redundant, so we can just copy the first result in this case. + + Operand lhs = operation.GetSource(0); + Operand rhs = operation.GetSource(1); + + if (lhs.Type == OperandType.Constant) + { + (lhs, rhs) = (rhs, lhs); + } + + if (rhs.Type != OperandType.Constant || rhs.Value != 0) + { + return; + } + + if (lhs.AsgOp is not Operation compareOp || !compareOp.Inst.IsComparison()) + { + return; + } + + operation.TurnIntoCopy(lhs); + } + private static void TryEliminateConditionalSelect(Operation operation) { Operand cond = operation.GetSource(0); diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs index 74a6d5a1e..6ec90fa3c 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs @@ -34,6 +34,50 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations return elemIndexSrc.Type == OperandType.Constant && elemIndexSrc.Value == elemIndex; } + private static bool IsSameOperand(Operand x, Operand y) + { + if (x.Type != y.Type || x.Value != y.Value) + { + return false; + } + + // TODO: Handle Load operations with the same storage and the same constant parameters. + return x == y || x.Type == OperandType.Constant || x.Type == OperandType.ConstantBuffer; + } + + private static bool AreAllSourcesEqual(INode node, INode otherNode) + { + if (node.SourcesCount != otherNode.SourcesCount) + { + return false; + } + + for (int index = 0; index < node.SourcesCount; index++) + { + if (!IsSameOperand(node.GetSource(index), otherNode.GetSource(index))) + { + return false; + } + } + + return true; + } + + public static bool AreAllSourcesTheSameOperand(INode node) + { + Operand firstSrc = node.GetSource(0); + + for (int index = 1; index < node.SourcesCount; index++) + { + if (!IsSameOperand(firstSrc, node.GetSource(index))) + { + return false; + } + } + + return true; + } + private static Operation FindBranchSource(BasicBlock block) { foreach (BasicBlock sourceBlock in block.Predecessors) @@ -55,6 +99,19 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations return inst == Instruction.BranchIfFalse || inst == Instruction.BranchIfTrue; } + private static bool IsSameCondition(Operand currentCondition, Operand queryCondition) + { + if (currentCondition == queryCondition) + { + return true; + } + + return currentCondition.AsgOp is Operation currentOperation && + queryCondition.AsgOp is Operation queryOperation && + currentOperation.Inst == queryOperation.Inst && + AreAllSourcesEqual(currentOperation, queryOperation); + } + private static bool BlockConditionsMatch(BasicBlock currentBlock, BasicBlock queryBlock) { // Check if all the conditions for the query block are satisfied by the current block. @@ -70,10 +127,10 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations return currentBranch != null && queryBranch != null && currentBranch.Inst == queryBranch.Inst && - currentCondition == queryCondition; + IsSameCondition(currentCondition, queryCondition); } - public static Operand FindLastOperation(Operand source, BasicBlock block) + public static Operand FindLastOperation(Operand source, BasicBlock block, bool recurse = true) { if (source.AsgOp is PhiNode phiNode) { @@ -81,13 +138,48 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations // Ensure that conditions met for that branch are also met for the current one. // Prefer the latest sources for the phi node. + int undefCount = 0; + for (int i = phiNode.SourcesCount - 1; i >= 0; i--) { BasicBlock phiBlock = phiNode.GetBlock(i); + Operand phiSource = phiNode.GetSource(i); if (BlockConditionsMatch(block, phiBlock)) { - return phiNode.GetSource(i); + return phiSource; + } + else if (recurse && phiSource.AsgOp is PhiNode) + { + // Phi source is another phi. + // Let's check if that phi has a block that matches our condition. + + Operand match = FindLastOperation(phiSource, block, false); + + if (match != phiSource) + { + return match; + } + } + else if (phiSource.Type == OperandType.Undefined) + { + undefCount++; + } + } + + // If all sources but one are undefined, we can assume that the one + // that is not undefined is the right one. + + if (undefCount == phiNode.SourcesCount - 1) + { + for (int i = phiNode.SourcesCount - 1; i >= 0; i--) + { + Operand phiSource = phiNode.GetSource(i); + + if (phiSource.Type != OperandType.Undefined) + { + return phiSource; + } } } } diff --git a/src/Ryujinx.Graphics.Shader/Translation/RegisterUsage.cs b/src/Ryujinx.Graphics.Shader/Translation/RegisterUsage.cs index e27e47070..1c724223c 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/RegisterUsage.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/RegisterUsage.cs @@ -155,9 +155,14 @@ namespace Ryujinx.Graphics.Shader.Translation localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index]; } - if (operation.Dest != null && operation.Dest.Type == OperandType.Register) + for (int dstIndex = 0; dstIndex < operation.DestsCount; dstIndex++) { - localOutputs[block.Index] |= GetMask(operation.Dest.GetRegister()); + Operand dest = operation.GetDest(dstIndex); + + if (dest != null && dest.Type == OperandType.Register) + { + localOutputs[block.Index] |= GetMask(dest.GetRegister()); + } } } } diff --git a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs index 83332711f..94691a5b4 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs @@ -14,17 +14,14 @@ namespace Ryujinx.Graphics.Shader.Translation private const int DefaultLocalMemorySize = 128; private const int DefaultSharedMemorySize = 4096; - // TODO: Non-hardcoded array size. - public const int SamplerArraySize = 4; - private static readonly string[] _stagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" }; private readonly IGpuAccessor _gpuAccessor; private readonly ShaderStage _stage; private readonly string _stagePrefix; - private readonly int[] _cbSlotToBindingMap; - private readonly int[] _sbSlotToBindingMap; + private readonly SetBindingPair[] _cbSlotToBindingMap; + private readonly SetBindingPair[] _sbSlotToBindingMap; private uint _sbSlotWritten; private readonly Dictionary _sbSlots; @@ -32,10 +29,11 @@ namespace Ryujinx.Graphics.Shader.Translation private readonly HashSet _usedConstantBufferBindings; - private readonly record struct TextureInfo(int CbufSlot, int Handle, bool Indexed, TextureFormat Format); + private readonly record struct TextureInfo(int CbufSlot, int Handle, int ArrayLength, bool Separate, SamplerType Type, TextureFormat Format); private struct TextureMeta { + public int Set; public int Binding; public bool AccurateType; public SamplerType Type; @@ -67,10 +65,10 @@ namespace Ryujinx.Graphics.Shader.Translation _stage = stage; _stagePrefix = GetShaderStagePrefix(stage); - _cbSlotToBindingMap = new int[18]; - _sbSlotToBindingMap = new int[16]; - _cbSlotToBindingMap.AsSpan().Fill(-1); - _sbSlotToBindingMap.AsSpan().Fill(-1); + _cbSlotToBindingMap = new SetBindingPair[18]; + _sbSlotToBindingMap = new SetBindingPair[16]; + _cbSlotToBindingMap.AsSpan().Fill(new(-1, -1)); + _sbSlotToBindingMap.AsSpan().Fill(new(-1, -1)); _sbSlots = new(); _sbSlotsReverse = new(); @@ -149,16 +147,16 @@ namespace Ryujinx.Graphics.Shader.Translation public int GetConstantBufferBinding(int slot) { - int binding = _cbSlotToBindingMap[slot]; - if (binding < 0) + SetBindingPair setAndBinding = _cbSlotToBindingMap[slot]; + if (setAndBinding.Binding < 0) { - binding = _gpuAccessor.QueryBindingConstantBuffer(slot); - _cbSlotToBindingMap[slot] = binding; + setAndBinding = _gpuAccessor.CreateConstantBufferBinding(slot); + _cbSlotToBindingMap[slot] = setAndBinding; string slotNumber = slot.ToString(CultureInfo.InvariantCulture); - AddNewConstantBuffer(binding, $"{_stagePrefix}_c{slotNumber}"); + AddNewConstantBuffer(setAndBinding.SetIndex, setAndBinding.Binding, $"{_stagePrefix}_c{slotNumber}"); } - return binding; + return setAndBinding.Binding; } public bool TryGetStorageBufferBinding(int sbCbSlot, int sbCbOffset, bool write, out int binding) @@ -169,14 +167,14 @@ namespace Ryujinx.Graphics.Shader.Translation return false; } - binding = _sbSlotToBindingMap[slot]; + SetBindingPair setAndBinding = _sbSlotToBindingMap[slot]; - if (binding < 0) + if (setAndBinding.Binding < 0) { - binding = _gpuAccessor.QueryBindingStorageBuffer(slot); - _sbSlotToBindingMap[slot] = binding; + setAndBinding = _gpuAccessor.CreateStorageBufferBinding(slot); + _sbSlotToBindingMap[slot] = setAndBinding; string slotNumber = slot.ToString(CultureInfo.InvariantCulture); - AddNewStorageBuffer(binding, $"{_stagePrefix}_s{slotNumber}"); + AddNewStorageBuffer(setAndBinding.SetIndex, setAndBinding.Binding, $"{_stagePrefix}_s{slotNumber}"); } if (write) @@ -184,6 +182,7 @@ namespace Ryujinx.Graphics.Shader.Translation _sbSlotWritten |= 1u << slot; } + binding = setAndBinding.Binding; return true; } @@ -211,7 +210,7 @@ namespace Ryujinx.Graphics.Shader.Translation { for (slot = 0; slot < _cbSlotToBindingMap.Length; slot++) { - if (_cbSlotToBindingMap[slot] == binding) + if (_cbSlotToBindingMap[slot].Binding == binding) { return true; } @@ -221,17 +220,19 @@ namespace Ryujinx.Graphics.Shader.Translation return false; } - public int GetTextureOrImageBinding( + public SetBindingPair GetTextureOrImageBinding( Instruction inst, SamplerType type, TextureFormat format, TextureFlags flags, int cbufSlot, - int handle) + int handle, + int arrayLength = 1, + bool separate = false) { inst &= Instruction.Mask; - bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic; - bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic; + bool isImage = inst.IsImage(); + bool isWrite = inst.IsImageStore(); bool accurateType = !inst.IsTextureQuery(); bool intCoords = isImage || flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureQuerySize; bool coherent = flags.HasFlag(TextureFlags.Coherent); @@ -241,26 +242,38 @@ namespace Ryujinx.Graphics.Shader.Translation format = TextureFormat.Unknown; } - int binding = GetTextureOrImageBinding(cbufSlot, handle, type, format, isImage, intCoords, isWrite, accurateType, coherent); + SetBindingPair setAndBinding = GetTextureOrImageBinding( + cbufSlot, + handle, + arrayLength, + type, + format, + isImage, + intCoords, + isWrite, + accurateType, + coherent, + separate); _gpuAccessor.RegisterTexture(handle, cbufSlot); - return binding; + return setAndBinding; } - private int GetTextureOrImageBinding( + private SetBindingPair GetTextureOrImageBinding( int cbufSlot, int handle, + int arrayLength, SamplerType type, TextureFormat format, bool isImage, bool intCoords, bool write, bool accurateType, - bool coherent) + bool coherent, + bool separate) { - var dimensions = type.GetDimensions(); - var isIndexed = type.HasFlag(SamplerType.Indexed); + var dimensions = type == SamplerType.None ? 0 : type.GetDimensions(); var dict = isImage ? _usedImages : _usedTextures; var usageFlags = TextureUsageFlags.None; @@ -269,7 +282,7 @@ namespace Ryujinx.Graphics.Shader.Translation { usageFlags |= TextureUsageFlags.NeedsScaleValue; - var canScale = _stage.SupportsRenderScale() && !isIndexed && !write && dimensions == 2; + var canScale = _stage.SupportsRenderScale() && arrayLength == 1 && !write && dimensions == 2; if (!canScale) { @@ -289,80 +302,102 @@ namespace Ryujinx.Graphics.Shader.Translation usageFlags |= TextureUsageFlags.ImageCoherent; } - int arraySize = isIndexed ? SamplerArraySize : 1; - int firstBinding = -1; - - for (int layer = 0; layer < arraySize; layer++) + // For array textures, we also want to use type as key, + // since we may have texture handles stores in the same buffer, but for textures with different types. + var keyType = arrayLength > 1 ? type : SamplerType.None; + var info = new TextureInfo(cbufSlot, handle, arrayLength, separate, keyType, format); + var meta = new TextureMeta() { - var info = new TextureInfo(cbufSlot, handle + layer * 2, isIndexed, format); - var meta = new TextureMeta() - { - AccurateType = accurateType, - Type = type, - UsageFlags = usageFlags, - }; + AccurateType = accurateType, + Type = type, + UsageFlags = usageFlags, + }; - int binding; + int setIndex; + int binding; - if (dict.TryGetValue(info, out var existingMeta)) + if (dict.TryGetValue(info, out var existingMeta)) + { + dict[info] = MergeTextureMeta(meta, existingMeta); + setIndex = existingMeta.Set; + binding = existingMeta.Binding; + } + else + { + if (arrayLength > 1 && (setIndex = _gpuAccessor.CreateExtraSet()) >= 0) { - dict[info] = MergeTextureMeta(meta, existingMeta); - binding = existingMeta.Binding; + // We reserved an "extra set" for the array. + // In this case the binding is always the first one (0). + // Using separate sets for array is better as we need to do less descriptor set updates. + + binding = 0; } else { bool isBuffer = (type & SamplerType.Mask) == SamplerType.TextureBuffer; - binding = isImage - ? _gpuAccessor.QueryBindingImage(dict.Count, isBuffer) - : _gpuAccessor.QueryBindingTexture(dict.Count, isBuffer); + SetBindingPair setAndBinding = isImage + ? _gpuAccessor.CreateImageBinding(arrayLength, isBuffer) + : _gpuAccessor.CreateTextureBinding(arrayLength, isBuffer); - meta.Binding = binding; - - dict.Add(info, meta); + setIndex = setAndBinding.SetIndex; + binding = setAndBinding.Binding; } - string nameSuffix; + meta.Set = setIndex; + meta.Binding = binding; - if (isImage) - { - nameSuffix = cbufSlot < 0 - ? $"i_tcb_{handle:X}_{format.ToGlslFormat()}" - : $"i_cb{cbufSlot}_{handle:X}_{format.ToGlslFormat()}"; - } - else - { - nameSuffix = cbufSlot < 0 ? $"t_tcb_{handle:X}" : $"t_cb{cbufSlot}_{handle:X}"; - } - - var definition = new TextureDefinition( - isImage ? 3 : 2, - binding, - $"{_stagePrefix}_{nameSuffix}", - meta.Type, - info.Format, - meta.UsageFlags); - - if (isImage) - { - Properties.AddOrUpdateImage(definition); - } - else - { - Properties.AddOrUpdateTexture(definition); - } - - if (layer == 0) - { - firstBinding = binding; - } + dict.Add(info, meta); } - return firstBinding; + string nameSuffix; + string prefix = isImage ? "i" : "t"; + + if (arrayLength != 1 && type != SamplerType.None) + { + prefix += type.ToShortSamplerType(); + } + + if (isImage) + { + nameSuffix = cbufSlot < 0 + ? $"{prefix}_tcb_{handle:X}_{format.ToGlslFormat()}" + : $"{prefix}_cb{cbufSlot}_{handle:X}_{format.ToGlslFormat()}"; + } + else if (type == SamplerType.None) + { + nameSuffix = cbufSlot < 0 ? $"s_tcb_{handle:X}" : $"s_cb{cbufSlot}_{handle:X}"; + } + else + { + nameSuffix = cbufSlot < 0 ? $"{prefix}_tcb_{handle:X}" : $"{prefix}_cb{cbufSlot}_{handle:X}"; + } + + var definition = new TextureDefinition( + setIndex, + binding, + arrayLength, + separate, + $"{_stagePrefix}_{nameSuffix}", + meta.Type, + info.Format, + meta.UsageFlags); + + if (isImage) + { + Properties.AddOrUpdateImage(definition); + } + else + { + Properties.AddOrUpdateTexture(definition); + } + + return new SetBindingPair(setIndex, binding); } private static TextureMeta MergeTextureMeta(TextureMeta meta, TextureMeta existingMeta) { + meta.Set = existingMeta.Set; meta.Binding = existingMeta.Binding; meta.UsageFlags |= existingMeta.UsageFlags; @@ -399,8 +434,7 @@ namespace Ryujinx.Graphics.Shader.Translation selectedMeta.UsageFlags |= TextureUsageFlags.NeedsScaleValue; var dimensions = type.GetDimensions(); - var isIndexed = type.HasFlag(SamplerType.Indexed); - var canScale = _stage.SupportsRenderScale() && !isIndexed && dimensions == 2; + var canScale = _stage.SupportsRenderScale() && selectedInfo.ArrayLength == 1 && dimensions == 2; if (!canScale) { @@ -426,11 +460,11 @@ namespace Ryujinx.Graphics.Shader.Translation for (int slot = 0; slot < _cbSlotToBindingMap.Length; slot++) { - int binding = _cbSlotToBindingMap[slot]; + SetBindingPair setAndBinding = _cbSlotToBindingMap[slot]; - if (binding >= 0 && _usedConstantBufferBindings.Contains(binding)) + if (setAndBinding.Binding >= 0 && _usedConstantBufferBindings.Contains(setAndBinding.Binding)) { - descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot); + descriptors[descriptorIndex++] = new BufferDescriptor(setAndBinding.SetIndex, setAndBinding.Binding, slot); } } @@ -450,13 +484,13 @@ namespace Ryujinx.Graphics.Shader.Translation foreach ((int key, int slot) in _sbSlots) { - int binding = _sbSlotToBindingMap[slot]; + SetBindingPair setAndBinding = _sbSlotToBindingMap[slot]; - if (binding >= 0) + if (setAndBinding.Binding >= 0) { (int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key); BufferUsageFlags flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None; - descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot, sbCbSlot, sbCbOffset, flags); + descriptors[descriptorIndex++] = new BufferDescriptor(setAndBinding.SetIndex, setAndBinding.Binding, slot, sbCbSlot, sbCbOffset, flags); } } @@ -468,34 +502,65 @@ namespace Ryujinx.Graphics.Shader.Translation return descriptors; } - public TextureDescriptor[] GetTextureDescriptors() + public TextureDescriptor[] GetTextureDescriptors(bool includeArrays = true) { - return GetDescriptors(_usedTextures, _usedTextures.Count); + return GetDescriptors(_usedTextures, includeArrays); } - public TextureDescriptor[] GetImageDescriptors() + public TextureDescriptor[] GetImageDescriptors(bool includeArrays = true) { - return GetDescriptors(_usedImages, _usedImages.Count); + return GetDescriptors(_usedImages, includeArrays); } - private static TextureDescriptor[] GetDescriptors(IReadOnlyDictionary usedResources, int count) + private static TextureDescriptor[] GetDescriptors(IReadOnlyDictionary usedResources, bool includeArrays) { - TextureDescriptor[] descriptors = new TextureDescriptor[count]; + List descriptors = new(); - int descriptorIndex = 0; + bool hasAnyArray = false; foreach ((TextureInfo info, TextureMeta meta) in usedResources) { - descriptors[descriptorIndex++] = new TextureDescriptor( + if (info.ArrayLength > 1) + { + hasAnyArray = true; + continue; + } + + descriptors.Add(new TextureDescriptor( + meta.Set, meta.Binding, meta.Type, info.Format, info.CbufSlot, info.Handle, - meta.UsageFlags); + info.ArrayLength, + info.Separate, + meta.UsageFlags)); } - return descriptors; + if (hasAnyArray && includeArrays) + { + foreach ((TextureInfo info, TextureMeta meta) in usedResources) + { + if (info.ArrayLength <= 1) + { + continue; + } + + descriptors.Add(new TextureDescriptor( + meta.Set, + meta.Binding, + meta.Type, + info.Format, + info.CbufSlot, + info.Handle, + info.ArrayLength, + info.Separate, + meta.UsageFlags)); + } + } + + return descriptors.ToArray(); } public bool TryGetCbufSlotAndHandleForTexture(int binding, out int cbufSlot, out int handle) @@ -531,24 +596,37 @@ namespace Ryujinx.Graphics.Shader.Translation return FindDescriptorIndex(GetImageDescriptors(), binding); } - private void AddNewConstantBuffer(int binding, string name) + public bool IsArrayOfTexturesOrImages(int binding, bool isImage) + { + foreach ((TextureInfo info, TextureMeta meta) in isImage ? _usedImages : _usedTextures) + { + if (meta.Binding == binding) + { + return info.ArrayLength != 1; + } + } + + return false; + } + + private void AddNewConstantBuffer(int setIndex, int binding, string name) { StructureType type = new(new[] { new StructureField(AggregateType.Array | AggregateType.Vector4 | AggregateType.FP32, "data", Constants.ConstantBufferSize / 16), }); - Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, 0, binding, name, type)); + Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, setIndex, binding, name, type)); } - private void AddNewStorageBuffer(int binding, string name) + private void AddNewStorageBuffer(int setIndex, int binding, string name) { StructureType type = new(new[] { new StructureField(AggregateType.Array | AggregateType.U32, "data", 0), }); - Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, 1, binding, name, type)); + Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, setIndex, binding, name, type)); } public static string GetShaderStagePrefix(ShaderStage stage) diff --git a/src/Ryujinx.Graphics.Shader/Translation/ResourceReservations.cs b/src/Ryujinx.Graphics.Shader/Translation/ResourceReservations.cs index d559f6699..c89c4d0b6 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/ResourceReservations.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/ResourceReservations.cs @@ -11,6 +11,8 @@ namespace Ryujinx.Graphics.Shader.Translation public const int MaxVertexBufferTextures = 32; + private const int TextureSetIndex = 2; // TODO: Get from GPU accessor. + public int VertexInfoConstantBufferBinding { get; } public int VertexOutputStorageBufferBinding { get; } public int GeometryVertexOutputStorageBufferBinding { get; } @@ -163,6 +165,21 @@ namespace Ryujinx.Graphics.Shader.Translation return _vertexBufferTextureBaseBinding + vaLocation; } + public SetBindingPair GetVertexBufferTextureSetAndBinding(int vaLocation) + { + return new SetBindingPair(TextureSetIndex, GetVertexBufferTextureBinding(vaLocation)); + } + + public SetBindingPair GetIndexBufferTextureSetAndBinding() + { + return new SetBindingPair(TextureSetIndex, IndexBufferTextureBinding); + } + + public SetBindingPair GetTopologyRemapBufferTextureSetAndBinding() + { + return new SetBindingPair(TextureSetIndex, TopologyRemapBufferTextureBinding); + } + internal bool TryGetOffset(StorageKind storageKind, int location, int component, out int offset) { return _offsets.TryGetValue(new IoDefinition(storageKind, IoVariable.UserDefined, location, component), out offset); diff --git a/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs b/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs index 3246e2594..f831ec940 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs @@ -45,6 +45,8 @@ namespace Ryujinx.Graphics.Shader.Translation public bool YNegateEnabled => _graphicsState.YNegateEnabled; public bool OriginUpperLeft => _graphicsState.OriginUpperLeft; + public bool HalvePrimitiveId => _graphicsState.HalvePrimitiveId; + public ImapPixelType[] ImapTypes { get; } public bool IaIndexing { get; private set; } public bool OaIndexing { get; private set; } diff --git a/src/Ryujinx.Graphics.Shader/Translation/TransformContext.cs b/src/Ryujinx.Graphics.Shader/Translation/TransformContext.cs index 87ebb8e7c..1e87585f1 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/TransformContext.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/TransformContext.cs @@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Shader.Translation public readonly ShaderDefinitions Definitions; public readonly ResourceManager ResourceManager; public readonly IGpuAccessor GpuAccessor; + public readonly TargetApi TargetApi; public readonly TargetLanguage TargetLanguage; public readonly ShaderStage Stage; public readonly ref FeatureFlags UsedFeatures; @@ -19,6 +20,7 @@ namespace Ryujinx.Graphics.Shader.Translation ShaderDefinitions definitions, ResourceManager resourceManager, IGpuAccessor gpuAccessor, + TargetApi targetApi, TargetLanguage targetLanguage, ShaderStage stage, ref FeatureFlags usedFeatures) @@ -28,6 +30,7 @@ namespace Ryujinx.Graphics.Shader.Translation Definitions = definitions; ResourceManager = resourceManager; GpuAccessor = gpuAccessor; + TargetApi = targetApi; TargetLanguage = targetLanguage; Stage = stage; UsedFeatures = ref usedFeatures; diff --git a/src/Ryujinx.Graphics.Shader/Translation/Transforms/TexturePass.cs b/src/Ryujinx.Graphics.Shader/Translation/Transforms/TexturePass.cs index 495ea8a94..6ba8cb44a 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Transforms/TexturePass.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Transforms/TexturePass.cs @@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms { node = InsertCoordNormalization(context.Hfm, node, context.ResourceManager, context.GpuAccessor, context.Stage); node = InsertCoordGatherBias(node, context.ResourceManager, context.GpuAccessor); - node = InsertConstOffsets(node, context.GpuAccessor, context.Stage); + node = InsertConstOffsets(node, context.ResourceManager, context.GpuAccessor, context.Stage); if (texOp.Type == SamplerType.TextureBuffer && !context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat()) { @@ -45,13 +45,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool intCoords = (texOp.Flags & TextureFlags.IntCoords) != 0; - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - - int coordsCount = texOp.Type.GetDimensions(); - - int coordsIndex = isBindless || isIndexed ? 1 : 0; bool isImage = IsImageInstructionWithScale(texOp.Inst); + bool isIndexed = resourceManager.IsArrayOfTexturesOrImages(texOp.Binding, isImage); if ((texOp.Inst == Instruction.TextureSample || isImage) && (intCoords || isImage) && @@ -62,9 +58,12 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms { int functionId = hfm.GetOrCreateFunctionId(HelperFunctionName.TexelFetchScale); int samplerIndex = isImage - ? resourceManager.GetTextureDescriptors().Length + resourceManager.FindImageDescriptorIndex(texOp.Binding) + ? resourceManager.GetTextureDescriptors(includeArrays: false).Length + resourceManager.FindImageDescriptorIndex(texOp.Binding) : resourceManager.FindTextureDescriptorIndex(texOp.Binding); + int coordsCount = texOp.Type.GetDimensions(); + int coordsIndex = isBindless ? 1 : 0; + for (int index = 0; index < coordsCount; index++) { Operand scaledCoord = Local(); @@ -97,7 +96,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms TextureOperation texOp = (TextureOperation)node.Value; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; + bool isIndexed = resourceManager.IsArrayOfTexturesOrImages(texOp.Binding, isImage: false); if (texOp.Inst == Instruction.TextureQuerySize && texOp.Index < 2 && @@ -152,8 +151,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms TextureOperation texOp = (TextureOperation)node.Value; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; + bool isIndexed = resourceManager.IsArrayOfTexturesOrImages(texOp.Binding, isImage: false); - if (isBindless || !resourceManager.TryGetCbufSlotAndHandleForTexture(texOp.Binding, out int cbufSlot, out int handle)) + if (isBindless || isIndexed || !resourceManager.TryGetCbufSlotAndHandleForTexture(texOp.Binding, out int cbufSlot, out int handle)) { return node; } @@ -167,10 +167,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms return node; } - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - int coordsCount = texOp.Type.GetDimensions(); - int coordsIndex = isBindless || isIndexed ? 1 : 0; int normCoordsCount = (texOp.Type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : coordsCount; @@ -178,22 +175,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms { Operand coordSize = Local(); - Operand[] texSizeSources; - - if (isBindless || isIndexed) - { - texSizeSources = new Operand[] { texOp.GetSource(0), Const(0) }; - } - else - { - texSizeSources = new Operand[] { Const(0) }; - } + Operand[] texSizeSources = new Operand[] { Const(0) }; LinkedListNode textureSizeNode = node.List.AddBefore(node, new TextureOperation( Instruction.TextureQuerySize, texOp.Type, texOp.Format, texOp.Flags, + texOp.Set, texOp.Binding, index, new[] { coordSize }, @@ -201,13 +190,13 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms resourceManager.SetUsageFlagsForTextureQuery(texOp.Binding, texOp.Type); - Operand source = texOp.GetSource(coordsIndex + index); + Operand source = texOp.GetSource(index); Operand coordNormalized = Local(); node.List.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Divide, coordNormalized, source, GenerateI2f(node, coordSize))); - texOp.SetSource(coordsIndex + index, coordNormalized); + texOp.SetSource(index, coordNormalized); InsertTextureSizeUnscale(hfm, textureSizeNode, resourceManager, stage); } @@ -234,7 +223,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms return node; } - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; + bool isIndexed = resourceManager.IsArrayOfTexturesOrImages(texOp.Binding, isImage: false); int coordsCount = texOp.Type.GetDimensions(); int coordsIndex = isBindless || isIndexed ? 1 : 0; @@ -263,6 +252,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms texOp.Type, texOp.Format, texOp.Flags, + texOp.Set, texOp.Binding, index, new[] { coordSize }, @@ -287,7 +277,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms return node; } - private static LinkedListNode InsertConstOffsets(LinkedListNode node, IGpuAccessor gpuAccessor, ShaderStage stage) + private static LinkedListNode InsertConstOffsets(LinkedListNode node, ResourceManager resourceManager, IGpuAccessor gpuAccessor, ShaderStage stage) { // Non-constant texture offsets are not allowed (according to the spec), // however some GPUs does support that. @@ -321,7 +311,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms bool hasLodLevel = (texOp.Flags & TextureFlags.LodLevel) != 0; bool isArray = (texOp.Type & SamplerType.Array) != 0; - bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0; bool isShadow = (texOp.Type & SamplerType.Shadow) != 0; @@ -342,6 +331,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms offsetsCount = 0; } + bool isIndexed = resourceManager.IsArrayOfTexturesOrImages(texOp.Binding, isImage: false); + Operand[] offsets = new Operand[offsetsCount]; Operand[] sources = new Operand[texOp.SourcesCount - offsetsCount]; @@ -482,6 +473,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms texOp.Type, texOp.Format, texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets), + texOp.Set, texOp.Binding, 1 << 3, // W component: i=0, j=0 new[] { dests[destIndex++] }, @@ -538,6 +530,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms texOp.Type, texOp.Format, texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets), + texOp.Set, texOp.Binding, componentIndex, dests, @@ -584,6 +577,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms texOp.Type, texOp.Format, texOp.Flags, + texOp.Set, texOp.Binding, index, new[] { texSizes[index] }, @@ -614,6 +608,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms texOp.Type, texOp.Format, texOp.Flags, + texOp.Set, texOp.Binding, 0, new[] { lod }, @@ -644,6 +639,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms texOp.Type, texOp.Format, texOp.Flags, + texOp.Set, texOp.Binding, index, new[] { texSizes[index] }, diff --git a/src/Ryujinx.Graphics.Shader/Translation/Transforms/VertexToCompute.cs b/src/Ryujinx.Graphics.Shader/Translation/Transforms/VertexToCompute.cs index d71ada865..ddd2134d2 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Transforms/VertexToCompute.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Transforms/VertexToCompute.cs @@ -54,6 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms { bool needsSextNorm = context.Definitions.IsAttributePackedRgb10A2Signed(location); + SetBindingPair setAndBinding = context.ResourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location); Operand temp = needsSextNorm ? Local() : dest; Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, 0); @@ -62,7 +63,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms SamplerType.TextureBuffer, TextureFormat.Unknown, TextureFlags.IntCoords, - context.ResourceManager.Reservations.GetVertexBufferTextureBinding(location), + setAndBinding.SetIndex, + setAndBinding.Binding, 1 << component, new[] { temp }, new[] { vertexElemOffset })); @@ -75,6 +77,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms } else { + SetBindingPair setAndBinding = context.ResourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location); Operand temp = component > 0 ? Local() : dest; Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, component); @@ -83,7 +86,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms SamplerType.TextureBuffer, TextureFormat.Unknown, TextureFlags.IntCoords, - context.ResourceManager.Reservations.GetVertexBufferTextureBinding(location), + setAndBinding.SetIndex, + setAndBinding.Binding, 1, new[] { temp }, new[] { vertexElemOffset })); diff --git a/src/Ryujinx.Graphics.Shader/Translation/Translator.cs b/src/Ryujinx.Graphics.Shader/Translation/Translator.cs index 6a31ea2e7..d1fbca0eb 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Translator.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Translator.cs @@ -190,7 +190,7 @@ namespace Ryujinx.Graphics.Shader.Translation if (stage == ShaderStage.Vertex) { - InitializePositionOutput(context); + InitializeVertexOutputs(context); } UInt128 usedAttributes = context.TranslatorContext.AttributeUsage.NextInputAttributesComponents; @@ -236,12 +236,20 @@ namespace Ryujinx.Graphics.Shader.Translation } } - private static void InitializePositionOutput(EmitterContext context) + private static void InitializeVertexOutputs(EmitterContext context) { for (int c = 0; c < 4; c++) { context.Store(StorageKind.Output, IoVariable.Position, null, Const(c), ConstF(c == 3 ? 1f : 0f)); } + + if (context.Program.ClipDistancesWritten != 0) + { + for (int i = 0; i < 8; i++) + { + context.Store(StorageKind.Output, IoVariable.ClipDistance, null, Const(i), ConstF(0f)); + } + } } private static void InitializeOutput(EmitterContext context, int location, bool perPatch) diff --git a/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs b/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs index a193ab3c4..a579433f9 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs @@ -294,6 +294,7 @@ namespace Ryujinx.Graphics.Shader.Translation Definitions, resourceManager, GpuAccessor, + Options.TargetApi, Options.TargetLanguage, Definitions.Stage, ref usedFeatures); @@ -362,6 +363,7 @@ namespace Ryujinx.Graphics.Shader.Translation GpuAccessor.QueryHostSupportsGeometryShaderPassthrough(), GpuAccessor.QueryHostSupportsShaderBallot(), GpuAccessor.QueryHostSupportsShaderBarrierDivergence(), + GpuAccessor.QueryHostSupportsShaderFloat64(), GpuAccessor.QueryHostSupportsTextureShadowLod(), GpuAccessor.QueryHostSupportsViewportMask()); @@ -411,8 +413,8 @@ namespace Ryujinx.Graphics.Shader.Translation if (Stage == ShaderStage.Vertex) { - int ibBinding = resourceManager.Reservations.IndexBufferTextureBinding; - TextureDefinition indexBuffer = new(2, ibBinding, "ib_data", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None); + SetBindingPair ibSetAndBinding = resourceManager.Reservations.GetIndexBufferTextureSetAndBinding(); + TextureDefinition indexBuffer = new(ibSetAndBinding.SetIndex, ibSetAndBinding.Binding, "ib_data", SamplerType.TextureBuffer); resourceManager.Properties.AddOrUpdateTexture(indexBuffer); int inputMap = _program.AttributeUsage.UsedInputAttributes; @@ -420,8 +422,8 @@ namespace Ryujinx.Graphics.Shader.Translation while (inputMap != 0) { int location = BitOperations.TrailingZeroCount(inputMap); - int binding = resourceManager.Reservations.GetVertexBufferTextureBinding(location); - TextureDefinition vaBuffer = new(2, binding, $"vb_data{location}", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None); + SetBindingPair setAndBinding = resourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location); + TextureDefinition vaBuffer = new(setAndBinding.SetIndex, setAndBinding.Binding, $"vb_data{location}", SamplerType.TextureBuffer); resourceManager.Properties.AddOrUpdateTexture(vaBuffer); inputMap &= ~(1 << location); @@ -429,8 +431,8 @@ namespace Ryujinx.Graphics.Shader.Translation } else if (Stage == ShaderStage.Geometry) { - int trbBinding = resourceManager.Reservations.TopologyRemapBufferTextureBinding; - TextureDefinition remapBuffer = new(2, trbBinding, "trb_data", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None); + SetBindingPair trbSetAndBinding = resourceManager.Reservations.GetTopologyRemapBufferTextureSetAndBinding(); + TextureDefinition remapBuffer = new(trbSetAndBinding.SetIndex, trbSetAndBinding.Binding, "trb_data", SamplerType.TextureBuffer); resourceManager.Properties.AddOrUpdateTexture(remapBuffer); int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding; diff --git a/src/Ryujinx.Graphics.Texture/Astc/AstcDecoder.cs b/src/Ryujinx.Graphics.Texture/Astc/AstcDecoder.cs index 3f65e1225..1defb1696 100644 --- a/src/Ryujinx.Graphics.Texture/Astc/AstcDecoder.cs +++ b/src/Ryujinx.Graphics.Texture/Astc/AstcDecoder.cs @@ -293,9 +293,9 @@ namespace Ryujinx.Graphics.Texture.Astc int depth, int levels, int layers, - out IMemoryOwner decoded) + out MemoryOwner decoded) { - decoded = ByteMemoryPool.Rent(QueryDecompressedSize(width, height, depth, levels, layers)); + decoded = MemoryOwner.Rent(QueryDecompressedSize(width, height, depth, levels, layers)); AstcDecoder decoder = new(data, decoded.Memory, blockWidth, blockHeight, width, height, depth, levels, layers); diff --git a/src/Ryujinx.Graphics.Texture/BCnDecoder.cs b/src/Ryujinx.Graphics.Texture/BCnDecoder.cs index fef3b1f03..5359122e7 100644 --- a/src/Ryujinx.Graphics.Texture/BCnDecoder.cs +++ b/src/Ryujinx.Graphics.Texture/BCnDecoder.cs @@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Texture private const int BlockWidth = 4; private const int BlockHeight = 4; - public static IMemoryOwner DecodeBC1(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) + public static MemoryOwner DecodeBC1(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) { int size = 0; @@ -23,12 +23,12 @@ namespace Ryujinx.Graphics.Texture size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4; } - IMemoryOwner output = ByteMemoryPool.Rent(size); + MemoryOwner output = MemoryOwner.Rent(size); Span tile = stackalloc byte[BlockWidth * BlockHeight * 4]; Span tileAsUint = MemoryMarshal.Cast(tile); - Span outputAsUint = MemoryMarshal.Cast(output.Memory.Span); + Span outputAsUint = MemoryMarshal.Cast(output.Span); Span> tileAsVector128 = MemoryMarshal.Cast>(tile); @@ -102,7 +102,7 @@ namespace Ryujinx.Graphics.Texture return output; } - public static IMemoryOwner DecodeBC2(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) + public static MemoryOwner DecodeBC2(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) { int size = 0; @@ -111,12 +111,12 @@ namespace Ryujinx.Graphics.Texture size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4; } - IMemoryOwner output = ByteMemoryPool.Rent(size); + MemoryOwner output = MemoryOwner.Rent(size); Span tile = stackalloc byte[BlockWidth * BlockHeight * 4]; Span tileAsUint = MemoryMarshal.Cast(tile); - Span outputAsUint = MemoryMarshal.Cast(output.Memory.Span); + Span outputAsUint = MemoryMarshal.Cast(output.Span); Span> tileAsVector128 = MemoryMarshal.Cast>(tile); @@ -197,7 +197,7 @@ namespace Ryujinx.Graphics.Texture return output; } - public static IMemoryOwner DecodeBC3(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) + public static MemoryOwner DecodeBC3(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) { int size = 0; @@ -206,13 +206,13 @@ namespace Ryujinx.Graphics.Texture size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4; } - IMemoryOwner output = ByteMemoryPool.Rent(size); + MemoryOwner output = MemoryOwner.Rent(size); Span tile = stackalloc byte[BlockWidth * BlockHeight * 4]; Span rPal = stackalloc byte[8]; Span tileAsUint = MemoryMarshal.Cast(tile); - Span outputAsUint = MemoryMarshal.Cast(output.Memory.Span); + Span outputAsUint = MemoryMarshal.Cast(output.Span); Span> tileAsVector128 = MemoryMarshal.Cast>(tile); @@ -294,7 +294,7 @@ namespace Ryujinx.Graphics.Texture return output; } - public static IMemoryOwner DecodeBC4(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed) + public static MemoryOwner DecodeBC4(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed) { int size = 0; @@ -306,8 +306,8 @@ namespace Ryujinx.Graphics.Texture // Backends currently expect a stride alignment of 4 bytes, so output width must be aligned. int alignedWidth = BitUtils.AlignUp(width, 4); - IMemoryOwner output = ByteMemoryPool.Rent(size); - Span outputSpan = output.Memory.Span; + MemoryOwner output = MemoryOwner.Rent(size); + Span outputSpan = output.Span; ReadOnlySpan data64 = MemoryMarshal.Cast(data); @@ -402,7 +402,7 @@ namespace Ryujinx.Graphics.Texture return output; } - public static IMemoryOwner DecodeBC5(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed) + public static MemoryOwner DecodeBC5(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed) { int size = 0; @@ -414,7 +414,7 @@ namespace Ryujinx.Graphics.Texture // Backends currently expect a stride alignment of 4 bytes, so output width must be aligned. int alignedWidth = BitUtils.AlignUp(width, 2); - IMemoryOwner output = ByteMemoryPool.Rent(size); + MemoryOwner output = MemoryOwner.Rent(size); ReadOnlySpan data64 = MemoryMarshal.Cast(data); @@ -423,7 +423,7 @@ namespace Ryujinx.Graphics.Texture Span rPal = stackalloc byte[8]; Span gPal = stackalloc byte[8]; - Span outputAsUshort = MemoryMarshal.Cast(output.Memory.Span); + Span outputAsUshort = MemoryMarshal.Cast(output.Span); Span rTileAsUint = MemoryMarshal.Cast(rTile); Span gTileAsUint = MemoryMarshal.Cast(gTile); @@ -527,7 +527,7 @@ namespace Ryujinx.Graphics.Texture return output; } - public static IMemoryOwner DecodeBC6(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed) + public static MemoryOwner DecodeBC6(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed) { int size = 0; @@ -536,7 +536,8 @@ namespace Ryujinx.Graphics.Texture size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 8; } - IMemoryOwner output = ByteMemoryPool.Rent(size); + MemoryOwner output = MemoryOwner.Rent(size); + Span outputSpan = output.Span; int inputOffset = 0; int outputOffset = 0; @@ -550,7 +551,7 @@ namespace Ryujinx.Graphics.Texture { for (int z = 0; z < depth; z++) { - BC6Decoder.Decode(output.Memory.Span[outputOffset..], data[inputOffset..], width, height, signed); + BC6Decoder.Decode(outputSpan[outputOffset..], data[inputOffset..], width, height, signed); inputOffset += w * h * 16; outputOffset += width * height * 8; @@ -565,7 +566,7 @@ namespace Ryujinx.Graphics.Texture return output; } - public static IMemoryOwner DecodeBC7(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) + public static MemoryOwner DecodeBC7(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) { int size = 0; @@ -574,7 +575,8 @@ namespace Ryujinx.Graphics.Texture size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4; } - IMemoryOwner output = ByteMemoryPool.Rent(size); + MemoryOwner output = MemoryOwner.Rent(size); + Span outputSpan = output.Span; int inputOffset = 0; int outputOffset = 0; @@ -588,7 +590,7 @@ namespace Ryujinx.Graphics.Texture { for (int z = 0; z < depth; z++) { - BC7Decoder.Decode(output.Memory.Span[outputOffset..], data[inputOffset..], width, height); + BC7Decoder.Decode(outputSpan[outputOffset..], data[inputOffset..], width, height); inputOffset += w * h * 16; outputOffset += width * height * 4; diff --git a/src/Ryujinx.Graphics.Texture/BCnEncoder.cs b/src/Ryujinx.Graphics.Texture/BCnEncoder.cs index 74df038b3..c9838b11d 100644 --- a/src/Ryujinx.Graphics.Texture/BCnEncoder.cs +++ b/src/Ryujinx.Graphics.Texture/BCnEncoder.cs @@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Texture private const int BlockWidth = 4; private const int BlockHeight = 4; - public static IMemoryOwner EncodeBC7(Memory data, int width, int height, int depth, int levels, int layers) + public static MemoryOwner EncodeBC7(Memory data, int width, int height, int depth, int levels, int layers) { int size = 0; @@ -23,7 +23,8 @@ namespace Ryujinx.Graphics.Texture size += w * h * 16 * Math.Max(1, depth >> l) * layers; } - IMemoryOwner output = ByteMemoryPool.Rent(size); + MemoryOwner output = MemoryOwner.Rent(size); + Memory outputMemory = output.Memory; int imageBaseIOffs = 0; int imageBaseOOffs = 0; @@ -38,7 +39,7 @@ namespace Ryujinx.Graphics.Texture for (int z = 0; z < depth; z++) { BC7Encoder.Encode( - output.Memory[imageBaseOOffs..], + outputMemory[imageBaseOOffs..], data[imageBaseIOffs..], width, height, diff --git a/src/Ryujinx.Graphics.Texture/ETC2Decoder.cs b/src/Ryujinx.Graphics.Texture/ETC2Decoder.cs index 52801ff47..66ee6fb4e 100644 --- a/src/Ryujinx.Graphics.Texture/ETC2Decoder.cs +++ b/src/Ryujinx.Graphics.Texture/ETC2Decoder.cs @@ -51,15 +51,15 @@ namespace Ryujinx.Graphics.Texture new int[] { -3, -5, -7, -9, 2, 4, 6, 8 }, }; - public static IMemoryOwner DecodeRgb(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) + public static MemoryOwner DecodeRgb(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) { ReadOnlySpan dataUlong = MemoryMarshal.Cast(data); int inputOffset = 0; - IMemoryOwner output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers)); + MemoryOwner output = MemoryOwner.Rent(CalculateOutputSize(width, height, depth, levels, layers)); - Span outputUint = MemoryMarshal.Cast(output.Memory.Span); + Span outputUint = MemoryMarshal.Cast(output.Span); Span tile = stackalloc uint[BlockWidth * BlockHeight]; int imageBaseOOffs = 0; @@ -113,15 +113,15 @@ namespace Ryujinx.Graphics.Texture return output; } - public static IMemoryOwner DecodePta(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) + public static MemoryOwner DecodePta(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) { ReadOnlySpan dataUlong = MemoryMarshal.Cast(data); int inputOffset = 0; - IMemoryOwner output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers)); + MemoryOwner output = MemoryOwner.Rent(CalculateOutputSize(width, height, depth, levels, layers)); - Span outputUint = MemoryMarshal.Cast(output.Memory.Span); + Span outputUint = MemoryMarshal.Cast(output.Span); Span tile = stackalloc uint[BlockWidth * BlockHeight]; int imageBaseOOffs = 0; @@ -170,15 +170,15 @@ namespace Ryujinx.Graphics.Texture return output; } - public static IMemoryOwner DecodeRgba(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) + public static MemoryOwner DecodeRgba(ReadOnlySpan data, int width, int height, int depth, int levels, int layers) { ReadOnlySpan dataUlong = MemoryMarshal.Cast(data); int inputOffset = 0; - IMemoryOwner output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers)); + MemoryOwner output = MemoryOwner.Rent(CalculateOutputSize(width, height, depth, levels, layers)); - Span outputUint = MemoryMarshal.Cast(output.Memory.Span); + Span outputUint = MemoryMarshal.Cast(output.Span); Span tile = stackalloc uint[BlockWidth * BlockHeight]; int imageBaseOOffs = 0; diff --git a/src/Ryujinx.Graphics.Texture/LayoutConverter.cs b/src/Ryujinx.Graphics.Texture/LayoutConverter.cs index d6732674b..b0d36f0c4 100644 --- a/src/Ryujinx.Graphics.Texture/LayoutConverter.cs +++ b/src/Ryujinx.Graphics.Texture/LayoutConverter.cs @@ -95,7 +95,7 @@ namespace Ryujinx.Graphics.Texture }; } - public static IMemoryOwner ConvertBlockLinearToLinear( + public static MemoryOwner ConvertBlockLinearToLinear( int width, int height, int depth, @@ -121,8 +121,8 @@ namespace Ryujinx.Graphics.Texture blockHeight, bytesPerPixel); - IMemoryOwner outputOwner = ByteMemoryPool.Rent(outSize); - Span output = outputOwner.Memory.Span; + MemoryOwner outputOwner = MemoryOwner.Rent(outSize); + Span output = outputOwner.Span; int outOffs = 0; @@ -249,7 +249,7 @@ namespace Ryujinx.Graphics.Texture return outputOwner; } - public static IMemoryOwner ConvertLinearStridedToLinear( + public static MemoryOwner ConvertLinearStridedToLinear( int width, int height, int blockWidth, @@ -265,8 +265,8 @@ namespace Ryujinx.Graphics.Texture int outStride = BitUtils.AlignUp(w * bytesPerPixel, HostStrideAlignment); lineSize = Math.Min(lineSize, outStride); - IMemoryOwner output = ByteMemoryPool.Rent(h * outStride); - Span outSpan = output.Memory.Span; + MemoryOwner output = MemoryOwner.Rent(h * outStride); + Span outSpan = output.Span; int outOffs = 0; int inOffs = 0; diff --git a/src/Ryujinx.Graphics.Texture/PixelConverter.cs b/src/Ryujinx.Graphics.Texture/PixelConverter.cs index 27d134074..414f26554 100644 --- a/src/Ryujinx.Graphics.Texture/PixelConverter.cs +++ b/src/Ryujinx.Graphics.Texture/PixelConverter.cs @@ -21,13 +21,14 @@ namespace Ryujinx.Graphics.Texture return (remainder, outRemainder, length / stride); } - public unsafe static IMemoryOwner ConvertR4G4ToR4G4B4A4(ReadOnlySpan data, int width) + public unsafe static MemoryOwner ConvertR4G4ToR4G4B4A4(ReadOnlySpan data, int width) { - IMemoryOwner output = ByteMemoryPool.Rent(data.Length * 2); + MemoryOwner output = MemoryOwner.Rent(data.Length * 2); + Span outputSpan = output.Span; (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 1, 2); - Span outputSpan = MemoryMarshal.Cast(output.Memory.Span); + Span outputSpanUInt16 = MemoryMarshal.Cast(outputSpan); if (remainder == 0) { @@ -38,7 +39,7 @@ namespace Ryujinx.Graphics.Texture int sizeTrunc = data.Length & ~7; start = sizeTrunc; - fixed (byte* inputPtr = data, outputPtr = output.Memory.Span) + fixed (byte* inputPtr = data, outputPtr = outputSpan) { for (ulong offset = 0; offset < (ulong)sizeTrunc; offset += 8) { @@ -49,7 +50,7 @@ namespace Ryujinx.Graphics.Texture for (int i = start; i < data.Length; i++) { - outputSpan[i] = (ushort)data[i]; + outputSpanUInt16[i] = data[i]; } } else @@ -61,7 +62,7 @@ namespace Ryujinx.Graphics.Texture { for (int x = 0; x < width; x++) { - outputSpan[outOffset++] = data[offset++]; + outputSpanUInt16[outOffset++] = data[offset++]; } offset += remainder; @@ -72,16 +73,16 @@ namespace Ryujinx.Graphics.Texture return output; } - public unsafe static IMemoryOwner ConvertR5G6B5ToR8G8B8A8(ReadOnlySpan data, int width) + public static MemoryOwner ConvertR5G6B5ToR8G8B8A8(ReadOnlySpan data, int width) { - IMemoryOwner output = ByteMemoryPool.Rent(data.Length * 2); + MemoryOwner output = MemoryOwner.Rent(data.Length * 2); int offset = 0; int outOffset = 0; (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); ReadOnlySpan inputSpan = MemoryMarshal.Cast(data); - Span outputSpan = MemoryMarshal.Cast(output.Memory.Span); + Span outputSpan = MemoryMarshal.Cast(output.Span); for (int y = 0; y < height; y++) { @@ -109,16 +110,16 @@ namespace Ryujinx.Graphics.Texture return output; } - public unsafe static IMemoryOwner ConvertR5G5B5ToR8G8B8A8(ReadOnlySpan data, int width, bool forceAlpha) + public static MemoryOwner ConvertR5G5B5ToR8G8B8A8(ReadOnlySpan data, int width, bool forceAlpha) { - IMemoryOwner output = ByteMemoryPool.Rent(data.Length * 2); + MemoryOwner output = MemoryOwner.Rent(data.Length * 2); int offset = 0; int outOffset = 0; (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); ReadOnlySpan inputSpan = MemoryMarshal.Cast(data); - Span outputSpan = MemoryMarshal.Cast(output.Memory.Span); + Span outputSpan = MemoryMarshal.Cast(output.Span); for (int y = 0; y < height; y++) { @@ -146,16 +147,16 @@ namespace Ryujinx.Graphics.Texture return output; } - public unsafe static IMemoryOwner ConvertA1B5G5R5ToR8G8B8A8(ReadOnlySpan data, int width) + public static MemoryOwner ConvertA1B5G5R5ToR8G8B8A8(ReadOnlySpan data, int width) { - IMemoryOwner output = ByteMemoryPool.Rent(data.Length * 2); + MemoryOwner output = MemoryOwner.Rent(data.Length * 2); int offset = 0; int outOffset = 0; (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); ReadOnlySpan inputSpan = MemoryMarshal.Cast(data); - Span outputSpan = MemoryMarshal.Cast(output.Memory.Span); + Span outputSpan = MemoryMarshal.Cast(output.Span); for (int y = 0; y < height; y++) { @@ -183,16 +184,16 @@ namespace Ryujinx.Graphics.Texture return output; } - public unsafe static IMemoryOwner ConvertR4G4B4A4ToR8G8B8A8(ReadOnlySpan data, int width) + public static MemoryOwner ConvertR4G4B4A4ToR8G8B8A8(ReadOnlySpan data, int width) { - IMemoryOwner output = ByteMemoryPool.Rent(data.Length * 2); + MemoryOwner output = MemoryOwner.Rent(data.Length * 2); int offset = 0; int outOffset = 0; (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); ReadOnlySpan inputSpan = MemoryMarshal.Cast(data); - Span outputSpan = MemoryMarshal.Cast(output.Memory.Span); + Span outputSpan = MemoryMarshal.Cast(output.Span); for (int y = 0; y < height; y++) { diff --git a/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs b/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs index 8a9acd912..83f00f345 100644 --- a/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs +++ b/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs @@ -454,7 +454,7 @@ namespace Ryujinx.Graphics.Vic.Image int srcStride = GetPitch(width, bytesPerPixel); int inSize = srcStride * height; - ReadOnlySpan src = rm.Gmm.GetSpan(ExtendOffset(offset), inSize); + ReadOnlySpan src = rm.MemoryManager.GetSpan(ExtendOffset(offset), inSize); int outSize = dstStride * height; int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer); @@ -481,7 +481,7 @@ namespace Ryujinx.Graphics.Vic.Image { int inSize = GetBlockLinearSize(width, height, bytesPerPixel, gobBlocksInY); - ReadOnlySpan src = rm.Gmm.GetSpan(ExtendOffset(offset), inSize); + ReadOnlySpan src = rm.MemoryManager.GetSpan(ExtendOffset(offset), inSize); int outSize = dstStride * height; int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer); diff --git a/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs b/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs index b06640499..b5008b7b5 100644 --- a/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs +++ b/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs @@ -636,7 +636,7 @@ namespace Ryujinx.Graphics.Vic.Image { if (linear) { - rm.Gmm.WriteMapped(ExtendOffset(offset), src); + rm.MemoryManager.Write(ExtendOffset(offset), src); return; } @@ -659,7 +659,7 @@ namespace Ryujinx.Graphics.Vic.Image LayoutConverter.ConvertLinearToBlockLinear(dst, width, height, dstStride, bytesPerPixel, gobBlocksInY, src); - rm.Gmm.WriteMapped(ExtendOffset(offset), dst); + rm.MemoryManager.Write(ExtendOffset(offset), dst); rm.BufferPool.Return(dstIndex); } diff --git a/src/Ryujinx.Graphics.Vic/ResourceManager.cs b/src/Ryujinx.Graphics.Vic/ResourceManager.cs index b0ff8e10e..e7d7ef74a 100644 --- a/src/Ryujinx.Graphics.Vic/ResourceManager.cs +++ b/src/Ryujinx.Graphics.Vic/ResourceManager.cs @@ -1,17 +1,17 @@ -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Vic.Image; namespace Ryujinx.Graphics.Vic { readonly struct ResourceManager { - public MemoryManager Gmm { get; } + public DeviceMemoryManager MemoryManager { get; } public BufferPool SurfacePool { get; } public BufferPool BufferPool { get; } - public ResourceManager(MemoryManager gmm, BufferPool surfacePool, BufferPool bufferPool) + public ResourceManager(DeviceMemoryManager mm, BufferPool surfacePool, BufferPool bufferPool) { - Gmm = gmm; + MemoryManager = mm; SurfacePool = surfacePool; BufferPool = bufferPool; } diff --git a/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj b/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj index cfebcfa2a..a6c4fb2bb 100644 --- a/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj +++ b/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj @@ -8,8 +8,6 @@ - - diff --git a/src/Ryujinx.Graphics.Vic/VicDevice.cs b/src/Ryujinx.Graphics.Vic/VicDevice.cs index 2ddb94a4e..2b25a74c8 100644 --- a/src/Ryujinx.Graphics.Vic/VicDevice.cs +++ b/src/Ryujinx.Graphics.Vic/VicDevice.cs @@ -1,5 +1,4 @@ using Ryujinx.Graphics.Device; -using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Vic.Image; using Ryujinx.Graphics.Vic.Types; using System; @@ -9,14 +8,14 @@ namespace Ryujinx.Graphics.Vic { public class VicDevice : IDeviceState { - private readonly MemoryManager _gmm; + private readonly DeviceMemoryManager _mm; private readonly ResourceManager _rm; private readonly DeviceState _state; - public VicDevice(MemoryManager gmm) + public VicDevice(DeviceMemoryManager mm) { - _gmm = gmm; - _rm = new ResourceManager(gmm, new BufferPool(), new BufferPool()); + _mm = mm; + _rm = new ResourceManager(mm, new BufferPool(), new BufferPool()); _state = new DeviceState(new Dictionary { { nameof(VicRegisters.Execute), new RwCallback(Execute, null) }, @@ -68,7 +67,7 @@ namespace Ryujinx.Graphics.Vic private T ReadIndirect(uint offset) where T : unmanaged { - return _gmm.Read((ulong)offset << 8); + return _mm.Read((ulong)offset << 8); } } } diff --git a/src/Ryujinx.Graphics.Vulkan/BackgroundResources.cs b/src/Ryujinx.Graphics.Vulkan/BackgroundResources.cs index 24e600a26..0290987fd 100644 --- a/src/Ryujinx.Graphics.Vulkan/BackgroundResources.cs +++ b/src/Ryujinx.Graphics.Vulkan/BackgroundResources.cs @@ -29,7 +29,14 @@ namespace Ryujinx.Graphics.Vulkan lock (queueLock) { - _pool = new CommandBufferPool(_gd.Api, _device, queue, queueLock, _gd.QueueFamilyIndex, isLight: true); + _pool = new CommandBufferPool( + _gd.Api, + _device, + queue, + queueLock, + _gd.QueueFamilyIndex, + _gd.IsQualcommProprietary, + isLight: true); } } diff --git a/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs b/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs new file mode 100644 index 000000000..bcfb3dbfe --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs @@ -0,0 +1,458 @@ +using Silk.NET.Vulkan; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Ryujinx.Graphics.Vulkan +{ + internal class BarrierBatch : IDisposable + { + private const int MaxBarriersPerCall = 16; + + private const AccessFlags BaseAccess = AccessFlags.ShaderReadBit | AccessFlags.ShaderWriteBit; + private const AccessFlags BufferAccess = AccessFlags.IndexReadBit | AccessFlags.VertexAttributeReadBit | AccessFlags.UniformReadBit; + private const AccessFlags CommandBufferAccess = AccessFlags.IndirectCommandReadBit; + + private readonly VulkanRenderer _gd; + + private readonly NativeArray _memoryBarrierBatch = new(MaxBarriersPerCall); + private readonly NativeArray _bufferBarrierBatch = new(MaxBarriersPerCall); + private readonly NativeArray _imageBarrierBatch = new(MaxBarriersPerCall); + + private readonly List> _memoryBarriers = new(); + private readonly List> _bufferBarriers = new(); + private readonly List> _imageBarriers = new(); + private int _queuedBarrierCount; + + private enum IncoherentBarrierType + { + None, + Texture, + All, + CommandBuffer + } + + private bool _feedbackLoopActive; + private PipelineStageFlags _incoherentBufferWriteStages; + private PipelineStageFlags _incoherentTextureWriteStages; + private PipelineStageFlags _extraStages; + private IncoherentBarrierType _queuedIncoherentBarrier; + private bool _queuedFeedbackLoopBarrier; + + public BarrierBatch(VulkanRenderer gd) + { + _gd = gd; + } + + public static (AccessFlags Access, PipelineStageFlags Stages) GetSubpassAccessSuperset(VulkanRenderer gd) + { + AccessFlags access = BufferAccess; + PipelineStageFlags stages = PipelineStageFlags.AllGraphicsBit; + + if (gd.TransformFeedbackApi != null) + { + access |= AccessFlags.TransformFeedbackWriteBitExt; + stages |= PipelineStageFlags.TransformFeedbackBitExt; + } + + return (access, stages); + } + + private readonly record struct StageFlags : IEquatable + { + public readonly PipelineStageFlags Source; + public readonly PipelineStageFlags Dest; + + public StageFlags(PipelineStageFlags source, PipelineStageFlags dest) + { + Source = source; + Dest = dest; + } + } + + private readonly struct BarrierWithStageFlags where T : unmanaged + { + public readonly StageFlags Flags; + public readonly T Barrier; + public readonly T2 Resource; + + public BarrierWithStageFlags(StageFlags flags, T barrier) + { + Flags = flags; + Barrier = barrier; + Resource = default; + } + + public BarrierWithStageFlags(PipelineStageFlags srcStageFlags, PipelineStageFlags dstStageFlags, T barrier, T2 resource) + { + Flags = new StageFlags(srcStageFlags, dstStageFlags); + Barrier = barrier; + Resource = resource; + } + } + + private void QueueBarrier(List> list, T barrier, T2 resource, PipelineStageFlags srcStageFlags, PipelineStageFlags dstStageFlags) where T : unmanaged + { + list.Add(new BarrierWithStageFlags(srcStageFlags, dstStageFlags, barrier, resource)); + _queuedBarrierCount++; + } + + public void QueueBarrier(MemoryBarrier barrier, PipelineStageFlags srcStageFlags, PipelineStageFlags dstStageFlags) + { + QueueBarrier(_memoryBarriers, barrier, default, srcStageFlags, dstStageFlags); + } + + public void QueueBarrier(BufferMemoryBarrier barrier, PipelineStageFlags srcStageFlags, PipelineStageFlags dstStageFlags) + { + QueueBarrier(_bufferBarriers, barrier, default, srcStageFlags, dstStageFlags); + } + + public void QueueBarrier(ImageMemoryBarrier barrier, TextureStorage resource, PipelineStageFlags srcStageFlags, PipelineStageFlags dstStageFlags) + { + QueueBarrier(_imageBarriers, barrier, resource, srcStageFlags, dstStageFlags); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe void FlushMemoryBarrier(ShaderCollection program, bool inRenderPass) + { + if (_queuedIncoherentBarrier > IncoherentBarrierType.None) + { + // We should emit a memory barrier if there's a write access in the program (current program, or program since last barrier) + bool hasTextureWrite = _incoherentTextureWriteStages != PipelineStageFlags.None; + bool hasBufferWrite = _incoherentBufferWriteStages != PipelineStageFlags.None; + bool hasBufferBarrier = _queuedIncoherentBarrier > IncoherentBarrierType.Texture; + + if (hasTextureWrite || (hasBufferBarrier && hasBufferWrite)) + { + AccessFlags access = BaseAccess; + + PipelineStageFlags stages = inRenderPass ? PipelineStageFlags.AllGraphicsBit : PipelineStageFlags.AllCommandsBit; + + if (hasBufferBarrier && hasBufferWrite) + { + access |= BufferAccess; + + if (_gd.TransformFeedbackApi != null) + { + access |= AccessFlags.TransformFeedbackWriteBitExt; + stages |= PipelineStageFlags.TransformFeedbackBitExt; + } + } + + if (_queuedIncoherentBarrier == IncoherentBarrierType.CommandBuffer) + { + access |= CommandBufferAccess; + stages |= PipelineStageFlags.DrawIndirectBit; + } + + MemoryBarrier barrier = new MemoryBarrier() + { + SType = StructureType.MemoryBarrier, + SrcAccessMask = access, + DstAccessMask = access + }; + + QueueBarrier(barrier, stages, stages); + + _incoherentTextureWriteStages = program?.IncoherentTextureWriteStages ?? PipelineStageFlags.None; + + if (_queuedIncoherentBarrier > IncoherentBarrierType.Texture) + { + if (program != null) + { + _incoherentBufferWriteStages = program.IncoherentBufferWriteStages | _extraStages; + } + else + { + _incoherentBufferWriteStages = PipelineStageFlags.None; + } + } + + _queuedIncoherentBarrier = IncoherentBarrierType.None; + _queuedFeedbackLoopBarrier = false; + } + else if (_feedbackLoopActive && _queuedFeedbackLoopBarrier) + { + // Feedback loop barrier. + + MemoryBarrier barrier = new MemoryBarrier() + { + SType = StructureType.MemoryBarrier, + SrcAccessMask = AccessFlags.ShaderWriteBit, + DstAccessMask = AccessFlags.ShaderReadBit + }; + + QueueBarrier(barrier, PipelineStageFlags.FragmentShaderBit, PipelineStageFlags.AllGraphicsBit); + + _queuedFeedbackLoopBarrier = false; + } + + _feedbackLoopActive = false; + } + } + + public unsafe void Flush(CommandBufferScoped cbs, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass) + { + Flush(cbs, null, false, inRenderPass, rpHolder, endRenderPass); + } + + public unsafe void Flush(CommandBufferScoped cbs, ShaderCollection program, bool feedbackLoopActive, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass) + { + if (program != null) + { + _incoherentBufferWriteStages |= program.IncoherentBufferWriteStages | _extraStages; + _incoherentTextureWriteStages |= program.IncoherentTextureWriteStages; + } + + _feedbackLoopActive |= feedbackLoopActive; + + FlushMemoryBarrier(program, inRenderPass); + + if (!inRenderPass && rpHolder != null) + { + // Render pass is about to begin. Queue any fences that normally interrupt the pass. + rpHolder.InsertForcedFences(cbs); + } + + while (_queuedBarrierCount > 0) + { + int memoryCount = 0; + int bufferCount = 0; + int imageCount = 0; + + bool hasBarrier = false; + StageFlags flags = default; + + static void AddBarriers( + Span target, + ref int queuedBarrierCount, + ref bool hasBarrier, + ref StageFlags flags, + ref int count, + List> list) where T : unmanaged + { + int firstMatch = -1; + int end = list.Count; + + for (int i = 0; i < list.Count; i++) + { + BarrierWithStageFlags barrier = list[i]; + + if (!hasBarrier) + { + flags = barrier.Flags; + hasBarrier = true; + + target[count++] = barrier.Barrier; + queuedBarrierCount--; + firstMatch = i; + + if (count >= target.Length) + { + end = i + 1; + break; + } + } + else + { + if (flags.Equals(barrier.Flags)) + { + target[count++] = barrier.Barrier; + queuedBarrierCount--; + + if (firstMatch == -1) + { + firstMatch = i; + } + + if (count >= target.Length) + { + end = i + 1; + break; + } + } + else + { + // Delete consumed barriers from the first match to the current non-match. + if (firstMatch != -1) + { + int deleteCount = i - firstMatch; + list.RemoveRange(firstMatch, deleteCount); + i -= deleteCount; + + firstMatch = -1; + end = list.Count; + } + } + } + } + + if (firstMatch == 0 && end == list.Count) + { + list.Clear(); + } + else if (firstMatch != -1) + { + int deleteCount = end - firstMatch; + + list.RemoveRange(firstMatch, deleteCount); + } + } + + if (inRenderPass && _imageBarriers.Count > 0) + { + // Image barriers queued in the batch are meant to be globally scoped, + // but inside a render pass they're scoped to just the range of the render pass. + + // On MoltenVK, we just break the rules and always use image barrier. + // On desktop GPUs, all barriers are globally scoped, so we just replace it with a generic memory barrier. + // Generally, we want to avoid this from happening in the future, so flag the texture to immediately + // emit a barrier whenever the current render pass is bound again. + + bool anyIsNonAttachment = false; + + foreach (BarrierWithStageFlags barrier in _imageBarriers) + { + // If the binding is an attachment, don't add it as a forced fence. + bool isAttachment = rpHolder.ContainsAttachment(barrier.Resource); + + if (!isAttachment) + { + rpHolder.AddForcedFence(barrier.Resource, barrier.Flags.Dest); + anyIsNonAttachment = true; + } + } + + if (_gd.IsTBDR) + { + if (!_gd.IsMoltenVk) + { + if (!anyIsNonAttachment) + { + // This case is a feedback loop. To prevent this from causing an absolute performance disaster, + // remove the barriers entirely. + // If this is not here, there will be a lot of single draw render passes. + // TODO: explicit handling for feedback loops, likely outside this class. + + _queuedBarrierCount -= _imageBarriers.Count; + _imageBarriers.Clear(); + } + else + { + // TBDR GPUs are sensitive to barriers, so we need to end the pass to ensure the data is available. + // Metal already has hazard tracking so MVK doesn't need this. + endRenderPass(); + inRenderPass = false; + } + } + } + else + { + // Generic pipeline memory barriers will work for desktop GPUs. + // They do require a few more access flags on the subpass dependency, though. + foreach (var barrier in _imageBarriers) + { + _memoryBarriers.Add(new BarrierWithStageFlags( + barrier.Flags, + new MemoryBarrier() + { + SType = StructureType.MemoryBarrier, + SrcAccessMask = barrier.Barrier.SrcAccessMask, + DstAccessMask = barrier.Barrier.DstAccessMask + })); + } + + _imageBarriers.Clear(); + } + } + + if (inRenderPass && _memoryBarriers.Count > 0) + { + PipelineStageFlags allFlags = PipelineStageFlags.None; + + foreach (var barrier in _memoryBarriers) + { + allFlags |= barrier.Flags.Dest; + } + + if (allFlags.HasFlag(PipelineStageFlags.DrawIndirectBit) || !_gd.SupportsRenderPassBarrier(allFlags)) + { + endRenderPass(); + inRenderPass = false; + } + } + + AddBarriers(_memoryBarrierBatch.AsSpan(), ref _queuedBarrierCount, ref hasBarrier, ref flags, ref memoryCount, _memoryBarriers); + AddBarriers(_bufferBarrierBatch.AsSpan(), ref _queuedBarrierCount, ref hasBarrier, ref flags, ref bufferCount, _bufferBarriers); + AddBarriers(_imageBarrierBatch.AsSpan(), ref _queuedBarrierCount, ref hasBarrier, ref flags, ref imageCount, _imageBarriers); + + if (hasBarrier) + { + PipelineStageFlags srcStageFlags = flags.Source; + + if (inRenderPass) + { + // Inside a render pass, barrier stages can only be from rasterization. + srcStageFlags &= ~PipelineStageFlags.ComputeShaderBit; + } + + _gd.Api.CmdPipelineBarrier( + cbs.CommandBuffer, + srcStageFlags, + flags.Dest, + 0, + (uint)memoryCount, + _memoryBarrierBatch.Pointer, + (uint)bufferCount, + _bufferBarrierBatch.Pointer, + (uint)imageCount, + _imageBarrierBatch.Pointer); + } + } + } + + private void QueueIncoherentBarrier(IncoherentBarrierType type) + { + if (type > _queuedIncoherentBarrier) + { + _queuedIncoherentBarrier = type; + } + + _queuedFeedbackLoopBarrier = true; + } + + public void QueueTextureBarrier() + { + QueueIncoherentBarrier(IncoherentBarrierType.Texture); + } + + public void QueueMemoryBarrier() + { + QueueIncoherentBarrier(IncoherentBarrierType.All); + } + + public void QueueCommandBufferBarrier() + { + QueueIncoherentBarrier(IncoherentBarrierType.CommandBuffer); + } + + public void EnableTfbBarriers(bool enable) + { + if (enable) + { + _extraStages |= PipelineStageFlags.TransformFeedbackBitExt; + } + else + { + _extraStages &= ~PipelineStageFlags.TransformFeedbackBitExt; + } + } + + public void Dispose() + { + _memoryBarrierBatch.Dispose(); + _bufferBarrierBatch.Dispose(); + _imageBarrierBatch.Dispose(); + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs index b54ff3ab6..e840fdc02 100644 --- a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs +++ b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs @@ -1,9 +1,9 @@ -using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Silk.NET.Vulkan; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading; using VkBuffer = Silk.NET.Vulkan.Buffer; using VkFormat = Silk.NET.Vulkan.Format; @@ -30,40 +30,29 @@ namespace Ryujinx.Graphics.Vulkan private readonly VulkanRenderer _gd; private readonly Device _device; - private MemoryAllocation _allocation; - private Auto _buffer; - private Auto _allocationAuto; + private readonly MemoryAllocation _allocation; + private readonly Auto _buffer; + private readonly Auto _allocationAuto; private readonly bool _allocationImported; - private ulong _bufferHandle; + private readonly ulong _bufferHandle; private CacheByRange _cachedConvertedBuffers; public int Size { get; } - private IntPtr _map; + private readonly IntPtr _map; - private MultiFenceHolder _waitable; + private readonly MultiFenceHolder _waitable; private bool _lastAccessIsWrite; - private BufferAllocationType _baseType; - private BufferAllocationType _currentType; - private bool _swapQueued; - - public BufferAllocationType DesiredType { get; private set; } - - private int _setCount; - private int _writeCount; - private int _flushCount; - private int _flushTemp; - private int _lastFlushWrite = -1; + private readonly BufferAllocationType _baseType; + private readonly BufferAllocationType _activeType; private readonly ReaderWriterLockSlim _flushLock; private FenceHolder _flushFence; private int _flushWaiting; - private List _swapActions; - private byte[] _pendingData; private BufferMirrorRangeList _pendingDataRanges; private Dictionary _mirrors; @@ -82,8 +71,7 @@ namespace Ryujinx.Graphics.Vulkan _map = allocation.HostPointer; _baseType = type; - _currentType = currentType; - DesiredType = currentType; + _activeType = currentType; _flushLock = new ReaderWriterLockSlim(); _useMirrors = gd.IsTBDR; @@ -103,8 +91,7 @@ namespace Ryujinx.Graphics.Vulkan _map = _allocation.HostPointer + offset; _baseType = type; - _currentType = currentType; - DesiredType = currentType; + _activeType = currentType; _flushLock = new ReaderWriterLockSlim(); } @@ -119,164 +106,11 @@ namespace Ryujinx.Graphics.Vulkan Size = size; _baseType = BufferAllocationType.Sparse; - _currentType = BufferAllocationType.Sparse; - DesiredType = BufferAllocationType.Sparse; + _activeType = BufferAllocationType.Sparse; _flushLock = new ReaderWriterLockSlim(); } - public bool TryBackingSwap(ref CommandBufferScoped? cbs) - { - if (_swapQueued && DesiredType != _currentType) - { - // Only swap if the buffer is not used in any queued command buffer. - bool isRented = _buffer.HasRentedCommandBufferDependency(_gd.CommandBufferPool); - - if (!isRented && _gd.CommandBufferPool.OwnedByCurrentThread && !_flushLock.IsReadLockHeld && (_pendingData == null || cbs != null)) - { - var currentAllocation = _allocationAuto; - var currentBuffer = _buffer; - IntPtr currentMap = _map; - - (VkBuffer buffer, MemoryAllocation allocation, BufferAllocationType resultType) = _gd.BufferManager.CreateBacking(_gd, Size, DesiredType, false, false, _currentType); - - if (buffer.Handle != 0) - { - if (cbs != null) - { - ClearMirrors(cbs.Value, 0, Size); - } - - _flushLock.EnterWriteLock(); - - ClearFlushFence(); - - _waitable = new MultiFenceHolder(Size); - - _allocation = allocation; - _allocationAuto = new Auto(allocation); - _buffer = new Auto(new DisposableBuffer(_gd.Api, _device, buffer), this, _waitable, _allocationAuto); - _bufferHandle = buffer.Handle; - _map = allocation.HostPointer; - - if (_map != IntPtr.Zero && currentMap != IntPtr.Zero) - { - // Copy data directly. Readbacks don't have to wait if this is done. - - unsafe - { - new Span((void*)currentMap, Size).CopyTo(new Span((void*)_map, Size)); - } - } - else - { - cbs ??= _gd.CommandBufferPool.Rent(); - - CommandBufferScoped cbsV = cbs.Value; - - Copy(_gd, cbsV, currentBuffer, _buffer, 0, 0, Size); - - // Need to wait for the data to reach the new buffer before data can be flushed. - - _flushFence = _gd.CommandBufferPool.GetFence(cbsV.CommandBufferIndex); - _flushFence.Get(); - } - - Logger.Debug?.PrintMsg(LogClass.Gpu, $"Converted {Size} buffer {_currentType} to {resultType}"); - - _currentType = resultType; - - if (_swapActions != null) - { - foreach (var action in _swapActions) - { - action(); - } - - _swapActions.Clear(); - } - - currentBuffer.Dispose(); - currentAllocation.Dispose(); - - _gd.PipelineInternal.SwapBuffer(currentBuffer, _buffer); - - _flushLock.ExitWriteLock(); - } - - _swapQueued = false; - - return true; - } - - return false; - } - - _swapQueued = false; - - return true; - } - - private void ConsiderBackingSwap() - { - if (_baseType == BufferAllocationType.Auto) - { - // When flushed, wait for a bit more info to make a decision. - bool wasFlushed = _flushTemp > 0; - int multiplier = wasFlushed ? 2 : 0; - if (_writeCount >= (WriteCountThreshold << multiplier) || _setCount >= (SetCountThreshold << multiplier) || _flushCount >= (FlushCountThreshold << multiplier)) - { - if (_flushCount > 0 || _flushTemp-- > 0) - { - // Buffers that flush should ideally be mapped in host address space for easy copies. - // If the buffer is large it will do better on GPU memory, as there will be more writes than data flushes (typically individual pages). - // If it is small, then it's likely most of the buffer will be flushed so we want it on host memory, as access is cached. - - bool hostMappingSensitive = _gd.Vendor == Vendor.Nvidia; - bool deviceLocalMapped = Size > DeviceLocalSizeThreshold || (wasFlushed && _writeCount > _flushCount * 10 && hostMappingSensitive) || _currentType == BufferAllocationType.DeviceLocalMapped; - - DesiredType = deviceLocalMapped ? BufferAllocationType.DeviceLocalMapped : BufferAllocationType.HostMapped; - - // It's harder for a buffer that is flushed to revert to another type of mapping. - if (_flushCount > 0) - { - _flushTemp = 1000; - } - } - else if (_writeCount >= (WriteCountThreshold << multiplier)) - { - // Buffers that are written often should ideally be in the device local heap. (Storage buffers) - DesiredType = BufferAllocationType.DeviceLocal; - } - else if (_setCount > (SetCountThreshold << multiplier)) - { - // Buffers that have their data set often should ideally be host mapped. (Constant buffers) - DesiredType = BufferAllocationType.HostMapped; - } - - _lastFlushWrite = -1; - _flushCount = 0; - _writeCount = 0; - _setCount = 0; - } - - if (!_swapQueued && DesiredType != _currentType) - { - _swapQueued = true; - - _gd.PipelineInternal.AddBackingSwap(this); - } - } - } - - public void Pin() - { - if (_baseType == BufferAllocationType.Auto) - { - _baseType = _currentType; - } - } - public unsafe Auto CreateView(VkFormat format, int offset, int size, Action invalidateView) { var bufferViewCreateInfo = new BufferViewCreateInfo @@ -288,21 +122,11 @@ namespace Ryujinx.Graphics.Vulkan Range = (uint)size, }; - _gd.Api.CreateBufferView(_device, bufferViewCreateInfo, null, out var bufferView).ThrowOnError(); - - (_swapActions ??= new List()).Add(invalidateView); + _gd.Api.CreateBufferView(_device, in bufferViewCreateInfo, null, out var bufferView).ThrowOnError(); return new Auto(new DisposableBufferView(_gd.Api, _device, bufferView), this, _waitable, _buffer); } - public void InheritMetrics(BufferHolder other) - { - _setCount = other._setCount; - _writeCount = other._writeCount; - _flushCount = other._flushCount; - _flushTemp = other._flushTemp; - } - public unsafe void InsertBarrier(CommandBuffer commandBuffer, bool isWrite) { // If the last access is write, we always need a barrier to be sure we will read or modify @@ -329,7 +153,7 @@ namespace Ryujinx.Graphics.Vulkan PipelineStageFlags.AllCommandsBit, DependencyFlags.DeviceGroupBit, 1, - memoryBarrier, + in memoryBarrier, 0, null, 0, @@ -384,7 +208,7 @@ namespace Ryujinx.Graphics.Vulkan var baseData = new Span((void*)(_map + offset), size); var modData = _pendingData.AsSpan(offset, size); - StagingBufferReserved? newMirror = _gd.BufferManager.StagingBuffer.TryReserveData(cbs, size, (int)_gd.Capabilities.MinResourceAlignment); + StagingBufferReserved? newMirror = _gd.BufferManager.StagingBuffer.TryReserveData(cbs, size); if (newMirror != null) { @@ -422,18 +246,8 @@ namespace Ryujinx.Graphics.Vulkan { if (isWrite) { - _writeCount++; - SignalWrite(0, Size); } - else if (isSSBO) - { - // Always consider SSBO access for swapping to device local memory. - - _writeCount++; - - ConsiderBackingSwap(); - } return _buffer; } @@ -442,8 +256,6 @@ namespace Ryujinx.Graphics.Vulkan { if (isWrite) { - _writeCount++; - SignalWrite(offset, size); } @@ -520,7 +332,7 @@ namespace Ryujinx.Graphics.Vulkan if (_gd.PipelineInternal.CurrentCommandBuffer.CommandBuffer.Handle == cbs.CommandBuffer.Handle) { - SetData(rangeOffset, _pendingData.AsSpan(rangeOffset, rangeSize), cbs, _gd.PipelineInternal.EndRenderPass, false); + SetData(rangeOffset, _pendingData.AsSpan(rangeOffset, rangeSize), cbs, _gd.PipelineInternal.EndRenderPassDelegate, false); } else { @@ -542,8 +354,6 @@ namespace Ryujinx.Graphics.Vulkan public void SignalWrite(int offset, int size) { - ConsiderBackingSwap(); - if (offset == 0 && size == Size) { _cachedConvertedBuffers.Clear(); @@ -623,13 +433,6 @@ namespace Ryujinx.Graphics.Vulkan WaitForFlushFence(); - if (_lastFlushWrite != _writeCount) - { - // If it's on the same page as the last flush, ignore it. - _lastFlushWrite = _writeCount; - _flushCount++; - } - Span result; if (_map != IntPtr.Zero) @@ -710,8 +513,7 @@ namespace Ryujinx.Graphics.Vulkan return; } - _setCount++; - bool allowMirror = _useMirrors && allowCbsWait && cbs != null && _currentType <= BufferAllocationType.HostMapped; + bool allowMirror = _useMirrors && allowCbsWait && cbs != null && _activeType <= BufferAllocationType.HostMapped; if (_map != IntPtr.Zero) { @@ -838,6 +640,11 @@ namespace Ryujinx.Graphics.Vulkan } } + public unsafe void SetDataUnchecked(int offset, ReadOnlySpan data) where T : unmanaged + { + SetDataUnchecked(offset, MemoryMarshal.AsBytes(data)); + } + public void SetDataInline(CommandBufferScoped cbs, Action endRenderPass, int dstOffset, ReadOnlySpan data) { if (!TryPushData(cbs, endRenderPass, dstOffset, data)) @@ -857,8 +664,6 @@ namespace Ryujinx.Graphics.Vulkan var dstBuffer = GetBuffer(cbs.CommandBuffer, dstOffset, data.Length, true).Get(cbs, dstOffset, data.Length, true).Value; - _writeCount--; - InsertBufferBarrier( _gd, cbs.CommandBuffer, @@ -965,7 +770,7 @@ namespace Ryujinx.Graphics.Vulkan 0, null, 1, - memoryBarrier, + in memoryBarrier, 0, null); } @@ -1094,8 +899,6 @@ namespace Ryujinx.Graphics.Vulkan public void Dispose() { - _swapQueued = false; - _gd.PipelineInternal?.FlushCommandsIfWeightExceeding(_buffer, (ulong)Size); _buffer.Dispose(); diff --git a/src/Ryujinx.Graphics.Vulkan/BufferManager.cs b/src/Ryujinx.Graphics.Vulkan/BufferManager.cs index e9ac98847..7523913ec 100644 --- a/src/Ryujinx.Graphics.Vulkan/BufferManager.cs +++ b/src/Ryujinx.Graphics.Vulkan/BufferManager.cs @@ -9,6 +9,36 @@ using VkFormat = Silk.NET.Vulkan.Format; namespace Ryujinx.Graphics.Vulkan { + readonly struct ScopedTemporaryBuffer : IDisposable + { + private readonly BufferManager _bufferManager; + private readonly bool _isReserved; + + public readonly BufferRange Range; + public readonly BufferHolder Holder; + + public BufferHandle Handle => Range.Handle; + public int Offset => Range.Offset; + + public ScopedTemporaryBuffer(BufferManager bufferManager, BufferHolder holder, BufferHandle handle, int offset, int size, bool isReserved) + { + _bufferManager = bufferManager; + + Range = new BufferRange(handle, offset, size); + Holder = holder; + + _isReserved = isReserved; + } + + public void Dispose() + { + if (!_isReserved) + { + _bufferManager.Delete(Range.Handle); + } + } + } + class BufferManager : IDisposable { public const MemoryPropertyFlags DefaultBufferMemoryFlags = @@ -73,12 +103,19 @@ namespace Ryujinx.Graphics.Vulkan usage |= BufferUsageFlags.IndirectBufferBit; } + var externalMemoryBuffer = new ExternalMemoryBufferCreateInfo + { + SType = StructureType.ExternalMemoryBufferCreateInfo, + HandleTypes = ExternalMemoryHandleTypeFlags.HostAllocationBitExt, + }; + var bufferCreateInfo = new BufferCreateInfo { SType = StructureType.BufferCreateInfo, Size = (ulong)size, Usage = usage, SharingMode = SharingMode.Exclusive, + PNext = &externalMemoryBuffer, }; gd.Api.CreateBuffer(_device, in bufferCreateInfo, null, out var buffer).ThrowOnError(); @@ -135,10 +172,6 @@ namespace Ryujinx.Graphics.Vulkan if (TryGetBuffer(range.Handle, out var existingHolder)) { - // Since this buffer now also owns the memory from the referenced buffer, - // we pin it to ensure the memory location will not change. - existingHolder.Pin(); - (var memory, var offset) = existingHolder.GetDeviceMemoryAndOffset(); memoryBinds[index] = new SparseMemoryBind() @@ -188,7 +221,7 @@ namespace Ryujinx.Graphics.Vulkan PBufferBinds = &bufferBind }; - gd.Api.QueueBindSparse(gd.Queue, 1, bindSparseInfo, default).ThrowOnError(); + gd.Api.QueueBindSparse(gd.Queue, 1, in bindSparseInfo, default).ThrowOnError(); } var holder = new BufferHolder(gd, _device, buffer, (int)size, storageAllocations); @@ -205,10 +238,9 @@ namespace Ryujinx.Graphics.Vulkan int size, bool sparseCompatible = false, BufferAllocationType baseType = BufferAllocationType.HostMapped, - BufferHandle storageHint = default, bool forceMirrors = false) { - return CreateWithHandle(gd, size, out _, sparseCompatible, baseType, storageHint, forceMirrors); + return CreateWithHandle(gd, size, out _, sparseCompatible, baseType, forceMirrors); } public BufferHandle CreateWithHandle( @@ -217,10 +249,9 @@ namespace Ryujinx.Graphics.Vulkan out BufferHolder holder, bool sparseCompatible = false, BufferAllocationType baseType = BufferAllocationType.HostMapped, - BufferHandle storageHint = default, bool forceMirrors = false) { - holder = Create(gd, size, forConditionalRendering: false, sparseCompatible, baseType, storageHint); + holder = Create(gd, size, forConditionalRendering: false, sparseCompatible, baseType); if (holder == null) { return BufferHandle.Null; @@ -238,6 +269,23 @@ namespace Ryujinx.Graphics.Vulkan return Unsafe.As(ref handle64); } + public ScopedTemporaryBuffer ReserveOrCreate(VulkanRenderer gd, CommandBufferScoped cbs, int size) + { + StagingBufferReserved? result = StagingBuffer.TryReserveData(cbs, size); + + if (result.HasValue) + { + return new ScopedTemporaryBuffer(this, result.Value.Buffer, StagingBuffer.Handle, result.Value.Offset, result.Value.Size, true); + } + else + { + // Create a temporary buffer. + BufferHandle handle = CreateWithHandle(gd, size, out BufferHolder holder); + + return new ScopedTemporaryBuffer(this, holder, handle, 0, size, false); + } + } + public unsafe MemoryRequirements GetHostImportedUsageRequirements(VulkanRenderer gd) { var usage = HostImportedBufferUsageFlags; @@ -340,31 +388,13 @@ namespace Ryujinx.Graphics.Vulkan int size, bool forConditionalRendering = false, bool sparseCompatible = false, - BufferAllocationType baseType = BufferAllocationType.HostMapped, - BufferHandle storageHint = default) + BufferAllocationType baseType = BufferAllocationType.HostMapped) { BufferAllocationType type = baseType; - BufferHolder storageHintHolder = null; if (baseType == BufferAllocationType.Auto) { - if (gd.IsSharedMemory) - { - baseType = BufferAllocationType.HostMapped; - type = baseType; - } - else - { - type = size >= BufferHolder.DeviceLocalSizeThreshold ? BufferAllocationType.DeviceLocal : BufferAllocationType.HostMapped; - } - - if (storageHint != BufferHandle.Null) - { - if (TryGetBuffer(storageHint, out storageHintHolder)) - { - type = storageHintHolder.DesiredType; - } - } + type = BufferAllocationType.HostMapped; } (VkBuffer buffer, MemoryAllocation allocation, BufferAllocationType resultType) = @@ -374,11 +404,6 @@ namespace Ryujinx.Graphics.Vulkan { var holder = new BufferHolder(gd, _device, buffer, allocation, size, baseType, resultType); - if (storageHintHolder != null) - { - holder.InheritMetrics(storageHintHolder); - } - return holder; } @@ -635,13 +660,14 @@ namespace Ryujinx.Graphics.Vulkan { if (disposing) { + StagingBuffer.Dispose(); + foreach (BufferHolder buffer in _buffers) { buffer.Dispose(); } _buffers.Clear(); - StagingBuffer.Dispose(); } } diff --git a/src/Ryujinx.Graphics.Vulkan/BufferState.cs b/src/Ryujinx.Graphics.Vulkan/BufferState.cs index d585dd53c..e49df765d 100644 --- a/src/Ryujinx.Graphics.Vulkan/BufferState.cs +++ b/src/Ryujinx.Graphics.Vulkan/BufferState.cs @@ -25,7 +25,10 @@ namespace Ryujinx.Graphics.Vulkan { var buffer = _buffer.Get(cbs, _offset, _size, true).Value; - gd.TransformFeedbackApi.CmdBindTransformFeedbackBuffers(cbs.CommandBuffer, binding, 1, buffer, (ulong)_offset, (ulong)_size); + ulong offset = (ulong)_offset; + ulong size = (ulong)_size; + + gd.TransformFeedbackApi.CmdBindTransformFeedbackBuffers(cbs.CommandBuffer, binding, 1, in buffer, in offset, in size); } } diff --git a/src/Ryujinx.Graphics.Vulkan/CommandBufferPool.cs b/src/Ryujinx.Graphics.Vulkan/CommandBufferPool.cs index 777a34cee..e1fd3fb9d 100644 --- a/src/Ryujinx.Graphics.Vulkan/CommandBufferPool.cs +++ b/src/Ryujinx.Graphics.Vulkan/CommandBufferPool.cs @@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Vulkan private readonly Device _device; private readonly Queue _queue; private readonly object _queueLock; + private readonly bool _concurrentFenceWaitUnsupported; private readonly CommandPool _pool; private readonly Thread _owner; @@ -30,11 +31,9 @@ namespace Ryujinx.Graphics.Vulkan public int SubmissionCount; public CommandBuffer CommandBuffer; public FenceHolder Fence; - public SemaphoreHolder Semaphore; public List Dependants; public List Waitables; - public HashSet Dependencies; public void Initialize(Vk api, Device device, CommandPool pool) { @@ -46,11 +45,10 @@ namespace Ryujinx.Graphics.Vulkan Level = CommandBufferLevel.Primary, }; - api.AllocateCommandBuffers(device, allocateInfo, out CommandBuffer); + api.AllocateCommandBuffers(device, in allocateInfo, out CommandBuffer); Dependants = new List(); Waitables = new List(); - Dependencies = new HashSet(); } } @@ -61,12 +59,20 @@ namespace Ryujinx.Graphics.Vulkan private int _queuedCount; private int _inUseCount; - public unsafe CommandBufferPool(Vk api, Device device, Queue queue, object queueLock, uint queueFamilyIndex, bool isLight = false) + public unsafe CommandBufferPool( + Vk api, + Device device, + Queue queue, + object queueLock, + uint queueFamilyIndex, + bool concurrentFenceWaitUnsupported, + bool isLight = false) { _api = api; _device = device; _queue = queue; _queueLock = queueLock; + _concurrentFenceWaitUnsupported = concurrentFenceWaitUnsupported; _owner = Thread.CurrentThread; var commandPoolCreateInfo = new CommandPoolCreateInfo @@ -77,7 +83,7 @@ namespace Ryujinx.Graphics.Vulkan CommandPoolCreateFlags.ResetCommandBufferBit, }; - api.CreateCommandPool(device, commandPoolCreateInfo, null, out _pool).ThrowOnError(); + api.CreateCommandPool(device, in commandPoolCreateInfo, null, out _pool).ThrowOnError(); // We need at least 2 command buffers to get texture data in some cases. _totalCommandBuffers = isLight ? 2 : MaxCommandBuffers; @@ -134,14 +140,6 @@ namespace Ryujinx.Graphics.Vulkan } } - public void AddDependency(int cbIndex, CommandBufferScoped dependencyCbs) - { - Debug.Assert(_commandBuffers[cbIndex].InUse); - var semaphoreHolder = _commandBuffers[dependencyCbs.CommandBufferIndex].Semaphore; - semaphoreHolder.Get(); - _commandBuffers[cbIndex].Dependencies.Add(semaphoreHolder); - } - public void AddWaitable(int cbIndex, MultiFenceHolder waitable) { ref var entry = ref _commandBuffers[cbIndex]; @@ -255,7 +253,7 @@ namespace Ryujinx.Graphics.Vulkan SType = StructureType.CommandBufferBeginInfo, }; - _api.BeginCommandBuffer(entry.CommandBuffer, commandBufferBeginInfo).ThrowOnError(); + _api.BeginCommandBuffer(entry.CommandBuffer, in commandBufferBeginInfo).ThrowOnError(); return new CommandBufferScoped(this, entry.CommandBuffer, cursor); } @@ -302,25 +300,18 @@ namespace Ryujinx.Graphics.Vulkan SubmitInfo sInfo = new() { SType = StructureType.SubmitInfo, - WaitSemaphoreCount = waitSemaphores != null ? (uint)waitSemaphores.Length : 0, + WaitSemaphoreCount = !waitSemaphores.IsEmpty ? (uint)waitSemaphores.Length : 0, PWaitSemaphores = pWaitSemaphores, PWaitDstStageMask = pWaitDstStageMask, CommandBufferCount = 1, PCommandBuffers = &commandBuffer, - SignalSemaphoreCount = signalSemaphores != null ? (uint)signalSemaphores.Length : 0, + SignalSemaphoreCount = !signalSemaphores.IsEmpty ? (uint)signalSemaphores.Length : 0, PSignalSemaphores = pSignalSemaphores, }; lock (_queueLock) { - Result result = _api.QueueSubmit(_queue, 1, sInfo, entry.Fence.GetUnsafe()); - - if (result != Result.Success) - { - - Console.WriteLine($"QueueSubmit failed with error: {result}"); - - } + _api.QueueSubmit(_queue, 1, in sInfo, entry.Fence.GetUnsafe()).ThrowOnError(); } } } @@ -352,19 +343,13 @@ namespace Ryujinx.Graphics.Vulkan waitable.RemoveBufferUses(cbIndex); } - foreach (var dependency in entry.Dependencies) - { - dependency.Put(); - } - entry.Dependants.Clear(); entry.Waitables.Clear(); - entry.Dependencies.Clear(); entry.Fence?.Dispose(); if (refreshFence) { - entry.Fence = new FenceHolder(_api, _device); + entry.Fence = new FenceHolder(_api, _device, _concurrentFenceWaitUnsupported); } else { diff --git a/src/Ryujinx.Graphics.Vulkan/CommandBufferScoped.cs b/src/Ryujinx.Graphics.Vulkan/CommandBufferScoped.cs index 270cdc6e6..2accd69b2 100644 --- a/src/Ryujinx.Graphics.Vulkan/CommandBufferScoped.cs +++ b/src/Ryujinx.Graphics.Vulkan/CommandBufferScoped.cs @@ -26,11 +26,6 @@ namespace Ryujinx.Graphics.Vulkan _pool.AddWaitable(CommandBufferIndex, waitable); } - public void AddDependency(CommandBufferScoped dependencyCbs) - { - _pool.AddDependency(CommandBufferIndex, dependencyCbs); - } - public FenceHolder GetFence() { return _pool.GetFence(CommandBufferIndex); diff --git a/src/Ryujinx.Graphics.Vulkan/Constants.cs b/src/Ryujinx.Graphics.Vulkan/Constants.cs index cd6122112..20ce65818 100644 --- a/src/Ryujinx.Graphics.Vulkan/Constants.cs +++ b/src/Ryujinx.Graphics.Vulkan/Constants.cs @@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Vulkan public const int MaxStorageBufferBindings = MaxStorageBuffersPerStage * MaxShaderStages; public const int MaxTextureBindings = MaxTexturesPerStage * MaxShaderStages; public const int MaxImageBindings = MaxImagesPerStage * MaxShaderStages; + public const int MaxPushDescriptorBinding = 64; public const ulong SparseBufferAlignment = 0x10000; } diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetCollection.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetCollection.cs index ae5167334..bdbc79f92 100644 --- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetCollection.cs +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetCollection.cs @@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Vulkan PBufferInfo = &bufferInfo, }; - _holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null); + _holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null); } } @@ -75,7 +75,25 @@ namespace Ryujinx.Graphics.Vulkan { if (info.Buffer.Handle == 0) { - throw new Exception("One of the buffers in bufferInfo is null or uninitialized."); + if (bufferInfo.Length == 0) + { + return; + } + + fixed (DescriptorBufferInfo* pBufferInfo = bufferInfo) + { + var writeDescriptorSet = new WriteDescriptorSet + { + SType = StructureType.WriteDescriptorSet, + DstSet = _descriptorSets[setIndex], + DstBinding = (uint)baseBinding, + DescriptorType = type, + DescriptorCount = (uint)bufferInfo.Length, + PBufferInfo = pBufferInfo, + }; + + _holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null); + } } } */ @@ -113,7 +131,7 @@ namespace Ryujinx.Graphics.Vulkan PImageInfo = &imageInfo, }; - _holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null); + _holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null); } } @@ -150,9 +168,7 @@ namespace Ryujinx.Graphics.Vulkan PImageInfo = pImageInfo, }; - - - _holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null); + _holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null); } } @@ -189,7 +205,7 @@ namespace Ryujinx.Graphics.Vulkan PImageInfo = pImageInfo, }; - _holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null); + _holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null); i += count - 1; } @@ -211,7 +227,7 @@ namespace Ryujinx.Graphics.Vulkan PTexelBufferView = &texelBufferView, }; - _holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null); + _holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null); } } @@ -245,7 +261,7 @@ namespace Ryujinx.Graphics.Vulkan PTexelBufferView = pTexelBufferView + i, }; - _holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null); + _holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null); } i += count; diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetManager.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetManager.cs index 7e3e4568b..97669942c 100644 --- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetManager.cs +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetManager.cs @@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Vulkan { class DescriptorSetManager : IDisposable { - public const uint MaxSets = 32; + public const uint MaxSets = 8; public class DescriptorPoolHolder : IDisposable { @@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Vulkan PPoolSizes = pPoolsSize, }; - Api.CreateDescriptorPool(device, descriptorPoolCreateInfo, null, out _pool).ThrowOnError(); + Api.CreateDescriptorPool(device, in descriptorPoolCreateInfo, null, out _pool).ThrowOnError(); } } diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplate.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplate.cs new file mode 100644 index 000000000..117f79bb4 --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplate.cs @@ -0,0 +1,210 @@ +using Ryujinx.Graphics.GAL; +using Silk.NET.Vulkan; +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Ryujinx.Graphics.Vulkan +{ + class DescriptorSetTemplate : IDisposable + { + /// + /// Renderdoc seems to crash when doing a templated uniform update with count > 1 on a push descriptor. + /// When this is true, consecutive buffers are always updated individually. + /// + private const bool RenderdocPushCountBug = true; + + private readonly VulkanRenderer _gd; + private readonly Device _device; + + public readonly DescriptorUpdateTemplate Template; + public readonly int Size; + + public unsafe DescriptorSetTemplate( + VulkanRenderer gd, + Device device, + ResourceBindingSegment[] segments, + PipelineLayoutCacheEntry plce, + PipelineBindPoint pbp, + int setIndex) + { + _gd = gd; + _device = device; + + // Create a template from the set usages. Assumes the descriptor set is updated in segment order then binding order. + + DescriptorUpdateTemplateEntry* entries = stackalloc DescriptorUpdateTemplateEntry[segments.Length]; + nuint structureOffset = 0; + + for (int seg = 0; seg < segments.Length; seg++) + { + ResourceBindingSegment segment = segments[seg]; + + int binding = segment.Binding; + int count = segment.Count; + + if (IsBufferType(segment.Type)) + { + entries[seg] = new DescriptorUpdateTemplateEntry() + { + DescriptorType = segment.Type.Convert(), + DstBinding = (uint)binding, + DescriptorCount = (uint)count, + Offset = structureOffset, + Stride = (nuint)Unsafe.SizeOf() + }; + + structureOffset += (nuint)(Unsafe.SizeOf() * count); + } + else if (IsBufferTextureType(segment.Type)) + { + entries[seg] = new DescriptorUpdateTemplateEntry() + { + DescriptorType = segment.Type.Convert(), + DstBinding = (uint)binding, + DescriptorCount = (uint)count, + Offset = structureOffset, + Stride = (nuint)Unsafe.SizeOf() + }; + + structureOffset += (nuint)(Unsafe.SizeOf() * count); + } + else + { + entries[seg] = new DescriptorUpdateTemplateEntry() + { + DescriptorType = segment.Type.Convert(), + DstBinding = (uint)binding, + DescriptorCount = (uint)count, + Offset = structureOffset, + Stride = (nuint)Unsafe.SizeOf() + }; + + structureOffset += (nuint)(Unsafe.SizeOf() * count); + } + } + + Size = (int)structureOffset; + + var info = new DescriptorUpdateTemplateCreateInfo() + { + SType = StructureType.DescriptorUpdateTemplateCreateInfo, + DescriptorUpdateEntryCount = (uint)segments.Length, + PDescriptorUpdateEntries = entries, + + TemplateType = DescriptorUpdateTemplateType.DescriptorSet, + DescriptorSetLayout = plce.DescriptorSetLayouts[setIndex], + PipelineBindPoint = pbp, + PipelineLayout = plce.PipelineLayout, + Set = (uint)setIndex, + }; + + DescriptorUpdateTemplate result; + gd.Api.CreateDescriptorUpdateTemplate(device, &info, null, &result).ThrowOnError(); + + Template = result; + } + + public unsafe DescriptorSetTemplate( + VulkanRenderer gd, + Device device, + ResourceDescriptorCollection descriptors, + long updateMask, + PipelineLayoutCacheEntry plce, + PipelineBindPoint pbp, + int setIndex) + { + _gd = gd; + _device = device; + + // Create a template from the set usages. Assumes the descriptor set is updated in segment order then binding order. + int segmentCount = BitOperations.PopCount((ulong)updateMask); + + DescriptorUpdateTemplateEntry* entries = stackalloc DescriptorUpdateTemplateEntry[segmentCount]; + int entry = 0; + nuint structureOffset = 0; + + void AddBinding(int binding, int count) + { + entries[entry++] = new DescriptorUpdateTemplateEntry() + { + DescriptorType = DescriptorType.UniformBuffer, + DstBinding = (uint)binding, + DescriptorCount = (uint)count, + Offset = structureOffset, + Stride = (nuint)Unsafe.SizeOf() + }; + + structureOffset += (nuint)(Unsafe.SizeOf() * count); + } + + int startBinding = 0; + int bindingCount = 0; + + foreach (ResourceDescriptor descriptor in descriptors.Descriptors) + { + for (int i = 0; i < descriptor.Count; i++) + { + int binding = descriptor.Binding + i; + + if ((updateMask & (1L << binding)) != 0) + { + if (bindingCount > 0 && (RenderdocPushCountBug || startBinding + bindingCount != binding)) + { + AddBinding(startBinding, bindingCount); + + bindingCount = 0; + } + + if (bindingCount == 0) + { + startBinding = binding; + } + + bindingCount++; + } + } + } + + if (bindingCount > 0) + { + AddBinding(startBinding, bindingCount); + } + + Size = (int)structureOffset; + + var info = new DescriptorUpdateTemplateCreateInfo() + { + SType = StructureType.DescriptorUpdateTemplateCreateInfo, + DescriptorUpdateEntryCount = (uint)entry, + PDescriptorUpdateEntries = entries, + + TemplateType = DescriptorUpdateTemplateType.PushDescriptorsKhr, + DescriptorSetLayout = plce.DescriptorSetLayouts[setIndex], + PipelineBindPoint = pbp, + PipelineLayout = plce.PipelineLayout, + Set = (uint)setIndex, + }; + + DescriptorUpdateTemplate result; + gd.Api.CreateDescriptorUpdateTemplate(device, &info, null, &result).ThrowOnError(); + + Template = result; + } + + private static bool IsBufferType(ResourceType type) + { + return type == ResourceType.UniformBuffer || type == ResourceType.StorageBuffer; + } + + private static bool IsBufferTextureType(ResourceType type) + { + return type == ResourceType.BufferTexture || type == ResourceType.BufferImage; + } + + public unsafe void Dispose() + { + _gd.Api.DestroyDescriptorUpdateTemplate(_device, Template, null); + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplateUpdater.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplateUpdater.cs new file mode 100644 index 000000000..88db7e769 --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplateUpdater.cs @@ -0,0 +1,77 @@ +using Ryujinx.Common; +using Silk.NET.Vulkan; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Vulkan +{ + ref struct DescriptorSetTemplateWriter + { + private Span _data; + + public DescriptorSetTemplateWriter(Span data) + { + _data = data; + } + + public void Push(ReadOnlySpan values) where T : unmanaged + { + Span target = MemoryMarshal.Cast(_data); + + values.CopyTo(target); + + _data = _data[(Unsafe.SizeOf() * values.Length)..]; + } + } + + unsafe class DescriptorSetTemplateUpdater : IDisposable + { + private const int SizeGranularity = 512; + + private DescriptorSetTemplate _activeTemplate; + private NativeArray _data; + + private void EnsureSize(int size) + { + if (_data == null || _data.Length < size) + { + _data?.Dispose(); + + int dataSize = BitUtils.AlignUp(size, SizeGranularity); + _data = new NativeArray(dataSize); + } + } + + public DescriptorSetTemplateWriter Begin(DescriptorSetTemplate template) + { + _activeTemplate = template; + + EnsureSize(template.Size); + + return new DescriptorSetTemplateWriter(new Span(_data.Pointer, template.Size)); + } + + public DescriptorSetTemplateWriter Begin(int maxSize) + { + EnsureSize(maxSize); + + return new DescriptorSetTemplateWriter(new Span(_data.Pointer, maxSize)); + } + + public void Commit(VulkanRenderer gd, Device device, DescriptorSet set) + { + gd.Api.UpdateDescriptorSetWithTemplate(device, set, _activeTemplate.Template, _data.Pointer); + } + + public void CommitPushDescriptor(VulkanRenderer gd, CommandBufferScoped cbs, DescriptorSetTemplate template, PipelineLayout layout) + { + gd.PushDescriptorApi.CmdPushDescriptorSetWithTemplate(cbs.CommandBuffer, template.Template, layout, 0, _data.Pointer); + } + + public void Dispose() + { + _data?.Dispose(); + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs index a12e880a7..f47b1c87d 100644 --- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs @@ -3,7 +3,10 @@ using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Shader; using Silk.NET.Vulkan; using System; +using System.Buffers; +using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using CompareOp = Ryujinx.Graphics.GAL.CompareOp; using Format = Ryujinx.Graphics.GAL.Format; using SamplerCreateInfo = Ryujinx.Graphics.GAL.SamplerCreateInfo; @@ -13,6 +16,9 @@ namespace Ryujinx.Graphics.Vulkan class DescriptorSetUpdater { private const ulong StorageBufferMaxMirrorable = 0x2000; + + private const int ArrayGrowthSize = 16; + private record struct BufferRef { public Auto Buffer; @@ -34,18 +40,54 @@ namespace Ryujinx.Graphics.Vulkan } } + private record struct TextureRef + { + public ShaderStage Stage; + public TextureView View; + public Auto ImageView; + public Auto Sampler; + + public TextureRef(ShaderStage stage, TextureView view, Auto imageView, Auto sampler) + { + Stage = stage; + View = view; + ImageView = imageView; + Sampler = sampler; + } + } + + private record struct ImageRef + { + public ShaderStage Stage; + public TextureView View; + public Auto ImageView; + + public ImageRef(ShaderStage stage, TextureView view, Auto imageView) + { + Stage = stage; + View = view; + ImageView = imageView; + } + } + + private readonly record struct ArrayRef(ShaderStage Stage, T Array); + private readonly VulkanRenderer _gd; - private readonly PipelineBase _pipeline; + private readonly Device _device; private ShaderCollection _program; private readonly BufferRef[] _uniformBufferRefs; private readonly BufferRef[] _storageBufferRefs; - private readonly Auto[] _textureRefs; - private readonly Auto[] _samplerRefs; - private readonly Auto[] _imageRefs; + private readonly TextureRef[] _textureRefs; + private readonly ImageRef[] _imageRefs; private readonly TextureBuffer[] _bufferTextureRefs; private readonly TextureBuffer[] _bufferImageRefs; - private readonly Format[] _bufferImageFormats; + + private ArrayRef[] _textureArrayRefs; + private ArrayRef[] _imageArrayRefs; + + private ArrayRef[] _textureArrayExtraRefs; + private ArrayRef[] _imageArrayExtraRefs; private readonly DescriptorBufferInfo[] _uniformBuffers; private readonly DescriptorBufferInfo[] _storageBuffers; @@ -54,10 +96,14 @@ namespace Ryujinx.Graphics.Vulkan private readonly BufferView[] _bufferTextures; private readonly BufferView[] _bufferImages; + private readonly DescriptorSetTemplateUpdater _templateUpdater; + private BitMapStruct> _uniformSet; private BitMapStruct> _storageSet; private BitMapStruct> _uniformMirrored; private BitMapStruct> _storageMirrored; + private readonly int[] _uniformSetPd; + private int _pdSequence = 1; private bool _updateDescriptorCacheCbIndex; @@ -78,22 +124,28 @@ namespace Ryujinx.Graphics.Vulkan private readonly TextureView _dummyTexture; private readonly SamplerHolder _dummySampler; - public DescriptorSetUpdater(VulkanRenderer gd, PipelineBase pipeline) + public List FeedbackLoopHazards { get; private set; } + + public DescriptorSetUpdater(VulkanRenderer gd, Device device) { _gd = gd; - _pipeline = pipeline; + _device = device; // Some of the bindings counts needs to be multiplied by 2 because we have buffer and // regular textures/images interleaved on the same descriptor set. _uniformBufferRefs = new BufferRef[Constants.MaxUniformBufferBindings]; _storageBufferRefs = new BufferRef[Constants.MaxStorageBufferBindings]; - _textureRefs = new Auto[Constants.MaxTextureBindings * 2]; - _samplerRefs = new Auto[Constants.MaxTextureBindings * 2]; - _imageRefs = new Auto[Constants.MaxImageBindings * 2]; + _textureRefs = new TextureRef[Constants.MaxTextureBindings * 2]; + _imageRefs = new ImageRef[Constants.MaxImageBindings * 2]; _bufferTextureRefs = new TextureBuffer[Constants.MaxTextureBindings * 2]; _bufferImageRefs = new TextureBuffer[Constants.MaxImageBindings * 2]; - _bufferImageFormats = new Format[Constants.MaxImageBindings * 2]; + + _textureArrayRefs = Array.Empty>(); + _imageArrayRefs = Array.Empty>(); + + _textureArrayExtraRefs = Array.Empty>(); + _imageArrayExtraRefs = Array.Empty>(); _uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings]; _storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings]; @@ -102,6 +154,8 @@ namespace Ryujinx.Graphics.Vulkan _bufferTextures = new BufferView[Constants.MaxTexturesPerStage]; _bufferImages = new BufferView[Constants.MaxImagesPerStage]; + _uniformSetPd = new int[Constants.MaxUniformBufferBindings]; + var initialImageInfo = new DescriptorImageInfo { ImageLayout = ImageLayout.General, @@ -152,12 +206,19 @@ namespace Ryujinx.Graphics.Vulkan 0, 0, 1f)); + + _templateUpdater = new(); } - public void Initialize() + public void Initialize(bool isMainPipeline) { - Span dummyTextureData = stackalloc byte[4]; + MemoryOwner dummyTextureData = MemoryOwner.RentCleared(4); _dummyTexture.SetData(dummyTextureData); + + if (isMainPipeline) + { + FeedbackLoopHazards = new(); + } } private static bool BindingOverlaps(ref DescriptorBufferInfo info, int bindingOffset, int offset, int size) @@ -187,6 +248,7 @@ namespace Ryujinx.Graphics.Vulkan if (BindingOverlaps(ref info, bindingOffset, offset, size)) { _uniformSet.Clear(binding); + _uniformSetPd[binding] = 0; SignalDirty(DirtyFlags.Uniform); } } @@ -217,29 +279,135 @@ namespace Ryujinx.Graphics.Vulkan }); } - public void SetProgram(ShaderCollection program) + public void InsertBindingBarriers(CommandBufferScoped cbs) { + if ((FeedbackLoopHazards?.Count ?? 0) > 0) + { + // Clear existing hazards - they will be rebuilt. + + foreach (TextureView hazard in FeedbackLoopHazards) + { + hazard.DecrementHazardUses(); + } + + FeedbackLoopHazards.Clear(); + } + + foreach (ResourceBindingSegment segment in _program.BindingSegments[PipelineBase.TextureSetIndex]) + { + if (segment.Type == ResourceType.TextureAndSampler) + { + if (!segment.IsArray) + { + for (int i = 0; i < segment.Count; i++) + { + ref var texture = ref _textureRefs[segment.Binding + i]; + texture.View?.PrepareForUsage(cbs, texture.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards); + } + } + else + { + ref var arrayRef = ref _textureArrayRefs[segment.Binding]; + PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags(); + arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags); + } + } + } + + foreach (ResourceBindingSegment segment in _program.BindingSegments[PipelineBase.ImageSetIndex]) + { + if (segment.Type == ResourceType.Image) + { + if (!segment.IsArray) + { + for (int i = 0; i < segment.Count; i++) + { + ref var image = ref _imageRefs[segment.Binding + i]; + image.View?.PrepareForUsage(cbs, image.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards); + } + } + else + { + ref var arrayRef = ref _imageArrayRefs[segment.Binding]; + PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags(); + arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags); + } + } + } + + for (int setIndex = PipelineBase.DescriptorSetLayouts; setIndex < _program.BindingSegments.Length; setIndex++) + { + var bindingSegments = _program.BindingSegments[setIndex]; + + if (bindingSegments.Length == 0) + { + continue; + } + + ResourceBindingSegment segment = bindingSegments[0]; + + if (segment.IsArray) + { + if (segment.Type == ResourceType.Texture || + segment.Type == ResourceType.Sampler || + segment.Type == ResourceType.TextureAndSampler || + segment.Type == ResourceType.BufferTexture) + { + ref var arrayRef = ref _textureArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts]; + PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags(); + arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags); + } + else if (segment.Type == ResourceType.Image || segment.Type == ResourceType.BufferImage) + { + ref var arrayRef = ref _imageArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts]; + PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags(); + arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags); + } + } + } + } + + public void AdvancePdSequence() + { + if (++_pdSequence == 0) + { + _pdSequence = 1; + } + } + + public void SetProgram(CommandBufferScoped cbs, ShaderCollection program, bool isBound) + { + if (!program.HasSameLayout(_program)) + { + // When the pipeline layout changes, push descriptor bindings are invalidated. + + AdvancePdSequence(); + } + _program = program; _updateDescriptorCacheCbIndex = true; _dirty = DirtyFlags.All; } - public void SetImage(int binding, ITexture image, Format imageFormat) + public void SetImage(CommandBufferScoped cbs, ShaderStage stage, int binding, ITexture image) { if (image is TextureBuffer imageBuffer) { _bufferImageRefs[binding] = imageBuffer; - _bufferImageFormats[binding] = imageFormat; } else if (image is TextureView view) { - _imageRefs[binding] = view.GetView(imageFormat).GetIdentityImageView(); + ref ImageRef iRef = ref _imageRefs[binding]; + + iRef.View?.ClearUsage(FeedbackLoopHazards); + view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards); + + iRef = new(stage, view, view.GetIdentityImageView()); } else { - _imageRefs[binding] = null; + _imageRefs[binding] = default; _bufferImageRefs[binding] = null; - _bufferImageFormats[binding] = default; } SignalDirty(DirtyFlags.Image); @@ -247,7 +415,7 @@ namespace Ryujinx.Graphics.Vulkan public void SetImage(int binding, Auto image) { - _imageRefs[binding] = image; + _imageRefs[binding] = new(ShaderStage.Compute, null, image); SignalDirty(DirtyFlags.Image); } @@ -332,15 +500,16 @@ namespace Ryujinx.Graphics.Vulkan } else if (texture is TextureView view) { - view.Storage.InsertWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags()); + ref TextureRef iRef = ref _textureRefs[binding]; - _textureRefs[binding] = view.GetImageView(); - _samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler(); + iRef.View?.ClearUsage(FeedbackLoopHazards); + view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards); + + iRef = new(stage, view, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler()); } else { - _textureRefs[binding] = null; - _samplerRefs[binding] = null; + _textureRefs[binding] = default; _bufferTextureRefs[binding] = null; } @@ -356,10 +525,9 @@ namespace Ryujinx.Graphics.Vulkan { if (texture is TextureView view) { - view.Storage.InsertWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags()); + view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags()); - _textureRefs[binding] = view.GetIdentityImageView(); - _samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler(); + _textureRefs[binding] = new(stage, view, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler()); SignalDirty(DirtyFlags.Texture); } @@ -369,6 +537,98 @@ namespace Ryujinx.Graphics.Vulkan } } + public void SetTextureArray(CommandBufferScoped cbs, ShaderStage stage, int binding, ITextureArray array) + { + ref ArrayRef arrayRef = ref GetArrayRef(ref _textureArrayRefs, binding, ArrayGrowthSize); + + if (arrayRef.Stage != stage || arrayRef.Array != array) + { + arrayRef.Array?.DecrementBindCount(); + + if (array is TextureArray textureArray) + { + textureArray.IncrementBindCount(); + textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags()); + } + + arrayRef = new ArrayRef(stage, array as TextureArray); + + SignalDirty(DirtyFlags.Texture); + } + } + + public void SetTextureArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, ITextureArray array) + { + ref ArrayRef arrayRef = ref GetArrayRef(ref _textureArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts); + + if (arrayRef.Stage != stage || arrayRef.Array != array) + { + arrayRef.Array?.DecrementBindCount(); + + if (array is TextureArray textureArray) + { + textureArray.IncrementBindCount(); + textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags()); + } + + arrayRef = new ArrayRef(stage, array as TextureArray); + + SignalDirty(DirtyFlags.Texture); + } + } + + public void SetImageArray(CommandBufferScoped cbs, ShaderStage stage, int binding, IImageArray array) + { + ref ArrayRef arrayRef = ref GetArrayRef(ref _imageArrayRefs, binding, ArrayGrowthSize); + + if (arrayRef.Stage != stage || arrayRef.Array != array) + { + arrayRef.Array?.DecrementBindCount(); + + if (array is ImageArray imageArray) + { + imageArray.IncrementBindCount(); + imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags()); + } + + arrayRef = new ArrayRef(stage, array as ImageArray); + + SignalDirty(DirtyFlags.Image); + } + } + + public void SetImageArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, IImageArray array) + { + ref ArrayRef arrayRef = ref GetArrayRef(ref _imageArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts); + + if (arrayRef.Stage != stage || arrayRef.Array != array) + { + arrayRef.Array?.DecrementBindCount(); + + if (array is ImageArray imageArray) + { + imageArray.IncrementBindCount(); + imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags()); + } + + arrayRef = new ArrayRef(stage, array as ImageArray); + + SignalDirty(DirtyFlags.Image); + } + } + + private static ref ArrayRef GetArrayRef(ref ArrayRef[] array, int index, int growthSize = 1) + { + ArgumentOutOfRangeException.ThrowIfNegative(index); + + if (array.Length <= index) + { + Array.Resize(ref array, index + growthSize); + } + + return ref array[index]; + } + public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan buffers) { for (int i = 0; i < buffers.Length; i++) @@ -396,6 +656,7 @@ namespace Ryujinx.Graphics.Vulkan if (!currentBufferRef.Equals(newRef) || currentInfo.Range != info.Range) { _uniformSet.Clear(index); + _uniformSetPd[index] = 0; currentInfo = info; currentBufferRef = newRef; @@ -417,31 +678,47 @@ namespace Ryujinx.Graphics.Vulkan return; } + var program = _program; + if (_dirty.HasFlag(DirtyFlags.Uniform)) { - if (_program.UsePushDescriptors) + if (program.UsePushDescriptors) { - UpdateAndBindUniformBufferPd(cbs, pbp); + UpdateAndBindUniformBufferPd(cbs); } else { - UpdateAndBind(cbs, PipelineBase.UniformSetIndex, pbp); + UpdateAndBind(cbs, program, PipelineBase.UniformSetIndex, pbp); } } if (_dirty.HasFlag(DirtyFlags.Storage)) { - UpdateAndBind(cbs, PipelineBase.StorageSetIndex, pbp); + UpdateAndBind(cbs, program, PipelineBase.StorageSetIndex, pbp); } if (_dirty.HasFlag(DirtyFlags.Texture)) { - UpdateAndBind(cbs, PipelineBase.TextureSetIndex, pbp); + if (program.UpdateTexturesWithoutTemplate) + { + UpdateAndBindTexturesWithoutTemplate(cbs, program, pbp); + } + else + { + UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp); + } } if (_dirty.HasFlag(DirtyFlags.Image)) { - UpdateAndBind(cbs, PipelineBase.ImageSetIndex, pbp); + UpdateAndBind(cbs, program, PipelineBase.ImageSetIndex, pbp); + } + + if (program.BindingSegments.Length > PipelineBase.DescriptorSetLayouts) + { + // Program is using extra sets, we need to bind those too. + + BindExtraSets(cbs, program, pbp); } _dirty = DirtyFlags.None; @@ -481,9 +758,8 @@ namespace Ryujinx.Graphics.Vulkan } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void UpdateAndBind(CommandBufferScoped cbs, int setIndex, PipelineBindPoint pbp) + private void UpdateAndBind(CommandBufferScoped cbs, ShaderCollection program, int setIndex, PipelineBindPoint pbp) { - var program = _program; var bindingSegments = program.BindingSegments[setIndex]; if (bindingSegments.Length == 0) @@ -509,6 +785,10 @@ namespace Ryujinx.Graphics.Vulkan } } + DescriptorSetTemplate template = program.Templates[setIndex]; + + DescriptorSetTemplateWriter tu = _templateUpdater.Begin(template); + foreach (ResourceBindingSegment segment in bindingSegments) { int binding = segment.Binding; @@ -531,7 +811,8 @@ namespace Ryujinx.Graphics.Vulkan } ReadOnlySpan uniformBuffers = _uniformBuffers; - dsc.UpdateBuffers(0, binding, uniformBuffers.Slice(binding, count), DescriptorType.UniformBuffer); + + tu.Push(uniformBuffers.Slice(binding, count)); } else if (setIndex == PipelineBase.StorageSetIndex) { @@ -556,9 +837,133 @@ namespace Ryujinx.Graphics.Vulkan } ReadOnlySpan storageBuffers = _storageBuffers; - dsc.UpdateBuffers(0, binding, storageBuffers.Slice(binding, count), DescriptorType.StorageBuffer); + + tu.Push(storageBuffers.Slice(binding, count)); } else if (setIndex == PipelineBase.TextureSetIndex) + { + if (!segment.IsArray) + { + if (segment.Type != ResourceType.BufferTexture) + { + Span textures = _textures; + + for (int i = 0; i < count; i++) + { + ref var texture = ref textures[i]; + ref var refs = ref _textureRefs[binding + i]; + + texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default; + texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default; + + if (texture.ImageView.Handle == 0) + { + texture.ImageView = _dummyTexture.GetImageView().Get(cbs).Value; + } + + if (texture.Sampler.Handle == 0) + { + texture.Sampler = _dummySampler.GetSampler().Get(cbs).Value; + } + } + + tu.Push(textures[..count]); + } + else + { + Span bufferTextures = _bufferTextures; + + for (int i = 0; i < count; i++) + { + bufferTextures[i] = _bufferTextureRefs[binding + i]?.GetBufferView(cbs, false) ?? default; + } + + tu.Push(bufferTextures[..count]); + } + } + else + { + if (segment.Type != ResourceType.BufferTexture) + { + tu.Push(_textureArrayRefs[binding].Array.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler)); + } + else + { + tu.Push(_textureArrayRefs[binding].Array.GetBufferViews(cbs)); + } + } + } + else if (setIndex == PipelineBase.ImageSetIndex) + { + if (!segment.IsArray) + { + if (segment.Type != ResourceType.BufferImage) + { + Span images = _images; + + for (int i = 0; i < count; i++) + { + images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? default; + } + + tu.Push(images[..count]); + } + else + { + Span bufferImages = _bufferImages; + + for (int i = 0; i < count; i++) + { + bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, true) ?? default; + } + + tu.Push(bufferImages[..count]); + } + } + else + { + if (segment.Type != ResourceType.BufferTexture) + { + tu.Push(_imageArrayRefs[binding].Array.GetImageInfos(_gd, cbs, _dummyTexture)); + } + else + { + tu.Push(_imageArrayRefs[binding].Array.GetBufferViews(cbs)); + } + } + } + } + + var sets = dsc.GetSets(); + _templateUpdater.Commit(_gd, _device, sets[0]); + + _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan.Empty); + } + + private void UpdateAndBindTexturesWithoutTemplate(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp) + { + int setIndex = PipelineBase.TextureSetIndex; + var bindingSegments = program.BindingSegments[setIndex]; + + if (bindingSegments.Length == 0) + { + return; + } + + if (_updateDescriptorCacheCbIndex) + { + _updateDescriptorCacheCbIndex = false; + program.UpdateDescriptorCacheCommandBufferIndex(cbs.CommandBufferIndex); + } + + var dsc = program.GetNewDescriptorSetCollection(setIndex, out _).Get(cbs); + + foreach (ResourceBindingSegment segment in bindingSegments) + { + int binding = segment.Binding; + int count = segment.Count; + + if (!segment.IsArray) { if (segment.Type != ResourceType.BufferTexture) { @@ -567,9 +972,10 @@ namespace Ryujinx.Graphics.Vulkan for (int i = 0; i < count; i++) { ref var texture = ref textures[i]; + ref var refs = ref _textureRefs[binding + i]; - texture.ImageView = _textureRefs[binding + i]?.Get(cbs).Value ?? default; - texture.Sampler = _samplerRefs[binding + i]?.Get(cbs).Value ?? default; + texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default; + texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default; if (texture.ImageView.Handle == 0) { @@ -602,35 +1008,24 @@ namespace Ryujinx.Graphics.Vulkan dsc.UpdateBufferImages(0, binding, bufferTextures[..count], DescriptorType.UniformTexelBuffer); } } - else if (setIndex == PipelineBase.ImageSetIndex) + else { - if (segment.Type != ResourceType.BufferImage) + if (segment.Type != ResourceType.BufferTexture) { - Span images = _images; + // Span images = _imageRefs.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler); - for (int i = 0; i < count; i++) + if (OperatingSystem.IsIOS()) { - images[i].ImageView = _imageRefs[binding + i]?.Get(cbs).Value ?? default; - if (OperatingSystem.IsIOS()) { - Span singleImage = images.Slice(i, 1); - dsc.UpdateImages(0, binding + i, singleImage, DescriptorType.StorageImage); - } + dsc.UpdateImages(0, binding, _textureArrayRefs[binding].Array.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler), DescriptorType.CombinedImageSampler); } - - if (!OperatingSystem.IsIOS()) { - dsc.UpdateImages(0, binding, images[..count], DescriptorType.StorageImage); + else + { + dsc.UpdateImages(0, binding, _textureArrayRefs[binding].Array.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler), DescriptorType.CombinedImageSampler); } } else { - Span bufferImages = _bufferImages; - - for (int i = 0; i < count; i++) - { - bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, _bufferImageFormats[binding + i], true) ?? default; - } - - dsc.UpdateBufferImages(0, binding, bufferImages[..count], DescriptorType.StorageTexelBuffer); + dsc.UpdateBufferImages(0, binding, _textureArrayRefs[binding].Array.GetBufferViews(cbs), DescriptorType.UniformTexelBuffer); } } } @@ -640,45 +1035,22 @@ namespace Ryujinx.Graphics.Vulkan _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan.Empty); } - private unsafe void UpdateBuffers( - CommandBufferScoped cbs, - PipelineBindPoint pbp, - int baseBinding, - ReadOnlySpan bufferInfo, - DescriptorType type) - { - if (bufferInfo.Length == 0) - { - return; - } - - fixed (DescriptorBufferInfo* pBufferInfo = bufferInfo) - { - var writeDescriptorSet = new WriteDescriptorSet - { - SType = StructureType.WriteDescriptorSet, - DstBinding = (uint)baseBinding, - DescriptorType = type, - DescriptorCount = (uint)bufferInfo.Length, - PBufferInfo = pBufferInfo, - }; - - _gd.PushDescriptorApi.CmdPushDescriptorSet(cbs.CommandBuffer, pbp, _program.PipelineLayout, 0, 1, &writeDescriptorSet); - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs, PipelineBindPoint pbp) + private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs) { + int sequence = _pdSequence; var bindingSegments = _program.BindingSegments[PipelineBase.UniformSetIndex]; var dummyBuffer = _dummyBuffer?.GetBuffer(); + long updatedBindings = 0; + DescriptorSetTemplateWriter writer = _templateUpdater.Begin(32 * Unsafe.SizeOf()); + foreach (ResourceBindingSegment segment in bindingSegments) { int binding = segment.Binding; int count = segment.Count; - bool doUpdate = false; + ReadOnlySpan uniformBuffers = _uniformBuffers; for (int i = 0; i < count; i++) { @@ -687,16 +1059,28 @@ namespace Ryujinx.Graphics.Vulkan if (_uniformSet.Set(index)) { ref BufferRef buffer = ref _uniformBufferRefs[index]; - UpdateBuffer(cbs, ref _uniformBuffers[index], ref buffer, dummyBuffer, true); - doUpdate = true; + + bool mirrored = UpdateBuffer(cbs, ref _uniformBuffers[index], ref buffer, dummyBuffer, true); + + _uniformMirrored.Set(index, mirrored); + } + + if (_uniformSetPd[index] != sequence) + { + // Need to set this push descriptor (even if the buffer binding has not changed) + + _uniformSetPd[index] = sequence; + updatedBindings |= 1L << index; + + writer.Push(MemoryMarshal.CreateReadOnlySpan(ref _uniformBuffers[index], 1)); } } + } - if (doUpdate) - { - ReadOnlySpan uniformBuffers = _uniformBuffers; - UpdateBuffers(cbs, pbp, binding, uniformBuffers.Slice(binding, count), DescriptorType.UniformBuffer); - } + if (updatedBindings > 0) + { + DescriptorSetTemplate template = _program.GetPushDescriptorTemplate(updatedBindings); + _templateUpdater.CommitPushDescriptor(_gd, cbs, template, _program.PipelineLayout); } } @@ -716,6 +1100,56 @@ namespace Ryujinx.Graphics.Vulkan } } + private void BindExtraSets(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp) + { + for (int setIndex = PipelineBase.DescriptorSetLayouts; setIndex < program.BindingSegments.Length; setIndex++) + { + var bindingSegments = program.BindingSegments[setIndex]; + + if (bindingSegments.Length == 0) + { + continue; + } + + ResourceBindingSegment segment = bindingSegments[0]; + + if (segment.IsArray) + { + DescriptorSet[] sets = null; + + if (segment.Type == ResourceType.Texture || + segment.Type == ResourceType.Sampler || + segment.Type == ResourceType.TextureAndSampler || + segment.Type == ResourceType.BufferTexture) + { + sets = _textureArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets( + _device, + cbs, + _templateUpdater, + program, + setIndex, + _dummyTexture, + _dummySampler); + } + else if (segment.Type == ResourceType.Image || segment.Type == ResourceType.BufferImage) + { + sets = _imageArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets( + _device, + cbs, + _templateUpdater, + program, + setIndex, + _dummyTexture); + } + + if (sets != null) + { + _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan.Empty); + } + } + } + } + public void SignalCommandBufferChange() { _updateDescriptorCacheCbIndex = true; @@ -723,6 +1157,17 @@ namespace Ryujinx.Graphics.Vulkan _uniformSet.Clear(); _storageSet.Clear(); + AdvancePdSequence(); + } + + public void ForceTextureDirty() + { + SignalDirty(DirtyFlags.Texture); + } + + public void ForceImageDirty() + { + SignalDirty(DirtyFlags.Image); } private static void SwapBuffer(BufferRef[] list, Auto from, Auto to) @@ -748,6 +1193,7 @@ namespace Ryujinx.Graphics.Vulkan { _dummyTexture.Dispose(); _dummySampler.Dispose(); + _templateUpdater.Dispose(); } } diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/AreaScalingFilter.cs b/src/Ryujinx.Graphics.Vulkan/Effects/AreaScalingFilter.cs new file mode 100644 index 000000000..87b46df80 --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/Effects/AreaScalingFilter.cs @@ -0,0 +1,101 @@ +using Ryujinx.Common; +using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Shader; +using Ryujinx.Graphics.Shader.Translation; +using Silk.NET.Vulkan; +using System; +using Extent2D = Ryujinx.Graphics.GAL.Extents2D; +using Format = Silk.NET.Vulkan.Format; +using SamplerCreateInfo = Ryujinx.Graphics.GAL.SamplerCreateInfo; + +namespace Ryujinx.Graphics.Vulkan.Effects +{ + internal class AreaScalingFilter : IScalingFilter + { + private readonly VulkanRenderer _renderer; + private PipelineHelperShader _pipeline; + private ISampler _sampler; + private ShaderCollection _scalingProgram; + private Device _device; + + public float Level { get; set; } + + public AreaScalingFilter(VulkanRenderer renderer, Device device) + { + _device = device; + _renderer = renderer; + + Initialize(); + } + + public void Dispose() + { + _pipeline.Dispose(); + _scalingProgram.Dispose(); + _sampler.Dispose(); + } + + public void Initialize() + { + _pipeline = new PipelineHelperShader(_renderer, _device); + + _pipeline.Initialize(); + + var scalingShader = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.spv"); + + var scalingResourceLayout = new ResourceLayoutBuilder() + .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2) + .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1) + .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build(); + + _sampler = _renderer.CreateSampler(SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear)); + + _scalingProgram = _renderer.CreateProgramWithMinimalLayout(new[] + { + new ShaderSource(scalingShader, ShaderStage.Compute, TargetLanguage.Spirv), + }, scalingResourceLayout); + } + + public void Run( + TextureView view, + CommandBufferScoped cbs, + Auto destinationTexture, + Format format, + int width, + int height, + Extent2D source, + Extent2D destination) + { + _pipeline.SetCommandBuffer(cbs); + _pipeline.SetProgram(_scalingProgram); + _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _sampler); + + ReadOnlySpan dimensionsBuffer = stackalloc float[] + { + source.X1, + source.X2, + source.Y1, + source.Y2, + destination.X1, + destination.X2, + destination.Y1, + destination.Y2, + }; + + int rangeSize = dimensionsBuffer.Length * sizeof(float); + using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize); + buffer.Holder.SetDataUnchecked(buffer.Offset, dimensionsBuffer); + + int threadGroupWorkRegionDim = 16; + int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; + int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; + + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); + _pipeline.SetImage(0, destinationTexture); + _pipeline.DispatchCompute(dispatchX, dispatchY, 1); + _pipeline.ComputeBarrier(); + + _pipeline.Finish(); + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs b/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs index 23acdcf8f..080dde5e5 100644 --- a/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs +++ b/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs @@ -59,14 +59,14 @@ namespace Ryujinx.Graphics.Vulkan.Effects var scalingResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2) .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1) - .Add(ResourceStages.Compute, ResourceType.Image, 0).Build(); + .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build(); var sharpeningResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2) .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 3) .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 4) .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1) - .Add(ResourceStages.Compute, ResourceType.Image, 0).Build(); + .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build(); _sampler = _renderer.CreateSampler(SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear)); @@ -142,36 +142,31 @@ namespace Ryujinx.Graphics.Vulkan.Effects }; int rangeSize = dimensionsBuffer.Length * sizeof(float); - var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize); - _renderer.BufferManager.SetData(bufferHandle, 0, dimensionsBuffer); + using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize); + buffer.Holder.SetDataUnchecked(buffer.Offset, dimensionsBuffer); - ReadOnlySpan sharpeningBuffer = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f) }; - var sharpeningBufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, sizeof(float)); - _renderer.BufferManager.SetData(sharpeningBufferHandle, 0, sharpeningBuffer); + ReadOnlySpan sharpeningBufferData = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f) }; + using var sharpeningBuffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, sizeof(float)); + sharpeningBuffer.Holder.SetDataUnchecked(sharpeningBuffer.Offset, sharpeningBufferData); int threadGroupWorkRegionDim = 16; int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; - var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) }); - _pipeline.SetImage(0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); + _pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format))); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.ComputeBarrier(); // Sharpening pass _pipeline.SetProgram(_sharpeningProgram); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _intermediaryTexture, _sampler); - var sharpeningRange = new BufferRange(sharpeningBufferHandle, 0, sizeof(float)); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningRange) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningBuffer.Range) }); _pipeline.SetImage(0, destinationTexture); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.ComputeBarrier(); _pipeline.Finish(); - - _renderer.BufferManager.Delete(bufferHandle); - _renderer.BufferManager.Delete(sharpeningBufferHandle); } } } diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs index 67e461e51..26314b7bf 100644 --- a/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs +++ b/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs @@ -42,7 +42,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects var resourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2) .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1) - .Add(ResourceStages.Compute, ResourceType.Image, 0).Build(); + .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build(); _samplerLinear = _renderer.CreateSampler(SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear)); @@ -66,20 +66,18 @@ namespace Ryujinx.Graphics.Vulkan.Effects ReadOnlySpan resolutionBuffer = stackalloc float[] { view.Width, view.Height }; int rangeSize = resolutionBuffer.Length * sizeof(float); - var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize); + using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize); - _renderer.BufferManager.SetData(bufferHandle, 0, resolutionBuffer); + buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer); - var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize); var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize); - _pipeline.SetImage(0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); + _pipeline.SetImage(ShaderStage.Compute, 0, _texture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format))); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); - _renderer.BufferManager.Delete(bufferHandle); _pipeline.ComputeBarrier(); _pipeline.Finish(); diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.glsl b/src/Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.glsl new file mode 100644 index 000000000..e34dd77dd --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.glsl @@ -0,0 +1,122 @@ +// Scaling + +#version 430 core +layout (local_size_x = 16, local_size_y = 16) in; +layout( rgba8, binding = 0, set = 3) uniform image2D imgOutput; +layout( binding = 1, set = 2) uniform sampler2D Source; +layout( binding = 2 ) uniform dimensions{ + float srcX0; + float srcX1; + float srcY0; + float srcY1; + float dstX0; + float dstX1; + float dstY0; + float dstY1; +}; + +/***** Area Sampling *****/ + +// By Sam Belliveau and Filippo Tarpini. Public Domain license. +// Effectively a more accurate sharp bilinear filter when upscaling, +// that also works as a mathematically perfect downscale filter. +// https://entropymine.com/imageworsener/pixelmixing/ +// https://github.com/obsproject/obs-studio/pull/1715 +// https://legacy.imagemagick.org/Usage/filter/ +vec4 AreaSampling(vec2 xy) +{ + // Determine the sizes of the source and target images. + vec2 source_size = vec2(abs(srcX1 - srcX0), abs(srcY1 - srcY0)); + vec2 target_size = vec2(abs(dstX1 - dstX0), abs(dstY1 - dstY0)); + vec2 inverted_target_size = vec2(1.0) / target_size; + + // Compute the top-left and bottom-right corners of the target pixel box. + vec2 t_beg = floor(xy - vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1)); + vec2 t_end = t_beg + vec2(1.0, 1.0); + + // Convert the target pixel box to source pixel box. + vec2 beg = t_beg * inverted_target_size * source_size; + vec2 end = t_end * inverted_target_size * source_size; + + // Compute the top-left and bottom-right corners of the pixel box. + ivec2 f_beg = ivec2(beg); + ivec2 f_end = ivec2(end); + + // Compute how much of the start and end pixels are covered horizontally & vertically. + float area_w = 1.0 - fract(beg.x); + float area_n = 1.0 - fract(beg.y); + float area_e = fract(end.x); + float area_s = fract(end.y); + + // Compute the areas of the corner pixels in the pixel box. + float area_nw = area_n * area_w; + float area_ne = area_n * area_e; + float area_sw = area_s * area_w; + float area_se = area_s * area_e; + + // Initialize the color accumulator. + vec4 avg_color = vec4(0.0, 0.0, 0.0, 0.0); + + // Accumulate corner pixels. + avg_color += area_nw * texelFetch(Source, ivec2(f_beg.x, f_beg.y), 0); + avg_color += area_ne * texelFetch(Source, ivec2(f_end.x, f_beg.y), 0); + avg_color += area_sw * texelFetch(Source, ivec2(f_beg.x, f_end.y), 0); + avg_color += area_se * texelFetch(Source, ivec2(f_end.x, f_end.y), 0); + + // Determine the size of the pixel box. + int x_range = int(f_end.x - f_beg.x - 0.5); + int y_range = int(f_end.y - f_beg.y - 0.5); + + // Accumulate top and bottom edge pixels. + for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) + { + avg_color += area_n * texelFetch(Source, ivec2(x, f_beg.y), 0); + avg_color += area_s * texelFetch(Source, ivec2(x, f_end.y), 0); + } + + // Accumulate left and right edge pixels and all the pixels in between. + for (int y = f_beg.y + 1; y <= f_beg.y + y_range; ++y) + { + avg_color += area_w * texelFetch(Source, ivec2(f_beg.x, y), 0); + avg_color += area_e * texelFetch(Source, ivec2(f_end.x, y), 0); + + for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) + { + avg_color += texelFetch(Source, ivec2(x, y), 0); + } + } + + // Compute the area of the pixel box that was sampled. + float area_corners = area_nw + area_ne + area_sw + area_se; + float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e); + float area_center = float(x_range) * float(y_range); + + // Return the normalized average color. + return avg_color / (area_corners + area_edges + area_center); +} + +float insideBox(vec2 v, vec2 bLeft, vec2 tRight) { + vec2 s = step(bLeft, v) - step(tRight, v); + return s.x * s.y; +} + +vec2 translateDest(vec2 pos) { + vec2 translatedPos = vec2(pos.x, pos.y); + translatedPos.x = dstX1 < dstX0 ? dstX1 - translatedPos.x : translatedPos.x; + translatedPos.y = dstY0 < dstY1 ? dstY1 + dstY0 - translatedPos.y - 1 : translatedPos.y; + return translatedPos; +} + +void main() +{ + vec2 bLeft = vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1); + vec2 tRight = vec2(dstX1 > dstX0 ? dstX1 : dstX0, dstY1 > dstY0 ? dstY1 : dstY0); + ivec2 loc = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y); + if (insideBox(loc, bLeft, tRight) == 0) { + imageStore(imgOutput, loc, vec4(0, 0, 0, 1)); + return; + } + + vec4 outColor = AreaSampling(loc); + imageStore(imgOutput, ivec2(translateDest(loc)), vec4(outColor.rgb, 1)); +} diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.spv b/src/Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.spv new file mode 100644 index 0000000000000000000000000000000000000000..7d097280f0c781e90318832e0a3cc8463a8beb08 GIT binary patch literal 12428 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 C(9DGZ literal 0 HcmV?d00001 diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs index c521f2273..a8e68f429 100644 --- a/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs +++ b/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs @@ -81,20 +81,20 @@ namespace Ryujinx.Graphics.Vulkan.Effects var edgeResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2) .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1) - .Add(ResourceStages.Compute, ResourceType.Image, 0).Build(); + .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build(); var blendResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2) .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1) .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 3) .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 4) - .Add(ResourceStages.Compute, ResourceType.Image, 0).Build(); + .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build(); var neighbourResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2) .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1) .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 3) - .Add(ResourceStages.Compute, ResourceType.Image, 0).Build(); + .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build(); _samplerLinear = _renderer.CreateSampler(SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear)); @@ -174,8 +174,8 @@ namespace Ryujinx.Graphics.Vulkan.Effects SwizzleComponent.Blue, SwizzleComponent.Alpha); - var areaTexture = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Textures/SmaaAreaTexture.bin"); - var searchTexture = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Textures/SmaaSearchTexture.bin"); + var areaTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.Vulkan/Effects/Textures/SmaaAreaTexture.bin"); + var searchTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.Vulkan/Effects/Textures/SmaaSearchTexture.bin"); _areaTexture = _renderer.CreateTexture(areaInfo) as TextureView; _searchTexture = _renderer.CreateTexture(searchInfo) as TextureView; @@ -215,12 +215,11 @@ namespace Ryujinx.Graphics.Vulkan.Effects ReadOnlySpan resolutionBuffer = stackalloc float[] { view.Width, view.Height }; int rangeSize = resolutionBuffer.Length * sizeof(float); - var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize); + using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize); - _renderer.BufferManager.SetData(bufferHandle, 0, resolutionBuffer); - var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) }); - _pipeline.SetImage(0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); + buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); + _pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format))); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.ComputeBarrier(); @@ -230,7 +229,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _edgeOutputTexture, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _areaTexture, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 4, _searchTexture, _samplerLinear); - _pipeline.SetImage(0, _blendOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); + _pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format))); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.ComputeBarrier(); @@ -239,14 +238,12 @@ namespace Ryujinx.Graphics.Vulkan.Effects _pipeline.Specialize(_specConstants); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _blendOutputTexture, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear); - _pipeline.SetImage(0, _outputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); + _pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format))); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.ComputeBarrier(); _pipeline.Finish(); - _renderer.BufferManager.Delete(bufferHandle); - return _outputTexture; } @@ -260,7 +257,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects scissors[0] = new Rectangle(0, 0, texture.Width, texture.Height); - _pipeline.SetRenderTarget(texture.GetImageViewForAttachment(), (uint)texture.Width, (uint)texture.Height, false, texture.VkFormat); + _pipeline.SetRenderTarget(texture, (uint)texture.Width, (uint)texture.Height); _pipeline.SetRenderTargetColorMasks(colorMasks); _pipeline.SetScissors(scissors); _pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f)); diff --git a/src/Ryujinx.Graphics.Vulkan/EnumConversion.cs b/src/Ryujinx.Graphics.Vulkan/EnumConversion.cs index e10027057..9d1fd9ffd 100644 --- a/src/Ryujinx.Graphics.Vulkan/EnumConversion.cs +++ b/src/Ryujinx.Graphics.Vulkan/EnumConversion.cs @@ -376,7 +376,7 @@ namespace Ryujinx.Graphics.Vulkan { return format switch { - Format.D16Unorm or Format.D32Float => ImageAspectFlags.DepthBit, + Format.D16Unorm or Format.D32Float or Format.X8UintD24Unorm => ImageAspectFlags.DepthBit, Format.S8Uint => ImageAspectFlags.StencilBit, Format.D24UnormS8Uint or Format.D32FloatS8Uint or @@ -389,7 +389,7 @@ namespace Ryujinx.Graphics.Vulkan { return format switch { - Format.D16Unorm or Format.D32Float => ImageAspectFlags.DepthBit, + Format.D16Unorm or Format.D32Float or Format.X8UintD24Unorm => ImageAspectFlags.DepthBit, Format.S8Uint => ImageAspectFlags.StencilBit, Format.D24UnormS8Uint or Format.D32FloatS8Uint or @@ -424,10 +424,20 @@ namespace Ryujinx.Graphics.Vulkan public static BufferAllocationType Convert(this BufferAccess access) { - if (access.HasFlag(BufferAccess.FlushPersistent) || access.HasFlag(BufferAccess.Stream)) + BufferAccess memType = access & BufferAccess.MemoryTypeMask; + + if (memType == BufferAccess.HostMemory || access.HasFlag(BufferAccess.Stream)) { return BufferAllocationType.HostMapped; } + else if (memType == BufferAccess.DeviceMemory) + { + return BufferAllocationType.DeviceLocal; + } + else if (memType == BufferAccess.DeviceMemoryMapped) + { + return BufferAllocationType.DeviceLocalMapped; + } return BufferAllocationType.Auto; } diff --git a/src/Ryujinx.Graphics.Vulkan/FeedbackLoopAspects.cs b/src/Ryujinx.Graphics.Vulkan/FeedbackLoopAspects.cs new file mode 100644 index 000000000..22f73679d --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/FeedbackLoopAspects.cs @@ -0,0 +1,12 @@ +using System; + +namespace Ryujinx.Graphics.Vulkan +{ + [Flags] + internal enum FeedbackLoopAspects + { + None = 0, + Color = 1 << 0, + Depth = 1 << 1, + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/FenceHolder.cs b/src/Ryujinx.Graphics.Vulkan/FenceHolder.cs index 4f0a87160..0cdb93f20 100644 --- a/src/Ryujinx.Graphics.Vulkan/FenceHolder.cs +++ b/src/Ryujinx.Graphics.Vulkan/FenceHolder.cs @@ -10,12 +10,15 @@ namespace Ryujinx.Graphics.Vulkan private readonly Device _device; private Fence _fence; private int _referenceCount; + private int _lock; + private readonly bool _concurrentWaitUnsupported; private bool _disposed; - public unsafe FenceHolder(Vk api, Device device) + public unsafe FenceHolder(Vk api, Device device, bool concurrentWaitUnsupported) { _api = api; _device = device; + _concurrentWaitUnsupported = concurrentWaitUnsupported; var fenceCreateInfo = new FenceCreateInfo { @@ -47,6 +50,11 @@ namespace Ryujinx.Graphics.Vulkan } while (Interlocked.CompareExchange(ref _referenceCount, lastValue + 1, lastValue) != lastValue); + if (_concurrentWaitUnsupported) + { + AcquireLock(); + } + fence = _fence; return true; } @@ -57,6 +65,16 @@ namespace Ryujinx.Graphics.Vulkan return _fence; } + public void PutLock() + { + Put(); + + if (_concurrentWaitUnsupported) + { + ReleaseLock(); + } + } + public void Put() { if (Interlocked.Decrement(ref _referenceCount) == 0) @@ -66,24 +84,67 @@ namespace Ryujinx.Graphics.Vulkan } } + private void AcquireLock() + { + while (!TryAcquireLock()) + { + Thread.SpinWait(32); + } + } + + private bool TryAcquireLock() + { + return Interlocked.Exchange(ref _lock, 1) == 0; + } + + private void ReleaseLock() + { + Interlocked.Exchange(ref _lock, 0); + } + public void Wait() { - Span fences = stackalloc Fence[] + if (_concurrentWaitUnsupported) { - _fence, - }; + AcquireLock(); - FenceHelper.WaitAllIndefinitely(_api, _device, fences); + try + { + FenceHelper.WaitAllIndefinitely(_api, _device, stackalloc Fence[] { _fence }); + } + finally + { + ReleaseLock(); + } + } + else + { + FenceHelper.WaitAllIndefinitely(_api, _device, stackalloc Fence[] { _fence }); + } } public bool IsSignaled() { - Span fences = stackalloc Fence[] + if (_concurrentWaitUnsupported) { - _fence, - }; + if (!TryAcquireLock()) + { + return false; + } - return FenceHelper.AllSignaled(_api, _device, fences); + try + { + return FenceHelper.AllSignaled(_api, _device, stackalloc Fence[] { _fence }); + } + finally + { + ReleaseLock(); + } + } + else + { + return FenceHelper.AllSignaled(_api, _device, stackalloc Fence[] { _fence }); + } } public void Dispose() diff --git a/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs b/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs index 7307a0ee0..9ea8cec4b 100644 --- a/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs +++ b/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs @@ -220,7 +220,7 @@ namespace Ryujinx.Graphics.Vulkan public static bool IsD24S8(Format format) { - return format == Format.D24UnormS8Uint || format == Format.S8UintD24Unorm; + return format == Format.D24UnormS8Uint || format == Format.S8UintD24Unorm || format == Format.X8UintD24Unorm; } private static bool IsRGB16IntFloat(Format format) diff --git a/src/Ryujinx.Graphics.Vulkan/FormatTable.cs b/src/Ryujinx.Graphics.Vulkan/FormatTable.cs index 5f767df16..98796d9bf 100644 --- a/src/Ryujinx.Graphics.Vulkan/FormatTable.cs +++ b/src/Ryujinx.Graphics.Vulkan/FormatTable.cs @@ -1,5 +1,6 @@ using Ryujinx.Graphics.GAL; using System; +using System.Collections.Generic; using VkFormat = Silk.NET.Vulkan.Format; namespace Ryujinx.Graphics.Vulkan @@ -7,10 +8,12 @@ namespace Ryujinx.Graphics.Vulkan static class FormatTable { private static readonly VkFormat[] _table; + private static readonly Dictionary _reverseMap; static FormatTable() { _table = new VkFormat[Enum.GetNames(typeof(Format)).Length]; + _reverseMap = new Dictionary(); #pragma warning disable IDE0055 // Disable formatting Add(Format.R8Unorm, VkFormat.R8Unorm); @@ -64,6 +67,7 @@ namespace Ryujinx.Graphics.Vulkan Add(Format.S8Uint, VkFormat.S8Uint); Add(Format.D16Unorm, VkFormat.D16Unorm); Add(Format.S8UintD24Unorm, VkFormat.D24UnormS8Uint); + Add(Format.X8UintD24Unorm, VkFormat.X8D24UnormPack32); Add(Format.D32Float, VkFormat.D32Sfloat); Add(Format.D24UnormS8Uint, VkFormat.D24UnormS8Uint); Add(Format.D32FloatS8Uint, VkFormat.D32SfloatS8Uint); @@ -158,12 +162,14 @@ namespace Ryujinx.Graphics.Vulkan Add(Format.A1B5G5R5Unorm, VkFormat.R5G5B5A1UnormPack16); Add(Format.B8G8R8A8Unorm, VkFormat.B8G8R8A8Unorm); Add(Format.B8G8R8A8Srgb, VkFormat.B8G8R8A8Srgb); + Add(Format.B10G10R10A2Unorm, VkFormat.A2R10G10B10UnormPack32); #pragma warning restore IDE0055 } private static void Add(Format format, VkFormat vkFormat) { _table[(int)format] = vkFormat; + _reverseMap[vkFormat] = format; } public static VkFormat GetFormat(Format format) @@ -171,6 +177,16 @@ namespace Ryujinx.Graphics.Vulkan return _table[(int)format]; } + public static Format GetFormat(VkFormat format) + { + if (!_reverseMap.TryGetValue(format, out Format result)) + { + return Format.B8G8R8A8Unorm; + } + + return result; + } + public static Format ConvertRgba8SrgbToUnorm(Format format) { return format switch diff --git a/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs b/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs index 458a16464..8d80e9d05 100644 --- a/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs +++ b/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs @@ -12,6 +12,8 @@ namespace Ryujinx.Graphics.Vulkan private readonly Auto[] _attachments; private readonly TextureView[] _colors; private readonly TextureView _depthStencil; + private readonly TextureView[] _colorsCanonical; + private readonly TextureView _baseAttachment; private readonly uint _validColorAttachments; public uint Width { get; } @@ -22,32 +24,43 @@ namespace Ryujinx.Graphics.Vulkan public VkFormat[] AttachmentFormats { get; } public int[] AttachmentIndices { get; } public uint AttachmentIntegerFormatMask { get; } + public bool LogicOpsAllowed { get; } public int AttachmentsCount { get; } public int MaxColorAttachmentIndex => AttachmentIndices.Length > 0 ? AttachmentIndices[^1] : -1; public bool HasDepthStencil { get; } public int ColorAttachmentsCount => AttachmentsCount - (HasDepthStencil ? 1 : 0); - public FramebufferParams( - Device device, - Auto view, - uint width, - uint height, - uint samples, - bool isDepthStencil, - VkFormat format) + public FramebufferParams(Device device, TextureView view, uint width, uint height) { + var format = view.Info.Format; + + bool isDepthStencil = format.IsDepthOrStencil(); + _device = device; - _attachments = new[] { view }; + _attachments = new[] { view.GetImageViewForAttachment() }; _validColorAttachments = isDepthStencil ? 0u : 1u; + _baseAttachment = view; + + if (isDepthStencil) + { + _depthStencil = view; + } + else + { + _colors = new TextureView[] { view }; + _colorsCanonical = _colors; + } Width = width; Height = height; Layers = 1; - AttachmentSamples = new[] { samples }; - AttachmentFormats = new[] { format }; + AttachmentSamples = new[] { (uint)view.Info.Samples }; + AttachmentFormats = new[] { view.VkFormat }; AttachmentIndices = isDepthStencil ? Array.Empty() : new[] { 0 }; + AttachmentIntegerFormatMask = format.IsInteger() ? 1u : 0u; + LogicOpsAllowed = !format.IsFloatOrSrgb(); AttachmentsCount = 1; @@ -64,6 +77,7 @@ namespace Ryujinx.Graphics.Vulkan _attachments = new Auto[count]; _colors = new TextureView[colorsCount]; + _colorsCanonical = colors.Select(color => color is TextureView view && view.Valid ? view : null).ToArray(); AttachmentSamples = new uint[count]; AttachmentFormats = new VkFormat[count]; @@ -76,6 +90,7 @@ namespace Ryujinx.Graphics.Vulkan int index = 0; int bindIndex = 0; uint attachmentIntegerFormatMask = 0; + bool allFormatsFloatOrSrgb = colorsCount != 0; foreach (ITexture color in colors) { @@ -86,16 +101,21 @@ namespace Ryujinx.Graphics.Vulkan _attachments[index] = texture.GetImageViewForAttachment(); _colors[index] = texture; _validColorAttachments |= 1u << bindIndex; + _baseAttachment = texture; AttachmentSamples[index] = (uint)texture.Info.Samples; AttachmentFormats[index] = texture.VkFormat; AttachmentIndices[index] = bindIndex; - if (texture.Info.Format.IsInteger()) + var format = texture.Info.Format; + + if (format.IsInteger()) { attachmentIntegerFormatMask |= 1u << bindIndex; } + allFormatsFloatOrSrgb &= format.IsFloatOrSrgb(); + width = Math.Min(width, (uint)texture.Width); height = Math.Min(height, (uint)texture.Height); layers = Math.Min(layers, (uint)texture.Layers); @@ -110,11 +130,13 @@ namespace Ryujinx.Graphics.Vulkan } AttachmentIntegerFormatMask = attachmentIntegerFormatMask; + LogicOpsAllowed = !allFormatsFloatOrSrgb; if (depthStencil is TextureView dsTexture && dsTexture.Valid) { _attachments[count - 1] = dsTexture.GetImageViewForAttachment(); _depthStencil = dsTexture; + _baseAttachment ??= dsTexture; AttachmentSamples[count - 1] = (uint)dsTexture.Info.Samples; AttachmentFormats[count - 1] = dsTexture.VkFormat; @@ -228,51 +250,95 @@ namespace Ryujinx.Graphics.Vulkan Layers = Layers, }; - api.CreateFramebuffer(_device, framebufferCreateInfo, null, out var framebuffer).ThrowOnError(); + api.CreateFramebuffer(_device, in framebufferCreateInfo, null, out var framebuffer).ThrowOnError(); return new Auto(new DisposableFramebuffer(api, _device, framebuffer), null, _attachments); } - public void UpdateModifications() + public TextureView[] GetAttachmentViews() + { + var result = new TextureView[_attachments.Length]; + + _colors?.CopyTo(result, 0); + + if (_depthStencil != null) + { + result[^1] = _depthStencil; + } + + return result; + } + + public RenderPassCacheKey GetRenderPassCacheKey() + { + return new RenderPassCacheKey(_depthStencil, _colorsCanonical); + } + + public void InsertLoadOpBarriers(VulkanRenderer gd, CommandBufferScoped cbs) { if (_colors != null) { - for (int index = 0; index < _colors.Length; index++) + foreach (var color in _colors) { - _colors[index].Storage.SetModification( - AccessFlags.ColorAttachmentWriteBit, - PipelineStageFlags.ColorAttachmentOutputBit); + // If Clear or DontCare were used, this would need to be write bit. + color.Storage?.QueueLoadOpBarrier(cbs, false); } } - _depthStencil?.Storage.SetModification( - AccessFlags.DepthStencilAttachmentWriteBit, - PipelineStageFlags.LateFragmentTestsBit); + _depthStencil?.Storage?.QueueLoadOpBarrier(cbs, true); + + gd.Barriers.Flush(cbs, false, null, null); } - public void InsertClearBarrier(CommandBufferScoped cbs, int index) + public void AddStoreOpUsage() { if (_colors != null) { - int realIndex = Array.IndexOf(AttachmentIndices, index); - - if (realIndex != -1) + foreach (var color in _colors) { - _colors[realIndex].Storage?.InsertReadToWriteBarrier( - cbs, - AccessFlags.ColorAttachmentWriteBit, - PipelineStageFlags.ColorAttachmentOutputBit, - insideRenderPass: true); + color.Storage?.AddStoreOpUsage(false); } } + + _depthStencil?.Storage?.AddStoreOpUsage(true); + } + + public void ClearBindings() + { + _depthStencil?.Storage.ClearBindings(); + + for (int i = 0; i < _colorsCanonical.Length; i++) + { + _colorsCanonical[i]?.Storage.ClearBindings(); + } } - public void InsertClearBarrierDS(CommandBufferScoped cbs) + public void AddBindings() { - _depthStencil?.Storage?.InsertReadToWriteBarrier( - cbs, - AccessFlags.DepthStencilAttachmentWriteBit, - PipelineStageFlags.LateFragmentTestsBit, - insideRenderPass: true); + _depthStencil?.Storage.AddBinding(_depthStencil); + + for (int i = 0; i < _colorsCanonical.Length; i++) + { + TextureView color = _colorsCanonical[i]; + color?.Storage.AddBinding(color); + } + } + + public (RenderPassHolder rpHolder, Auto framebuffer) GetPassAndFramebuffer( + VulkanRenderer gd, + Device device, + CommandBufferScoped cbs) + { + return _baseAttachment.GetPassAndFramebuffer(gd, device, cbs, this); + } + + public TextureView GetColorView(int index) + { + return _colorsCanonical[index]; + } + + public TextureView GetDepthStencilView() + { + return _depthStencil; } } } diff --git a/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs b/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs index f6120c9dc..e4d4b0adc 100644 --- a/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs +++ b/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs @@ -34,6 +34,7 @@ namespace Ryujinx.Graphics.Vulkan public readonly bool SupportsMultiView; public readonly bool SupportsNullDescriptors; public readonly bool SupportsPushDescriptors; + public readonly uint MaxPushDescriptors; public readonly bool SupportsPrimitiveTopologyListRestart; public readonly bool SupportsPrimitiveTopologyPatchListRestart; public readonly bool SupportsTransformFeedback; @@ -45,6 +46,8 @@ namespace Ryujinx.Graphics.Vulkan public readonly bool SupportsViewportArray2; public readonly bool SupportsHostImportedMemory; public readonly bool SupportsDepthClipControl; + public readonly bool SupportsAttachmentFeedbackLoop; + public readonly bool SupportsDynamicAttachmentFeedbackLoop; public readonly uint SubgroupSize; public readonly SampleCountFlags SupportedSampleCounts; public readonly PortabilitySubsetFlags PortabilitySubset; @@ -71,6 +74,7 @@ namespace Ryujinx.Graphics.Vulkan bool supportsMultiView, bool supportsNullDescriptors, bool supportsPushDescriptors, + uint maxPushDescriptors, bool supportsPrimitiveTopologyListRestart, bool supportsPrimitiveTopologyPatchListRestart, bool supportsTransformFeedback, @@ -82,6 +86,8 @@ namespace Ryujinx.Graphics.Vulkan bool supportsViewportArray2, bool supportsHostImportedMemory, bool supportsDepthClipControl, + bool supportsAttachmentFeedbackLoop, + bool supportsDynamicAttachmentFeedbackLoop, uint subgroupSize, SampleCountFlags supportedSampleCounts, PortabilitySubsetFlags portabilitySubset, @@ -107,6 +113,7 @@ namespace Ryujinx.Graphics.Vulkan SupportsMultiView = supportsMultiView; SupportsNullDescriptors = supportsNullDescriptors; SupportsPushDescriptors = supportsPushDescriptors; + MaxPushDescriptors = maxPushDescriptors; SupportsPrimitiveTopologyListRestart = supportsPrimitiveTopologyListRestart; SupportsPrimitiveTopologyPatchListRestart = supportsPrimitiveTopologyPatchListRestart; SupportsTransformFeedback = supportsTransformFeedback; @@ -118,6 +125,8 @@ namespace Ryujinx.Graphics.Vulkan SupportsViewportArray2 = supportsViewportArray2; SupportsHostImportedMemory = supportsHostImportedMemory; SupportsDepthClipControl = supportsDepthClipControl; + SupportsAttachmentFeedbackLoop = supportsAttachmentFeedbackLoop; + SupportsDynamicAttachmentFeedbackLoop = supportsDynamicAttachmentFeedbackLoop; SubgroupSize = subgroupSize; SupportedSampleCounts = supportedSampleCounts; PortabilitySubset = portabilitySubset; diff --git a/src/Ryujinx.Graphics.Vulkan/HashTableSlim.cs b/src/Ryujinx.Graphics.Vulkan/HashTableSlim.cs index ff4eb7890..3796e3c52 100644 --- a/src/Ryujinx.Graphics.Vulkan/HashTableSlim.cs +++ b/src/Ryujinx.Graphics.Vulkan/HashTableSlim.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Ryujinx.Graphics.Vulkan { @@ -20,20 +21,29 @@ namespace Ryujinx.Graphics.Vulkan public TValue Value; } - private readonly Entry[][] _hashTable = new Entry[TotalBuckets][]; + private struct Bucket + { + public int Length; + public Entry[] Entries; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Span AsSpan() + { + return Entries == null ? Span.Empty : Entries.AsSpan(0, Length); + } + } + + private readonly Bucket[] _hashTable = new Bucket[TotalBuckets]; public IEnumerable Keys { get { - foreach (Entry[] bucket in _hashTable) + foreach (Bucket bucket in _hashTable) { - if (bucket != null) + for (int i = 0; i < bucket.Length; i++) { - foreach (Entry entry in bucket) - { - yield return entry.Key; - } + yield return bucket.Entries[i].Key; } } } @@ -43,14 +53,11 @@ namespace Ryujinx.Graphics.Vulkan { get { - foreach (Entry[] bucket in _hashTable) + foreach (Bucket bucket in _hashTable) { - if (bucket != null) + for (int i = 0; i < bucket.Length; i++) { - foreach (Entry entry in bucket) - { - yield return entry.Value; - } + yield return bucket.Entries[i].Value; } } } @@ -68,40 +75,64 @@ namespace Ryujinx.Graphics.Vulkan int hashCode = key.GetHashCode(); int bucketIndex = hashCode & TotalBucketsMask; - var bucket = _hashTable[bucketIndex]; - if (bucket != null) + ref var bucket = ref _hashTable[bucketIndex]; + if (bucket.Entries != null) { int index = bucket.Length; - Array.Resize(ref _hashTable[bucketIndex], index + 1); + if (index >= bucket.Entries.Length) + { + Array.Resize(ref bucket.Entries, index + 1); + } - _hashTable[bucketIndex][index] = entry; + bucket.Entries[index] = entry; } else { - _hashTable[bucketIndex] = new[] + bucket.Entries = new[] { entry, }; } + + bucket.Length++; + } + + public bool Remove(ref TKey key) + { + int hashCode = key.GetHashCode(); + + ref var bucket = ref _hashTable[hashCode & TotalBucketsMask]; + var entries = bucket.AsSpan(); + for (int i = 0; i < entries.Length; i++) + { + ref var entry = ref entries[i]; + + if (entry.Hash == hashCode && entry.Key.Equals(ref key)) + { + entries[(i + 1)..].CopyTo(entries[i..]); + bucket.Length--; + + return true; + } + } + + return false; } public bool TryGetValue(ref TKey key, out TValue value) { int hashCode = key.GetHashCode(); - var bucket = _hashTable[hashCode & TotalBucketsMask]; - if (bucket != null) + var entries = _hashTable[hashCode & TotalBucketsMask].AsSpan(); + for (int i = 0; i < entries.Length; i++) { - for (int i = 0; i < bucket.Length; i++) - { - ref var entry = ref bucket[i]; + ref var entry = ref entries[i]; - if (entry.Hash == hashCode && entry.Key.Equals(ref key)) - { - value = entry.Value; - return true; - } + if (entry.Hash == hashCode && entry.Key.Equals(ref key)) + { + value = entry.Value; + return true; } } diff --git a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs index deaf81625..b7c42aff0 100644 --- a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -115,7 +115,7 @@ namespace Ryujinx.Graphics.Vulkan var strideChangeResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 0) .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1) - .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2).Build(); + .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2, true).Build(); _programStrideChange = gd.CreateProgramWithMinimalLayout(new[] { @@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Vulkan var colorCopyResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 0) .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 0) - .Add(ResourceStages.Compute, ResourceType.Image, 0).Build(); + .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build(); _programColorCopyShortening = gd.CreateProgramWithMinimalLayout(new[] { @@ -155,7 +155,7 @@ namespace Ryujinx.Graphics.Vulkan var convertD32S8ToD24S8ResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 0) .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1) - .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2).Build(); + .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2, true).Build(); _programConvertD32S8ToD24S8 = gd.CreateProgramWithMinimalLayout(new[] { @@ -165,7 +165,7 @@ namespace Ryujinx.Graphics.Vulkan var convertIndexBufferResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 0) .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1) - .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2).Build(); + .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2, true).Build(); _programConvertIndexBuffer = gd.CreateProgramWithMinimalLayout(new[] { @@ -175,7 +175,7 @@ namespace Ryujinx.Graphics.Vulkan var convertIndirectDataResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 0) .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1) - .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2) + .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2, true) .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 3).Build(); _programConvertIndirectData = gd.CreateProgramWithMinimalLayout(new[] @@ -256,17 +256,8 @@ namespace Ryujinx.Graphics.Vulkan using var cbs = gd.CommandBufferPool.Rent(); - var dstFormat = dst.VkFormat; - var dstSamples = dst.Info.Samples; - for (int l = 0; l < levels; l++) { - int srcWidth = Math.Max(1, src.Width >> l); - int srcHeight = Math.Max(1, src.Height >> l); - - int dstWidth = Math.Max(1, dst.Width >> l); - int dstHeight = Math.Max(1, dst.Height >> l); - var mipSrcRegion = new Extents2D( srcRegion.X1 >> l, srcRegion.Y1 >> l, @@ -290,11 +281,7 @@ namespace Ryujinx.Graphics.Vulkan gd, cbs, srcView, - dst.GetImageViewForAttachment(), - dstWidth, - dstHeight, - dstSamples, - dstFormat, + dstView, mipSrcRegion, mipDstRegion); } @@ -304,12 +291,7 @@ namespace Ryujinx.Graphics.Vulkan gd, cbs, srcView, - dst.GetImageViewForAttachment(), - dstWidth, - dstHeight, - dstSamples, - dstFormat, - false, + dstView, mipSrcRegion, mipDstRegion, linearFilter, @@ -367,12 +349,7 @@ namespace Ryujinx.Graphics.Vulkan gd, cbs, srcView, - dstView.GetImageViewForAttachment(), - dstView.Width, - dstView.Height, - dstView.Info.Samples, - dstView.VkFormat, - dstView.Info.Format.IsDepthOrStencil(), + dstView, extents, extents, false); @@ -394,12 +371,7 @@ namespace Ryujinx.Graphics.Vulkan VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, - Auto dst, - int dstWidth, - int dstHeight, - int dstSamples, - VkFormat dstFormat, - bool dstIsDepthOrStencil, + TextureView dst, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter, @@ -430,11 +402,11 @@ namespace Ryujinx.Graphics.Vulkan (region[2], region[3]) = (region[3], region[2]); } - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, RegionBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, region); + buffer.Holder.SetDataUnchecked(buffer.Offset, region); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) }); Span viewports = stackalloc Viewport[1]; @@ -453,6 +425,8 @@ namespace Ryujinx.Graphics.Vulkan 0f, 1f); + bool dstIsDepthOrStencil = dst.Info.Format.IsDepthOrStencil(); + if (dstIsDepthOrStencil) { _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit); @@ -471,7 +445,10 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetProgram(_programColorBlit); } - _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, (uint)dstSamples, dstIsDepthOrStencil, dstFormat); + int dstWidth = dst.Width; + int dstHeight = dst.Height; + + _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight); _pipeline.SetRenderTargetColorMasks(new uint[] { 0xf }); _pipeline.SetScissors(stackalloc Rectangle[] { new Rectangle(0, 0, dstWidth, dstHeight) }); @@ -490,19 +467,13 @@ namespace Ryujinx.Graphics.Vulkan } _pipeline.Finish(gd, cbs); - - gd.BufferManager.Delete(bufferHandle); } private void BlitDepthStencil( VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, - Auto dst, - int dstWidth, - int dstHeight, - int dstSamples, - VkFormat dstFormat, + TextureView dst, Extents2D srcRegion, Extents2D dstRegion) { @@ -527,11 +498,11 @@ namespace Ryujinx.Graphics.Vulkan (region[2], region[3]) = (region[3], region[2]); } - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, RegionBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, region); + buffer.Holder.SetDataUnchecked(buffer.Offset, region); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) }); Span viewports = stackalloc Viewport[1]; @@ -550,7 +521,10 @@ namespace Ryujinx.Graphics.Vulkan 0f, 1f); - _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, (uint)dstSamples, true, dstFormat); + int dstWidth = dst.Width; + int dstHeight = dst.Height; + + _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight); _pipeline.SetScissors(stackalloc Rectangle[] { new Rectangle(0, 0, dstWidth, dstHeight) }); _pipeline.SetViewports(viewports); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); @@ -582,8 +556,6 @@ namespace Ryujinx.Graphics.Vulkan } _pipeline.Finish(gd, cbs); - - gd.BufferManager.Delete(bufferHandle); } private static TextureView CreateDepthOrStencilView(TextureView depthStencilTexture, DepthStencilMode depthStencilMode) @@ -664,12 +636,11 @@ namespace Ryujinx.Graphics.Vulkan public void Clear( VulkanRenderer gd, - Auto dst, + TextureView dst, ReadOnlySpan clearColor, uint componentMask, int dstWidth, int dstHeight, - VkFormat dstFormat, ComponentType type, Rectangle scissor) { @@ -681,11 +652,11 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetCommandBuffer(cbs); - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ClearColorBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, clearColor); + buffer.Holder.SetDataUnchecked(buffer.Offset, clearColor); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, ClearColorBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) }); Span viewports = stackalloc Viewport[1]; @@ -714,20 +685,18 @@ namespace Ryujinx.Graphics.Vulkan } _pipeline.SetProgram(program); - _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat); + _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight); _pipeline.SetRenderTargetColorMasks(new[] { componentMask }); _pipeline.SetViewports(viewports); _pipeline.SetScissors(stackalloc Rectangle[] { scissor }); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); _pipeline.Draw(4, 1, 0, 0); _pipeline.Finish(); - - gd.BufferManager.Delete(bufferHandle); } public void Clear( VulkanRenderer gd, - Auto dst, + TextureView dst, float depthValue, bool depthMask, int stencilValue, @@ -745,11 +714,11 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetCommandBuffer(cbs); - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ClearColorBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, stackalloc float[] { depthValue }); + buffer.Holder.SetDataUnchecked(buffer.Offset, stackalloc float[] { depthValue }); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, ClearColorBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) }); Span viewports = stackalloc Viewport[1]; @@ -763,7 +732,7 @@ namespace Ryujinx.Graphics.Vulkan 1f); _pipeline.SetProgram(_programDepthStencilClear); - _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, true, dstFormat); + _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight); _pipeline.SetViewports(viewports); _pipeline.SetScissors(stackalloc Rectangle[] { scissor }); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); @@ -771,8 +740,6 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xff, stencilMask)); _pipeline.Draw(4, 1, 0, 0); _pipeline.Finish(); - - gd.BufferManager.Delete(bufferHandle); } public void DrawTexture( @@ -878,13 +845,13 @@ namespace Ryujinx.Graphics.Vulkan shaderParams[2] = size; shaderParams[3] = srcOffset; - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, shaderParams); + buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams); _pipeline.SetCommandBuffer(cbs); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) }); Span> sbRanges = new Auto[2]; @@ -896,8 +863,6 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetProgram(_programStrideChange); _pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1); - gd.BufferManager.Delete(bufferHandle); - _pipeline.Finish(gd, cbs); } else @@ -1025,7 +990,7 @@ namespace Ryujinx.Graphics.Vulkan { const int ParamsBufferSize = 4; - Span shaderParams = stackalloc int[sizeof(int)]; + Span shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)]; int srcBpp = src.Info.BytesPerPixel; int dstBpp = dst.Info.BytesPerPixel; @@ -1034,9 +999,9 @@ namespace Ryujinx.Graphics.Vulkan shaderParams[0] = BitOperations.Log2((uint)ratio); - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, shaderParams); + buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams); TextureView.InsertImageBarrier( gd.Api, @@ -1064,7 +1029,7 @@ namespace Ryujinx.Graphics.Vulkan var srcFormat = GetFormat(componentSize, srcBpp / componentSize); var dstFormat = GetFormat(componentSize, dstBpp / componentSize); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) }); for (int l = 0; l < levels; l++) { @@ -1074,7 +1039,7 @@ namespace Ryujinx.Graphics.Vulkan var dstView = Create2DLayerView(dst, dstLayer + z, dstLevel + l); _pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null); - _pipeline.SetImage(0, dstView, dstFormat); + _pipeline.SetImage(ShaderStage.Compute, 0, dstView.GetView(dstFormat)); int dispatchX = (Math.Min(srcView.Info.Width, dstView.Info.Width) + 31) / 32; int dispatchY = (Math.Min(srcView.Info.Height, dstView.Info.Height) + 31) / 32; @@ -1093,8 +1058,6 @@ namespace Ryujinx.Graphics.Vulkan } } - gd.BufferManager.Delete(bufferHandle); - _pipeline.Finish(gd, cbs); TextureView.InsertImageBarrier( @@ -1128,9 +1091,9 @@ namespace Ryujinx.Graphics.Vulkan (shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples); (shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples)); - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, shaderParams); + buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams); TextureView.InsertImageBarrier( gd.Api, @@ -1147,7 +1110,7 @@ namespace Ryujinx.Graphics.Vulkan 1); _pipeline.SetCommandBuffer(cbs); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) }); if (isDepthOrStencil) { @@ -1175,12 +1138,7 @@ namespace Ryujinx.Graphics.Vulkan var srcView = Create2DLayerView(src, srcLayer + z, 0); var dstView = Create2DLayerView(dst, dstLayer + z, 0); - _pipeline.SetRenderTarget( - dstView.GetImageViewForAttachment(), - (uint)dst.Width, - (uint)dst.Height, - true, - dst.VkFormat); + _pipeline.SetRenderTarget(dstView, (uint)dst.Width, (uint)dst.Height); CopyMSDraw(srcView, aspectFlags, fromMS: true); @@ -1210,7 +1168,7 @@ namespace Ryujinx.Graphics.Vulkan var dstView = Create2DLayerView(dst, dstLayer + z, 0); _pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null); - _pipeline.SetImage(0, dstView, format); + _pipeline.SetImage(ShaderStage.Compute, 0, dstView.GetView(format)); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); @@ -1226,8 +1184,6 @@ namespace Ryujinx.Graphics.Vulkan } } - gd.BufferManager.Delete(bufferHandle); - _pipeline.Finish(gd, cbs); TextureView.InsertImageBarrier( @@ -1261,9 +1217,9 @@ namespace Ryujinx.Graphics.Vulkan (shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples); (shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples)); - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, shaderParams); + buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams); TextureView.InsertImageBarrier( gd.Api, @@ -1299,7 +1255,7 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetViewports(viewports); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) }); if (isDepthOrStencil) { @@ -1308,13 +1264,7 @@ namespace Ryujinx.Graphics.Vulkan var srcView = Create2DLayerView(src, srcLayer + z, 0); var dstView = Create2DLayerView(dst, dstLayer + z, 0); - _pipeline.SetRenderTarget( - dstView.GetImageViewForAttachment(), - (uint)dst.Width, - (uint)dst.Height, - (uint)samples, - true, - dst.VkFormat); + _pipeline.SetRenderTarget(dstView, (uint)dst.Width, (uint)dst.Height); CopyMSDraw(srcView, aspectFlags, fromMS: false); @@ -1342,13 +1292,7 @@ namespace Ryujinx.Graphics.Vulkan var dstView = Create2DLayerView(dst, dstLayer + z, 0); _pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Fragment, 0, srcView, null); - _pipeline.SetRenderTarget( - dstView.GetView(format).GetImageViewForAttachment(), - (uint)dst.Width, - (uint)dst.Height, - (uint)samples, - false, - vkFormat); + _pipeline.SetRenderTarget(dstView.GetView(format), (uint)dst.Width, (uint)dst.Height); _pipeline.Draw(4, 1, 0, 0); @@ -1364,8 +1308,6 @@ namespace Ryujinx.Graphics.Vulkan } } - gd.BufferManager.Delete(bufferHandle); - _pipeline.Finish(gd, cbs); TextureView.InsertImageBarrier( @@ -1487,9 +1429,9 @@ namespace Ryujinx.Graphics.Vulkan }; var info = new TextureCreateInfo( - from.Info.Width, - from.Info.Height, - from.Info.Depth, + Math.Max(1, from.Info.Width >> level), + Math.Max(1, from.Info.Height >> level), + 1, 1, from.Info.Samples, from.Info.BlockWidth, @@ -1616,10 +1558,11 @@ namespace Ryujinx.Graphics.Vulkan pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]); - var patternBufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, out var patternBuffer); + using var patternScoped = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); + var patternBuffer = patternScoped.Holder; var patternBufferAuto = patternBuffer.GetBuffer(); - gd.BufferManager.SetData(patternBufferHandle, 0, shaderParams); + patternBuffer.SetDataUnchecked(patternScoped.Offset, shaderParams); _pipeline.SetCommandBuffer(cbs); @@ -1635,7 +1578,8 @@ namespace Ryujinx.Graphics.Vulkan indirectDataSize); _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, drawCountBufferAligned) }); - _pipeline.SetStorageBuffers(1, new[] { srcIndirectBuffer.GetBuffer(), dstIndirectBuffer.GetBuffer(), patternBuffer.GetBuffer() }); + _pipeline.SetStorageBuffers(1, new[] { srcIndirectBuffer.GetBuffer(), dstIndirectBuffer.GetBuffer() }); + _pipeline.SetStorageBuffers(stackalloc[] { new BufferAssignment(3, patternScoped.Range) }); _pipeline.SetProgram(_programConvertIndirectData); _pipeline.DispatchCompute(1, 1, 1); @@ -1643,12 +1587,12 @@ namespace Ryujinx.Graphics.Vulkan BufferHolder.InsertBufferBarrier( gd, cbs.CommandBuffer, - patternBufferAuto.Get(cbs, ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value, + patternBufferAuto.Get(cbs, patternScoped.Offset + ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value, AccessFlags.ShaderWriteBit, AccessFlags.IndirectCommandReadBit, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.DrawIndirectBit, - ParamsIndirectDispatchOffset, + patternScoped.Offset + ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize); BufferHolder.InsertBufferBarrier( @@ -1662,11 +1606,11 @@ namespace Ryujinx.Graphics.Vulkan 0, convertedCount * outputIndexSize); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(patternBufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(patternScoped.Handle, patternScoped.Offset, ParamsBufferSize)) }); _pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() }); _pipeline.SetProgram(_programConvertIndexBuffer); - _pipeline.DispatchComputeIndirect(patternBufferAuto, ParamsIndirectDispatchOffset); + _pipeline.DispatchComputeIndirect(patternBufferAuto, patternScoped.Offset + ParamsIndirectDispatchOffset); BufferHolder.InsertBufferBarrier( gd, @@ -1679,8 +1623,6 @@ namespace Ryujinx.Graphics.Vulkan 0, convertedCount * outputIndexSize); - gd.BufferManager.Delete(patternBufferHandle); - _pipeline.Finish(gd, cbs); } @@ -1726,13 +1668,13 @@ namespace Ryujinx.Graphics.Vulkan shaderParams[0] = pixelCount; shaderParams[1] = dstOffset; - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, shaderParams); + buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams); _pipeline.SetCommandBuffer(cbs); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) }); Span> sbRanges = new Auto[2]; @@ -1744,8 +1686,6 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetProgram(_programConvertD32S8ToD24S8); _pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1); - gd.BufferManager.Delete(bufferHandle); - _pipeline.Finish(gd, cbs); BufferHolder.InsertBufferBarrier( diff --git a/src/Ryujinx.Graphics.Vulkan/HostMemoryAllocator.cs b/src/Ryujinx.Graphics.Vulkan/HostMemoryAllocator.cs index baccc698f..ff1565246 100644 --- a/src/Ryujinx.Graphics.Vulkan/HostMemoryAllocator.cs +++ b/src/Ryujinx.Graphics.Vulkan/HostMemoryAllocator.cs @@ -115,7 +115,7 @@ namespace Ryujinx.Graphics.Vulkan PNext = &importInfo, }; - Result result = _api.AllocateMemory(_device, memoryAllocateInfo, null, out var deviceMemory); + Result result = _api.AllocateMemory(_device, in memoryAllocateInfo, null, out var deviceMemory); if (result < Result.Success) { diff --git a/src/Ryujinx.Graphics.Vulkan/ImageArray.cs b/src/Ryujinx.Graphics.Vulkan/ImageArray.cs new file mode 100644 index 000000000..019286d28 --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/ImageArray.cs @@ -0,0 +1,207 @@ +using Ryujinx.Graphics.GAL; +using Silk.NET.Vulkan; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Vulkan +{ + class ImageArray : ResourceArray, IImageArray + { + private readonly VulkanRenderer _gd; + + private record struct TextureRef + { + public TextureStorage Storage; + public TextureView View; + } + + private readonly TextureRef[] _textureRefs; + private readonly TextureBuffer[] _bufferTextureRefs; + + private readonly DescriptorImageInfo[] _textures; + private readonly BufferView[] _bufferTextures; + + private HashSet _storages; + + private int _cachedCommandBufferIndex; + private int _cachedSubmissionCount; + + private readonly bool _isBuffer; + + public ImageArray(VulkanRenderer gd, int size, bool isBuffer) + { + _gd = gd; + + if (isBuffer) + { + _bufferTextureRefs = new TextureBuffer[size]; + _bufferTextures = new BufferView[size]; + } + else + { + _textureRefs = new TextureRef[size]; + _textures = new DescriptorImageInfo[size]; + } + + _storages = null; + + _cachedCommandBufferIndex = -1; + _cachedSubmissionCount = 0; + + _isBuffer = isBuffer; + } + + public void SetImages(int index, ITexture[] images) + { + for (int i = 0; i < images.Length; i++) + { + ITexture image = images[i]; + + if (image is TextureBuffer textureBuffer) + { + _bufferTextureRefs[index + i] = textureBuffer; + } + else if (image is TextureView view) + { + _textureRefs[index + i].Storage = view.Storage; + _textureRefs[index + i].View = view; + } + else if (!_isBuffer) + { + _textureRefs[index + i].Storage = null; + _textureRefs[index + i].View = default; + } + else + { + _bufferTextureRefs[index + i] = null; + } + } + + SetDirty(); + } + + private void SetDirty() + { + _cachedCommandBufferIndex = -1; + _storages = null; + SetDirty(_gd, isImage: true); + } + + public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags) + { + HashSet storages = _storages; + + if (storages == null) + { + storages = new HashSet(); + + for (int index = 0; index < _textureRefs.Length; index++) + { + if (_textureRefs[index].Storage != null) + { + storages.Add(_textureRefs[index].Storage); + } + } + + _storages = storages; + } + + foreach (TextureStorage storage in storages) + { + storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stageFlags); + } + } + + public ReadOnlySpan GetImageInfos(VulkanRenderer gd, CommandBufferScoped cbs, TextureView dummyTexture) + { + int submissionCount = gd.CommandBufferPool.GetSubmissionCount(cbs.CommandBufferIndex); + + Span textures = _textures; + + if (cbs.CommandBufferIndex == _cachedCommandBufferIndex && submissionCount == _cachedSubmissionCount) + { + return textures; + } + + _cachedCommandBufferIndex = cbs.CommandBufferIndex; + _cachedSubmissionCount = submissionCount; + + for (int i = 0; i < textures.Length; i++) + { + ref var texture = ref textures[i]; + ref var refs = ref _textureRefs[i]; + + if (i > 0 && _textureRefs[i - 1].View == refs.View) + { + texture = textures[i - 1]; + + continue; + } + + texture.ImageLayout = ImageLayout.General; + texture.ImageView = refs.View?.GetIdentityImageView().Get(cbs).Value ?? default; + + if (texture.ImageView.Handle == 0) + { + texture.ImageView = dummyTexture.GetImageView().Get(cbs).Value; + } + } + + return textures; + } + + public ReadOnlySpan GetBufferViews(CommandBufferScoped cbs) + { + Span bufferTextures = _bufferTextures; + + for (int i = 0; i < bufferTextures.Length; i++) + { + bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, true) ?? default; + } + + return bufferTextures; + } + + public DescriptorSet[] GetDescriptorSets( + Device device, + CommandBufferScoped cbs, + DescriptorSetTemplateUpdater templateUpdater, + ShaderCollection program, + int setIndex, + TextureView dummyTexture) + { + if (TryGetCachedDescriptorSets(cbs, program, setIndex, out DescriptorSet[] sets)) + { + // We still need to ensure the current command buffer holds a reference to all used textures. + + if (!_isBuffer) + { + GetImageInfos(_gd, cbs, dummyTexture); + } + else + { + GetBufferViews(cbs); + } + + return sets; + } + + DescriptorSetTemplate template = program.Templates[setIndex]; + + DescriptorSetTemplateWriter tu = templateUpdater.Begin(template); + + if (!_isBuffer) + { + tu.Push(GetImageInfos(_gd, cbs, dummyTexture)); + } + else + { + tu.Push(GetBufferViews(cbs)); + } + + templateUpdater.Commit(_gd, device, sets[0]); + + return sets; + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/MemoryAllocatorBlockList.cs b/src/Ryujinx.Graphics.Vulkan/MemoryAllocatorBlockList.cs index a1acc90f9..3d42ed7e2 100644 --- a/src/Ryujinx.Graphics.Vulkan/MemoryAllocatorBlockList.cs +++ b/src/Ryujinx.Graphics.Vulkan/MemoryAllocatorBlockList.cs @@ -220,7 +220,7 @@ namespace Ryujinx.Graphics.Vulkan MemoryTypeIndex = (uint)MemoryTypeIndex, }; - _api.AllocateMemory(_device, memoryAllocateInfo, null, out var deviceMemory).ThrowOnError(); + _api.AllocateMemory(_device, in memoryAllocateInfo, null, out var deviceMemory).ThrowOnError(); IntPtr hostPointer = IntPtr.Zero; diff --git a/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs b/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs index b46ead9f9..e532ff4a5 100644 --- a/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs +++ b/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs @@ -1,3 +1,4 @@ +using Silk.NET.Core.Loader; using Silk.NET.Vulkan; using System; using System.Runtime.InteropServices; @@ -9,6 +10,8 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK [SupportedOSPlatform("ios")] public static partial class MVKInitialization { + private const string VulkanLib = "libvulkan.dylib"; + [LibraryImport("libMoltenVK.dylib")] private static partial Result vkGetMoltenVKConfigurationMVK(IntPtr unusedInstance, out MVKConfiguration config, in IntPtr configSize); @@ -31,5 +34,20 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK vkSetMoltenVKConfigurationMVK(IntPtr.Zero, config, configSize); } + + private static string[] Resolver(string path) + { + if (path.EndsWith(VulkanLib)) + { + path = path[..^VulkanLib.Length] + "libMoltenVK.dylib"; + return [path]; + } + return Array.Empty(); + } + + public static void InitializeResolver() + { + ((DefaultPathResolver)PathResolver.Default).Resolvers.Insert(0, Resolver); + } } } diff --git a/src/Ryujinx.Graphics.Vulkan/MultiFenceHolder.cs b/src/Ryujinx.Graphics.Vulkan/MultiFenceHolder.cs index 0bce3b72d..b42524712 100644 --- a/src/Ryujinx.Graphics.Vulkan/MultiFenceHolder.cs +++ b/src/Ryujinx.Graphics.Vulkan/MultiFenceHolder.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Memory; using Silk.NET.Vulkan; using System; @@ -165,14 +166,15 @@ namespace Ryujinx.Graphics.Vulkan /// True if all fences were signaled before the timeout expired, false otherwise private bool WaitForFencesImpl(Vk api, Device device, int offset, int size, bool hasTimeout, ulong timeout) { - Span fenceHolders = new FenceHolder[CommandBufferPool.MaxCommandBuffers]; + using SpanOwner fenceHoldersOwner = SpanOwner.Rent(CommandBufferPool.MaxCommandBuffers); + Span fenceHolders = fenceHoldersOwner.Span; int count = size != 0 ? GetOverlappingFences(fenceHolders, offset, size) : GetFences(fenceHolders); Span fences = stackalloc Fence[count]; int fenceCount = 0; - for (int i = 0; i < count; i++) + for (int i = 0; i < fences.Length; i++) { if (fenceHolders[i].TryGet(out Fence fence)) { @@ -194,18 +196,23 @@ namespace Ryujinx.Graphics.Vulkan bool signaled = true; - if (hasTimeout) + try { - signaled = FenceHelper.AllSignaled(api, device, fences[..fenceCount], timeout); + if (hasTimeout) + { + signaled = FenceHelper.AllSignaled(api, device, fences[..fenceCount], timeout); + } + else + { + FenceHelper.WaitAllIndefinitely(api, device, fences[..fenceCount]); + } } - else + finally { - FenceHelper.WaitAllIndefinitely(api, device, fences[..fenceCount]); - } - - for (int i = 0; i < fenceCount; i++) - { - fenceHolders[i].Put(); + for (int i = 0; i < fenceCount; i++) + { + fenceHolders[i].PutLock(); + } } return signaled; diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index 2300a440d..5fc8351a5 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -2,6 +2,7 @@ using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Shader; using Silk.NET.Vulkan; using System; +using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; @@ -30,10 +31,14 @@ namespace Ryujinx.Graphics.Vulkan public readonly PipelineCache PipelineCache; public readonly AutoFlushCounter AutoFlush; + public readonly Action EndRenderPassDelegate; protected PipelineDynamicState DynamicState; + protected bool IsMainPipeline; private PipelineState _newState; - private bool _stateDirty; + private bool _graphicsStateDirty; + private bool _computeStateDirty; + private bool _bindingBarriersDirty; private PrimitiveTopology _topology; private ulong _currentPipelineHandle; @@ -52,7 +57,9 @@ namespace Ryujinx.Graphics.Vulkan protected FramebufferParams FramebufferParams; private Auto _framebuffer; + private RenderPassHolder _rpHolder; private Auto _renderPass; + private RenderPassHolder _nullRenderPass; private int _writtenAttachmentCount; private bool _framebufferUsingColorWriteMask; @@ -80,9 +87,10 @@ namespace Ryujinx.Graphics.Vulkan private bool _tfEnabled; private bool _tfActive; - private readonly PipelineColorBlendAttachmentState[] _storedBlend; + private FeedbackLoopAspects _feedbackLoop; + private bool _passWritesDepthStencil; - private ulong _drawCountSinceBarrier; + private readonly PipelineColorBlendAttachmentState[] _storedBlend; public ulong DrawCount { get; private set; } public bool RenderPassActive { get; private set; } @@ -92,15 +100,16 @@ namespace Ryujinx.Graphics.Vulkan Device = device; AutoFlush = new AutoFlushCounter(gd); + EndRenderPassDelegate = EndRenderPass; var pipelineCacheCreateInfo = new PipelineCacheCreateInfo { SType = StructureType.PipelineCacheCreateInfo, }; - gd.Api.CreatePipelineCache(device, pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError(); + gd.Api.CreatePipelineCache(device, in pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError(); - _descriptorSetUpdater = new DescriptorSetUpdater(gd, this); + _descriptorSetUpdater = new DescriptorSetUpdater(gd, device); _vertexBufferUpdater = new VertexBufferUpdater(gd); _transformFeedbackBuffers = new BufferState[Constants.MaxTransformFeedbackBuffers]; @@ -122,7 +131,7 @@ namespace Ryujinx.Graphics.Vulkan public void Initialize() { - _descriptorSetUpdater.Initialize(); + _descriptorSetUpdater.Initialize(IsMainPipeline); QuadsToTrisPattern = new IndexBufferPattern(Gd, 4, 6, 0, new[] { 0, 1, 2, 0, 2, 3 }, 4, false); TriFanToTrisPattern = new IndexBufferPattern(Gd, 3, 3, 2, new[] { int.MinValue, -1, 0 }, 1, true); @@ -130,48 +139,7 @@ namespace Ryujinx.Graphics.Vulkan public unsafe void Barrier() { - if (_drawCountSinceBarrier != DrawCount) - { - _drawCountSinceBarrier = DrawCount; - - // Barriers are not supported inside a render pass on Apple GPUs. - // As a workaround, end the render pass. - if (Gd.Vendor == Vendor.Apple) - { - EndRenderPass(); - } - } - - MemoryBarrier memoryBarrier = new() - { - SType = StructureType.MemoryBarrier, - SrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit, - DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit, - }; - - PipelineStageFlags pipelineStageFlags = PipelineStageFlags.VertexShaderBit | PipelineStageFlags.FragmentShaderBit; - - if (Gd.Capabilities.SupportsGeometryShader) - { - pipelineStageFlags |= PipelineStageFlags.GeometryShaderBit; - } - - if (Gd.Capabilities.SupportsTessellationShader) - { - pipelineStageFlags |= PipelineStageFlags.TessellationControlShaderBit | PipelineStageFlags.TessellationEvaluationShaderBit; - } - - Gd.Api.CmdPipelineBarrier( - CommandBuffer, - pipelineStageFlags, - pipelineStageFlags, - 0, - 1, - memoryBarrier, - 0, - null, - 0, - null); + Gd.Barriers.QueueMemoryBarrier(); } public void ComputeBarrier() @@ -198,6 +166,7 @@ namespace Ryujinx.Graphics.Vulkan public void BeginTransformFeedback(PrimitiveTopology topology) { + Gd.Barriers.EnableTfbBarriers(true); _tfEnabled = true; } @@ -244,14 +213,14 @@ namespace Ryujinx.Graphics.Vulkan CreateRenderPass(); } + Gd.Barriers.Flush(Cbs, RenderPassActive, _rpHolder, EndRenderPassDelegate); + BeginRenderPass(); var clearValue = new ClearValue(new ClearColorValue(color.Red, color.Green, color.Blue, color.Alpha)); var attachment = new ClearAttachment(ImageAspectFlags.ColorBit, (uint)index, clearValue); var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount); - FramebufferParams.InsertClearBarrier(Cbs, index); - Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect); } @@ -282,36 +251,19 @@ namespace Ryujinx.Graphics.Vulkan CreateRenderPass(); } + Gd.Barriers.Flush(Cbs, RenderPassActive, _rpHolder, EndRenderPassDelegate); + BeginRenderPass(); var attachment = new ClearAttachment(flags, 0, clearValue); var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount); - FramebufferParams.InsertClearBarrierDS(Cbs); - Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect); } public unsafe void CommandBufferBarrier() { - MemoryBarrier memoryBarrier = new() - { - SType = StructureType.MemoryBarrier, - SrcAccessMask = BufferHolder.DefaultAccessFlags, - DstAccessMask = AccessFlags.IndirectCommandReadBit, - }; - - Gd.Api.CmdPipelineBarrier( - CommandBuffer, - PipelineStageFlags.AllCommandsBit, - PipelineStageFlags.DrawIndirectBit, - 0, - 1, - memoryBarrier, - 0, - null, - 0, - null); + Gd.Barriers.QueueCommandBufferBarrier(); } public void CopyBuffer(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size) @@ -351,7 +303,7 @@ namespace Ryujinx.Graphics.Vulkan } EndRenderPass(); - RecreatePipelineIfNeeded(PipelineBindPoint.Compute); + RecreateComputePipelineIfNeeded(); Gd.Api.CmdDispatch(CommandBuffer, (uint)groupsX, (uint)groupsY, (uint)groupsZ); } @@ -364,19 +316,23 @@ namespace Ryujinx.Graphics.Vulkan } EndRenderPass(); - RecreatePipelineIfNeeded(PipelineBindPoint.Compute); + RecreateComputePipelineIfNeeded(); Gd.Api.CmdDispatchIndirect(CommandBuffer, indirectBuffer.Get(Cbs, indirectBufferOffset, 12).Value, (ulong)indirectBufferOffset); } public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance) { - if (!_program.IsLinked || vertexCount == 0) + if (vertexCount == 0) + { + return; + } + + if (!RecreateGraphicsPipelineIfNeeded()) { return; } - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); BeginRenderPass(); DrawCount++; @@ -435,13 +391,18 @@ namespace Ryujinx.Graphics.Vulkan public void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance) { - if (!_program.IsLinked || indexCount == 0) + if (indexCount == 0) { return; } UpdateIndexBufferPattern(); - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); + + if (!RecreateGraphicsPipelineIfNeeded()) + { + return; + } + BeginRenderPass(); DrawCount++; @@ -474,17 +435,17 @@ namespace Ryujinx.Graphics.Vulkan public void DrawIndexedIndirect(BufferRange indirectBuffer) { - if (!_program.IsLinked) - { - return; - } - var buffer = Gd.BufferManager .GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false) .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value; UpdateIndexBufferPattern(); - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); + + if (!RecreateGraphicsPipelineIfNeeded()) + { + return; + } + BeginRenderPass(); DrawCount++; @@ -520,11 +481,6 @@ namespace Ryujinx.Graphics.Vulkan public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride) { - if (!_program.IsLinked) - { - return; - } - var countBuffer = Gd.BufferManager .GetBuffer(CommandBuffer, parameterBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, false) .Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value; @@ -534,7 +490,12 @@ namespace Ryujinx.Graphics.Vulkan .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value; UpdateIndexBufferPattern(); - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); + + if (!RecreateGraphicsPipelineIfNeeded()) + { + return; + } + BeginRenderPass(); DrawCount++; @@ -612,18 +573,17 @@ namespace Ryujinx.Graphics.Vulkan public void DrawIndirect(BufferRange indirectBuffer) { - if (!_program.IsLinked) - { - return; - } - // TODO: Support quads and other unsupported topologies. var buffer = Gd.BufferManager .GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false) .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size, false).Value; - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); + if (!RecreateGraphicsPipelineIfNeeded()) + { + return; + } + BeginRenderPass(); ResumeTransformFeedbackInternal(); DrawCount++; @@ -639,11 +599,6 @@ namespace Ryujinx.Graphics.Vulkan throw new NotSupportedException(); } - if (!_program.IsLinked) - { - return; - } - var buffer = Gd.BufferManager .GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false) .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size, false).Value; @@ -654,7 +609,11 @@ namespace Ryujinx.Graphics.Vulkan // TODO: Support quads and other unsupported topologies. - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); + if (!RecreateGraphicsPipelineIfNeeded()) + { + return; + } + BeginRenderPass(); ResumeTransformFeedbackInternal(); DrawCount++; @@ -677,9 +636,9 @@ namespace Ryujinx.Graphics.Vulkan var oldStencilTestEnable = _newState.StencilTestEnable; var oldDepthTestEnable = _newState.DepthTestEnable; var oldDepthWriteEnable = _newState.DepthWriteEnable; - var oldTopology = _newState.Topology; var oldViewports = DynamicState.Viewports; var oldViewportsCount = _newState.ViewportsCount; + var oldTopology = _topology; _newState.CullMode = CullModeFlags.None; _newState.StencilTestEnable = false; @@ -699,7 +658,7 @@ namespace Ryujinx.Graphics.Vulkan _newState.StencilTestEnable = oldStencilTestEnable; _newState.DepthTestEnable = oldDepthTestEnable; _newState.DepthWriteEnable = oldDepthWriteEnable; - _newState.Topology = oldTopology; + SetPrimitiveTopology(oldTopology); DynamicState.SetViewports(ref oldViewports, oldViewportsCount); @@ -710,6 +669,7 @@ namespace Ryujinx.Graphics.Vulkan public void EndTransformFeedback() { + Gd.Barriers.EnableTfbBarriers(false); PauseTransformFeedbackInternal(); _tfEnabled = false; } @@ -739,14 +699,12 @@ namespace Ryujinx.Graphics.Vulkan _vertexBufferUpdater.Commit(Cbs); } -#pragma warning disable CA1822 // Mark member as static public void SetAlphaTest(bool enable, float reference, CompareOp op) { // This is currently handled using shader specialization, as Vulkan does not support alpha test. // In the future, we may want to use this to write the reference value into the support buffer, // to avoid creating one version of the shader per reference value used. } -#pragma warning restore CA1822 public void SetBlendState(AdvancedBlendDescriptor blend) { @@ -861,6 +819,8 @@ namespace Ryujinx.Graphics.Vulkan _newState.DepthTestEnable = depthTest.TestEnable; _newState.DepthWriteEnable = depthTest.WriteEnable; _newState.DepthCompareOp = depthTest.Func.Convert(); + + UpdatePassDepthStencil(); SignalStateChange(); } @@ -876,9 +836,9 @@ namespace Ryujinx.Graphics.Vulkan SignalStateChange(); } - public void SetImage(int binding, ITexture image, Format imageFormat) + public void SetImage(ShaderStage stage, int binding, ITexture image) { - _descriptorSetUpdater.SetImage(binding, image, imageFormat); + _descriptorSetUpdater.SetImage(Cbs, stage, binding, image); } public void SetImage(int binding, Auto image) @@ -886,6 +846,16 @@ namespace Ryujinx.Graphics.Vulkan _descriptorSetUpdater.SetImage(binding, image); } + public void SetImageArray(ShaderStage stage, int binding, IImageArray array) + { + _descriptorSetUpdater.SetImageArray(Cbs, stage, binding, array); + } + + public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array) + { + _descriptorSetUpdater.SetImageArraySeparate(Cbs, stage, setIndex, array); + } + public void SetIndexBuffer(BufferRange buffer, IndexType type) { if (buffer.Handle != BufferHandle.Null) @@ -928,7 +898,6 @@ namespace Ryujinx.Graphics.Vulkan // TODO: Default levels (likely needs emulation on shaders?) } -#pragma warning disable CA1822 // Mark member as static public void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin) { // TODO. @@ -938,7 +907,6 @@ namespace Ryujinx.Graphics.Vulkan { // TODO. } -#pragma warning restore CA1822 public void SetPrimitiveRestart(bool enable, int index) { @@ -965,9 +933,11 @@ namespace Ryujinx.Graphics.Vulkan _program = internalProgram; - _descriptorSetUpdater.SetProgram(internalProgram); + _descriptorSetUpdater.SetProgram(Cbs, internalProgram, _currentPipelineHandle != 0); + _bindingBarriersDirty = true; _newState.PipelineLayout = internalProgram.PipelineLayout; + _newState.HasTessellationControlShader = internalProgram.HasTessellationControlShader; _newState.StagesCount = (uint)stages.Length; stages.CopyTo(_newState.Stages.AsSpan()[..stages.Length]); @@ -1000,6 +970,13 @@ namespace Ryujinx.Graphics.Vulkan { _newState.RasterizerDiscardEnable = discard; SignalStateChange(); + + if (!discard && Gd.IsQualcommProprietary) + { + // On Adreno, enabling rasterizer discard somehow corrupts the viewport state. + // Force it to be updated on next use to work around this bug. + DynamicState.ForceAllDirty(); + } } public void SetRenderTargetColorMasks(ReadOnlySpan componentMask) @@ -1055,7 +1032,6 @@ namespace Ryujinx.Graphics.Vulkan private void SetRenderTargetsInternal(ITexture[] colors, ITexture depthStencil, bool filterWriteMasked) { CreateFramebuffer(colors, depthStencil, filterWriteMasked); - FramebufferParams?.UpdateModifications(); CreateRenderPass(); SignalStateChange(); SignalAttachmentChange(); @@ -1110,6 +1086,8 @@ namespace Ryujinx.Graphics.Vulkan _newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert(); _newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert(); _newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert(); + + UpdatePassDepthStencil(); SignalStateChange(); } @@ -1133,6 +1111,16 @@ namespace Ryujinx.Graphics.Vulkan _descriptorSetUpdater.SetTextureAndSamplerIdentitySwizzle(Cbs, stage, binding, texture, sampler); } + public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array) + { + _descriptorSetUpdater.SetTextureArray(Cbs, stage, binding, array); + } + + public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array) + { + _descriptorSetUpdater.SetTextureArraySeparate(Cbs, stage, setIndex, array); + } + public void SetTransformFeedbackBuffers(ReadOnlySpan buffers) { PauseTransformFeedbackInternal(); @@ -1163,12 +1151,10 @@ namespace Ryujinx.Graphics.Vulkan _descriptorSetUpdater.SetUniformBuffers(CommandBuffer, buffers); } -#pragma warning disable CA1822 // Mark member as static public void SetUserClipDistance(int index, bool enableClip) { // TODO. } -#pragma warning restore CA1822 public void SetVertexAttribs(ReadOnlySpan vertexAttribs) { @@ -1362,26 +1348,19 @@ namespace Ryujinx.Graphics.Vulkan SignalCommandBufferChange(); } + public void ForceTextureDirty() + { + _descriptorSetUpdater.ForceTextureDirty(); + } + + public void ForceImageDirty() + { + _descriptorSetUpdater.ForceImageDirty(); + } + public unsafe void TextureBarrier() { - MemoryBarrier memoryBarrier = new() - { - SType = StructureType.MemoryBarrier, - SrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit, - DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit, - }; - - Gd.Api.CmdPipelineBarrier( - CommandBuffer, - PipelineStageFlags.FragmentShaderBit, - PipelineStageFlags.FragmentShaderBit, - 0, - 1, - memoryBarrier, - 0, - null, - 0, - null); + Gd.Barriers.QueueTextureBarrier(); } public void TextureBarrierTiled() @@ -1456,7 +1435,23 @@ namespace Ryujinx.Graphics.Vulkan } } + if (IsMainPipeline) + { + FramebufferParams?.ClearBindings(); + } + FramebufferParams = new FramebufferParams(Device, colors, depthStencil); + + if (IsMainPipeline) + { + FramebufferParams.AddBindings(); + + _newState.FeedbackLoopAspects = FeedbackLoopAspects.None; + _bindingBarriersDirty = true; + } + + _passWritesDepthStencil = false; + UpdatePassDepthStencil(); UpdatePipelineAttachmentFormats(); } @@ -1465,6 +1460,7 @@ namespace Ryujinx.Graphics.Vulkan var dstAttachmentFormats = _newState.Internal.AttachmentFormats.AsSpan(); FramebufferParams.AttachmentFormats.CopyTo(dstAttachmentFormats); _newState.Internal.AttachmentIntegerFormatMask = FramebufferParams.AttachmentIntegerFormatMask; + _newState.Internal.LogicOpsAllowed = FramebufferParams.LogicOpsAllowed; for (int i = FramebufferParams.AttachmentFormats.Length; i < dstAttachmentFormats.Length; i++) { @@ -1478,113 +1474,134 @@ namespace Ryujinx.Graphics.Vulkan protected unsafe void CreateRenderPass() { - const int MaxAttachments = Constants.MaxRenderTargets + 1; - - AttachmentDescription[] attachmentDescs = null; - - var subpass = new SubpassDescription - { - PipelineBindPoint = PipelineBindPoint.Graphics, - }; - - AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments]; - var hasFramebuffer = FramebufferParams != null; - if (hasFramebuffer && FramebufferParams.AttachmentsCount != 0) - { - attachmentDescs = new AttachmentDescription[FramebufferParams.AttachmentsCount]; - - for (int i = 0; i < FramebufferParams.AttachmentsCount; i++) - { - attachmentDescs[i] = new AttachmentDescription( - 0, - FramebufferParams.AttachmentFormats[i], - TextureStorage.ConvertToSampleCountFlags(Gd.Capabilities.SupportedSampleCounts, FramebufferParams.AttachmentSamples[i]), - AttachmentLoadOp.Load, - AttachmentStoreOp.Store, - AttachmentLoadOp.Load, - AttachmentStoreOp.Store, - ImageLayout.General, - ImageLayout.General); - } - - int colorAttachmentsCount = FramebufferParams.ColorAttachmentsCount; - - if (colorAttachmentsCount > MaxAttachments - 1) - { - colorAttachmentsCount = MaxAttachments - 1; - } - - if (colorAttachmentsCount != 0) - { - int maxAttachmentIndex = FramebufferParams.MaxColorAttachmentIndex; - subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1; - subpass.PColorAttachments = &attachmentReferences[0]; - - // Fill with VK_ATTACHMENT_UNUSED to cover any gaps. - for (int i = 0; i <= maxAttachmentIndex; i++) - { - subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined); - } - - for (int i = 0; i < colorAttachmentsCount; i++) - { - int bindIndex = FramebufferParams.AttachmentIndices[i]; - - subpass.PColorAttachments[bindIndex] = new AttachmentReference((uint)i, ImageLayout.General); - } - } - - if (FramebufferParams.HasDepthStencil) - { - uint dsIndex = (uint)FramebufferParams.AttachmentsCount - 1; - - subpass.PDepthStencilAttachment = &attachmentReferences[MaxAttachments - 1]; - *subpass.PDepthStencilAttachment = new AttachmentReference(dsIndex, ImageLayout.General); - } - } - - var subpassDependency = PipelineConverter.CreateSubpassDependency(); - - fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs) - { - var renderPassCreateInfo = new RenderPassCreateInfo - { - SType = StructureType.RenderPassCreateInfo, - PAttachments = pAttachmentDescs, - AttachmentCount = attachmentDescs != null ? (uint)attachmentDescs.Length : 0, - PSubpasses = &subpass, - SubpassCount = 1, - PDependencies = &subpassDependency, - DependencyCount = 1, - }; - - Gd.Api.CreateRenderPass(Device, renderPassCreateInfo, null, out var renderPass).ThrowOnError(); - - _renderPass?.Dispose(); - _renderPass = new Auto(new DisposableRenderPass(Gd.Api, Device, renderPass)); - } - EndRenderPass(); - _framebuffer?.Dispose(); - _framebuffer = hasFramebuffer ? FramebufferParams.Create(Gd.Api, Cbs, _renderPass) : null; + if (!hasFramebuffer || FramebufferParams.AttachmentsCount == 0) + { + // Use the null framebuffer. + _nullRenderPass ??= new RenderPassHolder(Gd, Device, new RenderPassCacheKey(), FramebufferParams); + + _rpHolder = _nullRenderPass; + _renderPass = _nullRenderPass.GetRenderPass(); + _framebuffer = _nullRenderPass.GetFramebuffer(Gd, Cbs, FramebufferParams); + } + else + { + (_rpHolder, _framebuffer) = FramebufferParams.GetPassAndFramebuffer(Gd, Device, Cbs); + + _renderPass = _rpHolder.GetRenderPass(); + } } protected void SignalStateChange() { - _stateDirty = true; + _graphicsStateDirty = true; + _computeStateDirty = true; } - private void RecreatePipelineIfNeeded(PipelineBindPoint pbp) + private void RecreateComputePipelineIfNeeded() + { + if (_computeStateDirty || Pbp != PipelineBindPoint.Compute) + { + CreatePipeline(PipelineBindPoint.Compute); + _computeStateDirty = false; + Pbp = PipelineBindPoint.Compute; + + if (_bindingBarriersDirty) + { + // Stale barriers may have been activated by switching program. Emit any that are relevant. + _descriptorSetUpdater.InsertBindingBarriers(Cbs); + + _bindingBarriersDirty = false; + } + } + + Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate); + + _descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Compute); + } + + private bool ChangeFeedbackLoop(FeedbackLoopAspects aspects) + { + if (_feedbackLoop != aspects) + { + if (Gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop) + { + DynamicState.SetFeedbackLoop(aspects); + } + else + { + _newState.FeedbackLoopAspects = aspects; + } + + _feedbackLoop = aspects; + + return true; + } + + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool UpdateFeedbackLoop() + { + List hazards = _descriptorSetUpdater.FeedbackLoopHazards; + + if ((hazards?.Count ?? 0) > 0) + { + FeedbackLoopAspects aspects = 0; + + foreach (TextureView view in hazards) + { + // May need to enforce feedback loop layout here in the future. + // Though technically, it should always work with the general layout. + + if (view.Info.Format.IsDepthOrStencil()) + { + if (_passWritesDepthStencil) + { + // If depth/stencil isn't written in the pass, it doesn't count as a feedback loop. + + aspects |= FeedbackLoopAspects.Depth; + } + } + else + { + aspects |= FeedbackLoopAspects.Color; + } + } + + return ChangeFeedbackLoop(aspects); + } + else if (_feedbackLoop != 0) + { + return ChangeFeedbackLoop(FeedbackLoopAspects.None); + } + + return false; + } + + private void UpdatePassDepthStencil() + { + if (!RenderPassActive) + { + _passWritesDepthStencil = false; + } + + // Stencil test being enabled doesn't necessarily mean a write, but it's not critical to check. + _passWritesDepthStencil |= (_newState.DepthTestEnable && _newState.DepthWriteEnable) || _newState.StencilTestEnable; + } + + private bool RecreateGraphicsPipelineIfNeeded() { if (AutoFlush.ShouldFlushDraw(DrawCount)) { Gd.FlushAllCommands(); } - DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer); + DynamicState.ReplayIfDirty(Gd, CommandBuffer); if (_needsIndexBufferRebind && _indexBufferPattern == null) { @@ -1618,17 +1635,33 @@ namespace Ryujinx.Graphics.Vulkan _vertexBufferUpdater.Commit(Cbs); } - if (_stateDirty || Pbp != pbp) + if (_bindingBarriersDirty) { - CreatePipeline(pbp); - _stateDirty = false; - Pbp = pbp; + // Stale barriers may have been activated by switching program. Emit any that are relevant. + _descriptorSetUpdater.InsertBindingBarriers(Cbs); + + _bindingBarriersDirty = false; } - _descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, pbp); + if (UpdateFeedbackLoop() || _graphicsStateDirty || Pbp != PipelineBindPoint.Graphics) + { + if (!CreatePipeline(PipelineBindPoint.Graphics)) + { + return false; + } + + _graphicsStateDirty = false; + Pbp = PipelineBindPoint.Graphics; + } + + Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate); + + _descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Graphics); + + return true; } - private void CreatePipeline(PipelineBindPoint pbp) + private bool CreatePipeline(PipelineBindPoint pbp) { // We can only create a pipeline if the have the shader stages set. if (_newState.Stages != null) @@ -1638,10 +1671,25 @@ namespace Ryujinx.Graphics.Vulkan CreateRenderPass(); } + if (!_program.IsLinked) + { + // Background compile failed, we likely can't create the pipeline because the shader is broken + // or the driver failed to compile it. + + return false; + } + var pipeline = pbp == PipelineBindPoint.Compute ? _newState.CreateComputePipeline(Gd, Device, _program, PipelineCache) : _newState.CreateGraphicsPipeline(Gd, Device, _program, PipelineCache, _renderPass.Get(Cbs).Value); + if (pipeline == null) + { + // Host failed to create the pipeline, likely due to driver bugs. + + return false; + } + ulong pipelineHandle = pipeline.GetUnsafe().Value.Handle; if (_currentPipelineHandle != pipelineHandle) @@ -1653,12 +1701,16 @@ namespace Ryujinx.Graphics.Vulkan Gd.Api.CmdBindPipeline(CommandBuffer, pbp, Pipeline.Get(Cbs).Value); } } + + return true; } private unsafe void BeginRenderPass() { if (!RenderPassActive) { + FramebufferParams.InsertLoadOpBarriers(Gd, Cbs); + var renderArea = new Rect2D(null, new Extent2D(FramebufferParams.Width, FramebufferParams.Height)); var clearValue = new ClearValue(); @@ -1672,7 +1724,7 @@ namespace Ryujinx.Graphics.Vulkan ClearValueCount = 1, }; - Gd.Api.CmdBeginRenderPass(CommandBuffer, renderPassBeginInfo, SubpassContents.Inline); + Gd.Api.CmdBeginRenderPass(CommandBuffer, in renderPassBeginInfo, SubpassContents.Inline); RenderPassActive = true; } } @@ -1681,6 +1733,8 @@ namespace Ryujinx.Graphics.Vulkan { if (RenderPassActive) { + FramebufferParams.AddStoreOpUsage(); + PauseTransformFeedbackInternal(); Gd.Api.CmdEndRenderPass(CommandBuffer); SignalRenderPassEnd(); @@ -1724,8 +1778,7 @@ namespace Ryujinx.Graphics.Vulkan { if (disposing) { - _renderPass?.Dispose(); - _framebuffer?.Dispose(); + _nullRenderPass?.Dispose(); _newState.Dispose(); _descriptorSetUpdater.Dispose(); _vertexBufferUpdater.Dispose(); diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs b/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs index 95b480a5e..85069c6b2 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs @@ -9,13 +9,6 @@ namespace Ryujinx.Graphics.Vulkan { static class PipelineConverter { - private const AccessFlags SubpassAccessMask = - AccessFlags.MemoryReadBit | - AccessFlags.MemoryWriteBit | - AccessFlags.ShaderReadBit | - AccessFlags.ColorAttachmentWriteBit | - AccessFlags.DepthStencilAttachmentWriteBit; - public static unsafe DisposableRenderPass ToRenderPass(this ProgramPipelineState state, VulkanRenderer gd, Device device) { const int MaxAttachments = Constants.MaxRenderTargets + 1; @@ -108,7 +101,7 @@ namespace Ryujinx.Graphics.Vulkan } } - var subpassDependency = CreateSubpassDependency(); + var subpassDependency = CreateSubpassDependency(gd); fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs) { @@ -123,35 +116,39 @@ namespace Ryujinx.Graphics.Vulkan DependencyCount = 1, }; - gd.Api.CreateRenderPass(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError(); + gd.Api.CreateRenderPass(device, in renderPassCreateInfo, null, out var renderPass).ThrowOnError(); return new DisposableRenderPass(gd.Api, device, renderPass); } } - public static SubpassDependency CreateSubpassDependency() + public static SubpassDependency CreateSubpassDependency(VulkanRenderer gd) { + var (access, stages) = BarrierBatch.GetSubpassAccessSuperset(gd); + return new SubpassDependency( 0, 0, - PipelineStageFlags.AllGraphicsBit, - PipelineStageFlags.AllGraphicsBit, - SubpassAccessMask, - SubpassAccessMask, + stages, + stages, + access, + access, 0); } - public unsafe static SubpassDependency2 CreateSubpassDependency2() + public unsafe static SubpassDependency2 CreateSubpassDependency2(VulkanRenderer gd) { + var (access, stages) = BarrierBatch.GetSubpassAccessSuperset(gd); + return new SubpassDependency2( StructureType.SubpassDependency2, null, 0, 0, - PipelineStageFlags.AllGraphicsBit, - PipelineStageFlags.AllGraphicsBit, - SubpassAccessMask, - SubpassAccessMask, + stages, + stages, + access, + access, 0); } @@ -180,9 +177,6 @@ namespace Ryujinx.Graphics.Vulkan pipeline.LogicOpEnable = state.LogicOpEnable; pipeline.LogicOp = state.LogicOp.Convert(); - pipeline.MinDepthBounds = 0f; // Not implemented. - pipeline.MaxDepthBounds = 0f; // Not implemented. - pipeline.PatchControlPoints = state.PatchControlPoints; pipeline.PolygonMode = PolygonMode.Fill; // Not implemented. pipeline.PrimitiveRestartEnable = state.PrimitiveRestartEnable; @@ -208,17 +202,11 @@ namespace Ryujinx.Graphics.Vulkan pipeline.StencilFrontPassOp = state.StencilTest.FrontDpPass.Convert(); pipeline.StencilFrontDepthFailOp = state.StencilTest.FrontDpFail.Convert(); pipeline.StencilFrontCompareOp = state.StencilTest.FrontFunc.Convert(); - pipeline.StencilFrontCompareMask = 0; - pipeline.StencilFrontWriteMask = 0; - pipeline.StencilFrontReference = 0; pipeline.StencilBackFailOp = state.StencilTest.BackSFail.Convert(); pipeline.StencilBackPassOp = state.StencilTest.BackDpPass.Convert(); pipeline.StencilBackDepthFailOp = state.StencilTest.BackDpFail.Convert(); pipeline.StencilBackCompareOp = state.StencilTest.BackFunc.Convert(); - pipeline.StencilBackCompareMask = 0; - pipeline.StencilBackWriteMask = 0; - pipeline.StencilBackReference = 0; pipeline.StencilTestEnable = state.StencilTest.TestEnable; @@ -302,6 +290,7 @@ namespace Ryujinx.Graphics.Vulkan int attachmentCount = 0; int maxColorAttachmentIndex = -1; uint attachmentIntegerFormatMask = 0; + bool allFormatsFloatOrSrgb = true; for (int i = 0; i < Constants.MaxRenderTargets; i++) { @@ -314,6 +303,8 @@ namespace Ryujinx.Graphics.Vulkan { attachmentIntegerFormatMask |= 1u << i; } + + allFormatsFloatOrSrgb &= state.AttachmentFormats[i].IsFloatOrSrgb(); } } @@ -325,6 +316,7 @@ namespace Ryujinx.Graphics.Vulkan pipeline.ColorBlendAttachmentStateCount = (uint)(maxColorAttachmentIndex + 1); pipeline.VertexAttributeDescriptionsCount = (uint)Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount); pipeline.Internal.AttachmentIntegerFormatMask = attachmentIntegerFormatMask; + pipeline.Internal.LogicOpsAllowed = attachmentCount == 0 || !allFormatsFloatOrSrgb; return pipeline; } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs index 1cc33f728..ad26ff7b3 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs @@ -1,5 +1,6 @@ using Ryujinx.Common.Memory; using Silk.NET.Vulkan; +using Silk.NET.Vulkan.Extensions.EXT; namespace Ryujinx.Graphics.Vulkan { @@ -21,6 +22,8 @@ namespace Ryujinx.Graphics.Vulkan private Array4 _blendConstants; + private FeedbackLoopAspects _feedbackLoopAspects; + public uint ViewportsCount; public Array16 Viewports; @@ -32,7 +35,8 @@ namespace Ryujinx.Graphics.Vulkan Scissor = 1 << 2, Stencil = 1 << 3, Viewport = 1 << 4, - All = Blend | DepthBias | Scissor | Stencil | Viewport, + FeedbackLoop = 1 << 5, + All = Blend | DepthBias | Scissor | Stencil | Viewport | FeedbackLoop, } private DirtyFlags _dirty; @@ -99,13 +103,22 @@ namespace Ryujinx.Graphics.Vulkan } } + public void SetFeedbackLoop(FeedbackLoopAspects aspects) + { + _feedbackLoopAspects = aspects; + + _dirty |= DirtyFlags.FeedbackLoop; + } + public void ForceAllDirty() { _dirty = DirtyFlags.All; } - public void ReplayIfDirty(Vk api, CommandBuffer commandBuffer) + public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer) { + Vk api = gd.Api; + if (_dirty.HasFlag(DirtyFlags.Blend)) { RecordBlend(api, commandBuffer); @@ -131,6 +144,11 @@ namespace Ryujinx.Graphics.Vulkan RecordViewport(api, commandBuffer); } + if (_dirty.HasFlag(DirtyFlags.FeedbackLoop) && gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop) + { + RecordFeedbackLoop(gd.DynamicFeedbackLoopApi, commandBuffer); + } + _dirty = DirtyFlags.None; } @@ -169,5 +187,17 @@ namespace Ryujinx.Graphics.Vulkan api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan()); } } + + private readonly void RecordFeedbackLoop(ExtAttachmentFeedbackLoopDynamicState api, CommandBuffer commandBuffer) + { + ImageAspectFlags aspects = (_feedbackLoopAspects & FeedbackLoopAspects.Color) != 0 ? ImageAspectFlags.ColorBit : 0; + + if ((_feedbackLoopAspects & FeedbackLoopAspects.Depth) != 0) + { + aspects |= ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit; + } + + api.CmdSetAttachmentFeedbackLoopEnable(commandBuffer, aspects); + } } } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs b/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs index 24ca715fe..54d43bdba 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs @@ -28,6 +28,8 @@ namespace Ryujinx.Graphics.Vulkan _activeBufferMirrors = new(); CommandBuffer = (Cbs = gd.CommandBufferPool.Rent()).CommandBuffer; + + IsMainPipeline = true; } private void CopyPendingQuery() @@ -47,11 +49,12 @@ namespace Ryujinx.Graphics.Vulkan return; } - if (componentMask != 0xf) + if (componentMask != 0xf || Gd.IsQualcommProprietary) { // We can't use CmdClearAttachments if not writing all components, // because on Vulkan, the pipeline state does not affect clears. - var dstTexture = FramebufferParams.GetAttachment(index); + // On proprietary Adreno drivers, CmdClearAttachments appears to execute out of order, so it's better to not use it at all. + var dstTexture = FramebufferParams.GetColorView(index); if (dstTexture == null) { return; @@ -71,7 +74,6 @@ namespace Ryujinx.Graphics.Vulkan componentMask, (int)FramebufferParams.Width, (int)FramebufferParams.Height, - FramebufferParams.AttachmentFormats[index], FramebufferParams.GetAttachmentComponentType(index), ClearScissor); } @@ -88,11 +90,12 @@ namespace Ryujinx.Graphics.Vulkan return; } - if (stencilMask != 0 && stencilMask != 0xff) + if ((stencilMask != 0 && stencilMask != 0xff) || Gd.IsQualcommProprietary) { // We can't use CmdClearAttachments if not clearing all (mask is all ones, 0xFF) or none (mask is 0) of the stencil bits, // because on Vulkan, the pipeline state does not affect clears. - var dstTexture = FramebufferParams.GetDepthStencilAttachment(); + // On proprietary Adreno drivers, CmdClearAttachments appears to execute out of order, so it's better to not use it at all. + var dstTexture = FramebufferParams.GetDepthStencilView(); if (dstTexture == null) { return; @@ -223,20 +226,6 @@ namespace Ryujinx.Graphics.Vulkan } } - private void TryBackingSwaps() - { - CommandBufferScoped? cbs = null; - - _backingSwaps.RemoveAll(holder => holder.TryBackingSwap(ref cbs)); - - cbs?.Dispose(); - } - - public void AddBackingSwap(BufferHolder holder) - { - _backingSwaps.Add(holder); - } - public void Restore() { if (Pipeline != null) @@ -246,7 +235,10 @@ namespace Ryujinx.Graphics.Vulkan SignalCommandBufferChange(); - DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer); + if (Pipeline != null && Pbp == PipelineBindPoint.Graphics) + { + DynamicState.ReplayIfDirty(Gd, CommandBuffer); + } } public void FlushCommandsImpl() @@ -267,6 +259,7 @@ namespace Ryujinx.Graphics.Vulkan PreloadCbs = null; } + Gd.Barriers.Flush(Cbs, false, null, null); CommandBuffer = (Cbs = Gd.CommandBufferPool.ReturnAndRent(Cbs)).CommandBuffer; Gd.RegisterFlush(); @@ -288,8 +281,6 @@ namespace Ryujinx.Graphics.Vulkan Gd.ResetCounterPool(); - TryBackingSwaps(); - Restore(); } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineHelperShader.cs b/src/Ryujinx.Graphics.Vulkan/PipelineHelperShader.cs index 0a871a5c8..dfbf19013 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineHelperShader.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineHelperShader.cs @@ -9,21 +9,16 @@ namespace Ryujinx.Graphics.Vulkan { } - public void SetRenderTarget(Auto view, uint width, uint height, bool isDepthStencil, VkFormat format) + public void SetRenderTarget(TextureView view, uint width, uint height) { - SetRenderTarget(view, width, height, 1u, isDepthStencil, format); - } - - public void SetRenderTarget(Auto view, uint width, uint height, uint samples, bool isDepthStencil, VkFormat format) - { - CreateFramebuffer(view, width, height, samples, isDepthStencil, format); + CreateFramebuffer(view, width, height); CreateRenderPass(); SignalStateChange(); } - private void CreateFramebuffer(Auto view, uint width, uint height, uint samples, bool isDepthStencil, VkFormat format) + private void CreateFramebuffer(TextureView view, uint width, uint height) { - FramebufferParams = new FramebufferParams(Device, view, width, height, samples, isDepthStencil, format); + FramebufferParams = new FramebufferParams(Device, view, width, height); UpdatePipelineAttachmentFormats(); } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineLayoutCacheEntry.cs b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutCacheEntry.cs index 2840dda0f..ae296b033 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineLayoutCacheEntry.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutCacheEntry.cs @@ -3,27 +3,26 @@ using Silk.NET.Vulkan; using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Vulkan { class PipelineLayoutCacheEntry { - // Those were adjusted based on current descriptor usage and the descriptor counts usually used on pipeline layouts. - // It might be a good idea to tweak them again if those change, or maybe find a way to calculate an optimal value dynamically. - private const uint DefaultUniformBufferPoolCapacity = 19 * DescriptorSetManager.MaxSets; - private const uint DefaultStorageBufferPoolCapacity = 16 * DescriptorSetManager.MaxSets; - private const uint DefaultTexturePoolCapacity = 128 * DescriptorSetManager.MaxSets; - private const uint DefaultImagePoolCapacity = 8 * DescriptorSetManager.MaxSets; - - private const int MaxPoolSizesPerSet = 2; + private const int MaxPoolSizesPerSet = 8; private readonly VulkanRenderer _gd; private readonly Device _device; public DescriptorSetLayout[] DescriptorSetLayouts { get; } + public bool[] DescriptorSetLayoutsUpdateAfterBind { get; } public PipelineLayout PipelineLayout { get; } private readonly int[] _consumedDescriptorsPerSet; + private readonly DescriptorPoolSize[][] _poolSizes; + + private readonly DescriptorSetManager _descriptorSetManager; private readonly List>[][] _dsCache; private List>[] _currentDsCache; @@ -31,6 +30,46 @@ namespace Ryujinx.Graphics.Vulkan private int _dsLastCbIndex; private int _dsLastSubmissionCount; + private struct ManualDescriptorSetEntry + { + public Auto DescriptorSet; + public uint CbRefMask; + public bool InUse; + + public ManualDescriptorSetEntry(Auto descriptorSet, int cbIndex) + { + DescriptorSet = descriptorSet; + CbRefMask = 1u << cbIndex; + InUse = true; + } + } + + private readonly struct PendingManualDsConsumption + { + public FenceHolder Fence { get; } + public int CommandBufferIndex { get; } + public int SetIndex { get; } + public int CacheIndex { get; } + + public PendingManualDsConsumption(FenceHolder fence, int commandBufferIndex, int setIndex, int cacheIndex) + { + Fence = fence; + CommandBufferIndex = commandBufferIndex; + SetIndex = setIndex; + CacheIndex = cacheIndex; + fence.Get(); + } + } + + private readonly List[] _manualDsCache; + private readonly Queue _pendingManualDsConsumptions; + private readonly Queue[] _freeManualDsCacheEntries; + + private readonly Dictionary _pdTemplates; + private readonly ResourceDescriptorCollection _pdDescriptors; + private long _lastPdUsage; + private DescriptorSetTemplate _lastPdTemplate; + private PipelineLayoutCacheEntry(VulkanRenderer gd, Device device, int setsCount) { _gd = gd; @@ -49,6 +88,9 @@ namespace Ryujinx.Graphics.Vulkan } _dsCacheCursor = new int[setsCount]; + _manualDsCache = new List[setsCount]; + _pendingManualDsConsumptions = new Queue(); + _freeManualDsCacheEntries = new Queue[setsCount]; } public PipelineLayoutCacheEntry( @@ -57,9 +99,16 @@ namespace Ryujinx.Graphics.Vulkan ReadOnlyCollection setDescriptors, bool usePushDescriptors) : this(gd, device, setDescriptors.Count) { - (DescriptorSetLayouts, PipelineLayout) = PipelineLayoutFactory.Create(gd, device, setDescriptors, usePushDescriptors); + ResourceLayouts layouts = PipelineLayoutFactory.Create(gd, device, setDescriptors, usePushDescriptors); + + DescriptorSetLayouts = layouts.DescriptorSetLayouts; + DescriptorSetLayoutsUpdateAfterBind = layouts.DescriptorSetLayoutsUpdateAfterBind; + PipelineLayout = layouts.PipelineLayout; _consumedDescriptorsPerSet = new int[setDescriptors.Count]; + _poolSizes = new DescriptorPoolSize[setDescriptors.Count][]; + + Span poolSizes = stackalloc DescriptorPoolSize[MaxPoolSizesPerSet]; for (int setIndex = 0; setIndex < setDescriptors.Count; setIndex++) { @@ -71,7 +120,16 @@ namespace Ryujinx.Graphics.Vulkan } _consumedDescriptorsPerSet[setIndex] = count; + _poolSizes[setIndex] = GetDescriptorPoolSizes(poolSizes, setDescriptors[setIndex], DescriptorSetManager.MaxSets).ToArray(); } + + if (usePushDescriptors) + { + _pdDescriptors = setDescriptors[0]; + _pdTemplates = new(); + } + + _descriptorSetManager = new DescriptorSetManager(_device, setDescriptors.Count); } public void UpdateCommandBufferIndex(int commandBufferIndex) @@ -94,18 +152,13 @@ namespace Ryujinx.Graphics.Vulkan int index = _dsCacheCursor[setIndex]++; if (index == list.Count) { - Span poolSizes = stackalloc DescriptorPoolSize[MaxPoolSizesPerSet]; - poolSizes = GetDescriptorPoolSizes(poolSizes, setIndex); - - int consumedDescriptors = _consumedDescriptorsPerSet[setIndex]; - - var dsc = _gd.DescriptorSetManager.AllocateDescriptorSet( + var dsc = _descriptorSetManager.AllocateDescriptorSet( _gd.Api, DescriptorSetLayouts[setIndex], - poolSizes, + _poolSizes[setIndex], setIndex, - consumedDescriptors, - false); + _consumedDescriptorsPerSet[setIndex], + DescriptorSetLayoutsUpdateAfterBind[setIndex]); list.Add(dsc); isNew = true; @@ -116,37 +169,168 @@ namespace Ryujinx.Graphics.Vulkan return list[index]; } - private static Span GetDescriptorPoolSizes(Span output, int setIndex) + public Auto GetNewManualDescriptorSetCollection(CommandBufferScoped cbs, int setIndex, out int cacheIndex) { - int count = 1; + FreeCompletedManualDescriptorSets(); - switch (setIndex) + var list = _manualDsCache[setIndex] ??= new(); + var span = CollectionsMarshal.AsSpan(list); + + Queue freeQueue = _freeManualDsCacheEntries[setIndex]; + + // Do we have at least one freed descriptor set? If so, just use that. + if (freeQueue != null && freeQueue.TryDequeue(out int freeIndex)) { - case PipelineBase.UniformSetIndex: - output[0] = new(DescriptorType.UniformBuffer, DefaultUniformBufferPoolCapacity); - break; - case PipelineBase.StorageSetIndex: - output[0] = new(DescriptorType.StorageBuffer, DefaultStorageBufferPoolCapacity); - break; - case PipelineBase.TextureSetIndex: - output[0] = new(DescriptorType.CombinedImageSampler, DefaultTexturePoolCapacity); - output[1] = new(DescriptorType.UniformTexelBuffer, DefaultTexturePoolCapacity); - count = 2; - break; - case PipelineBase.ImageSetIndex: - output[0] = new(DescriptorType.StorageImage, DefaultImagePoolCapacity); - output[1] = new(DescriptorType.StorageTexelBuffer, DefaultImagePoolCapacity); - count = 2; - break; + ref ManualDescriptorSetEntry entry = ref span[freeIndex]; + + Debug.Assert(!entry.InUse && entry.CbRefMask == 0); + + entry.InUse = true; + entry.CbRefMask = 1u << cbs.CommandBufferIndex; + cacheIndex = freeIndex; + + _pendingManualDsConsumptions.Enqueue(new PendingManualDsConsumption(cbs.GetFence(), cbs.CommandBufferIndex, setIndex, freeIndex)); + + return entry.DescriptorSet; + } + + // Otherwise create a new descriptor set, and add to our pending queue for command buffer consumption tracking. + var dsc = _descriptorSetManager.AllocateDescriptorSet( + _gd.Api, + DescriptorSetLayouts[setIndex], + _poolSizes[setIndex], + setIndex, + _consumedDescriptorsPerSet[setIndex], + DescriptorSetLayoutsUpdateAfterBind[setIndex]); + + cacheIndex = list.Count; + list.Add(new ManualDescriptorSetEntry(dsc, cbs.CommandBufferIndex)); + _pendingManualDsConsumptions.Enqueue(new PendingManualDsConsumption(cbs.GetFence(), cbs.CommandBufferIndex, setIndex, cacheIndex)); + + return dsc; + } + + public void UpdateManualDescriptorSetCollectionOwnership(CommandBufferScoped cbs, int setIndex, int cacheIndex) + { + FreeCompletedManualDescriptorSets(); + + var list = _manualDsCache[setIndex]; + var span = CollectionsMarshal.AsSpan(list); + ref var entry = ref span[cacheIndex]; + + uint cbMask = 1u << cbs.CommandBufferIndex; + + if ((entry.CbRefMask & cbMask) == 0) + { + entry.CbRefMask |= cbMask; + + _pendingManualDsConsumptions.Enqueue(new PendingManualDsConsumption(cbs.GetFence(), cbs.CommandBufferIndex, setIndex, cacheIndex)); + } + } + + private void FreeCompletedManualDescriptorSets() + { + FenceHolder signalledFence = null; + while (_pendingManualDsConsumptions.TryPeek(out var pds) && (pds.Fence == signalledFence || pds.Fence.IsSignaled())) + { + signalledFence = pds.Fence; // Already checked - don't need to do it again. + var dequeued = _pendingManualDsConsumptions.Dequeue(); + Debug.Assert(dequeued.Fence == pds.Fence); + pds.Fence.Put(); + + var span = CollectionsMarshal.AsSpan(_manualDsCache[dequeued.SetIndex]); + ref var entry = ref span[dequeued.CacheIndex]; + entry.CbRefMask &= ~(1u << dequeued.CommandBufferIndex); + + if (!entry.InUse && entry.CbRefMask == 0) + { + // If not in use by any array, and not bound to any command buffer, the descriptor set can be re-used immediately. + (_freeManualDsCacheEntries[dequeued.SetIndex] ??= new()).Enqueue(dequeued.CacheIndex); + } + } + } + + public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex) + { + var list = _manualDsCache[setIndex]; + var span = CollectionsMarshal.AsSpan(list); + + span[cacheIndex].InUse = false; + + if (span[cacheIndex].CbRefMask == 0) + { + // This is no longer in use by any array, so if not bound to any command buffer, the descriptor set can be re-used immediately. + (_freeManualDsCacheEntries[setIndex] ??= new()).Enqueue(cacheIndex); + } + } + + private static Span GetDescriptorPoolSizes(Span output, ResourceDescriptorCollection setDescriptor, uint multiplier) + { + int count = 0; + + for (int index = 0; index < setDescriptor.Descriptors.Count; index++) + { + ResourceDescriptor descriptor = setDescriptor.Descriptors[index]; + DescriptorType descriptorType = descriptor.Type.Convert(); + + bool found = false; + + for (int poolSizeIndex = 0; poolSizeIndex < count; poolSizeIndex++) + { + if (output[poolSizeIndex].Type == descriptorType) + { + output[poolSizeIndex].DescriptorCount += (uint)descriptor.Count * multiplier; + found = true; + break; + } + } + + if (!found) + { + output[count++] = new DescriptorPoolSize() + { + Type = descriptorType, + DescriptorCount = (uint)descriptor.Count, + }; + } } return output[..count]; } + public DescriptorSetTemplate GetPushDescriptorTemplate(PipelineBindPoint pbp, long updateMask) + { + if (_lastPdUsage == updateMask && _lastPdTemplate != null) + { + // Most likely result is that it asks to update the same buffers. + return _lastPdTemplate; + } + + if (!_pdTemplates.TryGetValue(updateMask, out DescriptorSetTemplate template)) + { + template = new DescriptorSetTemplate(_gd, _device, _pdDescriptors, updateMask, this, pbp, 0); + + _pdTemplates.Add(updateMask, template); + } + + _lastPdUsage = updateMask; + _lastPdTemplate = template; + + return template; + } + protected virtual unsafe void Dispose(bool disposing) { if (disposing) { + if (_pdTemplates != null) + { + foreach (DescriptorSetTemplate template in _pdTemplates.Values) + { + template.Dispose(); + } + } + for (int i = 0; i < _dsCache.Length; i++) { for (int j = 0; j < _dsCache[i].Length; j++) @@ -160,12 +344,34 @@ namespace Ryujinx.Graphics.Vulkan } } + for (int i = 0; i < _manualDsCache.Length; i++) + { + if (_manualDsCache[i] == null) + { + continue; + } + + for (int j = 0; j < _manualDsCache[i].Count; j++) + { + _manualDsCache[i][j].DescriptorSet.Dispose(); + } + + _manualDsCache[i].Clear(); + } + _gd.Api.DestroyPipelineLayout(_device, PipelineLayout, null); for (int i = 0; i < DescriptorSetLayouts.Length; i++) { _gd.Api.DestroyDescriptorSetLayout(_device, DescriptorSetLayouts[i], null); } + + while (_pendingManualDsConsumptions.TryDequeue(out var pds)) + { + pds.Fence.Put(); + } + + _descriptorSetManager.Dispose(); } } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs index 8bf286c65..8d7815616 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs @@ -1,18 +1,23 @@ +using Ryujinx.Common.Memory; using Ryujinx.Graphics.GAL; using Silk.NET.Vulkan; +using System; using System.Collections.ObjectModel; namespace Ryujinx.Graphics.Vulkan { + record struct ResourceLayouts(DescriptorSetLayout[] DescriptorSetLayouts, bool[] DescriptorSetLayoutsUpdateAfterBind, PipelineLayout PipelineLayout); + static class PipelineLayoutFactory { - public static unsafe (DescriptorSetLayout[], PipelineLayout) Create( + public static unsafe ResourceLayouts Create( VulkanRenderer gd, Device device, ReadOnlyCollection setDescriptors, bool usePushDescriptors) { DescriptorSetLayout[] layouts = new DescriptorSetLayout[setDescriptors.Count]; + bool[] updateAfterBindFlags = new bool[setDescriptors.Count]; bool isMoltenVk = gd.IsMoltenVk; @@ -32,10 +37,11 @@ namespace Ryujinx.Graphics.Vulkan DescriptorSetLayoutBinding[] layoutBindings = new DescriptorSetLayoutBinding[rdc.Descriptors.Count]; + bool hasArray = false; + for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++) { ResourceDescriptor descriptor = rdc.Descriptors[descIndex]; - ResourceStages stages = descriptor.Stages; if (descriptor.Type == ResourceType.StorageBuffer && isMoltenVk) @@ -52,19 +58,40 @@ namespace Ryujinx.Graphics.Vulkan DescriptorCount = (uint)descriptor.Count, StageFlags = stages.Convert(), }; + + if (descriptor.Count > 1) + { + hasArray = true; + } } fixed (DescriptorSetLayoutBinding* pLayoutBindings = layoutBindings) { + DescriptorSetLayoutCreateFlags flags = DescriptorSetLayoutCreateFlags.None; + + if (usePushDescriptors && setIndex == 0) + { + flags = DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr; + } + + if (gd.Vendor == Vendor.Intel && hasArray) + { + // Some vendors (like Intel) have low per-stage limits. + // We must set the flag if we exceed those limits. + flags |= DescriptorSetLayoutCreateFlags.UpdateAfterBindPoolBit; + + updateAfterBindFlags[setIndex] = true; + } + var descriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo { SType = StructureType.DescriptorSetLayoutCreateInfo, PBindings = pLayoutBindings, BindingCount = (uint)layoutBindings.Length, - Flags = usePushDescriptors && setIndex == 0 ? DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr : DescriptorSetLayoutCreateFlags.None, + Flags = flags, }; - gd.Api.CreateDescriptorSetLayout(device, descriptorSetLayoutCreateInfo, null, out layouts[setIndex]).ThrowOnError(); + gd.Api.CreateDescriptorSetLayout(device, in descriptorSetLayoutCreateInfo, null, out layouts[setIndex]).ThrowOnError(); } } @@ -82,7 +109,7 @@ namespace Ryujinx.Graphics.Vulkan gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError(); } - return (layouts, layout); + return new ResourceLayouts(layouts, updateAfterBindFlags, layout); } } } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs index cb5f6b3b2..a726b9edb 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Vulkan struct PipelineState : IDisposable { private const int RequiredSubgroupSize = 32; + private const int MaxDynamicStatesCount = 9; public PipelineUid Internal; @@ -71,248 +72,242 @@ namespace Ryujinx.Graphics.Vulkan set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF) | ((ulong)value << 32); } - public float MinDepthBounds - { - readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id5 >> 0) & 0xFFFFFFFF)); - set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0); - } - - public float MaxDepthBounds - { - readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id5 >> 32) & 0xFFFFFFFF)); - set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32); - } - public PolygonMode PolygonMode { - readonly get => (PolygonMode)((Internal.Id6 >> 0) & 0x3FFFFFFF); - set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFC0000000) | ((ulong)value << 0); + readonly get => (PolygonMode)((Internal.Id5 >> 0) & 0x3FFFFFFF); + set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFFC0000000) | ((ulong)value << 0); } public uint StagesCount { - readonly get => (byte)((Internal.Id6 >> 30) & 0xFF); - set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30); + readonly get => (byte)((Internal.Id5 >> 30) & 0xFF); + set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30); } public uint VertexAttributeDescriptionsCount { - readonly get => (byte)((Internal.Id6 >> 38) & 0xFF); - set => Internal.Id6 = (Internal.Id6 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38); + readonly get => (byte)((Internal.Id5 >> 38) & 0xFF); + set => Internal.Id5 = (Internal.Id5 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38); } public uint VertexBindingDescriptionsCount { - readonly get => (byte)((Internal.Id6 >> 46) & 0xFF); - set => Internal.Id6 = (Internal.Id6 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46); + readonly get => (byte)((Internal.Id5 >> 46) & 0xFF); + set => Internal.Id5 = (Internal.Id5 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46); } public uint ViewportsCount { - readonly get => (byte)((Internal.Id6 >> 54) & 0xFF); - set => Internal.Id6 = (Internal.Id6 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54); + readonly get => (byte)((Internal.Id5 >> 54) & 0xFF); + set => Internal.Id5 = (Internal.Id5 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54); } public uint ScissorsCount { - readonly get => (byte)((Internal.Id7 >> 0) & 0xFF); - set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0); + readonly get => (byte)((Internal.Id6 >> 0) & 0xFF); + set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0); } public uint ColorBlendAttachmentStateCount { - readonly get => (byte)((Internal.Id7 >> 8) & 0xFF); - set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8); + readonly get => (byte)((Internal.Id6 >> 8) & 0xFF); + set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8); } public PrimitiveTopology Topology { - readonly get => (PrimitiveTopology)((Internal.Id7 >> 16) & 0xF); - set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16); + readonly get => (PrimitiveTopology)((Internal.Id6 >> 16) & 0xF); + set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16); } public LogicOp LogicOp { - readonly get => (LogicOp)((Internal.Id7 >> 20) & 0xF); - set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20); + readonly get => (LogicOp)((Internal.Id6 >> 20) & 0xF); + set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20); } public CompareOp DepthCompareOp { - readonly get => (CompareOp)((Internal.Id7 >> 24) & 0x7); - set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24); + readonly get => (CompareOp)((Internal.Id6 >> 24) & 0x7); + set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24); } public StencilOp StencilFrontFailOp { - readonly get => (StencilOp)((Internal.Id7 >> 27) & 0x7); - set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27); + readonly get => (StencilOp)((Internal.Id6 >> 27) & 0x7); + set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27); } public StencilOp StencilFrontPassOp { - readonly get => (StencilOp)((Internal.Id7 >> 30) & 0x7); - set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30); + readonly get => (StencilOp)((Internal.Id6 >> 30) & 0x7); + set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30); } public StencilOp StencilFrontDepthFailOp { - readonly get => (StencilOp)((Internal.Id7 >> 33) & 0x7); - set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33); + readonly get => (StencilOp)((Internal.Id6 >> 33) & 0x7); + set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33); } public CompareOp StencilFrontCompareOp { - readonly get => (CompareOp)((Internal.Id7 >> 36) & 0x7); - set => Internal.Id7 = (Internal.Id7 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36); + readonly get => (CompareOp)((Internal.Id6 >> 36) & 0x7); + set => Internal.Id6 = (Internal.Id6 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36); } public StencilOp StencilBackFailOp { - readonly get => (StencilOp)((Internal.Id7 >> 39) & 0x7); - set => Internal.Id7 = (Internal.Id7 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39); + readonly get => (StencilOp)((Internal.Id6 >> 39) & 0x7); + set => Internal.Id6 = (Internal.Id6 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39); } public StencilOp StencilBackPassOp { - readonly get => (StencilOp)((Internal.Id7 >> 42) & 0x7); - set => Internal.Id7 = (Internal.Id7 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42); + readonly get => (StencilOp)((Internal.Id6 >> 42) & 0x7); + set => Internal.Id6 = (Internal.Id6 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42); } public StencilOp StencilBackDepthFailOp { - readonly get => (StencilOp)((Internal.Id7 >> 45) & 0x7); - set => Internal.Id7 = (Internal.Id7 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45); + readonly get => (StencilOp)((Internal.Id6 >> 45) & 0x7); + set => Internal.Id6 = (Internal.Id6 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45); } public CompareOp StencilBackCompareOp { - readonly get => (CompareOp)((Internal.Id7 >> 48) & 0x7); - set => Internal.Id7 = (Internal.Id7 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48); + readonly get => (CompareOp)((Internal.Id6 >> 48) & 0x7); + set => Internal.Id6 = (Internal.Id6 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48); } public CullModeFlags CullMode { - readonly get => (CullModeFlags)((Internal.Id7 >> 51) & 0x3); - set => Internal.Id7 = (Internal.Id7 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51); + readonly get => (CullModeFlags)((Internal.Id6 >> 51) & 0x3); + set => Internal.Id6 = (Internal.Id6 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51); } public bool PrimitiveRestartEnable { - readonly get => ((Internal.Id7 >> 53) & 0x1) != 0UL; - set => Internal.Id7 = (Internal.Id7 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53); + readonly get => ((Internal.Id6 >> 53) & 0x1) != 0UL; + set => Internal.Id6 = (Internal.Id6 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53); } public bool DepthClampEnable { - readonly get => ((Internal.Id7 >> 54) & 0x1) != 0UL; - set => Internal.Id7 = (Internal.Id7 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54); + readonly get => ((Internal.Id6 >> 54) & 0x1) != 0UL; + set => Internal.Id6 = (Internal.Id6 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54); } public bool RasterizerDiscardEnable { - readonly get => ((Internal.Id7 >> 55) & 0x1) != 0UL; - set => Internal.Id7 = (Internal.Id7 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55); + readonly get => ((Internal.Id6 >> 55) & 0x1) != 0UL; + set => Internal.Id6 = (Internal.Id6 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55); } public FrontFace FrontFace { - readonly get => (FrontFace)((Internal.Id7 >> 56) & 0x1); - set => Internal.Id7 = (Internal.Id7 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56); + readonly get => (FrontFace)((Internal.Id6 >> 56) & 0x1); + set => Internal.Id6 = (Internal.Id6 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56); } public bool DepthBiasEnable { - readonly get => ((Internal.Id7 >> 57) & 0x1) != 0UL; - set => Internal.Id7 = (Internal.Id7 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57); + readonly get => ((Internal.Id6 >> 57) & 0x1) != 0UL; + set => Internal.Id6 = (Internal.Id6 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57); } public bool DepthTestEnable { - readonly get => ((Internal.Id7 >> 58) & 0x1) != 0UL; - set => Internal.Id7 = (Internal.Id7 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58); + readonly get => ((Internal.Id6 >> 58) & 0x1) != 0UL; + set => Internal.Id6 = (Internal.Id6 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58); } public bool DepthWriteEnable { - readonly get => ((Internal.Id7 >> 59) & 0x1) != 0UL; - set => Internal.Id7 = (Internal.Id7 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59); + readonly get => ((Internal.Id6 >> 59) & 0x1) != 0UL; + set => Internal.Id6 = (Internal.Id6 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59); } public bool DepthBoundsTestEnable { - readonly get => ((Internal.Id7 >> 60) & 0x1) != 0UL; - set => Internal.Id7 = (Internal.Id7 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60); + readonly get => ((Internal.Id6 >> 60) & 0x1) != 0UL; + set => Internal.Id6 = (Internal.Id6 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60); } public bool StencilTestEnable { - readonly get => ((Internal.Id7 >> 61) & 0x1) != 0UL; - set => Internal.Id7 = (Internal.Id7 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61); + readonly get => ((Internal.Id6 >> 61) & 0x1) != 0UL; + set => Internal.Id6 = (Internal.Id6 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61); } public bool LogicOpEnable { - readonly get => ((Internal.Id7 >> 62) & 0x1) != 0UL; - set => Internal.Id7 = (Internal.Id7 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62); + readonly get => ((Internal.Id6 >> 62) & 0x1) != 0UL; + set => Internal.Id6 = (Internal.Id6 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62); } public bool HasDepthStencil { - readonly get => ((Internal.Id7 >> 63) & 0x1) != 0UL; - set => Internal.Id7 = (Internal.Id7 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63); + readonly get => ((Internal.Id6 >> 63) & 0x1) != 0UL; + set => Internal.Id6 = (Internal.Id6 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63); } public uint PatchControlPoints { - readonly get => (uint)((Internal.Id8 >> 0) & 0xFFFFFFFF); - set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFF00000000) | ((ulong)value << 0); + readonly get => (uint)((Internal.Id7 >> 0) & 0xFFFFFFFF); + set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFF00000000) | ((ulong)value << 0); } public uint SamplesCount { - readonly get => (uint)((Internal.Id8 >> 32) & 0xFFFFFFFF); - set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFF) | ((ulong)value << 32); + readonly get => (uint)((Internal.Id7 >> 32) & 0xFFFFFFFF); + set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFF) | ((ulong)value << 32); } public bool AlphaToCoverageEnable { - readonly get => ((Internal.Id9 >> 0) & 0x1) != 0UL; - set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0); + readonly get => ((Internal.Id8 >> 0) & 0x1) != 0UL; + set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0); } public bool AlphaToOneEnable { - readonly get => ((Internal.Id9 >> 1) & 0x1) != 0UL; - set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1); + readonly get => ((Internal.Id8 >> 1) & 0x1) != 0UL; + set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1); } public bool AdvancedBlendSrcPreMultiplied { - readonly get => ((Internal.Id9 >> 2) & 0x1) != 0UL; - set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2); + readonly get => ((Internal.Id8 >> 2) & 0x1) != 0UL; + set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2); } public bool AdvancedBlendDstPreMultiplied { - readonly get => ((Internal.Id9 >> 3) & 0x1) != 0UL; - set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3); + readonly get => ((Internal.Id8 >> 3) & 0x1) != 0UL; + set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3); } public BlendOverlapEXT AdvancedBlendOverlap { - readonly get => (BlendOverlapEXT)((Internal.Id9 >> 4) & 0x3); - set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4); + readonly get => (BlendOverlapEXT)((Internal.Id8 >> 4) & 0x3); + set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4); } public bool DepthMode { - readonly get => ((Internal.Id9 >> 6) & 0x1) != 0UL; - set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6); + readonly get => ((Internal.Id8 >> 6) & 0x1) != 0UL; + set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6); } + public FeedbackLoopAspects FeedbackLoopAspects + { + readonly get => (FeedbackLoopAspects)((Internal.Id8 >> 7) & 0x3); + set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFE7F) | (((ulong)value) << 7); + } + + public bool HasTessellationControlShader; public NativeArray Stages; - public NativeArray StageRequiredSubgroupSizes; public PipelineLayout PipelineLayout; public SpecData SpecializationData; @@ -320,17 +315,8 @@ namespace Ryujinx.Graphics.Vulkan public void Initialize() { + HasTessellationControlShader = false; Stages = new NativeArray(Constants.MaxShaderStages); - StageRequiredSubgroupSizes = new NativeArray(Constants.MaxShaderStages); - - for (int index = 0; index < Constants.MaxShaderStages; index++) - { - StageRequiredSubgroupSizes[index] = new PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT - { - SType = StructureType.PipelineShaderStageRequiredSubgroupSizeCreateInfoExt, - RequiredSubgroupSize = RequiredSubgroupSize, - }; - } AdvancedBlendSrcPreMultiplied = true; AdvancedBlendDstPreMultiplied = true; @@ -397,7 +383,8 @@ namespace Ryujinx.Graphics.Vulkan Device device, ShaderCollection program, PipelineCache cache, - RenderPass renderPass) + RenderPass renderPass, + bool throwOnError = false) { if (program.TryGetGraphicsPipeline(ref Internal, out var pipeline)) { @@ -416,8 +403,6 @@ namespace Ryujinx.Graphics.Vulkan fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions = &Internal.VertexAttributeDescriptions[0]) fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions2 = &_vertexAttributeDescriptions2[0]) fixed (VertexInputBindingDescription* pVertexBindingDescriptions = &Internal.VertexBindingDescriptions[0]) - fixed (Viewport* pViewports = &Internal.Viewports[0]) - fixed (Rect2D* pScissors = &Internal.Scissors[0]) fixed (PipelineColorBlendAttachmentState* pColorBlendAttachmentState = &Internal.ColorBlendAttachmentState[0]) { var vertexInputState = new PipelineVertexInputStateCreateInfo @@ -429,6 +414,15 @@ namespace Ryujinx.Graphics.Vulkan PVertexBindingDescriptions = pVertexBindingDescriptions, }; + // Using patches topology without a tessellation shader is invalid. + // If we find such a case, return null pipeline to skip the draw. + if (Topology == PrimitiveTopology.PatchList && !HasTessellationControlShader) + { + program.AddGraphicsPipeline(ref Internal, null); + + return null; + } + bool primitiveRestartEnable = PrimitiveRestartEnable; bool topologySupportsRestart; @@ -452,7 +446,7 @@ namespace Ryujinx.Graphics.Vulkan { SType = StructureType.PipelineInputAssemblyStateCreateInfo, PrimitiveRestartEnable = primitiveRestartEnable, - Topology = Topology, + Topology = HasTessellationControlShader ? PrimitiveTopology.PatchList : Topology, }; var tessellationState = new PipelineTessellationStateCreateInfo @@ -471,18 +465,13 @@ namespace Ryujinx.Graphics.Vulkan CullMode = CullMode, FrontFace = FrontFace, DepthBiasEnable = DepthBiasEnable, - DepthBiasClamp = DepthBiasClamp, - DepthBiasConstantFactor = DepthBiasConstantFactor, - DepthBiasSlopeFactor = DepthBiasSlopeFactor, }; var viewportState = new PipelineViewportStateCreateInfo { SType = StructureType.PipelineViewportStateCreateInfo, ViewportCount = ViewportsCount, - PViewports = pViewports, ScissorCount = ScissorsCount, - PScissors = pScissors, }; if (gd.Capabilities.SupportsDepthClipControl) @@ -510,19 +499,13 @@ namespace Ryujinx.Graphics.Vulkan StencilFrontFailOp, StencilFrontPassOp, StencilFrontDepthFailOp, - StencilFrontCompareOp, - StencilFrontCompareMask, - StencilFrontWriteMask, - StencilFrontReference); + StencilFrontCompareOp); var stencilBack = new StencilOpState( StencilBackFailOp, StencilBackPassOp, StencilBackDepthFailOp, - StencilBackCompareOp, - StencilBackCompareMask, - StencilBackWriteMask, - StencilBackReference); + StencilBackCompareOp); var depthStencilState = new PipelineDepthStencilStateCreateInfo { @@ -530,12 +513,10 @@ namespace Ryujinx.Graphics.Vulkan DepthTestEnable = DepthTestEnable, DepthWriteEnable = DepthWriteEnable, DepthCompareOp = DepthCompareOp, - DepthBoundsTestEnable = DepthBoundsTestEnable, + DepthBoundsTestEnable = false, StencilTestEnable = StencilTestEnable, Front = stencilFront, Back = stencilBack, - MinDepthBounds = MinDepthBounds, - MaxDepthBounds = MaxDepthBounds, }; uint blendEnables = 0; @@ -559,10 +540,14 @@ namespace Ryujinx.Graphics.Vulkan } } + // Vendors other than NVIDIA have a bug where it enables logical operations even for float formats, + // so we need to force disable them here. + bool logicOpEnable = LogicOpEnable && (gd.Vendor == Vendor.Nvidia || Internal.LogicOpsAllowed); + var colorBlendState = new PipelineColorBlendStateCreateInfo { SType = StructureType.PipelineColorBlendStateCreateInfo, - LogicOpEnable = LogicOpEnable, + LogicOpEnable = logicOpEnable, LogicOp = LogicOp, AttachmentCount = ColorBlendAttachmentStateCount, PAttachments = pColorBlendAttachmentState, @@ -586,22 +571,28 @@ namespace Ryujinx.Graphics.Vulkan } bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState; - int dynamicStatesCount = supportsExtDynamicState ? 9 : 8; + bool supportsFeedbackLoopDynamicState = gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop; - DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount]; + DynamicState* dynamicStates = stackalloc DynamicState[MaxDynamicStatesCount]; + + int dynamicStatesCount = 7; dynamicStates[0] = DynamicState.Viewport; dynamicStates[1] = DynamicState.Scissor; dynamicStates[2] = DynamicState.DepthBias; - dynamicStates[3] = DynamicState.DepthBounds; - dynamicStates[4] = DynamicState.StencilCompareMask; - dynamicStates[5] = DynamicState.StencilWriteMask; - dynamicStates[6] = DynamicState.StencilReference; - dynamicStates[7] = DynamicState.BlendConstants; + dynamicStates[3] = DynamicState.StencilCompareMask; + dynamicStates[4] = DynamicState.StencilWriteMask; + dynamicStates[5] = DynamicState.StencilReference; + dynamicStates[6] = DynamicState.BlendConstants; if (supportsExtDynamicState) { - // dynamicStates[8] = DynamicState.VertexInputBindingStrideExt; + dynamicStates[dynamicStatesCount++] = DynamicState.VertexInputBindingStrideExt; + } + + if (supportsFeedbackLoopDynamicState) + { + dynamicStates[dynamicStatesCount++] = DynamicState.AttachmentFeedbackLoopEnableExt; } var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo @@ -611,9 +602,27 @@ namespace Ryujinx.Graphics.Vulkan PDynamicStates = dynamicStates, }; + PipelineCreateFlags flags = 0; + + if (gd.Capabilities.SupportsAttachmentFeedbackLoop) + { + FeedbackLoopAspects aspects = FeedbackLoopAspects; + + if ((aspects & FeedbackLoopAspects.Color) != 0) + { + flags |= PipelineCreateFlags.CreateColorAttachmentFeedbackLoopBitExt; + } + + if ((aspects & FeedbackLoopAspects.Depth) != 0) + { + flags |= PipelineCreateFlags.CreateDepthStencilAttachmentFeedbackLoopBitExt; + } + } + var pipelineCreateInfo = new GraphicsPipelineCreateInfo { SType = StructureType.GraphicsPipelineCreateInfo, + Flags = flags, StageCount = StagesCount, PStages = Stages.Pointer, PVertexInputState = &vertexInputState, @@ -627,10 +636,20 @@ namespace Ryujinx.Graphics.Vulkan PDynamicState = &pipelineDynamicStateCreateInfo, Layout = PipelineLayout, RenderPass = renderPass, - BasePipelineIndex = -1, }; - gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle).ThrowOnError(); + Result result = gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle); + + if (throwOnError) + { + result.ThrowOnError(); + } + else if (result.IsError()) + { + program.AddGraphicsPipeline(ref Internal, null); + + return null; + } // Restore previous blend enable values if we changed it. while (blendEnables != 0) @@ -708,7 +727,6 @@ namespace Ryujinx.Graphics.Vulkan public readonly void Dispose() { Stages.Dispose(); - StageRequiredSubgroupSizes.Dispose(); } } } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineUid.cs b/src/Ryujinx.Graphics.Vulkan/PipelineUid.cs index 3448d9743..c56224216 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineUid.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineUid.cs @@ -17,23 +17,21 @@ namespace Ryujinx.Graphics.Vulkan public ulong Id4; public ulong Id5; public ulong Id6; + public ulong Id7; - public ulong Id8; - public ulong Id9; - private readonly uint VertexAttributeDescriptionsCount => (byte)((Id6 >> 38) & 0xFF); - private readonly uint VertexBindingDescriptionsCount => (byte)((Id6 >> 46) & 0xFF); - private readonly uint ColorBlendAttachmentStateCount => (byte)((Id7 >> 8) & 0xFF); - private readonly bool HasDepthStencil => ((Id7 >> 63) & 0x1) != 0UL; + private readonly uint VertexAttributeDescriptionsCount => (byte)((Id5 >> 38) & 0xFF); + private readonly uint VertexBindingDescriptionsCount => (byte)((Id5 >> 46) & 0xFF); + private readonly uint ColorBlendAttachmentStateCount => (byte)((Id6 >> 8) & 0xFF); + private readonly bool HasDepthStencil => ((Id6 >> 63) & 0x1) != 0UL; public Array32 VertexAttributeDescriptions; public Array33 VertexBindingDescriptions; - public Array16 Viewports; - public Array16 Scissors; public Array8 ColorBlendAttachmentState; public Array9 AttachmentFormats; public uint AttachmentIntegerFormatMask; + public bool LogicOpsAllowed; public readonly override bool Equals(object obj) { @@ -44,7 +42,7 @@ namespace Ryujinx.Graphics.Vulkan { if (!Unsafe.As>(ref Id0).Equals(Unsafe.As>(ref other.Id0)) || !Unsafe.As>(ref Id4).Equals(Unsafe.As>(ref other.Id4)) || - !Unsafe.As>(ref Id8).Equals(Unsafe.As>(ref other.Id8))) + !Unsafe.As>(ref Id7).Equals(Unsafe.As>(ref other.Id7))) { return false; } @@ -87,8 +85,7 @@ namespace Ryujinx.Graphics.Vulkan Id5 * 23 ^ Id6 * 23 ^ Id7 * 23 ^ - Id8 * 23 ^ - Id9 * 23; + Id8 * 23; for (int i = 0; i < (int)VertexAttributeDescriptionsCount; i++) { diff --git a/src/Ryujinx.Graphics.Vulkan/Queries/BufferedQuery.cs b/src/Ryujinx.Graphics.Vulkan/Queries/BufferedQuery.cs index 3fdc5afa5..c9a546648 100644 --- a/src/Ryujinx.Graphics.Vulkan/Queries/BufferedQuery.cs +++ b/src/Ryujinx.Graphics.Vulkan/Queries/BufferedQuery.cs @@ -10,8 +10,8 @@ namespace Ryujinx.Graphics.Vulkan.Queries class BufferedQuery : IDisposable { private const int MaxQueryRetries = 5000; - private const long DefaultValue = -1; - private const long DefaultValueInt = 0xFFFFFFFF; + private const long DefaultValue = unchecked((long)0xFFFFFFFEFFFFFFFE); + private const long DefaultValueInt = 0xFFFFFFFE; private const ulong HighMask = 0xFFFFFFFF00000000; private readonly Vk _api; @@ -52,7 +52,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries PipelineStatistics = flags, }; - gd.Api.CreateQueryPool(device, queryPoolCreateInfo, null, out _queryPool).ThrowOnError(); + gd.Api.CreateQueryPool(device, in queryPoolCreateInfo, null, out _queryPool).ThrowOnError(); } var buffer = gd.BufferManager.Create(gd, sizeof(long), forConditionalRendering: true); diff --git a/src/Ryujinx.Graphics.Vulkan/Queries/CounterQueue.cs b/src/Ryujinx.Graphics.Vulkan/Queries/CounterQueue.cs index 3984e2826..0d133e50e 100644 --- a/src/Ryujinx.Graphics.Vulkan/Queries/CounterQueue.cs +++ b/src/Ryujinx.Graphics.Vulkan/Queries/CounterQueue.cs @@ -67,9 +67,18 @@ namespace Ryujinx.Graphics.Vulkan.Queries lock (_queryPool) { count = Math.Min(count, _queryPool.Count); - for (int i = 0; i < count; i++) + + if (count > 0) { - _queryPool.ElementAt(i).PoolReset(cmd, ResetSequence); + foreach (BufferedQuery query in _queryPool) + { + query.PoolReset(cmd, ResetSequence); + + if (--count == 0) + { + break; + } + } } } } diff --git a/src/Ryujinx.Graphics.Vulkan/RenderPassCacheKey.cs b/src/Ryujinx.Graphics.Vulkan/RenderPassCacheKey.cs new file mode 100644 index 000000000..7c57b8feb --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/RenderPassCacheKey.cs @@ -0,0 +1,43 @@ +using System; +using System.Linq; + +namespace Ryujinx.Graphics.Vulkan +{ + internal readonly struct RenderPassCacheKey : IRefEquatable + { + private readonly TextureView _depthStencil; + private readonly TextureView[] _colors; + + public RenderPassCacheKey(TextureView depthStencil, TextureView[] colors) + { + _depthStencil = depthStencil; + _colors = colors; + } + + public override int GetHashCode() + { + HashCode hc = new(); + + hc.Add(_depthStencil); + + if (_colors != null) + { + foreach (var color in _colors) + { + hc.Add(color); + } + } + + return hc.ToHashCode(); + } + + public bool Equals(ref RenderPassCacheKey other) + { + bool colorsNull = _colors == null; + bool otherNull = other._colors == null; + return other._depthStencil == _depthStencil && + colorsNull == otherNull && + (colorsNull || other._colors.SequenceEqual(_colors)); + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs b/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs new file mode 100644 index 000000000..a364c5716 --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs @@ -0,0 +1,221 @@ +using Silk.NET.Vulkan; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Ryujinx.Graphics.Vulkan +{ + internal class RenderPassHolder + { + private readonly struct FramebufferCacheKey : IRefEquatable + { + private readonly uint _width; + private readonly uint _height; + private readonly uint _layers; + + public FramebufferCacheKey(uint width, uint height, uint layers) + { + _width = width; + _height = height; + _layers = layers; + } + + public override int GetHashCode() + { + return HashCode.Combine(_width, _height, _layers); + } + + public bool Equals(ref FramebufferCacheKey other) + { + return other._width == _width && other._height == _height && other._layers == _layers; + } + } + + private readonly record struct ForcedFence(TextureStorage Texture, PipelineStageFlags StageFlags); + + private readonly TextureView[] _textures; + private readonly Auto _renderPass; + private readonly HashTableSlim> _framebuffers; + private readonly RenderPassCacheKey _key; + private readonly List _forcedFences; + + public unsafe RenderPassHolder(VulkanRenderer gd, Device device, RenderPassCacheKey key, FramebufferParams fb) + { + // Create render pass using framebuffer params. + + const int MaxAttachments = Constants.MaxRenderTargets + 1; + + AttachmentDescription[] attachmentDescs = null; + + var subpass = new SubpassDescription + { + PipelineBindPoint = PipelineBindPoint.Graphics, + }; + + AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments]; + + var hasFramebuffer = fb != null; + + if (hasFramebuffer && fb.AttachmentsCount != 0) + { + attachmentDescs = new AttachmentDescription[fb.AttachmentsCount]; + + for (int i = 0; i < fb.AttachmentsCount; i++) + { + attachmentDescs[i] = new AttachmentDescription( + 0, + fb.AttachmentFormats[i], + TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, fb.AttachmentSamples[i]), + AttachmentLoadOp.Load, + AttachmentStoreOp.Store, + AttachmentLoadOp.Load, + AttachmentStoreOp.Store, + ImageLayout.General, + ImageLayout.General); + } + + int colorAttachmentsCount = fb.ColorAttachmentsCount; + + if (colorAttachmentsCount > MaxAttachments - 1) + { + colorAttachmentsCount = MaxAttachments - 1; + } + + if (colorAttachmentsCount != 0) + { + int maxAttachmentIndex = fb.MaxColorAttachmentIndex; + subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1; + subpass.PColorAttachments = &attachmentReferences[0]; + + // Fill with VK_ATTACHMENT_UNUSED to cover any gaps. + for (int i = 0; i <= maxAttachmentIndex; i++) + { + subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined); + } + + for (int i = 0; i < colorAttachmentsCount; i++) + { + int bindIndex = fb.AttachmentIndices[i]; + + subpass.PColorAttachments[bindIndex] = new AttachmentReference((uint)i, ImageLayout.General); + } + } + + if (fb.HasDepthStencil) + { + uint dsIndex = (uint)fb.AttachmentsCount - 1; + + subpass.PDepthStencilAttachment = &attachmentReferences[MaxAttachments - 1]; + *subpass.PDepthStencilAttachment = new AttachmentReference(dsIndex, ImageLayout.General); + } + } + + var subpassDependency = PipelineConverter.CreateSubpassDependency(gd); + + fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs) + { + var renderPassCreateInfo = new RenderPassCreateInfo + { + SType = StructureType.RenderPassCreateInfo, + PAttachments = pAttachmentDescs, + AttachmentCount = attachmentDescs != null ? (uint)attachmentDescs.Length : 0, + PSubpasses = &subpass, + SubpassCount = 1, + PDependencies = &subpassDependency, + DependencyCount = 1, + }; + + gd.Api.CreateRenderPass(device, in renderPassCreateInfo, null, out var renderPass).ThrowOnError(); + + _renderPass = new Auto(new DisposableRenderPass(gd.Api, device, renderPass)); + } + + _framebuffers = new HashTableSlim>(); + + // Register this render pass with all render target views. + + var textures = fb.GetAttachmentViews(); + + foreach (var texture in textures) + { + texture.AddRenderPass(key, this); + } + + _textures = textures; + _key = key; + + _forcedFences = new List(); + } + + public Auto GetFramebuffer(VulkanRenderer gd, CommandBufferScoped cbs, FramebufferParams fb) + { + var key = new FramebufferCacheKey(fb.Width, fb.Height, fb.Layers); + + if (!_framebuffers.TryGetValue(ref key, out Auto result)) + { + result = fb.Create(gd.Api, cbs, _renderPass); + + _framebuffers.Add(ref key, result); + } + + return result; + } + + public Auto GetRenderPass() + { + return _renderPass; + } + + public void AddForcedFence(TextureStorage storage, PipelineStageFlags stageFlags) + { + if (!_forcedFences.Any(fence => fence.Texture == storage)) + { + _forcedFences.Add(new ForcedFence(storage, stageFlags)); + } + } + + public void InsertForcedFences(CommandBufferScoped cbs) + { + if (_forcedFences.Count > 0) + { + _forcedFences.RemoveAll((entry) => + { + if (entry.Texture.Disposed) + { + return true; + } + + entry.Texture.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, entry.StageFlags); + + return false; + }); + } + } + + public bool ContainsAttachment(TextureStorage storage) + { + return _textures.Any(view => view.Storage == storage); + } + + public void Dispose() + { + // Dispose all framebuffers. + + foreach (var fb in _framebuffers.Values) + { + fb.Dispose(); + } + + // Notify all texture views that this render pass has been disposed. + + foreach (var texture in _textures) + { + texture.RemoveRenderPass(_key); + } + + // Dispose render pass. + + _renderPass.Dispose(); + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/ResourceArray.cs b/src/Ryujinx.Graphics.Vulkan/ResourceArray.cs new file mode 100644 index 000000000..f96b4a845 --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/ResourceArray.cs @@ -0,0 +1,81 @@ +using Silk.NET.Vulkan; +using System; +using System.Diagnostics; + +namespace Ryujinx.Graphics.Vulkan +{ + class ResourceArray : IDisposable + { + private DescriptorSet[] _cachedDescriptorSets; + + private ShaderCollection _cachedDscProgram; + private int _cachedDscSetIndex; + private int _cachedDscIndex; + + private int _bindCount; + + protected void SetDirty(VulkanRenderer gd, bool isImage) + { + ReleaseDescriptorSet(); + + if (_bindCount != 0) + { + if (isImage) + { + gd.PipelineInternal.ForceImageDirty(); + } + else + { + gd.PipelineInternal.ForceTextureDirty(); + } + } + } + + public bool TryGetCachedDescriptorSets(CommandBufferScoped cbs, ShaderCollection program, int setIndex, out DescriptorSet[] sets) + { + if (_cachedDescriptorSets != null) + { + _cachedDscProgram.UpdateManualDescriptorSetCollectionOwnership(cbs, _cachedDscSetIndex, _cachedDscIndex); + + sets = _cachedDescriptorSets; + + return true; + } + + var dsc = program.GetNewManualDescriptorSetCollection(cbs, setIndex, out _cachedDscIndex).Get(cbs); + + sets = dsc.GetSets(); + + _cachedDescriptorSets = sets; + _cachedDscProgram = program; + _cachedDscSetIndex = setIndex; + + return false; + } + + public void IncrementBindCount() + { + _bindCount++; + } + + public void DecrementBindCount() + { + int newBindCount = --_bindCount; + Debug.Assert(newBindCount >= 0); + } + + private void ReleaseDescriptorSet() + { + if (_cachedDescriptorSets != null) + { + _cachedDscProgram.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex); + _cachedDescriptorSets = null; + } + } + + public void Dispose() + { + ReleaseDescriptorSet(); + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/ResourceBindingSegment.cs b/src/Ryujinx.Graphics.Vulkan/ResourceBindingSegment.cs index 8902f13e6..6e27da4a6 100644 --- a/src/Ryujinx.Graphics.Vulkan/ResourceBindingSegment.cs +++ b/src/Ryujinx.Graphics.Vulkan/ResourceBindingSegment.cs @@ -8,13 +8,15 @@ namespace Ryujinx.Graphics.Vulkan public readonly int Count; public readonly ResourceType Type; public readonly ResourceStages Stages; + public readonly bool IsArray; - public ResourceBindingSegment(int binding, int count, ResourceType type, ResourceStages stages) + public ResourceBindingSegment(int binding, int count, ResourceType type, ResourceStages stages, bool isArray) { Binding = binding; Count = count; Type = type; Stages = stages; + IsArray = isArray; } } } diff --git a/src/Ryujinx.Graphics.Vulkan/ResourceLayoutBuilder.cs b/src/Ryujinx.Graphics.Vulkan/ResourceLayoutBuilder.cs index f5ac39684..730a0a2f9 100644 --- a/src/Ryujinx.Graphics.Vulkan/ResourceLayoutBuilder.cs +++ b/src/Ryujinx.Graphics.Vulkan/ResourceLayoutBuilder.cs @@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Vulkan } } - public ResourceLayoutBuilder Add(ResourceStages stages, ResourceType type, int binding) + public ResourceLayoutBuilder Add(ResourceStages stages, ResourceType type, int binding, bool write = false) { int setIndex = type switch { @@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.Vulkan }; _resourceDescriptors[setIndex].Add(new ResourceDescriptor(binding, 1, type, stages)); - _resourceUsages[setIndex].Add(new ResourceUsage(binding, type, stages)); + _resourceUsages[setIndex].Add(new ResourceUsage(binding, 1, type, stages, write)); return this; } diff --git a/src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj b/src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj index f6a7be91e..aae28733f 100644 --- a/src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj +++ b/src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Ryujinx.Graphics.Vulkan/SamplerHolder.cs b/src/Ryujinx.Graphics.Vulkan/SamplerHolder.cs index f67daeecc..7f37ab139 100644 --- a/src/Ryujinx.Graphics.Vulkan/SamplerHolder.cs +++ b/src/Ryujinx.Graphics.Vulkan/SamplerHolder.cs @@ -68,7 +68,7 @@ namespace Ryujinx.Graphics.Vulkan samplerCreateInfo.BorderColor = BorderColor.FloatCustomExt; } - gd.Api.CreateSampler(device, samplerCreateInfo, null, out var sampler).ThrowOnError(); + gd.Api.CreateSampler(device, in samplerCreateInfo, null, out var sampler).ThrowOnError(); _sampler = new Auto(new DisposableSampler(gd.Api, device, sampler)); } diff --git a/src/Ryujinx.Graphics.Vulkan/SemaphoreHolder.cs b/src/Ryujinx.Graphics.Vulkan/SemaphoreHolder.cs deleted file mode 100644 index 618a7d488..000000000 --- a/src/Ryujinx.Graphics.Vulkan/SemaphoreHolder.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Silk.NET.Vulkan; -using System; -using System.Threading; -using VkSemaphore = Silk.NET.Vulkan.Semaphore; - -namespace Ryujinx.Graphics.Vulkan -{ - class SemaphoreHolder : IDisposable - { - private readonly Vk _api; - private readonly Device _device; - private VkSemaphore _semaphore; - private int _referenceCount; - private bool _disposed; - - public unsafe SemaphoreHolder(Vk api, Device device) - { - _api = api; - _device = device; - - var semaphoreCreateInfo = new SemaphoreCreateInfo - { - SType = StructureType.SemaphoreCreateInfo, - }; - - api.CreateSemaphore(device, in semaphoreCreateInfo, null, out _semaphore).ThrowOnError(); - - _referenceCount = 1; - } - - public VkSemaphore GetUnsafe() - { - return _semaphore; - } - - public VkSemaphore Get() - { - Interlocked.Increment(ref _referenceCount); - return _semaphore; - } - - public unsafe void Put() - { - if (Interlocked.Decrement(ref _referenceCount) == 0) - { - _api.DestroySemaphore(_device, _semaphore, null); - _semaphore = default; - } - } - - public void Dispose() - { - if (!_disposed) - { - Put(); - _disposed = true; - } - } - } -} diff --git a/src/Ryujinx.Graphics.Vulkan/Shader.cs b/src/Ryujinx.Graphics.Vulkan/Shader.cs index 06f3499db..1c8caffd9 100644 --- a/src/Ryujinx.Graphics.Vulkan/Shader.cs +++ b/src/Ryujinx.Graphics.Vulkan/Shader.cs @@ -64,7 +64,7 @@ namespace Ryujinx.Graphics.Vulkan PCode = (uint*)pCode, }; - api.CreateShaderModule(device, shaderModuleCreateInfo, null, out _module).ThrowOnError(); + api.CreateShaderModule(device, in shaderModuleCreateInfo, null, out _module).ThrowOnError(); } CompileStatus = ProgramLinkStatus.Success; diff --git a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs index d01eebf3a..c9aab4018 100644 --- a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs +++ b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs @@ -21,11 +21,18 @@ namespace Ryujinx.Graphics.Vulkan public bool HasMinimalLayout { get; } public bool UsePushDescriptors { get; } public bool IsCompute { get; } + public bool HasTessellationControlShader => (Stages & (1u << 3)) != 0; + + public bool UpdateTexturesWithoutTemplate { get; } public uint Stages { get; } + public PipelineStageFlags IncoherentBufferWriteStages { get; } + public PipelineStageFlags IncoherentTextureWriteStages { get; } + public ResourceBindingSegment[][] ClearSegments { get; } public ResourceBindingSegment[][] BindingSegments { get; } + public DescriptorSetTemplate[] Templates { get; } public ProgramLinkStatus LinkStatus { get; private set; } @@ -107,17 +114,30 @@ namespace Ryujinx.Graphics.Vulkan _shaders = internalShaders; - bool usePushDescriptors = !isMinimal && VulkanConfiguration.UsePushDescriptors && _gd.Capabilities.SupportsPushDescriptors; + bool usePushDescriptors = !isMinimal && + VulkanConfiguration.UsePushDescriptors && + _gd.Capabilities.SupportsPushDescriptors && + !IsCompute && + !HasPushDescriptorsBug(gd) && + CanUsePushDescriptors(gd, resourceLayout, IsCompute); - _plce = gd.PipelineLayoutCache.GetOrCreate(gd, device, resourceLayout.Sets, usePushDescriptors); + ReadOnlyCollection sets = usePushDescriptors ? + BuildPushDescriptorSets(gd, resourceLayout.Sets) : resourceLayout.Sets; + + _plce = gd.PipelineLayoutCache.GetOrCreate(gd, device, sets, usePushDescriptors); HasMinimalLayout = isMinimal; UsePushDescriptors = usePushDescriptors; Stages = stages; - ClearSegments = BuildClearSegments(resourceLayout.Sets); - BindingSegments = BuildBindingSegments(resourceLayout.SetUsages); + ClearSegments = BuildClearSegments(sets); + BindingSegments = BuildBindingSegments(resourceLayout.SetUsages, out bool usesBufferTextures); + Templates = BuildTemplates(usePushDescriptors); + (IncoherentBufferWriteStages, IncoherentTextureWriteStages) = BuildIncoherentStages(resourceLayout.SetUsages); + + // Updating buffer texture bindings using template updates crashes the Adreno driver on Windows. + UpdateTexturesWithoutTemplate = gd.IsQualcommProprietary && usesBufferTextures; _compileTask = Task.CompletedTask; _firstBackgroundUse = false; @@ -137,6 +157,82 @@ namespace Ryujinx.Graphics.Vulkan _firstBackgroundUse = !fromCache; } + private static bool HasPushDescriptorsBug(VulkanRenderer gd) + { + // Those GPUs/drivers do not work properly with push descriptors, so we must force disable them. + return gd.IsNvidiaPreTuring || (gd.IsIntelArc && gd.IsIntelWindows); + } + + private static bool CanUsePushDescriptors(VulkanRenderer gd, ResourceLayout layout, bool isCompute) + { + // If binding 3 is immediately used, use an alternate set of reserved bindings. + ReadOnlyCollection uniformUsage = layout.SetUsages[0].Usages; + bool hasBinding3 = uniformUsage.Any(x => x.Binding == 3); + int[] reserved = isCompute ? Array.Empty() : gd.GetPushDescriptorReservedBindings(hasBinding3); + + // Can't use any of the reserved usages. + for (int i = 0; i < uniformUsage.Count; i++) + { + var binding = uniformUsage[i].Binding; + + if (reserved.Contains(binding) || + binding >= Constants.MaxPushDescriptorBinding || + binding >= gd.Capabilities.MaxPushDescriptors + reserved.Count(id => id < binding)) + { + return false; + } + } + + return true; + } + + private static ReadOnlyCollection BuildPushDescriptorSets( + VulkanRenderer gd, + ReadOnlyCollection sets) + { + // The reserved bindings were selected when determining if push descriptors could be used. + int[] reserved = gd.GetPushDescriptorReservedBindings(false); + + var result = new ResourceDescriptorCollection[sets.Count]; + + for (int i = 0; i < sets.Count; i++) + { + if (i == 0) + { + // Push descriptors apply here. Remove reserved bindings. + ResourceDescriptorCollection original = sets[i]; + + var pdUniforms = new ResourceDescriptor[original.Descriptors.Count]; + int j = 0; + + foreach (ResourceDescriptor descriptor in original.Descriptors) + { + if (reserved.Contains(descriptor.Binding)) + { + // If the binding is reserved, set its descriptor count to 0. + pdUniforms[j++] = new ResourceDescriptor( + descriptor.Binding, + 0, + descriptor.Type, + descriptor.Stages); + } + else + { + pdUniforms[j++] = descriptor; + } + } + + result[i] = new ResourceDescriptorCollection(new(pdUniforms)); + } + else + { + result[i] = sets[i]; + } + } + + return new(result); + } + private static ResourceBindingSegment[][] BuildClearSegments(ReadOnlyCollection sets) { ResourceBindingSegment[][] segments = new ResourceBindingSegment[sets.Count][]; @@ -154,7 +250,9 @@ namespace Ryujinx.Graphics.Vulkan if (currentDescriptor.Binding + currentCount != descriptor.Binding || currentDescriptor.Type != descriptor.Type || - currentDescriptor.Stages != descriptor.Stages) + currentDescriptor.Stages != descriptor.Stages || + currentDescriptor.Count > 1 || + descriptor.Count > 1) { if (currentCount != 0) { @@ -162,7 +260,8 @@ namespace Ryujinx.Graphics.Vulkan currentDescriptor.Binding, currentCount, currentDescriptor.Type, - currentDescriptor.Stages)); + currentDescriptor.Stages, + currentDescriptor.Count > 1)); } currentDescriptor = descriptor; @@ -180,7 +279,8 @@ namespace Ryujinx.Graphics.Vulkan currentDescriptor.Binding, currentCount, currentDescriptor.Type, - currentDescriptor.Stages)); + currentDescriptor.Stages, + currentDescriptor.Count > 1)); } segments[setIndex] = currentSegments.ToArray(); @@ -189,8 +289,10 @@ namespace Ryujinx.Graphics.Vulkan return segments; } - private static ResourceBindingSegment[][] BuildBindingSegments(ReadOnlyCollection setUsages) + private static ResourceBindingSegment[][] BuildBindingSegments(ReadOnlyCollection setUsages, out bool usesBufferTextures) { + usesBufferTextures = false; + ResourceBindingSegment[][] segments = new ResourceBindingSegment[setUsages.Count][]; for (int setIndex = 0; setIndex < setUsages.Count; setIndex++) @@ -204,9 +306,16 @@ namespace Ryujinx.Graphics.Vulkan { ResourceUsage usage = setUsages[setIndex].Usages[index]; + if (usage.Type == ResourceType.BufferTexture) + { + usesBufferTextures = true; + } + if (currentUsage.Binding + currentCount != usage.Binding || currentUsage.Type != usage.Type || - currentUsage.Stages != usage.Stages) + currentUsage.Stages != usage.Stages || + currentUsage.ArrayLength > 1 || + usage.ArrayLength > 1) { if (currentCount != 0) { @@ -214,11 +323,12 @@ namespace Ryujinx.Graphics.Vulkan currentUsage.Binding, currentCount, currentUsage.Type, - currentUsage.Stages)); + currentUsage.Stages, + currentUsage.ArrayLength > 1)); } currentUsage = usage; - currentCount = 1; + currentCount = usage.ArrayLength; } else { @@ -232,7 +342,8 @@ namespace Ryujinx.Graphics.Vulkan currentUsage.Binding, currentCount, currentUsage.Type, - currentUsage.Stages)); + currentUsage.Stages, + currentUsage.ArrayLength > 1)); } segments[setIndex] = currentSegments.ToArray(); @@ -241,6 +352,102 @@ namespace Ryujinx.Graphics.Vulkan return segments; } + private DescriptorSetTemplate[] BuildTemplates(bool usePushDescriptors) + { + var templates = new DescriptorSetTemplate[BindingSegments.Length]; + + for (int setIndex = 0; setIndex < BindingSegments.Length; setIndex++) + { + if (usePushDescriptors && setIndex == 0) + { + // Push descriptors get updated using templates owned by the pipeline layout. + continue; + } + + ResourceBindingSegment[] segments = BindingSegments[setIndex]; + + if (segments != null && segments.Length > 0) + { + templates[setIndex] = new DescriptorSetTemplate( + _gd, + _device, + segments, + _plce, + IsCompute ? PipelineBindPoint.Compute : PipelineBindPoint.Graphics, + setIndex); + } + } + + return templates; + } + + private PipelineStageFlags GetPipelineStages(ResourceStages stages) + { + PipelineStageFlags result = 0; + + if ((stages & ResourceStages.Compute) != 0) + { + result |= PipelineStageFlags.ComputeShaderBit; + } + + if ((stages & ResourceStages.Vertex) != 0) + { + result |= PipelineStageFlags.VertexShaderBit; + } + + if ((stages & ResourceStages.Fragment) != 0) + { + result |= PipelineStageFlags.FragmentShaderBit; + } + + if ((stages & ResourceStages.Geometry) != 0) + { + result |= PipelineStageFlags.GeometryShaderBit; + } + + if ((stages & ResourceStages.TessellationControl) != 0) + { + result |= PipelineStageFlags.TessellationControlShaderBit; + } + + if ((stages & ResourceStages.TessellationEvaluation) != 0) + { + result |= PipelineStageFlags.TessellationEvaluationShaderBit; + } + + return result; + } + + private (PipelineStageFlags Buffer, PipelineStageFlags Texture) BuildIncoherentStages(ReadOnlyCollection setUsages) + { + PipelineStageFlags buffer = PipelineStageFlags.None; + PipelineStageFlags texture = PipelineStageFlags.None; + + foreach (var set in setUsages) + { + foreach (var range in set.Usages) + { + if (range.Write) + { + PipelineStageFlags stages = GetPipelineStages(range.Stages); + + switch (range.Type) + { + case ResourceType.Image: + texture |= stages; + break; + case ResourceType.StorageBuffer: + case ResourceType.BufferImage: + buffer |= stages; + break; + } + } + } + } + + return (buffer, texture); + } + private async Task BackgroundCompilation() { await Task.WhenAll(_shaders.Select(shader => shader.CompileTask)); @@ -352,10 +559,11 @@ namespace Ryujinx.Graphics.Vulkan stages[i] = _shaders[i].GetInfo(); } + pipeline.HasTessellationControlShader = HasTessellationControlShader; pipeline.StagesCount = (uint)_shaders.Length; pipeline.PipelineLayout = PipelineLayout; - pipeline.CreateGraphicsPipeline(_gd, _device, this, (_gd.Pipeline as PipelineBase).PipelineCache, renderPass.Value); + pipeline.CreateGraphicsPipeline(_gd, _device, this, (_gd.Pipeline as PipelineBase).PipelineCache, renderPass.Value, throwOnError: true); pipeline.Dispose(); } @@ -414,6 +622,11 @@ namespace Ryujinx.Graphics.Vulkan return null; } + public DescriptorSetTemplate GetPushDescriptorTemplate(long updateMask) + { + return _plce.GetPushDescriptorTemplate(IsCompute ? PipelineBindPoint.Compute : PipelineBindPoint.Graphics, updateMask); + } + public void AddComputePipeline(ref SpecData key, Auto pipeline) { (_computePipelineCache ??= new()).Add(ref key, pipeline); @@ -474,6 +687,26 @@ namespace Ryujinx.Graphics.Vulkan return _plce.GetNewDescriptorSetCollection(setIndex, out isNew); } + public Auto GetNewManualDescriptorSetCollection(CommandBufferScoped cbs, int setIndex, out int cacheIndex) + { + return _plce.GetNewManualDescriptorSetCollection(cbs, setIndex, out cacheIndex); + } + + public void UpdateManualDescriptorSetCollectionOwnership(CommandBufferScoped cbs, int setIndex, int cacheIndex) + { + _plce.UpdateManualDescriptorSetCollectionOwnership(cbs, setIndex, cacheIndex); + } + + public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex) + { + _plce.ReleaseManualDescriptorSetCollection(setIndex, cacheIndex); + } + + public bool HasSameLayout(ShaderCollection other) + { + return other != null && _plce == other._plce; + } + protected virtual void Dispose(bool disposing) { if (disposing) @@ -492,7 +725,7 @@ namespace Ryujinx.Graphics.Vulkan { foreach (Auto pipeline in _graphicsPipelineCache.Values) { - pipeline.Dispose(); + pipeline?.Dispose(); } } @@ -504,6 +737,11 @@ namespace Ryujinx.Graphics.Vulkan } } + for (int i = 0; i < Templates.Length; i++) + { + Templates[i]?.Dispose(); + } + if (_dummyRenderPass.Value.Handle != 0) { _dummyRenderPass.Dispose(); diff --git a/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs b/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs index 3a02a28dc..90a47bb67 100644 --- a/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs +++ b/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs @@ -1,5 +1,6 @@ using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.Graphics.GAL; using System; using System.Collections.Generic; using System.Diagnostics; @@ -29,6 +30,9 @@ namespace Ryujinx.Graphics.Vulkan private readonly VulkanRenderer _gd; private readonly BufferHolder _buffer; + private readonly int _resourceAlignment; + + public readonly BufferHandle Handle; private readonly struct PendingCopy { @@ -48,9 +52,10 @@ namespace Ryujinx.Graphics.Vulkan public StagingBuffer(VulkanRenderer gd, BufferManager bufferManager) { _gd = gd; - _buffer = bufferManager.Create(gd, BufferSize); + Handle = bufferManager.CreateWithHandle(gd, BufferSize, out _buffer); _pendingCopies = new Queue(); _freeSize = BufferSize; + _resourceAlignment = (int)gd.Capabilities.MinResourceAlignment; } public void PushData(CommandBufferPool cbp, CommandBufferScoped? cbs, Action endRenderPass, BufferHolder dst, int dstOffset, ReadOnlySpan data) @@ -197,7 +202,7 @@ namespace Ryujinx.Graphics.Vulkan /// Reserve a range on the staging buffer for the current command buffer and upload data to it. /// /// Command buffer to reserve the data on - /// The data to upload + /// The minimum size the reserved data requires /// The required alignment for the buffer offset /// The reserved range of the staging buffer public unsafe StagingBufferReserved? TryReserveData(CommandBufferScoped cbs, int size, int alignment) @@ -223,6 +228,18 @@ namespace Ryujinx.Graphics.Vulkan return ReserveDataImpl(cbs, size, alignment); } + /// + /// Reserve a range on the staging buffer for the current command buffer and upload data to it. + /// Uses the most permissive byte alignment. + /// + /// Command buffer to reserve the data on + /// The minimum size the reserved data requires + /// The reserved range of the staging buffer + public unsafe StagingBufferReserved? TryReserveData(CommandBufferScoped cbs, int size) + { + return TryReserveData(cbs, size, _resourceAlignment); + } + private bool WaitFreeCompleted(CommandBufferPool cbp) { if (_pendingCopies.TryPeek(out var pc)) @@ -263,7 +280,7 @@ namespace Ryujinx.Graphics.Vulkan { if (disposing) { - _buffer.Dispose(); + _gd.BufferManager.Delete(Handle); while (_pendingCopies.TryDequeue(out var pc)) { diff --git a/src/Ryujinx.Graphics.Vulkan/TextureArray.cs b/src/Ryujinx.Graphics.Vulkan/TextureArray.cs new file mode 100644 index 000000000..99238b1f5 --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/TextureArray.cs @@ -0,0 +1,234 @@ +using Ryujinx.Graphics.GAL; +using Silk.NET.Vulkan; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Vulkan +{ + class TextureArray : ResourceArray, ITextureArray + { + private readonly VulkanRenderer _gd; + + private struct TextureRef + { + public TextureStorage Storage; + public Auto View; + public Auto Sampler; + } + + private readonly TextureRef[] _textureRefs; + private readonly TextureBuffer[] _bufferTextureRefs; + + private readonly DescriptorImageInfo[] _textures; + private readonly BufferView[] _bufferTextures; + + private HashSet _storages; + + private int _cachedCommandBufferIndex; + private int _cachedSubmissionCount; + + private readonly bool _isBuffer; + + public TextureArray(VulkanRenderer gd, int size, bool isBuffer) + { + _gd = gd; + + if (isBuffer) + { + _bufferTextureRefs = new TextureBuffer[size]; + _bufferTextures = new BufferView[size]; + } + else + { + _textureRefs = new TextureRef[size]; + _textures = new DescriptorImageInfo[size]; + } + + _storages = null; + + _cachedCommandBufferIndex = -1; + _cachedSubmissionCount = 0; + + _isBuffer = isBuffer; + } + + public void SetSamplers(int index, ISampler[] samplers) + { + for (int i = 0; i < samplers.Length; i++) + { + ISampler sampler = samplers[i]; + + if (sampler is SamplerHolder samplerHolder) + { + _textureRefs[index + i].Sampler = samplerHolder.GetSampler(); + } + else + { + _textureRefs[index + i].Sampler = default; + } + } + + SetDirty(); + } + + public void SetTextures(int index, ITexture[] textures) + { + for (int i = 0; i < textures.Length; i++) + { + ITexture texture = textures[i]; + + if (texture is TextureBuffer textureBuffer) + { + _bufferTextureRefs[index + i] = textureBuffer; + } + else if (texture is TextureView view) + { + _textureRefs[index + i].Storage = view.Storage; + _textureRefs[index + i].View = view.GetImageView(); + } + else if (!_isBuffer) + { + _textureRefs[index + i].Storage = null; + _textureRefs[index + i].View = default; + } + else + { + _bufferTextureRefs[index + i] = null; + } + } + + SetDirty(); + } + + private void SetDirty() + { + _cachedCommandBufferIndex = -1; + _storages = null; + SetDirty(_gd, isImage: false); + } + + public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags) + { + HashSet storages = _storages; + + if (storages == null) + { + storages = new HashSet(); + + for (int index = 0; index < _textureRefs.Length; index++) + { + if (_textureRefs[index].Storage != null) + { + storages.Add(_textureRefs[index].Storage); + } + } + + _storages = storages; + } + + foreach (TextureStorage storage in storages) + { + storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stageFlags); + } + } + + public ReadOnlySpan GetImageInfos(VulkanRenderer gd, CommandBufferScoped cbs, TextureView dummyTexture, SamplerHolder dummySampler) + { + int submissionCount = gd.CommandBufferPool.GetSubmissionCount(cbs.CommandBufferIndex); + + Span textures = _textures; + + if (cbs.CommandBufferIndex == _cachedCommandBufferIndex && submissionCount == _cachedSubmissionCount) + { + return textures; + } + + _cachedCommandBufferIndex = cbs.CommandBufferIndex; + _cachedSubmissionCount = submissionCount; + + for (int i = 0; i < textures.Length; i++) + { + ref var texture = ref textures[i]; + ref var refs = ref _textureRefs[i]; + + if (i > 0 && _textureRefs[i - 1].View == refs.View && _textureRefs[i - 1].Sampler == refs.Sampler) + { + texture = textures[i - 1]; + + continue; + } + + texture.ImageLayout = ImageLayout.General; + texture.ImageView = refs.View?.Get(cbs).Value ?? default; + texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default; + + if (texture.ImageView.Handle == 0) + { + texture.ImageView = dummyTexture.GetImageView().Get(cbs).Value; + } + + if (texture.Sampler.Handle == 0) + { + texture.Sampler = dummySampler.GetSampler().Get(cbs).Value; + } + } + + return textures; + } + + public ReadOnlySpan GetBufferViews(CommandBufferScoped cbs) + { + Span bufferTextures = _bufferTextures; + + for (int i = 0; i < bufferTextures.Length; i++) + { + bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, false) ?? default; + } + + return bufferTextures; + } + + public DescriptorSet[] GetDescriptorSets( + Device device, + CommandBufferScoped cbs, + DescriptorSetTemplateUpdater templateUpdater, + ShaderCollection program, + int setIndex, + TextureView dummyTexture, + SamplerHolder dummySampler) + { + if (TryGetCachedDescriptorSets(cbs, program, setIndex, out DescriptorSet[] sets)) + { + // We still need to ensure the current command buffer holds a reference to all used textures. + + if (!_isBuffer) + { + GetImageInfos(_gd, cbs, dummyTexture, dummySampler); + } + else + { + GetBufferViews(cbs); + } + + return sets; + } + + DescriptorSetTemplate template = program.Templates[setIndex]; + + DescriptorSetTemplateWriter tu = templateUpdater.Begin(template); + + if (!_isBuffer) + { + tu.Push(GetImageInfos(_gd, cbs, dummyTexture, dummySampler)); + } + else + { + tu.Push(GetBufferViews(cbs)); + } + + templateUpdater.Commit(_gd, device, sets[0]); + + return sets; + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/TextureBuffer.cs b/src/Ryujinx.Graphics.Vulkan/TextureBuffer.cs index 5cb8b8f49..52589d69b 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureBuffer.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureBuffer.cs @@ -17,7 +17,6 @@ namespace Ryujinx.Graphics.Vulkan private int _offset; private int _size; private Auto _bufferView; - private Dictionary> _selfManagedViews; private int _bufferCount; @@ -81,33 +80,26 @@ namespace Ryujinx.Graphics.Vulkan private void ReleaseImpl() { - if (_selfManagedViews != null) - { - foreach (var bufferView in _selfManagedViews.Values) - { - bufferView.Dispose(); - } - - _selfManagedViews = null; - } - _bufferView?.Dispose(); _bufferView = null; } - public void SetData(IMemoryOwner data) + /// + public void SetData(MemoryOwner data) { - _gd.SetBufferData(_bufferHandle, _offset, data.Memory.Span); + _gd.SetBufferData(_bufferHandle, _offset, data.Span); data.Dispose(); } - public void SetData(IMemoryOwner data, int layer, int level) + /// + public void SetData(MemoryOwner data, int layer, int level) { data.Dispose(); throw new NotSupportedException(); } - public void SetData(IMemoryOwner data, int layer, int level, Rectangle region) + /// + public void SetData(MemoryOwner data, int layer, int level, Rectangle region) { data.Dispose(); throw new NotSupportedException(); @@ -137,28 +129,5 @@ namespace Ryujinx.Graphics.Vulkan return _bufferView?.Get(cbs, _offset, _size, write).Value ?? default; } - - public BufferView GetBufferView(CommandBufferScoped cbs, Format format, bool write) - { - var vkFormat = FormatTable.GetFormat(format); - if (vkFormat == VkFormat) - { - return GetBufferView(cbs, write); - } - - if (_selfManagedViews != null && _selfManagedViews.TryGetValue(format, out var bufferView)) - { - return bufferView.Get(cbs, _offset, _size, write).Value; - } - - bufferView = _gd.BufferManager.CreateView(_bufferHandle, vkFormat, _offset, _size, ReleaseImpl); - - if (bufferView != null) - { - (_selfManagedViews ??= new Dictionary>()).Add(format, bufferView); - } - - return bufferView?.Get(cbs, _offset, _size, write).Value ?? default; - } } } diff --git a/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs b/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs index 7c06a5df6..45cddd772 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs @@ -88,7 +88,7 @@ namespace Ryujinx.Graphics.Vulkan DstOffsets = dstOffsets, }; - api.CmdBlitImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region, filter); + api.CmdBlitImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, in region, filter); copySrcLevel++; copyDstLevel++; @@ -320,13 +320,13 @@ namespace Ryujinx.Graphics.Vulkan { var region = new ImageResolve(srcSl, new Offset3D(0, 0, srcZ), dstSl, new Offset3D(0, 0, dstZ), extent); - api.CmdResolveImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region); + api.CmdResolveImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, in region); } else { var region = new ImageCopy(srcSl, new Offset3D(0, 0, srcZ), dstSl, new Offset3D(0, 0, dstZ), extent); - api.CmdCopyImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region); + api.CmdCopyImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, in region); } width = Math.Max(1, width >> 1); @@ -407,7 +407,7 @@ namespace Ryujinx.Graphics.Vulkan ImageLayout.General, ImageLayout.General); - var subpassDependency = PipelineConverter.CreateSubpassDependency2(); + var subpassDependency = PipelineConverter.CreateSubpassDependency2(gd); fixed (AttachmentDescription2* pAttachmentDescs = attachmentDescs) { @@ -422,7 +422,7 @@ namespace Ryujinx.Graphics.Vulkan DependencyCount = 1, }; - gd.Api.CreateRenderPass2(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError(); + gd.Api.CreateRenderPass2(device, in renderPassCreateInfo, null, out var renderPass).ThrowOnError(); using var rp = new Auto(new DisposableRenderPass(gd.Api, device, renderPass)); @@ -445,7 +445,7 @@ namespace Ryujinx.Graphics.Vulkan Layers = (uint)src.Layers, }; - gd.Api.CreateFramebuffer(device, framebufferCreateInfo, null, out var framebuffer).ThrowOnError(); + gd.Api.CreateFramebuffer(device, in framebufferCreateInfo, null, out var framebuffer).ThrowOnError(); using var fb = new Auto(new DisposableFramebuffer(gd.Api, device, framebuffer), null, srcView, dstView); var renderArea = new Rect2D(null, new Extent2D((uint)src.Info.Width, (uint)src.Info.Height)); @@ -465,7 +465,7 @@ namespace Ryujinx.Graphics.Vulkan // to resolve the depth-stencil texture. // TODO: Do speculative resolve and part of the same render pass as the draw to avoid // ending the current render pass? - gd.Api.CmdBeginRenderPass(cbs.CommandBuffer, renderPassBeginInfo, SubpassContents.Inline); + gd.Api.CmdBeginRenderPass(cbs.CommandBuffer, in renderPassBeginInfo, SubpassContents.Inline); gd.Api.CmdEndRenderPass(cbs.CommandBuffer); } } diff --git a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs index b763fa987..10b36a3f9 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs @@ -4,6 +4,7 @@ using Silk.NET.Vulkan; using System; using System.Collections.Generic; using System.Numerics; +using System.Runtime.CompilerServices; using Format = Ryujinx.Graphics.GAL.Format; using VkBuffer = Silk.NET.Vulkan.Buffer; using VkFormat = Silk.NET.Vulkan.Format; @@ -12,6 +13,11 @@ namespace Ryujinx.Graphics.Vulkan { class TextureStorage : IDisposable { + private struct TextureSliceInfo + { + public int BindCount; + } + private const MemoryPropertyFlags DefaultImageMemoryFlags = MemoryPropertyFlags.DeviceLocalBit; @@ -38,9 +44,12 @@ namespace Ryujinx.Graphics.Vulkan public TextureCreateInfo Info => _info; + public bool Disposed { get; private set; } + private readonly Image _image; private readonly Auto _imageAuto; private readonly Auto _allocationAuto; + private readonly int _depthOrLayers; private Auto _foreignAllocationAuto; private Dictionary _aliasedStorages; @@ -53,6 +62,9 @@ namespace Ryujinx.Graphics.Vulkan private int _viewsCount; private readonly ulong _size; + private int _bindCount; + private readonly TextureSliceInfo[] _slices; + public VkFormat VkFormat { get; } public unsafe TextureStorage( @@ -71,6 +83,7 @@ namespace Ryujinx.Graphics.Vulkan var depth = (uint)(info.Target == Target.Texture3D ? info.Depth : 1); VkFormat = format; + _depthOrLayers = info.GetDepthOrLayers(); var type = info.Target.Convert(); @@ -78,9 +91,9 @@ namespace Ryujinx.Graphics.Vulkan var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples); - var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample); + var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities); - var flags = ImageCreateFlags.CreateMutableFormatBit; + var flags = ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit; // This flag causes mipmapped texture arrays to break on AMD GCN, so for that copy dependencies are forced for aliasing as cube. bool isCube = info.Target == Target.Cubemap || info.Target == Target.CubemapArray; @@ -112,7 +125,7 @@ namespace Ryujinx.Graphics.Vulkan Flags = flags, }; - gd.Api.CreateImage(device, imageCreateInfo, null, out _image).ThrowOnError(); + gd.Api.CreateImage(device, in imageCreateInfo, null, out _image).ThrowOnError(); if (foreignAllocation == null) { @@ -146,6 +159,8 @@ namespace Ryujinx.Graphics.Vulkan InitialTransition(ImageLayout.Preinitialized, ImageLayout.General); } + + _slices = new TextureSliceInfo[levels * _depthOrLayers]; } public TextureStorage CreateAliasedColorForDepthStorageUnsafe(Format format) @@ -154,9 +169,8 @@ namespace Ryujinx.Graphics.Vulkan { Format.S8Uint => Format.R8Unorm, Format.D16Unorm => Format.R16Unorm, - Format.S8UintD24Unorm => Format.R8G8B8A8Unorm, + Format.D24UnormS8Uint or Format.S8UintD24Unorm or Format.X8UintD24Unorm => Format.R8G8B8A8Unorm, Format.D32Float => Format.R32Float, - Format.D24UnormS8Uint => Format.R8G8B8A8Unorm, Format.D32FloatS8Uint => Format.R32G32Float, _ => throw new ArgumentException($"\"{format}\" is not a supported depth or stencil format."), }; @@ -283,7 +297,7 @@ namespace Ryujinx.Graphics.Vulkan 0, null, 1, - barrier); + in barrier); if (useTempCbs) { @@ -291,7 +305,7 @@ namespace Ryujinx.Graphics.Vulkan } } - public static ImageUsageFlags GetImageUsage(Format format, Target target, bool supportsMsStorage) + public static ImageUsageFlags GetImageUsage(Format format, Target target, in HardwareCapabilities capabilities) { var usage = DefaultUsageFlags; @@ -304,11 +318,19 @@ namespace Ryujinx.Graphics.Vulkan usage |= ImageUsageFlags.ColorAttachmentBit; } + bool supportsMsStorage = capabilities.SupportsShaderStorageImageMultisample; + if (format.IsImageCompatible() && (supportsMsStorage || !target.IsMultisample())) { usage |= ImageUsageFlags.StorageBit; } + if (capabilities.SupportsAttachmentFeedbackLoop && + (usage & (ImageUsageFlags.DepthStencilAttachmentBit | ImageUsageFlags.ColorAttachmentBit)) != 0) + { + usage |= ImageUsageFlags.AttachmentFeedbackLoopBitExt; + } + return usage; } @@ -400,11 +422,11 @@ namespace Ryujinx.Graphics.Vulkan if (to) { - _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region); + _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, in region); } else { - _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region); + _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, in region); } offset += mipSize; @@ -434,104 +456,130 @@ namespace Ryujinx.Graphics.Vulkan return FormatCapabilities.IsD24S8(Info.Format) && VkFormat == VkFormat.D32SfloatS8Uint; } - public void SetModification(AccessFlags accessFlags, PipelineStageFlags stage) + public void AddStoreOpUsage(bool depthStencil) { - _lastModificationAccess = accessFlags; - _lastModificationStage = stage; + _lastModificationStage = depthStencil ? + PipelineStageFlags.LateFragmentTestsBit : + PipelineStageFlags.ColorAttachmentOutputBit; + + _lastModificationAccess = depthStencil ? + AccessFlags.DepthStencilAttachmentWriteBit : + AccessFlags.ColorAttachmentWriteBit; } - public void InsertReadToWriteBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags, bool insideRenderPass) + public void QueueLoadOpBarrier(CommandBufferScoped cbs, bool depthStencil) { - var lastReadStage = _lastReadStage; + PipelineStageFlags srcStageFlags = _lastReadStage | _lastModificationStage; + PipelineStageFlags dstStageFlags = depthStencil ? + PipelineStageFlags.EarlyFragmentTestsBit | PipelineStageFlags.LateFragmentTestsBit : + PipelineStageFlags.ColorAttachmentOutputBit; - if (insideRenderPass) + AccessFlags srcAccessFlags = _lastModificationAccess | _lastReadAccess; + AccessFlags dstAccessFlags = depthStencil ? + AccessFlags.DepthStencilAttachmentWriteBit | AccessFlags.DepthStencilAttachmentReadBit : + AccessFlags.ColorAttachmentWriteBit | AccessFlags.ColorAttachmentReadBit; + + if (srcAccessFlags != AccessFlags.None) { - // We can't have barrier from compute inside a render pass, - // as it is invalid to specify compute in the subpass dependency stage mask. + ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags(); + ImageMemoryBarrier barrier = TextureView.GetImageBarrier( + _imageAuto.Get(cbs).Value, + srcAccessFlags, + dstAccessFlags, + aspectFlags, + 0, + 0, + _info.GetLayers(), + _info.Levels); - lastReadStage &= ~PipelineStageFlags.ComputeShaderBit; - } + _gd.Barriers.QueueBarrier(barrier, this, srcStageFlags, dstStageFlags); - if (lastReadStage != PipelineStageFlags.None) - { - // This would result in a validation error, but is - // required on MoltenVK as the generic barrier results in - // severe texture flickering in some scenarios. - if (_gd.IsMoltenVk) - { - ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags(); - TextureView.InsertImageBarrier( - _gd.Api, - cbs.CommandBuffer, - _imageAuto.Get(cbs).Value, - _lastReadAccess, - dstAccessFlags, - _lastReadStage, - dstStageFlags, - aspectFlags, - 0, - 0, - _info.GetLayers(), - _info.Levels); - } - else - { - TextureView.InsertMemoryBarrier( - _gd.Api, - cbs.CommandBuffer, - _lastReadAccess, - dstAccessFlags, - lastReadStage, - dstStageFlags); - } - - _lastReadAccess = AccessFlags.None; _lastReadStage = PipelineStageFlags.None; + _lastReadAccess = AccessFlags.None; } + + _lastModificationStage = depthStencil ? + PipelineStageFlags.LateFragmentTestsBit : + PipelineStageFlags.ColorAttachmentOutputBit; + + _lastModificationAccess = depthStencil ? + AccessFlags.DepthStencilAttachmentWriteBit : + AccessFlags.ColorAttachmentWriteBit; } - public void InsertWriteToReadBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags) + public void QueueWriteToReadBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags) { _lastReadAccess |= dstAccessFlags; _lastReadStage |= dstStageFlags; if (_lastModificationAccess != AccessFlags.None) { - // This would result in a validation error, but is - // required on MoltenVK as the generic barrier results in - // severe texture flickering in some scenarios. - if (_gd.IsMoltenVk) - { - ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags(); - TextureView.InsertImageBarrier( - _gd.Api, - cbs.CommandBuffer, - _imageAuto.Get(cbs).Value, - _lastModificationAccess, - dstAccessFlags, - _lastModificationStage, - dstStageFlags, - aspectFlags, - 0, - 0, - _info.GetLayers(), - _info.Levels); - } - else - { - TextureView.InsertMemoryBarrier( - _gd.Api, - cbs.CommandBuffer, - _lastModificationAccess, - dstAccessFlags, - _lastModificationStage, - dstStageFlags); - } + ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags(); + ImageMemoryBarrier barrier = TextureView.GetImageBarrier( + _imageAuto.Get(cbs).Value, + _lastModificationAccess, + dstAccessFlags, + aspectFlags, + 0, + 0, + _info.GetLayers(), + _info.Levels); + + _gd.Barriers.QueueBarrier(barrier, this, _lastModificationStage, dstStageFlags); _lastModificationAccess = AccessFlags.None; } } + public void AddBinding(TextureView view) + { + // Assumes a view only has a first level. + + int index = view.FirstLevel * _depthOrLayers + view.FirstLayer; + int layers = view.Layers; + + for (int i = 0; i < layers; i++) + { + ref TextureSliceInfo info = ref _slices[index++]; + + info.BindCount++; + } + + _bindCount++; + } + + public void ClearBindings() + { + if (_bindCount != 0) + { + Array.Clear(_slices, 0, _slices.Length); + + _bindCount = 0; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsBound(TextureView view) + { + if (_bindCount != 0) + { + int index = view.FirstLevel * _depthOrLayers + view.FirstLayer; + int layers = view.Layers; + + for (int i = 0; i < layers; i++) + { + ref TextureSliceInfo info = ref _slices[index++]; + + if (info.BindCount != 0) + { + return true; + } + } + } + + return false; + } + public void IncrementViewsCount() { _viewsCount++; @@ -549,6 +597,8 @@ namespace Ryujinx.Graphics.Vulkan public void Dispose() { + Disposed = true; + if (_aliasedStorages != null) { foreach (var storage in _aliasedStorages.Values) diff --git a/src/Ryujinx.Graphics.Vulkan/TextureView.cs b/src/Ryujinx.Graphics.Vulkan/TextureView.cs index 96e113f07..796fc3bec 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureView.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureView.cs @@ -4,6 +4,8 @@ using Silk.NET.Vulkan; using System; using System.Buffers; using System.Collections.Generic; +using System.Linq; +using System.Threading; using Format = Ryujinx.Graphics.GAL.Format; using VkBuffer = Silk.NET.Vulkan.Buffer; using VkFormat = Silk.NET.Vulkan.Format; @@ -22,8 +24,12 @@ namespace Ryujinx.Graphics.Vulkan private readonly Auto _imageView2dArray; private Dictionary _selfManagedViews; + private int _hazardUses; + private readonly TextureCreateInfo _info; + private HashTableSlim _renderPasses; + public TextureCreateInfo Info => _info; public TextureStorage Storage { get; } @@ -34,7 +40,8 @@ namespace Ryujinx.Graphics.Vulkan public int FirstLayer { get; } public int FirstLevel { get; } public VkFormat VkFormat { get; } - public bool Valid { get; private set; } + private int _isValid; + public bool Valid => Volatile.Read(ref _isValid) != 0; public TextureView( VulkanRenderer gd, @@ -56,7 +63,7 @@ namespace Ryujinx.Graphics.Vulkan gd.Textures.Add(this); var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format); - var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample); + var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities); var levels = (uint)info.Levels; var layers = (uint)info.GetLayers(); @@ -96,7 +103,7 @@ namespace Ryujinx.Graphics.Vulkan unsafe Auto CreateImageView(ComponentMapping cm, ImageSubresourceRange sr, ImageViewType viewType, ImageUsageFlags usageFlags) { - var usage = new ImageViewUsageCreateInfo + var imageViewUsage = new ImageViewUsageCreateInfo { SType = StructureType.ImageViewUsageCreateInfo, Usage = usageFlags, @@ -110,16 +117,16 @@ namespace Ryujinx.Graphics.Vulkan Format = format, Components = cm, SubresourceRange = sr, - PNext = &usage, + PNext = &imageViewUsage, }; - gd.Api.CreateImageView(device, imageCreateInfo, null, out var imageView).ThrowOnError(); + gd.Api.CreateImageView(device, in imageCreateInfo, null, out var imageView).ThrowOnError(); return new Auto(new DisposableImageView(gd.Api, device, imageView), null, storage.GetImage()); } ImageUsageFlags shaderUsage = ImageUsageFlags.SampledBit; - if (info.Format.IsImageCompatible()) + if (info.Format.IsImageCompatible() && (_gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample())) { shaderUsage |= ImageUsageFlags.StorageBit; } @@ -150,13 +157,33 @@ namespace Ryujinx.Graphics.Vulkan } else { - subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth); + subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, 1, (uint)firstLayer, (uint)info.Depth); _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2DArray, usage); } } - Valid = true; + _isValid = 1; + } + + /// + /// Create a texture view for an existing swapchain image view. + /// Does not set storage, so only appropriate for swapchain use. + /// + /// Do not use this for normal textures, and make sure uses do not try to read storage. + public TextureView(VulkanRenderer gd, Device device, DisposableImageView view, TextureCreateInfo info, VkFormat format) + { + _gd = gd; + _device = device; + + _imageView = new Auto(view); + _imageViewDraw = _imageView; + _imageViewIdentity = _imageView; + _info = info; + + VkFormat = format; + + _isValid = 1; } public Auto GetImage() @@ -468,13 +495,37 @@ namespace Ryujinx.Graphics.Vulkan dstStageMask, DependencyFlags.None, 1, - memoryBarrier, + in memoryBarrier, 0, null, 0, null); } + public static ImageMemoryBarrier GetImageBarrier( + Image image, + AccessFlags srcAccessMask, + AccessFlags dstAccessMask, + ImageAspectFlags aspectFlags, + int firstLayer, + int firstLevel, + int layers, + int levels) + { + return new() + { + SType = StructureType.ImageMemoryBarrier, + SrcAccessMask = srcAccessMask, + DstAccessMask = dstAccessMask, + SrcQueueFamilyIndex = Vk.QueueFamilyIgnored, + DstQueueFamilyIndex = Vk.QueueFamilyIgnored, + Image = image, + OldLayout = ImageLayout.General, + NewLayout = ImageLayout.General, + SubresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, (uint)levels, (uint)firstLayer, (uint)layers), + }; + } + public static unsafe void InsertImageBarrier( Vk api, CommandBuffer commandBuffer, @@ -489,18 +540,15 @@ namespace Ryujinx.Graphics.Vulkan int layers, int levels) { - ImageMemoryBarrier memoryBarrier = new() - { - SType = StructureType.ImageMemoryBarrier, - SrcAccessMask = srcAccessMask, - DstAccessMask = dstAccessMask, - SrcQueueFamilyIndex = Vk.QueueFamilyIgnored, - DstQueueFamilyIndex = Vk.QueueFamilyIgnored, - Image = image, - OldLayout = ImageLayout.General, - NewLayout = ImageLayout.General, - SubresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, (uint)levels, (uint)firstLayer, (uint)layers), - }; + ImageMemoryBarrier memoryBarrier = GetImageBarrier( + image, + srcAccessMask, + dstAccessMask, + aspectFlags, + firstLayer, + firstLevel, + layers, + levels); api.CmdPipelineBarrier( commandBuffer, @@ -512,7 +560,7 @@ namespace Ryujinx.Graphics.Vulkan 0, null, 1, - memoryBarrier); + in memoryBarrier); } public TextureView GetView(Format format) @@ -622,8 +670,36 @@ namespace Ryujinx.Graphics.Vulkan if (PrepareOutputBuffer(cbs, hostSize, buffer, out VkBuffer copyToBuffer, out BufferHolder tempCopyHolder)) { + // No barrier necessary, as this is a temporary copy buffer. offset = 0; } + else + { + BufferHolder.InsertBufferBarrier( + _gd, + cbs.CommandBuffer, + copyToBuffer, + BufferHolder.DefaultAccessFlags, + AccessFlags.TransferWriteBit, + PipelineStageFlags.AllCommandsBit, + PipelineStageFlags.TransferBit, + offset, + outSize); + } + + InsertImageBarrier( + _gd.Api, + cbs.CommandBuffer, + image, + TextureStorage.DefaultAccessMask, + AccessFlags.TransferReadBit, + PipelineStageFlags.AllCommandsBit, + PipelineStageFlags.TransferBit, + Info.Format.ConvertAspectFlags(), + FirstLayer + layer, + FirstLevel + level, + 1, + 1); CopyFromOrToBuffer(cbs.CommandBuffer, copyToBuffer, image, hostSize, true, layer, level, 1, 1, singleSlice: true, offset, stride); @@ -632,6 +708,19 @@ namespace Ryujinx.Graphics.Vulkan CopyDataToOutputBuffer(cbs, tempCopyHolder, autoBuffer, hostSize, range.Offset); tempCopyHolder.Dispose(); } + else + { + BufferHolder.InsertBufferBarrier( + _gd, + cbs.CommandBuffer, + copyToBuffer, + AccessFlags.TransferWriteBit, + BufferHolder.DefaultAccessFlags, + PipelineStageFlags.TransferBit, + PipelineStageFlags.AllCommandsBit, + offset, + outSize); + } } private ReadOnlySpan GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer) @@ -657,26 +746,24 @@ namespace Ryujinx.Graphics.Vulkan return GetDataFromBuffer(result, size, result); } - public void SetData(ReadOnlySpan data) + /// + public void SetData(MemoryOwner data) { - SetData(data, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false); - } - - public void SetData(IMemoryOwner data) - { - SetData(data.Memory.Span); + SetData(data.Span, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false); data.Dispose(); } - public void SetData(IMemoryOwner data, int layer, int level) + /// + public void SetData(MemoryOwner data, int layer, int level) { - SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true); + SetData(data.Span, layer, level, 1, 1, singleSlice: true); data.Dispose(); } - public void SetData(IMemoryOwner data, int layer, int level, Rectangle region) + /// + public void SetData(MemoryOwner data, int layer, int level, Rectangle region) { - SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true, region); + SetData(data.Span, layer, level, 1, 1, singleSlice: true, region); data.Dispose(); } @@ -825,7 +912,9 @@ namespace Ryujinx.Graphics.Vulkan for (int level = 0; level < levels; level++) { - int mipSize = GetBufferDataLength(Info.GetMipSize2D(dstLevel + level) * dstLayers); + int mipSize = GetBufferDataLength(is3D && !singleSlice + ? Info.GetMipSize(dstLevel + level) + : Info.GetMipSize2D(dstLevel + level) * dstLayers); int endOffset = offset + mipSize; @@ -863,11 +952,11 @@ namespace Ryujinx.Graphics.Vulkan if (to) { - _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region); + _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, in region); } else { - _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region); + _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, in region); } offset += mipSize; @@ -924,11 +1013,11 @@ namespace Ryujinx.Graphics.Vulkan if (to) { - _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region); + _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, in region); } else { - _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region); + _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, in region); } } @@ -948,40 +1037,111 @@ namespace Ryujinx.Graphics.Vulkan throw new NotImplementedException(); } + public void PrepareForUsage(CommandBufferScoped cbs, PipelineStageFlags flags, List feedbackLoopHazards) + { + Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, flags); + + if (feedbackLoopHazards != null && Storage.IsBound(this)) + { + feedbackLoopHazards.Add(this); + _hazardUses++; + } + } + + public void ClearUsage(List feedbackLoopHazards) + { + if (_hazardUses != 0 && feedbackLoopHazards != null) + { + feedbackLoopHazards.Remove(this); + _hazardUses--; + } + } + + public void DecrementHazardUses() + { + if (_hazardUses != 0) + { + _hazardUses--; + } + } + + public (RenderPassHolder rpHolder, Auto framebuffer) GetPassAndFramebuffer( + VulkanRenderer gd, + Device device, + CommandBufferScoped cbs, + FramebufferParams fb) + { + var key = fb.GetRenderPassCacheKey(); + + if (_renderPasses == null || !_renderPasses.TryGetValue(ref key, out RenderPassHolder rpHolder)) + { + rpHolder = new RenderPassHolder(gd, device, key, fb); + } + + return (rpHolder, rpHolder.GetFramebuffer(gd, cbs, fb)); + } + + public void AddRenderPass(RenderPassCacheKey key, RenderPassHolder renderPass) + { + _renderPasses ??= new HashTableSlim(); + + _renderPasses.Add(ref key, renderPass); + } + + public void RemoveRenderPass(RenderPassCacheKey key) + { + _renderPasses.Remove(ref key); + } + protected virtual void Dispose(bool disposing) { if (disposing) { - Valid = false; - - if (_gd.Textures.Remove(this)) + bool wasValid = Interlocked.Exchange(ref _isValid, 0) != 0; + if (wasValid) { + _gd.Textures.Remove(this); + _imageView.Dispose(); - _imageViewIdentity.Dispose(); _imageView2dArray?.Dispose(); + if (_imageViewIdentity != _imageView) + { + _imageViewIdentity.Dispose(); + } + if (_imageViewDraw != _imageViewIdentity) { _imageViewDraw.Dispose(); } - Storage.DecrementViewsCount(); + Storage?.DecrementViewsCount(); + + if (_renderPasses != null) + { + var renderPasses = _renderPasses.Values.ToArray(); + + foreach (var pass in renderPasses) + { + pass.Dispose(); + } + } + + if (_selfManagedViews != null) + { + foreach (var view in _selfManagedViews.Values) + { + view.Dispose(); + } + + _selfManagedViews = null; + } } } } public void Dispose() { - if (_selfManagedViews != null) - { - foreach (var view in _selfManagedViews.Values) - { - view.Dispose(); - } - - _selfManagedViews = null; - } - Dispose(true); } diff --git a/src/Ryujinx.Graphics.Vulkan/Vendor.cs b/src/Ryujinx.Graphics.Vulkan/Vendor.cs index 2d2f17b25..55ae0cd81 100644 --- a/src/Ryujinx.Graphics.Vulkan/Vendor.cs +++ b/src/Ryujinx.Graphics.Vulkan/Vendor.cs @@ -1,3 +1,4 @@ +using Silk.NET.Vulkan; using System.Text.RegularExpressions; namespace Ryujinx.Graphics.Vulkan @@ -20,6 +21,9 @@ namespace Ryujinx.Graphics.Vulkan [GeneratedRegex("Radeon (((HD|R(5|7|9|X)) )?((M?[2-6]\\d{2}(\\D|$))|([7-8]\\d{3}(\\D|$))|Fury|Nano))|(Pro Duo)")] public static partial Regex AmdGcnRegex(); + [GeneratedRegex("NVIDIA GeForce (R|G)?TX? (\\d{3}\\d?)M?")] + public static partial Regex NvidiaConsumerClassRegex(); + public static Vendor FromId(uint id) { return id switch @@ -58,5 +62,39 @@ namespace Ryujinx.Graphics.Vulkan _ => $"0x{id:X}", }; } + + public static string GetFriendlyDriverName(DriverId id) + { + return id switch + { + DriverId.AmdProprietary => "AMD", + DriverId.AmdOpenSource => "AMD (Open)", + DriverId.MesaRadv => "RADV", + DriverId.NvidiaProprietary => "NVIDIA", + DriverId.IntelProprietaryWindows => "Intel", + DriverId.IntelOpenSourceMesa => "Intel (Open)", + DriverId.ImaginationProprietary => "Imagination", + DriverId.QualcommProprietary => "Qualcomm", + DriverId.ArmProprietary => "ARM", + DriverId.GoogleSwiftshader => "SwiftShader", + DriverId.GgpProprietary => "GGP", + DriverId.BroadcomProprietary => "Broadcom", + DriverId.MesaLlvmpipe => "LLVMpipe", + DriverId.Moltenvk => "MoltenVK", + DriverId.CoreaviProprietary => "CoreAVI", + DriverId.JuiceProprietary => "Juice", + DriverId.VerisiliconProprietary => "Verisilicon", + DriverId.MesaTurnip => "Turnip", + DriverId.MesaV3DV => "V3DV", + DriverId.MesaPanvk => "PanVK", + DriverId.SamsungProprietary => "Samsung", + DriverId.MesaVenus => "Venus", + DriverId.MesaDozen => "Dozen", + DriverId.MesaNvk => "NVK", + DriverId.ImaginationOpenSourceMesa => "Imagination (Open)", + DriverId.MesaAgxv => "Honeykrisp", + _ => id.ToString(), + }; + } } } diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanConfiguration.cs b/src/Ryujinx.Graphics.Vulkan/VulkanConfiguration.cs index a1fdc4aed..596c0e176 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanConfiguration.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanConfiguration.cs @@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Vulkan { public const bool UseFastBufferUpdates = true; public const bool UseUnsafeBlit = true; - public const bool UsePushDescriptors = false; + public const bool UsePushDescriptors = true; public const bool ForceD24S8Unsupported = false; public const bool ForceRGB16IntFloatUnsupported = false; diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanException.cs b/src/Ryujinx.Graphics.Vulkan/VulkanException.cs index 0d4036802..e203a3a21 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanException.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanException.cs @@ -6,10 +6,16 @@ namespace Ryujinx.Graphics.Vulkan { static class ResultExtensions { + public static bool IsError(this Result result) + { + // Only negative result codes are errors. + return result < Result.Success; + } + public static void ThrowOnError(this Result result) { // Only negative result codes are errors. - if ((int)result < (int)Result.Success) + if (result.IsError()) { throw new VulkanException(result); } diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs index 5df7f5890..a2eccc82d 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs @@ -42,6 +42,10 @@ namespace Ryujinx.Graphics.Vulkan "VK_EXT_depth_clip_control", "VK_KHR_portability_subset", // As per spec, we should enable this if present. "VK_EXT_4444_formats", + "VK_KHR_8bit_storage", + "VK_KHR_maintenance2", + "VK_EXT_attachment_feedback_loop_layout", + "VK_EXT_attachment_feedback_loop_dynamic_state", }; private static readonly string[] _requiredExtensions = { @@ -136,7 +140,7 @@ namespace Ryujinx.Graphics.Vulkan { instance.EnumeratePhysicalDevices(out var physicalDevices).ThrowOnError(); - // First we try to pick the the user preferred GPU. + // First we try to pick the user preferred GPU. for (int i = 0; i < physicalDevices.Length; i++) { if (IsPreferredAndSuitableDevice(api, physicalDevices[i], surface, preferredGpuId)) @@ -355,6 +359,36 @@ namespace Ryujinx.Graphics.Vulkan features2.PNext = &supportedFeaturesDepthClipControl; } + PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT supportedFeaturesAttachmentFeedbackLoopLayout = new() + { + SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt, + PNext = features2.PNext, + }; + + if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout")) + { + features2.PNext = &supportedFeaturesAttachmentFeedbackLoopLayout; + } + + PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT supportedFeaturesDynamicAttachmentFeedbackLoopLayout = new() + { + SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt, + PNext = features2.PNext, + }; + + if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state")) + { + features2.PNext = &supportedFeaturesDynamicAttachmentFeedbackLoopLayout; + } + + PhysicalDeviceVulkan12Features supportedPhysicalDeviceVulkan12Features = new() + { + SType = StructureType.PhysicalDeviceVulkan12Features, + PNext = features2.PNext, + }; + + features2.PNext = &supportedPhysicalDeviceVulkan12Features; + api.GetPhysicalDeviceFeatures2(physicalDevice.PhysicalDevice, &features2); var supportedFeatures = features2.Features; @@ -382,6 +416,7 @@ namespace Ryujinx.Graphics.Vulkan TessellationShader = supportedFeatures.TessellationShader, VertexPipelineStoresAndAtomics = supportedFeatures.VertexPipelineStoresAndAtomics, RobustBufferAccess = useRobustBufferAccess, + SampleRateShading = supportedFeatures.SampleRateShading, }; void* pExtendedFeatures = null; @@ -451,9 +486,11 @@ namespace Ryujinx.Graphics.Vulkan { SType = StructureType.PhysicalDeviceVulkan12Features, PNext = pExtendedFeatures, - DescriptorIndexing = physicalDevice.IsDeviceExtensionPresent("VK_EXT_descriptor_indexing"), - DrawIndirectCount = physicalDevice.IsDeviceExtensionPresent(KhrDrawIndirectCount.ExtensionName), - UniformBufferStandardLayout = physicalDevice.IsDeviceExtensionPresent("VK_KHR_uniform_buffer_standard_layout"), + DescriptorIndexing = supportedPhysicalDeviceVulkan12Features.DescriptorIndexing, + DrawIndirectCount = supportedPhysicalDeviceVulkan12Features.DrawIndirectCount, + UniformBufferStandardLayout = supportedPhysicalDeviceVulkan12Features.UniformBufferStandardLayout, + UniformAndStorageBuffer8BitAccess = supportedPhysicalDeviceVulkan12Features.UniformAndStorageBuffer8BitAccess, + StorageBuffer8BitAccess = supportedPhysicalDeviceVulkan12Features.StorageBuffer8BitAccess, }; pExtendedFeatures = &featuresVk12; @@ -486,20 +523,6 @@ namespace Ryujinx.Graphics.Vulkan pExtendedFeatures = &featuresFragmentShaderInterlock; } - PhysicalDeviceSubgroupSizeControlFeaturesEXT featuresSubgroupSizeControl; - - if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_subgroup_size_control")) - { - featuresSubgroupSizeControl = new PhysicalDeviceSubgroupSizeControlFeaturesEXT - { - SType = StructureType.PhysicalDeviceSubgroupSizeControlFeaturesExt, - PNext = pExtendedFeatures, - SubgroupSizeControl = true, - }; - - pExtendedFeatures = &featuresSubgroupSizeControl; - } - PhysicalDeviceCustomBorderColorFeaturesEXT featuresCustomBorderColor; if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_custom_border_color") && @@ -532,6 +555,36 @@ namespace Ryujinx.Graphics.Vulkan pExtendedFeatures = &featuresDepthClipControl; } + PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoopLayout; + + if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout") && + supportedFeaturesAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopLayout) + { + featuresAttachmentFeedbackLoopLayout = new() + { + SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt, + PNext = pExtendedFeatures, + AttachmentFeedbackLoopLayout = true, + }; + + pExtendedFeatures = &featuresAttachmentFeedbackLoopLayout; + } + + PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoopLayout; + + if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state") && + supportedFeaturesDynamicAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopDynamicState) + { + featuresDynamicAttachmentFeedbackLoopLayout = new() + { + SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt, + PNext = pExtendedFeatures, + AttachmentFeedbackLoopDynamicState = true, + }; + + pExtendedFeatures = &featuresDynamicAttachmentFeedbackLoopLayout; + } + var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray(); IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length]; diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs b/src/Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs index 547f36543..3bee1e9d8 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs @@ -58,6 +58,33 @@ namespace Ryujinx.Graphics.Vulkan public bool IsDeviceExtensionPresent(string extension) => DeviceExtensions.Contains(extension); + public unsafe bool TryGetPhysicalDeviceDriverPropertiesKHR(Vk api, out PhysicalDeviceDriverPropertiesKHR res) + { + if (!IsDeviceExtensionPresent("VK_KHR_driver_properties")) + { + res = default; + + return false; + } + + PhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties = new() + { + SType = StructureType.PhysicalDeviceDriverPropertiesKhr + }; + + PhysicalDeviceProperties2 physicalDeviceProperties2 = new() + { + SType = StructureType.PhysicalDeviceProperties2, + PNext = &physicalDeviceDriverProperties + }; + + api.GetPhysicalDeviceProperties2(PhysicalDevice, &physicalDeviceProperties2); + + res = physicalDeviceDriverProperties; + + return true; + } + public DeviceInfo ToDeviceInfo() { return new DeviceInfo( diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 4911db757..a77dba8e6 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -38,6 +38,7 @@ namespace Ryujinx.Graphics.Vulkan internal KhrPushDescriptor PushDescriptorApi { get; private set; } internal ExtTransformFeedback TransformFeedbackApi { get; private set; } internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; } + internal ExtAttachmentFeedbackLoopDynamicState DynamicFeedbackLoopApi { get; private set; } internal uint QueueFamilyIndex { get; private set; } internal Queue Queue { get; private set; } @@ -48,7 +49,6 @@ namespace Ryujinx.Graphics.Vulkan internal MemoryAllocator MemoryAllocator { get; private set; } internal HostMemoryAllocator HostMemoryAllocator { get; private set; } internal CommandBufferPool CommandBufferPool { get; private set; } - internal DescriptorSetManager DescriptorSetManager { get; private set; } internal PipelineLayoutCache PipelineLayoutCache { get; private set; } internal BackgroundResources BackgroundResources { get; private set; } internal Action InterruptAction { get; private set; } @@ -68,6 +68,8 @@ namespace Ryujinx.Graphics.Vulkan internal HelperShader HelperShader { get; private set; } internal PipelineFull PipelineInternal => _pipeline; + internal BarrierBatch Barriers { get; private set; } + public IPipeline Pipeline => _pipeline; public IWindow Window => _window; @@ -76,14 +78,23 @@ namespace Ryujinx.Graphics.Vulkan private readonly Func _getRequiredExtensions; private readonly string _preferredGpuId; + private int[] _pdReservedBindings; + private readonly static int[] _pdReservedBindingsNvn = { 3, 18, 21, 36, 30 }; + private readonly static int[] _pdReservedBindingsOgl = { 17, 18, 34, 35, 36 }; + internal Vendor Vendor { get; private set; } internal bool IsAmdWindows { get; private set; } internal bool IsIntelWindows { get; private set; } internal bool IsAmdGcn { get; private set; } + internal bool IsNvidiaPreTuring { get; private set; } + internal bool IsIntelArc { get; private set; } + internal bool IsQualcommProprietary { get; private set; } internal bool IsMoltenVk { get; private set; } internal bool IsTBDR { get; private set; } internal bool IsSharedMemory { get; private set; } + public string GpuVendor { get; private set; } + public string GpuDriver { get; private set; } public string GpuRenderer { get; private set; } public string GpuVersion { get; private set; } @@ -139,6 +150,11 @@ namespace Ryujinx.Graphics.Vulkan DrawIndirectCountApi = drawIndirectCountApi; } + if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtAttachmentFeedbackLoopDynamicState dynamicFeedbackLoopApi)) + { + DynamicFeedbackLoopApi = dynamicFeedbackLoopApi; + } + if (maxQueueCount >= 2) { Api.GetDeviceQueue(_device, queueFamilyIndex, 1, out var backgroundQueue); @@ -190,6 +206,19 @@ namespace Ryujinx.Graphics.Vulkan SType = StructureType.PhysicalDevicePortabilitySubsetPropertiesKhr, }; + bool supportsPushDescriptors = _physicalDevice.IsDeviceExtensionPresent(KhrPushDescriptor.ExtensionName); + + PhysicalDevicePushDescriptorPropertiesKHR propertiesPushDescriptor = new PhysicalDevicePushDescriptorPropertiesKHR() + { + SType = StructureType.PhysicalDevicePushDescriptorPropertiesKhr + }; + + if (supportsPushDescriptors) + { + propertiesPushDescriptor.PNext = properties2.PNext; + properties2.PNext = &propertiesPushDescriptor; + } + PhysicalDeviceFeatures2 features2 = new() { SType = StructureType.PhysicalDeviceFeatures2, @@ -220,6 +249,16 @@ namespace Ryujinx.Graphics.Vulkan SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt, }; + PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoop = new() + { + SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt, + }; + + PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoop = new() + { + SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt, + }; + PhysicalDevicePortabilitySubsetFeaturesKHR featuresPortabilitySubset = new() { SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr, @@ -256,6 +295,22 @@ namespace Ryujinx.Graphics.Vulkan features2.PNext = &featuresDepthClipControl; } + bool supportsAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout"); + + if (supportsAttachmentFeedbackLoop) + { + featuresAttachmentFeedbackLoop.PNext = features2.PNext; + features2.PNext = &featuresAttachmentFeedbackLoop; + } + + bool supportsDynamicAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state"); + + if (supportsDynamicAttachmentFeedbackLoop) + { + featuresDynamicAttachmentFeedbackLoop.PNext = features2.PNext; + features2.PNext = &featuresDynamicAttachmentFeedbackLoop; + } + bool usePortability = _physicalDevice.IsDeviceExtensionPresent("VK_KHR_portability_subset"); if (usePortability) @@ -289,6 +344,52 @@ namespace Ryujinx.Graphics.Vulkan ref var properties = ref properties2.Properties; + var hasDriverProperties = _physicalDevice.TryGetPhysicalDeviceDriverPropertiesKHR(Api, out var driverProperties); + + Vendor = VendorUtils.FromId(properties.VendorID); + + IsAmdWindows = Vendor == Vendor.Amd && OperatingSystem.IsWindows(); + IsIntelWindows = Vendor == Vendor.Intel && OperatingSystem.IsWindows(); + IsTBDR = + Vendor == Vendor.Apple || + Vendor == Vendor.Qualcomm || + Vendor == Vendor.ARM || + Vendor == Vendor.Broadcom || + Vendor == Vendor.ImgTec; + + GpuVendor = VendorUtils.GetNameFromId(properties.VendorID); + GpuDriver = hasDriverProperties && !OperatingSystem.IsMacOS() ? + VendorUtils.GetFriendlyDriverName(driverProperties.DriverID) : GpuVendor; // Fallback to vendor name if driver is unavailable or on MacOS where vendor is preferred. + + fixed (byte* deviceName = properties.DeviceName) + { + GpuRenderer = Marshal.PtrToStringAnsi((IntPtr)deviceName); + } + + GpuVersion = $"Vulkan v{ParseStandardVulkanVersion(properties.ApiVersion)}, Driver v{ParseDriverVersion(ref properties)}"; + + IsAmdGcn = !IsMoltenVk && Vendor == Vendor.Amd && VendorUtils.AmdGcnRegex().IsMatch(GpuRenderer); + + if (Vendor == Vendor.Nvidia) + { + var match = VendorUtils.NvidiaConsumerClassRegex().Match(GpuRenderer); + + if (match != null && int.TryParse(match.Groups[2].Value, out int gpuNumber)) + { + IsNvidiaPreTuring = gpuNumber < 2000; + } + else if (GpuRenderer.Contains("TITAN") && !GpuRenderer.Contains("RTX")) + { + IsNvidiaPreTuring = true; + } + } + else if (Vendor == Vendor.Intel) + { + IsIntelArc = GpuRenderer.StartsWith("Intel(R) Arc(TM)"); + } + + IsQualcommProprietary = hasDriverProperties && driverProperties.DriverID == DriverId.QualcommProprietary; + ulong minResourceAlignment = Math.Max( Math.Max( properties.Limits.MinStorageBufferOffsetAlignment, @@ -323,7 +424,8 @@ namespace Ryujinx.Graphics.Vulkan isDynamicStateSupported, features2.Features.MultiViewport && !(IsMoltenVk && Vendor == Vendor.Amd), // Workaround for AMD on MoltenVK issue !IsMoltenVk ? featuresRobustness2.NullDescriptor : false, - _physicalDevice.IsDeviceExtensionPresent(KhrPushDescriptor.ExtensionName), + supportsPushDescriptors && !IsMoltenVk, + propertiesPushDescriptor.MaxPushDescriptors, featuresPrimitiveTopologyListRestart.PrimitiveTopologyListRestart, featuresPrimitiveTopologyListRestart.PrimitiveTopologyPatchListRestart, supportsTransformFeedback, @@ -335,6 +437,8 @@ namespace Ryujinx.Graphics.Vulkan _physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"), _physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName), supportsDepthClipControl && featuresDepthClipControl.DepthClipControl, + supportsAttachmentFeedbackLoop && featuresAttachmentFeedbackLoop.AttachmentFeedbackLoopLayout, + supportsDynamicAttachmentFeedbackLoop && featuresDynamicAttachmentFeedbackLoop.AttachmentFeedbackLoopDynamicState, propertiesSubgroup.SubgroupSize, supportedSampleCounts, portabilityFlags, @@ -349,9 +453,7 @@ namespace Ryujinx.Graphics.Vulkan Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExternalMemoryHost hostMemoryApi); HostMemoryAllocator = new HostMemoryAllocator(MemoryAllocator, Api, hostMemoryApi, _device); - CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex); - - DescriptorSetManager = new DescriptorSetManager(_device, PipelineBase.DescriptorSetLayouts); + CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex, IsQualcommProprietary); PipelineLayoutCache = new PipelineLayoutCache(); @@ -365,6 +467,8 @@ namespace Ryujinx.Graphics.Vulkan HelperShader = new HelperShader(this, _device); + Barriers = new BarrierBatch(this); + _counters = new Counters(this, _device, _pipeline); } @@ -403,14 +507,28 @@ namespace Ryujinx.Graphics.Vulkan _initialized = true; } - public BufferHandle CreateBuffer(int size, BufferAccess access) + internal int[] GetPushDescriptorReservedBindings(bool isOgl) { - return BufferManager.CreateWithHandle(this, size, access.HasFlag(BufferAccess.SparseCompatible), access.Convert(), default, access == BufferAccess.Stream); + // The first call of this method determines what push descriptor layout is used for all shaders on this renderer. + // This is chosen to minimize shaders that can't fit their uniforms on the device's max number of push descriptors. + if (_pdReservedBindings == null) + { + if (Capabilities.MaxPushDescriptors <= Constants.MaxUniformBuffersPerStage * 2) + { + _pdReservedBindings = isOgl ? _pdReservedBindingsOgl : _pdReservedBindingsNvn; + } + else + { + _pdReservedBindings = Array.Empty(); + } + } + + return _pdReservedBindings; } - public BufferHandle CreateBuffer(int size, BufferAccess access, BufferHandle storageHint) + public BufferHandle CreateBuffer(int size, BufferAccess access) { - return BufferManager.CreateWithHandle(this, size, access.HasFlag(BufferAccess.SparseCompatible), access.Convert(), storageHint); + return BufferManager.CreateWithHandle(this, size, access.HasFlag(BufferAccess.SparseCompatible), access.Convert(), access.HasFlag(BufferAccess.Stream)); } public BufferHandle CreateBuffer(nint pointer, int size) @@ -423,6 +541,11 @@ namespace Ryujinx.Graphics.Vulkan return BufferManager.CreateSparse(this, storageBuffers); } + public IImageArray CreateImageArray(int size, bool isBuffer) + { + return new ImageArray(this, size, isBuffer); + } + public IProgram CreateProgram(ShaderSource[] sources, ShaderInfo info) { bool isCompute = sources.Length == 1 && sources[0].Stage == ShaderStage.Compute; @@ -455,6 +578,11 @@ namespace Ryujinx.Graphics.Vulkan return CreateTextureView(info); } + public ITextureArray CreateTextureArray(int size, bool isBuffer) + { + return new TextureArray(this, size, isBuffer); + } + internal TextureView CreateTextureView(TextureCreateInfo info) { // This should be disposed when all views are destroyed. @@ -584,11 +712,25 @@ namespace Ryujinx.Graphics.Vulkan var limits = _physicalDevice.PhysicalDeviceProperties.Limits; var mainQueueProperties = _physicalDevice.QueueFamilyProperties[QueueFamilyIndex]; + SystemMemoryType memoryType; + + if (IsSharedMemory) + { + memoryType = SystemMemoryType.UnifiedMemory; + } + else + { + memoryType = Vendor == Vendor.Nvidia ? + SystemMemoryType.DedicatedMemorySlowStorage : + SystemMemoryType.DedicatedMemory; + } + return new Capabilities( api: TargetApi.Vulkan, GpuVendor, + memoryType: memoryType, hasFrontFacingBug: IsIntelWindows, - hasVectorIndexingBug: Vendor == Vendor.Qualcomm, + hasVectorIndexingBug: IsQualcommProprietary, needsFragmentOutputSpecialization: IsMoltenVk, reduceShaderPrecision: IsMoltenVk, supportsAstcCompression: features2.Features.TextureCompressionAstcLdr && supportsAstcFormats, @@ -600,6 +742,7 @@ namespace Ryujinx.Graphics.Vulkan supportsBgraFormat: true, supportsR4G4Format: false, supportsR4G4B4A4Format: supportsR4G4B4A4Format, + supportsScaledVertexFormats: FormatCapabilities.SupportsScaledVertexFormats(), supportsSnormBufferTextureFormat: true, supports5BitComponentFormat: supports5BitComponentFormat, supportsSparseBuffer: features2.Features.SparseBinding && mainQueueProperties.QueueFlags.HasFlag(QueueFlags.SparseBindingBit), @@ -614,7 +757,8 @@ namespace Ryujinx.Graphics.Vulkan supportsMismatchingViewFormat: true, supportsCubemapView: !IsAmdGcn, supportsNonConstantTextureOffset: false, - supportsScaledVertexFormats: FormatCapabilities.SupportsScaledVertexFormats(), + supportsQuads: false, + supportsSeparateSampler: true, supportsShaderBallot: false, supportsShaderBarrierDivergence: Vendor != Vendor.Intel, supportsShaderFloat64: Capabilities.SupportsShaderFloat64, @@ -626,6 +770,12 @@ namespace Ryujinx.Graphics.Vulkan supportsViewportSwizzle: false, supportsIndirectParameters: true, supportsDepthClipControl: Capabilities.SupportsDepthClipControl, + uniformBufferSetIndex: PipelineBase.UniformSetIndex, + storageBufferSetIndex: PipelineBase.StorageSetIndex, + textureSetIndex: PipelineBase.TextureSetIndex, + imageSetIndex: PipelineBase.ImageSetIndex, + extraSetBaseIndex: PipelineBase.DescriptorSetLayouts, + maximumExtraSets: Math.Max(0, (int)limits.MaxBoundDescriptorSets - PipelineBase.DescriptorSetLayouts), maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage, maximumStorageBuffersPerStage: Constants.MaxStorageBuffersPerStage, maximumTexturesPerStage: Constants.MaxTexturesPerStage, @@ -635,12 +785,31 @@ namespace Ryujinx.Graphics.Vulkan shaderSubgroupSize: (int)Capabilities.SubgroupSize, storageBufferOffsetAlignment: (int)limits.MinStorageBufferOffsetAlignment, textureBufferOffsetAlignment: (int)limits.MinTexelBufferOffsetAlignment, - gatherBiasPrecision: IsIntelWindows || IsAmdWindows ? (int)Capabilities.SubTexelPrecisionBits : 0); + gatherBiasPrecision: IsIntelWindows || IsAmdWindows ? (int)Capabilities.SubTexelPrecisionBits : 0, + maximumGpuMemory: GetTotalGPUMemory()); + } + + private ulong GetTotalGPUMemory() + { + ulong totalMemory = 0; + + Api.GetPhysicalDeviceMemoryProperties(_physicalDevice.PhysicalDevice, out PhysicalDeviceMemoryProperties memoryProperties); + + for (int i = 0; i < memoryProperties.MemoryHeapCount; i++) + { + var heap = memoryProperties.MemoryHeaps[i]; + if ((heap.Flags & MemoryHeapFlags.DeviceLocalBit) == MemoryHeapFlags.DeviceLocalBit) + { + totalMemory += heap.Size; + } + } + + return totalMemory; } public HardwareInfo GetHardwareInfo() { - return new HardwareInfo(GpuVendor, GpuRenderer); + return new HardwareInfo(GpuVendor, GpuRenderer, GpuDriver); } /// @@ -693,39 +862,15 @@ namespace Ryujinx.Graphics.Vulkan return ParseStandardVulkanVersion(driverVersionRaw); } - private unsafe void PrintGpuInformation() - { - var properties = _physicalDevice.PhysicalDeviceProperties; - - string vendorName = VendorUtils.GetNameFromId(properties.VendorID); - - Vendor = VendorUtils.FromId(properties.VendorID); - - IsAmdWindows = Vendor == Vendor.Amd && OperatingSystem.IsWindows(); - IsIntelWindows = Vendor == Vendor.Intel && OperatingSystem.IsWindows(); - IsTBDR = - Vendor == Vendor.Apple || - Vendor == Vendor.Qualcomm || - Vendor == Vendor.ARM || - Vendor == Vendor.Broadcom || - Vendor == Vendor.ImgTec; - - GpuVendor = vendorName; - GpuRenderer = Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName); - GpuVersion = $"Vulkan v{ParseStandardVulkanVersion(properties.ApiVersion)}, Driver v{ParseDriverVersion(ref properties)}"; - - IsAmdGcn = !IsMoltenVk && Vendor == Vendor.Amd && VendorUtils.AmdGcnRegex().IsMatch(GpuRenderer); - - Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})"); - } - internal PrimitiveTopology TopologyRemap(PrimitiveTopology topology) { return topology switch { PrimitiveTopology.Quads => PrimitiveTopology.Triangles, PrimitiveTopology.QuadStrip => PrimitiveTopology.TriangleStrip, - PrimitiveTopology.TriangleFan => Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.NoTriangleFans) ? PrimitiveTopology.Triangles : topology, + PrimitiveTopology.TriangleFan or PrimitiveTopology.Polygon => Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.NoTriangleFans) + ? PrimitiveTopology.Triangles + : topology, _ => topology, }; } @@ -735,11 +880,17 @@ namespace Ryujinx.Graphics.Vulkan return topology switch { PrimitiveTopology.Quads => true, - PrimitiveTopology.TriangleFan => Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.NoTriangleFans), + PrimitiveTopology.TriangleFan or PrimitiveTopology.Polygon => Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.NoTriangleFans), _ => false, }; } + private void PrintGpuInformation() + { + Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})"); + Logger.Notice.Print(LogClass.Gpu, $"GPU Memory: {GetTotalGPUMemory() / (1024 * 1024)} MiB"); + } + public void Initialize(GraphicsDebugLevel logLevel) { SetupContext(logLevel); @@ -788,7 +939,7 @@ namespace Ryujinx.Graphics.Vulkan public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan data) { - BufferManager.SetData(buffer, offset, data, _pipeline.CurrentCommandBuffer, _pipeline.EndRenderPass); + BufferManager.SetData(buffer, offset, data, _pipeline.CurrentCommandBuffer, _pipeline.EndRenderPassDelegate); } public void UpdateCounters() @@ -846,6 +997,11 @@ namespace Ryujinx.Graphics.Vulkan ScreenCaptured?.Invoke(this, bitmap); } + public bool SupportsRenderPassBarrier(PipelineStageFlags flags) + { + return !(IsMoltenVk || IsQualcommProprietary); + } + public unsafe void Dispose() { if (!_initialized) @@ -860,8 +1016,8 @@ namespace Ryujinx.Graphics.Vulkan HelperShader.Dispose(); _pipeline.Dispose(); BufferManager.Dispose(); - DescriptorSetManager.Dispose(); PipelineLayoutCache.Dispose(); + Barriers.Dispose(); MemoryAllocator.Dispose(); diff --git a/src/Ryujinx.Graphics.Vulkan/Window.cs b/src/Ryujinx.Graphics.Vulkan/Window.cs index 2c5764a99..3dc6d4e19 100644 --- a/src/Ryujinx.Graphics.Vulkan/Window.cs +++ b/src/Ryujinx.Graphics.Vulkan/Window.cs @@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Vulkan private SwapchainKHR _swapchain; private Image[] _swapchainImages; - private Auto[] _swapchainImageViews; + private TextureView[] _swapchainImageViews; private Semaphore[] _imageAvailableSemaphores; private Semaphore[] _renderFinishedSemaphores; @@ -143,7 +143,24 @@ namespace Ryujinx.Graphics.Vulkan Clipped = true, }; - _gd.SwapchainApi.CreateSwapchain(_device, swapchainCreateInfo, null, out _swapchain).ThrowOnError(); + var textureCreateInfo = new TextureCreateInfo( + _width, + _height, + 1, + 1, + 1, + 1, + 1, + 1, + FormatTable.GetFormat(surfaceFormat.Format), + DepthStencilMode.Depth, + Target.Texture2D, + SwizzleComponent.Red, + SwizzleComponent.Green, + SwizzleComponent.Blue, + SwizzleComponent.Alpha); + + _gd.SwapchainApi.CreateSwapchain(_device, in swapchainCreateInfo, null, out _swapchain).ThrowOnError(); _gd.SwapchainApi.GetSwapchainImages(_device, _swapchain, &imageCount, null); @@ -154,11 +171,11 @@ namespace Ryujinx.Graphics.Vulkan _gd.SwapchainApi.GetSwapchainImages(_device, _swapchain, &imageCount, pSwapchainImages); } - _swapchainImageViews = new Auto[imageCount]; + _swapchainImageViews = new TextureView[imageCount]; for (int i = 0; i < _swapchainImageViews.Length; i++) { - _swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format); + _swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format, textureCreateInfo); } var semaphoreCreateInfo = new SemaphoreCreateInfo @@ -170,18 +187,18 @@ namespace Ryujinx.Graphics.Vulkan for (int i = 0; i < _imageAvailableSemaphores.Length; i++) { - _gd.Api.CreateSemaphore(_device, semaphoreCreateInfo, null, out _imageAvailableSemaphores[i]).ThrowOnError(); + _gd.Api.CreateSemaphore(_device, in semaphoreCreateInfo, null, out _imageAvailableSemaphores[i]).ThrowOnError(); } _renderFinishedSemaphores = new Semaphore[imageCount]; for (int i = 0; i < _renderFinishedSemaphores.Length; i++) { - _gd.Api.CreateSemaphore(_device, semaphoreCreateInfo, null, out _renderFinishedSemaphores[i]).ThrowOnError(); + _gd.Api.CreateSemaphore(_device, in semaphoreCreateInfo, null, out _renderFinishedSemaphores[i]).ThrowOnError(); } } - private unsafe Auto CreateSwapchainImageView(Image swapchainImage, VkFormat format) + private unsafe TextureView CreateSwapchainImageView(Image swapchainImage, VkFormat format, TextureCreateInfo info) { var componentMapping = new ComponentMapping( ComponentSwizzle.R, @@ -203,8 +220,9 @@ namespace Ryujinx.Graphics.Vulkan SubresourceRange = subresourceRange, }; - _gd.Api.CreateImageView(_device, imageCreateInfo, null, out var imageView).ThrowOnError(); - return new Auto(new DisposableImageView(_gd.Api, _device, imageView)); + _gd.Api.CreateImageView(_device, in imageCreateInfo, null, out var imageView).ThrowOnError(); + + return new TextureView(_gd, _device, new DisposableImageView(_gd.Api, _device, imageView), info, format); } private static SurfaceFormatKHR ChooseSwapSurfaceFormat(SurfaceFormatKHR[] availableFormats, bool colorSpacePassthroughEnabled) @@ -312,6 +330,7 @@ namespace Ryujinx.Graphics.Vulkan _swapchainIsDirty) { RecreateSwapchain(); + semaphoreIndex = (_frameIndex - 1) % _imageAvailableSemaphores.Length; } else { @@ -406,7 +425,7 @@ namespace Ryujinx.Graphics.Vulkan _scalingFilter.Run( view, cbs, - _swapchainImageViews[nextImage], + _swapchainImageViews[nextImage].GetImageViewForAttachment(), _format, _width, _height, @@ -421,11 +440,6 @@ namespace Ryujinx.Graphics.Vulkan cbs, view, _swapchainImageViews[nextImage], - _width, - _height, - 1, - _format, - false, new Extents2D(srcX0, srcY0, srcX1, srcY1), new Extents2D(dstX0, dstY1, dstX1, dstY0), _isLinear, @@ -465,7 +479,7 @@ namespace Ryujinx.Graphics.Vulkan lock (_gd.QueueLock) { - _gd.SwapchainApi.QueuePresent(_gd.Queue, presentInfo); + _gd.SwapchainApi.QueuePresent(_gd.Queue, in presentInfo); } } @@ -554,6 +568,13 @@ namespace Ryujinx.Graphics.Vulkan _scalingFilter.Level = _scalingFilterLevel; break; + case ScalingFilter.Area: + if (_scalingFilter is not AreaScalingFilter) + { + _scalingFilter?.Dispose(); + _scalingFilter = new AreaScalingFilter(_gd, _device); + } + break; } } } @@ -597,7 +618,7 @@ namespace Ryujinx.Graphics.Vulkan 0, null, 1, - barrier); + in barrier); } private void CaptureFrame(TextureView texture, int x, int y, int width, int height, bool isBgra, bool flipX, bool flipY) @@ -609,7 +630,8 @@ namespace Ryujinx.Graphics.Vulkan public override void SetSize(int width, int height) { - // Not needed as we can get the size from the surface. + // We don't need to use width and height as we can get the size from the surface. + _swapchainIsDirty = true; } public override void ChangeVSyncMode(bool vsyncEnabled) diff --git a/src/Ryujinx/Input/GTK3/GTK3Keyboard.cs b/src/Ryujinx.Gtk3/Input/GTK3/GTK3Keyboard.cs similarity index 100% rename from src/Ryujinx/Input/GTK3/GTK3Keyboard.cs rename to src/Ryujinx.Gtk3/Input/GTK3/GTK3Keyboard.cs diff --git a/src/Ryujinx/Input/GTK3/GTK3KeyboardDriver.cs b/src/Ryujinx.Gtk3/Input/GTK3/GTK3KeyboardDriver.cs similarity index 96% rename from src/Ryujinx/Input/GTK3/GTK3KeyboardDriver.cs rename to src/Ryujinx.Gtk3/Input/GTK3/GTK3KeyboardDriver.cs index e502254be..bd71c7933 100644 --- a/src/Ryujinx/Input/GTK3/GTK3KeyboardDriver.cs +++ b/src/Ryujinx.Gtk3/Input/GTK3/GTK3KeyboardDriver.cs @@ -81,6 +81,11 @@ namespace Ryujinx.Input.GTK3 return _pressedKeys.Contains(nativeKey); } + public void Clear() + { + _pressedKeys.Clear(); + } + public IGamepad GetGamepad(string id) { if (!_keyboardIdentifers[0].Equals(id)) diff --git a/src/Ryujinx/Input/GTK3/GTK3MappingHelper.cs b/src/Ryujinx.Gtk3/Input/GTK3/GTK3MappingHelper.cs similarity index 100% rename from src/Ryujinx/Input/GTK3/GTK3MappingHelper.cs rename to src/Ryujinx.Gtk3/Input/GTK3/GTK3MappingHelper.cs diff --git a/src/Ryujinx/Input/GTK3/GTK3Mouse.cs b/src/Ryujinx.Gtk3/Input/GTK3/GTK3Mouse.cs similarity index 100% rename from src/Ryujinx/Input/GTK3/GTK3Mouse.cs rename to src/Ryujinx.Gtk3/Input/GTK3/GTK3Mouse.cs diff --git a/src/Ryujinx/Input/GTK3/GTK3MouseDriver.cs b/src/Ryujinx.Gtk3/Input/GTK3/GTK3MouseDriver.cs similarity index 100% rename from src/Ryujinx/Input/GTK3/GTK3MouseDriver.cs rename to src/Ryujinx.Gtk3/Input/GTK3/GTK3MouseDriver.cs diff --git a/src/Ryujinx/Modules/Updater/UpdateDialog.cs b/src/Ryujinx.Gtk3/Modules/Updater/UpdateDialog.cs similarity index 87% rename from src/Ryujinx/Modules/Updater/UpdateDialog.cs rename to src/Ryujinx.Gtk3/Modules/Updater/UpdateDialog.cs index 695634374..43bde9420 100644 --- a/src/Ryujinx/Modules/Updater/UpdateDialog.cs +++ b/src/Ryujinx.Gtk3/Modules/Updater/UpdateDialog.cs @@ -1,9 +1,10 @@ using Gdk; using Gtk; using Ryujinx.Common; -using Ryujinx.Ui; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.Common.Configuration; +using Ryujinx.UI; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using System; using System.Diagnostics; using System.Reflection; @@ -24,7 +25,7 @@ namespace Ryujinx.Modules private readonly string _buildUrl; private bool _restartQuery; - public UpdateDialog(MainWindow mainWindow, Version newVersion, string buildUrl) : this(new Builder("Ryujinx.Modules.Updater.UpdateDialog.glade"), mainWindow, newVersion, buildUrl) { } + public UpdateDialog(MainWindow mainWindow, Version newVersion, string buildUrl) : this(new Builder("Ryujinx.Gtk3.Modules.Updater.UpdateDialog.glade"), mainWindow, newVersion, buildUrl) { } private UpdateDialog(Builder builder, MainWindow mainWindow, Version newVersion, string buildUrl) : base(builder.GetRawOwnedObject("UpdateDialog")) { @@ -33,7 +34,7 @@ namespace Ryujinx.Modules _mainWindow = mainWindow; _buildUrl = buildUrl; - Icon = new Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Gtk3.UI.Common.Resources.Logo_Ryujinx.png"); MainText.Text = "Do you want to update Ryujinx to the latest version?"; SecondaryText.Text = $"{Program.Version} -> {newVersion}"; @@ -52,7 +53,7 @@ namespace Ryujinx.Modules ProcessStartInfo processStart = new(ryuName) { UseShellExecute = true, - WorkingDirectory = ReleaseInformation.GetBaseApplicationDirectory(), + WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory }; foreach (string argument in CommandLineState.Arguments) diff --git a/src/Ryujinx/Modules/Updater/UpdateDialog.glade b/src/Ryujinx.Gtk3/Modules/Updater/UpdateDialog.glade similarity index 100% rename from src/Ryujinx/Modules/Updater/UpdateDialog.glade rename to src/Ryujinx.Gtk3/Modules/Updater/UpdateDialog.glade diff --git a/src/Ryujinx.Gtk3/Modules/Updater/Updater.cs b/src/Ryujinx.Gtk3/Modules/Updater/Updater.cs new file mode 100644 index 000000000..8b006f63f --- /dev/null +++ b/src/Ryujinx.Gtk3/Modules/Updater/Updater.cs @@ -0,0 +1,622 @@ +using Gtk; +using ICSharpCode.SharpZipLib.GZip; +using ICSharpCode.SharpZipLib.Tar; +using ICSharpCode.SharpZipLib.Zip; +using Ryujinx.Common; +using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; +using Ryujinx.UI; +using Ryujinx.UI.Common.Models.Github; +using Ryujinx.UI.Widgets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.NetworkInformation; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Ryujinx.Modules +{ + public static class Updater + { + private const string GitHubApiUrl = "https://api.github.com"; + private const int ConnectionCount = 4; + + internal static bool Running; + + private static readonly string _homeDir = AppDomain.CurrentDomain.BaseDirectory; + private static readonly string _updateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update"); + private static readonly string _updatePublishDir = Path.Combine(_updateDir, "publish"); + + private static string _buildVer; + private static string _platformExt; + private static string _buildUrl; + private static long _buildSize; + + private static readonly GithubReleasesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + + // On Windows, GtkSharp.Dependencies adds these extra dirs that must be cleaned during updates. + private static readonly string[] _windowsDependencyDirs = { "bin", "etc", "lib", "share" }; + + private static HttpClient ConstructHttpClient() + { + HttpClient result = new(); + + // Required by GitHub to interact with APIs. + result.DefaultRequestHeaders.Add("User-Agent", "Ryujinx-Updater/1.0.0"); + + return result; + } + + public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate) + { + if (Running) + { + return; + } + + Running = true; + mainWindow.UpdateMenuItem.Sensitive = false; + + int artifactIndex = -1; + + // Detect current platform + if (OperatingSystem.IsMacOS()) + { + _platformExt = "osx_x64.zip"; + artifactIndex = 1; + } + else if (OperatingSystem.IsWindows()) + { + _platformExt = "win_x64.zip"; + artifactIndex = 2; + } + else if (OperatingSystem.IsLinux()) + { + var arch = RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "arm64" : "x64"; + _platformExt = $"linux_{arch}.tar.gz"; + artifactIndex = 0; + } + + if (artifactIndex == -1) + { + GtkDialog.CreateErrorDialog("Your platform is not supported!"); + + return; + } + + Version newVersion; + Version currentVersion; + + try + { + currentVersion = Version.Parse(Program.Version); + } + catch + { + GtkDialog.CreateWarningDialog("Failed to convert the current Ryujinx version.", "Cancelling Update!"); + Logger.Error?.Print(LogClass.Application, "Failed to convert the current Ryujinx version!"); + + return; + } + + // Get latest version number from GitHub API + try + { + using HttpClient jsonClient = ConstructHttpClient(); + string buildInfoUrl = $"{GitHubApiUrl}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest"; + + // Fetch latest build information + string fetchedJson = await jsonClient.GetStringAsync(buildInfoUrl); + var fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse); + _buildVer = fetched.Name; + + foreach (var asset in fetched.Assets) + { + if (asset.Name.StartsWith("gtk-ryujinx") && asset.Name.EndsWith(_platformExt)) + { + _buildUrl = asset.BrowserDownloadUrl; + + if (asset.State != "uploaded") + { + if (showVersionUpToDate) + { + GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", ""); + } + + return; + } + + break; + } + } + + if (_buildUrl == null) + { + if (showVersionUpToDate) + { + GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", ""); + } + + return; + } + } + catch (Exception exception) + { + Logger.Error?.Print(LogClass.Application, exception.Message); + GtkDialog.CreateErrorDialog("An error occurred when trying to get release information from GitHub Release. This can be caused if a new release is being compiled by GitHub Actions. Try again in a few minutes."); + + return; + } + + try + { + newVersion = Version.Parse(_buildVer); + } + catch + { + GtkDialog.CreateWarningDialog("Failed to convert the received Ryujinx version from GitHub Release.", "Cancelling Update!"); + Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from GitHub Release!"); + + return; + } + + if (newVersion <= currentVersion) + { + if (showVersionUpToDate) + { + GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", ""); + } + + Running = false; + mainWindow.UpdateMenuItem.Sensitive = true; + + return; + } + + // Fetch build size information to learn chunk sizes. + using HttpClient buildSizeClient = ConstructHttpClient(); + try + { + buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0"); + + HttpResponseMessage message = await buildSizeClient.GetAsync(new Uri(_buildUrl), HttpCompletionOption.ResponseHeadersRead); + + _buildSize = message.Content.Headers.ContentRange.Length.Value; + } + catch (Exception ex) + { + Logger.Warning?.Print(LogClass.Application, ex.Message); + Logger.Warning?.Print(LogClass.Application, "Couldn't determine build size for update, using single-threaded updater"); + + _buildSize = -1; + } + + // Show a message asking the user if they want to update + UpdateDialog updateDialog = new(mainWindow, newVersion, _buildUrl); + updateDialog.Show(); + } + + public static void UpdateRyujinx(UpdateDialog updateDialog, string downloadUrl) + { + // Empty update dir, although it shouldn't ever have anything inside it + if (Directory.Exists(_updateDir)) + { + Directory.Delete(_updateDir, true); + } + + Directory.CreateDirectory(_updateDir); + + string updateFile = Path.Combine(_updateDir, "update.bin"); + + // Download the update .zip + updateDialog.MainText.Text = "Downloading Update..."; + updateDialog.ProgressBar.Value = 0; + updateDialog.ProgressBar.MaxValue = 100; + + if (_buildSize >= 0) + { + DoUpdateWithMultipleThreads(updateDialog, downloadUrl, updateFile); + } + else + { + DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile); + } + } + + private static void DoUpdateWithMultipleThreads(UpdateDialog updateDialog, string downloadUrl, string updateFile) + { + // Multi-Threaded Updater + long chunkSize = _buildSize / ConnectionCount; + long remainderChunk = _buildSize % ConnectionCount; + + int completedRequests = 0; + int totalProgressPercentage = 0; + int[] progressPercentage = new int[ConnectionCount]; + + List list = new(ConnectionCount); + List webClients = new(ConnectionCount); + + for (int i = 0; i < ConnectionCount; i++) + { + list.Add(Array.Empty()); + } + + for (int i = 0; i < ConnectionCount; i++) + { +#pragma warning disable SYSLIB0014 + // TODO: WebClient is obsolete and need to be replaced with a more complex logic using HttpClient. + using WebClient client = new(); +#pragma warning restore SYSLIB0014 + webClients.Add(client); + + if (i == ConnectionCount - 1) + { + client.Headers.Add("Range", $"bytes={chunkSize * i}-{(chunkSize * (i + 1) - 1) + remainderChunk}"); + } + else + { + client.Headers.Add("Range", $"bytes={chunkSize * i}-{chunkSize * (i + 1) - 1}"); + } + + client.DownloadProgressChanged += (_, args) => + { + int index = (int)args.UserState; + + Interlocked.Add(ref totalProgressPercentage, -1 * progressPercentage[index]); + Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage); + Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage); + + updateDialog.ProgressBar.Value = totalProgressPercentage / ConnectionCount; + }; + + client.DownloadDataCompleted += (_, args) => + { + int index = (int)args.UserState; + + if (args.Cancelled) + { + webClients[index].Dispose(); + + return; + } + + list[index] = args.Result; + Interlocked.Increment(ref completedRequests); + + if (Equals(completedRequests, ConnectionCount)) + { + byte[] mergedFileBytes = new byte[_buildSize]; + for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++) + { + Array.Copy(list[connectionIndex], 0, mergedFileBytes, destinationOffset, list[connectionIndex].Length); + destinationOffset += list[connectionIndex].Length; + } + + File.WriteAllBytes(updateFile, mergedFileBytes); + + try + { + InstallUpdate(updateDialog, updateFile); + } + catch (Exception e) + { + Logger.Warning?.Print(LogClass.Application, e.Message); + Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater."); + + DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile); + + return; + } + } + }; + + try + { + client.DownloadDataAsync(new Uri(downloadUrl), i); + } + catch (WebException ex) + { + Logger.Warning?.Print(LogClass.Application, ex.Message); + Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater."); + + foreach (WebClient webClient in webClients) + { + webClient.CancelAsync(); + } + + DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile); + + return; + } + } + } + + private static void DoUpdateWithSingleThreadWorker(UpdateDialog updateDialog, string downloadUrl, string updateFile) + { + using HttpClient client = new(); + // We do not want to timeout while downloading + client.Timeout = TimeSpan.FromDays(1); + + using HttpResponseMessage response = client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead).Result; + using Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result; + using Stream updateFileStream = File.Open(updateFile, FileMode.Create); + + long totalBytes = response.Content.Headers.ContentLength.Value; + long byteWritten = 0; + + byte[] buffer = new byte[32 * 1024]; + + while (true) + { + int readSize = remoteFileStream.Read(buffer); + + if (readSize == 0) + { + break; + } + + byteWritten += readSize; + + updateDialog.ProgressBar.Value = ((double)byteWritten / totalBytes) * 100; + updateFileStream.Write(buffer, 0, readSize); + } + + InstallUpdate(updateDialog, updateFile); + } + + private static void DoUpdateWithSingleThread(UpdateDialog updateDialog, string downloadUrl, string updateFile) + { + Thread worker = new(() => DoUpdateWithSingleThreadWorker(updateDialog, downloadUrl, updateFile)) + { + Name = "Updater.SingleThreadWorker", + }; + worker.Start(); + } + + private static async void InstallUpdate(UpdateDialog updateDialog, string updateFile) + { + // Extract Update + updateDialog.MainText.Text = "Extracting Update..."; + updateDialog.ProgressBar.Value = 0; + + if (OperatingSystem.IsLinux()) + { + using Stream inStream = File.OpenRead(updateFile); + using Stream gzipStream = new GZipInputStream(inStream); + using TarInputStream tarStream = new(gzipStream, Encoding.ASCII); + updateDialog.ProgressBar.MaxValue = inStream.Length; + + await Task.Run(() => + { + TarEntry tarEntry; + + if (!OperatingSystem.IsWindows()) + { + while ((tarEntry = tarStream.GetNextEntry()) != null) + { + if (tarEntry.IsDirectory) + { + continue; + } + + string outPath = Path.Combine(_updateDir, tarEntry.Name); + + Directory.CreateDirectory(Path.GetDirectoryName(outPath)); + + using FileStream outStream = File.OpenWrite(outPath); + tarStream.CopyEntryContents(outStream); + + File.SetUnixFileMode(outPath, (UnixFileMode)tarEntry.TarHeader.Mode); + File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc)); + + TarEntry entry = tarEntry; + + Application.Invoke(delegate + { + updateDialog.ProgressBar.Value += entry.Size; + }); + } + } + }); + + updateDialog.ProgressBar.Value = inStream.Length; + } + else + { + using Stream inStream = File.OpenRead(updateFile); + using ZipFile zipFile = new(inStream); + updateDialog.ProgressBar.MaxValue = zipFile.Count; + + await Task.Run(() => + { + foreach (ZipEntry zipEntry in zipFile) + { + if (zipEntry.IsDirectory) + { + continue; + } + + string outPath = Path.Combine(_updateDir, zipEntry.Name); + + Directory.CreateDirectory(Path.GetDirectoryName(outPath)); + + using Stream zipStream = zipFile.GetInputStream(zipEntry); + using FileStream outStream = File.OpenWrite(outPath); + zipStream.CopyTo(outStream); + + File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc)); + + Application.Invoke(delegate + { + updateDialog.ProgressBar.Value++; + }); + } + }); + } + + // Delete downloaded zip + File.Delete(updateFile); + + List allFiles = EnumerateFilesToDelete().ToList(); + + updateDialog.MainText.Text = "Renaming Old Files..."; + updateDialog.ProgressBar.Value = 0; + updateDialog.ProgressBar.MaxValue = allFiles.Count; + + // Replace old files + await Task.Run(() => + { + foreach (string file in allFiles) + { + try + { + File.Move(file, file + ".ryuold"); + + Application.Invoke(delegate + { + updateDialog.ProgressBar.Value++; + }); + } + catch + { + Logger.Warning?.Print(LogClass.Application, "Updater was unable to rename file: " + file); + } + } + + Application.Invoke(delegate + { + updateDialog.MainText.Text = "Adding New Files..."; + updateDialog.ProgressBar.Value = 0; + updateDialog.ProgressBar.MaxValue = Directory.GetFiles(_updatePublishDir, "*", SearchOption.AllDirectories).Length; + }); + + MoveAllFilesOver(_updatePublishDir, _homeDir, updateDialog); + }); + + Directory.Delete(_updateDir, true); + + updateDialog.MainText.Text = "Update Complete!"; + updateDialog.SecondaryText.Text = "Do you want to restart Ryujinx now?"; + updateDialog.Modal = true; + + updateDialog.ProgressBar.Hide(); + updateDialog.YesButton.Show(); + updateDialog.NoButton.Show(); + } + + public static bool CanUpdate(bool showWarnings) + { +#if !DISABLE_UPDATER + if (!NetworkInterface.GetIsNetworkAvailable()) + { + if (showWarnings) + { + GtkDialog.CreateWarningDialog("You are not connected to the Internet!", "Please verify that you have a working Internet connection!"); + } + + return false; + } + + if (Program.Version.Contains("dirty") || !ReleaseInformation.IsValid) + { + if (showWarnings) + { + GtkDialog.CreateWarningDialog("You cannot update a Dirty build of Ryujinx!", "Please download Ryujinx at https://ryujinx.org/ if you are looking for a supported version."); + } + + return false; + } + + return true; +#else + if (showWarnings) + { + if (ReleaseInformation.IsFlatHubBuild) + { + GtkDialog.CreateWarningDialog("Updater Disabled!", "Please update Ryujinx via FlatHub."); + } + else + { + GtkDialog.CreateWarningDialog("Updater Disabled!", "Please download Ryujinx at https://ryujinx.org/ if you are looking for a supported version."); + } + } + + return false; +#endif + } + + // NOTE: This method should always reflect the latest build layout. + private static IEnumerable EnumerateFilesToDelete() + { + var files = Directory.EnumerateFiles(_homeDir); // All files directly in base dir. + + // Determine and exclude user files only when the updater is running, not when cleaning old files + if (Running) + { + // Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list. + var oldFiles = Directory.EnumerateFiles(_homeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName); + var newFiles = Directory.EnumerateFiles(_updatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName); + var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(_homeDir, filename)); + + // Remove user files from the paths in files. + files = files.Except(userFiles); + } + + if (OperatingSystem.IsWindows()) + { + foreach (string dir in _windowsDependencyDirs) + { + string dirPath = Path.Combine(_homeDir, dir); + if (Directory.Exists(dirPath)) + { + files = files.Concat(Directory.EnumerateFiles(dirPath, "*", SearchOption.AllDirectories)); + } + } + } + + return files.Where(f => !new FileInfo(f).Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System)); + } + + private static void MoveAllFilesOver(string root, string dest, UpdateDialog dialog) + { + foreach (string directory in Directory.GetDirectories(root)) + { + string dirName = Path.GetFileName(directory); + + if (!Directory.Exists(Path.Combine(dest, dirName))) + { + Directory.CreateDirectory(Path.Combine(dest, dirName)); + } + + MoveAllFilesOver(directory, Path.Combine(dest, dirName), dialog); + } + + foreach (string file in Directory.GetFiles(root)) + { + File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true); + + Application.Invoke(delegate + { + dialog.ProgressBar.Value++; + }); + } + } + + public static void CleanupUpdate() + { + foreach (string file in EnumerateFilesToDelete()) + { + if (Path.GetExtension(file).EndsWith(".ryuold")) + { + File.Delete(file); + } + } + } + } +} diff --git a/src/Ryujinx.Gtk3/Program.cs b/src/Ryujinx.Gtk3/Program.cs new file mode 100644 index 000000000..2d350374b --- /dev/null +++ b/src/Ryujinx.Gtk3/Program.cs @@ -0,0 +1,403 @@ +using Gtk; +using Ryujinx.Common; +using Ryujinx.Common.Configuration; +using Ryujinx.Common.GraphicsDriver; +using Ryujinx.Common.Logging; +using Ryujinx.Common.SystemInterop; +using Ryujinx.Common.Utilities; +using Ryujinx.Graphics.Vulkan.MoltenVK; +using Ryujinx.Modules; +using Ryujinx.SDL2.Common; +using Ryujinx.UI; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Common.SystemInfo; +using Ryujinx.UI.Widgets; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +namespace Ryujinx +{ + partial class Program + { + public static double WindowScaleFactor { get; private set; } + + public static string Version { get; private set; } + + public static string ConfigurationPath { get; set; } + + public static string CommandLineProfile { get; set; } + + private const string X11LibraryName = "libX11"; + + [LibraryImport(X11LibraryName)] + private static partial int XInitThreads(); + + [LibraryImport("user32.dll", SetLastError = true)] + public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type); + + private const uint MbIconWarning = 0x30; + + static Program() + { + if (OperatingSystem.IsLinux()) + { + NativeLibrary.SetDllImportResolver(typeof(Program).Assembly, (name, assembly, path) => + { + if (name != X11LibraryName) + { + return IntPtr.Zero; + } + + if (!NativeLibrary.TryLoad("libX11.so.6", assembly, path, out IntPtr result)) + { + if (!NativeLibrary.TryLoad("libX11.so", assembly, path, out result)) + { + return IntPtr.Zero; + } + } + + return result; + }); + } + } + + static void Main(string[] args) + { + Version = ReleaseInformation.Version; + + if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134)) + { + MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nRyujinx supports Windows 10 version 1803 and newer.\n", $"Ryujinx {Version}", MbIconWarning); + } + + // Parse arguments + CommandLineState.ParseArguments(args); + + // Hook unhandled exception and process exit events. + GLib.ExceptionManager.UnhandledException += (GLib.UnhandledExceptionArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); + AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); + AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit(); + + // Make process DPI aware for proper window sizing on high-res screens. + ForceDpiAware.Windows(); + WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor(); + + // Delete backup files after updating. + Task.Run(Updater.CleanupUpdate); + + Console.Title = $"Ryujinx Console {Version}"; + + // NOTE: GTK3 doesn't init X11 in a multi threaded way. + // This ends up causing race condition and abort of XCB when a context is created by SPB (even if SPB do call XInitThreads). + if (OperatingSystem.IsLinux()) + { + if (XInitThreads() == 0) + { + throw new NotSupportedException("Failed to initialize multi-threading support."); + } + + OsUtils.SetEnvironmentVariableNoCaching("GDK_BACKEND", "x11"); + } + + if (OperatingSystem.IsMacOS()) + { + MVKInitialization.InitializeResolver(); + + string baseDirectory = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); + string resourcesDataDir; + + if (Path.GetFileName(baseDirectory) == "MacOS") + { + resourcesDataDir = Path.Combine(Directory.GetParent(baseDirectory).FullName, "Resources"); + } + else + { + resourcesDataDir = baseDirectory; + } + + // On macOS, GTK3 needs XDG_DATA_DIRS to be set, otherwise it will try searching for "gschemas.compiled" in system directories. + OsUtils.SetEnvironmentVariableNoCaching("XDG_DATA_DIRS", Path.Combine(resourcesDataDir, "share")); + + // On macOS, GTK3 needs GDK_PIXBUF_MODULE_FILE to be set, otherwise it will try searching for "loaders.cache" in system directories. + OsUtils.SetEnvironmentVariableNoCaching("GDK_PIXBUF_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gdk-pixbuf-2.0", "2.10.0", "loaders.cache")); + + OsUtils.SetEnvironmentVariableNoCaching("GTK_IM_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gtk-3.0", "3.0.0", "immodules.cache")); + } + + string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); + Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}"); + + // Setup base data directory. + AppDataManager.Initialize(CommandLineState.BaseDirPathArg); + + // Initialize the configuration. + ConfigurationState.Initialize(); + + // Initialize the logger system. + LoggerModule.Initialize(); + + // Initialize Discord integration. + DiscordIntegrationModule.Initialize(); + + // Initialize SDL2 driver + SDL2Driver.MainThreadDispatcher = action => + { + Application.Invoke(delegate + { + action(); + }); + }; + + string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName); + string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName); + + // Now load the configuration as the other subsystems are now registered + ConfigurationPath = File.Exists(localConfigurationPath) + ? localConfigurationPath + : File.Exists(appDataConfigurationPath) + ? appDataConfigurationPath + : null; + + if (ConfigurationPath == null) + { + // No configuration, we load the default values and save it to disk + ConfigurationPath = appDataConfigurationPath; + Logger.Notice.Print(LogClass.Application, $"No configuration file found. Saving default configuration to: {ConfigurationPath}"); + + ConfigurationState.Instance.LoadDefault(); + ConfigurationState.Instance.ToFileFormat().SaveConfig(ConfigurationPath); + } + else + { + Logger.Notice.Print(LogClass.Application, $"Loading configuration from: {ConfigurationPath}"); + + if (ConfigurationFileFormat.TryLoad(ConfigurationPath, out ConfigurationFileFormat configurationFileFormat)) + { + ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); + } + else + { + Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location: {ConfigurationPath}"); + + ConfigurationState.Instance.LoadDefault(); + } + } + + // Check if graphics backend was overridden. + if (CommandLineState.OverrideGraphicsBackend != null) + { + if (CommandLineState.OverrideGraphicsBackend.ToLower() == "opengl") + { + ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.OpenGl; + } + else if (CommandLineState.OverrideGraphicsBackend.ToLower() == "vulkan") + { + ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.Vulkan; + } + } + + // Check if HideCursor was overridden. + if (CommandLineState.OverrideHideCursor is not null) + { + ConfigurationState.Instance.HideCursor.Value = CommandLineState.OverrideHideCursor!.ToLower() switch + { + "never" => HideCursorMode.Never, + "onidle" => HideCursorMode.OnIdle, + "always" => HideCursorMode.Always, + _ => ConfigurationState.Instance.HideCursor.Value, + }; + } + + // Check if docked mode was overridden. + if (CommandLineState.OverrideDockedMode.HasValue) + { + ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value; + } + + // Logging system information. + PrintSystemInfo(); + + // Enable OGL multithreading on the driver, and some other flags. + BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading; + DriverUtilities.InitDriverConfig(threadingMode == BackendThreading.Off); + + // Initialize Gtk. + Application.Init(); + + // Check if keys exists. + bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")); + bool hasCommonProdKeys = AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys")); + if (!hasSystemProdKeys && !hasCommonProdKeys) + { + UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys); + } + + // Show the main window UI. + MainWindow mainWindow = new(); + mainWindow.Show(); + + // Load the game table if no application was requested by the command line + if (CommandLineState.LaunchPathArg == null) + { + mainWindow.UpdateGameTable(); + } + + if (OperatingSystem.IsLinux()) + { + int currentVmMaxMapCount = LinuxHelper.VmMaxMapCount; + + if (LinuxHelper.VmMaxMapCount < LinuxHelper.RecommendedVmMaxMapCount) + { + Logger.Warning?.Print(LogClass.Application, $"The value of vm.max_map_count is lower than {LinuxHelper.RecommendedVmMaxMapCount}. ({currentVmMaxMapCount})"); + + if (LinuxHelper.PkExecPath is not null) + { + var buttonTexts = new Dictionary() + { + { 0, "Yes, until the next restart" }, + { 1, "Yes, permanently" }, + { 2, "No" }, + }; + + ResponseType response = GtkDialog.CreateCustomDialog( + "Ryujinx - Low limit for memory mappings detected", + $"Would you like to increase the value of vm.max_map_count to {LinuxHelper.RecommendedVmMaxMapCount}?", + "Some games might try to create more memory mappings than currently allowed. " + + "Ryujinx will crash as soon as this limit gets exceeded.", + buttonTexts, + MessageType.Question); + + int rc; + + switch ((int)response) + { + case 0: + rc = LinuxHelper.RunPkExec($"echo {LinuxHelper.RecommendedVmMaxMapCount} > {LinuxHelper.VmMaxMapCountPath}"); + if (rc == 0) + { + Logger.Info?.Print(LogClass.Application, $"vm.max_map_count set to {LinuxHelper.VmMaxMapCount} until the next restart."); + } + else + { + Logger.Error?.Print(LogClass.Application, $"Unable to change vm.max_map_count. Process exited with code: {rc}"); + } + break; + case 1: + rc = LinuxHelper.RunPkExec($"echo \"vm.max_map_count = {LinuxHelper.RecommendedVmMaxMapCount}\" > {LinuxHelper.SysCtlConfigPath} && sysctl -p {LinuxHelper.SysCtlConfigPath}"); + if (rc == 0) + { + Logger.Info?.Print(LogClass.Application, $"vm.max_map_count set to {LinuxHelper.VmMaxMapCount}. Written to config: {LinuxHelper.SysCtlConfigPath}"); + } + else + { + Logger.Error?.Print(LogClass.Application, $"Unable to write new value for vm.max_map_count to config. Process exited with code: {rc}"); + } + break; + } + } + else + { + GtkDialog.CreateWarningDialog( + "Max amount of memory mappings is lower than recommended.", + $"The current value of vm.max_map_count ({currentVmMaxMapCount}) is lower than {LinuxHelper.RecommendedVmMaxMapCount}." + + "Some games might try to create more memory mappings than currently allowed. " + + "Ryujinx will crash as soon as this limit gets exceeded.\n\n" + + "You might want to either manually increase the limit or install pkexec, which allows Ryujinx to assist with that."); + } + } + } + + if (CommandLineState.LaunchPathArg != null) + { + if (mainWindow.ApplicationLibrary.TryGetApplicationsFromFile(CommandLineState.LaunchPathArg, out List applications)) + { + ApplicationData applicationData; + + if (CommandLineState.LaunchApplicationId != null) + { + applicationData = applications.Find(application => application.IdString == CommandLineState.LaunchApplicationId); + + if (applicationData != null) + { + mainWindow.RunApplication(applicationData, CommandLineState.StartFullscreenArg); + } + else + { + Logger.Error?.Print(LogClass.Application, $"Couldn't find requested application id '{CommandLineState.LaunchApplicationId}' in '{CommandLineState.LaunchPathArg}'."); + UserErrorDialog.CreateUserErrorDialog(UserError.ApplicationNotFound); + } + } + else + { + applicationData = applications[0]; + mainWindow.RunApplication(applicationData, CommandLineState.StartFullscreenArg); + } + } + else + { + Logger.Error?.Print(LogClass.Application, $"Couldn't find any application in '{CommandLineState.LaunchPathArg}'."); + UserErrorDialog.CreateUserErrorDialog(UserError.ApplicationNotFound); + } + } + + if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false)) + { + Updater.BeginParse(mainWindow, false).ContinueWith(task => + { + Logger.Error?.Print(LogClass.Application, $"Updater Error: {task.Exception}"); + }, TaskContinuationOptions.OnlyOnFaulted); + } + + Application.Run(); + } + + private static void PrintSystemInfo() + { + Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}"); + SystemInfo.Gather().Print(); + + var enabledLogs = Logger.GetEnabledLevels(); + Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogs.Count == 0 ? "" : string.Join(", ", enabledLogs))}"); + + if (AppDataManager.Mode == AppDataManager.LaunchMode.Custom) + { + Logger.Notice.Print(LogClass.Application, $"Launch Mode: Custom Path {AppDataManager.BaseDirPath}"); + } + else + { + Logger.Notice.Print(LogClass.Application, $"Launch Mode: {AppDataManager.Mode}"); + } + } + + private static void ProcessUnhandledException(Exception ex, bool isTerminating) + { + string message = $"Unhandled exception caught: {ex}"; + + Logger.Error?.PrintMsg(LogClass.Application, message); + + if (Logger.Error == null) + { + Logger.Notice.PrintMsg(LogClass.Application, message); + } + + if (isTerminating) + { + Exit(); + } + } + + public static void Exit() + { + DiscordIntegrationModule.Exit(); + + Logger.Shutdown(); + } + } +} diff --git a/src/Ryujinx.Gtk3/Ryujinx.Gtk3.csproj b/src/Ryujinx.Gtk3/Ryujinx.Gtk3.csproj new file mode 100644 index 000000000..722d6080b --- /dev/null +++ b/src/Ryujinx.Gtk3/Ryujinx.Gtk3.csproj @@ -0,0 +1,103 @@ + + + + net8.0 + win-x64;osx-x64;linux-x64 + Exe + true + 1.0.0-dirty + $(DefineConstants);$(ExtraDefineConstants) + + true + true + + + + true + false + true + partial + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + alsoft.ini + + + Always + THIRDPARTY.md + + + Always + LICENSE.txt + + + + + + Always + + + Always + mime\Ryujinx.xml + + + + + + false + Ryujinx.ico + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx.Ava/Ryujinx.ico b/src/Ryujinx.Gtk3/Ryujinx.ico similarity index 100% rename from src/Ryujinx.Ava/Ryujinx.ico rename to src/Ryujinx.Gtk3/Ryujinx.ico diff --git a/src/Ryujinx/Ui/Applet/ErrorAppletDialog.cs b/src/Ryujinx.Gtk3/UI/Applet/ErrorAppletDialog.cs similarity index 84% rename from src/Ryujinx/Ui/Applet/ErrorAppletDialog.cs rename to src/Ryujinx.Gtk3/UI/Applet/ErrorAppletDialog.cs index c6bcf3f28..cb8103cae 100644 --- a/src/Ryujinx/Ui/Applet/ErrorAppletDialog.cs +++ b/src/Ryujinx.Gtk3/UI/Applet/ErrorAppletDialog.cs @@ -1,14 +1,14 @@ using Gtk; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System.Reflection; -namespace Ryujinx.Ui.Applet +namespace Ryujinx.UI.Applet { internal class ErrorAppletDialog : MessageDialog { public ErrorAppletDialog(Window parentWindow, DialogFlags dialogFlags, MessageType messageType, string[] buttons) : base(parentWindow, dialogFlags, messageType, ButtonsType.None, null) { - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Gtk3.UI.Common.Resources.Logo_Ryujinx.png"); int responseId = 0; diff --git a/src/Ryujinx/Ui/Applet/GtkDynamicTextInputHandler.cs b/src/Ryujinx.Gtk3/UI/Applet/GtkDynamicTextInputHandler.cs similarity index 97% rename from src/Ryujinx/Ui/Applet/GtkDynamicTextInputHandler.cs rename to src/Ryujinx.Gtk3/UI/Applet/GtkDynamicTextInputHandler.cs index 3a3da4650..0e560b789 100644 --- a/src/Ryujinx/Ui/Applet/GtkDynamicTextInputHandler.cs +++ b/src/Ryujinx.Gtk3/UI/Applet/GtkDynamicTextInputHandler.cs @@ -1,10 +1,10 @@ using Gtk; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Input.GTK3; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Widgets; using System.Threading; -namespace Ryujinx.Ui.Applet +namespace Ryujinx.UI.Applet { /// /// Class that forwards key events to a GTK Entry so they can be processed into text. diff --git a/src/Ryujinx/Ui/Applet/GtkHostUiHandler.cs b/src/Ryujinx.Gtk3/UI/Applet/GtkHostUIHandler.cs similarity index 92% rename from src/Ryujinx/Ui/Applet/GtkHostUiHandler.cs rename to src/Ryujinx.Gtk3/UI/Applet/GtkHostUIHandler.cs index fcd6cf589..81c84ebca 100644 --- a/src/Ryujinx/Ui/Applet/GtkHostUiHandler.cs +++ b/src/Ryujinx.Gtk3/UI/Applet/GtkHostUIHandler.cs @@ -1,27 +1,27 @@ using Gtk; using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; -using Ryujinx.HLE.Ui; -using Ryujinx.Ui.Widgets; +using Ryujinx.HLE.UI; +using Ryujinx.UI.Widgets; using System; using System.Threading; -namespace Ryujinx.Ui.Applet +namespace Ryujinx.UI.Applet { - internal class GtkHostUiHandler : IHostUiHandler + internal class GtkHostUIHandler : IHostUIHandler { private readonly Window _parent; - public IHostUiTheme HostUiTheme { get; } + public IHostUITheme HostUITheme { get; } - public GtkHostUiHandler(Window parent) + public GtkHostUIHandler(Window parent) { _parent = parent; - HostUiTheme = new GtkHostUiTheme(parent); + HostUITheme = new GtkHostUITheme(parent); } - public bool DisplayMessageDialog(ControllerAppletUiArgs args) + public bool DisplayMessageDialog(ControllerAppletUIArgs args) { string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}"; @@ -81,7 +81,7 @@ namespace Ryujinx.Ui.Applet return okPressed; } - public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action onTextEntered) + public void DisplayInputDialog(SoftwareKeyboardUIArgs args, Action onTextEntered) { onTextEntered?.Invoke("MeloNX"); return; diff --git a/src/Ryujinx/Ui/Applet/GtkHostUiTheme.cs b/src/Ryujinx.Gtk3/UI/Applet/GtkHostUITheme.cs similarity index 96% rename from src/Ryujinx/Ui/Applet/GtkHostUiTheme.cs rename to src/Ryujinx.Gtk3/UI/Applet/GtkHostUITheme.cs index 1bc010591..52d1123bb 100644 --- a/src/Ryujinx/Ui/Applet/GtkHostUiTheme.cs +++ b/src/Ryujinx.Gtk3/UI/Applet/GtkHostUITheme.cs @@ -1,10 +1,10 @@ using Gtk; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System.Diagnostics; -namespace Ryujinx.Ui.Applet +namespace Ryujinx.UI.Applet { - internal class GtkHostUiTheme : IHostUiTheme + internal class GtkHostUITheme : IHostUITheme { private const int RenderSurfaceWidth = 32; private const int RenderSurfaceHeight = 32; @@ -17,7 +17,7 @@ namespace Ryujinx.Ui.Applet public ThemeColor SelectionBackgroundColor { get; } public ThemeColor SelectionForegroundColor { get; } - public GtkHostUiTheme(Window parent) + public GtkHostUITheme(Window parent) { Entry entry = new(); entry.SetStateFlags(StateFlags.Selected, true); diff --git a/src/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs b/src/Ryujinx.Gtk3/UI/Applet/SwkbdAppletDialog.cs similarity index 99% rename from src/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs rename to src/Ryujinx.Gtk3/UI/Applet/SwkbdAppletDialog.cs index c1f3d77c1..8045da91e 100644 --- a/src/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs +++ b/src/Ryujinx.Gtk3/UI/Applet/SwkbdAppletDialog.cs @@ -3,7 +3,7 @@ using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard; using System; using System.Linq; -namespace Ryujinx.Ui.Applet +namespace Ryujinx.UI.Applet { public class SwkbdAppletDialog : MessageDialog { diff --git a/src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs b/src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs new file mode 100644 index 000000000..5a8ca96a1 --- /dev/null +++ b/src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs @@ -0,0 +1,158 @@ +using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Input; +using System; +using System.Collections.Generic; +using Key = Ryujinx.Common.Configuration.Hid.Key; +using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; + +namespace Ryujinx.UI.Helper +{ + public static class ButtonHelper + { + private static readonly Dictionary _keysMap = new() + { + { Key.Unknown, "Unknown" }, + { Key.ShiftLeft, "ShiftLeft" }, + { Key.ShiftRight, "ShiftRight" }, + { Key.ControlLeft, "CtrlLeft" }, + { Key.ControlRight, "CtrlRight" }, + { Key.AltLeft, OperatingSystem.IsMacOS() ? "OptLeft" : "AltLeft" }, + { Key.AltRight, OperatingSystem.IsMacOS() ? "OptRight" : "AltRight" }, + { Key.WinLeft, OperatingSystem.IsMacOS() ? "CmdLeft" : "WinLeft" }, + { Key.WinRight, OperatingSystem.IsMacOS() ? "CmdRight" : "WinRight" }, + { Key.Up, "Up" }, + { Key.Down, "Down" }, + { Key.Left, "Left" }, + { Key.Right, "Right" }, + { Key.Enter, "Enter" }, + { Key.Escape, "Escape" }, + { Key.Space, "Space" }, + { Key.Tab, "Tab" }, + { Key.BackSpace, "Backspace" }, + { Key.Insert, "Insert" }, + { Key.Delete, "Delete" }, + { Key.PageUp, "PageUp" }, + { Key.PageDown, "PageDown" }, + { Key.Home, "Home" }, + { Key.End, "End" }, + { Key.CapsLock, "CapsLock" }, + { Key.ScrollLock, "ScrollLock" }, + { Key.PrintScreen, "PrintScreen" }, + { Key.Pause, "Pause" }, + { Key.NumLock, "NumLock" }, + { Key.Clear, "Clear" }, + { Key.Keypad0, "Keypad0" }, + { Key.Keypad1, "Keypad1" }, + { Key.Keypad2, "Keypad2" }, + { Key.Keypad3, "Keypad3" }, + { Key.Keypad4, "Keypad4" }, + { Key.Keypad5, "Keypad5" }, + { Key.Keypad6, "Keypad6" }, + { Key.Keypad7, "Keypad7" }, + { Key.Keypad8, "Keypad8" }, + { Key.Keypad9, "Keypad9" }, + { Key.KeypadDivide, "KeypadDivide" }, + { Key.KeypadMultiply, "KeypadMultiply" }, + { Key.KeypadSubtract, "KeypadSubtract" }, + { Key.KeypadAdd, "KeypadAdd" }, + { Key.KeypadDecimal, "KeypadDecimal" }, + { Key.KeypadEnter, "KeypadEnter" }, + { Key.Number0, "0" }, + { Key.Number1, "1" }, + { Key.Number2, "2" }, + { Key.Number3, "3" }, + { Key.Number4, "4" }, + { Key.Number5, "5" }, + { Key.Number6, "6" }, + { Key.Number7, "7" }, + { Key.Number8, "8" }, + { Key.Number9, "9" }, + { Key.Tilde, "~" }, + { Key.Grave, "`" }, + { Key.Minus, "-" }, + { Key.Plus, "+" }, + { Key.BracketLeft, "[" }, + { Key.BracketRight, "]" }, + { Key.Semicolon, ";" }, + { Key.Quote, "'" }, + { Key.Comma, "," }, + { Key.Period, "." }, + { Key.Slash, "/" }, + { Key.BackSlash, "\\" }, + { Key.Unbound, "Unbound" }, + }; + + private static readonly Dictionary _gamepadInputIdMap = new() + { + { GamepadInputId.LeftStick, "LeftStick" }, + { GamepadInputId.RightStick, "RightStick" }, + { GamepadInputId.LeftShoulder, "LeftShoulder" }, + { GamepadInputId.RightShoulder, "RightShoulder" }, + { GamepadInputId.LeftTrigger, "LeftTrigger" }, + { GamepadInputId.RightTrigger, "RightTrigger" }, + { GamepadInputId.DpadUp, "DpadUp" }, + { GamepadInputId.DpadDown, "DpadDown" }, + { GamepadInputId.DpadLeft, "DpadLeft" }, + { GamepadInputId.DpadRight, "DpadRight" }, + { GamepadInputId.Minus, "Minus" }, + { GamepadInputId.Plus, "Plus" }, + { GamepadInputId.Guide, "Guide" }, + { GamepadInputId.Misc1, "Misc1" }, + { GamepadInputId.Paddle1, "Paddle1" }, + { GamepadInputId.Paddle2, "Paddle2" }, + { GamepadInputId.Paddle3, "Paddle3" }, + { GamepadInputId.Paddle4, "Paddle4" }, + { GamepadInputId.Touchpad, "Touchpad" }, + { GamepadInputId.SingleLeftTrigger0, "SingleLeftTrigger0" }, + { GamepadInputId.SingleRightTrigger0, "SingleRightTrigger0" }, + { GamepadInputId.SingleLeftTrigger1, "SingleLeftTrigger1" }, + { GamepadInputId.SingleRightTrigger1, "SingleRightTrigger1" }, + { GamepadInputId.Unbound, "Unbound" }, + }; + + private static readonly Dictionary _stickInputIdMap = new() + { + { StickInputId.Left, "StickLeft" }, + { StickInputId.Right, "StickRight" }, + { StickInputId.Unbound, "Unbound" }, + }; + + public static string ToString(Button button) + { + string keyString = ""; + + switch (button.Type) + { + case ButtonType.Key: + var key = button.AsHidType(); + + if (!_keysMap.TryGetValue(button.AsHidType(), out keyString)) + { + keyString = key.ToString(); + } + + break; + case ButtonType.GamepadButtonInputId: + var gamepadButton = button.AsHidType(); + + if (!_gamepadInputIdMap.TryGetValue(button.AsHidType(), out keyString)) + { + keyString = gamepadButton.ToString(); + } + + break; + case ButtonType.StickId: + var stickInput = button.AsHidType(); + + if (!_stickInputIdMap.TryGetValue(button.AsHidType(), out keyString)) + { + keyString = stickInput.ToString(); + } + + break; + } + + return keyString; + } + } +} diff --git a/src/Ryujinx/Ui/Helper/MetalHelper.cs b/src/Ryujinx.Gtk3/UI/Helper/MetalHelper.cs similarity index 99% rename from src/Ryujinx/Ui/Helper/MetalHelper.cs rename to src/Ryujinx.Gtk3/UI/Helper/MetalHelper.cs index f46a5e36e..f58adf6e8 100644 --- a/src/Ryujinx/Ui/Helper/MetalHelper.cs +++ b/src/Ryujinx.Gtk3/UI/Helper/MetalHelper.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Helper +namespace Ryujinx.UI.Helper { public delegate void UpdateBoundsCallbackDelegate(Window window); diff --git a/src/Ryujinx/Ui/Helper/SortHelper.cs b/src/Ryujinx.Gtk3/UI/Helper/SortHelper.cs similarity index 94% rename from src/Ryujinx/Ui/Helper/SortHelper.cs rename to src/Ryujinx.Gtk3/UI/Helper/SortHelper.cs index 4e625f922..3e3fbeaae 100644 --- a/src/Ryujinx/Ui/Helper/SortHelper.cs +++ b/src/Ryujinx.Gtk3/UI/Helper/SortHelper.cs @@ -1,8 +1,8 @@ using Gtk; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System; -namespace Ryujinx.Ui.Helper +namespace Ryujinx.UI.Helper { static class SortHelper { diff --git a/src/Ryujinx/Ui/Helper/ThemeHelper.cs b/src/Ryujinx.Gtk3/UI/Helper/ThemeHelper.cs similarity index 54% rename from src/Ryujinx/Ui/Helper/ThemeHelper.cs rename to src/Ryujinx.Gtk3/UI/Helper/ThemeHelper.cs index 67962cb6c..e1fed1c4d 100644 --- a/src/Ryujinx/Ui/Helper/ThemeHelper.cs +++ b/src/Ryujinx.Gtk3/UI/Helper/ThemeHelper.cs @@ -1,33 +1,34 @@ using Gtk; +using Ryujinx.Common; using Ryujinx.Common.Logging; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System.IO; -namespace Ryujinx.Ui.Helper +namespace Ryujinx.UI.Helper { static class ThemeHelper { public static void ApplyTheme() { - if (!ConfigurationState.Instance.Ui.EnableCustomTheme) + if (!ConfigurationState.Instance.UI.EnableCustomTheme) { return; } - if (File.Exists(ConfigurationState.Instance.Ui.CustomThemePath) && (Path.GetExtension(ConfigurationState.Instance.Ui.CustomThemePath) == ".css")) + if (File.Exists(ConfigurationState.Instance.UI.CustomThemePath) && (Path.GetExtension(ConfigurationState.Instance.UI.CustomThemePath) == ".css")) { CssProvider cssProvider = new(); - cssProvider.LoadFromPath(ConfigurationState.Instance.Ui.CustomThemePath); + cssProvider.LoadFromPath(ConfigurationState.Instance.UI.CustomThemePath); StyleContext.AddProviderForScreen(Gdk.Screen.Default, cssProvider, 800); } else { - Logger.Warning?.Print(LogClass.Application, $"The \"custom_theme_path\" section in \"Config.json\" contains an invalid path: \"{ConfigurationState.Instance.Ui.CustomThemePath}\"."); + Logger.Warning?.Print(LogClass.Application, $"The \"custom_theme_path\" section in \"{ReleaseInformation.ConfigName}\" contains an invalid path: \"{ConfigurationState.Instance.UI.CustomThemePath}\"."); - ConfigurationState.Instance.Ui.CustomThemePath.Value = ""; - ConfigurationState.Instance.Ui.EnableCustomTheme.Value = false; + ConfigurationState.Instance.UI.CustomThemePath.Value = ""; + ConfigurationState.Instance.UI.EnableCustomTheme.Value = false; ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); } } diff --git a/src/Ryujinx/Ui/MainWindow.cs b/src/Ryujinx.Gtk3/UI/MainWindow.cs similarity index 87% rename from src/Ryujinx/Ui/MainWindow.cs rename to src/Ryujinx.Gtk3/UI/MainWindow.cs index 2a088f561..b10dfe3f9 100644 --- a/src/Ryujinx/Ui/MainWindow.cs +++ b/src/Ryujinx.Gtk3/UI/MainWindow.cs @@ -1,4 +1,3 @@ -using ARMeilleure.Translation; using Gtk; using LibHac.Common; using LibHac.Common.Keys; @@ -27,18 +26,20 @@ using Ryujinx.Input.GTK3; using Ryujinx.Input.HLE; using Ryujinx.Input.SDL2; using Ryujinx.Modules; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Applet; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Helper; -using Ryujinx.Ui.Widgets; -using Ryujinx.Ui.Windows; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Applet; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Helper; +using Ryujinx.UI.Widgets; +using Ryujinx.UI.Windows; using Silk.NET.Vulkan; using SPB.Graphics.Vulkan; using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Reflection; using System.Threading; @@ -46,7 +47,7 @@ using System.Threading.Tasks; using GUI = Gtk.Builder.ObjectAttribute; using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public class MainWindow : Window { @@ -61,8 +62,7 @@ namespace Ryujinx.Ui private WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution; - private readonly ApplicationLibrary _applicationLibrary; - private readonly GtkHostUiHandler _uiHandler; + private readonly GtkHostUIHandler _uiHandler; private readonly AutoResetEvent _deviceExitStatus; private readonly ListStore _tableStore; @@ -70,11 +70,12 @@ namespace Ryujinx.Ui private bool _gameLoaded; private bool _ending; - private string _currentEmulatedGamePath = null; + private ApplicationData _currentApplicationData = null; private string _lastScannedAmiiboId = ""; private bool _lastScannedAmiiboShowAll = false; + public readonly ApplicationLibrary ApplicationLibrary; public RendererWidgetBase RendererWidget; public InputManager InputManager; @@ -100,7 +101,7 @@ namespace Ryujinx.Ui [GUI] MenuItem _simulateWakeUpMessage; [GUI] MenuItem _scanAmiibo; [GUI] MenuItem _takeScreenshot; - [GUI] MenuItem _hideUi; + [GUI] MenuItem _hideUI; [GUI] MenuItem _fullScreen; [GUI] CheckMenuItem _startFullScreen; [GUI] CheckMenuItem _showConsole; @@ -144,7 +145,7 @@ namespace Ryujinx.Ui #pragma warning restore CS0649, IDE0044, CS0169, IDE0051 - public MainWindow() : this(new Builder("Ryujinx.Ui.MainWindow.glade")) { } + public MainWindow() : this(new Builder("Ryujinx.Gtk3.UI.MainWindow.glade")) { } private MainWindow(Builder builder) : base(builder.GetRawOwnedObject("_mainWin")) { @@ -155,7 +156,7 @@ namespace Ryujinx.Ui SetWindowSizePosition(); - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); Title = $"Ryujinx {Program.Version}"; // Hide emulation context status bar. @@ -181,9 +182,16 @@ namespace Ryujinx.Ui _accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, CommandLineState.Profile); _userChannelPersistence = new UserChannelPersistence(); + IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks + ? IntegrityCheckLevel.ErrorOnInvalid + : IntegrityCheckLevel.None; + // Instantiate GUI objects. - _applicationLibrary = new ApplicationLibrary(_virtualFileSystem); - _uiHandler = new GtkHostUiHandler(this); + ApplicationLibrary = new ApplicationLibrary(_virtualFileSystem, checkLevel) + { + DesiredLanguage = ConfigurationState.Instance.System.Language, + }; + _uiHandler = new GtkHostUIHandler(this); _deviceExitStatus = new AutoResetEvent(false); WindowStateEvent += WindowStateEvent_Changed; @@ -191,8 +199,8 @@ namespace Ryujinx.Ui FocusInEvent += MainWindow_FocusInEvent; FocusOutEvent += MainWindow_FocusOutEvent; - _applicationLibrary.ApplicationAdded += Application_Added; - _applicationLibrary.ApplicationCountUpdated += ApplicationCount_Updated; + ApplicationLibrary.ApplicationAdded += Application_Added; + ApplicationLibrary.ApplicationCountUpdated += ApplicationCount_Updated; _fileMenu.StateChanged += FileMenu_StateChanged; _actionMenu.StateChanged += ActionMenu_StateChanged; @@ -211,24 +219,24 @@ namespace Ryujinx.Ui ConfigurationState.Instance.Multiplayer.Mode.Event += UpdateMultiplayerMode; ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateMultiplayerLanInterfaceId; - if (ConfigurationState.Instance.Ui.StartFullscreen) + if (ConfigurationState.Instance.UI.StartFullscreen) { _startFullScreen.Active = true; } - _showConsole.Active = ConfigurationState.Instance.Ui.ShowConsole.Value; + _showConsole.Active = ConfigurationState.Instance.UI.ShowConsole.Value; _showConsole.Visible = ConsoleHelper.SetConsoleWindowStateSupported; _actionMenu.Sensitive = false; _pauseEmulation.Sensitive = false; _resumeEmulation.Sensitive = false; - _nspShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value; - _pfs0Shown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value; - _xciShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value; - _ncaShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value; - _nroShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value; - _nsoShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value; + _nspShown.Active = ConfigurationState.Instance.UI.ShownFileTypes.NSP.Value; + _pfs0Shown.Active = ConfigurationState.Instance.UI.ShownFileTypes.PFS0.Value; + _xciShown.Active = ConfigurationState.Instance.UI.ShownFileTypes.XCI.Value; + _ncaShown.Active = ConfigurationState.Instance.UI.ShownFileTypes.NCA.Value; + _nroShown.Active = ConfigurationState.Instance.UI.ShownFileTypes.NRO.Value; + _nsoShown.Active = ConfigurationState.Instance.UI.ShownFileTypes.NSO.Value; _nspShown.Toggled += NSP_Shown_Toggled; _pfs0Shown.Toggled += PFS0_Shown_Toggled; @@ -239,43 +247,43 @@ namespace Ryujinx.Ui _fileTypesSubMenu.Visible = FileAssociationHelper.IsTypeAssociationSupported; - if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FavColumn) { _favToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.IconColumn) + if (ConfigurationState.Instance.UI.GuiColumns.IconColumn) { _iconToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn) + if (ConfigurationState.Instance.UI.GuiColumns.AppColumn) { _appToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn) + if (ConfigurationState.Instance.UI.GuiColumns.DevColumn) { _developerToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.VersionColumn) + if (ConfigurationState.Instance.UI.GuiColumns.VersionColumn) { _versionToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) + if (ConfigurationState.Instance.UI.GuiColumns.TimePlayedColumn) { _timePlayedToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) + if (ConfigurationState.Instance.UI.GuiColumns.LastPlayedColumn) { _lastPlayedToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FileExtColumn) { _fileExtToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FileSizeColumn) { _fileSizeToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn) + if (ConfigurationState.Instance.UI.GuiColumns.PathColumn) { _pathToggle.Active = true; } @@ -308,8 +316,8 @@ namespace Ryujinx.Ui _tableStore.SetSortFunc(6, SortHelper.LastPlayedSort); _tableStore.SetSortFunc(8, SortHelper.FileSizeSort); - int columnId = ConfigurationState.Instance.Ui.ColumnSort.SortColumnId; - bool ascending = ConfigurationState.Instance.Ui.ColumnSort.SortAscending; + int columnId = ConfigurationState.Instance.UI.ColumnSort.SortColumnId; + bool ascending = ConfigurationState.Instance.UI.ColumnSort.SortAscending; _tableStore.SetSortColumnId(columnId, ascending ? SortType.Ascending : SortType.Descending); @@ -317,12 +325,11 @@ namespace Ryujinx.Ui _gameTable.SearchColumn = 2; _gameTable.SearchEqualFunc = (model, col, key, iter) => !((string)model.GetValue(iter, col)).Contains(key, StringComparison.InvariantCultureIgnoreCase); - _hideUi.Label = _hideUi.Label.Replace("SHOWUIKEY", ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi.ToString()); + _hideUI.Label = _hideUI.Label.Replace("SHOWUIKEY", ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI.ToString()); UpdateColumns(); - UpdateGameTable(); - ConfigurationState.Instance.Ui.GameDirs.Event += (sender, args) => + ConfigurationState.Instance.UI.GameDirs.Event += (sender, args) => { if (args.OldValue != args.NewValue) { @@ -402,43 +409,43 @@ namespace Ryujinx.Ui CellRendererToggle favToggle = new(); favToggle.Toggled += FavToggle_Toggled; - if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FavColumn) { _gameTable.AppendColumn("Fav", favToggle, "active", 0); } - if (ConfigurationState.Instance.Ui.GuiColumns.IconColumn) + if (ConfigurationState.Instance.UI.GuiColumns.IconColumn) { _gameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 1); } - if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn) + if (ConfigurationState.Instance.UI.GuiColumns.AppColumn) { _gameTable.AppendColumn("Application", new CellRendererText(), "text", 2); } - if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn) + if (ConfigurationState.Instance.UI.GuiColumns.DevColumn) { _gameTable.AppendColumn("Developer", new CellRendererText(), "text", 3); } - if (ConfigurationState.Instance.Ui.GuiColumns.VersionColumn) + if (ConfigurationState.Instance.UI.GuiColumns.VersionColumn) { _gameTable.AppendColumn("Version", new CellRendererText(), "text", 4); } - if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) + if (ConfigurationState.Instance.UI.GuiColumns.TimePlayedColumn) { _gameTable.AppendColumn("Time Played", new CellRendererText(), "text", 5); } - if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) + if (ConfigurationState.Instance.UI.GuiColumns.LastPlayedColumn) { _gameTable.AppendColumn("Last Played", new CellRendererText(), "text", 6); } - if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FileExtColumn) { _gameTable.AppendColumn("File Ext", new CellRendererText(), "text", 7); } - if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FileSizeColumn) { _gameTable.AppendColumn("File Size", new CellRendererText(), "text", 8); } - if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn) + if (ConfigurationState.Instance.UI.GuiColumns.PathColumn) { _gameTable.AppendColumn("Path", new CellRendererText(), "text", 9); } @@ -640,7 +647,7 @@ namespace Ryujinx.Ui } var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value - ? HLE.MemoryConfiguration.MemoryConfiguration6GiB + ? HLE.MemoryConfiguration.MemoryConfiguration8GiB : HLE.MemoryConfiguration.MemoryConfiguration4GiB; IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None; @@ -680,7 +687,7 @@ namespace Ryujinx.Ui return new SurfaceKHR((ulong)((VulkanRenderer)RendererWidget).CreateWindowSurface(instance.Handle)); } - private void SetupProgressUiHandlers() + private void SetupProgressUIHandlers() { if (_emulationContext.Processes.ActiveApplication.DiskCacheLoadState != null) { @@ -733,7 +740,8 @@ namespace Ryujinx.Ui Thread applicationLibraryThread = new(() => { - _applicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs, ConfigurationState.Instance.System.Language); + ApplicationLibrary.DesiredLanguage = ConfigurationState.Instance.System.Language; + ApplicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs); _updatingGameTable = false; }) @@ -784,7 +792,7 @@ namespace Ryujinx.Ui } } - private bool LoadApplication(string path, bool isFirmwareTitle) + private bool LoadApplication(string path, ulong applicationId, bool isFirmwareTitle) { SystemVersion firmwareVersion = _contentManager.GetCurrentFirmwareVersion(); @@ -858,7 +866,7 @@ namespace Ryujinx.Ui case ".xci": Logger.Info?.Print(LogClass.Application, "Loading as XCI."); - return _emulationContext.LoadXci(path); + return _emulationContext.LoadXci(path, applicationId); case ".nca": Logger.Info?.Print(LogClass.Application, "Loading as NCA."); @@ -867,7 +875,7 @@ namespace Ryujinx.Ui case ".pfs0": Logger.Info?.Print(LogClass.Application, "Loading as NSP."); - return _emulationContext.LoadNsp(path); + return _emulationContext.LoadNsp(path, applicationId); default: Logger.Info?.Print(LogClass.Application, "Loading as Homebrew."); try @@ -888,7 +896,7 @@ namespace Ryujinx.Ui return false; } - public void RunApplication(string path, bool startFullscreen = false) + public void RunApplication(ApplicationData application, bool startFullscreen = false) { if (_gameLoaded) { @@ -910,14 +918,14 @@ namespace Ryujinx.Ui bool isFirmwareTitle = false; - if (path.StartsWith("@SystemContent")) + if (application.Path.StartsWith("@SystemContent")) { - path = VirtualFileSystem.SwitchPathToSystemPath(path); + application.Path = VirtualFileSystem.SwitchPathToSystemPath(application.Path); isFirmwareTitle = true; } - if (!LoadApplication(path, isFirmwareTitle)) + if (!LoadApplication(application.Path, application.Id, isFirmwareTitle)) { _emulationContext.Dispose(); SwitchToGameTable(); @@ -925,14 +933,12 @@ namespace Ryujinx.Ui return; } - SetupProgressUiHandlers(); + SetupProgressUIHandlers(); - _currentEmulatedGamePath = path; + _currentApplicationData = application; _deviceExitStatus.Reset(); - Translator.IsReadyForTranslation.Reset(); - Thread windowThread = new(CreateGameWindow) { Name = "GUI.WindowThread", @@ -984,7 +990,7 @@ namespace Ryujinx.Ui { ToggleExtraWidgets(false); } - else if (startFullscreen || ConfigurationState.Instance.Ui.StartFullscreen.Value) + else if (startFullscreen || ConfigurationState.Instance.UI.StartFullscreen.Value) { FullScreen_Toggled(null, null); } @@ -1168,7 +1174,7 @@ namespace Ryujinx.Ui _tableStore.AppendValues( args.AppData.Favorite, new Gdk.Pixbuf(args.AppData.Icon, 75, 75), - $"{args.AppData.TitleName}\n{args.AppData.TitleId.ToUpper()}", + $"{args.AppData.Name}\n{args.AppData.IdString.ToUpper()}", args.AppData.Developer, args.AppData.Version, args.AppData.TimePlayedString, @@ -1246,8 +1252,8 @@ namespace Ryujinx.Ui { TreeViewColumn column = (TreeViewColumn)sender; - ConfigurationState.Instance.Ui.ColumnSort.SortColumnId.Value = column.SortColumnId; - ConfigurationState.Instance.Ui.ColumnSort.SortAscending.Value = column.SortOrder == SortType.Ascending; + ConfigurationState.Instance.UI.ColumnSort.SortColumnId.Value = column.SortColumnId; + ConfigurationState.Instance.UI.ColumnSort.SortAscending.Value = column.SortOrder == SortType.Ascending; SaveConfig(); } @@ -1256,9 +1262,22 @@ namespace Ryujinx.Ui { _gameTableSelection.GetSelected(out TreeIter treeIter); - string path = (string)_tableStore.GetValue(treeIter, 9); + ApplicationData application = new() + { + Favorite = (bool)_tableStore.GetValue(treeIter, 0), + Name = ((string)_tableStore.GetValue(treeIter, 2)).Split('\n')[0], + Id = ulong.Parse(((string)_tableStore.GetValue(treeIter, 2)).Split('\n')[1], NumberStyles.HexNumber), + Developer = (string)_tableStore.GetValue(treeIter, 3), + Version = (string)_tableStore.GetValue(treeIter, 4), + TimePlayed = ValueFormatUtils.ParseTimeSpan((string)_tableStore.GetValue(treeIter, 5)), + LastPlayed = ValueFormatUtils.ParseDateTime((string)_tableStore.GetValue(treeIter, 6)), + FileExtension = (string)_tableStore.GetValue(treeIter, 7), + FileSize = ValueFormatUtils.ParseFileSize((string)_tableStore.GetValue(treeIter, 8)), + Path = (string)_tableStore.GetValue(treeIter, 9), + ControlHolder = (BlitStruct)_tableStore.GetValue(treeIter, 10), + }; - RunApplication(path); + RunApplication(application); } private void VSyncStatus_Clicked(object sender, ButtonReleaseEventArgs args) @@ -1316,13 +1335,22 @@ namespace Ryujinx.Ui return; } - string titleFilePath = _tableStore.GetValue(treeIter, 9).ToString(); - string titleName = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[0]; - string titleId = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower(); + ApplicationData application = new() + { + Favorite = (bool)_tableStore.GetValue(treeIter, 0), + Name = ((string)_tableStore.GetValue(treeIter, 2)).Split('\n')[0], + Id = ulong.Parse(((string)_tableStore.GetValue(treeIter, 2)).Split('\n')[1], NumberStyles.HexNumber), + Developer = (string)_tableStore.GetValue(treeIter, 3), + Version = (string)_tableStore.GetValue(treeIter, 4), + TimePlayed = ValueFormatUtils.ParseTimeSpan((string)_tableStore.GetValue(treeIter, 5)), + LastPlayed = ValueFormatUtils.ParseDateTime((string)_tableStore.GetValue(treeIter, 6)), + FileExtension = (string)_tableStore.GetValue(treeIter, 7), + FileSize = ValueFormatUtils.ParseFileSize((string)_tableStore.GetValue(treeIter, 8)), + Path = (string)_tableStore.GetValue(treeIter, 9), + ControlHolder = (BlitStruct)_tableStore.GetValue(treeIter, 10), + }; - BlitStruct controlData = (BlitStruct)_tableStore.GetValue(treeIter, 10); - - _ = new GameTableContextMenu(this, _virtualFileSystem, _accountManager, _libHacHorizonManager.RyujinxClient, titleFilePath, titleName, titleId, controlData); + _ = new GameTableContextMenu(this, _virtualFileSystem, _accountManager, _libHacHorizonManager.RyujinxClient, application); } private void Load_Application_File(object sender, EventArgs args) @@ -1344,7 +1372,15 @@ namespace Ryujinx.Ui if (fileChooser.Run() == (int)ResponseType.Accept) { - RunApplication(fileChooser.Filename); + if (ApplicationLibrary.TryGetApplicationsFromFile(fileChooser.Filename, + out List applications)) + { + RunApplication(applications[0]); + } + else + { + GtkDialog.CreateErrorDialog("No applications found in selected file."); + } } } @@ -1354,7 +1390,13 @@ namespace Ryujinx.Ui if (fileChooser.Run() == (int)ResponseType.Accept) { - RunApplication(fileChooser.Filename); + ApplicationData applicationData = new() + { + Name = System.IO.Path.GetFileNameWithoutExtension(fileChooser.Filename), + Path = fileChooser.Filename, + }; + + RunApplication(applicationData); } } @@ -1369,7 +1411,14 @@ namespace Ryujinx.Ui { string contentPath = _contentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program); - RunApplication(contentPath); + ApplicationData applicationData = new() + { + Name = "miiEdit", + Id = 0x0100000000001009ul, + Path = contentPath, + }; + + RunApplication(applicationData); } private void Open_Ryu_Folder(object sender, EventArgs args) @@ -1379,11 +1428,11 @@ namespace Ryujinx.Ui private void OpenLogsFolder_Pressed(object sender, EventArgs args) { - string logPath = System.IO.Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "Logs"); - - new DirectoryInfo(logPath).Create(); - - OpenHelper.OpenFolder(logPath); + string logPath = AppDataManager.GetOrCreateLogsDir(); + if (!string.IsNullOrEmpty(logPath)) + { + OpenHelper.OpenFolder(logPath); + } } private void Exit_Pressed(object sender, EventArgs args) @@ -1410,12 +1459,12 @@ namespace Ryujinx.Ui private void SetWindowSizePosition() { - DefaultWidth = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth; - DefaultHeight = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight; + DefaultWidth = ConfigurationState.Instance.UI.WindowStartup.WindowSizeWidth; + DefaultHeight = ConfigurationState.Instance.UI.WindowStartup.WindowSizeHeight; - Move(ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX, ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY); + Move(ConfigurationState.Instance.UI.WindowStartup.WindowPositionX, ConfigurationState.Instance.UI.WindowStartup.WindowPositionY); - if (ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized) + if (ConfigurationState.Instance.UI.WindowStartup.WindowMaximized) { Maximize(); } @@ -1426,11 +1475,11 @@ namespace Ryujinx.Ui GetSize(out int windowWidth, out int windowHeight); GetPosition(out int windowXPos, out int windowYPos); - ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized.Value = IsMaximized; - ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth.Value = windowWidth; - ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight.Value = windowHeight; - ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX.Value = windowXPos; - ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY.Value = windowYPos; + ConfigurationState.Instance.UI.WindowStartup.WindowMaximized.Value = IsMaximized; + ConfigurationState.Instance.UI.WindowStartup.WindowSizeWidth.Value = windowWidth; + ConfigurationState.Instance.UI.WindowStartup.WindowSizeHeight.Value = windowHeight; + ConfigurationState.Instance.UI.WindowStartup.WindowPositionX.Value = windowXPos; + ConfigurationState.Instance.UI.WindowStartup.WindowPositionY.Value = windowYPos; SaveConfig(); } @@ -1649,13 +1698,13 @@ namespace Ryujinx.Ui { _userChannelPersistence.ShouldRestart = false; - RunApplication(_currentEmulatedGamePath); + RunApplication(_currentApplicationData); } else { // otherwise, clear state. _userChannelPersistence = new UserChannelPersistence(); - _currentEmulatedGamePath = null; + _currentApplicationData = null; _actionMenu.Sensitive = false; _firmwareInstallFile.Sensitive = true; _firmwareInstallDirectory.Sensitive = true; @@ -1680,14 +1729,14 @@ namespace Ryujinx.Ui private void StartFullScreen_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.StartFullscreen.Value = _startFullScreen.Active; + ConfigurationState.Instance.UI.StartFullscreen.Value = _startFullScreen.Active; SaveConfig(); } private void ShowConsole_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShowConsole.Value = _showConsole.Active; + ConfigurationState.Instance.UI.ShowConsole.Value = _showConsole.Active; SaveConfig(); } @@ -1705,7 +1754,7 @@ namespace Ryujinx.Ui settingsWindow.Show(); } - private void HideUi_Pressed(object sender, EventArgs args) + private void HideUI_Pressed(object sender, EventArgs args) { ToggleExtraWidgets(false); } @@ -1717,7 +1766,7 @@ namespace Ryujinx.Ui _emulationContext.Processes.ActiveApplication.ProgramId, _emulationContext.Processes.ActiveApplication.ApplicationControlProperties .Title[(int)_emulationContext.System.State.DesiredTitleLanguage].NameString.ToString(), - _currentEmulatedGamePath); + _currentApplicationData.Path); window.Destroyed += CheatWindow_Destroyed; window.Show(); @@ -1810,7 +1859,7 @@ namespace Ryujinx.Ui private void Fav_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.FavColumn.Value = _favToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.FavColumn.Value = _favToggle.Active; SaveConfig(); UpdateColumns(); @@ -1818,7 +1867,7 @@ namespace Ryujinx.Ui private void Icon_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.IconColumn.Value = _iconToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.IconColumn.Value = _iconToggle.Active; SaveConfig(); UpdateColumns(); @@ -1826,7 +1875,7 @@ namespace Ryujinx.Ui private void App_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.AppColumn.Value = _appToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.AppColumn.Value = _appToggle.Active; SaveConfig(); UpdateColumns(); @@ -1834,7 +1883,7 @@ namespace Ryujinx.Ui private void Developer_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.DevColumn.Value = _developerToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.DevColumn.Value = _developerToggle.Active; SaveConfig(); UpdateColumns(); @@ -1842,7 +1891,7 @@ namespace Ryujinx.Ui private void Version_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.VersionColumn.Value = _versionToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.VersionColumn.Value = _versionToggle.Active; SaveConfig(); UpdateColumns(); @@ -1850,7 +1899,7 @@ namespace Ryujinx.Ui private void TimePlayed_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn.Value = _timePlayedToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.TimePlayedColumn.Value = _timePlayedToggle.Active; SaveConfig(); UpdateColumns(); @@ -1858,7 +1907,7 @@ namespace Ryujinx.Ui private void LastPlayed_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn.Value = _lastPlayedToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.LastPlayedColumn.Value = _lastPlayedToggle.Active; SaveConfig(); UpdateColumns(); @@ -1866,7 +1915,7 @@ namespace Ryujinx.Ui private void FileExt_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn.Value = _fileExtToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.FileExtColumn.Value = _fileExtToggle.Active; SaveConfig(); UpdateColumns(); @@ -1874,7 +1923,7 @@ namespace Ryujinx.Ui private void FileSize_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn.Value = _fileSizeToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.FileSizeColumn.Value = _fileSizeToggle.Active; SaveConfig(); UpdateColumns(); @@ -1882,7 +1931,7 @@ namespace Ryujinx.Ui private void Path_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.PathColumn.Value = _pathToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.PathColumn.Value = _pathToggle.Active; SaveConfig(); UpdateColumns(); @@ -1890,7 +1939,7 @@ namespace Ryujinx.Ui private void NSP_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value = _nspShown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.NSP.Value = _nspShown.Active; SaveConfig(); UpdateGameTable(); @@ -1898,7 +1947,7 @@ namespace Ryujinx.Ui private void PFS0_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value = _pfs0Shown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.PFS0.Value = _pfs0Shown.Active; SaveConfig(); UpdateGameTable(); @@ -1906,7 +1955,7 @@ namespace Ryujinx.Ui private void XCI_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value = _xciShown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.XCI.Value = _xciShown.Active; SaveConfig(); UpdateGameTable(); @@ -1914,7 +1963,7 @@ namespace Ryujinx.Ui private void NCA_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value = _ncaShown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.NCA.Value = _ncaShown.Active; SaveConfig(); UpdateGameTable(); @@ -1922,7 +1971,7 @@ namespace Ryujinx.Ui private void NRO_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value = _nroShown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.NRO.Value = _nroShown.Active; SaveConfig(); UpdateGameTable(); @@ -1930,7 +1979,7 @@ namespace Ryujinx.Ui private void NSO_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value = _nsoShown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.NSO.Value = _nsoShown.Active; SaveConfig(); UpdateGameTable(); diff --git a/src/Ryujinx/Ui/MainWindow.glade b/src/Ryujinx.Gtk3/UI/MainWindow.glade similarity index 99% rename from src/Ryujinx/Ui/MainWindow.glade rename to src/Ryujinx.Gtk3/UI/MainWindow.glade index 58d5d9558..d1b6872a9 100644 --- a/src/Ryujinx/Ui/MainWindow.glade +++ b/src/Ryujinx.Gtk3/UI/MainWindow.glade @@ -437,12 +437,12 @@ - + True False Hide UI (SHOWUIKEY to show) True - + diff --git a/src/Ryujinx/Ui/OpenGLRenderer.cs b/src/Ryujinx.Gtk3/UI/OpenGLRenderer.cs similarity index 96% rename from src/Ryujinx/Ui/OpenGLRenderer.cs rename to src/Ryujinx.Gtk3/UI/OpenGLRenderer.cs index d10445b00..1fdabc754 100644 --- a/src/Ryujinx/Ui/OpenGLRenderer.cs +++ b/src/Ryujinx.Gtk3/UI/OpenGLRenderer.cs @@ -12,7 +12,7 @@ using SPB.Windowing; using System; using System.Runtime.InteropServices; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public partial class OpenGLRenderer : RendererWidgetBase { @@ -120,7 +120,7 @@ namespace Ryujinx.Ui } catch (ContextException e) { - Logger.Warning?.Print(LogClass.Ui, $"Failed to bind OpenGL context: {e}"); + Logger.Warning?.Print(LogClass.UI, $"Failed to bind OpenGL context: {e}"); } Device?.DisposeGpu(); @@ -133,7 +133,7 @@ namespace Ryujinx.Ui } catch (ContextException e) { - Logger.Warning?.Print(LogClass.Ui, $"Failed to unbind OpenGL context: {e}"); + Logger.Warning?.Print(LogClass.UI, $"Failed to unbind OpenGL context: {e}"); } _openGLContext?.Dispose(); diff --git a/src/Ryujinx/Ui/OpenToolkitBindingsContext.cs b/src/Ryujinx.Gtk3/UI/OpenToolkitBindingsContext.cs similarity index 95% rename from src/Ryujinx/Ui/OpenToolkitBindingsContext.cs rename to src/Ryujinx.Gtk3/UI/OpenToolkitBindingsContext.cs index 49dd5da8e..1224ccfe0 100644 --- a/src/Ryujinx/Ui/OpenToolkitBindingsContext.cs +++ b/src/Ryujinx.Gtk3/UI/OpenToolkitBindingsContext.cs @@ -1,7 +1,7 @@ using SPB.Graphics; using System; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public class OpenToolkitBindingsContext : OpenTK.IBindingsContext { diff --git a/src/Ryujinx/Ui/RendererWidgetBase.cs b/src/Ryujinx.Gtk3/UI/RendererWidgetBase.cs similarity index 92% rename from src/Ryujinx/Ui/RendererWidgetBase.cs rename to src/Ryujinx.Gtk3/UI/RendererWidgetBase.cs index 6ae122a0a..12139e87d 100644 --- a/src/Ryujinx/Ui/RendererWidgetBase.cs +++ b/src/Ryujinx.Gtk3/UI/RendererWidgetBase.cs @@ -1,33 +1,30 @@ -using ARMeilleure.Translation; using Gdk; using Gtk; using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.Gpu; using Ryujinx.Input; using Ryujinx.Input.GTK3; using Ryujinx.Input.HLE; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Widgets; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Widgets; +using SkiaSharp; using System; using System.Diagnostics; using System.IO; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using Image = SixLabors.ImageSharp.Image; using Key = Ryujinx.Input.Key; using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter; using Switch = Ryujinx.HLE.Switch; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public abstract class RendererWidgetBase : DrawingArea { @@ -78,7 +75,7 @@ namespace Ryujinx.Ui private readonly IKeyboard _keyboardInterface; private readonly GraphicsDebugLevel _glLogLevel; private string _gpuBackendName; - private string _gpuVendorName; + private string _gpuDriverName; private bool _isMouseInClient; public RendererWidgetBase(InputManager inputManager, GraphicsDebugLevel glLogLevel) @@ -142,9 +139,9 @@ namespace Ryujinx.Ui protected abstract string GetGpuBackendName(); - private string GetGpuVendorName() + private string GetGpuDriverName() { - return Renderer.GetHardwareInfo().GpuVendor; + return Renderer.GetHardwareInfo().GpuDriver; } private void HideCursorStateChanged(object sender, ReactiveEventArgs state) @@ -379,8 +376,12 @@ namespace Ryujinx.Ui { lock (this) { - var currentTime = DateTime.Now; - string filename = $"ryujinx_capture_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png"; + string applicationName = Device.Processes.ActiveApplication.Name; + string sanitizedApplicationName = FileSystemUtils.SanitizeFileName(applicationName); + DateTime currentTime = DateTime.Now; + + string filename = $"{sanitizedApplicationName}_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png"; + string directory = AppDataManager.Mode switch { AppDataManager.LaunchMode.Portable or AppDataManager.LaunchMode.Custom => System.IO.Path.Combine(AppDataManager.BaseDirPath, "screenshots"), @@ -400,23 +401,31 @@ namespace Ryujinx.Ui return; } - Image image = e.IsBgra ? Image.LoadPixelData(e.Data, e.Width, e.Height) - : Image.LoadPixelData(e.Data, e.Width, e.Height); + var colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888; + using var image = new SKBitmap(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul)); - if (e.FlipX) + Marshal.Copy(e.Data, 0, image.GetPixels(), e.Data.Length); + using var surface = SKSurface.Create(image.Info); + var canvas = surface.Canvas; + + if (e.FlipX || e.FlipY) { - image.Mutate(x => x.Flip(FlipMode.Horizontal)); + canvas.Clear(SKColors.Transparent); + + float scaleX = e.FlipX ? -1 : 1; + float scaleY = e.FlipY ? -1 : 1; + + var matrix = SKMatrix.CreateScale(scaleX, scaleY, image.Width / 2f, image.Height / 2f); + + canvas.SetMatrix(matrix); } + canvas.DrawBitmap(image, new SKPoint()); - if (e.FlipY) - { - image.Mutate(x => x.Flip(FlipMode.Vertical)); - } - - image.SaveAsPng(path, new PngEncoder() - { - ColorType = PngColorType.Rgb, - }); + surface.Flush(); + using var snapshot = surface.Snapshot(); + using var encoded = snapshot.Encode(SKEncodedImageFormat.Png, 80); + using var file = File.OpenWrite(path); + encoded.SaveTo(file); image.Dispose(); @@ -444,13 +453,12 @@ namespace Ryujinx.Ui Renderer.Window.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value); _gpuBackendName = GetGpuBackendName(); - _gpuVendorName = GetGpuVendorName(); + _gpuDriverName = GetGpuDriverName(); Device.Gpu.Renderer.RunLoop(() => { Device.Gpu.SetGpuThread(); Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token); - Translator.IsReadyForTranslation.Set(); Renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync); @@ -496,7 +504,7 @@ namespace Ryujinx.Ui ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), $"Game: {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", $"FIFO: {Device.Statistics.GetFifoPercent():0.00} %", - $"GPU: {_gpuVendorName}")); + $"GPU: {_gpuDriverName}")); _ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame); } @@ -661,8 +669,8 @@ namespace Ryujinx.Ui Renderer.Screenshot(); } - if (currentHotkeyState.HasFlag(KeyboardHotkeyState.ShowUi) && - !_prevHotkeyState.HasFlag(KeyboardHotkeyState.ShowUi)) + if (currentHotkeyState.HasFlag(KeyboardHotkeyState.ShowUI) && + !_prevHotkeyState.HasFlag(KeyboardHotkeyState.ShowUI)) { (Toplevel as MainWindow).ToggleExtraWidgets(true); } @@ -741,7 +749,7 @@ namespace Ryujinx.Ui None = 0, ToggleVSync = 1 << 0, Screenshot = 1 << 1, - ShowUi = 1 << 2, + ShowUI = 1 << 2, Pause = 1 << 3, ToggleMute = 1 << 4, ResScaleUp = 1 << 5, @@ -764,9 +772,9 @@ namespace Ryujinx.Ui state |= KeyboardHotkeyState.Screenshot; } - if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi)) + if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI)) { - state |= KeyboardHotkeyState.ShowUi; + state |= KeyboardHotkeyState.ShowUI; } if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause)) diff --git a/src/Ryujinx/Ui/SPBOpenGLContext.cs b/src/Ryujinx.Gtk3/UI/SPBOpenGLContext.cs similarity index 94% rename from src/Ryujinx/Ui/SPBOpenGLContext.cs rename to src/Ryujinx.Gtk3/UI/SPBOpenGLContext.cs index 6f2db697a..97feb4345 100644 --- a/src/Ryujinx/Ui/SPBOpenGLContext.cs +++ b/src/Ryujinx.Gtk3/UI/SPBOpenGLContext.cs @@ -5,7 +5,7 @@ using SPB.Graphics.OpenGL; using SPB.Platform; using SPB.Windowing; -namespace Ryujinx.Ui +namespace Ryujinx.UI { class SPBOpenGLContext : IOpenGLContext { @@ -29,6 +29,8 @@ namespace Ryujinx.Ui _context.MakeCurrent(_window); } + public bool HasContext() => _context.IsCurrent; + public static SPBOpenGLContext CreateBackgroundContext(OpenGLContextBase sharedContext) { OpenGLContextBase context = PlatformHelper.CreateOpenGLContext(FramebufferFormat.Default, 3, 3, OpenGLContextFlags.Compat, true, sharedContext); diff --git a/src/Ryujinx/Ui/StatusUpdatedEventArgs.cs b/src/Ryujinx.Gtk3/UI/StatusUpdatedEventArgs.cs similarity index 97% rename from src/Ryujinx/Ui/StatusUpdatedEventArgs.cs rename to src/Ryujinx.Gtk3/UI/StatusUpdatedEventArgs.cs index 72e7d7f5b..db467ebfc 100644 --- a/src/Ryujinx/Ui/StatusUpdatedEventArgs.cs +++ b/src/Ryujinx.Gtk3/UI/StatusUpdatedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public class StatusUpdatedEventArgs : EventArgs { diff --git a/src/Ryujinx/Ui/VulkanRenderer.cs b/src/Ryujinx.Gtk3/UI/VulkanRenderer.cs similarity index 98% rename from src/Ryujinx/Ui/VulkanRenderer.cs rename to src/Ryujinx.Gtk3/UI/VulkanRenderer.cs index e1aae0965..eefc56999 100644 --- a/src/Ryujinx/Ui/VulkanRenderer.cs +++ b/src/Ryujinx.Gtk3/UI/VulkanRenderer.cs @@ -1,7 +1,7 @@ using Gdk; using Ryujinx.Common.Configuration; using Ryujinx.Input.HLE; -using Ryujinx.Ui.Helper; +using Ryujinx.UI.Helper; using SPB.Graphics.Vulkan; using SPB.Platform.Metal; using SPB.Platform.Win32; @@ -10,7 +10,7 @@ using SPB.Windowing; using System; using System.Runtime.InteropServices; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public partial class VulkanRenderer : RendererWidgetBase { diff --git a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.Designer.cs b/src/Ryujinx.Gtk3/UI/Widgets/GameTableContextMenu.Designer.cs similarity index 96% rename from src/Ryujinx/Ui/Widgets/GameTableContextMenu.Designer.cs rename to src/Ryujinx.Gtk3/UI/Widgets/GameTableContextMenu.Designer.cs index 734437eea..8ee1cd2f3 100644 --- a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.Designer.cs +++ b/src/Ryujinx.Gtk3/UI/Widgets/GameTableContextMenu.Designer.cs @@ -1,6 +1,7 @@ using Gtk; +using System; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { public partial class GameTableContextMenu : Menu { @@ -193,7 +194,7 @@ namespace Ryujinx.Ui.Widgets // _createShortcutMenuItem = new MenuItem("Create Application Shortcut") { - TooltipText = "Create a Desktop Shortcut that launches the selected Application." + TooltipText = OperatingSystem.IsMacOS() ? "Create a shortcut in macOS's Applications folder that launches the selected Application" : "Create a Desktop Shortcut that launches the selected Application." }; _createShortcutMenuItem.Activated += CreateShortcut_Clicked; diff --git a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs b/src/Ryujinx.Gtk3/UI/Widgets/GameTableContextMenu.cs similarity index 83% rename from src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs rename to src/Ryujinx.Gtk3/UI/Widgets/GameTableContextMenu.cs index eb048b00d..a3e3d4c8c 100644 --- a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs +++ b/src/Ryujinx.Gtk3/UI/Widgets/GameTableContextMenu.cs @@ -16,19 +16,20 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Windows; +using Ryujinx.HLE.Loaders.Processes.Extensions; +using Ryujinx.HLE.Utilities; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Windows; using System; using System.Buffers; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Reflection; using System.Threading; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { public partial class GameTableContextMenu : Menu { @@ -36,17 +37,13 @@ namespace Ryujinx.Ui.Widgets private readonly VirtualFileSystem _virtualFileSystem; private readonly AccountManager _accountManager; private readonly HorizonClient _horizonClient; - private readonly BlitStruct _controlData; - private readonly string _titleFilePath; - private readonly string _titleName; - private readonly string _titleIdText; - private readonly ulong _titleId; + private readonly ApplicationData _applicationData; private MessageDialog _dialog; private bool _cancel; - public GameTableContextMenu(MainWindow parent, VirtualFileSystem virtualFileSystem, AccountManager accountManager, HorizonClient horizonClient, string titleFilePath, string titleName, string titleId, BlitStruct controlData) + public GameTableContextMenu(MainWindow parent, VirtualFileSystem virtualFileSystem, AccountManager accountManager, HorizonClient horizonClient, ApplicationData applicationData) { _parent = parent; @@ -55,30 +52,29 @@ namespace Ryujinx.Ui.Widgets _virtualFileSystem = virtualFileSystem; _accountManager = accountManager; _horizonClient = horizonClient; - _titleFilePath = titleFilePath; - _titleName = titleName; - _titleIdText = titleId; - _controlData = controlData; + _applicationData = applicationData; - if (!ulong.TryParse(_titleIdText, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out _titleId)) + if (!_applicationData.ControlHolder.ByteSpan.IsZeros()) { - GtkDialog.CreateErrorDialog("The selected game did not have a valid Title Id"); - - return; + _openSaveUserDirMenuItem.Sensitive = _applicationData.ControlHolder.Value.UserAccountSaveDataSize > 0; + _openSaveDeviceDirMenuItem.Sensitive = _applicationData.ControlHolder.Value.DeviceSaveDataSize > 0; + _openSaveBcatDirMenuItem.Sensitive = _applicationData.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0; + } + else + { + _openSaveUserDirMenuItem.Sensitive = false; + _openSaveDeviceDirMenuItem.Sensitive = false; + _openSaveBcatDirMenuItem.Sensitive = false; } - _openSaveUserDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.UserAccountSaveDataSize > 0; - _openSaveDeviceDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.DeviceSaveDataSize > 0; - _openSaveBcatDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.BcatDeliveryCacheStorageSize > 0; - - string fileExt = System.IO.Path.GetExtension(_titleFilePath).ToLower(); + string fileExt = System.IO.Path.GetExtension(_applicationData.Path).ToLower(); bool hasNca = fileExt == ".nca" || fileExt == ".nsp" || fileExt == ".pfs0" || fileExt == ".xci"; _extractRomFsMenuItem.Sensitive = hasNca; _extractExeFsMenuItem.Sensitive = hasNca; _extractLogoMenuItem.Sensitive = hasNca; - _createShortcutMenuItem.Sensitive = !ReleaseInformation.IsFlatHubBuild(); + _createShortcutMenuItem.Sensitive = !ReleaseInformation.IsFlatHubBuild; PopupAtPointer(null); } @@ -137,7 +133,7 @@ namespace Ryujinx.Ui.Widgets private void OpenSaveDir(in SaveDataFilter saveDataFilter) { - if (!TryFindSaveData(_titleName, _titleId, _controlData, in saveDataFilter, out ulong saveDataId)) + if (!TryFindSaveData(_applicationData.Name, _applicationData.Id, _applicationData.ControlHolder, in saveDataFilter, out ulong saveDataId)) { return; } @@ -189,8 +185,8 @@ namespace Ryujinx.Ui.Widgets _dialog = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Cancel, null) { Title = "Ryujinx - NCA Section Extractor", - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"), - SecondaryText = $"Extracting {ncaSectionType} section from {System.IO.Path.GetFileName(_titleFilePath)}...", + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Gtk3.UI.Common.Resources.Logo_Ryujinx.png"), + SecondaryText = $"Extracting {ncaSectionType} section from {System.IO.Path.GetFileName(_applicationData.Path)}...", WindowPosition = WindowPosition.Center, }; @@ -202,29 +198,16 @@ namespace Ryujinx.Ui.Widgets } }); - using FileStream file = new(_titleFilePath, FileMode.Open, FileAccess.Read); + using FileStream file = new(_applicationData.Path, FileMode.Open, FileAccess.Read); Nca mainNca = null; Nca patchNca = null; - if ((System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".nsp") || - (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".pfs0") || - (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".xci")) + if ((System.IO.Path.GetExtension(_applicationData.Path).ToLower() == ".nsp") || + (System.IO.Path.GetExtension(_applicationData.Path).ToLower() == ".pfs0") || + (System.IO.Path.GetExtension(_applicationData.Path).ToLower() == ".xci")) { - IFileSystem pfs; - - if (System.IO.Path.GetExtension(_titleFilePath) == ".xci") - { - Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage()); - - pfs = xci.OpenPartition(XciPartitionType.Secure); - } - else - { - var pfsTemp = new PartitionFileSystem(); - pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); - pfs = pfsTemp; - } + IFileSystem pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(_applicationData.Path, _virtualFileSystem); foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) { @@ -249,7 +232,7 @@ namespace Ryujinx.Ui.Widgets } } } - else if (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".nca") + else if (System.IO.Path.GetExtension(_applicationData.Path).ToLower() == ".nca") { mainNca = new Nca(_virtualFileSystem.KeySet, file.AsStorage()); } @@ -266,7 +249,11 @@ namespace Ryujinx.Ui.Widgets return; } - (Nca updatePatchNca, _) = ApplicationLibrary.GetGameUpdateData(_virtualFileSystem, mainNca.Header.TitleId.ToString("x16"), programIndex, out _); + IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks + ? IntegrityCheckLevel.ErrorOnInvalid + : IntegrityCheckLevel.None; + + (Nca updatePatchNca, _) = mainNca.GetUpdateData(_virtualFileSystem, checkLevel, programIndex, out _); if (updatePatchNca != null) { @@ -320,7 +307,7 @@ namespace Ryujinx.Ui.Widgets MessageDialog dialog = new(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null) { Title = "Ryujinx - NCA Section Extractor", - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"), + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"), SecondaryText = "Extraction completed successfully.", WindowPosition = WindowPosition.Center, }; @@ -460,44 +447,44 @@ namespace Ryujinx.Ui.Widgets private void OpenSaveUserDir_Clicked(object sender, EventArgs args) { var userId = new LibHac.Fs.UserId((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low); - var saveDataFilter = SaveDataFilter.Make(_titleId, saveType: default, userId, saveDataId: default, index: default); + var saveDataFilter = SaveDataFilter.Make(_applicationData.Id, saveType: default, userId, saveDataId: default, index: default); OpenSaveDir(in saveDataFilter); } private void OpenSaveDeviceDir_Clicked(object sender, EventArgs args) { - var saveDataFilter = SaveDataFilter.Make(_titleId, SaveDataType.Device, userId: default, saveDataId: default, index: default); + var saveDataFilter = SaveDataFilter.Make(_applicationData.Id, SaveDataType.Device, userId: default, saveDataId: default, index: default); OpenSaveDir(in saveDataFilter); } private void OpenSaveBcatDir_Clicked(object sender, EventArgs args) { - var saveDataFilter = SaveDataFilter.Make(_titleId, SaveDataType.Bcat, userId: default, saveDataId: default, index: default); + var saveDataFilter = SaveDataFilter.Make(_applicationData.Id, SaveDataType.Bcat, userId: default, saveDataId: default, index: default); OpenSaveDir(in saveDataFilter); } private void ManageTitleUpdates_Clicked(object sender, EventArgs args) { - new TitleUpdateWindow(_parent, _virtualFileSystem, _titleIdText, _titleName).Show(); + new TitleUpdateWindow(_parent, _virtualFileSystem, _applicationData).Show(); } private void ManageDlc_Clicked(object sender, EventArgs args) { - new DlcWindow(_virtualFileSystem, _titleIdText, _titleName).Show(); + new DlcWindow(_virtualFileSystem, _applicationData.IdBaseString, _applicationData).Show(); } private void ManageCheats_Clicked(object sender, EventArgs args) { - new CheatWindow(_virtualFileSystem, _titleId, _titleName, _titleFilePath).Show(); + new CheatWindow(_virtualFileSystem, _applicationData.Id, _applicationData.Name, _applicationData.Path).Show(); } private void OpenTitleModDir_Clicked(object sender, EventArgs args) { string modsBasePath = ModLoader.GetModsBasePath(); - string titleModsPath = ModLoader.GetTitleDir(modsBasePath, _titleIdText); + string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, _applicationData.IdString); OpenHelper.OpenFolder(titleModsPath); } @@ -505,7 +492,7 @@ namespace Ryujinx.Ui.Widgets private void OpenTitleSdModDir_Clicked(object sender, EventArgs args) { string sdModsBasePath = ModLoader.GetSdModsBasePath(); - string titleModsPath = ModLoader.GetTitleDir(sdModsBasePath, _titleIdText); + string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, _applicationData.IdString); OpenHelper.OpenFolder(titleModsPath); } @@ -527,7 +514,7 @@ namespace Ryujinx.Ui.Widgets private void OpenPtcDir_Clicked(object sender, EventArgs args) { - string ptcDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu"); + string ptcDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _applicationData.IdString, "cache", "cpu"); string mainPath = System.IO.Path.Combine(ptcDir, "0"); string backupPath = System.IO.Path.Combine(ptcDir, "1"); @@ -544,7 +531,7 @@ namespace Ryujinx.Ui.Widgets private void OpenShaderCacheDir_Clicked(object sender, EventArgs args) { - string shaderCacheDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "shader"); + string shaderCacheDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _applicationData.IdString, "cache", "shader"); if (!Directory.Exists(shaderCacheDir)) { @@ -556,10 +543,10 @@ namespace Ryujinx.Ui.Widgets private void PurgePtcCache_Clicked(object sender, EventArgs args) { - DirectoryInfo mainDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "0")); - DirectoryInfo backupDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "1")); + DirectoryInfo mainDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _applicationData.IdString, "cache", "cpu", "0")); + DirectoryInfo backupDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _applicationData.IdString, "cache", "cpu", "1")); - MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to queue a PPTC rebuild on the next boot of:\n\n{_titleName}\n\nAre you sure you want to proceed?"); + MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to queue a PPTC rebuild on the next boot of:\n\n{_applicationData.Name}\n\nAre you sure you want to proceed?"); List cacheFiles = new(); @@ -593,9 +580,9 @@ namespace Ryujinx.Ui.Widgets private void PurgeShaderCache_Clicked(object sender, EventArgs args) { - DirectoryInfo shaderCacheDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "shader")); + DirectoryInfo shaderCacheDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _applicationData.IdString, "cache", "shader")); - using MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to delete the shader cache for :\n\n{_titleName}\n\nAre you sure you want to proceed?"); + using MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to delete the shader cache for :\n\n{_applicationData.Name}\n\nAre you sure you want to proceed?"); List oldCacheDirectories = new(); List newCacheFiles = new(); @@ -637,8 +624,11 @@ namespace Ryujinx.Ui.Widgets private void CreateShortcut_Clicked(object sender, EventArgs args) { - byte[] appIcon = new ApplicationLibrary(_virtualFileSystem).GetApplicationIcon(_titleFilePath, ConfigurationState.Instance.System.Language); - ShortcutHelper.CreateAppShortcut(_titleFilePath, _titleName, _titleIdText, appIcon); + IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks + ? IntegrityCheckLevel.ErrorOnInvalid + : IntegrityCheckLevel.None; + byte[] appIcon = new ApplicationLibrary(_virtualFileSystem, checkLevel).GetApplicationIcon(_applicationData.Path, ConfigurationState.Instance.System.Language, _applicationData.Id); + ShortcutHelper.CreateAppShortcut(_applicationData.Path, _applicationData.Name, _applicationData.IdString, appIcon); } } } diff --git a/src/Ryujinx/Ui/Widgets/GtkDialog.cs b/src/Ryujinx.Gtk3/UI/Widgets/GtkDialog.cs similarity index 96% rename from src/Ryujinx/Ui/Widgets/GtkDialog.cs rename to src/Ryujinx.Gtk3/UI/Widgets/GtkDialog.cs index 51e777fa1..567f9ad67 100644 --- a/src/Ryujinx/Ui/Widgets/GtkDialog.cs +++ b/src/Ryujinx.Gtk3/UI/Widgets/GtkDialog.cs @@ -1,10 +1,10 @@ using Gtk; using Ryujinx.Common.Logging; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System.Collections.Generic; using System.Reflection; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { internal class GtkDialog : MessageDialog { @@ -14,7 +14,7 @@ namespace Ryujinx.Ui.Widgets : base(null, DialogFlags.Modal, messageType, buttonsType, null) { Title = title; - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); Text = mainText; SecondaryText = secondaryText; WindowPosition = WindowPosition.Center; diff --git a/src/Ryujinx/Ui/Widgets/GtkInputDialog.cs b/src/Ryujinx.Gtk3/UI/Widgets/GtkInputDialog.cs similarity index 97% rename from src/Ryujinx/Ui/Widgets/GtkInputDialog.cs rename to src/Ryujinx.Gtk3/UI/Widgets/GtkInputDialog.cs index 622980921..fd85248b7 100644 --- a/src/Ryujinx/Ui/Widgets/GtkInputDialog.cs +++ b/src/Ryujinx.Gtk3/UI/Widgets/GtkInputDialog.cs @@ -1,6 +1,6 @@ using Gtk; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { public class GtkInputDialog : MessageDialog { diff --git a/src/Ryujinx/Ui/Widgets/ProfileDialog.cs b/src/Ryujinx.Gtk3/UI/Widgets/ProfileDialog.cs similarity index 87% rename from src/Ryujinx/Ui/Widgets/ProfileDialog.cs rename to src/Ryujinx.Gtk3/UI/Widgets/ProfileDialog.cs index 0731b37a1..3b3e2fbbe 100644 --- a/src/Ryujinx/Ui/Widgets/ProfileDialog.cs +++ b/src/Ryujinx.Gtk3/UI/Widgets/ProfileDialog.cs @@ -1,10 +1,10 @@ using Gtk; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System; using System.Reflection; using GUI = Gtk.Builder.ObjectAttribute; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { public class ProfileDialog : Dialog { @@ -15,12 +15,12 @@ namespace Ryujinx.Ui.Widgets [GUI] Label _errorMessage; #pragma warning restore CS0649, IDE0044 - public ProfileDialog() : this(new Builder("Ryujinx.Ui.Widgets.ProfileDialog.glade")) { } + public ProfileDialog() : this(new Builder("Ryujinx.Gtk3.UI.Widgets.ProfileDialog.glade")) { } private ProfileDialog(Builder builder) : base(builder.GetRawOwnedObject("_profileDialog")) { builder.Autoconnect(this); - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); } private void OkToggle_Activated(object sender, EventArgs args) diff --git a/src/Ryujinx/Ui/Widgets/ProfileDialog.glade b/src/Ryujinx.Gtk3/UI/Widgets/ProfileDialog.glade similarity index 100% rename from src/Ryujinx/Ui/Widgets/ProfileDialog.glade rename to src/Ryujinx.Gtk3/UI/Widgets/ProfileDialog.glade diff --git a/src/Ryujinx/Ui/Widgets/RawInputToTextEntry.cs b/src/Ryujinx.Gtk3/UI/Widgets/RawInputToTextEntry.cs similarity index 95% rename from src/Ryujinx/Ui/Widgets/RawInputToTextEntry.cs rename to src/Ryujinx.Gtk3/UI/Widgets/RawInputToTextEntry.cs index e82a3d492..6470790e8 100644 --- a/src/Ryujinx/Ui/Widgets/RawInputToTextEntry.cs +++ b/src/Ryujinx.Gtk3/UI/Widgets/RawInputToTextEntry.cs @@ -1,6 +1,6 @@ using Gtk; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { public class RawInputToTextEntry : Entry { diff --git a/src/Ryujinx/Ui/Widgets/UserErrorDialog.cs b/src/Ryujinx.Gtk3/UI/Widgets/UserErrorDialog.cs similarity index 97% rename from src/Ryujinx/Ui/Widgets/UserErrorDialog.cs rename to src/Ryujinx.Gtk3/UI/Widgets/UserErrorDialog.cs index 63a280e6d..f0b55cd8b 100644 --- a/src/Ryujinx/Ui/Widgets/UserErrorDialog.cs +++ b/src/Ryujinx.Gtk3/UI/Widgets/UserErrorDialog.cs @@ -1,8 +1,8 @@ using Gtk; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Helper; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { internal class UserErrorDialog : MessageDialog { diff --git a/src/Ryujinx/Ui/Windows/AboutWindow.Designer.cs b/src/Ryujinx.Gtk3/UI/Windows/AboutWindow.Designer.cs similarity index 97% rename from src/Ryujinx/Ui/Windows/AboutWindow.Designer.cs rename to src/Ryujinx.Gtk3/UI/Windows/AboutWindow.Designer.cs index 345026334..fd912ef9a 100644 --- a/src/Ryujinx/Ui/Windows/AboutWindow.Designer.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/AboutWindow.Designer.cs @@ -1,9 +1,9 @@ using Gtk; using Pango; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System.Reflection; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class AboutWindow : Window { @@ -88,7 +88,7 @@ namespace Ryujinx.Ui.Windows // // _ryujinxLogo // - _ryujinxLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png", 100, 100)) + _ryujinxLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png", 100, 100)) { Margin = 10, MarginStart = 15, @@ -223,7 +223,7 @@ namespace Ryujinx.Ui.Windows // // _patreonLogo // - _patreonLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Patreon_Light.png", 30, 30)) + _patreonLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Patreon_Light.png", 30, 30)) { Margin = 10, }; @@ -253,7 +253,7 @@ namespace Ryujinx.Ui.Windows // // _githubLogo // - _githubLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_GitHub_Light.png", 30, 30)) + _githubLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_GitHub_Light.png", 30, 30)) { Margin = 10, }; @@ -283,7 +283,7 @@ namespace Ryujinx.Ui.Windows // // _discordLogo // - _discordLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Discord_Light.png", 30, 30)) + _discordLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Discord_Light.png", 30, 30)) { Margin = 10, }; @@ -313,7 +313,7 @@ namespace Ryujinx.Ui.Windows // // _twitterLogo // - _twitterLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Twitter_Light.png", 30, 30)) + _twitterLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Twitter_Light.png", 30, 30)) { Margin = 10, }; diff --git a/src/Ryujinx/Ui/Windows/AboutWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/AboutWindow.cs similarity index 95% rename from src/Ryujinx/Ui/Windows/AboutWindow.cs rename to src/Ryujinx.Gtk3/UI/Windows/AboutWindow.cs index ba12bb68b..f4bb533c3 100644 --- a/src/Ryujinx/Ui/Windows/AboutWindow.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/AboutWindow.cs @@ -1,18 +1,18 @@ using Gtk; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System.Net.Http; using System.Net.NetworkInformation; using System.Reflection; using System.Threading.Tasks; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class AboutWindow : Window { public AboutWindow() : base($"Ryujinx {Program.Version} - About") { - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(OpenHelper)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(OpenHelper)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); InitializeComponent(); _ = DownloadPatronsJson(); diff --git a/src/Ryujinx/Ui/Windows/AmiiboWindow.Designer.cs b/src/Ryujinx.Gtk3/UI/Windows/AmiiboWindow.Designer.cs similarity index 99% rename from src/Ryujinx/Ui/Windows/AmiiboWindow.Designer.cs rename to src/Ryujinx.Gtk3/UI/Windows/AmiiboWindow.Designer.cs index cb27c34cb..3bf73318f 100644 --- a/src/Ryujinx/Ui/Windows/AmiiboWindow.Designer.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/AmiiboWindow.Designer.cs @@ -1,6 +1,6 @@ using Gtk; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class AmiiboWindow : Window { diff --git a/src/Ryujinx/Ui/Windows/AmiiboWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/AmiiboWindow.cs similarity index 74% rename from src/Ryujinx/Ui/Windows/AmiiboWindow.cs rename to src/Ryujinx.Gtk3/UI/Windows/AmiiboWindow.cs index 2673f9121..d8c0b0c0d 100644 --- a/src/Ryujinx/Ui/Windows/AmiiboWindow.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/AmiiboWindow.cs @@ -1,11 +1,12 @@ +using Gdk; using Gtk; using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Models.Amiibo; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Models.Amiibo; +using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; using System.IO; @@ -13,9 +14,11 @@ using System.Linq; using System.Net.Http; using System.Reflection; using System.Text; +using System.Text.Json; using System.Threading.Tasks; +using Window = Gtk.Window; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class AmiiboWindow : Window { @@ -49,11 +52,11 @@ namespace Ryujinx.Ui.Windows public AmiiboWindow() : base($"Ryujinx {Program.Version} - Amiibo") { - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); InitializeComponent(); - _httpClient = new HttpClient() + _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(30), }; @@ -63,8 +66,8 @@ namespace Ryujinx.Ui.Windows _amiiboJsonPath = System.IO.Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", "Amiibo.json"); _amiiboList = new List(); - _amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png"); - _amiiboImage.Pixbuf = new Gdk.Pixbuf(_amiiboLogoBytes); + _amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.UI.Common/Resources/Logo_Amiibo.png"); + _amiiboImage.Pixbuf = new Pixbuf(_amiiboLogoBytes); _scanButton.Sensitive = false; _randomUuidCheckBox.Sensitive = false; @@ -72,17 +75,25 @@ namespace Ryujinx.Ui.Windows _ = LoadContentAsync(); } - private bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson) + private static bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson) { + if (string.IsNullOrEmpty(json)) + { + amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson); + + return false; + } + try { - amiiboJson = JsonHelper.Deserialize(json, _serializerContext.AmiiboJson); + amiiboJson = JsonHelper.Deserialize(json, _serializerContext.AmiiboJson); return true; } - catch + catch (JsonException exception) { - amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson); + Logger.Error?.Print(LogClass.Application, $"Unable to deserialize amiibo data: {exception}"); + amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson); return false; } @@ -92,27 +103,41 @@ namespace Ryujinx.Ui.Windows { bool localIsValid = false; bool remoteIsValid = false; - AmiiboJson amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson); + AmiiboJson amiiboJson = new(); try { - localIsValid = TryGetAmiiboJson(File.ReadAllText(_amiiboJsonPath), out amiiboJson); + try + { + if (File.Exists(_amiiboJsonPath)) + { + localIsValid = TryGetAmiiboJson(await File.ReadAllTextAsync(_amiiboJsonPath), out amiiboJson); + } + } + catch (Exception exception) + { + Logger.Warning?.Print(LogClass.Application, $"Unable to read data from '{_amiiboJsonPath}': {exception}"); + } if (!localIsValid || await NeedsUpdate(amiiboJson.LastUpdated)) { remoteIsValid = TryGetAmiiboJson(await DownloadAmiiboJson(), out amiiboJson); } } - catch + catch (Exception exception) { if (!(localIsValid || remoteIsValid)) { + Logger.Error?.Print(LogClass.Application, $"Couldn't get valid amiibo data: {exception}"); + // Neither local or remote files are valid JSON, close window. ShowInfoDialog(); Close(); } else if (!remoteIsValid) { + Logger.Warning?.Print(LogClass.Application, $"Couldn't update amiibo data: {exception}"); + // Only the local file is valid, the local one should be used // but the user should be warned. ShowInfoDialog(); @@ -196,11 +221,18 @@ namespace Ryujinx.Ui.Windows private async Task NeedsUpdate(DateTime oldLastModified) { - HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/")); - - if (response.IsSuccessStatusCode) + try { - return response.Content.Headers.LastModified != oldLastModified; + HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/")); + + if (response.IsSuccessStatusCode) + { + return response.Content.Headers.LastModified != oldLastModified; + } + } + catch (HttpRequestException exception) + { + Logger.Error?.Print(LogClass.Application, $"Unable to check for amiibo data updates: {exception}"); } return false; @@ -208,29 +240,37 @@ namespace Ryujinx.Ui.Windows private async Task DownloadAmiiboJson() { - HttpResponseMessage response = await _httpClient.GetAsync("https://amiibo.ryujinx.org/"); - - if (response.IsSuccessStatusCode) + try { - string amiiboJsonString = await response.Content.ReadAsStringAsync(); + HttpResponseMessage response = await _httpClient.GetAsync("https://amiibo.ryujinx.org/"); - using (FileStream dlcJsonStream = File.Create(_amiiboJsonPath, 4096, FileOptions.WriteThrough)) + if (response.IsSuccessStatusCode) { - dlcJsonStream.Write(Encoding.UTF8.GetBytes(amiiboJsonString)); + string amiiboJsonString = await response.Content.ReadAsStringAsync(); + + try + { + using FileStream dlcJsonStream = File.Create(_amiiboJsonPath, 4096, FileOptions.WriteThrough); + dlcJsonStream.Write(Encoding.UTF8.GetBytes(amiiboJsonString)); + } + catch (Exception exception) + { + Logger.Warning?.Print(LogClass.Application, $"Couldn't write amiibo data to file '{_amiiboJsonPath}: {exception}'"); + } + + return amiiboJsonString; } - return amiiboJsonString; - } - else - { Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data. Response status code: {response.StatusCode}"); - - GtkDialog.CreateInfoDialog($"Amiibo API", "An error occured while fetching information from the API."); - - Close(); + } + catch (HttpRequestException exception) + { + Logger.Error?.Print(LogClass.Application, $"Failed to request amiibo data: {exception}"); } - return DefaultJson; + GtkDialog.CreateInfoDialog("Amiibo API", "An error occured while fetching information from the API."); + + return null; } private async Task UpdateAmiiboPreview(string imageUrl) @@ -240,7 +280,7 @@ namespace Ryujinx.Ui.Windows if (response.IsSuccessStatusCode) { byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync(); - Gdk.Pixbuf amiiboPreview = new(amiiboPreviewBytes); + Pixbuf amiiboPreview = new(amiiboPreviewBytes); float ratio = Math.Min((float)_amiiboImage.AllocatedWidth / amiiboPreview.Width, (float)_amiiboImage.AllocatedHeight / amiiboPreview.Height); @@ -248,7 +288,7 @@ namespace Ryujinx.Ui.Windows int resizeHeight = (int)(amiiboPreview.Height * ratio); int resizeWidth = (int)(amiiboPreview.Width * ratio); - _amiiboImage.Pixbuf = amiiboPreview.ScaleSimple(resizeWidth, resizeHeight, Gdk.InterpType.Bilinear); + _amiiboImage.Pixbuf = amiiboPreview.ScaleSimple(resizeWidth, resizeHeight, InterpType.Bilinear); } else { @@ -258,7 +298,7 @@ namespace Ryujinx.Ui.Windows private static void ShowInfoDialog() { - GtkDialog.CreateInfoDialog($"Amiibo API", "Unable to connect to Amiibo API server. The service may be down or you may need to verify your internet connection is online."); + GtkDialog.CreateInfoDialog("Amiibo API", "Unable to connect to Amiibo API server. The service may be down or you may need to verify your internet connection is online."); } // @@ -314,7 +354,7 @@ namespace Ryujinx.Ui.Windows { AmiiboId = _amiiboCharsComboBox.ActiveId; - _amiiboImage.Pixbuf = new Gdk.Pixbuf(_amiiboLogoBytes); + _amiiboImage.Pixbuf = new Pixbuf(_amiiboLogoBytes); string imageUrl = _amiiboList.Find(amiibo => amiibo.Head + amiibo.Tail == _amiiboCharsComboBox.ActiveId).Image; @@ -354,7 +394,7 @@ namespace Ryujinx.Ui.Windows private void ShowAllCheckBox_Clicked(object sender, EventArgs e) { - _amiiboImage.Pixbuf = new Gdk.Pixbuf(_amiiboLogoBytes); + _amiiboImage.Pixbuf = new Pixbuf(_amiiboLogoBytes); _amiiboSeriesComboBox.Changed -= SeriesComboBox_Changed; _amiiboCharsComboBox.Changed -= CharacterComboBox_Changed; @@ -365,7 +405,7 @@ namespace Ryujinx.Ui.Windows _scanButton.Sensitive = false; _randomUuidCheckBox.Sensitive = false; - new Task(() => ParseAmiiboData()).Start(); + new Task(ParseAmiiboData).Start(); } private void ScanButton_Pressed(object sender, EventArgs args) diff --git a/src/Ryujinx/Ui/Windows/AvatarWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/AvatarWindow.cs similarity index 88% rename from src/Ryujinx/Ui/Windows/AvatarWindow.cs rename to src/Ryujinx.Gtk3/UI/Windows/AvatarWindow.cs index 3d3ff7c3c..fcd960df0 100644 --- a/src/Ryujinx/Ui/Windows/AvatarWindow.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/AvatarWindow.cs @@ -8,19 +8,16 @@ using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Memory; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.Common.Configuration; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; +using Ryujinx.UI.Common.Configuration; +using SkiaSharp; using System; using System.Buffers.Binary; using System.Collections.Generic; using System.IO; using System.Reflection; -using Image = SixLabors.ImageSharp.Image; +using System.Runtime.InteropServices; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class AvatarWindow : Window { @@ -36,7 +33,7 @@ namespace Ryujinx.Ui.Windows public AvatarWindow() : base($"Ryujinx {Program.Version} - Manage Accounts - Avatar") { - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); CanFocus = false; Resizable = false; @@ -144,9 +141,11 @@ namespace Ryujinx.Ui.Windows stream.Position = 0; - Image avatarImage = Image.LoadPixelData(DecompressYaz0(stream), 256, 256); + using var avatarImage = new SKBitmap(new SKImageInfo(256, 256, SKColorType.Rgba8888)); + var data = DecompressYaz0(stream); + Marshal.Copy(data, 0, avatarImage.GetPixels(), data.Length); - avatarImage.SaveAsPng(streamPng); + avatarImage.Encode(streamPng, SKEncodedImageFormat.Png, 80); _avatarDict.Add(item.FullPath, streamPng.ToArray()); } @@ -170,15 +169,23 @@ namespace Ryujinx.Ui.Windows { using MemoryStream streamJpg = MemoryStreamManager.Shared.GetStream(); - Image avatarImage = Image.Load(data, new PngDecoder()); + using var avatarImage = SKBitmap.Decode(data); + using var surface = SKSurface.Create(avatarImage.Info); - avatarImage.Mutate(x => x.BackgroundColor(new Rgba32( + var background = new SKColor( (byte)(_backgroundColor.Red * 255), (byte)(_backgroundColor.Green * 255), (byte)(_backgroundColor.Blue * 255), (byte)(_backgroundColor.Alpha * 255) - ))); - avatarImage.SaveAsJpeg(streamJpg); + ); + var canvas = surface.Canvas; + canvas.Clear(background); + canvas.DrawBitmap(avatarImage, new SKPoint()); + + surface.Flush(); + using var snapshot = surface.Snapshot(); + using var encoded = snapshot.Encode(SKEncodedImageFormat.Jpeg, 80); + encoded.SaveTo(streamJpg); return streamJpg.ToArray(); } @@ -233,7 +240,7 @@ namespace Ryujinx.Ui.Windows reader.ReadInt64(); // Padding byte[] input = new byte[stream.Length - stream.Position]; - stream.Read(input, 0, input.Length); + stream.ReadExactly(input, 0, input.Length); long inputOffset = 0; diff --git a/src/Ryujinx/Ui/Windows/CheatWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/CheatWindow.cs similarity index 90% rename from src/Ryujinx/Ui/Windows/CheatWindow.cs rename to src/Ryujinx.Gtk3/UI/Windows/CheatWindow.cs index 1eca732b2..d9f01918f 100644 --- a/src/Ryujinx/Ui/Windows/CheatWindow.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/CheatWindow.cs @@ -1,14 +1,16 @@ using Gtk; +using LibHac.Tools.FsSystem; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common.Configuration; using System; using System.Collections.Generic; using System.IO; using System.Linq; using GUI = Gtk.Builder.ObjectAttribute; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class CheatWindow : Window { @@ -22,16 +24,21 @@ namespace Ryujinx.Ui.Windows [GUI] Button _saveButton; #pragma warning restore CS0649, IDE0044 - public CheatWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName, string titlePath) : this(new Builder("Ryujinx.Ui.Windows.CheatWindow.glade"), virtualFileSystem, titleId, titleName, titlePath) { } + public CheatWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName, string titlePath) : this(new Builder("Ryujinx.Gtk3.UI.Windows.CheatWindow.glade"), virtualFileSystem, titleId, titleName, titlePath) { } private CheatWindow(Builder builder, VirtualFileSystem virtualFileSystem, ulong titleId, string titleName, string titlePath) : base(builder.GetRawOwnedObject("_cheatWindow")) { builder.Autoconnect(this); + + IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks + ? IntegrityCheckLevel.ErrorOnInvalid + : IntegrityCheckLevel.None; + _baseTitleInfoLabel.Text = $"Cheats Available for {titleName} [{titleId:X16}]"; - _buildIdTextView.Buffer.Text = $"BuildId: {ApplicationData.GetApplicationBuildId(virtualFileSystem, titlePath)}"; + _buildIdTextView.Buffer.Text = $"BuildId: {ApplicationData.GetBuildId(virtualFileSystem, checkLevel, titlePath)}"; string modsBasePath = ModLoader.GetModsBasePath(); - string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId.ToString("X16")); + string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, titleId.ToString("X16")); _enabledCheatsPath = System.IO.Path.Combine(titleModsPath, "cheats", "enabled.txt"); diff --git a/src/Ryujinx/Ui/Windows/CheatWindow.glade b/src/Ryujinx.Gtk3/UI/Windows/CheatWindow.glade similarity index 100% rename from src/Ryujinx/Ui/Windows/CheatWindow.glade rename to src/Ryujinx.Gtk3/UI/Windows/CheatWindow.glade diff --git a/src/Ryujinx/Ui/Windows/ControllerWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs similarity index 98% rename from src/Ryujinx/Ui/Windows/ControllerWindow.cs rename to src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs index ebf22ab60..d0b8266f4 100644 --- a/src/Ryujinx/Ui/Windows/ControllerWindow.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs @@ -9,20 +9,22 @@ using Ryujinx.Common.Utilities; using Ryujinx.Input; using Ryujinx.Input.Assigner; using Ryujinx.Input.GTK3; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Helper; +using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text.Json; using System.Threading; +using Button = Ryujinx.Input.Button; using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId; using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; using GUI = Gtk.Builder.ObjectAttribute; using Key = Ryujinx.Common.Configuration.Hid.Key; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class ControllerWindow : Window { @@ -117,7 +119,7 @@ namespace Ryujinx.Ui.Windows private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - public ControllerWindow(MainWindow mainWindow, PlayerIndex controllerId) : this(mainWindow, new Builder("Ryujinx.Ui.Windows.ControllerWindow.glade"), controllerId) { } + public ControllerWindow(MainWindow mainWindow, PlayerIndex controllerId) : this(mainWindow, new Builder("Ryujinx.Gtk3.UI.Windows.ControllerWindow.glade"), controllerId) { } private ControllerWindow(MainWindow mainWindow, Builder builder, PlayerIndex controllerId) : base(builder.GetRawOwnedObject("_controllerWin")) { @@ -127,7 +129,7 @@ namespace Ryujinx.Ui.Windows // NOTE: To get input in this window, we need to bind a custom keyboard driver instead of using the InputManager one as the main window isn't focused... _gtk3KeyboardDriver = new GTK3KeyboardDriver(this); - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); builder.Autoconnect(this); @@ -377,10 +379,10 @@ namespace Ryujinx.Ui.Windows { _controllerImage.Pixbuf = _controllerType.ActiveId switch { - "ProController" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_ProCon.svg", 400, 400), - "JoyconLeft" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConLeft.svg", 400, 500), - "JoyconRight" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConRight.svg", 400, 500), - _ => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConPair.svg", 400, 500), + "ProController" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Controller_ProCon.svg", 400, 400), + "JoyconLeft" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Controller_JoyConLeft.svg", 400, 500), + "JoyconRight" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Controller_JoyConRight.svg", 400, 500), + _ => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Controller_JoyConPair.svg", 400, 500), }; } } @@ -887,13 +889,13 @@ namespace Ryujinx.Ui.Windows Thread.Sleep(10); assigner.ReadInput(); - if (_mousePressed || keyboard.IsPressed(Ryujinx.Input.Key.Escape) || assigner.HasAnyButtonPressed() || assigner.ShouldCancel()) + if (_mousePressed || keyboard.IsPressed(Ryujinx.Input.Key.Escape) || assigner.IsAnyButtonPressed() || assigner.ShouldCancel()) { break; } } - string pressedButton = assigner.GetPressedButton(); + string pressedButton = ButtonHelper.ToString(assigner.GetPressedButton() ?? new Button(Input.Key.Unknown)); Application.Invoke(delegate { diff --git a/src/Ryujinx/Ui/Windows/ControllerWindow.glade b/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.glade similarity index 100% rename from src/Ryujinx/Ui/Windows/ControllerWindow.glade rename to src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.glade diff --git a/src/Ryujinx/Ui/Windows/DlcWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/DlcWindow.cs similarity index 73% rename from src/Ryujinx/Ui/Windows/DlcWindow.cs rename to src/Ryujinx.Gtk3/UI/Windows/DlcWindow.cs index 9f7179467..fb3189e1c 100644 --- a/src/Ryujinx/Ui/Windows/DlcWindow.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/DlcWindow.cs @@ -2,25 +2,29 @@ using Gtk; using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; -using LibHac.FsSystem; using LibHac.Tools.Fs; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Configuration; using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.Widgets; +using Ryujinx.HLE.Loaders.Processes.Extensions; +using Ryujinx.HLE.Utilities; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; +using System.Globalization; using System.IO; +using System.Linq; using GUI = Gtk.Builder.ObjectAttribute; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class DlcWindow : Window { private readonly VirtualFileSystem _virtualFileSystem; - private readonly string _titleId; + private readonly string _applicationIdBase; private readonly string _dlcJsonPath; private readonly List _dlcContainerList; @@ -32,16 +36,16 @@ namespace Ryujinx.Ui.Windows [GUI] TreeSelection _dlcTreeSelection; #pragma warning restore CS0649, IDE0044 - public DlcWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.Ui.Windows.DlcWindow.glade"), virtualFileSystem, titleId, titleName) { } + public DlcWindow(VirtualFileSystem virtualFileSystem, string applicationIdBase, ApplicationData applicationData) : this(new Builder("Ryujinx.Gtk3.UI.Windows.DlcWindow.glade"), virtualFileSystem, applicationIdBase, applicationData) { } - private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetRawOwnedObject("_dlcWindow")) + private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string applicationIdBase, ApplicationData applicationData) : base(builder.GetRawOwnedObject("_dlcWindow")) { builder.Autoconnect(this); - _titleId = titleId; + _applicationIdBase = applicationIdBase; _virtualFileSystem = virtualFileSystem; - _dlcJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "dlc.json"); - _baseTitleInfoLabel.Text = $"DLC Available for {titleName} [{titleId.ToUpper()}]"; + _dlcJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _applicationIdBase, "dlc.json"); + _baseTitleInfoLabel.Text = $"DLC Available for {applicationData.Name} [{applicationIdBase.ToUpper()}]"; try { @@ -72,7 +76,7 @@ namespace Ryujinx.Ui.Windows }; _dlcTreeView.AppendColumn("Enabled", enableToggle, "active", 0); - _dlcTreeView.AppendColumn("TitleId", new CellRendererText(), "text", 1); + _dlcTreeView.AppendColumn("ApplicationId", new CellRendererText(), "text", 1); _dlcTreeView.AppendColumn("Path", new CellRendererText(), "text", 2); foreach (DownloadableContentContainer dlcContainer in _dlcContainerList) @@ -86,18 +90,18 @@ namespace Ryujinx.Ui.Windows bool areAllContentPacksEnabled = dlcContainer.DownloadableContentNcaList.TrueForAll((nca) => nca.Enabled); TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(areAllContentPacksEnabled, "", dlcContainer.ContainerPath); - using FileStream containerFile = File.OpenRead(dlcContainer.ContainerPath); + using IFileSystem partitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(dlcContainer.ContainerPath, _virtualFileSystem, false); - PartitionFileSystem pfs = new(); - pfs.Initialize(containerFile.AsStorage()).ThrowIfFailure(); - - _virtualFileSystem.ImportTickets(pfs); + if (partitionFileSystem == null) + { + continue; + } foreach (DownloadableContentNca dlcNca in dlcContainer.DownloadableContentNcaList) { using var ncaFile = new UniqueRef(); - pfs.OpenFile(ref ncaFile.Ref, dlcNca.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); + partitionFileSystem.OpenFile(ref ncaFile.Ref, dlcNca.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), dlcContainer.ContainerPath); if (nca != null) @@ -112,6 +116,9 @@ namespace Ryujinx.Ui.Windows TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(false, "", $"(MISSING) {dlcContainer.ContainerPath}"); } } + + // NOTE: Try to load downloadable contents from PFS last to preserve enabled state. + AddDlc(applicationData.Path, true); } private Nca TryCreateNca(IStorage ncaStorage, string containerPath) @@ -128,6 +135,52 @@ namespace Ryujinx.Ui.Windows return null; } + private void AddDlc(string path, bool ignoreNotFound = false) + { + if (!File.Exists(path) || _dlcContainerList.Any(x => x.ContainerPath == path)) + { + return; + } + + using IFileSystem partitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(path, _virtualFileSystem); + + bool containsDlc = false; + + TreeIter? parentIter = null; + + foreach (DirectoryEntryEx fileEntry in partitionFileSystem.EnumerateEntries("/", "*.nca")) + { + using var ncaFile = new UniqueRef(); + + partitionFileSystem.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); + + Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), path); + + if (nca == null) + { + continue; + } + + if (nca.Header.ContentType == NcaContentType.PublicData) + { + if (nca.GetProgramIdBase() != ulong.Parse(_applicationIdBase, NumberStyles.HexNumber)) + { + continue; + } + + parentIter ??= ((TreeStore)_dlcTreeView.Model).AppendValues(true, "", path); + + ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter.Value, true, nca.Header.TitleId.ToString("X16"), fileEntry.FullPath); + containsDlc = true; + } + } + + if (!containsDlc && !ignoreNotFound) + { + GtkDialog.CreateErrorDialog("The specified file does not contain DLC for the selected title!"); + } + } + private void AddButton_Clicked(object sender, EventArgs args) { FileChooserNative fileChooser = new("Select DLC files", this, FileChooserAction.Open, "Add", "Cancel") @@ -147,52 +200,7 @@ namespace Ryujinx.Ui.Windows { foreach (string containerPath in fileChooser.Filenames) { - if (!File.Exists(containerPath)) - { - return; - } - - using FileStream containerFile = File.OpenRead(containerPath); - - PartitionFileSystem pfs = new(); - pfs.Initialize(containerFile.AsStorage()).ThrowIfFailure(); - bool containsDlc = false; - - _virtualFileSystem.ImportTickets(pfs); - - TreeIter? parentIter = null; - - foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) - { - using var ncaFile = new UniqueRef(); - - pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), containerPath); - - if (nca == null) - { - continue; - } - - if (nca.Header.ContentType == NcaContentType.PublicData) - { - if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000).ToString("x16") != _titleId) - { - break; - } - - parentIter ??= ((TreeStore)_dlcTreeView.Model).AppendValues(true, "", containerPath); - - ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter.Value, true, nca.Header.TitleId.ToString("X16"), fileEntry.FullPath); - containsDlc = true; - } - } - - if (!containsDlc) - { - GtkDialog.CreateErrorDialog("The specified file does not contain DLC for the selected title!"); - } + AddDlc(containerPath); } } diff --git a/src/Ryujinx/Ui/Windows/DlcWindow.glade b/src/Ryujinx.Gtk3/UI/Windows/DlcWindow.glade similarity index 100% rename from src/Ryujinx/Ui/Windows/DlcWindow.glade rename to src/Ryujinx.Gtk3/UI/Windows/DlcWindow.glade diff --git a/src/Ryujinx/Ui/Windows/SettingsWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/SettingsWindow.cs similarity index 98% rename from src/Ryujinx/Ui/Windows/SettingsWindow.cs rename to src/Ryujinx.Gtk3/UI/Windows/SettingsWindow.cs index dabef14dd..dc467c0f2 100644 --- a/src/Ryujinx/Ui/Windows/SettingsWindow.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/SettingsWindow.cs @@ -9,10 +9,10 @@ using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.GraphicsDriver; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Time.TimeZone; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Configuration.System; -using Ryujinx.Ui.Helper; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Configuration.System; +using Ryujinx.UI.Helper; +using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; using System.Globalization; @@ -23,7 +23,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using GUI = Gtk.Builder.ObjectAttribute; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class SettingsWindow : Window { @@ -120,11 +120,11 @@ namespace Ryujinx.Ui.Windows #pragma warning restore CS0649, IDE0044 - public SettingsWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this(parent, new Builder("Ryujinx.Ui.Windows.SettingsWindow.glade"), virtualFileSystem, contentManager) { } + public SettingsWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this(parent, new Builder("Ryujinx.Gtk3.UI.Windows.SettingsWindow.glade"), virtualFileSystem, contentManager) { } private SettingsWindow(MainWindow parent, Builder builder, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : base(builder.GetRawOwnedObject("_settingsWin")) { - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); _parent = parent; @@ -311,7 +311,7 @@ namespace Ryujinx.Ui.Windows _directMouseAccess.Click(); } - if (ConfigurationState.Instance.Ui.EnableCustomTheme) + if (ConfigurationState.Instance.UI.EnableCustomTheme) { _custThemeToggle.Click(); } @@ -366,7 +366,7 @@ namespace Ryujinx.Ui.Windows _multiLanSelect.SetActiveId(ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value); _multiModeSelect.SetActiveId(ConfigurationState.Instance.Multiplayer.Mode.Value.ToString()); - _custThemePath.Buffer.Text = ConfigurationState.Instance.Ui.CustomThemePath; + _custThemePath.Buffer.Text = ConfigurationState.Instance.UI.CustomThemePath; _resScaleText.Buffer.Text = ConfigurationState.Instance.Graphics.ResScaleCustom.Value.ToString(); _scalingFilterLevel.Value = ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value; _resScaleText.Visible = _resScaleCombo.ActiveId == "-1"; @@ -379,7 +379,7 @@ namespace Ryujinx.Ui.Windows _gameDirsBoxStore = new ListStore(typeof(string)); _gameDirsBox.Model = _gameDirsBoxStore; - foreach (string gameDir in ConfigurationState.Instance.Ui.GameDirs.Value) + foreach (string gameDir in ConfigurationState.Instance.UI.GameDirs.Value) { _gameDirsBoxStore.AppendValues(gameDir); } @@ -568,7 +568,7 @@ namespace Ryujinx.Ui.Windows _gameDirsBoxStore.IterNext(ref treeIter); } - ConfigurationState.Instance.Ui.GameDirs.Value = gameDirs; + ConfigurationState.Instance.UI.GameDirs.Value = gameDirs; _directoryChanged = false; } @@ -640,11 +640,11 @@ namespace Ryujinx.Ui.Windows ConfigurationState.Instance.System.IgnoreMissingServices.Value = _ignoreToggle.Active; ConfigurationState.Instance.Hid.EnableKeyboard.Value = _directKeyboardAccess.Active; ConfigurationState.Instance.Hid.EnableMouse.Value = _directMouseAccess.Active; - ConfigurationState.Instance.Ui.EnableCustomTheme.Value = _custThemeToggle.Active; + ConfigurationState.Instance.UI.EnableCustomTheme.Value = _custThemeToggle.Active; ConfigurationState.Instance.System.Language.Value = Enum.Parse(_systemLanguageSelect.ActiveId); ConfigurationState.Instance.System.Region.Value = Enum.Parse(_systemRegionSelect.ActiveId); ConfigurationState.Instance.System.SystemTimeOffset.Value = _systemTimeOffset; - ConfigurationState.Instance.Ui.CustomThemePath.Value = _custThemePath.Buffer.Text; + ConfigurationState.Instance.UI.CustomThemePath.Value = _custThemePath.Buffer.Text; ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = _graphicsShadersDumpPath.Buffer.Text; ConfigurationState.Instance.System.FsGlobalAccessLogMode.Value = (int)_fsLogSpinAdjustment.Value; ConfigurationState.Instance.Graphics.MaxAnisotropy.Value = float.Parse(_anisotropy.ActiveId, CultureInfo.InvariantCulture); diff --git a/src/Ryujinx/Ui/Windows/SettingsWindow.glade b/src/Ryujinx.Gtk3/UI/Windows/SettingsWindow.glade similarity index 100% rename from src/Ryujinx/Ui/Windows/SettingsWindow.glade rename to src/Ryujinx.Gtk3/UI/Windows/SettingsWindow.glade diff --git a/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/TitleUpdateWindow.cs similarity index 62% rename from src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs rename to src/Ryujinx.Gtk3/UI/Windows/TitleUpdateWindow.cs index 51918eeab..a08f59597 100644 --- a/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/TitleUpdateWindow.cs @@ -2,15 +2,18 @@ using Gtk; using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; -using LibHac.FsSystem; +using LibHac.Ncm; using LibHac.Ns; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Configuration; using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Widgets; +using Ryujinx.HLE.Loaders.Processes.Extensions; +using Ryujinx.HLE.Utilities; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; using System.IO; @@ -18,13 +21,13 @@ using System.Linq; using GUI = Gtk.Builder.ObjectAttribute; using SpanHelpers = LibHac.Common.SpanHelpers; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class TitleUpdateWindow : Window { private readonly MainWindow _parent; private readonly VirtualFileSystem _virtualFileSystem; - private readonly string _titleId; + private readonly ApplicationData _applicationData; private readonly string _updateJsonPath; private TitleUpdateMetadata _titleUpdateWindowData; @@ -38,17 +41,17 @@ namespace Ryujinx.Ui.Windows [GUI] RadioButton _noUpdateRadioButton; #pragma warning restore CS0649, IDE0044 - public TitleUpdateWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.Ui.Windows.TitleUpdateWindow.glade"), parent, virtualFileSystem, titleId, titleName) { } + public TitleUpdateWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, ApplicationData applicationData) : this(new Builder("Ryujinx.Gtk3.UI.Windows.TitleUpdateWindow.glade"), parent, virtualFileSystem, applicationData) { } - private TitleUpdateWindow(Builder builder, MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetRawOwnedObject("_titleUpdateWindow")) + private TitleUpdateWindow(Builder builder, MainWindow parent, VirtualFileSystem virtualFileSystem, ApplicationData applicationData) : base(builder.GetRawOwnedObject("_titleUpdateWindow")) { _parent = parent; builder.Autoconnect(this); - _titleId = titleId; + _applicationData = applicationData; _virtualFileSystem = virtualFileSystem; - _updateJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "updates.json"); + _updateJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, applicationData.IdBaseString, "updates.json"); _radioButtonToPathDictionary = new Dictionary(); try @@ -64,7 +67,10 @@ namespace Ryujinx.Ui.Windows }; } - _baseTitleInfoLabel.Text = $"Updates Available for {titleName} [{titleId.ToUpper()}]"; + _baseTitleInfoLabel.Text = $"Updates Available for {applicationData.Name} [{applicationData.IdBaseString}]"; + + // Try to get updates from PFS first + AddUpdate(_applicationData.Path, true); foreach (string path in _titleUpdateWindowData.Paths) { @@ -84,46 +90,68 @@ namespace Ryujinx.Ui.Windows } } - private void AddUpdate(string path) + private void AddUpdate(string path, bool ignoreNotFound = false) { - if (File.Exists(path)) + if (!File.Exists(path) || _radioButtonToPathDictionary.ContainsValue(path)) { - using FileStream file = new(path, FileMode.Open, FileAccess.Read); + return; + } - PartitionFileSystem nsp = new(); - nsp.Initialize(file.AsStorage()).ThrowIfFailure(); + IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks + ? IntegrityCheckLevel.ErrorOnInvalid + : IntegrityCheckLevel.None; - try + try + { + using IFileSystem pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(path, _virtualFileSystem); + + Dictionary updates = pfs.GetContentData(ContentMetaType.Patch, _virtualFileSystem, checkLevel); + + Nca patchNca = null; + Nca controlNca = null; + + if (updates.TryGetValue(_applicationData.Id, out ContentMetaData update)) { - (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(_virtualFileSystem, nsp, _titleId, 0); + patchNca = update.GetNcaByType(_virtualFileSystem.KeySet, LibHac.Ncm.ContentType.Program); + controlNca = update.GetNcaByType(_virtualFileSystem.KeySet, LibHac.Ncm.ContentType.Control); + } - if (controlNca != null && patchNca != null) + if (controlNca != null && patchNca != null) + { + ApplicationControlProperty controlData = new(); + + using var nacpFile = new UniqueRef(); + + controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); + nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure(); + + string radioLabel = $"Version {controlData.DisplayVersionString.ToString()} - {path}"; + + if (System.IO.Path.GetExtension(path).ToLower() == ".xci") { - ApplicationControlProperty controlData = new(); - - using var nacpFile = new UniqueRef(); - - controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); - nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure(); - - RadioButton radioButton = new($"Version {controlData.DisplayVersionString.ToString()} - {path}"); - radioButton.JoinGroup(_noUpdateRadioButton); - - _availableUpdatesBox.Add(radioButton); - _radioButtonToPathDictionary.Add(radioButton, path); - - radioButton.Show(); - radioButton.Active = true; + radioLabel = "Bundled: " + radioLabel; } - else + + RadioButton radioButton = new(radioLabel); + radioButton.JoinGroup(_noUpdateRadioButton); + + _availableUpdatesBox.Add(radioButton); + _radioButtonToPathDictionary.Add(radioButton, path); + + radioButton.Show(); + radioButton.Active = true; + } + else + { + if (!ignoreNotFound) { GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!"); } } - catch (Exception exception) - { - GtkDialog.CreateErrorDialog($"{exception.Message}. Errored File: {path}"); - } + } + catch (Exception exception) + { + GtkDialog.CreateErrorDialog($"{exception.Message}. Errored File: {path}"); } } diff --git a/src/Ryujinx/Ui/Windows/TitleUpdateWindow.glade b/src/Ryujinx.Gtk3/UI/Windows/TitleUpdateWindow.glade similarity index 100% rename from src/Ryujinx/Ui/Windows/TitleUpdateWindow.glade rename to src/Ryujinx.Gtk3/UI/Windows/TitleUpdateWindow.glade diff --git a/src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs b/src/Ryujinx.Gtk3/UI/Windows/UserProfilesManagerWindow.Designer.cs similarity index 99% rename from src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs rename to src/Ryujinx.Gtk3/UI/Windows/UserProfilesManagerWindow.Designer.cs index 804bd3fb0..bc5a18f95 100644 --- a/src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/UserProfilesManagerWindow.Designer.cs @@ -2,7 +2,7 @@ using Pango; using System; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class UserProfilesManagerWindow : Window { diff --git a/src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/UserProfilesManagerWindow.cs similarity index 96% rename from src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs rename to src/Ryujinx.Gtk3/UI/Windows/UserProfilesManagerWindow.cs index 3d503f64e..77afc5d1f 100644 --- a/src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs +++ b/src/Ryujinx.Gtk3/UI/Windows/UserProfilesManagerWindow.cs @@ -2,19 +2,17 @@ using Gtk; using Ryujinx.Common.Memory; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Widgets; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Processing; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Widgets; +using SkiaSharp; using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Threading; using System.Threading.Tasks; -using Image = SixLabors.ImageSharp.Image; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class UserProfilesManagerWindow : Window { @@ -32,7 +30,7 @@ namespace Ryujinx.Ui.Windows public UserProfilesManagerWindow(AccountManager accountManager, ContentManager contentManager, VirtualFileSystem virtualFileSystem) : base($"Ryujinx {Program.Version} - Manage User Profiles") { - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); InitializeComponent(); @@ -177,13 +175,13 @@ namespace Ryujinx.Ui.Windows private void ProcessProfileImage(byte[] buffer) { - using Image image = Image.Load(buffer); + using var image = SKBitmap.Decode(buffer); - image.Mutate(x => x.Resize(256, 256)); + image.Resize(new SKImageInfo(256, 256), SKFilterQuality.High); using MemoryStream streamJpg = MemoryStreamManager.Shared.GetStream(); - image.SaveAsJpeg(streamJpg); + image.Encode(streamJpg, SKEncodedImageFormat.Jpeg, 80); _bufferImageProfile = streamJpg.ToArray(); } diff --git a/src/Ryujinx.HLE.Generators/CodeGenerator.cs b/src/Ryujinx.HLE.Generators/CodeGenerator.cs index 726a07f0c..7e4848ad3 100644 --- a/src/Ryujinx.HLE.Generators/CodeGenerator.cs +++ b/src/Ryujinx.HLE.Generators/CodeGenerator.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; namespace Ryujinx.HLE.Generators { diff --git a/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs b/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs index bfeb972fc..91258c6c8 100644 --- a/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs +++ b/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Linq; @@ -13,25 +13,6 @@ namespace Ryujinx.HLE.Generators var syntaxReceiver = (ServiceSyntaxReceiver)context.SyntaxReceiver; CodeGenerator generator = new CodeGenerator(); - generator.EnterScope($"namespace Ryujinx.rd"); - generator.EnterScope($"public class Rd"); - - generator.AppendLine($"public string rd = \"\"\""); - foreach (var className in syntaxReceiver.Types) - { - if (className.Modifiers.Any(SyntaxKind.AbstractKeyword) || className.Modifiers.Any(SyntaxKind.PrivateKeyword)) - continue; - - var name = GetFullName(className, context).Replace("global::", ""); - generator.AppendLine($""); - } - generator.AppendLine($"\"\"\";"); - - generator.LeaveScope(); - generator.LeaveScope(); - context.AddSource($"rd.g.cs", generator.ToString()); - generator = new CodeGenerator(); - generator.AppendLine("using System;"); generator.EnterScope($"namespace Ryujinx.HLE.HOS.Services.Sm"); generator.EnterScope($"partial class IUserInterface"); diff --git a/src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs b/src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs index 6fc1c7199..e4269cb9a 100644 --- a/src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs +++ b/src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs @@ -1,10 +1,6 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.CSharp; -using System; using System.Collections.Generic; -using System.Text; -using System.Linq; namespace Ryujinx.HLE.Generators { @@ -21,8 +17,6 @@ namespace Ryujinx.HLE.Generators return; } - var name = classDeclaration.Identifier.ToString(); - Types.Add(classDeclaration); } } diff --git a/src/Ryujinx.HLE/FileSystem/ContentManager.cs b/src/Ryujinx.HLE/FileSystem/ContentManager.cs index b27eb5ead..e6c0fce08 100644 --- a/src/Ryujinx.HLE/FileSystem/ContentManager.cs +++ b/src/Ryujinx.HLE/FileSystem/ContentManager.cs @@ -14,6 +14,7 @@ using Ryujinx.Common.Utilities; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.HOS.Services.Ssl; using Ryujinx.HLE.HOS.Services.Time; +using Ryujinx.HLE.Utilities; using System; using System.Collections.Generic; using System.IO; @@ -104,20 +105,15 @@ namespace Ryujinx.HLE.FileSystem foreach (StorageId storageId in Enum.GetValues()) { - string contentDirectory = null; - string contentPathString = null; - string registeredDirectory = null; - - try - { - contentPathString = ContentPath.GetContentPath(storageId); - contentDirectory = ContentPath.GetRealPath(contentPathString); - registeredDirectory = Path.Combine(contentDirectory, "registered"); - } - catch (NotSupportedException) + if (!ContentPath.TryGetContentPath(storageId, out var contentPathString)) { continue; } + if (!ContentPath.TryGetRealPath(contentPathString, out var contentDirectory)) + { + continue; + } + var registeredDirectory = Path.Combine(contentDirectory, "registered"); Directory.CreateDirectory(registeredDirectory); @@ -189,41 +185,6 @@ namespace Ryujinx.HLE.FileSystem } } - // fs must contain AOC nca files in its root - public void AddAocData(IFileSystem fs, string containerPath, ulong aocBaseId, IntegrityCheckLevel integrityCheckLevel) - { - _virtualFileSystem.ImportTickets(fs); - - foreach (var ncaPath in fs.EnumerateEntries("*.cnmt.nca", SearchOptions.Default)) - { - using var ncaFile = new UniqueRef(); - - fs.OpenFile(ref ncaFile.Ref, ncaPath.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - var nca = new Nca(_virtualFileSystem.KeySet, ncaFile.Get.AsStorage()); - if (nca.Header.ContentType != NcaContentType.Meta) - { - Logger.Warning?.Print(LogClass.Application, $"{ncaPath} is not a valid metadata file"); - - continue; - } - - using var pfs0 = nca.OpenFileSystem(0, integrityCheckLevel); - using var cnmtFile = new UniqueRef(); - - pfs0.OpenFile(ref cnmtFile.Ref, pfs0.EnumerateEntries().Single().FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - var cnmt = new Cnmt(cnmtFile.Get.AsStream()); - if (cnmt.Type != ContentMetaType.AddOnContent || (cnmt.TitleId & 0xFFFFFFFFFFFFE000) != aocBaseId) - { - continue; - } - - string ncaId = Convert.ToHexString(cnmt.ContentEntries[0].NcaId).ToLower(); - - AddAocItem(cnmt.TitleId, containerPath, $"/{ncaId}.nca", true); - } - } - public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool mergedToContainer = false) { // TODO: Check Aoc version. @@ -237,11 +198,7 @@ namespace Ryujinx.HLE.FileSystem if (!mergedToContainer) { - using FileStream fileStream = File.OpenRead(containerPath); - using PartitionFileSystem partitionFileSystem = new(); - partitionFileSystem.Initialize(fileStream.AsStorage()).ThrowIfFailure(); - - _virtualFileSystem.ImportTickets(partitionFileSystem); + using var pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(containerPath, _virtualFileSystem); } } } @@ -471,8 +428,8 @@ namespace Ryujinx.HLE.FileSystem public void InstallFirmware(string firmwareSource) { - string contentPathString = ContentPath.GetContentPath(StorageId.BuiltInSystem); - string contentDirectory = ContentPath.GetRealPath(contentPathString); + ContentPath.TryGetContentPath(StorageId.BuiltInSystem, out var contentPathString); + ContentPath.TryGetRealPath(contentPathString, out var contentDirectory); string registeredDirectory = Path.Combine(contentDirectory, "registered"); string temporaryDirectory = Path.Combine(contentDirectory, "temp"); diff --git a/src/Ryujinx.HLE/FileSystem/ContentMetaData.cs b/src/Ryujinx.HLE/FileSystem/ContentMetaData.cs new file mode 100644 index 000000000..aebcf7988 --- /dev/null +++ b/src/Ryujinx.HLE/FileSystem/ContentMetaData.cs @@ -0,0 +1,61 @@ +using LibHac.Common.Keys; +using LibHac.Fs.Fsa; +using LibHac.Ncm; +using LibHac.Tools.FsSystem.NcaUtils; +using LibHac.Tools.Ncm; +using Ryujinx.HLE.Loaders.Processes.Extensions; +using System; + +namespace Ryujinx.HLE.FileSystem +{ + /// + /// Thin wrapper around + /// + public class ContentMetaData + { + private readonly IFileSystem _pfs; + private readonly Cnmt _cnmt; + + public ulong Id => _cnmt.TitleId; + public TitleVersion Version => _cnmt.TitleVersion; + public ContentMetaType Type => _cnmt.Type; + public ulong ApplicationId => _cnmt.ApplicationTitleId; + public ulong PatchId => _cnmt.PatchTitleId; + public TitleVersion RequiredSystemVersion => _cnmt.MinimumSystemVersion; + public TitleVersion RequiredApplicationVersion => _cnmt.MinimumApplicationVersion; + public byte[] Digest => _cnmt.Hash; + + public ulong ProgramBaseId => Id & ~0x1FFFUL; + public bool IsSystemTitle => _cnmt.Type < ContentMetaType.Application; + + public ContentMetaData(IFileSystem pfs, Cnmt cnmt) + { + _pfs = pfs; + _cnmt = cnmt; + } + + public Nca GetNcaByType(KeySet keySet, ContentType type, int programIndex = 0) + { + // TODO: Replace this with a check for IdOffset as soon as LibHac supports it: + // && entry.IdOffset == programIndex + + foreach (var entry in _cnmt.ContentEntries) + { + if (entry.Type != type) + { + continue; + } + + string ncaId = BitConverter.ToString(entry.NcaId).Replace("-", null).ToLower(); + Nca nca = _pfs.GetNca(keySet, $"/{ncaId}.nca"); + + if (nca.GetProgramIndex() == programIndex) + { + return nca; + } + } + + return null; + } + } +} diff --git a/src/Ryujinx.HLE/FileSystem/ContentPath.cs b/src/Ryujinx.HLE/FileSystem/ContentPath.cs index 02539c5c6..ffc212f77 100644 --- a/src/Ryujinx.HLE/FileSystem/ContentPath.cs +++ b/src/Ryujinx.HLE/FileSystem/ContentPath.cs @@ -26,17 +26,19 @@ namespace Ryujinx.HLE.FileSystem public const string Nintendo = "Nintendo"; public const string Contents = "Contents"; - public static string GetRealPath(string switchContentPath) + public static bool TryGetRealPath(string switchContentPath, out string realPath) { - return switchContentPath switch + realPath = switchContentPath switch { SystemContent => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath, Contents), UserContent => Path.Combine(AppDataManager.BaseDirPath, UserNandPath, Contents), SdCardContent => Path.Combine(GetSdCardPath(), Nintendo, Contents), System => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath), User => Path.Combine(AppDataManager.BaseDirPath, UserNandPath), - _ => throw new NotSupportedException($"Content Path \"`{switchContentPath}`\" is not supported."), + _ => null, }; + + return realPath != null; } public static string GetContentPath(ContentStorageId contentStorageId) @@ -50,15 +52,17 @@ namespace Ryujinx.HLE.FileSystem }; } - public static string GetContentPath(StorageId storageId) + public static bool TryGetContentPath(StorageId storageId, out string contentPath) { - return storageId switch + contentPath = storageId switch { StorageId.BuiltInSystem => SystemContent, StorageId.BuiltInUser => UserContent, StorageId.SdCard => SdCardContent, - _ => throw new NotSupportedException($"Storage Id \"`{storageId}`\" is not supported."), + _ => null, }; + + return contentPath != null; } public static StorageId GetStorageId(string contentPathString) diff --git a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index 43bd27761..0827266a1 100644 --- a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs +++ b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -186,7 +186,12 @@ namespace Ryujinx.HLE.FileSystem public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient) { - LocalFileSystem serverBaseFs = new(AppDataManager.BaseDirPath); + LocalFileSystem serverBaseFs = new(useUnixTimeStamps: true); + Result result = serverBaseFs.Initialize(AppDataManager.BaseDirPath, LocalFileSystem.PathMode.DefaultCaseSensitivity, ensurePathExists: true); + if (result.IsFailure()) + { + throw new HorizonResultException(result, "Error creating LocalFileSystem."); + } fsServerClient = horizon.CreatePrivilegedHorizonClient(); var fsServer = new FileSystemServer(fsServerClient); diff --git a/src/Ryujinx.HLE/HLEConfiguration.cs b/src/Ryujinx.HLE/HLEConfiguration.cs index f589bfdda..955fee4b5 100644 --- a/src/Ryujinx.HLE/HLEConfiguration.cs +++ b/src/Ryujinx.HLE/HLEConfiguration.cs @@ -7,7 +7,7 @@ using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.SystemState; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System; namespace Ryujinx.HLE @@ -63,7 +63,7 @@ namespace Ryujinx.HLE /// The handler for various UI related operations needed outside of HLE. /// /// This cannot be changed after instantiation. - internal readonly IHostUiHandler HostUiHandler; + internal readonly IHostUIHandler HostUIHandler; /// /// Control the memory configuration used by the emulation context. @@ -177,7 +177,7 @@ namespace Ryujinx.HLE IRenderer gpuRenderer, IHardwareDeviceDriver audioDeviceDriver, MemoryConfiguration memoryConfiguration, - IHostUiHandler hostUiHandler, + IHostUIHandler hostUIHandler, SystemLanguage systemLanguage, RegionCode region, bool enableVsync, @@ -204,7 +204,7 @@ namespace Ryujinx.HLE GpuRenderer = gpuRenderer; AudioDeviceDriver = audioDeviceDriver; MemoryConfiguration = memoryConfiguration; - HostUiHandler = hostUiHandler; + HostUIHandler = hostUIHandler; SystemLanguage = systemLanguage; Region = region; EnableVsync = enableVsync; diff --git a/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs b/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs index 867202178..5ec9d4b08 100644 --- a/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs @@ -86,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Applets PlayerIndex primaryIndex; while (!_system.Device.Hid.Npads.Validate(playerMin, playerMax, (ControllerType)privateArg.NpadStyleSet, out configuredCount, out primaryIndex)) { - ControllerAppletUiArgs uiArgs = new() + ControllerAppletUIArgs uiArgs = new() { PlayerCountMin = playerMin, PlayerCountMax = playerMax, @@ -95,7 +95,7 @@ namespace Ryujinx.HLE.HOS.Applets IsDocked = _system.State.DockedMode, }; - if (!_system.Device.UiHandler.DisplayMessageDialog(uiArgs)) + if (!_system.Device.UIHandler.DisplayMessageDialog(uiArgs)) { break; } diff --git a/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUiArgs.cs b/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUIArgs.cs similarity index 88% rename from src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUiArgs.cs rename to src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUIArgs.cs index bf440515b..10cba58ba 100644 --- a/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUiArgs.cs +++ b/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUIArgs.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Applets { - public struct ControllerAppletUiArgs + public struct ControllerAppletUIArgs { public int PlayerCountMin; public int PlayerCountMax; diff --git a/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs b/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs index 5c474f229..7ee9b9e90 100644 --- a/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs @@ -166,13 +166,13 @@ namespace Ryujinx.HLE.HOS.Applets.Error string[] buttons = GetButtonsText(module, description, "DlgBtn"); - bool showDetails = _horizon.Device.UiHandler.DisplayErrorAppletDialog($"Error Code: {module}-{description:0000}", "\n" + message, buttons); + bool showDetails = _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Code: {module}-{description:0000}", "\n" + message, buttons); if (showDetails) { message = GetMessageText(module, description, "FlvMsg"); buttons = GetButtonsText(module, description, "FlvBtn"); - _horizon.Device.UiHandler.DisplayErrorAppletDialog($"Details: {module}-{description:0000}", "\n" + message, buttons); + _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Details: {module}-{description:0000}", "\n" + message, buttons); } } @@ -200,12 +200,12 @@ namespace Ryujinx.HLE.HOS.Applets.Error buttons.Add("OK"); - bool showDetails = _horizon.Device.UiHandler.DisplayErrorAppletDialog($"Error Number: {applicationErrorArg.ErrorNumber}", "\n" + messageText, buttons.ToArray()); + bool showDetails = _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Number: {applicationErrorArg.ErrorNumber}", "\n" + messageText, buttons.ToArray()); if (showDetails) { buttons.RemoveAt(0); - _horizon.Device.UiHandler.DisplayErrorAppletDialog($"Error Number: {applicationErrorArg.ErrorNumber} (Details)", "\n" + detailsText, buttons.ToArray()); + _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Number: {applicationErrorArg.ErrorNumber} (Details)", "\n" + detailsText, buttons.ToArray()); } } diff --git a/src/Ryujinx.HLE/HOS/Applets/IApplet.cs b/src/Ryujinx.HLE/HOS/Applets/IApplet.cs index 5ccf3994f..985887c47 100644 --- a/src/Ryujinx.HLE/HOS/Applets/IApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/IApplet.cs @@ -1,5 +1,5 @@ using Ryujinx.HLE.HOS.Services.Am.AppletAE; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Memory; using System; using System.Runtime.InteropServices; diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs index f04bb4e22..5c6fbec97 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs @@ -4,8 +4,8 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard; using Ryujinx.HLE.HOS.Services.Am.AppletAE; using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad; -using Ryujinx.HLE.Ui; -using Ryujinx.HLE.Ui.Input; +using Ryujinx.HLE.UI; +using Ryujinx.HLE.UI.Input; using Ryujinx.Memory; using System; using System.Diagnostics; @@ -94,14 +94,14 @@ namespace Ryujinx.HLE.HOS.Applets _keyboardBackgroundInitialize = MemoryMarshal.Read(keyboardConfig); _backgroundState = InlineKeyboardState.Uninitialized; - if (_device.UiHandler == null) + if (_device.UIHandler == null) { Logger.Error?.Print(LogClass.ServiceAm, "GUI Handler is not set, software keyboard applet will not work properly"); } else { // Create a text handler that converts keyboard strokes to strings. - _dynamicTextInputHandler = _device.UiHandler.CreateDynamicTextInputHandler(); + _dynamicTextInputHandler = _device.UIHandler.CreateDynamicTextInputHandler(); _dynamicTextInputHandler.TextChangedEvent += HandleTextChangedEvent; _dynamicTextInputHandler.KeyPressedEvent += HandleKeyPressedEvent; @@ -109,7 +109,7 @@ namespace Ryujinx.HLE.HOS.Applets _npads.NpadButtonDownEvent += HandleNpadButtonDownEvent; _npads.NpadButtonUpEvent += HandleNpadButtonUpEvent; - _keyboardRenderer = new SoftwareKeyboardRenderer(_device.UiHandler.HostUiTheme); + _keyboardRenderer = new SoftwareKeyboardRenderer(_device.UIHandler.HostUITheme); } return ResultCode.Success; @@ -203,13 +203,12 @@ namespace Ryujinx.HLE.HOS.Applets _keyboardForegroundConfig.StringLengthMax = 100; } - // If no GUI handler is set, fallback to default behavior. - if (_device.UiHandler == null) + if (_device.UIHandler == null) { Logger.Warning?.Print(LogClass.Application, "GUI Handler is not set. Falling back to default"); - // Prepare the SoftwareKeyboardUiArgs struct - var args = new SoftwareKeyboardUiArgs + // Prepare the SoftwareKeyboardUIArgs struct + var args = new SoftwareKeyboardUIArgs { KeyboardMode = _keyboardForegroundConfig.Mode, HeaderText = StripUnicodeControlCodes(_keyboardForegroundConfig.HeaderText), @@ -228,7 +227,7 @@ namespace Ryujinx.HLE.HOS.Applets else { // Call the configured GUI handler to get user's input. - var args = new SoftwareKeyboardUiArgs + var args = new SoftwareKeyboardUIArgs { KeyboardMode = _keyboardForegroundConfig.Mode, HeaderText = StripUnicodeControlCodes(_keyboardForegroundConfig.HeaderText), @@ -240,7 +239,7 @@ namespace Ryujinx.HLE.HOS.Applets StringLengthMax = _keyboardForegroundConfig.StringLengthMax, InitialText = initialText, }; - _device.UiHandler.DisplayInputDialog(args, inputText => + _device.UIHandler.DisplayInputDialog(args, inputText => { Console.WriteLine($"User entered: {inputText}"); diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRenderer.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRenderer.cs index f76cce295..239535ad5 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRenderer.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRenderer.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Memory; using System; using System.Threading; @@ -15,13 +15,13 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard private readonly object _stateLock = new(); - private readonly SoftwareKeyboardUiState _state = new(); + private readonly SoftwareKeyboardUIState _state = new(); private readonly SoftwareKeyboardRendererBase _renderer; private readonly TimedAction _textBoxBlinkTimedAction = new(); private readonly TimedAction _renderAction = new(); - public SoftwareKeyboardRenderer(IHostUiTheme uiTheme) + public SoftwareKeyboardRenderer(IHostUITheme uiTheme) { _renderer = new SoftwareKeyboardRendererBase(uiTheme); @@ -29,7 +29,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard StartRenderer(_renderAction, _renderer, _state, _stateLock); } - private static void StartTextBoxBlinker(TimedAction timedAction, SoftwareKeyboardUiState state, object stateLock) + private static void StartTextBoxBlinker(TimedAction timedAction, SoftwareKeyboardUIState state, object stateLock) { timedAction.Reset(() => { @@ -45,9 +45,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard }, TextBoxBlinkSleepMilliseconds); } - private static void StartRenderer(TimedAction timedAction, SoftwareKeyboardRendererBase renderer, SoftwareKeyboardUiState state, object stateLock) + private static void StartRenderer(TimedAction timedAction, SoftwareKeyboardRendererBase renderer, SoftwareKeyboardUIState state, object stateLock) { - SoftwareKeyboardUiState internalState = new(); + SoftwareKeyboardUIState internalState = new(); bool canCreateSurface = false; bool needsUpdate = true; @@ -112,11 +112,16 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard { // Update the parameters that were provided. _state.InputText = inputText ?? _state.InputText; - _state.CursorBegin = cursorBegin.GetValueOrDefault(_state.CursorBegin); - _state.CursorEnd = cursorEnd.GetValueOrDefault(_state.CursorEnd); + _state.CursorBegin = Math.Max(0, cursorBegin.GetValueOrDefault(_state.CursorBegin)); + _state.CursorEnd = Math.Min(cursorEnd.GetValueOrDefault(_state.CursorEnd), _state.InputText.Length); _state.OverwriteMode = overwriteMode.GetValueOrDefault(_state.OverwriteMode); _state.TypingEnabled = typingEnabled.GetValueOrDefault(_state.TypingEnabled); + var begin = _state.CursorBegin; + var end = _state.CursorEnd; + _state.CursorBegin = Math.Min(begin, end); + _state.CursorEnd = Math.Max(begin, end); + // Reset the cursor blink. _state.TextBoxBlinkCounter = 0; diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs index 43a5df758..6251c325b 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs @@ -1,14 +1,9 @@ -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Memory; -using SixLabors.Fonts; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Drawing.Processing; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; +using SkiaSharp; using System; using System.Diagnostics; using System.IO; -using System.Numerics; using System.Reflection; using System.Runtime.InteropServices; @@ -29,41 +24,42 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard private readonly object _bufferLock = new(); private RenderingSurfaceInfo _surfaceInfo = null; - private Image _surface = null; + private SKImageInfo _imageInfo; + private SKSurface _surface = null; private byte[] _bufferData = null; - private readonly Image _ryujinxLogo = null; - private readonly Image _padAcceptIcon = null; - private readonly Image _padCancelIcon = null; - private readonly Image _keyModeIcon = null; + private readonly SKBitmap _ryujinxLogo = null; + private readonly SKBitmap _padAcceptIcon = null; + private readonly SKBitmap _padCancelIcon = null; + private readonly SKBitmap _keyModeIcon = null; private readonly float _textBoxOutlineWidth; private readonly float _padPressedPenWidth; - private readonly Color _textNormalColor; - private readonly Color _textSelectedColor; - private readonly Color _textOverCursorColor; + private readonly SKColor _textNormalColor; + private readonly SKColor _textSelectedColor; + private readonly SKColor _textOverCursorColor; - private readonly IBrush _panelBrush; - private readonly IBrush _disabledBrush; - private readonly IBrush _cursorBrush; - private readonly IBrush _selectionBoxBrush; + private readonly SKPaint _panelBrush; + private readonly SKPaint _disabledBrush; + private readonly SKPaint _cursorBrush; + private readonly SKPaint _selectionBoxBrush; - private readonly Pen _textBoxOutlinePen; - private readonly Pen _cursorPen; - private readonly Pen _selectionBoxPen; - private readonly Pen _padPressedPen; + private readonly SKPaint _textBoxOutlinePen; + private readonly SKPaint _cursorPen; + private readonly SKPaint _selectionBoxPen; + private readonly SKPaint _padPressedPen; private readonly int _inputTextFontSize; - private Font _messageFont; - private Font _inputTextFont; - private Font _labelsTextFont; + private SKFont _messageFont; + private SKFont _inputTextFont; + private SKFont _labelsTextFont; - private RectangleF _panelRectangle; - private Point _logoPosition; + private SKRect _panelRectangle; + private SKPoint _logoPosition; private float _messagePositionY; - public SoftwareKeyboardRendererBase(IHostUiTheme uiTheme) + public SoftwareKeyboardRendererBase(IHostUITheme uiTheme) { int ryujinxLogoSize = 32; @@ -78,10 +74,10 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard _padCancelIcon = LoadResource(typeof(SoftwareKeyboardRendererBase).Assembly, padCancelIconPath, 0, 0); _keyModeIcon = LoadResource(typeof(SoftwareKeyboardRendererBase).Assembly, keyModeIconPath, 0, 0); - Color panelColor = ToColor(uiTheme.DefaultBackgroundColor, 255); - Color panelTransparentColor = ToColor(uiTheme.DefaultBackgroundColor, 150); - Color borderColor = ToColor(uiTheme.DefaultBorderColor); - Color selectionBackgroundColor = ToColor(uiTheme.SelectionBackgroundColor); + var panelColor = ToColor(uiTheme.DefaultBackgroundColor, 255); + var panelTransparentColor = ToColor(uiTheme.DefaultBackgroundColor, 150); + var borderColor = ToColor(uiTheme.DefaultBorderColor); + var selectionBackgroundColor = ToColor(uiTheme.SelectionBackgroundColor); _textNormalColor = ToColor(uiTheme.DefaultForegroundColor); _textSelectedColor = ToColor(uiTheme.SelectionForegroundColor); @@ -92,70 +88,36 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard _textBoxOutlineWidth = 2; _padPressedPenWidth = 2; - _panelBrush = new SolidBrush(panelColor); - _disabledBrush = new SolidBrush(panelTransparentColor); - _cursorBrush = new SolidBrush(_textNormalColor); - _selectionBoxBrush = new SolidBrush(selectionBackgroundColor); + _panelBrush = new SKPaint() + { + Color = panelColor, + IsAntialias = true + }; + _disabledBrush = new SKPaint() + { + Color = panelTransparentColor, + IsAntialias = true + }; + _cursorBrush = new SKPaint() { Color = _textNormalColor, IsAntialias = true }; + _selectionBoxBrush = new SKPaint() { Color = selectionBackgroundColor, IsAntialias = true }; - _textBoxOutlinePen = new Pen(borderColor, _textBoxOutlineWidth); - _cursorPen = new Pen(_textNormalColor, cursorWidth); - _selectionBoxPen = new Pen(selectionBackgroundColor, cursorWidth); - _padPressedPen = new Pen(borderColor, _padPressedPenWidth); + _textBoxOutlinePen = new SKPaint() + { + Color = borderColor, + StrokeWidth = _textBoxOutlineWidth, + IsStroke = true, + IsAntialias = true + }; + _cursorPen = new SKPaint() { Color = _textNormalColor, StrokeWidth = cursorWidth, IsStroke = true, IsAntialias = true }; + _selectionBoxPen = new SKPaint() { Color = selectionBackgroundColor, StrokeWidth = cursorWidth, IsStroke = true, IsAntialias = true }; + _padPressedPen = new SKPaint() { Color = borderColor, StrokeWidth = _padPressedPenWidth, IsStroke = true, IsAntialias = true }; _inputTextFontSize = 20; - CreateFonts(uiTheme.FontFamily); + // CreateFonts(uiTheme.FontFamily); } -private void CreateFonts(string uiThemeFontFamily) -{ - // Try a list of fonts in case any of them is not available in the system. - string[] availableFonts = { uiThemeFontFamily }; - - // If it's iOS, we'll want to use a more appropriate set of fonts. - if (OperatingSystem.IsIOS()) - { - availableFonts = new string[] { - "SF Pro", - "New York", - "Helvetica Neue", - "Avenir" - }; - } - else - { - // Fallback for other platforms (e.g., Android, Windows, etc.) - availableFonts = new string[] { - uiThemeFontFamily, - "Liberation Sans", - "FreeSans", - "DejaVu Sans", - "Lucida Grande" - }; - } - - // Try to create the fonts with the selected font families - foreach (string fontFamily in availableFonts) - { - try - { - _messageFont = SystemFonts.CreateFont(fontFamily, 26, FontStyle.Regular); - _inputTextFont = SystemFonts.CreateFont(fontFamily, _inputTextFontSize, FontStyle.Regular); - _labelsTextFont = SystemFonts.CreateFont(fontFamily, 24, FontStyle.Regular); - - return; - } - catch - { - // If the font creation fails, try the next font family - } - } - - throw new Exception($"None of these fonts were found in the system: {String.Join(", ", availableFonts)}!"); -} - - - private static Color ToColor(ThemeColor color, byte? overrideAlpha = null, bool flipRgb = false) + private static SKColor ToColor(ThemeColor color, byte? overrideAlpha = null, bool flipRgb = false) { var a = (byte)(color.A * 255); var r = (byte)(color.R * 255); @@ -169,34 +131,33 @@ private void CreateFonts(string uiThemeFontFamily) b = (byte)(255 - b); } - return Color.FromRgba(r, g, b, overrideAlpha.GetValueOrDefault(a)); + return new SKColor(r, g, b, overrideAlpha.GetValueOrDefault(a)); } - private static Image LoadResource(Assembly assembly, string resourcePath, int newWidth, int newHeight) + private static SKBitmap LoadResource(Assembly assembly, string resourcePath, int newWidth, int newHeight) { Stream resourceStream = assembly.GetManifestResourceStream(resourcePath); return LoadResource(resourceStream, newWidth, newHeight); } - private static Image LoadResource(Stream resourceStream, int newWidth, int newHeight) + private static SKBitmap LoadResource(Stream resourceStream, int newWidth, int newHeight) { Debug.Assert(resourceStream != null); - var image = Image.Load(resourceStream); + var bitmap = SKBitmap.Decode(resourceStream); if (newHeight != 0 && newWidth != 0) { - image.Mutate(x => x.Resize(newWidth, newHeight, KnownResamplers.Lanczos3)); + var resized = bitmap.Resize(new SKImageInfo(newWidth, newHeight), SKFilterQuality.High); + if (resized != null) + { + bitmap.Dispose(); + bitmap = resized; + } } - return image; - } - - private static void SetGraphicsOptions(IImageProcessingContext context) - { - context.GetGraphicsOptions().Antialias = true; - context.GetShapeGraphicsOptions().GraphicsOptions.Antialias = true; + return bitmap; } private void DrawImmutableElements() @@ -205,65 +166,64 @@ private void CreateFonts(string uiThemeFontFamily) { return; } + var canvas = _surface.Canvas; - _surface.Mutate(context => - { - SetGraphicsOptions(context); + canvas.Clear(SKColors.Transparent); + canvas.DrawRect(_panelRectangle, _panelBrush); + canvas.DrawBitmap(_ryujinxLogo, _logoPosition); - context.Clear(Color.Transparent); - context.Fill(_panelBrush, _panelRectangle); - context.DrawImage(_ryujinxLogo, _logoPosition, 1); + float halfWidth = _panelRectangle.Width / 2; + float buttonsY = _panelRectangle.Top + 185; - float halfWidth = _panelRectangle.Width / 2; - float buttonsY = _panelRectangle.Y + 185; + SKPoint disableButtonPosition = new(halfWidth + 180, buttonsY); - PointF disableButtonPosition = new(halfWidth + 180, buttonsY); - - DrawControllerToggle(context, disableButtonPosition); - }); + DrawControllerToggle(canvas, disableButtonPosition); } - public void DrawMutableElements(SoftwareKeyboardUiState state) + public void DrawMutableElements(SoftwareKeyboardUIState state) { if (_surface == null) { return; } - _surface.Mutate(context => + using var paint = new SKPaint(_messageFont) { - var messageRectangle = MeasureString(MessageText, _messageFont); - float messagePositionX = (_panelRectangle.Width - messageRectangle.Width) / 2 - messageRectangle.X; - float messagePositionY = _messagePositionY - messageRectangle.Y; - var messagePosition = new PointF(messagePositionX, messagePositionY); - var messageBoundRectangle = new RectangleF(messagePositionX, messagePositionY, messageRectangle.Width, messageRectangle.Height); + Color = _textNormalColor, + IsAntialias = true + }; - SetGraphicsOptions(context); + var canvas = _surface.Canvas; + var messageRectangle = MeasureString(MessageText, paint); + float messagePositionX = (_panelRectangle.Width - messageRectangle.Width) / 2 - messageRectangle.Left; + float messagePositionY = _messagePositionY - messageRectangle.Top; + var messagePosition = new SKPoint(messagePositionX, messagePositionY); + var messageBoundRectangle = SKRect.Create(messagePositionX, messagePositionY, messageRectangle.Width, messageRectangle.Height); - context.Fill(_panelBrush, messageBoundRectangle); + canvas.DrawRect(messageBoundRectangle, _panelBrush); - context.DrawText(MessageText, _messageFont, _textNormalColor, messagePosition); + canvas.DrawText(MessageText, messagePosition.X, messagePosition.Y + _messageFont.Metrics.XHeight + _messageFont.Metrics.Descent, paint); - if (!state.TypingEnabled) - { - // Just draw a semi-transparent rectangle on top to fade the component with the background. - // TODO (caian): This will not work if one decides to add make background semi-transparent as well. + if (!state.TypingEnabled) + { + // Just draw a semi-transparent rectangle on top to fade the component with the background. + // TODO (caian): This will not work if one decides to add make background semi-transparent as well. - context.Fill(_disabledBrush, messageBoundRectangle); - } + canvas.DrawRect(messageBoundRectangle, _disabledBrush); + } - DrawTextBox(context, state); + DrawTextBox(canvas, state); - float halfWidth = _panelRectangle.Width / 2; - float buttonsY = _panelRectangle.Y + 185; + float halfWidth = _panelRectangle.Width / 2; + float buttonsY = _panelRectangle.Top + 185; - PointF acceptButtonPosition = new(halfWidth - 180, buttonsY); - PointF cancelButtonPosition = new(halfWidth, buttonsY); - PointF disableButtonPosition = new(halfWidth + 180, buttonsY); + SKPoint acceptButtonPosition = new(halfWidth - 180, buttonsY); + SKPoint cancelButtonPosition = new(halfWidth, buttonsY); + SKPoint disableButtonPosition = new(halfWidth + 180, buttonsY); + + DrawPadButton(canvas, acceptButtonPosition, _padAcceptIcon, AcceptText, state.AcceptPressed, state.ControllerEnabled); + DrawPadButton(canvas, cancelButtonPosition, _padCancelIcon, CancelText, state.CancelPressed, state.ControllerEnabled); - DrawPadButton(context, acceptButtonPosition, _padAcceptIcon, AcceptText, state.AcceptPressed, state.ControllerEnabled); - DrawPadButton(context, cancelButtonPosition, _padCancelIcon, CancelText, state.CancelPressed, state.ControllerEnabled); - }); } public void CreateSurface(RenderingSurfaceInfo surfaceInfo) @@ -286,7 +246,8 @@ private void CreateFonts(string uiThemeFontFamily) Debug.Assert(_surfaceInfo.Height <= totalHeight); Debug.Assert(_surfaceInfo.Pitch * _surfaceInfo.Height <= _surfaceInfo.Size); - _surface = new Image((int)totalWidth, (int)totalHeight); + _imageInfo = new SKImageInfo((int)totalWidth, (int)totalHeight, SKColorType.Rgba8888); + _surface = SKSurface.Create(_imageInfo); ComputeConstants(); DrawImmutableElements(); @@ -300,76 +261,81 @@ private void CreateFonts(string uiThemeFontFamily) int panelHeight = 240; int panelPositionY = totalHeight - panelHeight; - _panelRectangle = new RectangleF(0, panelPositionY, totalWidth, panelHeight); + _panelRectangle = SKRect.Create(0, panelPositionY, totalWidth, panelHeight); _messagePositionY = panelPositionY + 60; int logoPositionX = (totalWidth - _ryujinxLogo.Width) / 2; int logoPositionY = panelPositionY + 18; - _logoPosition = new Point(logoPositionX, logoPositionY); + _logoPosition = new SKPoint(logoPositionX, logoPositionY); } - private static RectangleF MeasureString(string text, Font font) + private static SKRect MeasureString(string text, SKPaint paint) { - RendererOptions options = new(font); + SKRect bounds = SKRect.Empty; if (text == "") { - FontRectangle emptyRectangle = TextMeasurer.Measure(" ", options); - - return new RectangleF(0, emptyRectangle.Y, 0, emptyRectangle.Height); + paint.MeasureText(" ", ref bounds); + } + else + { + paint.MeasureText(text, ref bounds); } - FontRectangle rectangle = TextMeasurer.Measure(text, options); - - return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); + return bounds; } - private static RectangleF MeasureString(ReadOnlySpan text, Font font) + private static SKRect MeasureString(ReadOnlySpan text, SKPaint paint) { - RendererOptions options = new(font); + SKRect bounds = SKRect.Empty; if (text == "") { - FontRectangle emptyRectangle = TextMeasurer.Measure(" ", options); - return new RectangleF(0, emptyRectangle.Y, 0, emptyRectangle.Height); + paint.MeasureText(" ", ref bounds); + } + else + { + paint.MeasureText(text, ref bounds); } - FontRectangle rectangle = TextMeasurer.Measure(text, options); - - return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); + return bounds; } - private void DrawTextBox(IImageProcessingContext context, SoftwareKeyboardUiState state) + private void DrawTextBox(SKCanvas canvas, SoftwareKeyboardUIState state) { - var inputTextRectangle = MeasureString(state.InputText, _inputTextFont); + using var textPaint = new SKPaint(_labelsTextFont) + { + IsAntialias = true, + Color = _textNormalColor + }; + var inputTextRectangle = MeasureString(state.InputText, textPaint); - float boxWidth = (int)(Math.Max(300, inputTextRectangle.Width + inputTextRectangle.X + 8)); + float boxWidth = (int)(Math.Max(300, inputTextRectangle.Width + inputTextRectangle.Left + 8)); float boxHeight = 32; - float boxY = _panelRectangle.Y + 110; + float boxY = _panelRectangle.Top + 110; float boxX = (int)((_panelRectangle.Width - boxWidth) / 2); - RectangleF boxRectangle = new(boxX, boxY, boxWidth, boxHeight); + SKRect boxRectangle = SKRect.Create(boxX, boxY, boxWidth, boxHeight); - RectangleF boundRectangle = new(_panelRectangle.X, boxY - _textBoxOutlineWidth, + SKRect boundRectangle = SKRect.Create(_panelRectangle.Left, boxY - _textBoxOutlineWidth, _panelRectangle.Width, boxHeight + 2 * _textBoxOutlineWidth); - context.Fill(_panelBrush, boundRectangle); + canvas.DrawRect(boundRectangle, _panelBrush); - context.Draw(_textBoxOutlinePen, boxRectangle); + canvas.DrawRect(boxRectangle, _textBoxOutlinePen); - float inputTextX = (_panelRectangle.Width - inputTextRectangle.Width) / 2 - inputTextRectangle.X; + float inputTextX = (_panelRectangle.Width - inputTextRectangle.Width) / 2 - inputTextRectangle.Left; float inputTextY = boxY + 5; - var inputTextPosition = new PointF(inputTextX, inputTextY); - - context.DrawText(state.InputText, _inputTextFont, _textNormalColor, inputTextPosition); + var inputTextPosition = new SKPoint(inputTextX, inputTextY); + canvas.DrawText(state.InputText, inputTextPosition.X, inputTextPosition.Y + (_labelsTextFont.Metrics.XHeight + _labelsTextFont.Metrics.Descent), textPaint); // Draw the cursor on top of the text and redraw the text with a different color if necessary. - Color cursorTextColor; - IBrush cursorBrush; - Pen cursorPen; + SKColor cursorTextColor; + SKPaint cursorBrush; + SKPaint cursorPen; float cursorPositionYTop = inputTextY + 1; float cursorPositionYBottom = cursorPositionYTop + _inputTextFontSize + 1; @@ -389,12 +355,12 @@ private void CreateFonts(string uiThemeFontFamily) ReadOnlySpan textUntilBegin = state.InputText.AsSpan(0, state.CursorBegin); ReadOnlySpan textUntilEnd = state.InputText.AsSpan(0, state.CursorEnd); - var selectionBeginRectangle = MeasureString(textUntilBegin, _inputTextFont); - var selectionEndRectangle = MeasureString(textUntilEnd, _inputTextFont); + var selectionBeginRectangle = MeasureString(textUntilBegin, textPaint); + var selectionEndRectangle = MeasureString(textUntilEnd, textPaint); cursorVisible = true; - cursorPositionXLeft = inputTextX + selectionBeginRectangle.Width + selectionBeginRectangle.X; - cursorPositionXRight = inputTextX + selectionEndRectangle.Width + selectionEndRectangle.X; + cursorPositionXLeft = inputTextX + selectionBeginRectangle.Width + selectionBeginRectangle.Left; + cursorPositionXRight = inputTextX + selectionEndRectangle.Width + selectionEndRectangle.Left; } else { @@ -408,10 +374,10 @@ private void CreateFonts(string uiThemeFontFamily) int cursorBegin = Math.Min(state.InputText.Length, state.CursorBegin); ReadOnlySpan textUntilCursor = state.InputText.AsSpan(0, cursorBegin); - var cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont); + var cursorTextRectangle = MeasureString(textUntilCursor, textPaint); cursorVisible = true; - cursorPositionXLeft = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X; + cursorPositionXLeft = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.Left; if (state.OverwriteMode) { @@ -420,8 +386,8 @@ private void CreateFonts(string uiThemeFontFamily) if (state.CursorBegin < state.InputText.Length) { textUntilCursor = state.InputText.AsSpan(0, cursorBegin + 1); - cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont); - cursorPositionXRight = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X; + cursorTextRectangle = MeasureString(textUntilCursor, textPaint); + cursorPositionXRight = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.Left; } else { @@ -448,29 +414,32 @@ private void CreateFonts(string uiThemeFontFamily) if (cursorWidth == 0) { - PointF[] points = { - new PointF(cursorPositionXLeft, cursorPositionYTop), - new PointF(cursorPositionXLeft, cursorPositionYBottom), - }; - - context.DrawLines(cursorPen, points); + canvas.DrawLine(new SKPoint(cursorPositionXLeft, cursorPositionYTop), + new SKPoint(cursorPositionXLeft, cursorPositionYBottom), + cursorPen); } else { - var cursorRectangle = new RectangleF(cursorPositionXLeft, cursorPositionYTop, cursorWidth, cursorHeight); + var cursorRectangle = SKRect.Create(cursorPositionXLeft, cursorPositionYTop, cursorWidth, cursorHeight); - context.Draw(cursorPen, cursorRectangle); - context.Fill(cursorBrush, cursorRectangle); + canvas.DrawRect(cursorRectangle, cursorPen); + canvas.DrawRect(cursorRectangle, cursorBrush); - Image textOverCursor = new((int)cursorRectangle.Width, (int)cursorRectangle.Height); - textOverCursor.Mutate(context => + using var textOverCursor = SKSurface.Create(new SKImageInfo((int)cursorRectangle.Width, (int)cursorRectangle.Height, SKColorType.Rgba8888)); + var textOverCanvas = textOverCursor.Canvas; + var textRelativePosition = new SKPoint(inputTextPosition.X - cursorRectangle.Left, inputTextPosition.Y - cursorRectangle.Top); + + using var cursorPaint = new SKPaint(_inputTextFont) { - var textRelativePosition = new PointF(inputTextPosition.X - cursorRectangle.X, inputTextPosition.Y - cursorRectangle.Y); - context.DrawText(state.InputText, _inputTextFont, cursorTextColor, textRelativePosition); - }); + Color = cursorTextColor, + IsAntialias = true + }; - var cursorPosition = new Point((int)cursorRectangle.X, (int)cursorRectangle.Y); - context.DrawImage(textOverCursor, cursorPosition, 1); + textOverCanvas.DrawText(state.InputText, textRelativePosition.X, textRelativePosition.Y + _inputTextFont.Metrics.XHeight + _inputTextFont.Metrics.Descent, cursorPaint); + + var cursorPosition = new SKPoint((int)cursorRectangle.Left, (int)cursorRectangle.Top); + textOverCursor.Flush(); + canvas.DrawSurface(textOverCursor, cursorPosition); } } else if (!state.TypingEnabled) @@ -478,25 +447,31 @@ private void CreateFonts(string uiThemeFontFamily) // Just draw a semi-transparent rectangle on top to fade the component with the background. // TODO (caian): This will not work if one decides to add make background semi-transparent as well. - context.Fill(_disabledBrush, boundRectangle); + canvas.DrawRect(boundRectangle, _disabledBrush); } } - private void DrawPadButton(IImageProcessingContext context, PointF point, Image icon, string label, bool pressed, bool enabled) + private void DrawPadButton(SKCanvas canvas, SKPoint point, SKBitmap icon, string label, bool pressed, bool enabled) { - // Use relative positions so we can center the the entire drawing later. + // Use relative positions so we can center the entire drawing later. float iconX = 0; float iconY = 0; float iconWidth = icon.Width; float iconHeight = icon.Height; - var labelRectangle = MeasureString(label, _labelsTextFont); + using var paint = new SKPaint(_labelsTextFont) + { + Color = _textNormalColor, + IsAntialias = true + }; - float labelPositionX = iconWidth + 8 - labelRectangle.X; + var labelRectangle = MeasureString(label, paint); + + float labelPositionX = iconWidth + 8 - labelRectangle.Left; float labelPositionY = 3; - float fullWidth = labelPositionX + labelRectangle.Width + labelRectangle.X; + float fullWidth = labelPositionX + labelRectangle.Width + labelRectangle.Left; float fullHeight = iconHeight; // Convert all relative positions into absolute. @@ -507,24 +482,24 @@ private void CreateFonts(string uiThemeFontFamily) iconX += originX; iconY += originY; - var iconPosition = new Point((int)iconX, (int)iconY); - var labelPosition = new PointF(labelPositionX + originX, labelPositionY + originY); + var iconPosition = new SKPoint((int)iconX, (int)iconY); + var labelPosition = new SKPoint(labelPositionX + originX, labelPositionY + originY); - var selectedRectangle = new RectangleF(originX - 2 * _padPressedPenWidth, originY - 2 * _padPressedPenWidth, + var selectedRectangle = SKRect.Create(originX - 2 * _padPressedPenWidth, originY - 2 * _padPressedPenWidth, fullWidth + 4 * _padPressedPenWidth, fullHeight + 4 * _padPressedPenWidth); - var boundRectangle = new RectangleF(originX, originY, fullWidth, fullHeight); + var boundRectangle = SKRect.Create(originX, originY, fullWidth, fullHeight); boundRectangle.Inflate(4 * _padPressedPenWidth, 4 * _padPressedPenWidth); - context.Fill(_panelBrush, boundRectangle); - context.DrawImage(icon, iconPosition, 1); - context.DrawText(label, _labelsTextFont, _textNormalColor, labelPosition); + canvas.DrawRect(boundRectangle, _panelBrush); + canvas.DrawBitmap(icon, iconPosition); + canvas.DrawText(label, labelPosition.X, labelPosition.Y + _labelsTextFont.Metrics.XHeight + _labelsTextFont.Metrics.Descent, paint); if (enabled) { if (pressed) { - context.Draw(_padPressedPen, selectedRectangle); + canvas.DrawRect(selectedRectangle, _padPressedPen); } } else @@ -532,21 +507,26 @@ private void CreateFonts(string uiThemeFontFamily) // Just draw a semi-transparent rectangle on top to fade the component with the background. // TODO (caian): This will not work if one decides to add make background semi-transparent as well. - context.Fill(_disabledBrush, boundRectangle); + canvas.DrawRect(boundRectangle, _disabledBrush); } } - private void DrawControllerToggle(IImageProcessingContext context, PointF point) + private void DrawControllerToggle(SKCanvas canvas, SKPoint point) { - var labelRectangle = MeasureString(ControllerToggleText, _labelsTextFont); + using var paint = new SKPaint(_labelsTextFont) + { + IsAntialias = true, + Color = _textNormalColor + }; + var labelRectangle = MeasureString(ControllerToggleText, paint); - // Use relative positions so we can center the the entire drawing later. + // Use relative positions so we can center the entire drawing later. float keyWidth = _keyModeIcon.Width; float keyHeight = _keyModeIcon.Height; - float labelPositionX = keyWidth + 8 - labelRectangle.X; - float labelPositionY = -labelRectangle.Y - 1; + float labelPositionX = keyWidth + 8 - labelRectangle.Left; + float labelPositionY = -labelRectangle.Top - 1; float keyX = 0; float keyY = (int)((labelPositionY + labelRectangle.Height - keyHeight) / 2); @@ -562,14 +542,14 @@ private void CreateFonts(string uiThemeFontFamily) keyX += originX; keyY += originY; - var labelPosition = new PointF(labelPositionX + originX, labelPositionY + originY); - var overlayPosition = new Point((int)keyX, (int)keyY); + var labelPosition = new SKPoint(labelPositionX + originX, labelPositionY + originY); + var overlayPosition = new SKPoint((int)keyX, (int)keyY); - context.DrawImage(_keyModeIcon, overlayPosition, 1); - context.DrawText(ControllerToggleText, _labelsTextFont, _textNormalColor, labelPosition); + canvas.DrawBitmap(_keyModeIcon, overlayPosition); + canvas.DrawText(ControllerToggleText, labelPosition.X, labelPosition.Y + _labelsTextFont.Metrics.XHeight, paint); } - public void CopyImageToBuffer() + public unsafe void CopyImageToBuffer() { lock (_bufferLock) { @@ -579,21 +559,20 @@ private void CreateFonts(string uiThemeFontFamily) } // Convert the pixel format used in the image to the one used in the Switch surface. + _surface.Flush(); - if (!_surface.TryGetSinglePixelSpan(out Span pixels)) + var buffer = new byte[_imageInfo.BytesSize]; + fixed (byte* bufferPtr = buffer) { - return; + if (!_surface.ReadPixels(_imageInfo, (nint)bufferPtr, _imageInfo.RowBytes, 0, 0)) + { + return; + } } - _bufferData = MemoryMarshal.AsBytes(pixels).ToArray(); - Span dataConvert = MemoryMarshal.Cast(_bufferData); + _bufferData = buffer; - Debug.Assert(_bufferData.Length == _surfaceInfo.Size); - - for (int i = 0; i < dataConvert.Length; i++) - { - dataConvert[i] = BitOperations.RotateRight(dataConvert[i], 8); - } + Debug.Assert(buffer.Length == _surfaceInfo.Size); } } diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiArgs.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIArgs.cs similarity index 90% rename from src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiArgs.cs rename to src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIArgs.cs index 52fa7ed85..854f04a3b 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiArgs.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIArgs.cs @@ -2,7 +2,7 @@ using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard; namespace Ryujinx.HLE.HOS.Applets { - public struct SoftwareKeyboardUiArgs + public struct SoftwareKeyboardUIArgs { public KeyboardMode KeyboardMode; public string HeaderText; diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiState.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIState.cs similarity index 89% rename from src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiState.cs rename to src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIState.cs index 608d51f32..6199ff666 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiState.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIState.cs @@ -1,11 +1,11 @@ -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard { /// /// TODO /// - internal class SoftwareKeyboardUiState + internal class SoftwareKeyboardUIState { public string InputText = ""; public int CursorBegin = 0; diff --git a/src/Ryujinx.HLE/HOS/ArmProcessContext.cs b/src/Ryujinx.HLE/HOS/ArmProcessContext.cs index 476e5d6a9..fde489ab7 100644 --- a/src/Ryujinx.HLE/HOS/ArmProcessContext.cs +++ b/src/Ryujinx.HLE/HOS/ArmProcessContext.cs @@ -57,6 +57,8 @@ namespace Ryujinx.HLE.HOS public void Execute(IExecutionContext context, ulong codeAddress) { + // We must wait until shader cache is loaded, among other things, before executing CPU code. + _gpuContext.WaitUntilGpuReady(); _cpuContext.Execute(context, codeAddress); } diff --git a/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs b/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs index 9fbe1e013..ae0e5742b 100644 --- a/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs +++ b/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs @@ -72,9 +72,10 @@ namespace Ryujinx.HLE.HOS AddressSpace addressSpace = null; - if ((mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe) && (MemoryBlock.GetPageSize() <= 0x1000)) + // We want to use host tracked mode if the host page size is > 4KB. + if ((mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe) && MemoryBlock.GetPageSize() <= 0x1000) { - if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, MemoryBlock.GetPageSize() == MemoryManagerHostMapped.PageSize, out addressSpace)) + if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, out addressSpace)) { Logger.Warning?.Print(LogClass.Cpu, "Address space creation failed, falling back to software page table"); @@ -93,7 +94,7 @@ namespace Ryujinx.HLE.HOS case MemoryManagerMode.HostMappedUnsafe: if (addressSpace == null) { - var memoryManagerHostTracked = new MemoryManagerHostTracked(context.Memory, addressSpaceSize, invalidAccessHandler); + var memoryManagerHostTracked = new MemoryManagerHostTracked(context.Memory, addressSpaceSize, mode == MemoryManagerMode.HostMappedUnsafe, invalidAccessHandler); processContext = new ArmProcessContext(pid, cpuEngine, _gpu, memoryManagerHostTracked, addressSpaceSize, for64Bit); } else diff --git a/src/Ryujinx.HLE/HOS/Horizon.cs b/src/Ryujinx.HLE/HOS/Horizon.cs index 1a402240f..64b08e309 100644 --- a/src/Ryujinx.HLE/HOS/Horizon.cs +++ b/src/Ryujinx.HLE/HOS/Horizon.cs @@ -4,12 +4,6 @@ using LibHac.Fs; using LibHac.Fs.Shim; using LibHac.FsSystem; using LibHac.Tools.FsSystem; -using Ryujinx.Audio; -using Ryujinx.Audio.Input; -using Ryujinx.Audio.Integration; -using Ryujinx.Audio.Output; -using Ryujinx.Audio.Renderer.Device; -using Ryujinx.Audio.Renderer.Server; using Ryujinx.Cpu; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Kernel; @@ -20,7 +14,6 @@ using Ryujinx.HLE.HOS.Services; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy; using Ryujinx.HLE.HOS.Services.Apm; -using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer; using Ryujinx.HLE.HOS.Services.Caps; using Ryujinx.HLE.HOS.Services.Mii; using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager; @@ -61,11 +54,6 @@ namespace Ryujinx.HLE.HOS internal ITickSource TickSource { get; } internal SurfaceFlinger SurfaceFlinger { get; private set; } - internal AudioManager AudioManager { get; private set; } - internal AudioOutputManager AudioOutputManager { get; private set; } - internal AudioInputManager AudioInputManager { get; private set; } - internal AudioRendererManager AudioRendererManager { get; private set; } - internal VirtualDeviceSessionRegistry AudioDeviceSessionRegistry { get; private set; } public SystemStateMgr State { get; private set; } @@ -79,8 +67,6 @@ namespace Ryujinx.HLE.HOS internal ServerBase SmServer { get; private set; } internal ServerBase BsdServer { get; private set; } - internal ServerBase AudRenServer { get; private set; } - internal ServerBase AudOutServer { get; private set; } internal ServerBase FsServer { get; private set; } internal ServerBase HidServer { get; private set; } internal ServerBase NvDrvServer { get; private set; } @@ -248,60 +234,9 @@ namespace Ryujinx.HLE.HOS HostSyncpoint = new NvHostSyncpt(device); SurfaceFlinger = new SurfaceFlinger(device); - - InitializeAudioRenderer(TickSource); - InitializeServices(); } - private void InitializeAudioRenderer(ITickSource tickSource) - { - AudioManager = new AudioManager(); - AudioOutputManager = new AudioOutputManager(); - AudioInputManager = new AudioInputManager(); - AudioRendererManager = new AudioRendererManager(tickSource); - AudioRendererManager.SetVolume(Device.Configuration.AudioVolume); - AudioDeviceSessionRegistry = new VirtualDeviceSessionRegistry(Device.AudioDeviceDriver); - - IWritableEvent[] audioOutputRegisterBufferEvents = new IWritableEvent[Constants.AudioOutSessionCountMax]; - - for (int i = 0; i < audioOutputRegisterBufferEvents.Length; i++) - { - KEvent registerBufferEvent = new(KernelContext); - - audioOutputRegisterBufferEvents[i] = new AudioKernelEvent(registerBufferEvent); - } - - AudioOutputManager.Initialize(Device.AudioDeviceDriver, audioOutputRegisterBufferEvents); - AudioOutputManager.SetVolume(Device.Configuration.AudioVolume); - - IWritableEvent[] audioInputRegisterBufferEvents = new IWritableEvent[Constants.AudioInSessionCountMax]; - - for (int i = 0; i < audioInputRegisterBufferEvents.Length; i++) - { - KEvent registerBufferEvent = new(KernelContext); - - audioInputRegisterBufferEvents[i] = new AudioKernelEvent(registerBufferEvent); - } - - AudioInputManager.Initialize(Device.AudioDeviceDriver, audioInputRegisterBufferEvents); - - IWritableEvent[] systemEvents = new IWritableEvent[Constants.AudioRendererSessionCountMax]; - - for (int i = 0; i < systemEvents.Length; i++) - { - KEvent systemEvent = new(KernelContext); - - systemEvents[i] = new AudioKernelEvent(systemEvent); - } - - AudioManager.Initialize(Device.AudioDeviceDriver.GetUpdateRequiredEvent(), AudioOutputManager.Update, AudioInputManager.Update); - - AudioRendererManager.Initialize(systemEvents, Device.AudioDeviceDriver); - - AudioManager.Start(); - } - - private void InitializeServices() + public void InitializeServices() { SmRegistry = new SmRegistry(); SmServer = new ServerBase(KernelContext, "SmServer", () => new IUserInterface(KernelContext, SmRegistry)); @@ -311,8 +246,6 @@ namespace Ryujinx.HLE.HOS SmServer.InitDone.WaitOne(); BsdServer = new ServerBase(KernelContext, "BsdServer"); - AudRenServer = new ServerBase(KernelContext, "AudioRendererServer"); - AudOutServer = new ServerBase(KernelContext, "AudioOutServer"); FsServer = new ServerBase(KernelContext, "FsServer"); HidServer = new ServerBase(KernelContext, "HidServer"); NvDrvServer = new ServerBase(KernelContext, "NvservicesServer"); @@ -330,7 +263,13 @@ namespace Ryujinx.HLE.HOS HorizonFsClient fsClient = new(this); ServiceTable = new ServiceTable(); - var services = ServiceTable.GetServices(new HorizonOptions(Device.Configuration.IgnoreMissingServices, LibHacHorizonManager.BcatClient, fsClient)); + var services = ServiceTable.GetServices(new HorizonOptions + (Device.Configuration.IgnoreMissingServices, + LibHacHorizonManager.BcatClient, + fsClient, + AccountManager, + Device.AudioDeviceDriver, + TickSource)); foreach (var service in services) { @@ -385,17 +324,6 @@ namespace Ryujinx.HLE.HOS } } - public void SetVolume(float volume) - { - AudioOutputManager.SetVolume(volume); - AudioRendererManager.SetVolume(volume); - } - - public float GetVolume() - { - return AudioOutputManager.GetVolume() == 0 ? AudioRendererManager.GetVolume() : AudioOutputManager.GetVolume(); - } - public void ReturnFocus() { AppletState.SetFocus(true); @@ -459,11 +387,7 @@ namespace Ryujinx.HLE.HOS // "Soft" stops AudioRenderer and AudioManager to avoid some sound between resume and stop. if (IsPaused) { - AudioManager.StopUpdates(); - TogglePauseEmulation(false); - - AudioRendererManager.StopSendingCommands(); } KProcess terminationProcess = new(KernelContext); @@ -514,12 +438,6 @@ namespace Ryujinx.HLE.HOS // This is safe as KThread that are likely to call ioctls are going to be terminated by the post handler hook on the SVC facade. INvDrvServices.Destroy(); - AudioManager.Dispose(); - AudioOutputManager.Dispose(); - AudioInputManager.Dispose(); - - AudioRendererManager.Dispose(); - if (LibHacHorizonManager.ApplicationClient != null) { LibHacHorizonManager.PmClient.Fs.UnregisterProgram(LibHacHorizonManager.ApplicationClient.Os.GetCurrentProcessId().Value).ThrowIfFailure(); diff --git a/src/Ryujinx.HLE/HOS/Kernel/Common/KSystemControl.cs b/src/Ryujinx.HLE/HOS/Kernel/Common/KSystemControl.cs index 10f0b6f78..3f194e0ed 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Common/KSystemControl.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Common/KSystemControl.cs @@ -28,8 +28,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Common MemoryArrange.MemoryArrange4GiBSystemDev or MemoryArrange.MemoryArrange6GiBAppletDev => 3285 * MiB, MemoryArrange.MemoryArrange4GiBAppletDev => 2048 * MiB, - MemoryArrange.MemoryArrange6GiB or - MemoryArrange.MemoryArrange8GiB => 4916 * MiB, + MemoryArrange.MemoryArrange6GiB => 4916 * MiB, + MemoryArrange.MemoryArrange8GiB => 6964 * MiB, _ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."), }; } @@ -42,8 +42,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Common MemoryArrange.MemoryArrange4GiBAppletDev => 1554 * MiB, MemoryArrange.MemoryArrange4GiBSystemDev => 448 * MiB, MemoryArrange.MemoryArrange6GiB => 562 * MiB, - MemoryArrange.MemoryArrange6GiBAppletDev or - MemoryArrange.MemoryArrange8GiB => 2193 * MiB, + MemoryArrange.MemoryArrange6GiBAppletDev => 2193 * MiB, + MemoryArrange.MemoryArrange8GiB => 562 * MiB, _ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."), }; } diff --git a/src/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs b/src/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs index 7e41a3f3a..3b4280855 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs @@ -570,7 +570,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc } else { - serverProcess.CpuMemory.Write(copyDst, clientProcess.CpuMemory.GetSpan(copySrc, (int)copySize)); + serverProcess.CpuMemory.Write(copyDst, clientProcess.CpuMemory.GetReadOnlySequence(copySrc, (int)copySize)); } if (clientResult != Result.Success) @@ -858,7 +858,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc } else { - clientProcess.CpuMemory.Write(copyDst, serverProcess.CpuMemory.GetSpan(copySrc, (int)copySize)); + clientProcess.CpuMemory.Write(copyDst, serverProcess.CpuMemory.GetReadOnlySequence(copySrc, (int)copySize)); } } diff --git a/src/Ryujinx.HLE/HOS/Kernel/Memory/AddressSpaceType.cs b/src/Ryujinx.HLE/HOS/Kernel/Memory/AddressSpaceType.cs deleted file mode 100644 index 8dfa4303f..000000000 --- a/src/Ryujinx.HLE/HOS/Kernel/Memory/AddressSpaceType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.HOS.Kernel.Memory -{ - enum AddressSpaceType - { - Addr32Bits = 0, - Addr36Bits = 1, - Addr32BitsNoMap = 2, - Addr39Bits = 3, - } -} diff --git a/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs b/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs index 4c8858bb0..e62bfb353 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs @@ -2,6 +2,7 @@ using Ryujinx.Horizon.Common; using Ryujinx.Memory; using Ryujinx.Memory.Range; using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; @@ -11,7 +12,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory { private readonly IVirtualMemoryManager _cpuMemory; - protected override bool Supports4KBPages => _cpuMemory.Supports4KBPages; + protected override bool UsesPrivateAllocations => _cpuMemory.UsesPrivateAllocations; public KPageTable(KernelContext context, IVirtualMemoryManager cpuMemory, ulong reservedAddressSpaceSize) : base(context, reservedAddressSpaceSize) { @@ -34,6 +35,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } } + /// + protected override ReadOnlySequence GetReadOnlySequence(ulong va, int size) + { + return _cpuMemory.GetReadOnlySequence(va, size); + } + /// protected override ReadOnlySpan GetSpan(ulong va, int size) { @@ -119,7 +126,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory Context.MemoryManager.IncrementPagesReferenceCount(srcPa, pagesCount); } - if (shouldFillPages && (Supports4KBPages || !flags.HasFlag(MemoryMapFlags.Private) || fillValue != 0)) + if (shouldFillPages && (!OperatingSystem.IsIOS() || !flags.HasFlag(MemoryMapFlags.Private) || fillValue != 0)) { _cpuMemory.Fill(dstVa, size, fillValue); } @@ -149,7 +156,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory _cpuMemory.Map(currentVa, addr, size, flags); - if (shouldFillPages && (Supports4KBPages || !flags.HasFlag(MemoryMapFlags.Private) || fillValue != 0)) + if (shouldFillPages && (!OperatingSystem.IsIOS() || !flags.HasFlag(MemoryMapFlags.Private) || fillValue != 0)) { _cpuMemory.Fill(currentVa, size, fillValue); } @@ -247,6 +254,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory _cpuMemory.SignalMemoryTracking(va, size, write); } + /// + protected override void Write(ulong va, ReadOnlySequence data) + { + _cpuMemory.Write(va, data); + } + /// protected override void Write(ulong va, ReadOnlySpan data) { diff --git a/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs b/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs index b065e9c58..bf2bbb97b 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs @@ -5,6 +5,7 @@ using Ryujinx.Horizon.Common; using Ryujinx.Memory; using Ryujinx.Memory.Range; using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; @@ -32,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory private const int MaxBlocksNeededForInsertion = 2; protected readonly KernelContext Context; - protected virtual bool Supports4KBPages => true; + protected virtual bool UsesPrivateAllocations => false; public ulong AddrSpaceStart { get; private set; } public ulong AddrSpaceEnd { get; private set; } @@ -57,11 +58,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory public ulong AslrRegionStart { get; private set; } public ulong AslrRegionEnd { get; private set; } -#pragma warning disable IDE0052 // Remove unread private member private ulong _heapCapacity; -#pragma warning restore IDE0052 public ulong PhysicalMemoryUsage { get; private set; } + public ulong AliasRegionExtraSize { get; private set; } private readonly KMemoryBlockManager _blockManager; @@ -97,30 +97,21 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory _reservedAddressSpaceSize = reservedAddressSpaceSize; } - private static readonly int[] _addrSpaceSizes = { 32, 36, 32, 39 }; - public Result InitializeForProcess( - AddressSpaceType addrSpaceType, - bool aslrEnabled, + ProcessCreationFlags flags, bool fromBack, MemoryRegion memRegion, ulong address, ulong size, KMemoryBlockSlabManager slabManager) { - if ((uint)addrSpaceType > (uint)AddressSpaceType.Addr39Bits) - { - throw new ArgumentException($"AddressSpaceType bigger than {(uint)AddressSpaceType.Addr39Bits}: {(uint)addrSpaceType}", nameof(addrSpaceType)); - } - _contextId = Context.ContextIdManager.GetId(); ulong addrSpaceBase = 0; - ulong addrSpaceSize = 1UL << _addrSpaceSizes[(int)addrSpaceType]; + ulong addrSpaceSize = 1UL << GetAddressSpaceWidth(flags); Result result = CreateUserAddressSpace( - addrSpaceType, - aslrEnabled, + flags, fromBack, addrSpaceBase, addrSpaceSize, @@ -137,6 +128,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return result; } + private static int GetAddressSpaceWidth(ProcessCreationFlags flags) + { + switch (flags & ProcessCreationFlags.AddressSpaceMask) + { + case ProcessCreationFlags.AddressSpace32Bit: + case ProcessCreationFlags.AddressSpace32BitWithoutAlias: + return 32; + case ProcessCreationFlags.AddressSpace64BitDeprecated: + return 36; + case ProcessCreationFlags.AddressSpace64Bit: + return 39; + } + + throw new ArgumentException($"Invalid process flags {flags}", nameof(flags)); + } + private struct Region { public ulong Start; @@ -146,8 +153,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } private Result CreateUserAddressSpace( - AddressSpaceType addrSpaceType, - bool aslrEnabled, + ProcessCreationFlags flags, bool fromBack, ulong addrSpaceStart, ulong addrSpaceEnd, @@ -167,9 +173,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong stackAndTlsIoStart; ulong stackAndTlsIoEnd; - switch (addrSpaceType) + AliasRegionExtraSize = 0; + + switch (flags & ProcessCreationFlags.AddressSpaceMask) { - case AddressSpaceType.Addr32Bits: + case ProcessCreationFlags.AddressSpace32Bit: aliasRegion.Size = 0x40000000; heapRegion.Size = 0x40000000; stackRegion.Size = 0; @@ -182,7 +190,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory stackAndTlsIoEnd = 0x40000000; break; - case AddressSpaceType.Addr36Bits: + case ProcessCreationFlags.AddressSpace64BitDeprecated: aliasRegion.Size = 0x180000000; heapRegion.Size = 0x180000000; stackRegion.Size = 0; @@ -195,7 +203,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory stackAndTlsIoEnd = 0x80000000; break; - case AddressSpaceType.Addr32BitsNoMap: + case ProcessCreationFlags.AddressSpace32BitWithoutAlias: aliasRegion.Size = 0; heapRegion.Size = 0x80000000; stackRegion.Size = 0; @@ -208,7 +216,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory stackAndTlsIoEnd = 0x40000000; break; - case AddressSpaceType.Addr39Bits: + case ProcessCreationFlags.AddressSpace64Bit: if (_reservedAddressSpaceSize < addrSpaceEnd) { int addressSpaceWidth = (int)ulong.Log2(_reservedAddressSpaceSize); @@ -217,8 +225,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory heapRegion.Size = 0x180000000; stackRegion.Size = 1UL << (addressSpaceWidth - 8); tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3); - CodeRegionStart = BitUtils.AlignDown(address, RegionAlignment); - codeRegionSize = BitUtils.AlignUp(endAddr, RegionAlignment) - CodeRegionStart; + CodeRegionStart = BitUtils.AlignDown(address, RegionAlignment); + codeRegionSize = BitUtils.AlignUp(endAddr, RegionAlignment) - CodeRegionStart; stackAndTlsIoStart = 0; stackAndTlsIoEnd = 0; AslrRegionStart = 0x8000000; @@ -238,9 +246,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory stackAndTlsIoStart = 0; stackAndTlsIoEnd = 0; } + + if (flags.HasFlag(ProcessCreationFlags.EnableAliasRegionExtraSize)) + { + AliasRegionExtraSize = addrSpaceEnd / 8; + aliasRegion.Size += AliasRegionExtraSize; + } break; + default: - throw new ArgumentException($"AddressSpaceType bigger than {(uint)AddressSpaceType.Addr39Bits}: {(uint)addrSpaceType}", nameof(addrSpaceType)); + throw new ArgumentException($"Invalid process flags {flags}", nameof(flags)); } CodeRegionEnd = CodeRegionStart + codeRegionSize; @@ -265,6 +280,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong aslrMaxOffset = mapAvailableSize - mapTotalSize; + bool aslrEnabled = flags.HasFlag(ProcessCreationFlags.EnableAslr); + _aslrEnabled = aslrEnabled; AddrSpaceStart = addrSpaceStart; @@ -673,9 +690,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory MemoryState.UnmapProcessCodeMemoryAllowed, KMemoryPermission.None, KMemoryPermission.None, - MemoryAttribute.Mask, + MemoryAttribute.Mask & ~MemoryAttribute.PermissionLocked, MemoryAttribute.None, - MemoryAttribute.IpcAndDeviceMapped | MemoryAttribute.PermissionLocked, + MemoryAttribute.IpcAndDeviceMapped, out MemoryState state, out _, out _); @@ -724,7 +741,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory { address = 0; - if (size > HeapRegionEnd - HeapRegionStart) + if (size > HeapRegionEnd - HeapRegionStart || size > _heapCapacity) { return KernelResult.OutOfMemory; } @@ -1568,7 +1585,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory while (size > 0) { - ulong copySize = 0x100000; // Copy chunck size. Any value will do, moderate sizes are recommended. + ulong copySize = int.MaxValue; if (copySize > size) { @@ -1577,11 +1594,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory if (toServer) { - currentProcess.CpuMemory.Write(serverAddress, GetSpan(clientAddress, (int)copySize)); + currentProcess.CpuMemory.Write(serverAddress, GetReadOnlySequence(clientAddress, (int)copySize)); } else { - Write(clientAddress, currentProcess.CpuMemory.GetSpan(serverAddress, (int)copySize)); + Write(clientAddress, currentProcess.CpuMemory.GetReadOnlySequence(serverAddress, (int)copySize)); } serverAddress += copySize; @@ -1911,9 +1928,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory Context.Memory.Fill(GetDramAddressFromPa(dstFirstPagePa), unusedSizeBefore, (byte)_ipcFillValue); ulong copySize = addressRounded <= endAddr ? addressRounded - address : size; - var data = srcPageTable.GetSpan(addressTruncated + unusedSizeBefore, (int)copySize); + var data = srcPageTable.GetReadOnlySequence(addressTruncated + unusedSizeBefore, (int)copySize); - Context.Memory.Write(GetDramAddressFromPa(dstFirstPagePa + unusedSizeBefore), data); + ((IWritableBlock)Context.Memory).Write(GetDramAddressFromPa(dstFirstPagePa + unusedSizeBefore), data); firstPageFillAddress += unusedSizeBefore + copySize; @@ -1947,17 +1964,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory Result result; - if (srcPageTable.Supports4KBPages) + if (srcPageTable.UsesPrivateAllocations) + { + result = MapForeign(srcPageTable.GetHostRegions(addressRounded, alignedSize), currentVa, alignedSize); + } + else { KPageList pageList = new(); srcPageTable.GetPhysicalRegions(addressRounded, alignedSize, pageList); result = MapPages(currentVa, pageList, permission, MemoryMapFlags.None); } - else - { - result = MapForeign(srcPageTable.GetHostRegions(addressRounded, alignedSize), currentVa, alignedSize); - } if (result != Result.Success) { @@ -1977,9 +1994,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory if (send) { ulong copySize = endAddr - endAddrTruncated; - var data = srcPageTable.GetSpan(endAddrTruncated, (int)copySize); + var data = srcPageTable.GetReadOnlySequence(endAddrTruncated, (int)copySize); - Context.Memory.Write(GetDramAddressFromPa(dstLastPagePa), data); + ((IWritableBlock)Context.Memory).Write(GetDramAddressFromPa(dstLastPagePa), data); lastPageFillAddr += copySize; @@ -2943,6 +2960,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// Page list where the ranges will be added protected abstract void GetPhysicalRegions(ulong va, ulong size, KPageList pageList); + /// + /// Gets a read-only sequence of data from CPU mapped memory. + /// + /// + /// Allows reading non-contiguous memory without first copying it to a newly allocated single contiguous block. + /// + /// Virtual address of the data + /// Size of the data + /// A read-only sequence of the data + /// Throw for unhandled invalid or unmapped memory accesses + protected abstract ReadOnlySequence GetReadOnlySequence(ulong va, int size); + /// /// Gets a read-only span of data from CPU mapped memory. /// @@ -2952,7 +2981,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// /// Virtual address of the data /// Size of the data - /// True if read tracking is triggered on the span /// A read-only span of the data /// Throw for unhandled invalid or unmapped memory accesses protected abstract ReadOnlySpan GetSpan(ulong va, int size); @@ -3060,6 +3088,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// Size of the region protected abstract void SignalMemoryTracking(ulong va, ulong size, bool write); + /// + /// Writes data to CPU mapped memory, with write tracking. + /// + /// Virtual address to write the data into + /// Data to be written + /// Throw for unhandled invalid or unmapped memory accesses + protected abstract void Write(ulong va, ReadOnlySequence data); + /// /// Writes data to CPU mapped memory, with write tracking. /// diff --git a/src/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs b/src/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs index e302ee443..e593a7e13 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs @@ -2,7 +2,6 @@ using Ryujinx.Common; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.Horizon.Common; -using Ryujinx.Memory; namespace Ryujinx.HLE.HOS.Kernel.Memory { @@ -49,17 +48,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return KernelResult.InvalidPermission; } - // On platforms with page size > 4 KB, this can fail due to the address not being page aligned, - // we can return an error to force the application to retry with a different address. - - try - { - return memoryManager.MapPages(address, _pageList, MemoryState.SharedMemory, permission); - } - catch (InvalidMemoryRegionException) - { - return KernelResult.InvalidMemState; - } + return memoryManager.MapPages(address, _pageList, MemoryState.SharedMemory, permission); } public Result UnmapFromProcess(KPageTableBase memoryManager, ulong address, ulong size, KProcess process) diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs index 6008548be..422f03c64 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs @@ -126,8 +126,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process _contextFactory = contextFactory ?? new ProcessContextFactory(); _customThreadStart = customThreadStart; - AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift); - Pid = KernelContext.NewKipId(); if (Pid == 0 || Pid >= KernelConstants.InitialProcessId) @@ -137,8 +135,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process InitializeMemoryManager(creationInfo.Flags); - bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr); - ulong codeAddress = creationInfo.CodeAddress; ulong codeSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize; @@ -148,9 +144,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process : KernelContext.SmallMemoryBlockSlabManager; Result result = MemoryManager.InitializeForProcess( - addrSpaceType, - aslrEnabled, - !aslrEnabled, + creationInfo.Flags, + !creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr), memRegion, codeAddress, codeSize, @@ -234,8 +229,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process : KernelContext.SmallMemoryBlockSlabManager; } - AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift); - Pid = KernelContext.NewProcessId(); if (Pid == ulong.MaxValue || Pid < KernelConstants.InitialProcessId) @@ -245,16 +238,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process InitializeMemoryManager(creationInfo.Flags); - bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr); - ulong codeAddress = creationInfo.CodeAddress; ulong codeSize = codePagesCount * KPageTableBase.PageSize; Result result = MemoryManager.InitializeForProcess( - addrSpaceType, - aslrEnabled, - !aslrEnabled, + creationInfo.Flags, + !creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr), memRegion, codeAddress, codeSize, @@ -309,8 +299,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process private Result ParseProcessInfo(ProcessCreationInfo creationInfo) { // Ensure that the current kernel version is equal or above to the minimum required. - uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19; - uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf; + uint requiredKernelVersionMajor = Capabilities.KernelReleaseVersion >> 19; + uint requiredKernelVersionMinor = (Capabilities.KernelReleaseVersion >> 15) & 0xf; if (KernelContext.EnableVersionChecks) { @@ -519,12 +509,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return result; } -#pragma warning disable CA1822 // Mark member as static private void GenerateRandomEntropy() { // TODO. } -#pragma warning restore CA1822 public Result Start(int mainThreadPriority, ulong stackSize) { @@ -1182,5 +1170,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process // TODO return false; } + + public bool IsSvcPermitted(int svcId) + { + return Capabilities.IsSvcPermitted(svcId); + } } } diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs index 314aadf36..ebab67bb8 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs @@ -8,6 +8,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { class KProcessCapabilities { + private const int SvcMaskElementBits = 8; + public byte[] SvcAccessMask { get; } public byte[] IrqAccessMask { get; } @@ -22,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public KProcessCapabilities() { // length / number of bits of the underlying type - SvcAccessMask = new byte[KernelConstants.SupervisorCallCount / 8]; + SvcAccessMask = new byte[KernelConstants.SupervisorCallCount / SvcMaskElementBits]; IrqAccessMask = new byte[0x80]; } @@ -208,7 +210,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return KernelResult.MaximumExceeded; } - SvcAccessMask[svcId / 8] |= (byte)(1 << (svcId & 7)); + SvcAccessMask[svcId / SvcMaskElementBits] |= (byte)(1 << (svcId % SvcMaskElementBits)); } break; @@ -324,5 +326,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return mask << (int)min; } + + public bool IsSvcPermitted(int svcId) + { + int index = svcId / SvcMaskElementBits; + int mask = 1 << (svcId % SvcMaskElementBits); + + return (uint)svcId < KernelConstants.SupervisorCallCount && (SvcAccessMask[index] & mask) != 0; + } } } diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs index f0e43e023..1b62a29d4 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs @@ -29,6 +29,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process PoolPartitionMask = 0xf << PoolPartitionShift, OptimizeMemoryAllocation = 1 << 11, + DisableDeviceAddressSpaceMerge = 1 << 12, + EnableAliasRegionExtraSize = 1 << 13, All = Is64Bit | @@ -38,6 +40,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process IsApplication | DeprecatedUseSecureMemory | PoolPartitionMask | - OptimizeMemoryAllocation, + OptimizeMemoryAllocation | + DisableDeviceAddressSpaceMerge | + EnableAliasRegionExtraSize, } } diff --git a/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/ExternalEvent.cs b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/ExternalEvent.cs new file mode 100644 index 000000000..738d6b64a --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/ExternalEvent.cs @@ -0,0 +1,25 @@ +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Horizon.Common; + +namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall +{ + readonly struct ExternalEvent : IExternalEvent + { + private readonly KWritableEvent _writableEvent; + + public ExternalEvent(KWritableEvent writableEvent) + { + _writableEvent = writableEvent; + } + + public readonly void Signal() + { + _writableEvent.Signal(); + } + + public readonly void Clear() + { + _writableEvent.Clear(); + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/InfoType.cs b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/InfoType.cs index c0db82105..cbaae8780 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/InfoType.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/InfoType.cs @@ -21,14 +21,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall SystemResourceSizeTotal, SystemResourceSizeUsed, ProgramId, - // NOTE: Added in 4.0.0, removed in 5.0.0. - InitialProcessIdRange, + InitialProcessIdRange, // NOTE: Added in 4.0.0, removed in 5.0.0. UserExceptionContextAddress, TotalNonSystemMemorySize, UsedNonSystemMemorySize, IsApplication, FreeThreadCount, ThreadTickCount, + IsSvcPermitted, + IoRegionHint, + AliasRegionExtraSize, + MesosphereCurrentProcess = 65001, } } diff --git a/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs index b07f5194e..2f487243d 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs @@ -8,6 +8,7 @@ using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.Horizon.Common; +using Ryujinx.Memory; using System; using System.Buffers; using System.Threading; @@ -83,6 +84,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidSize; } + if (info.Flags.HasFlag(ProcessCreationFlags.EnableAliasRegionExtraSize)) + { + if ((info.Flags & ProcessCreationFlags.AddressSpaceMask) != ProcessCreationFlags.AddressSpace64Bit || + info.SystemResourcePagesCount <= 0) + { + return KernelResult.InvalidState; + } + + // TODO: Check that we are in debug mode. + } + if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) && !info.Flags.HasFlag(ProcessCreationFlags.IsApplication)) { @@ -138,7 +150,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return handleTable.GenerateHandle(process, out handle); } -#pragma warning disable CA1822 // Mark member as static public Result StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize) { KProcess process = KernelStatic.GetCurrentProcess().HandleTable.GetObject(handle); @@ -171,17 +182,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return Result.Success; } -#pragma warning restore CA1822 [Svc(0x5f)] -#pragma warning disable CA1822 // Mark member as static public Result FlushProcessDataCache(int processHandle, ulong address, ulong size) { // FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0. // As we don't support (and don't actually need) to flush the cache, this is stubbed. return Result.Success; } -#pragma warning restore CA1822 // IPC @@ -255,7 +263,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } [Svc(0x22)] -#pragma warning disable CA1822 // Mark member as static public Result SendSyncRequestWithUserBuffer( [PointerSized] ulong messagePtr, [PointerSized] ulong messageSize, @@ -305,7 +312,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } -#pragma warning restore CA1822 [Svc(0x23)] public Result SendAsyncRequestWithUserBuffer( @@ -615,7 +621,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } - ArrayPool.Shared.Return(syncObjsArray); + ArrayPool.Shared.Return(syncObjsArray, true); return result; } @@ -895,7 +901,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } [Svc(2)] -#pragma warning disable CA1822 // Mark member as static public Result SetMemoryPermission([PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission) { if (!PageAligned(address)) @@ -927,10 +932,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return currentProcess.MemoryManager.SetMemoryPermission(address, size, permission); } -#pragma warning restore CA1822 [Svc(3)] -#pragma warning disable CA1822 // Mark member as static public Result SetMemoryAttribute( [PointerSized] ulong address, [PointerSized] ulong size, @@ -978,10 +981,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } -#pragma warning restore CA1822 [Svc(4)] -#pragma warning disable CA1822 // Mark member as static public Result MapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size) { if (!PageAligned(src | dst)) @@ -1017,10 +1018,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return process.MemoryManager.Map(dst, src, size); } -#pragma warning restore CA1822 [Svc(5)] -#pragma warning disable CA1822 // Mark member as static public Result UnmapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size) { if (!PageAligned(src | dst)) @@ -1056,7 +1055,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return process.MemoryManager.Unmap(dst, src, size); } -#pragma warning restore CA1822 [Svc(6)] public Result QueryMemory([PointerSized] ulong infoPtr, [PointerSized] out ulong pageInfo, [PointerSized] ulong address) @@ -1073,7 +1071,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } -#pragma warning disable CA1822 // Mark member as static public Result QueryMemory(out MemoryInfo info, out ulong pageInfo, ulong address) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -1093,10 +1090,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return Result.Success; } -#pragma warning restore CA1822 [Svc(0x13)] -#pragma warning disable CA1822 // Mark member as static public Result MapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission) { if (!PageAligned(address)) @@ -1142,10 +1137,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall currentProcess, permission); } -#pragma warning restore CA1822 [Svc(0x14)] -#pragma warning disable CA1822 // Mark member as static public Result UnmapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size) { if (!PageAligned(address)) @@ -1185,7 +1178,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall size, currentProcess); } -#pragma warning restore CA1822 [Svc(0x15)] public Result CreateTransferMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission) @@ -1252,7 +1244,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } [Svc(0x51)] -#pragma warning disable CA1822 // Mark member as static public Result MapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission) { if (!PageAligned(address)) @@ -1298,10 +1289,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall currentProcess, permission); } -#pragma warning restore CA1822 [Svc(0x52)] -#pragma warning disable CA1822 // Mark member as static public Result UnmapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size) { if (!PageAligned(address)) @@ -1341,10 +1330,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall size, currentProcess); } -#pragma warning restore CA1822 [Svc(0x2c)] -#pragma warning disable CA1822 // Mark member as static public Result MapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size) { if (!PageAligned(address)) @@ -1379,10 +1366,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return process.MemoryManager.MapPhysicalMemory(address, size); } -#pragma warning restore CA1822 [Svc(0x2d)] -#pragma warning disable CA1822 // Mark member as static public Result UnmapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size) { if (!PageAligned(address)) @@ -1417,7 +1402,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return process.MemoryManager.UnmapPhysicalMemory(address, size); } -#pragma warning restore CA1822 [Svc(0x4b)] public Result CreateCodeMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size) @@ -1461,7 +1445,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } [Svc(0x4c)] -#pragma warning disable CA1822 // Mark member as static public Result ControlCodeMemory( int handle, CodeMemoryOperation op, @@ -1539,14 +1522,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidEnumValue; } } -#pragma warning restore CA1822 [Svc(0x73)] -#pragma warning disable CA1822 // Mark member as static public Result SetProcessMemoryPermission( int handle, - [PointerSized] ulong src, - [PointerSized] ulong size, + ulong src, + ulong size, KMemoryPermission permission) { if (!PageAligned(src)) @@ -1583,10 +1564,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return targetProcess.MemoryManager.SetProcessMemoryPermission(src, size, permission); } -#pragma warning restore CA1822 [Svc(0x74)] -#pragma warning disable CA1822 // Mark member as static public Result MapProcessMemory( [PointerSized] ulong dst, int handle, @@ -1642,10 +1621,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return dstProcess.MemoryManager.MapPages(dst, pageList, MemoryState.ProcessMemory, KMemoryPermission.ReadAndWrite); } -#pragma warning restore CA1822 [Svc(0x75)] -#pragma warning disable CA1822 // Mark member as static public Result UnmapProcessMemory( [PointerSized] ulong dst, int handle, @@ -1690,10 +1667,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return Result.Success; } -#pragma warning restore CA1822 [Svc(0x77)] -#pragma warning disable CA1822 // Mark member as static public Result MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size) { if (!PageAligned(dst) || !PageAligned(src)) @@ -1730,10 +1705,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size); } -#pragma warning restore CA1822 [Svc(0x78)] -#pragma warning disable CA1822 // Mark member as static public Result UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size) { if (!PageAligned(dst) || !PageAligned(src)) @@ -1770,7 +1743,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size); } -#pragma warning restore CA1822 private static bool PageAligned(ulong address) { @@ -1780,7 +1752,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall // System [Svc(0x7b)] -#pragma warning disable CA1822 // Mark member as static public Result TerminateProcess(int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -1809,15 +1780,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } -#pragma warning restore CA1822 [Svc(7)] -#pragma warning disable CA1822 // Mark member as static public void ExitProcess() { KernelStatic.GetCurrentProcess().TerminateCurrentProcess(); } -#pragma warning restore CA1822 [Svc(0x11)] public Result SignalEvent(int handle) @@ -1910,7 +1878,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } [Svc(0x26)] -#pragma warning disable CA1822 // Mark member as static public void Break(ulong reason) { KThread currentThread = KernelStatic.GetCurrentThread(); @@ -1936,10 +1903,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall Logger.Debug?.Print(LogClass.KernelSvc, "Debugger triggered."); } } -#pragma warning restore CA1822 [Svc(0x27)] -#pragma warning disable CA1822 // Mark member as static public void OutputDebugString([PointerSized] ulong strPtr, [PointerSized] ulong size) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -1948,7 +1913,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall Logger.Warning?.Print(LogClass.KernelSvc, str); } -#pragma warning restore CA1822 [Svc(0x29)] public Result GetInfo(out ulong value, InfoType id, int handle, long subId) @@ -1977,6 +1941,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall case InfoType.UsedNonSystemMemorySize: case InfoType.IsApplication: case InfoType.FreeThreadCount: + case InfoType.AliasRegionExtraSize: { if (subId != 0) { @@ -2005,22 +1970,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall value = process.MemoryManager.AliasRegionStart; break; case InfoType.AliasRegionSize: - value = (process.MemoryManager.AliasRegionEnd - - process.MemoryManager.AliasRegionStart); + value = process.MemoryManager.AliasRegionEnd - process.MemoryManager.AliasRegionStart; break; case InfoType.HeapRegionAddress: value = process.MemoryManager.HeapRegionStart; break; case InfoType.HeapRegionSize: - value = (process.MemoryManager.HeapRegionEnd - - process.MemoryManager.HeapRegionStart); + value = process.MemoryManager.HeapRegionEnd - process.MemoryManager.HeapRegionStart; break; case InfoType.TotalMemorySize: value = process.GetMemoryCapacity(); break; - case InfoType.UsedMemorySize: value = process.GetMemoryUsage(); break; @@ -2028,7 +1990,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall case InfoType.AslrRegionAddress: value = process.MemoryManager.GetAddrSpaceBaseAddr(); break; - case InfoType.AslrRegionSize: value = process.MemoryManager.GetAddrSpaceSize(); break; @@ -2037,20 +1998,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall value = process.MemoryManager.StackRegionStart; break; case InfoType.StackRegionSize: - value = (process.MemoryManager.StackRegionEnd - - process.MemoryManager.StackRegionStart); + value = process.MemoryManager.StackRegionEnd - process.MemoryManager.StackRegionStart; break; case InfoType.SystemResourceSizeTotal: value = process.PersonalMmHeapPagesCount * KPageTableBase.PageSize; break; - case InfoType.SystemResourceSizeUsed: if (process.PersonalMmHeapPagesCount != 0) { value = process.MemoryManager.GetMmUsedPages() * KPageTableBase.PageSize; } - break; case InfoType.ProgramId: @@ -2064,7 +2022,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall case InfoType.TotalNonSystemMemorySize: value = process.GetMemoryCapacityWithoutPersonalMmHeap(); break; - case InfoType.UsedNonSystemMemorySize: value = process.GetMemoryUsageWithoutPersonalMmHeap(); break; @@ -2083,10 +2040,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { value = 0; } + break; + case InfoType.AliasRegionExtraSize: + value = process.MemoryManager.AliasRegionExtraSize; break; } - break; } @@ -2103,7 +2062,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } value = KernelStatic.GetCurrentProcess().Debug ? 1UL : 0UL; - break; } @@ -2135,7 +2093,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall value = (uint)resLimHandle; } - break; } @@ -2154,7 +2111,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } value = (ulong)KTimeManager.ConvertHostTicksToTicks(_context.Schedulers[currentCore].TotalIdleTimeTicks); - break; } @@ -2173,7 +2129,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall KProcess currentProcess = KernelStatic.GetCurrentProcess(); value = currentProcess.RandomEntropy[subId]; - break; } @@ -2219,7 +2174,22 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall value = (ulong)KTimeManager.ConvertHostTicksToTicks(totalTimeRunning); } + break; + } + case InfoType.IsSvcPermitted: + { + if (handle != 0) + { + return KernelResult.InvalidHandle; + } + + if (subId != 0x36) + { + return KernelResult.InvalidCombination; + } + + value = KernelStatic.GetCurrentProcess().IsSvcPermitted((int)subId) ? 1UL : 0UL; break; } @@ -2230,7 +2200,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidHandle; } - if ((ulong)subId != 0) + if (subId != 0) { return KernelResult.InvalidCombination; } @@ -2245,8 +2215,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - value = (ulong)outHandle; - + value = (uint)outHandle; break; } @@ -2397,7 +2366,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } [Svc(0x30)] -#pragma warning disable CA1822 // Mark member as static public Result GetResourceLimitLimitValue(out long limitValue, int handle, LimitableResource resource) { limitValue = 0; @@ -2418,10 +2386,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return Result.Success; } -#pragma warning restore CA1822 [Svc(0x31)] -#pragma warning disable CA1822 // Mark member as static public Result GetResourceLimitCurrentValue(out long limitValue, int handle, LimitableResource resource) { limitValue = 0; @@ -2442,10 +2408,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return Result.Success; } -#pragma warning restore CA1822 [Svc(0x37)] -#pragma warning disable CA1822 // Mark member as static public Result GetResourceLimitPeakValue(out long peak, int handle, LimitableResource resource) { peak = 0; @@ -2466,7 +2430,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return Result.Success; } -#pragma warning restore CA1822 [Svc(0x7d)] public Result CreateResourceLimit(out int handle) @@ -2479,7 +2442,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } [Svc(0x7e)] -#pragma warning disable CA1822 // Mark member as static public Result SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue) { if (resource >= LimitableResource.Count) @@ -2496,7 +2458,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return resourceLimit.SetLimitValue(resource, limitValue); } -#pragma warning restore CA1822 // Thread @@ -2576,7 +2537,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } [Svc(9)] -#pragma warning disable CA1822 // Mark member as static public Result StartThread(int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -2603,17 +2563,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidHandle; } } -#pragma warning restore CA1822 [Svc(0xa)] -#pragma warning disable CA1822 // Mark member as static public void ExitThread() { KThread currentThread = KernelStatic.GetCurrentThread(); currentThread.Exit(); } -#pragma warning restore CA1822 [Svc(0xb)] public void SleepThread(long timeout) @@ -2640,7 +2597,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } [Svc(0xc)] -#pragma warning disable CA1822 // Mark member as static public Result GetThreadPriority(out int priority, int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -2660,10 +2616,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidHandle; } } -#pragma warning restore CA1822 [Svc(0xd)] -#pragma warning disable CA1822 // Mark member as static public Result SetThreadPriority(int handle, int priority) { // TODO: NPDM check. @@ -2681,10 +2635,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return Result.Success; } -#pragma warning restore CA1822 [Svc(0xe)] -#pragma warning disable CA1822 // Mark member as static public Result GetThreadCoreMask(out int preferredCore, out ulong affinityMask, int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -2706,10 +2658,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidHandle; } } -#pragma warning restore CA1822 [Svc(0xf)] -#pragma warning disable CA1822 // Mark member as static public Result SetThreadCoreMask(int handle, int preferredCore, ulong affinityMask) { KProcess currentProcess = KernelStatic.GetCurrentProcess(); @@ -2757,18 +2707,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return thread.SetCoreAndAffinityMask(preferredCore, affinityMask); } -#pragma warning restore CA1822 [Svc(0x10)] -#pragma warning disable CA1822 // Mark member as static public int GetCurrentProcessorNumber() { return KernelStatic.GetCurrentThread().CurrentCore; } -#pragma warning restore CA1822 [Svc(0x25)] -#pragma warning disable CA1822 // Mark member as static public Result GetThreadId(out ulong threadUid, int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -2788,10 +2734,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidHandle; } } -#pragma warning restore CA1822 [Svc(0x32)] -#pragma warning disable CA1822 // Mark member as static public Result SetThreadActivity(int handle, bool pause) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -2815,10 +2759,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return thread.SetActivity(pause); } -#pragma warning restore CA1822 [Svc(0x33)] -#pragma warning disable CA1822 // Mark member as static public Result GetThreadContext3([PointerSized] ulong address, int handle) { KProcess currentProcess = KernelStatic.GetCurrentProcess(); @@ -2852,7 +2794,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } -#pragma warning restore CA1822 // Thread synchronization @@ -2985,7 +2926,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } [Svc(0x1a)] -#pragma warning disable CA1822 // Mark member as static public Result ArbitrateLock(int ownerHandle, [PointerSized] ulong mutexAddress, int requesterHandle) { if (IsPointingInsideKernel(mutexAddress)) @@ -3002,10 +2942,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle); } -#pragma warning restore CA1822 [Svc(0x1b)] -#pragma warning disable CA1822 // Mark member as static public Result ArbitrateUnlock([PointerSized] ulong mutexAddress) { if (IsPointingInsideKernel(mutexAddress)) @@ -3022,10 +2960,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress); } -#pragma warning restore CA1822 [Svc(0x1c)] -#pragma warning disable CA1822 // Mark member as static public Result WaitProcessWideKeyAtomic( [PointerSized] ulong mutexAddress, [PointerSized] ulong condVarAddress, @@ -3055,10 +2991,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall handle, timeout); } -#pragma warning restore CA1822 [Svc(0x1d)] -#pragma warning disable CA1822 // Mark member as static public Result SignalProcessWideKey([PointerSized] ulong address, int count) { KProcess currentProcess = KernelStatic.GetCurrentProcess(); @@ -3067,10 +3001,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return Result.Success; } -#pragma warning restore CA1822 [Svc(0x34)] -#pragma warning disable CA1822 // Mark member as static public Result WaitForAddress([PointerSized] ulong address, ArbitrationType type, int value, long timeout) { if (IsPointingInsideKernel(address)) @@ -3101,10 +3033,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall _ => KernelResult.InvalidEnumValue, }; } -#pragma warning restore CA1822 [Svc(0x35)] -#pragma warning disable CA1822 // Mark member as static public Result SignalToAddress([PointerSized] ulong address, SignalType type, int value, int count) { if (IsPointingInsideKernel(address)) @@ -3130,17 +3060,45 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall _ => KernelResult.InvalidEnumValue, }; } -#pragma warning restore CA1822 [Svc(0x36)] -#pragma warning disable CA1822 // Mark member as static public Result SynchronizePreemptionState() { KernelStatic.GetCurrentThread().SynchronizePreemptionState(); return Result.Success; } -#pragma warning restore CA1822 + + // Not actual syscalls, used by HLE services and such. + + public IExternalEvent GetExternalEvent(int handle) + { + KWritableEvent writableEvent = KernelStatic.GetCurrentProcess().HandleTable.GetObject(handle); + + if (writableEvent == null) + { + return null; + } + + return new ExternalEvent(writableEvent); + } + + public IVirtualMemoryManager GetMemoryManagerByProcessHandle(int handle) + { + return KernelStatic.GetCurrentProcess().HandleTable.GetKProcess(handle).CpuMemory; + } + + public ulong GetTransferMemoryAddress(int handle) + { + KTransferMemory transferMemory = KernelStatic.GetCurrentProcess().HandleTable.GetObject(handle); + + if (transferMemory == null) + { + return 0; + } + + return transferMemory.Address; + } private static bool IsPointingInsideKernel(ulong address) { diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs index 905c61d66..8ef77902c 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs @@ -28,42 +28,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading private SchedulingState _state; - private AutoResetEvent _idleInterruptEvent; - private readonly object _idleInterruptEventLock; - private KThread _previousThread; private KThread _currentThread; - private readonly KThread _idleThread; + + private int _coreIdleLock; + private bool _idleSignalled = true; + private bool _idleActive = true; + private long _idleTimeRunning; public KThread PreviousThread => _previousThread; public KThread CurrentThread => _currentThread; public long LastContextSwitchTime { get; private set; } - public long TotalIdleTimeTicks => _idleThread.TotalTimeRunning; + public long TotalIdleTimeTicks => _idleTimeRunning; public KScheduler(KernelContext context, int coreId) { _context = context; _coreId = coreId; - _idleInterruptEvent = new AutoResetEvent(false); - _idleInterruptEventLock = new object(); - - KThread idleThread = CreateIdleThread(context, coreId); - - _currentThread = idleThread; - _idleThread = idleThread; - - idleThread.StartHostThread(); - idleThread.SchedulerWaitEvent.Set(); - } - - private KThread CreateIdleThread(KernelContext context, int cpuCore) - { - KThread idleThread = new(context); - - idleThread.Initialize(0UL, 0UL, 0UL, PrioritiesCount, cpuCore, null, ThreadType.Dummy, IdleThreadLoop); - - return idleThread; + _currentThread = null; } public static ulong SelectThreads(KernelContext context) @@ -237,39 +220,64 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading KThread threadToSignal = context.Schedulers[coreToSignal]._currentThread; // Request the thread running on that core to stop and reschedule, if we have one. - if (threadToSignal != context.Schedulers[coreToSignal]._idleThread) - { - threadToSignal.Context.RequestInterrupt(); - } + threadToSignal?.Context.RequestInterrupt(); // If the core is idle, ensure that the idle thread is awaken. - context.Schedulers[coreToSignal]._idleInterruptEvent.Set(); + context.Schedulers[coreToSignal].NotifyIdleThread(); scheduledCoresMask &= ~(1UL << coreToSignal); } } - private void IdleThreadLoop() + private void ActivateIdleThread() { - while (_context.Running) + while (Interlocked.CompareExchange(ref _coreIdleLock, 1, 0) != 0) + { + Thread.SpinWait(1); + } + + Thread.MemoryBarrier(); + + // Signals that idle thread is now active on this core. + _idleActive = true; + + TryLeaveIdle(); + + Interlocked.Exchange(ref _coreIdleLock, 0); + } + + private void NotifyIdleThread() + { + while (Interlocked.CompareExchange(ref _coreIdleLock, 1, 0) != 0) + { + Thread.SpinWait(1); + } + + Thread.MemoryBarrier(); + + // Signals that the idle core may be able to exit idle. + _idleSignalled = true; + + TryLeaveIdle(); + + Interlocked.Exchange(ref _coreIdleLock, 0); + } + + public void TryLeaveIdle() + { + if (_idleSignalled && _idleActive) { _state.NeedsScheduling = false; Thread.MemoryBarrier(); - KThread nextThread = PickNextThread(_state.SelectedThread); + KThread nextThread = PickNextThread(null, _state.SelectedThread); - if (_idleThread != nextThread) + if (nextThread != null) { - _idleThread.SchedulerWaitEvent.Reset(); - WaitHandle.SignalAndWait(nextThread.SchedulerWaitEvent, _idleThread.SchedulerWaitEvent); + _idleActive = false; + nextThread.SchedulerWaitEvent.Set(); } - _idleInterruptEvent.WaitOne(); - } - - lock (_idleInterruptEventLock) - { - _idleInterruptEvent.Dispose(); - _idleInterruptEvent = null; + _idleSignalled = false; } } @@ -292,20 +300,37 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading // Wake all the threads that might be waiting until this thread context is unlocked. for (int core = 0; core < CpuCoresCount; core++) { - _context.Schedulers[core]._idleInterruptEvent.Set(); + _context.Schedulers[core].NotifyIdleThread(); } - KThread nextThread = PickNextThread(selectedThread); + KThread nextThread = PickNextThread(KernelStatic.GetCurrentThread(), selectedThread); if (currentThread.Context.Running) { // Wait until this thread is scheduled again, and allow the next thread to run. - WaitHandle.SignalAndWait(nextThread.SchedulerWaitEvent, currentThread.SchedulerWaitEvent); + + if (nextThread == null) + { + ActivateIdleThread(); + currentThread.SchedulerWaitEvent.WaitOne(); + } + else + { + WaitHandle.SignalAndWait(nextThread.SchedulerWaitEvent, currentThread.SchedulerWaitEvent); + } } else { // Allow the next thread to run. - nextThread.SchedulerWaitEvent.Set(); + + if (nextThread == null) + { + ActivateIdleThread(); + } + else + { + nextThread.SchedulerWaitEvent.Set(); + } // We don't need to wait since the thread is exiting, however we need to // make sure this thread will never call the scheduler again, since it is @@ -319,7 +344,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading } } - private KThread PickNextThread(KThread selectedThread) + private KThread PickNextThread(KThread currentThread, KThread selectedThread) { while (true) { @@ -335,7 +360,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading // on the core, as the scheduled thread will handle the next switch. if (selectedThread.ThreadContext.Lock()) { - SwitchTo(selectedThread); + SwitchTo(currentThread, selectedThread); if (!_state.NeedsScheduling) { @@ -346,15 +371,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading } else { - return _idleThread; + return null; } } else { // The core is idle now, make sure that the idle thread can run // and switch the core when a thread is available. - SwitchTo(null); - return _idleThread; + SwitchTo(currentThread, null); + return null; } _state.NeedsScheduling = false; @@ -363,12 +388,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading } } - private void SwitchTo(KThread nextThread) + private void SwitchTo(KThread currentThread, KThread nextThread) { - KProcess currentProcess = KernelStatic.GetCurrentProcess(); - KThread currentThread = KernelStatic.GetCurrentThread(); - - nextThread ??= _idleThread; + KProcess currentProcess = currentThread?.Owner; if (currentThread != nextThread) { @@ -376,7 +398,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading long currentTicks = PerformanceCounter.ElapsedTicks; long ticksDelta = currentTicks - previousTicks; - currentThread.AddCpuTime(ticksDelta); + if (currentThread == null) + { + Interlocked.Add(ref _idleTimeRunning, ticksDelta); + } + else + { + currentThread.AddCpuTime(ticksDelta); + } currentProcess?.AddCpuTime(ticksDelta); @@ -386,13 +415,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading { _previousThread = !currentThread.TerminationRequested && currentThread.ActiveCore == _coreId ? currentThread : null; } - else if (currentThread == _idleThread) + else if (currentThread == null) { _previousThread = null; } } - if (nextThread.CurrentCore != _coreId) + if (nextThread != null && nextThread.CurrentCore != _coreId) { nextThread.CurrentCore = _coreId; } @@ -645,11 +674,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading public void Dispose() { - // Ensure that the idle thread is not blocked and can exit. - lock (_idleInterruptEventLock) - { - _idleInterruptEvent?.Set(); - } + // No resources to dispose for now. } } } diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs index b1af06b0d..21c2730bf 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs @@ -104,7 +104,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading } } - ArrayPool>.Shared.Return(syncNodesArray); + ArrayPool>.Shared.Return(syncNodesArray, true); } _context.CriticalSection.Leave(); diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs index 12383fb8a..835bf5d40 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs @@ -143,9 +143,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading PreferredCore = cpuCore; AffinityMask |= 1UL << cpuCore; - SchedFlags = type == ThreadType.Dummy - ? ThreadSchedState.Running - : ThreadSchedState.None; + SchedFlags = ThreadSchedState.None; ActiveCore = cpuCore; ObjSyncResult = KernelResult.ThreadNotStarted; @@ -1055,6 +1053,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading // If the thread is not schedulable, we want to just run or pause // it directly as we don't care about priority or the core it is // running on in this case. + if (SchedFlags == ThreadSchedState.Running) { _schedulerWaitEvent.Set(); diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/ThreadType.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/ThreadType.cs index 83093570b..e2dfd2ffb 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Threading/ThreadType.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/ThreadType.cs @@ -2,7 +2,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading { enum ThreadType { - Dummy, Kernel, Kernel2, User, diff --git a/src/Ryujinx.HLE/HOS/ModLoader.cs b/src/Ryujinx.HLE/HOS/ModLoader.cs index 834bc0595..ee179c929 100644 --- a/src/Ryujinx.HLE/HOS/ModLoader.cs +++ b/src/Ryujinx.HLE/HOS/ModLoader.cs @@ -7,6 +7,7 @@ using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.RomFs; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Mods; @@ -17,6 +18,7 @@ using System.Collections.Specialized; using System.Globalization; using System.IO; using System.Linq; +using LazyFile = Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy.LazyFile; using Path = System.IO.Path; namespace Ryujinx.HLE.HOS @@ -37,15 +39,19 @@ namespace Ryujinx.HLE.HOS private const string AmsNroPatchDir = "nro_patches"; private const string AmsKipPatchDir = "kip_patches"; + private static readonly ModMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + public readonly struct Mod where T : FileSystemInfo { public readonly string Name; public readonly T Path; + public readonly bool Enabled; - public Mod(string name, T path) + public Mod(string name, T path, bool enabled) { Name = name; Path = path; + Enabled = enabled; } } @@ -67,7 +73,7 @@ namespace Ryujinx.HLE.HOS } } - // Title dependent mods + // Application dependent mods public class ModCache { public List> RomfsContainers { get; } @@ -88,7 +94,7 @@ namespace Ryujinx.HLE.HOS } } - // Title independent mods + // Application independent mods private class PatchCache { public List> NsoPatches { get; } @@ -107,7 +113,7 @@ namespace Ryujinx.HLE.HOS } } - private readonly Dictionary _appMods; // key is TitleId + private readonly Dictionary _appMods; // key is ApplicationId private PatchCache _patches; private static readonly EnumerationOptions _dirEnumOptions; @@ -153,26 +159,32 @@ namespace Ryujinx.HLE.HOS return modsDir.FullName; } - private static DirectoryInfo FindTitleDir(DirectoryInfo contentsDir, string titleId) - => contentsDir.EnumerateDirectories(titleId, _dirEnumOptions).FirstOrDefault(); + private static DirectoryInfo FindApplicationDir(DirectoryInfo contentsDir, string applicationId) + => contentsDir.EnumerateDirectories(applicationId, _dirEnumOptions).FirstOrDefault(); - private static void AddModsFromDirectory(ModCache mods, DirectoryInfo dir, string titleId) + private static void AddModsFromDirectory(ModCache mods, DirectoryInfo dir, ModMetadata modMetadata) { System.Text.StringBuilder types = new(); foreach (var modDir in dir.EnumerateDirectories()) { types.Clear(); - Mod mod = new("", null); + Mod mod = new("", null, true); if (StrEquals(RomfsDir, modDir.Name)) { - mods.RomfsDirs.Add(mod = new Mod(dir.Name, modDir)); + var modData = modMetadata.Mods.Find(x => modDir.FullName.Contains(x.Path)); + var enabled = modData?.Enabled ?? true; + + mods.RomfsDirs.Add(mod = new Mod(dir.Name, modDir, enabled)); types.Append('R'); } else if (StrEquals(ExefsDir, modDir.Name)) { - mods.ExefsDirs.Add(mod = new Mod(dir.Name, modDir)); + var modData = modMetadata.Mods.Find(x => modDir.FullName.Contains(x.Path)); + var enabled = modData?.Enabled ?? true; + + mods.ExefsDirs.Add(mod = new Mod(dir.Name, modDir, enabled)); types.Append('E'); } else if (StrEquals(CheatDir, modDir.Name)) @@ -181,28 +193,28 @@ namespace Ryujinx.HLE.HOS } else { - AddModsFromDirectory(mods, modDir, titleId); + AddModsFromDirectory(mods, modDir, modMetadata); } if (types.Length > 0) { - Logger.Info?.Print(LogClass.ModLoader, $"Found mod '{mod.Name}' [{types}]"); + Logger.Info?.Print(LogClass.ModLoader, $"Found {(mod.Enabled ? "enabled" : "disabled")} mod '{mod.Name}' [{types}]"); } } } - public static string GetTitleDir(string modsBasePath, string titleId) + public static string GetApplicationDir(string modsBasePath, string applicationId) { var contentsDir = new DirectoryInfo(Path.Combine(modsBasePath, AmsContentsDir)); - var titleModsPath = FindTitleDir(contentsDir, titleId); + var applicationModsPath = FindApplicationDir(contentsDir, applicationId); - if (titleModsPath == null) + if (applicationModsPath == null) { - Logger.Info?.Print(LogClass.ModLoader, $"Creating mods directory for Title {titleId.ToUpper()}"); - titleModsPath = contentsDir.CreateSubdirectory(titleId); + Logger.Info?.Print(LogClass.ModLoader, $"Creating mods directory for Application {applicationId.ToUpper()}"); + applicationModsPath = contentsDir.CreateSubdirectory(applicationId); } - return titleModsPath.FullName; + return applicationModsPath.FullName; } // Static Query Methods @@ -238,47 +250,68 @@ namespace Ryujinx.HLE.HOS foreach (var modDir in patchDir.EnumerateDirectories()) { - patches.Add(new Mod(modDir.Name, modDir)); + patches.Add(new Mod(modDir.Name, modDir, true)); Logger.Info?.Print(LogClass.ModLoader, $"Found {type} patch '{modDir.Name}'"); } } - private static void QueryTitleDir(ModCache mods, DirectoryInfo titleDir) + private static void QueryApplicationDir(ModCache mods, DirectoryInfo applicationDir, ulong applicationId) { - if (!titleDir.Exists) + if (!applicationDir.Exists) { return; } - var fsFile = new FileInfo(Path.Combine(titleDir.FullName, RomfsContainer)); - if (fsFile.Exists) + string modJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationId.ToString("x16"), "mods.json"); + ModMetadata modMetadata = new(); + + if (File.Exists(modJsonPath)) { - mods.RomfsContainers.Add(new Mod($"<{titleDir.Name} RomFs>", fsFile)); + try + { + modMetadata = JsonHelper.DeserializeFromFile(modJsonPath, _serializerContext.ModMetadata); + } + catch + { + Logger.Warning?.Print(LogClass.ModLoader, $"Failed to deserialize mod data for {applicationId:X16} at {modJsonPath}"); + } } - fsFile = new FileInfo(Path.Combine(titleDir.FullName, ExefsContainer)); + var fsFile = new FileInfo(Path.Combine(applicationDir.FullName, RomfsContainer)); if (fsFile.Exists) { - mods.ExefsContainers.Add(new Mod($"<{titleDir.Name} ExeFs>", fsFile)); + var modData = modMetadata.Mods.Find(x => fsFile.FullName.Contains(x.Path)); + var enabled = modData == null || modData.Enabled; + + mods.RomfsContainers.Add(new Mod($"<{applicationDir.Name} RomFs>", fsFile, enabled)); } - AddModsFromDirectory(mods, titleDir, titleDir.Name); + fsFile = new FileInfo(Path.Combine(applicationDir.FullName, ExefsContainer)); + if (fsFile.Exists) + { + var modData = modMetadata.Mods.Find(x => fsFile.FullName.Contains(x.Path)); + var enabled = modData == null || modData.Enabled; + + mods.ExefsContainers.Add(new Mod($"<{applicationDir.Name} ExeFs>", fsFile, enabled)); + } + + AddModsFromDirectory(mods, applicationDir, modMetadata); } - public static void QueryContentsDir(ModCache mods, DirectoryInfo contentsDir, ulong titleId) + public static void QueryContentsDir(ModCache mods, DirectoryInfo contentsDir, ulong applicationId) { if (!contentsDir.Exists) { return; } - Logger.Info?.Print(LogClass.ModLoader, $"Searching mods for {((titleId & 0x1000) != 0 ? "DLC" : "Title")} {titleId:X16}"); + Logger.Info?.Print(LogClass.ModLoader, $"Searching mods for {((applicationId & 0x1000) != 0 ? "DLC" : "Application")} {applicationId:X16} in \"{contentsDir.FullName}\""); - var titleDir = FindTitleDir(contentsDir, $"{titleId:x16}"); + var applicationDir = FindApplicationDir(contentsDir, $"{applicationId:x16}"); - if (titleDir != null) + if (applicationDir != null) { - QueryTitleDir(mods, titleDir); + QueryApplicationDir(mods, applicationDir, applicationId); } } @@ -387,9 +420,9 @@ namespace Ryujinx.HLE.HOS { if (IsContentsDir(searchDir.Name)) { - foreach ((ulong titleId, ModCache cache) in modCaches) + foreach ((ulong applicationId, ModCache cache) in modCaches) { - QueryContentsDir(cache, searchDir, titleId); + QueryContentsDir(cache, searchDir, applicationId); } return true; @@ -410,7 +443,7 @@ namespace Ryujinx.HLE.HOS if (!searchDir.Exists) { Logger.Warning?.Print(LogClass.ModLoader, $"Mod Search Dir '{searchDir.FullName}' doesn't exist"); - continue; + return; } if (!TryQuery(searchDir, patches, modCaches)) @@ -425,21 +458,21 @@ namespace Ryujinx.HLE.HOS patches.Initialized = true; } - public void CollectMods(IEnumerable titles, params string[] searchDirPaths) + public void CollectMods(IEnumerable applications, params string[] searchDirPaths) { Clear(); - foreach (ulong titleId in titles) + foreach (ulong applicationId in applications) { - _appMods[titleId] = new ModCache(); + _appMods[applicationId] = new ModCache(); } CollectMods(_appMods, _patches, searchDirPaths); } - internal IStorage ApplyRomFsMods(ulong titleId, IStorage baseStorage) + internal IStorage ApplyRomFsMods(ulong applicationId, IStorage baseStorage) { - if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.RomfsDirs.Count + mods.RomfsContainers.Count == 0) + if (!_appMods.TryGetValue(applicationId, out ModCache mods) || mods.RomfsDirs.Count + mods.RomfsContainers.Count == 0) { return baseStorage; } @@ -448,14 +481,19 @@ namespace Ryujinx.HLE.HOS var builder = new RomFsBuilder(); int count = 0; - Logger.Info?.Print(LogClass.ModLoader, $"Applying RomFS mods for Title {titleId:X16}"); + Logger.Info?.Print(LogClass.ModLoader, $"Applying RomFS mods for Application {applicationId:X16}"); // Prioritize loose files first foreach (var mod in mods.RomfsDirs) { + if (!mod.Enabled) + { + continue; + } + using (IFileSystem fs = new LocalFileSystem(mod.Path.FullName)) { - AddFiles(fs, mod.Name, fileSet, builder); + AddFiles(fs, mod.Name, mod.Path.FullName, fileSet, builder); } count++; } @@ -463,10 +501,15 @@ namespace Ryujinx.HLE.HOS // Then files inside images foreach (var mod in mods.RomfsContainers) { - Logger.Info?.Print(LogClass.ModLoader, $"Found 'romfs.bin' for Title {titleId:X16}"); + if (!mod.Enabled) + { + continue; + } + + Logger.Info?.Print(LogClass.ModLoader, $"Found 'romfs.bin' for Application {applicationId:X16}"); using (IFileSystem fs = new RomFsFileSystem(mod.Path.OpenRead().AsStorage())) { - AddFiles(fs, mod.Name, fileSet, builder); + AddFiles(fs, mod.Name, mod.Path.FullName, fileSet, builder); } count++; } @@ -499,18 +542,18 @@ namespace Ryujinx.HLE.HOS return newStorage; } - private static void AddFiles(IFileSystem fs, string modName, ISet fileSet, RomFsBuilder builder) + private static void AddFiles(IFileSystem fs, string modName, string rootPath, ISet fileSet, RomFsBuilder builder) { foreach (var entry in fs.EnumerateEntries() + .AsParallel() .Where(f => f.Type == DirectoryEntryType.File) .OrderBy(f => f.FullPath, StringComparer.Ordinal)) { - using var file = new UniqueRef(); + var file = new LazyFile(entry.FullPath, rootPath, fs); - fs.OpenFile(ref file.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); if (fileSet.Add(entry.FullPath)) { - builder.AddFile(entry.FullPath, file.Release()); + builder.AddFile(entry.FullPath, file); } else { @@ -519,9 +562,9 @@ namespace Ryujinx.HLE.HOS } } - internal bool ReplaceExefsPartition(ulong titleId, ref IFileSystem exefs) + internal bool ReplaceExefsPartition(ulong applicationId, ref IFileSystem exefs) { - if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.ExefsContainers.Count == 0) + if (!_appMods.TryGetValue(applicationId, out ModCache mods) || mods.ExefsContainers.Count == 0) { return false; } @@ -549,7 +592,7 @@ namespace Ryujinx.HLE.HOS public bool Modified => (Stubs.Data | Replaces.Data) != 0; } - internal ModLoadResult ApplyExefsMods(ulong titleId, NsoExecutable[] nsos) + internal ModLoadResult ApplyExefsMods(ulong applicationId, NsoExecutable[] nsos) { ModLoadResult modLoadResult = new() { @@ -557,7 +600,7 @@ namespace Ryujinx.HLE.HOS Replaces = new BitVector32(), }; - if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.ExefsDirs.Count == 0) + if (!_appMods.TryGetValue(applicationId, out ModCache mods) || mods.ExefsDirs.Count == 0) { return modLoadResult; } @@ -571,6 +614,11 @@ namespace Ryujinx.HLE.HOS foreach (var mod in exeMods) { + if (!mod.Enabled) + { + continue; + } + for (int i = 0; i < ProcessConst.ExeFsPrefixes.Length; ++i) { var nsoName = ProcessConst.ExeFsPrefixes[i]; @@ -637,11 +685,11 @@ namespace Ryujinx.HLE.HOS ApplyProgramPatches(nroPatches, 0, nro); } - internal bool ApplyNsoPatches(ulong titleId, params IExecutable[] programs) + internal bool ApplyNsoPatches(ulong applicationId, params IExecutable[] programs) { IEnumerable> nsoMods = _patches.NsoPatches; - if (_appMods.TryGetValue(titleId, out ModCache mods)) + if (_appMods.TryGetValue(applicationId, out ModCache mods)) { nsoMods = nsoMods.Concat(mods.ExefsDirs); } @@ -651,7 +699,7 @@ namespace Ryujinx.HLE.HOS return ApplyProgramPatches(nsoMods, 0x100, programs); } - internal void LoadCheats(ulong titleId, ProcessTamperInfo tamperInfo, TamperMachine tamperMachine) + internal void LoadCheats(ulong applicationId, ProcessTamperInfo tamperInfo, TamperMachine tamperMachine) { if (tamperInfo?.BuildIds == null || tamperInfo.CodeAddresses == null) { @@ -660,9 +708,9 @@ namespace Ryujinx.HLE.HOS return; } - Logger.Info?.Print(LogClass.ModLoader, $"Build ids found for title {titleId:X16}:\n {String.Join("\n ", tamperInfo.BuildIds)}"); + Logger.Info?.Print(LogClass.ModLoader, $"Build ids found for application {applicationId:X16}:\n {String.Join("\n ", tamperInfo.BuildIds)}"); - if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.Cheats.Count == 0) + if (!_appMods.TryGetValue(applicationId, out ModCache mods) || mods.Cheats.Count == 0) { return; } @@ -687,12 +735,12 @@ namespace Ryujinx.HLE.HOS tamperMachine.InstallAtmosphereCheat(cheat.Name, cheatId, cheat.Instructions, tamperInfo, exeAddress); } - EnableCheats(titleId, tamperMachine); + EnableCheats(applicationId, tamperMachine); } - internal static void EnableCheats(ulong titleId, TamperMachine tamperMachine) + internal static void EnableCheats(ulong applicationId, TamperMachine tamperMachine) { - var contentDirectory = FindTitleDir(new DirectoryInfo(Path.Combine(GetModsBasePath(), AmsContentsDir)), $"{titleId:x16}"); + var contentDirectory = FindApplicationDir(new DirectoryInfo(Path.Combine(GetModsBasePath(), AmsContentsDir)), $"{applicationId:x16}"); string enabledCheatsPath = Path.Combine(contentDirectory.FullName, CheatDir, "enabled.txt"); if (File.Exists(enabledCheatsPath)) @@ -724,6 +772,11 @@ namespace Ryujinx.HLE.HOS // Collect patches foreach (var mod in mods) { + if (!mod.Enabled) + { + continue; + } + var patchDir = mod.Path; foreach (var patchFile in patchDir.EnumerateFiles()) { diff --git a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs index c13c81285..e88c738c9 100644 --- a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs @@ -4,6 +4,7 @@ using LibHac.Fs; using LibHac.Fs.Shim; using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Sdk.Account; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -11,7 +12,7 @@ using System.Linq; namespace Ryujinx.HLE.HOS.Services.Account.Acc { - public class AccountManager + public class AccountManager : IEmulatorAccountManager { public static readonly UserId DefaultUserId = new("00000000000000010000000000000000"); @@ -106,6 +107,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc _accountSaveDataManager.Save(_profiles); } + public void OpenUserOnlinePlay(Uid userId) + { + OpenUserOnlinePlay(new UserId((long)userId.Low, (long)userId.High)); + } + public void OpenUserOnlinePlay(UserId userId) { if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile)) @@ -127,6 +133,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc _accountSaveDataManager.Save(_profiles); } + public void CloseUserOnlinePlay(Uid userId) + { + CloseUserOnlinePlay(new UserId((long)userId.Low, (long)userId.High)); + } + public void CloseUserOnlinePlay(UserId userId) { if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile)) diff --git a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/ManagerServer.cs b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/ManagerServer.cs index 4c75d430f..75bad0e3f 100644 --- a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/ManagerServer.cs +++ b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/ManagerServer.cs @@ -1,10 +1,12 @@ +using Microsoft.IdentityModel.JsonWebTokens; using Microsoft.IdentityModel.Tokens; using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext; using System; -using System.IdentityModel.Tokens.Jwt; +using System.Collections.Generic; using System.Security.Cryptography; +using System.Security.Principal; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -20,6 +22,9 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService private readonly UserId _userId; #pragma warning restore IDE0052 + private byte[] _cachedTokenData; + private DateTime _cachedTokenExpiry; + public ManagerServer(UserId userId) { _userId = userId; @@ -37,11 +42,6 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService credentials.Key.KeyId = parameters.ToString(); - var header = new JwtHeader(credentials) - { - { "jku", "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com/1.0.0/certificates" }, - }; - byte[] rawUserId = new byte[0x10]; RandomNumberGenerator.Fill(rawUserId); @@ -51,23 +51,25 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService byte[] deviceAccountId = new byte[0x10]; RandomNumberGenerator.Fill(deviceId); - var payload = new JwtPayload + var descriptor = new SecurityTokenDescriptor { - { "sub", Convert.ToHexString(rawUserId).ToLower() }, - { "aud", "ed9e2f05d286f7b8" }, - { "di", Convert.ToHexString(deviceId).ToLower() }, - { "sn", "XAW10000000000" }, - { "bs:did", Convert.ToHexString(deviceAccountId).ToLower() }, - { "iss", "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com" }, - { "typ", "id_token" }, - { "iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds() }, - { "jti", Guid.NewGuid().ToString() }, - { "exp", (DateTimeOffset.UtcNow + TimeSpan.FromHours(3)).ToUnixTimeSeconds() }, + Subject = new GenericIdentity(Convert.ToHexString(rawUserId).ToLower()), + SigningCredentials = credentials, + Audience = "ed9e2f05d286f7b8", + Issuer = "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com", + TokenType = "id_token", + IssuedAt = DateTime.UtcNow, + Expires = DateTime.UtcNow + TimeSpan.FromHours(3), + Claims = new Dictionary + { + { "jku", "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com/1.0.0/certificates" }, + { "di", Convert.ToHexString(deviceId).ToLower() }, + { "sn", "XAW10000000000" }, + { "bs:did", Convert.ToHexString(deviceAccountId).ToLower() } + } }; - JwtSecurityToken securityToken = new(header, payload); - - return new JwtSecurityTokenHandler().WriteToken(securityToken); + return new JsonWebTokenHandler().CreateToken(descriptor); } public ResultCode CheckAvailability(ServiceCtx context) @@ -145,7 +147,13 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService } */ - byte[] tokenData = Encoding.ASCII.GetBytes(GenerateIdToken()); + if (_cachedTokenData == null || DateTime.UtcNow > _cachedTokenExpiry) + { + _cachedTokenExpiry = DateTime.UtcNow + TimeSpan.FromHours(3); + _cachedTokenData = Encoding.ASCII.GetBytes(GenerateIdToken()); + } + + byte[] tokenData = _cachedTokenData; context.Memory.Write(bufferPosition, tokenData); context.ResponseData.Write(tokenData.Length); diff --git a/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs index 271d00605..9a7fdcc16 100644 --- a/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs +++ b/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs @@ -97,7 +97,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati if (titleId == 0) { - context.Device.UiHandler.ExecuteProgram(context.Device, ProgramSpecifyKind.RestartProgram, titleId); + context.Device.UIHandler.ExecuteProgram(context.Device, ProgramSpecifyKind.RestartProgram, titleId); } else { @@ -524,7 +524,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati Logger.Stub?.PrintStub(LogClass.ServiceAm, new { kind, value }); - context.Device.UiHandler.ExecuteProgram(context.Device, kind, value); + context.Device.UIHandler.ExecuteProgram(context.Device, kind, value); return ResultCode.Success; } diff --git a/src/Ryujinx.HLE/HOS/Services/Arp/IReader.cs b/src/Ryujinx.HLE/HOS/Services/Arp/IReader.cs deleted file mode 100644 index 611310421..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Arp/IReader.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Arp -{ - [Service("arp:r")] - class IReader : IpcService - { - public IReader(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Arp/IWriter.cs b/src/Ryujinx.HLE/HOS/Services/Arp/IWriter.cs deleted file mode 100644 index 22d081b9b..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Arp/IWriter.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Arp -{ - [Service("arp:w")] - class IWriter : IpcService - { - public IWriter(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioIn.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioIn.cs deleted file mode 100644 index acf83f488..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioIn.cs +++ /dev/null @@ -1,108 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.Audio.Input; -using Ryujinx.Audio.Integration; -using Ryujinx.HLE.HOS.Kernel; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer; -using System; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioIn -{ - class AudioIn : IAudioIn - { - private readonly AudioInputSystem _system; - private readonly uint _processHandle; - private readonly KernelContext _kernelContext; - - public AudioIn(AudioInputSystem system, KernelContext kernelContext, uint processHandle) - { - _system = system; - _kernelContext = kernelContext; - _processHandle = processHandle; - } - - public ResultCode AppendBuffer(ulong bufferTag, ref AudioUserBuffer buffer) - { - return (ResultCode)_system.AppendBuffer(bufferTag, ref buffer); - } - - public ResultCode AppendUacBuffer(ulong bufferTag, ref AudioUserBuffer buffer, uint handle) - { - return (ResultCode)_system.AppendUacBuffer(bufferTag, ref buffer, handle); - } - - public bool ContainsBuffer(ulong bufferTag) - { - return _system.ContainsBuffer(bufferTag); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _system.Dispose(); - - _kernelContext.Syscall.CloseHandle((int)_processHandle); - } - } - - public bool FlushBuffers() - { - return _system.FlushBuffers(); - } - - public uint GetBufferCount() - { - return _system.GetBufferCount(); - } - - public ResultCode GetReleasedBuffers(Span releasedBuffers, out uint releasedCount) - { - return (ResultCode)_system.GetReleasedBuffers(releasedBuffers, out releasedCount); - } - - public AudioDeviceState GetState() - { - return _system.GetState(); - } - - public float GetVolume() - { - return _system.GetVolume(); - } - - public KEvent RegisterBufferEvent() - { - IWritableEvent outEvent = _system.RegisterBufferEvent(); - - if (outEvent is AudioKernelEvent kernelEvent) - { - return kernelEvent.Event; - } - else - { - throw new NotImplementedException(); - } - } - - public void SetVolume(float volume) - { - _system.SetVolume(volume); - } - - public ResultCode Start() - { - return (ResultCode)_system.Start(); - } - - public ResultCode Stop() - { - return (ResultCode)_system.Stop(); - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs deleted file mode 100644 index 3f138021c..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs +++ /dev/null @@ -1,200 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.Cpu; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.Horizon.Common; -using Ryujinx.Memory; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioIn -{ - class AudioInServer : DisposableIpcService - { - private readonly IAudioIn _impl; - - public AudioInServer(IAudioIn impl) - { - _impl = impl; - } - - [CommandCmif(0)] - // GetAudioInState() -> u32 state - public ResultCode GetAudioInState(ServiceCtx context) - { - context.ResponseData.Write((uint)_impl.GetState()); - - return ResultCode.Success; - } - - [CommandCmif(1)] - // Start() - public ResultCode Start(ServiceCtx context) - { - return _impl.Start(); - } - - [CommandCmif(2)] - // Stop() - public ResultCode StopAudioIn(ServiceCtx context) - { - return _impl.Stop(); - } - - [CommandCmif(3)] - // AppendAudioInBuffer(u64 tag, buffer) - public ResultCode AppendAudioInBuffer(ServiceCtx context) - { - ulong position = context.Request.SendBuff[0].Position; - - ulong bufferTag = context.RequestData.ReadUInt64(); - - AudioUserBuffer data = MemoryHelper.Read(context.Memory, position); - - return _impl.AppendBuffer(bufferTag, ref data); - } - - [CommandCmif(4)] - // RegisterBufferEvent() -> handle - public ResultCode RegisterBufferEvent(ServiceCtx context) - { - KEvent bufferEvent = _impl.RegisterBufferEvent(); - - if (context.Process.HandleTable.GenerateHandle(bufferEvent.ReadableEvent, out int handle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - return ResultCode.Success; - } - - [CommandCmif(5)] - // GetReleasedAudioInBuffers() -> (u32 count, buffer tags) - public ResultCode GetReleasedAudioInBuffers(ServiceCtx context) - { - ulong position = context.Request.ReceiveBuff[0].Position; - ulong size = context.Request.ReceiveBuff[0].Size; - - using WritableRegion outputRegion = context.Memory.GetWritableRegion((ulong)position, (int)size); - ResultCode result = _impl.GetReleasedBuffers(MemoryMarshal.Cast(outputRegion.Memory.Span), out uint releasedCount); - - context.ResponseData.Write(releasedCount); - - return result; - } - - [CommandCmif(6)] - // ContainsAudioInBuffer(u64 tag) -> b8 - public ResultCode ContainsAudioInBuffer(ServiceCtx context) - { - ulong bufferTag = context.RequestData.ReadUInt64(); - - context.ResponseData.Write(_impl.ContainsBuffer(bufferTag)); - - return ResultCode.Success; - } - - [CommandCmif(7)] // 3.0.0+ - // AppendUacInBuffer(u64 tag, handle, buffer) - public ResultCode AppendUacInBuffer(ServiceCtx context) - { - ulong position = context.Request.SendBuff[0].Position; - - ulong bufferTag = context.RequestData.ReadUInt64(); - uint handle = (uint)context.Request.HandleDesc.ToCopy[0]; - - AudioUserBuffer data = MemoryHelper.Read(context.Memory, position); - - return _impl.AppendUacBuffer(bufferTag, ref data, handle); - } - - [CommandCmif(8)] // 3.0.0+ - // AppendAudioInBufferAuto(u64 tag, buffer) - public ResultCode AppendAudioInBufferAuto(ServiceCtx context) - { - (ulong position, _) = context.Request.GetBufferType0x21(); - - ulong bufferTag = context.RequestData.ReadUInt64(); - - AudioUserBuffer data = MemoryHelper.Read(context.Memory, position); - - return _impl.AppendBuffer(bufferTag, ref data); - } - - [CommandCmif(9)] // 3.0.0+ - // GetReleasedAudioInBuffersAuto() -> (u32 count, buffer tags) - public ResultCode GetReleasedAudioInBuffersAuto(ServiceCtx context) - { - (ulong position, ulong size) = context.Request.GetBufferType0x22(); - - using WritableRegion outputRegion = context.Memory.GetWritableRegion(position, (int)size); - ResultCode result = _impl.GetReleasedBuffers(MemoryMarshal.Cast(outputRegion.Memory.Span), out uint releasedCount); - - context.ResponseData.Write(releasedCount); - - return result; - } - - [CommandCmif(10)] // 3.0.0+ - // AppendUacInBufferAuto(u64 tag, handle, buffer) - public ResultCode AppendUacInBufferAuto(ServiceCtx context) - { - (ulong position, _) = context.Request.GetBufferType0x21(); - - ulong bufferTag = context.RequestData.ReadUInt64(); - uint handle = (uint)context.Request.HandleDesc.ToCopy[0]; - - AudioUserBuffer data = MemoryHelper.Read(context.Memory, position); - - return _impl.AppendUacBuffer(bufferTag, ref data, handle); - } - - [CommandCmif(11)] // 4.0.0+ - // GetAudioInBufferCount() -> u32 - public ResultCode GetAudioInBufferCount(ServiceCtx context) - { - context.ResponseData.Write(_impl.GetBufferCount()); - - return ResultCode.Success; - } - - [CommandCmif(12)] // 4.0.0+ - // SetAudioInVolume(s32) - public ResultCode SetAudioInVolume(ServiceCtx context) - { - float volume = context.RequestData.ReadSingle(); - - _impl.SetVolume(volume); - - return ResultCode.Success; - } - - [CommandCmif(13)] // 4.0.0+ - // GetAudioInVolume() -> s32 - public ResultCode GetAudioInVolume(ServiceCtx context) - { - context.ResponseData.Write(_impl.GetVolume()); - - return ResultCode.Success; - } - - [CommandCmif(14)] // 6.0.0+ - // FlushAudioInBuffers() -> b8 - public ResultCode FlushAudioInBuffers(ServiceCtx context) - { - context.ResponseData.Write(_impl.FlushBuffers()); - - return ResultCode.Success; - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) - { - _impl.Dispose(); - } - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/IAudioIn.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/IAudioIn.cs deleted file mode 100644 index 4e67303df..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioIn/IAudioIn.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using System; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioIn -{ - interface IAudioIn : IDisposable - { - AudioDeviceState GetState(); - - ResultCode Start(); - - ResultCode Stop(); - - ResultCode AppendBuffer(ulong bufferTag, ref AudioUserBuffer buffer); - - // NOTE: This is broken by design... not quite sure what it's used for (if anything in production). - ResultCode AppendUacBuffer(ulong bufferTag, ref AudioUserBuffer buffer, uint handle); - - KEvent RegisterBufferEvent(); - - ResultCode GetReleasedBuffers(Span releasedBuffers, out uint releasedCount); - - bool ContainsBuffer(ulong bufferTag); - - uint GetBufferCount(); - - bool FlushBuffers(); - - void SetVolume(float volume); - - float GetVolume(); - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioInManager.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioInManager.cs deleted file mode 100644 index 1e759e0ca..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioInManager.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.Audio.Input; -using Ryujinx.HLE.HOS.Services.Audio.AudioIn; -using AudioInManagerImpl = Ryujinx.Audio.Input.AudioInputManager; - -namespace Ryujinx.HLE.HOS.Services.Audio -{ - class AudioInManager : IAudioInManager - { - private readonly AudioInManagerImpl _impl; - - public AudioInManager(AudioInManagerImpl impl) - { - _impl = impl; - } - - public string[] ListAudioIns(bool filtered) - { - return _impl.ListAudioIns(filtered); - } - - public ResultCode OpenAudioIn(ServiceCtx context, out string outputDeviceName, out AudioOutputConfiguration outputConfiguration, out IAudioIn obj, string inputDeviceName, ref AudioInputConfiguration parameter, ulong appletResourceUserId, uint processHandle) - { - var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory; - - ResultCode result = (ResultCode)_impl.OpenAudioIn(out outputDeviceName, out outputConfiguration, out AudioInputSystem inSystem, memoryManager, inputDeviceName, SampleFormat.PcmInt16, ref parameter, appletResourceUserId, processHandle); - - if (result == ResultCode.Success) - { - obj = new AudioIn.AudioIn(inSystem, context.Device.System.KernelContext, processHandle); - } - else - { - obj = null; - } - - return result; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioInManagerServer.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioInManagerServer.cs deleted file mode 100644 index 1b35a62d8..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioInManagerServer.cs +++ /dev/null @@ -1,243 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Cpu; -using Ryujinx.HLE.HOS.Services.Audio.AudioIn; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audin:u")] - class AudioInManagerServer : IpcService - { - private const int AudioInNameSize = 0x100; - - private readonly IAudioInManager _impl; - - public AudioInManagerServer(ServiceCtx context) : this(context, new AudioInManager(context.Device.System.AudioInputManager)) { } - - public AudioInManagerServer(ServiceCtx context, IAudioInManager impl) : base(context.Device.System.AudOutServer) - { - _impl = impl; - } - - [CommandCmif(0)] - // ListAudioIns() -> (u32, buffer) - public ResultCode ListAudioIns(ServiceCtx context) - { - string[] deviceNames = _impl.ListAudioIns(false); - - ulong position = context.Request.ReceiveBuff[0].Position; - ulong size = context.Request.ReceiveBuff[0].Size; - - ulong basePosition = position; - - int count = 0; - - foreach (string name in deviceNames) - { - byte[] buffer = Encoding.ASCII.GetBytes(name); - - if ((position - basePosition) + (ulong)buffer.Length > size) - { - Logger.Error?.Print(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - - break; - } - - context.Memory.Write(position, buffer); - MemoryHelper.FillWithZeros(context.Memory, position + (ulong)buffer.Length, AudioInNameSize - buffer.Length); - - position += AudioInNameSize; - count++; - } - - context.ResponseData.Write(count); - - return ResultCode.Success; - } - - [CommandCmif(1)] - // OpenAudioIn(AudioInInputConfiguration input_config, nn::applet::AppletResourceUserId, pid, handle, buffer name) - // -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object, buffer name) - public ResultCode OpenAudioIn(ServiceCtx context) - { - AudioInputConfiguration inputConfiguration = context.RequestData.ReadStruct(); - ulong appletResourceUserId = context.RequestData.ReadUInt64(); - - ulong deviceNameInputPosition = context.Request.SendBuff[0].Position; - ulong deviceNameInputSize = context.Request.SendBuff[0].Size; - - ulong deviceNameOutputPosition = context.Request.ReceiveBuff[0].Position; -#pragma warning disable IDE0059 // Remove unnecessary value assignment - ulong deviceNameOutputSize = context.Request.ReceiveBuff[0].Size; -#pragma warning restore IDE0059 - - uint processHandle = (uint)context.Request.HandleDesc.ToCopy[0]; - - string inputDeviceName = MemoryHelper.ReadAsciiString(context.Memory, deviceNameInputPosition, (long)deviceNameInputSize); - - ResultCode resultCode = _impl.OpenAudioIn(context, out string outputDeviceName, out AudioOutputConfiguration outputConfiguration, out IAudioIn obj, inputDeviceName, ref inputConfiguration, appletResourceUserId, processHandle); - - if (resultCode == ResultCode.Success) - { - context.ResponseData.WriteStruct(outputConfiguration); - - byte[] outputDeviceNameRaw = Encoding.ASCII.GetBytes(outputDeviceName); - - context.Memory.Write(deviceNameOutputPosition, outputDeviceNameRaw); - MemoryHelper.FillWithZeros(context.Memory, deviceNameOutputPosition + (ulong)outputDeviceNameRaw.Length, AudioInNameSize - outputDeviceNameRaw.Length); - - MakeObject(context, new AudioInServer(obj)); - } - - return resultCode; - } - - [CommandCmif(2)] // 3.0.0+ - // ListAudioInsAuto() -> (u32, buffer) - public ResultCode ListAudioInsAuto(ServiceCtx context) - { - string[] deviceNames = _impl.ListAudioIns(false); - - (ulong position, ulong size) = context.Request.GetBufferType0x22(); - - ulong basePosition = position; - - int count = 0; - - foreach (string name in deviceNames) - { - byte[] buffer = Encoding.ASCII.GetBytes(name); - - if ((position - basePosition) + (ulong)buffer.Length > size) - { - Logger.Error?.Print(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - - break; - } - - context.Memory.Write(position, buffer); - MemoryHelper.FillWithZeros(context.Memory, position + (ulong)buffer.Length, AudioInNameSize - buffer.Length); - - position += AudioInNameSize; - count++; - } - - context.ResponseData.Write(count); - - return ResultCode.Success; - } - - [CommandCmif(3)] // 3.0.0+ - // OpenAudioInAuto(AudioInInputConfiguration input_config, nn::applet::AppletResourceUserId, pid, handle, buffer) - // -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object, buffer name) - public ResultCode OpenAudioInAuto(ServiceCtx context) - { - AudioInputConfiguration inputConfiguration = context.RequestData.ReadStruct(); - ulong appletResourceUserId = context.RequestData.ReadUInt64(); - - (ulong deviceNameInputPosition, ulong deviceNameInputSize) = context.Request.GetBufferType0x21(); -#pragma warning disable IDE0059 // Remove unnecessary value assignment - (ulong deviceNameOutputPosition, ulong deviceNameOutputSize) = context.Request.GetBufferType0x22(); -#pragma warning restore IDE0059 - - uint processHandle = (uint)context.Request.HandleDesc.ToCopy[0]; - - string inputDeviceName = MemoryHelper.ReadAsciiString(context.Memory, deviceNameInputPosition, (long)deviceNameInputSize); - - ResultCode resultCode = _impl.OpenAudioIn(context, out string outputDeviceName, out AudioOutputConfiguration outputConfiguration, out IAudioIn obj, inputDeviceName, ref inputConfiguration, appletResourceUserId, processHandle); - - if (resultCode == ResultCode.Success) - { - context.ResponseData.WriteStruct(outputConfiguration); - - byte[] outputDeviceNameRaw = Encoding.ASCII.GetBytes(outputDeviceName); - - context.Memory.Write(deviceNameOutputPosition, outputDeviceNameRaw); - MemoryHelper.FillWithZeros(context.Memory, deviceNameOutputPosition + (ulong)outputDeviceNameRaw.Length, AudioInNameSize - outputDeviceNameRaw.Length); - - MakeObject(context, new AudioInServer(obj)); - } - - return resultCode; - } - - [CommandCmif(4)] // 3.0.0+ - // ListAudioInsAutoFiltered() -> (u32, buffer) - public ResultCode ListAudioInsAutoFiltered(ServiceCtx context) - { - string[] deviceNames = _impl.ListAudioIns(true); - - (ulong position, ulong size) = context.Request.GetBufferType0x22(); - - ulong basePosition = position; - - int count = 0; - - foreach (string name in deviceNames) - { - byte[] buffer = Encoding.ASCII.GetBytes(name); - - if ((position - basePosition) + (ulong)buffer.Length > size) - { - Logger.Error?.Print(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - - break; - } - - context.Memory.Write(position, buffer); - MemoryHelper.FillWithZeros(context.Memory, position + (ulong)buffer.Length, AudioInNameSize - buffer.Length); - - position += AudioInNameSize; - count++; - } - - context.ResponseData.Write(count); - - return ResultCode.Success; - } - - [CommandCmif(5)] // 5.0.0+ - // OpenAudioInProtocolSpecified(b64 protocol_specified_related, AudioInInputConfiguration input_config, nn::applet::AppletResourceUserId, pid, handle, buffer name) - // -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object, buffer name) - public ResultCode OpenAudioInProtocolSpecified(ServiceCtx context) - { - // NOTE: We always assume that only the default device will be plugged (we never report any USB Audio Class type devices). -#pragma warning disable IDE0059 // Remove unnecessary value assignment - bool protocolSpecifiedRelated = context.RequestData.ReadUInt64() == 1; -#pragma warning restore IDE0059 - - AudioInputConfiguration inputConfiguration = context.RequestData.ReadStruct(); - ulong appletResourceUserId = context.RequestData.ReadUInt64(); - - ulong deviceNameInputPosition = context.Request.SendBuff[0].Position; - ulong deviceNameInputSize = context.Request.SendBuff[0].Size; - - ulong deviceNameOutputPosition = context.Request.ReceiveBuff[0].Position; -#pragma warning disable IDE0051, IDE0059 // Remove unused private member - ulong deviceNameOutputSize = context.Request.ReceiveBuff[0].Size; -#pragma warning restore IDE0051, IDE0059 - - uint processHandle = (uint)context.Request.HandleDesc.ToCopy[0]; - - string inputDeviceName = MemoryHelper.ReadAsciiString(context.Memory, deviceNameInputPosition, (long)deviceNameInputSize); - - ResultCode resultCode = _impl.OpenAudioIn(context, out string outputDeviceName, out AudioOutputConfiguration outputConfiguration, out IAudioIn obj, inputDeviceName, ref inputConfiguration, appletResourceUserId, processHandle); - - if (resultCode == ResultCode.Success) - { - context.ResponseData.WriteStruct(outputConfiguration); - - byte[] outputDeviceNameRaw = Encoding.ASCII.GetBytes(outputDeviceName); - - context.Memory.Write(deviceNameOutputPosition, outputDeviceNameRaw); - MemoryHelper.FillWithZeros(context.Memory, deviceNameOutputPosition + (ulong)outputDeviceNameRaw.Length, AudioInNameSize - outputDeviceNameRaw.Length); - - MakeObject(context, new AudioInServer(obj)); - } - - return resultCode; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOut.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOut.cs deleted file mode 100644 index 2ccf0657f..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOut.cs +++ /dev/null @@ -1,108 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.Audio.Integration; -using Ryujinx.Audio.Output; -using Ryujinx.HLE.HOS.Kernel; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer; -using System; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut -{ - class AudioOut : IAudioOut - { - private readonly AudioOutputSystem _system; - private readonly uint _processHandle; - private readonly KernelContext _kernelContext; - - public AudioOut(AudioOutputSystem system, KernelContext kernelContext, uint processHandle) - { - _system = system; - _kernelContext = kernelContext; - _processHandle = processHandle; - } - - public ResultCode AppendBuffer(ulong bufferTag, ref AudioUserBuffer buffer) - { - return (ResultCode)_system.AppendBuffer(bufferTag, ref buffer); - } - - public bool ContainsBuffer(ulong bufferTag) - { - return _system.ContainsBuffer(bufferTag); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _system.Dispose(); - - _kernelContext.Syscall.CloseHandle((int)_processHandle); - } - } - - public bool FlushBuffers() - { - return _system.FlushBuffers(); - } - - public uint GetBufferCount() - { - return _system.GetBufferCount(); - } - - public ulong GetPlayedSampleCount() - { - return _system.GetPlayedSampleCount(); - } - - public ResultCode GetReleasedBuffers(Span releasedBuffers, out uint releasedCount) - { - return (ResultCode)_system.GetReleasedBuffer(releasedBuffers, out releasedCount); - } - - public AudioDeviceState GetState() - { - return _system.GetState(); - } - - public float GetVolume() - { - return _system.GetVolume(); - } - - public KEvent RegisterBufferEvent() - { - IWritableEvent outEvent = _system.RegisterBufferEvent(); - - if (outEvent is AudioKernelEvent kernelEvent) - { - return kernelEvent.Event; - } - else - { - throw new NotImplementedException(); - } - } - - public void SetVolume(float volume) - { - _system.SetVolume(volume); - } - - public ResultCode Start() - { - return (ResultCode)_system.Start(); - } - - public ResultCode Stop() - { - return (ResultCode)_system.Stop(); - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs deleted file mode 100644 index e1b252631..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs +++ /dev/null @@ -1,181 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.Cpu; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.Horizon.Common; -using Ryujinx.Memory; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut -{ - class AudioOutServer : DisposableIpcService - { - private readonly IAudioOut _impl; - - public AudioOutServer(IAudioOut impl) - { - _impl = impl; - } - - [CommandCmif(0)] - // GetAudioOutState() -> u32 state - public ResultCode GetAudioOutState(ServiceCtx context) - { - context.ResponseData.Write((uint)_impl.GetState()); - - return ResultCode.Success; - } - - [CommandCmif(1)] - // Start() - public ResultCode Start(ServiceCtx context) - { - return _impl.Start(); - } - - [CommandCmif(2)] - // Stop() - public ResultCode Stop(ServiceCtx context) - { - return _impl.Stop(); - } - - [CommandCmif(3)] - // AppendAudioOutBuffer(u64 bufferTag, buffer buffer) - public ResultCode AppendAudioOutBuffer(ServiceCtx context) - { - ulong position = context.Request.SendBuff[0].Position; - - ulong bufferTag = context.RequestData.ReadUInt64(); - - AudioUserBuffer data = MemoryHelper.Read(context.Memory, position); - - return _impl.AppendBuffer(bufferTag, ref data); - } - - [CommandCmif(4)] - // RegisterBufferEvent() -> handle - public ResultCode RegisterBufferEvent(ServiceCtx context) - { - KEvent bufferEvent = _impl.RegisterBufferEvent(); - - if (context.Process.HandleTable.GenerateHandle(bufferEvent.ReadableEvent, out int handle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - return ResultCode.Success; - } - - [CommandCmif(5)] - // GetReleasedAudioOutBuffers() -> (u32 count, buffer tags) - public ResultCode GetReleasedAudioOutBuffers(ServiceCtx context) - { - ulong position = context.Request.ReceiveBuff[0].Position; - ulong size = context.Request.ReceiveBuff[0].Size; - - using WritableRegion outputRegion = context.Memory.GetWritableRegion(position, (int)size); - ResultCode result = _impl.GetReleasedBuffers(MemoryMarshal.Cast(outputRegion.Memory.Span), out uint releasedCount); - - context.ResponseData.Write(releasedCount); - - return result; - } - - [CommandCmif(6)] - // ContainsAudioOutBuffer(u64 tag) -> b8 - public ResultCode ContainsAudioOutBuffer(ServiceCtx context) - { - ulong bufferTag = context.RequestData.ReadUInt64(); - - context.ResponseData.Write(_impl.ContainsBuffer(bufferTag)); - - return ResultCode.Success; - } - - [CommandCmif(7)] // 3.0.0+ - // AppendAudioOutBufferAuto(u64 tag, buffer) - public ResultCode AppendAudioOutBufferAuto(ServiceCtx context) - { - (ulong position, _) = context.Request.GetBufferType0x21(); - - ulong bufferTag = context.RequestData.ReadUInt64(); - - AudioUserBuffer data = MemoryHelper.Read(context.Memory, position); - - return _impl.AppendBuffer(bufferTag, ref data); - } - - [CommandCmif(8)] // 3.0.0+ - // GetReleasedAudioOutBuffersAuto() -> (u32 count, buffer tags) - public ResultCode GetReleasedAudioOutBuffersAuto(ServiceCtx context) - { - (ulong position, ulong size) = context.Request.GetBufferType0x22(); - - using WritableRegion outputRegion = context.Memory.GetWritableRegion(position, (int)size); - ResultCode result = _impl.GetReleasedBuffers(MemoryMarshal.Cast(outputRegion.Memory.Span), out uint releasedCount); - - context.ResponseData.Write(releasedCount); - - return result; - } - - [CommandCmif(9)] // 4.0.0+ - // GetAudioOutBufferCount() -> u32 - public ResultCode GetAudioOutBufferCount(ServiceCtx context) - { - context.ResponseData.Write(_impl.GetBufferCount()); - - return ResultCode.Success; - } - - [CommandCmif(10)] // 4.0.0+ - // GetAudioOutPlayedSampleCount() -> u64 - public ResultCode GetAudioOutPlayedSampleCount(ServiceCtx context) - { - context.ResponseData.Write(_impl.GetPlayedSampleCount()); - - return ResultCode.Success; - } - - [CommandCmif(11)] // 4.0.0+ - // FlushAudioOutBuffers() -> b8 - public ResultCode FlushAudioOutBuffers(ServiceCtx context) - { - context.ResponseData.Write(_impl.FlushBuffers()); - - return ResultCode.Success; - } - - [CommandCmif(12)] // 6.0.0+ - // SetAudioOutVolume(s32) - public ResultCode SetAudioOutVolume(ServiceCtx context) - { - float volume = context.RequestData.ReadSingle(); - - _impl.SetVolume(volume); - - return ResultCode.Success; - } - - [CommandCmif(13)] // 6.0.0+ - // GetAudioOutVolume() -> s32 - public ResultCode GetAudioOutVolume(ServiceCtx context) - { - context.ResponseData.Write(_impl.GetVolume()); - - return ResultCode.Success; - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) - { - _impl.Dispose(); - } - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/IAudioOut.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/IAudioOut.cs deleted file mode 100644 index 8c8c68629..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioOut/IAudioOut.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using System; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut -{ - interface IAudioOut : IDisposable - { - AudioDeviceState GetState(); - - ResultCode Start(); - - ResultCode Stop(); - - ResultCode AppendBuffer(ulong bufferTag, ref AudioUserBuffer buffer); - - KEvent RegisterBufferEvent(); - - ResultCode GetReleasedBuffers(Span releasedBuffers, out uint releasedCount); - - bool ContainsBuffer(ulong bufferTag); - - uint GetBufferCount(); - - ulong GetPlayedSampleCount(); - - bool FlushBuffers(); - - void SetVolume(float volume); - - float GetVolume(); - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager.cs deleted file mode 100644 index c45a485bc..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.Audio.Output; -using Ryujinx.HLE.HOS.Services.Audio.AudioOut; -using AudioOutManagerImpl = Ryujinx.Audio.Output.AudioOutputManager; - -namespace Ryujinx.HLE.HOS.Services.Audio -{ - class AudioOutManager : IAudioOutManager - { - private readonly AudioOutManagerImpl _impl; - - public AudioOutManager(AudioOutManagerImpl impl) - { - _impl = impl; - } - - public string[] ListAudioOuts() - { - return _impl.ListAudioOuts(); - } - - public ResultCode OpenAudioOut(ServiceCtx context, out string outputDeviceName, out AudioOutputConfiguration outputConfiguration, out IAudioOut obj, string inputDeviceName, ref AudioInputConfiguration parameter, ulong appletResourceUserId, uint processHandle, float volume) - { - var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory; - - ResultCode result = (ResultCode)_impl.OpenAudioOut(out outputDeviceName, out outputConfiguration, out AudioOutputSystem outSystem, memoryManager, inputDeviceName, SampleFormat.PcmInt16, ref parameter, appletResourceUserId, processHandle, volume); - - if (result == ResultCode.Success) - { - obj = new AudioOut.AudioOut(outSystem, context.Device.System.KernelContext, processHandle); - } - else - { - obj = null; - } - - return result; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioOutManagerServer.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioOutManagerServer.cs deleted file mode 100644 index 79ae6a141..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioOutManagerServer.cs +++ /dev/null @@ -1,166 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Cpu; -using Ryujinx.HLE.HOS.Services.Audio.AudioOut; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audout:u")] - class AudioOutManagerServer : IpcService - { - private const int AudioOutNameSize = 0x100; - - private readonly IAudioOutManager _impl; - - public AudioOutManagerServer(ServiceCtx context) : this(context, new AudioOutManager(context.Device.System.AudioOutputManager)) { } - - public AudioOutManagerServer(ServiceCtx context, IAudioOutManager impl) : base(context.Device.System.AudOutServer) - { - _impl = impl; - } - - [CommandCmif(0)] - // ListAudioOuts() -> (u32, buffer) - public ResultCode ListAudioOuts(ServiceCtx context) - { - string[] deviceNames = _impl.ListAudioOuts(); - - ulong position = context.Request.ReceiveBuff[0].Position; - ulong size = context.Request.ReceiveBuff[0].Size; - - ulong basePosition = position; - - int count = 0; - - foreach (string name in deviceNames) - { - byte[] buffer = Encoding.ASCII.GetBytes(name); - - if ((position - basePosition) + (ulong)buffer.Length > size) - { - Logger.Error?.Print(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - - break; - } - - context.Memory.Write(position, buffer); - MemoryHelper.FillWithZeros(context.Memory, position + (ulong)buffer.Length, AudioOutNameSize - buffer.Length); - - position += AudioOutNameSize; - count++; - } - - context.ResponseData.Write(count); - - return ResultCode.Success; - } - - [CommandCmif(1)] - // OpenAudioOut(AudioOutInputConfiguration input_config, nn::applet::AppletResourceUserId, pid, handle process_handle, buffer name_in) - // -> (AudioOutInputConfiguration output_config, object, buffer name_out) - public ResultCode OpenAudioOut(ServiceCtx context) - { - AudioInputConfiguration inputConfiguration = context.RequestData.ReadStruct(); - ulong appletResourceUserId = context.RequestData.ReadUInt64(); - - ulong deviceNameInputPosition = context.Request.SendBuff[0].Position; - ulong deviceNameInputSize = context.Request.SendBuff[0].Size; - - ulong deviceNameOutputPosition = context.Request.ReceiveBuff[0].Position; -#pragma warning disable IDE0059 // Remove unnecessary value assignment - ulong deviceNameOutputSize = context.Request.ReceiveBuff[0].Size; -#pragma warning restore IDE0059 - - uint processHandle = (uint)context.Request.HandleDesc.ToCopy[0]; - - string inputDeviceName = MemoryHelper.ReadAsciiString(context.Memory, deviceNameInputPosition, (long)deviceNameInputSize); - - ResultCode resultCode = _impl.OpenAudioOut(context, out string outputDeviceName, out AudioOutputConfiguration outputConfiguration, out IAudioOut obj, inputDeviceName, ref inputConfiguration, appletResourceUserId, processHandle, context.Device.Configuration.AudioVolume); - - if (resultCode == ResultCode.Success) - { - context.ResponseData.WriteStruct(outputConfiguration); - - byte[] outputDeviceNameRaw = Encoding.ASCII.GetBytes(outputDeviceName); - - context.Memory.Write(deviceNameOutputPosition, outputDeviceNameRaw); - MemoryHelper.FillWithZeros(context.Memory, deviceNameOutputPosition + (ulong)outputDeviceNameRaw.Length, AudioOutNameSize - outputDeviceNameRaw.Length); - - MakeObject(context, new AudioOutServer(obj)); - } - - return resultCode; - } - - [CommandCmif(2)] // 3.0.0+ - // ListAudioOutsAuto() -> (u32, buffer) - public ResultCode ListAudioOutsAuto(ServiceCtx context) - { - string[] deviceNames = _impl.ListAudioOuts(); - - (ulong position, ulong size) = context.Request.GetBufferType0x22(); - - ulong basePosition = position; - - int count = 0; - - foreach (string name in deviceNames) - { - byte[] buffer = Encoding.ASCII.GetBytes(name); - - if ((position - basePosition) + (ulong)buffer.Length > size) - { - Logger.Error?.Print(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - - break; - } - - context.Memory.Write(position, buffer); - MemoryHelper.FillWithZeros(context.Memory, position + (ulong)buffer.Length, AudioOutNameSize - buffer.Length); - - position += AudioOutNameSize; - count++; - } - - context.ResponseData.Write(count); - - return ResultCode.Success; - } - - [CommandCmif(3)] // 3.0.0+ - // OpenAudioOut(AudioOutInputConfiguration input_config, nn::applet::AppletResourceUserId, pid, handle process_handle, buffer name_in) - // -> (AudioOutInputConfiguration output_config, object, buffer name_out) - public ResultCode OpenAudioOutAuto(ServiceCtx context) - { - AudioInputConfiguration inputConfiguration = context.RequestData.ReadStruct(); - ulong appletResourceUserId = context.RequestData.ReadUInt64(); - - (ulong deviceNameInputPosition, ulong deviceNameInputSize) = context.Request.GetBufferType0x21(); -#pragma warning disable IDE0059 // Remove unnecessary value assignment - (ulong deviceNameOutputPosition, ulong deviceNameOutputSize) = context.Request.GetBufferType0x22(); -#pragma warning restore IDE0059 - - uint processHandle = (uint)context.Request.HandleDesc.ToCopy[0]; - - string inputDeviceName = MemoryHelper.ReadAsciiString(context.Memory, deviceNameInputPosition, (long)deviceNameInputSize); - - ResultCode resultCode = _impl.OpenAudioOut(context, out string outputDeviceName, out AudioOutputConfiguration outputConfiguration, out IAudioOut obj, inputDeviceName, ref inputConfiguration, appletResourceUserId, processHandle, context.Device.Configuration.AudioVolume); - - if (resultCode == ResultCode.Success) - { - context.ResponseData.WriteStruct(outputConfiguration); - - byte[] outputDeviceNameRaw = Encoding.ASCII.GetBytes(outputDeviceName); - - context.Memory.Write(deviceNameOutputPosition, outputDeviceNameRaw); - MemoryHelper.FillWithZeros(context.Memory, deviceNameOutputPosition + (ulong)outputDeviceNameRaw.Length, AudioOutNameSize - outputDeviceNameRaw.Length); - - MakeObject(context, new AudioOutServer(obj)); - } - - return resultCode; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDevice.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDevice.cs deleted file mode 100644 index 6497a3b84..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDevice.cs +++ /dev/null @@ -1,174 +0,0 @@ -using Ryujinx.Audio.Renderer.Device; -using Ryujinx.Audio.Renderer.Server; -using Ryujinx.HLE.HOS.Kernel; -using Ryujinx.HLE.HOS.Kernel.Threading; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer -{ - class AudioDevice : IAudioDevice - { - private readonly VirtualDeviceSession[] _sessions; -#pragma warning disable IDE0052 // Remove unread private member - private readonly ulong _appletResourceId; - private readonly int _revision; -#pragma warning restore IDE0052 - private readonly bool _isUsbDeviceSupported; - - private readonly VirtualDeviceSessionRegistry _registry; - private readonly KEvent _systemEvent; - - public AudioDevice(VirtualDeviceSessionRegistry registry, KernelContext context, ulong appletResourceId, int revision) - { - _registry = registry; - _appletResourceId = appletResourceId; - _revision = revision; - - BehaviourContext behaviourContext = new(); - behaviourContext.SetUserRevision(revision); - - _isUsbDeviceSupported = behaviourContext.IsAudioUsbDeviceOutputSupported(); - _sessions = _registry.GetSessionByAppletResourceId(appletResourceId); - - // TODO: support the 3 different events correctly when we will have hot plugable audio devices. - _systemEvent = new KEvent(context); - _systemEvent.ReadableEvent.Signal(); - } - - private bool TryGetDeviceByName(out VirtualDeviceSession result, string name, bool ignoreRevLimitation = false) - { - result = null; - - foreach (VirtualDeviceSession session in _sessions) - { - if (session.Device.Name.Equals(name)) - { - if (!ignoreRevLimitation && !_isUsbDeviceSupported && session.Device.IsUsbDevice()) - { - return false; - } - - result = session; - - return true; - } - } - - return false; - } - - public string GetActiveAudioDeviceName() - { - VirtualDevice device = _registry.ActiveDevice; - - if (!_isUsbDeviceSupported && device.IsUsbDevice()) - { - device = _registry.DefaultDevice; - } - - return device.Name; - } - - public uint GetActiveChannelCount() - { - VirtualDevice device = _registry.ActiveDevice; - - if (!_isUsbDeviceSupported && device.IsUsbDevice()) - { - device = _registry.DefaultDevice; - } - - return device.ChannelCount; - } - - public ResultCode GetAudioDeviceOutputVolume(string name, out float volume) - { - if (TryGetDeviceByName(out VirtualDeviceSession result, name)) - { - volume = result.Volume; - } - else - { - volume = 0.0f; - } - - return ResultCode.Success; - } - - public ResultCode SetAudioDeviceOutputVolume(string name, float volume) - { - if (TryGetDeviceByName(out VirtualDeviceSession result, name, true)) - { - if (!_isUsbDeviceSupported && result.Device.IsUsbDevice()) - { - result = _sessions[0]; - } - - result.Volume = volume; - } - - return ResultCode.Success; - } - - public string GetActiveAudioOutputDeviceName() - { - return _registry.ActiveDevice.GetOutputDeviceName(); - } - - public string[] ListAudioDeviceName() - { - int deviceCount = _sessions.Length; - - if (!_isUsbDeviceSupported) - { - deviceCount--; - } - - string[] result = new string[deviceCount]; - - int i = 0; - - foreach (VirtualDeviceSession session in _sessions) - { - if (!_isUsbDeviceSupported && session.Device.IsUsbDevice()) - { - continue; - } - - result[i] = session.Device.Name; - - i++; - } - - return result; - } - - public string[] ListAudioOutputDeviceName() - { - int deviceCount = _sessions.Length; - - string[] result = new string[deviceCount]; - - for (int i = 0; i < deviceCount; i++) - { - result[i] = _sessions[i].Device.GetOutputDeviceName(); - } - - return result; - } - - public KEvent QueryAudioDeviceInputEvent() - { - return _systemEvent; - } - - public KEvent QueryAudioDeviceOutputEvent() - { - return _systemEvent; - } - - public KEvent QueryAudioDeviceSystemEvent() - { - return _systemEvent; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs deleted file mode 100644 index 6206215d5..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs +++ /dev/null @@ -1,320 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.Cpu; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.Horizon.Common; -using System; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer -{ - class AudioDeviceServer : IpcService - { - private const int AudioDeviceNameSize = 0x100; - - private readonly IAudioDevice _impl; - - public AudioDeviceServer(IAudioDevice impl) - { - _impl = impl; - } - - [CommandCmif(0)] - // ListAudioDeviceName() -> (u32, buffer) - public ResultCode ListAudioDeviceName(ServiceCtx context) - { - string[] deviceNames = _impl.ListAudioDeviceName(); - - ulong position = context.Request.ReceiveBuff[0].Position; - ulong size = context.Request.ReceiveBuff[0].Size; - - ulong basePosition = position; - - int count = 0; - - foreach (string name in deviceNames) - { - byte[] buffer = Encoding.ASCII.GetBytes(name); - - if ((position - basePosition) + (ulong)buffer.Length > size) - { - break; - } - - context.Memory.Write(position, buffer); - MemoryHelper.FillWithZeros(context.Memory, position + (ulong)buffer.Length, AudioDeviceNameSize - buffer.Length); - - position += AudioDeviceNameSize; - count++; - } - - context.ResponseData.Write(count); - - return ResultCode.Success; - } - - [CommandCmif(1)] - // SetAudioDeviceOutputVolume(f32 volume, buffer name) - public ResultCode SetAudioDeviceOutputVolume(ServiceCtx context) - { - float volume = context.RequestData.ReadSingle(); - - ulong position = context.Request.SendBuff[0].Position; - ulong size = context.Request.SendBuff[0].Size; - - string deviceName = MemoryHelper.ReadAsciiString(context.Memory, position, (long)size); - - return _impl.SetAudioDeviceOutputVolume(deviceName, volume); - } - - [CommandCmif(2)] - // GetAudioDeviceOutputVolume(buffer name) -> f32 volume - public ResultCode GetAudioDeviceOutputVolume(ServiceCtx context) - { - ulong position = context.Request.SendBuff[0].Position; - ulong size = context.Request.SendBuff[0].Size; - - string deviceName = MemoryHelper.ReadAsciiString(context.Memory, position, (long)size); - - ResultCode result = _impl.GetAudioDeviceOutputVolume(deviceName, out float volume); - - if (result == ResultCode.Success) - { - context.ResponseData.Write(volume); - } - - return result; - } - - [CommandCmif(3)] - // GetActiveAudioDeviceName() -> buffer - public ResultCode GetActiveAudioDeviceName(ServiceCtx context) - { - string name = _impl.GetActiveAudioDeviceName(); - - ulong position = context.Request.ReceiveBuff[0].Position; - ulong size = context.Request.ReceiveBuff[0].Size; - - byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(name + "\0"); - - if ((ulong)deviceNameBuffer.Length <= size) - { - context.Memory.Write(position, deviceNameBuffer); - } - else - { - Logger.Error?.Print(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - } - - return ResultCode.Success; - } - - [CommandCmif(4)] - // QueryAudioDeviceSystemEvent() -> handle - public ResultCode QueryAudioDeviceSystemEvent(ServiceCtx context) - { - KEvent deviceSystemEvent = _impl.QueryAudioDeviceSystemEvent(); - - if (context.Process.HandleTable.GenerateHandle(deviceSystemEvent.ReadableEvent, out int handle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - Logger.Stub?.PrintStub(LogClass.ServiceAudio); - - return ResultCode.Success; - } - - [CommandCmif(5)] - // GetActiveChannelCount() -> u32 - public ResultCode GetActiveChannelCount(ServiceCtx context) - { - context.ResponseData.Write(_impl.GetActiveChannelCount()); - - Logger.Stub?.PrintStub(LogClass.ServiceAudio); - - return ResultCode.Success; - } - - [CommandCmif(6)] // 3.0.0+ - // ListAudioDeviceNameAuto() -> (u32, buffer) - public ResultCode ListAudioDeviceNameAuto(ServiceCtx context) - { - string[] deviceNames = _impl.ListAudioDeviceName(); - - (ulong position, ulong size) = context.Request.GetBufferType0x22(); - - ulong basePosition = position; - - int count = 0; - - foreach (string name in deviceNames) - { - byte[] buffer = Encoding.ASCII.GetBytes(name); - - if ((position - basePosition) + (ulong)buffer.Length > size) - { - break; - } - - context.Memory.Write(position, buffer); - MemoryHelper.FillWithZeros(context.Memory, position + (ulong)buffer.Length, AudioDeviceNameSize - buffer.Length); - - position += AudioDeviceNameSize; - count++; - } - - context.ResponseData.Write(count); - - return ResultCode.Success; - } - - [CommandCmif(7)] // 3.0.0+ - // SetAudioDeviceOutputVolumeAuto(f32 volume, buffer name) - public ResultCode SetAudioDeviceOutputVolumeAuto(ServiceCtx context) - { - float volume = context.RequestData.ReadSingle(); - - (ulong position, ulong size) = context.Request.GetBufferType0x21(); - - string deviceName = MemoryHelper.ReadAsciiString(context.Memory, position, (long)size); - - return _impl.SetAudioDeviceOutputVolume(deviceName, volume); - } - - [CommandCmif(8)] // 3.0.0+ - // GetAudioDeviceOutputVolumeAuto(buffer name) -> f32 - public ResultCode GetAudioDeviceOutputVolumeAuto(ServiceCtx context) - { - (ulong position, ulong size) = context.Request.GetBufferType0x21(); - - string deviceName = MemoryHelper.ReadAsciiString(context.Memory, position, (long)size); - - ResultCode result = _impl.GetAudioDeviceOutputVolume(deviceName, out float volume); - - if (result == ResultCode.Success) - { - context.ResponseData.Write(volume); - } - - return ResultCode.Success; - } - - [CommandCmif(10)] // 3.0.0+ - // GetActiveAudioDeviceNameAuto() -> buffer - public ResultCode GetActiveAudioDeviceNameAuto(ServiceCtx context) - { - string name = _impl.GetActiveAudioDeviceName(); - - (ulong position, ulong size) = context.Request.GetBufferType0x22(); - - byte[] deviceNameBuffer = Encoding.UTF8.GetBytes(name + '\0'); - - if ((ulong)deviceNameBuffer.Length <= size) - { - context.Memory.Write(position, deviceNameBuffer); - } - else - { - Logger.Error?.Print(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - } - - return ResultCode.Success; - } - - [CommandCmif(11)] // 3.0.0+ - // QueryAudioDeviceInputEvent() -> handle - public ResultCode QueryAudioDeviceInputEvent(ServiceCtx context) - { - KEvent deviceInputEvent = _impl.QueryAudioDeviceInputEvent(); - - if (context.Process.HandleTable.GenerateHandle(deviceInputEvent.ReadableEvent, out int handle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - Logger.Stub?.PrintStub(LogClass.ServiceAudio); - - return ResultCode.Success; - } - - [CommandCmif(12)] // 3.0.0+ - // QueryAudioDeviceOutputEvent() -> handle - public ResultCode QueryAudioDeviceOutputEvent(ServiceCtx context) - { - KEvent deviceOutputEvent = _impl.QueryAudioDeviceOutputEvent(); - - if (context.Process.HandleTable.GenerateHandle(deviceOutputEvent.ReadableEvent, out int handle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - Logger.Stub?.PrintStub(LogClass.ServiceAudio); - - return ResultCode.Success; - } - - [CommandCmif(13)] // 13.0.0+ - // GetActiveAudioOutputDeviceName() -> buffer - public ResultCode GetActiveAudioOutputDeviceName(ServiceCtx context) - { - string name = _impl.GetActiveAudioOutputDeviceName(); - - ulong position = context.Request.ReceiveBuff[0].Position; - ulong size = context.Request.ReceiveBuff[0].Size; - - byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(name + "\0"); - - if ((ulong)deviceNameBuffer.Length <= size) - { - context.Memory.Write(position, deviceNameBuffer); - } - else - { - Logger.Error?.Print(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - } - - return ResultCode.Success; - } - - [CommandCmif(14)] // 13.0.0+ - // ListAudioOutputDeviceName() -> (u32, buffer) - public ResultCode ListAudioOutputDeviceName(ServiceCtx context) - { - string[] deviceNames = _impl.ListAudioOutputDeviceName(); - - ulong position = context.Request.ReceiveBuff[0].Position; - ulong size = context.Request.ReceiveBuff[0].Size; - - ulong basePosition = position; - - int count = 0; - - foreach (string name in deviceNames) - { - byte[] buffer = Encoding.ASCII.GetBytes(name); - - if ((position - basePosition) + (ulong)buffer.Length > size) - { - break; - } - - context.Memory.Write(position, buffer); - MemoryHelper.FillWithZeros(context.Memory, position + (ulong)buffer.Length, AudioDeviceNameSize - buffer.Length); - - position += AudioDeviceNameSize; - count++; - } - - context.ResponseData.Write(count); - - return ResultCode.Success; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioKernelEvent.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioKernelEvent.cs deleted file mode 100644 index 414c70a43..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioKernelEvent.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Ryujinx.Audio.Integration; -using Ryujinx.HLE.HOS.Kernel.Threading; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer -{ - class AudioKernelEvent : IWritableEvent - { - public KEvent Event { get; } - - public AudioKernelEvent(KEvent evnt) - { - Event = evnt; - } - - public void Clear() - { - Event.WritableEvent.Clear(); - } - - public void Signal() - { - Event.WritableEvent.Signal(); - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs deleted file mode 100644 index 88456be3e..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs +++ /dev/null @@ -1,122 +0,0 @@ -using Ryujinx.Audio.Integration; -using Ryujinx.Audio.Renderer.Server; -using Ryujinx.HLE.HOS.Kernel.Threading; -using System; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer -{ - class AudioRenderer : IAudioRenderer - { - private readonly AudioRenderSystem _impl; - - public AudioRenderer(AudioRenderSystem impl) - { - _impl = impl; - } - - public ResultCode ExecuteAudioRendererRendering() - { - return (ResultCode)_impl.ExecuteAudioRendererRendering(); - } - - public uint GetMixBufferCount() - { - return _impl.GetMixBufferCount(); - } - - public uint GetRenderingTimeLimit() - { - return _impl.GetRenderingTimeLimit(); - } - - public uint GetSampleCount() - { - return _impl.GetSampleCount(); - } - - public uint GetSampleRate() - { - return _impl.GetSampleRate(); - } - - public int GetState() - { - if (_impl.IsActive()) - { - return 0; - } - - return 1; - } - - public ResultCode QuerySystemEvent(out KEvent systemEvent) - { - ResultCode resultCode = (ResultCode)_impl.QuerySystemEvent(out IWritableEvent outEvent); - - if (resultCode == ResultCode.Success) - { - if (outEvent is AudioKernelEvent kernelEvent) - { - systemEvent = kernelEvent.Event; - } - else - { - throw new NotImplementedException(); - } - } - else - { - systemEvent = null; - } - - return resultCode; - } - - public ResultCode RequestUpdate(Memory output, Memory performanceOutput, ReadOnlyMemory input) - { - return (ResultCode)_impl.Update(output, performanceOutput, input); - } - - public void SetRenderingTimeLimit(uint percent) - { - _impl.SetRenderingTimeLimitPercent(percent); - } - - public ResultCode Start() - { - _impl.Start(); - - return ResultCode.Success; - } - - public ResultCode Stop() - { - _impl.Stop(); - - return ResultCode.Success; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _impl.Dispose(); - } - } - - public void SetVoiceDropParameter(float voiceDropParameter) - { - _impl.SetVoiceDropParameter(voiceDropParameter); - } - - public float GetVoiceDropParameter() - { - return _impl.GetVoiceDropParameter(); - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs deleted file mode 100644 index baea01072..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs +++ /dev/null @@ -1,215 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.Common.Memory; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.Horizon.Common; -using System; -using System.Buffers; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer -{ - class AudioRendererServer : DisposableIpcService - { - private readonly IAudioRenderer _impl; - - public AudioRendererServer(IAudioRenderer impl) - { - _impl = impl; - } - - [CommandCmif(0)] - // GetSampleRate() -> u32 - public ResultCode GetSampleRate(ServiceCtx context) - { - context.ResponseData.Write(_impl.GetSampleRate()); - - return ResultCode.Success; - } - - [CommandCmif(1)] - // GetSampleCount() -> u32 - public ResultCode GetSampleCount(ServiceCtx context) - { - context.ResponseData.Write(_impl.GetSampleCount()); - - return ResultCode.Success; - } - - [CommandCmif(2)] - // GetMixBufferCount() -> u32 - public ResultCode GetMixBufferCount(ServiceCtx context) - { - context.ResponseData.Write(_impl.GetMixBufferCount()); - - return ResultCode.Success; - } - - [CommandCmif(3)] - // GetState() -> u32 - public ResultCode GetState(ServiceCtx context) - { - context.ResponseData.Write(_impl.GetState()); - - return ResultCode.Success; - } - - [CommandCmif(4)] - // RequestUpdate(buffer input) - // -> (buffer output, buffer performanceOutput) - public ResultCode RequestUpdate(ServiceCtx context) - { - ulong inputPosition = context.Request.SendBuff[0].Position; - ulong inputSize = context.Request.SendBuff[0].Size; - - ulong outputPosition = context.Request.ReceiveBuff[0].Position; - ulong outputSize = context.Request.ReceiveBuff[0].Size; - - ulong performanceOutputPosition = context.Request.ReceiveBuff[1].Position; - ulong performanceOutputSize = context.Request.ReceiveBuff[1].Size; - - ReadOnlyMemory input = context.Memory.GetSpan(inputPosition, (int)inputSize).ToArray(); - - using IMemoryOwner outputOwner = ByteMemoryPool.RentCleared(outputSize); - using IMemoryOwner performanceOutputOwner = ByteMemoryPool.RentCleared(performanceOutputSize); - Memory output = outputOwner.Memory; - Memory performanceOutput = performanceOutputOwner.Memory; - - using MemoryHandle outputHandle = output.Pin(); - using MemoryHandle performanceOutputHandle = performanceOutput.Pin(); - - ResultCode result = _impl.RequestUpdate(output, performanceOutput, input); - - if (result == ResultCode.Success) - { - context.Memory.Write(outputPosition, output.Span); - context.Memory.Write(performanceOutputPosition, performanceOutput.Span); - } - else - { - Logger.Error?.Print(LogClass.ServiceAudio, $"Error while processing renderer update: 0x{(int)result:X}"); - } - - return result; - } - - [CommandCmif(5)] - // Start() - public ResultCode Start(ServiceCtx context) - { - return _impl.Start(); - } - - [CommandCmif(6)] - // Stop() - public ResultCode Stop(ServiceCtx context) - { - return _impl.Stop(); - } - - [CommandCmif(7)] - // QuerySystemEvent() -> handle - public ResultCode QuerySystemEvent(ServiceCtx context) - { - ResultCode result = _impl.QuerySystemEvent(out KEvent systemEvent); - - if (result == ResultCode.Success) - { - if (context.Process.HandleTable.GenerateHandle(systemEvent.ReadableEvent, out int handle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - } - - return result; - } - - [CommandCmif(8)] - // SetAudioRendererRenderingTimeLimit(u32 limit) - public ResultCode SetAudioRendererRenderingTimeLimit(ServiceCtx context) - { - uint limit = context.RequestData.ReadUInt32(); - - _impl.SetRenderingTimeLimit(limit); - - return ResultCode.Success; - } - - [CommandCmif(9)] - // GetAudioRendererRenderingTimeLimit() -> u32 limit - public ResultCode GetAudioRendererRenderingTimeLimit(ServiceCtx context) - { - uint limit = _impl.GetRenderingTimeLimit(); - - context.ResponseData.Write(limit); - - return ResultCode.Success; - } - - [CommandCmif(10)] // 3.0.0+ - // RequestUpdateAuto(buffer input) - // -> (buffer output, buffer performanceOutput) - public ResultCode RequestUpdateAuto(ServiceCtx context) - { - (ulong inputPosition, ulong inputSize) = context.Request.GetBufferType0x21(); - (ulong outputPosition, ulong outputSize) = context.Request.GetBufferType0x22(0); - (ulong performanceOutputPosition, ulong performanceOutputSize) = context.Request.GetBufferType0x22(1); - - ReadOnlyMemory input = context.Memory.GetSpan(inputPosition, (int)inputSize).ToArray(); - - Memory output = new byte[outputSize]; - Memory performanceOutput = new byte[performanceOutputSize]; - - using MemoryHandle outputHandle = output.Pin(); - using MemoryHandle performanceOutputHandle = performanceOutput.Pin(); - - ResultCode result = _impl.RequestUpdate(output, performanceOutput, input); - - if (result == ResultCode.Success) - { - context.Memory.Write(outputPosition, output.Span); - context.Memory.Write(performanceOutputPosition, performanceOutput.Span); - } - - return result; - } - - [CommandCmif(11)] // 3.0.0+ - // ExecuteAudioRendererRendering() - public ResultCode ExecuteAudioRendererRendering(ServiceCtx context) - { - return _impl.ExecuteAudioRendererRendering(); - } - - [CommandCmif(12)] // 15.0.0+ - // SetVoiceDropParameter(f32 voiceDropParameter) - public ResultCode SetVoiceDropParameter(ServiceCtx context) - { - float voiceDropParameter = context.RequestData.ReadSingle(); - - _impl.SetVoiceDropParameter(voiceDropParameter); - - return ResultCode.Success; - } - - [CommandCmif(13)] // 15.0.0+ - // GetVoiceDropParameter() -> f32 voiceDropParameter - public ResultCode GetVoiceDropParameter(ServiceCtx context) - { - float voiceDropParameter = _impl.GetVoiceDropParameter(); - - context.ResponseData.Write(voiceDropParameter); - - return ResultCode.Success; - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) - { - _impl.Dispose(); - } - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioDevice.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioDevice.cs deleted file mode 100644 index 0f181a477..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioDevice.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Threading; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer -{ - interface IAudioDevice - { - string[] ListAudioDeviceName(); - ResultCode SetAudioDeviceOutputVolume(string name, float volume); - ResultCode GetAudioDeviceOutputVolume(string name, out float volume); - string GetActiveAudioDeviceName(); - KEvent QueryAudioDeviceSystemEvent(); - uint GetActiveChannelCount(); - KEvent QueryAudioDeviceInputEvent(); - KEvent QueryAudioDeviceOutputEvent(); - string GetActiveAudioOutputDeviceName(); - string[] ListAudioOutputDeviceName(); - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs deleted file mode 100644 index 6bb4a5dec..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Threading; -using System; - -namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer -{ - interface IAudioRenderer : IDisposable - { - uint GetSampleRate(); - uint GetSampleCount(); - uint GetMixBufferCount(); - int GetState(); - ResultCode RequestUpdate(Memory output, Memory performanceOutput, ReadOnlyMemory input); - ResultCode Start(); - ResultCode Stop(); - ResultCode QuerySystemEvent(out KEvent systemEvent); - void SetRenderingTimeLimit(uint percent); - uint GetRenderingTimeLimit(); - ResultCode ExecuteAudioRendererRendering(); - void SetVoiceDropParameter(float voiceDropParameter); - float GetVoiceDropParameter(); - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs deleted file mode 100644 index 87d0001e3..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Ryujinx.Audio.Renderer.Device; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server; -using Ryujinx.HLE.HOS.Kernel.Memory; -using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer; - -using AudioRendererManagerImpl = Ryujinx.Audio.Renderer.Server.AudioRendererManager; - -namespace Ryujinx.HLE.HOS.Services.Audio -{ - class AudioRendererManager : IAudioRendererManager - { - private readonly AudioRendererManagerImpl _impl; - private readonly VirtualDeviceSessionRegistry _registry; - - public AudioRendererManager(AudioRendererManagerImpl impl, VirtualDeviceSessionRegistry registry) - { - _impl = impl; - _registry = registry; - } - - public ResultCode GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context, out IAudioDevice outObject, int revision, ulong appletResourceUserId) - { - outObject = new AudioDevice(_registry, context.Device.System.KernelContext, appletResourceUserId, revision); - - return ResultCode.Success; - } - - public ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter) - { - return AudioRendererManagerImpl.GetWorkBufferSize(ref parameter); - } - - public ResultCode OpenAudioRenderer( - ServiceCtx context, - out IAudioRenderer obj, - ref AudioRendererConfiguration parameter, - ulong workBufferSize, - ulong appletResourceUserId, - KTransferMemory workBufferTransferMemory, - uint processHandle) - { - var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory; - - ResultCode result = (ResultCode)_impl.OpenAudioRenderer( - out AudioRenderSystem renderer, - memoryManager, - ref parameter, - appletResourceUserId, - workBufferTransferMemory.Address, - workBufferTransferMemory.Size, - processHandle, - context.Device.Configuration.AudioVolume); - - if (result == ResultCode.Success) - { - obj = new AudioRenderer.AudioRenderer(renderer); - } - else - { - obj = null; - } - - return result; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs b/src/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs deleted file mode 100644 index 38a841d82..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs +++ /dev/null @@ -1,116 +0,0 @@ -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Kernel.Memory; -using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer; - -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audren:u")] - class AudioRendererManagerServer : IpcService - { - private const int InitialRevision = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('1' << 24); - - private readonly IAudioRendererManager _impl; - - public AudioRendererManagerServer(ServiceCtx context) : this(context, new AudioRendererManager(context.Device.System.AudioRendererManager, context.Device.System.AudioDeviceSessionRegistry)) { } - - public AudioRendererManagerServer(ServiceCtx context, IAudioRendererManager impl) : base(context.Device.System.AudRenServer) - { - _impl = impl; - } - - [CommandCmif(0)] - // OpenAudioRenderer(nn::audio::detail::AudioRendererParameterInternal parameter, u64 workBufferSize, nn::applet::AppletResourceUserId appletResourceId, pid, handle workBuffer, handle processHandle) - // -> object - public ResultCode OpenAudioRenderer(ServiceCtx context) - { - AudioRendererConfiguration parameter = context.RequestData.ReadStruct(); - ulong workBufferSize = context.RequestData.ReadUInt64(); - ulong appletResourceUserId = context.RequestData.ReadUInt64(); - - int transferMemoryHandle = context.Request.HandleDesc.ToCopy[0]; - KTransferMemory workBufferTransferMemory = context.Process.HandleTable.GetObject(transferMemoryHandle); - uint processHandle = (uint)context.Request.HandleDesc.ToCopy[1]; - - ResultCode result = _impl.OpenAudioRenderer( - context, - out IAudioRenderer renderer, - ref parameter, - workBufferSize, - appletResourceUserId, - workBufferTransferMemory, - processHandle); - - if (result == ResultCode.Success) - { - MakeObject(context, new AudioRendererServer(renderer)); - } - - context.Device.System.KernelContext.Syscall.CloseHandle(transferMemoryHandle); - context.Device.System.KernelContext.Syscall.CloseHandle((int)processHandle); - - return result; - } - - [CommandCmif(1)] - // GetWorkBufferSize(nn::audio::detail::AudioRendererParameterInternal parameter) -> u64 workBufferSize - public ResultCode GetAudioRendererWorkBufferSize(ServiceCtx context) - { - AudioRendererConfiguration parameter = context.RequestData.ReadStruct(); - - if (BehaviourContext.CheckValidRevision(parameter.Revision)) - { - ulong size = _impl.GetWorkBufferSize(ref parameter); - - context.ResponseData.Write(size); - - Logger.Debug?.Print(LogClass.ServiceAudio, $"WorkBufferSize is 0x{size:x16}."); - - return ResultCode.Success; - } - else - { - context.ResponseData.Write(0L); - - Logger.Warning?.Print(LogClass.ServiceAudio, $"Library Revision REV{BehaviourContext.GetRevisionNumber(parameter.Revision)} is not supported!"); - - return ResultCode.UnsupportedRevision; - } - } - - [CommandCmif(2)] - // GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object - public ResultCode GetAudioDeviceService(ServiceCtx context) - { - ulong appletResourceUserId = context.RequestData.ReadUInt64(); - - ResultCode result = _impl.GetAudioDeviceServiceWithRevisionInfo(context, out IAudioDevice device, InitialRevision, appletResourceUserId); - - if (result == ResultCode.Success) - { - MakeObject(context, new AudioDeviceServer(device)); - } - - return result; - } - - [CommandCmif(4)] // 4.0.0+ - // GetAudioDeviceServiceWithRevisionInfo(s32 revision, nn::applet::AppletResourceUserId appletResourceId) -> object - public ResultCode GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context) - { - int revision = context.RequestData.ReadInt32(); - ulong appletResourceUserId = context.RequestData.ReadUInt64(); - - ResultCode result = _impl.GetAudioDeviceServiceWithRevisionInfo(context, out IAudioDevice device, revision, appletResourceUserId); - - if (result == ResultCode.Success) - { - MakeObject(context, new AudioDeviceServer(device)); - } - - return result; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/Decoder.cs b/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/Decoder.cs deleted file mode 100644 index c5dd2f00d..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/Decoder.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Concentus.Structs; - -namespace Ryujinx.HLE.HOS.Services.Audio.HardwareOpusDecoderManager -{ - class Decoder : IDecoder - { - private readonly OpusDecoder _decoder; - - public int SampleRate => _decoder.SampleRate; - public int ChannelsCount => _decoder.NumChannels; - - public Decoder(int sampleRate, int channelsCount) - { - _decoder = new OpusDecoder(sampleRate, channelsCount); - } - - public int Decode(byte[] inData, int inDataOffset, int len, short[] outPcm, int outPcmOffset, int frameSize) - { - return _decoder.Decode(inData, inDataOffset, len, outPcm, outPcmOffset, frameSize); - } - - public void ResetState() - { - _decoder.ResetState(); - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/DecoderCommon.cs b/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/DecoderCommon.cs deleted file mode 100644 index 9ff511a50..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/DecoderCommon.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Concentus; -using Concentus.Enums; -using Concentus.Structs; -using Ryujinx.HLE.HOS.Services.Audio.Types; -using System; -using System.Runtime.CompilerServices; - -namespace Ryujinx.HLE.HOS.Services.Audio.HardwareOpusDecoderManager -{ - static class DecoderCommon - { - private static ResultCode GetPacketNumSamples(this IDecoder decoder, out int numSamples, byte[] packet) - { - int result = OpusPacketInfo.GetNumSamples(packet, 0, packet.Length, decoder.SampleRate); - - numSamples = result; - - if (result == OpusError.OPUS_INVALID_PACKET) - { - return ResultCode.OpusInvalidInput; - } - else if (result == OpusError.OPUS_BAD_ARG) - { - return ResultCode.OpusInvalidInput; - } - - return ResultCode.Success; - } - - public static ResultCode DecodeInterleaved( - this IDecoder decoder, - bool reset, - ReadOnlySpan input, - out short[] outPcmData, - ulong outputSize, - out uint outConsumed, - out int outSamples) - { - outPcmData = null; - outConsumed = 0; - outSamples = 0; - - int streamSize = input.Length; - - if (streamSize < Unsafe.SizeOf()) - { - return ResultCode.OpusInvalidInput; - } - - OpusPacketHeader header = OpusPacketHeader.FromSpan(input); - int headerSize = Unsafe.SizeOf(); - uint totalSize = header.length + (uint)headerSize; - - if (totalSize > streamSize) - { - return ResultCode.OpusInvalidInput; - } - - byte[] opusData = input.Slice(headerSize, (int)header.length).ToArray(); - - ResultCode result = decoder.GetPacketNumSamples(out int numSamples, opusData); - - if (result == ResultCode.Success) - { - if ((uint)numSamples * (uint)decoder.ChannelsCount * sizeof(short) > outputSize) - { - return ResultCode.OpusInvalidInput; - } - - outPcmData = new short[numSamples * decoder.ChannelsCount]; - - if (reset) - { - decoder.ResetState(); - } - - try - { - outSamples = decoder.Decode(opusData, 0, opusData.Length, outPcmData, 0, outPcmData.Length / decoder.ChannelsCount); - outConsumed = totalSize; - } - catch (OpusException) - { - // TODO: as OpusException doesn't provide us the exact error code, this is kind of inaccurate in some cases... - return ResultCode.OpusInvalidInput; - } - } - - return ResultCode.Success; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IDecoder.cs b/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IDecoder.cs deleted file mode 100644 index cc83be5e3..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IDecoder.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio.HardwareOpusDecoderManager -{ - interface IDecoder - { - int SampleRate { get; } - int ChannelsCount { get; } - - int Decode(byte[] inData, int inDataOffset, int len, short[] outPcm, int outPcmOffset, int frameSize); - void ResetState(); - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IHardwareOpusDecoder.cs b/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IHardwareOpusDecoder.cs deleted file mode 100644 index 3d5d2839f..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IHardwareOpusDecoder.cs +++ /dev/null @@ -1,116 +0,0 @@ -using Ryujinx.HLE.HOS.Services.Audio.Types; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Audio.HardwareOpusDecoderManager -{ - class IHardwareOpusDecoder : IpcService - { - private readonly IDecoder _decoder; - private readonly OpusDecoderFlags _flags; - - public IHardwareOpusDecoder(int sampleRate, int channelsCount, OpusDecoderFlags flags) - { - _decoder = new Decoder(sampleRate, channelsCount); - _flags = flags; - } - - public IHardwareOpusDecoder(int sampleRate, int channelsCount, int streams, int coupledStreams, OpusDecoderFlags flags, byte[] mapping) - { - _decoder = new MultiSampleDecoder(sampleRate, channelsCount, streams, coupledStreams, mapping); - _flags = flags; - } - - [CommandCmif(0)] - // DecodeInterleavedOld(buffer) -> (u32, u32, buffer) - public ResultCode DecodeInterleavedOld(ServiceCtx context) - { - return DecodeInterleavedInternal(context, OpusDecoderFlags.None, reset: false, withPerf: false); - } - - [CommandCmif(2)] - // DecodeInterleavedForMultiStreamOld(buffer) -> (u32, u32, buffer) - public ResultCode DecodeInterleavedForMultiStreamOld(ServiceCtx context) - { - return DecodeInterleavedInternal(context, OpusDecoderFlags.None, reset: false, withPerf: false); - } - - [CommandCmif(4)] // 6.0.0+ - // DecodeInterleavedWithPerfOld(buffer) -> (u32, u32, u64, buffer) - public ResultCode DecodeInterleavedWithPerfOld(ServiceCtx context) - { - return DecodeInterleavedInternal(context, OpusDecoderFlags.None, reset: false, withPerf: true); - } - - [CommandCmif(5)] // 6.0.0+ - // DecodeInterleavedForMultiStreamWithPerfOld(buffer) -> (u32, u32, u64, buffer) - public ResultCode DecodeInterleavedForMultiStreamWithPerfOld(ServiceCtx context) - { - return DecodeInterleavedInternal(context, OpusDecoderFlags.None, reset: false, withPerf: true); - } - - [CommandCmif(6)] // 6.0.0+ - // DecodeInterleavedWithPerfAndResetOld(bool reset, buffer) -> (u32, u32, u64, buffer) - public ResultCode DecodeInterleavedWithPerfAndResetOld(ServiceCtx context) - { - bool reset = context.RequestData.ReadBoolean(); - - return DecodeInterleavedInternal(context, OpusDecoderFlags.None, reset, withPerf: true); - } - - [CommandCmif(7)] // 6.0.0+ - // DecodeInterleavedForMultiStreamWithPerfAndResetOld(bool reset, buffer) -> (u32, u32, u64, buffer) - public ResultCode DecodeInterleavedForMultiStreamWithPerfAndResetOld(ServiceCtx context) - { - bool reset = context.RequestData.ReadBoolean(); - - return DecodeInterleavedInternal(context, OpusDecoderFlags.None, reset, withPerf: true); - } - - [CommandCmif(8)] // 7.0.0+ - // DecodeInterleaved(bool reset, buffer) -> (u32, u32, u64, buffer) - public ResultCode DecodeInterleaved(ServiceCtx context) - { - bool reset = context.RequestData.ReadBoolean(); - - return DecodeInterleavedInternal(context, _flags, reset, withPerf: true); - } - - [CommandCmif(9)] // 7.0.0+ - // DecodeInterleavedForMultiStream(bool reset, buffer) -> (u32, u32, u64, buffer) - public ResultCode DecodeInterleavedForMultiStream(ServiceCtx context) - { - bool reset = context.RequestData.ReadBoolean(); - - return DecodeInterleavedInternal(context, _flags, reset, withPerf: true); - } - - private ResultCode DecodeInterleavedInternal(ServiceCtx context, OpusDecoderFlags flags, bool reset, bool withPerf) - { - ulong inPosition = context.Request.SendBuff[0].Position; - ulong inSize = context.Request.SendBuff[0].Size; - ulong outputPosition = context.Request.ReceiveBuff[0].Position; - ulong outputSize = context.Request.ReceiveBuff[0].Size; - - ReadOnlySpan input = context.Memory.GetSpan(inPosition, (int)inSize); - - ResultCode result = _decoder.DecodeInterleaved(reset, input, out short[] outPcmData, outputSize, out uint outConsumed, out int outSamples); - - if (result == ResultCode.Success) - { - context.Memory.Write(outputPosition, MemoryMarshal.Cast(outPcmData.AsSpan())); - - context.ResponseData.Write(outConsumed); - context.ResponseData.Write(outSamples); - - if (withPerf) - { - // This is the time the DSP took to process the request, TODO: fill this. - context.ResponseData.Write(0UL); - } - } - - return result; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/MultiSampleDecoder.cs b/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/MultiSampleDecoder.cs deleted file mode 100644 index 910bb23ee..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/MultiSampleDecoder.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Concentus.Structs; - -namespace Ryujinx.HLE.HOS.Services.Audio.HardwareOpusDecoderManager -{ - class MultiSampleDecoder : IDecoder - { - private readonly OpusMSDecoder _decoder; - - public int SampleRate => _decoder.SampleRate; - public int ChannelsCount { get; } - - public MultiSampleDecoder(int sampleRate, int channelsCount, int streams, int coupledStreams, byte[] mapping) - { - ChannelsCount = channelsCount; - _decoder = new OpusMSDecoder(sampleRate, channelsCount, streams, coupledStreams, mapping); - } - - public int Decode(byte[] inData, int inDataOffset, int len, short[] outPcm, int outPcmOffset, int frameSize) - { - return _decoder.DecodeMultistream(inData, inDataOffset, len, outPcm, outPcmOffset, frameSize, 0); - } - - public void ResetState() - { - _decoder.ResetState(); - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioController.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IAudioController.cs deleted file mode 100644 index a250ec799..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioController.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audctl")] - class IAudioController : IpcService - { - public IAudioController(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs deleted file mode 100644 index 861e9f2dc..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.HLE.HOS.Services.Audio.AudioIn; - -namespace Ryujinx.HLE.HOS.Services.Audio -{ - interface IAudioInManager - { - public string[] ListAudioIns(bool filtered); - - public ResultCode OpenAudioIn(ServiceCtx context, out string outputDeviceName, out AudioOutputConfiguration outputConfiguration, out IAudioIn obj, string inputDeviceName, ref AudioInputConfiguration parameter, ulong appletResourceUserId, uint processHandle); - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForApplet.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForApplet.cs deleted file mode 100644 index d0c385b56..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForApplet.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audin:a")] - class IAudioInManagerForApplet : IpcService - { - public IAudioInManagerForApplet(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForDebugger.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForDebugger.cs deleted file mode 100644 index 120136158..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForDebugger.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audin:d")] - class IAudioInManagerForDebugger : IpcService - { - public IAudioInManagerForDebugger(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs deleted file mode 100644 index cd7cbe41c..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.HLE.HOS.Services.Audio.AudioOut; - -namespace Ryujinx.HLE.HOS.Services.Audio -{ - interface IAudioOutManager - { - public string[] ListAudioOuts(); - - public ResultCode OpenAudioOut(ServiceCtx context, out string outputDeviceName, out AudioOutputConfiguration outputConfiguration, out IAudioOut obj, string inputDeviceName, ref AudioInputConfiguration parameter, ulong appletResourceUserId, uint processHandle, float volume); - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForApplet.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForApplet.cs deleted file mode 100644 index 9925777e2..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForApplet.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audout:a")] - class IAudioOutManagerForApplet : IpcService - { - public IAudioOutManagerForApplet(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForDebugger.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForDebugger.cs deleted file mode 100644 index c41767a01..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForDebugger.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audout:d")] - class IAudioOutManagerForDebugger : IpcService - { - public IAudioOutManagerForDebugger(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs deleted file mode 100644 index 112e246c0..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.HLE.HOS.Kernel.Memory; -using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer; - -namespace Ryujinx.HLE.HOS.Services.Audio -{ - interface IAudioRendererManager - { - // TODO: Remove ServiceCtx argument - // BODY: This is only needed by the legacy backend. Refactor this when removing the legacy backend. - ResultCode GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context, out IAudioDevice outObject, int revision, ulong appletResourceUserId); - - // TODO: Remove ServiceCtx argument - // BODY: This is only needed by the legacy backend. Refactor this when removing the legacy backend. - ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle); - - ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter); - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForApplet.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForApplet.cs deleted file mode 100644 index dd767993d..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForApplet.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audren:a")] - class IAudioRendererManagerForApplet : IpcService - { - public IAudioRendererManagerForApplet(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForDebugger.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForDebugger.cs deleted file mode 100644 index cd2af09b2..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForDebugger.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audren:d")] - class IAudioRendererManagerForDebugger : IpcService - { - public IAudioRendererManagerForDebugger(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioSnoopManager.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IAudioSnoopManager.cs deleted file mode 100644 index aa9789ac5..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IAudioSnoopManager.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("auddev")] // 6.0.0+ - class IAudioSnoopManager : IpcService - { - public IAudioSnoopManager(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManager.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManager.cs deleted file mode 100644 index 9b58213e9..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManager.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audrec:u")] - class IFinalOutputRecorderManager : IpcService - { - public IFinalOutputRecorderManager(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForApplet.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForApplet.cs deleted file mode 100644 index e2d62eee3..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForApplet.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audrec:a")] - class IFinalOutputRecorderManagerForApplet : IpcService - { - public IFinalOutputRecorderManagerForApplet(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForDebugger.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForDebugger.cs deleted file mode 100644 index 7ded79435..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForDebugger.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("audrec:d")] - class IFinalOutputRecorderManagerForDebugger : IpcService - { - public IFinalOutputRecorderManagerForDebugger(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs b/src/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs deleted file mode 100644 index 514b51a51..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs +++ /dev/null @@ -1,227 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Services.Audio.HardwareOpusDecoderManager; -using Ryujinx.HLE.HOS.Services.Audio.Types; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Audio -{ - [Service("hwopus")] - class IHardwareOpusDecoderManager : IpcService - { - public IHardwareOpusDecoderManager(ServiceCtx context) { } - - [CommandCmif(0)] - // Initialize(bytes<8, 4>, u32, handle) -> object - public ResultCode Initialize(ServiceCtx context) - { - int sampleRate = context.RequestData.ReadInt32(); - int channelsCount = context.RequestData.ReadInt32(); - - MakeObject(context, new IHardwareOpusDecoder(sampleRate, channelsCount, OpusDecoderFlags.None)); - - // Close transfer memory immediately as we don't use it. - context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]); - - return ResultCode.Success; - } - - [CommandCmif(1)] - // GetWorkBufferSize(bytes<8, 4>) -> u32 - public ResultCode GetWorkBufferSize(ServiceCtx context) - { - int sampleRate = context.RequestData.ReadInt32(); - int channelsCount = context.RequestData.ReadInt32(); - - int opusDecoderSize = GetOpusDecoderSize(channelsCount); - - int frameSize = BitUtils.AlignUp(channelsCount * 1920 / (48000 / sampleRate), 64); - int totalSize = opusDecoderSize + 1536 + frameSize; - - context.ResponseData.Write(totalSize); - - return ResultCode.Success; - } - - [CommandCmif(2)] // 3.0.0+ - // InitializeForMultiStream(u32, handle, buffer, 0x19>) -> object - public ResultCode InitializeForMultiStream(ServiceCtx context) - { - ulong parametersAddress = context.Request.PtrBuff[0].Position; - - OpusMultiStreamParameters parameters = context.Memory.Read(parametersAddress); - - MakeObject(context, new IHardwareOpusDecoder(parameters.SampleRate, parameters.ChannelsCount, OpusDecoderFlags.None)); - - // Close transfer memory immediately as we don't use it. - context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]); - - return ResultCode.Success; - } - - [CommandCmif(3)] // 3.0.0+ - // GetWorkBufferSizeForMultiStream(buffer, 0x19>) -> u32 - public ResultCode GetWorkBufferSizeForMultiStream(ServiceCtx context) - { - ulong parametersAddress = context.Request.PtrBuff[0].Position; - - OpusMultiStreamParameters parameters = context.Memory.Read(parametersAddress); - - int opusDecoderSize = GetOpusMultistreamDecoderSize(parameters.NumberOfStreams, parameters.NumberOfStereoStreams); - - int streamSize = BitUtils.AlignUp(parameters.NumberOfStreams * 1500, 64); - int frameSize = BitUtils.AlignUp(parameters.ChannelsCount * 1920 / (48000 / parameters.SampleRate), 64); - int totalSize = opusDecoderSize + streamSize + frameSize; - - context.ResponseData.Write(totalSize); - - return ResultCode.Success; - } - - [CommandCmif(4)] // 12.0.0+ - // InitializeEx(OpusParametersEx, u32, handle) -> object - public ResultCode InitializeEx(ServiceCtx context) - { - OpusParametersEx parameters = context.RequestData.ReadStruct(); - - // UseLargeFrameSize can be ignored due to not relying on fixed size buffers for storing the decoded result. - MakeObject(context, new IHardwareOpusDecoder(parameters.SampleRate, parameters.ChannelsCount, parameters.Flags)); - - // Close transfer memory immediately as we don't use it. - context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]); - - return ResultCode.Success; - } - - [CommandCmif(5)] // 12.0.0+ - // GetWorkBufferSizeEx(OpusParametersEx) -> u32 - public ResultCode GetWorkBufferSizeEx(ServiceCtx context) - { - OpusParametersEx parameters = context.RequestData.ReadStruct(); - - int opusDecoderSize = GetOpusDecoderSize(parameters.ChannelsCount); - - int frameSizeMono48KHz = parameters.Flags.HasFlag(OpusDecoderFlags.LargeFrameSize) ? 5760 : 1920; - int frameSize = BitUtils.AlignUp(parameters.ChannelsCount * frameSizeMono48KHz / (48000 / parameters.SampleRate), 64); - int totalSize = opusDecoderSize + 1536 + frameSize; - - context.ResponseData.Write(totalSize); - - return ResultCode.Success; - } - - [CommandCmif(6)] // 12.0.0+ - // InitializeForMultiStreamEx(u32, handle, buffer, 0x19>) -> object - public ResultCode InitializeForMultiStreamEx(ServiceCtx context) - { - ulong parametersAddress = context.Request.PtrBuff[0].Position; - - OpusMultiStreamParametersEx parameters = context.Memory.Read(parametersAddress); - - byte[] mappings = MemoryMarshal.Cast(parameters.ChannelMappings.AsSpan()).ToArray(); - - // UseLargeFrameSize can be ignored due to not relying on fixed size buffers for storing the decoded result. - MakeObject(context, new IHardwareOpusDecoder( - parameters.SampleRate, - parameters.ChannelsCount, - parameters.NumberOfStreams, - parameters.NumberOfStereoStreams, - parameters.Flags, - mappings)); - - // Close transfer memory immediately as we don't use it. - context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]); - - return ResultCode.Success; - } - - [CommandCmif(7)] // 12.0.0+ - // GetWorkBufferSizeForMultiStreamEx(buffer, 0x19>) -> u32 - public ResultCode GetWorkBufferSizeForMultiStreamEx(ServiceCtx context) - { - ulong parametersAddress = context.Request.PtrBuff[0].Position; - - OpusMultiStreamParametersEx parameters = context.Memory.Read(parametersAddress); - - int opusDecoderSize = GetOpusMultistreamDecoderSize(parameters.NumberOfStreams, parameters.NumberOfStereoStreams); - - int frameSizeMono48KHz = parameters.Flags.HasFlag(OpusDecoderFlags.LargeFrameSize) ? 5760 : 1920; - int streamSize = BitUtils.AlignUp(parameters.NumberOfStreams * 1500, 64); - int frameSize = BitUtils.AlignUp(parameters.ChannelsCount * frameSizeMono48KHz / (48000 / parameters.SampleRate), 64); - int totalSize = opusDecoderSize + streamSize + frameSize; - - context.ResponseData.Write(totalSize); - - return ResultCode.Success; - } - - [CommandCmif(8)] // 16.0.0+ - // GetWorkBufferSizeExEx(OpusParametersEx) -> u32 - public ResultCode GetWorkBufferSizeExEx(ServiceCtx context) - { - // NOTE: GetWorkBufferSizeEx use hardcoded values to compute the returned size. - // GetWorkBufferSizeExEx fixes that by using dynamic values. - // Since we're already doing that, it's fine to call it directly. - - return GetWorkBufferSizeEx(context); - } - - [CommandCmif(9)] // 16.0.0+ - // GetWorkBufferSizeForMultiStreamExEx(buffer, 0x19>) -> u32 - public ResultCode GetWorkBufferSizeForMultiStreamExEx(ServiceCtx context) - { - // NOTE: GetWorkBufferSizeForMultiStreamEx use hardcoded values to compute the returned size. - // GetWorkBufferSizeForMultiStreamExEx fixes that by using dynamic values. - // Since we're already doing that, it's fine to call it directly. - - return GetWorkBufferSizeForMultiStreamEx(context); - } - - private static int GetOpusMultistreamDecoderSize(int streams, int coupledStreams) - { - if (streams < 1 || coupledStreams > streams || coupledStreams < 0) - { - return 0; - } - - int coupledSize = GetOpusDecoderSize(2); - int monoSize = GetOpusDecoderSize(1); - - return Align4(monoSize - GetOpusDecoderAllocSize(1)) * (streams - coupledStreams) + - Align4(coupledSize - GetOpusDecoderAllocSize(2)) * coupledStreams + 0xb90c; - } - - private static int Align4(int value) - { - return BitUtils.AlignUp(value, 4); - } - - private static int GetOpusDecoderSize(int channelsCount) - { - const int SilkDecoderSize = 0x2160; - - if (channelsCount < 1 || channelsCount > 2) - { - return 0; - } - - int celtDecoderSize = GetCeltDecoderSize(channelsCount); - int opusDecoderSize = GetOpusDecoderAllocSize(channelsCount) | 0x4c; - - return opusDecoderSize + SilkDecoderSize + celtDecoderSize; - } - - private static int GetOpusDecoderAllocSize(int channelsCount) - { - return (channelsCount * 0x800 + 0x4803) & -0x800; - } - - private static int GetCeltDecoderSize(int channelsCount) - { - const int DecodeBufferSize = 0x2030; - const int Overlap = 120; - const int EBandsCount = 21; - - return (DecodeBufferSize + Overlap * 4) * channelsCount + EBandsCount * 16 + 0x50; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/ResultCode.cs b/src/Ryujinx.HLE/HOS/Services/Audio/ResultCode.cs deleted file mode 100644 index c1d49109c..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/ResultCode.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio -{ - enum ResultCode - { - ModuleId = 153, - ErrorCodeShift = 9, - - Success = 0, - - DeviceNotFound = (1 << ErrorCodeShift) | ModuleId, - UnsupportedRevision = (2 << ErrorCodeShift) | ModuleId, - UnsupportedSampleRate = (3 << ErrorCodeShift) | ModuleId, - BufferSizeTooSmall = (4 << ErrorCodeShift) | ModuleId, - OpusInvalidInput = (6 << ErrorCodeShift) | ModuleId, - TooManyBuffersInUse = (8 << ErrorCodeShift) | ModuleId, - InvalidChannelCount = (10 << ErrorCodeShift) | ModuleId, - InvalidOperation = (513 << ErrorCodeShift) | ModuleId, - InvalidHandle = (1536 << ErrorCodeShift) | ModuleId, - OutputAlreadyStarted = (1540 << ErrorCodeShift) | ModuleId, - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusPacketHeader.cs b/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusPacketHeader.cs deleted file mode 100644 index 099769b3a..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusPacketHeader.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Buffers.Binary; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Audio.Types -{ - [StructLayout(LayoutKind.Sequential)] - struct OpusPacketHeader - { - public uint length; - public uint finalRange; - - public static OpusPacketHeader FromSpan(ReadOnlySpan data) - { - OpusPacketHeader header = MemoryMarshal.Cast(data)[0]; - - header.length = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(header.length) : header.length; - header.finalRange = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(header.finalRange) : header.finalRange; - - return header; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusParametersEx.cs b/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusParametersEx.cs deleted file mode 100644 index 4d1e0c824..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusParametersEx.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Audio.Types -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10)] - struct OpusParametersEx - { - public int SampleRate; - public int ChannelsCount; - public OpusDecoderFlags Flags; - - Array4 Padding1; - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Caps/CaptureManager.cs b/src/Ryujinx.HLE/HOS/Services/Caps/CaptureManager.cs index 91a8958e6..bf0c7e9dc 100644 --- a/src/Ryujinx.HLE/HOS/Services/Caps/CaptureManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Caps/CaptureManager.cs @@ -1,10 +1,10 @@ using Ryujinx.Common.Memory; using Ryujinx.HLE.HOS.Services.Caps.Types; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; +using SkiaSharp; using System; using System.IO; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Security.Cryptography; namespace Ryujinx.HLE.HOS.Services.Caps @@ -118,7 +118,11 @@ namespace Ryujinx.HLE.HOS.Services.Caps } // NOTE: The saved JPEG file doesn't have the limitation in the extra EXIF data. - Image.LoadPixelData(screenshotData, 1280, 720).SaveAsJpegAsync(filePath); + using var bitmap = new SKBitmap(new SKImageInfo(1280, 720, SKColorType.Rgba8888)); + Marshal.Copy(screenshotData, 0, bitmap.GetPixels(), screenshotData.Length); + using var data = bitmap.Encode(SKEncodedImageFormat.Jpeg, 80); + using var file = File.OpenWrite(filePath); + data.SaveTo(file); return ResultCode.Success; } diff --git a/src/Ryujinx.HLE/HOS/Services/Fatal/IService.cs b/src/Ryujinx.HLE/HOS/Services/Fatal/IService.cs index 21daf8758..155077745 100644 --- a/src/Ryujinx.HLE/HOS/Services/Fatal/IService.cs +++ b/src/Ryujinx.HLE/HOS/Services/Fatal/IService.cs @@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.Services.Fatal errorReport.AppendLine($"\tResultCode: {((int)resultCode & 0x1FF) + 2000}-{((int)resultCode >> 9) & 0x3FFF:d4}"); errorReport.AppendLine($"\tFatalPolicy: {fatalPolicy}"); - if (cpuContext != null) + if (!cpuContext.IsEmpty) { errorReport.AppendLine("CPU Context:"); diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs b/src/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs deleted file mode 100644 index 3f15f3fc6..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator; - -namespace Ryujinx.HLE.HOS.Services.Friend -{ - [Service("friend:a", FriendServicePermissionLevel.Administrator)] - [Service("friend:m", FriendServicePermissionLevel.Manager)] - [Service("friend:s", FriendServicePermissionLevel.System)] - [Service("friend:u", FriendServicePermissionLevel.User)] - [Service("friend:v", FriendServicePermissionLevel.Viewer)] - class IServiceCreator : IpcService - { - private readonly FriendServicePermissionLevel _permissionLevel; - - public IServiceCreator(ServiceCtx context, FriendServicePermissionLevel permissionLevel) - { - _permissionLevel = permissionLevel; - } - - [CommandCmif(0)] - // CreateFriendService() -> object - public ResultCode CreateFriendService(ServiceCtx context) - { - MakeObject(context, new IFriendService(_permissionLevel)); - - return ResultCode.Success; - } - - [CommandCmif(1)] // 2.0.0+ - // CreateNotificationService(nn::account::Uid userId) -> object - public ResultCode CreateNotificationService(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - MakeObject(context, new INotificationService(context, userId, _permissionLevel)); - - return ResultCode.Success; - } - - [CommandCmif(2)] // 4.0.0+ - // CreateDaemonSuspendSessionService() -> object - public ResultCode CreateDaemonSuspendSessionService(ServiceCtx context) - { - MakeObject(context, new IDaemonSuspendSessionService(_permissionLevel)); - - return ResultCode.Success; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ResultCode.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ResultCode.cs deleted file mode 100644 index 9f612059c..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ResultCode.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Friend -{ - enum ResultCode - { - ModuleId = 121, - ErrorCodeShift = 9, - - Success = 0, - - InvalidArgument = (2 << ErrorCodeShift) | ModuleId, - InternetRequestDenied = (6 << ErrorCodeShift) | ModuleId, - NotificationQueueEmpty = (15 << ErrorCodeShift) | ModuleId, - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs deleted file mode 100644 index 28745c3f2..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService -{ - [StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x200, CharSet = CharSet.Ansi)] - struct Friend - { - public UserId UserId; - public long NetworkUserId; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x21)] - public string Nickname; - - public UserPresence presence; - - [MarshalAs(UnmanagedType.I1)] - public bool IsFavourite; - - [MarshalAs(UnmanagedType.I1)] - public bool IsNew; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x6)] - readonly char[] Unknown; - - [MarshalAs(UnmanagedType.I1)] - public bool IsValid; - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs deleted file mode 100644 index 5f13f3136..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService -{ - [StructLayout(LayoutKind.Sequential)] - struct FriendFilter - { - public PresenceStatusFilter PresenceStatus; - - [MarshalAs(UnmanagedType.I1)] - public bool IsFavoriteOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsSameAppPresenceOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsSameAppPlayedOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsArbitraryAppPlayedOnly; - - public long PresenceGroupId; - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs deleted file mode 100644 index 80d142059..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Ryujinx.Common.Memory; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService -{ - [StructLayout(LayoutKind.Sequential, Pack = 0x8)] - struct UserPresence - { - public UserId UserId; - public long LastTimeOnlineTimestamp; - public PresenceStatus Status; - - [MarshalAs(UnmanagedType.I1)] - public bool SamePresenceGroupApplication; - - public Array3 Unknown; - private AppKeyValueStorageHolder _appKeyValueStorage; - - public Span AppKeyValueStorage => MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref _appKeyValueStorage, AppKeyValueStorageHolder.Size)); - - [StructLayout(LayoutKind.Sequential, Pack = 0x1, Size = Size)] - private struct AppKeyValueStorageHolder - { - public const int Size = 0xC0; - } - - public readonly override string ToString() - { - return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status} }}"; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs deleted file mode 100644 index 3b1601abb..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator -{ - class IDaemonSuspendSessionService : IpcService - { -#pragma warning disable IDE0052 // Remove unread private member - private readonly FriendServicePermissionLevel _permissionLevel; -#pragma warning restore IDE0052 - - public IDaemonSuspendSessionService(FriendServicePermissionLevel permissionLevel) - { - _permissionLevel = permissionLevel; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs deleted file mode 100644 index 54d23e88c..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs +++ /dev/null @@ -1,374 +0,0 @@ -using LibHac.Ns; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Common.Memory; -using Ryujinx.Common.Utilities; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService; -using Ryujinx.Horizon.Common; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator -{ - class IFriendService : IpcService - { -#pragma warning disable IDE0052 // Remove unread private member - private readonly FriendServicePermissionLevel _permissionLevel; -#pragma warning restore IDE0052 - private KEvent _completionEvent; - - public IFriendService(FriendServicePermissionLevel permissionLevel) - { - _permissionLevel = permissionLevel; - } - - [CommandCmif(0)] - // GetCompletionEvent() -> handle - public ResultCode GetCompletionEvent(ServiceCtx context) - { - _completionEvent ??= new KEvent(context.Device.System.KernelContext); - - if (context.Process.HandleTable.GenerateHandle(_completionEvent.ReadableEvent, out int completionEventHandle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - _completionEvent.WritableEvent.Signal(); - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(completionEventHandle); - - return ResultCode.Success; - } - - [CommandCmif(1)] - // nn::friends::Cancel() - public ResultCode Cancel(ServiceCtx context) - { - // TODO: Original service sets an internal field to 1 here. Determine usage. - Logger.Stub?.PrintStub(LogClass.ServiceFriend); - - return ResultCode.Success; - } - - [CommandCmif(10100)] - // nn::friends::GetFriendListIds(int offset, nn::account::Uid userId, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) - // -> int outCount, array - public ResultCode GetFriendListIds(ServiceCtx context) - { - int offset = context.RequestData.ReadInt32(); - - // Padding - context.RequestData.ReadInt32(); - - UserId userId = context.RequestData.ReadStruct(); - FriendFilter filter = context.RequestData.ReadStruct(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. - context.ResponseData.Write(0); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new - { - UserId = userId.ToString(), - offset, - filter.PresenceStatus, - filter.IsFavoriteOnly, - filter.IsSameAppPresenceOnly, - filter.IsSameAppPlayedOnly, - filter.IsArbitraryAppPlayedOnly, - filter.PresenceGroupId, - }); - - return ResultCode.Success; - } - - [CommandCmif(10101)] - // nn::friends::GetFriendList(int offset, nn::account::Uid userId, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) - // -> int outCount, array - public ResultCode GetFriendList(ServiceCtx context) - { - int offset = context.RequestData.ReadInt32(); - - // Padding - context.RequestData.ReadInt32(); - - UserId userId = context.RequestData.ReadStruct(); - FriendFilter filter = context.RequestData.ReadStruct(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. - context.ResponseData.Write(0); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new - { - UserId = userId.ToString(), - offset, - filter.PresenceStatus, - filter.IsFavoriteOnly, - filter.IsSameAppPresenceOnly, - filter.IsSameAppPlayedOnly, - filter.IsArbitraryAppPlayedOnly, - filter.PresenceGroupId, - }); - - return ResultCode.Success; - } - - [CommandCmif(10120)] // 10.0.0+ - // nn::friends::IsFriendListCacheAvailable(nn::account::Uid userId) -> bool - public ResultCode IsFriendListCacheAvailable(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // TODO: Service mount the friends:/ system savedata and try to load friend.cache file, returns true if exists, false otherwise. - // NOTE: If no cache is available, guest then calls nn::friends::EnsureFriendListAvailable, we can avoid that by faking the cache check. - context.ResponseData.Write(true); - - // TODO: Since we don't support friend features, it's fine to stub it for now. - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10121)] // 10.0.0+ - // nn::friends::EnsureFriendListAvailable(nn::account::Uid userId) - public ResultCode EnsureFriendListAvailable(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // TODO: Service mount the friends:/ system savedata and create a friend.cache file for the given user id. - // Since we don't support friend features, it's fine to stub it for now. - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10400)] - // nn::friends::GetBlockedUserListIds(int offset, nn::account::Uid userId) -> (u32, buffer) - public ResultCode GetBlockedUserListIds(ServiceCtx context) - { - int offset = context.RequestData.ReadInt32(); - - // Padding - context.RequestData.ReadInt32(); - - UserId userId = context.RequestData.ReadStruct(); - - // There are no friends blocked, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. - context.ResponseData.Write(0); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { offset, UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10420)] - // nn::friends::CheckBlockedUserListAvailability(nn::account::Uid userId) -> bool - public ResultCode CheckBlockedUserListAvailability(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - // Yes, it is available. - context.ResponseData.Write(true); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10600)] - // nn::friends::DeclareOpenOnlinePlaySession(nn::account::Uid userId) - public ResultCode DeclareOpenOnlinePlaySession(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - context.Device.System.AccountManager.OpenUserOnlinePlay(userId); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10601)] - // nn::friends::DeclareCloseOnlinePlaySession(nn::account::Uid userId) - public ResultCode DeclareCloseOnlinePlaySession(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - context.Device.System.AccountManager.CloseUserOnlinePlay(userId); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10610)] - // nn::friends::UpdateUserPresence(nn::account::Uid, u64, pid, buffer) - public ResultCode UpdateUserPresence(ServiceCtx context) - { - UserId uuid = context.RequestData.ReadStruct(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - ulong position = context.Request.PtrBuff[0].Position; - ulong size = context.Request.PtrBuff[0].Size; - - ReadOnlySpan userPresenceInputArray = MemoryMarshal.Cast(context.Memory.GetSpan(position, (int)size)); - - if (uuid.IsNull) - { - return ResultCode.InvalidArgument; - } - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray = userPresenceInputArray.ToArray() }); - - return ResultCode.Success; - } - - [CommandCmif(10700)] - // nn::friends::GetPlayHistoryRegistrationKey(b8 unknown, nn::account::Uid) -> buffer - public ResultCode GetPlayHistoryRegistrationKey(ServiceCtx context) - { - bool unknownBool = context.RequestData.ReadBoolean(); - UserId userId = context.RequestData.ReadStruct(); - - context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize(0x40UL); - - ulong bufferPosition = context.Request.RecvListBuff[0].Position; - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // NOTE: Calls nn::friends::detail::service::core::PlayHistoryManager::GetInstance and stores the instance. - - byte[] randomBytes = new byte[8]; - - Random.Shared.NextBytes(randomBytes); - - // NOTE: Calls nn::friends::detail::service::core::UuidManager::GetInstance and stores the instance. - // Then call nn::friends::detail::service::core::AccountStorageManager::GetInstance and store the instance. - // Then it checks if an Uuid is already stored for the UserId, if not it generates a random Uuid. - // And store it in the savedata 8000000000000080 in the friends:/uid.bin file. - - Array16 randomGuid = new(); - - Guid.NewGuid().ToByteArray().AsSpan().CopyTo(randomGuid.AsSpan()); - - PlayHistoryRegistrationKey playHistoryRegistrationKey = new() - { - Type = 0x101, - KeyIndex = (byte)(randomBytes[0] & 7), - UserIdBool = 0, // TODO: Find it. - UnknownBool = (byte)(unknownBool ? 1 : 0), // TODO: Find it. - Reserved = new Array11(), - Uuid = randomGuid, - }; - - ReadOnlySpan playHistoryRegistrationKeyBuffer = SpanHelpers.AsByteSpan(ref playHistoryRegistrationKey); - - /* - - NOTE: The service uses the KeyIndex to get a random key from a keys buffer (since the key index is stored in the returned buffer). - We currently don't support play history and online services so we can use a blank key for now. - Code for reference: - - byte[] hmacKey = new byte[0x20]; - - HMACSHA256 hmacSha256 = new HMACSHA256(hmacKey); - byte[] hmacHash = hmacSha256.ComputeHash(playHistoryRegistrationKeyBuffer); - - */ - - context.Memory.Write(bufferPosition, playHistoryRegistrationKeyBuffer); - context.Memory.Write(bufferPosition + 0x20, new byte[0x20]); // HmacHash - - return ResultCode.Success; - } - - [CommandCmif(10702)] - // nn::friends::AddPlayHistory(nn::account::Uid, u64, pid, buffer, buffer, buffer) - public ResultCode AddPlayHistory(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - // Pid placeholder - context.RequestData.ReadInt64(); -#pragma warning disable IDE0059 // Remove unnecessary value assignment - ulong pid = context.Request.HandleDesc.PId; - - ulong playHistoryRegistrationKeyPosition = context.Request.PtrBuff[0].Position; - ulong playHistoryRegistrationKeySize = context.Request.PtrBuff[0].Size; - - ulong inAppScreenName1Position = context.Request.PtrBuff[1].Position; -#pragma warning restore IDE0059 - ulong inAppScreenName1Size = context.Request.PtrBuff[1].Size; - -#pragma warning disable IDE0059 // Remove unnecessary value assignment - ulong inAppScreenName2Position = context.Request.PtrBuff[2].Position; -#pragma warning restore IDE0059 - ulong inAppScreenName2Size = context.Request.PtrBuff[2].Size; - - if (userId.IsNull || inAppScreenName1Size > 0x48 || inAppScreenName2Size > 0x48) - { - return ResultCode.InvalidArgument; - } - - // TODO: Call nn::arp::GetApplicationControlProperty here when implemented. -#pragma warning disable IDE0059 // Remove unnecessary value assignment - ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties; -#pragma warning restore IDE0059 - - /* - - NOTE: The service calls nn::friends::detail::service::core::PlayHistoryManager to store informations using the registration key computed in GetPlayHistoryRegistrationKey. - Then calls nn::friends::detail::service::core::FriendListManager to update informations on the friend list. - We currently don't support play history and online services so it's fine to do nothing. - - */ - - Logger.Stub?.PrintStub(LogClass.ServiceFriend); - - return ResultCode.Success; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs deleted file mode 100644 index 8fc7a4609..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs +++ /dev/null @@ -1,178 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService; -using Ryujinx.Horizon.Common; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator -{ - class INotificationService : DisposableIpcService - { - private readonly UserId _userId; - private readonly FriendServicePermissionLevel _permissionLevel; - - private readonly object _lock = new(); - - private readonly KEvent _notificationEvent; - private int _notificationEventHandle = 0; - - private readonly LinkedList _notifications; - - private bool _hasNewFriendRequest; - private bool _hasFriendListUpdate; - - public INotificationService(ServiceCtx context, UserId userId, FriendServicePermissionLevel permissionLevel) - { - _userId = userId; - _permissionLevel = permissionLevel; - _notifications = new LinkedList(); - _notificationEvent = new KEvent(context.Device.System.KernelContext); - - _hasNewFriendRequest = false; - _hasFriendListUpdate = false; - - NotificationEventHandler.Instance.RegisterNotificationService(this); - } - - [CommandCmif(0)] //2.0.0+ - // nn::friends::detail::ipc::INotificationService::GetEvent() -> handle - public ResultCode GetEvent(ServiceCtx context) - { - if (_notificationEventHandle == 0) - { - if (context.Process.HandleTable.GenerateHandle(_notificationEvent.ReadableEvent, out _notificationEventHandle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_notificationEventHandle); - - return ResultCode.Success; - } - - [CommandCmif(1)] //2.0.0+ - // nn::friends::detail::ipc::INotificationService::Clear() - public ResultCode Clear(ServiceCtx context) - { - lock (_lock) - { - _hasNewFriendRequest = false; - _hasFriendListUpdate = false; - - _notifications.Clear(); - } - - return ResultCode.Success; - } - - [CommandCmif(2)] // 2.0.0+ - // nn::friends::detail::ipc::INotificationService::Pop() -> nn::friends::detail::ipc::SizedNotificationInfo - public ResultCode Pop(ServiceCtx context) - { - lock (_lock) - { - if (_notifications.Count >= 1) - { - NotificationInfo notificationInfo = _notifications.First.Value; - _notifications.RemoveFirst(); - - if (notificationInfo.Type == NotificationEventType.FriendListUpdate) - { - _hasFriendListUpdate = false; - } - else if (notificationInfo.Type == NotificationEventType.NewFriendRequest) - { - _hasNewFriendRequest = false; - } - - context.ResponseData.WriteStruct(notificationInfo); - - return ResultCode.Success; - } - } - - return ResultCode.NotificationQueueEmpty; - } - - public void SignalFriendListUpdate(UserId targetId) - { - lock (_lock) - { - if (_userId == targetId) - { - if (!_hasFriendListUpdate) - { - NotificationInfo friendListNotification = new(); - - if (_notifications.Count != 0) - { - friendListNotification = _notifications.First.Value; - _notifications.RemoveFirst(); - } - - friendListNotification.Type = NotificationEventType.FriendListUpdate; - _hasFriendListUpdate = true; - - if (_hasNewFriendRequest) - { - NotificationInfo newFriendRequestNotification = new(); - - if (_notifications.Count != 0) - { - newFriendRequestNotification = _notifications.First.Value; - _notifications.RemoveFirst(); - } - - newFriendRequestNotification.Type = NotificationEventType.NewFriendRequest; - _notifications.AddFirst(newFriendRequestNotification); - } - - // We defer this to make sure we are on top of the queue. - _notifications.AddFirst(friendListNotification); - } - - _notificationEvent.ReadableEvent.Signal(); - } - } - } - - public void SignalNewFriendRequest(UserId targetId) - { - lock (_lock) - { - if ((_permissionLevel & FriendServicePermissionLevel.ViewerMask) != 0 && _userId == targetId) - { - if (!_hasNewFriendRequest) - { - if (_notifications.Count == 100) - { - SignalFriendListUpdate(targetId); - } - - NotificationInfo newFriendRequestNotification = new() - { - Type = NotificationEventType.NewFriendRequest, - }; - - _notifications.AddLast(newFriendRequestNotification); - _hasNewFriendRequest = true; - } - - _notificationEvent.ReadableEvent.Signal(); - } - } - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) - { - NotificationEventHandler.Instance.UnregisterNotificationService(this); - } - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs deleted file mode 100644 index 88627fd78..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Ryujinx.HLE.HOS.Services.Account.Acc; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService -{ - public sealed class NotificationEventHandler - { - private static NotificationEventHandler _instance; - private static readonly object _instanceLock = new(); - - private readonly INotificationService[] _registry; - - public static NotificationEventHandler Instance - { - get - { - lock (_instanceLock) - { - _instance ??= new NotificationEventHandler(); - - return _instance; - } - } - } - - NotificationEventHandler() - { - _registry = new INotificationService[0x20]; - } - - internal void RegisterNotificationService(INotificationService service) - { - // NOTE: in case there isn't space anymore in the registry array, Nintendo doesn't return any errors. - for (int i = 0; i < _registry.Length; i++) - { - if (_registry[i] == null) - { - _registry[i] = service; - break; - } - } - } - - internal void UnregisterNotificationService(INotificationService service) - { - // NOTE: in case there isn't the entry in the registry array, Nintendo doesn't return any errors. - for (int i = 0; i < _registry.Length; i++) - { - if (_registry[i] == service) - { - _registry[i] = null; - break; - } - } - } - - // TODO: Use this when we will have enough things to go online. - public void SignalFriendListUpdate(UserId targetId) - { - for (int i = 0; i < _registry.Length; i++) - { - _registry[i]?.SignalFriendListUpdate(targetId); - } - } - - // TODO: Use this when we will have enough things to go online. - public void SignalNewFriendRequest(UserId targetId) - { - for (int i = 0; i < _registry.Length; i++) - { - _registry[i]?.SignalNewFriendRequest(targetId); - } - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs deleted file mode 100644 index aa58433d8..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10)] - struct NotificationInfo - { - public NotificationEventType Type; - private Array4 _padding; - public long NetworkUserIdPlaceholder; - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs index 66020d57b..e19d17912 100644 --- a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs +++ b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs @@ -2,6 +2,7 @@ using LibHac; using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; +using Ryujinx.Common.Logging; using Path = LibHac.FsSrv.Sf.Path; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy @@ -149,7 +150,13 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // Commit() public ResultCode Commit(ServiceCtx context) { - return (ResultCode)_fileSystem.Get.Commit().Value; + ResultCode resultCode = (ResultCode)_fileSystem.Get.Commit().Value; + if (resultCode == ResultCode.PathAlreadyInUse) + { + Logger.Warning?.Print(LogClass.ServiceFs, "The file system is already in use by another process."); + } + + return resultCode; } [CommandCmif(11)] diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/LazyFile.cs b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/LazyFile.cs new file mode 100644 index 000000000..a179e8e38 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/LazyFile.cs @@ -0,0 +1,65 @@ +using LibHac; +using LibHac.Common; +using LibHac.Fs; +using System; +using System.IO; + +namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy +{ + class LazyFile : LibHac.Fs.Fsa.IFile + { + private readonly LibHac.Fs.Fsa.IFileSystem _fs; + private readonly string _filePath; + private readonly UniqueRef _fileReference = new(); + private readonly FileInfo _fileInfo; + + public LazyFile(string filePath, string prefix, LibHac.Fs.Fsa.IFileSystem fs) + { + _fs = fs; + _filePath = filePath; + _fileInfo = new FileInfo(prefix + "/" + filePath); + } + + private void PrepareFile() + { + if (_fileReference.Get == null) + { + _fs.OpenFile(ref _fileReference.Ref, _filePath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); + } + } + + protected override Result DoRead(out long bytesRead, long offset, Span destination, in ReadOption option) + { + PrepareFile(); + + return _fileReference.Get!.Read(out bytesRead, offset, destination); + } + + protected override Result DoWrite(long offset, ReadOnlySpan source, in WriteOption option) + { + throw new NotSupportedException(); + } + + protected override Result DoFlush() + { + throw new NotSupportedException(); + } + + protected override Result DoSetSize(long size) + { + throw new NotSupportedException(); + } + + protected override Result DoGetSize(out long size) + { + size = _fileInfo.Length; + + return Result.Success; + } + + protected override Result DoOperateRange(Span outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan inBuffer) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs b/src/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs index b2dd3feaf..2e62d206b 100644 --- a/src/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs +++ b/src/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs @@ -23,8 +23,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid newState.Buttons = (MouseButton)buttons; newState.X = mouseX; newState.Y = mouseY; - newState.DeltaX = mouseX - previousEntry.DeltaX; - newState.DeltaY = mouseY - previousEntry.DeltaY; + newState.DeltaX = mouseX - previousEntry.X; + newState.DeltaY = mouseY - previousEntry.Y; newState.WheelDeltaX = scrollX; newState.WheelDeltaY = scrollY; newState.Attributes = connected ? MouseAttribute.IsConnected : MouseAttribute.None; diff --git a/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs index 1d1b145cc..e3f505f37 100644 --- a/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs +++ b/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs @@ -22,6 +22,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid private bool _sixAxisSensorFusionEnabled; private bool _unintendedHomeButtonInputProtectionEnabled; + private bool _npadAnalogStickCenterClampEnabled; private bool _vibrationPermitted; private bool _usbFullKeyControllerEnabled; private readonly bool _isFirmwareUpdateAvailableForSixAxisSensor; @@ -1107,6 +1108,19 @@ namespace Ryujinx.HLE.HOS.Services.Hid // If not, it returns nothing. } + [CommandCmif(134)] // 6.1.0+ + // SetNpadUseAnalogStickUseCenterClamp(bool Enable, nn::applet::AppletResourceUserId) + public ResultCode SetNpadUseAnalogStickUseCenterClamp(ServiceCtx context) + { + ulong pid = context.RequestData.ReadUInt64(); + _npadAnalogStickCenterClampEnabled = context.RequestData.ReadUInt32() != 0; + long appletResourceUserId = context.RequestData.ReadInt64(); + + Logger.Stub?.PrintStub(LogClass.ServiceHid, new { pid, appletResourceUserId, _npadAnalogStickCenterClampEnabled }); + + return ResultCode.Success; + } + [CommandCmif(200)] // GetVibrationDeviceInfo(nn::hid::VibrationDeviceHandle) -> nn::hid::VibrationDeviceInfo public ResultCode GetVibrationDeviceInfo(ServiceCtx context) @@ -1821,5 +1835,18 @@ namespace Ryujinx.HLE.HOS.Services.Hid return ResultCode.Success; } + + [CommandCmif(1004)] // 17.0.0+ + // SetTouchScreenResolution(int width, int height, nn::applet::AppletResourceUserId) + public ResultCode SetTouchScreenResolution(ServiceCtx context) + { + int width = context.RequestData.ReadInt32(); + int height = context.RequestData.ReadInt32(); + long appletResourceUserId = context.RequestData.ReadInt64(); + + Logger.Stub?.PrintStub(LogClass.ServiceHid, new { width, height, appletResourceUserId }); + + return ResultCode.Success; + } } } diff --git a/src/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs b/src/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs index 52412489a..d7e276ea0 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs @@ -40,5 +40,12 @@ namespace Ryujinx.HLE.HOS.Services.Nim return ResultCode.Success; } + + [CommandCmif(5)] // 17.0.0+ + // CreateServerInterface2(pid, handle, u64) -> object + public ResultCode CreateServerInterface2(ServiceCtx context) + { + return CreateServerInterface(context); + } } } diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs b/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs index 371edbecd..7c7ebf22d 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs @@ -1,4 +1,4 @@ -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Host1x; using Ryujinx.Graphics.Nvdec; using Ryujinx.Graphics.Vic; @@ -9,7 +9,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv { class Host1xContext : IDisposable { - public MemoryManager Smmu { get; } + public DeviceMemoryManager Smmu { get; } public NvMemoryAllocator MemoryAllocator { get; } public Host1xDevice Host1x { get; } @@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv { MemoryAllocator = new NvMemoryAllocator(); Host1x = new Host1xDevice(gpu.Synchronization); - Smmu = gpu.CreateMemoryManager(pid); + Smmu = gpu.CreateDeviceMemoryManager(pid); var nvdec = new NvdecDevice(Smmu); var vic = new VicDevice(Smmu); Host1x.RegisterDevice(ClassId.Nvdec, nvdec); diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs index 03c4ed860..ff9a67644 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs @@ -266,7 +266,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu if (size == 0) { - size = (uint)map.Size; + size = map.Size; } NvInternalResult result = NvInternalResult.Success; diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs index 53db5eca4..bc70b05cf 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs @@ -250,12 +250,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel { if (map.DmaMapAddress == 0) { - ulong va = _host1xContext.MemoryAllocator.GetFreeAddress((ulong)map.Size, out ulong freeAddressStartPosition, 1, MemoryManager.PageSize); + ulong va = _host1xContext.MemoryAllocator.GetFreeAddress(map.Size, out ulong freeAddressStartPosition, 1, MemoryManager.PageSize); - if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + (uint)map.Size) <= uint.MaxValue) + if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + map.Size) <= uint.MaxValue) { - _host1xContext.MemoryAllocator.AllocateRange(va, (uint)map.Size, freeAddressStartPosition); - _host1xContext.Smmu.Map(map.Address, va, (uint)map.Size, PteKind.Pitch); // FIXME: This should not use the GMMU. + _host1xContext.MemoryAllocator.AllocateRange(va, map.Size, freeAddressStartPosition); + _host1xContext.Smmu.Map(map.Address, va, map.Size); map.DmaMapAddress = va; } else diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs index d287c6d9e..29198617f 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs @@ -50,6 +50,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu case 0x06: result = CallIoctlMethod(GetTpcMasks, arguments); break; + case 0x12: + result = CallIoctlMethod(NumVsms, arguments); + break; + case 0x13: + result = CallIoctlMethod(VsmsMapping, arguments); + break; case 0x14: result = CallIoctlMethod(GetActiveSlotMask, arguments); break; @@ -76,6 +82,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu case 0x06: result = CallIoctlMethod(GetTpcMasks, arguments, inlineOutBuffer); break; + case 0x12: + result = CallIoctlMethod(NumVsms, arguments); + break; + case 0x13: + result = CallIoctlMethod(VsmsMapping, arguments); + break; } } @@ -216,6 +228,27 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu return NvInternalResult.Success; } + private NvInternalResult NumVsms(ref NumVsmsArguments arguments) + { + Logger.Stub?.PrintStub(LogClass.ServiceNv); + + arguments.NumVsms = 2; + + return NvInternalResult.Success; + } + + private NvInternalResult VsmsMapping(ref VsmsMappingArguments arguments) + { + Logger.Stub?.PrintStub(LogClass.ServiceNv); + + arguments.Sm0GpcIndex = 0; + arguments.Sm0TpcIndex = 0; + arguments.Sm1GpcIndex = 0; + arguments.Sm1TpcIndex = 1; + + return NvInternalResult.Success; + } + private NvInternalResult GetActiveSlotMask(ref GetActiveSlotMaskArguments arguments) { Logger.Stub?.PrintStub(LogClass.ServiceNv); diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/NumVsmsArguments.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/NumVsmsArguments.cs new file mode 100644 index 000000000..fb5013a70 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/NumVsmsArguments.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct NumVsmsArguments + { + public uint NumVsms; + public uint Reserved; + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/VsmsMappingArguments.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/VsmsMappingArguments.cs new file mode 100644 index 000000000..baada9197 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/VsmsMappingArguments.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct VsmsMappingArguments + { + public byte Sm0GpcIndex; + public byte Sm0TpcIndex; + public byte Sm1GpcIndex; + public byte Sm1TpcIndex; + public uint Reserved; + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs index abe0a4de8..6a0ac58bd 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs @@ -69,7 +69,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap return NvInternalResult.InvalidInput; } - int size = BitUtils.AlignUp(arguments.Size, (int)MemoryManager.PageSize); + uint size = BitUtils.AlignUp(arguments.Size, (uint)MemoryManager.PageSize); arguments.Handle = CreateHandleFromMap(new NvMapHandle(size)); @@ -128,7 +128,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap map.Align = arguments.Align; map.Kind = (byte)arguments.Kind; - int size = BitUtils.AlignUp(map.Size, (int)MemoryManager.PageSize); + uint size = BitUtils.AlignUp(map.Size, (uint)MemoryManager.PageSize); ulong address = arguments.Address; @@ -191,7 +191,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap switch (arguments.Param) { case NvMapHandleParam.Size: - arguments.Result = map.Size; + arguments.Result = (int)map.Size; break; case NvMapHandleParam.Align: arguments.Result = map.Align; diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs index 5380c45c7..f4047497a 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs @@ -5,7 +5,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap [StructLayout(LayoutKind.Sequential)] struct NvMapCreate { - public int Size; + public uint Size; public int Handle; } } diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs index b0b3fa2d6..ce93e9e5e 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs @@ -8,7 +8,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap public int Handle; public int Padding; public ulong Address; - public int Size; + public uint Size; public int Flags; } } diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs index 301179747..e821b571d 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs @@ -8,7 +8,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap public int Handle; public int Id; #pragma warning restore CS0649 - public int Size; + public uint Size; public int Align; public int Kind; public ulong Address; @@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap _dupes = 1; } - public NvMapHandle(int size) : this() + public NvMapHandle(uint size) : this() { Size = size; } diff --git a/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs b/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs index cf8c1f78d..9b026a1c3 100644 --- a/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs +++ b/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs @@ -159,9 +159,7 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory } else { -#pragma warning disable CS0162 // Unreachable code return ResultCode.StereoVisionRestrictionConfigurableDisabled; -#pragma warning restore CS0162 } } diff --git a/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs b/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs deleted file mode 100644 index 66ffd0a49..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Services.Ptm.Ts.Types; - -namespace Ryujinx.HLE.HOS.Services.Ptm.Ts -{ - [Service("ts")] - class IMeasurementServer : IpcService - { - private const uint DefaultTemperature = 42u; - - public IMeasurementServer(ServiceCtx context) { } - - [CommandCmif(1)] - // GetTemperature(Location location) -> u32 - public ResultCode GetTemperature(ServiceCtx context) - { - Location location = (Location)context.RequestData.ReadByte(); - - Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location }); - - context.ResponseData.Write(DefaultTemperature); - - return ResultCode.Success; - } - - [CommandCmif(3)] - // GetTemperatureMilliC(Location location) -> u32 - public ResultCode GetTemperatureMilliC(ServiceCtx context) - { - Location location = (Location)context.RequestData.ReadByte(); - - Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location }); - - context.ResponseData.Write(DefaultTemperature * 1000); - - return ResultCode.Success; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/ServerBase.cs b/src/Ryujinx.HLE/HOS/Services/ServerBase.cs index e892d6ab6..f67699b90 100644 --- a/src/Ryujinx.HLE/HOS/Services/ServerBase.cs +++ b/src/Ryujinx.HLE/HOS/Services/ServerBase.cs @@ -287,6 +287,10 @@ namespace Ryujinx.HLE.HOS.Services _wakeEvent.WritableEvent.Clear(); } } + else if (rc == KernelResult.PortRemoteClosed && signaledIndex >= 0 && SmObjectFactory != null) + { + DestroySession(handles[signaledIndex]); + } _selfProcess.CpuMemory.Write(messagePtr + 0x0, 0); _selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10); @@ -299,6 +303,16 @@ namespace Ryujinx.HLE.HOS.Services Dispose(); } + private void DestroySession(int serverSessionHandle) + { + _context.Syscall.CloseHandle(serverSessionHandle); + + if (RemoveSessionObj(serverSessionHandle, out var session)) + { + (session as IDisposable)?.Dispose(); + } + } + private bool Process(int serverSessionHandle, ulong recvListAddr) { IpcMessage request = ReadRequest(); @@ -360,7 +374,7 @@ namespace Ryujinx.HLE.HOS.Services response.RawData = _responseDataStream.ToArray(); } else if (request.Type == IpcMessageType.CmifControl || - request.Type == IpcMessageType.CmifControlWithContext) + request.Type == IpcMessageType.CmifControlWithContext) { #pragma warning disable IDE0059 // Remove unnecessary value assignment uint magic = (uint)_requestDataReader.ReadUInt64(); @@ -412,11 +426,7 @@ namespace Ryujinx.HLE.HOS.Services } else if (request.Type == IpcMessageType.CmifCloseSession || request.Type == IpcMessageType.TipcCloseSession) { - _context.Syscall.CloseHandle(serverSessionHandle); - if (RemoveSessionObj(serverSessionHandle, out var session)) - { - (session as IDisposable)?.Dispose(); - } + DestroySession(serverSessionHandle); shouldReply = false; } // If the type is past 0xF, we are using TIPC @@ -464,9 +474,9 @@ namespace Ryujinx.HLE.HOS.Services { const int MessageSize = 0x100; - using IMemoryOwner reqDataOwner = ByteMemoryPool.Rent(MessageSize); + using SpanOwner reqDataOwner = SpanOwner.Rent(MessageSize); - Span reqDataSpan = reqDataOwner.Memory.Span; + Span reqDataSpan = reqDataOwner.Span; _selfProcess.CpuMemory.Read(_selfThread.TlsAddress, reqDataSpan); diff --git a/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs b/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs index 870a6b36c..21d48288e 100644 --- a/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs @@ -121,7 +121,14 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd { IPEndPoint endPoint = isRemote ? socket.RemoteEndPoint : socket.LocalEndPoint; - context.Memory.Write(bufferPosition, BsdSockAddr.FromIPEndPoint(endPoint)); + if (endPoint != null) + { + context.Memory.Write(bufferPosition, BsdSockAddr.FromIPEndPoint(endPoint)); + } + else + { + context.Memory.Write(bufferPosition, new BsdSockAddr()); + } } [CommandCmif(0)] @@ -433,8 +440,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd // If we are here, that mean nothing was available, sleep for 50ms context.Device.System.KernelContext.Syscall.SleepThread(50 * 1000000); + context.Thread.HandlePostSyscall(); } - while (PerformanceCounter.ElapsedMilliseconds < budgetLeftMilliseconds); + while (context.Thread.Context.Running && PerformanceCounter.ElapsedMilliseconds < budgetLeftMilliseconds); } else if (timeout == -1) { diff --git a/src/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs b/src/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs index 4dd6367ed..8cc761baf 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs +++ b/src/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs @@ -3,6 +3,7 @@ using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl; using Ryujinx.HLE.HOS.Services.Ssl.Types; using System; using System.IO; +using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; @@ -83,10 +84,40 @@ namespace Ryujinx.HLE.HOS.Services.Ssl.SslService } #pragma warning restore SYSLIB0039 + /// + /// Retrieve the hostname of the current remote in case the provided hostname is null or empty. + /// + /// The current hostname + /// Either the resolved or provided hostname + /// + /// This is done to avoid getting an + /// as the remote certificate will be rejected with RemoteCertificateNameMismatch due to an empty hostname. + /// This is not what the switch does! + /// It might just skip remote hostname verification if the hostname wasn't set with before. + /// TODO: Remove this as soon as we know how the switch deals with empty hostnames + /// + private string RetrieveHostName(string hostName) + { + if (!string.IsNullOrEmpty(hostName)) + { + return hostName; + } + + try + { + return Dns.GetHostEntry(Socket.RemoteEndPoint.Address).HostName; + } + catch (SocketException) + { + return hostName; + } + } + public ResultCode Handshake(string hostName) { StartSslOperation(); _stream = new SslStream(new NetworkStream(((ManagedSocket)Socket).Socket, false), false, null, null); + hostName = RetrieveHostName(hostName); _stream.AuthenticateAsClient(hostName, null, TranslateSslVersion(_sslVersion), false); EndSslOperation(); diff --git a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IBinder.cs b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IBinder.cs index 0fb2dfd2e..54aac48ae 100644 --- a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IBinder.cs +++ b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IBinder.cs @@ -13,10 +13,10 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger ResultCode OnTransact(uint code, uint flags, ReadOnlySpan inputParcel, Span outputParcel) { - Parcel inputParcelReader = new(inputParcel.ToArray()); + using Parcel inputParcelReader = new(inputParcel); // TODO: support objects? - Parcel outputParcelWriter = new((uint)(outputParcel.Length - Unsafe.SizeOf()), 0); + using Parcel outputParcelWriter = new((uint)(outputParcel.Length - Unsafe.SizeOf()), 0); string inputInterfaceToken = inputParcelReader.ReadInterfaceToken(); diff --git a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs index 7cb6763b8..2ffa961cb 100644 --- a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs +++ b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs @@ -85,9 +85,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger ReadOnlySpan inputParcel = context.Memory.GetSpan(dataPos, (int)dataSize); - using IMemoryOwner outputParcelOwner = ByteMemoryPool.RentCleared(replySize); + using SpanOwner outputParcelOwner = SpanOwner.RentCleared(checked((int)replySize)); - Span outputParcel = outputParcelOwner.Memory.Span; + Span outputParcel = outputParcelOwner.Span; ResultCode result = OnTransact(binderId, code, flags, inputParcel, outputParcel); diff --git a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Parcel.cs b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Parcel.cs index 4ac0525ba..1df280dce 100644 --- a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Parcel.cs +++ b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Parcel.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Common.Memory; using Ryujinx.Common.Utilities; using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types; using System; @@ -9,13 +10,13 @@ using System.Text; namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger { - class Parcel + sealed class Parcel : IDisposable { - private readonly byte[] _rawData; + private readonly MemoryOwner _rawDataOwner; - private Span Raw => new(_rawData); + private Span Raw => _rawDataOwner.Span; - private ref ParcelHeader Header => ref MemoryMarshal.Cast(_rawData)[0]; + private ref ParcelHeader Header => ref MemoryMarshal.Cast(Raw)[0]; private Span Payload => Raw.Slice((int)Header.PayloadOffset, (int)Header.PayloadSize); @@ -24,9 +25,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger private int _payloadPosition; private int _objectPosition; - public Parcel(byte[] rawData) + private bool _isDisposed; + + public Parcel(ReadOnlySpan data) { - _rawData = rawData; + _rawDataOwner = MemoryOwner.RentCopy(data); _payloadPosition = 0; _objectPosition = 0; @@ -36,7 +39,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger { uint headerSize = (uint)Unsafe.SizeOf(); - _rawData = new byte[BitUtils.AlignUp(headerSize + payloadSize + objectsSize, 4)]; + _rawDataOwner = MemoryOwner.RentCleared(checked((int)BitUtils.AlignUp(headerSize + payloadSize + objectsSize, 4))); Header.PayloadSize = payloadSize; Header.ObjectsSize = objectsSize; @@ -132,7 +135,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger // TODO: figure out what this value is - WriteInplaceObject(new byte[4] { 0, 0, 0, 0 }); + Span fourBytes = stackalloc byte[4]; + + WriteInplaceObject(fourBytes); } public AndroidStrongPointer ReadStrongPointer() where T : unmanaged, IFlattenable @@ -219,5 +224,15 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger return Raw[..(int)(Header.PayloadSize + Header.ObjectsSize + Unsafe.SizeOf())]; } + + public void Dispose() + { + if (!_isDisposed) + { + _isDisposed = true; + + _rawDataOwner.Dispose(); + } + } } } diff --git a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs index fd517b1ae..4c17e7aed 100644 --- a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs +++ b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs @@ -412,9 +412,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat); - int bytesPerPixel = + byte bytesPerPixel = format == Format.B5G6R5Unorm || - format == Format.R4G4B4A4Unorm ? 2 : 4; + format == Format.R4G4B4A4Unorm ? (byte)2 : (byte)4; int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2; diff --git a/src/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs b/src/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs index 143e21661..a2b1fb524 100644 --- a/src/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs +++ b/src/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs @@ -7,7 +7,7 @@ using Ryujinx.HLE.HOS.Services.SurfaceFlinger; using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService; using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService.Types; using Ryujinx.HLE.HOS.Services.Vi.Types; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Horizon.Common; using System; using System.Collections.Generic; @@ -250,7 +250,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); - Parcel parcel = new(0x28, 0x4); + using Parcel parcel = new(0x28, 0x4); parcel.WriteObject(producer, "dispdrv\0"); @@ -288,7 +288,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); - Parcel parcel = new(0x28, 0x4); + using Parcel parcel = new(0x28, 0x4); parcel.WriteObject(producer, "dispdrv\0"); diff --git a/src/Ryujinx.HLE/HOS/TamperMachine.cs b/src/Ryujinx.HLE/HOS/TamperMachine.cs index f234e540e..609221535 100644 --- a/src/Ryujinx.HLE/HOS/TamperMachine.cs +++ b/src/Ryujinx.HLE/HOS/TamperMachine.cs @@ -143,7 +143,7 @@ namespace Ryujinx.HLE.HOS try { - ControllerKeys pressedKeys = (ControllerKeys)Thread.VolatileRead(ref _pressedKeys); + ControllerKeys pressedKeys = (ControllerKeys)Volatile.Read(ref _pressedKeys); program.Process.TamperedCodeMemory = false; program.Execute(pressedKeys); @@ -175,14 +175,14 @@ namespace Ryujinx.HLE.HOS { if (input.PlayerId == PlayerIndex.Player1 || input.PlayerId == PlayerIndex.Handheld) { - Thread.VolatileWrite(ref _pressedKeys, (long)input.Buttons); + Volatile.Write(ref _pressedKeys, (long)input.Buttons); return; } } // Clear the input because player one is not conected. - Thread.VolatileWrite(ref _pressedKeys, 0); + Volatile.Write(ref _pressedKeys, 0); } } } diff --git a/src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs b/src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs index 9a5b6b0aa..8d828e8ed 100644 --- a/src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs +++ b/src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs @@ -15,6 +15,12 @@ namespace Ryujinx.HLE.Loaders.Npdm public ServiceAccessControl ServiceAccessControl { get; private set; } public KernelAccessControl KernelAccessControl { get; private set; } + /// The stream doesn't contain valid ACI0 data. + /// The stream does not support reading, is , or is already closed. + /// The end of the stream is reached. + /// The stream is closed. + /// An I/O error occurred. + /// The FsAccessHeader.ContentOwnerId section is not implemented. public Aci0(Stream stream, int offset) { stream.Seek(offset, SeekOrigin.Begin); diff --git a/src/Ryujinx.HLE/Loaders/Npdm/ACID.cs b/src/Ryujinx.HLE/Loaders/Npdm/ACID.cs index ab30b40ca..57d0ee274 100644 --- a/src/Ryujinx.HLE/Loaders/Npdm/ACID.cs +++ b/src/Ryujinx.HLE/Loaders/Npdm/ACID.cs @@ -19,6 +19,11 @@ namespace Ryujinx.HLE.Loaders.Npdm public ServiceAccessControl ServiceAccessControl { get; private set; } public KernelAccessControl KernelAccessControl { get; private set; } + /// The stream doesn't contain valid ACID data. + /// The stream does not support reading, is , or is already closed. + /// The end of the stream is reached. + /// The stream is closed. + /// An I/O error occurred. public Acid(Stream stream, int offset) { stream.Seek(offset, SeekOrigin.Begin); diff --git a/src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs index f17ca348b..a369f9f2d 100644 --- a/src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs +++ b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs @@ -11,6 +11,10 @@ namespace Ryujinx.HLE.Loaders.Npdm public int Unknown3 { get; private set; } public int Unknown4 { get; private set; } + /// The stream does not support reading, is , or is already closed. + /// The end of the stream is reached. + /// The stream is closed. + /// An I/O error occurred. public FsAccessControl(Stream stream, int offset, int size) { stream.Seek(offset, SeekOrigin.Begin); diff --git a/src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs index 5987be0ef..249f8dd9d 100644 --- a/src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs +++ b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs @@ -9,6 +9,12 @@ namespace Ryujinx.HLE.Loaders.Npdm public int Version { get; private set; } public ulong PermissionsBitmask { get; private set; } + /// The stream contains invalid data. + /// The ContentOwnerId section is not implemented. + /// The stream does not support reading, is , or is already closed. + /// The end of the stream is reached. + /// The stream is closed. + /// An I/O error occurred. public FsAccessHeader(Stream stream, int offset, int size) { stream.Seek(offset, SeekOrigin.Begin); diff --git a/src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs b/src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs index 171243799..979c6f669 100644 --- a/src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs +++ b/src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs @@ -6,6 +6,10 @@ namespace Ryujinx.HLE.Loaders.Npdm { public int[] Capabilities { get; private set; } + /// The stream does not support reading, is , or is already closed. + /// The end of the stream is reached. + /// The stream is closed. + /// An I/O error occurred. public KernelAccessControl(Stream stream, int offset, int size) { stream.Seek(offset, SeekOrigin.Begin); diff --git a/src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs b/src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs index 622d7ee03..4a99de98c 100644 --- a/src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs +++ b/src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs @@ -24,6 +24,13 @@ namespace Ryujinx.HLE.Loaders.Npdm public Aci0 Aci0 { get; private set; } public Acid Acid { get; private set; } + /// The stream doesn't contain valid NPDM data. + /// The FsAccessHeader.ContentOwnerId section is not implemented. + /// The stream does not support reading, is , or is already closed. + /// An error occured while reading bytes from the stream. + /// The end of the stream is reached. + /// The stream is closed. + /// An I/O error occurred. public Npdm(Stream stream) { BinaryReader reader = new(stream); diff --git a/src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs b/src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs index bb6df27fa..b6bc6492d 100644 --- a/src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs +++ b/src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs @@ -9,6 +9,11 @@ namespace Ryujinx.HLE.Loaders.Npdm { public IReadOnlyDictionary Services { get; private set; } + /// The stream does not support reading, is , or is already closed. + /// An error occured while reading bytes from the stream. + /// The end of the stream is reached. + /// The stream is closed. + /// An I/O error occurred. public ServiceAccessControl(Stream stream, int offset, int size) { stream.Seek(offset, SeekOrigin.Begin); diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs index 28f6fcff4..3904d660e 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs @@ -34,7 +34,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions return metaLoader; } - public static ProcessResult Load(this IFileSystem exeFs, Switch device, BlitStruct nacpData, MetaLoader metaLoader, bool isHomebrew = false) + public static ProcessResult Load(this IFileSystem exeFs, Switch device, BlitStruct nacpData, MetaLoader metaLoader, byte programIndex, bool isHomebrew = false) { ulong programId = metaLoader.GetProgramId(); @@ -119,6 +119,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions true, programName, metaLoader.GetProgramId(), + programIndex, null, nsoExecutables); diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs index 798a9261e..6c2a19894 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs @@ -3,7 +3,6 @@ using LibHac.FsSystem; using LibHac.Loader; using LibHac.Ncm; using LibHac.Ns; -using Ryujinx.HLE.HOS; using Ryujinx.HLE.Loaders.Processes.Extensions; namespace Ryujinx.HLE.Loaders.Processes @@ -16,17 +15,14 @@ namespace Ryujinx.HLE.Loaders.Processes var nacpData = new BlitStruct(1); ulong programId = metaLoader.GetProgramId(); - device.Configuration.VirtualFileSystem.ModLoader.CollectMods( - new[] { programId }, - ModLoader.GetModsBasePath(), - ModLoader.GetSdModsBasePath()); + device.Configuration.VirtualFileSystem.ModLoader.CollectMods(new[] { programId }); if (programId != 0) { ProcessLoaderHelper.EnsureSaveData(device, new ApplicationId(programId), nacpData); } - ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader); + ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader, 0); // Load RomFS. if (!string.IsNullOrEmpty(romFsPath)) diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs index e369f4b04..2928ac7fe 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs @@ -7,16 +7,25 @@ using LibHac.Ncm; using LibHac.Ns; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; +using LibHac.Tools.Ncm; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; +using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; +using Ryujinx.HLE.Utilities; using System.IO; using System.Linq; using ApplicationId = LibHac.Ncm.ApplicationId; +using ContentType = LibHac.Ncm.ContentType; +using Path = System.IO.Path; namespace Ryujinx.HLE.Loaders.Processes.Extensions { - static class NcaExtensions + public static class NcaExtensions { + private static readonly TitleUpdateMetadataJsonSerializerContext _applicationSerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + public static ProcessResult Load(this Nca nca, Switch device, Nca patchNca, Nca controlNca) { // Extract RomFs and ExeFs from NCA. @@ -47,7 +56,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions nacpData = controlNca.GetNacp(device); } - /* TODO: Rework this since it's wrong and doesn't work as it takes the DisplayVersion from a "potential" inexistant update. + /* TODO: Rework this since it's wrong and doesn't work as it takes the DisplayVersion from a "potential" non-existent update. // Load program 0 control NCA as we are going to need it for display version. (_, Nca updateProgram0ControlNca) = GetGameUpdateData(_device.Configuration.VirtualFileSystem, mainNca.Header.TitleId.ToString("x16"), 0, out _); @@ -61,7 +70,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions */ - ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader); + ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader, (byte)nca.GetProgramIndex()); // Load RomFS. if (romFs == null) @@ -86,6 +95,11 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions return processResult; } + public static ulong GetProgramIdBase(this Nca nca) + { + return nca.Header.TitleId & ~0x1FFFUL; + } + public static int GetProgramIndex(this Nca nca) { return (int)(nca.Header.TitleId & 0xF); @@ -96,6 +110,11 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions return nca.Header.ContentType == NcaContentType.Program; } + public static bool IsMain(this Nca nca) + { + return nca.IsProgram() && !nca.IsPatch(); + } + public static bool IsPatch(this Nca nca) { int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); @@ -108,6 +127,43 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions return nca.Header.ContentType == NcaContentType.Control; } + public static (Nca, Nca) GetUpdateData(this Nca mainNca, VirtualFileSystem fileSystem, IntegrityCheckLevel checkLevel, int programIndex, out string updatePath) + { + updatePath = null; + + // Load Update NCAs. + Nca updatePatchNca = null; + Nca updateControlNca = null; + + // Clear the program index part. + ulong titleIdBase = mainNca.GetProgramIdBase(); + + // Load update information if exists. + string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, titleIdBase.ToString("x16"), "updates.json"); + if (File.Exists(titleUpdateMetadataPath)) + { + updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _applicationSerializerContext.TitleUpdateMetadata).Selected; + if (File.Exists(updatePath)) + { + IFileSystem updatePartitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(updatePath, fileSystem); + + foreach ((ulong applicationTitleId, ContentMetaData content) in updatePartitionFileSystem.GetContentData(ContentMetaType.Patch, fileSystem, checkLevel)) + { + if ((applicationTitleId & ~0x1FFFUL) != titleIdBase) + { + continue; + } + + updatePatchNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Program, programIndex); + updateControlNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Control, programIndex); + break; + } + } + } + + return (updatePatchNca, updateControlNca); + } + public static IFileSystem GetExeFs(this Nca nca, Switch device, Nca patchNca = null) { IFileSystem exeFs = null; @@ -172,5 +228,31 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions return nacpData; } + + public static Cnmt GetCnmt(this Nca cnmtNca, IntegrityCheckLevel checkLevel, ContentMetaType metaType) + { + string path = $"/{metaType}_{cnmtNca.Header.TitleId:x16}.cnmt"; + using var cnmtFile = new UniqueRef(); + + try + { + Result result = cnmtNca.OpenFileSystem(0, checkLevel) + .OpenFile(ref cnmtFile.Ref, path.ToU8Span(), OpenMode.Read); + + if (result.IsSuccess()) + { + return new Cnmt(cnmtFile.Release().AsStream()); + } + } + catch (HorizonResultException ex) + { + if (!ResultFs.PathNotFound.Includes(ex.ResultValue)) + { + Logger.Warning?.Print(LogClass.Application, $"Failed get CNMT for '{cnmtNca.Header.TitleId:x16}' from NCA: {ex.Message}"); + } + } + + return null; + } } } diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs index 87141ab85..e3a4f7008 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs @@ -1,26 +1,61 @@ using LibHac.Common; +using LibHac.Common.Keys; using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem; +using LibHac.Ncm; using LibHac.Tools.Fs; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; +using LibHac.Tools.Ncm; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; +using Ryujinx.HLE.FileSystem; using System; using System.Collections.Generic; -using System.Globalization; using System.IO; +using System.Globalization; +using ContentType = LibHac.Ncm.ContentType; namespace Ryujinx.HLE.Loaders.Processes.Extensions { public static class PartitionFileSystemExtensions { private static readonly DownloadableContentJsonSerializerContext _contentSerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + private static readonly TitleUpdateMetadataJsonSerializerContext _titleSerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - internal static (bool, ProcessResult) TryLoad(this PartitionFileSystemCore partitionFileSystem, Switch device, string path, out string errorMessage) + public static Dictionary GetContentData(this IFileSystem partitionFileSystem, + ContentMetaType contentType, VirtualFileSystem fileSystem, IntegrityCheckLevel checkLevel) + { + fileSystem.ImportTickets(partitionFileSystem); + + var programs = new Dictionary(); + + foreach (DirectoryEntryEx fileEntry in partitionFileSystem.EnumerateEntries("/", "*.cnmt.nca")) + { + Cnmt cnmt = partitionFileSystem.GetNca(fileSystem.KeySet, fileEntry.FullPath).GetCnmt(checkLevel, contentType); + + if (cnmt == null) + { + continue; + } + + ContentMetaData content = new(partitionFileSystem, cnmt); + + if (content.Type != contentType) + { + continue; + } + + programs.TryAdd(content.ApplicationId, content); + } + + return programs; + } + + internal static (bool, ProcessResult) TryLoad(this PartitionFileSystemCore partitionFileSystem, Switch device, string path, ulong applicationId, out string errorMessage) where TMetaData : PartitionFileSystemMetaCore, new() where TFormat : IPartitionFileSystemFormat where THeader : unmanaged, IPartitionFileSystemHeader @@ -35,31 +70,22 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions try { - device.Configuration.VirtualFileSystem.ImportTickets(partitionFileSystem); + Dictionary applications = partitionFileSystem.GetContentData(ContentMetaType.Application, device.FileSystem, device.System.FsIntegrityCheckLevel); - // TODO: To support multi-games container, this should use CNMT NCA instead. - foreach (DirectoryEntryEx fileEntry in partitionFileSystem.EnumerateEntries("/", "*.nca")) + if (applicationId == 0) { - Nca nca = partitionFileSystem.GetNca(device, fileEntry.FullPath); - - if (nca.GetProgramIndex() != device.Configuration.UserChannelPersistence.Index) + foreach ((ulong _, ContentMetaData content) in applications) { - continue; - } - - if (nca.IsPatch()) - { - patchNca = nca; - } - else if (nca.IsProgram()) - { - mainNca = nca; - } - else if (nca.IsControl()) - { - controlNca = nca; + mainNca = content.GetNcaByType(device.FileSystem.KeySet, ContentType.Program, device.Configuration.UserChannelPersistence.Index); + controlNca = content.GetNcaByType(device.FileSystem.KeySet, ContentType.Control, device.Configuration.UserChannelPersistence.Index); + break; } } + else if (applications.TryGetValue(applicationId, out ContentMetaData content)) + { + mainNca = content.GetNcaByType(device.FileSystem.KeySet, ContentType.Program, device.Configuration.UserChannelPersistence.Index); + controlNca = content.GetNcaByType(device.FileSystem.KeySet, ContentType.Control, device.Configuration.UserChannelPersistence.Index); + } ProcessLoaderHelper.RegisterProgramMapInfo(device, partitionFileSystem).ThrowIfFailure(); } @@ -138,13 +164,11 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions controlNca = updateControlNca; } - // Load contained DownloadableContents. // TODO: If we want to support multi-processes in future, we shouldn't clear AddOnContent data here. device.Configuration.ContentManager.ClearAocData(); - device.Configuration.ContentManager.AddAocData(partitionFileSystem, path, mainNca.Header.TitleId, device.Configuration.FsIntegrityCheckLevel); // Load DownloadableContents. - string addOnContentMetadataPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, mainNca.Header.TitleId.ToString("x16"), "dlc.json"); + string addOnContentMetadataPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, mainNca.GetProgramIdBase().ToString("x16"), "dlc.json"); if (File.Exists(addOnContentMetadataPath)) { List dlcContainerList = JsonHelper.DeserializeFromFile(addOnContentMetadataPath, _contentSerializerContext.ListDownloadableContentContainer); @@ -170,7 +194,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions return (true, mainNca.Load(device, patchNca, controlNca)); } - errorMessage = "Unable to load: Could not find Main NCA"; + errorMessage = $"Unable to load: Could not find Main NCA for title \"{applicationId:X16}\""; return (false, ProcessResult.Failed); } @@ -193,5 +217,14 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions return new Nca(device.Configuration.VirtualFileSystem.KeySet, ncaFile.Release().AsStorage()); } + + public static Nca GetNca(this IFileSystem fileSystem, KeySet keySet, string path) + { + using var ncaFile = new UniqueRef(); + + fileSystem.OpenFile(ref ncaFile.Ref, path.ToU8Span(), OpenMode.Read).ThrowIfFailure(); + + return new Nca(keySet, ncaFile.Release().AsStorage()); + } } } diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs index efeb9f613..12d9c8bd9 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs @@ -32,7 +32,7 @@ namespace Ryujinx.HLE.Loaders.Processes _processesByPid = new ConcurrentDictionary(); } - public bool LoadXci(string path) + public bool LoadXci(string path, ulong applicationId) { FileStream stream = new(path, FileMode.Open, FileAccess.Read); Xci xci = new(_device.Configuration.VirtualFileSystem.KeySet, stream.AsStorage()); @@ -44,7 +44,7 @@ namespace Ryujinx.HLE.Loaders.Processes return false; } - (bool success, ProcessResult processResult) = xci.OpenPartition(XciPartitionType.Secure).TryLoad(_device, path, out string errorMessage); + (bool success, ProcessResult processResult) = xci.OpenPartition(XciPartitionType.Secure).TryLoad(_device, path, applicationId, out string errorMessage); if (!success) { @@ -66,18 +66,18 @@ namespace Ryujinx.HLE.Loaders.Processes return false; } - public bool LoadNsp(string path) + public bool LoadNsp(string path, ulong applicationId) { FileStream file = new(path, FileMode.Open, FileAccess.Read); PartitionFileSystem partitionFileSystem = new(); partitionFileSystem.Initialize(file.AsStorage()).ThrowIfFailure(); - (bool success, ProcessResult processResult) = partitionFileSystem.TryLoad(_device, path, out string errorMessage); + (bool success, ProcessResult processResult) = partitionFileSystem.TryLoad(_device, path, applicationId, out string errorMessage); if (processResult.ProcessId == 0) { // This is not a normal NSP, it's actually a ExeFS as a NSP - processResult = partitionFileSystem.Load(_device, new BlitStruct(1), partitionFileSystem.GetNpdm(), true); + processResult = partitionFileSystem.Load(_device, new BlitStruct(1), partitionFileSystem.GetNpdm(), 0, true); } if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult)) @@ -198,7 +198,7 @@ namespace Ryujinx.HLE.Loaders.Processes } else { - programName = System.IO.Path.GetFileNameWithoutExtension(path); + programName = Path.GetFileNameWithoutExtension(path); executable = new NsoExecutable(new LocalStorage(path, FileAccess.Read), programName); } @@ -215,6 +215,7 @@ namespace Ryujinx.HLE.Loaders.Processes allowCodeMemoryForJit: true, programName, programId, + 0, null, executable); diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs index a6a1d87e0..cf4eb416e 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs @@ -19,6 +19,7 @@ using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Processes.Extensions; using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; using System; using System.Linq; using System.Runtime.InteropServices; @@ -42,15 +43,14 @@ namespace Ryujinx.HLE.Loaders.Processes foreach (DirectoryEntryEx fileEntry in partitionFileSystem.EnumerateEntries("/", "*.nca")) { - Nca nca = partitionFileSystem.GetNca(device, fileEntry.FullPath); + Nca nca = partitionFileSystem.GetNca(device.FileSystem.KeySet, fileEntry.FullPath); - if (!nca.IsProgram() && nca.IsPatch()) + if (!nca.IsProgram()) { continue; } - ulong currentProgramId = nca.Header.TitleId; - ulong currentMainProgramId = currentProgramId & ~0xFFFul; + ulong currentMainProgramId = nca.GetProgramIdBase(); if (applicationId == 0 && currentMainProgramId != 0) { @@ -67,7 +67,7 @@ namespace Ryujinx.HLE.Loaders.Processes break; } - hasIndex[(int)(currentProgramId & 0xF)] = true; + hasIndex[nca.GetProgramIndex()] = true; } if (programCount == 0) @@ -229,6 +229,7 @@ namespace Ryujinx.HLE.Loaders.Processes bool allowCodeMemoryForJit, string name, ulong programId, + byte programIndex, byte[] arguments = null, params IExecutable[] executables) { @@ -421,7 +422,7 @@ namespace Ryujinx.HLE.Loaders.Processes // Once everything is loaded, we can load cheats. device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(programId, tamperInfo, device.TamperMachine); - return new ProcessResult( + ProcessResult processResult = new( metaLoader, applicationControlProperties, diskCacheEnabled, @@ -431,6 +432,25 @@ namespace Ryujinx.HLE.Loaders.Processes meta.MainThreadPriority, meta.MainThreadStackSize, device.System.State.DesiredTitleLanguage); + + // Register everything in arp service. + device.System.ServiceTable.ArpWriter.AcquireRegistrar(out IRegistrar registrar); + registrar.SetApplicationControlProperty(MemoryMarshal.Cast(applicationControlProperties.ByteSpan)[0]); + // TODO: Handle Version and StorageId when it will be needed. + registrar.SetApplicationLaunchProperty(new ApplicationLaunchProperty() + { + ApplicationId = new Horizon.Sdk.Ncm.ApplicationId(programId), + Version = 0x00, + Storage = Horizon.Sdk.Ncm.StorageId.BuiltInUser, + PatchStorage = Horizon.Sdk.Ncm.StorageId.None, + ApplicationKind = ApplicationKind.Application, + }); + + device.System.ServiceTable.ArpReader.GetApplicationInstanceId(out ulong applicationInstanceId, process.Pid); + device.System.ServiceTable.ArpWriter.AcquireApplicationProcessPropertyUpdater(out IUpdater updater, applicationInstanceId); + updater.SetApplicationProcessProperty(process.Pid, new ApplicationProcessProperty() { ProgramIndex = programIndex }); + + return processResult; } public static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress) diff --git a/src/Ryujinx.HLE/Ryujinx.HLE.csproj b/src/Ryujinx.HLE/Ryujinx.HLE.csproj index 59892c214..3fab16fac 100644 --- a/src/Ryujinx.HLE/Ryujinx.HLE.csproj +++ b/src/Ryujinx.HLE/Ryujinx.HLE.csproj @@ -2,6 +2,7 @@ net8.0 + true @@ -11,9 +12,7 @@ - + @@ -25,20 +24,14 @@ - + - - - + + - - - NU1605 - - diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs index 0c7112c0a..3b15c1336 100644 --- a/src/Ryujinx.HLE/Switch.cs +++ b/src/Ryujinx.HLE/Switch.cs @@ -8,7 +8,7 @@ using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Apm; using Ryujinx.HLE.HOS.Services.Hid; using Ryujinx.HLE.Loaders.Processes; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Memory; using System; @@ -26,7 +26,7 @@ namespace Ryujinx.HLE public PerformanceStatistics Statistics { get; } public Hid Hid { get; } public TamperMachine TamperMachine { get; } - public IHostUiHandler UiHandler { get; } + public IHostUIHandler UIHandler { get; } public bool EnableDeviceVsync { get; set; } = true; @@ -40,7 +40,7 @@ namespace Ryujinx.HLE Configuration = configuration; FileSystem = Configuration.VirtualFileSystem; - UiHandler = Configuration.HostUiHandler; + UIHandler = Configuration.HostUIHandler; MemoryAllocationFlags memoryAllocationFlags = configuration.MemoryManagerMode == MemoryManagerMode.SoftwarePageTable ? MemoryAllocationFlags.Reserve @@ -56,6 +56,7 @@ namespace Ryujinx.HLE Processes = new ProcessLoader(this); TamperMachine = new TamperMachine(); + System.InitializeServices(); System.State.SetLanguage(Configuration.SystemLanguage); System.State.SetRegion(Configuration.Region); @@ -86,9 +87,9 @@ namespace Ryujinx.HLE return Processes.LoadUnpackedNca(exeFsDir, romFsFile); } - public bool LoadXci(string xciFile) + public bool LoadXci(string xciFile, ulong applicationId = 0) { - return Processes.LoadXci(xciFile); + return Processes.LoadXci(xciFile, applicationId); } public bool LoadNca(string ncaFile) @@ -96,9 +97,9 @@ namespace Ryujinx.HLE return Processes.LoadNca(ncaFile); } - public bool LoadNsp(string nspFile) + public bool LoadNsp(string nspFile, ulong applicationId = 0) { - return Processes.LoadNsp(nspFile); + return Processes.LoadNsp(nspFile, applicationId); } public bool LoadProgram(string fileName) @@ -130,12 +131,12 @@ namespace Ryujinx.HLE public void SetVolume(float volume) { - System.SetVolume(Math.Clamp(volume, 0, 1)); + AudioDeviceDriver.Volume = Math.Clamp(volume, 0f, 1f); } public float GetVolume() { - return System.GetVolume(); + return AudioDeviceDriver.Volume; } public void EnableCheats() @@ -145,7 +146,7 @@ namespace Ryujinx.HLE public bool IsAudioMuted() { - return System.GetVolume() == 0; + return AudioDeviceDriver.Volume == 0; } public void DisposeGpu() diff --git a/src/Ryujinx.HLE/Ui/DynamicTextChangedHandler.cs b/src/Ryujinx.HLE/UI/DynamicTextChangedHandler.cs similarity index 82% rename from src/Ryujinx.HLE/Ui/DynamicTextChangedHandler.cs rename to src/Ryujinx.HLE/UI/DynamicTextChangedHandler.cs index cb9ca0dec..c0945259b 100644 --- a/src/Ryujinx.HLE/Ui/DynamicTextChangedHandler.cs +++ b/src/Ryujinx.HLE/UI/DynamicTextChangedHandler.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { public delegate void DynamicTextChangedHandler(string text, int cursorBegin, int cursorEnd, bool overwriteMode); } diff --git a/src/Ryujinx.HLE/Ui/IDynamicTextInputHandler.cs b/src/Ryujinx.HLE/UI/IDynamicTextInputHandler.cs similarity index 94% rename from src/Ryujinx.HLE/Ui/IDynamicTextInputHandler.cs rename to src/Ryujinx.HLE/UI/IDynamicTextInputHandler.cs index e530d2c4e..1ff451d10 100644 --- a/src/Ryujinx.HLE/Ui/IDynamicTextInputHandler.cs +++ b/src/Ryujinx.HLE/UI/IDynamicTextInputHandler.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { public interface IDynamicTextInputHandler : IDisposable { diff --git a/src/Ryujinx.HLE/Ui/IHostUiHandler.cs b/src/Ryujinx.HLE/UI/IHostUIHandler.cs similarity index 90% rename from src/Ryujinx.HLE/Ui/IHostUiHandler.cs rename to src/Ryujinx.HLE/UI/IHostUIHandler.cs index 105e9dd90..5f7970ece 100644 --- a/src/Ryujinx.HLE/Ui/IHostUiHandler.cs +++ b/src/Ryujinx.HLE/UI/IHostUIHandler.cs @@ -2,16 +2,16 @@ using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; using System; -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { - public interface IHostUiHandler + public interface IHostUIHandler { /// /// Displays an Input Dialog box to the user and blocks until text is entered. /// /// Text that the user entered. Set to `null` on internal errors /// True when OK is pressed, False otherwise. Also returns True on internal errors - public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action onTextEntered); + public void DisplayInputDialog(SoftwareKeyboardUIArgs args, Action onTextEntered); /// /// Displays a Message Dialog box to the user and blocks until it is closed. @@ -23,7 +23,7 @@ namespace Ryujinx.HLE.Ui /// Displays a Message Dialog box specific to Controller Applet and blocks until it is closed. /// /// True when OK is pressed, False otherwise. - bool DisplayMessageDialog(ControllerAppletUiArgs args); + bool DisplayMessageDialog(ControllerAppletUIArgs args); /// /// Tell the UI that we need to transisition to another program. @@ -47,6 +47,6 @@ namespace Ryujinx.HLE.Ui /// /// Gets fonts and colors used by the host. /// - IHostUiTheme HostUiTheme { get; } + IHostUITheme HostUITheme { get; } } } diff --git a/src/Ryujinx.HLE/Ui/IHostUiTheme.cs b/src/Ryujinx.HLE/UI/IHostUITheme.cs similarity index 83% rename from src/Ryujinx.HLE/Ui/IHostUiTheme.cs rename to src/Ryujinx.HLE/UI/IHostUITheme.cs index 11d82361a..3b0544004 100644 --- a/src/Ryujinx.HLE/Ui/IHostUiTheme.cs +++ b/src/Ryujinx.HLE/UI/IHostUITheme.cs @@ -1,6 +1,6 @@ -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { - public interface IHostUiTheme + public interface IHostUITheme { string FontFamily { get; } diff --git a/src/Ryujinx.HLE/Ui/Input/NpadButtonHandler.cs b/src/Ryujinx.HLE/UI/Input/NpadButtonHandler.cs similarity index 81% rename from src/Ryujinx.HLE/Ui/Input/NpadButtonHandler.cs rename to src/Ryujinx.HLE/UI/Input/NpadButtonHandler.cs index 2d1c1c491..73c306614 100644 --- a/src/Ryujinx.HLE/Ui/Input/NpadButtonHandler.cs +++ b/src/Ryujinx.HLE/UI/Input/NpadButtonHandler.cs @@ -1,6 +1,6 @@ using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad; -namespace Ryujinx.HLE.Ui.Input +namespace Ryujinx.HLE.UI.Input { delegate void NpadButtonHandler(int npadIndex, NpadButton button); } diff --git a/src/Ryujinx.HLE/Ui/Input/NpadReader.cs b/src/Ryujinx.HLE/UI/Input/NpadReader.cs similarity index 99% rename from src/Ryujinx.HLE/Ui/Input/NpadReader.cs rename to src/Ryujinx.HLE/UI/Input/NpadReader.cs index 8fc95dc94..8276d6160 100644 --- a/src/Ryujinx.HLE/Ui/Input/NpadReader.cs +++ b/src/Ryujinx.HLE/UI/Input/NpadReader.cs @@ -1,7 +1,7 @@ using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad; -namespace Ryujinx.HLE.Ui.Input +namespace Ryujinx.HLE.UI.Input { /// /// Class that converts Hid entries for the Npad into pressed / released events. diff --git a/src/Ryujinx.HLE/Ui/KeyPressedHandler.cs b/src/Ryujinx.HLE/UI/KeyPressedHandler.cs similarity index 79% rename from src/Ryujinx.HLE/Ui/KeyPressedHandler.cs rename to src/Ryujinx.HLE/UI/KeyPressedHandler.cs index 31e754377..6feb11bd8 100644 --- a/src/Ryujinx.HLE/Ui/KeyPressedHandler.cs +++ b/src/Ryujinx.HLE/UI/KeyPressedHandler.cs @@ -1,6 +1,6 @@ using Ryujinx.Common.Configuration.Hid; -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { public delegate bool KeyPressedHandler(Key key); } diff --git a/src/Ryujinx.HLE/Ui/KeyReleasedHandler.cs b/src/Ryujinx.HLE/UI/KeyReleasedHandler.cs similarity index 79% rename from src/Ryujinx.HLE/Ui/KeyReleasedHandler.cs rename to src/Ryujinx.HLE/UI/KeyReleasedHandler.cs index d5b6d2019..3de89d0c7 100644 --- a/src/Ryujinx.HLE/Ui/KeyReleasedHandler.cs +++ b/src/Ryujinx.HLE/UI/KeyReleasedHandler.cs @@ -1,6 +1,6 @@ using Ryujinx.Common.Configuration.Hid; -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { public delegate bool KeyReleasedHandler(Key key); } diff --git a/src/Ryujinx.HLE/Ui/RenderingSurfaceInfo.cs b/src/Ryujinx.HLE/UI/RenderingSurfaceInfo.cs similarity index 98% rename from src/Ryujinx.HLE/Ui/RenderingSurfaceInfo.cs rename to src/Ryujinx.HLE/UI/RenderingSurfaceInfo.cs index 0b3d0a909..af0a0d44e 100644 --- a/src/Ryujinx.HLE/Ui/RenderingSurfaceInfo.cs +++ b/src/Ryujinx.HLE/UI/RenderingSurfaceInfo.cs @@ -1,7 +1,7 @@ using Ryujinx.HLE.HOS.Services.SurfaceFlinger; using System; -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { /// /// Information about the indirect layer that is being drawn to. diff --git a/src/Ryujinx.HLE/Ui/ThemeColor.cs b/src/Ryujinx.HLE/UI/ThemeColor.cs similarity index 93% rename from src/Ryujinx.HLE/Ui/ThemeColor.cs rename to src/Ryujinx.HLE/UI/ThemeColor.cs index 23657ed2b..c5cfb1474 100644 --- a/src/Ryujinx.HLE/Ui/ThemeColor.cs +++ b/src/Ryujinx.HLE/UI/ThemeColor.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { public readonly struct ThemeColor { diff --git a/src/Ryujinx.HLE/Utilities/PartitionFileSystemUtils.cs b/src/Ryujinx.HLE/Utilities/PartitionFileSystemUtils.cs new file mode 100644 index 000000000..3c4ce0850 --- /dev/null +++ b/src/Ryujinx.HLE/Utilities/PartitionFileSystemUtils.cs @@ -0,0 +1,45 @@ +using LibHac; +using LibHac.Fs.Fsa; +using LibHac.FsSystem; +using LibHac.Tools.Fs; +using LibHac.Tools.FsSystem; +using Ryujinx.HLE.FileSystem; +using System.IO; + +namespace Ryujinx.HLE.Utilities +{ + public static class PartitionFileSystemUtils + { + public static IFileSystem OpenApplicationFileSystem(string path, VirtualFileSystem fileSystem, bool throwOnFailure = true) + { + FileStream file = File.OpenRead(path); + + IFileSystem partitionFileSystem; + + if (Path.GetExtension(path).ToLower() == ".xci") + { + partitionFileSystem = new Xci(fileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure); + } + else + { + var pfsTemp = new PartitionFileSystem(); + Result initResult = pfsTemp.Initialize(file.AsStorage()); + + if (throwOnFailure) + { + initResult.ThrowIfFailure(); + } + else if (initResult.IsFailure()) + { + return null; + } + + partitionFileSystem = pfsTemp; + } + + fileSystem.ImportTickets(partitionFileSystem); + + return partitionFileSystem; + } + } +} diff --git a/src/Ryujinx.Headless.SDL2/HeadlessDynamicTextInputHandler.cs b/src/Ryujinx.Headless.SDL2/HeadlessDynamicTextInputHandler.cs index aae01a0ce..503874ff1 100644 --- a/src/Ryujinx.Headless.SDL2/HeadlessDynamicTextInputHandler.cs +++ b/src/Ryujinx.Headless.SDL2/HeadlessDynamicTextInputHandler.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System.Threading; using System.Threading.Tasks; diff --git a/src/Ryujinx.Headless.SDL2/HeadlessHostUiTheme.cs b/src/Ryujinx.Headless.SDL2/HeadlessHostUiTheme.cs index a2df6f3ee..78cd43ae5 100644 --- a/src/Ryujinx.Headless.SDL2/HeadlessHostUiTheme.cs +++ b/src/Ryujinx.Headless.SDL2/HeadlessHostUiTheme.cs @@ -1,8 +1,8 @@ -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; namespace Ryujinx.Headless.SDL2 { - internal class HeadlessHostUiTheme : IHostUiTheme + internal class HeadlessHostUiTheme : IHostUITheme { public string FontFamily => "sans-serif"; diff --git a/src/Ryujinx.Headless.SDL2/Keyboard-iOS.cs b/src/Ryujinx.Headless.SDL2/Keyboard-iOS.cs index 88af25318..2d75906d3 100644 --- a/src/Ryujinx.Headless.SDL2/Keyboard-iOS.cs +++ b/src/Ryujinx.Headless.SDL2/Keyboard-iOS.cs @@ -1,6 +1,6 @@ using System; using System.Runtime.InteropServices; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System.Threading; namespace Ryujinx.Headless.SDL2 diff --git a/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs b/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs index 3fb93a0ec..7ea6e1481 100644 --- a/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs +++ b/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs @@ -96,6 +96,8 @@ namespace Ryujinx.Headless.SDL2.OpenGL } } + public bool HasContext() => SDL_GL_GetCurrentContext() != IntPtr.Zero; + public void Dispose() { SDL_GL_DeleteContext(_context); diff --git a/src/Ryujinx.Headless.SDL2/Options.cs b/src/Ryujinx.Headless.SDL2/Options.cs index bd3ad4c17..8dfe33a63 100644 --- a/src/Ryujinx.Headless.SDL2/Options.cs +++ b/src/Ryujinx.Headless.SDL2/Options.cs @@ -222,7 +222,7 @@ namespace Ryujinx.Headless.SDL2 // Hacks - [Option("expand-ram", Required = false, Default = false, HelpText = "Expands the RAM amount on the emulated system from 4GiB to 6GiB.")] + [Option("expand-ram", Required = false, Default = false, HelpText = "Expands the RAM amount on the emulated system from 4GiB to 8GiB.")] public bool ExpandRAM { get; set; } [Option("ignore-missing-services", Required = false, Default = false, HelpText = "Enable ignoring missing services.")] diff --git a/src/Ryujinx.Headless.SDL2/Program.cs b/src/Ryujinx.Headless.SDL2/Program.cs index 3d8be7c7b..8796fb96d 100644 --- a/src/Ryujinx.Headless.SDL2/Program.cs +++ b/src/Ryujinx.Headless.SDL2/Program.cs @@ -1,4 +1,3 @@ -using ARMeilleure.Translation; using CommandLine; using LibHac.Tools.FsSystem; using Ryujinx.Audio.Backends.SDL2; @@ -8,6 +7,7 @@ using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller.Motion; using Ryujinx.Common.Configuration.Hid.Keyboard; +using Ryujinx.Common.GraphicsDriver; using Ryujinx.Common.Logging; using Ryujinx.Common.Logging.Targets; using Ryujinx.Common.SystemInterop; @@ -19,6 +19,7 @@ using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu.Shader; using Ryujinx.Graphics.OpenGL; using Ryujinx.Graphics.Vulkan; +using Ryujinx.Graphics.Vulkan.MoltenVK; using Ryujinx.Headless.SDL2.OpenGL; using Ryujinx.Headless.SDL2.Vulkan; using Ryujinx.HLE; @@ -29,9 +30,9 @@ using Ryujinx.Input; using Ryujinx.Input.HLE; using Ryujinx.Input.SDL2; using Ryujinx.SDL2.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Configuration.System; -using Ryujinx.Ui.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Configuration.System; +using Ryujinx.UI.Common; using Silk.NET.Vulkan; using System; using System.Collections.Generic; @@ -55,7 +56,7 @@ using LibHac.Tools.FsSystem; using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Audio.Backends.Dummy; using Ryujinx.HLE.HOS.SystemState; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Audio.Integration; using Ryujinx.Audio.Backends.SDL2; @@ -74,13 +75,13 @@ using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.HLE.Loaders.Npdm; using Ryujinx.Common.Utilities; using System.Globalization; -using Ryujinx.Ui.Common.Configuration.System; +using Ryujinx.UI.Common.Configuration.System; using Ryujinx.Common.Logging.Targets; using System.Collections.Generic; using LibHac.Bcat; -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; using System.Text; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using ARMeilleure.Translation; using LibHac.Ncm; using LibHac.Tools.FsSystem.NcaUtils; @@ -304,11 +305,9 @@ namespace Ryujinx.Headless.SDL2 Silk.NET.Core.Loader.SearchPathContainer.Platform = Silk.NET.Core.Loader.UnderlyingPlatform.MacOS; - Version = ReleaseInformation.GetVersion(); - if (!OperatingSystem.IsIOS()) { - Console.Title = $"Ryujinx Console {Version} (Headless SDL2)"; + // Console.Title = $"Ryujinx Console {Version} (Headless SDL2)"; } if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS() || OperatingSystem.IsLinux()) @@ -331,14 +330,14 @@ namespace Ryujinx.Headless.SDL2 }; } - var result = Parser.Default.ParseArguments(args) - .WithParsed(options => - { - Load(options); - }) - .WithNotParsed(errors => errors.Output()); - + if (OperatingSystem.IsMacOS()) + { + MVKInitialization.InitializeResolver(); + } + Parser.Default.ParseArguments(args) + .WithParsed(Load) + .WithNotParsed(errors => errors.Output()); } [UnmanagedCallersOnly(EntryPoint = "install_firmware")] @@ -408,11 +407,6 @@ namespace Ryujinx.Headless.SDL2 { if (_window != null) { - if (_window._isPaused) { - _window._isPaused = false; - } else { - _window._isPaused = true; - } } } @@ -1251,11 +1245,26 @@ namespace Ryujinx.Headless.SDL2 if (!option.DisableFileLog) { - Logger.AddTarget(new AsyncLogTargetWrapper( - new FileLogTarget(ReleaseInformation.GetBaseApplicationDirectory(), "file"), - 1000, - AsyncLogTargetOverflowAction.Block - )); + string logDir = AppDataManager.LogsDirPath; + FileStream logFile = null; + + if (!string.IsNullOrEmpty(logDir)) + { + logFile = FileLogTarget.PrepareLogFile(logDir); + } + + if (logFile != null) + { + Logger.AddTarget(new AsyncLogTargetWrapper( + new FileLogTarget("file", logFile), + 1000, + AsyncLogTargetOverflowAction.Block + )); + } + else + { + Logger.Error?.Print(LogClass.Application, "No writable log directory available. Make sure either the Logs directory, Application Data, or the Ryujinx directory is writable."); + } } // Setup graphics configuration @@ -1266,6 +1275,8 @@ namespace Ryujinx.Headless.SDL2 GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath; GraphicsConfig.EnableMacroHLE = !option.DisableMacroHLE; + DriverUtilities.InitDriverConfig(option.BackendThreading == BackendThreading.Off); + while (true) { LoadApplication(option); @@ -1389,7 +1400,7 @@ namespace Ryujinx.Headless.SDL2 _userChannelPersistence, renderer, new SDL2HardwareDeviceDriver(), - options.ExpandRAM ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB, + options.ExpandRAM ? MemoryConfiguration.MemoryConfiguration8GiB : MemoryConfiguration.MemoryConfiguration4GiB, window, options.SystemLanguage, options.SystemRegion, @@ -1588,9 +1599,6 @@ namespace Ryujinx.Headless.SDL2 } SetupProgressHandler(); - - Translator.IsReadyForTranslation.Reset(); - ExecutionEntrypoint(); return true; diff --git a/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj b/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj index 059ba0d68..af0176dfc 100644 --- a/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj +++ b/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj @@ -106,7 +106,7 @@ - + @@ -120,7 +120,7 @@ - + Always diff --git a/src/Ryujinx.Headless.SDL2/WindowBase.cs b/src/Ryujinx.Headless.SDL2/WindowBase.cs index f88feb86a..48e17b4f1 100644 --- a/src/Ryujinx.Headless.SDL2/WindowBase.cs +++ b/src/Ryujinx.Headless.SDL2/WindowBase.cs @@ -1,4 +1,3 @@ -using ARMeilleure.Translation; using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Logging; @@ -8,7 +7,7 @@ using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.OpenGL; using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Input; using Ryujinx.Input.HLE; using Ryujinx.SDL2.Common; @@ -26,7 +25,7 @@ using Switch = Ryujinx.HLE.Switch; namespace Ryujinx.Headless.SDL2 { - abstract partial class WindowBase : IHostUiHandler, IDisposable + abstract partial class WindowBase : IHostUIHandler, IDisposable { protected const int DefaultWidth = 1280; protected const int DefaultHeight = 720; @@ -54,7 +53,7 @@ namespace Ryujinx.Headless.SDL2 public IntPtr WindowHandle; - public IHostUiTheme HostUiTheme { get; } + public IHostUITheme HostUITheme { get; } public int Width { get; private set; } public int Height { get; private set; } public int DisplayId { get; set; } @@ -81,9 +80,7 @@ namespace Ryujinx.Headless.SDL2 private bool _isStopped; private uint _windowId; - public bool _isPaused = false; - - private string _gpuVendorName; + private string _gpuDriverName; private readonly AspectRatio _aspectRatio; private readonly bool _enableMouse; @@ -109,7 +106,7 @@ namespace Ryujinx.Headless.SDL2 _gpuDoneEvent = new ManualResetEvent(false); _aspectRatio = aspectRatio; _enableMouse = enableMouse; - HostUiTheme = new HeadlessHostUiTheme(); + HostUITheme = new HeadlessHostUiTheme(); SDL2Driver.Instance.Initialize(); } @@ -259,9 +256,9 @@ namespace Ryujinx.Headless.SDL2 public abstract SDL_WindowFlags GetWindowFlags(); - private string GetGpuVendorName() + private string GetGpuDriverName() { - return Renderer.GetHardwareInfo().GpuVendor; + return Renderer.GetHardwareInfo().GpuDriver; } private void SetAntiAliasing() @@ -287,13 +284,12 @@ namespace Ryujinx.Headless.SDL2 SetScalingFilter(); - _gpuVendorName = GetGpuVendorName(); + _gpuDriverName = GetGpuDriverName(); Device.Gpu.Renderer.RunLoop(() => { Device.Gpu.SetGpuThread(); Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token); - Translator.IsReadyForTranslation.Set(); while (_isActive) { @@ -302,11 +298,6 @@ namespace Ryujinx.Headless.SDL2 return; } - if (_isPaused) - { - return; - } - _ticks += _chrono.ElapsedTicks; _chrono.Restart(); @@ -338,7 +329,7 @@ namespace Ryujinx.Headless.SDL2 Device.Configuration.AspectRatio.ToText(), $"Game: {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", $"FIFO: {Device.Statistics.GetFifoPercent():0.00} %", - $"GPU: {_gpuVendorName}")); + $"GPU: {_gpuDriverName}")); _ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame); } @@ -388,12 +379,6 @@ namespace Ryujinx.Headless.SDL2 while (_isActive) { - if (_isPaused) - { - Thread.Sleep(1); - return; - } - UpdateFrame(); SDL_PumpEvents(); @@ -433,11 +418,6 @@ namespace Ryujinx.Headless.SDL2 return true; } - if (_isPaused) - { - return true; - } - if (_isStopped) { return false; @@ -489,7 +469,7 @@ namespace Ryujinx.Headless.SDL2 Exit(); } - public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action onTextEntered) + public void DisplayInputDialog(SoftwareKeyboardUIArgs args, Action onTextEntered) { // SDL2 doesn't support input dialogs // Trying to use Objective-C on iDevices @@ -511,7 +491,7 @@ namespace Ryujinx.Headless.SDL2 return true; } - public bool DisplayMessageDialog(ControllerAppletUiArgs args) + public bool DisplayMessageDialog(ControllerAppletUIArgs args) { string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}"; diff --git a/src/Ryujinx.Horizon.Common/IExternalEvent.cs b/src/Ryujinx.Horizon.Common/IExternalEvent.cs new file mode 100644 index 000000000..dedf4c72a --- /dev/null +++ b/src/Ryujinx.Horizon.Common/IExternalEvent.cs @@ -0,0 +1,10 @@ +using System; + +namespace Ryujinx.Horizon.Common +{ + public interface IExternalEvent + { + void Signal(); + void Clear(); + } +} diff --git a/src/Ryujinx.Horizon.Common/ISyscallApi.cs b/src/Ryujinx.Horizon.Common/ISyscallApi.cs index 20277f344..3d6da0416 100644 --- a/src/Ryujinx.Horizon.Common/ISyscallApi.cs +++ b/src/Ryujinx.Horizon.Common/ISyscallApi.cs @@ -1,3 +1,4 @@ +using Ryujinx.Memory; using System; namespace Ryujinx.Horizon.Common @@ -29,5 +30,9 @@ namespace Ryujinx.Horizon.Common Result CreatePort(out int serverPortHandle, out int clientPortHandle, int maxSessions, bool isLight, string name); Result ManageNamedPort(out int handle, string name, int maxSessions); Result ConnectToPort(out int clientSessionHandle, int clientPortHandle); + + IExternalEvent GetExternalEvent(int handle); + IVirtualMemoryManager GetMemoryManagerByProcessHandle(int handle); + ulong GetTransferMemoryAddress(int handle); } } diff --git a/src/Ryujinx.Horizon.Common/Result.cs b/src/Ryujinx.Horizon.Common/Result.cs index d313554e3..4b120b847 100644 --- a/src/Ryujinx.Horizon.Common/Result.cs +++ b/src/Ryujinx.Horizon.Common/Result.cs @@ -36,6 +36,11 @@ namespace Ryujinx.Horizon.Common ErrorCode = module | (description << ModuleBits); } + public Result(int errorCode) + { + ErrorCode = errorCode; + } + public readonly override bool Equals(object obj) { return obj is Result result && result.Equals(this); diff --git a/src/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs b/src/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs index a65ec3abd..d1be8298d 100644 --- a/src/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs +++ b/src/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs @@ -17,6 +17,8 @@ namespace Ryujinx.Horizon.Generators.Hipc private const string ResponseVariableName = "response"; private const string OutRawDataVariableName = "outRawData"; + private const string TypeSystemBuffersReadOnlySequence = "System.Buffers.ReadOnlySequence"; + private const string TypeSystemMemory = "System.Memory"; private const string TypeSystemReadOnlySpan = "System.ReadOnlySpan"; private const string TypeSystemSpan = "System.Span"; private const string TypeStructLayoutAttribute = "System.Runtime.InteropServices.StructLayoutAttribute"; @@ -74,6 +76,7 @@ namespace Ryujinx.Horizon.Generators.Hipc generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf.Cmif;"); generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf.Hipc;"); generator.AppendLine("using System;"); + generator.AppendLine("using System.Collections.Frozen;"); generator.AppendLine("using System.Collections.Generic;"); generator.AppendLine("using System.Runtime.CompilerServices;"); generator.AppendLine("using System.Runtime.InteropServices;"); @@ -115,67 +118,76 @@ namespace Ryujinx.Horizon.Generators.Hipc private static void GenerateMethodTable(CodeGenerator generator, Compilation compilation, CommandInterface commandInterface) { generator.EnterScope($"public IReadOnlyDictionary GetCommandHandlers()"); - generator.EnterScope($"return new Dictionary()"); - foreach (var method in commandInterface.CommandImplementations) + if (commandInterface.CommandImplementations.Count == 0) { - foreach (var commandId in GetAttributeAguments(compilation, method, TypeCommandAttribute, 0)) + generator.AppendLine("return FrozenDictionary.Empty;"); + } + else + { + generator.EnterScope($"return FrozenDictionary.ToFrozenDictionary(new []"); + + foreach (var method in commandInterface.CommandImplementations) { - string[] args = new string[method.ParameterList.Parameters.Count]; - - if (args.Length == 0) + foreach (var commandId in GetAttributeArguments(compilation, method, TypeCommandAttribute, 0)) { - generator.AppendLine($"{{ {commandId}, new CommandHandler({method.Identifier.Text}, Array.Empty()) }},"); - } - else - { - int index = 0; + string[] args = new string[method.ParameterList.Parameters.Count]; - foreach (var parameter in method.ParameterList.Parameters) + if (args.Length == 0) { - string canonicalTypeName = GetCanonicalTypeNameWithGenericArguments(compilation, parameter.Type); - CommandArgType argType = GetCommandArgType(compilation, parameter); + generator.AppendLine($"KeyValuePair.Create({commandId}, new CommandHandler({method.Identifier.Text}, Array.Empty())),"); + } + else + { + int index = 0; - string arg; - - if (argType == CommandArgType.Buffer) + foreach (var parameter in method.ParameterList.Parameters) { - string bufferFlags = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 0); - string bufferFixedSize = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 1); + string canonicalTypeName = GetCanonicalTypeNameWithGenericArguments(compilation, parameter.Type); + CommandArgType argType = GetCommandArgType(compilation, parameter); - if (bufferFixedSize != null) + string arg; + + if (argType == CommandArgType.Buffer) { - arg = $"new CommandArg({bufferFlags} | HipcBufferFlags.FixedSize, {bufferFixedSize})"; + string bufferFlags = GetFirstAttributeArgument(compilation, parameter, TypeBufferAttribute, 0); + string bufferFixedSize = GetFirstAttributeArgument(compilation, parameter, TypeBufferAttribute, 1); + + if (bufferFixedSize != null) + { + arg = $"new CommandArg({bufferFlags} | HipcBufferFlags.FixedSize, {bufferFixedSize})"; + } + else + { + arg = $"new CommandArg({bufferFlags})"; + } + } + else if (argType == CommandArgType.InArgument || argType == CommandArgType.OutArgument) + { + string alignment = GetTypeAlignmentExpression(compilation, parameter.Type); + + arg = $"new CommandArg(CommandArgType.{argType}, Unsafe.SizeOf<{canonicalTypeName}>(), {alignment})"; } else { - arg = $"new CommandArg({bufferFlags})"; + arg = $"new CommandArg(CommandArgType.{argType})"; } - } - else if (argType == CommandArgType.InArgument || argType == CommandArgType.OutArgument) - { - string alignment = GetTypeAlignmentExpression(compilation, parameter.Type); - arg = $"new CommandArg(CommandArgType.{argType}, Unsafe.SizeOf<{canonicalTypeName}>(), {alignment})"; - } - else - { - arg = $"new CommandArg(CommandArgType.{argType})"; + args[index++] = arg; } - args[index++] = arg; + generator.AppendLine($"KeyValuePair.Create({commandId}, new CommandHandler({method.Identifier.Text}, {string.Join(", ", args)})),"); } - - generator.AppendLine($"{{ {commandId}, new CommandHandler({method.Identifier.Text}, {string.Join(", ", args)}) }},"); } } + + generator.LeaveScope(");"); } - generator.LeaveScope(";"); generator.LeaveScope(); } - private static IEnumerable GetAttributeAguments(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex) + private static IEnumerable GetAttributeArguments(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex) { ISymbol symbol = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode); @@ -188,9 +200,9 @@ namespace Ryujinx.Horizon.Generators.Hipc } } - private static string GetFirstAttributeAgument(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex) + private static string GetFirstAttributeArgument(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex) { - return GetAttributeAguments(compilation, syntaxNode, attributeName, argIndex).FirstOrDefault(); + return GetAttributeArguments(compilation, syntaxNode, attributeName, argIndex).FirstOrDefault(); } private static void GenerateMethod(CodeGenerator generator, Compilation compilation, MethodDeclarationSyntax method) @@ -233,7 +245,7 @@ namespace Ryujinx.Horizon.Generators.Hipc if (buffersCount != 0) { - generator.AppendLine($"bool[] {IsBufferMapAliasVariableName} = new bool[{method.ParameterList.Parameters.Count}];"); + generator.AppendLine($"Span {IsBufferMapAliasVariableName} = stackalloc bool[{method.ParameterList.Parameters.Count}];"); generator.AppendLine(); generator.AppendLine($"{ResultVariableName} = processor.ProcessBuffers(ref context, {IsBufferMapAliasVariableName}, runtimeMetadata);"); @@ -286,13 +298,13 @@ namespace Ryujinx.Horizon.Generators.Hipc { if (IsNonSpanOutBuffer(compilation, parameter)) { - generator.AppendLine($"using var {argName} = CommandSerialization.GetWritableRegion(processor.GetBufferRange({outArgIndex++}));"); + generator.AppendLine($"using var {argName} = CommandSerialization.GetWritableRegion(processor.GetBufferRange({index}));"); argName = $"out {GenerateSpanCastElement0(canonicalTypeName, $"{argName}.Memory.Span")}"; } else { - outParameters.Add(new OutParameter(argName, canonicalTypeName, index, argType)); + outParameters.Add(new OutParameter(argName, canonicalTypeName, outArgIndex++, argType)); argName = $"out {canonicalTypeName} {argName}"; } @@ -319,7 +331,15 @@ namespace Ryujinx.Horizon.Generators.Hipc value = $"{InObjectsVariableName}[{inObjectIndex++}]"; break; case CommandArgType.Buffer: - if (IsReadOnlySpan(compilation, parameter)) + if (IsMemory(compilation, parameter)) + { + value = $"CommandSerialization.GetWritableRegion(processor.GetBufferRange({index}))"; + } + else if (IsReadOnlySequence(compilation, parameter)) + { + value = $"CommandSerialization.GetReadOnlySequence(processor.GetBufferRange({index}))"; + } + else if (IsReadOnlySpan(compilation, parameter)) { string spanGenericTypeName = GetCanonicalTypeNameOfGenericArgument(compilation, parameter.Type, 0); value = GenerateSpanCast(spanGenericTypeName, $"CommandSerialization.GetReadOnlySpan(processor.GetBufferRange({index}))"); @@ -336,7 +356,13 @@ namespace Ryujinx.Horizon.Generators.Hipc break; } - if (IsSpan(compilation, parameter)) + if (IsMemory(compilation, parameter)) + { + generator.AppendLine($"using var {argName} = {value};"); + + argName = $"{argName}.Memory"; + } + else if (IsSpan(compilation, parameter)) { generator.AppendLine($"using var {argName} = {value};"); @@ -627,7 +653,9 @@ namespace Ryujinx.Horizon.Generators.Hipc private static bool IsValidTypeForBuffer(Compilation compilation, ParameterSyntax parameter) { - return IsReadOnlySpan(compilation, parameter) || + return IsMemory(compilation, parameter) || + IsReadOnlySequence(compilation, parameter) || + IsReadOnlySpan(compilation, parameter) || IsSpan(compilation, parameter) || IsUnmanagedType(compilation, parameter.Type); } @@ -639,6 +667,16 @@ namespace Ryujinx.Horizon.Generators.Hipc return typeInfo.Type.IsUnmanagedType; } + private static bool IsMemory(Compilation compilation, ParameterSyntax parameter) + { + return GetCanonicalTypeName(compilation, parameter.Type) == TypeSystemMemory; + } + + private static bool IsReadOnlySequence(Compilation compilation, ParameterSyntax parameter) + { + return GetCanonicalTypeName(compilation, parameter.Type) == TypeSystemBuffersReadOnlySequence; + } + private static bool IsReadOnlySpan(Compilation compilation, ParameterSyntax parameter) { return GetCanonicalTypeName(compilation, parameter.Type) == TypeSystemReadOnlySpan; @@ -719,7 +757,9 @@ namespace Ryujinx.Horizon.Generators.Hipc private static string GenerateSpanCast(string targetType, string input) { - return $"MemoryMarshal.Cast({input})"; + return targetType == "byte" + ? input + : $"MemoryMarshal.Cast({input})"; } private static bool HasAttribute(Compilation compilation, ParameterSyntax parameterSyntax, string fullAttributeName) diff --git a/src/Ryujinx.Horizon/Arp/ArpIpcServer.cs b/src/Ryujinx.Horizon/Arp/ArpIpcServer.cs new file mode 100644 index 000000000..a6017b8a6 --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/ArpIpcServer.cs @@ -0,0 +1,62 @@ +using Ryujinx.Horizon.Arp.Ipc; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Arp +{ + class ArpIpcServer + { + private const int ArpRMaxSessionsCount = 16; + private const int ArpWMaxSessionsCount = 8; + private const int MaxSessionsCount = ArpRMaxSessionsCount + ArpWMaxSessionsCount; + + private const int PointerBufferSize = 0x1000; + private const int MaxDomains = 24; + private const int MaxDomainObjects = 32; + private const int MaxPortsCount = 2; + + private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); + + private SmApi _sm; + private ServerManager _serverManager; + private ApplicationInstanceManager _applicationInstanceManager; + + public IReader Reader { get; private set; } + public IWriter Writer { get; private set; } + + public void Initialize() + { + HeapAllocator allocator = new(); + + _sm = new SmApi(); + _sm.Initialize().AbortOnFailure(); + + _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _managerOptions, MaxSessionsCount); + + _applicationInstanceManager = new ApplicationInstanceManager(); + + Reader reader = new(_applicationInstanceManager); + Reader = reader; + + Writer writer = new(_applicationInstanceManager); + Writer = writer; + + _serverManager.RegisterObjectForServer(reader, ServiceName.Encode("arp:r"), ArpRMaxSessionsCount); + _serverManager.RegisterObjectForServer(writer, ServiceName.Encode("arp:w"), ArpWMaxSessionsCount); + } + + public void ServiceRequests() + { + _serverManager.ServiceRequests(); + } + + public void Shutdown() + { + _applicationInstanceManager.Dispose(); + _serverManager.Dispose(); + _sm.Dispose(); + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/ArpMain.cs b/src/Ryujinx.Horizon/Arp/ArpMain.cs new file mode 100644 index 000000000..a28baa71a --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/ArpMain.cs @@ -0,0 +1,20 @@ +namespace Ryujinx.Horizon.Arp +{ + class ArpMain : IService + { + public static void Main(ServiceTable serviceTable) + { + ArpIpcServer arpIpcServer = new(); + + arpIpcServer.Initialize(); + + serviceTable.ArpReader = arpIpcServer.Reader; + serviceTable.ArpWriter = arpIpcServer.Writer; + + serviceTable.SignalServiceReady(); + + arpIpcServer.ServiceRequests(); + arpIpcServer.Shutdown(); + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Reader.cs b/src/Ryujinx.Horizon/Arp/Ipc/Reader.cs new file mode 100644 index 000000000..de99c2ade --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/Ipc/Reader.cs @@ -0,0 +1,135 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.Ns; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Arp.Ipc +{ + partial class Reader : IReader, IServiceObject + { + private readonly ApplicationInstanceManager _applicationInstanceManager; + + public Reader(ApplicationInstanceManager applicationInstanceManager) + { + _applicationInstanceManager = applicationInstanceManager; + } + + [CmifCommand(0)] + public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId) + { + if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].LaunchProperty.HasValue) + { + applicationLaunchProperty = default; + + return ArpResult.InvalidInstanceId; + } + + applicationLaunchProperty = _applicationInstanceManager.Entries[applicationInstanceId].LaunchProperty.Value; + + return Result.Success; + } + + [CmifCommand(1)] + public Result GetApplicationControlProperty([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias, 0x4000)] out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId) + { + if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].ControlProperty.HasValue) + { + applicationControlProperty = default; + + return ArpResult.InvalidInstanceId; + } + + applicationControlProperty = _applicationInstanceManager.Entries[applicationInstanceId].ControlProperty.Value; + + return Result.Success; + } + + [CmifCommand(2)] + public Result GetApplicationProcessProperty(out ApplicationProcessProperty applicationProcessProperty, ulong applicationInstanceId) + { + if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].ProcessProperty.HasValue) + { + applicationProcessProperty = default; + + return ArpResult.InvalidInstanceId; + } + + applicationProcessProperty = _applicationInstanceManager.Entries[applicationInstanceId].ProcessProperty.Value; + + return Result.Success; + } + + [CmifCommand(3)] + public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong pid) + { + applicationInstanceId = 0; + + if (pid == 0) + { + return ArpResult.InvalidPid; + } + + for (int i = 0; i < _applicationInstanceManager.Entries.Length; i++) + { + if (_applicationInstanceManager.Entries[i] != null && _applicationInstanceManager.Entries[i].Pid == pid) + { + applicationInstanceId = (ulong)i; + + return Result.Success; + } + } + + return ArpResult.InvalidPid; + } + + [CmifCommand(4)] + public Result GetApplicationInstanceUnregistrationNotifier(out IUnregistrationNotifier unregistrationNotifier) + { + unregistrationNotifier = new UnregistrationNotifier(_applicationInstanceManager); + + return Result.Success; + } + + [CmifCommand(5)] + public Result ListApplicationInstanceId(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span applicationInstanceIdList) + { + count = 0; + + if (_applicationInstanceManager.Entries[0] != null) + { + applicationInstanceIdList[count++] = 0; + } + + if (_applicationInstanceManager.Entries[1] != null) + { + applicationInstanceIdList[count++] = 1; + } + + return Result.Success; + } + + [CmifCommand(6)] + public Result GetMicroApplicationInstanceId(out ulong microApplicationInstanceId, [ClientProcessId] ulong pid) + { + return GetApplicationInstanceId(out microApplicationInstanceId, pid); + } + + [CmifCommand(7)] + public Result GetApplicationCertificate([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize, 0x528)] out ApplicationCertificate applicationCertificate, ulong applicationInstanceId) + { + if (_applicationInstanceManager.Entries[applicationInstanceId] == null) + { + applicationCertificate = default; + + return ArpResult.InvalidInstanceId; + } + + applicationCertificate = _applicationInstanceManager.Entries[applicationInstanceId].Certificate.Value; + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs b/src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs new file mode 100644 index 000000000..841ab7601 --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs @@ -0,0 +1,52 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.Ns; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Arp.Ipc +{ + partial class Registrar : IRegistrar, IServiceObject + { + private readonly ApplicationInstance _applicationInstance; + + public Registrar(ApplicationInstance applicationInstance) + { + _applicationInstance = applicationInstance; + } + + [CmifCommand(0)] + public Result Issue(out ulong applicationInstanceId) + { + throw new NotImplementedException(); + } + + [CmifCommand(1)] + public Result SetApplicationLaunchProperty(ApplicationLaunchProperty applicationLaunchProperty) + { + if (_applicationInstance.LaunchProperty != null) + { + return ArpResult.DataAlreadyBound; + } + + _applicationInstance.LaunchProperty = applicationLaunchProperty; + + return Result.Success; + } + + [CmifCommand(2)] + public Result SetApplicationControlProperty([Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize, 0x4000)] in ApplicationControlProperty applicationControlProperty) + { + if (_applicationInstance.ControlProperty != null) + { + return ArpResult.DataAlreadyBound; + } + + _applicationInstance.ControlProperty = applicationControlProperty; + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs b/src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs new file mode 100644 index 000000000..49f2b1cce --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs @@ -0,0 +1,25 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Arp.Ipc +{ + partial class UnregistrationNotifier : IUnregistrationNotifier, IServiceObject + { + private readonly ApplicationInstanceManager _applicationInstanceManager; + + public UnregistrationNotifier(ApplicationInstanceManager applicationInstanceManager) + { + _applicationInstanceManager = applicationInstanceManager; + } + + [CmifCommand(0)] + public Result GetReadableHandle([CopyHandle] out int readableHandle) + { + readableHandle = _applicationInstanceManager.EventHandle; + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Updater.cs b/src/Ryujinx.Horizon/Arp/Ipc/Updater.cs new file mode 100644 index 000000000..f7531d712 --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/Ipc/Updater.cs @@ -0,0 +1,74 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Arp.Ipc +{ + partial class Updater : IUpdater, IServiceObject + { + private readonly ApplicationInstanceManager _applicationInstanceManager; + private readonly ulong _applicationInstanceId; + private readonly bool _forCertificate; + + public Updater(ApplicationInstanceManager applicationInstanceManager, ulong applicationInstanceId, bool forCertificate) + { + _applicationInstanceManager = applicationInstanceManager; + _applicationInstanceId = applicationInstanceId; + _forCertificate = forCertificate; + } + + [CmifCommand(0)] + public Result Issue() + { + throw new NotImplementedException(); + } + + [CmifCommand(1)] + public Result SetApplicationProcessProperty(ulong pid, ApplicationProcessProperty applicationProcessProperty) + { + if (_forCertificate) + { + return ArpResult.DataAlreadyBound; + } + + if (pid == 0) + { + return ArpResult.InvalidPid; + } + + _applicationInstanceManager.Entries[_applicationInstanceId].Pid = pid; + _applicationInstanceManager.Entries[_applicationInstanceId].ProcessProperty = applicationProcessProperty; + + return Result.Success; + } + + [CmifCommand(2)] + public Result DeleteApplicationProcessProperty() + { + if (_forCertificate) + { + return ArpResult.DataAlreadyBound; + } + + _applicationInstanceManager.Entries[_applicationInstanceId].ProcessProperty = new ApplicationProcessProperty(); + + return Result.Success; + } + + [CmifCommand(3)] + public Result SetApplicationCertificate([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ApplicationCertificate applicationCertificate) + { + if (!_forCertificate) + { + return ArpResult.DataAlreadyBound; + } + + _applicationInstanceManager.Entries[_applicationInstanceId].Certificate = applicationCertificate; + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Writer.cs b/src/Ryujinx.Horizon/Arp/Ipc/Writer.cs new file mode 100644 index 000000000..29c98b779 --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/Ipc/Writer.cs @@ -0,0 +1,75 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.OsTypes; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Arp.Ipc +{ + partial class Writer : IWriter, IServiceObject + { + private readonly ApplicationInstanceManager _applicationInstanceManager; + + public Writer(ApplicationInstanceManager applicationInstanceManager) + { + _applicationInstanceManager = applicationInstanceManager; + } + + [CmifCommand(0)] + public Result AcquireRegistrar(out IRegistrar registrar) + { + if (_applicationInstanceManager.Entries[0] != null) + { + if (_applicationInstanceManager.Entries[1] != null) + { + registrar = null; + + return ArpResult.NoFreeInstance; + } + else + { + _applicationInstanceManager.Entries[1] = new ApplicationInstance(); + + registrar = new Registrar(_applicationInstanceManager.Entries[1]); + } + } + else + { + _applicationInstanceManager.Entries[0] = new ApplicationInstance(); + + registrar = new Registrar(_applicationInstanceManager.Entries[0]); + } + + return Result.Success; + } + + [CmifCommand(1)] + public Result UnregisterApplicationInstance(ulong applicationInstanceId) + { + if (_applicationInstanceManager.Entries[applicationInstanceId] != null) + { + _applicationInstanceManager.Entries[applicationInstanceId] = null; + } + + Os.SignalSystemEvent(ref _applicationInstanceManager.SystemEvent); + + return Result.Success; + } + + [CmifCommand(2)] + public Result AcquireApplicationProcessPropertyUpdater(out IUpdater updater, ulong applicationInstanceId) + { + updater = new Updater(_applicationInstanceManager, applicationInstanceId, false); + + return Result.Success; + } + + [CmifCommand(3)] + public Result AcquireApplicationCertificateUpdater(out IUpdater updater, ulong applicationInstanceId) + { + updater = new Updater(_applicationInstanceManager, applicationInstanceId, true); + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Audio/AudioMain.cs b/src/Ryujinx.Horizon/Audio/AudioMain.cs new file mode 100644 index 000000000..92c9e804f --- /dev/null +++ b/src/Ryujinx.Horizon/Audio/AudioMain.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Horizon.Audio +{ + class AudioMain : IService + { + public static void Main(ServiceTable serviceTable) + { + AudioUserIpcServer ipcServer = new(); + + ipcServer.Initialize(); + + serviceTable.SignalServiceReady(); + + ipcServer.ServiceRequests(); + ipcServer.Shutdown(); + } + } +} diff --git a/src/Ryujinx.Horizon/Audio/AudioManagers.cs b/src/Ryujinx.Horizon/Audio/AudioManagers.cs new file mode 100644 index 000000000..493a6f9b5 --- /dev/null +++ b/src/Ryujinx.Horizon/Audio/AudioManagers.cs @@ -0,0 +1,78 @@ +using Ryujinx.Audio; +using Ryujinx.Audio.Input; +using Ryujinx.Audio.Integration; +using Ryujinx.Audio.Output; +using Ryujinx.Audio.Renderer.Device; +using Ryujinx.Audio.Renderer.Server; +using Ryujinx.Cpu; +using Ryujinx.Horizon.Sdk.Audio; +using System; + +namespace Ryujinx.Horizon.Audio +{ + class AudioManagers : IDisposable + { + public AudioManager AudioManager { get; } + public AudioOutputManager AudioOutputManager { get; } + public AudioInputManager AudioInputManager { get; } + public AudioRendererManager AudioRendererManager { get; } + public VirtualDeviceSessionRegistry AudioDeviceSessionRegistry { get; } + + public AudioManagers(IHardwareDeviceDriver audioDeviceDriver, ITickSource tickSource) + { + AudioManager = new AudioManager(); + AudioOutputManager = new AudioOutputManager(); + AudioInputManager = new AudioInputManager(); + AudioRendererManager = new AudioRendererManager(tickSource); + AudioDeviceSessionRegistry = new VirtualDeviceSessionRegistry(audioDeviceDriver); + + IWritableEvent[] audioOutputRegisterBufferEvents = new IWritableEvent[Constants.AudioOutSessionCountMax]; + + for (int i = 0; i < audioOutputRegisterBufferEvents.Length; i++) + { + audioOutputRegisterBufferEvents[i] = new AudioEvent(); + } + + AudioOutputManager.Initialize(audioDeviceDriver, audioOutputRegisterBufferEvents); + + IWritableEvent[] audioInputRegisterBufferEvents = new IWritableEvent[Constants.AudioInSessionCountMax]; + + for (int i = 0; i < audioInputRegisterBufferEvents.Length; i++) + { + audioInputRegisterBufferEvents[i] = new AudioEvent(); + } + + AudioInputManager.Initialize(audioDeviceDriver, audioInputRegisterBufferEvents); + + IWritableEvent[] systemEvents = new IWritableEvent[Constants.AudioRendererSessionCountMax]; + + for (int i = 0; i < systemEvents.Length; i++) + { + systemEvents[i] = new AudioEvent(); + } + + AudioManager.Initialize(audioDeviceDriver.GetUpdateRequiredEvent(), AudioOutputManager.Update, AudioInputManager.Update); + + AudioRendererManager.Initialize(systemEvents, audioDeviceDriver); + + AudioManager.Start(); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + AudioManager.Dispose(); + AudioOutputManager.Dispose(); + AudioInputManager.Dispose(); + AudioRendererManager.Dispose(); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Horizon/Audio/AudioUserIpcServer.cs b/src/Ryujinx.Horizon/Audio/AudioUserIpcServer.cs new file mode 100644 index 000000000..20c824e1e --- /dev/null +++ b/src/Ryujinx.Horizon/Audio/AudioUserIpcServer.cs @@ -0,0 +1,55 @@ +using Ryujinx.Horizon.Sdk.Audio.Detail; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Audio +{ + class AudioUserIpcServer + { + private const int MaxSessionsCount = 30; + + private const int PointerBufferSize = 0xB40; + private const int MaxDomains = 0; + private const int MaxDomainObjects = 0; + private const int MaxPortsCount = 1; + + private static readonly ManagerOptions _options = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); + + private SmApi _sm; + private ServerManager _serverManager; + private AudioManagers _managers; + + public void Initialize() + { + HeapAllocator allocator = new(); + + _sm = new SmApi(); + _sm.Initialize().AbortOnFailure(); + + _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _options, MaxSessionsCount); + _managers = new AudioManagers(HorizonStatic.Options.AudioDeviceDriver, HorizonStatic.Options.TickSource); + + AudioRendererManager audioRendererManager = new(_managers.AudioRendererManager, _managers.AudioDeviceSessionRegistry); + AudioOutManager audioOutManager = new(_managers.AudioOutputManager); + AudioInManager audioInManager = new(_managers.AudioInputManager); + FinalOutputRecorderManager finalOutputRecorderManager = new(); + + _serverManager.RegisterObjectForServer(audioRendererManager, ServiceName.Encode("audren:u"), MaxSessionsCount); + _serverManager.RegisterObjectForServer(audioOutManager, ServiceName.Encode("audout:u"), MaxSessionsCount); + _serverManager.RegisterObjectForServer(audioInManager, ServiceName.Encode("audin:u"), MaxSessionsCount); + _serverManager.RegisterObjectForServer(finalOutputRecorderManager, ServiceName.Encode("audrec:u"), MaxSessionsCount); + } + + public void ServiceRequests() + { + _serverManager.ServiceRequests(); + } + + public void Shutdown() + { + _serverManager.Dispose(); + _managers.Dispose(); + _sm.Dispose(); + } + } +} diff --git a/src/Ryujinx.Horizon/Audio/HwopusIpcServer.cs b/src/Ryujinx.Horizon/Audio/HwopusIpcServer.cs new file mode 100644 index 000000000..e60e033cc --- /dev/null +++ b/src/Ryujinx.Horizon/Audio/HwopusIpcServer.cs @@ -0,0 +1,46 @@ +using Ryujinx.Horizon.Sdk.Codec.Detail; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Audio +{ + class HwopusIpcServer + { + private const int MaxSessionsCount = 24; + + private const int PointerBufferSize = 0x1000; + private const int MaxDomains = 8; + private const int MaxDomainObjects = 256; + private const int MaxPortsCount = 1; + + private static readonly ManagerOptions _options = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); + + private SmApi _sm; + private ServerManager _serverManager; + + public void Initialize() + { + HeapAllocator allocator = new(); + + _sm = new SmApi(); + _sm.Initialize().AbortOnFailure(); + + _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _options, MaxSessionsCount); + + HardwareOpusDecoderManager hardwareOpusDecoderManager = new(); + + _serverManager.RegisterObjectForServer(hardwareOpusDecoderManager, ServiceName.Encode("hwopus"), MaxSessionsCount); + } + + public void ServiceRequests() + { + _serverManager.ServiceRequests(); + } + + public void Shutdown() + { + _serverManager.Dispose(); + _sm.Dispose(); + } + } +} diff --git a/src/Ryujinx.Horizon/Audio/HwopusMain.cs b/src/Ryujinx.Horizon/Audio/HwopusMain.cs new file mode 100644 index 000000000..04eee3fad --- /dev/null +++ b/src/Ryujinx.Horizon/Audio/HwopusMain.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Horizon.Audio +{ + class HwopusMain : IService + { + public static void Main(ServiceTable serviceTable) + { + HwopusIpcServer ipcServer = new(); + + ipcServer.Initialize(); + + serviceTable.SignalServiceReady(); + + ipcServer.ServiceRequests(); + ipcServer.Shutdown(); + } + } +} diff --git a/src/Ryujinx.Horizon/Bcat/BcatIpcServer.cs b/src/Ryujinx.Horizon/Bcat/BcatIpcServer.cs index dd4e5b53a..8da3971cf 100644 --- a/src/Ryujinx.Horizon/Bcat/BcatIpcServer.cs +++ b/src/Ryujinx.Horizon/Bcat/BcatIpcServer.cs @@ -44,6 +44,7 @@ namespace Ryujinx.Horizon.Bcat public void Shutdown() { _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/Friends/FriendsIpcServer.cs b/src/Ryujinx.Horizon/Friends/FriendsIpcServer.cs new file mode 100644 index 000000000..a12c0cae8 --- /dev/null +++ b/src/Ryujinx.Horizon/Friends/FriendsIpcServer.cs @@ -0,0 +1,50 @@ +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Friends +{ + class FriendsIpcServer + { + private const int MaxSessionsCount = 8; + private const int TotalMaxSessionsCount = MaxSessionsCount * 5; + + private const int PointerBufferSize = 0xA00; + private const int MaxDomains = 64; + private const int MaxDomainObjects = 16; + private const int MaxPortsCount = 5; + + private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); + + private SmApi _sm; + private FriendsServerManager _serverManager; + + public void Initialize() + { + HeapAllocator allocator = new(); + + _sm = new SmApi(); + _sm.Initialize().AbortOnFailure(); + + _serverManager = new FriendsServerManager(allocator, _sm, MaxPortsCount, _managerOptions, TotalMaxSessionsCount); + +#pragma warning disable IDE0055 // Disable formatting + _serverManager.RegisterServer((int)FriendsPortIndex.Admin, ServiceName.Encode("friend:a"), MaxSessionsCount); + _serverManager.RegisterServer((int)FriendsPortIndex.User, ServiceName.Encode("friend:u"), MaxSessionsCount); + _serverManager.RegisterServer((int)FriendsPortIndex.Viewer, ServiceName.Encode("friend:v"), MaxSessionsCount); + _serverManager.RegisterServer((int)FriendsPortIndex.Manager, ServiceName.Encode("friend:m"), MaxSessionsCount); + _serverManager.RegisterServer((int)FriendsPortIndex.System, ServiceName.Encode("friend:s"), MaxSessionsCount); +#pragma warning restore IDE0055 + } + + public void ServiceRequests() + { + _serverManager.ServiceRequests(); + } + + public void Shutdown() + { + _serverManager.Dispose(); + _sm.Dispose(); + } + } +} diff --git a/src/Ryujinx.Horizon/Friends/FriendsMain.cs b/src/Ryujinx.Horizon/Friends/FriendsMain.cs new file mode 100644 index 000000000..0f119cf01 --- /dev/null +++ b/src/Ryujinx.Horizon/Friends/FriendsMain.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Horizon.Friends +{ + class FriendsMain : IService + { + public static void Main(ServiceTable serviceTable) + { + FriendsIpcServer ipcServer = new(); + + ipcServer.Initialize(); + + serviceTable.SignalServiceReady(); + + ipcServer.ServiceRequests(); + ipcServer.Shutdown(); + } + } +} diff --git a/src/Ryujinx.Horizon/Friends/FriendsPortIndex.cs b/src/Ryujinx.Horizon/Friends/FriendsPortIndex.cs new file mode 100644 index 000000000..f567db302 --- /dev/null +++ b/src/Ryujinx.Horizon/Friends/FriendsPortIndex.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.Horizon.Friends +{ + enum FriendsPortIndex + { + Admin, + User, + Viewer, + Manager, + System, + } +} diff --git a/src/Ryujinx.Horizon/Friends/FriendsServerManager.cs b/src/Ryujinx.Horizon/Friends/FriendsServerManager.cs new file mode 100644 index 000000000..5026206b7 --- /dev/null +++ b/src/Ryujinx.Horizon/Friends/FriendsServerManager.cs @@ -0,0 +1,36 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.Friends.Detail.Ipc; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; +using System; + +namespace Ryujinx.Horizon.Friends +{ + class FriendsServerManager : ServerManager + { + private readonly IEmulatorAccountManager _accountManager; + private readonly NotificationEventHandler _notificationEventHandler; + + public FriendsServerManager(HeapAllocator allocator, SmApi sm, int maxPorts, ManagerOptions options, int maxSessions) : base(allocator, sm, maxPorts, options, maxSessions) + { + _accountManager = HorizonStatic.Options.AccountManager; + _notificationEventHandler = new(); + } + + protected override Result OnNeedsToAccept(int portIndex, Server server) + { + return (FriendsPortIndex)portIndex switch + { +#pragma warning disable IDE0055 // Disable formatting + FriendsPortIndex.Admin => AcceptImpl(server, new ServiceCreator(_accountManager, _notificationEventHandler, FriendsServicePermissionLevel.Admin)), + FriendsPortIndex.User => AcceptImpl(server, new ServiceCreator(_accountManager, _notificationEventHandler, FriendsServicePermissionLevel.User)), + FriendsPortIndex.Viewer => AcceptImpl(server, new ServiceCreator(_accountManager, _notificationEventHandler, FriendsServicePermissionLevel.Viewer)), + FriendsPortIndex.Manager => AcceptImpl(server, new ServiceCreator(_accountManager, _notificationEventHandler, FriendsServicePermissionLevel.Manager)), + FriendsPortIndex.System => AcceptImpl(server, new ServiceCreator(_accountManager, _notificationEventHandler, FriendsServicePermissionLevel.System)), + _ => throw new ArgumentOutOfRangeException(nameof(portIndex)), +#pragma warning restore IDE0055 + }; + } + } +} diff --git a/src/Ryujinx.Horizon/HorizonOptions.cs b/src/Ryujinx.Horizon/HorizonOptions.cs index e3c862da4..a24ce7f61 100644 --- a/src/Ryujinx.Horizon/HorizonOptions.cs +++ b/src/Ryujinx.Horizon/HorizonOptions.cs @@ -1,4 +1,7 @@ using LibHac; +using Ryujinx.Audio.Integration; +using Ryujinx.Cpu; +using Ryujinx.Horizon.Sdk.Account; using Ryujinx.Horizon.Sdk.Fs; namespace Ryujinx.Horizon @@ -10,13 +13,25 @@ namespace Ryujinx.Horizon public HorizonClient BcatClient { get; } public IFsClient FsClient { get; } + public IEmulatorAccountManager AccountManager { get; } + public IHardwareDeviceDriver AudioDeviceDriver { get; } + public ITickSource TickSource { get; } - public HorizonOptions(bool ignoreMissingServices, HorizonClient bcatClient, IFsClient fsClient) + public HorizonOptions( + bool ignoreMissingServices, + HorizonClient bcatClient, + IFsClient fsClient, + IEmulatorAccountManager accountManager, + IHardwareDeviceDriver audioDeviceDriver, + ITickSource tickSource) { IgnoreMissingServices = ignoreMissingServices; ThrowOnInvalidCommandIds = true; BcatClient = bcatClient; FsClient = fsClient; + AccountManager = accountManager; + AudioDeviceDriver = audioDeviceDriver; + TickSource = tickSource; } } } diff --git a/src/Ryujinx.Horizon/Hshl/HshlIpcServer.cs b/src/Ryujinx.Horizon/Hshl/HshlIpcServer.cs index d7d89e24b..b1cc7259d 100644 --- a/src/Ryujinx.Horizon/Hshl/HshlIpcServer.cs +++ b/src/Ryujinx.Horizon/Hshl/HshlIpcServer.cs @@ -42,6 +42,7 @@ namespace Ryujinx.Horizon.Hshl public void Shutdown() { _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/Ins/InsIpcServer.cs b/src/Ryujinx.Horizon/Ins/InsIpcServer.cs index bb2749d5f..4e06dcadd 100644 --- a/src/Ryujinx.Horizon/Ins/InsIpcServer.cs +++ b/src/Ryujinx.Horizon/Ins/InsIpcServer.cs @@ -42,6 +42,7 @@ namespace Ryujinx.Horizon.Ins public void Shutdown() { _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/Lbl/LblIpcServer.cs b/src/Ryujinx.Horizon/Lbl/LblIpcServer.cs index 6b5421653..f25fc54b1 100644 --- a/src/Ryujinx.Horizon/Lbl/LblIpcServer.cs +++ b/src/Ryujinx.Horizon/Lbl/LblIpcServer.cs @@ -38,6 +38,7 @@ namespace Ryujinx.Horizon.Lbl public void Shutdown() { _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/LogManager/LmIpcServer.cs b/src/Ryujinx.Horizon/LogManager/LmIpcServer.cs index d023ff927..6bb4e11c7 100644 --- a/src/Ryujinx.Horizon/LogManager/LmIpcServer.cs +++ b/src/Ryujinx.Horizon/LogManager/LmIpcServer.cs @@ -38,6 +38,7 @@ namespace Ryujinx.Horizon.LogManager public void Shutdown() { _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs b/src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs index c52a294f5..b3ce81182 100644 --- a/src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs +++ b/src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs @@ -38,6 +38,7 @@ namespace Ryujinx.Horizon.MmNv public void Shutdown() { _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/Ngc/Ipc/Service.cs b/src/Ryujinx.Horizon/Ngc/Ipc/Service.cs index 828c09199..740f893f8 100644 --- a/src/Ryujinx.Horizon/Ngc/Ipc/Service.cs +++ b/src/Ryujinx.Horizon/Ngc/Ipc/Service.cs @@ -26,7 +26,11 @@ namespace Ryujinx.Horizon.Ngc.Ipc } [CmifCommand(1)] - public Result Check(out uint checkMask, ReadOnlySpan text, uint regionMask, ProfanityFilterOption option) + public Result Check( + out uint checkMask, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan text, + uint regionMask, + ProfanityFilterOption option) { lock (_profanityFilter) { diff --git a/src/Ryujinx.Horizon/Ngc/NgcIpcServer.cs b/src/Ryujinx.Horizon/Ngc/NgcIpcServer.cs index b2a74fb22..ec73f96ae 100644 --- a/src/Ryujinx.Horizon/Ngc/NgcIpcServer.cs +++ b/src/Ryujinx.Horizon/Ngc/NgcIpcServer.cs @@ -3,7 +3,6 @@ using Ryujinx.Horizon.Sdk.Fs; using Ryujinx.Horizon.Sdk.Ngc.Detail; using Ryujinx.Horizon.Sdk.Sf.Hipc; using Ryujinx.Horizon.Sdk.Sm; -using System; namespace Ryujinx.Horizon.Ngc { @@ -46,6 +45,7 @@ namespace Ryujinx.Horizon.Ngc { _serverManager.Dispose(); _profanityFilter.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/Ovln/OvlnIpcServer.cs b/src/Ryujinx.Horizon/Ovln/OvlnIpcServer.cs index c4580a861..d4257be8d 100644 --- a/src/Ryujinx.Horizon/Ovln/OvlnIpcServer.cs +++ b/src/Ryujinx.Horizon/Ovln/OvlnIpcServer.cs @@ -43,6 +43,7 @@ namespace Ryujinx.Horizon.Ovln public void Shutdown() { _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs b/src/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs index c165f46fa..4ed7dd48e 100644 --- a/src/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs +++ b/src/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs @@ -5,6 +5,7 @@ using Ryujinx.Common.Utilities; using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Prepo.Types; using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.Arp; using Ryujinx.Horizon.Sdk.Prepo; using Ryujinx.Horizon.Sdk.Sf; using Ryujinx.Horizon.Sdk.Sf.Hipc; @@ -22,14 +23,16 @@ namespace Ryujinx.Horizon.Prepo.Ipc System, } + private readonly ArpApi _arp; private readonly PrepoServicePermissionLevel _permissionLevel; private ulong _systemSessionId; private bool _immediateTransmissionEnabled; private bool _userAgreementCheckEnabled = true; - public PrepoService(PrepoServicePermissionLevel permissionLevel) + public PrepoService(ArpApi arp, PrepoServicePermissionLevel permissionLevel) { + _arp = arp; _permissionLevel = permissionLevel; } @@ -165,7 +168,7 @@ namespace Ryujinx.Horizon.Prepo.Ipc return PrepoResult.PermissionDenied; } - private static Result ProcessPlayReport(PlayReportKind playReportKind, ReadOnlySpan gameRoomBuffer, ReadOnlySpan reportBuffer, ulong pid, Uid userId, bool withUserId = false, ApplicationId applicationId = default) + private Result ProcessPlayReport(PlayReportKind playReportKind, ReadOnlySpan gameRoomBuffer, ReadOnlySpan reportBuffer, ulong pid, Uid userId, bool withUserId = false, ApplicationId applicationId = default) { if (withUserId) { @@ -199,8 +202,8 @@ namespace Ryujinx.Horizon.Prepo.Ipc builder.AppendLine("PlayReport log:"); builder.AppendLine($" Kind: {playReportKind}"); - // NOTE: The service calls arp:r using the pid to get the application id, if it fails PrepoResult.InvalidPid is returned. - // Reports are stored internally and an event is signaled to transmit them. + // NOTE: Reports are stored internally and an event is signaled to transmit them. + if (pid != 0) { builder.AppendLine($" Pid: {pid}"); @@ -210,6 +213,16 @@ namespace Ryujinx.Horizon.Prepo.Ipc builder.AppendLine($" ApplicationId: {applicationId}"); } + Result result = _arp.GetApplicationInstanceId(out ulong applicationInstanceId, pid); + if (result.IsFailure) + { + return PrepoResult.InvalidPid; + } + + _arp.GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, applicationInstanceId).AbortOnFailure(); + + builder.AppendLine($" ApplicationVersion: {applicationLaunchProperty.Version}"); + if (!userId.IsNull) { builder.AppendLine($" UserId: {userId}"); diff --git a/src/Ryujinx.Horizon/Prepo/PrepoIpcServer.cs b/src/Ryujinx.Horizon/Prepo/PrepoIpcServer.cs index fd3f86ff9..669a64594 100644 --- a/src/Ryujinx.Horizon/Prepo/PrepoIpcServer.cs +++ b/src/Ryujinx.Horizon/Prepo/PrepoIpcServer.cs @@ -1,4 +1,5 @@ using Ryujinx.Horizon.Prepo.Types; +using Ryujinx.Horizon.Sdk.Arp; using Ryujinx.Horizon.Sdk.Sf.Hipc; using Ryujinx.Horizon.Sdk.Sm; @@ -17,16 +18,19 @@ namespace Ryujinx.Horizon.Prepo private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); private SmApi _sm; + private ArpApi _arp; private PrepoServerManager _serverManager; public void Initialize() { HeapAllocator allocator = new(); + _arp = new ArpApi(allocator); + _sm = new SmApi(); _sm.Initialize().AbortOnFailure(); - _serverManager = new PrepoServerManager(allocator, _sm, MaxPortsCount, _managerOptions, TotalMaxSessionsCount); + _serverManager = new PrepoServerManager(allocator, _sm, _arp, MaxPortsCount, _managerOptions, TotalMaxSessionsCount); #pragma warning disable IDE0055 // Disable formatting _serverManager.RegisterServer((int)PrepoPortIndex.Admin, ServiceName.Encode("prepo:a"), MaxSessionsCount); // 1.0.0-5.1.0 @@ -45,7 +49,9 @@ namespace Ryujinx.Horizon.Prepo public void Shutdown() { + _arp.Dispose(); _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/Prepo/PrepoServerManager.cs b/src/Ryujinx.Horizon/Prepo/PrepoServerManager.cs index 0c1c782f6..8cac44c8f 100644 --- a/src/Ryujinx.Horizon/Prepo/PrepoServerManager.cs +++ b/src/Ryujinx.Horizon/Prepo/PrepoServerManager.cs @@ -1,6 +1,7 @@ using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Prepo.Ipc; using Ryujinx.Horizon.Prepo.Types; +using Ryujinx.Horizon.Sdk.Arp; using Ryujinx.Horizon.Sdk.Sf.Hipc; using Ryujinx.Horizon.Sdk.Sm; using System; @@ -9,8 +10,11 @@ namespace Ryujinx.Horizon.Prepo { class PrepoServerManager : ServerManager { - public PrepoServerManager(HeapAllocator allocator, SmApi sm, int maxPorts, ManagerOptions options, int maxSessions) : base(allocator, sm, maxPorts, options, maxSessions) + private readonly ArpApi _arp; + + public PrepoServerManager(HeapAllocator allocator, SmApi sm, ArpApi arp, int maxPorts, ManagerOptions options, int maxSessions) : base(allocator, sm, maxPorts, options, maxSessions) { + _arp = arp; } protected override Result OnNeedsToAccept(int portIndex, Server server) @@ -18,12 +22,12 @@ namespace Ryujinx.Horizon.Prepo return (PrepoPortIndex)portIndex switch { #pragma warning disable IDE0055 // Disable formatting - PrepoPortIndex.Admin => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Admin)), - PrepoPortIndex.Admin2 => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Admin)), - PrepoPortIndex.Manager => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Manager)), - PrepoPortIndex.User => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.User)), - PrepoPortIndex.System => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.System)), - PrepoPortIndex.Debug => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Debug)), + PrepoPortIndex.Admin => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Admin)), + PrepoPortIndex.Admin2 => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Admin)), + PrepoPortIndex.Manager => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Manager)), + PrepoPortIndex.User => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.User)), + PrepoPortIndex.System => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.System)), + PrepoPortIndex.Debug => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Debug)), _ => throw new ArgumentOutOfRangeException(nameof(portIndex)), #pragma warning restore IDE0055 }; diff --git a/src/Ryujinx.Horizon/Psc/PscIpcServer.cs b/src/Ryujinx.Horizon/Psc/PscIpcServer.cs index d6ac65685..8e574ddda 100644 --- a/src/Ryujinx.Horizon/Psc/PscIpcServer.cs +++ b/src/Ryujinx.Horizon/Psc/PscIpcServer.cs @@ -45,6 +45,7 @@ namespace Ryujinx.Horizon.Psc public void Shutdown() { _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/Ptm/Ipc/MeasurementServer.cs b/src/Ryujinx.Horizon/Ptm/Ipc/MeasurementServer.cs new file mode 100644 index 000000000..ce7c0474a --- /dev/null +++ b/src/Ryujinx.Horizon/Ptm/Ipc/MeasurementServer.cs @@ -0,0 +1,63 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Ts; +using Ryujinx.Horizon.Ts.Ipc; + +namespace Ryujinx.Horizon.Ptm.Ipc +{ + partial class MeasurementServer : IMeasurementServer + { + // NOTE: Values are randomly choosen. + public const int DefaultTemperature = 42; + public const int MinimumTemperature = 0; + public const int MaximumTemperature = 100; + + [CmifCommand(0)] // 1.0.0-16.1.0 + public Result GetTemperatureRange(out int minimumTemperature, out int maximumTemperature, Location location) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location }); + + minimumTemperature = MinimumTemperature; + maximumTemperature = MaximumTemperature; + + return Result.Success; + } + + [CmifCommand(1)] // 1.0.0-16.1.0 + public Result GetTemperature(out int temperature, Location location) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location }); + + temperature = DefaultTemperature; + + return Result.Success; + } + + [CmifCommand(2)] // 1.0.0-13.2.1 + public Result SetMeasurementMode(Location location, byte measurementMode) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location, measurementMode }); + + return Result.Success; + } + + [CmifCommand(3)] // 1.0.0-13.2.1 + public Result GetTemperatureMilliC(out int temperatureMilliC, Location location) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location }); + + temperatureMilliC = DefaultTemperature * 1000; + + return Result.Success; + } + + [CmifCommand(4)] // 8.0.0+ + public Result OpenSession(out ISession session, DeviceCode deviceCode) + { + session = new Session(deviceCode); + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Ptm/Ipc/Session.cs b/src/Ryujinx.Horizon/Ptm/Ipc/Session.cs new file mode 100644 index 000000000..191a4b3af --- /dev/null +++ b/src/Ryujinx.Horizon/Ptm/Ipc/Session.cs @@ -0,0 +1,47 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Ptm.Ipc; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Ts; + +namespace Ryujinx.Horizon.Ts.Ipc +{ + partial class Session : ISession + { + private readonly DeviceCode _deviceCode; + + public Session(DeviceCode deviceCode) + { + _deviceCode = deviceCode; + } + + [CmifCommand(0)] + public Result GetTemperatureRange(out int minimumTemperature, out int maximumTemperature) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { _deviceCode }); + + minimumTemperature = MeasurementServer.MinimumTemperature; + maximumTemperature = MeasurementServer.MaximumTemperature; + + return Result.Success; + } + + [CmifCommand(2)] + public Result SetMeasurementMode(byte measurementMode) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { _deviceCode, measurementMode }); + + return Result.Success; + } + + [CmifCommand(4)] + public Result GetTemperature(out int temperature) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { _deviceCode }); + + temperature = MeasurementServer.DefaultTemperature; + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Ptm/TsIpcServer.cs b/src/Ryujinx.Horizon/Ptm/TsIpcServer.cs new file mode 100644 index 000000000..db25d8e2e --- /dev/null +++ b/src/Ryujinx.Horizon/Ptm/TsIpcServer.cs @@ -0,0 +1,44 @@ +using Ryujinx.Horizon.Ptm.Ipc; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Ptm +{ + class TsIpcServer + { + private const int MaxSessionsCount = 4; + + private const int PointerBufferSize = 0; + private const int MaxDomains = 0; + private const int MaxDomainObjects = 0; + private const int MaxPortsCount = 1; + + private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); + + private SmApi _sm; + private ServerManager _serverManager; + + public void Initialize() + { + HeapAllocator allocator = new(); + + _sm = new SmApi(); + _sm.Initialize().AbortOnFailure(); + + _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _managerOptions, MaxSessionsCount); + + _serverManager.RegisterObjectForServer(new MeasurementServer(), ServiceName.Encode("ts"), MaxSessionsCount); + } + + public void ServiceRequests() + { + _serverManager.ServiceRequests(); + } + + public void Shutdown() + { + _serverManager.Dispose(); + _sm.Dispose(); + } + } +} diff --git a/src/Ryujinx.Horizon/Ptm/TsMain.cs b/src/Ryujinx.Horizon/Ptm/TsMain.cs new file mode 100644 index 000000000..237d52cd4 --- /dev/null +++ b/src/Ryujinx.Horizon/Ptm/TsMain.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Horizon.Ptm +{ + class TsMain : IService + { + public static void Main(ServiceTable serviceTable) + { + TsIpcServer ipcServer = new(); + + ipcServer.Initialize(); + + serviceTable.SignalServiceReady(); + + ipcServer.ServiceRequests(); + ipcServer.Shutdown(); + } + } +} diff --git a/src/Ryujinx.Horizon/Ryujinx.Horizon.csproj b/src/Ryujinx.Horizon/Ryujinx.Horizon.csproj index ae40f7b5e..bf34ddd17 100644 --- a/src/Ryujinx.Horizon/Ryujinx.Horizon.csproj +++ b/src/Ryujinx.Horizon/Ryujinx.Horizon.csproj @@ -1,10 +1,11 @@ - + net8.0 + @@ -12,7 +13,7 @@ + - diff --git a/src/Ryujinx.Horizon/Sdk/Account/IEmulatorAccountManager.cs b/src/Ryujinx.Horizon/Sdk/Account/IEmulatorAccountManager.cs new file mode 100644 index 000000000..af02cc8eb --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Account/IEmulatorAccountManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Horizon.Sdk.Account +{ + public interface IEmulatorAccountManager + { + void OpenUserOnlinePlay(Uid userId); + void CloseUserOnlinePlay(Uid userId); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Account/NetworkServiceAccountId.cs b/src/Ryujinx.Horizon/Sdk/Account/NetworkServiceAccountId.cs new file mode 100644 index 000000000..2512975e3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Account/NetworkServiceAccountId.cs @@ -0,0 +1,20 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Account +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x8)] + readonly record struct NetworkServiceAccountId + { + public readonly ulong Id; + + public NetworkServiceAccountId(ulong id) + { + Id = id; + } + + public override readonly string ToString() + { + return Id.ToString("x16"); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Account/Nickname.cs b/src/Ryujinx.Horizon/Sdk/Account/Nickname.cs new file mode 100644 index 000000000..1f351ee3a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Account/Nickname.cs @@ -0,0 +1,29 @@ +using Ryujinx.Common.Memory; +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Account +{ + [StructLayout(LayoutKind.Sequential, Size = 0x21, Pack = 0x1)] + readonly struct Nickname + { + public readonly Array33 Name; + + public Nickname(in Array33 name) + { + Name = name; + } + + public override string ToString() + { + int length = ((ReadOnlySpan)Name.AsSpan()).IndexOf((byte)0); + if (length < 0) + { + length = 33; + } + + return Encoding.UTF8.GetString(Name.AsSpan()[..length]); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Account/Uid.cs b/src/Ryujinx.Horizon/Sdk/Account/Uid.cs index a76e6d256..d612f4792 100644 --- a/src/Ryujinx.Horizon/Sdk/Account/Uid.cs +++ b/src/Ryujinx.Horizon/Sdk/Account/Uid.cs @@ -5,17 +5,17 @@ using System.Runtime.InteropServices; namespace Ryujinx.Horizon.Sdk.Account { - [StructLayout(LayoutKind.Sequential)] - readonly record struct Uid + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + public readonly record struct Uid { - public readonly long High; - public readonly long Low; + public readonly ulong High; + public readonly ulong Low; public bool IsNull => (Low | High) == 0; public static Uid Null => new(0, 0); - public Uid(long low, long high) + public Uid(ulong low, ulong high) { Low = low; High = high; @@ -23,8 +23,8 @@ namespace Ryujinx.Horizon.Sdk.Account public Uid(byte[] bytes) { - High = BitConverter.ToInt64(bytes, 0); - Low = BitConverter.ToInt64(bytes, 8); + High = BitConverter.ToUInt64(bytes, 0); + Low = BitConverter.ToUInt64(bytes, 8); } public Uid(string hex) @@ -34,8 +34,8 @@ namespace Ryujinx.Horizon.Sdk.Account throw new ArgumentException("Invalid Hex value!", nameof(hex)); } - Low = Convert.ToInt64(hex[16..], 16); - High = Convert.ToInt64(hex[..16], 16); + Low = Convert.ToUInt64(hex[16..], 16); + High = Convert.ToUInt64(hex[..16], 16); } public void Write(BinaryWriter binaryWriter) diff --git a/src/Ryujinx.Horizon/Sdk/Applet/AppletId.cs b/src/Ryujinx.Horizon/Sdk/Applet/AppletId.cs new file mode 100644 index 000000000..2b81fbf6f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Applet/AppletId.cs @@ -0,0 +1,71 @@ +namespace Ryujinx.Horizon.Sdk.Applet +{ + enum AppletId : uint + { + None = 0x00, + Application = 0x01, + OverlayApplet = 0x02, + SystemAppletMenu = 0x03, + SystemApplication = 0x04, + LibraryAppletAuth = 0x0A, + LibraryAppletCabinet = 0x0B, + LibraryAppletController = 0x0C, + LibraryAppletDataErase = 0x0D, + LibraryAppletError = 0x0E, + LibraryAppletNetConnect = 0x0F, + LibraryAppletPlayerSelect = 0x10, + LibraryAppletSwkbd = 0x11, + LibraryAppletMiiEdit = 0x12, + LibraryAppletWeb = 0x13, + LibraryAppletShop = 0x14, + LibraryAppletPhotoViewer = 0x15, + LibraryAppletSet = 0x16, + LibraryAppletOfflineWeb = 0x17, + LibraryAppletLoginShare = 0x18, + LibraryAppletWifiWebAuth = 0x19, + LibraryAppletMyPage = 0x1A, + LibraryAppletGift = 0x1B, + LibraryAppletUserMigration = 0x1C, + LibraryAppletPreomiaSys = 0x1D, + LibraryAppletStory = 0x1E, + LibraryAppletPreomiaUsr = 0x1F, + LibraryAppletPreomiaUsrDummy = 0x20, + LibraryAppletSample = 0x21, + LibraryAppletPromoteQualification = 0x22, + LibraryAppletOfflineWebFw17 = 0x32, + LibraryAppletOfflineWeb2Fw17 = 0x33, + LibraryAppletLoginShareFw17 = 0x35, + LibraryAppletLoginShare2Fw17 = 0x36, + LibraryAppletLoginShare3Fw17 = 0x37, + Unknown38 = 0x38, + DevlopmentTool = 0x3E8, + CombinationLA = 0x3F1, + AeSystemApplet = 0x3F2, + AeOverlayApplet = 0x3F3, + AeStarter = 0x3F4, + AeLibraryAppletAlone = 0x3F5, + AeLibraryApplet1 = 0x3F6, + AeLibraryApplet2 = 0x3F7, + AeLibraryApplet3 = 0x3F8, + AeLibraryApplet4 = 0x3F9, + AppletISA = 0x3FA, + AppletIOA = 0x3FB, + AppletISTA = 0x3FC, + AppletILA1 = 0x3FD, + AppletILA2 = 0x3FE, + CombinationLAFw17 = 0x700000DC, + AeSystemAppletFw17 = 0x700000E6, + AeOverlayAppletFw17 = 0x700000E7, + AeStarterFw17 = 0x700000E8, + AeLibraryAppletAloneFw17 = 0x700000E9, + AeLibraryApplet1Fw17 = 0x700000EA, + AeLibraryApplet2Fw17 = 0x700000EB, + AeLibraryApplet3Fw17 = 0x700000EC, + AeLibraryApplet4Fw17 = 0x700000ED, + AppletISAFw17 = 0x700000F0, + AppletIOAFw17 = 0x700000F1, + AppletISTAFw17 = 0x700000F2, + AppletILA1Fw17 = 0x700000F3, + AppletILA2Fw17 = 0x700000F4, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Applet/AppletResourceUserId.cs b/src/Ryujinx.Horizon/Sdk/Applet/AppletResourceUserId.cs new file mode 100644 index 000000000..00e2ad368 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Applet/AppletResourceUserId.cs @@ -0,0 +1,15 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Applet +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x8)] + readonly struct AppletResourceUserId + { + public readonly ulong Id; + + public AppletResourceUserId(ulong id) + { + Id = id; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs new file mode 100644 index 000000000..d60d337d3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + [StructLayout(LayoutKind.Sequential, Size = 0x528)] + public struct ApplicationCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs new file mode 100644 index 000000000..586e6a98a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Horizon.Sdk.Arp +{ + public enum ApplicationKind : byte + { + Application, + MicroApplication, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs new file mode 100644 index 000000000..00b818321 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs @@ -0,0 +1,14 @@ +using Ryujinx.Horizon.Sdk.Ncm; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public struct ApplicationLaunchProperty + { + public ApplicationId ApplicationId; + public uint Version; + public StorageId Storage; + public StorageId PatchStorage; + public ApplicationKind ApplicationKind; + public byte Padding; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs new file mode 100644 index 000000000..13d222a12 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs @@ -0,0 +1,10 @@ +using Ryujinx.Common.Memory; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public struct ApplicationProcessProperty + { + public byte ProgramIndex; + public Array15 Unknown; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs b/src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs new file mode 100644 index 000000000..b0acc0062 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs @@ -0,0 +1,130 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Ns; +using Ryujinx.Horizon.Sdk.Sf.Cmif; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; +using System; +using System.Runtime.CompilerServices; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + class ArpApi : IDisposable + { + private const string ArpRName = "arp:r"; + + private readonly HeapAllocator _allocator; + private int _sessionHandle; + + public ArpApi(HeapAllocator allocator) + { + _allocator = allocator; + } + + private void InitializeArpRService() + { + if (_sessionHandle == 0) + { + using var smApi = new SmApi(); + + smApi.Initialize(); + smApi.GetServiceHandle(out _sessionHandle, ServiceName.Encode(ArpRName)).AbortOnFailure(); + } + } + + public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong applicationPid) + { + Span data = stackalloc byte[8]; + SpanWriter writer = new(data); + + writer.Write(applicationPid); + + InitializeArpRService(); + + Result result = ServiceUtil.SendRequest(out CmifResponse response, _sessionHandle, 3, sendPid: false, data); + if (result.IsFailure) + { + applicationInstanceId = 0; + + return result; + } + + SpanReader reader = new(response.Data); + + applicationInstanceId = reader.Read(); + + return Result.Success; + } + + public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId) + { + applicationLaunchProperty = default; + + Span data = stackalloc byte[8]; + SpanWriter writer = new(data); + + writer.Write(applicationInstanceId); + + InitializeArpRService(); + + Result result = ServiceUtil.SendRequest(out CmifResponse response, _sessionHandle, 0, sendPid: false, data); + if (result.IsFailure) + { + return result; + } + + SpanReader reader = new(response.Data); + + applicationLaunchProperty = reader.Read(); + + return Result.Success; + } + + public Result GetApplicationControlProperty(out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId) + { + applicationControlProperty = default; + + Span data = stackalloc byte[8]; + SpanWriter writer = new(data); + + writer.Write(applicationInstanceId); + + ulong bufferSize = (ulong)Unsafe.SizeOf(); + ulong bufferAddress = _allocator.Allocate(bufferSize); + + InitializeArpRService(); + + Result result = ServiceUtil.SendRequest( + out CmifResponse response, + _sessionHandle, + 1, + sendPid: false, + data, + stackalloc[] { HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize }, + stackalloc[] { new PointerAndSize(bufferAddress, bufferSize) }); + + if (result.IsFailure) + { + return result; + } + + applicationControlProperty = HorizonStatic.AddressSpace.Read(bufferAddress); + + _allocator.Free(bufferAddress, bufferSize); + + return Result.Success; + } + + public void Dispose() + { + if (_sessionHandle != 0) + { + HorizonStatic.Syscall.CloseHandle(_sessionHandle); + + _sessionHandle = 0; + } + + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs b/src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs new file mode 100644 index 000000000..5de07871d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs @@ -0,0 +1,17 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + static class ArpResult + { + private const int ModuleId = 157; + + public static Result InvalidArgument => new(ModuleId, 30); + public static Result InvalidPid => new(ModuleId, 31); + public static Result InvalidPointer => new(ModuleId, 32); + public static Result DataAlreadyBound => new(ModuleId, 42); + public static Result AllocationFailed => new(ModuleId, 63); + public static Result NoFreeInstance => new(ModuleId, 101); + public static Result InvalidInstanceId => new(ModuleId, 102); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs new file mode 100644 index 000000000..5eb0ab184 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs @@ -0,0 +1,13 @@ +using Ryujinx.Horizon.Sdk.Ns; + +namespace Ryujinx.Horizon.Sdk.Arp.Detail +{ + class ApplicationInstance + { + public ulong Pid { get; set; } + public ApplicationLaunchProperty? LaunchProperty { get; set; } + public ApplicationProcessProperty? ProcessProperty { get; set; } + public ApplicationControlProperty? ControlProperty { get; set; } + public ApplicationCertificate? Certificate { get; set; } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstanceManager.cs b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstanceManager.cs new file mode 100644 index 000000000..18c993ce4 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstanceManager.cs @@ -0,0 +1,31 @@ +using Ryujinx.Horizon.Sdk.OsTypes; +using System; +using System.Threading; + +namespace Ryujinx.Horizon.Sdk.Arp.Detail +{ + class ApplicationInstanceManager : IDisposable + { + private int _disposalState; + + public SystemEventType SystemEvent; + public int EventHandle; + + public readonly ApplicationInstance[] Entries = new ApplicationInstance[2]; + + public ApplicationInstanceManager() + { + Os.CreateSystemEvent(out SystemEvent, EventClearMode.ManualClear, true).AbortOnFailure(); + + EventHandle = Os.GetReadableHandleOfSystemEvent(ref SystemEvent); + } + + public void Dispose() + { + if (EventHandle != 0 && Interlocked.Exchange(ref _disposalState, 1) == 0) + { + Os.DestroySystemEvent(ref SystemEvent); + } + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IReader.cs b/src/Ryujinx.Horizon/Sdk/Arp/IReader.cs new file mode 100644 index 000000000..ef78f7fd6 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IReader.cs @@ -0,0 +1,18 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Ns; +using System; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IReader + { + public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId); + public Result GetApplicationControlProperty(out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId); + public Result GetApplicationProcessProperty(out ApplicationProcessProperty applicationControlProperty, ulong applicationInstanceId); + public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong pid); + public Result GetApplicationInstanceUnregistrationNotifier(out IUnregistrationNotifier unregistrationNotifier); + public Result ListApplicationInstanceId(out int count, Span applicationInstanceIdList); + public Result GetMicroApplicationInstanceId(out ulong MicroApplicationInstanceId, ulong pid); + public Result GetApplicationCertificate(out ApplicationCertificate applicationCertificate, ulong applicationInstanceId); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs b/src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs new file mode 100644 index 000000000..467f3dbd3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Ns; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IRegistrar + { + public Result Issue(out ulong applicationInstanceId); + public Result SetApplicationLaunchProperty(ApplicationLaunchProperty applicationLaunchProperty); + public Result SetApplicationControlProperty(in ApplicationControlProperty applicationControlProperty); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs b/src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs new file mode 100644 index 000000000..24b9807d8 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs @@ -0,0 +1,9 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IUnregistrationNotifier + { + public Result GetReadableHandle(out int readableHandle); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs b/src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs new file mode 100644 index 000000000..f9beeb690 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IUpdater + { + public Result Issue(); + public Result SetApplicationProcessProperty(ulong pid, ApplicationProcessProperty applicationProcessProperty); + public Result DeleteApplicationProcessProperty(); + public Result SetApplicationCertificate(ApplicationCertificate applicationCertificate); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs b/src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs new file mode 100644 index 000000000..b3e000e1e --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IWriter + { + public Result AcquireRegistrar(out IRegistrar registrar); + public Result UnregisterApplicationInstance(ulong applicationInstanceId); + public Result AcquireApplicationProcessPropertyUpdater(out IUpdater updater, ulong applicationInstanceId); + public Result AcquireApplicationCertificateUpdater(out IUpdater updater, ulong applicationInstanceId); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/AudioEvent.cs b/src/Ryujinx.Horizon/Sdk/Audio/AudioEvent.cs new file mode 100644 index 000000000..efa8d5bc1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/AudioEvent.cs @@ -0,0 +1,50 @@ +using Ryujinx.Audio.Integration; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.OsTypes; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio +{ + class AudioEvent : IWritableEvent, IDisposable + { + private SystemEventType _systemEvent; + private readonly IExternalEvent _externalEvent; + + public AudioEvent() + { + Os.CreateSystemEvent(out _systemEvent, EventClearMode.ManualClear, interProcess: true); + + // We need to do this because the event will be signalled from a different thread. + _externalEvent = HorizonStatic.Syscall.GetExternalEvent(Os.GetWritableHandleOfSystemEvent(ref _systemEvent)); + } + + public void Signal() + { + _externalEvent.Signal(); + } + + public void Clear() + { + _externalEvent.Clear(); + } + + public int GetReadableHandle() + { + return Os.GetReadableHandleOfSystemEvent(ref _systemEvent); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + Os.DestroySystemEvent(ref _systemEvent); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/AudioResult.cs b/src/Ryujinx.Horizon/Sdk/Audio/AudioResult.cs new file mode 100644 index 000000000..5914a747c --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/AudioResult.cs @@ -0,0 +1,13 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Audio +{ + static class AudioResult + { + private const int ModuleId = 153; + + public static Result DeviceNotFound => new(ModuleId, 1); + public static Result UnsupportedRevision => new(ModuleId, 2); + public static Result NotImplemented => new(ModuleId, 513); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs new file mode 100644 index 000000000..2d3aa7ba9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs @@ -0,0 +1,294 @@ +using Ryujinx.Audio.Renderer.Device; +using Ryujinx.Audio.Renderer.Server; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Applet; +using Ryujinx.Horizon.Sdk.OsTypes; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + partial class AudioDevice : IAudioDevice, IDisposable + { + private readonly VirtualDeviceSessionRegistry _registry; + private readonly VirtualDeviceSession[] _sessions; + private readonly bool _isUsbDeviceSupported; + + private SystemEventType _audioEvent; + private SystemEventType _audioInputEvent; + private SystemEventType _audioOutputEvent; + + public AudioDevice(VirtualDeviceSessionRegistry registry, AppletResourceUserId appletResourceId, uint revision) + { + _registry = registry; + + BehaviourContext behaviourContext = new(); + behaviourContext.SetUserRevision((int)revision); + + _isUsbDeviceSupported = behaviourContext.IsAudioUsbDeviceOutputSupported(); + _sessions = registry.GetSessionByAppletResourceId(appletResourceId.Id); + + Os.CreateSystemEvent(out _audioEvent, EventClearMode.AutoClear, interProcess: true); + Os.CreateSystemEvent(out _audioInputEvent, EventClearMode.AutoClear, interProcess: true); + Os.CreateSystemEvent(out _audioOutputEvent, EventClearMode.AutoClear, interProcess: true); + } + + private bool TryGetDeviceByName(out VirtualDeviceSession result, string name, bool ignoreRevLimitation = false) + { + result = null; + + foreach (VirtualDeviceSession session in _sessions) + { + if (session.Device.Name.Equals(name)) + { + if (!ignoreRevLimitation && !_isUsbDeviceSupported && session.Device.IsUsbDevice()) + { + return false; + } + + result = session; + + return true; + } + } + + return false; + } + + [CmifCommand(0)] + public Result ListAudioDeviceName([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span names, out int nameCount) + { + int count = 0; + + foreach (VirtualDeviceSession session in _sessions) + { + if (!_isUsbDeviceSupported && session.Device.IsUsbDevice()) + { + continue; + } + + if (count >= names.Length) + { + break; + } + + names[count] = new DeviceName(session.Device.Name); + + count++; + } + + nameCount = count; + + return Result.Success; + } + + [CmifCommand(1)] + public Result SetAudioDeviceOutputVolume([Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan name, float volume) + { + if (name.Length > 0 && TryGetDeviceByName(out VirtualDeviceSession result, name[0].ToString(), ignoreRevLimitation: true)) + { + if (!_isUsbDeviceSupported && result.Device.IsUsbDevice()) + { + result = _sessions[0]; + } + + result.Volume = volume; + } + + return Result.Success; + } + + [CmifCommand(2)] + public Result GetAudioDeviceOutputVolume([Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan name, out float volume) + { + if (name.Length > 0 && TryGetDeviceByName(out VirtualDeviceSession result, name[0].ToString())) + { + volume = result.Volume; + } + else + { + volume = 0f; + } + + return Result.Success; + } + + [CmifCommand(3)] + public Result GetActiveAudioDeviceName([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span name) + { + VirtualDevice device = _registry.ActiveDevice; + + if (!_isUsbDeviceSupported && device.IsUsbDevice()) + { + device = _registry.DefaultDevice; + } + + if (name.Length > 0) + { + name[0] = new DeviceName(device.Name); + } + + return Result.Success; + } + + [CmifCommand(4)] + public Result QueryAudioDeviceSystemEvent([CopyHandle] out int eventHandle) + { + eventHandle = Os.GetReadableHandleOfSystemEvent(ref _audioEvent); + + return Result.Success; + } + + [CmifCommand(5)] + public Result GetActiveChannelCount(out int channelCount) + { + VirtualDevice device = _registry.ActiveDevice; + + if (!_isUsbDeviceSupported && device.IsUsbDevice()) + { + device = _registry.DefaultDevice; + } + + channelCount = (int)device.ChannelCount; + + return Result.Success; + } + + [CmifCommand(6)] // 3.0.0+ + public Result ListAudioDeviceNameAuto([Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span names, out int nameCount) + { + return ListAudioDeviceName(names, out nameCount); + } + + [CmifCommand(7)] // 3.0.0+ + public Result SetAudioDeviceOutputVolumeAuto([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ReadOnlySpan name, float volume) + { + return SetAudioDeviceOutputVolume(name, volume); + } + + [CmifCommand(8)] // 3.0.0+ + public Result GetAudioDeviceOutputVolumeAuto([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ReadOnlySpan name, out float volume) + { + return GetAudioDeviceOutputVolume(name, out volume); + } + + [CmifCommand(10)] // 3.0.0+ + public Result GetActiveAudioDeviceNameAuto([Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span name) + { + return GetActiveAudioDeviceName(name); + } + + [CmifCommand(11)] // 3.0.0+ + public Result QueryAudioDeviceInputEvent([CopyHandle] out int eventHandle) + { + eventHandle = Os.GetReadableHandleOfSystemEvent(ref _audioInputEvent); + + return Result.Success; + } + + [CmifCommand(12)] // 3.0.0+ + public Result QueryAudioDeviceOutputEvent([CopyHandle] out int eventHandle) + { + eventHandle = Os.GetReadableHandleOfSystemEvent(ref _audioOutputEvent); + + return Result.Success; + } + + [CmifCommand(13)] // 13.0.0+ + public Result GetActiveAudioOutputDeviceName([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span name) + { + if (name.Length > 0) + { + name[0] = new DeviceName(_registry.ActiveDevice.GetOutputDeviceName()); + } + + return Result.Success; + } + + [CmifCommand(14)] // 13.0.0+ + public Result ListAudioOutputDeviceName([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span names, out int nameCount) + { + int count = 0; + + foreach (VirtualDeviceSession session in _sessions) + { + if (!_isUsbDeviceSupported && session.Device.IsUsbDevice()) + { + continue; + } + + if (count >= names.Length) + { + break; + } + + names[count] = new DeviceName(session.Device.GetOutputDeviceName()); + + count++; + } + + nameCount = count; + + return Result.Success; + } + + [CmifCommand(15)] // 17.0.0+ + public Result AcquireAudioOutputDeviceNotification([CopyHandle] out int eventHandle, ulong deviceId) + { + eventHandle = 0; + + return AudioResult.NotImplemented; + } + + [CmifCommand(16)] // 17.0.0+ + public Result ReleaseAudioOutputDeviceNotification(ulong deviceId) + { + return AudioResult.NotImplemented; + } + + [CmifCommand(17)] // 17.0.0+ + public Result AcquireAudioInputDeviceNotification([CopyHandle] out int eventHandle, ulong deviceId) + { + eventHandle = 0; + + return AudioResult.NotImplemented; + } + + [CmifCommand(18)] // 17.0.0+ + public Result ReleaseAudioInputDeviceNotification(ulong deviceId) + { + return AudioResult.NotImplemented; + } + + [CmifCommand(19)] // 18.0.0+ + public Result SetAudioDeviceOutputVolumeAutoTuneEnabled(bool enabled) + { + return AudioResult.NotImplemented; + } + + [CmifCommand(20)] // 18.0.0+ + public Result IsAudioDeviceOutputVolumeAutoTuneEnabled(out bool enabled) + { + enabled = false; + + return AudioResult.NotImplemented; + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + Os.DestroySystemEvent(ref _audioEvent); + Os.DestroySystemEvent(ref _audioInputEvent); + Os.DestroySystemEvent(ref _audioOutputEvent); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioIn.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioIn.cs new file mode 100644 index 000000000..464ede581 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioIn.cs @@ -0,0 +1,171 @@ +using Ryujinx.Audio.Common; +using Ryujinx.Audio.Input; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + partial class AudioIn : IAudioIn, IDisposable + { + private readonly AudioInputSystem _impl; + private int _processHandle; + + public AudioIn(AudioInputSystem impl, int processHandle) + { + _impl = impl; + _processHandle = processHandle; + } + + [CmifCommand(0)] + public Result GetAudioInState(out AudioDeviceState state) + { + state = _impl.GetState(); + + return Result.Success; + } + + [CmifCommand(1)] + public Result Start() + { + return new Result((int)_impl.Start()); + } + + [CmifCommand(2)] + public Result Stop() + { + return new Result((int)_impl.Stop()); + } + + [CmifCommand(3)] + public Result AppendAudioInBuffer(ulong bufferTag, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan buffer) + { + AudioUserBuffer userBuffer = default; + + if (buffer.Length > 0) + { + userBuffer = buffer[0]; + } + + return new Result((int)_impl.AppendBuffer(bufferTag, ref userBuffer)); + } + + [CmifCommand(4)] + public Result RegisterBufferEvent([CopyHandle] out int eventHandle) + { + eventHandle = 0; + + if (_impl.RegisterBufferEvent() is AudioEvent audioEvent) + { + eventHandle = audioEvent.GetReadableHandle(); + } + + return Result.Success; + } + + [CmifCommand(5)] + public Result GetReleasedAudioInBuffers(out uint count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span bufferTags) + { + return new Result((int)_impl.GetReleasedBuffers(bufferTags, out count)); + } + + [CmifCommand(6)] + public Result ContainsAudioInBuffer(out bool contains, ulong bufferTag) + { + contains = _impl.ContainsBuffer(bufferTag); + + return Result.Success; + } + + [CmifCommand(7)] // 3.0.0+ + public Result AppendUacInBuffer( + ulong bufferTag, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan buffer, + [CopyHandle] int eventHandle) + { + AudioUserBuffer userBuffer = default; + + if (buffer.Length > 0) + { + userBuffer = buffer[0]; + } + + return new Result((int)_impl.AppendUacBuffer(bufferTag, ref userBuffer, (uint)eventHandle)); + } + + [CmifCommand(8)] // 3.0.0+ + public Result AppendAudioInBufferAuto(ulong bufferTag, [Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ReadOnlySpan buffer) + { + return AppendAudioInBuffer(bufferTag, buffer); + } + + [CmifCommand(9)] // 3.0.0+ + public Result GetReleasedAudioInBuffersAuto(out uint count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span bufferTags) + { + return GetReleasedAudioInBuffers(out count, bufferTags); + } + + [CmifCommand(10)] // 3.0.0+ + public Result AppendUacInBufferAuto( + ulong bufferTag, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ReadOnlySpan buffer, + [CopyHandle] int eventHandle) + { + return AppendUacInBuffer(bufferTag, buffer, eventHandle); + } + + [CmifCommand(11)] // 4.0.0+ + public Result GetAudioInBufferCount(out uint bufferCount) + { + bufferCount = _impl.GetBufferCount(); + + return Result.Success; + } + + [CmifCommand(12)] // 4.0.0+ + public Result SetDeviceGain(float gain) + { + _impl.SetVolume(gain); + + return Result.Success; + } + + [CmifCommand(13)] // 4.0.0+ + public Result GetDeviceGain(out float gain) + { + gain = _impl.GetVolume(); + + return Result.Success; + } + + [CmifCommand(14)] // 6.0.0+ + public Result FlushAudioInBuffers(out bool pending) + { + pending = _impl.FlushBuffers(); + + return Result.Success; + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _impl.Dispose(); + + if (_processHandle != 0) + { + HorizonStatic.Syscall.CloseHandle(_processHandle); + + _processHandle = 0; + } + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInManager.cs new file mode 100644 index 000000000..d5d047201 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInManager.cs @@ -0,0 +1,130 @@ +using Ryujinx.Audio; +using Ryujinx.Audio.Common; +using Ryujinx.Audio.Input; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Applet; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + partial class AudioInManager : IAudioInManager + { + private readonly AudioInputManager _impl; + + public AudioInManager(AudioInputManager impl) + { + _impl = impl; + } + + [CmifCommand(0)] + public Result ListAudioIns(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span names) + { + string[] deviceNames = _impl.ListAudioIns(filtered: false); + + count = 0; + + foreach (string deviceName in deviceNames) + { + if (count >= names.Length) + { + break; + } + + names[count++] = new DeviceName(deviceName); + } + + return Result.Success; + } + + [CmifCommand(1)] + public Result OpenAudioIn( + out AudioOutputConfiguration outputConfiguration, + out IAudioIn audioIn, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span outName, + AudioInputConfiguration parameter, + AppletResourceUserId appletResourceId, + [CopyHandle] int processHandle, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan name, + [ClientProcessId] ulong pid) + { + var clientMemoryManager = HorizonStatic.Syscall.GetMemoryManagerByProcessHandle(processHandle); + + ResultCode rc = _impl.OpenAudioIn( + out string outputDeviceName, + out outputConfiguration, + out AudioInputSystem inSystem, + clientMemoryManager, + name.Length > 0 ? name[0].ToString() : string.Empty, + SampleFormat.PcmInt16, + ref parameter); + + if (rc == ResultCode.Success && outName.Length > 0) + { + outName[0] = new DeviceName(outputDeviceName); + } + + audioIn = new AudioIn(inSystem, processHandle); + + return new Result((int)rc); + } + + [CmifCommand(2)] // 3.0.0+ + public Result ListAudioInsAuto(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span names) + { + return ListAudioIns(out count, names); + } + + [CmifCommand(3)] // 3.0.0+ + public Result OpenAudioInAuto( + out AudioOutputConfiguration outputConfig, + out IAudioIn audioIn, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span outName, + AudioInputConfiguration parameter, + AppletResourceUserId appletResourceId, + [CopyHandle] int processHandle, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ReadOnlySpan name, + [ClientProcessId] ulong pid) + { + return OpenAudioIn(out outputConfig, out audioIn, outName, parameter, appletResourceId, processHandle, name, pid); + } + + [CmifCommand(4)] // 3.0.0+ + public Result ListAudioInsAutoFiltered(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span names) + { + string[] deviceNames = _impl.ListAudioIns(filtered: true); + + count = 0; + + foreach (string deviceName in deviceNames) + { + if (count >= names.Length) + { + break; + } + + names[count++] = new DeviceName(deviceName); + } + + return Result.Success; + } + + [CmifCommand(5)] // 5.0.0+ + public Result OpenAudioInProtocolSpecified( + out AudioOutputConfiguration outputConfig, + out IAudioIn audioIn, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span outName, + AudioInProtocol protocol, + AudioInputConfiguration parameter, + AppletResourceUserId appletResourceId, + [CopyHandle] int processHandle, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan name, + [ClientProcessId] ulong pid) + { + // NOTE: We always assume that only the default device will be plugged (we never report any USB Audio Class type devices). + + return OpenAudioIn(out outputConfig, out audioIn, outName, parameter, appletResourceId, processHandle, name, pid); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInProtocol.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInProtocol.cs new file mode 100644 index 000000000..48785f1c0 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInProtocol.cs @@ -0,0 +1,23 @@ +using Ryujinx.Common.Memory; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x1)] + struct AudioInProtocol + { + public AudioInProtocolName Name; + public Array7 Padding; + + public AudioInProtocol(AudioInProtocolName name) + { + Name = name; + Padding = new(); + } + + public override readonly string ToString() + { + return Name.ToString(); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInProtocolName.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInProtocolName.cs new file mode 100644 index 000000000..68d283cc5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioInProtocolName.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + enum AudioInProtocolName : byte + { + DeviceIn = 0, + UacIn = 1, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioOut.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioOut.cs new file mode 100644 index 000000000..7607e2643 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioOut.cs @@ -0,0 +1,154 @@ +using Ryujinx.Audio.Common; +using Ryujinx.Audio.Output; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + partial class AudioOut : IAudioOut, IDisposable + { + private readonly AudioOutputSystem _impl; + private int _processHandle; + + public AudioOut(AudioOutputSystem impl, int processHandle) + { + _impl = impl; + _processHandle = processHandle; + } + + [CmifCommand(0)] + public Result GetAudioOutState(out AudioDeviceState state) + { + state = _impl.GetState(); + + return Result.Success; + } + + [CmifCommand(1)] + public Result Start() + { + return new Result((int)_impl.Start()); + } + + [CmifCommand(2)] + public Result Stop() + { + return new Result((int)_impl.Stop()); + } + + [CmifCommand(3)] + public Result AppendAudioOutBuffer(ulong bufferTag, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan buffer) + { + AudioUserBuffer userBuffer = default; + + if (buffer.Length > 0) + { + userBuffer = buffer[0]; + } + + return new Result((int)_impl.AppendBuffer(bufferTag, ref userBuffer)); + } + + [CmifCommand(4)] + public Result RegisterBufferEvent([CopyHandle] out int eventHandle) + { + eventHandle = 0; + + if (_impl.RegisterBufferEvent() is AudioEvent audioEvent) + { + eventHandle = audioEvent.GetReadableHandle(); + } + + return Result.Success; + } + + [CmifCommand(5)] + public Result GetReleasedAudioOutBuffers(out uint count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span bufferTags) + { + return new Result((int)_impl.GetReleasedBuffer(bufferTags, out count)); + } + + [CmifCommand(6)] + public Result ContainsAudioOutBuffer(out bool contains, ulong bufferTag) + { + contains = _impl.ContainsBuffer(bufferTag); + + return Result.Success; + } + + [CmifCommand(7)] // 3.0.0+ + public Result AppendAudioOutBufferAuto(ulong bufferTag, [Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ReadOnlySpan buffer) + { + return AppendAudioOutBuffer(bufferTag, buffer); + } + + [CmifCommand(8)] // 3.0.0+ + public Result GetReleasedAudioOutBuffersAuto(out uint count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span bufferTags) + { + return GetReleasedAudioOutBuffers(out count, bufferTags); + } + + [CmifCommand(9)] // 4.0.0+ + public Result GetAudioOutBufferCount(out uint bufferCount) + { + bufferCount = _impl.GetBufferCount(); + + return Result.Success; + } + + [CmifCommand(10)] // 4.0.0+ + public Result GetAudioOutPlayedSampleCount(out ulong sampleCount) + { + sampleCount = _impl.GetPlayedSampleCount(); + + return Result.Success; + } + + [CmifCommand(11)] // 4.0.0+ + public Result FlushAudioOutBuffers(out bool pending) + { + pending = _impl.FlushBuffers(); + + return Result.Success; + } + + [CmifCommand(12)] // 6.0.0+ + public Result SetAudioOutVolume(float volume) + { + _impl.SetVolume(volume); + + return Result.Success; + } + + [CmifCommand(13)] // 6.0.0+ + public Result GetAudioOutVolume(out float volume) + { + volume = _impl.GetVolume(); + + return Result.Success; + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _impl.Dispose(); + + if (_processHandle != 0) + { + HorizonStatic.Syscall.CloseHandle(_processHandle); + + _processHandle = 0; + } + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioOutManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioOutManager.cs new file mode 100644 index 000000000..3d129470c --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioOutManager.cs @@ -0,0 +1,93 @@ +using Ryujinx.Audio; +using Ryujinx.Audio.Common; +using Ryujinx.Audio.Output; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Applet; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + partial class AudioOutManager : IAudioOutManager + { + private readonly AudioOutputManager _impl; + + public AudioOutManager(AudioOutputManager impl) + { + _impl = impl; + } + + [CmifCommand(0)] + public Result ListAudioOuts(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span names) + { + string[] deviceNames = _impl.ListAudioOuts(); + + count = 0; + + foreach (string deviceName in deviceNames) + { + if (count >= names.Length) + { + break; + } + + names[count++] = new DeviceName(deviceName); + } + + return Result.Success; + } + + [CmifCommand(1)] + public Result OpenAudioOut( + out AudioOutputConfiguration outputConfig, + out IAudioOut audioOut, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span outName, + AudioInputConfiguration parameter, + AppletResourceUserId appletResourceId, + [CopyHandle] int processHandle, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan name, + [ClientProcessId] ulong pid) + { + var clientMemoryManager = HorizonStatic.Syscall.GetMemoryManagerByProcessHandle(processHandle); + + ResultCode rc = _impl.OpenAudioOut( + out string outputDeviceName, + out outputConfig, + out AudioOutputSystem outSystem, + clientMemoryManager, + name.Length > 0 ? name[0].ToString() : string.Empty, + SampleFormat.PcmInt16, + ref parameter); + + if (rc == ResultCode.Success && outName.Length > 0) + { + outName[0] = new DeviceName(outputDeviceName); + } + + audioOut = new AudioOut(outSystem, processHandle); + + return new Result((int)rc); + } + + [CmifCommand(2)] // 3.0.0+ + public Result ListAudioOutsAuto(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span names) + { + return ListAudioOuts(out count, names); + } + + [CmifCommand(3)] // 3.0.0+ + public Result OpenAudioOutAuto( + out AudioOutputConfiguration outputConfig, + out IAudioOut audioOut, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span outName, + AudioInputConfiguration parameter, + AppletResourceUserId appletResourceId, + [CopyHandle] int processHandle, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ReadOnlySpan name, + [ClientProcessId] ulong pid) + { + return OpenAudioOut(out outputConfig, out audioOut, outName, parameter, appletResourceId, processHandle, name, pid); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRenderer.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRenderer.cs new file mode 100644 index 000000000..4d446bba7 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRenderer.cs @@ -0,0 +1,178 @@ +using Ryujinx.Audio; +using Ryujinx.Audio.Integration; +using Ryujinx.Audio.Renderer.Server; +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; +using System.Buffers; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + partial class AudioRenderer : IAudioRenderer, IDisposable + { + private readonly AudioRenderSystem _renderSystem; + private int _workBufferHandle; + private int _processHandle; + + public AudioRenderer(AudioRenderSystem renderSystem, int workBufferHandle, int processHandle) + { + _renderSystem = renderSystem; + _workBufferHandle = workBufferHandle; + _processHandle = processHandle; + } + + [CmifCommand(0)] + public Result GetSampleRate(out int sampleRate) + { + sampleRate = (int)_renderSystem.GetSampleRate(); + + return Result.Success; + } + + [CmifCommand(1)] + public Result GetSampleCount(out int sampleCount) + { + sampleCount = (int)_renderSystem.GetSampleCount(); + + return Result.Success; + } + + [CmifCommand(2)] + public Result GetMixBufferCount(out int mixBufferCount) + { + mixBufferCount = (int)_renderSystem.GetMixBufferCount(); + + return Result.Success; + } + + [CmifCommand(3)] + public Result GetState(out int state) + { + state = _renderSystem.IsActive() ? 0 : 1; + + return Result.Success; + } + + [CmifCommand(4)] + public Result RequestUpdate( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Memory output, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Memory performanceOutput, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySequence input) + { + using MemoryHandle outputHandle = output.Pin(); + using MemoryHandle performanceOutputHandle = performanceOutput.Pin(); + + Result result = new Result((int)_renderSystem.Update(output, performanceOutput, input)); + + return result; + } + + [CmifCommand(5)] + public Result Start() + { + _renderSystem.Start(); + + return Result.Success; + } + + [CmifCommand(6)] + public Result Stop() + { + _renderSystem.Stop(); + + return Result.Success; + } + + [CmifCommand(7)] + public Result QuerySystemEvent([CopyHandle] out int eventHandle) + { + ResultCode rc = _renderSystem.QuerySystemEvent(out IWritableEvent systemEvent); + + eventHandle = 0; + + if (rc == ResultCode.Success && systemEvent is AudioEvent audioEvent) + { + eventHandle = audioEvent.GetReadableHandle(); + } + + return new Result((int)rc); + } + + [CmifCommand(8)] + public Result SetRenderingTimeLimit(int percent) + { + _renderSystem.SetRenderingTimeLimitPercent((uint)percent); + + return Result.Success; + } + + [CmifCommand(9)] + public Result GetRenderingTimeLimit(out int percent) + { + percent = (int)_renderSystem.GetRenderingTimeLimit(); + + return Result.Success; + } + + [CmifCommand(10)] // 3.0.0+ + public Result RequestUpdateAuto( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Memory output, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Memory performanceOutput, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ReadOnlySequence input) + { + return RequestUpdate(output, performanceOutput, input); + } + + [CmifCommand(11)] // 3.0.0+ + public Result ExecuteAudioRendererRendering() + { + return new Result((int)_renderSystem.ExecuteAudioRendererRendering()); + } + + [CmifCommand(12)] // 15.0.0+ + public Result SetVoiceDropParameter(float voiceDropParameter) + { + _renderSystem.SetVoiceDropParameter(voiceDropParameter); + + return Result.Success; + } + + [CmifCommand(13)] // 15.0.0+ + public Result GetVoiceDropParameter(out float voiceDropParameter) + { + voiceDropParameter = _renderSystem.GetVoiceDropParameter(); + + return Result.Success; + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _renderSystem.Dispose(); + + if (_workBufferHandle != 0) + { + HorizonStatic.Syscall.CloseHandle(_workBufferHandle); + + _workBufferHandle = 0; + } + + if (_processHandle != 0) + { + HorizonStatic.Syscall.CloseHandle(_processHandle); + + _processHandle = 0; + } + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererManager.cs new file mode 100644 index 000000000..7138d27ce --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererManager.cs @@ -0,0 +1,132 @@ +using Ryujinx.Audio.Renderer.Device; +using Ryujinx.Audio.Renderer.Server; +using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Applet; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + partial class AudioRendererManager : IAudioRendererManager + { + private const uint InitialRevision = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('1' << 24); + + private readonly Ryujinx.Audio.Renderer.Server.AudioRendererManager _impl; + private readonly VirtualDeviceSessionRegistry _registry; + + public AudioRendererManager(Ryujinx.Audio.Renderer.Server.AudioRendererManager impl, VirtualDeviceSessionRegistry registry) + { + _impl = impl; + _registry = registry; + } + + [CmifCommand(0)] + public Result OpenAudioRenderer( + out IAudioRenderer renderer, + AudioRendererParameterInternal parameter, + [CopyHandle] int workBufferHandle, + [CopyHandle] int processHandle, + ulong workBufferSize, + AppletResourceUserId appletResourceId, + [ClientProcessId] ulong pid) + { + var clientMemoryManager = HorizonStatic.Syscall.GetMemoryManagerByProcessHandle(processHandle); + ulong workBufferAddress = HorizonStatic.Syscall.GetTransferMemoryAddress(workBufferHandle); + + Result result = new Result((int)_impl.OpenAudioRenderer( + out var renderSystem, + clientMemoryManager, + ref parameter.Configuration, + appletResourceId.Id, + workBufferAddress, + workBufferSize, + (uint)processHandle)); + + if (result.IsSuccess) + { + renderer = new AudioRenderer(renderSystem, workBufferHandle, processHandle); + } + else + { + renderer = null; + + HorizonStatic.Syscall.CloseHandle(workBufferHandle); + HorizonStatic.Syscall.CloseHandle(processHandle); + } + + return result; + } + + [CmifCommand(1)] + public Result GetWorkBufferSize(out long workBufferSize, AudioRendererParameterInternal parameter) + { + if (BehaviourContext.CheckValidRevision(parameter.Configuration.Revision)) + { + workBufferSize = (long)Ryujinx.Audio.Renderer.Server.AudioRendererManager.GetWorkBufferSize(ref parameter.Configuration); + + Logger.Debug?.Print(LogClass.ServiceAudio, $"WorkBufferSize is 0x{workBufferSize:x16}."); + + return Result.Success; + } + else + { + workBufferSize = 0; + + Logger.Warning?.Print(LogClass.ServiceAudio, $"Library Revision REV{BehaviourContext.GetRevisionNumber(parameter.Configuration.Revision)} is not supported!"); + + return AudioResult.UnsupportedRevision; + } + } + + [CmifCommand(2)] + public Result GetAudioDeviceService(out IAudioDevice audioDevice, AppletResourceUserId appletResourceId) + { + audioDevice = new AudioDevice(_registry, appletResourceId, InitialRevision); + + return Result.Success; + } + + [CmifCommand(3)] // 3.0.0+ + public Result OpenAudioRendererForManualExecution( + out IAudioRenderer renderer, + AudioRendererParameterInternal parameter, + ulong workBufferAddress, + [CopyHandle] int processHandle, + ulong workBufferSize, + AppletResourceUserId appletResourceId, + [ClientProcessId] ulong pid) + { + var clientMemoryManager = HorizonStatic.Syscall.GetMemoryManagerByProcessHandle(processHandle); + + Result result = new Result((int)_impl.OpenAudioRenderer( + out var renderSystem, + clientMemoryManager, + ref parameter.Configuration, + appletResourceId.Id, + workBufferAddress, + workBufferSize, + (uint)processHandle)); + + if (result.IsSuccess) + { + renderer = new AudioRenderer(renderSystem, 0, processHandle); + } + else + { + renderer = null; + + HorizonStatic.Syscall.CloseHandle(processHandle); + } + + return result; + } + + [CmifCommand(4)] // 4.0.0+ + public Result GetAudioDeviceServiceWithRevisionInfo(out IAudioDevice audioDevice, AppletResourceUserId appletResourceId, uint revision) + { + audioDevice = new AudioDevice(_registry, appletResourceId, revision); + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererParameterInternal.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererParameterInternal.cs new file mode 100644 index 000000000..e5fcf7b3b --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererParameterInternal.cs @@ -0,0 +1,14 @@ +using Ryujinx.Audio.Renderer.Parameter; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + struct AudioRendererParameterInternal + { + public AudioRendererConfiguration Configuration; + + public AudioRendererParameterInternal(AudioRendererConfiguration configuration) + { + Configuration = configuration; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioSnoopManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioSnoopManager.cs new file mode 100644 index 000000000..cf1fe3d1d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioSnoopManager.cs @@ -0,0 +1,30 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + partial class AudioSnoopManager : IAudioSnoopManager + { + // Note: The interface changed completely on firmware 17.0.0, this implementation is for older firmware. + + [CmifCommand(0)] + public Result EnableDspUsageMeasurement() + { + return Result.Success; + } + + [CmifCommand(1)] + public Result DisableDspUsageMeasurement() + { + return Result.Success; + } + + [CmifCommand(6)] + public Result GetDspUsage(out uint usage) + { + usage = 0; + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/DeviceName.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/DeviceName.cs new file mode 100644 index 000000000..b77e2f402 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/DeviceName.cs @@ -0,0 +1,30 @@ +using Ryujinx.Common.Memory; +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x100, Pack = 1)] + struct DeviceName + { + public Array256 Name; + + public DeviceName(string name) + { + Name = new(); + Encoding.ASCII.GetBytes(name, Name.AsSpan()); + } + + public override string ToString() + { + int length = Name.AsSpan().IndexOf((byte)0); + if (length < 0) + { + length = 0x100; + } + + return Encoding.ASCII.GetString(Name.AsSpan()[..length]); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorder.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorder.cs new file mode 100644 index 000000000..393914371 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorder.cs @@ -0,0 +1,147 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.OsTypes; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + partial class FinalOutputRecorder : IFinalOutputRecorder, IDisposable + { + private int _processHandle; + private SystemEventType _event; + + public FinalOutputRecorder(int processHandle) + { + _processHandle = processHandle; + Os.CreateSystemEvent(out _event, EventClearMode.ManualClear, interProcess: true); + } + + [CmifCommand(0)] + public Result GetFinalOutputRecorderState(out uint state) + { + state = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceAudio); + + return Result.Success; + } + + [CmifCommand(1)] + public Result Start() + { + Logger.Stub?.PrintStub(LogClass.ServiceAudio); + + return Result.Success; + } + + [CmifCommand(2)] + public Result Stop() + { + Logger.Stub?.PrintStub(LogClass.ServiceAudio); + + return Result.Success; + } + + [CmifCommand(3)] + public Result AppendFinalOutputRecorderBuffer([Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan buffer, ulong bufferClientPtr) + { + Logger.Stub?.PrintStub(LogClass.ServiceAudio, new { bufferClientPtr }); + + return Result.Success; + } + + [CmifCommand(4)] + public Result RegisterBufferEvent([CopyHandle] out int eventHandle) + { + eventHandle = Os.GetReadableHandleOfSystemEvent(ref _event); + + Logger.Stub?.PrintStub(LogClass.ServiceAudio); + + return Result.Success; + } + + [CmifCommand(5)] + public Result GetReleasedFinalOutputRecorderBuffers([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span buffer, out uint count, out ulong released) + { + count = 0; + released = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceAudio); + + return Result.Success; + } + + [CmifCommand(6)] + public Result ContainsFinalOutputRecorderBuffer(ulong bufferPointer, out bool contains) + { + contains = false; + + Logger.Stub?.PrintStub(LogClass.ServiceAudio, new { bufferPointer }); + + return Result.Success; + } + + [CmifCommand(7)] + public Result GetFinalOutputRecorderBufferEndTime(ulong bufferPointer, out ulong released) + { + released = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceAudio, new { bufferPointer }); + + return Result.Success; + } + + [CmifCommand(8)] // 3.0.0+ + public Result AppendFinalOutputRecorderBufferAuto([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ReadOnlySpan buffer, ulong bufferClientPtr) + { + return AppendFinalOutputRecorderBuffer(buffer, bufferClientPtr); + } + + [CmifCommand(9)] // 3.0.0+ + public Result GetReleasedFinalOutputRecorderBuffersAuto([Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span buffer, out uint count, out ulong released) + { + return GetReleasedFinalOutputRecorderBuffers(buffer, out count, out released); + } + + [CmifCommand(10)] // 6.0.0+ + public Result FlushFinalOutputRecorderBuffers(out bool pending) + { + pending = false; + + Logger.Stub?.PrintStub(LogClass.ServiceAudio); + + return Result.Success; + } + + [CmifCommand(11)] // 9.0.0+ + public Result AttachWorkBuffer(FinalOutputRecorderParameterInternal parameter) + { + Logger.Stub?.PrintStub(LogClass.ServiceAudio, new { parameter }); + + return Result.Success; + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + Os.DestroySystemEvent(ref _event); + + if (_processHandle != 0) + { + HorizonStatic.Syscall.CloseHandle(_processHandle); + + _processHandle = 0; + } + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderManager.cs new file mode 100644 index 000000000..76491bb79 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderManager.cs @@ -0,0 +1,23 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Applet; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + partial class FinalOutputRecorderManager : IFinalOutputRecorderManager + { + [CmifCommand(0)] + public Result OpenFinalOutputRecorder( + out IFinalOutputRecorder recorder, + FinalOutputRecorderParameter parameter, + [CopyHandle] int processHandle, + out FinalOutputRecorderParameterInternal outParameter, + AppletResourceUserId appletResourceId) + { + recorder = new FinalOutputRecorder(processHandle); + outParameter = new(parameter.SampleRate, 2, 0); + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderParameter.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderParameter.cs new file mode 100644 index 000000000..afa060fca --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderParameter.cs @@ -0,0 +1,17 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x4)] + readonly struct FinalOutputRecorderParameter + { + public readonly uint SampleRate; + public readonly uint Padding; + + public FinalOutputRecorderParameter(uint sampleRate) + { + SampleRate = sampleRate; + Padding = 0; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderParameterInternal.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderParameterInternal.cs new file mode 100644 index 000000000..e88398eba --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/FinalOutputRecorderParameterInternal.cs @@ -0,0 +1,21 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x4)] + readonly struct FinalOutputRecorderParameterInternal + { + public readonly uint SampleRate; + public readonly uint ChannelCount; + public readonly uint UseLargeFrameSize; + public readonly uint Padding; + + public FinalOutputRecorderParameterInternal(uint sampleRate, uint channelCount, uint useLargeFrameSize) + { + SampleRate = sampleRate; + ChannelCount = channelCount; + UseLargeFrameSize = useLargeFrameSize; + Padding = 0; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioDevice.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioDevice.cs new file mode 100644 index 000000000..3df1fe227 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioDevice.cs @@ -0,0 +1,24 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + interface IAudioDevice : IServiceObject + { + Result ListAudioDeviceName(Span names, out int nameCount); + Result SetAudioDeviceOutputVolume(ReadOnlySpan name, float volume); + Result GetAudioDeviceOutputVolume(ReadOnlySpan name, out float volume); + Result GetActiveAudioDeviceName(Span name); + Result QueryAudioDeviceSystemEvent(out int eventHandle); + Result GetActiveChannelCount(out int channelCount); + Result ListAudioDeviceNameAuto(Span names, out int nameCount); + Result SetAudioDeviceOutputVolumeAuto(ReadOnlySpan name, float volume); + Result GetAudioDeviceOutputVolumeAuto(ReadOnlySpan name, out float volume); + Result GetActiveAudioDeviceNameAuto(Span name); + Result QueryAudioDeviceInputEvent(out int eventHandle); + Result QueryAudioDeviceOutputEvent(out int eventHandle); + Result GetActiveAudioOutputDeviceName(Span name); + Result ListAudioOutputDeviceName(Span names, out int nameCount); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioIn.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioIn.cs new file mode 100644 index 000000000..bdc3bcf62 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioIn.cs @@ -0,0 +1,26 @@ +using Ryujinx.Audio.Common; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + interface IAudioIn : IServiceObject + { + Result GetAudioInState(out AudioDeviceState state); + Result Start(); + Result Stop(); + Result AppendAudioInBuffer(ulong bufferTag, ReadOnlySpan buffer); + Result RegisterBufferEvent(out int eventHandle); + Result GetReleasedAudioInBuffers(out uint count, Span bufferTags); + Result ContainsAudioInBuffer(out bool contains, ulong bufferTag); + Result AppendUacInBuffer(ulong bufferTag, ReadOnlySpan buffer, int eventHandle); + Result AppendAudioInBufferAuto(ulong bufferTag, ReadOnlySpan buffer); + Result GetReleasedAudioInBuffersAuto(out uint count, Span bufferTags); + Result AppendUacInBufferAuto(ulong bufferTag, ReadOnlySpan buffer, int eventHandle); + Result GetAudioInBufferCount(out uint bufferCount); + Result SetDeviceGain(float gain); + Result GetDeviceGain(out float gain); + Result FlushAudioInBuffers(out bool pending); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioInManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioInManager.cs new file mode 100644 index 000000000..e7f32fbd2 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioInManager.cs @@ -0,0 +1,43 @@ +using Ryujinx.Audio.Common; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Applet; +using Ryujinx.Horizon.Sdk.Sf; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + interface IAudioInManager : IServiceObject + { + Result ListAudioIns(out int count, Span names); + Result OpenAudioIn( + out AudioOutputConfiguration outputConfig, + out IAudioIn audioIn, + Span outName, + AudioInputConfiguration parameter, + AppletResourceUserId appletResourceId, + int processHandle, + ReadOnlySpan name, + ulong pid); + Result ListAudioInsAuto(out int count, Span names); + Result OpenAudioInAuto( + out AudioOutputConfiguration outputConfig, + out IAudioIn audioIn, + Span outName, + AudioInputConfiguration parameter, + AppletResourceUserId appletResourceId, + int processHandle, + ReadOnlySpan name, + ulong pid); + Result ListAudioInsAutoFiltered(out int count, Span names); + Result OpenAudioInProtocolSpecified( + out AudioOutputConfiguration outputConfig, + out IAudioIn audioIn, + Span outName, + AudioInProtocol protocol, + AudioInputConfiguration parameter, + AppletResourceUserId appletResourceId, + int processHandle, + ReadOnlySpan name, + ulong pid); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioOut.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioOut.cs new file mode 100644 index 000000000..1b2009260 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioOut.cs @@ -0,0 +1,25 @@ +using Ryujinx.Audio.Common; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + interface IAudioOut : IServiceObject + { + Result GetAudioOutState(out AudioDeviceState state); + Result Start(); + Result Stop(); + Result AppendAudioOutBuffer(ulong bufferTag, ReadOnlySpan buffer); + Result RegisterBufferEvent(out int eventHandle); + Result GetReleasedAudioOutBuffers(out uint count, Span bufferTags); + Result ContainsAudioOutBuffer(out bool contains, ulong bufferTag); + Result AppendAudioOutBufferAuto(ulong bufferTag, ReadOnlySpan buffer); + Result GetReleasedAudioOutBuffersAuto(out uint count, Span bufferTags); + Result GetAudioOutBufferCount(out uint bufferCount); + Result GetAudioOutPlayedSampleCount(out ulong sampleCount); + Result FlushAudioOutBuffers(out bool pending); + Result SetAudioOutVolume(float volume); + Result GetAudioOutVolume(out float volume); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioOutManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioOutManager.cs new file mode 100644 index 000000000..40d62836b --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioOutManager.cs @@ -0,0 +1,32 @@ +using Ryujinx.Audio.Common; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Applet; +using Ryujinx.Horizon.Sdk.Sf; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + interface IAudioOutManager : IServiceObject + { + Result ListAudioOuts(out int count, Span names); + Result OpenAudioOut( + out AudioOutputConfiguration outputConfig, + out IAudioOut audioOut, + Span outName, + AudioInputConfiguration inputConfig, + AppletResourceUserId appletResourceId, + int processHandle, + ReadOnlySpan name, + ulong pid); + Result ListAudioOutsAuto(out int count, Span names); + Result OpenAudioOutAuto( + out AudioOutputConfiguration outputConfig, + out IAudioOut audioOut, + Span outName, + AudioInputConfiguration inputConfig, + AppletResourceUserId appletResourceId, + int processHandle, + ReadOnlySpan name, + ulong pid); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioRenderer.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioRenderer.cs new file mode 100644 index 000000000..b766bd73c --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioRenderer.cs @@ -0,0 +1,25 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using System; +using System.Buffers; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + interface IAudioRenderer : IServiceObject + { + Result GetSampleRate(out int sampleRate); + Result GetSampleCount(out int sampleCount); + Result GetMixBufferCount(out int mixBufferCount); + Result GetState(out int state); + Result RequestUpdate(Memory output, Memory performanceOutput, ReadOnlySequence input); + Result Start(); + Result Stop(); + Result QuerySystemEvent(out int eventHandle); + Result SetRenderingTimeLimit(int percent); + Result GetRenderingTimeLimit(out int percent); + Result RequestUpdateAuto(Memory output, Memory performanceOutput, ReadOnlySequence input); + Result ExecuteAudioRendererRendering(); + Result SetVoiceDropParameter(float voiceDropParameter); + Result GetVoiceDropParameter(out float voiceDropParameter); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioRendererManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioRendererManager.cs new file mode 100644 index 000000000..fe95a2084 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioRendererManager.cs @@ -0,0 +1,29 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Applet; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + interface IAudioRendererManager : IServiceObject + { + Result OpenAudioRenderer( + out IAudioRenderer renderer, + AudioRendererParameterInternal parameter, + int processHandle, + int workBufferHandle, + ulong workBufferSize, + AppletResourceUserId appletUserId, + ulong pid); + Result GetWorkBufferSize(out long workBufferSize, AudioRendererParameterInternal parameter); + Result GetAudioDeviceService(out IAudioDevice audioDevice, AppletResourceUserId appletUserId); + Result OpenAudioRendererForManualExecution( + out IAudioRenderer renderer, + AudioRendererParameterInternal parameter, + ulong workBufferAddress, + int processHandle, + ulong workBufferSize, + AppletResourceUserId appletUserId, + ulong pid); + Result GetAudioDeviceServiceWithRevisionInfo(out IAudioDevice audioDevice, AppletResourceUserId appletUserId, uint revision); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioSnoopManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioSnoopManager.cs new file mode 100644 index 000000000..72853886a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioSnoopManager.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + interface IAudioSnoopManager : IServiceObject + { + Result EnableDspUsageMeasurement(); + Result DisableDspUsageMeasurement(); + Result GetDspUsage(out uint usage); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IFinalOutputRecorder.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IFinalOutputRecorder.cs new file mode 100644 index 000000000..be21c38b7 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IFinalOutputRecorder.cs @@ -0,0 +1,22 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using System; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + interface IFinalOutputRecorder : IServiceObject + { + Result GetFinalOutputRecorderState(out uint state); + Result Start(); + Result Stop(); + Result AppendFinalOutputRecorderBuffer(ReadOnlySpan buffer, ulong bufferClientPtr); + Result RegisterBufferEvent(out int eventHandle); + Result GetReleasedFinalOutputRecorderBuffers(Span buffer, out uint count, out ulong released); + Result ContainsFinalOutputRecorderBuffer(ulong bufferPointer, out bool contains); + Result GetFinalOutputRecorderBufferEndTime(ulong bufferPointer, out ulong released); + Result AppendFinalOutputRecorderBufferAuto(ReadOnlySpan buffer, ulong bufferClientPtr); + Result GetReleasedFinalOutputRecorderBuffersAuto(Span buffer, out uint count, out ulong released); + Result FlushFinalOutputRecorderBuffers(out bool pending); + Result AttachWorkBuffer(FinalOutputRecorderParameterInternal parameter); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IFinalOutputRecorderManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IFinalOutputRecorderManager.cs new file mode 100644 index 000000000..bac41ca91 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IFinalOutputRecorderManager.cs @@ -0,0 +1,16 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Applet; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Audio.Detail +{ + interface IFinalOutputRecorderManager : IServiceObject + { + Result OpenFinalOutputRecorder( + out IFinalOutputRecorder recorder, + FinalOutputRecorderParameter parameter, + int processHandle, + out FinalOutputRecorderParameterInternal outParameter, + AppletResourceUserId appletResourceId); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Codec/CodecResult.cs b/src/Ryujinx.Horizon/Sdk/Codec/CodecResult.cs new file mode 100644 index 000000000..21508b7f1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Codec/CodecResult.cs @@ -0,0 +1,16 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Codec +{ + static class CodecResult + { + private const int ModuleId = 111; + + public static Result InvalidLength => new(ModuleId, 3); + public static Result OpusBadArg => new(ModuleId, 130); + public static Result OpusInvalidPacket => new(ModuleId, 133); + public static Result InvalidNumberOfStreams => new(ModuleId, 1000); + public static Result InvalidSampleRate => new(ModuleId, 1001); + public static Result InvalidChannelCount => new(ModuleId, 1002); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoder.cs b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoder.cs new file mode 100644 index 000000000..2146362df --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoder.cs @@ -0,0 +1,375 @@ +using Concentus; +using Concentus.Enums; +using Concentus.Structs; +using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; +using System.Buffers.Binary; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Codec.Detail +{ + partial class HardwareOpusDecoder : IHardwareOpusDecoder, IDisposable + { + static HardwareOpusDecoder() + { + OpusCodecFactory.AttemptToUseNativeLibrary = false; + } + + [StructLayout(LayoutKind.Sequential)] + private struct OpusPacketHeader + { + public uint Length; + public uint FinalRange; + + public static OpusPacketHeader FromSpan(ReadOnlySpan data) + { + return new() + { + Length = BinaryPrimitives.ReadUInt32BigEndian(data), + FinalRange = BinaryPrimitives.ReadUInt32BigEndian(data[sizeof(uint)..]), + }; + } + } + + private interface IDecoder : IDisposable + { + int SampleRate { get; } + int ChannelsCount { get; } + + int Decode(ReadOnlySpan inData, Span outPcm, int frameSize); + void ResetState(); + } + + private class Decoder : IDecoder + { + private readonly IOpusDecoder _decoder; + + public int SampleRate => _decoder.SampleRate; + public int ChannelsCount => _decoder.NumChannels; + + public Decoder(int sampleRate, int channelsCount) + { + _decoder = OpusCodecFactory.CreateDecoder(sampleRate, channelsCount); + } + + public int Decode(ReadOnlySpan inData, Span outPcm, int frameSize) + { + return _decoder.Decode(inData, outPcm, frameSize); + } + + public void ResetState() + { + _decoder.ResetState(); + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _decoder?.Dispose(); + } + } + } + + private class MultiSampleDecoder : IDecoder + { + private readonly IOpusMultiStreamDecoder _decoder; + + public int SampleRate => _decoder.SampleRate; + public int ChannelsCount => _decoder.NumChannels; + + public MultiSampleDecoder(int sampleRate, int channelsCount, int streams, int coupledStreams, byte[] mapping) + { + _decoder = OpusCodecFactory.CreateMultiStreamDecoder(sampleRate, channelsCount, streams, coupledStreams, mapping); + } + + public int Decode(ReadOnlySpan inData, Span outPcm, int frameSize) + { + return _decoder.DecodeMultistream(inData, outPcm, frameSize, false); + } + + public void ResetState() + { + _decoder.ResetState(); + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _decoder?.Dispose(); + } + } + } + + private readonly IDecoder _decoder; + private int _workBufferHandle; + + private HardwareOpusDecoder(int workBufferHandle) + { + _workBufferHandle = workBufferHandle; + } + + public HardwareOpusDecoder(int sampleRate, int channelsCount, int workBufferHandle) : this(workBufferHandle) + { + _decoder = new Decoder(sampleRate, channelsCount); + } + + public HardwareOpusDecoder(int sampleRate, int channelsCount, int streams, int coupledStreams, byte[] mapping, int workBufferHandle) : this(workBufferHandle) + { + _decoder = new MultiSampleDecoder(sampleRate, channelsCount, streams, coupledStreams, mapping); + } + + [CmifCommand(0)] + public Result DecodeInterleavedOld( + out int outConsumed, + out int outSamples, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span output, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan input) + { + return DecodeInterleavedInternal(out outConsumed, out outSamples, out _, output, input, reset: false, withPerf: false); + } + + [CmifCommand(1)] + public Result SetContext(ReadOnlySpan context) + { + Logger.Stub?.PrintStub(LogClass.ServiceAudio); + + return Result.Success; + } + + [CmifCommand(2)] // 3.0.0+ + public Result DecodeInterleavedForMultiStreamOld( + out int outConsumed, + out int outSamples, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span output, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan input) + { + return DecodeInterleavedInternal(out outConsumed, out outSamples, out _, output, input, reset: false, withPerf: false); + } + + [CmifCommand(3)] // 3.0.0+ + public Result SetContextForMultiStream(ReadOnlySpan arg0) + { + Logger.Stub?.PrintStub(LogClass.ServiceAudio); + + return Result.Success; + } + + [CmifCommand(4)] // 4.0.0+ + public Result DecodeInterleavedWithPerfOld( + out int outConsumed, + out long timeTaken, + out int outSamples, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.MapTransferAllowsNonSecure)] Span output, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan input) + { + return DecodeInterleavedInternal(out outConsumed, out outSamples, out timeTaken, output, input, reset: false, withPerf: true); + } + + [CmifCommand(5)] // 4.0.0+ + public Result DecodeInterleavedForMultiStreamWithPerfOld( + out int outConsumed, + out long timeTaken, + out int outSamples, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.MapTransferAllowsNonSecure)] Span output, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan input) + { + return DecodeInterleavedInternal(out outConsumed, out outSamples, out timeTaken, output, input, reset: false, withPerf: true); + } + + [CmifCommand(6)] // 6.0.0+ + public Result DecodeInterleavedWithPerfAndResetOld( + out int outConsumed, + out long timeTaken, + out int outSamples, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.MapTransferAllowsNonSecure)] Span output, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan input, + bool reset) + { + return DecodeInterleavedInternal(out outConsumed, out outSamples, out timeTaken, output, input, reset, withPerf: true); + } + + [CmifCommand(7)] // 6.0.0+ + public Result DecodeInterleavedForMultiStreamWithPerfAndResetOld( + out int outConsumed, + out long timeTaken, + out int outSamples, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.MapTransferAllowsNonSecure)] Span output, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan input, + bool reset) + { + return DecodeInterleavedInternal(out outConsumed, out outSamples, out timeTaken, output, input, reset, withPerf: true); + } + + [CmifCommand(8)] // 7.0.0+ + public Result DecodeInterleaved( + out int outConsumed, + out long timeTaken, + out int outSamples, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.MapTransferAllowsNonSecure)] Span output, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias | HipcBufferFlags.MapTransferAllowsNonSecure)] ReadOnlySpan input, + bool reset) + { + return DecodeInterleavedInternal(out outConsumed, out outSamples, out timeTaken, output, input, reset, withPerf: true); + } + + [CmifCommand(9)] // 7.0.0+ + public Result DecodeInterleavedForMultiStream( + out int outConsumed, + out long timeTaken, + out int outSamples, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.MapTransferAllowsNonSecure)] Span output, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias | HipcBufferFlags.MapTransferAllowsNonSecure)] ReadOnlySpan input, + bool reset) + { + return DecodeInterleavedInternal(out outConsumed, out outSamples, out timeTaken, output, input, reset, withPerf: true); + } + + private Result DecodeInterleavedInternal( + out int outConsumed, + out int outSamples, + out long timeTaken, + Span output, + ReadOnlySpan input, + bool reset, + bool withPerf) + { + timeTaken = 0; + + Span outPcmSpace = MemoryMarshal.Cast(output); + Result result = DecodeInterleaved(_decoder, reset, input, outPcmSpace, output.Length, out outConsumed, out outSamples); + + if (withPerf) + { + // This is the time the DSP took to process the request, TODO: fill this. + timeTaken = 0; + } + + return result; + } + + private static Result GetPacketNumSamples(IDecoder decoder, out int numSamples, ReadOnlySpan packet) + { + int result = OpusPacketInfo.GetNumSamples(packet, decoder.SampleRate); + + numSamples = result; + + if (result == OpusError.OPUS_INVALID_PACKET) + { + return CodecResult.OpusInvalidPacket; + } + else if (result == OpusError.OPUS_BAD_ARG) + { + return CodecResult.OpusBadArg; + } + + return Result.Success; + } + + private static Result DecodeInterleaved( + IDecoder decoder, + bool reset, + ReadOnlySpan input, + Span outPcmData, + int outputSize, + out int outConsumed, + out int outSamples) + { + outConsumed = 0; + outSamples = 0; + + int streamSize = input.Length; + + if (streamSize < Unsafe.SizeOf()) + { + return CodecResult.InvalidLength; + } + + OpusPacketHeader header = OpusPacketHeader.FromSpan(input); + int headerSize = Unsafe.SizeOf(); + uint totalSize = header.Length + (uint)headerSize; + + if (totalSize > streamSize) + { + return CodecResult.InvalidLength; + } + + ReadOnlySpan opusData = input.Slice(headerSize, (int)header.Length); + + Result result = GetPacketNumSamples(decoder, out int numSamples, opusData); + + if (result.IsSuccess) + { + if ((uint)numSamples * (uint)decoder.ChannelsCount * sizeof(short) > outputSize) + { + return CodecResult.InvalidLength; + } + + if (reset) + { + decoder.ResetState(); + } + + try + { + outSamples = decoder.Decode(opusData, outPcmData, numSamples); + outConsumed = (int)totalSize; + } + catch (OpusException e) + { + switch (e.OpusErrorCode) + { + case OpusError.OPUS_BUFFER_TOO_SMALL: + return CodecResult.InvalidLength; + case OpusError.OPUS_BAD_ARG: + return CodecResult.OpusBadArg; + case OpusError.OPUS_INVALID_PACKET: + return CodecResult.OpusInvalidPacket; + default: + return CodecResult.InvalidLength; + } + } + } + + return Result.Success; + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (_workBufferHandle != 0) + { + HorizonStatic.Syscall.CloseHandle(_workBufferHandle); + + _workBufferHandle = 0; + } + + _decoder?.Dispose(); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderManager.cs b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderManager.cs new file mode 100644 index 000000000..acec66e82 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderManager.cs @@ -0,0 +1,386 @@ +using Ryujinx.Common; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Sdk.Codec.Detail +{ + partial class HardwareOpusDecoderManager : IHardwareOpusDecoderManager + { + [CmifCommand(0)] + public Result OpenHardwareOpusDecoder( + out IHardwareOpusDecoder decoder, + HardwareOpusDecoderParameterInternal parameter, + [CopyHandle] int workBufferHandle, + int workBufferSize) + { + decoder = null; + + if (!IsValidSampleRate(parameter.SampleRate)) + { + HorizonStatic.Syscall.CloseHandle(workBufferHandle); + + return CodecResult.InvalidSampleRate; + } + + if (!IsValidChannelCount(parameter.ChannelsCount)) + { + HorizonStatic.Syscall.CloseHandle(workBufferHandle); + + return CodecResult.InvalidChannelCount; + } + + decoder = new HardwareOpusDecoder(parameter.SampleRate, parameter.ChannelsCount, workBufferHandle); + + return Result.Success; + } + + [CmifCommand(1)] + public Result GetWorkBufferSize(out int size, HardwareOpusDecoderParameterInternal parameter) + { + size = 0; + + if (!IsValidChannelCount(parameter.ChannelsCount)) + { + return CodecResult.InvalidChannelCount; + } + + if (!IsValidSampleRate(parameter.SampleRate)) + { + return CodecResult.InvalidSampleRate; + } + + int opusDecoderSize = GetOpusDecoderSize(parameter.ChannelsCount); + + int sampleRateRatio = parameter.SampleRate != 0 ? 48000 / parameter.SampleRate : 0; + int frameSize = BitUtils.AlignUp(sampleRateRatio != 0 ? parameter.ChannelsCount * 1920 / sampleRateRatio : 0, 64); + size = opusDecoderSize + 1536 + frameSize; + + return Result.Success; + } + + [CmifCommand(2)] // 3.0.0+ + public Result OpenHardwareOpusDecoderForMultiStream( + out IHardwareOpusDecoder decoder, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x110)] in HardwareOpusMultiStreamDecoderParameterInternal parameter, + [CopyHandle] int workBufferHandle, + int workBufferSize) + { + decoder = null; + + if (!IsValidSampleRate(parameter.SampleRate)) + { + HorizonStatic.Syscall.CloseHandle(workBufferHandle); + + return CodecResult.InvalidSampleRate; + } + + if (!IsValidMultiChannelCount(parameter.ChannelsCount)) + { + HorizonStatic.Syscall.CloseHandle(workBufferHandle); + + return CodecResult.InvalidChannelCount; + } + + if (!IsValidNumberOfStreams(parameter.NumberOfStreams, parameter.NumberOfStereoStreams, parameter.ChannelsCount)) + { + HorizonStatic.Syscall.CloseHandle(workBufferHandle); + + return CodecResult.InvalidNumberOfStreams; + } + + decoder = new HardwareOpusDecoder( + parameter.SampleRate, + parameter.ChannelsCount, + parameter.NumberOfStreams, + parameter.NumberOfStereoStreams, + parameter.ChannelMappings.AsSpan().ToArray(), + workBufferHandle); + + return Result.Success; + } + + [CmifCommand(3)] // 3.0.0+ + public Result GetWorkBufferSizeForMultiStream( + out int size, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x110)] in HardwareOpusMultiStreamDecoderParameterInternal parameter) + { + size = 0; + + if (!IsValidMultiChannelCount(parameter.ChannelsCount)) + { + return CodecResult.InvalidChannelCount; + } + + if (!IsValidSampleRate(parameter.SampleRate)) + { + return CodecResult.InvalidSampleRate; + } + + if (!IsValidNumberOfStreams(parameter.NumberOfStreams, parameter.NumberOfStereoStreams, parameter.ChannelsCount)) + { + return CodecResult.InvalidSampleRate; + } + + int opusDecoderSize = GetOpusMultistreamDecoderSize(parameter.NumberOfStreams, parameter.NumberOfStereoStreams); + + int streamSize = BitUtils.AlignUp(parameter.NumberOfStreams * 1500, 64); + int sampleRateRatio = parameter.SampleRate != 0 ? 48000 / parameter.SampleRate : 0; + int frameSize = BitUtils.AlignUp(sampleRateRatio != 0 ? parameter.ChannelsCount * 1920 / sampleRateRatio : 0, 64); + size = opusDecoderSize + streamSize + frameSize; + + return Result.Success; + } + + [CmifCommand(4)] // 12.0.0+ + public Result OpenHardwareOpusDecoderEx( + out IHardwareOpusDecoder decoder, + HardwareOpusDecoderParameterInternalEx parameter, + [CopyHandle] int workBufferHandle, + int workBufferSize) + { + decoder = null; + + if (!IsValidChannelCount(parameter.ChannelsCount)) + { + HorizonStatic.Syscall.CloseHandle(workBufferHandle); + + return CodecResult.InvalidChannelCount; + } + + if (!IsValidSampleRate(parameter.SampleRate)) + { + HorizonStatic.Syscall.CloseHandle(workBufferHandle); + + return CodecResult.InvalidSampleRate; + } + + decoder = new HardwareOpusDecoder(parameter.SampleRate, parameter.ChannelsCount, workBufferHandle); + + return Result.Success; + } + + [CmifCommand(5)] // 12.0.0+ + public Result GetWorkBufferSizeEx(out int size, HardwareOpusDecoderParameterInternalEx parameter) + { + return GetWorkBufferSizeExImpl(out size, in parameter, fromDsp: false); + } + + [CmifCommand(6)] // 12.0.0+ + public Result OpenHardwareOpusDecoderForMultiStreamEx( + out IHardwareOpusDecoder decoder, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x118)] in HardwareOpusMultiStreamDecoderParameterInternalEx parameter, + [CopyHandle] int workBufferHandle, + int workBufferSize) + { + decoder = null; + + if (!IsValidSampleRate(parameter.SampleRate)) + { + HorizonStatic.Syscall.CloseHandle(workBufferHandle); + + return CodecResult.InvalidSampleRate; + } + + if (!IsValidMultiChannelCount(parameter.ChannelsCount)) + { + HorizonStatic.Syscall.CloseHandle(workBufferHandle); + + return CodecResult.InvalidChannelCount; + } + + if (!IsValidNumberOfStreams(parameter.NumberOfStreams, parameter.NumberOfStereoStreams, parameter.ChannelsCount)) + { + HorizonStatic.Syscall.CloseHandle(workBufferHandle); + + return CodecResult.InvalidNumberOfStreams; + } + + decoder = new HardwareOpusDecoder( + parameter.SampleRate, + parameter.ChannelsCount, + parameter.NumberOfStreams, + parameter.NumberOfStereoStreams, + parameter.ChannelMappings.AsSpan().ToArray(), + workBufferHandle); + + return Result.Success; + } + + [CmifCommand(7)] // 12.0.0+ + public Result GetWorkBufferSizeForMultiStreamEx( + out int size, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x118)] in HardwareOpusMultiStreamDecoderParameterInternalEx parameter) + { + return GetWorkBufferSizeForMultiStreamExImpl(out size, in parameter, fromDsp: false); + } + + [CmifCommand(8)] // 16.0.0+ + public Result GetWorkBufferSizeExEx(out int size, HardwareOpusDecoderParameterInternalEx parameter) + { + return GetWorkBufferSizeExImpl(out size, in parameter, fromDsp: true); + } + + [CmifCommand(9)] // 16.0.0+ + public Result GetWorkBufferSizeForMultiStreamExEx( + out int size, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x118)] in HardwareOpusMultiStreamDecoderParameterInternalEx parameter) + { + return GetWorkBufferSizeForMultiStreamExImpl(out size, in parameter, fromDsp: true); + } + + private Result GetWorkBufferSizeExImpl(out int size, in HardwareOpusDecoderParameterInternalEx parameter, bool fromDsp) + { + size = 0; + + if (!IsValidChannelCount(parameter.ChannelsCount)) + { + return CodecResult.InvalidChannelCount; + } + + if (!IsValidSampleRate(parameter.SampleRate)) + { + return CodecResult.InvalidSampleRate; + } + + int opusDecoderSize = fromDsp ? GetDspOpusDecoderSize(parameter.ChannelsCount) : GetOpusDecoderSize(parameter.ChannelsCount); + + int frameSizeMono48KHz = parameter.Flags.HasFlag(OpusDecoderFlags.LargeFrameSize) ? 5760 : 1920; + int sampleRateRatio = parameter.SampleRate != 0 ? 48000 / parameter.SampleRate : 0; + int frameSize = BitUtils.AlignUp(sampleRateRatio != 0 ? parameter.ChannelsCount * frameSizeMono48KHz / sampleRateRatio : 0, 64); + size = opusDecoderSize + 1536 + frameSize; + + return Result.Success; + } + + private Result GetWorkBufferSizeForMultiStreamExImpl(out int size, in HardwareOpusMultiStreamDecoderParameterInternalEx parameter, bool fromDsp) + { + size = 0; + + if (!IsValidMultiChannelCount(parameter.ChannelsCount)) + { + return CodecResult.InvalidChannelCount; + } + + if (!IsValidSampleRate(parameter.SampleRate)) + { + return CodecResult.InvalidSampleRate; + } + + if (!IsValidNumberOfStreams(parameter.NumberOfStreams, parameter.NumberOfStereoStreams, parameter.ChannelsCount)) + { + return CodecResult.InvalidSampleRate; + } + + int opusDecoderSize = fromDsp + ? GetDspOpusMultistreamDecoderSize(parameter.NumberOfStreams, parameter.NumberOfStereoStreams) + : GetOpusMultistreamDecoderSize(parameter.NumberOfStreams, parameter.NumberOfStereoStreams); + + int frameSizeMono48KHz = parameter.Flags.HasFlag(OpusDecoderFlags.LargeFrameSize) ? 5760 : 1920; + int streamSize = BitUtils.AlignUp(parameter.NumberOfStreams * 1500, 64); + int sampleRateRatio = parameter.SampleRate != 0 ? 48000 / parameter.SampleRate : 0; + int frameSize = BitUtils.AlignUp(sampleRateRatio != 0 ? parameter.ChannelsCount * frameSizeMono48KHz / sampleRateRatio : 0, 64); + size = opusDecoderSize + streamSize + frameSize; + + return Result.Success; + } + + private static int GetDspOpusDecoderSize(int channelsCount) + { + // TODO: Figure out the size returned here. + // Not really important because we don't use the work buffer, and the size being lower is fine. + + return 0; + } + + private static int GetDspOpusMultistreamDecoderSize(int streams, int coupledStreams) + { + // TODO: Figure out the size returned here. + // Not really important because we don't use the work buffer, and the size being lower is fine. + + return 0; + } + + private static int GetOpusDecoderSize(int channelsCount) + { + const int SilkDecoderSize = 0x2160; + + if (channelsCount < 1 || channelsCount > 2) + { + return 0; + } + + int celtDecoderSize = GetCeltDecoderSize(channelsCount); + int opusDecoderSize = GetOpusDecoderAllocSize(channelsCount) | 0x50; + + return opusDecoderSize + SilkDecoderSize + celtDecoderSize; + } + + private static int GetOpusMultistreamDecoderSize(int streams, int coupledStreams) + { + if (streams < 1 || coupledStreams > streams || coupledStreams < 0) + { + return 0; + } + + int coupledSize = GetOpusDecoderSize(2); + int monoSize = GetOpusDecoderSize(1); + + return Align4(monoSize - GetOpusDecoderAllocSize(1)) * (streams - coupledStreams) + + Align4(coupledSize - GetOpusDecoderAllocSize(2)) * coupledStreams + 0xb920; + } + + private static int Align4(int value) + { + return BitUtils.AlignUp(value, 4); + } + + private static int GetOpusDecoderAllocSize(int channelsCount) + { + return channelsCount * 0x800 + 0x4800; + } + + private static int GetCeltDecoderSize(int channelsCount) + { + const int DecodeBufferSize = 0x2030; + const int Overlap = 120; + const int EBandsCount = 21; + + return (DecodeBufferSize + Overlap * 4) * channelsCount + EBandsCount * 16 + 0x54; + } + + private static bool IsValidChannelCount(int channelsCount) + { + return channelsCount > 0 && channelsCount <= 2; + } + + private static bool IsValidMultiChannelCount(int channelsCount) + { + return channelsCount > 0 && channelsCount <= 255; + } + + private static bool IsValidSampleRate(int sampleRate) + { + switch (sampleRate) + { + case 8000: + case 12000: + case 16000: + case 24000: + case 48000: + return true; + } + + return false; + } + + private static bool IsValidNumberOfStreams(int numberOfStreams, int numberOfStereoStreams, int channelsCount) + { + return numberOfStreams > 0 && + numberOfStreams + numberOfStereoStreams <= channelsCount && + numberOfStereoStreams >= 0 && + numberOfStereoStreams <= numberOfStreams; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderParameterInternal.cs b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderParameterInternal.cs new file mode 100644 index 000000000..271a592c1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderParameterInternal.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Codec.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x4)] + struct HardwareOpusDecoderParameterInternal + { + public int SampleRate; + public int ChannelsCount; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderParameterInternalEx.cs b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderParameterInternalEx.cs new file mode 100644 index 000000000..e2b81c771 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusDecoderParameterInternalEx.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Codec.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x4)] + struct HardwareOpusDecoderParameterInternalEx + { + public int SampleRate; + public int ChannelsCount; + public OpusDecoderFlags Flags; + public uint Reserved; + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusMultiStreamParameters.cs b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusMultiStreamDecoderParameterInternal.cs similarity index 65% rename from src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusMultiStreamParameters.cs rename to src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusMultiStreamDecoderParameterInternal.cs index fd63a4f79..98536a4f8 100644 --- a/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusMultiStreamParameters.cs +++ b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusMultiStreamDecoderParameterInternal.cs @@ -1,15 +1,15 @@ using Ryujinx.Common.Memory; using System.Runtime.InteropServices; -namespace Ryujinx.HLE.HOS.Services.Audio.Types +namespace Ryujinx.Horizon.Sdk.Codec.Detail { [StructLayout(LayoutKind.Sequential, Size = 0x110)] - struct OpusMultiStreamParameters + struct HardwareOpusMultiStreamDecoderParameterInternal { public int SampleRate; public int ChannelsCount; public int NumberOfStreams; public int NumberOfStereoStreams; - public Array64 ChannelMappings; + public Array256 ChannelMappings; } } diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusMultiStreamParametersEx.cs b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusMultiStreamDecoderParameterInternalEx.cs similarity index 64% rename from src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusMultiStreamParametersEx.cs rename to src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusMultiStreamDecoderParameterInternalEx.cs index 1315c734e..8f8615dff 100644 --- a/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusMultiStreamParametersEx.cs +++ b/src/Ryujinx.Horizon/Sdk/Codec/Detail/HardwareOpusMultiStreamDecoderParameterInternalEx.cs @@ -1,19 +1,17 @@ using Ryujinx.Common.Memory; using System.Runtime.InteropServices; -namespace Ryujinx.HLE.HOS.Services.Audio.Types +namespace Ryujinx.Horizon.Sdk.Codec.Detail { [StructLayout(LayoutKind.Sequential, Size = 0x118)] - struct OpusMultiStreamParametersEx + struct HardwareOpusMultiStreamDecoderParameterInternalEx { public int SampleRate; public int ChannelsCount; public int NumberOfStreams; public int NumberOfStereoStreams; public OpusDecoderFlags Flags; - - Array4 Padding1; - - public Array64 ChannelMappings; + public uint Reserved; + public Array256 ChannelMappings; } } diff --git a/src/Ryujinx.Horizon/Sdk/Codec/Detail/IHardwareOpusDecoder.cs b/src/Ryujinx.Horizon/Sdk/Codec/Detail/IHardwareOpusDecoder.cs new file mode 100644 index 000000000..ae09ad15a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Codec/Detail/IHardwareOpusDecoder.cs @@ -0,0 +1,20 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using System; + +namespace Ryujinx.Horizon.Sdk.Codec.Detail +{ + interface IHardwareOpusDecoder : IServiceObject + { + Result DecodeInterleavedOld(out int outConsumed, out int outSamples, Span output, ReadOnlySpan input); + Result SetContext(ReadOnlySpan context); + Result DecodeInterleavedForMultiStreamOld(out int outConsumed, out int outSamples, Span output, ReadOnlySpan input); + Result SetContextForMultiStream(ReadOnlySpan context); + Result DecodeInterleavedWithPerfOld(out int outConsumed, out long timeTaken, out int outSamples, Span output, ReadOnlySpan input); + Result DecodeInterleavedForMultiStreamWithPerfOld(out int outConsumed, out long timeTaken, out int outSamples, Span output, ReadOnlySpan input); + Result DecodeInterleavedWithPerfAndResetOld(out int outConsumed, out long timeTaken, out int outSamples, Span output, ReadOnlySpan input, bool reset); + Result DecodeInterleavedForMultiStreamWithPerfAndResetOld(out int outConsumed, out long timeTaken, out int outSamples, Span output, ReadOnlySpan input, bool reset); + Result DecodeInterleaved(out int outConsumed, out long timeTaken, out int outSamples, Span output, ReadOnlySpan input, bool reset); + Result DecodeInterleavedForMultiStream(out int outConsumed, out long timeTaken, out int outSamples, Span output, ReadOnlySpan input, bool reset); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Codec/Detail/IHardwareOpusDecoderManager.cs b/src/Ryujinx.Horizon/Sdk/Codec/Detail/IHardwareOpusDecoderManager.cs new file mode 100644 index 000000000..fb6c787b6 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Codec/Detail/IHardwareOpusDecoderManager.cs @@ -0,0 +1,19 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Codec.Detail +{ + interface IHardwareOpusDecoderManager : IServiceObject + { + Result OpenHardwareOpusDecoder(out IHardwareOpusDecoder decoder, HardwareOpusDecoderParameterInternal parameter, int workBufferHandle, int workBufferSize); + Result GetWorkBufferSize(out int size, HardwareOpusDecoderParameterInternal parameter); + Result OpenHardwareOpusDecoderForMultiStream(out IHardwareOpusDecoder decoder, in HardwareOpusMultiStreamDecoderParameterInternal parameter, int workBufferHandle, int workBufferSize); + Result GetWorkBufferSizeForMultiStream(out int size, in HardwareOpusMultiStreamDecoderParameterInternal parameter); + Result OpenHardwareOpusDecoderEx(out IHardwareOpusDecoder decoder, HardwareOpusDecoderParameterInternalEx parameter, int workBufferHandle, int workBufferSize); + Result GetWorkBufferSizeEx(out int size, HardwareOpusDecoderParameterInternalEx parameter); + Result OpenHardwareOpusDecoderForMultiStreamEx(out IHardwareOpusDecoder decoder, in HardwareOpusMultiStreamDecoderParameterInternalEx parameter, int workBufferHandle, int workBufferSize); + Result GetWorkBufferSizeForMultiStreamEx(out int size, in HardwareOpusMultiStreamDecoderParameterInternalEx parameter); + Result GetWorkBufferSizeExEx(out int size, HardwareOpusDecoderParameterInternalEx parameter); + Result GetWorkBufferSizeForMultiStreamExEx(out int size, in HardwareOpusMultiStreamDecoderParameterInternalEx parameter); + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusDecoderFlags.cs b/src/Ryujinx.Horizon/Sdk/Codec/Detail/OpusDecoderFlags.cs similarity index 72% rename from src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusDecoderFlags.cs rename to src/Ryujinx.Horizon/Sdk/Codec/Detail/OpusDecoderFlags.cs index 572535a92..d630b10f4 100644 --- a/src/Ryujinx.HLE/HOS/Services/Audio/Types/OpusDecoderFlags.cs +++ b/src/Ryujinx.Horizon/Sdk/Codec/Detail/OpusDecoderFlags.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.HLE.HOS.Services.Audio.Types +namespace Ryujinx.Horizon.Sdk.Codec.Detail { [Flags] enum OpusDecoderFlags : uint diff --git a/src/Ryujinx.Horizon/Sdk/Friends/ApplicationInfo.cs b/src/Ryujinx.Horizon/Sdk/Friends/ApplicationInfo.cs new file mode 100644 index 000000000..23bad3d13 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/ApplicationInfo.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Sdk.Ncm; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct ApplicationInfo + { + public ApplicationId ApplicationId; + public ulong PresenceGroupId; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/BlockedUserImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/BlockedUserImpl.cs new file mode 100644 index 000000000..d5f8a0313 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/BlockedUserImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct BlockedUserImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendCandidateImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendCandidateImpl.cs new file mode 100644 index 000000000..21e99c754 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendCandidateImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct FriendCandidateImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendDetailedInfoImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendDetailedInfoImpl.cs new file mode 100644 index 000000000..1b46dccd5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendDetailedInfoImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x800)] + struct FriendDetailedInfoImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendImpl.cs new file mode 100644 index 000000000..d22ca4b90 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendImpl.cs @@ -0,0 +1,19 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Sdk.Account; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x200, Pack = 0x8)] + struct FriendImpl + { + public Uid UserId; + public NetworkServiceAccountId NetworkUserId; + public Nickname Nickname; + public UserPresenceImpl Presence; + public bool IsFavourite; + public bool IsNew; + public Array6 Unknown; + public bool IsValid; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationForViewerImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationForViewerImpl.cs new file mode 100644 index 000000000..416ba3655 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationForViewerImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct FriendInvitationForViewerImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationGroupImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationGroupImpl.cs new file mode 100644 index 000000000..ef9238347 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationGroupImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x1400)] + struct FriendInvitationGroupImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendRequestImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendRequestImpl.cs new file mode 100644 index 000000000..ba5671692 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendRequestImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct FriendRequestImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendSettingImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendSettingImpl.cs new file mode 100644 index 000000000..f711d31fd --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendSettingImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x40)] + struct FriendSettingImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/DaemonSuspendSessionService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/DaemonSuspendSessionService.cs new file mode 100644 index 000000000..aaf88ed03 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/DaemonSuspendSessionService.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + partial class DaemonSuspendSessionService : IDaemonSuspendSessionService + { + // NOTE: This service has no commands. + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendService.cs new file mode 100644 index 000000000..1b4c8c309 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendService.cs @@ -0,0 +1,1015 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.OsTypes; +using Ryujinx.Horizon.Sdk.Settings; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + partial class FriendService : IFriendService, IDisposable + { + private readonly IEmulatorAccountManager _accountManager; + private SystemEventType _completionEvent; + + public FriendService(IEmulatorAccountManager accountManager, FriendsServicePermissionLevel permissionLevel) + { + _accountManager = accountManager; + + Os.CreateSystemEvent(out _completionEvent, EventClearMode.ManualClear, interProcess: true).AbortOnFailure(); + Os.SignalSystemEvent(ref _completionEvent); // TODO: Figure out where we are supposed to signal this. + } + + [CmifCommand(0)] + public Result GetCompletionEvent([CopyHandle] out int completionEventHandle) + { + completionEventHandle = Os.GetReadableHandleOfSystemEvent(ref _completionEvent); + + return Result.Success; + } + + [CmifCommand(1)] + public Result Cancel() + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend); + + return Result.Success; + } + + [CmifCommand(10100)] + public Result GetFriendListIds( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer)] Span friendIds, + Uid userId, + int offset, + SizedFriendFilter filter, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, offset, filter, pidPlaceholder, pid }); + + if (userId.IsNull) + { + return FriendResult.InvalidArgument; + } + + return Result.Success; + } + + [CmifCommand(10101)] + public Result GetFriendList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span friendList, + Uid userId, + int offset, + SizedFriendFilter filter, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, offset, filter, pidPlaceholder, pid }); + + if (userId.IsNull) + { + return FriendResult.InvalidArgument; + } + + return Result.Success; + } + + [CmifCommand(10102)] + public Result UpdateFriendInfo( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span info, + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan friendIds, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + string friendIdList = string.Join(", ", friendIds.ToArray()); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendIdList, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(10110)] + public Result GetFriendProfileImage( + out int size, + Uid userId, + NetworkServiceAccountId friendId, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span profileImage) + { + size = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(10120)] + public Result CheckFriendListAvailability(out bool listAvailable, Uid userId) + { + listAvailable = true; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(10121)] + public Result EnsureFriendListAvailable(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(10200)] + public Result SendFriendRequestForApplication( + Uid userId, + NetworkServiceAccountId friendId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg2, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg3, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2, arg3, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(10211)] + public Result AddFacedFriendRequestForApplication( + Uid userId, + FacedFriendRequestRegistrationKey key, + Nickname nickname, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan arg3, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg4, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg5, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, key, nickname, arg4, arg5, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(10400)] + public Result GetBlockedUserListIds( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer)] Span blockedIds, + Uid userId, + int offset) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, offset }); + + return Result.Success; + } + + [CmifCommand(10420)] + public Result CheckBlockedUserListAvailability(out bool listAvailable, Uid userId) + { + listAvailable = true; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(10421)] + public Result EnsureBlockedUserListAvailable(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(10500)] + public Result GetProfileList( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span profileList, + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan friendIds) + { + string friendIdList = string.Join(", ", friendIds.ToArray()); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendIdList }); + + return Result.Success; + } + + [CmifCommand(10600)] + public Result DeclareOpenOnlinePlaySession(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + if (userId.IsNull) + { + return FriendResult.InvalidArgument; + } + + _accountManager.OpenUserOnlinePlay(userId); + + return Result.Success; + } + + [CmifCommand(10601)] + public Result DeclareCloseOnlinePlaySession(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + if (userId.IsNull) + { + return FriendResult.InvalidArgument; + } + + _accountManager.CloseUserOnlinePlay(userId); + + return Result.Success; + } + + [CmifCommand(10610)] + public Result UpdateUserPresence( + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0xE0)] in UserPresenceImpl userPresence, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, userPresence, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(10700)] + public Result GetPlayHistoryRegistrationKey( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x40)] out PlayHistoryRegistrationKey registrationKey, + Uid userId, + bool arg2) + { + if (userId.IsNull) + { + registrationKey = default; + + return FriendResult.InvalidArgument; + } + + // NOTE: Calls nn::friends::detail::service::core::PlayHistoryManager::GetInstance and stores the instance. + + // NOTE: Calls nn::friends::detail::service::core::UuidManager::GetInstance and stores the instance. + // Then calls nn::friends::detail::service::core::AccountStorageManager::GetInstance and stores the instance. + // Then it checks if an Uuid is already stored for the UserId, if not it generates a random Uuid, + // and stores it in the savedata 8000000000000080 in the friends:/uid.bin file. + + /* + + NOTE: The service uses the KeyIndex to get a random key from a keys buffer (since the key index is stored in the returned buffer). + We currently don't support play history and online services so we can use a blank key for now. + Code for reference: + + byte[] hmacKey = new byte[0x20]; + + HMACSHA256 hmacSha256 = new HMACSHA256(hmacKey); + byte[] hmacHash = hmacSha256.ComputeHash(playHistoryRegistrationKeyBuffer); + + */ + + Uid randomGuid = new(); + + Guid.NewGuid().TryWriteBytes(MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref randomGuid, 1))); + + registrationKey = new() + { + Type = 0x101, + KeyIndex = (byte)(Random.Shared.Next() & 7), + UserIdBool = 0, // TODO: Find it. + UnknownBool = (byte)(arg2 ? 1 : 0), // TODO: Find it. + Reserved = new(), + Uuid = randomGuid, + HmacHash = new(), + }; + + return Result.Success; + } + + [CmifCommand(10701)] + public Result GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x40)] out PlayHistoryRegistrationKey registrationKey, + NetworkServiceAccountId friendId, + bool arg2) + { + registrationKey = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { friendId, arg2 }); + + return Result.Success; + } + + [CmifCommand(10702)] + public Result AddPlayHistory( + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x40)] in PlayHistoryRegistrationKey registrationKey, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg2, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg3, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, registrationKey, arg2, arg3, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(11000)] + public Result GetProfileImageUrl(out Url imageUrl, Url url, int arg2) + { + imageUrl = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { url, arg2 }); + + return Result.Success; + } + + [CmifCommand(20100)] + public Result GetFriendCount(out int count, Uid userId, SizedFriendFilter filter, ulong pidPlaceholder, [ClientProcessId] ulong pid) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, filter, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(20101)] + public Result GetNewlyFriendCount(out int count, Uid userId) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20102)] + public Result GetFriendDetailedInfo( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x800)] out FriendDetailedInfoImpl detailedInfo, + Uid userId, + NetworkServiceAccountId friendId) + { + detailedInfo = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(20103)] + public Result SyncFriendList(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20104)] + public Result RequestSyncFriendList(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20110)] + public Result LoadFriendSetting( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x40)] out FriendSettingImpl friendSetting, + Uid userId, + NetworkServiceAccountId friendId) + { + friendSetting = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(20200)] + public Result GetReceivedFriendRequestCount(out int count, out int count2, Uid userId) + { + count = 0; + count2 = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20201)] + public Result GetFriendRequestList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span requestList, + Uid userId, + int arg3, + int arg4) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg3, arg4 }); + + return Result.Success; + } + + [CmifCommand(20300)] + public Result GetFriendCandidateList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span candidateList, + Uid userId, + int arg3) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg3 }); + + return Result.Success; + } + + [CmifCommand(20301)] + public Result GetNintendoNetworkIdInfo( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x38)] out NintendoNetworkIdUserInfo networkIdInfo, + out int arg1, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span friendInfo, + Uid userId, + int arg4) + { + networkIdInfo = default; + arg1 = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg4 }); + + return Result.Success; + } + + [CmifCommand(20302)] + public Result GetSnsAccountLinkage(out SnsAccountLinkage accountLinkage, Uid userId) + { + accountLinkage = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20303)] + public Result GetSnsAccountProfile( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x380)] out SnsAccountProfile accountProfile, + Uid userId, + NetworkServiceAccountId friendId, + int arg3) + { + accountProfile = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg3 }); + + return Result.Success; + } + + [CmifCommand(20304)] + public Result GetSnsAccountFriendList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span friendList, + Uid userId, + int arg3) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg3 }); + + return Result.Success; + } + + [CmifCommand(20400)] + public Result GetBlockedUserList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span blockedUsers, + Uid userId, + int arg3) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg3 }); + + return Result.Success; + } + + [CmifCommand(20401)] + public Result SyncBlockedUserList(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20500)] + public Result GetProfileExtraList( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span extraList, + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan friendIds) + { + string friendIdList = string.Join(", ", friendIds.ToArray()); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendIdList }); + + return Result.Success; + } + + [CmifCommand(20501)] + public Result GetRelationship(out Relationship relationship, Uid userId, NetworkServiceAccountId friendId) + { + relationship = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(20600)] + public Result GetUserPresenceView([Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0xE0)] out UserPresenceViewImpl userPresenceView, Uid userId) + { + userPresenceView = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20700)] + public Result GetPlayHistoryList(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span playHistoryList, Uid userId, int arg3) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg3 }); + + return Result.Success; + } + + [CmifCommand(20701)] + public Result GetPlayHistoryStatistics(out PlayHistoryStatistics statistics, Uid userId) + { + statistics = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20800)] + public Result LoadUserSetting([Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x800)] out UserSettingImpl userSetting, Uid userId) + { + userSetting = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20801)] + public Result SyncUserSetting(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20900)] + public Result RequestListSummaryOverlayNotification() + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend); + + return Result.Success; + } + + [CmifCommand(21000)] + public Result GetExternalApplicationCatalog( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x4B8)] out ExternalApplicationCatalog catalog, + ExternalApplicationCatalogId catalogId, + LanguageCode language) + { + catalog = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { catalogId, language }); + + return Result.Success; + } + + [CmifCommand(22000)] + public Result GetReceivedFriendInvitationList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span invitationList, + Uid userId) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(22001)] + public Result GetReceivedFriendInvitationDetailedInfo( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias, 0x1400)] out FriendInvitationGroupImpl invicationGroup, + Uid userId, + FriendInvitationGroupId groupId) + { + invicationGroup = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, groupId }); + + return Result.Success; + } + + [CmifCommand(22010)] + public Result GetReceivedFriendInvitationCountCache(out int count, Uid userId) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30100)] + public Result DropFriendNewlyFlags(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30101)] + public Result DeleteFriend(Uid userId, NetworkServiceAccountId friendId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30110)] + public Result DropFriendNewlyFlag(Uid userId, NetworkServiceAccountId friendId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30120)] + public Result ChangeFriendFavoriteFlag(Uid userId, NetworkServiceAccountId friendId, bool favoriteFlag) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, favoriteFlag }); + + return Result.Success; + } + + [CmifCommand(30121)] + public Result ChangeFriendOnlineNotificationFlag(Uid userId, NetworkServiceAccountId friendId, bool onlineNotificationFlag) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, onlineNotificationFlag }); + + return Result.Success; + } + + [CmifCommand(30200)] + public Result SendFriendRequest(Uid userId, NetworkServiceAccountId friendId, int arg2) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2 }); + + return Result.Success; + } + + [CmifCommand(30201)] + public Result SendFriendRequestWithApplicationInfo( + Uid userId, + NetworkServiceAccountId friendId, + int arg2, + ApplicationInfo applicationInfo, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg4, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg5) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2, applicationInfo, arg4, arg5 }); + + return Result.Success; + } + + [CmifCommand(30202)] + public Result CancelFriendRequest(Uid userId, RequestId requestId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, requestId }); + + return Result.Success; + } + + [CmifCommand(30203)] + public Result AcceptFriendRequest(Uid userId, RequestId requestId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, requestId }); + + return Result.Success; + } + + [CmifCommand(30204)] + public Result RejectFriendRequest(Uid userId, RequestId requestId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, requestId }); + + return Result.Success; + } + + [CmifCommand(30205)] + public Result ReadFriendRequest(Uid userId, RequestId requestId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, requestId }); + + return Result.Success; + } + + [CmifCommand(30210)] + public Result GetFacedFriendRequestRegistrationKey(out FacedFriendRequestRegistrationKey registrationKey, Uid userId) + { + registrationKey = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30211)] + public Result AddFacedFriendRequest( + Uid userId, + FacedFriendRequestRegistrationKey registrationKey, + Nickname nickname, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan arg3) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, registrationKey, nickname }); + + return Result.Success; + } + + [CmifCommand(30212)] + public Result CancelFacedFriendRequest(Uid userId, NetworkServiceAccountId friendId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30213)] + public Result GetFacedFriendRequestProfileImage( + out int size, + Uid userId, + NetworkServiceAccountId friendId, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span profileImage) + { + size = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30214)] + public Result GetFacedFriendRequestProfileImageFromPath( + out int size, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan path, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span profileImage) + { + size = 0; + + string pathString = Encoding.UTF8.GetString(path); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { pathString }); + + return Result.Success; + } + + [CmifCommand(30215)] + public Result SendFriendRequestWithExternalApplicationCatalogId( + Uid userId, + NetworkServiceAccountId friendId, + int arg2, + ExternalApplicationCatalogId catalogId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg4, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg5) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2, catalogId, arg4, arg5 }); + + return Result.Success; + } + + [CmifCommand(30216)] + public Result ResendFacedFriendRequest(Uid userId, NetworkServiceAccountId friendId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30217)] + public Result SendFriendRequestWithNintendoNetworkIdInfo( + Uid userId, + NetworkServiceAccountId friendId, + int arg2, + MiiName arg3, + MiiImageUrlParam arg4, + MiiName arg5, + MiiImageUrlParam arg6) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2, arg3, arg4, arg5, arg6 }); + + return Result.Success; + } + + [CmifCommand(30300)] + public Result GetSnsAccountLinkPageUrl([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias, 0x1000)] out WebPageUrl url, Uid userId, int arg2) + { + url = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg2 }); + + return Result.Success; + } + + [CmifCommand(30301)] + public Result UnlinkSnsAccount(Uid userId, int arg1) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg1 }); + + return Result.Success; + } + + [CmifCommand(30400)] + public Result BlockUser(Uid userId, NetworkServiceAccountId friendId, int arg2) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2 }); + + return Result.Success; + } + + [CmifCommand(30401)] + public Result BlockUserWithApplicationInfo( + Uid userId, + NetworkServiceAccountId friendId, + int arg2, + ApplicationInfo applicationInfo, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg4) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2, applicationInfo, arg4 }); + + return Result.Success; + } + + [CmifCommand(30402)] + public Result UnblockUser(Uid userId, NetworkServiceAccountId friendId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30500)] + public Result GetProfileExtraFromFriendCode( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x400)] out ProfileExtraImpl profileExtra, + Uid userId, + FriendCode friendCode) + { + profileExtra = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendCode }); + + return Result.Success; + } + + [CmifCommand(30700)] + public Result DeletePlayHistory(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30810)] + public Result ChangePresencePermission(Uid userId, int permission) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, permission }); + + return Result.Success; + } + + [CmifCommand(30811)] + public Result ChangeFriendRequestReception(Uid userId, bool reception) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, reception }); + + return Result.Success; + } + + [CmifCommand(30812)] + public Result ChangePlayLogPermission(Uid userId, int permission) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, permission }); + + return Result.Success; + } + + [CmifCommand(30820)] + public Result IssueFriendCode(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30830)] + public Result ClearPlayLog(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30900)] + public Result SendFriendInvitation( + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan friendIds, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias, 0xC00)] in FriendInvitationGameModeDescription description, + ApplicationInfo applicationInfo, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan arg4, + bool arg5) + { + string friendIdList = string.Join(", ", friendIds.ToArray()); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendIdList, description, applicationInfo, arg5 }); + + return Result.Success; + } + + [CmifCommand(30910)] + public Result ReadFriendInvitation(Uid userId, [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan invitationIds) + { + string invitationIdList = string.Join(", ", invitationIds.ToArray()); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, invitationIdList }); + + return Result.Success; + } + + [CmifCommand(30911)] + public Result ReadAllFriendInvitations(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(40100)] + public Result DeleteFriendListCache(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(40400)] + public Result DeleteBlockedUserListCache(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(49900)] + public Result DeleteNetworkServiceAccountCache(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + Os.DestroySystemEvent(ref _completionEvent); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendsServicePermissionLevel.cs similarity index 64% rename from src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs rename to src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendsServicePermissionLevel.cs index 7902d9c53..f4bbe100f 100644 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendsServicePermissionLevel.cs @@ -1,16 +1,13 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc { - [Flags] - enum FriendServicePermissionLevel + enum FriendsServicePermissionLevel { UserMask = 1, ViewerMask = 2, ManagerMask = 4, SystemMask = 8, - Administrator = -1, + Admin = -1, User = UserMask, Viewer = UserMask | ViewerMask, Manager = UserMask | ViewerMask | ManagerMask, diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IDaemonSuspendSessionService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IDaemonSuspendSessionService.cs new file mode 100644 index 000000000..2bb0434e8 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IDaemonSuspendSessionService.cs @@ -0,0 +1,9 @@ +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + interface IDaemonSuspendSessionService : IServiceObject + { + // NOTE: This service has no commands. + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IFriendService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IFriendService.cs new file mode 100644 index 000000000..c19d0b788 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IFriendService.cs @@ -0,0 +1,97 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.Settings; +using Ryujinx.Horizon.Sdk.Sf; +using System; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + interface IFriendService : IServiceObject + { + Result GetCompletionEvent(out int completionEventHandle); + Result Cancel(); + Result GetFriendListIds(out int count, Span friendIds, Uid userId, int offset, SizedFriendFilter filter, ulong pidPlaceholder, ulong pid); + Result GetFriendList(out int count, Span friendList, Uid userId, int offset, SizedFriendFilter filter, ulong pidPlaceholder, ulong pid); + Result UpdateFriendInfo(Span info, Uid userId, ReadOnlySpan friendIds, ulong pidPlaceholder, ulong pid); + Result GetFriendProfileImage(out int size, Uid userId, NetworkServiceAccountId friendId, Span profileImage); + Result CheckFriendListAvailability(out bool listAvailable, Uid userId); + Result EnsureFriendListAvailable(Uid userId); + Result SendFriendRequestForApplication(Uid userId, NetworkServiceAccountId friendId, in InAppScreenName arg2, in InAppScreenName arg3, ulong pidPlaceholder, ulong pid); + Result AddFacedFriendRequestForApplication(Uid userId, FacedFriendRequestRegistrationKey key, Nickname nickname, ReadOnlySpan arg3, in InAppScreenName arg4, in InAppScreenName arg5, ulong pidPlaceholder, ulong pid); + Result GetBlockedUserListIds(out int count, Span blockedIds, Uid userId, int offset); + Result CheckBlockedUserListAvailability(out bool listAvailable, Uid userId); + Result EnsureBlockedUserListAvailable(Uid userId); + Result GetProfileList(Span profileList, Uid userId, ReadOnlySpan friendIds); + Result DeclareOpenOnlinePlaySession(Uid userId); + Result DeclareCloseOnlinePlaySession(Uid userId); + Result UpdateUserPresence(Uid userId, in UserPresenceImpl userPresence, ulong pidPlaceholder, ulong pid); + Result GetPlayHistoryRegistrationKey(out PlayHistoryRegistrationKey registrationKey, Uid userId, bool arg2); + Result GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId(out PlayHistoryRegistrationKey registrationKey, NetworkServiceAccountId friendId, bool arg2); + Result AddPlayHistory(Uid userId, in PlayHistoryRegistrationKey registrationKey, in InAppScreenName arg2, in InAppScreenName arg3, ulong pidPlaceholder, ulong pid); + Result GetProfileImageUrl(out Url imageUrl, Url url, int arg2); + Result GetFriendCount(out int count, Uid userId, SizedFriendFilter filter, ulong pidPlaceholder, ulong pid); + Result GetNewlyFriendCount(out int count, Uid userId); + Result GetFriendDetailedInfo(out FriendDetailedInfoImpl detailedInfo, Uid userId, NetworkServiceAccountId friendId); + Result SyncFriendList(Uid userId); + Result RequestSyncFriendList(Uid userId); + Result LoadFriendSetting(out FriendSettingImpl friendSetting, Uid userId, NetworkServiceAccountId friendId); + Result GetReceivedFriendRequestCount(out int count, out int count2, Uid userId); + Result GetFriendRequestList(out int count, Span requestList, Uid userId, int arg3, int arg4); + Result GetFriendCandidateList(out int count, Span candidateList, Uid userId, int arg3); + Result GetNintendoNetworkIdInfo(out NintendoNetworkIdUserInfo networkIdInfo, out int arg1, Span friendInfo, Uid userId, int arg4); + Result GetSnsAccountLinkage(out SnsAccountLinkage accountLinkage, Uid userId); + Result GetSnsAccountProfile(out SnsAccountProfile accountProfile, Uid userId, NetworkServiceAccountId friendId, int arg3); + Result GetSnsAccountFriendList(out int count, Span friendList, Uid userId, int arg3); + Result GetBlockedUserList(out int count, Span blockedUsers, Uid userId, int arg3); + Result SyncBlockedUserList(Uid userId); + Result GetProfileExtraList(Span extraList, Uid userId, ReadOnlySpan friendIds); + Result GetRelationship(out Relationship relationship, Uid userId, NetworkServiceAccountId friendId); + Result GetUserPresenceView(out UserPresenceViewImpl userPresenceView, Uid userId); + Result GetPlayHistoryList(out int count, Span playHistoryList, Uid userId, int arg3); + Result GetPlayHistoryStatistics(out PlayHistoryStatistics statistics, Uid userId); + Result LoadUserSetting(out UserSettingImpl userSetting, Uid userId); + Result SyncUserSetting(Uid userId); + Result RequestListSummaryOverlayNotification(); + Result GetExternalApplicationCatalog(out ExternalApplicationCatalog catalog, ExternalApplicationCatalogId catalogId, LanguageCode language); + Result GetReceivedFriendInvitationList(out int count, Span invitationList, Uid userId); + Result GetReceivedFriendInvitationDetailedInfo(out FriendInvitationGroupImpl invicationGroup, Uid userId, FriendInvitationGroupId groupId); + Result GetReceivedFriendInvitationCountCache(out int count, Uid userId); + Result DropFriendNewlyFlags(Uid userId); + Result DeleteFriend(Uid userId, NetworkServiceAccountId friendId); + Result DropFriendNewlyFlag(Uid userId, NetworkServiceAccountId friendId); + Result ChangeFriendFavoriteFlag(Uid userId, NetworkServiceAccountId friendId, bool favoriteFlag); + Result ChangeFriendOnlineNotificationFlag(Uid userId, NetworkServiceAccountId friendId, bool onlineNotificationFlag); + Result SendFriendRequest(Uid userId, NetworkServiceAccountId friendId, int arg2); + Result SendFriendRequestWithApplicationInfo(Uid userId, NetworkServiceAccountId friendId, int arg2, ApplicationInfo applicationInfo, in InAppScreenName arg4, in InAppScreenName arg5); + Result CancelFriendRequest(Uid userId, RequestId requestId); + Result AcceptFriendRequest(Uid userId, RequestId requestId); + Result RejectFriendRequest(Uid userId, RequestId requestId); + Result ReadFriendRequest(Uid userId, RequestId requestId); + Result GetFacedFriendRequestRegistrationKey(out FacedFriendRequestRegistrationKey registrationKey, Uid userId); + Result AddFacedFriendRequest(Uid userId, FacedFriendRequestRegistrationKey registrationKey, Nickname nickname, ReadOnlySpan arg3); + Result CancelFacedFriendRequest(Uid userId, NetworkServiceAccountId friendId); + Result GetFacedFriendRequestProfileImage(out int size, Uid userId, NetworkServiceAccountId friendId, Span profileImage); + Result GetFacedFriendRequestProfileImageFromPath(out int size, ReadOnlySpan path, Span profileImage); + Result SendFriendRequestWithExternalApplicationCatalogId(Uid userId, NetworkServiceAccountId friendId, int arg2, ExternalApplicationCatalogId catalogId, in InAppScreenName arg4, in InAppScreenName arg5); + Result ResendFacedFriendRequest(Uid userId, NetworkServiceAccountId friendId); + Result SendFriendRequestWithNintendoNetworkIdInfo(Uid userId, NetworkServiceAccountId friendId, int arg2, MiiName arg3, MiiImageUrlParam arg4, MiiName arg5, MiiImageUrlParam arg6); + Result GetSnsAccountLinkPageUrl(out WebPageUrl url, Uid userId, int arg2); + Result UnlinkSnsAccount(Uid userId, int arg1); + Result BlockUser(Uid userId, NetworkServiceAccountId friendId, int arg2); + Result BlockUserWithApplicationInfo(Uid userId, NetworkServiceAccountId friendId, int arg2, ApplicationInfo applicationInfo, in InAppScreenName arg4); + Result UnblockUser(Uid userId, NetworkServiceAccountId friendId); + Result GetProfileExtraFromFriendCode(out ProfileExtraImpl profileExtra, Uid userId, FriendCode friendCode); + Result DeletePlayHistory(Uid userId); + Result ChangePresencePermission(Uid userId, int permission); + Result ChangeFriendRequestReception(Uid userId, bool reception); + Result ChangePlayLogPermission(Uid userId, int permission); + Result IssueFriendCode(Uid userId); + Result ClearPlayLog(Uid userId); + Result SendFriendInvitation(Uid userId, ReadOnlySpan friendIds, in FriendInvitationGameModeDescription description, ApplicationInfo applicationInfo, ReadOnlySpan arg4, bool arg5); + Result ReadFriendInvitation(Uid userId, ReadOnlySpan invitationIds); + Result ReadAllFriendInvitations(Uid userId); + Result DeleteFriendListCache(Uid userId); + Result DeleteBlockedUserListCache(Uid userId); + Result DeleteNetworkServiceAccountCache(Uid userId); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/INotificationService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/INotificationService.cs new file mode 100644 index 000000000..a3a28e8ce --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/INotificationService.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + interface INotificationService : IServiceObject + { + Result GetEvent(out int eventHandle); + Result Clear(); + Result Pop(out SizedNotificationInfo sizedNotificationInfo); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IServiceCreator.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IServiceCreator.cs new file mode 100644 index 000000000..58e2569bb --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IServiceCreator.cs @@ -0,0 +1,13 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + interface IServiceCreator : IServiceObject + { + Result CreateFriendService(out IFriendService friendService); + Result CreateNotificationService(out INotificationService notificationService, Uid userId); + Result CreateDaemonSuspendSessionService(out IDaemonSuspendSessionService daemonSuspendSessionService); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventHandler.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventHandler.cs new file mode 100644 index 000000000..61c692a6e --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventHandler.cs @@ -0,0 +1,58 @@ +using Ryujinx.Horizon.Sdk.Account; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + sealed class NotificationEventHandler + { + private readonly NotificationService[] _registry; + + public NotificationEventHandler() + { + _registry = new NotificationService[0x20]; + } + + public void RegisterNotificationService(NotificationService service) + { + // NOTE: When there's no enough space in the registry array, Nintendo doesn't return any errors. + for (int i = 0; i < _registry.Length; i++) + { + if (_registry[i] == null) + { + _registry[i] = service; + break; + } + } + } + + public void UnregisterNotificationService(NotificationService service) + { + // NOTE: When there's no enough space in the registry array, Nintendo doesn't return any errors. + for (int i = 0; i < _registry.Length; i++) + { + if (_registry[i] == service) + { + _registry[i] = null; + break; + } + } + } + + // TODO: Use this when we have enough things to go online. + public void SignalFriendListUpdate(Uid targetId) + { + for (int i = 0; i < _registry.Length; i++) + { + _registry[i]?.SignalFriendListUpdate(targetId); + } + } + + // TODO: Use this when we have enough things to go online. + public void SignalNewFriendRequest(Uid targetId) + { + for (int i = 0; i < _registry.Length; i++) + { + _registry[i]?.SignalNewFriendRequest(targetId); + } + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventType.cs similarity index 64% rename from src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs rename to src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventType.cs index 363e03eaf..e46fc9b7a 100644 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventType.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc { enum NotificationEventType : uint { diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs new file mode 100644 index 000000000..534bf63ed --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs @@ -0,0 +1,172 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.OsTypes; +using Ryujinx.Horizon.Sdk.Sf; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + partial class NotificationService : INotificationService, IDisposable + { + private readonly NotificationEventHandler _notificationEventHandler; + private readonly Uid _userId; + private readonly FriendsServicePermissionLevel _permissionLevel; + + private readonly object _lock = new(); + + private SystemEventType _notificationEvent; + + private readonly LinkedList _notifications; + + private bool _hasNewFriendRequest; + private bool _hasFriendListUpdate; + + public NotificationService(NotificationEventHandler notificationEventHandler, Uid userId, FriendsServicePermissionLevel permissionLevel) + { + _notificationEventHandler = notificationEventHandler; + _userId = userId; + _permissionLevel = permissionLevel; + _notifications = new LinkedList(); + Os.CreateSystemEvent(out _notificationEvent, EventClearMode.AutoClear, interProcess: true).AbortOnFailure(); + + _hasNewFriendRequest = false; + _hasFriendListUpdate = false; + + notificationEventHandler.RegisterNotificationService(this); + } + + [CmifCommand(0)] + public Result GetEvent([CopyHandle] out int eventHandle) + { + eventHandle = Os.GetReadableHandleOfSystemEvent(ref _notificationEvent); + + return Result.Success; + } + + [CmifCommand(1)] + public Result Clear() + { + lock (_lock) + { + _hasNewFriendRequest = false; + _hasFriendListUpdate = false; + + _notifications.Clear(); + } + + return Result.Success; + } + + [CmifCommand(2)] + public Result Pop(out SizedNotificationInfo sizedNotificationInfo) + { + lock (_lock) + { + if (_notifications.Count >= 1) + { + sizedNotificationInfo = _notifications.First.Value; + _notifications.RemoveFirst(); + + if (sizedNotificationInfo.Type == NotificationEventType.FriendListUpdate) + { + _hasFriendListUpdate = false; + } + else if (sizedNotificationInfo.Type == NotificationEventType.NewFriendRequest) + { + _hasNewFriendRequest = false; + } + + return Result.Success; + } + } + + sizedNotificationInfo = default; + + return FriendResult.NotificationQueueEmpty; + } + + public void SignalFriendListUpdate(Uid targetId) + { + lock (_lock) + { + if (_userId == targetId) + { + if (!_hasFriendListUpdate) + { + SizedNotificationInfo friendListNotification = new(); + + if (_notifications.Count != 0) + { + friendListNotification = _notifications.First.Value; + _notifications.RemoveFirst(); + } + + friendListNotification.Type = NotificationEventType.FriendListUpdate; + _hasFriendListUpdate = true; + + if (_hasNewFriendRequest) + { + SizedNotificationInfo newFriendRequestNotification = new(); + + if (_notifications.Count != 0) + { + newFriendRequestNotification = _notifications.First.Value; + _notifications.RemoveFirst(); + } + + newFriendRequestNotification.Type = NotificationEventType.NewFriendRequest; + _notifications.AddFirst(newFriendRequestNotification); + } + + // We defer this to make sure we are on top of the queue. + _notifications.AddFirst(friendListNotification); + } + + Os.SignalSystemEvent(ref _notificationEvent); + } + } + } + + public void SignalNewFriendRequest(Uid targetId) + { + lock (_lock) + { + if (_permissionLevel.HasFlag(FriendsServicePermissionLevel.ViewerMask) && _userId == targetId) + { + if (!_hasNewFriendRequest) + { + if (_notifications.Count == 100) + { + SignalFriendListUpdate(targetId); + } + + SizedNotificationInfo newFriendRequestNotification = new() + { + Type = NotificationEventType.NewFriendRequest, + }; + + _notifications.AddLast(newFriendRequestNotification); + _hasNewFriendRequest = true; + } + + Os.SignalSystemEvent(ref _notificationEvent); + } + } + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _notificationEventHandler.UnregisterNotificationService(this); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/PresenceStatusFilter.cs similarity index 64% rename from src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs rename to src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/PresenceStatusFilter.cs index c9a54250f..3ea105872 100644 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/PresenceStatusFilter.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc { enum PresenceStatusFilter : uint { diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/ServiceCreator.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/ServiceCreator.cs new file mode 100644 index 000000000..1be804dfd --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/ServiceCreator.cs @@ -0,0 +1,51 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + partial class ServiceCreator : IServiceCreator + { + private readonly IEmulatorAccountManager _accountManager; + private readonly NotificationEventHandler _notificationEventHandler; + private readonly FriendsServicePermissionLevel _permissionLevel; + + public ServiceCreator(IEmulatorAccountManager accountManager, NotificationEventHandler notificationEventHandler, FriendsServicePermissionLevel permissionLevel) + { + _accountManager = accountManager; + _notificationEventHandler = notificationEventHandler; + _permissionLevel = permissionLevel; + } + + [CmifCommand(0)] + public Result CreateFriendService(out IFriendService friendService) + { + friendService = new FriendService(_accountManager, _permissionLevel); + + return Result.Success; + } + + [CmifCommand(1)] // 2.0.0+ + public Result CreateNotificationService(out INotificationService notificationService, Uid userId) + { + if (userId.IsNull) + { + notificationService = null; + + return FriendResult.InvalidArgument; + } + + notificationService = new NotificationService(_notificationEventHandler, userId, _permissionLevel); + + return Result.Success; + } + + [CmifCommand(2)] // 4.0.0+ + public Result CreateDaemonSuspendSessionService(out IDaemonSuspendSessionService daemonSuspendSessionService) + { + daemonSuspendSessionService = new DaemonSuspendSessionService(); + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedFriendFilter.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedFriendFilter.cs new file mode 100644 index 000000000..d93a2ae29 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedFriendFilter.cs @@ -0,0 +1,25 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct SizedFriendFilter + { + public PresenceStatusFilter PresenceStatus; + public bool IsFavoriteOnly; + public bool IsSameAppPresenceOnly; + public bool IsSameAppPlayedOnly; + public bool IsArbitraryAppPlayedOnly; + public ulong PresenceGroupId; + + public readonly override string ToString() + { + return $"{{ PresenceStatus: {PresenceStatus}, " + + $"IsFavoriteOnly: {IsFavoriteOnly}, " + + $"IsSameAppPresenceOnly: {IsSameAppPresenceOnly}, " + + $"IsSameAppPlayedOnly: {IsSameAppPlayedOnly}, " + + $"IsArbitraryAppPlayedOnly: {IsArbitraryAppPlayedOnly}, " + + $"PresenceGroupId: {PresenceGroupId} }}"; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedNotificationInfo.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedNotificationInfo.cs new file mode 100644 index 000000000..0da26a1ae --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedNotificationInfo.cs @@ -0,0 +1,13 @@ +using Ryujinx.Horizon.Sdk.Account; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct SizedNotificationInfo + { + public NotificationEventType Type; + public uint Padding; + public NetworkServiceAccountId NetworkUserIdPlaceholder; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/NintendoNetworkIdFriendImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/NintendoNetworkIdFriendImpl.cs new file mode 100644 index 000000000..66d61e4c1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/NintendoNetworkIdFriendImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct NintendoNetworkIdFriendImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/PlayHistoryImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/PlayHistoryImpl.cs new file mode 100644 index 000000000..9f90f0c8f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/PlayHistoryImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct PlayHistoryImpl + { + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/PresenceStatus.cs similarity index 58% rename from src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs rename to src/Ryujinx.Horizon/Sdk/Friends/Detail/PresenceStatus.cs index 7930aff0b..5ddbe14ea 100644 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/PresenceStatus.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService +namespace Ryujinx.Horizon.Sdk.Friends.Detail { enum PresenceStatus : uint { diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileExtraImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileExtraImpl.cs new file mode 100644 index 000000000..1548d725f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileExtraImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x400)] + struct ProfileExtraImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileImpl.cs new file mode 100644 index 000000000..f779d93cf --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct ProfileImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/SnsAccountFriendImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/SnsAccountFriendImpl.cs new file mode 100644 index 000000000..dc6adf03a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/SnsAccountFriendImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct SnsAccountFriendImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceImpl.cs new file mode 100644 index 000000000..cf4520cf4 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceImpl.cs @@ -0,0 +1,29 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Sdk.Account; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0xE0)] + struct UserPresenceImpl + { + public Uid UserId; + public long LastTimeOnlineTimestamp; + public PresenceStatus Status; + public bool SamePresenceGroupApplication; + public Array3 Unknown; + public AppKeyValueStorageHolder AppKeyValueStorage; + + [InlineArray(0xC0)] + public struct AppKeyValueStorageHolder + { + public byte Value; + } + + public readonly override string ToString() + { + return $"{{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status} }}"; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceViewImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceViewImpl.cs new file mode 100644 index 000000000..04c092600 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceViewImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0xE0)] + struct UserPresenceViewImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserSettingImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserSettingImpl.cs new file mode 100644 index 000000000..9d057fb1e --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserSettingImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x800)] + struct UserSettingImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalog.cs b/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalog.cs new file mode 100644 index 000000000..0d9c157d3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalog.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x4B8)] + struct ExternalApplicationCatalog + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalogId.cs b/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalogId.cs new file mode 100644 index 000000000..7ed36cd9d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalogId.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct ExternalApplicationCatalogId + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FacedFriendRequestRegistrationKey.cs b/src/Ryujinx.Horizon/Sdk/Friends/FacedFriendRequestRegistrationKey.cs new file mode 100644 index 000000000..6b5812f64 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FacedFriendRequestRegistrationKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x40, Pack = 0x1)] + struct FacedFriendRequestRegistrationKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FriendCode.cs b/src/Ryujinx.Horizon/Sdk/Friends/FriendCode.cs new file mode 100644 index 000000000..d78497a18 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FriendCode.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 0x1)] + struct FriendCode + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGameModeDescription.cs b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGameModeDescription.cs new file mode 100644 index 000000000..29b4a0974 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGameModeDescription.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0xC00)] + struct FriendInvitationGameModeDescription + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGroupId.cs b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGroupId.cs new file mode 100644 index 000000000..ef53882b3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGroupId.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x8)] + struct FriendInvitationGroupId + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationId.cs b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationId.cs new file mode 100644 index 000000000..7be19d574 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationId.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + struct FriendInvitationId + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FriendResult.cs b/src/Ryujinx.Horizon/Sdk/Friends/FriendResult.cs new file mode 100644 index 000000000..5965d508d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FriendResult.cs @@ -0,0 +1,13 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + static class FriendResult + { + private const int ModuleId = 121; + + public static Result InvalidArgument => new(ModuleId, 2); + public static Result InternetRequestDenied => new(ModuleId, 6); + public static Result NotificationQueueEmpty => new(ModuleId, 15); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/InAppScreenName.cs b/src/Ryujinx.Horizon/Sdk/Friends/InAppScreenName.cs new file mode 100644 index 000000000..22574a5cc --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/InAppScreenName.cs @@ -0,0 +1,26 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Sdk.Settings; +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x48)] + struct InAppScreenName + { + public Array64 Name; + public LanguageCode LanguageCode; + + public override readonly string ToString() + { + int length = Name.AsSpan().IndexOf((byte)0); + if (length < 0) + { + length = 64; + } + + return Encoding.UTF8.GetString(Name.AsSpan()[..length]); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/MiiImageUrlParam.cs b/src/Ryujinx.Horizon/Sdk/Friends/MiiImageUrlParam.cs new file mode 100644 index 000000000..8790bb931 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/MiiImageUrlParam.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x1)] + struct MiiImageUrlParam + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/MiiName.cs b/src/Ryujinx.Horizon/Sdk/Friends/MiiName.cs new file mode 100644 index 000000000..e73c0d833 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/MiiName.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 0x1)] + struct MiiName + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/NintendoNetworkIdUserInfo.cs b/src/Ryujinx.Horizon/Sdk/Friends/NintendoNetworkIdUserInfo.cs new file mode 100644 index 000000000..a2a9e046f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/NintendoNetworkIdUserInfo.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x38)] + struct NintendoNetworkIdUserInfo + { + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/PlayHistoryRegistrationKey.cs b/src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryRegistrationKey.cs similarity index 59% rename from src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/PlayHistoryRegistrationKey.cs rename to src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryRegistrationKey.cs index 9687c5478..bb672a795 100644 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/PlayHistoryRegistrationKey.cs +++ b/src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryRegistrationKey.cs @@ -1,9 +1,10 @@ using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Sdk.Account; using System.Runtime.InteropServices; -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator +namespace Ryujinx.Horizon.Sdk.Friends { - [StructLayout(LayoutKind.Sequential, Size = 0x20)] + [StructLayout(LayoutKind.Sequential, Size = 0x40)] struct PlayHistoryRegistrationKey { public ushort Type; @@ -11,6 +12,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator public byte UserIdBool; public byte UnknownBool; public Array11 Reserved; - public Array16 Uuid; + public Uid Uuid; + public Array32 HmacHash; } } diff --git a/src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryStatistics.cs b/src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryStatistics.cs new file mode 100644 index 000000000..ea3e3d997 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryStatistics.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct PlayHistoryStatistics + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Relationship.cs b/src/Ryujinx.Horizon/Sdk/Friends/Relationship.cs new file mode 100644 index 000000000..efba09a8f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Relationship.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x1)] + struct Relationship + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/RequestId.cs b/src/Ryujinx.Horizon/Sdk/Friends/RequestId.cs new file mode 100644 index 000000000..3236a1d7d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/RequestId.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x8)] + struct RequestId + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountLinkage.cs b/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountLinkage.cs new file mode 100644 index 000000000..b4660d9e7 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountLinkage.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x1)] + struct SnsAccountLinkage + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountProfile.cs b/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountProfile.cs new file mode 100644 index 000000000..d872b3dac --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountProfile.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x380)] + struct SnsAccountProfile + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Url.cs b/src/Ryujinx.Horizon/Sdk/Friends/Url.cs new file mode 100644 index 000000000..833ee1230 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Url.cs @@ -0,0 +1,30 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0xA0, Pack = 0x1)] + struct Url + { + public UrlStorage Path; + + [InlineArray(0xA0)] + public struct UrlStorage + { + public byte Value; + } + + public override readonly string ToString() + { + int length = ((ReadOnlySpan)Path).IndexOf((byte)0); + if (length < 0) + { + length = 33; + } + + return Encoding.UTF8.GetString(((ReadOnlySpan)Path)[..length]); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/WebPageUrl.cs b/src/Ryujinx.Horizon/Sdk/Friends/WebPageUrl.cs new file mode 100644 index 000000000..85488af61 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/WebPageUrl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x1000)] + struct WebPageUrl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs b/src/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs index 4c5e76e6f..24b7d9cab 100644 --- a/src/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs +++ b/src/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs @@ -1,6 +1,6 @@ namespace Ryujinx.Horizon.Sdk.Ncm { - readonly struct ApplicationId + public readonly struct ApplicationId { public readonly ulong Id; diff --git a/src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs b/src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs new file mode 100644 index 000000000..e2fb32505 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Horizon.Sdk.Ncm +{ + public enum StorageId : byte + { + None, + Host, + GameCard, + BuiltInSystem, + BuiltInUser, + SdCard, + Any, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Ns/ApplicationControlProperty.cs b/src/Ryujinx.Horizon/Sdk/Ns/ApplicationControlProperty.cs new file mode 100644 index 000000000..12c19168d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Ns/ApplicationControlProperty.cs @@ -0,0 +1,309 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Ns +{ + public struct ApplicationControlProperty + { + public Array16 Title; + public Array37 Isbn; + public StartupUserAccountValue StartupUserAccount; + public UserAccountSwitchLockValue UserAccountSwitchLock; + public AddOnContentRegistrationTypeValue AddOnContentRegistrationType; + public AttributeFlagValue AttributeFlag; + public uint SupportedLanguageFlag; + public ParentalControlFlagValue ParentalControlFlag; + public ScreenshotValue Screenshot; + public VideoCaptureValue VideoCapture; + public DataLossConfirmationValue DataLossConfirmation; + public PlayLogPolicyValue PlayLogPolicy; + public ulong PresenceGroupId; + public Array32 RatingAge; + public Array16 DisplayVersion; + public ulong AddOnContentBaseId; + public ulong SaveDataOwnerId; + public long UserAccountSaveDataSize; + public long UserAccountSaveDataJournalSize; + public long DeviceSaveDataSize; + public long DeviceSaveDataJournalSize; + public long BcatDeliveryCacheStorageSize; + public Array8 ApplicationErrorCodeCategory; + public Array8 LocalCommunicationId; + public LogoTypeValue LogoType; + public LogoHandlingValue LogoHandling; + public RuntimeAddOnContentInstallValue RuntimeAddOnContentInstall; + public RuntimeParameterDeliveryValue RuntimeParameterDelivery; + public Array2 Reserved30F4; + public CrashReportValue CrashReport; + public HdcpValue Hdcp; + public ulong SeedForPseudoDeviceId; + public Array65 BcatPassphrase; + public StartupUserAccountOptionFlagValue StartupUserAccountOption; + public Array6 ReservedForUserAccountSaveDataOperation; + public long UserAccountSaveDataSizeMax; + public long UserAccountSaveDataJournalSizeMax; + public long DeviceSaveDataSizeMax; + public long DeviceSaveDataJournalSizeMax; + public long TemporaryStorageSize; + public long CacheStorageSize; + public long CacheStorageJournalSize; + public long CacheStorageDataAndJournalSizeMax; + public ushort CacheStorageIndexMax; + public byte Reserved318A; + public byte RuntimeUpgrade; + public uint SupportingLimitedLicenses; + public Array16 PlayLogQueryableApplicationId; + public PlayLogQueryCapabilityValue PlayLogQueryCapability; + public RepairFlagValue RepairFlag; + public byte ProgramIndex; + public RequiredNetworkServiceLicenseOnLaunchValue RequiredNetworkServiceLicenseOnLaunchFlag; + public Array4 Reserved3214; + public ApplicationNeighborDetectionClientConfiguration NeighborDetectionClientConfiguration; + public ApplicationJitConfiguration JitConfiguration; + public RequiredAddOnContentsSetBinaryDescriptor RequiredAddOnContentsSetBinaryDescriptors; + public PlayReportPermissionValue PlayReportPermission; + public CrashScreenshotForProdValue CrashScreenshotForProd; + public CrashScreenshotForDevValue CrashScreenshotForDev; + public byte ContentsAvailabilityTransitionPolicy; + public Array4 Reserved3404; + public AccessibleLaunchRequiredVersionValue AccessibleLaunchRequiredVersion; + public ByteArray3000 Reserved3448; + + public readonly string IsbnString => Encoding.UTF8.GetString(Isbn.AsSpan()).TrimEnd('\0'); + public readonly string DisplayVersionString => Encoding.UTF8.GetString(DisplayVersion.AsSpan()).TrimEnd('\0'); + public readonly string ApplicationErrorCodeCategoryString => Encoding.UTF8.GetString(ApplicationErrorCodeCategory.AsSpan()).TrimEnd('\0'); + public readonly string BcatPassphraseString => Encoding.UTF8.GetString(BcatPassphrase.AsSpan()).TrimEnd('\0'); + + public struct ApplicationTitle + { + public ByteArray512 Name; + public Array256 Publisher; + + public readonly string NameString => Encoding.UTF8.GetString(Name.AsSpan()).TrimEnd('\0'); + public readonly string PublisherString => Encoding.UTF8.GetString(Publisher.AsSpan()).TrimEnd('\0'); + } + + public struct ApplicationNeighborDetectionClientConfiguration + { + public ApplicationNeighborDetectionGroupConfiguration SendGroupConfiguration; + public Array16 ReceivableGroupConfigurations; + } + + public struct ApplicationNeighborDetectionGroupConfiguration + { + public ulong GroupId; + public Array16 Key; + } + + public struct ApplicationJitConfiguration + { + public JitConfigurationFlag Flags; + public long MemorySize; + } + + public struct RequiredAddOnContentsSetBinaryDescriptor + { + public Array32 Descriptors; + } + + public struct AccessibleLaunchRequiredVersionValue + { + public Array8 ApplicationId; + } + + public enum Language + { + AmericanEnglish = 0, + BritishEnglish = 1, + Japanese = 2, + French = 3, + German = 4, + LatinAmericanSpanish = 5, + Spanish = 6, + Italian = 7, + Dutch = 8, + CanadianFrench = 9, + Portuguese = 10, + Russian = 11, + Korean = 12, + TraditionalChinese = 13, + SimplifiedChinese = 14, + BrazilianPortuguese = 15, + } + + public enum Organization + { + CERO = 0, + GRACGCRB = 1, + GSRMR = 2, + ESRB = 3, + ClassInd = 4, + USK = 5, + PEGI = 6, + PEGIPortugal = 7, + PEGIBBFC = 8, + Russian = 9, + ACB = 10, + OFLC = 11, + IARCGeneric = 12, + } + + public enum StartupUserAccountValue : byte + { + None = 0, + Required = 1, + RequiredWithNetworkServiceAccountAvailable = 2, + } + + public enum UserAccountSwitchLockValue : byte + { + Disable = 0, + Enable = 1, + } + + public enum AddOnContentRegistrationTypeValue : byte + { + AllOnLaunch = 0, + OnDemand = 1, + } + + [Flags] + public enum AttributeFlagValue + { + None = 0, + Demo = 1 << 0, + RetailInteractiveDisplay = 1 << 1, + } + + public enum ParentalControlFlagValue + { + None = 0, + FreeCommunication = 1, + } + + public enum ScreenshotValue : byte + { + Allow = 0, + Deny = 1, + } + + public enum VideoCaptureValue : byte + { + Disable = 0, + Manual = 1, + Enable = 2, + } + + public enum DataLossConfirmationValue : byte + { + None = 0, + Required = 1, + } + + public enum PlayLogPolicyValue : byte + { + Open = 0, + LogOnly = 1, + None = 2, + Closed = 3, + All = Open, + } + + public enum LogoTypeValue : byte + { + LicensedByNintendo = 0, + DistributedByNintendo = 1, + Nintendo = 2, + } + + public enum LogoHandlingValue : byte + { + Auto = 0, + Manual = 1, + } + + public enum RuntimeAddOnContentInstallValue : byte + { + Deny = 0, + AllowAppend = 1, + AllowAppendButDontDownloadWhenUsingNetwork = 2, + } + + public enum RuntimeParameterDeliveryValue : byte + { + Always = 0, + AlwaysIfUserStateMatched = 1, + OnRestart = 2, + } + + public enum CrashReportValue : byte + { + Deny = 0, + Allow = 1, + } + + public enum HdcpValue : byte + { + None = 0, + Required = 1, + } + + [Flags] + public enum StartupUserAccountOptionFlagValue : byte + { + None = 0, + IsOptional = 1 << 0, + } + + public enum PlayLogQueryCapabilityValue : byte + { + None = 0, + WhiteList = 1, + All = 2, + } + + [Flags] + public enum RepairFlagValue : byte + { + None = 0, + SuppressGameCardAccess = 1 << 0, + } + + [Flags] + public enum RequiredNetworkServiceLicenseOnLaunchValue : byte + { + None = 0, + Common = 1 << 0, + } + + [Flags] + public enum JitConfigurationFlag : ulong + { + None = 0, + Enabled = 1 << 0, + } + + [Flags] + public enum PlayReportPermissionValue : byte + { + None = 0, + TargetMarketing = 1 << 0, + } + + public enum CrashScreenshotForProdValue : byte + { + Deny = 0, + Allow = 1, + } + + public enum CrashScreenshotForDevValue : byte + { + Deny = 0, + Allow = 1, + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs b/src/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs index 2aefb0db5..406352003 100644 --- a/src/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs +++ b/src/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs @@ -21,6 +21,8 @@ namespace Ryujinx.Horizon.Sdk.OsTypes.Impl public long CurrentTime { get; private set; } + public IEnumerable MultiWaits => _multiWaits; + public MultiWaitImpl() { _multiWaits = new List(); diff --git a/src/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs b/src/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs index 0e73e3f88..41d17802a 100644 --- a/src/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs +++ b/src/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs @@ -1,4 +1,5 @@ using Ryujinx.Horizon.Sdk.OsTypes.Impl; +using System.Collections.Generic; namespace Ryujinx.Horizon.Sdk.OsTypes { @@ -6,6 +7,8 @@ namespace Ryujinx.Horizon.Sdk.OsTypes { private readonly MultiWaitImpl _impl; + public IEnumerable MultiWaits => _impl.MultiWaits; + public MultiWait() { _impl = new MultiWaitImpl(); diff --git a/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs b/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs index ccd6c93a6..5527c1e35 100644 --- a/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs +++ b/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs @@ -35,5 +35,254 @@ namespace Ryujinx.Horizon.Sdk return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0); } + + public static Result SendRequest( + out CmifResponse response, + int sessionHandle, + uint requestId, + bool sendPid, + scoped ReadOnlySpan data, + ReadOnlySpan bufferFlags, + ReadOnlySpan buffers) + { + ulong tlsAddress = HorizonStatic.ThreadContext.TlsAddress; + int tlsSize = Api.TlsMessageBufferSize; + + using (var tlsRegion = HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize)) + { + CmifRequestFormat format = new() + { + DataSize = data.Length, + RequestId = requestId, + SendPid = sendPid, + }; + + for (int index = 0; index < bufferFlags.Length; index++) + { + FormatProcessBuffer(ref format, bufferFlags[index]); + } + + CmifRequest request = CmifMessage.CreateRequest(tlsRegion.Memory.Span, format); + + for (int index = 0; index < buffers.Length; index++) + { + RequestProcessBuffer(ref request, buffers[index], bufferFlags[index]); + } + + data.CopyTo(request.Data); + } + + Result result = HorizonStatic.Syscall.SendSyncRequest(sessionHandle); + + if (result.IsFailure) + { + response = default; + + return result; + } + + return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0); + } + + private static void FormatProcessBuffer(ref CmifRequestFormat format, HipcBufferFlags flags) + { + if (flags == 0) + { + return; + } + + bool isIn = flags.HasFlag(HipcBufferFlags.In); + bool isOut = flags.HasFlag(HipcBufferFlags.Out); + + if (flags.HasFlag(HipcBufferFlags.AutoSelect)) + { + if (isIn) + { + format.InAutoBuffersCount++; + } + + if (isOut) + { + format.OutAutoBuffersCount++; + } + } + else if (flags.HasFlag(HipcBufferFlags.Pointer)) + { + if (isIn) + { + format.InPointersCount++; + } + + if (isOut) + { + if (flags.HasFlag(HipcBufferFlags.FixedSize)) + { + format.OutFixedPointersCount++; + } + else + { + format.OutPointersCount++; + } + } + } + else if (flags.HasFlag(HipcBufferFlags.MapAlias)) + { + if (isIn && isOut) + { + format.InOutBuffersCount++; + } + else if (isIn) + { + format.InBuffersCount++; + } + else + { + format.OutBuffersCount++; + } + } + } + + private static void RequestProcessBuffer(ref CmifRequest request, PointerAndSize buffer, HipcBufferFlags flags) + { + if (flags == 0) + { + return; + } + + bool isIn = flags.HasFlag(HipcBufferFlags.In); + bool isOut = flags.HasFlag(HipcBufferFlags.Out); + + if (flags.HasFlag(HipcBufferFlags.AutoSelect)) + { + HipcBufferMode mode = HipcBufferMode.Normal; + + if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure)) + { + mode = HipcBufferMode.NonSecure; + } + + if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice)) + { + mode = HipcBufferMode.NonDevice; + } + + if (isIn) + { + RequestInAutoBuffer(ref request, buffer.Address, buffer.Size, mode); + } + + if (isOut) + { + RequestOutAutoBuffer(ref request, buffer.Address, buffer.Size, mode); + } + } + else if (flags.HasFlag(HipcBufferFlags.Pointer)) + { + if (isIn) + { + RequestInPointer(ref request, buffer.Address, buffer.Size); + } + + if (isOut) + { + if (flags.HasFlag(HipcBufferFlags.FixedSize)) + { + RequestOutFixedPointer(ref request, buffer.Address, buffer.Size); + } + else + { + RequestOutPointer(ref request, buffer.Address, buffer.Size); + } + } + } + else if (flags.HasFlag(HipcBufferFlags.MapAlias)) + { + HipcBufferMode mode = HipcBufferMode.Normal; + + if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure)) + { + mode = HipcBufferMode.NonSecure; + } + + if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice)) + { + mode = HipcBufferMode.NonDevice; + } + + if (isIn && isOut) + { + RequestInOutBuffer(ref request, buffer.Address, buffer.Size, mode); + } + else if (isIn) + { + RequestInBuffer(ref request, buffer.Address, buffer.Size, mode); + } + else + { + RequestOutBuffer(ref request, buffer.Address, buffer.Size, mode); + } + } + } + + private static void RequestInAutoBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode) + { + if (request.ServerPointerSize != 0 && bufferSize <= (ulong)request.ServerPointerSize) + { + RequestInPointer(ref request, bufferAddress, bufferSize); + RequestInBuffer(ref request, 0UL, 0UL, mode); + } + else + { + RequestInPointer(ref request, 0UL, 0UL); + RequestInBuffer(ref request, bufferAddress, bufferSize, mode); + } + } + + private static void RequestOutAutoBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode) + { + if (request.ServerPointerSize != 0 && bufferSize <= (ulong)request.ServerPointerSize) + { + RequestOutPointer(ref request, bufferAddress, bufferSize); + RequestOutBuffer(ref request, 0UL, 0UL, mode); + } + else + { + RequestOutPointer(ref request, 0UL, 0UL); + RequestOutBuffer(ref request, bufferAddress, bufferSize, mode); + } + } + + private static void RequestInBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode) + { + request.Hipc.SendBuffers[request.SendBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode); + } + + private static void RequestOutBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode) + { + request.Hipc.ReceiveBuffers[request.RecvBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode); + } + + private static void RequestInOutBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode) + { + request.Hipc.ExchangeBuffers[request.ExchBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode); + } + + private static void RequestInPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize) + { + request.Hipc.SendStatics[request.SendStaticIndex++] = new HipcStaticDescriptor(bufferAddress, (ushort)bufferSize, request.CurrentInPointerId++); + request.ServerPointerSize -= (int)bufferSize; + } + + private static void RequestOutFixedPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize) + { + request.Hipc.ReceiveList[request.RecvListIndex++] = new HipcReceiveListEntry(bufferAddress, (ushort)bufferSize); + request.ServerPointerSize -= (int)bufferSize; + } + + private static void RequestOutPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize) + { + RequestOutFixedPointer(ref request, bufferAddress, bufferSize); + request.OutPointerSizes[request.OutPointerSizeIndex++] = (ushort)bufferSize; + } } } diff --git a/src/Ryujinx.Horizon/Sdk/Settings/BatteryLot.cs b/src/Ryujinx.Horizon/Sdk/Settings/BatteryLot.cs new file mode 100644 index 000000000..71185fcd0 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/BatteryLot.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings +{ + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x1)] + struct BatteryLot + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerOffset.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerOffset.cs new file mode 100644 index 000000000..292a368f1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerOffset.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x2)] + struct AccelerometerOffset + { + public ushort X; + public ushort Y; + public ushort Z; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerScale.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerScale.cs new file mode 100644 index 000000000..ef9d17ef9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerScale.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x2)] + struct AccelerometerScale + { + public ushort X; + public ushort Y; + public ushort Z; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcdsaCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcdsaCertificate.cs new file mode 100644 index 000000000..7cbab2f09 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcdsaCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x74, Pack = 0x4)] + struct AmiiboEcdsaCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsCertificate.cs new file mode 100644 index 000000000..8d16b51b1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x24, Pack = 0x4)] + struct AmiiboEcqvBlsCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsKey.cs new file mode 100644 index 000000000..da6ca53bc --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x48, Pack = 0x4)] + struct AmiiboEcqvBlsKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsRootCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsRootCertificate.cs new file mode 100644 index 000000000..e69e38a1a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsRootCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x94, Pack = 0x4)] + struct AmiiboEcqvBlsRootCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvCertificate.cs new file mode 100644 index 000000000..43742fbb7 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x4)] + struct AmiiboEcqvCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboKey.cs new file mode 100644 index 000000000..43ffccb00 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x58, Pack = 0x4)] + struct AmiiboKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickFactoryCalibration.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickFactoryCalibration.cs new file mode 100644 index 000000000..3fe6f3223 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickFactoryCalibration.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x9, Pack = 0x1)] + struct AnalogStickFactoryCalibration + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickModelParameter.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickModelParameter.cs new file mode 100644 index 000000000..a442032c7 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickModelParameter.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x12, Pack = 0x1)] + struct AnalogStickModelParameter + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/BdAddress.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/BdAddress.cs new file mode 100644 index 000000000..519d72e8f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/BdAddress.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x1)] + struct BdAddress + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConfigurationId1.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConfigurationId1.cs new file mode 100644 index 000000000..40565805f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConfigurationId1.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x1E, Pack = 0x1)] + struct ConfigurationId1 + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConsoleSixAxisSensorHorizontalOffset.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConsoleSixAxisSensorHorizontalOffset.cs new file mode 100644 index 000000000..c5503edc5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConsoleSixAxisSensorHorizontalOffset.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x2)] + struct ConsoleSixAxisSensorHorizontalOffset + { + public ushort X; + public ushort Y; + public ushort Z; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/CountryCode.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/CountryCode.cs new file mode 100644 index 000000000..daf2ba3b8 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/CountryCode.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + struct CountryCode + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceCertificate.cs new file mode 100644 index 000000000..727408ed5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x180)] + struct EccB233DeviceCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceKey.cs new file mode 100644 index 000000000..a0481f4dc --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x58, Pack = 0x4)] + struct EccB233DeviceKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardCertificate.cs new file mode 100644 index 000000000..ce3908afe --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x400)] + struct GameCardCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardKey.cs new file mode 100644 index 000000000..81144ac48 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x138)] + struct GameCardKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeOffset.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeOffset.cs new file mode 100644 index 000000000..801d117cb --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeOffset.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x2)] + struct GyroscopeOffset + { + public ushort X; + public ushort Y; + public ushort Z; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeScale.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeScale.cs new file mode 100644 index 000000000..7812281f8 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeScale.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x2)] + struct GyroscopeScale + { + public ushort X; + public ushort Y; + public ushort Z; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/MacAddress.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/MacAddress.cs new file mode 100644 index 000000000..65e222ee5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/MacAddress.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x1)] + struct MacAddress + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceCertificate.cs new file mode 100644 index 000000000..57217059f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x240)] + struct Rsa2048DeviceCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceKey.cs new file mode 100644 index 000000000..d2fd51cf7 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x248)] + struct Rsa2048DeviceKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/SerialNumber.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SerialNumber.cs new file mode 100644 index 000000000..af664cdc5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SerialNumber.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x1)] + struct SerialNumber + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/SpeakerParameter.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SpeakerParameter.cs new file mode 100644 index 000000000..f147f66ff --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SpeakerParameter.cs @@ -0,0 +1,32 @@ +using Ryujinx.Common.Memory; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x5A, Pack = 0x2)] + struct SpeakerParameter + { + public ushort Version; + public Array34 Reserved; + public ushort SpeakerHpf2A1; + public ushort SpeakerHpf2A2; + public ushort SpeakerHpf2H0; + public ushort SpeakerEqInputVolume; + public ushort SpeakerEqOutputVolume; + public ushort SpeakerEqCtrl1; + public ushort SpeakerEqCtrl2; + public ushort SpeakerDrcAgcCtrl2; + public ushort SpeakerDrcAgcCtrl3; + public ushort SpeakerDrcAgcCtrl1; + public ushort SpeakerAnalogVolume; + public ushort HeadphoneAnalogVolume; + public ushort SpeakerDigitalVolumeMin; + public ushort SpeakerDigitalVolumeMax; + public ushort HeadphoneDigitalVolumeMin; + public ushort HeadphoneDigitalVolumeMax; + public ushort MicFixedGain; + public ushort MicVariableVolumeMin; + public ushort MicVariableVolumeMax; + public Array16 Reserved2; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslCertificate.cs new file mode 100644 index 000000000..5d8252164 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x804)] + struct SslCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslKey.cs new file mode 100644 index 000000000..7d4b41369 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x138)] + struct SslKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Language.cs b/src/Ryujinx.Horizon/Sdk/Settings/Language.cs new file mode 100644 index 000000000..4ffc66fec --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Language.cs @@ -0,0 +1,24 @@ +namespace Ryujinx.Horizon.Sdk.Settings +{ + enum Language : uint + { + Japanese, + AmericanEnglish, + French, + German, + Italian, + Spanish, + Chinese, + Korean, + Dutch, + Portuguese, + Russian, + Taiwanese, + BritishEnglish, + CanadianFrench, + LatinAmericanSpanish, + SimplifiedChinese, + TraditionalChinese, + BrazilianPortuguese, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/LanguageCode.cs b/src/Ryujinx.Horizon/Sdk/Settings/LanguageCode.cs new file mode 100644 index 000000000..dc9712692 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/LanguageCode.cs @@ -0,0 +1,63 @@ +using Ryujinx.Common.Memory; +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Settings +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x1)] + struct LanguageCode + { + private static readonly string[] _languageCodes = new string[] + { + "ja", + "en-US", + "fr", + "de", + "it", + "es", + "zh-CN", + "ko", + "nl", + "pt", + "ru", + "zh-TW", + "en-GB", + "fr-CA", + "es-419", + "zh-Hans", + "zh-Hant", + "pt-BR" + }; + + public Array8 Value; + + public bool IsValid() + { + int length = Value.AsSpan().IndexOf((byte)0); + if (length < 0) + { + return false; + } + + string str = Encoding.ASCII.GetString(Value.AsSpan()[..length]); + + return _languageCodes.AsSpan().Contains(str); + } + + public LanguageCode(Language language) + { + if ((uint)language >= _languageCodes.Length) + { + throw new ArgumentOutOfRangeException(nameof(language)); + } + + Value = new LanguageCode(_languageCodes[(int)language]).Value; + } + + public LanguageCode(string strCode) + { + Encoding.ASCII.GetBytes(strCode, Value.AsSpan()); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/SettingsItemKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/SettingsItemKey.cs new file mode 100644 index 000000000..661184103 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/SettingsItemKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings +{ + [StructLayout(LayoutKind.Sequential, Size = 0x48)] + struct SettingsItemKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/SettingsName.cs b/src/Ryujinx.Horizon/Sdk/Settings/SettingsName.cs new file mode 100644 index 000000000..6864b8cd6 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/SettingsName.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings +{ + [StructLayout(LayoutKind.Sequential, Size = 0x48)] + struct SettingsName + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AccountNotificationSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountNotificationSettings.cs new file mode 100644 index 000000000..a2cbad6a6 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountNotificationSettings.cs @@ -0,0 +1,15 @@ +using Ryujinx.Horizon.Sdk.Account; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct AccountNotificationSettings + { +#pragma warning disable CS0649 // Field is never assigned to + public Uid UserId; + public uint Flags; + public byte FriendPresenceOverlayPermission; + public byte FriendInvitationOverlayPermission; + public ushort Reserved; +#pragma warning restore CS0649 + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AccountOnlineStorageSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountOnlineStorageSettings.cs new file mode 100644 index 000000000..3ed77e52b --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountOnlineStorageSettings.cs @@ -0,0 +1,6 @@ +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct AccountOnlineStorageSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AccountSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountSettings.cs new file mode 100644 index 000000000..bd27ea0bf --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountSettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x4, Pack = 0x4)] + struct AccountSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AllowedSslHost.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AllowedSslHost.cs new file mode 100644 index 000000000..cb90daf18 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AllowedSslHost.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x100)] + struct AllowedSslHost + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AnalogStickUserCalibration.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AnalogStickUserCalibration.cs new file mode 100644 index 000000000..36023da9c --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AnalogStickUserCalibration.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x4)] + struct AnalogStickUserCalibration + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AppletLaunchFlag.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AppletLaunchFlag.cs new file mode 100644 index 000000000..00d6f4d06 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AppletLaunchFlag.cs @@ -0,0 +1,9 @@ +using System; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum AppletLaunchFlag : uint + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AudioVolume.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AudioVolume.cs new file mode 100644 index 000000000..d246bc2b9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AudioVolume.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x4)] + struct AudioVolume + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettings.cs new file mode 100644 index 000000000..00de6869c --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettings.cs @@ -0,0 +1,22 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x28, Pack = 0x4)] + struct BacklightSettings + { + // TODO: Determine field names. + public uint Unknown0x00; + public float Unknown0x04; + // 1st group + public float Unknown0x08; + public float Unknown0x0C; + public float Unknown0x10; + // 2nd group + public float Unknown0x14; + public float Unknown0x18; + public float Unknown0x1C; + public float Unknown0x20; + public float Unknown0x24; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettingsEx.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettingsEx.cs new file mode 100644 index 000000000..347afdfe3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettingsEx.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x2C, Pack = 0x4)] + struct BacklightSettingsEx + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/BlePairingSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/BlePairingSettings.cs new file mode 100644 index 000000000..d9b01f9ff --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/BlePairingSettings.cs @@ -0,0 +1,6 @@ +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct BlePairingSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/BluetoothDevicesSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/BluetoothDevicesSettings.cs new file mode 100644 index 000000000..ec5c97c5a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/BluetoothDevicesSettings.cs @@ -0,0 +1,29 @@ +using Ryujinx.Common.Memory; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct BluetoothDevicesSettings + { +#pragma warning disable CS0649 // Field is never assigned to + public Array6 BdAddr; + public Array32 DeviceName; + public Array3 ClassOfDevice; + public Array16 LinkKey; + public bool LinkKeyPresent; + public ushort Version; + public uint TrustedServices; + public ushort Vid; + public ushort Pid; + public byte SubClass; + public byte AttributeMask; + public ushort DescriptorLength; + public Array128 Descriptor; + public byte KeyType; + public byte DeviceType; + public ushort BrrSize; + public Array9 Brr; + public Array256 Reserved; + public Array43 Reserved2; +#pragma warning restore CS0649 + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigRegisteredSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigRegisteredSettings.cs new file mode 100644 index 000000000..8bd4924e9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigRegisteredSettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x5C8)] + struct ButtonConfigRegisteredSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigSettings.cs new file mode 100644 index 000000000..2f06e32e1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigSettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x5A8)] + struct ButtonConfigSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationBias.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationBias.cs new file mode 100644 index 000000000..c70d4ff28 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationBias.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 0x4)] + struct ConsoleSixAxisSensorAccelerationBias + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationGain.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationGain.cs new file mode 100644 index 000000000..0803beb87 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationGain.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x24, Pack = 0x4)] + struct ConsoleSixAxisSensorAccelerationGain + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularAcceleration.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularAcceleration.cs new file mode 100644 index 000000000..831e44bd5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularAcceleration.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x24, Pack = 0x4)] + struct ConsoleSixAxisSensorAngularAcceleration + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityBias.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityBias.cs new file mode 100644 index 000000000..83d1faa8d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityBias.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 0x4)] + struct ConsoleSixAxisSensorAngularVelocityBias + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityGain.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityGain.cs new file mode 100644 index 000000000..68e0c614a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityGain.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x24, Pack = 0x4)] + struct ConsoleSixAxisSensorAngularVelocityGain + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityTimeBias.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityTimeBias.cs new file mode 100644 index 000000000..47f3d951c --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityTimeBias.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 0x4)] + struct ConsoleSixAxisSensorAngularVelocityTimeBias + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/DataDeletionSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/DataDeletionSettings.cs new file mode 100644 index 000000000..a10a265d1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/DataDeletionSettings.cs @@ -0,0 +1,18 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum DataDeletionFlag : uint + { + AutomaticDeletionFlag = 1 << 0, + } + + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x4)] + struct DataDeletionSettings + { + public DataDeletionFlag Flags; + public uint UseCount; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/DeviceNickName.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/DeviceNickName.cs new file mode 100644 index 000000000..99c9f9817 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/DeviceNickName.cs @@ -0,0 +1,25 @@ +using Ryujinx.Common.Memory; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x80)] + struct DeviceNickName + { + public Array128 Value; + + public DeviceNickName(string value) + { + int bytesWritten = Encoding.ASCII.GetBytes(value, Value.AsSpan()); + if (bytesWritten < 128) + { + Value[bytesWritten] = 0; + } + else + { + Value[127] = 0; + } + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/Edid.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/Edid.cs new file mode 100644 index 000000000..3ff566854 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/Edid.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x200)] + struct Edid + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/EulaVersion.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/EulaVersion.cs new file mode 100644 index 000000000..65905b1ba --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/EulaVersion.cs @@ -0,0 +1,6 @@ +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct EulaVersion + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/FatalDirtyFlag.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/FatalDirtyFlag.cs new file mode 100644 index 000000000..6be941151 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/FatalDirtyFlag.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct FatalDirtyFlag + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersion.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersion.cs new file mode 100644 index 000000000..39825e010 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersion.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x100)] + struct FirmwareVersion + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersionDigest.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersionDigest.cs new file mode 100644 index 000000000..0027d7ef1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersionDigest.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x40, Pack = 0x1)] + struct FirmwareVersionDigest + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/HomeMenuScheme.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/HomeMenuScheme.cs new file mode 100644 index 000000000..cc7b317be --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/HomeMenuScheme.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x14, Pack = 0x1)] + struct HomeMenuScheme + { + public uint Main; + public uint Back; + public uint Sub; + public uint Bezel; + public uint Extra; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/HostFsMountPoint.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/HostFsMountPoint.cs new file mode 100644 index 000000000..1a66abac9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/HostFsMountPoint.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x100)] + struct HostFsMountPoint + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/InitialLaunchSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/InitialLaunchSettings.cs new file mode 100644 index 000000000..b3989de75 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/InitialLaunchSettings.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 0x8)] + struct InitialLaunchSettings + { + public uint Flags; + public uint Reserved; + public ulong TimeStamp1; + public ulong TimeStamp2; + public ulong TimeStamp3; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/NetworkSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/NetworkSettings.cs new file mode 100644 index 000000000..a0101b626 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/NetworkSettings.cs @@ -0,0 +1,6 @@ +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct NetworkSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/NotificationSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/NotificationSettings.cs new file mode 100644 index 000000000..2ce56c4df --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/NotificationSettings.cs @@ -0,0 +1,38 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum NotificationFlag : uint + { + RingtoneFlag = 1 << 0, + DownloadCompletionFlag = 1 << 1, + EnablesNews = 1 << 8, + IncomingLampFlag = 1 << 9, + } + + enum NotificationVolume : uint + { + Mute, + Low, + High, + } + + struct NotificationTime + { +#pragma warning disable CS0649 // Field is never assigned to + public uint Hour; + public uint Minute; +#pragma warning restore CS0649 + } + + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x4)] + struct NotificationSettings + { + public NotificationFlag Flag; + public NotificationVolume Volume; + public NotificationTime HeadTime; + public NotificationTime TailTime; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerLegacySettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerLegacySettings.cs new file mode 100644 index 000000000..845715df2 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerLegacySettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x29)] + struct NxControllerLegacySettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerSettings.cs new file mode 100644 index 000000000..c8f81cecb --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerSettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x42C)] + struct NxControllerSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/PtmFuelGaugeParameter.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/PtmFuelGaugeParameter.cs new file mode 100644 index 000000000..b843bcd64 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/PtmFuelGaugeParameter.cs @@ -0,0 +1,20 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x4)] + struct PtmFuelGaugeParameter + { + public ushort Rcomp0; + public ushort TempCo; + public ushort FullCap; + public ushort FullCapNom; + public ushort IavgEmpty; + public ushort QrTable00; + public ushort QrTable10; + public ushort QrTable20; + public ushort QrTable30; + public ushort Reserved; + public uint Cycles; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/RebootlessSystemUpdateVersion.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/RebootlessSystemUpdateVersion.cs new file mode 100644 index 000000000..b4e9b8b28 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/RebootlessSystemUpdateVersion.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x40, Pack = 0x4)] + struct RebootlessSystemUpdateVersion + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/SerialNumber.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/SerialNumber.cs new file mode 100644 index 000000000..22ddb85ce --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/SerialNumber.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x1)] + struct SerialNumber + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ServiceDiscoveryControlSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ServiceDiscoveryControlSettings.cs new file mode 100644 index 000000000..7c7b625a2 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ServiceDiscoveryControlSettings.cs @@ -0,0 +1,10 @@ +using System; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum ServiceDiscoveryControlSettings : uint + { + IsChangeEnvironmentIdentifierDisabled = 1 << 0, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/SleepSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/SleepSettings.cs new file mode 100644 index 000000000..7493c677c --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/SleepSettings.cs @@ -0,0 +1,40 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum SleepFlag : uint + { + SleepsWhilePlayingMedia = 1 << 0, + WakesAtPowerStateChange = 1 << 1, + } + + enum HandheldSleepPlan : uint + { + At1Min, + At3Min, + At5Min, + At10Min, + At30Min, + Never, + } + + enum ConsoleSleepPlan : uint + { + At1Hour, + At2Hour, + At3Hour, + At6Hour, + At12Hour, + Never, + } + + [StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 0x4)] + struct SleepSettings + { + public SleepFlag Flags; + public HandheldSleepPlan HandheldSleepPlan; + public ConsoleSleepPlan ConsoleSleepPlan; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/TelemetryDirtyFlag.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/TelemetryDirtyFlag.cs new file mode 100644 index 000000000..46ec2d767 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/TelemetryDirtyFlag.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct TelemetryDirtyFlag + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeId.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeId.cs new file mode 100644 index 000000000..886ec8721 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeId.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x80, Pack = 0x8)] + struct ThemeId + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeSettings.cs new file mode 100644 index 000000000..ac36bcd80 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeSettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x8)] + struct ThemeSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/TvSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/TvSettings.cs new file mode 100644 index 000000000..5ee0b85d9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/TvSettings.cs @@ -0,0 +1,59 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum TvFlag : uint + { + Allows4k = 1 << 0, + Allows3d = 1 << 1, + AllowsCec = 1 << 2, + PreventsScreenBurnIn = 1 << 3, + } + + enum TvResolution : uint + { + Auto, + At1080p, + At720p, + At480p, + } + + enum HdmiContentType : uint + { + None, + Graphics, + Cinema, + Photo, + Game, + } + + enum RgbRange : uint + { + Auto, + Full, + Limited, + } + + enum CmuMode : uint + { + None, + ColorInvert, + HighContrast, + GrayScale, + } + + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 0x4)] + struct TvSettings + { + public TvFlag Flags; + public TvResolution TvResolution; + public HdmiContentType HdmiContentType; + public RgbRange RgbRange; + public CmuMode CmuMode; + public float TvUnderscan; + public float TvGamma; + public float ContrastRatio; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs b/src/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs index d409be5b3..62c15baa6 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs @@ -10,5 +10,12 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif public Span OutPointerSizes; public Span Objects; public int ServerPointerSize; + public int CurrentInPointerId; + public int SendBufferIndex; + public int RecvBufferIndex; + public int ExchBufferIndex; + public int SendStaticIndex; + public int RecvListIndex; + public int OutPointerSizeIndex; } } diff --git a/src/Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs b/src/Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs index 038135ac8..7f5284648 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs @@ -2,6 +2,7 @@ using Ryujinx.Horizon.Sdk.Sf.Cmif; using Ryujinx.Horizon.Sdk.Sf.Hipc; using Ryujinx.Memory; using System; +using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -9,6 +10,11 @@ namespace Ryujinx.Horizon.Sdk.Sf { static class CommandSerialization { + public static ReadOnlySequence GetReadOnlySequence(PointerAndSize bufferRange) + { + return HorizonStatic.AddressSpace.GetReadOnlySequence(bufferRange.Address, checked((int)bufferRange.Size)); + } + public static ReadOnlySpan GetReadOnlySpan(PointerAndSize bufferRange) { return HorizonStatic.AddressSpace.GetSpan(bufferRange.Address, checked((int)bufferRange.Size)); diff --git a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs index 03ef6d3fc..4e9628947 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs @@ -11,5 +11,12 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc public ulong Address => _addressLow | (((ulong)_word2 << 4) & 0xf00000000UL) | (((ulong)_word2 << 34) & 0x7000000000UL); public ulong Size => _sizeLow | ((ulong)_word2 << 8) & 0xf00000000UL; public HipcBufferMode Mode => (HipcBufferMode)(_word2 & 3); + + public HipcBufferDescriptor(ulong address, ulong size, HipcBufferMode mode) + { + _sizeLow = (uint)size; + _addressLow = (uint)address; + _word2 = (uint)mode | ((uint)(address >> 34) & 0x1c) | ((uint)(size >> 32) << 24) | ((uint)(address >> 4) & 0xf0000000); + } } } diff --git a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs index 887c82eb8..73321a891 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs @@ -181,6 +181,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc } Span dataWords = Span.Empty; + Span dataWordsPadded = Span.Empty; if (meta.DataWordsCount != 0) { @@ -189,6 +190,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc int padding = (dataOffsetAligned - dataOffset) / sizeof(uint); dataWords = MemoryMarshal.Cast(data)[padding..meta.DataWordsCount]; + dataWordsPadded = MemoryMarshal.Cast(data)[..meta.DataWordsCount]; data = data[(meta.DataWordsCount * sizeof(uint))..]; } @@ -209,6 +211,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc ReceiveBuffers = receiveBuffers, ExchangeBuffers = exchangeBuffers, DataWords = dataWords, + DataWordsPadded = dataWordsPadded, ReceiveList = receiveList, CopyHandles = copyHandles, MoveHandles = moveHandles, diff --git a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs index 548f12e8b..0d45d756f 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs @@ -9,6 +9,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc public Span ReceiveBuffers; public Span ExchangeBuffers; public Span DataWords; + public Span DataWordsPadded; public Span ReceiveList; public Span CopyHandles; public Span MoveHandles; diff --git a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs index 9886e1cbf..570e3c802 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs @@ -3,6 +3,7 @@ using Ryujinx.Horizon.Sdk.OsTypes; using Ryujinx.Horizon.Sdk.Sf.Cmif; using Ryujinx.Horizon.Sdk.Sm; using System; +using System.Linq; namespace Ryujinx.Horizon.Sdk.Sf.Hipc { @@ -116,6 +117,18 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc while (WaitAndProcessRequestsImpl()) { } + + // Unlink pending sessions, dispose expects them to be already unlinked. + + ServerSession[] serverSessions = Enumerable.OfType(_multiWait.MultiWaits).ToArray(); + + foreach (ServerSession serverSession in serverSessions) + { + if (serverSession.IsLinked) + { + serverSession.UnlinkFromMultiWaitHolder(); + } + } } public void WaitAndProcessRequests() diff --git a/src/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs b/src/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs index bb9b37e28..dc34f791a 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs @@ -127,7 +127,7 @@ namespace Ryujinx.Horizon.Sdk.Sf return _bufferRanges[argIndex]; } - public Result ProcessBuffers(ref ServiceDispatchContext context, bool[] isBufferMapAlias, ServerMessageRuntimeMetadata runtimeMetadata) + public Result ProcessBuffers(ref ServiceDispatchContext context, scoped Span isBufferMapAlias, ServerMessageRuntimeMetadata runtimeMetadata) { bool mapAliasBuffersValid = true; @@ -206,7 +206,7 @@ namespace Ryujinx.Horizon.Sdk.Sf } else { - var data = MemoryMarshal.Cast(context.Request.Data.DataWords); + var data = MemoryMarshal.Cast(context.Request.Data.DataWordsPadded); var recvPointerSizes = MemoryMarshal.Cast(data[runtimeMetadata.UnfixedOutPointerSizeOffset..]); size = recvPointerSizes[unfixedRecvPointerIndex++]; @@ -246,7 +246,7 @@ namespace Ryujinx.Horizon.Sdk.Sf return mode == HipcBufferMode.Normal; } - public void SetOutBuffers(HipcMessageData response, bool[] isBufferMapAlias) + public void SetOutBuffers(HipcMessageData response, ReadOnlySpan isBufferMapAlias) { int recvPointerIndex = 0; diff --git a/src/Ryujinx.Horizon/Sdk/Ts/DeviceCode.cs b/src/Ryujinx.Horizon/Sdk/Ts/DeviceCode.cs new file mode 100644 index 000000000..4fce4238e --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Ts/DeviceCode.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Horizon.Sdk.Ts +{ + enum DeviceCode : uint + { + Internal = 0x41000001, + External = 0x41000002, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Ts/IMeasurementServer.cs b/src/Ryujinx.Horizon/Sdk/Ts/IMeasurementServer.cs new file mode 100644 index 000000000..ba9c2a748 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Ts/IMeasurementServer.cs @@ -0,0 +1,14 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Ts +{ + interface IMeasurementServer : IServiceObject + { + Result GetTemperatureRange(out int minimumTemperature, out int maximumTemperature, Location location); + Result GetTemperature(out int temperature, Location location); + Result SetMeasurementMode(Location location, byte measurementMode); + Result GetTemperatureMilliC(out int temperatureMilliC, Location location); + Result OpenSession(out ISession session, DeviceCode deviceCode); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Ts/ISession.cs b/src/Ryujinx.Horizon/Sdk/Ts/ISession.cs new file mode 100644 index 000000000..23c0d94f6 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Ts/ISession.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Ts +{ + interface ISession : IServiceObject + { + Result GetTemperatureRange(out int minimumTemperature, out int maximumTemperature); + Result GetTemperature(out int temperature); + Result SetMeasurementMode(byte measurementMode); + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/Types/Location.cs b/src/Ryujinx.Horizon/Sdk/Ts/Location.cs similarity index 61% rename from src/Ryujinx.HLE/HOS/Services/Ptm/Ts/Types/Location.cs rename to src/Ryujinx.Horizon/Sdk/Ts/Location.cs index 409188a97..177b0ee88 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/Types/Location.cs +++ b/src/Ryujinx.Horizon/Sdk/Ts/Location.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Ptm.Ts.Types +namespace Ryujinx.Horizon.Sdk.Ts { enum Location : byte { diff --git a/src/Ryujinx.Horizon/ServiceTable.cs b/src/Ryujinx.Horizon/ServiceTable.cs index c79328a96..28c43a716 100644 --- a/src/Ryujinx.Horizon/ServiceTable.cs +++ b/src/Ryujinx.Horizon/ServiceTable.cs @@ -1,4 +1,7 @@ +using Ryujinx.Horizon.Arp; +using Ryujinx.Horizon.Audio; using Ryujinx.Horizon.Bcat; +using Ryujinx.Horizon.Friends; using Ryujinx.Horizon.Hshl; using Ryujinx.Horizon.Ins; using Ryujinx.Horizon.Lbl; @@ -8,6 +11,8 @@ using Ryujinx.Horizon.Ngc; using Ryujinx.Horizon.Ovln; using Ryujinx.Horizon.Prepo; using Ryujinx.Horizon.Psc; +using Ryujinx.Horizon.Ptm; +using Ryujinx.Horizon.Sdk.Arp; using Ryujinx.Horizon.Srepo; using Ryujinx.Horizon.Usb; using Ryujinx.Horizon.Wlan; @@ -23,6 +28,9 @@ namespace Ryujinx.Horizon private readonly ManualResetEvent _servicesReadyEvent = new(false); + public IReader ArpReader { get; internal set; } + public IWriter ArpWriter { get; internal set; } + public IEnumerable GetServices(HorizonOptions options) { List entries = new(); @@ -32,8 +40,12 @@ namespace Ryujinx.Horizon entries.Add(new ServiceEntry(T.Main, this, options)); } + RegisterService(); + RegisterService(); RegisterService(); + RegisterService(); RegisterService(); + RegisterService(); // TODO: Merge with audio once we can start multiple threads. RegisterService(); RegisterService(); RegisterService(); @@ -43,6 +55,7 @@ namespace Ryujinx.Horizon RegisterService(); RegisterService(); RegisterService(); + RegisterService(); RegisterService(); RegisterService(); diff --git a/src/Ryujinx.Horizon/Srepo/SrepoIpcServer.cs b/src/Ryujinx.Horizon/Srepo/SrepoIpcServer.cs index 2060782cc..44d008224 100644 --- a/src/Ryujinx.Horizon/Srepo/SrepoIpcServer.cs +++ b/src/Ryujinx.Horizon/Srepo/SrepoIpcServer.cs @@ -41,6 +41,7 @@ namespace Ryujinx.Horizon.Srepo public void Shutdown() { _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/Usb/UsbIpcServer.cs b/src/Ryujinx.Horizon/Usb/UsbIpcServer.cs index 38eeed496..a04b81f97 100644 --- a/src/Ryujinx.Horizon/Usb/UsbIpcServer.cs +++ b/src/Ryujinx.Horizon/Usb/UsbIpcServer.cs @@ -66,6 +66,7 @@ namespace Ryujinx.Horizon.Usb public void Shutdown() { _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Horizon/Wlan/WlanIpcServer.cs b/src/Ryujinx.Horizon/Wlan/WlanIpcServer.cs index c7b336231..776b9a7cb 100644 --- a/src/Ryujinx.Horizon/Wlan/WlanIpcServer.cs +++ b/src/Ryujinx.Horizon/Wlan/WlanIpcServer.cs @@ -54,6 +54,7 @@ namespace Ryujinx.Horizon.Wlan public void Shutdown() { _serverManager.Dispose(); + _sm.Dispose(); } } } diff --git a/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs b/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs index 0e3a13011..c741493c1 100644 --- a/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs +++ b/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs @@ -9,8 +9,18 @@ namespace Ryujinx.Input.SDL2 { private readonly Dictionary _gamepadsInstanceIdsMapping; private readonly List _gamepadsIds; + private readonly object _lock = new object(); - public ReadOnlySpan GamepadsIds => _gamepadsIds.ToArray(); + public ReadOnlySpan GamepadsIds + { + get + { + lock (_lock) + { + return _gamepadsIds.ToArray(); + } + } + } public string DriverName => "SDL2"; @@ -35,28 +45,39 @@ namespace Ryujinx.Input.SDL2 } } - private static string GenerateGamepadId(int joystickIndex) + private string GenerateGamepadId(int joystickIndex) { Guid guid = SDL_JoystickGetDeviceGUID(joystickIndex); + // Add a unique identifier to the start of the GUID in case of duplicates. + if (guid == Guid.Empty) { return null; } - return joystickIndex + "-" + guid; - } + string id; - private static int GetJoystickIndexByGamepadId(string id) - { - string[] data = id.Split("-"); - - if (data.Length != 6 || !int.TryParse(data[0], out int joystickIndex)) + lock (_lock) { - return -1; + int guidIndex = 0; + id = guidIndex + "-" + guid; + + while (_gamepadsIds.Contains(id)) + { + id = (++guidIndex) + "-" + guid; + } } - return joystickIndex; + return id; + } + + private int GetJoystickIndexByGamepadId(string id) + { + lock (_lock) + { + return _gamepadsIds.IndexOf(id); + } } private void HandleJoyStickDisconnected(int joystickInstanceId) @@ -64,7 +85,11 @@ namespace Ryujinx.Input.SDL2 if (_gamepadsInstanceIdsMapping.TryGetValue(joystickInstanceId, out string id)) { _gamepadsInstanceIdsMapping.Remove(joystickInstanceId); - _gamepadsIds.Remove(id); + + lock (_lock) + { + _gamepadsIds.Remove(id); + } OnGamepadDisconnected?.Invoke(id); } @@ -74,6 +99,13 @@ namespace Ryujinx.Input.SDL2 { if (SDL_IsGameController(joystickDeviceId) == SDL_bool.SDL_TRUE) { + if (_gamepadsInstanceIdsMapping.ContainsKey(joystickInstanceId)) + { + // Sometimes a JoyStick connected event fires after the app starts even though it was connected before + // so it is rejected to avoid doubling the entries. + return; + } + string id = GenerateGamepadId(joystickDeviceId); if (id == null) @@ -81,16 +113,12 @@ namespace Ryujinx.Input.SDL2 return; } - // Sometimes a JoyStick connected event fires after the app starts even though it was connected before - // so it is rejected to avoid doubling the entries. - if (_gamepadsIds.Contains(id)) - { - return; - } - if (_gamepadsInstanceIdsMapping.TryAdd(joystickInstanceId, id)) { - _gamepadsIds.Add(id); + lock (_lock) + { + _gamepadsIds.Add(id); + } OnGamepadConnected?.Invoke(id); } @@ -110,7 +138,10 @@ namespace Ryujinx.Input.SDL2 OnGamepadDisconnected?.Invoke(id); } - _gamepadsIds.Clear(); + lock (_lock) + { + _gamepadsIds.Clear(); + } SDL2Driver.Instance.Dispose(); } @@ -131,11 +162,6 @@ namespace Ryujinx.Input.SDL2 return null; } - if (id != GenerateGamepadId(joystickIndex)) - { - return null; - } - IntPtr gamepadHandle = SDL_GameControllerOpen(joystickIndex); if (gamepadHandle == IntPtr.Zero) diff --git a/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs b/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs index 388ebcc07..80fed2b82 100644 --- a/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs +++ b/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs @@ -49,9 +49,9 @@ namespace Ryujinx.Input.Assigner CollectButtonStats(); } - public bool HasAnyButtonPressed() + public bool IsAnyButtonPressed() { - return _detector.HasAnyButtonPressed(); + return _detector.IsAnyButtonPressed(); } public bool ShouldCancel() @@ -59,16 +59,11 @@ namespace Ryujinx.Input.Assigner return _gamepad == null || !_gamepad.IsConnected; } - public string GetPressedButton() + public Button? GetPressedButton() { IEnumerable pressedButtons = _detector.GetPressedButtons(); - if (pressedButtons.Any()) - { - return !_forStick ? pressedButtons.First().ToString() : ((StickInputId)pressedButtons.First()).ToString(); - } - - return ""; + return !_forStick ? new(pressedButtons.FirstOrDefault()) : new((StickInputId)pressedButtons.FirstOrDefault()); } private void CollectButtonStats() @@ -123,7 +118,7 @@ namespace Ryujinx.Input.Assigner _stats = new Dictionary(); } - public bool HasAnyButtonPressed() + public bool IsAnyButtonPressed() { return _stats.Values.Any(CheckButtonPressed); } diff --git a/src/Ryujinx.Input/Assigner/IButtonAssigner.cs b/src/Ryujinx.Input/Assigner/IButtonAssigner.cs index 76a9fece4..688fbddb4 100644 --- a/src/Ryujinx.Input/Assigner/IButtonAssigner.cs +++ b/src/Ryujinx.Input/Assigner/IButtonAssigner.cs @@ -19,7 +19,7 @@ namespace Ryujinx.Input.Assigner /// Check if a button was pressed. /// /// True if a button was pressed - bool HasAnyButtonPressed(); + bool IsAnyButtonPressed(); /// /// Indicate if the user of this API should cancel operations. This is triggered for example when a gamepad get disconnected or when a user cancel assignation operations. @@ -31,6 +31,6 @@ namespace Ryujinx.Input.Assigner /// Get the pressed button that was read in by the button assigner. /// /// The pressed button that was read - string GetPressedButton(); + Button? GetPressedButton(); } } diff --git a/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs b/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs index e52ef4a2c..3c011a63b 100644 --- a/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs +++ b/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs @@ -21,9 +21,9 @@ namespace Ryujinx.Input.Assigner _keyboardState = _keyboard.GetKeyboardStateSnapshot(); } - public bool HasAnyButtonPressed() + public bool IsAnyButtonPressed() { - return GetPressedButton().Length != 0; + return GetPressedButton() is not null; } public bool ShouldCancel() @@ -31,20 +31,20 @@ namespace Ryujinx.Input.Assigner return _keyboardState.IsPressed(Key.Escape); } - public string GetPressedButton() + public Button? GetPressedButton() { - string keyPressed = ""; + Button? keyPressed = null; for (Key key = Key.Unknown; key < Key.Count; key++) { if (_keyboardState.IsPressed(key)) { - keyPressed = key.ToString(); + keyPressed = new(key); break; } } - return !ShouldCancel() ? keyPressed : ""; + return !ShouldCancel() ? keyPressed : null; } } } diff --git a/src/Ryujinx.Input/Button.cs b/src/Ryujinx.Input/Button.cs new file mode 100644 index 000000000..4289901ce --- /dev/null +++ b/src/Ryujinx.Input/Button.cs @@ -0,0 +1,33 @@ +using System; + +namespace Ryujinx.Input +{ + public readonly struct Button + { + public readonly ButtonType Type; + private readonly uint _rawValue; + + public Button(Key key) + { + Type = ButtonType.Key; + _rawValue = (uint)key; + } + + public Button(GamepadButtonInputId gamepad) + { + Type = ButtonType.GamepadButtonInputId; + _rawValue = (uint)gamepad; + } + + public Button(StickInputId stick) + { + Type = ButtonType.StickId; + _rawValue = (uint)stick; + } + + public T AsHidType() where T : Enum + { + return (T)Enum.ToObject(typeof(T), _rawValue); + } + } +} diff --git a/src/Ryujinx.Input/ButtonType.cs b/src/Ryujinx.Input/ButtonType.cs new file mode 100644 index 000000000..25ef5eea8 --- /dev/null +++ b/src/Ryujinx.Input/ButtonType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Input +{ + public enum ButtonType + { + Key, + GamepadButtonInputId, + StickId, + } +} diff --git a/src/Ryujinx.Input/HLE/NpadController.cs b/src/Ryujinx.Input/HLE/NpadController.cs index f00db94e2..380745283 100644 --- a/src/Ryujinx.Input/HLE/NpadController.cs +++ b/src/Ryujinx.Input/HLE/NpadController.cs @@ -203,8 +203,6 @@ namespace Ryujinx.Input.HLE new(Key.NumLock, 10), }; - private bool _isValid; - private MotionInput _leftMotionInput; private MotionInput _rightMotionInput; @@ -222,7 +220,6 @@ namespace Ryujinx.Input.HLE { State = default; Id = null; - _isValid = false; _cemuHookClient = cemuHookClient; } @@ -234,20 +231,19 @@ namespace Ryujinx.Input.HLE Id = config.Id; _gamepad = GamepadDriver.GetGamepad(Id); - _isValid = _gamepad != null; UpdateUserConfiguration(config); - return _isValid; + return _gamepad != null; } public void UpdateUserConfiguration(InputConfig config) { if (config is StandardControllerInputConfig controllerConfig) { - bool needsMotionInputUpdate = _config == null || (_config is StandardControllerInputConfig oldControllerConfig && - (oldControllerConfig.Motion.EnableMotion != controllerConfig.Motion.EnableMotion) && - (oldControllerConfig.Motion.MotionBackend != controllerConfig.Motion.MotionBackend)); + bool needsMotionInputUpdate = _config is not StandardControllerInputConfig oldControllerConfig || + ((oldControllerConfig.Motion.EnableMotion != controllerConfig.Motion.EnableMotion) && + (oldControllerConfig.Motion.MotionBackend != controllerConfig.Motion.MotionBackend)); if (needsMotionInputUpdate) { @@ -262,10 +258,7 @@ namespace Ryujinx.Input.HLE _config = config; - if (_isValid) - { - _gamepad.SetConfiguration(config); - } + _gamepad?.SetConfiguration(config); } private void UpdateMotionInput(MotionConfigController motionConfig) @@ -282,18 +275,21 @@ namespace Ryujinx.Input.HLE public void Update() { - if (_isValid && GamepadDriver != null) + // _gamepad may be altered by other threads + var gamepad = _gamepad; + + if (gamepad != null && GamepadDriver != null) { - State = _gamepad.GetMappedStateSnapshot(); + State = gamepad.GetMappedStateSnapshot(); if (_config is StandardControllerInputConfig controllerConfig && controllerConfig.Motion.EnableMotion) { if (controllerConfig.Motion.MotionBackend == MotionInputBackendType.GamepadDriver) { - if (_gamepad.Features.HasFlag(GamepadFeaturesFlag.Motion)) + if (gamepad.Features.HasFlag(GamepadFeaturesFlag.Motion)) { - Vector3 accelerometer = _gamepad.GetMotionData(MotionInputId.Accelerometer); - Vector3 gyroscope = _gamepad.GetMotionData(MotionInputId.Gyroscope); + Vector3 accelerometer = gamepad.GetMotionData(MotionInputId.Accelerometer); + Vector3 gyroscope = gamepad.GetMotionData(MotionInputId.Gyroscope); accelerometer = new Vector3(accelerometer.X, -accelerometer.Z, accelerometer.Y); gyroscope = new Vector3(gyroscope.X, -gyroscope.Z, gyroscope.Y); @@ -491,38 +487,35 @@ namespace Ryujinx.Input.HLE return value; } - public KeyboardInput? GetHLEKeyboardInput() + public static KeyboardInput GetHLEKeyboardInput(IGamepadDriver KeyboardDriver) { - if (_gamepad is IKeyboard keyboard) + var keyboard = KeyboardDriver.GetGamepad("0") as IKeyboard; + + KeyboardStateSnapshot keyboardState = keyboard.GetKeyboardStateSnapshot(); + + KeyboardInput hidKeyboard = new() { - KeyboardStateSnapshot keyboardState = keyboard.GetKeyboardStateSnapshot(); + Modifier = 0, + Keys = new ulong[0x4], + }; - KeyboardInput hidKeyboard = new() - { - Modifier = 0, - Keys = new ulong[0x4], - }; + foreach (HLEKeyboardMappingEntry entry in _keyMapping) + { + ulong value = keyboardState.IsPressed(entry.TargetKey) ? 1UL : 0UL; - foreach (HLEKeyboardMappingEntry entry in _keyMapping) - { - ulong value = keyboardState.IsPressed(entry.TargetKey) ? 1UL : 0UL; - - hidKeyboard.Keys[entry.Target / 0x40] |= (value << (entry.Target % 0x40)); - } - - foreach (HLEKeyboardMappingEntry entry in _keyModifierMapping) - { - int value = keyboardState.IsPressed(entry.TargetKey) ? 1 : 0; - - hidKeyboard.Modifier |= value << entry.Target; - } - - return hidKeyboard; + hidKeyboard.Keys[entry.Target / 0x40] |= (value << (entry.Target % 0x40)); } - return null; - } + foreach (HLEKeyboardMappingEntry entry in _keyModifierMapping) + { + int value = keyboardState.IsPressed(entry.TargetKey) ? 1 : 0; + hidKeyboard.Modifier |= value << entry.Target; + } + + return hidKeyboard; + + } protected virtual void Dispose(bool disposing) { diff --git a/src/Ryujinx.Input/HLE/NpadManager.cs b/src/Ryujinx.Input/HLE/NpadManager.cs index 25887748f..1dc87358d 100644 --- a/src/Ryujinx.Input/HLE/NpadManager.cs +++ b/src/Ryujinx.Input/HLE/NpadManager.cs @@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Hid; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Runtime.CompilerServices; using CemuHookClient = Ryujinx.Input.Motion.CemuHook.Client; using ControllerType = Ryujinx.Common.Configuration.Hid.ControllerType; @@ -69,7 +70,20 @@ namespace Ryujinx.Input.HLE private void HandleOnGamepadDisconnected(string obj) { // Force input reload - ReloadConfiguration(_inputConfig, _enableKeyboard, _enableMouse); + lock (_lock) + { + // Forcibly disconnect any controllers with this ID. + for (int i = 0; i < _controllers.Length; i++) + { + if (_controllers[i]?.Id == obj) + { + _controllers[i]?.Dispose(); + _controllers[i] = null; + } + } + + ReloadConfiguration(_inputConfig, _enableKeyboard, _enableMouse); + } } private void HandleOnGamepadConnected(string id) @@ -106,31 +120,48 @@ namespace Ryujinx.Input.HLE { lock (_lock) { - for (int i = 0; i < _controllers.Length; i++) - { - _controllers[i]?.Dispose(); - _controllers[i] = null; - } + NpadController[] oldControllers = _controllers.ToArray(); List validInputs = new(); foreach (InputConfig inputConfigEntry in inputConfig) { - NpadController controller = new(_cemuHookClient); + NpadController controller; + int index = (int)inputConfigEntry.PlayerIndex; + + if (oldControllers[index] != null) + { + // Try reuse the existing controller. + controller = oldControllers[index]; + oldControllers[index] = null; + } + else + { + controller = new(_cemuHookClient); + } bool isValid = DriverConfigurationUpdate(ref controller, inputConfigEntry); if (!isValid) { + _controllers[index] = null; controller.Dispose(); } else { - _controllers[(int)inputConfigEntry.PlayerIndex] = controller; + _controllers[index] = controller; validInputs.Add(inputConfigEntry); } } + for (int i = 0; i < oldControllers.Length; i++) + { + // Disconnect any controllers that weren't reused by the new configuration. + + oldControllers[i]?.Dispose(); + oldControllers[i] = null; + } + _inputConfig = inputConfig; _enableKeyboard = enableKeyboard; _enableMouse = enableMouse; @@ -143,6 +174,11 @@ namespace Ryujinx.Input.HLE { lock (_lock) { + foreach (InputConfig inputConfig in _inputConfig) + { + _controllers[(int)inputConfig.PlayerIndex]?.GamepadDriver?.Clear(); + } + _blockInputUpdates = false; } } @@ -200,11 +236,6 @@ namespace Ryujinx.Input.HLE var altMotionState = isJoyconPair ? controller.GetHLEMotionState(true) : default; motionState = (controller.GetHLEMotionState(), altMotionState); - - if (_enableKeyboard) - { - hleKeyboardInput = controller.GetHLEKeyboardInput(); - } } else { @@ -226,6 +257,11 @@ namespace Ryujinx.Input.HLE } } + if (!_blockInputUpdates && _enableKeyboard) + { + hleKeyboardInput = NpadController.GetHLEKeyboardInput(_keyboardDriver); + } + _device.Hid.Npads.Update(hleInputStates); _device.Hid.Npads.UpdateSixAxis(hleMotionStates); diff --git a/src/Ryujinx.Input/IGamepadDriver.cs b/src/Ryujinx.Input/IGamepadDriver.cs index 67b01c26c..625c3e694 100644 --- a/src/Ryujinx.Input/IGamepadDriver.cs +++ b/src/Ryujinx.Input/IGamepadDriver.cs @@ -33,5 +33,11 @@ namespace Ryujinx.Input /// The unique id of the gamepad /// An instance of associated to the gamepad id given or null if not found IGamepad GetGamepad(string id); + + /// + /// Clear the internal state of the driver. + /// + /// Does nothing by default. + void Clear() { } } } diff --git a/src/Ryujinx.Memory/AddressSpaceManager.cs b/src/Ryujinx.Memory/AddressSpaceManager.cs index 05447ae39..807c5c0f4 100644 --- a/src/Ryujinx.Memory/AddressSpaceManager.cs +++ b/src/Ryujinx.Memory/AddressSpaceManager.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; namespace Ryujinx.Memory { @@ -11,25 +10,21 @@ namespace Ryujinx.Memory /// Represents a address space manager. /// Supports virtual memory region mapping, address translation and read/write access to mapped regions. /// - public sealed class AddressSpaceManager : IVirtualMemoryManager, IWritableBlock + public sealed class AddressSpaceManager : VirtualMemoryManagerBase, IVirtualMemoryManager { - public const int PageBits = PageTable.PageBits; - public const int PageSize = PageTable.PageSize; - public const int PageMask = PageTable.PageMask; - /// - public bool Supports4KBPages => true; + public bool UsesPrivateAllocations => false; /// /// Address space width in bits. /// public int AddressSpaceBits { get; } - private readonly ulong _addressSpaceSize; - private readonly MemoryBlock _backingMemory; private readonly PageTable _pageTable; + protected override ulong AddressSpaceSize { get; } + /// /// Creates a new instance of the memory manager. /// @@ -47,7 +42,7 @@ namespace Ryujinx.Memory } AddressSpaceBits = asBits; - _addressSpaceSize = asSize; + AddressSpaceSize = asSize; _backingMemory = backingMemory; _pageTable = new PageTable(); } @@ -67,8 +62,7 @@ namespace Ryujinx.Memory } } - /// - public void MapForeign(ulong va, nuint hostPointer, ulong size) + public override void MapForeign(ulong va, nuint hostPointer, ulong size) { AssertValidAddressAndSize(va, size); @@ -96,112 +90,6 @@ namespace Ryujinx.Memory } } - /// - public T Read(ulong va) where T : unmanaged - { - return MemoryMarshal.Cast(GetSpan(va, Unsafe.SizeOf()))[0]; - } - - /// - public void Read(ulong va, Span data) - { - ReadImpl(va, data); - } - - /// - public void Write(ulong va, T value) where T : unmanaged - { - Write(va, MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref value, 1))); - } - - /// - public void Write(ulong va, ReadOnlySpan data) - { - if (data.Length == 0) - { - return; - } - - AssertValidAddressAndSize(va, (ulong)data.Length); - - if (IsContiguousAndMapped(va, data.Length)) - { - data.CopyTo(GetHostSpanContiguous(va, data.Length)); - } - else - { - int offset = 0, size; - - if ((va & PageMask) != 0) - { - size = Math.Min(data.Length, PageSize - (int)(va & PageMask)); - - data[..size].CopyTo(GetHostSpanContiguous(va, size)); - - offset += size; - } - - for (; offset < data.Length; offset += size) - { - size = Math.Min(data.Length - offset, PageSize); - - data.Slice(offset, size).CopyTo(GetHostSpanContiguous(va + (ulong)offset, size)); - } - } - } - - /// - public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan data) - { - Write(va, data); - - return true; - } - - /// - public ReadOnlySpan GetSpan(ulong va, int size, bool tracked = false) - { - if (size == 0) - { - return ReadOnlySpan.Empty; - } - - if (IsContiguousAndMapped(va, size)) - { - return GetHostSpanContiguous(va, size); - } - else - { - Span data = new byte[size]; - - ReadImpl(va, data); - - return data; - } - } - - /// - public unsafe WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) - { - if (size == 0) - { - return new WritableRegion(null, va, Memory.Empty); - } - - if (IsContiguousAndMapped(va, size)) - { - return new WritableRegion(null, va, new NativeMemoryManager((byte*)GetHostAddress(va), size).Memory); - } - else - { - Memory memory = new byte[size]; - - GetSpan(va, size).CopyTo(memory.Span); - - return new WritableRegion(this, va, memory); - } - } - /// public unsafe ref T GetRef(ulong va) where T : unmanaged { @@ -213,50 +101,6 @@ namespace Ryujinx.Memory return ref *(T*)GetHostAddress(va); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetPagesCount(ulong va, uint size, out ulong startVa) - { - // WARNING: Always check if ulong does not overflow during the operations. - startVa = va & ~(ulong)PageMask; - ulong vaSpan = (va - startVa + size + PageMask) & ~(ulong)PageMask; - - return (int)(vaSpan / PageSize); - } - - private static void ThrowMemoryNotContiguous() => throw new MemoryNotContiguousException(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsContiguousAndMapped(ulong va, int size) => IsContiguous(va, size) && IsMapped(va); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsContiguous(ulong va, int size) - { - if (!ValidateAddress(va) || !ValidateAddressAndSize(va, (ulong)size)) - { - return false; - } - - int pages = GetPagesCount(va, (uint)size, out va); - - for (int page = 0; page < pages - 1; page++) - { - if (!ValidateAddress(va + PageSize)) - { - return false; - } - - if (GetHostAddress(va) + PageSize != GetHostAddress(va + PageSize)) - { - return false; - } - - va += PageSize; - } - - return true; - } - /// public IEnumerable GetHostRegions(ulong va, ulong size) { @@ -314,7 +158,7 @@ namespace Ryujinx.Memory return null; } - int pages = GetPagesCount(va, (uint)size, out va); + int pages = GetPagesCount(va, size, out va); var regions = new List(); @@ -346,37 +190,8 @@ namespace Ryujinx.Memory return regions; } - private void ReadImpl(ulong va, Span data) - { - if (data.Length == 0) - { - return; - } - - AssertValidAddressAndSize(va, (ulong)data.Length); - - int offset = 0, size; - - if ((va & PageMask) != 0) - { - size = Math.Min(data.Length, PageSize - (int)(va & PageMask)); - - GetHostSpanContiguous(va, size).CopyTo(data[..size]); - - offset += size; - } - - for (; offset < data.Length; offset += size) - { - size = Math.Min(data.Length - offset, PageSize); - - GetHostSpanContiguous(va + (ulong)offset, size).CopyTo(data.Slice(offset, size)); - } - } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsMapped(ulong va) + public override bool IsMapped(ulong va) { if (!ValidateAddress(va)) { @@ -389,7 +204,7 @@ namespace Ryujinx.Memory /// public bool IsRangeMapped(ulong va, ulong size) { - if (size == 0UL) + if (size == 0) { return true; } @@ -414,42 +229,6 @@ namespace Ryujinx.Memory return true; } - private bool ValidateAddress(ulong va) - { - return va < _addressSpaceSize; - } - - /// - /// Checks if the combination of virtual address and size is part of the addressable space. - /// - /// Virtual address of the range - /// Size of the range in bytes - /// True if the combination of virtual address and size is part of the addressable space - private bool ValidateAddressAndSize(ulong va, ulong size) - { - ulong endVa = va + size; - return endVa >= va && endVa >= size && endVa <= _addressSpaceSize; - } - - /// - /// Ensures the combination of virtual address and size is part of the addressable space. - /// - /// Virtual address of the range - /// Size of the range in bytes - /// Throw when the memory region specified outside the addressable space - private void AssertValidAddressAndSize(ulong va, ulong size) - { - if (!ValidateAddressAndSize(va, size)) - { - throw new InvalidMemoryRegionException($"va=0x{va:X16}, size=0x{size:X16}"); - } - } - - private unsafe Span GetHostSpanContiguous(ulong va, int size) - { - return new Span((void*)GetHostAddress(va), size); - } - private nuint GetHostAddress(ulong va) { return _pageTable.Read(va) + (nuint)(va & PageMask); @@ -461,15 +240,21 @@ namespace Ryujinx.Memory } /// - public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection) + public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection, bool guest = false) { throw new NotImplementedException(); } - /// - public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) - { - // Only the ARM Memory Manager has tracking for now. - } + protected unsafe override Memory GetPhysicalAddressMemory(nuint pa, int size) + => new NativeMemoryManager((byte*)pa, size).Memory; + + protected override unsafe Span GetPhysicalAddressSpan(nuint pa, int size) + => new Span((void*)pa, size); + + protected override nuint TranslateVirtualAddressChecked(ulong va) + => GetHostAddress(va); + + protected override nuint TranslateVirtualAddressUnchecked(ulong va) + => GetHostAddress(va); } } diff --git a/src/Ryujinx.Memory/BytesReadOnlySequenceSegment.cs b/src/Ryujinx.Memory/BytesReadOnlySequenceSegment.cs new file mode 100644 index 000000000..5fe8d936c --- /dev/null +++ b/src/Ryujinx.Memory/BytesReadOnlySequenceSegment.cs @@ -0,0 +1,60 @@ +using System; +using System.Buffers; +using System.Runtime.InteropServices; + +namespace Ryujinx.Memory +{ + /// + /// A concrete implementation of , + /// with methods to help build a full sequence. + /// + public sealed class BytesReadOnlySequenceSegment : ReadOnlySequenceSegment + { + public BytesReadOnlySequenceSegment(Memory memory) => Memory = memory; + + public BytesReadOnlySequenceSegment Append(Memory memory) + { + var nextSegment = new BytesReadOnlySequenceSegment(memory) + { + RunningIndex = RunningIndex + Memory.Length + }; + + Next = nextSegment; + + return nextSegment; + } + + /// + /// Attempts to determine if the current and are contiguous. + /// Only works if both were created by a . + /// + /// The segment to check if continuous with the current one + /// The starting address of the contiguous segment + /// The size of the contiguous segment + /// True if the segments are contiguous, otherwise false + public unsafe bool IsContiguousWith(Memory other, out nuint contiguousStart, out int contiguousSize) + { + if (MemoryMarshal.TryGetMemoryManager>(Memory, out var thisMemoryManager) && + MemoryMarshal.TryGetMemoryManager>(other, out var otherMemoryManager) && + thisMemoryManager.Pointer + thisMemoryManager.Length == otherMemoryManager.Pointer) + { + contiguousStart = (nuint)thisMemoryManager.Pointer; + contiguousSize = thisMemoryManager.Length + otherMemoryManager.Length; + return true; + } + else + { + contiguousStart = 0; + contiguousSize = 0; + return false; + } + } + + /// + /// Replaces the current value with the one provided. + /// + /// The new segment to hold in this + public void Replace(Memory memory) + => Memory = memory; + } +} diff --git a/src/Ryujinx.Memory/IVirtualMemoryManager.cs b/src/Ryujinx.Memory/IVirtualMemoryManager.cs index 9cf3663cf..102cedc94 100644 --- a/src/Ryujinx.Memory/IVirtualMemoryManager.cs +++ b/src/Ryujinx.Memory/IVirtualMemoryManager.cs @@ -8,10 +8,10 @@ namespace Ryujinx.Memory public interface IVirtualMemoryManager { /// - /// Indicates whenever the memory manager supports aliasing pages at 4KB granularity. + /// Indicates whether the memory manager creates private allocations when the flag is set on map. /// - /// True if 4KB pages are supported by the memory manager, false otherwise - bool Supports4KBPages { get; } + /// True if private mappings might be used, false otherwise + bool UsesPrivateAllocations { get; } /// /// Maps a virtual memory range into a physical memory range. @@ -124,6 +124,16 @@ namespace Ryujinx.Memory } } + /// + /// Gets a read-only sequence of read-only memory blocks from CPU mapped memory. + /// + /// Virtual address of the data + /// Size of the data + /// True if read tracking is triggered on the memory + /// A read-only sequence of read-only memory of the data + /// Throw for unhandled invalid or unmapped memory accesses + ReadOnlySequence GetReadOnlySequence(ulong va, int size, bool tracked = false); + /// /// Gets a read-only span of data from CPU mapped memory. /// @@ -214,6 +224,7 @@ namespace Ryujinx.Memory /// Virtual address base /// Size of the region to protect /// Memory protection to set - void TrackingReprotect(ulong va, ulong size, MemoryPermission protection); + /// True if the protection is for guest access, false otherwise + void TrackingReprotect(ulong va, ulong size, MemoryPermission protection, bool guest); } } diff --git a/src/Ryujinx.Memory/IWritableBlock.cs b/src/Ryujinx.Memory/IWritableBlock.cs index 0858e0c96..78ae2479d 100644 --- a/src/Ryujinx.Memory/IWritableBlock.cs +++ b/src/Ryujinx.Memory/IWritableBlock.cs @@ -1,9 +1,25 @@ using System; +using System.Buffers; namespace Ryujinx.Memory { public interface IWritableBlock { + /// + /// Writes data to CPU mapped memory, with write tracking. + /// + /// Virtual address to write the data into + /// Data to be written + /// Throw for unhandled invalid or unmapped memory accesses + void Write(ulong va, ReadOnlySequence data) + { + foreach (ReadOnlyMemory segment in data) + { + Write(va, segment.Span); + va += (ulong)segment.Length; + } + } + void Write(ulong va, ReadOnlySpan data); void WriteUntracked(ulong va, ReadOnlySpan data) => Write(va, data); diff --git a/src/Ryujinx.Memory/MemoryBlock.cs b/src/Ryujinx.Memory/MemoryBlock.cs index 477be893a..3bb379ced 100644 --- a/src/Ryujinx.Memory/MemoryBlock.cs +++ b/src/Ryujinx.Memory/MemoryBlock.cs @@ -174,7 +174,7 @@ namespace Ryujinx.Memory /// Starting offset of the range being read /// Span where the bytes being read will be copied to /// Throw when the memory block has already been disposed - /// Throw when the memory region specified for the the data is out of range + /// Throw when the memory region specified for the data is out of range [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Read(ulong offset, Span data) { @@ -188,7 +188,7 @@ namespace Ryujinx.Memory /// Offset where the data is located /// Data at the specified address /// Throw when the memory block has already been disposed - /// Throw when the memory region specified for the the data is out of range + /// Throw when the memory region specified for the data is out of range [MethodImpl(MethodImplOptions.AggressiveInlining)] public T Read(ulong offset) where T : unmanaged { @@ -201,7 +201,7 @@ namespace Ryujinx.Memory /// Starting offset of the range being written /// Span where the bytes being written will be copied from /// Throw when the memory block has already been disposed - /// Throw when the memory region specified for the the data is out of range + /// Throw when the memory region specified for the data is out of range [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(ulong offset, ReadOnlySpan data) { @@ -215,7 +215,7 @@ namespace Ryujinx.Memory /// Offset to write the data into /// Data to be written /// Throw when the memory block has already been disposed - /// Throw when the memory region specified for the the data is out of range + /// Throw when the memory region specified for the data is out of range [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(ulong offset, T data) where T : unmanaged { diff --git a/src/Ryujinx.Memory/NativeMemoryManager.cs b/src/Ryujinx.Memory/NativeMemoryManager.cs index fe718bda8..cb8d5c243 100644 --- a/src/Ryujinx.Memory/NativeMemoryManager.cs +++ b/src/Ryujinx.Memory/NativeMemoryManager.cs @@ -8,12 +8,21 @@ namespace Ryujinx.Memory private readonly T* _pointer; private readonly int _length; + public NativeMemoryManager(nuint pointer, int length) + : this((T*)pointer, length) + { + } + public NativeMemoryManager(T* pointer, int length) { _pointer = pointer; _length = length; } + public unsafe T* Pointer => _pointer; + + public int Length => _length; + public override Span GetSpan() { return new Span((void*)_pointer, _length); diff --git a/src/Ryujinx.Memory/Range/IMultiRangeItem.cs b/src/Ryujinx.Memory/Range/IMultiRangeItem.cs index 87fde2465..5f9611c75 100644 --- a/src/Ryujinx.Memory/Range/IMultiRangeItem.cs +++ b/src/Ryujinx.Memory/Range/IMultiRangeItem.cs @@ -4,6 +4,22 @@ namespace Ryujinx.Memory.Range { MultiRange Range { get; } - ulong BaseAddress => Range.GetSubRange(0).Address; + ulong BaseAddress + { + get + { + for (int index = 0; index < Range.Count; index++) + { + MemoryRange subRange = Range.GetSubRange(index); + + if (!MemoryRange.IsInvalid(ref subRange)) + { + return subRange.Address; + } + } + + return MemoryRange.InvalidAddress; + } + } } } diff --git a/src/Ryujinx.Memory/Range/MemoryRange.cs b/src/Ryujinx.Memory/Range/MemoryRange.cs index 46aca9ba0..20e9d00bb 100644 --- a/src/Ryujinx.Memory/Range/MemoryRange.cs +++ b/src/Ryujinx.Memory/Range/MemoryRange.cs @@ -5,6 +5,11 @@ namespace Ryujinx.Memory.Range /// public readonly record struct MemoryRange { + /// + /// Special address value used to indicate than an address is invalid. + /// + internal const ulong InvalidAddress = ulong.MaxValue; + /// /// An empty memory range, with a null address and zero size. /// @@ -58,13 +63,24 @@ namespace Ryujinx.Memory.Range return thisAddress < otherEndAddress && otherAddress < thisEndAddress; } + /// + /// Checks if a given sub-range of memory is invalid. + /// Those are used to represent unmapped memory regions (holes in the region mapping). + /// + /// Memory range to check + /// True if the memory range is considered invalid, false otherwise + internal static bool IsInvalid(ref MemoryRange subRange) + { + return subRange.Address == InvalidAddress; + } + /// /// Returns a string summary of the memory range. /// /// A string summary of the memory range public override string ToString() { - if (Address == ulong.MaxValue) + if (Address == InvalidAddress) { return $"[Unmapped 0x{Size:X}]"; } diff --git a/src/Ryujinx.Memory/Range/MultiRangeList.cs b/src/Ryujinx.Memory/Range/MultiRangeList.cs index 1804ff5c8..c3c6ae797 100644 --- a/src/Ryujinx.Memory/Range/MultiRangeList.cs +++ b/src/Ryujinx.Memory/Range/MultiRangeList.cs @@ -30,7 +30,7 @@ namespace Ryujinx.Memory.Range { var subrange = range.GetSubRange(i); - if (IsInvalid(ref subrange)) + if (MemoryRange.IsInvalid(ref subrange)) { continue; } @@ -56,7 +56,7 @@ namespace Ryujinx.Memory.Range { var subrange = range.GetSubRange(i); - if (IsInvalid(ref subrange)) + if (MemoryRange.IsInvalid(ref subrange)) { continue; } @@ -99,7 +99,7 @@ namespace Ryujinx.Memory.Range { var subrange = range.GetSubRange(i); - if (IsInvalid(ref subrange)) + if (MemoryRange.IsInvalid(ref subrange)) { continue; } @@ -142,17 +142,6 @@ namespace Ryujinx.Memory.Range return overlapCount; } - /// - /// Checks if a given sub-range of memory is invalid. - /// Those are used to represent unmapped memory regions (holes in the region mapping). - /// - /// Memory range to checl - /// True if the memory range is considered invalid, false otherwise - private static bool IsInvalid(ref MemoryRange subRange) - { - return subRange.Address == ulong.MaxValue; - } - /// /// Gets all items on the list starting at the specified memory address. /// diff --git a/src/Ryujinx.Memory/Tracking/MemoryTracking.cs b/src/Ryujinx.Memory/Tracking/MemoryTracking.cs index 6febcbbb3..96cb2c5f5 100644 --- a/src/Ryujinx.Memory/Tracking/MemoryTracking.cs +++ b/src/Ryujinx.Memory/Tracking/MemoryTracking.cs @@ -14,9 +14,14 @@ namespace Ryujinx.Memory.Tracking // Only use these from within the lock. private readonly NonOverlappingRangeList _virtualRegions; + // Guest virtual regions are a subset of the normal virtual regions, with potentially different protection + // and expanded area of effect on platforms that don't support misaligned page protection. + private readonly NonOverlappingRangeList _guestVirtualRegions; private readonly int _pageSize; + private readonly bool _singleByteGuestTracking; + /// /// This lock must be obtained when traversing or updating the region-handle hierarchy. /// It is not required when reading dirty flags. @@ -27,16 +32,27 @@ namespace Ryujinx.Memory.Tracking /// Create a new tracking structure for the given "physical" memory block, /// with a given "virtual" memory manager that will provide mappings and virtual memory protection. /// + /// + /// If is true, the memory manager must also support protection on partially + /// unmapped regions without throwing exceptions or dropping protection on the mapped portion. + /// /// Virtual memory manager - /// Physical memory block /// Page size of the virtual memory space - public MemoryTracking(IVirtualMemoryManager memoryManager, int pageSize, InvalidAccessHandler invalidAccessHandler = null) + /// Method to call for invalid memory accesses + /// True if the guest only signals writes for the first byte + public MemoryTracking( + IVirtualMemoryManager memoryManager, + int pageSize, + InvalidAccessHandler invalidAccessHandler = null, + bool singleByteGuestTracking = false) { _memoryManager = memoryManager; _pageSize = pageSize; _invalidAccessHandler = invalidAccessHandler; + _singleByteGuestTracking = singleByteGuestTracking; _virtualRegions = new NonOverlappingRangeList(); + _guestVirtualRegions = new NonOverlappingRangeList(); } private (ulong address, ulong size) PageAlign(ulong address, ulong size) @@ -62,20 +78,25 @@ namespace Ryujinx.Memory.Tracking { ref var overlaps = ref ThreadStaticArray.Get(); - int count = _virtualRegions.FindOverlapsNonOverlapping(va, size, ref overlaps); - - for (int i = 0; i < count; i++) + for (int type = 0; type < 2; type++) { - VirtualRegion region = overlaps[i]; + NonOverlappingRangeList regions = type == 0 ? _virtualRegions : _guestVirtualRegions; - // If the region has been fully remapped, signal that it has been mapped again. - bool remapped = _memoryManager.IsRangeMapped(region.Address, region.Size); - if (remapped) + int count = regions.FindOverlapsNonOverlapping(va, size, ref overlaps); + + for (int i = 0; i < count; i++) { - region.SignalMappingChanged(true); - } + VirtualRegion region = overlaps[i]; - region.UpdateProtection(); + // If the region has been fully remapped, signal that it has been mapped again. + bool remapped = _memoryManager.IsRangeMapped(region.Address, region.Size); + if (remapped) + { + region.SignalMappingChanged(true); + } + + region.UpdateProtection(); + } } } } @@ -95,27 +116,58 @@ namespace Ryujinx.Memory.Tracking { ref var overlaps = ref ThreadStaticArray.Get(); - int count = _virtualRegions.FindOverlapsNonOverlapping(va, size, ref overlaps); - - for (int i = 0; i < count; i++) + for (int type = 0; type < 2; type++) { - VirtualRegion region = overlaps[i]; + NonOverlappingRangeList regions = type == 0 ? _virtualRegions : _guestVirtualRegions; - region.SignalMappingChanged(false); + int count = regions.FindOverlapsNonOverlapping(va, size, ref overlaps); + + for (int i = 0; i < count; i++) + { + VirtualRegion region = overlaps[i]; + + region.SignalMappingChanged(false); + } } } } + /// + /// Alter a tracked memory region to properly capture unaligned accesses. + /// For most memory manager modes, this does nothing. + /// + /// Original region address + /// Original region size + /// A new address and size for tracking unaligned accesses + internal (ulong newAddress, ulong newSize) GetUnalignedSafeRegion(ulong address, ulong size) + { + if (_singleByteGuestTracking) + { + // The guest only signals the first byte of each memory access with the current memory manager. + // To catch unaligned access properly, we need to also protect the page before the address. + + // Assume that the address and size are already aligned. + + return (address - (ulong)_pageSize, size + (ulong)_pageSize); + } + else + { + return (address, size); + } + } + /// /// Get a list of virtual regions that a handle covers. /// /// Starting virtual memory address of the handle /// Size of the handle's memory region + /// True if getting handles for guest protection, false otherwise /// A list of virtual regions within the given range - internal List GetVirtualRegionsForHandle(ulong va, ulong size) + internal List GetVirtualRegionsForHandle(ulong va, ulong size, bool guest) { List result = new(); - _virtualRegions.GetOrAddRegions(result, va, size, (va, size) => new VirtualRegion(this, va, size)); + NonOverlappingRangeList regions = guest ? _guestVirtualRegions : _virtualRegions; + regions.GetOrAddRegions(result, va, size, (va, size) => new VirtualRegion(this, va, size, guest)); return result; } @@ -126,7 +178,14 @@ namespace Ryujinx.Memory.Tracking /// Region to remove internal void RemoveVirtual(VirtualRegion region) { - _virtualRegions.Remove(region); + if (region.Guest) + { + _guestVirtualRegions.Remove(region); + } + else + { + _virtualRegions.Remove(region); + } } /// @@ -137,10 +196,11 @@ namespace Ryujinx.Memory.Tracking /// Handles to inherit state from or reuse. When none are present, provide null /// Desired granularity of write tracking /// Handle ID + /// Region flags /// The memory tracking handle - public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id) + public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id, RegionFlags flags = RegionFlags.None) { - return new MultiRegionHandle(this, address, size, handles, granularity, id); + return new MultiRegionHandle(this, address, size, handles, granularity, id, flags); } /// @@ -164,15 +224,16 @@ namespace Ryujinx.Memory.Tracking /// CPU virtual address of the region /// Size of the region /// Handle ID + /// Region flags /// The memory tracking handle - public RegionHandle BeginTracking(ulong address, ulong size, int id) + public RegionHandle BeginTracking(ulong address, ulong size, int id, RegionFlags flags = RegionFlags.None) { var (paAddress, paSize) = PageAlign(address, size); lock (TrackingLock) { bool mapped = _memoryManager.IsRangeMapped(address, size); - RegionHandle handle = new(this, paAddress, paSize, address, size, id, mapped); + RegionHandle handle = new(this, paAddress, paSize, address, size, id, flags, mapped); return handle; } @@ -186,15 +247,16 @@ namespace Ryujinx.Memory.Tracking /// The bitmap owning the dirty flag for this handle /// The bit of this handle within the dirty flag /// Handle ID + /// Region flags /// The memory tracking handle - internal RegionHandle BeginTrackingBitmap(ulong address, ulong size, ConcurrentBitmap bitmap, int bit, int id) + internal RegionHandle BeginTrackingBitmap(ulong address, ulong size, ConcurrentBitmap bitmap, int bit, int id, RegionFlags flags = RegionFlags.None) { var (paAddress, paSize) = PageAlign(address, size); lock (TrackingLock) { bool mapped = _memoryManager.IsRangeMapped(address, size); - RegionHandle handle = new(this, paAddress, paSize, address, size, bitmap, bit, id, mapped); + RegionHandle handle = new(this, paAddress, paSize, address, size, bitmap, bit, id, flags, mapped); return handle; } @@ -202,6 +264,7 @@ namespace Ryujinx.Memory.Tracking /// /// Signal that a virtual memory event happened at the given location. + /// The memory event is assumed to be triggered by guest code. /// /// Virtual address accessed /// Size of the region affected in bytes @@ -209,7 +272,7 @@ namespace Ryujinx.Memory.Tracking /// True if the event triggered any tracking regions, false otherwise public bool VirtualMemoryEvent(ulong address, ulong size, bool write) { - return VirtualMemoryEvent(address, size, write, precise: false, null); + return VirtualMemoryEvent(address, size, write, precise: false, exemptId: null, guest: true); } /// @@ -222,8 +285,9 @@ namespace Ryujinx.Memory.Tracking /// Whether the region was written to or read /// True if the access is precise, false otherwise /// Optional ID that of the handles that should not be signalled + /// True if the access is from the guest, false otherwise /// True if the event triggered any tracking regions, false otherwise - public bool VirtualMemoryEvent(ulong address, ulong size, bool write, bool precise, int? exemptId = null) + public bool VirtualMemoryEvent(ulong address, ulong size, bool write, bool precise, int? exemptId = null, bool guest = false) { // Look up the virtual region using the region list. // Signal up the chain to relevant handles. @@ -234,7 +298,9 @@ namespace Ryujinx.Memory.Tracking { ref var overlaps = ref ThreadStaticArray.Get(); - int count = _virtualRegions.FindOverlapsNonOverlapping(address, size, ref overlaps); + NonOverlappingRangeList regions = guest ? _guestVirtualRegions : _virtualRegions; + + int count = regions.FindOverlapsNonOverlapping(address, size, ref overlaps); if (count == 0 && !precise) { @@ -242,7 +308,7 @@ namespace Ryujinx.Memory.Tracking { // TODO: There is currently the possibility that a page can be protected after its virtual region is removed. // This code handles that case when it happens, but it would be better to find out how this happens. - _memoryManager.TrackingReprotect(address & ~(ulong)(_pageSize - 1), (ulong)_pageSize, MemoryPermission.ReadAndWrite); + _memoryManager.TrackingReprotect(address & ~(ulong)(_pageSize - 1), (ulong)_pageSize, MemoryPermission.ReadAndWrite, guest); return true; // This memory _should_ be mapped, so we need to try again. } else @@ -252,6 +318,12 @@ namespace Ryujinx.Memory.Tracking } else { + if (guest && _singleByteGuestTracking) + { + // Increase the access size to trigger handles with misaligned accesses. + size += (ulong)_pageSize; + } + for (int i = 0; i < count; i++) { VirtualRegion region = overlaps[i]; @@ -285,9 +357,10 @@ namespace Ryujinx.Memory.Tracking /// /// Region to reprotect /// Memory permission to protect with - internal void ProtectVirtualRegion(VirtualRegion region, MemoryPermission permission) + /// True if the protection is for guest access, false otherwise + internal void ProtectVirtualRegion(VirtualRegion region, MemoryPermission permission, bool guest) { - _memoryManager.TrackingReprotect(region.Address, region.Size, permission); + _memoryManager.TrackingReprotect(region.Address, region.Size, permission, guest); } /// diff --git a/src/Ryujinx.Memory/Tracking/MultiRegionHandle.cs b/src/Ryujinx.Memory/Tracking/MultiRegionHandle.cs index 1c1b48b3c..6fdca69f5 100644 --- a/src/Ryujinx.Memory/Tracking/MultiRegionHandle.cs +++ b/src/Ryujinx.Memory/Tracking/MultiRegionHandle.cs @@ -37,7 +37,8 @@ namespace Ryujinx.Memory.Tracking ulong size, IEnumerable handles, ulong granularity, - int id) + int id, + RegionFlags flags) { _handles = new RegionHandle[(size + granularity - 1) / granularity]; Granularity = granularity; @@ -62,7 +63,7 @@ namespace Ryujinx.Memory.Tracking // Fill any gap left before this handle. while (i < startIndex) { - RegionHandle fillHandle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id); + RegionHandle fillHandle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id, flags); fillHandle.Parent = this; _handles[i++] = fillHandle; } @@ -83,7 +84,7 @@ namespace Ryujinx.Memory.Tracking while (i < endIndex) { - RegionHandle splitHandle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id); + RegionHandle splitHandle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id, flags); splitHandle.Parent = this; splitHandle.Reprotect(handle.Dirty); @@ -106,7 +107,7 @@ namespace Ryujinx.Memory.Tracking // Fill any remaining space with new handles. while (i < _handles.Length) { - RegionHandle handle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id); + RegionHandle handle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id, flags); handle.Parent = this; _handles[i++] = handle; } diff --git a/src/Ryujinx.Memory/Tracking/RegionFlags.cs b/src/Ryujinx.Memory/Tracking/RegionFlags.cs new file mode 100644 index 000000000..ceb8e56a6 --- /dev/null +++ b/src/Ryujinx.Memory/Tracking/RegionFlags.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Ryujinx.Memory.Tracking +{ + [Flags] + public enum RegionFlags + { + None = 0, + + /// + /// Access to the resource is expected to occasionally be unaligned. + /// With some memory managers, guest protection must extend into the previous page to cover unaligned access. + /// If this is not expected, protection is not altered, which can avoid unintended resource dirty/flush. + /// + UnalignedAccess = 1, + } +} diff --git a/src/Ryujinx.Memory/Tracking/RegionHandle.cs b/src/Ryujinx.Memory/Tracking/RegionHandle.cs index df3d9c311..a94ffa43c 100644 --- a/src/Ryujinx.Memory/Tracking/RegionHandle.cs +++ b/src/Ryujinx.Memory/Tracking/RegionHandle.cs @@ -55,6 +55,8 @@ namespace Ryujinx.Memory.Tracking private RegionSignal _preAction; // Action to perform before a read or write. This will block the memory access. private PreciseRegionSignal _preciseAction; // Action to perform on a precise read or write. private readonly List _regions; + private readonly List _guestRegions; + private readonly List _allRegions; private readonly MemoryTracking _tracking; private bool _disposed; @@ -99,6 +101,7 @@ namespace Ryujinx.Memory.Tracking /// The bitmap the dirty flag for this handle is stored in /// The bit index representing the dirty flag for this handle /// Handle ID + /// Region flags /// True if the region handle starts mapped internal RegionHandle( MemoryTracking tracking, @@ -109,6 +112,7 @@ namespace Ryujinx.Memory.Tracking ConcurrentBitmap bitmap, int bit, int id, + RegionFlags flags, bool mapped = true) { Bitmap = bitmap; @@ -128,11 +132,12 @@ namespace Ryujinx.Memory.Tracking RealEndAddress = realAddress + realSize; _tracking = tracking; - _regions = tracking.GetVirtualRegionsForHandle(address, size); - foreach (var region in _regions) - { - region.Handles.Add(this); - } + + _regions = tracking.GetVirtualRegionsForHandle(address, size, false); + _guestRegions = GetGuestRegions(tracking, address, size, flags); + _allRegions = new List(_regions.Count + _guestRegions.Count); + + InitializeRegions(); } /// @@ -145,8 +150,9 @@ namespace Ryujinx.Memory.Tracking /// The real, unaligned address of the handle /// The real, unaligned size of the handle /// Handle ID + /// Region flags /// True if the region handle starts mapped - internal RegionHandle(MemoryTracking tracking, ulong address, ulong size, ulong realAddress, ulong realSize, int id, bool mapped = true) + internal RegionHandle(MemoryTracking tracking, ulong address, ulong size, ulong realAddress, ulong realSize, int id, RegionFlags flags, bool mapped = true) { Bitmap = new ConcurrentBitmap(1, mapped); @@ -163,8 +169,37 @@ namespace Ryujinx.Memory.Tracking RealEndAddress = realAddress + realSize; _tracking = tracking; - _regions = tracking.GetVirtualRegionsForHandle(address, size); - foreach (var region in _regions) + + _regions = tracking.GetVirtualRegionsForHandle(address, size, false); + _guestRegions = GetGuestRegions(tracking, address, size, flags); + _allRegions = new List(_regions.Count + _guestRegions.Count); + + InitializeRegions(); + } + + private List GetGuestRegions(MemoryTracking tracking, ulong address, ulong size, RegionFlags flags) + { + ulong guestAddress; + ulong guestSize; + + if (flags.HasFlag(RegionFlags.UnalignedAccess)) + { + (guestAddress, guestSize) = tracking.GetUnalignedSafeRegion(address, size); + } + else + { + (guestAddress, guestSize) = (address, size); + } + + return tracking.GetVirtualRegionsForHandle(guestAddress, guestSize, true); + } + + private void InitializeRegions() + { + _allRegions.AddRange(_regions); + _allRegions.AddRange(_guestRegions); + + foreach (var region in _allRegions) { region.Handles.Add(this); } @@ -321,7 +356,7 @@ namespace Ryujinx.Memory.Tracking lock (_tracking.TrackingLock) { - foreach (VirtualRegion region in _regions) + foreach (VirtualRegion region in _allRegions) { protectionChanged |= region.UpdateProtection(); } @@ -379,7 +414,7 @@ namespace Ryujinx.Memory.Tracking { lock (_tracking.TrackingLock) { - foreach (VirtualRegion region in _regions) + foreach (VirtualRegion region in _allRegions) { region.UpdateProtection(); } @@ -414,7 +449,16 @@ namespace Ryujinx.Memory.Tracking /// Virtual region to add as a child internal void AddChild(VirtualRegion region) { - _regions.Add(region); + if (region.Guest) + { + _guestRegions.Add(region); + } + else + { + _regions.Add(region); + } + + _allRegions.Add(region); } /// @@ -469,7 +513,7 @@ namespace Ryujinx.Memory.Tracking lock (_tracking.TrackingLock) { - foreach (VirtualRegion region in _regions) + foreach (VirtualRegion region in _allRegions) { region.RemoveHandle(this); } diff --git a/src/Ryujinx.Memory/Tracking/VirtualRegion.cs b/src/Ryujinx.Memory/Tracking/VirtualRegion.cs index 538e94fef..35e9c2d9b 100644 --- a/src/Ryujinx.Memory/Tracking/VirtualRegion.cs +++ b/src/Ryujinx.Memory/Tracking/VirtualRegion.cs @@ -13,10 +13,14 @@ namespace Ryujinx.Memory.Tracking private readonly MemoryTracking _tracking; private MemoryPermission _lastPermission; - public VirtualRegion(MemoryTracking tracking, ulong address, ulong size, MemoryPermission lastPermission = MemoryPermission.Invalid) : base(address, size) + public bool Guest { get; } + + public VirtualRegion(MemoryTracking tracking, ulong address, ulong size, bool guest, MemoryPermission lastPermission = MemoryPermission.Invalid) : base(address, size) { _lastPermission = lastPermission; _tracking = tracking; + + Guest = guest; } /// @@ -66,9 +70,12 @@ namespace Ryujinx.Memory.Tracking { _lastPermission = MemoryPermission.Invalid; - foreach (RegionHandle handle in Handles) + if (!Guest) { - handle.SignalMappingChanged(mapped); + foreach (RegionHandle handle in Handles) + { + handle.SignalMappingChanged(mapped); + } } } @@ -103,7 +110,7 @@ namespace Ryujinx.Memory.Tracking if (_lastPermission != permission) { - _tracking.ProtectVirtualRegion(this, permission); + _tracking.ProtectVirtualRegion(this, permission, Guest); _lastPermission = permission; return true; @@ -131,7 +138,7 @@ namespace Ryujinx.Memory.Tracking public override INonOverlappingRange Split(ulong splitAddress) { - VirtualRegion newRegion = new(_tracking, splitAddress, EndAddress - splitAddress, _lastPermission); + VirtualRegion newRegion = new(_tracking, splitAddress, EndAddress - splitAddress, Guest, _lastPermission); Size = splitAddress - Address; // The new region inherits all of our parents. diff --git a/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs b/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs new file mode 100644 index 000000000..f41072244 --- /dev/null +++ b/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs @@ -0,0 +1,405 @@ +using Ryujinx.Common.Memory; +using System; +using System.Buffers; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Memory +{ + public abstract class VirtualMemoryManagerBase : IWritableBlock + { + public const int PageBits = 12; + public const int PageSize = 1 << PageBits; + public const int PageMask = PageSize - 1; + + protected abstract ulong AddressSpaceSize { get; } + + public virtual ReadOnlySequence GetReadOnlySequence(ulong va, int size, bool tracked = false) + { + if (size == 0) + { + return ReadOnlySequence.Empty; + } + + if (tracked) + { + SignalMemoryTracking(va, (ulong)size, false); + } + + if (IsContiguousAndMapped(va, size)) + { + nuint pa = TranslateVirtualAddressUnchecked(va); + + return new ReadOnlySequence(GetPhysicalAddressMemory(pa, size)); + } + else + { + AssertValidAddressAndSize(va, size); + + int offset = 0, segmentSize; + + BytesReadOnlySequenceSegment first = null, last = null; + + if ((va & PageMask) != 0) + { + nuint pa = TranslateVirtualAddressChecked(va); + + segmentSize = Math.Min(size, PageSize - (int)(va & PageMask)); + + Memory memory = GetPhysicalAddressMemory(pa, segmentSize); + + first = last = new BytesReadOnlySequenceSegment(memory); + + offset += segmentSize; + } + + for (; offset < size; offset += segmentSize) + { + nuint pa = TranslateVirtualAddressChecked(va + (ulong)offset); + + segmentSize = Math.Min(size - offset, PageSize); + + Memory memory = GetPhysicalAddressMemory(pa, segmentSize); + + if (first is null) + { + first = last = new BytesReadOnlySequenceSegment(memory); + } + else + { + if (last.IsContiguousWith(memory, out nuint contiguousStart, out int contiguousSize)) + { + last.Replace(GetPhysicalAddressMemory(contiguousStart, contiguousSize)); + } + else + { + last = last.Append(memory); + } + } + } + + return new ReadOnlySequence(first, 0, last, (int)(size - last.RunningIndex)); + } + } + + public virtual ReadOnlySpan GetSpan(ulong va, int size, bool tracked = false) + { + if (size == 0) + { + return ReadOnlySpan.Empty; + } + + if (tracked) + { + SignalMemoryTracking(va, (ulong)size, false); + } + + if (IsContiguousAndMapped(va, size)) + { + nuint pa = TranslateVirtualAddressUnchecked(va); + + return GetPhysicalAddressSpan(pa, size); + } + else + { + Span data = new byte[size]; + + Read(va, data); + + return data; + } + } + + public virtual WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) + { + if (size == 0) + { + return new WritableRegion(null, va, Memory.Empty); + } + + if (tracked) + { + SignalMemoryTracking(va, (ulong)size, true); + } + + if (IsContiguousAndMapped(va, size)) + { + nuint pa = TranslateVirtualAddressUnchecked(va); + + return new WritableRegion(null, va, GetPhysicalAddressMemory(pa, size)); + } + else + { + MemoryOwner memoryOwner = MemoryOwner.Rent(size); + + Read(va, memoryOwner.Span); + + return new WritableRegion(this, va, memoryOwner); + } + } + + public abstract bool IsMapped(ulong va); + + public virtual void MapForeign(ulong va, nuint hostPointer, ulong size) + { + throw new NotSupportedException(); + } + + public virtual T Read(ulong va) where T : unmanaged + { + return MemoryMarshal.Cast(GetSpan(va, Unsafe.SizeOf()))[0]; + } + + public virtual void Read(ulong va, Span data) + { + if (data.Length == 0) + { + return; + } + + AssertValidAddressAndSize(va, data.Length); + + int offset = 0, size; + + if ((va & PageMask) != 0) + { + nuint pa = TranslateVirtualAddressChecked(va); + + size = Math.Min(data.Length, PageSize - (int)(va & PageMask)); + + GetPhysicalAddressSpan(pa, size).CopyTo(data[..size]); + + offset += size; + } + + for (; offset < data.Length; offset += size) + { + nuint pa = TranslateVirtualAddressChecked(va + (ulong)offset); + + size = Math.Min(data.Length - offset, PageSize); + + GetPhysicalAddressSpan(pa, size).CopyTo(data.Slice(offset, size)); + } + } + + public virtual T ReadTracked(ulong va) where T : unmanaged + { + SignalMemoryTracking(va, (ulong)Unsafe.SizeOf(), false); + + return Read(va); + } + + public virtual void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) + { + // No default implementation + } + + public virtual void Write(ulong va, ReadOnlySpan data) + { + if (data.Length == 0) + { + return; + } + + SignalMemoryTracking(va, (ulong)data.Length, true); + + WriteImpl(va, data); + } + + public virtual void Write(ulong va, T value) where T : unmanaged + { + Write(va, MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref value, 1))); + } + + public virtual void WriteUntracked(ulong va, ReadOnlySpan data) + { + if (data.Length == 0) + { + return; + } + + WriteImpl(va, data); + } + + public virtual bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan data) + { + if (data.Length == 0) + { + return false; + } + + if (IsContiguousAndMapped(va, data.Length)) + { + SignalMemoryTracking(va, (ulong)data.Length, false); + + nuint pa = TranslateVirtualAddressChecked(va); + + var target = GetPhysicalAddressSpan(pa, data.Length); + + bool changed = !data.SequenceEqual(target); + + if (changed) + { + data.CopyTo(target); + } + + return changed; + } + else + { + Write(va, data); + + return true; + } + } + + /// + /// Ensures the combination of virtual address and size is part of the addressable space. + /// + /// Virtual address of the range + /// Size of the range in bytes + /// Throw when the memory region specified outside the addressable space + protected void AssertValidAddressAndSize(ulong va, ulong size) + { + if (!ValidateAddressAndSize(va, size)) + { + throw new InvalidMemoryRegionException($"va=0x{va:X16}, size=0x{size:X16}"); + } + } + + /// + /// Ensures the combination of virtual address and size is part of the addressable space. + /// + /// Virtual address of the range + /// Size of the range in bytes + /// Throw when the memory region specified outside the addressable space + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void AssertValidAddressAndSize(ulong va, int size) + => AssertValidAddressAndSize(va, (ulong)size); + + /// + /// Computes the number of pages in a virtual address range. + /// + /// Virtual address of the range + /// Size of the range + /// The virtual address of the beginning of the first page + /// This function does not differentiate between allocated and unallocated pages. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected static int GetPagesCount(ulong va, ulong size, out ulong startVa) + { + // WARNING: Always check if ulong does not overflow during the operations. + startVa = va & ~(ulong)PageMask; + ulong vaSpan = (va - startVa + size + PageMask) & ~(ulong)PageMask; + + return (int)(vaSpan / PageSize); + } + + protected abstract Memory GetPhysicalAddressMemory(nuint pa, int size); + + protected abstract Span GetPhysicalAddressSpan(nuint pa, int size); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected bool IsContiguous(ulong va, int size) => IsContiguous(va, (ulong)size); + + protected virtual bool IsContiguous(ulong va, ulong size) + { + if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size)) + { + return false; + } + + int pages = GetPagesCount(va, size, out va); + + for (int page = 0; page < pages - 1; page++) + { + if (!ValidateAddress(va + PageSize)) + { + return false; + } + + if (TranslateVirtualAddressUnchecked(va) + PageSize != TranslateVirtualAddressUnchecked(va + PageSize)) + { + return false; + } + + va += PageSize; + } + + return true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected bool IsContiguousAndMapped(ulong va, int size) + => IsContiguous(va, size) && IsMapped(va); + + protected abstract nuint TranslateVirtualAddressChecked(ulong va); + + protected abstract nuint TranslateVirtualAddressUnchecked(ulong va); + + /// + /// Checks if the virtual address is part of the addressable space. + /// + /// Virtual address + /// True if the virtual address is part of the addressable space + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected bool ValidateAddress(ulong va) + { + return va < AddressSpaceSize; + } + + /// + /// Checks if the combination of virtual address and size is part of the addressable space. + /// + /// Virtual address of the range + /// Size of the range in bytes + /// True if the combination of virtual address and size is part of the addressable space + protected bool ValidateAddressAndSize(ulong va, ulong size) + { + ulong endVa = va + size; + return endVa >= va && endVa >= size && endVa <= AddressSpaceSize; + } + + protected static void ThrowInvalidMemoryRegionException(string message) + => throw new InvalidMemoryRegionException(message); + + protected static void ThrowMemoryNotContiguous() + => throw new MemoryNotContiguousException(); + + protected virtual void WriteImpl(ulong va, ReadOnlySpan data) + { + AssertValidAddressAndSize(va, data.Length); + + if (IsContiguousAndMapped(va, data.Length)) + { + nuint pa = TranslateVirtualAddressUnchecked(va); + + data.CopyTo(GetPhysicalAddressSpan(pa, data.Length)); + } + else + { + int offset = 0, size; + + if ((va & PageMask) != 0) + { + nuint pa = TranslateVirtualAddressChecked(va); + + size = Math.Min(data.Length, PageSize - (int)(va & PageMask)); + + data[..size].CopyTo(GetPhysicalAddressSpan(pa, size)); + + offset += size; + } + + for (; offset < data.Length; offset += size) + { + nuint pa = TranslateVirtualAddressChecked(va + (ulong)offset); + + size = Math.Min(data.Length - offset, PageSize); + + data.Slice(offset, size).CopyTo(GetPhysicalAddressSpan(pa, size)); + } + } + } + + } +} diff --git a/src/Ryujinx.Memory/WritableRegion.cs b/src/Ryujinx.Memory/WritableRegion.cs index 666c8a99b..54facb508 100644 --- a/src/Ryujinx.Memory/WritableRegion.cs +++ b/src/Ryujinx.Memory/WritableRegion.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Memory; using System; namespace Ryujinx.Memory @@ -6,6 +7,7 @@ namespace Ryujinx.Memory { private readonly IWritableBlock _block; private readonly ulong _va; + private readonly MemoryOwner _memoryOwner; private readonly bool _tracked; private bool NeedsWriteback => _block != null; @@ -20,6 +22,12 @@ namespace Ryujinx.Memory Memory = memory; } + public WritableRegion(IWritableBlock block, ulong va, MemoryOwner memoryOwner, bool tracked = false) + : this(block, va, memoryOwner.Memory, tracked) + { + _memoryOwner = memoryOwner; + } + public void Dispose() { if (NeedsWriteback) @@ -33,6 +41,8 @@ namespace Ryujinx.Memory _block.WriteUntracked(_va, Memory.Span); } } + + _memoryOwner?.Dispose(); } } } diff --git a/src/Ryujinx.SDL2.Common/SDL2Driver.cs b/src/Ryujinx.SDL2.Common/SDL2Driver.cs index 49e7dd147..9acd0637c 100644 --- a/src/Ryujinx.SDL2.Common/SDL2Driver.cs +++ b/src/Ryujinx.SDL2.Common/SDL2Driver.cs @@ -1,4 +1,4 @@ -using Ryujinx.Common; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using System; using System.Collections.Concurrent; @@ -13,8 +13,6 @@ namespace Ryujinx.SDL2.Common { private static SDL2Driver _instance; - public static bool IsInitialized => _instance != null; - public static SDL2Driver Instance { get @@ -55,6 +53,7 @@ namespace Ryujinx.SDL2.Common return; } + SDL_SetHint(SDL_HINT_APP_NAME, "Ryujinx"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); diff --git a/src/Ryujinx.ShaderTools/Program.cs b/src/Ryujinx.ShaderTools/Program.cs index 04453912b..a84d7b466 100644 --- a/src/Ryujinx.ShaderTools/Program.cs +++ b/src/Ryujinx.ShaderTools/Program.cs @@ -11,17 +11,67 @@ namespace Ryujinx.ShaderTools { private class GpuAccessor : IGpuAccessor { + private const int DefaultArrayLength = 32; + private readonly byte[] _data; + private int _texturesCount; + private int _imagesCount; + public GpuAccessor(byte[] data) { _data = data; + _texturesCount = 0; + _imagesCount = 0; + } + + public SetBindingPair CreateConstantBufferBinding(int index) + { + return new SetBindingPair(0, index + 1); + } + + public SetBindingPair CreateImageBinding(int count, bool isBuffer) + { + int binding = _imagesCount; + + _imagesCount += count; + + return new SetBindingPair(3, binding); + } + + public SetBindingPair CreateStorageBufferBinding(int index) + { + return new SetBindingPair(1, index); + } + + public SetBindingPair CreateTextureBinding(int count, bool isBuffer) + { + int binding = _texturesCount; + + _texturesCount += count; + + return new SetBindingPair(2, binding); } public ReadOnlySpan GetCode(ulong address, int minimumSize) { return MemoryMarshal.Cast(new ReadOnlySpan(_data)[(int)address..]); } + + public int QuerySamplerArrayLengthFromPool() + { + return DefaultArrayLength; + } + + public int QueryTextureArrayLengthFromBuffer(int slot) + { + return DefaultArrayLength; + } + + public int QueryTextureArrayLengthFromPool() + { + return DefaultArrayLength; + } } private class Options diff --git a/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs b/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs index 5c8396e6d..3fe44db21 100644 --- a/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs +++ b/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs @@ -1,13 +1,14 @@ using Ryujinx.Memory; using Ryujinx.Memory.Range; using System; +using System.Buffers; using System.Collections.Generic; namespace Ryujinx.Tests.Memory { public class MockVirtualMemoryManager : IVirtualMemoryManager { - public bool Supports4KBPages => true; + public bool UsesPrivateAllocations => false; public bool NoMappings = false; @@ -57,6 +58,11 @@ namespace Ryujinx.Tests.Memory throw new NotImplementedException(); } + public ReadOnlySequence GetReadOnlySequence(ulong va, int size, bool tracked = false) + { + throw new NotImplementedException(); + } + public ReadOnlySpan GetSpan(ulong va, int size, bool tracked = false) { throw new NotImplementedException(); @@ -107,7 +113,7 @@ namespace Ryujinx.Tests.Memory throw new NotImplementedException(); } - public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection) + public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection, bool guest) { OnProtect?.Invoke(va, size, protection); } diff --git a/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs index 557581881..0b0ed7a54 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs @@ -52,7 +52,10 @@ namespace Ryujinx.Tests.Audio.Renderer.Server Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported()); + Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); @@ -78,7 +81,10 @@ namespace Ryujinx.Tests.Audio.Renderer.Server Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported()); + Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); @@ -104,7 +110,10 @@ namespace Ryujinx.Tests.Audio.Renderer.Server Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported()); + Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); @@ -130,7 +139,10 @@ namespace Ryujinx.Tests.Audio.Renderer.Server Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported()); + Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); Assert.AreEqual(0.75f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); @@ -156,7 +168,10 @@ namespace Ryujinx.Tests.Audio.Renderer.Server Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported()); + Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); @@ -182,7 +197,10 @@ namespace Ryujinx.Tests.Audio.Renderer.Server Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported()); + Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); @@ -208,7 +226,10 @@ namespace Ryujinx.Tests.Audio.Renderer.Server Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported()); + Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); @@ -234,7 +255,10 @@ namespace Ryujinx.Tests.Audio.Renderer.Server Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); Assert.IsTrue(behaviourContext.IsWaveBufferVersion2Supported()); Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported()); + Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(3, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); @@ -260,7 +284,10 @@ namespace Ryujinx.Tests.Audio.Renderer.Server Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); Assert.IsTrue(behaviourContext.IsWaveBufferVersion2Supported()); Assert.IsTrue(behaviourContext.IsEffectInfoVersion2Supported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported()); + Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(3, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); @@ -286,11 +313,101 @@ namespace Ryujinx.Tests.Audio.Renderer.Server Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); Assert.IsTrue(behaviourContext.IsWaveBufferVersion2Supported()); Assert.IsTrue(behaviourContext.IsEffectInfoVersion2Supported()); - Assert.IsTrue(behaviourContext.IsBiquadFilterGroupedOptimizationSupported()); + Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(4, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat()); } + + [Test] + public void TestRevision11() + { + BehaviourContext behaviourContext = new(); + + behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision11); + + Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourContext.IsSplitterSupported()); + Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourContext.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourContext.IsSplitterBugFixed()); + Assert.IsTrue(behaviourContext.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourContext.IsDecodingBehaviourFlagSupported()); + Assert.IsTrue(behaviourContext.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsTrue(behaviourContext.IsWaveBufferVersion2Supported()); + Assert.IsTrue(behaviourContext.IsEffectInfoVersion2Supported()); + Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsTrue(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(5, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision12() + { + BehaviourContext behaviourContext = new(); + + behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision12); + + Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourContext.IsSplitterSupported()); + Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourContext.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourContext.IsSplitterBugFixed()); + Assert.IsTrue(behaviourContext.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourContext.IsDecodingBehaviourFlagSupported()); + Assert.IsTrue(behaviourContext.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsTrue(behaviourContext.IsWaveBufferVersion2Supported()); + Assert.IsTrue(behaviourContext.IsEffectInfoVersion2Supported()); + Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsTrue(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsTrue(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(5, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision13() + { + BehaviourContext behaviourContext = new(); + + behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision13); + + Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourContext.IsSplitterSupported()); + Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourContext.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourContext.IsSplitterBugFixed()); + Assert.IsTrue(behaviourContext.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourContext.IsDecodingBehaviourFlagSupported()); + Assert.IsTrue(behaviourContext.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsTrue(behaviourContext.IsWaveBufferVersion2Supported()); + Assert.IsTrue(behaviourContext.IsEffectInfoVersion2Supported()); + Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing()); + Assert.IsTrue(behaviourContext.IsNewEffectChannelMappingSupported()); + Assert.IsTrue(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsTrue(behaviourContext.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(5, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat()); + } } } diff --git a/src/Ryujinx.Tests/Audio/Renderer/Server/SplitterDestinationTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Server/SplitterDestinationTests.cs index ad974aab1..80b801336 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/Server/SplitterDestinationTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/Server/SplitterDestinationTests.cs @@ -9,7 +9,8 @@ namespace Ryujinx.Tests.Audio.Renderer.Server [Test] public void EnsureTypeSize() { - Assert.AreEqual(0xE0, Unsafe.SizeOf()); + Assert.AreEqual(0xE0, Unsafe.SizeOf()); + Assert.AreEqual(0x110, Unsafe.SizeOf()); } } } diff --git a/src/Ryujinx.Tests/Common/Extensions/SequenceReaderExtensionsTests.cs b/src/Ryujinx.Tests/Common/Extensions/SequenceReaderExtensionsTests.cs new file mode 100644 index 000000000..c0127530a --- /dev/null +++ b/src/Ryujinx.Tests/Common/Extensions/SequenceReaderExtensionsTests.cs @@ -0,0 +1,359 @@ +using NUnit.Framework; +using Ryujinx.Common.Extensions; +using Ryujinx.Memory; +using System; +using System.Buffers; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Tests.Common.Extensions +{ + public class SequenceReaderExtensionsTests + { + [TestCase(null)] + [TestCase(sizeof(int) + 1)] + public void GetRefOrRefToCopy_ReadsMultiSegmentedSequenceSuccessfully(int? maxSegmentSize) + { + // Arrange + MyUnmanagedStruct[] originalStructs = EnumerateNewUnmanagedStructs().Take(3).ToArray(); + + ReadOnlySequence sequence = + CreateSegmentedByteSequence(originalStructs, maxSegmentSize ?? Unsafe.SizeOf()); + + var sequenceReader = new SequenceReader(sequence); + + foreach (var original in originalStructs) + { + // Act + ref readonly MyUnmanagedStruct read = ref sequenceReader.GetRefOrRefToCopy(out _); + + // Assert + MyUnmanagedStruct.Assert(Assert.AreEqual, original, read); + } + } + + [Test] + public void GetRefOrRefToCopy_FragmentedSequenceReturnsRefToCopy() + { + // Arrange + MyUnmanagedStruct[] originalStructs = EnumerateNewUnmanagedStructs().Take(1).ToArray(); + + ReadOnlySequence sequence = CreateSegmentedByteSequence(originalStructs, 3); + + var sequenceReader = new SequenceReader(sequence); + + foreach (var original in originalStructs) + { + // Act + ref readonly MyUnmanagedStruct read = ref sequenceReader.GetRefOrRefToCopy(out var copy); + + // Assert + MyUnmanagedStruct.Assert(Assert.AreEqual, original, read); + MyUnmanagedStruct.Assert(Assert.AreEqual, read, copy); + } + } + + [Test] + public void GetRefOrRefToCopy_ContiguousSequenceReturnsRefToBuffer() + { + // Arrange + MyUnmanagedStruct[] originalStructs = EnumerateNewUnmanagedStructs().Take(1).ToArray(); + + ReadOnlySequence sequence = CreateSegmentedByteSequence(originalStructs, int.MaxValue); + + var sequenceReader = new SequenceReader(sequence); + + foreach (var original in originalStructs) + { + // Act + ref readonly MyUnmanagedStruct read = ref sequenceReader.GetRefOrRefToCopy(out var copy); + + // Assert + MyUnmanagedStruct.Assert(Assert.AreEqual, original, read); + MyUnmanagedStruct.Assert(Assert.AreNotEqual, read, copy); + } + } + + [Test] + public void GetRefOrRefToCopy_ThrowsWhenNotEnoughData() + { + // Arrange + MyUnmanagedStruct[] originalStructs = EnumerateNewUnmanagedStructs().Take(1).ToArray(); + + ReadOnlySequence sequence = CreateSegmentedByteSequence(originalStructs, int.MaxValue); + + // Act/Assert + Assert.Throws(() => + { + var sequenceReader = new SequenceReader(sequence); + + sequenceReader.Advance(1); + + ref readonly MyUnmanagedStruct result = ref sequenceReader.GetRefOrRefToCopy(out _); + }); + } + + [Test] + public void ReadLittleEndian_Int32_RoundTripsSuccessfully() + { + // Arrange + const int TestValue = 0x1234abcd; + + byte[] buffer = new byte[sizeof(int)]; + + BinaryPrimitives.WriteInt32LittleEndian(buffer.AsSpan(), TestValue); + + var sequenceReader = new SequenceReader(new ReadOnlySequence(buffer)); + + // Act + sequenceReader.ReadLittleEndian(out int roundTrippedValue); + + // Assert + Assert.AreEqual(TestValue, roundTrippedValue); + } + + [Test] + public void ReadLittleEndian_Int32_ResultIsNotBigEndian() + { + // Arrange + const int TestValue = 0x1234abcd; + + byte[] buffer = new byte[sizeof(int)]; + + BinaryPrimitives.WriteInt32BigEndian(buffer.AsSpan(), TestValue); + + var sequenceReader = new SequenceReader(new ReadOnlySequence(buffer)); + + // Act + sequenceReader.ReadLittleEndian(out int roundTrippedValue); + + // Assert + Assert.AreNotEqual(TestValue, roundTrippedValue); + } + + [Test] + public void ReadLittleEndian_Int32_ThrowsWhenNotEnoughData() + { + // Arrange + const int TestValue = 0x1234abcd; + + byte[] buffer = new byte[sizeof(int)]; + + BinaryPrimitives.WriteInt32BigEndian(buffer.AsSpan(), TestValue); + + // Act/Assert + Assert.Throws(() => + { + var sequenceReader = new SequenceReader(new ReadOnlySequence(buffer)); + sequenceReader.Advance(1); + + sequenceReader.ReadLittleEndian(out int roundTrippedValue); + }); + } + + [Test] + public void ReadUnmanaged_ContiguousSequence_Succeeds() + => ReadUnmanaged_Succeeds(int.MaxValue); + + [Test] + public void ReadUnmanaged_FragmentedSequence_Succeeds() + => ReadUnmanaged_Succeeds(sizeof(int) + 1); + + [Test] + public void ReadUnmanaged_ThrowsWhenNotEnoughData() + { + // Arrange + MyUnmanagedStruct[] originalStructs = EnumerateNewUnmanagedStructs().Take(1).ToArray(); + + ReadOnlySequence sequence = CreateSegmentedByteSequence(originalStructs, int.MaxValue); + + // Act/Assert + Assert.Throws(() => + { + var sequenceReader = new SequenceReader(sequence); + + sequenceReader.Advance(1); + + sequenceReader.ReadUnmanaged(out MyUnmanagedStruct read); + }); + } + + [Test] + public void SetConsumed_ContiguousSequence_SucceedsWhenValid() + => SetConsumed_SucceedsWhenValid(int.MaxValue); + + [Test] + public void SetConsumed_FragmentedSequence_SucceedsWhenValid() + => SetConsumed_SucceedsWhenValid(sizeof(int) + 1); + + [Test] + public void SetConsumed_ThrowsWhenBeyondActualLength() + { + const int StructCount = 2; + // Arrange + MyUnmanagedStruct[] originalStructs = EnumerateNewUnmanagedStructs().Take(StructCount).ToArray(); + + ReadOnlySequence sequence = CreateSegmentedByteSequence(originalStructs, MyUnmanagedStruct.SizeOf); + + Assert.Throws(() => + { + var sequenceReader = new SequenceReader(sequence); + + sequenceReader.SetConsumed(MyUnmanagedStruct.SizeOf * StructCount + 1); + }); + } + + private static void ReadUnmanaged_Succeeds(int maxSegmentLength) + { + // Arrange + MyUnmanagedStruct[] originalStructs = EnumerateNewUnmanagedStructs().Take(3).ToArray(); + + ReadOnlySequence sequence = CreateSegmentedByteSequence(originalStructs, maxSegmentLength); + + var sequenceReader = new SequenceReader(sequence); + + foreach (var original in originalStructs) + { + // Act + sequenceReader.ReadUnmanaged(out MyUnmanagedStruct read); + + // Assert + MyUnmanagedStruct.Assert(Assert.AreEqual, original, read); + } + } + + private static void SetConsumed_SucceedsWhenValid(int maxSegmentLength) + { + // Arrange + MyUnmanagedStruct[] originalStructs = EnumerateNewUnmanagedStructs().Take(2).ToArray(); + + ReadOnlySequence sequence = CreateSegmentedByteSequence(originalStructs, maxSegmentLength); + + var sequenceReader = new SequenceReader(sequence); + + static void SetConsumedAndAssert(scoped ref SequenceReader sequenceReader, long consumed) + { + sequenceReader.SetConsumed(consumed); + Assert.AreEqual(consumed, sequenceReader.Consumed); + } + + // Act/Assert + ref readonly MyUnmanagedStruct struct0A = ref sequenceReader.GetRefOrRefToCopy(out _); + + Assert.AreEqual(sequenceReader.Consumed, MyUnmanagedStruct.SizeOf); + + SetConsumedAndAssert(ref sequenceReader, 0); + + ref readonly MyUnmanagedStruct struct0B = ref sequenceReader.GetRefOrRefToCopy(out _); + + MyUnmanagedStruct.Assert(Assert.AreEqual, struct0A, struct0B); + + SetConsumedAndAssert(ref sequenceReader, 1); + + SetConsumedAndAssert(ref sequenceReader, MyUnmanagedStruct.SizeOf); + + ref readonly MyUnmanagedStruct struct1A = ref sequenceReader.GetRefOrRefToCopy(out _); + + SetConsumedAndAssert(ref sequenceReader, MyUnmanagedStruct.SizeOf); + + ref readonly MyUnmanagedStruct struct1B = ref sequenceReader.GetRefOrRefToCopy(out _); + + MyUnmanagedStruct.Assert(Assert.AreEqual, struct1A, struct1B); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct MyUnmanagedStruct + { + public int BehaviourSize; + public int MemoryPoolsSize; + public short VoicesSize; + public int VoiceResourcesSize; + public short EffectsSize; + public int RenderInfoSize; + + public unsafe fixed byte Reserved[16]; + + public static readonly int SizeOf = Unsafe.SizeOf(); + + public static unsafe MyUnmanagedStruct Generate(Random rng) + { + const int BaseInt32Value = 0x1234abcd; + const short BaseInt16Value = 0x5678; + + var result = new MyUnmanagedStruct + { + BehaviourSize = BaseInt32Value ^ rng.Next(), + MemoryPoolsSize = BaseInt32Value ^ rng.Next(), + VoicesSize = (short)(BaseInt16Value ^ rng.Next()), + VoiceResourcesSize = BaseInt32Value ^ rng.Next(), + EffectsSize = (short)(BaseInt16Value ^ rng.Next()), + RenderInfoSize = BaseInt32Value ^ rng.Next(), + }; + + Unsafe.Write(result.Reserved, rng.NextInt64()); + + return result; + } + + public static unsafe void Assert(Action assert, in MyUnmanagedStruct expected, in MyUnmanagedStruct actual) + { + assert(expected.BehaviourSize, actual.BehaviourSize); + assert(expected.MemoryPoolsSize, actual.MemoryPoolsSize); + assert(expected.VoicesSize, actual.VoicesSize); + assert(expected.VoiceResourcesSize, actual.VoiceResourcesSize); + assert(expected.EffectsSize, actual.EffectsSize); + assert(expected.RenderInfoSize, actual.RenderInfoSize); + + fixed (void* expectedReservedPtr = expected.Reserved) + fixed (void* actualReservedPtr = actual.Reserved) + { + long expectedReservedLong = Unsafe.Read(expectedReservedPtr); + long actualReservedLong = Unsafe.Read(actualReservedPtr); + + assert(expectedReservedLong, actualReservedLong); + } + } + } + + private static IEnumerable EnumerateNewUnmanagedStructs() + { + var rng = new Random(0); + + while (true) + { + yield return MyUnmanagedStruct.Generate(rng); + } + } + + private static ReadOnlySequence CreateSegmentedByteSequence(T[] array, int maxSegmentLength) where T : unmanaged + { + byte[] arrayBytes = MemoryMarshal.AsBytes(array.AsSpan()).ToArray(); + var memory = new Memory(arrayBytes); + int index = 0; + + BytesReadOnlySequenceSegment first = null, last = null; + + while (index < memory.Length) + { + int nextSegmentLength = Math.Min(maxSegmentLength, memory.Length - index); + var nextSegment = memory.Slice(index, nextSegmentLength); + + if (first == null) + { + first = last = new BytesReadOnlySequenceSegment(nextSegment); + } + else + { + last = last.Append(nextSegment); + } + + index += nextSegmentLength; + } + + return new ReadOnlySequence(first, 0, last, (int)(memory.Length - last.RunningIndex)); + } + } +} diff --git a/src/Ryujinx.Tests/Cpu/CpuTest.cs b/src/Ryujinx.Tests/Cpu/CpuTest.cs index 35158c0b4..da0f03e6b 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTest.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTest.cs @@ -61,7 +61,6 @@ namespace Ryujinx.Tests.Cpu _memory.Map(DataBaseAddress, Size, Size, MemoryMapFlags.Private); _context = CpuContext.CreateExecutionContext(); - Translator.IsReadyForTranslation.Set(); _cpuContext = new CpuContext(_memory, for64Bit: true); diff --git a/src/Ryujinx.Tests/Cpu/CpuTest32.cs b/src/Ryujinx.Tests/Cpu/CpuTest32.cs index edfdbfa2f..dc0f5e23b 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTest32.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTest32.cs @@ -56,7 +56,6 @@ namespace Ryujinx.Tests.Cpu _context = CpuContext.CreateExecutionContext(); _context.IsAarch32 = true; - Translator.IsReadyForTranslation.Set(); _cpuContext = new CpuContext(_memory, for64Bit: false); diff --git a/src/Ryujinx.Tests/Cpu/CpuTestAlu32.cs b/src/Ryujinx.Tests/Cpu/CpuTestAlu32.cs index 41365c624..1e66d8112 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTestAlu32.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTestAlu32.cs @@ -25,6 +25,25 @@ namespace Ryujinx.Tests.Cpu }; } + private static uint[] UQAddSub16() + { + return new[] + { + 0xe6200f10u, // QADD16 R0, R0, R0 + 0xe6600f10u, // UQADD16 R0, R0, R0 + 0xe6600f70u, // UQSUB16 R0, R0, R0 + }; + } + + private static uint[] UQAddSub8() + { + return new[] + { + 0xe6600f90u, // UQADD8 R0, R0, R0 + 0xe6600ff0u, // UQSUB8 R0, R0, R0 + }; + } + private static uint[] SsatUsat() { return new[] @@ -182,6 +201,42 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + [Test, Pairwise] + public void U_Q_AddSub_16([ValueSource(nameof(UQAddSub16))] uint opcode, + [Values(0u, 0xdu)] uint rd, + [Values(1u)] uint rm, + [Values(2u)] uint rn, + [Random(RndCnt)] uint w0, + [Random(RndCnt)] uint w1, + [Random(RndCnt)] uint w2) + { + opcode |= ((rm & 15) << 0) | ((rd & 15) << 12) | ((rn & 15) << 16); + + uint sp = TestContext.CurrentContext.Random.NextUInt(); + + SingleOpcode(opcode, r0: w0, r1: w1, r2: w2, sp: sp); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void U_Q_AddSub_8([ValueSource(nameof(UQAddSub8))] uint opcode, + [Values(0u, 0xdu)] uint rd, + [Values(1u)] uint rm, + [Values(2u)] uint rn, + [Random(RndCnt)] uint w0, + [Random(RndCnt)] uint w1, + [Random(RndCnt)] uint w2) + { + opcode |= ((rm & 15) << 0) | ((rd & 15) << 12) | ((rn & 15) << 16); + + uint sp = TestContext.CurrentContext.Random.NextUInt(); + + SingleOpcode(opcode, r0: w0, r1: w1, r2: w2, sp: sp); + + CompareAgainstUnicorn(); + } + [Test, Pairwise] public void Uadd8_Sel([Values(0u)] uint rd, [Values(1u)] uint rm, diff --git a/src/Ryujinx.Tests/Cpu/CpuTestSimd32.cs b/src/Ryujinx.Tests/Cpu/CpuTestSimd32.cs index 6087a6834..08202c9e1 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTestSimd32.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTestSimd32.cs @@ -327,6 +327,55 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + + [Test, Pairwise, Description("VSHLL. {}, , #")] + public void Vshll([Values(0u, 2u)] uint rd, + [Values(1u, 0u)] uint rm, + [Values(0u, 1u, 2u)] uint size, + [Random(RndCnt)] ulong z, + [Random(RndCnt)] ulong a, + [Random(RndCnt)] ulong b) + { + uint opcode = 0xf3b20300u; // VSHLL.I8 Q0, D0, #8 + + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + opcode |= size << 18; + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, z); + V128 v2 = MakeVectorE0E1(b, z); + + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise, Description("VSWP D0, D0")] + public void Vswp([Values(0u, 1u)] uint rd, + [Values(0u, 1u)] uint rm, + [Values] bool q) + { + uint opcode = 0xf3b20000u; // VSWP D0, D0 + + if (q) + { + opcode |= 1u << 6; + + rd &= ~1u; + rm &= ~1u; + } + + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + + V128 v0 = new(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + V128 v1 = new(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + + SingleOpcode(opcode, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } #endif } } diff --git a/src/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs b/src/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs index 5b24432bb..ba201a480 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs @@ -511,6 +511,45 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + + [Test, Pairwise, Description("VRINTR.F , ")] + [Platform(Exclude = "Linux,MacOsX")] // Instruction isn't testable due to Unicorn. + public void Vrintr([Values(0u, 1u)] uint rd, + [Values(0u, 1u)] uint rm, + [Values(2u, 3u)] uint size, + [ValueSource(nameof(_1D_F_))] ulong s0, + [ValueSource(nameof(_1D_F_))] ulong s1, + [ValueSource(nameof(_1D_F_))] ulong s2, + [Values(RMode.Rn, RMode.Rm, RMode.Rp)] RMode rMode) + { + uint opcode = 0xEEB60A40; + + V128 v0, v1, v2; + + if (size == 2) + { + opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5); + opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22); + v0 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s0), (uint)BitConverter.SingleToInt32Bits(s0)); + v1 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s1), (uint)BitConverter.SingleToInt32Bits(s0)); + v2 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s2), (uint)BitConverter.SingleToInt32Bits(s1)); + } + else + { + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + v0 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s0), (uint)BitConverter.DoubleToInt64Bits(s0)); + v1 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s1), (uint)BitConverter.DoubleToInt64Bits(s0)); + v2 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s2), (uint)BitConverter.DoubleToInt64Bits(s1)); + } + + opcode |= ((size & 3) << 8); + + int fpscr = (int)rMode << (int)Fpcr.RMode; + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, fpscr: fpscr); + + CompareAgainstUnicorn(); + } #endif } } diff --git a/src/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs b/src/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs index 9d9606bba..843273dc2 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs @@ -908,6 +908,77 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + + [Test, Pairwise, Description("VQRDMULH. , , ")] + public void Vqrdmulh_I([Range(0u, 5u)] uint rd, + [Range(0u, 5u)] uint rn, + [Range(0u, 5u)] uint rm, + [ValueSource(nameof(_8B4H2S1D_))] ulong z, + [ValueSource(nameof(_8B4H2S1D_))] ulong a, + [ValueSource(nameof(_8B4H2S1D_))] ulong b, + [Values(1u, 2u)] uint size) // + { + rd >>= 1; + rd <<= 1; + rn >>= 1; + rn <<= 1; + rm >>= 1; + rm <<= 1; + + uint opcode = 0xf3100b40u & ~(3u << 20); // VQRDMULH.S16 Q0, Q0, Q0 + + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3); + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + + opcode |= (size & 0x3) << 20; + + V128 v0 = MakeVectorE0E1(z, ~z); + V128 v1 = MakeVectorE0E1(a, ~a); + V128 v2 = MakeVectorE0E1(b, ~b); + + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void Vp_Add_Long_Accumulate([Values(0u, 2u, 4u, 8u)] uint rd, + [Values(0u, 2u, 4u, 8u)] uint rm, + [Values(0u, 1u, 2u)] uint size, + [Random(RndCnt)] ulong z, + [Random(RndCnt)] ulong a, + [Random(RndCnt)] ulong b, + [Values] bool q, + [Values] bool unsigned) + { + uint opcode = 0xF3B00600; // VPADAL.S8 D0, Q0 + + if (q) + { + opcode |= 1 << 6; + rm <<= 1; + rd <<= 1; + } + + if (unsigned) + { + opcode |= 1 << 7; + } + + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + + opcode |= size << 18; + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, z); + V128 v2 = MakeVectorE0E1(b, z); + + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); + + CompareAgainstUnicorn(); + } #endif } } diff --git a/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs b/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs index fbac54c8c..9816bc2cc 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs @@ -311,6 +311,46 @@ namespace Ryujinx.Tests.Cpu }; } + private static uint[] _ShlImm_S_D_() + { + return new[] + { + 0x5F407400u, // SQSHL D0, D0, #0 + }; + } + + private static uint[] _ShlImm_V_8B_16B_() + { + return new[] + { + 0x0F087400u, // SQSHL V0.8B, V0.8B, #0 + }; + } + + private static uint[] _ShlImm_V_4H_8H_() + { + return new[] + { + 0x0F107400u, // SQSHL V0.4H, V0.4H, #0 + }; + } + + private static uint[] _ShlImm_V_2S_4S_() + { + return new[] + { + 0x0F207400u, // SQSHL V0.2S, V0.2S, #0 + }; + } + + private static uint[] _ShlImm_V_2D_() + { + return new[] + { + 0x4F407400u, // SQSHL V0.2D, V0.2D, #0 + }; + } + private static uint[] _ShrImm_Sri_S_D_() { return new[] @@ -813,6 +853,117 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + [Test, Pairwise] + public void ShlImm_S_D([ValueSource(nameof(_ShlImm_S_D_))] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource(nameof(_1D_))] ulong z, + [ValueSource(nameof(_1D_))] ulong a, + [Values(1u, 64u)] uint shift) + { + uint immHb = (64 + shift) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void ShlImm_V_8B_16B([ValueSource(nameof(_ShlImm_V_8B_16B_))] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource(nameof(_8B_))] ulong z, + [ValueSource(nameof(_8B_))] ulong a, + [Values(1u, 8u)] uint shift, + [Values(0b0u, 0b1u)] uint q) // <8B, 16B> + { + uint immHb = (8 + shift) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + opcodes |= ((q & 1) << 30); + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void ShlImm_V_4H_8H([ValueSource(nameof(_ShlImm_V_4H_8H_))] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource(nameof(_4H_))] ulong z, + [ValueSource(nameof(_4H_))] ulong a, + [Values(1u, 16u)] uint shift, + [Values(0b0u, 0b1u)] uint q) // <4H, 8H> + { + uint immHb = (16 + shift) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + opcodes |= ((q & 1) << 30); + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void ShlImm_V_2S_4S([ValueSource(nameof(_ShlImm_V_2S_4S_))] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource(nameof(_2S_))] ulong z, + [ValueSource(nameof(_2S_))] ulong a, + [Values(1u, 32u)] uint shift, + [Values(0b0u, 0b1u)] uint q) // <2S, 4S> + { + uint immHb = (32 + shift) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + opcodes |= (((q | (immHb >> 6)) & 1) << 30); + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void ShlImm_V_2D([ValueSource(nameof(_ShlImm_V_2D_))] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource(nameof(_1D_))] ulong z, + [ValueSource(nameof(_1D_))] ulong a, + [Values(1u, 64u)] uint shift) + { + uint immHb = (64 + shift) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + [Test, Pairwise] public void ShrImm_Sri_S_D([ValueSource(nameof(_ShrImm_Sri_S_D_))] uint opcodes, [Values(0u)] uint rd, diff --git a/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs b/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs index 39b50867f..7375f4d55 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs @@ -202,7 +202,7 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise, Description("VSHL. {}, , #")] - public void Vshl_Imm([Values(0u)] uint rd, + public void Vshl_Imm([Values(0u, 1u)] uint rd, [Values(2u, 0u)] uint rm, [Values(0u, 1u, 2u, 3u)] uint size, [Random(RndCntShiftImm)] uint shiftImm, @@ -262,6 +262,40 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + [Test, Pairwise, Description("VSLI. {}, , #")] + public void Vsli([Values(0u, 1u)] uint rd, + [Values(2u, 0u)] uint rm, + [Values(0u, 1u, 2u, 3u)] uint size, + [Random(RndCntShiftImm)] uint shiftImm, + [Random(RndCnt)] ulong z, + [Random(RndCnt)] ulong a, + [Random(RndCnt)] ulong b, + [Values] bool q) + { + uint opcode = 0xf3800510u; // VORR.I32 D0, #0x800000 (immediate value changes it into SLI) + if (q) + { + opcode |= 1 << 6; + rm <<= 1; + rd <<= 1; + } + + uint imm = 1u << ((int)size + 3); + imm |= shiftImm & (imm - 1); + + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + opcode |= ((imm & 0x3f) << 16) | ((imm & 0x40) << 1); + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, z); + V128 v2 = MakeVectorE0E1(b, z); + + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); + + CompareAgainstUnicorn(); + } + [Test, Pairwise] public void Vqshrn_Vqrshrn_Vrshrn_Imm([ValueSource(nameof(_Vqshrn_Vqrshrn_Vrshrn_Imm_))] uint opcode, [Values(0u, 1u)] uint rd, diff --git a/src/Ryujinx.Tests/Memory/PartialUnmaps.cs b/src/Ryujinx.Tests/Memory/PartialUnmaps.cs index 04f7f40e6..ace68e5c2 100644 --- a/src/Ryujinx.Tests/Memory/PartialUnmaps.cs +++ b/src/Ryujinx.Tests/Memory/PartialUnmaps.cs @@ -388,14 +388,14 @@ namespace Ryujinx.Tests.Memory { rwLock.AcquireReaderLock(); - int originalValue = Thread.VolatileRead(ref value); + int originalValue = Volatile.Read(ref value); count++; // Spin a bit. for (int i = 0; i < 100; i++) { - if (Thread.VolatileRead(ref readersAllowed) == 0) + if (Volatile.Read(ref readersAllowed) == 0) { error = true; running = false; @@ -403,7 +403,7 @@ namespace Ryujinx.Tests.Memory } // Should not change while the lock is held. - if (Thread.VolatileRead(ref value) != originalValue) + if (Volatile.Read(ref value) != originalValue) { error = true; running = false; diff --git a/src/Ryujinx.Ui.Common/App/ApplicationAddedEventArgs.cs b/src/Ryujinx.UI.Common/App/ApplicationAddedEventArgs.cs similarity index 81% rename from src/Ryujinx.Ui.Common/App/ApplicationAddedEventArgs.cs rename to src/Ryujinx.UI.Common/App/ApplicationAddedEventArgs.cs index 01e20276e..58e066b9d 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationAddedEventArgs.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationAddedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { public class ApplicationAddedEventArgs : EventArgs { diff --git a/src/Ryujinx.Ui.Common/App/ApplicationCountUpdatedEventArgs.cs b/src/Ryujinx.UI.Common/App/ApplicationCountUpdatedEventArgs.cs similarity index 85% rename from src/Ryujinx.Ui.Common/App/ApplicationCountUpdatedEventArgs.cs rename to src/Ryujinx.UI.Common/App/ApplicationCountUpdatedEventArgs.cs index ca54ddf7a..5ed7baf19 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationCountUpdatedEventArgs.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationCountUpdatedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { public class ApplicationCountUpdatedEventArgs : EventArgs { diff --git a/src/Ryujinx.Ui.Common/App/ApplicationData.cs b/src/Ryujinx.UI.Common/App/ApplicationData.cs similarity index 85% rename from src/Ryujinx.Ui.Common/App/ApplicationData.cs rename to src/Ryujinx.UI.Common/App/ApplicationData.cs index bd844805b..08bd2677d 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationData.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationData.cs @@ -9,20 +9,22 @@ using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.HLE.Loaders.Processes.Extensions; +using Ryujinx.UI.Common.Helper; using System; using System.IO; +using System.Text.Json.Serialization; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { public class ApplicationData { public bool Favorite { get; set; } public byte[] Icon { get; set; } - public string TitleName { get; set; } - public string TitleId { get; set; } - public string Developer { get; set; } - public string Version { get; set; } + public string Name { get; set; } = "Unknown"; + public ulong Id { get; set; } + public string Developer { get; set; } = "Unknown"; + public string Version { get; set; } = "0"; public TimeSpan TimePlayed { get; set; } public DateTime? LastPlayed { get; set; } public string FileExtension { get; set; } @@ -36,7 +38,13 @@ namespace Ryujinx.Ui.App.Common public string FileSizeString => ValueFormatUtils.FormatFileSize(FileSize); - public static string GetApplicationBuildId(VirtualFileSystem virtualFileSystem, string titleFilePath) + [JsonIgnore] public string IdString => Id.ToString("x16"); + + [JsonIgnore] public ulong IdBase => Id & ~0x1FFFUL; + + [JsonIgnore] public string IdBaseString => IdBase.ToString("x16"); + + public static string GetBuildId(VirtualFileSystem virtualFileSystem, IntegrityCheckLevel checkLevel, string titleFilePath) { using FileStream file = new(titleFilePath, FileMode.Open, FileAccess.Read); @@ -45,7 +53,7 @@ namespace Ryujinx.Ui.App.Common if (!System.IO.Path.Exists(titleFilePath)) { - Logger.Error?.Print(LogClass.Application, $"File does not exists. {titleFilePath}"); + Logger.Error?.Print(LogClass.Application, $"File \"{titleFilePath}\" does not exist."); return string.Empty; } @@ -105,7 +113,7 @@ namespace Ryujinx.Ui.App.Common return string.Empty; } - (Nca updatePatchNca, _) = ApplicationLibrary.GetGameUpdateData(virtualFileSystem, mainNca.Header.TitleId.ToString("x16"), 0, out _); + (Nca updatePatchNca, _) = mainNca.GetUpdateData(virtualFileSystem, checkLevel, 0, out string _); if (updatePatchNca != null) { diff --git a/src/Ryujinx.Ui.Common/App/ApplicationJsonSerializerContext.cs b/src/Ryujinx.UI.Common/App/ApplicationJsonSerializerContext.cs similarity index 88% rename from src/Ryujinx.Ui.Common/App/ApplicationJsonSerializerContext.cs rename to src/Ryujinx.UI.Common/App/ApplicationJsonSerializerContext.cs index 9a7b3eddf..ada7cc346 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationJsonSerializerContext.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationJsonSerializerContext.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(ApplicationMetadata))] diff --git a/src/Ryujinx.Ui.Common/App/ApplicationMetadata.cs b/src/Ryujinx.UI.Common/App/ApplicationMetadata.cs similarity index 98% rename from src/Ryujinx.Ui.Common/App/ApplicationMetadata.cs rename to src/Ryujinx.UI.Common/App/ApplicationMetadata.cs index 43647feef..81193c5b3 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationMetadata.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationMetadata.cs @@ -1,7 +1,7 @@ using System; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { public class ApplicationMetadata { diff --git a/src/Ryujinx.Ui.Common/Configuration/AudioBackend.cs b/src/Ryujinx.UI.Common/Configuration/AudioBackend.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Configuration/AudioBackend.cs rename to src/Ryujinx.UI.Common/Configuration/AudioBackend.cs index dc0a5ac61..a952e7ac0 100644 --- a/src/Ryujinx.Ui.Common/Configuration/AudioBackend.cs +++ b/src/Ryujinx.UI.Common/Configuration/AudioBackend.cs @@ -1,7 +1,7 @@ using Ryujinx.Common.Utilities; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { [JsonConverter(typeof(TypedStringEnumConverter))] public enum AudioBackend diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs similarity index 96% rename from src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs rename to src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs index 8a4db1fe7..8a0be4028 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs @@ -3,19 +3,19 @@ using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Configuration.System; -using Ryujinx.Ui.Common.Configuration.Ui; +using Ryujinx.UI.Common.Configuration.System; +using Ryujinx.UI.Common.Configuration.UI; using System.Collections.Generic; using System.Text.Json.Nodes; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { public class ConfigurationFileFormat { /// /// The current version of the file format /// - public const int CurrentVersion = 48; + public const int CurrentVersion = 51; /// /// Version of the configuration file format @@ -162,6 +162,16 @@ namespace Ryujinx.Ui.Common.Configuration /// public bool ShowConfirmExit { get; set; } + /// + /// Enables or disables save window size, position and state on close. + /// + public bool RememberWindowState { get; set; } + + /// + /// Enables hardware-accelerated rendering for Avalonia + /// + public bool EnableHardwareAcceleration { get; set; } + /// /// Whether to hide cursor on idle, always or never /// @@ -228,7 +238,7 @@ namespace Ryujinx.Ui.Common.Configuration public MemoryManagerMode MemoryManagerMode { get; set; } /// - /// Expands the RAM amount on the emulated system from 4GiB to 6GiB + /// Expands the RAM amount on the emulated system from 4GiB to 8GiB /// public bool ExpandRam { get; set; } diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormatSettings.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormatSettings.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormatSettings.cs rename to src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormatSettings.cs index 9a1841fc5..9861ebf1f 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormatSettings.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormatSettings.cs @@ -1,6 +1,6 @@ using Ryujinx.Common.Utilities; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { internal static class ConfigurationFileFormatSettings { diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationJsonSerializerContext.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationJsonSerializerContext.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Configuration/ConfigurationJsonSerializerContext.cs rename to src/Ryujinx.UI.Common/Configuration/ConfigurationJsonSerializerContext.cs index 03989edec..3c3e3f20d 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationJsonSerializerContext.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationJsonSerializerContext.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(ConfigurationFileFormat))] diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs similarity index 87% rename from src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs rename to src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs index 52575a7e3..bc9ccc706 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs @@ -6,21 +6,22 @@ using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Logging; using Ryujinx.Graphics.Vulkan; -using Ryujinx.Ui.Common.Configuration.System; -using Ryujinx.Ui.Common.Configuration.Ui; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Configuration.System; +using Ryujinx.UI.Common.Configuration.UI; +using Ryujinx.UI.Common.Helper; using System; using System.Collections.Generic; +using System.Globalization; using System.Text.Json.Nodes; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { public class ConfigurationState { /// /// UI configuration section /// - public class UiSection + public class UISection { public class Columns { @@ -186,7 +187,7 @@ namespace Ryujinx.Ui.Common.Configuration /// public ReactiveObject IsAscendingOrder { get; private set; } - public UiSection() + public UISection() { GuiColumns = new Columns(); ColumnSort = new ColumnSortSettings(); @@ -582,9 +583,9 @@ namespace Ryujinx.Ui.Common.Configuration public static ConfigurationState Instance { get; private set; } /// - /// The Ui section + /// The UI section /// - public UiSection Ui { get; private set; } + public UISection UI { get; private set; } /// /// The Logger section @@ -626,6 +627,16 @@ namespace Ryujinx.Ui.Common.Configuration /// public ReactiveObject ShowConfirmExit { get; private set; } + /// + /// Enables or disables save window size, position and state on close. + /// + public ReactiveObject RememberWindowState { get; private set; } + + /// + /// Enables hardware-accelerated rendering for Avalonia + /// + public ReactiveObject EnableHardwareAcceleration { get; private set; } + /// /// Hide Cursor on Idle /// @@ -633,7 +644,7 @@ namespace Ryujinx.Ui.Common.Configuration private ConfigurationState() { - Ui = new UiSection(); + UI = new UISection(); Logger = new LoggerSection(); System = new SystemSection(); Graphics = new GraphicsSection(); @@ -642,6 +653,8 @@ namespace Ryujinx.Ui.Common.Configuration EnableDiscordIntegration = new ReactiveObject(); CheckUpdatesOnStart = new ReactiveObject(); ShowConfirmExit = new ReactiveObject(); + RememberWindowState = new ReactiveObject(); + EnableHardwareAcceleration = new ReactiveObject(); HideCursor = new ReactiveObject(); } @@ -678,6 +691,8 @@ namespace Ryujinx.Ui.Common.Configuration EnableDiscordIntegration = EnableDiscordIntegration, CheckUpdatesOnStart = CheckUpdatesOnStart, ShowConfirmExit = ShowConfirmExit, + RememberWindowState = RememberWindowState, + EnableHardwareAcceleration = EnableHardwareAcceleration, HideCursor = HideCursor, EnableVsync = Graphics.EnableVsync, EnableShaderCache = Graphics.EnableShaderCache, @@ -696,51 +711,51 @@ namespace Ryujinx.Ui.Common.Configuration UseHypervisor = System.UseHypervisor, GuiColumns = new GuiColumns { - FavColumn = Ui.GuiColumns.FavColumn, - IconColumn = Ui.GuiColumns.IconColumn, - AppColumn = Ui.GuiColumns.AppColumn, - DevColumn = Ui.GuiColumns.DevColumn, - VersionColumn = Ui.GuiColumns.VersionColumn, - TimePlayedColumn = Ui.GuiColumns.TimePlayedColumn, - LastPlayedColumn = Ui.GuiColumns.LastPlayedColumn, - FileExtColumn = Ui.GuiColumns.FileExtColumn, - FileSizeColumn = Ui.GuiColumns.FileSizeColumn, - PathColumn = Ui.GuiColumns.PathColumn, + FavColumn = UI.GuiColumns.FavColumn, + IconColumn = UI.GuiColumns.IconColumn, + AppColumn = UI.GuiColumns.AppColumn, + DevColumn = UI.GuiColumns.DevColumn, + VersionColumn = UI.GuiColumns.VersionColumn, + TimePlayedColumn = UI.GuiColumns.TimePlayedColumn, + LastPlayedColumn = UI.GuiColumns.LastPlayedColumn, + FileExtColumn = UI.GuiColumns.FileExtColumn, + FileSizeColumn = UI.GuiColumns.FileSizeColumn, + PathColumn = UI.GuiColumns.PathColumn, }, ColumnSort = new ColumnSort { - SortColumnId = Ui.ColumnSort.SortColumnId, - SortAscending = Ui.ColumnSort.SortAscending, + SortColumnId = UI.ColumnSort.SortColumnId, + SortAscending = UI.ColumnSort.SortAscending, }, - GameDirs = Ui.GameDirs, + GameDirs = UI.GameDirs, ShownFileTypes = new ShownFileTypes { - NSP = Ui.ShownFileTypes.NSP, - PFS0 = Ui.ShownFileTypes.PFS0, - XCI = Ui.ShownFileTypes.XCI, - NCA = Ui.ShownFileTypes.NCA, - NRO = Ui.ShownFileTypes.NRO, - NSO = Ui.ShownFileTypes.NSO, + NSP = UI.ShownFileTypes.NSP, + PFS0 = UI.ShownFileTypes.PFS0, + XCI = UI.ShownFileTypes.XCI, + NCA = UI.ShownFileTypes.NCA, + NRO = UI.ShownFileTypes.NRO, + NSO = UI.ShownFileTypes.NSO, }, WindowStartup = new WindowStartup { - WindowSizeWidth = Ui.WindowStartup.WindowSizeWidth, - WindowSizeHeight = Ui.WindowStartup.WindowSizeHeight, - WindowPositionX = Ui.WindowStartup.WindowPositionX, - WindowPositionY = Ui.WindowStartup.WindowPositionY, - WindowMaximized = Ui.WindowStartup.WindowMaximized, + WindowSizeWidth = UI.WindowStartup.WindowSizeWidth, + WindowSizeHeight = UI.WindowStartup.WindowSizeHeight, + WindowPositionX = UI.WindowStartup.WindowPositionX, + WindowPositionY = UI.WindowStartup.WindowPositionY, + WindowMaximized = UI.WindowStartup.WindowMaximized, }, - LanguageCode = Ui.LanguageCode, - EnableCustomTheme = Ui.EnableCustomTheme, - CustomThemePath = Ui.CustomThemePath, - BaseStyle = Ui.BaseStyle, - GameListViewMode = Ui.GameListViewMode, - ShowNames = Ui.ShowNames, - GridSize = Ui.GridSize, - ApplicationSort = Ui.ApplicationSort, - IsAscendingOrder = Ui.IsAscendingOrder, - StartFullscreen = Ui.StartFullscreen, - ShowConsole = Ui.ShowConsole, + LanguageCode = UI.LanguageCode, + EnableCustomTheme = UI.EnableCustomTheme, + CustomThemePath = UI.CustomThemePath, + BaseStyle = UI.BaseStyle, + GameListViewMode = UI.GameListViewMode, + ShowNames = UI.ShowNames, + GridSize = UI.GridSize, + ApplicationSort = UI.ApplicationSort, + IsAscendingOrder = UI.IsAscendingOrder, + StartFullscreen = UI.StartFullscreen, + ShowConsole = UI.ShowConsole, EnableKeyboard = Hid.EnableKeyboard, EnableMouse = Hid.EnableMouse, Hotkeys = Hid.Hotkeys, @@ -785,6 +800,8 @@ namespace Ryujinx.Ui.Common.Configuration EnableDiscordIntegration.Value = true; CheckUpdatesOnStart.Value = true; ShowConfirmExit.Value = true; + RememberWindowState.Value = true; + EnableHardwareAcceleration.Value = true; HideCursor.Value = HideCursorMode.OnIdle; Graphics.EnableVsync.Value = true; Graphics.EnableShaderCache.Value = true; @@ -806,41 +823,41 @@ namespace Ryujinx.Ui.Common.Configuration System.UseHypervisor.Value = true; Multiplayer.LanInterfaceId.Value = "0"; Multiplayer.Mode.Value = MultiplayerMode.Disabled; - Ui.GuiColumns.FavColumn.Value = true; - Ui.GuiColumns.IconColumn.Value = true; - Ui.GuiColumns.AppColumn.Value = true; - Ui.GuiColumns.DevColumn.Value = true; - Ui.GuiColumns.VersionColumn.Value = true; - Ui.GuiColumns.TimePlayedColumn.Value = true; - Ui.GuiColumns.LastPlayedColumn.Value = true; - Ui.GuiColumns.FileExtColumn.Value = true; - Ui.GuiColumns.FileSizeColumn.Value = true; - Ui.GuiColumns.PathColumn.Value = true; - Ui.ColumnSort.SortColumnId.Value = 0; - Ui.ColumnSort.SortAscending.Value = false; - Ui.GameDirs.Value = new List(); - Ui.ShownFileTypes.NSP.Value = true; - Ui.ShownFileTypes.PFS0.Value = true; - Ui.ShownFileTypes.XCI.Value = true; - Ui.ShownFileTypes.NCA.Value = true; - Ui.ShownFileTypes.NRO.Value = true; - Ui.ShownFileTypes.NSO.Value = true; - Ui.EnableCustomTheme.Value = true; - Ui.LanguageCode.Value = "en_US"; - Ui.CustomThemePath.Value = ""; - Ui.BaseStyle.Value = "Dark"; - Ui.GameListViewMode.Value = 0; - Ui.ShowNames.Value = true; - Ui.GridSize.Value = 2; - Ui.ApplicationSort.Value = 0; - Ui.IsAscendingOrder.Value = true; - Ui.StartFullscreen.Value = false; - Ui.ShowConsole.Value = true; - Ui.WindowStartup.WindowSizeWidth.Value = 1280; - Ui.WindowStartup.WindowSizeHeight.Value = 760; - Ui.WindowStartup.WindowPositionX.Value = 0; - Ui.WindowStartup.WindowPositionY.Value = 0; - Ui.WindowStartup.WindowMaximized.Value = false; + UI.GuiColumns.FavColumn.Value = true; + UI.GuiColumns.IconColumn.Value = true; + UI.GuiColumns.AppColumn.Value = true; + UI.GuiColumns.DevColumn.Value = true; + UI.GuiColumns.VersionColumn.Value = true; + UI.GuiColumns.TimePlayedColumn.Value = true; + UI.GuiColumns.LastPlayedColumn.Value = true; + UI.GuiColumns.FileExtColumn.Value = true; + UI.GuiColumns.FileSizeColumn.Value = true; + UI.GuiColumns.PathColumn.Value = true; + UI.ColumnSort.SortColumnId.Value = 0; + UI.ColumnSort.SortAscending.Value = false; + UI.GameDirs.Value = new List(); + UI.ShownFileTypes.NSP.Value = true; + UI.ShownFileTypes.PFS0.Value = true; + UI.ShownFileTypes.XCI.Value = true; + UI.ShownFileTypes.NCA.Value = true; + UI.ShownFileTypes.NRO.Value = true; + UI.ShownFileTypes.NSO.Value = true; + UI.EnableCustomTheme.Value = true; + UI.LanguageCode.Value = "en_US"; + UI.CustomThemePath.Value = ""; + UI.BaseStyle.Value = "Dark"; + UI.GameListViewMode.Value = 0; + UI.ShowNames.Value = true; + UI.GridSize.Value = 2; + UI.ApplicationSort.Value = 0; + UI.IsAscendingOrder.Value = true; + UI.StartFullscreen.Value = false; + UI.ShowConsole.Value = true; + UI.WindowStartup.WindowSizeWidth.Value = 1280; + UI.WindowStartup.WindowSizeHeight.Value = 760; + UI.WindowStartup.WindowPositionX.Value = 0; + UI.WindowStartup.WindowPositionY.Value = 0; + UI.WindowStartup.WindowMaximized.Value = false; Hid.EnableKeyboard.Value = false; Hid.EnableMouse.Value = false; Hid.Hotkeys.Value = new KeyboardHotkeys @@ -848,7 +865,7 @@ namespace Ryujinx.Ui.Common.Configuration ToggleVsync = Key.F1, ToggleMute = Key.F2, Screenshot = Key.F8, - ShowUi = Key.F4, + ShowUI = Key.F4, Pause = Key.F5, ResScaleUp = Key.Unbound, ResScaleDown = Key.Unbound, @@ -1185,7 +1202,7 @@ namespace Ryujinx.Ui.Common.Configuration { ToggleVsync = Key.F1, Screenshot = Key.F8, - ShowUi = Key.F4, + ShowUI = Key.F4, }; configurationFileUpdated = true; @@ -1228,7 +1245,7 @@ namespace Ryujinx.Ui.Common.Configuration { ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, Screenshot = configurationFileFormat.Hotkeys.Screenshot, - ShowUi = configurationFileFormat.Hotkeys.ShowUi, + ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = Key.F5, }; @@ -1243,7 +1260,7 @@ namespace Ryujinx.Ui.Common.Configuration { ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, Screenshot = configurationFileFormat.Hotkeys.Screenshot, - ShowUi = configurationFileFormat.Hotkeys.ShowUi, + ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = configurationFileFormat.Hotkeys.Pause, ToggleMute = Key.F2, }; @@ -1317,7 +1334,7 @@ namespace Ryujinx.Ui.Common.Configuration { ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, Screenshot = configurationFileFormat.Hotkeys.Screenshot, - ShowUi = configurationFileFormat.Hotkeys.ShowUi, + ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = configurationFileFormat.Hotkeys.Pause, ToggleMute = configurationFileFormat.Hotkeys.ToggleMute, ResScaleUp = Key.Unbound, @@ -1344,7 +1361,7 @@ namespace Ryujinx.Ui.Common.Configuration { ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, Screenshot = configurationFileFormat.Hotkeys.Screenshot, - ShowUi = configurationFileFormat.Hotkeys.ShowUi, + ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = configurationFileFormat.Hotkeys.Pause, ToggleMute = configurationFileFormat.Hotkeys.ToggleMute, ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp, @@ -1430,6 +1447,36 @@ namespace Ryujinx.Ui.Common.Configuration configurationFileUpdated = true; } + if (configurationFileFormat.Version < 49) + { + Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 49."); + + if (OperatingSystem.IsMacOS()) + { + AppDataManager.FixMacOSConfigurationFolders(); + } + + configurationFileUpdated = true; + } + + if (configurationFileFormat.Version < 50) + { + Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 50."); + + configurationFileFormat.EnableHardwareAcceleration = true; + + configurationFileUpdated = true; + } + + if (configurationFileFormat.Version < 51) + { + Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 51."); + + configurationFileFormat.RememberWindowState = true; + + configurationFileUpdated = true; + } + Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog; Graphics.ResScale.Value = configurationFileFormat.ResScale; Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom; @@ -1460,6 +1507,8 @@ namespace Ryujinx.Ui.Common.Configuration EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration; CheckUpdatesOnStart.Value = configurationFileFormat.CheckUpdatesOnStart; ShowConfirmExit.Value = configurationFileFormat.ShowConfirmExit; + RememberWindowState.Value = configurationFileFormat.RememberWindowState; + EnableHardwareAcceleration.Value = configurationFileFormat.EnableHardwareAcceleration; HideCursor.Value = configurationFileFormat.HideCursor; Graphics.EnableVsync.Value = configurationFileFormat.EnableVsync; Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache; @@ -1476,41 +1525,41 @@ namespace Ryujinx.Ui.Common.Configuration System.ExpandRam.Value = configurationFileFormat.ExpandRam; System.IgnoreMissingServices.Value = configurationFileFormat.IgnoreMissingServices; System.UseHypervisor.Value = configurationFileFormat.UseHypervisor; - Ui.GuiColumns.FavColumn.Value = configurationFileFormat.GuiColumns.FavColumn; - Ui.GuiColumns.IconColumn.Value = configurationFileFormat.GuiColumns.IconColumn; - Ui.GuiColumns.AppColumn.Value = configurationFileFormat.GuiColumns.AppColumn; - Ui.GuiColumns.DevColumn.Value = configurationFileFormat.GuiColumns.DevColumn; - Ui.GuiColumns.VersionColumn.Value = configurationFileFormat.GuiColumns.VersionColumn; - Ui.GuiColumns.TimePlayedColumn.Value = configurationFileFormat.GuiColumns.TimePlayedColumn; - Ui.GuiColumns.LastPlayedColumn.Value = configurationFileFormat.GuiColumns.LastPlayedColumn; - Ui.GuiColumns.FileExtColumn.Value = configurationFileFormat.GuiColumns.FileExtColumn; - Ui.GuiColumns.FileSizeColumn.Value = configurationFileFormat.GuiColumns.FileSizeColumn; - Ui.GuiColumns.PathColumn.Value = configurationFileFormat.GuiColumns.PathColumn; - Ui.ColumnSort.SortColumnId.Value = configurationFileFormat.ColumnSort.SortColumnId; - Ui.ColumnSort.SortAscending.Value = configurationFileFormat.ColumnSort.SortAscending; - Ui.GameDirs.Value = configurationFileFormat.GameDirs; - Ui.ShownFileTypes.NSP.Value = configurationFileFormat.ShownFileTypes.NSP; - Ui.ShownFileTypes.PFS0.Value = configurationFileFormat.ShownFileTypes.PFS0; - Ui.ShownFileTypes.XCI.Value = configurationFileFormat.ShownFileTypes.XCI; - Ui.ShownFileTypes.NCA.Value = configurationFileFormat.ShownFileTypes.NCA; - Ui.ShownFileTypes.NRO.Value = configurationFileFormat.ShownFileTypes.NRO; - Ui.ShownFileTypes.NSO.Value = configurationFileFormat.ShownFileTypes.NSO; - Ui.EnableCustomTheme.Value = configurationFileFormat.EnableCustomTheme; - Ui.LanguageCode.Value = configurationFileFormat.LanguageCode; - Ui.CustomThemePath.Value = configurationFileFormat.CustomThemePath; - Ui.BaseStyle.Value = configurationFileFormat.BaseStyle; - Ui.GameListViewMode.Value = configurationFileFormat.GameListViewMode; - Ui.ShowNames.Value = configurationFileFormat.ShowNames; - Ui.IsAscendingOrder.Value = configurationFileFormat.IsAscendingOrder; - Ui.GridSize.Value = configurationFileFormat.GridSize; - Ui.ApplicationSort.Value = configurationFileFormat.ApplicationSort; - Ui.StartFullscreen.Value = configurationFileFormat.StartFullscreen; - Ui.ShowConsole.Value = configurationFileFormat.ShowConsole; - Ui.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth; - Ui.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight; - Ui.WindowStartup.WindowPositionX.Value = configurationFileFormat.WindowStartup.WindowPositionX; - Ui.WindowStartup.WindowPositionY.Value = configurationFileFormat.WindowStartup.WindowPositionY; - Ui.WindowStartup.WindowMaximized.Value = configurationFileFormat.WindowStartup.WindowMaximized; + UI.GuiColumns.FavColumn.Value = configurationFileFormat.GuiColumns.FavColumn; + UI.GuiColumns.IconColumn.Value = configurationFileFormat.GuiColumns.IconColumn; + UI.GuiColumns.AppColumn.Value = configurationFileFormat.GuiColumns.AppColumn; + UI.GuiColumns.DevColumn.Value = configurationFileFormat.GuiColumns.DevColumn; + UI.GuiColumns.VersionColumn.Value = configurationFileFormat.GuiColumns.VersionColumn; + UI.GuiColumns.TimePlayedColumn.Value = configurationFileFormat.GuiColumns.TimePlayedColumn; + UI.GuiColumns.LastPlayedColumn.Value = configurationFileFormat.GuiColumns.LastPlayedColumn; + UI.GuiColumns.FileExtColumn.Value = configurationFileFormat.GuiColumns.FileExtColumn; + UI.GuiColumns.FileSizeColumn.Value = configurationFileFormat.GuiColumns.FileSizeColumn; + UI.GuiColumns.PathColumn.Value = configurationFileFormat.GuiColumns.PathColumn; + UI.ColumnSort.SortColumnId.Value = configurationFileFormat.ColumnSort.SortColumnId; + UI.ColumnSort.SortAscending.Value = configurationFileFormat.ColumnSort.SortAscending; + UI.GameDirs.Value = configurationFileFormat.GameDirs; + UI.ShownFileTypes.NSP.Value = configurationFileFormat.ShownFileTypes.NSP; + UI.ShownFileTypes.PFS0.Value = configurationFileFormat.ShownFileTypes.PFS0; + UI.ShownFileTypes.XCI.Value = configurationFileFormat.ShownFileTypes.XCI; + UI.ShownFileTypes.NCA.Value = configurationFileFormat.ShownFileTypes.NCA; + UI.ShownFileTypes.NRO.Value = configurationFileFormat.ShownFileTypes.NRO; + UI.ShownFileTypes.NSO.Value = configurationFileFormat.ShownFileTypes.NSO; + UI.EnableCustomTheme.Value = configurationFileFormat.EnableCustomTheme; + UI.LanguageCode.Value = configurationFileFormat.LanguageCode; + UI.CustomThemePath.Value = configurationFileFormat.CustomThemePath; + UI.BaseStyle.Value = configurationFileFormat.BaseStyle; + UI.GameListViewMode.Value = configurationFileFormat.GameListViewMode; + UI.ShowNames.Value = configurationFileFormat.ShowNames; + UI.IsAscendingOrder.Value = configurationFileFormat.IsAscendingOrder; + UI.GridSize.Value = configurationFileFormat.GridSize; + UI.ApplicationSort.Value = configurationFileFormat.ApplicationSort; + UI.StartFullscreen.Value = configurationFileFormat.StartFullscreen; + UI.ShowConsole.Value = configurationFileFormat.ShowConsole; + UI.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth; + UI.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight; + UI.WindowStartup.WindowPositionX.Value = configurationFileFormat.WindowStartup.WindowPositionX; + UI.WindowStartup.WindowPositionY.Value = configurationFileFormat.WindowStartup.WindowPositionY; + UI.WindowStartup.WindowMaximized.Value = configurationFileFormat.WindowStartup.WindowMaximized; Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard; Hid.EnableMouse.Value = configurationFileFormat.EnableMouse; Hid.Hotkeys.Value = configurationFileFormat.Hotkeys; @@ -1546,7 +1595,9 @@ namespace Ryujinx.Ui.Common.Configuration private static void LogValueChange(ReactiveEventArgs eventArgs, string valueName) { - Ryujinx.Common.Logging.Logger.Info?.Print(LogClass.Configuration, $"{valueName} set to: {eventArgs.NewValue}"); + string message = string.Create(CultureInfo.InvariantCulture, $"{valueName} set to: {eventArgs.NewValue}"); + + Ryujinx.Common.Logging.Logger.Info?.Print(LogClass.Configuration, message); } public static void Initialize() diff --git a/src/Ryujinx.Ui.Common/Configuration/FileTypes.cs b/src/Ryujinx.UI.Common/Configuration/FileTypes.cs similarity index 81% rename from src/Ryujinx.Ui.Common/Configuration/FileTypes.cs rename to src/Ryujinx.UI.Common/Configuration/FileTypes.cs index 9d2f63864..1974207b6 100644 --- a/src/Ryujinx.Ui.Common/Configuration/FileTypes.cs +++ b/src/Ryujinx.UI.Common/Configuration/FileTypes.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common +namespace Ryujinx.UI.Common { public enum FileTypes { diff --git a/src/Ryujinx.Ui.Common/Configuration/LoggerModule.cs b/src/Ryujinx.UI.Common/Configuration/LoggerModule.cs similarity index 81% rename from src/Ryujinx.Ui.Common/Configuration/LoggerModule.cs rename to src/Ryujinx.UI.Common/Configuration/LoggerModule.cs index 54ad20dd7..9cb283593 100644 --- a/src/Ryujinx.Ui.Common/Configuration/LoggerModule.cs +++ b/src/Ryujinx.UI.Common/Configuration/LoggerModule.cs @@ -1,9 +1,11 @@ using Ryujinx.Common; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Logging.Targets; using System; +using System.IO; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { public static class LoggerModule { @@ -80,8 +82,24 @@ namespace Ryujinx.Ui.Common.Configuration { if (e.NewValue) { + string logDir = AppDataManager.LogsDirPath; + FileStream logFile = null; + + if (!string.IsNullOrEmpty(logDir)) + { + logFile = FileLogTarget.PrepareLogFile(logDir); + } + + if (logFile == null) + { + Logger.Error?.Print(LogClass.Application, "No writable log directory available. Make sure either the Logs directory, Application Data, or the Ryujinx directory is writable."); + Logger.RemoveTarget("file"); + + return; + } + Logger.AddTarget(new AsyncLogTargetWrapper( - new FileLogTarget(ReleaseInformation.GetBaseApplicationDirectory(), "file"), + new FileLogTarget("file", logFile), 1000, AsyncLogTargetOverflowAction.Block )); diff --git a/src/Ryujinx.Ui.Common/Configuration/System/Language.cs b/src/Ryujinx.UI.Common/Configuration/System/Language.cs similarity index 91% rename from src/Ryujinx.Ui.Common/Configuration/System/Language.cs rename to src/Ryujinx.UI.Common/Configuration/System/Language.cs index 72416bfe7..d1d395b00 100644 --- a/src/Ryujinx.Ui.Common/Configuration/System/Language.cs +++ b/src/Ryujinx.UI.Common/Configuration/System/Language.cs @@ -1,7 +1,7 @@ using Ryujinx.Common.Utilities; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Configuration.System +namespace Ryujinx.UI.Common.Configuration.System { [JsonConverter(typeof(TypedStringEnumConverter))] public enum Language diff --git a/src/Ryujinx.Ui.Common/Configuration/System/Region.cs b/src/Ryujinx.UI.Common/Configuration/System/Region.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Configuration/System/Region.cs rename to src/Ryujinx.UI.Common/Configuration/System/Region.cs index 2478b40f9..6087c70e5 100644 --- a/src/Ryujinx.Ui.Common/Configuration/System/Region.cs +++ b/src/Ryujinx.UI.Common/Configuration/System/Region.cs @@ -1,7 +1,7 @@ using Ryujinx.Common.Utilities; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Configuration.System +namespace Ryujinx.UI.Common.Configuration.System { [JsonConverter(typeof(TypedStringEnumConverter))] public enum Region diff --git a/src/Ryujinx.Ui.Common/Configuration/Ui/ColumnSort.cs b/src/Ryujinx.UI.Common/Configuration/UI/ColumnSort.cs similarity index 75% rename from src/Ryujinx.Ui.Common/Configuration/Ui/ColumnSort.cs rename to src/Ryujinx.UI.Common/Configuration/UI/ColumnSort.cs index 88cf7cdac..44e98c407 100644 --- a/src/Ryujinx.Ui.Common/Configuration/Ui/ColumnSort.cs +++ b/src/Ryujinx.UI.Common/Configuration/UI/ColumnSort.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common.Configuration.Ui +namespace Ryujinx.UI.Common.Configuration.UI { public struct ColumnSort { diff --git a/src/Ryujinx.Ui.Common/Configuration/Ui/GuiColumns.cs b/src/Ryujinx.UI.Common/Configuration/UI/GuiColumns.cs similarity index 91% rename from src/Ryujinx.Ui.Common/Configuration/Ui/GuiColumns.cs rename to src/Ryujinx.UI.Common/Configuration/UI/GuiColumns.cs index 7e944015b..c778ef1f1 100644 --- a/src/Ryujinx.Ui.Common/Configuration/Ui/GuiColumns.cs +++ b/src/Ryujinx.UI.Common/Configuration/UI/GuiColumns.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common.Configuration.Ui +namespace Ryujinx.UI.Common.Configuration.UI { public struct GuiColumns { diff --git a/src/Ryujinx.Ui.Common/Configuration/Ui/ShownFileTypes.cs b/src/Ryujinx.UI.Common/Configuration/UI/ShownFileTypes.cs similarity index 86% rename from src/Ryujinx.Ui.Common/Configuration/Ui/ShownFileTypes.cs rename to src/Ryujinx.UI.Common/Configuration/UI/ShownFileTypes.cs index 1b14fd467..6c72a6930 100644 --- a/src/Ryujinx.Ui.Common/Configuration/Ui/ShownFileTypes.cs +++ b/src/Ryujinx.UI.Common/Configuration/UI/ShownFileTypes.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common.Configuration.Ui +namespace Ryujinx.UI.Common.Configuration.UI { public struct ShownFileTypes { diff --git a/src/Ryujinx.Ui.Common/Configuration/Ui/WindowStartup.cs b/src/Ryujinx.UI.Common/Configuration/UI/WindowStartup.cs similarity index 86% rename from src/Ryujinx.Ui.Common/Configuration/Ui/WindowStartup.cs rename to src/Ryujinx.UI.Common/Configuration/UI/WindowStartup.cs index ce0dde6aa..0df459134 100644 --- a/src/Ryujinx.Ui.Common/Configuration/Ui/WindowStartup.cs +++ b/src/Ryujinx.UI.Common/Configuration/UI/WindowStartup.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common.Configuration.Ui +namespace Ryujinx.UI.Common.Configuration.UI { public struct WindowStartup { diff --git a/src/Ryujinx.Ui.Common/DiscordIntegrationModule.cs b/src/Ryujinx.UI.Common/DiscordIntegrationModule.cs similarity index 60% rename from src/Ryujinx.Ui.Common/DiscordIntegrationModule.cs rename to src/Ryujinx.UI.Common/DiscordIntegrationModule.cs index edc634aa5..6966038b6 100644 --- a/src/Ryujinx.Ui.Common/DiscordIntegrationModule.cs +++ b/src/Ryujinx.UI.Common/DiscordIntegrationModule.cs @@ -1,13 +1,17 @@ using DiscordRPC; using Ryujinx.Common; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; +using System.Text; -namespace Ryujinx.Ui.Common +namespace Ryujinx.UI.Common { public static class DiscordIntegrationModule { private const string Description = "A simple, experimental Nintendo Switch emulator."; - private const string CliendId = "568815339807309834"; + private const string ApplicationId = "1216775165866807456"; + + private const int ApplicationByteLimit = 128; + private const string Ellipsis = "…"; private static DiscordRpcClient _discordClient; private static RichPresence _discordPresenceMain; @@ -24,14 +28,14 @@ namespace Ryujinx.Ui.Common Details = "Main Menu", State = "Idling", Timestamps = Timestamps.Now, - Buttons = new[] - { + Buttons = + [ new Button { Label = "Website", - Url = "https://ryujinx.org/", + Url = "https://ryujinx.org/", }, - }, + ], }; ConfigurationState.Instance.EnableDiscordIntegration.Event += Update; @@ -52,7 +56,7 @@ namespace Ryujinx.Ui.Common // If we need to activate it and the client isn't active, initialize it if (evnt.NewValue && _discordClient == null) { - _discordClient = new DiscordRpcClient(CliendId); + _discordClient = new DiscordRpcClient(ApplicationId); _discordClient.Initialize(); _discordClient.SetPresence(_discordPresenceMain); @@ -60,28 +64,28 @@ namespace Ryujinx.Ui.Common } } - public static void SwitchToPlayingState(string titleId, string titleName) + public static void SwitchToPlayingState(string titleId, string applicationName) { _discordClient?.SetPresence(new RichPresence { Assets = new Assets { LargeImageKey = "game", - LargeImageText = titleName, + LargeImageText = TruncateToByteLength(applicationName, ApplicationByteLimit), SmallImageKey = "ryujinx", SmallImageText = Description, }, - Details = $"Playing {titleName}", + Details = TruncateToByteLength($"Playing {applicationName}", ApplicationByteLimit), State = (titleId == "0000000000000000") ? "Homebrew" : titleId.ToUpper(), Timestamps = Timestamps.Now, - Buttons = new[] - { + Buttons = + [ new Button { Label = "Website", Url = "https://ryujinx.org/", }, - }, + ], }); } @@ -90,6 +94,33 @@ namespace Ryujinx.Ui.Common _discordClient?.SetPresence(_discordPresenceMain); } + private static string TruncateToByteLength(string input, int byteLimit) + { + if (Encoding.UTF8.GetByteCount(input) <= byteLimit) + { + return input; + } + + // Find the length to trim the string to guarantee we have space for the trailing ellipsis. + int trimLimit = byteLimit - Encoding.UTF8.GetByteCount(Ellipsis); + + // Make sure the string is long enough to perform the basic trim. + // Amount of bytes != Length of the string + if (input.Length > trimLimit) + { + // Basic trim to best case scenario of 1 byte characters. + input = input[..trimLimit]; + } + + while (Encoding.UTF8.GetByteCount(input) > trimLimit) + { + // Remove one character from the end of the string at a time. + input = input[..^1]; + } + + return input.TrimEnd() + Ellipsis; + } + public static void Exit() { _discordClient?.Dispose(); diff --git a/src/Ryujinx.Ui.Common/Extensions/FileTypeExtensions.cs b/src/Ryujinx.UI.Common/Extensions/FileTypeExtensions.cs similarity index 91% rename from src/Ryujinx.Ui.Common/Extensions/FileTypeExtensions.cs rename to src/Ryujinx.UI.Common/Extensions/FileTypeExtensions.cs index c827f750e..7e71ba7a4 100644 --- a/src/Ryujinx.Ui.Common/Extensions/FileTypeExtensions.cs +++ b/src/Ryujinx.UI.Common/Extensions/FileTypeExtensions.cs @@ -1,7 +1,7 @@ using System; -using static Ryujinx.Ui.Common.Configuration.ConfigurationState.UiSection; +using static Ryujinx.UI.Common.Configuration.ConfigurationState.UISection; -namespace Ryujinx.Ui.Common +namespace Ryujinx.UI.Common { public static class FileTypesExtensions { diff --git a/src/Ryujinx.Ui.Common/Helper/CommandLineState.cs b/src/Ryujinx.UI.Common/Helper/CommandLineState.cs similarity index 87% rename from src/Ryujinx.Ui.Common/Helper/CommandLineState.cs rename to src/Ryujinx.UI.Common/Helper/CommandLineState.cs index 714cf2f0a..ae0e4d904 100644 --- a/src/Ryujinx.Ui.Common/Helper/CommandLineState.cs +++ b/src/Ryujinx.UI.Common/Helper/CommandLineState.cs @@ -1,18 +1,20 @@ using Ryujinx.Common.Logging; using System.Collections.Generic; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static class CommandLineState { public static string[] Arguments { get; private set; } public static bool? OverrideDockedMode { get; private set; } + public static bool? OverrideHardwareAcceleration { get; private set; } public static string OverrideGraphicsBackend { get; private set; } public static string OverrideHideCursor { get; private set; } public static string BaseDirPathArg { get; private set; } public static string Profile { get; private set; } public static string LaunchPathArg { get; private set; } + public static string LaunchApplicationId { get; private set; } public static bool StartFullscreenArg { get; private set; } public static void ParseArguments(string[] args) @@ -71,6 +73,10 @@ namespace Ryujinx.Ui.Common.Helper OverrideGraphicsBackend = args[++i]; break; + case "-i": + case "--application-id": + LaunchApplicationId = args[++i]; + break; case "--docked-mode": OverrideDockedMode = true; break; @@ -87,6 +93,9 @@ namespace Ryujinx.Ui.Common.Helper OverrideHideCursor = args[++i]; break; + case "--software-gui": + OverrideHardwareAcceleration = false; + break; default: LaunchPathArg = arg; break; diff --git a/src/Ryujinx.Ui.Common/Helper/ConsoleHelper.cs b/src/Ryujinx.UI.Common/Helper/ConsoleHelper.cs similarity index 97% rename from src/Ryujinx.Ui.Common/Helper/ConsoleHelper.cs rename to src/Ryujinx.UI.Common/Helper/ConsoleHelper.cs index 65155641f..208ff5c9d 100644 --- a/src/Ryujinx.Ui.Common/Helper/ConsoleHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/ConsoleHelper.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static partial class ConsoleHelper { diff --git a/src/Ryujinx.Ui.Common/Helper/FileAssociationHelper.cs b/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs similarity index 97% rename from src/Ryujinx.Ui.Common/Helper/FileAssociationHelper.cs rename to src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs index 570fb91e2..7ed020319 100644 --- a/src/Ryujinx.Ui.Common/Helper/FileAssociationHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs @@ -7,7 +7,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static partial class FileAssociationHelper { @@ -22,7 +22,7 @@ namespace Ryujinx.Ui.Common.Helper [LibraryImport("shell32.dll", SetLastError = true)] public static partial void SHChangeNotify(uint wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2); - public static bool IsTypeAssociationSupported => (OperatingSystem.IsLinux() || OperatingSystem.IsWindows()) && !ReleaseInformation.IsFlatHubBuild(); + public static bool IsTypeAssociationSupported => (OperatingSystem.IsLinux() || OperatingSystem.IsWindows()) && !ReleaseInformation.IsFlatHubBuild; [SupportedOSPlatform("linux")] private static bool AreMimeTypesRegisteredLinux() => File.Exists(Path.Combine(_mimeDbPath, "packages", "Ryujinx.xml")); @@ -34,7 +34,7 @@ namespace Ryujinx.Ui.Common.Helper if ((uninstall && AreMimeTypesRegisteredLinux()) || (!uninstall && !AreMimeTypesRegisteredLinux())) { - string mimeTypesFile = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "mime", "Ryujinx.xml"); + string mimeTypesFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "mime", "Ryujinx.xml"); string additionalArgs = !uninstall ? "--novendor" : ""; using Process mimeProcess = new(); diff --git a/src/Ryujinx.Ui.Common/Helper/LinuxHelper.cs b/src/Ryujinx.UI.Common/Helper/LinuxHelper.cs similarity index 98% rename from src/Ryujinx.Ui.Common/Helper/LinuxHelper.cs rename to src/Ryujinx.UI.Common/Helper/LinuxHelper.cs index bf647719a..b57793791 100644 --- a/src/Ryujinx.Ui.Common/Helper/LinuxHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/LinuxHelper.cs @@ -3,7 +3,7 @@ using System.Diagnostics; using System.IO; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { [SupportedOSPlatform("linux")] public static class LinuxHelper diff --git a/src/Ryujinx.Ui.Common/Helper/ObjectiveC.cs b/src/Ryujinx.UI.Common/Helper/ObjectiveC.cs similarity index 99% rename from src/Ryujinx.Ui.Common/Helper/ObjectiveC.cs rename to src/Ryujinx.UI.Common/Helper/ObjectiveC.cs index 16a67ecb2..a60aaa75f 100644 --- a/src/Ryujinx.Ui.Common/Helper/ObjectiveC.cs +++ b/src/Ryujinx.UI.Common/Helper/ObjectiveC.cs @@ -2,7 +2,7 @@ using System; using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { [SupportedOSPlatform("macos")] [SupportedOSPlatform("ios")] diff --git a/src/Ryujinx.Ui.Common/Helper/OpenHelper.cs b/src/Ryujinx.UI.Common/Helper/OpenHelper.cs similarity index 99% rename from src/Ryujinx.Ui.Common/Helper/OpenHelper.cs rename to src/Ryujinx.UI.Common/Helper/OpenHelper.cs index 04ebbf3b0..af6170afe 100644 --- a/src/Ryujinx.Ui.Common/Helper/OpenHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/OpenHelper.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static partial class OpenHelper { diff --git a/src/Ryujinx.Ui.Common/Helper/SetupValidator.cs b/src/Ryujinx.UI.Common/Helper/SetupValidator.cs similarity index 99% rename from src/Ryujinx.Ui.Common/Helper/SetupValidator.cs rename to src/Ryujinx.UI.Common/Helper/SetupValidator.cs index 65c38d7b8..a954be26f 100644 --- a/src/Ryujinx.Ui.Common/Helper/SetupValidator.cs +++ b/src/Ryujinx.UI.Common/Helper/SetupValidator.cs @@ -3,7 +3,7 @@ using Ryujinx.HLE.FileSystem; using System; using System.IO; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { /// /// Ensure installation validity diff --git a/src/Ryujinx.Ui.Common/Helper/ShortcutHelper.cs b/src/Ryujinx.UI.Common/Helper/ShortcutHelper.cs similarity index 69% rename from src/Ryujinx.Ui.Common/Helper/ShortcutHelper.cs rename to src/Ryujinx.UI.Common/Helper/ShortcutHelper.cs index 97b9853db..1849f40cb 100644 --- a/src/Ryujinx.Ui.Common/Helper/ShortcutHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/ShortcutHelper.cs @@ -1,59 +1,54 @@ using Ryujinx.Common; using Ryujinx.Common.Configuration; using ShellLink; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; +using SkiaSharp; using System; using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; using System.IO; using System.Runtime.Versioning; -using Image = System.Drawing.Image; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static class ShortcutHelper { [SupportedOSPlatform("windows")] - private static void CreateShortcutWindows(string applicationFilePath, byte[] iconData, string iconPath, string cleanedAppName, string desktopPath) + private static void CreateShortcutWindows(string applicationFilePath, string applicationId, byte[] iconData, string iconPath, string cleanedAppName, string desktopPath) { string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.FriendlyName + ".exe"); iconPath += ".ico"; MemoryStream iconDataStream = new(iconData); - using Image image = Image.FromStream(iconDataStream); - using Bitmap bitmap = new(128, 128); - using System.Drawing.Graphics graphic = System.Drawing.Graphics.FromImage(bitmap); - graphic.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphic.DrawImage(image, 0, 0, 128, 128); - SaveBitmapAsIcon(bitmap, iconPath); + using var image = SKBitmap.Decode(iconDataStream); + image.Resize(new SKImageInfo(128, 128), SKFilterQuality.High); + SaveBitmapAsIcon(image, iconPath); - var shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(applicationFilePath), iconPath, 0); + var shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(applicationFilePath, applicationId), iconPath, 0); shortcut.StringData.NameString = cleanedAppName; shortcut.WriteToFile(Path.Combine(desktopPath, cleanedAppName + ".lnk")); } [SupportedOSPlatform("linux")] - private static void CreateShortcutLinux(string applicationFilePath, byte[] iconData, string iconPath, string desktopPath, string cleanedAppName) + private static void CreateShortcutLinux(string applicationFilePath, string applicationId, byte[] iconData, string iconPath, string desktopPath, string cleanedAppName) { string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.sh"); - var desktopFile = EmbeddedResources.ReadAllText("Ryujinx.Ui.Common/shortcut-template.desktop"); + var desktopFile = EmbeddedResources.ReadAllText("Ryujinx.UI.Common/shortcut-template.desktop"); iconPath += ".png"; - var image = SixLabors.ImageSharp.Image.Load(iconData); - image.SaveAsPng(iconPath); + var image = SKBitmap.Decode(iconData); + using var data = image.Encode(SKEncodedImageFormat.Png, 100); + using var file = File.OpenWrite(iconPath); + data.SaveTo(file); using StreamWriter outputFile = new(Path.Combine(desktopPath, cleanedAppName + ".desktop")); - outputFile.Write(desktopFile, cleanedAppName, iconPath, $"{basePath} {GetArgsString(applicationFilePath)}"); + outputFile.Write(desktopFile, cleanedAppName, iconPath, $"{basePath} {GetArgsString(applicationFilePath, applicationId)}"); } [SupportedOSPlatform("macos")] - private static void CreateShortcutMacos(string appFilePath, byte[] iconData, string desktopPath, string cleanedAppName) + private static void CreateShortcutMacos(string appFilePath, string applicationId, byte[] iconData, string desktopPath, string cleanedAppName) { string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx"); - var plistFile = EmbeddedResources.ReadAllText("Ryujinx.Ui.Common/shortcut-template.plist"); + var plistFile = EmbeddedResources.ReadAllText("Ryujinx.UI.Common/shortcut-template.plist"); + var shortcutScript = EmbeddedResources.ReadAllText("Ryujinx.UI.Common/shortcut-launch-script.sh"); // Macos .App folder string contentFolderPath = Path.Combine("/Applications", cleanedAppName + ".app", "Contents"); string scriptFolderPath = Path.Combine(contentFolderPath, "MacOS"); @@ -68,8 +63,7 @@ namespace Ryujinx.Ui.Common.Helper string scriptPath = Path.Combine(scriptFolderPath, ScriptName); using StreamWriter scriptFile = new(scriptPath); - scriptFile.WriteLine("#!/bin/sh"); - scriptFile.WriteLine($"{basePath} {GetArgsString(appFilePath)}"); + scriptFile.Write(shortcutScript, basePath, GetArgsString(appFilePath, applicationId)); // Set execute permission FileInfo fileInfo = new(scriptPath); @@ -83,8 +77,10 @@ namespace Ryujinx.Ui.Common.Helper } const string IconName = "icon.png"; - var image = SixLabors.ImageSharp.Image.Load(iconData); - image.SaveAsPng(Path.Combine(resourceFolderPath, IconName)); + var image = SKBitmap.Decode(iconData); + using var data = image.Encode(SKEncodedImageFormat.Png, 100); + using var file = File.OpenWrite(Path.Combine(resourceFolderPath, IconName)); + data.SaveTo(file); // plist file using StreamWriter outputFile = new(Path.Combine(contentFolderPath, "Info.plist")); @@ -100,7 +96,7 @@ namespace Ryujinx.Ui.Common.Helper { string iconPath = Path.Combine(AppDataManager.BaseDirPath, "games", applicationId, "app"); - CreateShortcutWindows(applicationFilePath, iconData, iconPath, cleanedAppName, desktopPath); + CreateShortcutWindows(applicationFilePath, applicationId, iconData, iconPath, cleanedAppName, desktopPath); return; } @@ -110,14 +106,14 @@ namespace Ryujinx.Ui.Common.Helper string iconPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share", "icons", "Ryujinx"); Directory.CreateDirectory(iconPath); - CreateShortcutLinux(applicationFilePath, iconData, Path.Combine(iconPath, applicationId), desktopPath, cleanedAppName); + CreateShortcutLinux(applicationFilePath, applicationId, iconData, Path.Combine(iconPath, applicationId), desktopPath, cleanedAppName); return; } if (OperatingSystem.IsMacOS()) { - CreateShortcutMacos(applicationFilePath, iconData, desktopPath, cleanedAppName); + CreateShortcutMacos(applicationFilePath, applicationId, iconData, desktopPath, cleanedAppName); return; } @@ -125,7 +121,7 @@ namespace Ryujinx.Ui.Common.Helper throw new NotImplementedException("Shortcut support has not been implemented yet for this OS."); } - private static string GetArgsString(string appFilePath) + private static string GetArgsString(string appFilePath, string applicationId) { // args are first defined as a list, for easier adjustments in the future var argsList = new List(); @@ -136,6 +132,12 @@ namespace Ryujinx.Ui.Common.Helper argsList.Add($"\"{CommandLineState.BaseDirPathArg}\""); } + if (appFilePath.ToLower().EndsWith(".xci")) + { + argsList.Add("--application-id"); + argsList.Add($"\"{applicationId}\""); + } + argsList.Add($"\"{appFilePath}\""); return String.Join(" ", argsList); @@ -147,7 +149,7 @@ namespace Ryujinx.Ui.Common.Helper /// The source bitmap image that will be saved as an .ico file /// The location that the new .ico file will be saved too (Make sure to include '.ico' in the path). [SupportedOSPlatform("windows")] - private static void SaveBitmapAsIcon(Bitmap source, string filePath) + private static void SaveBitmapAsIcon(SKBitmap source, string filePath) { // Code Modified From https://stackoverflow.com/a/11448060/368354 by Benlitz byte[] header = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 32, 0, 0, 0, 0, 0, 22, 0, 0, 0 }; @@ -155,13 +157,16 @@ namespace Ryujinx.Ui.Common.Helper fs.Write(header); // Writing actual data - source.Save(fs, ImageFormat.Png); + using var data = source.Encode(SKEncodedImageFormat.Png, 100); + data.SaveTo(fs); // Getting data length (file length minus header) long dataLength = fs.Length - header.Length; // Write it in the correct place fs.Seek(14, SeekOrigin.Begin); fs.WriteByte((byte)dataLength); fs.WriteByte((byte)(dataLength >> 8)); + fs.WriteByte((byte)(dataLength >> 16)); + fs.WriteByte((byte)(dataLength >> 24)); } } } diff --git a/src/Ryujinx.Ui.Common/Helper/TitleHelper.cs b/src/Ryujinx.UI.Common/Helper/TitleHelper.cs similarity index 96% rename from src/Ryujinx.Ui.Common/Helper/TitleHelper.cs rename to src/Ryujinx.UI.Common/Helper/TitleHelper.cs index 089b52154..8b47ac38b 100644 --- a/src/Ryujinx.Ui.Common/Helper/TitleHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/TitleHelper.cs @@ -1,7 +1,7 @@ using Ryujinx.HLE.Loaders.Processes; using System; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static class TitleHelper { diff --git a/src/Ryujinx.Ui.Common/Helper/ValueFormatUtils.cs b/src/Ryujinx.UI.Common/Helper/ValueFormatUtils.cs similarity index 99% rename from src/Ryujinx.Ui.Common/Helper/ValueFormatUtils.cs rename to src/Ryujinx.UI.Common/Helper/ValueFormatUtils.cs index b1597a7cc..8ea3e721f 100644 --- a/src/Ryujinx.Ui.Common/Helper/ValueFormatUtils.cs +++ b/src/Ryujinx.UI.Common/Helper/ValueFormatUtils.cs @@ -2,7 +2,7 @@ using System; using System.Globalization; using System.Linq; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static class ValueFormatUtils { diff --git a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApi.cs b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApi.cs similarity index 97% rename from src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApi.cs rename to src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApi.cs index ff0b80c46..7989f0f1a 100644 --- a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApi.cs +++ b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApi.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Amiibo +namespace Ryujinx.UI.Common.Models.Amiibo { public struct AmiiboApi : IEquatable { diff --git a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs similarity index 90% rename from src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs rename to src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs index 3c62b7cc4..40e635bf0 100644 --- a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs +++ b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Amiibo +namespace Ryujinx.UI.Common.Models.Amiibo { public class AmiiboApiGamesSwitch { diff --git a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiUsage.cs b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiUsage.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiUsage.cs rename to src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiUsage.cs index 3c774fd56..4f8d292b1 100644 --- a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiUsage.cs +++ b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiUsage.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Amiibo +namespace Ryujinx.UI.Common.Models.Amiibo { public class AmiiboApiUsage { diff --git a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJson.cs b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJson.cs similarity index 88% rename from src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJson.cs rename to src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJson.cs index c9d91c50a..15083f505 100644 --- a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJson.cs +++ b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJson.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Amiibo +namespace Ryujinx.UI.Common.Models.Amiibo { public struct AmiiboJson { diff --git a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs similarity index 80% rename from src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs rename to src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs index 4906c6524..bc3f1303c 100644 --- a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs +++ b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Amiibo +namespace Ryujinx.UI.Common.Models.Amiibo { [JsonSerializable(typeof(AmiiboJson))] public partial class AmiiboJsonSerializerContext : JsonSerializerContext diff --git a/src/Ryujinx.Ui.Common/Models/Github/GithubReleaseAssetJsonResponse.cs b/src/Ryujinx.UI.Common/Models/Github/GithubReleaseAssetJsonResponse.cs similarity index 82% rename from src/Ryujinx.Ui.Common/Models/Github/GithubReleaseAssetJsonResponse.cs rename to src/Ryujinx.UI.Common/Models/Github/GithubReleaseAssetJsonResponse.cs index 67d238d24..8f528dc0b 100644 --- a/src/Ryujinx.Ui.Common/Models/Github/GithubReleaseAssetJsonResponse.cs +++ b/src/Ryujinx.UI.Common/Models/Github/GithubReleaseAssetJsonResponse.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common.Models.Github +namespace Ryujinx.UI.Common.Models.Github { public class GithubReleaseAssetJsonResponse { diff --git a/src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonResponse.cs b/src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonResponse.cs similarity index 83% rename from src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonResponse.cs rename to src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonResponse.cs index 0f83e32cc..0250e1094 100644 --- a/src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonResponse.cs +++ b/src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonResponse.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Ryujinx.Ui.Common.Models.Github +namespace Ryujinx.UI.Common.Models.Github { public class GithubReleasesJsonResponse { diff --git a/src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonSerializerContext.cs b/src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonSerializerContext.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonSerializerContext.cs rename to src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonSerializerContext.cs index 8a19277b3..71864257c 100644 --- a/src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonSerializerContext.cs +++ b/src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonSerializerContext.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Github +namespace Ryujinx.UI.Common.Models.Github { [JsonSerializable(typeof(GithubReleasesJsonResponse), GenerationMode = JsonSourceGenerationMode.Metadata)] public partial class GithubReleasesJsonSerializerContext : JsonSerializerContext diff --git a/src/Ryujinx.Ui.Common/Resources/Controller_JoyConLeft.svg b/src/Ryujinx.UI.Common/Resources/Controller_JoyConLeft.svg similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Controller_JoyConLeft.svg rename to src/Ryujinx.UI.Common/Resources/Controller_JoyConLeft.svg diff --git a/src/Ryujinx.Ui.Common/Resources/Controller_JoyConPair.svg b/src/Ryujinx.UI.Common/Resources/Controller_JoyConPair.svg similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Controller_JoyConPair.svg rename to src/Ryujinx.UI.Common/Resources/Controller_JoyConPair.svg diff --git a/src/Ryujinx.Ui.Common/Resources/Controller_JoyConRight.svg b/src/Ryujinx.UI.Common/Resources/Controller_JoyConRight.svg similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Controller_JoyConRight.svg rename to src/Ryujinx.UI.Common/Resources/Controller_JoyConRight.svg diff --git a/src/Ryujinx.Ui.Common/Resources/Controller_ProCon.svg b/src/Ryujinx.UI.Common/Resources/Controller_ProCon.svg similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Controller_ProCon.svg rename to src/Ryujinx.UI.Common/Resources/Controller_ProCon.svg diff --git a/src/Ryujinx.UI.Common/Resources/Icon_Blank.png b/src/Ryujinx.UI.Common/Resources/Icon_Blank.png new file mode 100644 index 0000000000000000000000000000000000000000..d2bba8a92f5dd5254d10460b9f6f0af468f8a1af GIT binary patch literal 16179 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 RX(j*w002ovPDHLkV1lP50o?!q literal 0 HcmV?d00001 diff --git a/src/Ryujinx.UI.Common/Resources/Icon_NCA.png b/src/Ryujinx.UI.Common/Resources/Icon_NCA.png new file mode 100644 index 0000000000000000000000000000000000000000..99def6cfd74712bffad207f9186a78f4ae141cd1 GIT binary patch literal 18432 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 literal 0 HcmV?d00001 diff --git a/src/Ryujinx.UI.Common/Resources/Icon_NRO.png b/src/Ryujinx.UI.Common/Resources/Icon_NRO.png new file mode 100644 index 0000000000000000000000000000000000000000..6cec176ad3d9ebccb5eac6e6e5562e380457b514 GIT binary patch literal 18404 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 LNkvXXu0mjfJl$nS literal 0 HcmV?d00001 diff --git a/src/Ryujinx.UI.Common/Resources/Icon_NSO.png b/src/Ryujinx.UI.Common/Resources/Icon_NSO.png new file mode 100644 index 0000000000000000000000000000000000000000..ad88459cfc9515dbf5f8ee0a909eb35d078e37e8 GIT binary patch literal 18705 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 fAl6k?RX6Gf@e(sXmR4CoPKZ}jNQje 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 Ef(IoLLI3~& literal 0 HcmV?d00001 diff --git a/src/Ryujinx.UI.Common/Resources/Icon_XCI.png b/src/Ryujinx.UI.Common/Resources/Icon_XCI.png new file mode 100644 index 0000000000000000000000000000000000000000..ef33f281620a5998b261a385c1be245c6febc391 GIT binary patch literal 18220 zcmX_{Wl$X7)3#S|x8SnD-CY-V50>B%T!Z`K8a%<>o!|s_cM{xwxI=J%`By#lR?Y03 z`LHw7r+2&ix=&A}nu;ts3NZ=*06>?QlhObHfbT;f014s!p#QDZ;{60>Eh(wyq9H2* zk(ZX_*VLQIT!2@wFk1$eg`FNF2e2Bpsa~ ziWHw85l!M>@*p;Iw(0@m_Q8L})$qg{+zsZ7cibHi6n2OvGadc8_Ssz!Dz_REXGq%P zNA?=ky3arBe|BF|Ts-KP7n8y>$U;J}EVHG+)E)QaGyYp1aAss1Ip7A*tlYaDRlXZq z5^A|{RX)2c z((l~o^&#I#s%(SQltrrb?gnT?}>&qv9z>Q+sufxtcF$7@#IVUQ)jgBB)}H9tPFx~zgQWTU7vX5%*i4- zj_Ry+zXGpE9-96*@>p0-g=gkxyt@S1NlwoN0KljD-wu@5puPYAq&4KF#6Nj1pJak# z>=p6DjyKB_{1>L0@M7#&&=7hS(dc}e>{s45D-z8&`Ocl3AJH=dXVpJG+2r83vn(vr zeV|v%g$9D)QSkn6U;#Hjx<1yHn#cYjfPgaf)rUr>{7Tr22xcW zkj7;>`2`i9+0*ZAwRNhpdEI;8|GI#p|w?kI>NronH?Q3$ zPw=jsaJ#7oVdEjFi9~LUOTCq?IJBKouyx-5=Pm(9LuZbin-~wV1*)_|wBr|<==dWT zIZ{R7;w)TxE3mIiRXHa1b7 z#%lEWMp{a?8-{n7_K# z8K#PB*Gbe5uaqQ6uxu3j$^!ZN!zjF3m{RW(LjogXILrjCN>Dsmu%T!*GUyi%pOS>v zCwni8%3&-k*#N9G&IZEp(paX$j#^9z=Wi=Uz`QM6dYs39w$48`ltGsKl|*~pUNb{P z@LwyV1<)xaZ@q-&|CM-M?G@SKTcHiwPGk{vqmwwcU)F3qOnR(Wn8Ds>srD9l%RAc=KAO|Wx*CWz=?A^-JQrTUJK3ZU7h2C3p=S>xb zWAmE3rR}i={wH$cxtM#)4c9s40Kw~N$-7BJVLC}-Qc|V0wY9?uz6~W25fKGST{1hS zaF}?qRZ`G2b&47l6&0h4RA8=^tUwd3i>H{#lVH2i2}xRf^CeHcjE;SR&95$8`IESv zTW`W3p_6Gq=Kb1gWO-Y+y;F7;GCNxg^jxU=$FJ?>B_v-iB0@Z zzmKb*{>%0`6L1^n7+U4bQVM)@rF@-J5jxH7!w@=g)H_;myKwBd(e^$pN||MBn3mhKDxyeE08TL+%;tSzbpK&f5Y4^`QKm@TO;(wg@Fz+aF=~w=0e% zI!1mxyBYcOD=QVhxIMNH3gTXU{xW0YRa+CI>k)Q;mUz}NaQkyUDSS0fkvqG~BuZ8o zVL0XF>H!E$p2-VYuH2Ce`y9jVA|Y7-LxM`(2}(Mt_gR%?O(N-rS4_xpr8vdJCA-xR zLJ(2rZ}vh$rS?4Lc?n6hRvq;r&`0msPnHy~*@PK98fObRnX<0TGRk2u zGud3`q^HUfk}*)vLay2Nl5FoI%$m-}qYV`T+UZmTjIO1nvA58U+hyCX%6|(x!`MC1 z7e%A+h&e`V(lu>ViMV7q6eD3*lQj>Y5G6SL+kXZ@<`-7VV=uGV4-5JUJF~wIG9hI; zeWZPqa`e7VmaXx=zL=9Sd#qo1p4`zFx)dmNu^-I}s_u{~Q)xYCF>HJk^nLTkZ+8I{ z<2G_RM4D?HdGK;=oOU|91FNbmxFfFPx`6Q$So(hkm zqrtJ=vD7<&L`K0x{U08YNG)sUQu5>-e^jW;hXTXXNzZ$>{XFztt_}D(q>X)3Mpf8% zI@u_~y%#Y4`yPoa9N7fxGU7|q&9GIkCK_PsJ5Y*wMHDwTg$WoOPJPBEuXc_!DQ)+E zI&BVkJ`Z?%3MG15ulzRwE$E#!qI5lb|Gl{$Y{!Xpc2IX=DD!6GAi-0%SgvD3-Da-H zJ5E>wN%iZ19E$_kVmKL8m69j>A-h=iRy5srSY{;ocrpHHG#*xUZ=P}I*=}@@BYmz5 z!MO5}TKzw9r~joF;1k@@K`?*8Cl5eN?tS!>dU+58e(sxRu5f2$TWX~N=NT(o$KT^? zwAk+{(Wgwhk)=O>Xv`)5HD_zFvc`H>f2(eU3oBLcaJMEc%51)}t@~imxFt57#nt5E ziX-@M)Qf@Itm+5ctysXTFZ|z@pTXC0?wwrLIyYH8c~P=eNWBA6E(jDgWS7XTVOz^R zoWVa`-TToG>|A5J9{<#c-W{q2JSse34KSgAbwzCPNgSRg9Q|E(B{4-B+TzQrswRSc zRz=-=^D}>crNo$x<;|A0-f9NU1LyNP1!quKv)yuf-=pG;DWLOjd0@rOs7s~a=XTFa z&aSkGye{>t{47N4!*K(bX!XE^R!s_`pu`m9=OsTha_+(nQ;^U}ZJ)u?+jYXKxtfCJ zAMU`<(nW8XsBG1X5N}(h zz9h&0^C?~$t+kFkLhj3fasUSrf zF$1@eLf9{PwHU$Ln0|a@A}~?*;F2`UHo4yYZ>!ZzezK(67bVzZIlvNPS;?KYVCeHb z1GBj#k_bYma6?Yj{X{EXt3Sue^*9wAMyQH>LuS!U{KMspqhDyfzt&xe5Dq#xz_$Ni z^ryz77houmyN*$S&FIAsNoW?VBz*G25<~kn(8}Yt>&KYC%7}yF`8{fIqPznBh<}SM zosC+g805aWFlav6lB+{n6VQRV=@0AjV&sTEzf5 z#yDmdOyNnv1-MM0+N6oCXtVg5(gl>TnFRha$!J;12>y8aJ-G~27MeDFyVd5|Tr>ag zf)H^MEF@a~T=><`>u_r9`t`{T0wvqG*l_4~{9wvm%0xYVOLs=lHcVkN0cG|Qe@*ZP0=rk2XqL6iYKK4q3yWwwVLueXx|L^IbAThQ=Zc!=I)cUK9nZBa zu4A?P_A9Z3M|hOYkezIb=Pi6WWSQ=XxS(eI<%K|n3KRuWXw$;pQISu(uuh=qx6PbRdPQreTOFx@z&XpSVbB?&;#PLcSCp&&R@1}95O_H3bSYq51|GKWhjxYrs z*K~Cb5%t#yJ4;P{aH#hFj}0w1?0O$MEMG1OhCq?-tSNe>Xg{s;{p?kDKJ)=JUvH5*{zbP?E1IzhUB(e?X``$_taE9SreFt>%IckMqDR za?X0`HclT+??Eem1${%|BPrwM&Vn9JJ@0O`&b(1BC|?v zrYNbPN9eFg0XBnIqjtHnQZa~&r1*1hfta$}lyZh!105vHYpB*3Y2!^SKT1u0fj?Gk zH)KpuGTvs7;+PsDV}(Z#VR07Dh~fOeHOb$PIr6*_M6GKK;?Jr;nke_NQ6G36StqlC z;7N%Sk`HyhQJvGGnZaC*Q!$g_+*`Fg-UVSt=D zeC<-m|CK(j1z(aE(#{V0D_^xS(uMOo5XhqIMWRdtj4Zc`%;bK-LQ;sv0%iR^i(R1wpuLS-XNStcm zpU`P+EhbdWfsP%`{FXP*X5)PMSCsBI%Z|grg=dir(UUcBJW~%o!lqbSW1{W<0PO#7 zx>6Zy6VzUg#kWc~8KZ{t6DsT4yA|m?LGr41hjS%<2<{S_djqj?H&@# zb=L9z4%?v8#34x~Ujz@}lZVJraxkny7w%+1ivhPATWiq#WGax!2&rpZy_InBspsF> zlEP#5M&*pL*PR2E-;|}CPJakfc1DNt?2As3YE<`k)S{Xvw#GuLTH_Fy~h&w4N4HTvl)VMu;ZhmJeqf z!1{01OILNHyT(b6bLKpv>{r;|4)OLVf}~DMuLqnh@L;fK3N!Fc1|3q%R~fg-=V-Fz zkN53}yX^I@Ni`MaXlPhFVR0w6VE4+?(YX3x18*Czbl%fdSez$ zvGPu1VP$+4J{2s2yqoje;KT{WZVS+#WU|Dd)@@e!tq>ZQ8B;172Yt@q0qO{f?SSaw zk_?}*{uad%f_-X{odatJMc3Q)Ofh#H3BAz(Zx5())7`Hp8(2Q5>DYbH%ASwYcLxNv z`>DdGnH|fTkzVfV@u)3az@-UtdIYHYmm=M+H<mibuFWler4e|NUEbsRSr=LYw z%iU_YkYbj@;kIVhHMBqKY1Y@nnp=OVwG)K3gea!tEo&)W@P!!0I4sIR9;3!+BI3IB zG@+nkRX_?ia)iSw++udSEOUHHMuC0r5?T0S3rq;9l$!BPx~z*E&e)~tM}NR8n&0;1 zY+l6-&PI}X@a_XDR*k-Z_&pVY$!aZfe~CG=r<*lOLJnP!3_9W`#xiG)Yl^6r;SyJd zdu58iF6>5swiqGzp!2N=rp zLT3NpL%<(mS;Gzl2_05bQg#i}1>A|+kI;C&=Ru4x%dl(6@5m&RfG09%Ew!BNi_$N^ zfWAc^_Ir=>GB%8fkYCeESx8#fS__XiB-bK{^a8s|BbFzh0gu0(S}cLd)EfpVYon1Y zGdmjVHl74*D5j_w2)ZT~&ia_kzTC<-aN`+K-PKvp@sg=&EmoB+F~6WSyPskFm-yp> zjP|C_3{M{5UIcXb{2a+CSL>}GR6>QG!x!pNJWN3OqB>S!6iV z+`0K_dgKh65UY*Phtt`MvHdwYJzQoo@x#Y_AL(L_LoY>;?N*47x}ivR-Xhm8VG!23 z*L&o(`9ot0iiuI_dy=1IL&mu#IFb>+q^g#76Z^T`aW#*yYgdvOhRNXYMq%oA(Zyz^ zZpAfBp^B+$nVtE4&8F~9m)pUMy}ibnoMf?tkLU@YFy@!chuXD((3VkQf6?AJa`0u9 z8hIx!;+CTnxe%~5BB{jSr>D%1QikbqYWP+X0L`xfsJXe%RGZ;^65ah$sX(O;c`x?U zQ_i$r;Qo#R$_;+%p|Zt) zM%L0mZM_v$9)9vwCY54ZGkKvjk~K)k_qRf1XYVJ;z#3l47aN&URrH-$?je zV;`R)hv2M=gCGA>g=0-cj+-xoVEJ!YaLUg`i%0KEh{rMl)Ppz6&$@hw~Vag2*7Ns8UL{T>;;6%2by^_^qIy#uOE~ zr|Un=>|p;hU#!M1G5?_oP279FQbbeT4*W3qXy|jfR-nflhJrFs0~7X=$s%|>305Os z0gX}B+g&2)uw#${U$^Owgd~K#+Ee$>K0V4wiI~?Rlkf#uc0?H?A7ecqFTh8(zX6b% zq4_t`(@kI1_T^A}f3N_iPL`m|HHJMzz2PdM4<`ce^SXyOtwM}B{az2tkVPRWCNm=#Tyz|2X!(OooWQvJHX|8Z{0PyHE!6T@4W1a8 z6D>CA5rWzH$W4wCy_Pyy=e@6Qon28O8Gpse@Zd~w{Ijte9FU($_@we}_p#q@87}2q zJt^jaKuGZi+fC-*7;8NN4?!C<%;{iOb&0YCN(+P|s*ls?qzFEr@ZfB|Bcu;p;h}=+ zS^*)f!e>&D1#Xa?`_F;_D64H+!QV4{u0Ih*KSuvM61R-X?83lKVGTx-=gdyyiq;E# z{{)gEnu>amCq(nsq1yB>p&TXp?2j>#Ga4CTZADF-i@;lA<3EMmkjXJjV<1-`g%aVJ zt~QeV%o-BE$JH6oMZILu#`D(U???VVoqX||}XyAyW~Wr0c?N&bvl!RcCa zB2smNag>RRk4nZjOfg^?=p?@<8nfd%XIfZC&krWTm3@*gR$;}!B_f8qK?sVe4rn$B z%63Z#7P$7a;EE9V;oGydy8_RW#u3<7;x+f?SAd z1~^VbdMk~NpaqYizl`toOypvpHChr!R!Ky*x7~(JSP?%u_PN5iHGtx0J%NeOHGXUe zn?d9-ZV9OhLpna2WPgGghbVdfyd@fQ^O>9o-b#rhRw+M5o*!b6u2E;=PyR73ddZAN zgcK2`FLiv{rb;1`Y`lx(76`L<+ms*v!@z)1z(S;>@%>nYi9S7qlSTiU3-sq|`kA%+ASqa~a-owHci0=;+YG9-^ROI#!*5yQeTA zH)d5>E3u)i%ecn9h(V6`2iB>52cbzKJ6XIW02+jdv_yp2~V{B{< z9|+`M{ryhuJ7=%rTGQNsmPMdrxbaJ+b~<6OGS?ypvJ^U`OQ;xpHFVV40OWyfT`PU7 zCHkv|nxK+?W1)jI{QE87PT+Ds9x0i)R1_x8Ng)I;fe(M90{v3e)30IN{ygocAcYvl zfwsu!`4en8H>j_BCe14wawpfFrVe-l?uZ$-mg>bW`8(^ z0&Er7=t@GjB!ue~`lf!M#uHr+R3BJ8S=~-^+a9|OOgx`k%5M^!V)(>emex08Z1Ar*#P9*=;EoU#1e+5jnHCim)@Q&-@6U#j@3xV1lb1H3TSDG+XpViNZT9Fo)$I}zf4v;>3SWAirEiyfC`Jk*!UL>L);xV0i2)3+iO@n21941x(MqGB+>_~A0x^GJSZ;u5 z>@CW>A2}`)cl#!IkdAuceY}){`GACMX9dmp-?CI{V8TiG%>Zvf@UJ0l)TMLjpAS@N z`r0~jJ?zoyFtjV|SF`OTY|n#3HWkE4B0wR+ewzR(T2OipNw#5N__!^>F<|z1s`(Ge zG#)RUfGVd4rh|foAK;trIkL@by%76dE~c?4>P7k|S}`BRqi6xZq46GhJ=e}uO8MB5d#X`PsyaR`&Sa&^fAU|1Z=x`YN^Dl+b(p%-M?1PW9sxPnA zQ+be;WGAizxJ;wU${7^~LrJl}1wH@t%d(x-3bhj#9Oa-*=k4}dv6 zSgS5pus8+-0uEwu?aWoKiIncoys11~_Vaq`D}Zdy0i1pY(&7ts!9*UwSbTJ^hUr!; zlxVdek%d4b#L+YlTc1UgYBlp?uXrUwA;A~y4}l@JO=CgQjTDO)@`7(i>4*FEgb0;P ziTq!&& zuekA|vQTv6c#R$`00Z8)ykR`of-&r}{j`hV$D9l!x=qO8P9Ldpg4}GW5$kmI5gRY! zZrfGujz5w1`p0KZ4lR55gUPPNo)5VBvh3M< zL7BO;z&+SrOobK59u0y>vNOXqF415quor%JU$zJc2rzPwE(=&lNl6*Q=z4uT-klPA zYp?Y5e+}=jg*8&4-DTt`Ih?W zq1|U6V=`0TY@|RMq09dz-*%yTW+H>HYXAOX3*6y#HTYPmStutipGck8ABn4(FBM7e zxZaLOr$UPI!E@Ddqf;HyA48OsNTay-TM)~CA3e+?p!2p6@reDI5s(9@e%S`}!x8+c z6FPg`=nBX=TBvbUvd9+oOXswlR7wCA&+=N&hD>G&$qF{u{E4!dNSAg81bbav8tnswu!ki2cJK!qQS>hCImJfc2#UpQu*E4tU8a;?FE97ZihVqQC4 zwL842HpdOosECMM1a#u*$D3n&Hh(~~L6aTPpGv)?I?JipC)@St5<2k6g+?q$lVQIT zakCb?dy-~_b9W@jd3wM-mN@XEWY}~9mF&St5*;3rF6>LQLy`B*Q39E8z-y*V452u! zQW|F{4z--IZ$OTyU%p|7w_cn7C%~3OoBOHNLbU<6#W-OIg?a=18U;qLJX9-2#_-F1 zSKq}LOn2uf7eRnW?gp?5eZIf^1qmiX?q6N2X0@r`{ZrJt! zMbTob3*84MZM3|Q{SLr$wR;Zdi~bSto9+>*FDCTwGmWI8+uhPv7oIDlPG7I1)mE-| zm&bv&PFI?_z5baWvu||=f*YK-WoF-vLgTiYhH!4p7AZz7Ek!&NZ2rpNwO4rGB?xz{ zvm-}ocZ0{q{|UN~zZzp{kqc{lC8Ogo?gosea!?)C8ux$%-Hz}MFJ7KJhy`7()E2}X zR$B`Dq6ygINgMD>abei}?k9v^eo0$c(81?%{@qT%{-zJWS7I~lQbNa!Q;T=?ln{59 zlUc20eNfH#e7yr$f9SG5*;tMuczrMv{O;S(yF!+8x1;&UY!M%so_KC+4Mv0C+`GdG z!Luc*Q@c{hWL0XrJ0nRA78ArwXM8}f2nsR(kjIDZHx(ltn_>Dt0ZvX!abrPs5953Q z3`~TCpL)9%;a`=s>&)eC^CmL|l0aLdKbW+&JKp~sg@Y%!v`P@Ny02q0eowbFxY{*_ z%5*B3xyH~xpfGyFcF#i4O+fCuujji00;t)lR{S6Sg??(VTS`R0BuDFn?N@-t`4S?b zq%dxz$sSB#3tlM>&!-fYlf?ktQr%j?7*c^ma#3G;kDOe+w=&HVjY{2La^Z0lVh9s# z)T-H}5AeeHZ2naF($NU4pqQv#FS&m+dlMNZJGJ*BYQWl?OdBl*kZSb zeR;f@I~y%6D##3538XIsm$t06dGK{&swE^Ca{~|%cRmWM3>Qtl>v8Juj@#Wo`allA zZ)7N7v0{1k{=UV`rMLITRp%B!{~nT~{AVTFN*2Y#fYZ2svW%y2n!3toy>y z3&Am9VHgBjBR;)G@yUk5d$_V|S)UejfAbDBtkh)=sQb+Hihpb0{cyD}i!V}$1)>oV z;`hET{gsAj7=dYj!dAmZ`zA*YkWlfxa{*ukxdEI^Q)2?-VXeRjALk%flp2$-aKBv- zP2K)8X!lGwF`X@xAMRc8e(^Y4{YVyt&oU~2+l;SIxCgi{hbDSYeihe4b|QQ=hrkF# zy4%EJz@0uOlZI46vgvx-Y1 z5`Z4?LZX6p)k&!1ytLVNIr`?>1h@O&6}GEPZhNOWE|yOk1|7f;43lOhXg)zO7gzfe z72bxHN=B<^Zl)X}(Zi2SzW8G;T+kx6PXz;2AC?0LXU@i(L#dOVbhMQlNGpJ|yJ=*+uIRC6$} zCx>rwbK9o0tEn}Mm1L&+!e5u;5r7+C?<3)B+z|wk#1H`yo=U$h`Gpez!v4=KUjdZS z6*@Ju4c2qR7~L}qTk9P@7GF&QqzK<8Z~R&L`ksR=Jo}9uJC7P|;97#jpb+01XMB-5W*eNb~~KFst8E z`jPv$=>Upv^+&e!nF3kKtwnE^4~(BK^l{V>wQf?ZyXAzb(7HWtaY#dQz}>w%LJd3D z_>J6DNdl~(HtKoTn3tQy2O=7UWcI{>Tu6iE6gel5rH^*=mCIrr;0P&{{%tiw`M!q9 z(cyiA5-h=<1kf-xq<)h#gN#@_2mDAp^8o(_{eCIxkHgv!;`2|-!YTMHlG6W#%31J9Z5W_REP zaivq?djf$_d|ZG{N;7*4AX>%)Owmx4c!6xg0e-eyq z$LSY_TP9DbA*RyWQ#_o{8pTRwKFYdMi@SNPB^evxq0yCH?*BO*|E)TF_uyX)M*_>K z?8aCu*fg9A(nYp#7TgYJy`Up#Ukhh8GdKr4jbRUEs(q%QZ~!H)KHZ)3jeg^CSWQJU z9x(7krv1#}Zb2x18j3+R+wSG^xY6wb@z?^wX*|r#hIq}Xw`u%3qlnngs$DSpIhRflu z+2puE4i-*hB>e!`03^j<*CM^=$rzRtG^FrI^9$a~^2qkaD3Ks$|O*T6H`Y_CykENxg z;COO>FzGZc`ZPOk6kqL6Nfuy@ix*_XnNu<1rhZI)uSnEHHODEt_X{+cz6m0i(mu@B z)iWbf0_nNl?zrS z`?cr5u&NQ3pA1ot)Ow`K*Uj-} z(jsADGosY13wiY=8ZkiBi5q|v>@@Qzr$zdf0X;sKsX0@$OA z3#k6`RjJHYL!}sO3$Q|nB0i}GUbI(#;j+Uq+u4c>QiEJ zf+K;OUd7}9Ok+>hGC2KjpJGi*C$a;Kw(T*XdD!tjS+FlsP57kWR0Z*ifP~a>0L|hN z)a6M2mT0`YxQ7;x31s8*b9`fb?zhTk1G-vMKnfQ?x^LR>D@n*Q$Og4hp!BrWO_X#1X9zdl|<0%gR(TCYp-i#l1mqm2R4MqM= zWp1U3(exeMK%4wF1{*4SLXa*_3!O$Rgsk~)AXLO+$oJsD!!oWRMpbl-G7E=MDxVszF2`-1Ca2-gq; zc=KiEm~wKvA((pe>2$NLo#f>~V3*giGU(5)j1IarDAalG<255YO(O21pH<-HhZ{4 zt}y6ic0;fF!C``rH38$92PuF*aMYN~6Xl|xU?>vm;kZlV76*gN|$w~O^ zk=9XSQ9PGpwGV#~%W0LWh6A>7veO*;ID3J#;qukMUD%adMUk0BRBr;|)0w$Xj(-lH z_3Ig(KCijYd;*SsXp%NB<(rWgCj=$VBFq4cvzDIBzCY22I~SJub8VJPhao!w})#8h){!s9|qhAj0eA>N!?x}PKoT}ON%`= zhh_!t$&2t#(SzGQUBP!WrJ_2$r9Hwjr6$bOrwtF~!4^U=Ep24_6#SpDWY|b>%X2kU zR`o#3yen02U^~RHf6FlEm)x&YI(egRJIr;OgHtr_^WtC2ni=0A%5*NIO@a7_ah)QA z$!Q*T5Ft3se5?q9#78?}paz#$q*s8CPg~vxEECa=_V!gnBO}M?bwT%9B6T&xzEbd} z1nRVSj~j4G%uC(W5b6W=n;*Y5#zKd7!OoV}kHnbUhl#w$Qj59?eqCS@s3G&C?f**4 zonb>Pa4Ms2A;dh`xZhk7ZL+jRGhRoEe_W9#Au4;RQj@I280Xmdedk^W3MPhKCL6E% zN0@b22m&||roZlc4-BFD6%!8U=N|q8cm2V}FiS|1$bCVEI?`PwTN9cAboc$`2OOIK zrf#`zUys*^y^J#X zouOeEWKr*Y(5LmT8bp{4#eTG&Erh&-aBrb}Qm*UKJaTq+b_5YuF=@p+8Jb*d_Ncwf z2_Ygrx5FIYKQQ69cXZ4YDH72CFY&&s8PIplBy4*quE2SFP|ad8GjbrBAlQ5)5#Dk# zQ~Vw0-+S1b?0Ql;%%J7kRZ(*#s#Io!F%aQD?r*Oz2P@5Na#wp3&esR()GC>TAy;>+ z>+g02xt_0+k&~0J#znBA+1&9wxf-v#mjJp}iVrbO2*6&P@#_o65#3W}Peku`leMy< zS4d&~UfZ1;LoV_=>Vqud;eB+)3njQNV76_{A-mzlojN5uvO-i~F1O|(@tZ%8w(Kn*n)^EFs zlb_$gm4D)$3)CvKS&(z9zBK>$F3PaOf4epYp+CLac}EHA z?i;Ish(Vg0wHv`ukh&CU)*k`feK(y@#G6~`-q3-n>haz7yh7y+Z5jEbU_{Jbw2=2H zlqXg%Rr~0*x_7bFM@qBny6`UVbX#l>ez#it%_HjnOkdE3<Rnb+*=aadj1pE}iH9 z^4RdU*EAOuJTYQ{CG5|{%eC<3mg;01JM<&E8)M%&r{-mesG1^)gJ5{{nW7c`6`|Isq zROcKkOZAo}z54vB*}}rSlrp^U!i9wmw1UljE$l4xK?I)C_HSh^gLY-=iP7G8T7t0G zx5Z>OBg0OicRc<)1|bz_?Ql=R-Uw-ZOJOroE0n|bje9T5FTINO#PEzojq1!thCh?` zH$4>BvMX~E*0iQskDR0dW&heS>DEG`HSJDT-DQ8ObiLP*R#%soffMh( z?ad%~w}IQETO;{Pv0jbB1S!udXnHiu3GT)68KT0CtYY*t{ zPGsox4^qGLg>Ou3lmz6C3bv#(o?j<$^hGmBWt$b0uJBy&NB>4})&}?$=uKyep$7WTk%4B&Lhs|Bed_WHd)w@5m-HKq6|BVJ87CWYzU*;*p8>)C4B&?FuO z_Ml`qM$gz-w5eG%ZfJ@%h9wrgT7tJAyW`4S;PQAwx4Z@T zia3@)HRK^1MJ=CLTTA=H^V`up!`^{LqyOu(fImEo=#|k+u>9V?o}M1351-u;$b*B& zQ#pcpS4qW*+Fb$Zj?q>O@74a6-ndx-mYP(xVFyYgL>%N#>*9hy1Rq)kAPdKb>V=p) zs9bK}IcF4-Z=x`7US1)?$8?d11+Vl@`CtAAZ%NaD5AE5yy;{`p^sLnFnait5jq(w9BETmh0E;FH!U7%Hr+dlF8mm5Ok3}q-ZFI(1(^j z+dW9ocXq7%4OOoP0>U1NyAun+tiI89U7xV*nF_#VACvSmWjgZDK>T=HYIDlm@2>b- zNbw&9(kq+}j=WWu`pUy5iIHUu0>=%^1=63l>)X zH0}PHzgg$i%^&Nmq0@ti;Z6_1^SlE~zZ*iQ8z115-+BAlR5e4e*Y|OK+ zBazRh7vT;38CTWKNSc#+sagR4^^3XV=cUy|o^`lEc55M!Q@@T;3fyUXvLkyUk%@lX z@p89~TVKgS3x~04gNfXGdu07h4yP3Zl{gx|gSU#;^VAPw7hlH?4w*DMUu4OH zu|)3zxK>}sQva;MfkphE?*+*9kjQV8vh`FjM#(+LgMKvRF|Ql^Fa=Sq^J4A_#u0_n zbRm;Fwf>DwXJ{eEb$Zf#>`Kv8Zl_g)j=Q(bRd?ff^ZlJXo?iVbP~En&@bqFvJm`ow ze5O2zu?nhbAmMqL5{)3p35Kl~rgH%Ov5kF}wx>8TUV-a$#Oy*#IO!Q{PVyeD`v3ae z>pl4HgseNHyr~4gCTcrP%tJMrxljI8ItZ~Hihmm%GHa%!j}y1$t1?Jc*Rb5kaOzwx zJo>gU?%}BY(0Xn!SocG?pPY2$$?E&VM!E)t_`-6p7a;;HdA~v|#4M;i;hzZz!YFja z`RmsqXKUmJrX;(%vjI+V_tfu78Qzq(-#TPETc4M!7nb{@7CmArl*4JO?OPGD+w{-w zw(D7kz5+-jx<-vp0cfnh##5LcRxXEhohIscY)_9!(ZC0N;@~IF+7cN zHsT|QVeAX|j)w)YVGUX6$HCHI_rikNyNdN~uiPwO%6QuXOKz-NG-#u5{W-n?Sy!OVo}lW4 zd2xkjfMvyUzq7taCSgmt_@6y39QP|Huki{|Sj(1t%vw<;J1g)*lVdw;rbX}i3jlDX z{p@Z1T{RD1Io|kJZ5TD;{;Bn8$20KN@w>v|&k9zd`VcQp$wE~+9vBA@ML@h)rc_%j zqvamc**meS_YCAlj7&f0?%zDH>-vdEgGCBH@#c@BA=!5e8Bh;5*JUEJjId_qVAV!dbIZiN7NY~wxej9ejAdq2sIg=KEX=7 z0&JW21-J}bx+^-P&Xcm7v#g}d@eUW6#bYDe7gV7s!XX#_Kg1bla;ik^$#!bHsapcW zR4kS3n{a?X^V_A~dSfGquFNYPt1M{bi*QMX6(v^i4wA}>NrE7|G0J_*Bzcsg0wU6b z9ZDoxVLn@GD}R!f;k1@|`?!#?#Ij!qc!o@Y4E@G`arNov{V8ar9x_jPYn9vgV_jWg z=dc~}kx#)NfUI5n25?dV_wR4yu^LM+RGZww0S)3LgH!3=xjJuDjV5TOvlLS9}Hhx_EcNi|9nuU-UP(} znjC5Dd`F!=`<1z!W-JrX5e>5E8nwKbp&B3{Pbn(@j8EQAEvV)6Nm#ID{|`-0nD(3j z8=Rs%MiC)R}|4R&}De6rA(bSH%l}iVyIwm@2{h_H?J8lcL2I;jAxKHC? ze0KrCKDre<&&gHX%&pjZ_^45*c*mO8(X{j1PPHN~clWBFa{T_Wup^NM9q`kzS0DD{ zsLfrO(%FAP%)=AmgVI;JP2Fh0YQ-eJ;2z%`7EEJL#5;4!%1Hc_cS}NUpifD z9Q)wuQxiiZ7AixgwdzVmtN8t47YE!5eIpm*?8S89g}ZQGb6SkeH^d5Fkaj7NRSH|c zF}sywlB~rW3mk2&9fsy{Mwz>Qy1a-1#hi&e*9aU|8@q$_!23H#;{o)L2)ACpdWw`C zy1LjA0s9gC$WOyORp+dVD)G+SXx}(Q-ZG$vqhjG7hPp?ja%%b6-9g995 zFtsn(=BZJNsFcLh)_r)%zK114Lo5)hpd)VcB)9qYYMc|4Ph|CJzuV9CYjP6gWy0aN z`{wK^buX5&5(=dDtUAiGpQCk>Y`n^mAI)mrC4p z(#8Y3G6C@zm_8TRnn6<1>h!WIceQg*+FKHQt!pI=1p81Px$QrH#%*~y^2TbK2btq` zRmxlu;#Im@4Q0T`lciG%6L>ul1O-dHo(IWj{7|&5=bSBMxI6tjp0Y{zA#KIQS|ia| z0YKAIXk_-6D3_Eb7dC6Tf9`AKevU>-8^{%ggtg?r?ZX*jrd;mr4D6m82ByCE$9w_u z+}u9#NKX4}tuK___?}{Lqz>ry=P7r<|$C&RoX{@&`~x ztU{amH218n5 z-QznYn2@;4alfykwBu?<=r)bB*#8Lt78(%L3;3qyyZ@vLG3K}b)hDnQ^0Gh2-?FZk zt8NWQpP2tsSSZLejpJu}0t(jtk4|yROTcSttCpN~k=^eD*reyi!x&v@X02kxp(zii~+ zBGUd70JLxUU~d-)tXjSQ_o8{60mKirYqX3RVPY*v7-*PyNO1F21!N=H}8*RC=;ceSx2(W zDbeOc*fWvYfTIaN<`noI_#SP}J5ej(Ven%C82@IUg!E{L3zVqDmRoLlOKJYIhm_y1 zhs?iU77_D50RSKT2OoTJZ&?B>fByOBd(=x@T4B8m1lNgM;Hc?XZ=UtcF?TMx%XclP z%v6j}WNE^%C;Su$4%WC8j=|HNu|QLZ&B7CWsNqcjx1i{Pab%>GI7{>p%BAl;%_~D1of$%TN(%%UHSRoiNC`;hUU3cB}gKEz-w>1sX zz;Wgu2_~1IIuzwvc!nKK=-G63jR0AE4o)`E=+!6m!eHzwl>h0ka~%brrgF|{zunhP z^E_p_4yBH@(MrW1fs%O1 z|B6XJ696n8R={srzWeUGZxl)MP=&mo znX^wN3msei+O~jc9pMiUupZoDy3s-(|L)v)Yaw>5^}Ys(e0&}spF(aj&HwW{@{uJ# zAaezyePnL~x2RuR;DRV8PB|2ZkHLi?Yrylqp1*-s9iLr5Fm)7fRhHjnk3atSokN)K z>tXr*;wStQ01yP08~O&UQr}evFj!^Yym|W-LAY;43U;qJ^(qh`3!#O}@%V1NyhC#O z@K`3?JSU;keBGGBAY{OBOx@On-4dUJTHfSl@4CIcHMaLR5Slo3x-LP4g4?U%pitYI zak!DsE764Ss;u|v3X9(K;DZm|*fc%9-+}Oh@J|4+*rf@>8dzzt2v!-EE7d?+Y4_cC zpIgiM1q2(_cdhbE*Qn)cEtyDK-hJjN%oZ?iZ=o~5I7^W0+z(LZ{OE+F7SO-4Of0Ou z-UKcjvKwU};=U$UeZHQ>V&OJ`*ov|B!T$}`Wcz=v|Gz0M|5XY77iHpqP`}+#+Wvt$ z_78)g|Iu#UpfC)=a1izy3^ zbeUw&&~OATFjV<->|g~OjDZvYH@*iT)(^j2q47XY!Ys;atCKihOA U2G4v@egFUf07*qoM6N<$g7fX;jsO4v literal 0 HcmV?d00001 diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Amiibo.png b/src/Ryujinx.UI.Common/Resources/Logo_Amiibo.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Amiibo.png rename to src/Ryujinx.UI.Common/Resources/Logo_Amiibo.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Discord_Dark.png b/src/Ryujinx.UI.Common/Resources/Logo_Discord_Dark.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Discord_Dark.png rename to src/Ryujinx.UI.Common/Resources/Logo_Discord_Dark.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Discord_Light.png b/src/Ryujinx.UI.Common/Resources/Logo_Discord_Light.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Discord_Light.png rename to src/Ryujinx.UI.Common/Resources/Logo_Discord_Light.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_GitHub_Dark.png b/src/Ryujinx.UI.Common/Resources/Logo_GitHub_Dark.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_GitHub_Dark.png rename to src/Ryujinx.UI.Common/Resources/Logo_GitHub_Dark.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_GitHub_Light.png b/src/Ryujinx.UI.Common/Resources/Logo_GitHub_Light.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_GitHub_Light.png rename to src/Ryujinx.UI.Common/Resources/Logo_GitHub_Light.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Patreon_Dark.png b/src/Ryujinx.UI.Common/Resources/Logo_Patreon_Dark.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Patreon_Dark.png rename to src/Ryujinx.UI.Common/Resources/Logo_Patreon_Dark.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Patreon_Light.png b/src/Ryujinx.UI.Common/Resources/Logo_Patreon_Light.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Patreon_Light.png rename to src/Ryujinx.UI.Common/Resources/Logo_Patreon_Light.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Ryujinx.png b/src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Ryujinx.png rename to src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Twitter_Dark.png b/src/Ryujinx.UI.Common/Resources/Logo_Twitter_Dark.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Twitter_Dark.png rename to src/Ryujinx.UI.Common/Resources/Logo_Twitter_Dark.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Twitter_Light.png b/src/Ryujinx.UI.Common/Resources/Logo_Twitter_Light.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Twitter_Light.png rename to src/Ryujinx.UI.Common/Resources/Logo_Twitter_Light.png diff --git a/src/Ryujinx.Ui.Common/Ryujinx.Ui.Common.csproj b/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj similarity index 94% rename from src/Ryujinx.Ui.Common/Ryujinx.Ui.Common.csproj rename to src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj index 74331fdef..387e998b0 100644 --- a/src/Ryujinx.Ui.Common/Ryujinx.Ui.Common.csproj +++ b/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj @@ -45,18 +45,18 @@ - + + - diff --git a/src/Ryujinx.Ui.Common/SystemInfo/LinuxSystemInfo.cs b/src/Ryujinx.UI.Common/SystemInfo/LinuxSystemInfo.cs similarity index 98% rename from src/Ryujinx.Ui.Common/SystemInfo/LinuxSystemInfo.cs rename to src/Ryujinx.UI.Common/SystemInfo/LinuxSystemInfo.cs index 5f1ab5416..c7fe05a09 100644 --- a/src/Ryujinx.Ui.Common/SystemInfo/LinuxSystemInfo.cs +++ b/src/Ryujinx.UI.Common/SystemInfo/LinuxSystemInfo.cs @@ -5,7 +5,7 @@ using System.Globalization; using System.IO; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.SystemInfo +namespace Ryujinx.UI.Common.SystemInfo { [SupportedOSPlatform("linux")] class LinuxSystemInfo : SystemInfo diff --git a/src/Ryujinx.Ui.Common/SystemInfo/MacOSSystemInfo.cs b/src/Ryujinx.UI.Common/SystemInfo/MacOSSystemInfo.cs similarity index 99% rename from src/Ryujinx.Ui.Common/SystemInfo/MacOSSystemInfo.cs rename to src/Ryujinx.UI.Common/SystemInfo/MacOSSystemInfo.cs index 3508ae3a4..36deaf35f 100644 --- a/src/Ryujinx.Ui.Common/SystemInfo/MacOSSystemInfo.cs +++ b/src/Ryujinx.UI.Common/SystemInfo/MacOSSystemInfo.cs @@ -5,7 +5,7 @@ using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; -namespace Ryujinx.Ui.Common.SystemInfo +namespace Ryujinx.UI.Common.SystemInfo { [SupportedOSPlatform("macos")] partial class MacOSSystemInfo : SystemInfo diff --git a/src/Ryujinx.Ui.Common/SystemInfo/SystemInfo.cs b/src/Ryujinx.UI.Common/SystemInfo/SystemInfo.cs similarity index 97% rename from src/Ryujinx.Ui.Common/SystemInfo/SystemInfo.cs rename to src/Ryujinx.UI.Common/SystemInfo/SystemInfo.cs index e78db8af7..38728b9cf 100644 --- a/src/Ryujinx.Ui.Common/SystemInfo/SystemInfo.cs +++ b/src/Ryujinx.UI.Common/SystemInfo/SystemInfo.cs @@ -1,11 +1,11 @@ using Ryujinx.Common.Logging; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; using System.Text; -namespace Ryujinx.Ui.Common.SystemInfo +namespace Ryujinx.UI.Common.SystemInfo { public class SystemInfo { diff --git a/src/Ryujinx.Ui.Common/SystemInfo/WindowsSystemInfo.cs b/src/Ryujinx.UI.Common/SystemInfo/WindowsSystemInfo.cs similarity index 98% rename from src/Ryujinx.Ui.Common/SystemInfo/WindowsSystemInfo.cs rename to src/Ryujinx.UI.Common/SystemInfo/WindowsSystemInfo.cs index 9bb0fbf74..bf49c2a66 100644 --- a/src/Ryujinx.Ui.Common/SystemInfo/WindowsSystemInfo.cs +++ b/src/Ryujinx.UI.Common/SystemInfo/WindowsSystemInfo.cs @@ -4,7 +4,7 @@ using System.Management; using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.SystemInfo +namespace Ryujinx.UI.Common.SystemInfo { [SupportedOSPlatform("windows")] partial class WindowsSystemInfo : SystemInfo diff --git a/src/Ryujinx.Ui.Common/UserError.cs b/src/Ryujinx.UI.Common/UserError.cs similarity index 96% rename from src/Ryujinx.Ui.Common/UserError.cs rename to src/Ryujinx.UI.Common/UserError.cs index 832aae9d6..706971efa 100644 --- a/src/Ryujinx.Ui.Common/UserError.cs +++ b/src/Ryujinx.UI.Common/UserError.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common +namespace Ryujinx.UI.Common { /// /// Represent a common error that could be reported to the user by the emulator. diff --git a/src/Ryujinx.Ui.LocaleGenerator/LocaleGenerator.cs b/src/Ryujinx.UI.LocaleGenerator/LocaleGenerator.cs similarity index 97% rename from src/Ryujinx.Ui.LocaleGenerator/LocaleGenerator.cs rename to src/Ryujinx.UI.LocaleGenerator/LocaleGenerator.cs index 27573a8fb..bb4918d55 100644 --- a/src/Ryujinx.Ui.LocaleGenerator/LocaleGenerator.cs +++ b/src/Ryujinx.UI.LocaleGenerator/LocaleGenerator.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis; using System.Linq; using System.Text; -namespace Ryujinx.Ui.LocaleGenerator +namespace Ryujinx.UI.LocaleGenerator { [Generator] public class LocaleGenerator : IIncrementalGenerator diff --git a/src/Ryujinx.Ui.LocaleGenerator/Ryujinx.Ui.LocaleGenerator.csproj b/src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj similarity index 100% rename from src/Ryujinx.Ui.LocaleGenerator/Ryujinx.Ui.LocaleGenerator.csproj rename to src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj diff --git a/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs b/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs index 4d0c4e8b9..2defc1f6c 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs +++ b/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs @@ -4,6 +4,7 @@ using LibHac.Common.Keys; using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem; +using LibHac.Ncm; using LibHac.Ns; using LibHac.Tools.Fs; using LibHac.Tools.FsSystem; @@ -14,23 +15,26 @@ using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.Loaders.Npdm; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Configuration.System; +using Ryujinx.HLE.Loaders.Processes.Extensions; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Configuration.System; using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; +using System.Reflection; using System.Text; using System.Text.Json; using System.Threading; +using ContentType = LibHac.Ncm.ContentType; using Path = System.IO.Path; using TimeSpan = System.TimeSpan; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { public class ApplicationLibrary { + public Language DesiredLanguage { get; set; } public event EventHandler ApplicationAdded; public event EventHandler ApplicationCountUpdated; @@ -41,292 +45,324 @@ namespace Ryujinx.Ui.App.Common private readonly byte[] _nsoIcon; private readonly VirtualFileSystem _virtualFileSystem; - private Language _desiredTitleLanguage; + private readonly IntegrityCheckLevel _checkLevel; private CancellationTokenSource _cancellationToken; private static readonly ApplicationJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - private static readonly TitleUpdateMetadataJsonSerializerContext _titleSerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - public ApplicationLibrary(VirtualFileSystem virtualFileSystem) + public ApplicationLibrary(VirtualFileSystem virtualFileSystem, IntegrityCheckLevel checkLevel) { _virtualFileSystem = virtualFileSystem; + _checkLevel = checkLevel; - _nspIcon = GetResourceBytes("Ryujinx.Ui.Common.Resources.Icon_NSP.png"); - _xciIcon = GetResourceBytes("Ryujinx.Ui.Common.Resources.Icon_XCI.png"); - _ncaIcon = GetResourceBytes("Ryujinx.Ui.Common.Resources.Icon_NCA.png"); - _nroIcon = GetResourceBytes("Ryujinx.Ui.Common.Resources.Icon_NRO.png"); - _nsoIcon = GetResourceBytes("Ryujinx.Ui.Common.Resources.Icon_NSO.png"); + _nspIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NSP.png"); + _xciIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_XCI.png"); + _ncaIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NCA.png"); + _nroIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NRO.png"); + _nsoIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NSO.png"); } private static byte[] GetResourceBytes(string resourceName) { - Stream resourceStream = typeof(ApplicationLibrary).Assembly.GetManifestResourceStream(resourceName); + Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(resourceName); byte[] resourceByteArray = new byte[resourceStream.Length]; - resourceStream.Read(resourceByteArray); + resourceStream.ReadExactly(resourceByteArray); return resourceByteArray; } - public void CancelLoading() + /// The npdm file doesn't contain valid data. + /// The FsAccessHeader.ContentOwnerId section is not implemented. + /// An error occured while reading bytes from the stream. + /// The end of the stream is reached. + /// An I/O error occurred. + private ApplicationData GetApplicationFromExeFs(PartitionFileSystem pfs, string filePath) { - _cancellationToken?.Cancel(); + ApplicationData data = new() + { + Icon = _nspIcon, + Path = filePath, + }; + + using UniqueRef npdmFile = new(); + + Result result = pfs.OpenFile(ref npdmFile.Ref, "/main.npdm".ToU8Span(), OpenMode.Read); + + if (ResultFs.PathNotFound.Includes(result)) + { + Npdm npdm = new(npdmFile.Get.AsStream()); + + data.Name = npdm.TitleName; + data.Id = npdm.Aci0.TitleId; + } + + return data; } - public static void ReadControlData(IFileSystem controlFs, Span outProperty) + /// The configured key set is missing a key. + /// The NCA header could not be decrypted. + /// The NCA version is not supported. + /// An error occured while reading PFS data. + /// The npdm file doesn't contain valid data. + /// The FsAccessHeader.ContentOwnerId section is not implemented. + /// An error occured while reading bytes from the stream. + /// The end of the stream is reached. + /// An I/O error occurred. + private ApplicationData GetApplicationFromNsp(PartitionFileSystem pfs, string filePath) { - using UniqueRef controlFile = new(); + bool isExeFs = false; - controlFs.OpenFile(ref controlFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); - controlFile.Get.Read(out _, 0, outProperty, ReadOption.None).ThrowIfFailure(); + // If the NSP doesn't have a main NCA, decrement the number of applications found and then continue to the next application. + bool hasMainNca = false; + + foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*")) + { + if (Path.GetExtension(fileEntry.FullPath)?.ToLower() == ".nca") + { + using UniqueRef ncaFile = new(); + + try + { + pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); + + Nca nca = new(_virtualFileSystem.KeySet, ncaFile.Get.AsStorage()); + int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); + + // Some main NCAs don't have a data partition, so check if the partition exists before opening it + if (nca.Header.ContentType == NcaContentType.Program && + !(nca.SectionExists(NcaSectionType.Data) && + nca.Header.GetFsHeader(dataIndex).IsPatchSection())) + { + hasMainNca = true; + + break; + } + } + catch (Exception exception) + { + Logger.Warning?.Print(LogClass.Application, $"Encountered an error while trying to load applications from file '{filePath}': {exception}"); + + return null; + } + } + else if (Path.GetFileNameWithoutExtension(fileEntry.FullPath) == "main") + { + isExeFs = true; + } + } + + if (hasMainNca) + { + List applications = GetApplicationsFromPfs(pfs, filePath); + + switch (applications.Count) + { + case 1: + return applications[0]; + case >= 1: + Logger.Warning?.Print(LogClass.Application, $"File '{filePath}' contains more applications than expected: {applications.Count}"); + return applications[0]; + default: + return null; + } + } + + if (isExeFs) + { + return GetApplicationFromExeFs(pfs, filePath); + } + + return null; } - public void LoadApplications(List appDirs, Language desiredTitleLanguage) + /// The configured key set is missing a key. + /// The NCA header could not be decrypted. + /// The NCA version is not supported. + /// An error occured while reading PFS data. + private List GetApplicationsFromPfs(IFileSystem pfs, string filePath) { - int numApplicationsFound = 0; - int numApplicationsLoaded = 0; + var applications = new List(); + string extension = Path.GetExtension(filePath).ToLower(); - _desiredTitleLanguage = desiredTitleLanguage; + foreach ((ulong titleId, ContentMetaData content) in pfs.GetContentData(ContentMetaType.Application, _virtualFileSystem, _checkLevel)) + { + ApplicationData applicationData = new() + { + Id = titleId, + Path = filePath, + }; - _cancellationToken = new CancellationTokenSource(); + Nca mainNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Program); + Nca controlNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Control); - // Builds the applications list with paths to found applications - List applications = new(); + BlitStruct controlHolder = new(1); + + IFileSystem controlFs = controlNca?.OpenFileSystem(NcaSectionType.Data, _checkLevel); + + // Check if there is an update available. + if (IsUpdateApplied(mainNca, out IFileSystem updatedControlFs)) + { + // Replace the original ControlFs by the updated one. + controlFs = updatedControlFs; + } + + if (controlFs == null) + { + continue; + } + + ReadControlData(controlFs, controlHolder.ByteSpan); + + GetApplicationInformation(ref controlHolder.Value, ref applicationData); + + // Read the icon from the ControlFS and store it as a byte array + try + { + using UniqueRef icon = new(); + + controlFs.OpenFile(ref icon.Ref, $"/icon_{DesiredLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure(); + + using MemoryStream stream = new(); + + icon.Get.AsStream().CopyTo(stream); + applicationData.Icon = stream.ToArray(); + } + catch (HorizonResultException) + { + foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*")) + { + if (entry.Name == "control.nacp") + { + continue; + } + + using var icon = new UniqueRef(); + + controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); + + using MemoryStream stream = new(); + + icon.Get.AsStream().CopyTo(stream); + applicationData.Icon = stream.ToArray(); + + if (applicationData.Icon != null) + { + break; + } + } + + applicationData.Icon ??= extension == ".xci" ? _xciIcon : _nspIcon; + } + + applicationData.ControlHolder = controlHolder; + + applications.Add(applicationData); + } + + return applications; + } + + public bool TryGetApplicationsFromFile(string applicationPath, out List applications) + { + applications = []; + long fileSize; try { - foreach (string appDir in appDirs) + fileSize = new FileInfo(applicationPath).Length; + } + catch (FileNotFoundException) + { + Logger.Warning?.Print(LogClass.Application, $"The file was not found: '{applicationPath}'"); + + return false; + } + + BlitStruct controlHolder = new(1); + + try + { + string extension = Path.GetExtension(applicationPath).ToLower(); + + using FileStream file = new(applicationPath, FileMode.Open, FileAccess.Read); + + switch (extension) { - if (_cancellationToken.Token.IsCancellationRequested) - { - return; - } - - if (!Directory.Exists(appDir)) - { - Logger.Warning?.Print(LogClass.Application, $"The \"game_dirs\" section in \"Config.json\" contains an invalid directory: \"{appDir}\""); - - continue; - } - - try - { - IEnumerable files = Directory.EnumerateFiles(appDir, "*", SearchOption.AllDirectories).Where(file => + case ".xci": { - return - (Path.GetExtension(file).ToLower() is ".nsp" && ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value) || - (Path.GetExtension(file).ToLower() is ".pfs0" && ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value) || - (Path.GetExtension(file).ToLower() is ".xci" && ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value) || - (Path.GetExtension(file).ToLower() is ".nca" && ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value) || - (Path.GetExtension(file).ToLower() is ".nro" && ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value) || - (Path.GetExtension(file).ToLower() is ".nso" && ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value); - }); + Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage()); - foreach (string app in files) - { - if (_cancellationToken.Token.IsCancellationRequested) + applications = GetApplicationsFromPfs(xci.OpenPartition(XciPartitionType.Secure), applicationPath); + + if (applications.Count == 0) { - return; + return false; } - var fileInfo = new FileInfo(app); - string extension = fileInfo.Extension.ToLower(); - - if (!fileInfo.Attributes.HasFlag(FileAttributes.Hidden) && extension is ".nsp" or ".pfs0" or ".xci" or ".nca" or ".nro" or ".nso") - { - var fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName; - - if (!File.Exists(fullPath)) - { - Logger.Warning?.Print(LogClass.Application, $"Skipping invalid symlink: {fileInfo.FullName}"); - continue; - } - - applications.Add(fullPath); - numApplicationsFound++; - } + break; } - } - catch (UnauthorizedAccessException) - { - Logger.Warning?.Print(LogClass.Application, $"Failed to get access to directory: \"{appDir}\""); - } - } - - // Loops through applications list, creating a struct and then firing an event containing the struct for each application - foreach (string applicationPath in applications) - { - if (_cancellationToken.Token.IsCancellationRequested) - { - return; - } - - long fileSize = new FileInfo(applicationPath).Length; - string titleName = "Unknown"; - string titleId = "0000000000000000"; - string developer = "Unknown"; - string version = "0"; - byte[] applicationIcon = null; - - BlitStruct controlHolder = new(1); - - try - { - string extension = Path.GetExtension(applicationPath).ToLower(); - - using FileStream file = new(applicationPath, FileMode.Open, FileAccess.Read); - - if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci") + case ".nsp": + case ".pfs0": { - try + var pfs = new PartitionFileSystem(); + pfs.Initialize(file.AsStorage()).ThrowIfFailure(); + + ApplicationData result = GetApplicationFromNsp(pfs, applicationPath); + + if (result == null) { - IFileSystem pfs; - - bool isExeFs = false; - - if (extension == ".xci") - { - Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage()); - - pfs = xci.OpenPartition(XciPartitionType.Secure); - } - else - { - var pfsTemp = new PartitionFileSystem(); - pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); - pfs = pfsTemp; - - // If the NSP doesn't have a main NCA, decrement the number of applications found and then continue to the next application. - bool hasMainNca = false; - - foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*")) - { - if (Path.GetExtension(fileEntry.FullPath).ToLower() == ".nca") - { - using UniqueRef ncaFile = new(); - - pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - Nca nca = new(_virtualFileSystem.KeySet, ncaFile.Get.AsStorage()); - int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); - - // Some main NCAs don't have a data partition, so check if the partition exists before opening it - if (nca.Header.ContentType == NcaContentType.Program && !(nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection())) - { - hasMainNca = true; - - break; - } - } - else if (Path.GetFileNameWithoutExtension(fileEntry.FullPath) == "main") - { - isExeFs = true; - } - } - - if (!hasMainNca && !isExeFs) - { - numApplicationsFound--; - - continue; - } - } - - if (isExeFs) - { - applicationIcon = _nspIcon; - - using UniqueRef npdmFile = new(); - - Result result = pfs.OpenFile(ref npdmFile.Ref, "/main.npdm".ToU8Span(), OpenMode.Read); - - if (ResultFs.PathNotFound.Includes(result)) - { - Npdm npdm = new(npdmFile.Get.AsStream()); - - titleName = npdm.TitleName; - titleId = npdm.Aci0.TitleId.ToString("x16"); - } - } - else - { - GetControlFsAndTitleId(pfs, out IFileSystem controlFs, out titleId); - - // Check if there is an update available. - if (IsUpdateApplied(titleId, out IFileSystem updatedControlFs)) - { - // Replace the original ControlFs by the updated one. - controlFs = updatedControlFs; - } - - ReadControlData(controlFs, controlHolder.ByteSpan); - - GetGameInformation(ref controlHolder.Value, out titleName, out _, out developer, out version); - - // Read the icon from the ControlFS and store it as a byte array - try - { - using UniqueRef icon = new(); - - controlFs.OpenFile(ref icon.Ref, $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - using MemoryStream stream = new(); - - icon.Get.AsStream().CopyTo(stream); - applicationIcon = stream.ToArray(); - } - catch (HorizonResultException) - { - foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*")) - { - if (entry.Name == "control.nacp") - { - continue; - } - - using var icon = new UniqueRef(); - - controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - using MemoryStream stream = new(); - - icon.Get.AsStream().CopyTo(stream); - applicationIcon = stream.ToArray(); - - if (applicationIcon != null) - { - break; - } - } - - applicationIcon ??= extension == ".xci" ? _xciIcon : _nspIcon; - } - } + return false; } - catch (MissingKeyException exception) - { - applicationIcon = extension == ".xci" ? _xciIcon : _nspIcon; - Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}"); - } - catch (InvalidDataException) - { - applicationIcon = extension == ".xci" ? _xciIcon : _nspIcon; + applications.Add(result); - Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}"); - } - catch (Exception exception) - { - Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{applicationPath}' Error: {exception}"); - - numApplicationsFound--; - - continue; - } + break; } - else if (extension == ".nro") + case ".nro": { BinaryReader reader = new(file); + ApplicationData application = new(); + + file.Seek(24, SeekOrigin.Begin); + + int assetOffset = reader.ReadInt32(); + + if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET") + { + byte[] iconSectionInfo = Read(assetOffset + 8, 0x10); + + long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0); + long iconSize = BitConverter.ToInt64(iconSectionInfo, 8); + + ulong nacpOffset = reader.ReadUInt64(); + ulong nacpSize = reader.ReadUInt64(); + + // Reads and stores game icon as byte array + if (iconSize > 0) + { + application.Icon = Read(assetOffset + iconOffset, (int)iconSize); + } + else + { + application.Icon = _nroIcon; + } + + // Read the NACP data + Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan); + + GetApplicationInformation(ref controlHolder.Value, ref application); + } + else + { + application.Icon = _nroIcon; + application.Name = Path.GetFileNameWithoutExtension(applicationPath); + } + + application.ControlHolder = controlHolder; + applications.Add(application); + + break; byte[] Read(long position, int size) { @@ -334,102 +370,74 @@ namespace Ryujinx.Ui.App.Common return reader.ReadBytes(size); } - - try - { - file.Seek(24, SeekOrigin.Begin); - - int assetOffset = reader.ReadInt32(); - - if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET") - { - byte[] iconSectionInfo = Read(assetOffset + 8, 0x10); - - long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0); - long iconSize = BitConverter.ToInt64(iconSectionInfo, 8); - - ulong nacpOffset = reader.ReadUInt64(); - ulong nacpSize = reader.ReadUInt64(); - - // Reads and stores game icon as byte array - if (iconSize > 0) - { - applicationIcon = Read(assetOffset + iconOffset, (int)iconSize); - } - else - { - applicationIcon = _nroIcon; - } - - // Read the NACP data - Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan); - - GetGameInformation(ref controlHolder.Value, out titleName, out titleId, out developer, out version); - } - else - { - applicationIcon = _nroIcon; - titleName = Path.GetFileNameWithoutExtension(applicationPath); - } - } - catch - { - Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}"); - - numApplicationsFound--; - - continue; - } } - else if (extension == ".nca") + case ".nca": { - try + ApplicationData application = new(); + + Nca nca = new(_virtualFileSystem.KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage()); + + if (!nca.IsProgram() || nca.IsPatch()) { - Nca nca = new(_virtualFileSystem.KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage()); - int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); - - if (nca.Header.ContentType != NcaContentType.Program || (nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection())) - { - numApplicationsFound--; - - continue; - } - } - catch (InvalidDataException) - { - Logger.Warning?.Print(LogClass.Application, $"The NCA header content type check has failed. This is usually because the header key is incorrect or missing. Errored File: {applicationPath}"); - } - catch - { - Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}"); - - numApplicationsFound--; - - continue; + return false; } - applicationIcon = _ncaIcon; - titleName = Path.GetFileNameWithoutExtension(applicationPath); + application.Icon = _ncaIcon; + application.Name = Path.GetFileNameWithoutExtension(applicationPath); + application.ControlHolder = controlHolder; + + applications.Add(application); + + break; } - // If its an NSO we just set defaults - else if (extension == ".nso") + // If its an NSO we just set defaults + case ".nso": { - applicationIcon = _nsoIcon; - titleName = Path.GetFileNameWithoutExtension(applicationPath); + ApplicationData application = new() + { + Icon = _nsoIcon, + Name = Path.GetFileNameWithoutExtension(applicationPath), + }; + + applications.Add(application); + + break; } - } - catch (IOException exception) + } + } + catch (MissingKeyException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}"); + + return false; + } + catch (InvalidDataException) + { + Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}"); + + return false; + } + catch (IOException exception) + { + Logger.Warning?.Print(LogClass.Application, exception.Message); + + return false; + } + catch (Exception exception) + { + Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{applicationPath}' Error: {exception}"); + + return false; + } + + foreach (var data in applications) + { + // Only load metadata for applications with an ID + if (data.Id != 0) + { + ApplicationMetadata appMetadata = LoadAndSaveMetaData(data.IdString, appMetadata => { - Logger.Warning?.Print(LogClass.Application, exception.Message); - - numApplicationsFound--; - - continue; - } - - ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId, appMetadata => - { - appMetadata.Title = titleName; + appMetadata.Title = data.Name; // Only do the migration if time_played has a value and timespan_played hasn't been updated yet. if (appMetadata.TimePlayedOld != default && appMetadata.TimePlayed == TimeSpan.Zero) @@ -453,28 +461,134 @@ namespace Ryujinx.Ui.App.Common } }); - ApplicationData data = new() - { - Favorite = appMetadata.Favorite, - Icon = applicationIcon, - TitleName = titleName, - TitleId = titleId, - Developer = developer, - Version = version, - TimePlayed = appMetadata.TimePlayed, - LastPlayed = appMetadata.LastPlayed, - FileExtension = Path.GetExtension(applicationPath).TrimStart('.').ToUpper(), - FileSize = fileSize, - Path = applicationPath, - ControlHolder = controlHolder, - }; + data.Favorite = appMetadata.Favorite; + data.TimePlayed = appMetadata.TimePlayed; + data.LastPlayed = appMetadata.LastPlayed; + } - numApplicationsLoaded++; + data.FileExtension = Path.GetExtension(applicationPath).TrimStart('.').ToUpper(); + data.FileSize = fileSize; + data.Path = applicationPath; + } - OnApplicationAdded(new ApplicationAddedEventArgs + return true; + } + + public void CancelLoading() + { + _cancellationToken?.Cancel(); + } + + public static void ReadControlData(IFileSystem controlFs, Span outProperty) + { + using UniqueRef controlFile = new(); + + controlFs.OpenFile(ref controlFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); + controlFile.Get.Read(out _, 0, outProperty, ReadOption.None).ThrowIfFailure(); + } + + public void LoadApplications(List appDirs) + { + int numApplicationsFound = 0; + int numApplicationsLoaded = 0; + + _cancellationToken = new CancellationTokenSource(); + + // Builds the applications list with paths to found applications + List applicationPaths = new(); + + try + { + foreach (string appDir in appDirs) + { + if (_cancellationToken.Token.IsCancellationRequested) { - AppData = data, - }); + return; + } + + if (!Directory.Exists(appDir)) + { + Logger.Warning?.Print(LogClass.Application, $"The specified game directory \"{appDir}\" does not exist."); + + continue; + } + + try + { + EnumerationOptions options = new() + { + RecurseSubdirectories = true, + IgnoreInaccessible = false, + }; + + IEnumerable files = Directory.EnumerateFiles(appDir, "*", options).Where(file => + { + return + (Path.GetExtension(file).ToLower() is ".nsp" && ConfigurationState.Instance.UI.ShownFileTypes.NSP.Value) || + (Path.GetExtension(file).ToLower() is ".pfs0" && ConfigurationState.Instance.UI.ShownFileTypes.PFS0.Value) || + (Path.GetExtension(file).ToLower() is ".xci" && ConfigurationState.Instance.UI.ShownFileTypes.XCI.Value) || + (Path.GetExtension(file).ToLower() is ".nca" && ConfigurationState.Instance.UI.ShownFileTypes.NCA.Value) || + (Path.GetExtension(file).ToLower() is ".nro" && ConfigurationState.Instance.UI.ShownFileTypes.NRO.Value) || + (Path.GetExtension(file).ToLower() is ".nso" && ConfigurationState.Instance.UI.ShownFileTypes.NSO.Value); + }); + + foreach (string app in files) + { + if (_cancellationToken.Token.IsCancellationRequested) + { + return; + } + + var fileInfo = new FileInfo(app); + + try + { + var fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName; + + applicationPaths.Add(fullPath); + numApplicationsFound++; + } + catch (IOException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Failed to resolve the full path to file: \"{app}\" Error: {exception}"); + } + } + } + catch (UnauthorizedAccessException) + { + Logger.Warning?.Print(LogClass.Application, $"Failed to get access to directory: \"{appDir}\""); + } + } + + // Loops through applications list, creating a struct and then firing an event containing the struct for each application + foreach (string applicationPath in applicationPaths) + { + if (_cancellationToken.Token.IsCancellationRequested) + { + return; + } + + if (TryGetApplicationsFromFile(applicationPath, out List applications)) + { + foreach (var application in applications) + { + OnApplicationAdded(new ApplicationAddedEventArgs + { + AppData = application, + }); + } + + if (applications.Count > 1) + { + numApplicationsFound += applications.Count - 1; + } + + numApplicationsLoaded += applications.Count; + } + else + { + numApplicationsFound--; + } OnApplicationCountUpdated(new ApplicationCountUpdatedEventArgs { @@ -506,15 +620,6 @@ namespace Ryujinx.Ui.App.Common ApplicationCountUpdated?.Invoke(null, e); } - private void GetControlFsAndTitleId(IFileSystem pfs, out IFileSystem controlFs, out string titleId) - { - (_, _, Nca controlNca) = GetGameData(_virtualFileSystem, pfs, 0); - - // Return the ControlFS - controlFs = controlNca?.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None); - titleId = controlNca?.Header.TitleId.ToString("x16"); - } - public static ApplicationMetadata LoadAndSaveMetaData(string titleId, Action modifyFunction = null) { string metadataFolder = Path.Combine(AppDataManager.GamesDirPath, titleId, "gui"); @@ -552,10 +657,29 @@ namespace Ryujinx.Ui.App.Common return appMetadata; } - public byte[] GetApplicationIcon(string applicationPath, Language desiredTitleLanguage) + public byte[] GetApplicationIcon(string applicationPath, Language desiredTitleLanguage, ulong applicationId) { byte[] applicationIcon = null; + if (applicationId == 0) + { + if (Directory.Exists(applicationPath)) + { + return _ncaIcon; + } + + return Path.GetExtension(applicationPath).ToLower() switch + { + ".nsp" => _nspIcon, + ".pfs0" => _nspIcon, + ".xci" => _xciIcon, + ".nso" => _nsoIcon, + ".nro" => _nroIcon, + ".nca" => _ncaIcon, + _ => _ncaIcon, + }; + } + try { // Look for icon only if applicationPath is not a directory @@ -601,7 +725,16 @@ namespace Ryujinx.Ui.App.Common else { // Store the ControlFS in variable called controlFs - GetControlFsAndTitleId(pfs, out IFileSystem controlFs, out _); + Dictionary programs = pfs.GetContentData(ContentMetaType.Application, _virtualFileSystem, _checkLevel); + IFileSystem controlFs = null; + + if (programs.TryGetValue(applicationId, out ContentMetaData value)) + { + if (value.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Control) is { } controlNca) + { + controlFs = controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None); + } + } // Read the icon from the ControlFS and store it as a byte array try @@ -628,16 +761,11 @@ namespace Ryujinx.Ui.App.Common controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - using (MemoryStream stream = new()) - { - icon.Get.AsStream().CopyTo(stream); - applicationIcon = stream.ToArray(); - } + using MemoryStream stream = new(); + icon.Get.AsStream().CopyTo(stream); + applicationIcon = stream.ToArray(); - if (applicationIcon != null) - { - break; - } + break; } applicationIcon ??= extension == ".xci" ? _xciIcon : _nspIcon; @@ -720,80 +848,79 @@ namespace Ryujinx.Ui.App.Common return applicationIcon ?? _ncaIcon; } - private void GetGameInformation(ref ApplicationControlProperty controlData, out string titleName, out string titleId, out string publisher, out string version) + private void GetApplicationInformation(ref ApplicationControlProperty controlData, ref ApplicationData data) { - _ = Enum.TryParse(_desiredTitleLanguage.ToString(), out TitleLanguage desiredTitleLanguage); + _ = Enum.TryParse(DesiredLanguage.ToString(), out TitleLanguage desiredTitleLanguage); if (controlData.Title.ItemsRo.Length > (int)desiredTitleLanguage) { - titleName = controlData.Title[(int)desiredTitleLanguage].NameString.ToString(); - publisher = controlData.Title[(int)desiredTitleLanguage].PublisherString.ToString(); + data.Name = controlData.Title[(int)desiredTitleLanguage].NameString.ToString(); + data.Developer = controlData.Title[(int)desiredTitleLanguage].PublisherString.ToString(); } else { - titleName = null; - publisher = null; + data.Name = null; + data.Developer = null; } - if (string.IsNullOrWhiteSpace(titleName)) + if (string.IsNullOrWhiteSpace(data.Name)) { foreach (ref readonly var controlTitle in controlData.Title.ItemsRo) { if (!controlTitle.NameString.IsEmpty()) { - titleName = controlTitle.NameString.ToString(); + data.Name = controlTitle.NameString.ToString(); break; } } } - if (string.IsNullOrWhiteSpace(publisher)) + if (string.IsNullOrWhiteSpace(data.Developer)) { foreach (ref readonly var controlTitle in controlData.Title.ItemsRo) { if (!controlTitle.PublisherString.IsEmpty()) { - publisher = controlTitle.PublisherString.ToString(); + data.Developer = controlTitle.PublisherString.ToString(); break; } } } - if (controlData.PresenceGroupId != 0) + if (data.Id == 0) { - titleId = controlData.PresenceGroupId.ToString("x16"); - } - else if (controlData.SaveDataOwnerId != 0) - { - titleId = controlData.SaveDataOwnerId.ToString(); - } - else if (controlData.AddOnContentBaseId != 0) - { - titleId = (controlData.AddOnContentBaseId - 0x1000).ToString("x16"); - } - else - { - titleId = "0000000000000000"; + if (controlData.SaveDataOwnerId != 0) + { + data.Id = controlData.SaveDataOwnerId; + } + else if (controlData.PresenceGroupId != 0) + { + data.Id = controlData.PresenceGroupId; + } + else if (controlData.AddOnContentBaseId != 0) + { + data.Id = (controlData.AddOnContentBaseId - 0x1000); + } } - version = controlData.DisplayVersionString.ToString(); + data.Version = controlData.DisplayVersionString.ToString(); } - private bool IsUpdateApplied(string titleId, out IFileSystem updatedControlFs) + private bool IsUpdateApplied(Nca mainNca, out IFileSystem updatedControlFs) { updatedControlFs = null; - string updatePath = "(unknown)"; + string updatePath = null; try { - (Nca patchNca, Nca controlNca) = GetGameUpdateData(_virtualFileSystem, titleId, 0, out updatePath); + (Nca patchNca, Nca controlNca) = mainNca.GetUpdateData(_virtualFileSystem, _checkLevel, 0, out updatePath); if (patchNca != null && controlNca != null) { - updatedControlFs = controlNca?.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None); + updatedControlFs = controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None); return true; } @@ -809,120 +936,5 @@ namespace Ryujinx.Ui.App.Common return false; } - - public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, IFileSystem pfs, int programIndex) - { - Nca mainNca = null; - Nca patchNca = null; - Nca controlNca = null; - - fileSystem.ImportTickets(pfs); - - foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) - { - using var ncaFile = new UniqueRef(); - - pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - Nca nca = new(fileSystem.KeySet, ncaFile.Release().AsStorage()); - - int ncaProgramIndex = (int)(nca.Header.TitleId & 0xF); - - if (ncaProgramIndex != programIndex) - { - continue; - } - - if (nca.Header.ContentType == NcaContentType.Program) - { - int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); - - if (nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection()) - { - patchNca = nca; - } - else - { - mainNca = nca; - } - } - else if (nca.Header.ContentType == NcaContentType.Control) - { - controlNca = nca; - } - } - - return (mainNca, patchNca, controlNca); - } - - public static (Nca patch, Nca control) GetGameUpdateDataFromPartition(VirtualFileSystem fileSystem, PartitionFileSystem pfs, string titleId, int programIndex) - { - Nca patchNca = null; - Nca controlNca = null; - - fileSystem.ImportTickets(pfs); - - foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) - { - using var ncaFile = new UniqueRef(); - - pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - Nca nca = new(fileSystem.KeySet, ncaFile.Release().AsStorage()); - - int ncaProgramIndex = (int)(nca.Header.TitleId & 0xF); - - if (ncaProgramIndex != programIndex) - { - continue; - } - - if ($"{nca.Header.TitleId.ToString("x16")[..^3]}000" != titleId) - { - break; - } - - if (nca.Header.ContentType == NcaContentType.Program) - { - patchNca = nca; - } - else if (nca.Header.ContentType == NcaContentType.Control) - { - controlNca = nca; - } - } - - return (patchNca, controlNca); - } - - public static (Nca patch, Nca control) GetGameUpdateData(VirtualFileSystem fileSystem, string titleId, int programIndex, out string updatePath) - { - updatePath = null; - - if (ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdBase)) - { - // Clear the program index part. - titleIdBase &= ~0xFUL; - - // Load update information if exists. - string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, titleIdBase.ToString("x16"), "updates.json"); - - if (File.Exists(titleUpdateMetadataPath)) - { - updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _titleSerializerContext.TitleUpdateMetadata).Selected; - - if (File.Exists(updatePath)) - { - FileStream file = new(updatePath, FileMode.Open, FileAccess.Read); - PartitionFileSystem nsp = new(); - nsp.Initialize(file.AsStorage()).ThrowIfFailure(); - - return GetGameUpdateDataFromPartition(fileSystem, nsp, titleIdBase.ToString("x16"), programIndex); - } - } - } - - return (null, null); - } } } diff --git a/src/Ryujinx.Ui.Common/Resources/Icon_NCA.png b/src/Ryujinx.Ui.Common/Resources/Icon_NCA.png deleted file mode 100644 index feae77b943f2b6f4498b6f2f5fb49e5e5726b933..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10190 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 Utxt6oQ~_w*)mAB0vVQ(Q0RPcgegFUf diff --git a/src/Ryujinx.Ui.Common/Resources/Icon_NSO.png b/src/Ryujinx.Ui.Common/Resources/Icon_NSO.png deleted file mode 100644 index 16de84bedbefaead611e52a86a83913cde292e06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10354 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 diff --git a/src/Ryujinx.Ui.Common/Resources/Icon_NSP.png b/src/Ryujinx.Ui.Common/Resources/Icon_NSP.png deleted file mode 100644 index 4f98e22eafda5553d04615dba312b927693c278a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9899 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 diff --git a/src/Ryujinx.Ui.Common/Resources/Icon_XCI.png b/src/Ryujinx.Ui.Common/Resources/Icon_XCI.png deleted file mode 100644 index f9c34f47f13e6db43afcef5a520888a2caa51044..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9809 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 IE87J9H?dhqZ2$lO diff --git a/src/Ryujinx.Ava/App.axaml b/src/Ryujinx/App.axaml similarity index 100% rename from src/Ryujinx.Ava/App.axaml rename to src/Ryujinx/App.axaml diff --git a/src/Ryujinx.Ava/App.axaml.cs b/src/Ryujinx/App.axaml.cs similarity index 71% rename from src/Ryujinx.Ava/App.axaml.cs rename to src/Ryujinx/App.axaml.cs index c1a3ab3e2..24d8a70a1 100644 --- a/src/Ryujinx.Ava/App.axaml.cs +++ b/src/Ryujinx/App.axaml.cs @@ -1,18 +1,19 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; +using Avalonia.Platform; using Avalonia.Styling; using Avalonia.Threading; +using Ryujinx.Ava.Common; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common; using Ryujinx.Common.Logging; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using System; using System.Diagnostics; -using System.IO; namespace Ryujinx.Ava { @@ -43,9 +44,9 @@ namespace Ryujinx.Ava { ApplyConfiguredTheme(); - ConfigurationState.Instance.Ui.BaseStyle.Event += ThemeChanged_Event; - ConfigurationState.Instance.Ui.CustomThemePath.Event += ThemeChanged_Event; - ConfigurationState.Instance.Ui.EnableCustomTheme.Event += CustomThemeChanged_Event; + ConfigurationState.Instance.UI.BaseStyle.Event += ThemeChanged_Event; + ConfigurationState.Instance.UI.CustomThemePath.Event += ThemeChanged_Event; + ConfigurationState.Instance.UI.EnableCustomTheme.Event += CustomThemeChanged_Event; } } @@ -85,45 +86,30 @@ namespace Ryujinx.Ava ApplyConfiguredTheme(); } - private void ApplyConfiguredTheme() + public void ApplyConfiguredTheme() { try { - string baseStyle = ConfigurationState.Instance.Ui.BaseStyle; - string themePath = ConfigurationState.Instance.Ui.CustomThemePath; - bool enableCustomTheme = ConfigurationState.Instance.Ui.EnableCustomTheme; + string baseStyle = ConfigurationState.Instance.UI.BaseStyle; if (string.IsNullOrWhiteSpace(baseStyle)) { - ConfigurationState.Instance.Ui.BaseStyle.Value = "Dark"; + ConfigurationState.Instance.UI.BaseStyle.Value = "Auto"; - baseStyle = ConfigurationState.Instance.Ui.BaseStyle; + baseStyle = ConfigurationState.Instance.UI.BaseStyle; } + ThemeVariant systemTheme = DetectSystemTheme(); + + ThemeManager.OnThemeChanged(); + RequestedThemeVariant = baseStyle switch { + "Auto" => systemTheme, "Light" => ThemeVariant.Light, "Dark" => ThemeVariant.Dark, _ => ThemeVariant.Default, }; - - if (enableCustomTheme) - { - if (!string.IsNullOrWhiteSpace(themePath)) - { - try - { - var themeContent = File.ReadAllText(themePath); - var customStyle = AvaloniaRuntimeXamlLoader.Parse(themeContent); - - Styles.Add(customStyle); - } - catch (Exception ex) - { - Logger.Error?.Print(LogClass.Application, $"Failed to Apply Custom Theme. Error: {ex.Message}"); - } - } - } } catch (Exception) { @@ -132,5 +118,28 @@ namespace Ryujinx.Ava ShowRestartDialog(); } } + + /// + /// Converts a PlatformThemeVariant value to the corresponding ThemeVariant value. + /// + public static ThemeVariant ConvertThemeVariant(PlatformThemeVariant platformThemeVariant) => + platformThemeVariant switch + { + PlatformThemeVariant.Dark => ThemeVariant.Dark, + PlatformThemeVariant.Light => ThemeVariant.Light, + _ => ThemeVariant.Default, + }; + + public static ThemeVariant DetectSystemTheme() + { + if (Application.Current is App app) + { + var colorValues = app.PlatformSettings.GetColorValues(); + + return ConvertThemeVariant(colorValues.ThemeVariant); + } + + return ThemeVariant.Default; + } } } diff --git a/src/Ryujinx.Ava/AppHost.cs b/src/Ryujinx/AppHost.cs similarity index 82% rename from src/Ryujinx.Ava/AppHost.cs rename to src/Ryujinx/AppHost.cs index cdda2d109..0af80ccd7 100644 --- a/src/Ryujinx.Ava/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -1,4 +1,3 @@ -using ARMeilleure.Translation; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; @@ -23,6 +22,7 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Logging; using Ryujinx.Common.SystemInterop; +using Ryujinx.Common.Utilities; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.Gpu; @@ -35,20 +35,18 @@ using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.Input; using Ryujinx.Input.HLE; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using Silk.NET.Vulkan; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; +using SkiaSharp; using SPB.Graphics.Vulkan; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using ARMeilleure.Translation; @@ -88,15 +86,11 @@ using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.Input; using Ryujinx.Input.HLE; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using Silk.NET.Vulkan; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; using SPB.Graphics.Vulkan; using System; using System.Collections.Generic; @@ -106,7 +100,6 @@ using System.Threading; using System.Threading.Tasks; using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop; using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing; -using Image = SixLabors.ImageSharp.Image; using InputManager = Ryujinx.Input.HLE.InputManager; using IRenderer = Ryujinx.Graphics.GAL.IRenderer; using Key = Ryujinx.Input.Key; @@ -147,6 +140,17 @@ namespace Ryujinx.Ava private long _lastCursorMoveTime; private bool _isCursorInRenderer = true; + private bool _ignoreCursorState = false; + + private enum CursorStates + { + CursorIsHidden, + CursorIsVisible, + ForceChangeCursor + }; + + private CursorStates _cursorState = !ConfigurationState.Instance.Hid.EnableMouse.Value ? + CursorStates.CursorIsVisible : CursorStates.CursorIsHidden; private bool _isStopped; private bool _isActive; @@ -165,6 +169,7 @@ namespace Ryujinx.Ava private readonly object _lockObject = new(); public event EventHandler AppExit; + public event EventHandler StatusInitEvent; public event EventHandler StatusUpdatedEvent; public VirtualFileSystem VirtualFileSystem { get; } @@ -176,12 +181,14 @@ namespace Ryujinx.Ava public int Width { get; private set; } public int Height { get; private set; } public string ApplicationPath { get; private set; } + public ulong ApplicationId { get; private set; } public bool ScreenshotRequested { get; set; } public AppHost( RendererHost renderer, InputManager inputManager, string applicationPath, + ulong applicationId, VirtualFileSystem virtualFileSystem, ContentManager contentManager, AccountManager accountManager, @@ -205,6 +212,7 @@ namespace Ryujinx.Ava NpadManager = _inputManager.CreateNpadManager(); TouchScreenManager = _inputManager.CreateTouchScreenManager(); ApplicationPath = applicationPath; + ApplicationId = applicationId; VirtualFileSystem = virtualFileSystem; ContentManager = contentManager; @@ -253,23 +261,65 @@ namespace Ryujinx.Ava private void TopLevel_PointerEnteredOrMoved(object sender, PointerEventArgs e) { + if (!_viewModel.IsActive) + { + _isCursorInRenderer = false; + _ignoreCursorState = false; + return; + } + if (sender is MainWindow window) { - _lastCursorMoveTime = Stopwatch.GetTimestamp(); + if (ConfigurationState.Instance.HideCursor.Value == HideCursorMode.OnIdle) + { + _lastCursorMoveTime = Stopwatch.GetTimestamp(); + } var point = e.GetCurrentPoint(window).Position; var bounds = RendererHost.EmbeddedWindow.Bounds; + var windowYOffset = bounds.Y + window.MenuBarHeight; + var windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1; + + if (!_viewModel.ShowMenuAndStatusBar) + { + windowYOffset -= window.MenuBarHeight; + windowYLimit += window.StatusBarHeight + 1; + } _isCursorInRenderer = point.X >= bounds.X && - point.X <= bounds.Width + bounds.X && - point.Y >= bounds.Y && - point.Y <= bounds.Height + bounds.Y; + Math.Ceiling(point.X) <= (int)window.Bounds.Width && + point.Y >= windowYOffset && + point.Y <= windowYLimit && + !_viewModel.IsSubMenuOpen; + + _ignoreCursorState = false; } } private void TopLevel_PointerExited(object sender, PointerEventArgs e) { _isCursorInRenderer = false; + + if (sender is MainWindow window) + { + var point = e.GetCurrentPoint(window).Position; + var bounds = RendererHost.EmbeddedWindow.Bounds; + var windowYOffset = bounds.Y + window.MenuBarHeight; + var windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1; + + if (!_viewModel.ShowMenuAndStatusBar) + { + windowYOffset -= window.MenuBarHeight; + windowYLimit += window.StatusBarHeight + 1; + } + + _ignoreCursorState = (point.X == bounds.X || + Math.Ceiling(point.X) == (int)window.Bounds.Width) && + point.Y >= windowYOffset && + point.Y <= windowYLimit; + } + + _cursorState = CursorStates.ForceChangeCursor; } private void UpdateScalingFilterLevel(object sender, ReactiveEventArgs e) @@ -297,9 +347,14 @@ namespace Ryujinx.Ava if (OperatingSystem.IsWindows()) { - SetCursor(_defaultCursorWin); + if (_cursorState != CursorStates.CursorIsHidden && !_ignoreCursorState) + { + SetCursor(_defaultCursorWin); + } } }); + + _cursorState = CursorStates.CursorIsVisible; } private void HideCursor() @@ -313,6 +368,8 @@ namespace Ryujinx.Ava SetCursor(_invisibleCursorWin); } }); + + _cursorState = CursorStates.CursorIsHidden; } private void SetRendererWindowSize(Size size) @@ -333,8 +390,11 @@ namespace Ryujinx.Ava { lock (_lockObject) { + string applicationName = Device.Processes.ActiveApplication.Name; + string sanitizedApplicationName = FileSystemUtils.SanitizeFileName(applicationName); DateTime currentTime = DateTime.Now; - string filename = $"ryujinx_capture_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png"; + + string filename = $"{sanitizedApplicationName}_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png"; string directory = AppDataManager.Mode switch { @@ -355,25 +415,25 @@ namespace Ryujinx.Ava return; } - Image image = e.IsBgra ? Image.LoadPixelData(e.Data, e.Width, e.Height) - : Image.LoadPixelData(e.Data, e.Width, e.Height); + var colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888; + using SKBitmap bitmap = new SKBitmap(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul)); - if (e.FlipX) - { - image.Mutate(x => x.Flip(FlipMode.Horizontal)); - } + Marshal.Copy(e.Data, 0, bitmap.GetPixels(), e.Data.Length); - if (e.FlipY) - { - image.Mutate(x => x.Flip(FlipMode.Vertical)); - } + using SKBitmap bitmapToSave = new SKBitmap(bitmap.Width, bitmap.Height); + using SKCanvas canvas = new SKCanvas(bitmapToSave); - image.SaveAsPng(path, new PngEncoder - { - ColorType = PngColorType.Rgb, - }); + canvas.Clear(SKColors.Black); - image.Dispose(); + float scaleX = e.FlipX ? -1 : 1; + float scaleY = e.FlipY ? -1 : 1; + + var matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f); + + canvas.SetMatrix(matrix); + canvas.DrawBitmap(bitmap, SKPoint.Empty); + + SaveBitmapAsPng(bitmapToSave, path); Logger.Notice.Print(LogClass.Application, $"Screenshot saved to {path}", "Screenshot"); } @@ -385,6 +445,14 @@ namespace Ryujinx.Ava } } + private void SaveBitmapAsPng(SKBitmap bitmap, string path) + { + using var data = bitmap.Encode(SKEncodedImageFormat.Png, 100); + using var stream = File.OpenWrite(path); + + data.SaveTo(stream); + } + public void Start() { if (OperatingSystem.IsWindows()) @@ -470,6 +538,12 @@ namespace Ryujinx.Ava Device.Configuration.MultiplayerMode = e.NewValue; } + public void ToggleVSync() + { + Device.EnableDeviceVsync = !Device.EnableDeviceVsync; + _renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync); + } + public void Stop() { _isActive = false; @@ -566,6 +640,8 @@ namespace Ryujinx.Ava { _lastCursorMoveTime = Stopwatch.GetTimestamp(); } + + _cursorState = CursorStates.ForceChangeCursor; } public async Task LoadGuestApplication() @@ -687,7 +763,7 @@ namespace Ryujinx.Ava { Logger.Info?.Print(LogClass.Application, "Loading as XCI."); - if (!Device.LoadXci(ApplicationPath)) + if (!Device.LoadXci(ApplicationPath, ApplicationId)) { Device.Dispose(); @@ -714,7 +790,7 @@ namespace Ryujinx.Ava { Logger.Info?.Print(LogClass.Application, "Loading as NSP."); - if (!Device.LoadNsp(ApplicationPath)) + if (!Device.LoadNsp(ApplicationPath, ApplicationId)) { Device.Dispose(); @@ -818,34 +894,34 @@ namespace Ryujinx.Ava Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}"); // Initialize Configuration. - var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB; + var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? MemoryConfiguration.MemoryConfiguration8GiB : MemoryConfiguration.MemoryConfiguration4GiB; HLEConfiguration configuration = new(VirtualFileSystem, - _viewModel.LibHacHorizonManager, - ContentManager, - _accountManager, - _userChannelPersistence, - renderer, - InitializeAudio(), - memoryConfiguration, - _viewModel.UiHandler, - (SystemLanguage)ConfigurationState.Instance.System.Language.Value, - (RegionCode)ConfigurationState.Instance.System.Region.Value, - ConfigurationState.Instance.Graphics.EnableVsync, - ConfigurationState.Instance.System.EnableDockedMode, - ConfigurationState.Instance.System.EnablePtc, - ConfigurationState.Instance.System.EnableInternetAccess, - ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None, - ConfigurationState.Instance.System.FsGlobalAccessLogMode, - ConfigurationState.Instance.System.SystemTimeOffset, - ConfigurationState.Instance.System.TimeZone, - ConfigurationState.Instance.System.MemoryManagerMode, - ConfigurationState.Instance.System.IgnoreMissingServices, - ConfigurationState.Instance.Graphics.AspectRatio, - ConfigurationState.Instance.System.AudioVolume, - ConfigurationState.Instance.System.UseHypervisor, - ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value, - ConfigurationState.Instance.Multiplayer.Mode); + _viewModel.LibHacHorizonManager, + ContentManager, + _accountManager, + _userChannelPersistence, + renderer, + InitializeAudio(), + memoryConfiguration, + _viewModel.UIHandler, + (SystemLanguage)ConfigurationState.Instance.System.Language.Value, + (RegionCode)ConfigurationState.Instance.System.Region.Value, + ConfigurationState.Instance.Graphics.EnableVsync, + ConfigurationState.Instance.System.EnableDockedMode, + ConfigurationState.Instance.System.EnablePtc, + ConfigurationState.Instance.System.EnableInternetAccess, + ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None, + ConfigurationState.Instance.System.FsGlobalAccessLogMode, + ConfigurationState.Instance.System.SystemTimeOffset, + ConfigurationState.Instance.System.TimeZone, + ConfigurationState.Instance.System.MemoryManagerMode, + ConfigurationState.Instance.System.IgnoreMissingServices, + ConfigurationState.Instance.Graphics.AspectRatio, + ConfigurationState.Instance.System.AudioVolume, + ConfigurationState.Instance.System.UseHypervisor, + ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value, + ConfigurationState.Instance.Multiplayer.Mode); Device = new Switch(configuration); } @@ -969,7 +1045,6 @@ namespace Ryujinx.Ava { Device.Gpu.SetGpuThread(); Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token); - Translator.IsReadyForTranslation.Set(); _renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync); @@ -992,6 +1067,7 @@ namespace Ryujinx.Ava { _renderingStarted = true; _viewModel.SwitchToRenderer(false); + InitStatus(); } Device.PresentFrame(() => (RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.SwapBuffers()); @@ -1015,6 +1091,18 @@ namespace Ryujinx.Ava (RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true); } + public void InitStatus() + { + StatusInitEvent?.Invoke(this, new StatusInitEventArgs( + ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch + { + GraphicsBackend.Vulkan => "Vulkan", + GraphicsBackend.OpenGl => "OpenGL", + _ => throw new NotImplementedException() + }, + $"GPU: {_renderer.GetHardwareInfo().GpuDriver}")); + } + public void UpdateStatus() { // Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued. @@ -1028,12 +1116,10 @@ namespace Ryujinx.Ava StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs( Device.EnableDeviceVsync, LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%", - ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan ? "Vulkan" : "OpenGL", dockedMode, ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), LocaleManager.Instance[LocaleKeys.Game] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", - $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %", - $"GPU: {_renderer.GetHardwareInfo().GpuVendor}")); + $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %")); } public async Task ShowExitPrompt() @@ -1070,38 +1156,32 @@ namespace Ryujinx.Ava if (_viewModel.IsActive) { - if (_isCursorInRenderer) + bool isCursorVisible = true; + + if (_isCursorInRenderer && !_viewModel.ShowLoadProgress) { - if (ConfigurationState.Instance.Hid.EnableMouse) + if (ConfigurationState.Instance.Hid.EnableMouse.Value) { - HideCursor(); + isCursorVisible = ConfigurationState.Instance.HideCursor.Value == HideCursorMode.Never; } else { - switch (ConfigurationState.Instance.HideCursor.Value) - { - case HideCursorMode.Never: - ShowCursor(); - break; - case HideCursorMode.OnIdle: - if (Stopwatch.GetTimestamp() - _lastCursorMoveTime >= CursorHideIdleTime * Stopwatch.Frequency) - { - HideCursor(); - } - else - { - ShowCursor(); - } - break; - case HideCursorMode.Always: - HideCursor(); - break; - } + isCursorVisible = ConfigurationState.Instance.HideCursor.Value == HideCursorMode.Never || + (ConfigurationState.Instance.HideCursor.Value == HideCursorMode.OnIdle && + Stopwatch.GetTimestamp() - _lastCursorMoveTime < CursorHideIdleTime * Stopwatch.Frequency); } } - else + + if (_cursorState != (isCursorVisible ? CursorStates.CursorIsVisible : CursorStates.CursorIsHidden)) { - ShowCursor(); + if (isCursorVisible) + { + ShowCursor(); + } + else + { + HideCursor(); + } } Dispatcher.UIThread.Post(() => @@ -1119,13 +1199,12 @@ namespace Ryujinx.Ava switch (currentHotkeyState) { case KeyboardHotkeyState.ToggleVSync: - Device.EnableDeviceVsync = !Device.EnableDeviceVsync; - + ToggleVSync(); break; case KeyboardHotkeyState.Screenshot: ScreenshotRequested = true; break; - case KeyboardHotkeyState.ShowUi: + case KeyboardHotkeyState.ShowUI: _viewModel.ShowMenuAndStatusBar = !_viewModel.ShowMenuAndStatusBar; break; case KeyboardHotkeyState.Pause: @@ -1188,7 +1267,7 @@ namespace Ryujinx.Ava // Touchscreen. bool hasTouch = false; - if (_viewModel.IsActive && !ConfigurationState.Instance.Hid.EnableMouse) + if (_viewModel.IsActive && !ConfigurationState.Instance.Hid.EnableMouse.Value) { hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as AvaloniaMouseDriver).IsButtonPressed(MouseButton.Button1), ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat()); } @@ -1215,9 +1294,9 @@ namespace Ryujinx.Ava { state = KeyboardHotkeyState.Screenshot; } - else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi)) + else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI)) { - state = KeyboardHotkeyState.ShowUi; + state = KeyboardHotkeyState.ShowUI; } else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause)) { diff --git a/src/Ryujinx.Ava/Assets/Fonts/SegoeFluentIcons.ttf b/src/Ryujinx/Assets/Fonts/SegoeFluentIcons.ttf similarity index 100% rename from src/Ryujinx.Ava/Assets/Fonts/SegoeFluentIcons.ttf rename to src/Ryujinx/Assets/Fonts/SegoeFluentIcons.ttf diff --git a/src/Ryujinx/Assets/Icons/Controller_JoyConLeft.svg b/src/Ryujinx/Assets/Icons/Controller_JoyConLeft.svg new file mode 100644 index 000000000..cf78cf120 --- /dev/null +++ b/src/Ryujinx/Assets/Icons/Controller_JoyConLeft.svg @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx/Assets/Icons/Controller_JoyConPair.svg b/src/Ryujinx/Assets/Icons/Controller_JoyConPair.svg new file mode 100644 index 000000000..8097762df --- /dev/null +++ b/src/Ryujinx/Assets/Icons/Controller_JoyConPair.svg @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx/Assets/Icons/Controller_JoyConRight.svg b/src/Ryujinx/Assets/Icons/Controller_JoyConRight.svg new file mode 100644 index 000000000..adb6e1e18 --- /dev/null +++ b/src/Ryujinx/Assets/Icons/Controller_JoyConRight.svg @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx/Assets/Icons/Controller_ProCon.svg b/src/Ryujinx/Assets/Icons/Controller_ProCon.svg new file mode 100644 index 000000000..53eef82c2 --- /dev/null +++ b/src/Ryujinx/Assets/Icons/Controller_ProCon.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Ryujinx/Assets/Locales/ar_SA.json b/src/Ryujinx/Assets/Locales/ar_SA.json new file mode 100644 index 000000000..73e55633b --- /dev/null +++ b/src/Ryujinx/Assets/Locales/ar_SA.json @@ -0,0 +1,780 @@ +{ + "Language": "اَلْعَرَبِيَّةُ", + "MenuBarFileOpenApplet": "فتح التطبيق المصغر", + "MenuBarFileOpenAppletOpenMiiAppletToolTip": "‫افتح تطبيق تحرير Mii في الوضع المستقل", + "SettingsTabInputDirectMouseAccess": "الوصول المباشر للفأرة", + "SettingsTabSystemMemoryManagerMode": "وضع إدارة الذاكرة:", + "SettingsTabSystemMemoryManagerModeSoftware": "البرنامج", + "SettingsTabSystemMemoryManagerModeHost": "المُضيف (سريع)", + "SettingsTabSystemMemoryManagerModeHostUnchecked": "المضيف (غير مفحوص) (أسرع، غير آمن)", + "SettingsTabSystemUseHypervisor": "استخدم مراقب الأجهزة الافتراضية", + "MenuBarFile": "_ملف", + "MenuBarFileOpenFromFile": "_تحميل تطبيق من ملف", + "MenuBarFileOpenUnpacked": "تحميل لُعْبَة غير محزومة", + "MenuBarFileOpenEmuFolder": "‫فتح مجلد Ryujinx", + "MenuBarFileOpenLogsFolder": "فتح مجلد السجلات", + "MenuBarFileExit": "_خروج", + "MenuBarOptions": "_خيارات", + "MenuBarOptionsToggleFullscreen": "التبديل إلى وضع ملء الشاشة", + "MenuBarOptionsStartGamesInFullscreen": "ابدأ الألعاب في وضع ملء الشاشة", + "MenuBarOptionsStopEmulation": "إيقاف المحاكاة", + "MenuBarOptionsSettings": "_الإعدادات", + "MenuBarOptionsManageUserProfiles": "_إدارة الملفات الشخصية للمستخدم", + "MenuBarActions": "_الإجراءات", + "MenuBarOptionsSimulateWakeUpMessage": "محاكاة رسالة الاستيقاظ", + "MenuBarActionsScanAmiibo": "‫فحص Amiibo", + "MenuBarTools": "_الأدوات", + "MenuBarToolsInstallFirmware": "تثبيت البرنامج الثابت", + "MenuBarFileToolsInstallFirmwareFromFile": "تثبيت برنامج ثابت من XCI أو ZIP", + "MenuBarFileToolsInstallFirmwareFromDirectory": "تثبيت برنامج ثابت من مجلد", + "MenuBarToolsManageFileTypes": "إدارة أنواع الملفات", + "MenuBarToolsInstallFileTypes": "تثبيت أنواع الملفات", + "MenuBarToolsUninstallFileTypes": "إزالة أنواع الملفات", + "MenuBarView": "_عرض", + "MenuBarViewWindow": "حجم النافذة", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_مساعدة", + "MenuBarHelpCheckForUpdates": "تحقق من التحديثات", + "MenuBarHelpAbout": "حول", + "MenuSearch": "بحث...", + "GameListHeaderFavorite": "مفضلة", + "GameListHeaderIcon": "الأيقونة", + "GameListHeaderApplication": "الاسم", + "GameListHeaderDeveloper": "المطور", + "GameListHeaderVersion": "الإصدار", + "GameListHeaderTimePlayed": "وقت اللعب", + "GameListHeaderLastPlayed": "آخر مرة لُعبت", + "GameListHeaderFileExtension": "صيغة الملف", + "GameListHeaderFileSize": "حجم الملف", + "GameListHeaderPath": "المسار", + "GameListContextMenuOpenUserSaveDirectory": "فتح مجلد حفظ المستخدم", + "GameListContextMenuOpenUserSaveDirectoryToolTip": "يفتح المجلد الذي يحتوي على حفظ المستخدم للتطبيق", + "GameListContextMenuOpenDeviceSaveDirectory": "فتح مجلد حفظ الجهاز", + "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "يفتح المجلد الذي يحتوي على حفظ الجهاز للتطبيق", + "GameListContextMenuOpenBcatSaveDirectory": "‫فتح مجلد حفظ الـBCAT", + "GameListContextMenuOpenBcatSaveDirectoryToolTip": "‫يفتح المجلد الذي يحتوي على حفظ الـBCAT للتطبيق", + "GameListContextMenuManageTitleUpdates": "إدارة تحديثات اللُعبة", + "GameListContextMenuManageTitleUpdatesToolTip": "يفتح نافذة إدارة تحديث اللُعبة", + "GameListContextMenuManageDlc": "إدارة المحتوي الإضافي", + "GameListContextMenuManageDlcToolTip": "يفتح نافذة إدارة المحتوي الإضافي", + "GameListContextMenuCacheManagement": "إدارة ذاكرة التخزين المؤقت", + "GameListContextMenuCacheManagementPurgePptc": "قائمة انتظار إعادة بناء الـ‫PPTC", + "GameListContextMenuCacheManagementPurgePptcToolTip": "تنشيط ‫PPTC لإعادة البناء في وقت الإقلاع عند بدء تشغيل اللعبة التالي", + "GameListContextMenuCacheManagementPurgeShaderCache": "تنظيف ذاكرة مرشحات الفيديو المؤقتة", + "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "يحذف ذاكرة مرشحات الفيديو المؤقتة الخاصة بالتطبيق", + "GameListContextMenuCacheManagementOpenPptcDirectory": "‫فتح مجلد PPTC", + "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "‫‫يفتح المجلد الذي يحتوي على ذاكرة التخزين المؤقت للترجمة المستمرة (PPTC) للتطبيق", + "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "فتح مجلد الذاكرة المؤقتة لمرشحات الفيديو ", + "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "يفتح المجلد الذي يحتوي على ذاكرة المظللات المؤقتة للتطبيق", + "GameListContextMenuExtractData": "استخراج البيانات", + "GameListContextMenuExtractDataExeFS": "ExeFS", + "GameListContextMenuExtractDataExeFSToolTip": "‫‫ استخراج قسم نظام الملفات القابل للتنفيذ (ExeFS) من الإعدادات الحالية للتطبيقات (يتضمن التحديثات)", + "GameListContextMenuExtractDataRomFS": "RomFS", + "GameListContextMenuExtractDataRomFSToolTip": "استخراج قسم RomFS من الإعدادات الحالية للتطبيقات (يتضمن التحديثات)", + "GameListContextMenuExtractDataLogo": "شعار", + "GameListContextMenuExtractDataLogoToolTip": "استخراج قسم الشعار من الإعدادات الحالية للتطبيقات (يتضمن التحديثات)", + "GameListContextMenuCreateShortcut": "إنشاء اختصار للتطبيق", + "GameListContextMenuCreateShortcutToolTip": "أنشئ اختصار سطح مكتب لتشغيل التطبيق المحدد", + "GameListContextMenuCreateShortcutToolTipMacOS": "أنشئ اختصار يُشغل التطبيق المحدد في مجلد تطبيقات ‫macOS", + "GameListContextMenuOpenModsDirectory": "‫فتح مجلد التعديلات (Mods)", + "GameListContextMenuOpenModsDirectoryToolTip": "يفتح المجلد الذي يحتوي على تعديلات‫(mods) التطبيق", + "GameListContextMenuOpenSdModsDirectory": "فتح مجلد تعديلات‫(mods) أتموسفير", + "GameListContextMenuOpenSdModsDirectoryToolTip": "يفتح مجلد أتموسفير لبطاقة SD البديلة الذي يحتوي على تعديلات التطبيق. مفيد للتعديلات التي تم تعبئتها للأجهزة الحقيقية.", + "StatusBarGamesLoaded": "{0}/{1} لعبة تم تحميلها", + "StatusBarSystemVersion": "إصدار النظام: {0}", + "LinuxVmMaxMapCountDialogTitle": "الحد الأدنى لتعيينات الذاكرة المكتشفة", + "LinuxVmMaxMapCountDialogTextPrimary": "هل ترغب في زيادة قيمة vm.max_map_count إلى {0}", + "LinuxVmMaxMapCountDialogTextSecondary": "قد تحاول بعض الألعاب إنشاء المزيد من تعيينات الذاكرة أكثر مما هو مسموح به حاليا. سيغلق ريوجينكس بمجرد تجاوز هذا الحد.", + "LinuxVmMaxMapCountDialogButtonUntilRestart": "نعم، حتى إعادة التشغيل التالية", + "LinuxVmMaxMapCountDialogButtonPersistent": "نعم، دائمًا", + "LinuxVmMaxMapCountWarningTextPrimary": "الحد الأقصى لمقدار تعيينات الذاكرة أقل من الموصى به.", + "LinuxVmMaxMapCountWarningTextSecondary": "القيمة الحالية لـ vm.max_map_count ({0}) أقل من {1}. قد تحاول بعض الألعاب إنشاء المزيد من تعيينات الذاكرة أكثر مما هو مسموح به حاليا. سيغلق ريوجينكس بمجرد تجاوز هذا الحد.\n\nقد ترغب إما في زيادة الحد يدويا أو تثبيت pkexec، مما يسمح لـ ريوجينكس بالمساعدة في ذلك.", + "Settings": "إعدادات", + "SettingsTabGeneral": "واجهة المستخدم", + "SettingsTabGeneralGeneral": "عام", + "SettingsTabGeneralEnableDiscordRichPresence": "تمكين وجود ديسكورد الغني", + "SettingsTabGeneralCheckUpdatesOnLaunch": "التحقق من وجود تحديثات عند التشغيل", + "SettingsTabGeneralShowConfirmExitDialog": "إظهار مربع حوار \"تأكيد الخروج\"", + "SettingsTabGeneralRememberWindowState": "تذكر حجم/موضع النافذة", + "SettingsTabGeneralHideCursor": "إخفاء المؤشر:", + "SettingsTabGeneralHideCursorNever": "مطلقا", + "SettingsTabGeneralHideCursorOnIdle": "عند الخمول", + "SettingsTabGeneralHideCursorAlways": "دائما", + "SettingsTabGeneralGameDirectories": "مجلدات الألعاب", + "SettingsTabGeneralAdd": "إضافة", + "SettingsTabGeneralRemove": "إزالة", + "SettingsTabSystem": "النظام", + "SettingsTabSystemCore": "النواة", + "SettingsTabSystemSystemRegion": "منطقة النظام:", + "SettingsTabSystemSystemRegionJapan": "اليابان", + "SettingsTabSystemSystemRegionUSA": "الولايات المتحدة الأمريكية", + "SettingsTabSystemSystemRegionEurope": "أوروبا", + "SettingsTabSystemSystemRegionAustralia": "أستراليا", + "SettingsTabSystemSystemRegionChina": "الصين", + "SettingsTabSystemSystemRegionKorea": "كوريا", + "SettingsTabSystemSystemRegionTaiwan": "تايوان", + "SettingsTabSystemSystemLanguage": "لغة النظام:", + "SettingsTabSystemSystemLanguageJapanese": "اليابانية", + "SettingsTabSystemSystemLanguageAmericanEnglish": "الإنجليزية الأمريكية", + "SettingsTabSystemSystemLanguageFrench": "الفرنسية", + "SettingsTabSystemSystemLanguageGerman": "الألمانية", + "SettingsTabSystemSystemLanguageItalian": "الإيطالية", + "SettingsTabSystemSystemLanguageSpanish": "الإسبانية", + "SettingsTabSystemSystemLanguageChinese": "الصينية", + "SettingsTabSystemSystemLanguageKorean": "الكورية", + "SettingsTabSystemSystemLanguageDutch": "الهولندية", + "SettingsTabSystemSystemLanguagePortuguese": "البرتغالية", + "SettingsTabSystemSystemLanguageRussian": "الروسية", + "SettingsTabSystemSystemLanguageTaiwanese": "التايوانية", + "SettingsTabSystemSystemLanguageBritishEnglish": "الإنجليزية البريطانية", + "SettingsTabSystemSystemLanguageCanadianFrench": "الفرنسية الكندية", + "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "إسبانية أمريكا اللاتينية", + "SettingsTabSystemSystemLanguageSimplifiedChinese": "الصينية المبسطة", + "SettingsTabSystemSystemLanguageTraditionalChinese": "الصينية التقليدية", + "SettingsTabSystemSystemTimeZone": "النطاق الزمني للنظام:", + "SettingsTabSystemSystemTime": "توقيت النظام:", + "SettingsTabSystemEnableVsync": "VSync", + "SettingsTabSystemEnablePptc": "PPTC (ذاكرة التخزين المؤقت للترجمة المستمرة)", + "SettingsTabSystemEnableFsIntegrityChecks": "التحقق من سلامة نظام الملفات", + "SettingsTabSystemAudioBackend": "خلفية الصوت:", + "SettingsTabSystemAudioBackendDummy": "زائف", + "SettingsTabSystemAudioBackendOpenAL": "OpenAL", + "SettingsTabSystemAudioBackendSoundIO": "SoundIO", + "SettingsTabSystemAudioBackendSDL2": "SDL2", + "SettingsTabSystemHacks": "هاكات", + "SettingsTabSystemHacksNote": "قد يتسبب في عدم الاستقرار", + "SettingsTabSystemExpandDramSize": "استخدام تخطيط الذاكرة البديل (المطورين)", + "SettingsTabSystemIgnoreMissingServices": "تجاهل الخدمات المفقودة", + "SettingsTabGraphics": "الرسومات", + "SettingsTabGraphicsAPI": "API الرسومات ", + "SettingsTabGraphicsEnableShaderCache": "تفعيل ذاكرة المظللات المؤقتة", + "SettingsTabGraphicsAnisotropicFiltering": "تصفية:", + "SettingsTabGraphicsAnisotropicFilteringAuto": "تلقائي", + "SettingsTabGraphicsAnisotropicFiltering2x": "2x", + "SettingsTabGraphicsAnisotropicFiltering4x": "4×", + "SettingsTabGraphicsAnisotropicFiltering8x": "8x", + "SettingsTabGraphicsAnisotropicFiltering16x": "16x", + "SettingsTabGraphicsResolutionScale": "مقياس الدقة", + "SettingsTabGraphicsResolutionScaleCustom": "مخصص (لا ينصح به)", + "SettingsTabGraphicsResolutionScaleNative": "الأصل ‫(720p/1080p)", + "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", + "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (لا ينصح به)", + "SettingsTabGraphicsAspectRatio": "نسبة الارتفاع إلى العرض:", + "SettingsTabGraphicsAspectRatio4x3": "4:3", + "SettingsTabGraphicsAspectRatio16x9": "16:9", + "SettingsTabGraphicsAspectRatio16x10": "16:10", + "SettingsTabGraphicsAspectRatio21x9": "21:9", + "SettingsTabGraphicsAspectRatio32x9": "32:9", + "SettingsTabGraphicsAspectRatioStretch": "تمديد لتناسب النافذة", + "SettingsTabGraphicsDeveloperOptions": "خيارات المطور", + "SettingsTabGraphicsShaderDumpPath": "مسار تفريغ المظللات:", + "SettingsTabLogging": "تسجيل", + "SettingsTabLoggingLogging": "تسجيل", + "SettingsTabLoggingEnableLoggingToFile": "تفعيل التسجيل إلى ملف", + "SettingsTabLoggingEnableStubLogs": "تفعيل سجلات الـStub", + "SettingsTabLoggingEnableInfoLogs": "تفعيل سجلات المعلومات", + "SettingsTabLoggingEnableWarningLogs": "تفعيل سجلات التحذير", + "SettingsTabLoggingEnableErrorLogs": "تفعيل سجلات الأخطاء", + "SettingsTabLoggingEnableTraceLogs": "تفعيل سجلات التتبع", + "SettingsTabLoggingEnableGuestLogs": "تفعيل سجلات الضيوف", + "SettingsTabLoggingEnableFsAccessLogs": "تمكين سجلات الوصول إلى نظام الملفات", + "SettingsTabLoggingFsGlobalAccessLogMode": "وضع سجل الوصول العالمي لنظام الملفات:", + "SettingsTabLoggingDeveloperOptions": "خيارات المطور", + "SettingsTabLoggingDeveloperOptionsNote": "تحذير: سوف يقلل من الأداء", + "SettingsTabLoggingGraphicsBackendLogLevel": "مستوى سجل خلفية الرسومات:", + "SettingsTabLoggingGraphicsBackendLogLevelNone": "لا شيء", + "SettingsTabLoggingGraphicsBackendLogLevelError": "خطأ", + "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "تباطؤ", + "SettingsTabLoggingGraphicsBackendLogLevelAll": "الكل", + "SettingsTabLoggingEnableDebugLogs": "تمكين سجلات التصحيح", + "SettingsTabInput": "الإدخال", + "SettingsTabInputEnableDockedMode": "تركيب بالمنصة", + "SettingsTabInputDirectKeyboardAccess": "الوصول المباشر للوحة المفاتيح", + "SettingsButtonSave": "حفظ", + "SettingsButtonClose": "إغلاق", + "SettingsButtonOk": "موافق", + "SettingsButtonCancel": "إلغاء", + "SettingsButtonApply": "تطبيق", + "ControllerSettingsPlayer": "اللاعب", + "ControllerSettingsPlayer1": "اللاعب 1", + "ControllerSettingsPlayer2": "اللاعب 2", + "ControllerSettingsPlayer3": "اللاعب 3", + "ControllerSettingsPlayer4": "اللاعب 4", + "ControllerSettingsPlayer5": "اللاعب 5", + "ControllerSettingsPlayer6": "اللاعب 6", + "ControllerSettingsPlayer7": "اللاعب 7", + "ControllerSettingsPlayer8": "اللاعب 8", + "ControllerSettingsHandheld": "محمول", + "ControllerSettingsInputDevice": "جهاز الإدخال", + "ControllerSettingsRefresh": "تحديث", + "ControllerSettingsDeviceDisabled": "معطل", + "ControllerSettingsControllerType": "نوع وحدة التحكم", + "ControllerSettingsControllerTypeHandheld": "محمول", + "ControllerSettingsControllerTypeProController": "وحدة تحكم برو", + "ControllerSettingsControllerTypeJoyConPair": "زوج جوي كون", + "ControllerSettingsControllerTypeJoyConLeft": "جوي كون اليسار ", + "ControllerSettingsControllerTypeJoyConRight": " جوي كون اليمين", + "ControllerSettingsProfile": "الملف الشخصي", + "ControllerSettingsProfileDefault": "افتراضي", + "ControllerSettingsLoad": "تحميل", + "ControllerSettingsAdd": "إضافة", + "ControllerSettingsRemove": "إزالة", + "ControllerSettingsButtons": "الأزرار", + "ControllerSettingsButtonA": "A", + "ControllerSettingsButtonB": "B", + "ControllerSettingsButtonX": "X", + "ControllerSettingsButtonY": "Y", + "ControllerSettingsButtonPlus": "+", + "ControllerSettingsButtonMinus": "-", + "ControllerSettingsDPad": "أسهم الاتجاهات", + "ControllerSettingsDPadUp": "اعلى", + "ControllerSettingsDPadDown": "أسفل", + "ControllerSettingsDPadLeft": "يسار", + "ControllerSettingsDPadRight": "يمين", + "ControllerSettingsStickButton": "زر", + "ControllerSettingsStickUp": "فوق", + "ControllerSettingsStickDown": "أسفل", + "ControllerSettingsStickLeft": "يسار", + "ControllerSettingsStickRight": "يمين", + "ControllerSettingsStickStick": "عصا", + "ControllerSettingsStickInvertXAxis": "عكس عرض العصا", + "ControllerSettingsStickInvertYAxis": "عكس أفق العصا", + "ControllerSettingsStickDeadzone": "المنطقة الميتة:", + "ControllerSettingsLStick": "العصا اليسرى", + "ControllerSettingsRStick": "العصا اليمنى", + "ControllerSettingsTriggersLeft": "الأزندة اليسرى", + "ControllerSettingsTriggersRight": "الأزندة اليمني", + "ControllerSettingsTriggersButtonsLeft": "أزرار الزناد اليسرى", + "ControllerSettingsTriggersButtonsRight": "أزرار الزناد اليمنى", + "ControllerSettingsTriggers": "أزندة", + "ControllerSettingsTriggerL": "L", + "ControllerSettingsTriggerR": "R", + "ControllerSettingsTriggerZL": "ZL", + "ControllerSettingsTriggerZR": "ZR", + "ControllerSettingsLeftSL": "SL", + "ControllerSettingsLeftSR": "SR", + "ControllerSettingsRightSL": "SL", + "ControllerSettingsRightSR": "SR", + "ControllerSettingsExtraButtonsLeft": "الأزرار اليسار", + "ControllerSettingsExtraButtonsRight": "الأزرار اليمين", + "ControllerSettingsMisc": "إعدادات إضافية", + "ControllerSettingsTriggerThreshold": "قوة التحفيز:", + "ControllerSettingsMotion": "الحركة", + "ControllerSettingsMotionUseCemuhookCompatibleMotion": "استخدام الحركة المتوافقة مع CemuHook", + "ControllerSettingsMotionControllerSlot": "خانة وحدة التحكم:", + "ControllerSettingsMotionMirrorInput": "إعادة الإدخال", + "ControllerSettingsMotionRightJoyConSlot": "خانة جويكون اليمين :", + "ControllerSettingsMotionServerHost": "مضيف الخادم:", + "ControllerSettingsMotionGyroSensitivity": "حساسية مستشعر الحركة:", + "ControllerSettingsMotionGyroDeadzone": "منطقة مستشعر الحركة الميتة:", + "ControllerSettingsSave": "حفظ", + "ControllerSettingsClose": "إغلاق", + "KeyUnknown": "مجهول", + "KeyShiftLeft": "زر ‫Shift الأيسر", + "KeyShiftRight": "زر ‫Shift الأيمن", + "KeyControlLeft": "زر ‫Ctrl الأيسر", + "KeyMacControlLeft": "زر ⌃ الأيسر", + "KeyControlRight": "زر ‫Ctrl الأيمن", + "KeyMacControlRight": "زر ⌃ الأيمن", + "KeyAltLeft": "زر ‫Alt الأيسر", + "KeyMacAltLeft": "زر ⌥ الأيسر", + "KeyAltRight": "زر ‫Alt الأيمن", + "KeyMacAltRight": "زر ⌥ الأيمن", + "KeyWinLeft": "زر ⊞ الأيسر", + "KeyMacWinLeft": "زر ⌘ الأيسر", + "KeyWinRight": "زر ⊞ الأيمن", + "KeyMacWinRight": "زر ⌘ الأيمن", + "KeyMenu": "زر القائمة", + "KeyUp": "فوق", + "KeyDown": "اسفل", + "KeyLeft": "يسار", + "KeyRight": "يمين", + "KeyEnter": "مفتاح الإدخال", + "KeyEscape": "زر ‫Escape", + "KeySpace": "مسافة", + "KeyTab": "زر ‫Tab", + "KeyBackSpace": "زر المسح للخلف", + "KeyInsert": "زر Insert", + "KeyDelete": "زر الحذف", + "KeyPageUp": "زر ‫Page Up", + "KeyPageDown": "زر ‫Page Down", + "KeyHome": "زر ‫Home", + "KeyEnd": "زر ‫End", + "KeyCapsLock": "زر الحروف الكبيرة", + "KeyScrollLock": "زر ‫Scroll Lock", + "KeyPrintScreen": "زر ‫Print Screen", + "KeyPause": "زر Pause", + "KeyNumLock": "زر Num Lock", + "KeyClear": "زر Clear", + "KeyKeypad0": "لوحة الأرقام 0", + "KeyKeypad1": "لوحة الأرقام 1", + "KeyKeypad2": "لوحة الأرقام 2", + "KeyKeypad3": "لوحة الأرقام 3", + "KeyKeypad4": "لوحة الأرقام 4", + "KeyKeypad5": "لوحة الأرقام 5", + "KeyKeypad6": "لوحة الأرقام 6", + "KeyKeypad7": "لوحة الأرقام 7", + "KeyKeypad8": "لوحة الأرقام 8", + "KeyKeypad9": "لوحة الأرقام 9", + "KeyKeypadDivide": "لوحة الأرقام علامة القسمة", + "KeyKeypadMultiply": "لوحة الأرقام علامة الضرب", + "KeyKeypadSubtract": "لوحة الأرقام علامة الطرح\n", + "KeyKeypadAdd": "لوحة الأرقام علامة الزائد", + "KeyKeypadDecimal": "لوحة الأرقام الفاصلة العشرية", + "KeyKeypadEnter": "لوحة الأرقام زر الإدخال", + "KeyNumber0": "٠", + "KeyNumber1": "١", + "KeyNumber2": "٢", + "KeyNumber3": "٣", + "KeyNumber4": "٤", + "KeyNumber5": "٥", + "KeyNumber6": "٦", + "KeyNumber7": "٧", + "KeyNumber8": "٨", + "KeyNumber9": "٩", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "غير مرتبط", + "GamepadLeftStick": "زر عصا التحكم اليسرى", + "GamepadRightStick": "زر عصا التحكم اليمنى", + "GamepadLeftShoulder": "زر الكتف الأيسر‫ L", + "GamepadRightShoulder": "زر الكتف الأيمن‫ R", + "GamepadLeftTrigger": "زر الزناد الأيسر‫ (ZL)", + "GamepadRightTrigger": "زر الزناد الأيمن‫ (ZR)", + "GamepadDpadUp": "فوق", + "GamepadDpadDown": "اسفل", + "GamepadDpadLeft": "يسار", + "GamepadDpadRight": "يمين", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "دليل", + "GamepadMisc1": "متنوع", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "لوحة اللمس", + "GamepadSingleLeftTrigger0": "زر الزناد الأيسر 0", + "GamepadSingleRightTrigger0": "زر الزناد الأيمن 0", + "GamepadSingleLeftTrigger1": "زر الزناد الأيسر 1", + "GamepadSingleRightTrigger1": "زر الزناد الأيمن 1", + "StickLeft": "عصا التحكم اليسرى", + "StickRight": "عصا التحكم اليمنى", + "UserProfilesSelectedUserProfile": "الملف الشخصي المحدد للمستخدم:", + "UserProfilesSaveProfileName": "حفظ اسم الملف الشخصي", + "UserProfilesChangeProfileImage": "تغيير صورة الملف الشخصي", + "UserProfilesAvailableUserProfiles": "الملفات الشخصية للمستخدم المتاحة:", + "UserProfilesAddNewProfile": "إنشاء ملف الشخصي", + "UserProfilesDelete": "حذف", + "UserProfilesClose": "إغلاق", + "ProfileNameSelectionWatermark": "اختر اسم مستعار", + "ProfileImageSelectionTitle": "تحديد صورة الملف الشخصي", + "ProfileImageSelectionHeader": "اختر صورة الملف الشخصي", + "ProfileImageSelectionNote": "يمكنك استيراد صورة ملف شخصي مخصصة، أو تحديد صورة رمزية من البرامج الثابتة للنظام", + "ProfileImageSelectionImportImage": "استيراد ملف الصورة", + "ProfileImageSelectionSelectAvatar": "حدد الصورة الرمزية من البرنامج الثابتة", + "InputDialogTitle": "حوار الإدخال", + "InputDialogOk": "موافق", + "InputDialogCancel": "إلغاء", + "InputDialogAddNewProfileTitle": "اختر اسم الملف الشخصي", + "InputDialogAddNewProfileHeader": "الرجاء إدخال اسم الملف الشخصي", + "InputDialogAddNewProfileSubtext": "(الطول الأقصى: {0})", + "AvatarChoose": "اختر الصورة الرمزية", + "AvatarSetBackgroundColor": "تعيين لون الخلفية", + "AvatarClose": "إغلاق", + "ControllerSettingsLoadProfileToolTip": "تحميل الملف الشخصي", + "ControllerSettingsAddProfileToolTip": "إضافة ملف شخصي", + "ControllerSettingsRemoveProfileToolTip": "إزالة الملف الشخصي", + "ControllerSettingsSaveProfileToolTip": "حفظ الملف الشخصي", + "MenuBarFileToolsTakeScreenshot": "أخذ لقطة للشاشة", + "MenuBarFileToolsHideUi": "إخفاء واجهة المستخدم", + "GameListContextMenuRunApplication": "تشغيل التطبيق", + "GameListContextMenuToggleFavorite": "تعيين كمفضل", + "GameListContextMenuToggleFavoriteToolTip": "تبديل الحالة المفضلة للعبة", + "SettingsTabGeneralTheme": "السمة:", + "SettingsTabGeneralThemeDark": "داكن", + "SettingsTabGeneralThemeLight": "فاتح", + "ControllerSettingsConfigureGeneral": "ضبط", + "ControllerSettingsRumble": "الاهتزاز", + "ControllerSettingsRumbleStrongMultiplier": "مضاعف اهتزاز قوي", + "ControllerSettingsRumbleWeakMultiplier": "مضاعف اهتزاز ضعيف", + "DialogMessageSaveNotAvailableMessage": "لا توجد بيانات الحفظ لـ {0} [{1:x16}]", + "DialogMessageSaveNotAvailableCreateSaveMessage": "هل ترغب في إنشاء بيانات الحفظ لهذه اللعبة؟", + "DialogConfirmationTitle": "ريوجينكس - تأكيد", + "DialogUpdaterTitle": "ريوجينكس - المحدث", + "DialogErrorTitle": "ريوجينكس - خطأ", + "DialogWarningTitle": "ريوجينكس - تحذير", + "DialogExitTitle": "ريوجينكس - الخروج", + "DialogErrorMessage": "واجه ريوجينكس خطأ", + "DialogExitMessage": "هل أنت متأكد من أنك تريد إغلاق ريوجينكس؟", + "DialogExitSubMessage": "سيتم فقدان كافة البيانات غير المحفوظة!", + "DialogMessageCreateSaveErrorMessage": "حدث خطأ أثناء إنشاء بيانات الحفظ المحددة: {0}", + "DialogMessageFindSaveErrorMessage": "حدث خطأ أثناء البحث عن بيانات الحفظ المحددة: {0}", + "FolderDialogExtractTitle": "اختر المجلد الذي تريد الاستخراج إليه", + "DialogNcaExtractionMessage": "استخراج قسم {0} من {1}...", + "DialogNcaExtractionTitle": "ريوجينكس - مستخرج قسم NCA", + "DialogNcaExtractionMainNcaNotFoundErrorMessage": "فشل الاستخراج. لم يكن NCA الرئيسي موجودا في الملف المحدد.", + "DialogNcaExtractionCheckLogErrorMessage": "فشل الاستخراج. اقرأ ملف التسجيل لمزيد من المعلومات.", + "DialogNcaExtractionSuccessMessage": "تم الاستخراج بنجاح.", + "DialogUpdaterConvertFailedMessage": "فشل تحويل إصدار ريوجينكس الحالي.", + "DialogUpdaterCancelUpdateMessage": "إلغاء التحديث", + "DialogUpdaterAlreadyOnLatestVersionMessage": "أنت تستخدم بالفعل أحدث إصدار من ريوجينكس!", + "DialogUpdaterFailedToGetVersionMessage": "حدث خطأ أثناء محاولة الحصول على معلومات الإصدار من إصدار غيت هاب. يمكن أن يحدث هذا إذا تم تجميع إصدار جديد بواسطة إجراءات غيت هاب. جرب مجددا بعد دقائق.", + "DialogUpdaterConvertFailedGithubMessage": "فشل تحويل إصدار ريوجينكس المستلم من إصدار غيت هاب.", + "DialogUpdaterDownloadingMessage": "جاري تنزيل التحديث...", + "DialogUpdaterExtractionMessage": "جاري استخراج التحديث...", + "DialogUpdaterRenamingMessage": "إعادة تسمية التحديث...", + "DialogUpdaterAddingFilesMessage": "إضافة تحديث جديد...", + "DialogUpdaterCompleteMessage": "اكتمل التحديث", + "DialogUpdaterRestartMessage": "هل تريد إعادة تشغيل ريوجينكس الآن؟", + "DialogUpdaterNoInternetMessage": "أنت غير متصل بالإنترنت.", + "DialogUpdaterNoInternetSubMessage": "يرجى التحقق من أن لديك اتصال إنترنت فعال!", + "DialogUpdaterDirtyBuildMessage": "لا يمكنك تحديث نسخة القذرة من ريوجينكس!", + "DialogUpdaterDirtyBuildSubMessage": "الرجاء تحميل ريوجينكس من https://ryujinx.org إذا كنت تبحث عن إصدار مدعوم.", + "DialogRestartRequiredMessage": "يتطلب إعادة التشغيل", + "DialogThemeRestartMessage": "تم حفظ السمة. إعادة التشغيل مطلوبة لتطبيق السمة.", + "DialogThemeRestartSubMessage": "هل تريد إعادة التشغيل", + "DialogFirmwareInstallEmbeddedMessage": "هل ترغب في تثبيت البرنامج الثابت المدمج في هذه اللعبة؟ (البرنامج الثابت {0})", + "DialogFirmwareInstallEmbeddedSuccessMessage": "لم يتم العثور على أي برنامج ثابت مثبت ولكن ريوجينكس كان قادرا على تثبيت البرنامج الثابت {0} من اللعبة المقدمة.\nسيبدأ المحاكي الآن.", + "DialogFirmwareNoFirmwareInstalledMessage": "لا يوجد برنامج ثابت مثبت", + "DialogFirmwareInstalledMessage": "تم تثبيت البرنامج الثابت {0}", + "DialogInstallFileTypesSuccessMessage": "تم تثبيت أنواع الملفات بنجاح!", + "DialogInstallFileTypesErrorMessage": "فشل تثبيت أنواع الملفات.", + "DialogUninstallFileTypesSuccessMessage": "تم إلغاء تثبيت أنواع الملفات بنجاح!", + "DialogUninstallFileTypesErrorMessage": "فشل إلغاء تثبيت أنواع الملفات.", + "DialogOpenSettingsWindowLabel": "فتح نافذة الإعدادات", + "DialogControllerAppletTitle": "تطبيق وحدة التحكم المصغر", + "DialogMessageDialogErrorExceptionMessage": "خطأ في عرض مربع حوار الرسالة: {0}", + "DialogSoftwareKeyboardErrorExceptionMessage": "خطأ في عرض لوحة مفاتيح البرامج: {0}", + "DialogErrorAppletErrorExceptionMessage": "خطأ في عرض مربع حوار خطأ التطبيق المصغر: {0}", + "DialogUserErrorDialogMessage": "{0}: {1}", + "DialogUserErrorDialogInfoMessage": "لمزيد من المعلومات حول كيفية إصلاح هذا الخطأ، اتبع دليل الإعداد الخاص بنا.", + "DialogUserErrorDialogTitle": "خطأ ريوجينكس ({0})", + "DialogAmiiboApiTitle": "أميبو API", + "DialogAmiiboApiFailFetchMessage": "حدث خطأ أثناء جلب المعلومات من API.", + "DialogAmiiboApiConnectErrorMessage": "غير قادر على الاتصال بخادم API أميبو. قد تكون الخدمة معطلة أو قد تحتاج إلى التحقق من اتصالك بالإنترنت.", + "DialogProfileInvalidProfileErrorMessage": "الملف الشخصي {0} غير متوافق مع نظام تكوين الإدخال الحالي.", + "DialogProfileDefaultProfileOverwriteErrorMessage": "لا يمكن الكتابة فوق الملف الشخصي الافتراضي", + "DialogProfileDeleteProfileTitle": "حذف الملف الشخصي", + "DialogProfileDeleteProfileMessage": "هذا الإجراء لا رجعة فيه، هل أنت متأكد من أنك تريد المتابعة؟", + "DialogWarning": "تحذير", + "DialogPPTCDeletionMessage": "أنت على وشك الإنتظار لإعادة بناء ذاكرة التخزين المؤقت للترجمة المستمرة (PPTC) عند الإقلاع التالي لـ:\n\n{0}\n\nأمتأكد من رغبتك في المتابعة؟", + "DialogPPTCDeletionErrorMessage": "خطأ خلال تنظيف ذاكرة التخزين المؤقت للترجمة المستمرة (PPTC) في {0}: {1}", + "DialogShaderDeletionMessage": "أنت على وشك حذف ذاكرة المظللات المؤقتة ل:\n\n{0}\n\nهل انت متأكد انك تريد المتابعة؟", + "DialogShaderDeletionErrorMessage": "حدث خطأ أثناء تنظيف ذاكرة المظللات المؤقتة في {0}: {1}", + "DialogRyujinxErrorMessage": "واجه ريوجينكس خطأ", + "DialogInvalidTitleIdErrorMessage": "خطأ في واجهة المستخدم: اللعبة المحددة لم يكن لديها معرف عنوان صالح", + "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "لم يتم العثور على برنامج ثابت للنظام صالح في {0}.", + "DialogFirmwareInstallerFirmwareInstallTitle": "تثبيت البرنامج الثابت {0}", + "DialogFirmwareInstallerFirmwareInstallMessage": "سيتم تثبيت إصدار النظام {0}.", + "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nهذا سيحل محل إصدار النظام الحالي {0}.", + "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\nهل تريد المتابعة؟", + "DialogFirmwareInstallerFirmwareInstallWaitMessage": "تثبيت البرنامج الثابت...", + "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "تم تثبيت إصدار النظام {0} بنجاح.", + "DialogUserProfileDeletionWarningMessage": "لن تكون هناك ملفات الشخصية أخرى لفتحها إذا تم حذف الملف الشخصي المحدد", + "DialogUserProfileDeletionConfirmMessage": "هل تريد حذف الملف الشخصي المحدد", + "DialogUserProfileUnsavedChangesTitle": "تحذير - التغييرات غير محفوظة", + "DialogUserProfileUnsavedChangesMessage": "لقد قمت بإجراء تغييرات على الملف الشخصي لهذا المستخدم هذا ولم يتم حفظها.", + "DialogUserProfileUnsavedChangesSubMessage": "هل تريد تجاهل التغييرات؟", + "DialogControllerSettingsModifiedConfirmMessage": "تم تحديث إعدادات وحدة التحكم الحالية.", + "DialogControllerSettingsModifiedConfirmSubMessage": "هل تريد الحفظ ؟", + "DialogLoadFileErrorMessage": "{0}. ملف خاطئ: {1}", + "DialogModAlreadyExistsMessage": "التعديل موجود بالفعل", + "DialogModInvalidMessage": "المجلد المحدد لا يحتوي على تعديل!", + "DialogModDeleteNoParentMessage": "فشل الحذف: لم يمكن العثور على المجلد الرئيسي للتعديل\"{0}\"!", + "DialogDlcNoDlcErrorMessage": "الملف المحدد لا يحتوي على محتوى إضافي للعنوان المحدد!", + "DialogPerformanceCheckLoggingEnabledMessage": "لقد تم تمكين تسجيل التتبع، والذي تم تصميمه ليتم استخدامه من قبل المطورين فقط.", + "DialogPerformanceCheckLoggingEnabledConfirmMessage": "للحصول على الأداء الأمثل، يوصى بتعطيل تسجيل التتبع. هل ترغب في تعطيل تسجيل التتبع الآن؟", + "DialogPerformanceCheckShaderDumpEnabledMessage": "لقد قمت بتمكين تفريغ المظللات، والذي تم تصميمه ليستخدمه المطورون فقط.", + "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "للحصول على الأداء الأمثل، يوصى بتعطيل تفريغ المظللات. هل ترغب في تعطيل تفريغ المظللات الآن؟", + "DialogLoadAppGameAlreadyLoadedMessage": "تم تحميل لعبة بالفعل", + "DialogLoadAppGameAlreadyLoadedSubMessage": "الرجاء إيقاف المحاكاة أو إغلاق المحاكي قبل بدء لعبة أخرى.", + "DialogUpdateAddUpdateErrorMessage": "الملف المحدد لا يحتوي على تحديث للعنوان المحدد!", + "DialogSettingsBackendThreadingWarningTitle": "تحذير - خلفية متعددة المسارات", + "DialogSettingsBackendThreadingWarningMessage": "يجب إعادة تشغيل ريوجينكس بعد تغيير هذا الخيار حتى يتم تطبيقه بالكامل. اعتمادا على النظام الأساسي الخاص بك، قد تحتاج إلى تعطيل تعدد المسارات الخاص ببرنامج الرسومات التشغيل الخاص بك يدويًا عند استخدام الخاص بريوجينكس.", + "DialogModManagerDeletionWarningMessage": "أنت على وشك حذف التعديل: {0}\n\nهل انت متأكد انك تريد المتابعة؟", + "DialogModManagerDeletionAllWarningMessage": "أنت على وشك حذف كافة التعديلات لهذا العنوان.\n\nهل انت متأكد انك تريد المتابعة؟", + "SettingsTabGraphicsFeaturesOptions": "المميزات", + "SettingsTabGraphicsBackendMultithreading": "تعدد المسارات لخلفية الرسومات:", + "CommonAuto": "تلقائي", + "CommonOff": "معطل", + "CommonOn": "تشغيل", + "InputDialogYes": "نعم", + "InputDialogNo": "لا", + "DialogProfileInvalidProfileNameErrorMessage": "يحتوي اسم الملف على أحرف غير صالحة. يرجى المحاولة مرة أخرى.", + "MenuBarOptionsPauseEmulation": "إيقاف مؤقت", + "MenuBarOptionsResumeEmulation": "استئناف", + "AboutUrlTooltipMessage": "انقر لفتح موقع ريوجينكس في متصفحك الافتراضي.", + "AboutDisclaimerMessage": "ريوجينكس لا ينتمي إلى نينتندو™،\nأو أي من شركائها بأي شكل من الأشكال.", + "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) يتم \nاستخدامه في محاكاة أمبيو لدينا.", + "AboutPatreonUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في باتريون في متصفحك الافتراضي.", + "AboutGithubUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في غيت هاب في متصفحك الافتراضي.", + "AboutDiscordUrlTooltipMessage": "انقر لفتح دعوة إلى خادم ريوجينكس في ديكسورد في متصفحك الافتراضي.", + "AboutTwitterUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في تويتر في متصفحك الافتراضي.", + "AboutRyujinxAboutTitle": "حول:", + "AboutRyujinxAboutContent": "ريوجينكس هو محاكي لجهاز نينتندو سويتش™.\nمن فضلك ادعمنا على باتريون.\nاحصل على آخر الأخبار على تويتر أو ديسكورد.\nيمكن للمطورين المهتمين بالمساهمة معرفة المزيد على غيت هاب أو ديسكورد.", + "AboutRyujinxMaintainersTitle": "تتم صيانته بواسطة:", + "AboutRyujinxMaintainersContentTooltipMessage": "انقر لفتح صفحة المساهمين في متصفحك الافتراضي.", + "AboutRyujinxSupprtersTitle": "مدعوم على باتريون بواسطة:", + "AmiiboSeriesLabel": "مجموعة أميبو", + "AmiiboCharacterLabel": "شخصية", + "AmiiboScanButtonLabel": "فحصه", + "AmiiboOptionsShowAllLabel": "إظهار كل أميبو", + "AmiiboOptionsUsRandomTagLabel": "هاك: استخدم علامة Uuid عشوائية ", + "DlcManagerTableHeadingEnabledLabel": "مفعل", + "DlcManagerTableHeadingTitleIdLabel": "معرف العنوان", + "DlcManagerTableHeadingContainerPathLabel": "مسار الحاوية", + "DlcManagerTableHeadingFullPathLabel": "المسار كاملا", + "DlcManagerRemoveAllButton": "حذف الكل", + "DlcManagerEnableAllButton": "تشغيل الكل", + "DlcManagerDisableAllButton": "تعطيل الكل", + "ModManagerDeleteAllButton": "حذف الكل", + "MenuBarOptionsChangeLanguage": "تغيير اللغة", + "MenuBarShowFileTypes": "إظهار أنواع الملفات", + "CommonSort": "فرز", + "CommonShowNames": "عرض الأسماء", + "CommonFavorite": "المفضلة", + "OrderAscending": "تصاعدي", + "OrderDescending": "تنازلي", + "SettingsTabGraphicsFeatures": "الميزات والتحسينات", + "ErrorWindowTitle": "نافذة الخطأ", + "ToggleDiscordTooltip": "اختر ما إذا كنت تريد عرض ريوجينكس في نشاط ديسكورد \"يتم تشغيله حاليا\" أم لا", + "AddGameDirBoxTooltip": "أدخل مجلد اللعبة لإضافته إلى القائمة", + "AddGameDirTooltip": "إضافة مجلد اللعبة إلى القائمة", + "RemoveGameDirTooltip": "إزالة مجلد اللعبة المحدد", + "CustomThemeCheckTooltip": "استخدم سمة أفالونيا المخصصة لواجهة المستخدم الرسومية لتغيير مظهر قوائم المحاكي", + "CustomThemePathTooltip": "مسار سمة واجهة المستخدم المخصصة", + "CustomThemeBrowseTooltip": "تصفح للحصول على سمة واجهة المستخدم المخصصة", + "DockModeToggleTooltip": "يجعل وضع تركيب بالمنصة النظام الذي تمت محاكاته بمثابة جهاز نينتندو سويتش الذي تم تركيبه بالمنصة. يؤدي هذا إلى تحسين الدقة الرسومية في معظم الألعاب. على العكس من ذلك، سيؤدي تعطيل هذا إلى جعل النظام الذي تمت محاكاته يعمل كجهاز نينتندو سويتش محمول، مما يقلل من جودة الرسومات.\n\nقم بتكوين عناصر تحكم اللاعب 1 إذا كنت تخطط لاستخدام وضع تركيب بالمنصة؛ قم بتكوين عناصر التحكم المحمولة إذا كنت تخطط لاستخدام الوضع المحمول.\n\nاتركه مشغل إذا لم تكن متأكدا.", + "DirectKeyboardTooltip": "دعم الوصول المباشر للوحة المفاتيح (HID). يوفر وصول الألعاب إلى لوحة المفاتيح الخاصة بك كجهاز لإدخال النص.\n\nيعمل فقط مع الألعاب التي تدعم استخدام لوحة المفاتيح في الأصل على أجهزة سويتش.\n\nاتركه معطلا إذا كنت غير متأكد.", + "DirectMouseTooltip": "دعم الوصول المباشر للوحة المفاتيح (HID). يوفر وصول الألعاب إلى لوحة المفاتيح الخاصة بك كجهاز لإدخال النص.\n\nيعمل فقط مع الألعاب التي تدعم استخدام لوحة المفاتيح في الأصل على أجهزة سويتش.\n\nاتركه معطلا إذا كنت غير متأكد.", + "RegionTooltip": "تغيير منطقة النظام", + "LanguageTooltip": "تغيير لغة النظام", + "TimezoneTooltip": "تغيير النطاق الزمني للنظام", + "TimeTooltip": "تغيير وقت النظام", + "VSyncToggleTooltip": "محاكاة المزامنة العمودية للجهاز. في الأساس محدد الإطار لغالبية الألعاب؛ قد يؤدي تعطيله إلى تشغيل الألعاب بسرعة أعلى أو جعل شاشات التحميل تستغرق وقتا أطول أو تتعطل.\n\nيمكن تبديله داخل اللعبة باستخدام مفتاح التشغيل السريع الذي تفضله (F1 افتراضيا). نوصي بالقيام بذلك إذا كنت تخطط لتعطيله.\n\nاتركه ممكنا إذا لم تكن متأكدا.", + "PptcToggleTooltip": "يحفظ وظائف JIT المترجمة بحيث لا تحتاج إلى ترجمتها في كل مرة يتم فيها تحميل اللعبة.\n\nيقلل من التقطيع ويسرع بشكل ملحوظ أوقات التشغيل بعد التشغيل الأول للعبة.\n\nاتركه ممكنا إذا لم تكن متأكدا.", + "FsIntegrityToggleTooltip": "يتحقق من وجود ملفات تالفة عند تشغيل لعبة ما، وإذا تم اكتشاف ملفات تالفة، فسيتم عرض خطأ تجزئة في السجل.\n\nليس له أي تأثير على الأداء ويهدف إلى المساعدة في استكشاف الأخطاء وإصلاحها.\n\nاتركه مفعلا إذا كنت غير متأكد.", + "AudioBackendTooltip": "يغير الواجهة الخلفية المستخدمة لتقديم الصوت.\n\nSDL2 هو الخيار المفضل، بينما يتم استخدام OpenAL وSoundIO كبديلين. زائف لن يكون لها صوت.\n\nاضبط على SDL2 إذا لم تكن متأكدا.", + "MemoryManagerTooltip": "تغيير كيفية تعيين ذاكرة الضيف والوصول إليها. يؤثر بشكل كبير على أداء وحدة المعالجة المركزية التي تمت محاكاتها.\n\nاضبط على المضيف غير محدد إذا لم تكن متأكدا.", + "MemoryManagerSoftwareTooltip": "استخدام جدول الصفحات البرمجي لترجمة العناوين. أعلى دقة ولكن أبطأ أداء.", + "MemoryManagerHostTooltip": "تعيين الذاكرة مباشرة في مساحة عنوان المضيف. تجميع وتنفيذ JIT أسرع بكثير.", + "MemoryManagerUnsafeTooltip": "تعيين الذاكرة مباشرة، ولكن لا تخفي العنوان داخل مساحة عنوان الضيف قبل الوصول. أسرع، ولكن على حساب السلامة. يمكن لتطبيق الضيف الوصول إلى الذاكرة من أي مكان في ريوجينكس، لذا قم بتشغيل البرامج التي تثق بها فقط مع هذا الوضع.", + "UseHypervisorTooltip": "استخدم هايبرڤايزور بدلا من JIT. يعمل على تحسين الأداء بشكل كبير عند توفره، ولكنه قد يكون غير مستقر في حالته الحالية.", + "DRamTooltip": "يستخدم تخطيط وضع الذاكرة البديل لتقليد نموذج سويتش المطورين.\n\nيعد هذا مفيدا فقط لحزم النسيج عالية الدقة أو تعديلات دقة 4K. لا يحسن الأداء.\n\nاتركه معطلا إذا لم تكن متأكدا.", + "IgnoreMissingServicesTooltip": "يتجاهل خدمات نظام هوريزون غير المنفذة. قد يساعد هذا في تجاوز الأعطال عند تشغيل ألعاب معينة.\n\nاتركه معطلا إذا كنت غير متأكد.", + "GraphicsBackendThreadingTooltip": "ينفذ أوامر الواجهة الخلفية للرسومات على مسار ثاني.\n\nيعمل على تسريع عملية تجميع المظللات وتقليل التقطيع وتحسين الأداء على برامج تشغيل وحدة الرسوميات دون دعم المسارات المتعددة الخاصة بهم. أداء أفضل قليلا على برامج التشغيل ذات المسارات المتعددة.\n\nاضبط على تلقائي إذا لم تكن متأكدا.", + "GalThreadingTooltip": "ينفذ أوامر الواجهة الخلفية للرسومات على مسار ثاني.\n\nيعمل على تسريع عملية تجميع المظللات وتقليل التقطيع وتحسين الأداء على برامج تشغيل وحدة الرسوميات دون دعم المسارات المتعددة الخاصة بهم. أداء أفضل قليلا على برامج التشغيل ذات المسارات المتعددة.\n\nاضبط على تلقائي إذا لم تكن متأكدا.", + "ShaderCacheToggleTooltip": "يحفظ ذاكرة المظللات المؤقتة على القرص مما يقلل من التقطيع في عمليات التشغيل اللاحقة.\n\nاتركه مفعلا إذا لم تكن متأكدا.", + "ResolutionScaleTooltip": "يضاعف دقة عرض اللعبة.\n\nقد لا تعمل بعض الألعاب مع هذا وتبدو منقطة حتى عند زيادة الدقة؛ بالنسبة لهذه الألعاب، قد تحتاج إلى العثور على تعديلات تزيل تنعيم الحواف أو تزيد من دقة العرض الداخلي. لاستخدام الأخير، من المحتمل أن ترغب في تحديد أصلي.\n\nيمكن تغيير هذا الخيار أثناء تشغيل اللعبة بالنقر فوق \"تطبيق\" أدناه؛ يمكنك ببساطة تحريك نافذة الإعدادات جانبًا والتجربة حتى تجد المظهر المفضل للعبة.\n\nضع في اعتبارك أن 4x مبالغة في أي إعداد تقريبًا.", + "ResolutionScaleEntryTooltip": "مقياس دقة النقطة العائمة، مثل 1.5. من المرجح أن تتسبب المقاييس غير المتكاملة في حدوث مشكلات أو تعطل.", + "AnisotropyTooltip": "مستوى تصفية. اضبط على تلقائي لاستخدام القيمة التي تطلبها اللعبة.", + "AspectRatioTooltip": "يتم تطبيق نسبة العرض إلى الارتفاع على نافذة العارض.\n\nقم بتغيير هذا فقط إذا كنت تستخدم تعديل نسبة العرض إلى الارتفاع للعبتك، وإلا سيتم تمديد الرسومات.\n\nاتركه16:9 إذا لم تكن متأكدا.", + "ShaderDumpPathTooltip": "مسار تفريغ المظللات", + "FileLogTooltip": "حفظ تسجيل وحدة التحكم إلى ملف سجل على القرص. لا يؤثر على الأداء.", + "StubLogTooltip": "طباعة رسائل سجل stub في وحدة التحكم. لا يؤثر على الأداء.", + "InfoLogTooltip": "طباعة رسائل سجل المعلومات في وحدة التحكم. لا يؤثر على الأداء.", + "WarnLogTooltip": "طباعة رسائل سجل التحذير في وحدة التحكم. لا يؤثر على الأداء.", + "ErrorLogTooltip": "طباعة رسائل سجل الأخطاء في وحدة التحكم. لا يؤثر على الأداء.", + "TraceLogTooltip": "طباعة رسائل سجل التتبع في وحدة التحكم. لا يؤثر على الأداء.", + "GuestLogTooltip": "طباعة رسائل سجل الضيف في وحدة التحكم. لا يؤثر على الأداء.", + "FileAccessLogTooltip": "طباعة رسائل سجل الوصول إلى الملفات في وحدة التحكم.", + "FSAccessLogModeTooltip": "تمكين إخراج سجل الوصول إلى نظام الملفات إلى وحدة التحكم. الأوضاع الممكنة هي 0-3", + "DeveloperOptionTooltip": "استخدمه بعناية", + "OpenGlLogLevel": "يتطلب تمكين مستويات السجل المناسبة", + "DebugLogTooltip": "طباعة رسائل سجل التصحيح في وحدة التحكم.\n\nاستخدم هذا فقط إذا طلب منك أحد الموظفين تحديدًا ذلك، لأنه سيجعل من الصعب قراءة السجلات وسيؤدي إلى تدهور أداء المحاكي.", + "LoadApplicationFileTooltip": "افتح مستكشف الملفات لاختيار ملف متوافق مع سويتش لتحميله", + "LoadApplicationFolderTooltip": "افتح مستكشف الملفات لاختيار تطبيق متوافق مع سويتش للتحميل", + "OpenRyujinxFolderTooltip": "فتح مجلد نظام ملفات ريوجينكس", + "OpenRyujinxLogsTooltip": "يفتح المجلد الذي تتم كتابة السجلات إليه", + "ExitTooltip": "الخروج من ريوجينكس", + "OpenSettingsTooltip": "فتح نافذة الإعدادات", + "OpenProfileManagerTooltip": "فتح نافذة إدارة الملفات الشخصية للمستخدمين", + "StopEmulationTooltip": "إيقاف محاكاة اللعبة الحالية والعودة إلى اختيار اللعبة", + "CheckUpdatesTooltip": "التحقق من وجود تحديثات لريوجينكس", + "OpenAboutTooltip": "فتح حول النافذة", + "GridSize": "حجم الشبكة", + "GridSizeTooltip": "تغيير حجم عناصر الشبكة", + "SettingsTabSystemSystemLanguageBrazilianPortuguese": "البرتغالية البرازيلية", + "AboutRyujinxContributorsButtonHeader": "رؤية جميع المساهمين", + "SettingsTabSystemAudioVolume": "مستوى الصوت:", + "AudioVolumeTooltip": "تغيير مستوى الصوت", + "SettingsTabSystemEnableInternetAccess": "الوصول إلى إنترنت كضيف/وضع LAN", + "EnableInternetAccessTooltip": "للسماح للتطبيق الذي تمت محاكاته بالاتصال بالإنترنت.\n\nيمكن للألعاب التي تحتوي على وضع LAN الاتصال ببعضها البعض عند تمكين ذلك وتوصيل الأنظمة بنفس نقطة الوصول. وهذا يشمل الأجهزة الحقيقية أيضا.\n\nلا يسمح بالاتصال بخوادم نينتندو. قد يتسبب في حدوث عطل في بعض الألعاب التي تحاول الاتصال بالإنترنت.\n\nاتركه معطلا إذا لم تكن متأكدا.", + "GameListContextMenuManageCheatToolTip": "إدارة الغش", + "GameListContextMenuManageCheat": "إدارة الغش", + "GameListContextMenuManageModToolTip": "إدارة التعديلات", + "GameListContextMenuManageMod": "إدارة التعديلات", + "ControllerSettingsStickRange": "نطاق:", + "DialogStopEmulationTitle": "ريوجينكس - إيقاف المحاكاة", + "DialogStopEmulationMessage": "هل أنت متأكد أنك تريد إيقاف المحاكاة؟", + "SettingsTabCpu": "المعالج", + "SettingsTabAudio": "الصوت", + "SettingsTabNetwork": "الشبكة", + "SettingsTabNetworkConnection": "اتصال الشبكة", + "SettingsTabCpuCache": "ذاكرة المعالج المؤقت", + "SettingsTabCpuMemory": "وضع المعالج", + "DialogUpdaterFlatpakNotSupportedMessage": "الرجاء تحديث ريوجينكس عبر فلات هاب.", + "UpdaterDisabledWarningTitle": "المحدث معطل!", + "ControllerSettingsRotate90": "تدوير 90 درجة في اتجاه عقارب الساعة", + "IconSize": "حجم الأيقونة", + "IconSizeTooltip": "تغيير حجم أيقونات اللعبة", + "MenuBarOptionsShowConsole": "عرض وحدة التحكم", + "ShaderCachePurgeError": "حدث خطأ أثناء تنظيف ذاكرة المظللات المؤقتة في {0}: {1}", + "UserErrorNoKeys": "المفاتيح غير موجودة", + "UserErrorNoFirmware": "لم يتم العثور على البرنامج الثابت", + "UserErrorFirmwareParsingFailed": "خطأ في تحليل البرنامج الثابت", + "UserErrorApplicationNotFound": "التطبيق غير موجود", + "UserErrorUnknown": "خطأ غير معروف", + "UserErrorUndefined": "خطأ غير محدد", + "UserErrorNoKeysDescription": "لم يتمكن ريوجينكس من العثور على ملف 'prod.keys' الخاص بك", + "UserErrorNoFirmwareDescription": "لم يتمكن ريوجينكس من العثور على أية برامج ثابتة مثبتة", + "UserErrorFirmwareParsingFailedDescription": "لم يتمكن ريوجينكس من تحليل البرامج الثابتة المتوفرة. يحدث هذا عادة بسبب المفاتيح القديمة.", + "UserErrorApplicationNotFoundDescription": "تعذر على ريوجينكس العثور على تطبيق صالح في المسار المحدد.", + "UserErrorUnknownDescription": "حدث خطأ غير معروف!", + "UserErrorUndefinedDescription": "حدث خطأ غير محدد! لا ينبغي أن يحدث هذا، يرجى الاتصال بمطور!", + "OpenSetupGuideMessage": "فتح دليل الإعداد", + "NoUpdate": "لا يوجد تحديث", + "TitleUpdateVersionLabel": "الإصدار: {0}", + "RyujinxInfo": "ريوجينكس - معلومات", + "RyujinxConfirm": "ريوجينكس - تأكيد", + "FileDialogAllTypes": "كل الأنواع", + "Never": "مطلقا", + "SwkbdMinCharacters": "يجب أن يبلغ طوله {0} حرفا على الأقل", + "SwkbdMinRangeCharacters": "يجب أن يتكون من {0}-{1} حرفا", + "SoftwareKeyboard": "لوحة المفاتيح البرمجية", + "SoftwareKeyboardModeNumeric": "يجب أن يكون 0-9 أو '.' فقط", + "SoftwareKeyboardModeAlphabet": "يجب أن تكون الأحرف غير CJK فقط", + "SoftwareKeyboardModeASCII": "يجب أن يكون نص ASCII فقط", + "ControllerAppletControllers": "وحدات التحكم المدعومة:", + "ControllerAppletPlayers": "اللاعبين:", + "ControllerAppletDescription": "الإعدادات الحالية غير صالحة. افتح الإعدادات وأعد تكوين المدخلات الخاصة بك.", + "ControllerAppletDocked": "تم ضبط وضع تركيب بالمنصة. يجب تعطيل التحكم المحمول.", + "UpdaterRenaming": "إعادة تسمية الملفات القديمة...", + "UpdaterRenameFailed": "المحدث غير قادر على إعادة تسمية الملف: {0}", + "UpdaterAddingFiles": "إضافة ملفات جديدة...", + "UpdaterExtracting": "استخراج التحديث...", + "UpdaterDownloading": "تحميل التحديث...", + "Game": "لعبة", + "Docked": "تركيب بالمنصة", + "Handheld": "محمول", + "ConnectionError": "خطأ في الاتصال", + "AboutPageDeveloperListMore": "{0} والمزيد...", + "ApiError": "خطأ في API.", + "LoadingHeading": "جاري تحميل {0}", + "CompilingPPTC": "تجميع الـ‫(PPTC)", + "CompilingShaders": "تجميع المظللات", + "AllKeyboards": "كل لوحات المفاتيح", + "OpenFileDialogTitle": "حدد ملف مدعوم لفتحه", + "OpenFolderDialogTitle": "حدد مجلدا يحتوي على لعبة غير مضغوطة", + "AllSupportedFormats": "كل التنسيقات المدعومة", + "RyujinxUpdater": "محدث ريوجينكس", + "SettingsTabHotkeys": "مفاتيح الاختصار في لوحة المفاتيح", + "SettingsTabHotkeysHotkeys": "مفاتيح الاختصار في لوحة المفاتيح", + "SettingsTabHotkeysToggleVsyncHotkey": "تبديل المزامنة العمودية:", + "SettingsTabHotkeysScreenshotHotkey": "لقطة الشاشة:", + "SettingsTabHotkeysShowUiHotkey": "عرض واجهة المستخدم:", + "SettingsTabHotkeysPauseHotkey": "إيقاف مؤقت:", + "SettingsTabHotkeysToggleMuteHotkey": "كتم:", + "ControllerMotionTitle": "إعدادات التحكم بالحركة", + "ControllerRumbleTitle": "إعدادات الهزاز", + "SettingsSelectThemeFileDialogTitle": "حدد ملف السمة", + "SettingsXamlThemeFile": "ملف سمة Xaml", + "AvatarWindowTitle": "إدارة الحسابات - الصورة الرمزية", + "Amiibo": "أميبو", + "Unknown": "غير معروف", + "Usage": "الاستخدام", + "Writable": "قابل للكتابة", + "SelectDlcDialogTitle": "حدد ملفات المحتوي الإضافي", + "SelectUpdateDialogTitle": "حدد ملفات التحديث", + "SelectModDialogTitle": "حدد مجلد التعديل", + "UserProfileWindowTitle": "مدير الملفات الشخصية للمستخدمين", + "CheatWindowTitle": "مدير الغش", + "DlcWindowTitle": "إدارة المحتوى القابل للتنزيل لـ {0} ({1})", + "ModWindowTitle": "إدارة التعديلات لـ {0} ({1})", + "UpdateWindowTitle": "مدير تحديث العنوان", + "CheatWindowHeading": "الغش متوفر لـ {0} [{1}]", + "BuildId": "معرف البناء:", + "DlcWindowHeading": "المحتويات القابلة للتنزيل {0}", + "ModWindowHeading": "{0} تعديل", + "UserProfilesEditProfile": "تعديل المحدد", + "Cancel": "إلغاء", + "Save": "حفظ", + "Discard": "تجاهل", + "Paused": "متوقف مؤقتا", + "UserProfilesSetProfileImage": "تعيين صورة الملف الشخصي", + "UserProfileEmptyNameError": "الاسم مطلوب", + "UserProfileNoImageError": "يجب تعيين صورة الملف الشخصي", + "GameUpdateWindowHeading": "إدارة التحديثات لـ {0} ({1})", + "SettingsTabHotkeysResScaleUpHotkey": "زيادة الدقة:", + "SettingsTabHotkeysResScaleDownHotkey": "خفض الدقة:", + "UserProfilesName": "الاسم:", + "UserProfilesUserId": "معرف المستخدم:", + "SettingsTabGraphicsBackend": "خلفية الرسومات", + "SettingsTabGraphicsBackendTooltip": "حدد الواجهة الخلفية للرسومات التي سيتم استخدامها في المحاكي.\n\nيعد برنامج فولكان أفضل بشكل عام لجميع بطاقات الرسومات الحديثة، طالما أن برامج التشغيل الخاصة بها محدثة. يتميز فولكان أيضا بتجميع مظللات أسرع (أقل تقطيعا) على جميع بائعي وحدات معالجة الرسومات.\n\nقد يحقق أوبن جي أل نتائج أفضل على وحدات معالجة الرسومات إنفيديا القديمة، أو على وحدات معالجة الرسومات إي إم دي القديمة على لينكس، أو على وحدات معالجة الرسومات ذات ذاكرة الوصول العشوائي للفيديوالأقل، على الرغم من أن تعثرات تجميع المظللات ستكون أكبر.\n\nاضبط على فولكان إذا لم تكن متأكدا. اضبط على أوبن جي أل إذا كانت وحدة معالجة الرسومات الخاصة بك لا تدعم فولكان حتى مع أحدث برامج تشغيل الرسومات.", + "SettingsEnableTextureRecompression": "تمكين إعادة ضغط التكستر", + "SettingsEnableTextureRecompressionTooltip": "يضغط تكستر ASTC من أجل تقليل استخدام ذاكرة الوصول العشوائي للفيديو.\n\nتتضمن الألعاب التي تستخدم تنسيق النسيج هذا Astral Chain وBayonetta 3 وFire Emblem Engage وMetroid Prime Remastered وSuper Mario Bros. Wonder وThe Legend of Zelda: Tears of the Kingdom.\n\nمن المحتمل أن تتعطل بطاقات الرسومات التي تحتوي على 4 جيجا بايت من ذاكرة الوصول العشوائي للفيديو أو أقل في مرحلة ما أثناء تشغيل هذه الألعاب.\n\nقم بالتمكين فقط في حالة نفاد ذاكرة الوصول العشوائي للفيديو في الألعاب المذكورة أعلاه. اتركه معطلا إذا لم تكن متأكدا.", + "SettingsTabGraphicsPreferredGpu": "وحدة معالجة الرسوميات المفضلة", + "SettingsTabGraphicsPreferredGpuTooltip": "حدد بطاقة الرسومات التي سيتم استخدامها مع الواجهة الخلفية لرسومات فولكان.\n\nلا يؤثر على وحدة معالجة الرسومات التي سيستخدمها أوبن جي أل.\n\nاضبط على وحدة معالجة الرسومات التي تم وضع علامة عليها كـ \"dGPU\" إذا لم تكن متأكدًا. إذا لم يكن هناك واحد، اتركه.", + "SettingsAppRequiredRestartMessage": "مطلوب إعادة تشغيل ريوجينكس", + "SettingsGpuBackendRestartMessage": "تم تعديل إعدادات الواجهة الخلفية للرسومات أو وحدة معالجة الرسومات. سيتطلب هذا إعادة التشغيل ليتم تطبيقه", + "SettingsGpuBackendRestartSubMessage": "\n\nهل تريد إعادة التشغيل الآن؟", + "RyujinxUpdaterMessage": "هل تريد تحديث ريوجينكس إلى أحدث إصدار؟", + "SettingsTabHotkeysVolumeUpHotkey": "زيادة مستوى الصوت:", + "SettingsTabHotkeysVolumeDownHotkey": "خفض مستوى الصوت:", + "SettingsEnableMacroHLE": "تمكين Maro HLE", + "SettingsEnableMacroHLETooltip": "محاكاة عالية المستوى لكود مايكرو وحدة معالجة الرسوميات.\n\nيعمل على تحسين الأداء، ولكنه قد يسبب خللا رسوميا في بعض الألعاب.\n\nاتركه مفعلا إذا لم تكن متأكدا.", + "SettingsEnableColorSpacePassthrough": "عبور مساحة اللون", + "SettingsEnableColorSpacePassthroughTooltip": "يوجه واجهة فولكان الخلفية لتمرير معلومات الألوان دون تحديد مساحة اللون. بالنسبة للمستخدمين الذين لديهم شاشات ذات نطاق واسع، قد يؤدي ذلك إلى الحصول على ألوان أكثر حيوية، على حساب صحة الألوان.", + "VolumeShort": "مستوى", + "UserProfilesManageSaves": "إدارة الحفظ", + "DeleteUserSave": "هل تريد حذف حفظ المستخدم لهذه اللعبة؟", + "IrreversibleActionNote": "هذا الإجراء لا يمكن التراجع عنه.", + "SaveManagerHeading": "إدارة الحفظ لـ {0} ({1})", + "SaveManagerTitle": "مدير الحفظ", + "Name": "الاسم", + "Size": "الحجم", + "Search": "بحث", + "UserProfilesRecoverLostAccounts": "استعادة الحسابات المفقودة", + "Recover": "استعادة", + "UserProfilesRecoverHeading": "تم العثور على حفظ للحسابات التالية", + "UserProfilesRecoverEmptyList": "لا توجد ملفات شخصية لاستردادها", + "GraphicsAATooltip": "يتم تطبيق تنعيم الحواف على عرض اللعبة.\n\nسوف يقوم FXAA بتعتيم معظم الصورة، بينما سيحاول SMAA العثور على حواف خشنة وتنعيمها.\n\nلا ينصح باستخدامه مع فلتر FSR لتكبير.\n\nيمكن تغيير هذا الخيار أثناء تشغيل اللعبة بالنقر فوق \"تطبيق\" أدناه؛ يمكنك ببساطة تحريك نافذة الإعدادات جانبا والتجربة حتى تجد المظهر المفضل للعبة.\n\nاتركه على لا شيء إذا لم تكن متأكدا.", + "GraphicsAALabel": "تنعيم الحواف:", + "GraphicsScalingFilterLabel": "فلتر التكبير:", + "GraphicsScalingFilterTooltip": "اختر فلتر التكبير الذي سيتم تطبيقه عند استخدام مقياس الدقة.\n\nيعمل Bilinear بشكل جيد مع الألعاب ثلاثية الأبعاد وهو خيار افتراضي آمن.\n\nيوصى باستخدام Nearest لألعاب البكسل الفنية.\n\nFSR 1.0 هو مجرد مرشح توضيحي، ولا ينصح باستخدامه مع FXAA أو SMAA.\n\nيمكن تغيير هذا الخيار أثناء تشغيل اللعبة بالنقر فوق \"تطبيق\" أدناه؛ يمكنك ببساطة تحريك نافذة الإعدادات جانبا والتجربة حتى تجد المظهر المفضل للعبة.\n\nاتركه على Bilinear إذا لم تكن متأكدا.", + "GraphicsScalingFilterBilinear": "Bilinear", + "GraphicsScalingFilterNearest": "Nearest", + "GraphicsScalingFilterFsr": "FSR", + "GraphicsScalingFilterLevelLabel": "المستوى", + "GraphicsScalingFilterLevelTooltip": "اضبط مستوى وضوح FSR 1.0. الأعلى هو أكثر وضوحا.", + "SmaaLow": "SMAA منخفض", + "SmaaMedium": "SMAA متوسط", + "SmaaHigh": "SMAA عالي", + "SmaaUltra": "SMAA فائق", + "UserEditorTitle": "تعديل المستخدم", + "UserEditorTitleCreate": "إنشاء مستخدم", + "SettingsTabNetworkInterface": "واجهة الشبكة:", + "NetworkInterfaceTooltip": "واجهة الشبكة مستخدمة لميزات LAN/LDN.\n\nبالاشتراك مع VPN أو XLink Kai ولعبة تدعم LAN، يمكن استخدامها لتزييف اتصال الشبكة نفسها عبر الإنترنت.\n\nاتركه على الافتراضي إذا لم تكن متأكدا.", + "NetworkInterfaceDefault": "افتراضي", + "PackagingShaders": "تعبئة المظللات", + "AboutChangelogButton": "عرض سجل التغييرات على غيت هاب", + "AboutChangelogButtonTooltipMessage": "انقر لفتح سجل التغيير لهذا الإصدار في متصفحك الافتراضي.", + "SettingsTabNetworkMultiplayer": "لعب جماعي", + "MultiplayerMode": "الوضع:", + "MultiplayerModeTooltip": "تغيير وضع LDN متعدد اللاعبين.\n\nسوف يقوم LdnMitm بتعديل وظيفة اللعب المحلية/اللاسلكية المحلية في الألعاب لتعمل كما لو كانت شبكة LAN، مما يسمح باتصالات الشبكة المحلية نفسها مع محاكيات ريوجينكس الأخرى وأجهزة نينتندو سويتش المخترقة التي تم تثبيت وحدة ldn_mitm عليها.\n\nيتطلب وضع اللاعبين المتعددين أن يكون جميع اللاعبين على نفس إصدار اللعبة (على سبيل المثال، يتعذر على الإصدار 13.0.1 من سوبر سماش برذرز ألتميت الاتصال بالإصدار 13.0.0).\n\nاتركه معطلا إذا لم تكن متأكدا.", + "MultiplayerModeDisabled": "معطل", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/de_DE.json b/src/Ryujinx/Assets/Locales/de_DE.json similarity index 79% rename from src/Ryujinx.Ava/Assets/Locales/de_DE.json rename to src/Ryujinx/Assets/Locales/de_DE.json index 7cdcdf5a2..401293198 100644 --- a/src/Ryujinx.Ava/Assets/Locales/de_DE.json +++ b/src/Ryujinx/Assets/Locales/de_DE.json @@ -9,12 +9,12 @@ "SettingsTabSystemMemoryManagerModeHostUnchecked": "Host ungeprüft (am schnellsten, unsicher)", "SettingsTabSystemUseHypervisor": "Hypervisor verwenden", "MenuBarFile": "_Datei", - "MenuBarFileOpenFromFile": "_Datei öffnen", + "MenuBarFileOpenFromFile": "Datei _öffnen", "MenuBarFileOpenUnpacked": "_Entpacktes Spiel öffnen", "MenuBarFileOpenEmuFolder": "Ryujinx-Ordner öffnen", "MenuBarFileOpenLogsFolder": "Logs-Ordner öffnen", "MenuBarFileExit": "_Beenden", - "MenuBarOptions": "Optionen", + "MenuBarOptions": "_Optionen", "MenuBarOptionsToggleFullscreen": "Vollbild", "MenuBarOptionsStartGamesInFullscreen": "Spiele im Vollbildmodus starten", "MenuBarOptionsStopEmulation": "Emulation beenden", @@ -23,14 +23,18 @@ "MenuBarActions": "_Aktionen", "MenuBarOptionsSimulateWakeUpMessage": "Aufwachnachricht simulieren", "MenuBarActionsScanAmiibo": "Amiibo scannen", - "MenuBarTools": "_Werkzeuge", + "MenuBarTools": "_Tools", "MenuBarToolsInstallFirmware": "Firmware installieren", "MenuBarFileToolsInstallFirmwareFromFile": "Firmware von einer XCI- oder einer ZIP-Datei installieren", "MenuBarFileToolsInstallFirmwareFromDirectory": "Firmware aus einem Verzeichnis installieren", "MenuBarToolsManageFileTypes": "Dateitypen verwalten", "MenuBarToolsInstallFileTypes": "Dateitypen installieren", "MenuBarToolsUninstallFileTypes": "Dateitypen deinstallieren", - "MenuBarHelp": "Hilfe", + "MenuBarView": "_Ansicht", + "MenuBarViewWindow": "Fenstergröße", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Hilfe", "MenuBarHelpCheckForUpdates": "Nach Updates suchen", "MenuBarHelpAbout": "Über Ryujinx", "MenuSearch": "Suchen...", @@ -54,9 +58,7 @@ "GameListContextMenuManageTitleUpdatesToolTip": "Öffnet den Spiel-Update-Manager", "GameListContextMenuManageDlc": "Verwalten von DLC", "GameListContextMenuManageDlcToolTip": "Öffnet den DLC-Manager", - "GameListContextMenuOpenModsDirectory": "Mod-Verzeichnis öffnen", - "GameListContextMenuOpenModsDirectoryToolTip": "Öffnet das Verzeichnis, welches Mods für die Spiele beinhaltet", - "GameListContextMenuCacheManagement": "Cache Verwaltung", + "GameListContextMenuCacheManagement": "Cache-Verwaltung", "GameListContextMenuCacheManagementPurgePptc": "PPTC als ungültig markieren", "GameListContextMenuCacheManagementPurgePptcToolTip": "Markiert den PPTC als ungültig, sodass dieser beim nächsten Spielstart neu erstellt wird", "GameListContextMenuCacheManagementPurgeShaderCache": "Shader Cache löschen", @@ -72,6 +74,13 @@ "GameListContextMenuExtractDataRomFSToolTip": "Extrahiert das RomFS aus der aktuellen Anwendungskonfiguration (einschließlich Updates)", "GameListContextMenuExtractDataLogo": "Logo", "GameListContextMenuExtractDataLogoToolTip": "Extrahiert das Logo aus der aktuellen Anwendungskonfiguration (einschließlich Updates)", + "GameListContextMenuCreateShortcut": "Erstelle Anwendungsverknüpfung", + "GameListContextMenuCreateShortcutToolTip": "Erstelle eine Desktop-Verknüpfung die die gewählte Anwendung startet", + "GameListContextMenuCreateShortcutToolTipMacOS": "Erstellen Sie eine Verknüpfung im MacOS-Programme-Ordner, die die ausgewählte Anwendung startet", + "GameListContextMenuOpenModsDirectory": "Mod-Verzeichnis öffnen", + "GameListContextMenuOpenModsDirectoryToolTip": "Öffnet das Verzeichnis, welches Mods für die Spiele beinhaltet", + "GameListContextMenuOpenSdModsDirectory": "Atmosphere-Mod-Verzeichnis öffnen", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Öffnet das alternative SD-Karten-Atmosphere-Verzeichnis, das die Mods der Anwendung enthält. Dieser Ordner ist nützlich für Mods, die für echte Hardware erstellt worden sind.", "StatusBarGamesLoaded": "{0}/{1} Spiele geladen", "StatusBarSystemVersion": "Systemversion: {0}", "LinuxVmMaxMapCountDialogTitle": "Niedriges Limit für Speicherzuordnungen erkannt", @@ -87,6 +96,7 @@ "SettingsTabGeneralEnableDiscordRichPresence": "Aktiviere die Statusanzeige für Discord", "SettingsTabGeneralCheckUpdatesOnLaunch": "Beim Start nach Updates suchen", "SettingsTabGeneralShowConfirmExitDialog": "Zeige den \"Beenden bestätigen\"-Dialog", + "SettingsTabGeneralRememberWindowState": "Fenstergröße/-position merken", "SettingsTabGeneralHideCursor": "Mauszeiger ausblenden", "SettingsTabGeneralHideCursorNever": "Niemals", "SettingsTabGeneralHideCursorOnIdle": "Mauszeiger bei Inaktivität ausblenden", @@ -150,7 +160,7 @@ "SettingsTabGraphicsResolutionScaleNative": "Nativ (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (Nicht empfohlen)", "SettingsTabGraphicsAspectRatio": "Bildseitenverhältnis:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -261,6 +271,107 @@ "ControllerSettingsMotionGyroDeadzone": "Gyro-Deadzone:", "ControllerSettingsSave": "Speichern", "ControllerSettingsClose": "Schließen", + "KeyUnknown": "Unbekannt", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", "UserProfilesSelectedUserProfile": "Ausgewähltes Profil:", "UserProfilesSaveProfileName": "Profilname speichern", "UserProfilesChangeProfileImage": "Profilbild ändern", @@ -292,13 +403,9 @@ "GameListContextMenuRunApplication": "Anwendung ausführen", "GameListContextMenuToggleFavorite": "Als Favoriten hinzufügen/entfernen", "GameListContextMenuToggleFavoriteToolTip": "Aktiviert den Favoriten-Status des Spiels", - "SettingsTabGeneralTheme": "Design", - "SettingsTabGeneralThemeCustomTheme": "Pfad für das benutzerdefinierte Design", - "SettingsTabGeneralThemeBaseStyle": "Farbschema", - "SettingsTabGeneralThemeBaseStyleDark": "Dunkel", - "SettingsTabGeneralThemeBaseStyleLight": "Hell", - "SettingsTabGeneralThemeEnableCustomTheme": "Design für die Emulator-Benutzeroberfläche", - "ButtonBrowse": "Durchsuchen", + "SettingsTabGeneralTheme": "Design:", + "SettingsTabGeneralThemeDark": "Dunkel", + "SettingsTabGeneralThemeLight": "Hell", "ControllerSettingsConfigureGeneral": "Konfigurieren", "ControllerSettingsRumble": "Vibration", "ControllerSettingsRumbleStrongMultiplier": "Starker Vibrations-Multiplikator", @@ -322,7 +429,7 @@ "DialogNcaExtractionCheckLogErrorMessage": "Extraktion fehlgeschlagen. Überprüfe die Logs für weitere Informationen.", "DialogNcaExtractionSuccessMessage": "Extraktion erfolgreich abgeschlossen.", "DialogUpdaterConvertFailedMessage": "Die Konvertierung der aktuellen Ryujinx-Version ist fehlgeschlagen.", - "DialogUpdaterCancelUpdateMessage": "Download wird abgebrochen!", + "DialogUpdaterCancelUpdateMessage": "Update wird abgebrochen!", "DialogUpdaterAlreadyOnLatestVersionMessage": "Es wird bereits die aktuellste Version von Ryujinx benutzt", "DialogUpdaterFailedToGetVersionMessage": "Beim Versuch, Veröffentlichungs-Info von GitHub Release zu erhalten, ist ein Fehler aufgetreten. Dies kann aufgrund einer neuen Veröffentlichung, die gerade von GitHub Actions kompiliert wird, verursacht werden.", "DialogUpdaterConvertFailedGithubMessage": "Fehler beim Konvertieren der erhaltenen Ryujinx-Version von GitHub Release.", @@ -332,8 +439,6 @@ "DialogUpdaterAddingFilesMessage": "Update wird hinzugefügt...", "DialogUpdaterCompleteMessage": "Update abgeschlossen!", "DialogUpdaterRestartMessage": "Ryujinx jetzt neu starten?", - "DialogUpdaterArchNotSupportedMessage": "Eine nicht unterstützte Systemarchitektur wird benutzt!", - "DialogUpdaterArchNotSupportedSubMessage": "Nur 64-Bit-Systeme werden unterstützt!", "DialogUpdaterNoInternetMessage": "Es besteht keine Verbindung mit dem Internet!", "DialogUpdaterNoInternetSubMessage": "Bitte vergewissern, dass eine funktionierende Internetverbindung existiert!", "DialogUpdaterDirtyBuildMessage": "Inoffizielle Versionen von Ryujinx können nicht aktualisiert werden", @@ -385,7 +490,10 @@ "DialogUserProfileUnsavedChangesSubMessage": "Möchten Sie Ihre Änderungen wirklich verwerfen?", "DialogControllerSettingsModifiedConfirmMessage": "Die aktuellen Controller-Einstellungen wurden aktualisiert.", "DialogControllerSettingsModifiedConfirmSubMessage": "Controller-Einstellungen speichern?", - "DialogLoadNcaErrorMessage": "{0}. Fehlerhafte Datei: {1}", + "DialogLoadFileErrorMessage": "{0}. Fehlerhafte Datei: {1}", + "DialogModAlreadyExistsMessage": "Mod ist bereits vorhanden", + "DialogModInvalidMessage": "Das angegebene Verzeichnis enthält keine Mods!", + "DialogModDeleteNoParentMessage": "Löschen fehlgeschlagen: Das übergeordnete Verzeichnis für den Mod \"{0}\" konnte nicht gefunden werden!", "DialogDlcNoDlcErrorMessage": "Die angegebene Datei enthält keinen DLC für den ausgewählten Titel!", "DialogPerformanceCheckLoggingEnabledMessage": "Es wurde die Debug Protokollierung aktiviert", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Um eine optimale Leistung zu erzielen, wird empfohlen, die Debug Protokollierung zu deaktivieren. Debug Protokollierung jetzt deaktivieren?", @@ -396,6 +504,8 @@ "DialogUpdateAddUpdateErrorMessage": "Die angegebene Datei enthält keine Updates für den ausgewählten Titel!", "DialogSettingsBackendThreadingWarningTitle": "Warnung - Render Threading", "DialogSettingsBackendThreadingWarningMessage": "Ryujinx muss muss neu gestartet werden, damit die Änderungen wirksam werden. Abhängig von dem Betriebssystem muss möglicherweise das Multithreading des Treibers manuell deaktiviert werden, wenn Ryujinx verwendet wird.", + "DialogModManagerDeletionWarningMessage": "Du bist dabei, diesen Mod zu lösche. {0}\n\nMöchtest du wirklich fortfahren?", + "DialogModManagerDeletionAllWarningMessage": "Du bist dabei, alle Mods für diesen Titel zu löschen.\n\nMöchtest du wirklich fortfahren?", "SettingsTabGraphicsFeaturesOptions": "Erweiterungen", "SettingsTabGraphicsBackendMultithreading": "Grafik-Backend Multithreading:", "CommonAuto": "Auto", @@ -418,7 +528,7 @@ "AboutRyujinxMaintainersTitle": "Entwickelt von:", "AboutRyujinxMaintainersContentTooltipMessage": "Klicke hier, um die Liste der Mitwirkenden im Standardbrowser zu öffnen.", "AboutRyujinxSupprtersTitle": "Unterstützt auf Patreon von:", - "AmiiboSeriesLabel": "Amiibo Serie", + "AmiiboSeriesLabel": "Amiibo-Serie", "AmiiboCharacterLabel": "Charakter", "AmiiboScanButtonLabel": "Einscannen", "AmiiboOptionsShowAllLabel": "Zeige alle Amiibos", @@ -430,6 +540,7 @@ "DlcManagerRemoveAllButton": "Entferne alle", "DlcManagerEnableAllButton": "Alle aktivieren", "DlcManagerDisableAllButton": "Alle deaktivieren", + "ModManagerDeleteAllButton": "Alle löschen", "MenuBarOptionsChangeLanguage": "Sprache ändern", "MenuBarShowFileTypes": "Dateitypen anzeigen", "CommonSort": "Sortieren", @@ -447,13 +558,13 @@ "CustomThemePathTooltip": "Gibt den Pfad zum Design für die Emulator-Benutzeroberfläche an", "CustomThemeBrowseTooltip": "Ermöglicht die Suche nach einem benutzerdefinierten Design für die Emulator-Benutzeroberfläche", "DockModeToggleTooltip": "Im gedockten Modus verhält sich das emulierte System wie eine Nintendo Switch im TV Modus. Dies verbessert die grafische Qualität der meisten Spiele. Umgekehrt führt die Deaktivierung dazu, dass sich das emulierte System wie eine Nintendo Switch im Handheld Modus verhält, was die Grafikqualität beeinträchtigt.\n\nKonfiguriere das Eingabegerät für Spieler 1, um im Docked Modus zu spielen; konfiguriere das Controllerprofil via der Handheld Option, wenn geplant wird den Handheld Modus zu nutzen.\n\nIm Zweifelsfall AN lassen.", - "DirectKeyboardTooltip": "Aktiviert/Deaktiviert den \"Direkter Tastaturzugriff (HID) Unterstützung\" (Ermöglicht die Benutzung der Tastaur als Eingabegerät in Spielen)", - "DirectMouseTooltip": "Aktiviert/Deaktiviert den \"Direkten Mauszugriff (HID) Unterstützung\" (Ermöglicht die Benutzung der Maus als Eingabegerät in Spielen)", + "DirectKeyboardTooltip": "Direkter Zugriff auf die Tastatur (HID). Bietet Spielen Zugriff auf Ihre Tastatur als Texteingabegerät.\n\nFunktioniert nur mit Spielen, die die Tastaturnutzung auf Switch-Hardware nativ unterstützen.\n\nAus lassen, wenn unsicher.", + "DirectMouseTooltip": "Unterstützt den direkten Mauszugriff (HID). Bietet Spielen Zugriff auf Ihre Maus als Zeigegerät.\n\nFunktioniert nur mit Spielen, die nativ die Steuerung mit der Maus auf Switch-Hardware unterstützen (nur sehr wenige).\n\nTouchscreen-Funktionalität ist möglicherweise eingeschränkt, wenn dies aktiviert ist.\n\n Aus lassen, wenn unsicher.", "RegionTooltip": "Ändert die Systemregion", "LanguageTooltip": "Ändert die Systemsprache", "TimezoneTooltip": "Ändert die Systemzeitzone", "TimeTooltip": "Ändert die Systemzeit", - "VSyncToggleTooltip": "Vertikale Synchronisierung der emulierten Konsole. Diese Option ist ein Frame-Limiter für die meisten Spiele; die Deaktivierung kann dazu führen, dass Spiele mit höherer Geschwindigkeit laufen, Ladebildschirme länger benötigen oder hängen bleiben.\n\nKann beim Spielen mit einem frei wählbaren Hotkey ein- und ausgeschaltet werden.\n\nIm Zweifelsfall AN lassen.", + "VSyncToggleTooltip": "Vertikale Synchronisierung der emulierten Konsole. Diese Option ist quasi ein Frame-Limiter für die meisten Spiele; die Deaktivierung kann dazu führen, dass Spiele mit höherer Geschwindigkeit laufen oder Ladebildschirme länger benötigen/hängen bleiben.\n\nKann beim Spielen mit einem frei wählbaren Hotkey ein- und ausgeschaltet werden (standardmäßig F1). \n\nIm Zweifelsfall AN lassen.", "PptcToggleTooltip": "Speichert übersetzte JIT-Funktionen, sodass jene nicht jedes Mal übersetzt werden müssen, wenn das Spiel geladen wird.\n\nVerringert Stottern und die Zeit beim zweiten und den darauffolgenden Startvorgängen eines Spiels erheblich.\n\nIm Zweifelsfall AN lassen.", "FsIntegrityToggleTooltip": "Prüft beim Startvorgang auf beschädigte Dateien und zeigt bei beschädigten Dateien einen Hash-Fehler (Hash Error) im Log an.\n\nDiese Einstellung hat keinen Einfluss auf die Leistung und hilft bei der Fehlersuche.\n\nIm Zweifelsfall AN lassen.", "AudioBackendTooltip": "Ändert das Backend, das zum Rendern von Audio verwendet wird.\n\nSDL2 ist das bevorzugte Audio-Backend, OpenAL und SoundIO sind als Alternativen vorhanden. Dummy wird keinen Audio-Output haben.\n\nIm Zweifelsfall SDL2 auswählen.", @@ -467,10 +578,10 @@ "GraphicsBackendThreadingTooltip": "Führt Grafik-Backend Befehle auf einem zweiten Thread aus.\n\nDies beschleunigt die Shader-Kompilierung, reduziert Stottern und verbessert die Leistung auf GPU-Treibern ohne eigene Multithreading-Unterstützung. Geringfügig bessere Leistung bei Treibern mit Multithreading.\n\nIm Zweifelsfall auf AUTO stellen.", "GalThreadingTooltip": "Führt Grafik-Backend Befehle auf einem zweiten Thread aus.\n\nDies Beschleunigt die Shader-Kompilierung, reduziert Stottern und verbessert die Leistung auf GPU-Treibern ohne eigene Multithreading-Unterstützung. Geringfügig bessere Leistung bei Treibern mit Multithreading.\n\nIm Zweifelsfall auf auf AUTO stellen.", "ShaderCacheToggleTooltip": "Speichert einen persistenten Shader Cache, der das Stottern bei nachfolgenden Durchläufen reduziert.\n\nIm Zweifelsfall AN lassen.", - "ResolutionScaleTooltip": "Wendet die Auflösungsskalierung auf anwendbare Render Ziele", + "ResolutionScaleTooltip": "Multipliziert die Rendering-Auflösung des Spiels.\n\nEinige wenige Spiele funktionieren damit nicht und sehen auch bei höherer Auflösung pixelig aus; für diese Spiele müssen Sie möglicherweise Mods finden, die Anti-Aliasing entfernen oder die interne Rendering-Auflösung erhöhen. Für die Verwendung von Letzterem sollten Sie Native wählen.\n\nSie können diese Option ändern, während ein Spiel läuft, indem Sie unten auf \"Übernehmen\" klicken; Sie können das Einstellungsfenster einfach zur Seite schieben und experimentieren, bis Sie Ihr bevorzugtes Aussehen für ein Spiel gefunden haben.\n\nDenken Sie daran, dass 4x für praktisch jedes Setup Overkill ist.", "ResolutionScaleEntryTooltip": "Fließkomma Auflösungsskalierung, wie 1,5.\n Bei nicht ganzzahligen Werten ist die Wahrscheinlichkeit größer, dass Probleme entstehen, die auch zum Absturz führen können.", - "AnisotropyTooltip": "Stufe der Anisotropen Filterung (Auf Auto setzen, um den vom Spiel geforderten Wert zu verwenden)", - "AspectRatioTooltip": "Auf das Renderer-Fenster angewandtes Seitenverhältnis.", + "AnisotropyTooltip": "Stufe der Anisotropen Filterung. Auf Auto setzen, um den vom Spiel geforderten Wert zu verwenden.", + "AspectRatioTooltip": "Seitenverhältnis, das auf das Renderer-Fenster angewendet wird.\n\nÄndern Sie dies nur, wenn Sie einen Seitenverhältnis-Mod für Ihr Spiel verwenden, da sonst die Grafik gestreckt wird.\n\nLassen Sie es auf 16:9, wenn Sie unsicher sind.", "ShaderDumpPathTooltip": "Grafik-Shader-Dump-Pfad", "FileLogTooltip": "Speichert die Konsolenausgabe in einer Log-Datei auf der Festplatte. Hat keinen Einfluss auf die Leistung.", "StubLogTooltip": "Ausgabe von Stub-Logs in der Konsole. Hat keinen Einfluss auf die Leistung.", @@ -504,6 +615,8 @@ "EnableInternetAccessTooltip": "Erlaubt es der emulierten Anwendung sich mit dem Internet zu verbinden.\n\nSpiele die den LAN-Modus unterstützen, ermöglichen es Ryujinx sich sowohl mit anderen Ryujinx-Systemen, als auch mit offiziellen Nintendo Switch Konsolen zu verbinden. Allerdings nur, wenn diese Option aktiviert ist und die Systeme mit demselben lokalen Netzwerk verbunden sind.\n\nDies erlaubt KEINE Verbindung zu Nintendo-Servern. Kann bei bestimmten Spielen die versuchen sich mit dem Internet zu verbinden zum Absturz führen.\n\nIm Zweifelsfall AUS lassen", "GameListContextMenuManageCheatToolTip": "Öffnet den Cheat-Manager", "GameListContextMenuManageCheat": "Cheats verwalten", + "GameListContextMenuManageModToolTip": "Mods verwalten", + "GameListContextMenuManageMod": "Mods verwalten", "ControllerSettingsStickRange": "Bereich:", "DialogStopEmulationTitle": "Ryujinx - Beende Emulation", "DialogStopEmulationMessage": "Emulation wirklich beenden?", @@ -513,10 +626,8 @@ "SettingsTabNetworkConnection": "Netwerkverbindung", "SettingsTabCpuCache": "CPU-Cache", "SettingsTabCpuMemory": "CPU-Speicher", - "DialogUpdaterFlatpakNotSupportedMessage": "Bitte aktualisiere Ryujinx mit FlatHub", + "DialogUpdaterFlatpakNotSupportedMessage": "Bitte aktualisiere Ryujinx über FlatHub", "UpdaterDisabledWarningTitle": "Updater deaktiviert!", - "GameListContextMenuOpenSdModsDirectory": "Atmosphere-Mod-Verzeichnis öffnen", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Öffnet das alternative SD-Karten-Atmosphere-Verzeichnis, das die Mods der Anwendung enthält. Dieser Ordner ist nützlich für Mods, die für einen gemoddete Switch erstellt worden sind.", "ControllerSettingsRotate90": "Um 90° rotieren", "IconSize": "Cover Größe", "IconSizeTooltip": "Ändert die Größe der Spiel-Cover", @@ -544,12 +655,13 @@ "SwkbdMinCharacters": "Muss mindestens {0} Zeichen lang sein", "SwkbdMinRangeCharacters": "Muss {0}-{1} Zeichen lang sein", "SoftwareKeyboard": "Software-Tastatur", - "SoftwareKeyboardModeNumbersOnly": "Nur Zahlen", + "SoftwareKeyboardModeNumeric": "Darf nur 0-9 oder \".\" sein", "SoftwareKeyboardModeAlphabet": "Keine CJK-Zeichen", "SoftwareKeyboardModeASCII": "Nur ASCII-Text", - "DialogControllerAppletMessagePlayerRange": "Die Anwendung benötigt {0} Spieler mit:\n\nTYPEN: {1}\n\nSPIELER: {2}\n\n{3}Bitte öffne die Einstellungen und rekonfiguriere die Controller Einstellungen oder drücke auf schließen.", - "DialogControllerAppletMessage": "Die Anwendung benötigt genau {0} Speieler mit:\n\nTYPEN: {1}\n\nSPIELER: {2}\n\n{3}Bitte öffne die Einstellungen und rekonfiguriere die Controller Einstellungen oder drücke auf schließen.", - "DialogControllerAppletDockModeSet": "Der 'Docked Modus' ist ausgewählt. Handheld ist ebenfalls ungültig.\n\n", + "ControllerAppletControllers": "Unterstützte Controller:", + "ControllerAppletPlayers": "Spieler:", + "ControllerAppletDescription": "Ihre aktuelle Konfiguration ist ungültig. Öffnen Sie die Einstellungen und konfigurieren Sie Ihre Eingaben neu.", + "ControllerAppletDocked": "Andockmodus gesetzt. Handheld-Steuerung sollte deaktiviert worden sein.", "UpdaterRenaming": "Alte Dateien umbenennen...", "UpdaterRenameFailed": "Der Updater konnte die folgende Datei nicht umbenennen: {0}", "UpdaterAddingFiles": "Neue Dateien hinzufügen...", @@ -569,8 +681,8 @@ "OpenFolderDialogTitle": "Wähle einen Ordner mit einem entpackten Spiel", "AllSupportedFormats": "Alle unterstützten Formate", "RyujinxUpdater": "Ryujinx - Updater", - "SettingsTabHotkeys": "Tastatur Hotkeys", - "SettingsTabHotkeysHotkeys": "Tastatur Hotkeys", + "SettingsTabHotkeys": "Tastatur-Hotkeys", + "SettingsTabHotkeysHotkeys": "Tastatur-Hotkeys", "SettingsTabHotkeysToggleVsyncHotkey": "VSync:", "SettingsTabHotkeysScreenshotHotkey": "Screenshot:", "SettingsTabHotkeysShowUiHotkey": "Zeige UI:", @@ -587,17 +699,21 @@ "Writable": "Beschreibbar", "SelectDlcDialogTitle": "DLC-Dateien auswählen", "SelectUpdateDialogTitle": "Update-Datei auswählen", + "SelectModDialogTitle": "Mod-Ordner auswählen", "UserProfileWindowTitle": "Benutzerprofile verwalten", "CheatWindowTitle": "Spiel-Cheats verwalten", "DlcWindowTitle": "Spiel-DLC verwalten", + "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "Spiel-Updates verwalten", "CheatWindowHeading": "Cheats verfügbar für {0} [{1}]", "BuildId": "BuildId:", "DlcWindowHeading": "DLC verfügbar für {0} [{1}]", + "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Profil bearbeiten", "Cancel": "Abbrechen", "Save": "Speichern", "Discard": "Verwerfen", + "Paused": "Pausiert", "UserProfilesSetProfileImage": "Profilbild einrichten", "UserProfileEmptyNameError": "Name ist erforderlich", "UserProfileNoImageError": "Bitte ein Profilbild auswählen", @@ -605,11 +721,11 @@ "SettingsTabHotkeysResScaleUpHotkey": "Auflösung erhöhen:", "SettingsTabHotkeysResScaleDownHotkey": "Auflösung verringern:", "UserProfilesName": "Name:", - "UserProfilesUserId": "Benutzer Id:", + "UserProfilesUserId": "Benutzer-ID:", "SettingsTabGraphicsBackend": "Grafik-Backend:", - "SettingsTabGraphicsBackendTooltip": "Verwendendetes Grafik-Backend", + "SettingsTabGraphicsBackendTooltip": "Wählen Sie das Grafik-Backend, das im Emulator verwendet werden soll.\n\nVulkan ist insgesamt besser für alle modernen Grafikkarten geeignet, sofern deren Treiber auf dem neuesten Stand sind. Vulkan bietet auch eine schnellere Shader-Kompilierung (weniger Stottern) auf allen GPU-Anbietern.\n\nOpenGL kann auf alten Nvidia-GPUs, alten AMD-GPUs unter Linux oder auf GPUs mit geringerem VRAM bessere Ergebnisse erzielen, obwohl die Shader-Kompilierung stärker stottert.\n\nSetzen Sie auf Vulkan, wenn Sie unsicher sind. Stellen Sie OpenGL ein, wenn Ihr Grafikprozessor selbst mit den neuesten Grafiktreibern Vulkan nicht unterstützt.", "SettingsEnableTextureRecompression": "Textur-Rekompression", - "SettingsEnableTextureRecompressionTooltip": "Komprimiert bestimmte Texturen, um den VRAM-Verbrauch zu reduzieren.\n\nEmpfohlen für die Verwendung von GPUs, die weniger als 4 GiB VRAM haben.\n\nIm Zweifelsfall AUS lassen", + "SettingsEnableTextureRecompressionTooltip": "Komprimiert ASTC-Texturen, um die VRAM-Nutzung zu reduzieren.\n\nZu den Spielen, die dieses Texturformat verwenden, gehören Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder und The Legend of Zelda: Tears of the Kingdom.\n\nGrafikkarten mit 4GiB VRAM oder weniger werden beim Ausführen dieser Spiele wahrscheinlich irgendwann abstürzen.\n\nAktivieren Sie diese Option nur, wenn Ihnen bei den oben genannten Spielen der VRAM ausgeht. Lassen Sie es aus, wenn Sie unsicher sind.", "SettingsTabGraphicsPreferredGpu": "Bevorzugte GPU:", "SettingsTabGraphicsPreferredGpuTooltip": "Wähle die Grafikkarte aus, die mit dem Vulkan Grafik-Backend verwendet werden soll.\n\nDies hat keinen Einfluss auf die GPU die OpenGL verwendet.\n\nIm Zweifelsfall die als \"dGPU\" gekennzeichnete GPU auswählen. Diese Einstellung unberührt lassen, wenn keine zur Auswahl steht.", "SettingsAppRequiredRestartMessage": "Ein Neustart von Ryujinx ist erforderlich", @@ -635,12 +751,15 @@ "Recover": "Wiederherstellen", "UserProfilesRecoverHeading": "Speicherstände wurden für die folgenden Konten gefunden", "UserProfilesRecoverEmptyList": "Keine Profile zum Wiederherstellen", - "GraphicsAATooltip": "Wendet Anti-Aliasing auf das Spiel-Rendering an", + "GraphicsAATooltip": "Wendet Anti-Aliasing auf das Rendering des Spiels an.\n\nFXAA verwischt den größten Teil des Bildes, während SMAA versucht, gezackte Kanten zu finden und sie zu glätten.\n\nEs wird nicht empfohlen, diese Option in Verbindung mit dem FSR-Skalierungsfilter zu verwenden.\n\nDiese Option kann geändert werden, während ein Spiel läuft, indem Sie unten auf \"Anwenden\" klicken; Sie können das Einstellungsfenster einfach zur Seite schieben und experimentieren, bis Sie Ihr bevorzugtes Aussehen für ein Spiel gefunden haben.\n\nLassen Sie die Option auf NONE, wenn Sie unsicher sind.", "GraphicsAALabel": "Antialiasing:", "GraphicsScalingFilterLabel": "Skalierungsfilter:", - "GraphicsScalingFilterTooltip": "Ermöglicht Framebuffer-Skalierung", + "GraphicsScalingFilterTooltip": "Wählen Sie den Skalierungsfilter, der bei der Auflösungsskalierung angewendet werden soll.\n\nBilinear eignet sich gut für 3D-Spiele und ist eine sichere Standardoption.\n\nNearest wird für Pixel-Art-Spiele empfohlen.\n\nFSR 1.0 ist lediglich ein Schärfungsfilter und wird nicht für die Verwendung mit FXAA oder SMAA empfohlen.\n\nDiese Option kann geändert werden, während ein Spiel läuft, indem Sie unten auf \"Anwenden\" klicken; Sie können das Einstellungsfenster einfach zur Seite schieben und experimentieren, bis Sie Ihr bevorzugtes Aussehen für ein Spiel gefunden haben.\n\nBleiben Sie auf BILINEAR, wenn Sie unsicher sind.", + "GraphicsScalingFilterBilinear": "Bilinear", + "GraphicsScalingFilterNearest": "Nächstes", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "Stufe", - "GraphicsScalingFilterLevelTooltip": "Skalierungsfilter-Stufe festlegen", + "GraphicsScalingFilterLevelTooltip": "FSR 1.0 Schärfelevel festlegen. Höher ist schärfer.", "SmaaLow": "SMAA Niedrig", "SmaaMedium": "SMAA Mittel", "SmaaHigh": "SMAA Hoch", @@ -648,9 +767,14 @@ "UserEditorTitle": "Nutzer bearbeiten", "UserEditorTitleCreate": "Nutzer erstellen", "SettingsTabNetworkInterface": "Netzwerkschnittstelle:", - "NetworkInterfaceTooltip": "Die Netzwerkschnittstelle, die für LAN-Funktionen verwendet wird", + "NetworkInterfaceTooltip": "Die für LAN/LDN-Funktionen verwendete Netzwerkschnittstelle.\n\nIn Verbindung mit einem VPN oder XLink Kai und einem Spiel mit LAN-Unterstützung kann eine Verbindung mit demselben Netzwerk über das Internet vorgetäuscht werden.\n\nIm Zweifelsfall auf DEFAULT belassen.", "NetworkInterfaceDefault": "Standard", "PackagingShaders": "Verpackt Shader", "AboutChangelogButton": "Changelog in GitHub öffnen", - "AboutChangelogButtonTooltipMessage": "Klicke hier, um das Changelog für diese Version in Ihrem Standardbrowser zu öffnen." -} \ No newline at end of file + "AboutChangelogButtonTooltipMessage": "Klicke hier, um das Changelog für diese Version in Ihrem Standardbrowser zu öffnen.", + "SettingsTabNetworkMultiplayer": "Mehrspieler", + "MultiplayerMode": "Modus:", + "MultiplayerModeTooltip": "Ändert den LDN-Mehrspielermodus.\n\nLdnMitm ändert die lokale drahtlose/lokale Spielfunktionalität in Spielen so, dass sie wie ein LAN funktioniert und lokale, netzwerkgleiche Verbindungen mit anderen Ryujinx-Instanzen und gehackten Nintendo Switch-Konsolen ermöglicht, auf denen das ldn_mitm-Modul installiert ist.\n\nMultiplayer erfordert, dass alle Spieler die gleiche Spielversion verwenden (d.h. Super Smash Bros. Ultimate v13.0.1 kann sich nicht mit v13.0.0 verbinden).\n\nIm Zweifelsfall auf DISABLED lassen.", + "MultiplayerModeDisabled": "Deaktiviert", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/el_GR.json b/src/Ryujinx/Assets/Locales/el_GR.json similarity index 80% rename from src/Ryujinx.Ava/Assets/Locales/el_GR.json rename to src/Ryujinx/Assets/Locales/el_GR.json index 59f50ad92..ccdf6e0e4 100644 --- a/src/Ryujinx.Ava/Assets/Locales/el_GR.json +++ b/src/Ryujinx/Assets/Locales/el_GR.json @@ -14,7 +14,7 @@ "MenuBarFileOpenEmuFolder": "Άνοιγμα Φακέλου Ryujinx", "MenuBarFileOpenLogsFolder": "Άνοιγμα Φακέλου Καταγραφής", "MenuBarFileExit": "_Έξοδος", - "MenuBarOptions": "Επιλογές", + "MenuBarOptions": "_Επιλογές", "MenuBarOptionsToggleFullscreen": "Λειτουργία Πλήρους Οθόνης", "MenuBarOptionsStartGamesInFullscreen": "Εκκίνηση Παιχνιδιών σε Πλήρη Οθόνη", "MenuBarOptionsStopEmulation": "Διακοπή Εξομοίωσης", @@ -30,7 +30,11 @@ "MenuBarToolsManageFileTypes": "Διαχείριση τύπων αρχείων", "MenuBarToolsInstallFileTypes": "Εγκαταστήσετε τύπους αρχείων.", "MenuBarToolsUninstallFileTypes": "Απεγκαταστήσετε τύπους αρχείων", - "MenuBarHelp": "Βοήθεια", + "MenuBarView": "_View", + "MenuBarViewWindow": "Window Size", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Βοήθεια", "MenuBarHelpCheckForUpdates": "Έλεγχος για Ενημερώσεις", "MenuBarHelpAbout": "Σχετικά με", "MenuSearch": "Αναζήτηση...", @@ -54,8 +58,6 @@ "GameListContextMenuManageTitleUpdatesToolTip": "Ανοίγει το παράθυρο διαχείρισης Ενημερώσεων Παιχνιδιού", "GameListContextMenuManageDlc": "Διαχείριση DLC", "GameListContextMenuManageDlcToolTip": "Ανοίγει το παράθυρο διαχείρισης DLC", - "GameListContextMenuOpenModsDirectory": "Άνοιγμα Τοποθεσίας Τροποποιήσεων", - "GameListContextMenuOpenModsDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει τις Τροποποιήσεις της εφαρμογής", "GameListContextMenuCacheManagement": "Διαχείριση Προσωρινής Μνήμης", "GameListContextMenuCacheManagementPurgePptc": "Εκκαθάριση Προσωρινής Μνήμης PPTC", "GameListContextMenuCacheManagementPurgePptcToolTip": "Διαγράφει την προσωρινή μνήμη PPTC της εφαρμογής", @@ -72,21 +74,29 @@ "GameListContextMenuExtractDataRomFSToolTip": "Εξαγωγή της ενότητας RomFS από την τρέχουσα διαμόρφωση της εφαρμογής (συμπεριλαμβανομένου ενημερώσεων)", "GameListContextMenuExtractDataLogo": "Λογότυπο", "GameListContextMenuExtractDataLogoToolTip": "Εξαγωγή της ενότητας Logo από την τρέχουσα διαμόρφωση της εφαρμογής (συμπεριλαμβανομένου ενημερώσεων)", + "GameListContextMenuCreateShortcut": "Δημιουργία Συντόμευσης Εφαρμογής", + "GameListContextMenuCreateShortcutToolTip": "Δημιουργία συντόμευσης επιφάνειας εργασίας που ανοίγει την επιλεγμένη εφαρμογή", + "GameListContextMenuCreateShortcutToolTipMacOS": "Create a shortcut in macOS's Applications folder that launches the selected Application", + "GameListContextMenuOpenModsDirectory": "Open Mods Directory", + "GameListContextMenuOpenModsDirectoryToolTip": "Opens the directory which contains Application's Mods", + "GameListContextMenuOpenSdModsDirectory": "Open Atmosphere Mods Directory", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.", "StatusBarGamesLoaded": "{0}/{1} Φορτωμένα Παιχνίδια", "StatusBarSystemVersion": "Έκδοση Συστήματος: {0}", - "LinuxVmMaxMapCountDialogTitle": "Low limit for memory mappings detected", - "LinuxVmMaxMapCountDialogTextPrimary": "Would you like to increase the value of vm.max_map_count to {0}", - "LinuxVmMaxMapCountDialogTextSecondary": "Some games might try to create more memory mappings than currently allowed. Ryujinx will crash as soon as this limit gets exceeded.", - "LinuxVmMaxMapCountDialogButtonUntilRestart": "Yes, until the next restart", - "LinuxVmMaxMapCountDialogButtonPersistent": "Yes, permanently", - "LinuxVmMaxMapCountWarningTextPrimary": "Max amount of memory mappings is lower than recommended.", - "LinuxVmMaxMapCountWarningTextSecondary": "The current value of vm.max_map_count ({0}) is lower than {1}. Some games might try to create more memory mappings than currently allowed. Ryujinx will crash as soon as this limit gets exceeded.\n\nYou might want to either manually increase the limit or install pkexec, which allows Ryujinx to assist with that.", + "LinuxVmMaxMapCountDialogTitle": "Εντοπίστηκε χαμηλό όριο για αντιστοιχίσεις μνήμης", + "LinuxVmMaxMapCountDialogTextPrimary": "Θα θέλατε να αυξήσετε την τιμή του vm.max_map_count σε {0}", + "LinuxVmMaxMapCountDialogTextSecondary": "Μερικά παιχνίδια μπορεί να προσπαθήσουν να δημιουργήσουν περισσότερες αντιστοιχίσεις μνήμης από αυτές που επιτρέπονται τώρα. Ο Ryujinx θα καταρρεύσει μόλις ξεπεραστεί αυτό το όριο.", + "LinuxVmMaxMapCountDialogButtonUntilRestart": "Ναι, μέχρι την επόμενη επανεκκίνηση", + "LinuxVmMaxMapCountDialogButtonPersistent": "Ναι, μόνιμα", + "LinuxVmMaxMapCountWarningTextPrimary": "Ο μέγιστος αριθμός αντιστοιχίσεων μνήμης είναι μικρότερος από τον συνιστώμενο.", + "LinuxVmMaxMapCountWarningTextSecondary": "Η τρέχουσα τιμή του vm.max_map_count ({0}) είναι χαμηλότερη από {1}. Ορισμένα παιχνίδια μπορεί να προσπαθήσουν να δημιουργήσουν περισσότερες αντιστοιχίσεις μνήμης από αυτές που επιτρέπονται τώρα. Ο Ryujinx θα συντριβεί μόλις ξεπεραστεί το όριο.\n\nΜπορεί να θέλετε είτε να αυξήσετε χειροκίνητα το όριο ή να εγκαταστήσετε το pkexec, το οποίο επιτρέπει Ryujinx να βοηθήσει με αυτό.", "Settings": "Ρυθμίσεις", "SettingsTabGeneral": "Εμφάνιση", "SettingsTabGeneralGeneral": "Γενικά", "SettingsTabGeneralEnableDiscordRichPresence": "Ενεργοποίηση Εμπλουτισμένης Παρουσίας Discord", "SettingsTabGeneralCheckUpdatesOnLaunch": "Έλεγχος για Ενημερώσεις στην Εκκίνηση", "SettingsTabGeneralShowConfirmExitDialog": "Εμφάνιση διαλόγου \"Επιβεβαίωση Εξόδου\".", + "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", "SettingsTabGeneralHideCursor": "Απόκρυψη Κέρσορα:", "SettingsTabGeneralHideCursorNever": "Ποτέ", "SettingsTabGeneralHideCursorOnIdle": "Απόκρυψη Δρομέα στην Αδράνεια", @@ -150,7 +160,7 @@ "SettingsTabGraphicsResolutionScaleNative": "Εγγενής (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (Not recommended)", "SettingsTabGraphicsAspectRatio": "Αναλογία Απεικόνισης:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -228,10 +238,10 @@ "ControllerSettingsStickDown": "Κάτω", "ControllerSettingsStickLeft": "Αριστερά", "ControllerSettingsStickRight": "Δεξιά", - "ControllerSettingsStickStick": "Stick", - "ControllerSettingsStickInvertXAxis": "Invert Stick X", - "ControllerSettingsStickInvertYAxis": "Invert Stick Y", - "ControllerSettingsStickDeadzone": "Deadzone:", + "ControllerSettingsStickStick": "Μοχλός", + "ControllerSettingsStickInvertXAxis": "Αντιστροφή Μοχλού X", + "ControllerSettingsStickInvertYAxis": "Αντιστροφή Μοχλού Y", + "ControllerSettingsStickDeadzone": "Νεκρή Ζώνη:", "ControllerSettingsLStick": "Αριστερός Μοχλός", "ControllerSettingsRStick": "Δεξιός Μοχλός", "ControllerSettingsTriggersLeft": "Αριστερή Σκανδάλη", @@ -261,6 +271,107 @@ "ControllerSettingsMotionGyroDeadzone": "Νεκρή Ζώνη Γυροσκοπίου:", "ControllerSettingsSave": "Αποθήκευση", "ControllerSettingsClose": "Κλείσιμο", + "KeyUnknown": "Unknown", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", "UserProfilesSelectedUserProfile": "Επιλεγμένο Προφίλ Χρήστη:", "UserProfilesSaveProfileName": "Αποθήκευση Ονόματος Προφίλ", "UserProfilesChangeProfileImage": "Αλλαγή Εικόνας Προφίλ", @@ -289,16 +400,12 @@ "ControllerSettingsSaveProfileToolTip": "Αποθήκευση Προφίλ", "MenuBarFileToolsTakeScreenshot": "Λήψη Στιγμιότυπου", "MenuBarFileToolsHideUi": "Απόκρυψη UI", - "GameListContextMenuRunApplication": "Run Application", + "GameListContextMenuRunApplication": "Εκτέλεση Εφαρμογής", "GameListContextMenuToggleFavorite": "Εναλλαγή Αγαπημένου", "GameListContextMenuToggleFavoriteToolTip": "Εναλλαγή της Κατάστασης Αγαπημένο του Παιχνιδιού", - "SettingsTabGeneralTheme": "Θέμα", - "SettingsTabGeneralThemeCustomTheme": "Προσαρμοσμένη Τοποθεσία Θέματος", - "SettingsTabGeneralThemeBaseStyle": "Βασικό Στυλ", - "SettingsTabGeneralThemeBaseStyleDark": "Σκούρο", - "SettingsTabGeneralThemeBaseStyleLight": "Ανοιχτό", - "SettingsTabGeneralThemeEnableCustomTheme": "Ενεργοποίηση Προσαρμοσμένου Θέματος", - "ButtonBrowse": "Αναζήτηση", + "SettingsTabGeneralTheme": "Theme:", + "SettingsTabGeneralThemeDark": "Dark", + "SettingsTabGeneralThemeLight": "Light", "ControllerSettingsConfigureGeneral": "Παραμέτρων", "ControllerSettingsRumble": "Δόνηση", "ControllerSettingsRumbleStrongMultiplier": "Ισχυρός Πολλαπλασιαστής Δόνησης", @@ -332,8 +439,6 @@ "DialogUpdaterAddingFilesMessage": "Προσθήκη Νέας Ενημέρωσης...", "DialogUpdaterCompleteMessage": "Η Ενημέρωση Ολοκληρώθηκε!", "DialogUpdaterRestartMessage": "Θέλετε να επανεκκινήσετε το Ryujinx τώρα;", - "DialogUpdaterArchNotSupportedMessage": "Δεν υπάρχει υποστηριζόμενη αρχιτεκτονική συστήματος!", - "DialogUpdaterArchNotSupportedSubMessage": "(Υποστηρίζονται μόνο συστήματα x64!)", "DialogUpdaterNoInternetMessage": "Δεν είστε συνδεδεμένοι στο Διαδίκτυο!", "DialogUpdaterNoInternetSubMessage": "Επαληθεύστε ότι έχετε σύνδεση στο Διαδίκτυο που λειτουργεί!", "DialogUpdaterDirtyBuildMessage": "Δεν μπορείτε να ενημερώσετε μία Πρόχειρη Έκδοση του Ryujinx!", @@ -342,7 +447,7 @@ "DialogThemeRestartMessage": "Το θέμα έχει αποθηκευτεί. Απαιτείται επανεκκίνηση για την εφαρμογή του θέματος.", "DialogThemeRestartSubMessage": "Θέλετε να κάνετε επανεκκίνηση", "DialogFirmwareInstallEmbeddedMessage": "Θα θέλατε να εγκαταστήσετε το Firmware που είναι ενσωματωμένο σε αυτό το παιχνίδι; (Firmware {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "Δεν βρέθηκε εγκατεστημένο Firmware, αλλά το Ryujinx μπόρεσε να εγκαταστήσει το Firmware {0} από το παρεχόμενο παιχνίδι.\nΟ εξομοιωτής θα ξεκινήσει τώρα.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "No installed firmware was found but Ryujinx was able to install firmware {0} from the provided game.\nThe emulator will now start.", "DialogFirmwareNoFirmwareInstalledMessage": "Δεν έχει εγκατασταθεί Firmware", "DialogFirmwareInstalledMessage": "Το Firmware {0} εγκαταστάθηκε", "DialogInstallFileTypesSuccessMessage": "Επιτυχής εγκατάσταση τύπων αρχείων!", @@ -385,7 +490,10 @@ "DialogUserProfileUnsavedChangesSubMessage": "Θέλετε να απορρίψετε τις αλλαγές σας;", "DialogControllerSettingsModifiedConfirmMessage": "Οι τρέχουσες ρυθμίσεις χειρισμού έχουν ενημερωθεί.", "DialogControllerSettingsModifiedConfirmSubMessage": "Θέλετε να αποθηκεύσετε;", - "DialogLoadNcaErrorMessage": "{0}. Σφάλμα Αρχείου: {1}", + "DialogLoadFileErrorMessage": "{0}. Errored File: {1}", + "DialogModAlreadyExistsMessage": "Mod already exists", + "DialogModInvalidMessage": "The specified directory does not contain a mod!", + "DialogModDeleteNoParentMessage": "Failed to Delete: Could not find the parent directory for mod \"{0}\"!", "DialogDlcNoDlcErrorMessage": "Το αρχείο δεν περιέχει DLC για τον επιλεγμένο τίτλο!", "DialogPerformanceCheckLoggingEnabledMessage": "Έχετε ενεργοποιημένη την καταγραφή εντοπισμού σφαλμάτων, η οποία έχει σχεδιαστεί για χρήση μόνο από προγραμματιστές.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Για βέλτιστη απόδοση, συνιστάται η απενεργοποίηση καταγραφής εντοπισμού σφαλμάτων. Θέλετε να απενεργοποιήσετε την καταγραφή τώρα;", @@ -396,6 +504,8 @@ "DialogUpdateAddUpdateErrorMessage": "Το αρχείο δεν περιέχει ενημέρωση για τον επιλεγμένο τίτλο!", "DialogSettingsBackendThreadingWarningTitle": "Προειδοποίηση - Backend Threading", "DialogSettingsBackendThreadingWarningMessage": "Το Ryujinx πρέπει να επανεκκινηθεί αφού αλλάξει αυτή η επιλογή για να εφαρμοστεί πλήρως. Ανάλογα με την πλατφόρμα σας, μπορεί να χρειαστεί να απενεργοποιήσετε με μη αυτόματο τρόπο το multithreading του ίδιου του προγράμματος οδήγησης όταν χρησιμοποιείτε το Ryujinx.", + "DialogModManagerDeletionWarningMessage": "You are about to delete the mod: {0}\n\nAre you sure you want to proceed?", + "DialogModManagerDeletionAllWarningMessage": "You are about to delete all mods for this title.\n\nAre you sure you want to proceed?", "SettingsTabGraphicsFeaturesOptions": "Χαρακτηριστικά", "SettingsTabGraphicsBackendMultithreading": "Πολυνηματική Επεξεργασία Γραφικών:", "CommonAuto": "Αυτόματο", @@ -430,6 +540,7 @@ "DlcManagerRemoveAllButton": "Αφαίρεση όλων", "DlcManagerEnableAllButton": "Ενεργοποίηση Όλων", "DlcManagerDisableAllButton": "Απενεργοποίηση Όλων", + "ModManagerDeleteAllButton": "Delete All", "MenuBarOptionsChangeLanguage": "Αλλαξε γλώσσα", "MenuBarShowFileTypes": "Εμφάνιση Τύπων Αρχείων", "CommonSort": "Κατάταξη", @@ -447,13 +558,13 @@ "CustomThemePathTooltip": "Διαδρομή προς το προσαρμοσμένο θέμα GUI", "CustomThemeBrowseTooltip": "Αναζητήστε ένα προσαρμοσμένο θέμα GUI", "DockModeToggleTooltip": "Ενεργοποιήστε ή απενεργοποιήστε τη λειτουργία σύνδεσης", - "DirectKeyboardTooltip": "Ενεργοποίηση ή απενεργοποίηση της \"υποστήριξης άμεσης πρόσβασης πληκτρολογίου (HID)\" (Παρέχει πρόσβαση στα παιχνίδια στο πληκτρολόγιό σας ως συσκευή εισαγωγής κειμένου)", - "DirectMouseTooltip": "Ενεργοποίηση ή απενεργοποίηση της \"υποστήριξης άμεσης πρόσβασης ποντικιού (HID)\" (Παρέχει πρόσβαση στα παιχνίδια στο ποντίκι σας ως συσκευή κατάδειξης)", + "DirectKeyboardTooltip": "Direct keyboard access (HID) support. Provides games access to your keyboard as a text entry device.\n\nOnly works with games that natively support keyboard usage on Switch hardware.\n\nLeave OFF if unsure.", + "DirectMouseTooltip": "Direct mouse access (HID) support. Provides games access to your mouse as a pointing device.\n\nOnly works with games that natively support mouse controls on Switch hardware, which are few and far between.\n\nWhen enabled, touch screen functionality may not work.\n\nLeave OFF if unsure.", "RegionTooltip": "Αλλαγή Περιοχής Συστήματος", "LanguageTooltip": "Αλλαγή Γλώσσας Συστήματος", "TimezoneTooltip": "Αλλαγή Ζώνης Ώρας Συστήματος", "TimeTooltip": "Αλλαγή Ώρας Συστήματος", - "VSyncToggleTooltip": "Ενεργοποιεί ή απενεργοποιεί τον κατακόρυφο συγχρονισμό", + "VSyncToggleTooltip": "Emulated console's Vertical Sync. Essentially a frame-limiter for the majority of games; disabling it may cause games to run at higher speed or make loading screens take longer or get stuck.\n\nCan be toggled in-game with a hotkey of your preference (F1 by default). We recommend doing this if you plan on disabling it.\n\nLeave ON if unsure.", "PptcToggleTooltip": "Ενεργοποιεί ή απενεργοποιεί το PPTC", "FsIntegrityToggleTooltip": "Ενεργοποιεί τους ελέγχους ακεραιότητας σε αρχεία περιεχομένου παιχνιδιού", "AudioBackendTooltip": "Αλλαγή ήχου υποστήριξης", @@ -467,10 +578,10 @@ "GraphicsBackendThreadingTooltip": "Ενεργοποίηση Πολυνηματικής Επεξεργασίας Γραφικών", "GalThreadingTooltip": "Εκτελεί εντολές γραφικών σε ένα δεύτερο νήμα. Επιτρέπει την πολυνηματική μεταγλώττιση Shader σε χρόνο εκτέλεσης, μειώνει το τρεμόπαιγμα και βελτιώνει την απόδοση των προγραμμάτων οδήγησης χωρίς τη δική τους υποστήριξη πολλαπλών νημάτων. Ποικίλες κορυφαίες επιδόσεις σε προγράμματα οδήγησης με multithreading. Μπορεί να χρειαστεί επανεκκίνηση του Ryujinx για να απενεργοποιήσετε σωστά την ενσωματωμένη λειτουργία πολλαπλών νημάτων του προγράμματος οδήγησης ή ίσως χρειαστεί να το κάνετε χειροκίνητα για να έχετε την καλύτερη απόδοση.", "ShaderCacheToggleTooltip": "Ενεργοποιεί ή απενεργοποιεί την Προσωρινή Μνήμη Shader", - "ResolutionScaleTooltip": "Κλίμακα ανάλυσης που εφαρμόστηκε σε ισχύοντες στόχους απόδοσης", + "ResolutionScaleTooltip": "Multiplies the game's rendering resolution.\n\nA few games may not work with this and look pixelated even when the resolution is increased; for those games, you may need to find mods that remove anti-aliasing or that increase their internal rendering resolution. For using the latter, you'll likely want to select Native.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nKeep in mind 4x is overkill for virtually any setup.", "ResolutionScaleEntryTooltip": "Κλίμακα ανάλυσης κινητής υποδιαστολής, όπως 1,5. Οι μη αναπόσπαστες τιμές είναι πιθανό να προκαλέσουν προβλήματα ή σφάλματα.", - "AnisotropyTooltip": "Επίπεδο Ανισότροπου Φιλτραρίσματος (ρυθμίστε το στο Αυτόματο για να χρησιμοποιηθεί η τιμή που ζητήθηκε από το παιχνίδι)", - "AspectRatioTooltip": "Λόγος διαστάσεων που εφαρμόστηκε στο παράθυρο απόδοσης.", + "AnisotropyTooltip": "Level of Anisotropic Filtering. Set to Auto to use the value requested by the game.", + "AspectRatioTooltip": "Aspect Ratio applied to the renderer window.\n\nOnly change this if you're using an aspect ratio mod for your game, otherwise the graphics will be stretched.\n\nLeave on 16:9 if unsure.", "ShaderDumpPathTooltip": "Τοποθεσία Εναπόθεσης Προσωρινής Μνήμης Shaders", "FileLogTooltip": "Ενεργοποιεί ή απενεργοποιεί την καταγραφή σε ένα αρχείο στο δίσκο", "StubLogTooltip": "Ενεργοποιεί την εκτύπωση μηνυμάτων καταγραφής ατελειών", @@ -504,6 +615,8 @@ "EnableInternetAccessTooltip": "Επιτρέπει την πρόσβαση επισκέπτη στο Διαδίκτυο. Εάν ενεργοποιηθεί, η εξομοιωμένη κονσόλα Switch θα συμπεριφέρεται σαν να είναι συνδεδεμένη στο Διαδίκτυο. Λάβετε υπόψη ότι σε ορισμένες περιπτώσεις, οι εφαρμογές ενδέχεται να εξακολουθούν να έχουν πρόσβαση στο Διαδίκτυο, ακόμη και όταν αυτή η επιλογή είναι απενεργοποιημένη", "GameListContextMenuManageCheatToolTip": "Διαχείριση Κόλπων", "GameListContextMenuManageCheat": "Διαχείριση Κόλπων", + "GameListContextMenuManageModToolTip": "Manage Mods", + "GameListContextMenuManageMod": "Manage Mods", "ControllerSettingsStickRange": "Εύρος:", "DialogStopEmulationTitle": "Ryujinx - Διακοπή εξομοίωσης", "DialogStopEmulationMessage": "Είστε βέβαιοι ότι θέλετε να σταματήσετε την εξομοίωση;", @@ -515,8 +628,6 @@ "SettingsTabCpuMemory": "Μνήμη CPU", "DialogUpdaterFlatpakNotSupportedMessage": "Παρακαλούμε ενημερώστε το Ryujinx μέσω FlatHub.", "UpdaterDisabledWarningTitle": "Ο Διαχειριστής Ενημερώσεων Είναι Απενεργοποιημένος!", - "GameListContextMenuOpenSdModsDirectory": "Άνοιγμα Της Τοποθεσίας Των Atmosphere Mods", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Ανοίγει τον εναλλακτικό SD card Atmosphere κατάλογο που περιέχει Mods για το Application. Χρήσιμο για mods τα οποία συσκευάστηκαν για την πραγματική κονσόλα.", "ControllerSettingsRotate90": "Περιστροφή 90° Δεξιόστροφα", "IconSize": "Μέγεθος Εικονιδίου", "IconSizeTooltip": "Αλλάξτε μέγεθος εικονιδίων των παιχνιδιών", @@ -544,12 +655,13 @@ "SwkbdMinCharacters": "Πρέπει να έχει μήκος τουλάχιστον {0} χαρακτήρες", "SwkbdMinRangeCharacters": "Πρέπει να έχει μήκος {0}-{1} χαρακτήρες", "SoftwareKeyboard": "Εικονικό Πληκτρολόγιο", - "SoftwareKeyboardModeNumbersOnly": "Must be numbers only", - "SoftwareKeyboardModeAlphabet": "Must be non CJK-characters only", - "SoftwareKeyboardModeASCII": "Must be ASCII text only", - "DialogControllerAppletMessagePlayerRange": "Η εφαρμογή ζητά {0} παίκτη(ες) με:\n\nΤΥΠΟΥΣ: {1}\n\nΠΑΙΚΤΕΣ: {2}\n\n{3}Παρακαλώ ανοίξτε τις ρυθμίσεις και αλλάξτε τις ρυθμίσεις εισαγωγής τώρα ή πατήστε Κλείσιμο.", - "DialogControllerAppletMessage": "Η εφαρμογή ζητά ακριβώς {0} παίκτη(ες) με:\n\nΤΥΠΟΥΣ: {1}\n\nΠΑΙΚΤΕΣ: {2}\n\n{3}Παρακαλώ ανοίξτε τις ρυθμίσεις και αλλάξτε τις Ρυθμίσεις εισαγωγής τώρα ή πατήστε Κλείσιμο.", - "DialogControllerAppletDockModeSet": "Η κατάσταση Docked ενεργοποιήθηκε. Το συσκευή παλάμης είναι επίσης μην αποδεκτό.", + "SoftwareKeyboardModeNumeric": "Πρέπει να είναι 0-9 ή '.' μόνο", + "SoftwareKeyboardModeAlphabet": "Πρέπει να μην είναι μόνο χαρακτήρες CJK", + "SoftwareKeyboardModeASCII": "Πρέπει να είναι μόνο κείμενο ASCII", + "ControllerAppletControllers": "Supported Controllers:", + "ControllerAppletPlayers": "Players:", + "ControllerAppletDescription": "Your current configuration is invalid. Open settings and reconfigure your inputs.", + "ControllerAppletDocked": "Docked mode set. Handheld control should be disabled.", "UpdaterRenaming": "Μετονομασία Παλαιών Αρχείων...", "UpdaterRenameFailed": "Δεν ήταν δυνατή η μετονομασία του αρχείου: {0}", "UpdaterAddingFiles": "Προσθήκη Νέων Αρχείων...", @@ -587,17 +699,21 @@ "Writable": "Εγγράψιμο", "SelectDlcDialogTitle": "Επιλογή αρχείων DLC", "SelectUpdateDialogTitle": "Επιλογή αρχείων ενημέρωσης", + "SelectModDialogTitle": "Select mod directory", "UserProfileWindowTitle": "Διαχειριστής Προφίλ Χρήστη", "CheatWindowTitle": "Διαχειριστής των Cheats", "DlcWindowTitle": "Downloadable Content Manager", + "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "Διαχειριστής Ενημερώσεων Τίτλου", "CheatWindowHeading": "Διαθέσιμα Cheats για {0} [{1}]", "BuildId": "BuildId:", "DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})", + "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Επεξεργασία Επιλεγμένων", "Cancel": "Ακύρωση", "Save": "Αποθήκευση", "Discard": "Απόρριψη", + "Paused": "Σε παύση", "UserProfilesSetProfileImage": "Ορισμός Εικόνας Προφίλ", "UserProfileEmptyNameError": "Απαιτείται όνομα", "UserProfileNoImageError": "Η εικόνα προφίλ πρέπει να οριστεί", @@ -607,9 +723,9 @@ "UserProfilesName": "Όνομα:", "UserProfilesUserId": "User Id:", "SettingsTabGraphicsBackend": "Σύστημα Υποστήριξης Γραφικών", - "SettingsTabGraphicsBackendTooltip": "Backend Γραφικών που θα χρησιμοποιηθεί", + "SettingsTabGraphicsBackendTooltip": "Select the graphics backend that will be used in the emulator.\n\nVulkan is overall better for all modern graphics cards, as long as their drivers are up to date. Vulkan also features faster shader compilation (less stuttering) on all GPU vendors.\n\nOpenGL may achieve better results on old Nvidia GPUs, on old AMD GPUs on Linux, or on GPUs with lower VRAM, though shader compilation stutters will be greater.\n\nSet to Vulkan if unsure. Set to OpenGL if your GPU does not support Vulkan even with the latest graphics drivers.", "SettingsEnableTextureRecompression": "Ενεργοποίηση Επανασυμπίεσης Των Texture", - "SettingsEnableTextureRecompressionTooltip": "Συμπιέζει συγκεκριμένα texture για να μειωθεί η χρήση της VRAM.\nΣυνίσταται για χρήση σε κάρτες γραφικών με λιγότερο από 4 GiB VRAM.\nΑφήστε το Απενεργοποιημένο αν είστε αβέβαιοι.", + "SettingsEnableTextureRecompressionTooltip": "Compresses ASTC textures in order to reduce VRAM usage.\n\nGames using this texture format include Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder and The Legend of Zelda: Tears of the Kingdom.\n\nGraphics cards with 4GiB VRAM or less will likely crash at some point while running these games.\n\nEnable only if you're running out of VRAM on the aforementioned games. Leave OFF if unsure.", "SettingsTabGraphicsPreferredGpu": "Προτιμώμενη GPU", "SettingsTabGraphicsPreferredGpuTooltip": "Επιλέξτε την κάρτα γραφικών η οποία θα χρησιμοποιηθεί από το Vulkan.\n\nΔεν επηρεάζει το OpenGL.\n\nΔιαλέξτε την GPU που διαθέτει την υπόδειξη \"dGPU\" αν δεν είστε βέβαιοι. Αν δεν υπάρχει κάποιαν, το πειράξετε", "SettingsAppRequiredRestartMessage": "Απαιτείται Επανεκκίνηση Του Ryujinx", @@ -620,8 +736,8 @@ "SettingsTabHotkeysVolumeDownHotkey": "Μείωση Έντασης:", "SettingsEnableMacroHLE": "Ενεργοποίηση του Macro HLE", "SettingsEnableMacroHLETooltip": "Προσομοίωση του κώδικα GPU Macro .\n\nΒελτιώνει την απόδοση, αλλά μπορεί να προκαλέσει γραφικά προβλήματα σε μερικά παιχνίδια.\n\nΑφήστε ΕΝΕΡΓΟ αν δεν είστε σίγουροι.", - "SettingsEnableColorSpacePassthrough": "Color Space Passthrough", - "SettingsEnableColorSpacePassthroughTooltip": "Directs the Vulkan backend to pass through color information without specifying a color space. For users with wide gamut displays, this may result in more vibrant colors, at the cost of color correctness.", + "SettingsEnableColorSpacePassthrough": "Διέλευση Χρωματικού Χώρου", + "SettingsEnableColorSpacePassthroughTooltip": "Σκηνοθετεί το σύστημα υποστήριξης του Vulkan για να περάσει από πληροφορίες χρώματος χωρίς να καθορίσει έναν χρωματικό χώρο. Για χρήστες με ευρείες οθόνες γκάμας, αυτό μπορεί να οδηγήσει σε πιο ζωηρά χρώματα, με κόστος την ορθότητα του χρώματος.", "VolumeShort": "Έντ.", "UserProfilesManageSaves": "Διαχείριση Των Save", "DeleteUserSave": "Επιθυμείτε να διαγράψετε το save χρήστη για το συγκεκριμένο παιχνίδι;", @@ -635,12 +751,15 @@ "Recover": "Ανάκτηση", "UserProfilesRecoverHeading": "Βρέθηκαν save για τους ακόλουθους λογαριασμούς", "UserProfilesRecoverEmptyList": "Δεν υπάρχουν προφίλ για ανάκτηση", - "GraphicsAATooltip": "Εφαρμόζει anti-aliasing στην απόδοση του παιχνιδιού", + "GraphicsAATooltip": "Applies anti-aliasing to the game render.\n\nFXAA will blur most of the image, while SMAA will attempt to find jagged edges and smooth them out.\n\nNot recommended to use in conjunction with the FSR scaling filter.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on NONE if unsure.", "GraphicsAALabel": "Anti-Aliasing", "GraphicsScalingFilterLabel": "Φίλτρο Κλιμάκωσης:", - "GraphicsScalingFilterTooltip": "Ενεργοποιεί Κλίμακα Framebuffer", + "GraphicsScalingFilterTooltip": "Choose the scaling filter that will be applied when using resolution scale.\n\nBilinear works well for 3D games and is a safe default option.\n\nNearest is recommended for pixel art games.\n\nFSR 1.0 is merely a sharpening filter, not recommended for use with FXAA or SMAA.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on BILINEAR if unsure.", + "GraphicsScalingFilterBilinear": "Bilinear", + "GraphicsScalingFilterNearest": "Nearest", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "Επίπεδο", - "GraphicsScalingFilterLevelTooltip": "Ορισμός Επιπέδου Φίλτρου Κλιμάκωσης", + "GraphicsScalingFilterLevelTooltip": "Set FSR 1.0 sharpening level. Higher is sharper.", "SmaaLow": "Χαμηλό SMAA", "SmaaMedium": " Μεσαίο SMAA", "SmaaHigh": "Υψηλό SMAA", @@ -648,9 +767,14 @@ "UserEditorTitle": "Επεξεργασία Χρήστη", "UserEditorTitleCreate": "Δημιουργία Χρήστη", "SettingsTabNetworkInterface": "Διεπαφή Δικτύου", - "NetworkInterfaceTooltip": "Η διεπαφή δικτύου που χρησιμοποιείται για τα χαρακτηριστικά LAN", + "NetworkInterfaceTooltip": "The network interface used for LAN/LDN features.\n\nIn conjunction with a VPN or XLink Kai and a game with LAN support, can be used to spoof a same-network connection over the Internet.\n\nLeave on DEFAULT if unsure.", "NetworkInterfaceDefault": "Προεπιλογή", "PackagingShaders": "Shaders Συσκευασίας", - "AboutChangelogButton": "View Changelog on GitHub", - "AboutChangelogButtonTooltipMessage": "Click to open the changelog for this version in your default browser." -} \ No newline at end of file + "AboutChangelogButton": "Προβολή αρχείου αλλαγών στο GitHub", + "AboutChangelogButtonTooltipMessage": "Κάντε κλικ για να ανοίξετε το αρχείο αλλαγών για αυτήν την έκδοση στο προεπιλεγμένο πρόγραμμα περιήγησης σας.", + "SettingsTabNetworkMultiplayer": "Πολλαπλοί παίκτες", + "MultiplayerMode": "Λειτουργία:", + "MultiplayerModeTooltip": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.", + "MultiplayerModeDisabled": "Disabled", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/en_US.json b/src/Ryujinx/Assets/Locales/en_US.json similarity index 81% rename from src/Ryujinx.Ava/Assets/Locales/en_US.json rename to src/Ryujinx/Assets/Locales/en_US.json index 493aaa81f..b3cab7f5f 100644 --- a/src/Ryujinx.Ava/Assets/Locales/en_US.json +++ b/src/Ryujinx/Assets/Locales/en_US.json @@ -10,6 +10,7 @@ "SettingsTabSystemUseHypervisor": "Use Hypervisor", "MenuBarFile": "_File", "MenuBarFileOpenFromFile": "_Load Application From File", + "MenuBarFileOpenFromFileError": "No applications found in selected file.", "MenuBarFileOpenUnpacked": "Load _Unpacked Game", "MenuBarFileOpenEmuFolder": "Open Ryujinx Folder", "MenuBarFileOpenLogsFolder": "Open Logs Folder", @@ -30,6 +31,10 @@ "MenuBarToolsManageFileTypes": "Manage file types", "MenuBarToolsInstallFileTypes": "Install file types", "MenuBarToolsUninstallFileTypes": "Uninstall file types", + "MenuBarView": "_View", + "MenuBarViewWindow": "Window Size", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_Help", "MenuBarHelpCheckForUpdates": "Check for Updates", "MenuBarHelpAbout": "About", @@ -54,8 +59,6 @@ "GameListContextMenuManageTitleUpdatesToolTip": "Opens the Title Update management window", "GameListContextMenuManageDlc": "Manage DLC", "GameListContextMenuManageDlcToolTip": "Opens the DLC management window", - "GameListContextMenuOpenModsDirectory": "Open Mods Directory", - "GameListContextMenuOpenModsDirectoryToolTip": "Opens the directory which contains Application's Mods", "GameListContextMenuCacheManagement": "Cache Management", "GameListContextMenuCacheManagementPurgePptc": "Queue PPTC Rebuild", "GameListContextMenuCacheManagementPurgePptcToolTip": "Trigger PPTC to rebuild at boot time on the next game launch", @@ -74,6 +77,11 @@ "GameListContextMenuExtractDataLogoToolTip": "Extract the Logo section from Application's current config (including updates)", "GameListContextMenuCreateShortcut": "Create Application Shortcut", "GameListContextMenuCreateShortcutToolTip": "Create a Desktop Shortcut that launches the selected Application", + "GameListContextMenuCreateShortcutToolTipMacOS": "Create a shortcut in macOS's Applications folder that launches the selected Application", + "GameListContextMenuOpenModsDirectory": "Open Mods Directory", + "GameListContextMenuOpenModsDirectoryToolTip": "Opens the directory which contains Application's Mods", + "GameListContextMenuOpenSdModsDirectory": "Open Atmosphere Mods Directory", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.", "StatusBarGamesLoaded": "{0}/{1} Games Loaded", "StatusBarSystemVersion": "System Version: {0}", "LinuxVmMaxMapCountDialogTitle": "Low limit for memory mappings detected", @@ -89,6 +97,7 @@ "SettingsTabGeneralEnableDiscordRichPresence": "Enable Discord Rich Presence", "SettingsTabGeneralCheckUpdatesOnLaunch": "Check for Updates on Launch", "SettingsTabGeneralShowConfirmExitDialog": "Show \"Confirm Exit\" Dialog", + "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", "SettingsTabGeneralHideCursor": "Hide Cursor:", "SettingsTabGeneralHideCursorNever": "Never", "SettingsTabGeneralHideCursorOnIdle": "On Idle", @@ -136,7 +145,7 @@ "SettingsTabSystemAudioBackendSDL2": "SDL2", "SettingsTabSystemHacks": "Hacks", "SettingsTabSystemHacksNote": "May cause instability", - "SettingsTabSystemExpandDramSize": "Use alternative memory layout (Developers)", + "SettingsTabSystemExpandDramSize": "Expand DRAM to 8GiB", "SettingsTabSystemIgnoreMissingServices": "Ignore Missing Services", "SettingsTabGraphics": "Graphics", "SettingsTabGraphicsAPI": "Graphics API", @@ -152,7 +161,7 @@ "SettingsTabGraphicsResolutionScaleNative": "Native (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (Not recommended)", "SettingsTabGraphicsAspectRatio": "Aspect Ratio:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -263,6 +272,107 @@ "ControllerSettingsMotionGyroDeadzone": "Gyro Deadzone:", "ControllerSettingsSave": "Save", "ControllerSettingsClose": "Close", + "KeyUnknown": "Unknown", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", "UserProfilesSelectedUserProfile": "Selected User Profile:", "UserProfilesSaveProfileName": "Save Profile Name", "UserProfilesChangeProfileImage": "Change Profile Image", @@ -294,13 +404,10 @@ "GameListContextMenuRunApplication": "Run Application", "GameListContextMenuToggleFavorite": "Toggle Favorite", "GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game", - "SettingsTabGeneralTheme": "Theme", - "SettingsTabGeneralThemeCustomTheme": "Custom Theme Path", - "SettingsTabGeneralThemeBaseStyle": "Base Style", - "SettingsTabGeneralThemeBaseStyleDark": "Dark", - "SettingsTabGeneralThemeBaseStyleLight": "Light", - "SettingsTabGeneralThemeEnableCustomTheme": "Enable Custom Theme", - "ButtonBrowse": "Browse", + "SettingsTabGeneralTheme": "Theme:", + "SettingsTabGeneralThemeAuto": "Auto", + "SettingsTabGeneralThemeDark": "Dark", + "SettingsTabGeneralThemeLight": "Light", "ControllerSettingsConfigureGeneral": "Configure", "ControllerSettingsRumble": "Rumble", "ControllerSettingsRumbleStrongMultiplier": "Strong Rumble Multiplier", @@ -334,8 +441,6 @@ "DialogUpdaterAddingFilesMessage": "Adding New Update...", "DialogUpdaterCompleteMessage": "Update Complete!", "DialogUpdaterRestartMessage": "Do you want to restart Ryujinx now?", - "DialogUpdaterArchNotSupportedMessage": "You are not running a supported system architecture!", - "DialogUpdaterArchNotSupportedSubMessage": "(Only x64 systems are supported!)", "DialogUpdaterNoInternetMessage": "You are not connected to the Internet!", "DialogUpdaterNoInternetSubMessage": "Please verify that you have a working Internet connection!", "DialogUpdaterDirtyBuildMessage": "You Cannot update a Dirty build of Ryujinx!", @@ -344,7 +449,7 @@ "DialogThemeRestartMessage": "Theme has been saved. A restart is needed to apply the theme.", "DialogThemeRestartSubMessage": "Do you want to restart", "DialogFirmwareInstallEmbeddedMessage": "Would you like to install the firmware embedded in this game? (Firmware {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "No installed firmware was found but Ryujinx was able to install firmware {0} from the provided game.\\nThe emulator will now start.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "No installed firmware was found but Ryujinx was able to install firmware {0} from the provided game.\nThe emulator will now start.", "DialogFirmwareNoFirmwareInstalledMessage": "No Firmware Installed", "DialogFirmwareInstalledMessage": "Firmware {0} was installed", "DialogInstallFileTypesSuccessMessage": "Successfully installed file types!", @@ -387,7 +492,10 @@ "DialogUserProfileUnsavedChangesSubMessage": "Do you want to discard your changes?", "DialogControllerSettingsModifiedConfirmMessage": "The current controller settings has been updated.", "DialogControllerSettingsModifiedConfirmSubMessage": "Do you want to save?", - "DialogLoadNcaErrorMessage": "{0}. Errored File: {1}", + "DialogLoadFileErrorMessage": "{0}. Errored File: {1}", + "DialogModAlreadyExistsMessage": "Mod already exists", + "DialogModInvalidMessage": "The specified directory does not contain a mod!", + "DialogModDeleteNoParentMessage": "Failed to Delete: Could not find the parent directory for mod \"{0}\"!", "DialogDlcNoDlcErrorMessage": "The specified file does not contain a DLC for the selected title!", "DialogPerformanceCheckLoggingEnabledMessage": "You have trace logging enabled, which is designed to be used by developers only.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "For optimal performance, it's recommended to disable trace logging. Would you like to disable trace logging now?", @@ -398,6 +506,8 @@ "DialogUpdateAddUpdateErrorMessage": "The specified file does not contain an update for the selected title!", "DialogSettingsBackendThreadingWarningTitle": "Warning - Backend Threading", "DialogSettingsBackendThreadingWarningMessage": "Ryujinx must be restarted after changing this option for it to apply fully. Depending on your platform, you may need to manually disable your driver's own multithreading when using Ryujinx's.", + "DialogModManagerDeletionWarningMessage": "You are about to delete the mod: {0}\n\nAre you sure you want to proceed?", + "DialogModManagerDeletionAllWarningMessage": "You are about to delete all mods for this title.\n\nAre you sure you want to proceed?", "SettingsTabGraphicsFeaturesOptions": "Features", "SettingsTabGraphicsBackendMultithreading": "Graphics Backend Multithreading:", "CommonAuto": "Auto", @@ -432,6 +542,7 @@ "DlcManagerRemoveAllButton": "Remove All", "DlcManagerEnableAllButton": "Enable All", "DlcManagerDisableAllButton": "Disable All", + "ModManagerDeleteAllButton": "Delete All", "MenuBarOptionsChangeLanguage": "Change Language", "MenuBarShowFileTypes": "Show File Types", "CommonSort": "Sort", @@ -449,13 +560,13 @@ "CustomThemePathTooltip": "Path to custom GUI theme", "CustomThemeBrowseTooltip": "Browse for a custom GUI theme", "DockModeToggleTooltip": "Docked mode makes the emulated system behave as a docked Nintendo Switch. This improves graphical fidelity in most games. Conversely, disabling this will make the emulated system behave as a handheld Nintendo Switch, reducing graphics quality.\n\nConfigure player 1 controls if planning to use docked mode; configure handheld controls if planning to use handheld mode.\n\nLeave ON if unsure.", - "DirectKeyboardTooltip": "Direct keyboard access (HID) support. Provides games access to your keyboard as a text entry device.", - "DirectMouseTooltip": "Direct mouse access (HID) support. Provides games access to your mouse as a pointing device.", + "DirectKeyboardTooltip": "Direct keyboard access (HID) support. Provides games access to your keyboard as a text entry device.\n\nOnly works with games that natively support keyboard usage on Switch hardware.\n\nLeave OFF if unsure.", + "DirectMouseTooltip": "Direct mouse access (HID) support. Provides games access to your mouse as a pointing device.\n\nOnly works with games that natively support mouse controls on Switch hardware, which are few and far between.\n\nWhen enabled, touch screen functionality may not work.\n\nLeave OFF if unsure.", "RegionTooltip": "Change System Region", "LanguageTooltip": "Change System Language", "TimezoneTooltip": "Change System TimeZone", "TimeTooltip": "Change System Time", - "VSyncToggleTooltip": "Emulated console's Vertical Sync. Essentially a frame-limiter for the majority of games; disabling it may cause games to run at higher speed or make loading screens take longer or get stuck.\n\nCan be toggled in-game with a hotkey of your preference. We recommend doing this if you plan on disabling it.\n\nLeave ON if unsure.", + "VSyncToggleTooltip": "Emulated console's Vertical Sync. Essentially a frame-limiter for the majority of games; disabling it may cause games to run at higher speed or make loading screens take longer or get stuck.\n\nCan be toggled in-game with a hotkey of your preference (F1 by default). We recommend doing this if you plan on disabling it.\n\nLeave ON if unsure.", "PptcToggleTooltip": "Saves translated JIT functions so that they do not need to be translated every time the game loads.\n\nReduces stuttering and significantly speeds up boot times after the first boot of a game.\n\nLeave ON if unsure.", "FsIntegrityToggleTooltip": "Checks for corrupt files when booting a game, and if corrupt files are detected, displays a hash error in the log.\n\nHas no impact on performance and is meant to help troubleshooting.\n\nLeave ON if unsure.", "AudioBackendTooltip": "Changes the backend used to render audio.\n\nSDL2 is the preferred one, while OpenAL and SoundIO are used as fallbacks. Dummy will have no sound.\n\nSet to SDL2 if unsure.", @@ -464,15 +575,15 @@ "MemoryManagerHostTooltip": "Directly map memory in the host address space. Much faster JIT compilation and execution.", "MemoryManagerUnsafeTooltip": "Directly map memory, but do not mask the address within the guest address space before access. Faster, but at the cost of safety. The guest application can access memory from anywhere in Ryujinx, so only run programs you trust with this mode.", "UseHypervisorTooltip": "Use Hypervisor instead of JIT. Greatly improves performance when available, but can be unstable in its current state.", - "DRamTooltip": "Utilizes an alternative MemoryMode layout to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.", + "DRamTooltip": "Utilizes an alternative memory mode with 8GiB of DRAM to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.", "IgnoreMissingServicesTooltip": "Ignores unimplemented Horizon OS services. This may help in bypassing crashes when booting certain games.\n\nLeave OFF if unsure.", "GraphicsBackendThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.", "GalThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.", "ShaderCacheToggleTooltip": "Saves a disk shader cache which reduces stuttering in subsequent runs.\n\nLeave ON if unsure.", - "ResolutionScaleTooltip": "Resolution Scale applied to applicable render targets", + "ResolutionScaleTooltip": "Multiplies the game's rendering resolution.\n\nA few games may not work with this and look pixelated even when the resolution is increased; for those games, you may need to find mods that remove anti-aliasing or that increase their internal rendering resolution. For using the latter, you'll likely want to select Native.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nKeep in mind 4x is overkill for virtually any setup.", "ResolutionScaleEntryTooltip": "Floating point resolution scale, such as 1.5. Non-integral scales are more likely to cause issues or crash.", - "AnisotropyTooltip": "Level of Anisotropic Filtering (set to Auto to use the value requested by the game)", - "AspectRatioTooltip": "Aspect Ratio applied to the renderer window.", + "AnisotropyTooltip": "Level of Anisotropic Filtering. Set to Auto to use the value requested by the game.", + "AspectRatioTooltip": "Aspect Ratio applied to the renderer window.\n\nOnly change this if you're using an aspect ratio mod for your game, otherwise the graphics will be stretched.\n\nLeave on 16:9 if unsure.", "ShaderDumpPathTooltip": "Graphics Shaders Dump Path", "FileLogTooltip": "Saves console logging to a log file on disk. Does not affect performance.", "StubLogTooltip": "Prints stub log messages in the console. Does not affect performance.", @@ -506,6 +617,8 @@ "EnableInternetAccessTooltip": "Allows the emulated application to connect to the Internet.\n\nGames with a LAN mode can connect to each other when this is enabled and the systems are connected to the same access point. This includes real consoles as well.\n\nDoes NOT allow connecting to Nintendo servers. May cause crashing in certain games that try to connect to the Internet.\n\nLeave OFF if unsure.", "GameListContextMenuManageCheatToolTip": "Manage Cheats", "GameListContextMenuManageCheat": "Manage Cheats", + "GameListContextMenuManageModToolTip": "Manage Mods", + "GameListContextMenuManageMod": "Manage Mods", "ControllerSettingsStickRange": "Range:", "DialogStopEmulationTitle": "Ryujinx - Stop Emulation", "DialogStopEmulationMessage": "Are you sure you want to stop emulation?", @@ -517,8 +630,6 @@ "SettingsTabCpuMemory": "CPU Mode", "DialogUpdaterFlatpakNotSupportedMessage": "Please update Ryujinx via FlatHub.", "UpdaterDisabledWarningTitle": "Updater Disabled!", - "GameListContextMenuOpenSdModsDirectory": "Open Atmosphere Mods Directory", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.", "ControllerSettingsRotate90": "Rotate 90° Clockwise", "IconSize": "Icon Size", "IconSizeTooltip": "Change the size of game icons", @@ -539,6 +650,8 @@ "OpenSetupGuideMessage": "Open the Setup Guide", "NoUpdate": "No Update", "TitleUpdateVersionLabel": "Version {0}", + "TitleBundledUpdateVersionLabel": "Bundled: Version {0}", + "TitleBundledDlcLabel": "Bundled:", "RyujinxInfo": "Ryujinx - Info", "RyujinxConfirm": "Ryujinx - Confirmation", "FileDialogAllTypes": "All types", @@ -549,9 +662,10 @@ "SoftwareKeyboardModeNumeric": "Must be 0-9 or '.' only", "SoftwareKeyboardModeAlphabet": "Must be non CJK-characters only", "SoftwareKeyboardModeASCII": "Must be ASCII text only", - "DialogControllerAppletMessagePlayerRange": "Application requests {0} player(s) with:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}Please open Settings and reconfigure Input now or press Close.", - "DialogControllerAppletMessage": "Application requests exactly {0} player(s) with:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}Please open Settings and reconfigure Input now or press Close.", - "DialogControllerAppletDockModeSet": "Docked mode set. Handheld is also invalid.\n\n", + "ControllerAppletControllers": "Supported Controllers:", + "ControllerAppletPlayers": "Players:", + "ControllerAppletDescription": "Your current configuration is invalid. Open settings and reconfigure your inputs.", + "ControllerAppletDocked": "Docked mode set. Handheld control should be disabled.", "UpdaterRenaming": "Renaming Old Files...", "UpdaterRenameFailed": "Updater was unable to rename file: {0}", "UpdaterAddingFiles": "Adding New Files...", @@ -589,13 +703,16 @@ "Writable": "Writable", "SelectDlcDialogTitle": "Select DLC files", "SelectUpdateDialogTitle": "Select update files", + "SelectModDialogTitle": "Select mod directory", "UserProfileWindowTitle": "User Profiles Manager", "CheatWindowTitle": "Cheats Manager", "DlcWindowTitle": "Manage Downloadable Content for {0} ({1})", + "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "Title Update Manager", "CheatWindowHeading": "Cheats Available for {0} [{1}]", "BuildId": "BuildId:", "DlcWindowHeading": "{0} Downloadable Content(s)", + "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Edit Selected", "Cancel": "Cancel", "Save": "Save", @@ -610,9 +727,9 @@ "UserProfilesName": "Name:", "UserProfilesUserId": "User ID:", "SettingsTabGraphicsBackend": "Graphics Backend", - "SettingsTabGraphicsBackendTooltip": "Graphics Backend to use", + "SettingsTabGraphicsBackendTooltip": "Select the graphics backend that will be used in the emulator.\n\nVulkan is overall better for all modern graphics cards, as long as their drivers are up to date. Vulkan also features faster shader compilation (less stuttering) on all GPU vendors.\n\nOpenGL may achieve better results on old Nvidia GPUs, on old AMD GPUs on Linux, or on GPUs with lower VRAM, though shader compilation stutters will be greater.\n\nSet to Vulkan if unsure. Set to OpenGL if your GPU does not support Vulkan even with the latest graphics drivers.", "SettingsEnableTextureRecompression": "Enable Texture Recompression", - "SettingsEnableTextureRecompressionTooltip": "Compresses certain textures in order to reduce VRAM usage.\n\nRecommended for use with GPUs that have less than 4GiB VRAM.\n\nLeave OFF if unsure.", + "SettingsEnableTextureRecompressionTooltip": "Compresses ASTC textures in order to reduce VRAM usage.\n\nGames using this texture format include Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder and The Legend of Zelda: Tears of the Kingdom.\n\nGraphics cards with 4GiB VRAM or less will likely crash at some point while running these games.\n\nEnable only if you're running out of VRAM on the aforementioned games. Leave OFF if unsure.", "SettingsTabGraphicsPreferredGpu": "Preferred GPU", "SettingsTabGraphicsPreferredGpuTooltip": "Select the graphics card that will be used with the Vulkan graphics backend.\n\nDoes not affect the GPU that OpenGL will use.\n\nSet to the GPU flagged as \"dGPU\" if unsure. If there isn't one, leave untouched.", "SettingsAppRequiredRestartMessage": "Ryujinx Restart Required", @@ -638,12 +755,16 @@ "Recover": "Recover", "UserProfilesRecoverHeading": "Saves were found for the following accounts", "UserProfilesRecoverEmptyList": "No profiles to recover", - "GraphicsAATooltip": "Applies anti-aliasing to the game render", + "GraphicsAATooltip": "Applies anti-aliasing to the game render.\n\nFXAA will blur most of the image, while SMAA will attempt to find jagged edges and smooth them out.\n\nNot recommended to use in conjunction with the FSR scaling filter.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on NONE if unsure.", "GraphicsAALabel": "Anti-Aliasing:", "GraphicsScalingFilterLabel": "Scaling Filter:", - "GraphicsScalingFilterTooltip": "Enables Framebuffer Scaling", + "GraphicsScalingFilterTooltip": "Choose the scaling filter that will be applied when using resolution scale.\n\nBilinear works well for 3D games and is a safe default option.\n\nNearest is recommended for pixel art games.\n\nFSR 1.0 is merely a sharpening filter, not recommended for use with FXAA or SMAA.\n\nArea scaling is recommended when downscaling resolutions that are larger than the output window. It can be used to achieve a supersampled anti-aliasing effect when downscaling by more than 2x.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on BILINEAR if unsure.", + "GraphicsScalingFilterBilinear": "Bilinear", + "GraphicsScalingFilterNearest": "Nearest", + "GraphicsScalingFilterFsr": "FSR", + "GraphicsScalingFilterArea": "Area", "GraphicsScalingFilterLevelLabel": "Level", - "GraphicsScalingFilterLevelTooltip": "Set Scaling Filter Level", + "GraphicsScalingFilterLevelTooltip": "Set FSR 1.0 sharpening level. Higher is sharper.", "SmaaLow": "SMAA Low", "SmaaMedium": "SMAA Medium", "SmaaHigh": "SMAA High", @@ -651,12 +772,14 @@ "UserEditorTitle": "Edit User", "UserEditorTitleCreate": "Create User", "SettingsTabNetworkInterface": "Network Interface:", - "NetworkInterfaceTooltip": "The network interface used for LAN/LDN features", + "NetworkInterfaceTooltip": "The network interface used for LAN/LDN features.\n\nIn conjunction with a VPN or XLink Kai and a game with LAN support, can be used to spoof a same-network connection over the Internet.\n\nLeave on DEFAULT if unsure.", "NetworkInterfaceDefault": "Default", "PackagingShaders": "Packaging Shaders", "AboutChangelogButton": "View Changelog on GitHub", "AboutChangelogButtonTooltipMessage": "Click to open the changelog for this version in your default browser.", "SettingsTabNetworkMultiplayer": "Multiplayer", "MultiplayerMode": "Mode:", - "MultiplayerModeTooltip": "Change multiplayer mode" + "MultiplayerModeTooltip": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.", + "MultiplayerModeDisabled": "Disabled", + "MultiplayerModeLdnMitm": "ldn_mitm" } diff --git a/src/Ryujinx.Ava/Assets/Locales/es_ES.json b/src/Ryujinx/Assets/Locales/es_ES.json similarity index 79% rename from src/Ryujinx.Ava/Assets/Locales/es_ES.json rename to src/Ryujinx/Assets/Locales/es_ES.json index 91bcd8f11..e58fa5dcf 100644 --- a/src/Ryujinx.Ava/Assets/Locales/es_ES.json +++ b/src/Ryujinx/Assets/Locales/es_ES.json @@ -30,7 +30,11 @@ "MenuBarToolsManageFileTypes": "Administrar tipos de archivo", "MenuBarToolsInstallFileTypes": "Instalar tipos de archivo", "MenuBarToolsUninstallFileTypes": "Desinstalar tipos de archivo", - "MenuBarHelp": "Ayuda", + "MenuBarView": "_View", + "MenuBarViewWindow": "Window Size", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Ayuda", "MenuBarHelpCheckForUpdates": "Buscar actualizaciones", "MenuBarHelpAbout": "Acerca de", "MenuSearch": "Buscar...", @@ -54,17 +58,15 @@ "GameListContextMenuManageTitleUpdatesToolTip": "Abrir la ventana de gestión de actualizaciones de esta aplicación", "GameListContextMenuManageDlc": "Gestionar DLC", "GameListContextMenuManageDlcToolTip": "Abrir la ventana de gestión del DLC", - "GameListContextMenuOpenModsDirectory": "Abrir carpeta de mods", - "GameListContextMenuOpenModsDirectoryToolTip": "Abrir la carpeta que contiene los mods (archivos modificantes) de esta aplicación", "GameListContextMenuCacheManagement": "Gestión de caché ", "GameListContextMenuCacheManagementPurgePptc": "Reconstruir PPTC en cola", "GameListContextMenuCacheManagementPurgePptcToolTip": "Elimina la caché de PPTC de esta aplicación", - "GameListContextMenuCacheManagementPurgeShaderCache": "Limpiar caché de sombras", - "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Eliminar la caché de sombras de esta aplicación", + "GameListContextMenuCacheManagementPurgeShaderCache": "Limpiar caché de sombreadores", + "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Eliminar la caché de sombreadores de esta aplicación", "GameListContextMenuCacheManagementOpenPptcDirectory": "Abrir carpeta de PPTC", "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Abrir la carpeta que contiene la caché de PPTC de esta aplicación", - "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Abrir carpeta de caché de sombras", - "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Abrir la carpeta que contiene la caché de sombras de esta aplicación", + "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Abrir carpeta de caché de sombreadores", + "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Abrir la carpeta que contiene la caché de sombreadores de esta aplicación", "GameListContextMenuExtractData": "Extraer datos", "GameListContextMenuExtractDataExeFS": "ExeFS", "GameListContextMenuExtractDataExeFSToolTip": "Extraer la sección ExeFS de la configuración actual de la aplicación (incluyendo actualizaciones)", @@ -72,6 +74,13 @@ "GameListContextMenuExtractDataRomFSToolTip": "Extraer la sección RomFS de la configuración actual de la aplicación (incluyendo actualizaciones)", "GameListContextMenuExtractDataLogo": "Logotipo", "GameListContextMenuExtractDataLogoToolTip": "Extraer la sección Logo de la configuración actual de la aplicación (incluyendo actualizaciones)", + "GameListContextMenuCreateShortcut": "Crear acceso directo de aplicación", + "GameListContextMenuCreateShortcutToolTip": "Crear un acceso directo en el escritorio que lance la aplicación seleccionada", + "GameListContextMenuCreateShortcutToolTipMacOS": "Crea un acceso directo en la carpeta de Aplicaciones de macOS que inicie la Aplicación seleccionada", + "GameListContextMenuOpenModsDirectory": "Abrir Directorio de Mods", + "GameListContextMenuOpenModsDirectoryToolTip": "Abre el directorio que contiene los Mods de la Aplicación.", + "GameListContextMenuOpenSdModsDirectory": "Abrir Directorio de Mods de Atmosphere\n\n\n\n\n\n", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Abre el directorio alternativo de la tarjeta SD de Atmosphere que contiene los Mods de la Aplicación. Útil para los mods que están empaquetados para el hardware real.", "StatusBarGamesLoaded": "{0}/{1} juegos cargados", "StatusBarSystemVersion": "Versión del sistema: {0}", "LinuxVmMaxMapCountDialogTitle": "Límite inferior para mapeos de memoria detectado", @@ -87,6 +96,7 @@ "SettingsTabGeneralEnableDiscordRichPresence": "Habilitar estado en Discord", "SettingsTabGeneralCheckUpdatesOnLaunch": "Buscar actualizaciones al iniciar", "SettingsTabGeneralShowConfirmExitDialog": "Mostrar diálogo de confirmación al cerrar", + "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", "SettingsTabGeneralHideCursor": "Esconder el cursor:", "SettingsTabGeneralHideCursorNever": "Nunca", "SettingsTabGeneralHideCursorOnIdle": "Ocultar cursor cuando esté inactivo", @@ -138,7 +148,7 @@ "SettingsTabSystemIgnoreMissingServices": "Ignorar servicios no implementados", "SettingsTabGraphics": "Gráficos", "SettingsTabGraphicsAPI": "API de gráficos", - "SettingsTabGraphicsEnableShaderCache": "Habilitar caché de sombras", + "SettingsTabGraphicsEnableShaderCache": "Habilitar caché de sombreadores", "SettingsTabGraphicsAnisotropicFiltering": "Filtro anisotrópico:", "SettingsTabGraphicsAnisotropicFilteringAuto": "Automático", "SettingsTabGraphicsAnisotropicFiltering2x": "x2", @@ -150,7 +160,7 @@ "SettingsTabGraphicsResolutionScaleNative": "Nativa (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "x2 (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "x3 (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "x4 (2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (no recomendado)", "SettingsTabGraphicsAspectRatio": "Relación de aspecto:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -159,7 +169,7 @@ "SettingsTabGraphicsAspectRatio32x9": "32:9", "SettingsTabGraphicsAspectRatioStretch": "Estirar a la ventana", "SettingsTabGraphicsDeveloperOptions": "Opciones de desarrollador", - "SettingsTabGraphicsShaderDumpPath": "Directorio de volcado de sombras:", + "SettingsTabGraphicsShaderDumpPath": "Directorio de volcado de sombreadores:", "SettingsTabLogging": "Registros", "SettingsTabLoggingLogging": "Registros", "SettingsTabLoggingEnableLoggingToFile": "Habilitar registro a archivo", @@ -261,6 +271,107 @@ "ControllerSettingsMotionGyroDeadzone": "Zona muerta de Gyro:", "ControllerSettingsSave": "Guardar", "ControllerSettingsClose": "Cerrar", + "KeyUnknown": "Desconocido", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", "UserProfilesSelectedUserProfile": "Perfil de usuario seleccionado:", "UserProfilesSaveProfileName": "Guardar nombre de perfil", "UserProfilesChangeProfileImage": "Cambiar imagen de perfil", @@ -292,13 +403,9 @@ "GameListContextMenuRunApplication": "Ejecutar aplicación", "GameListContextMenuToggleFavorite": "Marcar favorito", "GameListContextMenuToggleFavoriteToolTip": "Marca o desmarca el juego como favorito", - "SettingsTabGeneralTheme": "Tema", - "SettingsTabGeneralThemeCustomTheme": "Directorio de tema personalizado", - "SettingsTabGeneralThemeBaseStyle": "Estilo base", - "SettingsTabGeneralThemeBaseStyleDark": "Oscuro", - "SettingsTabGeneralThemeBaseStyleLight": "Claro", - "SettingsTabGeneralThemeEnableCustomTheme": "Habilitar tema personalizado", - "ButtonBrowse": "Buscar", + "SettingsTabGeneralTheme": "Tema:", + "SettingsTabGeneralThemeDark": "Oscuro", + "SettingsTabGeneralThemeLight": "Claro", "ControllerSettingsConfigureGeneral": "Configurar", "ControllerSettingsRumble": "Vibración", "ControllerSettingsRumbleStrongMultiplier": "Multiplicador de vibraciones fuertes", @@ -332,8 +439,6 @@ "DialogUpdaterAddingFilesMessage": "Aplicando actualización...", "DialogUpdaterCompleteMessage": "¡Actualización completa!", "DialogUpdaterRestartMessage": "¿Quieres reiniciar Ryujinx?", - "DialogUpdaterArchNotSupportedMessage": "¡Tu arquitectura de sistema no es compatible!", - "DialogUpdaterArchNotSupportedSubMessage": "(¡Solo son compatibles los sistemas x64!)", "DialogUpdaterNoInternetMessage": "¡No estás conectado a internet!", "DialogUpdaterNoInternetSubMessage": "¡Por favor, verifica que tu conexión a Internet funciona!", "DialogUpdaterDirtyBuildMessage": "¡No puedes actualizar una versión \"dirty\" de Ryujinx!", @@ -342,7 +447,7 @@ "DialogThemeRestartMessage": "Tema guardado. Se necesita reiniciar para aplicar el tema.", "DialogThemeRestartSubMessage": "¿Quieres reiniciar?", "DialogFirmwareInstallEmbeddedMessage": "¿Quieres instalar el firmware incluido en este juego? (Firmware versión {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "No se encontró firmware instalado pero Ryujinx pudo instalar el firmware {0} a partir de este juego.\nA continuación, se iniciará el emulador.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "No installed firmware was found but Ryujinx was able to install firmware {0} from the provided game.\nThe emulator will now start.", "DialogFirmwareNoFirmwareInstalledMessage": "No hay firmware instalado", "DialogFirmwareInstalledMessage": "Se instaló el firmware {0}", "DialogInstallFileTypesSuccessMessage": "¡Tipos de archivos instalados con éxito!", @@ -385,17 +490,22 @@ "DialogUserProfileUnsavedChangesSubMessage": "¿Quieres descartar los cambios realizados?", "DialogControllerSettingsModifiedConfirmMessage": "Se ha actualizado la configuración del mando actual.", "DialogControllerSettingsModifiedConfirmSubMessage": "¿Guardar cambios?", - "DialogLoadNcaErrorMessage": "{0}. Archivo con error: {1}", + "DialogLoadFileErrorMessage": "{0}. Archivo con error: {1}", + "DialogModAlreadyExistsMessage": "El mod ya existe", + "DialogModInvalidMessage": "¡El directorio especificado no contiene un mod!", + "DialogModDeleteNoParentMessage": "Error al eliminar: ¡No se pudo encontrar el directorio principal para el mod \"{0}\"!", "DialogDlcNoDlcErrorMessage": "¡Ese archivo no contiene contenido descargable para el título seleccionado!", "DialogPerformanceCheckLoggingEnabledMessage": "Has habilitado los registros debug, diseñados solo para uso de los desarrolladores.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Para un rendimiento óptimo, se recomienda deshabilitar los registros debug. ¿Quieres deshabilitarlos ahora?", - "DialogPerformanceCheckShaderDumpEnabledMessage": "Has habilitado el volcado de sombras, diseñado solo para uso de los desarrolladores.", - "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Para un rendimiento óptimo, se recomienda deshabilitar el volcado de sombraa. ¿Quieres deshabilitarlo ahora?", + "DialogPerformanceCheckShaderDumpEnabledMessage": "Has habilitado el volcado de sombreadores, diseñado solo para uso de los desarrolladores.", + "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Para un rendimiento óptimo, se recomienda deshabilitar el volcado de sombreadores. ¿Quieres deshabilitarlo ahora?", "DialogLoadAppGameAlreadyLoadedMessage": "Ya has cargado un juego", "DialogLoadAppGameAlreadyLoadedSubMessage": "Por favor, detén la emulación o cierra el emulador antes de iniciar otro juego.", "DialogUpdateAddUpdateErrorMessage": "¡Ese archivo no contiene una actualización para el título seleccionado!", "DialogSettingsBackendThreadingWarningTitle": "Advertencia - multihilado de gráficos", "DialogSettingsBackendThreadingWarningMessage": "Ryujinx debe reiniciarse para aplicar este cambio. Dependiendo de tu plataforma, puede que tengas que desactivar manualmente la optimización enlazada de tus controladores gráficos para usar el multihilo de Ryujinx.", + "DialogModManagerDeletionWarningMessage": "Estás a punto de eliminar el mod: {0}\n\n¿Estás seguro de que quieres continuar?", + "DialogModManagerDeletionAllWarningMessage": "Estás a punto de eliminar todos los Mods para este título.\n\n¿Estás seguro de que quieres continuar?", "SettingsTabGraphicsFeaturesOptions": "Funcionalidades", "SettingsTabGraphicsBackendMultithreading": "Multihilado del motor gráfico:", "CommonAuto": "Automático", @@ -430,6 +540,7 @@ "DlcManagerRemoveAllButton": "Quitar todo", "DlcManagerEnableAllButton": "Activar todas", "DlcManagerDisableAllButton": "Desactivar todos", + "ModManagerDeleteAllButton": "Eliminar Todo", "MenuBarOptionsChangeLanguage": "Cambiar idioma", "MenuBarShowFileTypes": "Mostrar tipos de archivo", "CommonSort": "Orden", @@ -447,13 +558,13 @@ "CustomThemePathTooltip": "Carpeta que contiene los temas personalizados para la interfaz", "CustomThemeBrowseTooltip": "Busca un tema personalizado para la interfaz", "DockModeToggleTooltip": "El modo dock o modo TV hace que la consola emulada se comporte como una Nintendo Switch en su dock. Esto mejora la calidad gráfica en la mayoría de los juegos. Del mismo modo, si lo desactivas, el sistema emulado se comportará como una Nintendo Switch en modo portátil, reduciendo la cálidad de los gráficos.\n\nConfigura los controles de \"Jugador\" 1 si planeas jugar en modo dock/TV; configura los controles de \"Portátil\" si planeas jugar en modo portátil.\n\nActívalo si no sabes qué hacer.", - "DirectKeyboardTooltip": "Activa o desactiva \"soporte para acceso directo al teclado (HID)\" (Permite a los juegos utilizar tu teclado como entrada de texto)", - "DirectMouseTooltip": "Activa o desactiva \"soporte para acceso directo al ratón (HID)\" (Permite a los juegos utilizar tu ratón como cursor)", + "DirectKeyboardTooltip": "Direct keyboard access (HID) support. Provides games access to your keyboard as a text entry device.\n\nOnly works with games that natively support keyboard usage on Switch hardware.\n\nLeave OFF if unsure.", + "DirectMouseTooltip": "Direct mouse access (HID) support. Provides games access to your mouse as a pointing device.\n\nOnly works with games that natively support mouse controls on Switch hardware, which are few and far between.\n\nWhen enabled, touch screen functionality may not work.\n\nLeave OFF if unsure.", "RegionTooltip": "Cambia la región del sistema", "LanguageTooltip": "Cambia el idioma del sistema", "TimezoneTooltip": "Cambia la zona horaria del sistema", "TimeTooltip": "Cambia la hora del sistema", - "VSyncToggleTooltip": "Sincronización vertical del sistema emulado. A efectos prácticos es un límite de fotogramas para la mayoría de juegos; deshabilitarlo puede hacer que los juegos se aceleren o que las pantallas de carga tarden más o se atasquen.\n\nPuedes activar y desactivar esto mientras el emulador está funcionando con un atajo de teclado a tu elección. Recomendamos hacer esto en vez de deshabilitarlo.\n\nActívalo si no sabes qué hacer.", + "VSyncToggleTooltip": "Emulated console's Vertical Sync. Essentially a frame-limiter for the majority of games; disabling it may cause games to run at higher speed or make loading screens take longer or get stuck.\n\nCan be toggled in-game with a hotkey of your preference (F1 by default). We recommend doing this if you plan on disabling it.\n\nLeave ON if unsure.", "PptcToggleTooltip": "Guarda funciones de JIT traducidas para que no sea necesario traducirlas cada vez que el juego carga.\n\nReduce los tirones y acelera significativamente el tiempo de inicio de los juegos después de haberlos ejecutado al menos una vez.\n\nActívalo si no sabes qué hacer.", "FsIntegrityToggleTooltip": "Comprueba si hay archivos corruptos en los juegos que ejecutes al abrirlos, y si detecta archivos corruptos, muestra un error de Hash en los registros.\n\nEsto no tiene impacto alguno en el rendimiento y está pensado para ayudar a resolver problemas.\n\nActívalo si no sabes qué hacer.", "AudioBackendTooltip": "Cambia el motor usado para renderizar audio.\n\nSDL2 es el preferido, mientras que OpenAL y SoundIO se usan si hay problemas con este. Dummy no produce audio.\n\nSelecciona SDL2 si no sabes qué hacer.", @@ -464,13 +575,13 @@ "UseHypervisorTooltip": "Usar Hypervisor en lugar de JIT. Mejora enormemente el rendimiento cuando está disponible, pero puede ser inestable en su estado actual.", "DRamTooltip": "Expande la memoria DRAM del sistema emulado de 4GiB a 6GiB.\n\nUtilizar solo con packs de texturas HD o mods de resolución 4K. NO mejora el rendimiento.\n\nDesactívalo si no sabes qué hacer.", "IgnoreMissingServicesTooltip": "Hack para ignorar servicios no implementados del Horizon OS. Esto puede ayudar a sobrepasar crasheos cuando inicies ciertos juegos.\n\nDesactívalo si no sabes qué hacer.", - "GraphicsBackendThreadingTooltip": "Ejecuta los comandos del motor gráfico en un segundo hilo. Acelera la compilación de sombreadores, reduce los tirones, y mejora el rendimiento en controladores gráficos que no realicen su propio multihilado. Rendimiento máximo ligeramente superior en controladores gráficos que soporten multihilado.\n\nSelecciona \"Auto\" si no sabes qué hacer.", - "GalThreadingTooltip": "Ejecuta los comandos del motor gráfico en un segundo hilo. Acelera la compilación de sombreadores, reduce los tirones, y mejora el rendimiento en controladores gráficos que no realicen su propio multihilado. Rendimiento máximo ligeramente superior en controladores gráficos que soporten multihilado.\n\nSelecciona \"Auto\" si no sabes qué hacer.", + "GraphicsBackendThreadingTooltip": "Ejecuta los comandos del motor gráfico en un segundo hilo. Acelera la compilación de sombreadores, reduce los tirones, y mejora el rendimiento en controladores gráficos que no realicen su propio procesamiento con múltiples hilos. Rendimiento ligeramente superior en controladores gráficos que soporten múltiples hilos.\n\nSelecciona \"Auto\" si no sabes qué hacer.", + "GalThreadingTooltip": "Ejecuta los comandos del motor gráfico en un segundo hilo. Acelera la compilación de sombreadores, reduce los tirones, y mejora el rendimiento en controladores gráficos que no realicen su propio procesamiento con múltiples hilos. Rendimiento ligeramente superior en controladores gráficos que soporten múltiples hilos.\n\nSelecciona \"Auto\" si no sabes qué hacer.", "ShaderCacheToggleTooltip": "Guarda una caché de sombreadores en disco, la cual reduce los tirones a medida que vas jugando.\n\nActívalo si no sabes qué hacer.", - "ResolutionScaleTooltip": "Escala de resolución aplicada a objetivos aplicables en el renderizado", + "ResolutionScaleTooltip": "Multiplies the game's rendering resolution.\n\nA few games may not work with this and look pixelated even when the resolution is increased; for those games, you may need to find mods that remove anti-aliasing or that increase their internal rendering resolution. For using the latter, you'll likely want to select Native.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nKeep in mind 4x is overkill for virtually any setup.", "ResolutionScaleEntryTooltip": "Escalado de resolución de coma flotante, como por ejemplo 1,5. Los valores no íntegros pueden causar errores gráficos o crashes.", - "AnisotropyTooltip": "Nivel de filtrado anisotrópico (selecciona Auto para utilizar el valor solicitado por el juego)", - "AspectRatioTooltip": "Relación de aspecto aplicada a la ventana de renderizado.", + "AnisotropyTooltip": "Level of Anisotropic Filtering. Set to Auto to use the value requested by the game.", + "AspectRatioTooltip": "Aspect Ratio applied to the renderer window.\n\nOnly change this if you're using an aspect ratio mod for your game, otherwise the graphics will be stretched.\n\nLeave on 16:9 if unsure.", "ShaderDumpPathTooltip": "Directorio en el cual se volcarán los sombreadores de los gráficos", "FileLogTooltip": "Guarda los registros de la consola en archivos en disco. No afectan al rendimiento.", "StubLogTooltip": "Escribe mensajes de Stub en la consola. No afectan al rendimiento.", @@ -504,6 +615,8 @@ "EnableInternetAccessTooltip": "Permite a la aplicación emulada conectarse a Internet.\n\nLos juegos que tengan modo LAN podrán conectarse entre sí habilitando esta opción y estando conectados al mismo módem. Asimismo, esto permite conexiones con consolas reales.\n\nNO permite conectar con los servidores de Nintendo Online. Puede causar que ciertos juegos crasheen al intentar conectarse a sus servidores.\n\nDesactívalo si no estás seguro.", "GameListContextMenuManageCheatToolTip": "Activa o desactiva los cheats", "GameListContextMenuManageCheat": "Administrar cheats", + "GameListContextMenuManageModToolTip": "Gestionar Mods", + "GameListContextMenuManageMod": "Gestionar Mods", "ControllerSettingsStickRange": "Alcance:", "DialogStopEmulationTitle": "Ryujinx - Detener emulación", "DialogStopEmulationMessage": "¿Seguro que quieres detener la emulación actual?", @@ -515,13 +628,11 @@ "SettingsTabCpuMemory": "Memoria de CPU", "DialogUpdaterFlatpakNotSupportedMessage": "Por favor, actualiza Ryujinx a través de FlatHub.", "UpdaterDisabledWarningTitle": "¡Actualizador deshabilitado!", - "GameListContextMenuOpenSdModsDirectory": "Abrir carpeta de mods Atmosphere", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Abre la carpeta alternativa de mods en la que puedes insertar mods de Atmosphere. Útil para mods que vengan organizados para uso en consola.", "ControllerSettingsRotate90": "Rotar 90° en el sentido de las agujas del reloj", "IconSize": "Tamaño de iconos", "IconSizeTooltip": "Cambia el tamaño de los iconos de juegos", "MenuBarOptionsShowConsole": "Mostrar consola", - "ShaderCachePurgeError": "Error al eliminar la caché en {0}: {1}", + "ShaderCachePurgeError": "Error al eliminar la caché de sombreadores en {0}: {1}", "UserErrorNoKeys": "No se encontraron keys", "UserErrorNoFirmware": "No se encontró firmware", "UserErrorFirmwareParsingFailed": "Error al analizar el firmware", @@ -544,12 +655,13 @@ "SwkbdMinCharacters": "Debe tener al menos {0} caracteres", "SwkbdMinRangeCharacters": "Debe tener {0}-{1} caracteres", "SoftwareKeyboard": "Teclado de software", - "SoftwareKeyboardModeNumbersOnly": "Solo deben ser números", + "SoftwareKeyboardModeNumeric": "Debe ser sólo 0-9 o '.'", "SoftwareKeyboardModeAlphabet": "Solo deben ser caracteres no CJK", "SoftwareKeyboardModeASCII": "Solo deben ser texto ASCII", - "DialogControllerAppletMessagePlayerRange": "La aplicación require {0} jugador(es) con:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}Por favor abre las opciones y reconfigura los dispositivos de entrada o presiona 'Cerrar'.", - "DialogControllerAppletMessage": "La aplicación require exactamente {0} jugador(es) con:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}Por favor abre las opciones y reconfigura los dispositivos de entrada o presiona 'Cerrar'.", - "DialogControllerAppletDockModeSet": "Modo dock/TV activo. El control portátil también es inválido.\n\n", + "ControllerAppletControllers": "Controladores Compatibles:", + "ControllerAppletPlayers": "Jugadores:", + "ControllerAppletDescription": "Tu configuración actual no es válida. Abre la configuración y vuelve a configurar tus entradas", + "ControllerAppletDocked": "Modo acoplado activado. El modo portátil debería estar desactivado.", "UpdaterRenaming": "Renombrando archivos viejos...", "UpdaterRenameFailed": "El actualizador no pudo renombrar el archivo: {0}", "UpdaterAddingFiles": "Añadiendo nuevos archivos...", @@ -587,17 +699,21 @@ "Writable": "Escribible", "SelectDlcDialogTitle": "Selecciona archivo(s) de DLC", "SelectUpdateDialogTitle": "Selecciona archivo(s) de actualización", + "SelectModDialogTitle": "Seleccionar un directorio de Mods", "UserProfileWindowTitle": "Administrar perfiles de usuario", "CheatWindowTitle": "Administrar cheats", "DlcWindowTitle": "Administrar contenido descargable", + "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "Administrar actualizaciones", "CheatWindowHeading": "Cheats disponibles para {0} [{1}]", "BuildId": "Id de compilación:", "DlcWindowHeading": "Contenido descargable disponible para {0} [{1}]", + "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Editar selección", "Cancel": "Cancelar", "Save": "Guardar", "Discard": "Descartar", + "Paused": "Pausado", "UserProfilesSetProfileImage": "Elegir Imagen de Perfil ", "UserProfileEmptyNameError": "El nombre es obligatorio", "UserProfileNoImageError": "Debe establecerse la imagen de perfil", @@ -607,9 +723,9 @@ "UserProfilesName": "Nombre:", "UserProfilesUserId": "Id de Usuario:", "SettingsTabGraphicsBackend": "Fondo de gráficos", - "SettingsTabGraphicsBackendTooltip": "Back-end de los gráficos a utilizar", + "SettingsTabGraphicsBackendTooltip": "Select the graphics backend that will be used in the emulator.\n\nVulkan is overall better for all modern graphics cards, as long as their drivers are up to date. Vulkan also features faster shader compilation (less stuttering) on all GPU vendors.\n\nOpenGL may achieve better results on old Nvidia GPUs, on old AMD GPUs on Linux, or on GPUs with lower VRAM, though shader compilation stutters will be greater.\n\nSet to Vulkan if unsure. Set to OpenGL if your GPU does not support Vulkan even with the latest graphics drivers.", "SettingsEnableTextureRecompression": "Activar recompresión de texturas", - "SettingsEnableTextureRecompressionTooltip": "Comprime ciertas texturas para reducir el uso de la VRAM.\n\nRecomendado para GPUs que tienen menos de 4 GB de VRAM.\n\nMantén esta opción desactivada si no estás seguro.", + "SettingsEnableTextureRecompressionTooltip": "Compresses ASTC textures in order to reduce VRAM usage.\n\nGames using this texture format include Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder and The Legend of Zelda: Tears of the Kingdom.\n\nGraphics cards with 4GiB VRAM or less will likely crash at some point while running these games.\n\nEnable only if you're running out of VRAM on the aforementioned games. Leave OFF if unsure.", "SettingsTabGraphicsPreferredGpu": "GPU preferida", "SettingsTabGraphicsPreferredGpuTooltip": "Selecciona la tarjeta gráfica que se utilizará con los back-end de gráficos Vulkan.\n\nNo afecta la GPU que utilizará OpenGL.\n\nFije a la GPU marcada como \"dGUP\" ante dudas. Si no hay una, no haga modificaciones.", "SettingsAppRequiredRestartMessage": "Reinicio de Ryujinx requerido.", @@ -635,12 +751,15 @@ "Recover": "Recuperar", "UserProfilesRecoverHeading": "Datos de guardado fueron encontrados para las siguientes cuentas", "UserProfilesRecoverEmptyList": "No hay perfiles a recuperar", - "GraphicsAATooltip": "Aplica el suavizado de bordes al procesamiento del juego", + "GraphicsAATooltip": "Applies anti-aliasing to the game render.\n\nFXAA will blur most of the image, while SMAA will attempt to find jagged edges and smooth them out.\n\nNot recommended to use in conjunction with the FSR scaling filter.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on NONE if unsure.", "GraphicsAALabel": "Suavizado de bordes:", "GraphicsScalingFilterLabel": "Filtro de escalado:", - "GraphicsScalingFilterTooltip": "Activa el escalado de búfer de fotogramas", + "GraphicsScalingFilterTooltip": "Elija el filtro de escala que se aplicará al utilizar la escala de resolución.\n\nBilinear funciona bien para juegos 3D y es una opción predeterminada segura.\n\nSe recomienda el bilinear para juegos de pixel art.\n\nFSR 1.0 es simplemente un filtro de afilado, no se recomienda su uso con FXAA o SMAA.\n\nEsta opción se puede cambiar mientras se ejecuta un juego haciendo clic en \"Aplicar\" a continuación; simplemente puedes mover la ventana de configuración a un lado y experimentar hasta que encuentres tu estilo preferido para un juego.\n\nDéjelo en BILINEAR si no está seguro.", + "GraphicsScalingFilterBilinear": "Bilinear\n", + "GraphicsScalingFilterNearest": "Cercano", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "Nivel", - "GraphicsScalingFilterLevelTooltip": "Establecer nivel del filtro de escalado", + "GraphicsScalingFilterLevelTooltip": "Ajuste el nivel de nitidez FSR 1.0. Mayor es más nítido.", "SmaaLow": "SMAA Bajo", "SmaaMedium": "SMAA Medio", "SmaaHigh": "SMAA Alto", @@ -648,9 +767,14 @@ "UserEditorTitle": "Editar usuario", "UserEditorTitleCreate": "Crear Usuario", "SettingsTabNetworkInterface": "Interfaz de Red", - "NetworkInterfaceTooltip": "Interfaz de red usada para las características LAN", + "NetworkInterfaceTooltip": "Interfaz de red usada para características LAN/LDN.\n\njunto con una VPN o XLink Kai y un juego con soporte LAN, puede usarse para suplantar una conexión de la misma red a través de Internet.\n\nDeje en DEFAULT si no está seguro.", "NetworkInterfaceDefault": "Predeterminado", "PackagingShaders": "Empaquetando sombreadores", "AboutChangelogButton": "Ver registro de cambios en GitHub", - "AboutChangelogButtonTooltipMessage": "Haga clic para abrir el registro de cambios para esta versión en su navegador predeterminado." -} \ No newline at end of file + "AboutChangelogButtonTooltipMessage": "Haga clic para abrir el registro de cambios para esta versión en su navegador predeterminado.", + "SettingsTabNetworkMultiplayer": "Multijugador", + "MultiplayerMode": "Modo:", + "MultiplayerModeTooltip": "Cambiar modo LDN multijugador.\n\nLdnMitm modificará la funcionalidad local de juego inalámbrico para funcionar como si fuera LAN, permitiendo locales conexiones de la misma red con otras instancias de Ryujinx y consolas hackeadas de Nintendo Switch que tienen instalado el módulo ldn_mitm.\n\nMultijugador requiere que todos los jugadores estén en la misma versión del juego (por ejemplo, Super Smash Bros. Ultimate v13.0.1 no se puede conectar a v13.0.0).\n\nDejar DESACTIVADO si no está seguro.", + "MultiplayerModeDisabled": "Deshabilitar", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/fr_FR.json b/src/Ryujinx/Assets/Locales/fr_FR.json similarity index 73% rename from src/Ryujinx.Ava/Assets/Locales/fr_FR.json rename to src/Ryujinx/Assets/Locales/fr_FR.json index 5bab6f7b2..99a060650 100644 --- a/src/Ryujinx.Ava/Assets/Locales/fr_FR.json +++ b/src/Ryujinx/Assets/Locales/fr_FR.json @@ -1,7 +1,7 @@ { "Language": "Français", - "MenuBarFileOpenApplet": "Ouvrir Applet", - "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Ouvrir l'Éditeur Applet Mii en mode autonome", + "MenuBarFileOpenApplet": "Ouvrir un applet", + "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Ouvrir l'Applet Mii Editor en mode Standalone", "SettingsTabInputDirectMouseAccess": "Accès direct à la souris", "SettingsTabSystemMemoryManagerMode": "Mode de gestion de la mémoire :", "SettingsTabSystemMemoryManagerModeSoftware": "Logiciel", @@ -14,9 +14,9 @@ "MenuBarFileOpenEmuFolder": "Ouvrir le dossier Ryujinx", "MenuBarFileOpenLogsFolder": "Ouvrir le dossier des journaux", "MenuBarFileExit": "_Quitter", - "MenuBarOptions": "Options", + "MenuBarOptions": "_Options", "MenuBarOptionsToggleFullscreen": "Basculer en plein écran", - "MenuBarOptionsStartGamesInFullscreen": "Démarrer jeux en plein écran", + "MenuBarOptionsStartGamesInFullscreen": "Démarrer le jeu en plein écran", "MenuBarOptionsStopEmulation": "Arrêter l'émulation", "MenuBarOptionsSettings": "_Paramètres", "MenuBarOptionsManageUserProfiles": "_Gérer les profils d'utilisateurs", @@ -30,9 +30,13 @@ "MenuBarToolsManageFileTypes": "Gérer les types de fichiers", "MenuBarToolsInstallFileTypes": "Installer les types de fichiers", "MenuBarToolsUninstallFileTypes": "Désinstaller les types de fichiers", - "MenuBarHelp": "Aide", + "MenuBarView": "_View", + "MenuBarViewWindow": "Window Size", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Aide", "MenuBarHelpCheckForUpdates": "Vérifier les mises à jour", - "MenuBarHelpAbout": "Á propos", + "MenuBarHelpAbout": "À propos", "MenuSearch": "Rechercher...", "GameListHeaderFavorite": "Favoris", "GameListHeaderIcon": "Icône", @@ -40,8 +44,8 @@ "GameListHeaderDeveloper": "Développeur", "GameListHeaderVersion": "Version", "GameListHeaderTimePlayed": "Temps de jeu", - "GameListHeaderLastPlayed": "jouer la dernière fois", - "GameListHeaderFileExtension": "Fichier externe", + "GameListHeaderLastPlayed": "Dernière partie jouée", + "GameListHeaderFileExtension": "Extension du Fichier", "GameListHeaderFileSize": "Taille du Fichier", "GameListHeaderPath": "Chemin", "GameListContextMenuOpenUserSaveDirectory": "Ouvrir le dossier de sauvegarde utilisateur", @@ -51,15 +55,13 @@ "GameListContextMenuOpenBcatSaveDirectory": "Ouvrir le dossier de sauvegarde BCAT", "GameListContextMenuOpenBcatSaveDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde BCAT du jeu", "GameListContextMenuManageTitleUpdates": "Gérer la mise à jour des titres", - "GameListContextMenuManageTitleUpdatesToolTip": "Ouvre la fenêtre de gestion de la mise à jour des titres", + "GameListContextMenuManageTitleUpdatesToolTip": "Ouvre la fenêtre de gestion des mises à jour du jeu", "GameListContextMenuManageDlc": "Gérer les DLC", "GameListContextMenuManageDlcToolTip": "Ouvre la fenêtre de gestion des DLC", - "GameListContextMenuOpenModsDirectory": "Ouvrir le dossier des Mods", - "GameListContextMenuOpenModsDirectoryToolTip": "Ouvre le dossier contenant les mods du jeu", "GameListContextMenuCacheManagement": "Gestion des caches", - "GameListContextMenuCacheManagementPurgePptc": "Purger le PPTC", - "GameListContextMenuCacheManagementPurgePptcToolTip": "Supprime le PPTC du jeu", - "GameListContextMenuCacheManagementPurgeShaderCache": "Purger le cache des Shaders", + "GameListContextMenuCacheManagementPurgePptc": "Reconstruction du PPTC", + "GameListContextMenuCacheManagementPurgePptcToolTip": "Effectuer une reconstruction du PPTC au prochain démarrage du jeu", + "GameListContextMenuCacheManagementPurgeShaderCache": "Purger le cache des shaders", "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Supprime le cache des shaders du jeu", "GameListContextMenuCacheManagementOpenPptcDirectory": "Ouvrir le dossier du PPTC", "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Ouvre le dossier contenant le PPTC du jeu", @@ -72,28 +74,36 @@ "GameListContextMenuExtractDataRomFSToolTip": "Extrait la section RomFS du jeu (mise à jour incluse)", "GameListContextMenuExtractDataLogo": "Logo", "GameListContextMenuExtractDataLogoToolTip": "Extrait la section Logo du jeu (mise à jour incluse)", + "GameListContextMenuCreateShortcut": "Créer un raccourci d'application", + "GameListContextMenuCreateShortcutToolTip": "Créer un raccourci sur le bureau qui lance l'application sélectionnée", + "GameListContextMenuCreateShortcutToolTipMacOS": "Créer un raccourci dans le dossier Applications de macOS qui lance l'application sélectionnée", + "GameListContextMenuOpenModsDirectory": "Ouvrir le dossier des mods", + "GameListContextMenuOpenModsDirectoryToolTip": "Ouvre le dossier contenant les mods de l'application", + "GameListContextMenuOpenSdModsDirectory": "Ouvrir le dossier des mods Atmosphère", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Ouvre le dossier alternatif de la carte SD Atmosphère qui contient les mods de l'application. Utile pour les mods conçus pour du matériel réel.", "StatusBarGamesLoaded": "{0}/{1} Jeux chargés", "StatusBarSystemVersion": "Version du Firmware: {0}", - "LinuxVmMaxMapCountDialogTitle": "Limite basse pour les mappages de mémoire détectés", + "LinuxVmMaxMapCountDialogTitle": "Limite basse pour les mappings mémoire détectée", "LinuxVmMaxMapCountDialogTextPrimary": "Voulez-vous augmenter la valeur de vm.max_map_count à {0}", - "LinuxVmMaxMapCountDialogTextSecondary": "Certains jeux peuvent essayer de créer plus de mappages de mémoire que ce qui est actuellement autorisé. Ryujinx plantera dès que cette limite sera dépassée.", + "LinuxVmMaxMapCountDialogTextSecondary": "Certains jeux peuvent essayer de créer plus de mappings mémoire que ce qui est actuellement autorisé. Ryujinx plantera dès que cette limite sera dépassée.", "LinuxVmMaxMapCountDialogButtonUntilRestart": "Oui, jusqu'au prochain redémarrage", "LinuxVmMaxMapCountDialogButtonPersistent": "Oui, en permanence", "LinuxVmMaxMapCountWarningTextPrimary": "La quantité maximale de mappings mémoire est inférieure à la valeur recommandée.", - "LinuxVmMaxMapCountWarningTextSecondary": "La valeur actuelle de vm.max_map_count ({0}) est inférieure à {1}. Certains jeux peuvent essayer de créer plus de mappings mémoire que ceux actuellement autorisés. Ryujinx s'écrasera dès que cette limite sera dépassée.\n\nVous pouvez soit augmenter manuellement la limite, soit installer pkexec, ce qui permet à Ryujinx de l'aider.", + "LinuxVmMaxMapCountWarningTextSecondary": "La valeur actuelle de vm.max_map_count ({0}) est inférieure à {1}. Certains jeux peuvent essayer de créer plus de mappings mémoire que ceux actuellement autorisés. Ryujinx plantera dès que cette limite sera dépassée.\n\nVous pouvez soit augmenter manuellement la limite, soit installer pkexec, ce qui permet à Ryujinx de l'aider.", "Settings": "Paramètres", "SettingsTabGeneral": "Interface Utilisateur", "SettingsTabGeneralGeneral": "Général", "SettingsTabGeneralEnableDiscordRichPresence": "Activer Discord Rich Presence", "SettingsTabGeneralCheckUpdatesOnLaunch": "Vérifier les mises à jour au démarrage", "SettingsTabGeneralShowConfirmExitDialog": "Afficher le message de \"Confirmation de sortie\"", + "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", "SettingsTabGeneralHideCursor": "Masquer le Curseur :", "SettingsTabGeneralHideCursorNever": "Jamais", "SettingsTabGeneralHideCursorOnIdle": "Masquer le curseur si inactif", "SettingsTabGeneralHideCursorAlways": "Toujours", - "SettingsTabGeneralGameDirectories": "Dossiers de Jeux", + "SettingsTabGeneralGameDirectories": "Dossiers des jeux", "SettingsTabGeneralAdd": "Ajouter", - "SettingsTabGeneralRemove": "Supprimer", + "SettingsTabGeneralRemove": "Retirer", "SettingsTabSystem": "Système", "SettingsTabSystemCore": "Cœur", "SettingsTabSystemSystemRegion": "Région du système:", @@ -124,19 +134,19 @@ "SettingsTabSystemSystemLanguageTraditionalChinese": "Chinois traditionnel", "SettingsTabSystemSystemTimeZone": "Fuseau horaire du système :", "SettingsTabSystemSystemTime": "Heure du système:", - "SettingsTabSystemEnableVsync": "Activer le VSync", + "SettingsTabSystemEnableVsync": "Synchronisation verticale (VSync)", "SettingsTabSystemEnablePptc": "Activer le PPTC (Profiled Persistent Translation Cache)", "SettingsTabSystemEnableFsIntegrityChecks": "Activer la vérification de l'intégrité du système de fichiers", - "SettingsTabSystemAudioBackend": "Back-end audio", + "SettingsTabSystemAudioBackend": "Bibliothèque Audio :", "SettingsTabSystemAudioBackendDummy": "Factice", "SettingsTabSystemAudioBackendOpenAL": "OpenAL", "SettingsTabSystemAudioBackendSoundIO": "SoundIO", "SettingsTabSystemAudioBackendSDL2": "SDL2", "SettingsTabSystemHacks": "Hacks", - "SettingsTabSystemHacksNote": " (Cela peut causer des instabilités)", + "SettingsTabSystemHacksNote": "Cela peut causer des instabilités", "SettingsTabSystemExpandDramSize": "Utiliser disposition alternative de la mémoire (développeur)", "SettingsTabSystemIgnoreMissingServices": "Ignorer les services manquants", - "SettingsTabGraphics": "Graphique", + "SettingsTabGraphics": "Graphismes", "SettingsTabGraphicsAPI": "API Graphique", "SettingsTabGraphicsEnableShaderCache": "Activer le cache des shaders", "SettingsTabGraphicsAnisotropicFiltering": "Filtrage anisotrope:", @@ -150,8 +160,8 @@ "SettingsTabGraphicsResolutionScaleNative": "Natif (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "x2 (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "x3 (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "x4 (2880p/4320p)", - "SettingsTabGraphicsAspectRatio": "Format :", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (Non recommandé)", + "SettingsTabGraphicsAspectRatio": "Format d'affichage :", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", "SettingsTabGraphicsAspectRatio16x10": "16:10", @@ -159,7 +169,7 @@ "SettingsTabGraphicsAspectRatio32x9": "32:9", "SettingsTabGraphicsAspectRatioStretch": "Écran étiré", "SettingsTabGraphicsDeveloperOptions": "Options développeur", - "SettingsTabGraphicsShaderDumpPath": "Chemin du dossier de dump des shaders:", + "SettingsTabGraphicsShaderDumpPath": "Chemin du dossier de copie des shaders:", "SettingsTabLogging": "Journaux", "SettingsTabLoggingLogging": "Journaux", "SettingsTabLoggingEnableLoggingToFile": "Activer la sauvegarde des journaux vers un fichier", @@ -169,9 +179,9 @@ "SettingsTabLoggingEnableErrorLogs": "Activer les journaux d'erreurs", "SettingsTabLoggingEnableTraceLogs": "Activer journaux d'erreurs Trace", "SettingsTabLoggingEnableGuestLogs": "Activer les journaux du programme simulé", - "SettingsTabLoggingEnableFsAccessLogs": "Activer les journaux des accès au système de fichiers", - "SettingsTabLoggingFsGlobalAccessLogMode": "Niveau des journaux des accès au système de fichiers:", - "SettingsTabLoggingDeveloperOptions": "Options développeur (ATTENTION: Cela peut réduire les performances)", + "SettingsTabLoggingEnableFsAccessLogs": "Activer les journaux d'accès au système de fichiers", + "SettingsTabLoggingFsGlobalAccessLogMode": "Niveau des journaux d'accès au système de fichiers:", + "SettingsTabLoggingDeveloperOptions": "Options développeur", "SettingsTabLoggingDeveloperOptionsNote": "ATTENTION : Réduira les performances", "SettingsTabLoggingGraphicsBackendLogLevel": "Niveau du journal du backend graphique :", "SettingsTabLoggingGraphicsBackendLogLevelNone": "Aucun", @@ -200,7 +210,7 @@ "ControllerSettingsInputDevice": "Périphériques", "ControllerSettingsRefresh": "Actualiser", "ControllerSettingsDeviceDisabled": "Désactivé", - "ControllerSettingsControllerType": "Type de Controleur", + "ControllerSettingsControllerType": "Type de contrôleur", "ControllerSettingsControllerTypeHandheld": "Portable", "ControllerSettingsControllerTypeProController": "Pro Controller", "ControllerSettingsControllerTypeJoyConPair": "JoyCon Joints", @@ -218,7 +228,7 @@ "ControllerSettingsButtonY": "Y", "ControllerSettingsButtonPlus": "+", "ControllerSettingsButtonMinus": "-", - "ControllerSettingsDPad": "Croix Directionnelle", + "ControllerSettingsDPad": "Croix directionnelle", "ControllerSettingsDPadUp": "Haut", "ControllerSettingsDPadDown": "Bas", "ControllerSettingsDPadLeft": "Gauche", @@ -228,7 +238,7 @@ "ControllerSettingsStickDown": "Bas", "ControllerSettingsStickLeft": "Gauche", "ControllerSettingsStickRight": "Droite", - "ControllerSettingsStickStick": "Stick", + "ControllerSettingsStickStick": "Joystick", "ControllerSettingsStickInvertXAxis": "Inverser l'axe X", "ControllerSettingsStickInvertYAxis": "Inverser l'axe Y", "ControllerSettingsStickDeadzone": "Zone morte :", @@ -256,16 +266,117 @@ "ControllerSettingsMotionControllerSlot": "Contrôleur ID:", "ControllerSettingsMotionMirrorInput": "Inverser les contrôles", "ControllerSettingsMotionRightJoyConSlot": "JoyCon Droit ID:", - "ControllerSettingsMotionServerHost": "Addresse du Server:", + "ControllerSettingsMotionServerHost": "Serveur d'hébergement :", "ControllerSettingsMotionGyroSensitivity": "Sensibilitée du gyroscope:", "ControllerSettingsMotionGyroDeadzone": "Zone morte du gyroscope:", "ControllerSettingsSave": "Enregistrer", "ControllerSettingsClose": "Fermer", - "UserProfilesSelectedUserProfile": "Choisir un profil utilisateur:", + "KeyUnknown": "Unknown", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", + "UserProfilesSelectedUserProfile": "Profil utilisateur sélectionné :", "UserProfilesSaveProfileName": "Enregistrer le nom du profil", "UserProfilesChangeProfileImage": "Changer l'image du profil", - "UserProfilesAvailableUserProfiles": "Profils utilisateurs disponible:", - "UserProfilesAddNewProfile": "Ajouter un nouveau profil", + "UserProfilesAvailableUserProfiles": "Profils utilisateurs disponibles:", + "UserProfilesAddNewProfile": "Créer un profil", "UserProfilesDelete": "Supprimer", "UserProfilesClose": "Fermer", "ProfileNameSelectionWatermark": "Choisir un pseudo", @@ -280,25 +391,21 @@ "InputDialogAddNewProfileTitle": "Choisir un nom de profil", "InputDialogAddNewProfileHeader": "Merci d'entrer un nom de profil", "InputDialogAddNewProfileSubtext": "(Longueur max.: {0})", - "AvatarChoose": "Choisir", + "AvatarChoose": "Choisir un avatar", "AvatarSetBackgroundColor": "Choisir une couleur de fond", "AvatarClose": "Fermer", "ControllerSettingsLoadProfileToolTip": "Charger un profil", "ControllerSettingsAddProfileToolTip": "Ajouter un profil", "ControllerSettingsRemoveProfileToolTip": "Supprimer un profil", "ControllerSettingsSaveProfileToolTip": "Enregistrer un profil", - "MenuBarFileToolsTakeScreenshot": "Prendre une Capture d'Écran", + "MenuBarFileToolsTakeScreenshot": "Prendre une capture d'écran", "MenuBarFileToolsHideUi": "Masquer l'interface utilisateur", "GameListContextMenuRunApplication": "Démarrer l'application", "GameListContextMenuToggleFavorite": "Ajouter/Retirer des favoris", "GameListContextMenuToggleFavoriteToolTip": "Activer/désactiver le statut favori du jeu", - "SettingsTabGeneralTheme": "Thème", - "SettingsTabGeneralThemeCustomTheme": "Chemin du thème personnalisé", - "SettingsTabGeneralThemeBaseStyle": "Style par défaut", - "SettingsTabGeneralThemeBaseStyleDark": "Sombre", - "SettingsTabGeneralThemeBaseStyleLight": "Lumière", - "SettingsTabGeneralThemeEnableCustomTheme": "Activer un Thème Personnalisé", - "ButtonBrowse": "Parcourir", + "SettingsTabGeneralTheme": "Thème :", + "SettingsTabGeneralThemeDark": "Sombre", + "SettingsTabGeneralThemeLight": "Clair", "ControllerSettingsConfigureGeneral": "Configurer", "ControllerSettingsRumble": "Vibreur", "ControllerSettingsRumbleStrongMultiplier": "Multiplicateur de vibrations fortes", @@ -312,7 +419,7 @@ "DialogExitTitle": "Ryujinx - Quitter", "DialogErrorMessage": "Ryujinx a rencontré une erreur", "DialogExitMessage": "Êtes-vous sûr de vouloir fermer Ryujinx ?", - "DialogExitSubMessage": "Toute progression non sauvegardée sera perdue.", + "DialogExitSubMessage": "Toutes les données non enregistrées seront perdues !", "DialogMessageCreateSaveErrorMessage": "Une erreur s'est produite lors de la création de la sauvegarde spécifiée : {0}", "DialogMessageFindSaveErrorMessage": "Une erreur s'est produite lors de la recherche de la sauvegarde spécifiée : {0}", "FolderDialogExtractTitle": "Choisissez le dossier dans lequel extraire", @@ -322,8 +429,8 @@ "DialogNcaExtractionCheckLogErrorMessage": "Échec de l'extraction. Lisez le fichier journal pour plus d'informations.", "DialogNcaExtractionSuccessMessage": "Extraction terminée avec succès.", "DialogUpdaterConvertFailedMessage": "Échec de la conversion de la version actuelle de Ryujinx.", - "DialogUpdaterCancelUpdateMessage": "Annuler la mise à jour!", - "DialogUpdaterAlreadyOnLatestVersionMessage": "Vous utilisez déjà la version la plus mise à jour de Ryujinx!", + "DialogUpdaterCancelUpdateMessage": "Annuler la mise à jour !", + "DialogUpdaterAlreadyOnLatestVersionMessage": "Vous utilisez déjà la version la plus récente de Ryujinx !", "DialogUpdaterFailedToGetVersionMessage": "Une erreur s'est produite lors de la tentative d'obtention des informations de publication de la version GitHub. Cela peut survenir lorsqu'une nouvelle version est en cours de compilation par GitHub Actions. Réessayez dans quelques minutes.", "DialogUpdaterConvertFailedGithubMessage": "Impossible de convertir la version reçue de Ryujinx depuis Github Release.", "DialogUpdaterDownloadingMessage": "Téléchargement de la mise à jour...", @@ -332,17 +439,15 @@ "DialogUpdaterAddingFilesMessage": "Ajout d'une nouvelle mise à jour...", "DialogUpdaterCompleteMessage": "Mise à jour terminée !", "DialogUpdaterRestartMessage": "Voulez-vous redémarrer Ryujinx maintenant ?", - "DialogUpdaterArchNotSupportedMessage": "Vous n'utilisez pas d'architecture système prise en charge !", - "DialogUpdaterArchNotSupportedSubMessage": "(Seuls les systèmes x64 sont pris en charge !)", "DialogUpdaterNoInternetMessage": "Vous n'êtes pas connecté à Internet !", - "DialogUpdaterNoInternetSubMessage": "Veuillez vérifier que vous avez une connexion Internet fonctionnelle!", - "DialogUpdaterDirtyBuildMessage": "Vous ne pouvez pas mettre à jour une version Dirty de Ryujinx!", + "DialogUpdaterNoInternetSubMessage": "Veuillez vérifier que vous disposez d'une connexion Internet fonctionnelle !", + "DialogUpdaterDirtyBuildMessage": "Vous ne pouvez pas mettre à jour une version Dirty de Ryujinx !", "DialogUpdaterDirtyBuildSubMessage": "Veuillez télécharger Ryujinx sur https://ryujinx.org/ si vous recherchez une version prise en charge.", - "DialogRestartRequiredMessage": "Redémarrage Requis", + "DialogRestartRequiredMessage": "Redémarrage requis", "DialogThemeRestartMessage": "Le thème a été enregistré. Un redémarrage est requis pour appliquer le thème.", "DialogThemeRestartSubMessage": "Voulez-vous redémarrer", "DialogFirmwareInstallEmbeddedMessage": "Voulez-vous installer le firmware intégré dans ce jeu ? (Firmware {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "Aucun firmware installé n'a été trouvé mais Ryujinx a pu installer le firmware {0} à partir du jeu fourni.\\nL'émulateur va maintenant démarrer.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "Aucun firmware installé n'a été trouvé mais Ryujinx a pu installer le firmware {0} à partir du jeu fourni.\nL'émulateur va maintenant démarrer.", "DialogFirmwareNoFirmwareInstalledMessage": "Aucun Firmware installé", "DialogFirmwareInstalledMessage": "Le firmware {0} a été installé", "DialogInstallFileTypesSuccessMessage": "Types de fichiers installés avec succès!", @@ -384,8 +489,11 @@ "DialogUserProfileUnsavedChangesMessage": "Vous avez effectué des modifications sur ce profil d'utilisateur qui n'ont pas été enregistrées.", "DialogUserProfileUnsavedChangesSubMessage": "Voulez-vous annuler les modifications ?", "DialogControllerSettingsModifiedConfirmMessage": "Les paramètres actuels du contrôleur ont été mis à jour.", - "DialogControllerSettingsModifiedConfirmSubMessage": "Voulez-vous sauvegarder?", - "DialogLoadNcaErrorMessage": "{0}. Fichier erroné : {1}", + "DialogControllerSettingsModifiedConfirmSubMessage": "Voulez-vous sauvegarder ?", + "DialogLoadFileErrorMessage": "{0}. Fichier erroné : {1}", + "DialogModAlreadyExistsMessage": "Le mod existe déjà", + "DialogModInvalidMessage": "Le répertoire spécifié ne contient pas de mod !", + "DialogModDeleteNoParentMessage": "Impossible de supprimer : impossible de trouver le répertoire parent pour le mod \"{0} \" !", "DialogDlcNoDlcErrorMessage": "Le fichier spécifié ne contient pas de DLC pour le titre sélectionné !", "DialogPerformanceCheckLoggingEnabledMessage": "Vous avez activé la journalisation des traces, conçue pour être utilisée uniquement par les développeurs.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Pour des performances optimales, il est recommandé de désactiver la journalisation des traces. Souhaitez-vous désactiver la journalisation des traces maintenant ?", @@ -396,6 +504,8 @@ "DialogUpdateAddUpdateErrorMessage": "Le fichier spécifié ne contient pas de mise à jour pour le titre sélectionné !", "DialogSettingsBackendThreadingWarningTitle": "Avertissement - Backend Threading ", "DialogSettingsBackendThreadingWarningMessage": "Ryujinx doit être redémarré après avoir changé cette option pour qu'elle s'applique complètement. Selon votre plate-forme, vous devrez peut-être désactiver manuellement le multithreading de votre pilote lorsque vous utilisez Ryujinx.", + "DialogModManagerDeletionWarningMessage": "Vous êtes sur le point de supprimer le mod : {0}\n\nÊtes-vous sûr de vouloir continuer ?", + "DialogModManagerDeletionAllWarningMessage": "Vous êtes sur le point de supprimer tous les mods pour ce titre.\n\nÊtes-vous sûr de vouloir continuer ?", "SettingsTabGraphicsFeaturesOptions": "Fonctionnalités", "SettingsTabGraphicsBackendMultithreading": "Interface graphique multithread", "CommonAuto": "Auto", @@ -413,7 +523,7 @@ "AboutGithubUrlTooltipMessage": "Cliquez pour ouvrir la page GitHub de Ryujinx dans votre navigateur par défaut.", "AboutDiscordUrlTooltipMessage": "Cliquez pour ouvrir une invitation au serveur Discord de Ryujinx dans votre navigateur par défaut.", "AboutTwitterUrlTooltipMessage": "Cliquez pour ouvrir la page Twitter de Ryujinx dans votre navigateur par défaut.", - "AboutRyujinxAboutTitle": "Á propos:", + "AboutRyujinxAboutTitle": "À propos :", "AboutRyujinxAboutContent": "Ryujinx est un émulateur pour la Nintendo Switch™.\nMerci de nous soutenir sur Patreon.\nObtenez toutes les dernières actualités sur notre Twitter ou notre Discord.\nLes développeurs intéressés à contribuer peuvent en savoir plus sur notre GitHub ou notre Discord.", "AboutRyujinxMaintainersTitle": "Maintenu par :", "AboutRyujinxMaintainersContentTooltipMessage": "Cliquez pour ouvrir la page Contributeurs dans votre navigateur par défaut.", @@ -428,9 +538,10 @@ "DlcManagerTableHeadingContainerPathLabel": "Chemin du conteneur", "DlcManagerTableHeadingFullPathLabel": "Chemin complet", "DlcManagerRemoveAllButton": "Tout supprimer", - "DlcManagerEnableAllButton": "Activer Tout", - "DlcManagerDisableAllButton": "Désactiver Tout", - "MenuBarOptionsChangeLanguage": "Changer la Langue", + "DlcManagerEnableAllButton": "Tout activer", + "DlcManagerDisableAllButton": "Tout désactiver", + "ModManagerDeleteAllButton": "Tout supprimer", + "MenuBarOptionsChangeLanguage": "Changer la langue", "MenuBarShowFileTypes": "Afficher les types de fichiers", "CommonSort": "Trier", "CommonShowNames": "Afficher les noms", @@ -442,18 +553,18 @@ "ToggleDiscordTooltip": "Choisissez d'afficher ou non Ryujinx sur votre activité « en cours de jeu » Discord", "AddGameDirBoxTooltip": "Entrez un répertoire de jeux à ajouter à la liste", "AddGameDirTooltip": "Ajouter un répertoire de jeux à la liste", - "RemoveGameDirTooltip": "Supprimer le dossier sélectionné", + "RemoveGameDirTooltip": "Supprimer le répertoire de jeu sélectionné", "CustomThemeCheckTooltip": "Utilisez un thème personnalisé Avalonia pour modifier l'apparence des menus de l'émulateur", "CustomThemePathTooltip": "Chemin vers le thème personnalisé de l'interface utilisateur", "CustomThemeBrowseTooltip": "Parcourir vers un thème personnalisé pour l'interface utilisateur", "DockModeToggleTooltip": "Le mode station d'accueil permet à la console émulée de se comporter comme une Nintendo Switch en mode station d'accueil, ce qui améliore la fidélité graphique dans la plupart des jeux. Inversement, la désactivation de cette option rendra la console émulée comme une console Nintendo Switch portable, réduisant la qualité graphique.\n\nConfigurer les controles du joueur 1 si vous prévoyez d'utiliser le mode station d'accueil; configurez les commandes portable si vous prévoyez d'utiliser le mode portable.\n\nLaissez ACTIVER si vous n'êtes pas sûr.", - "DirectKeyboardTooltip": "Prise en charge de l'accès direct au clavier (HID). Fournit aux jeux l'accès à votre clavier en tant que périphérique de saisie de texte.", - "DirectMouseTooltip": "Prise en charge de l'accès à la souris (HID). Permet aux jeux d'accéder a votre souris en tant que périphérique de pointage.", + "DirectKeyboardTooltip": "Prise en charge de l'accès direct au clavier (HID). Permet aux jeux d'accéder à votre clavier comme périphérique de saisie de texte.\n\nFonctionne uniquement avec les jeux prenant en charge nativement l'utilisation du clavier sur le matériel Switch.\n\nLaissez OFF si vous n'êtes pas sûr.", + "DirectMouseTooltip": "Prise en charge de l'accès direct à la souris (HID). Permet aux jeux d'accéder à votre souris en tant que dispositif de pointage.\n\nFonctionne uniquement avec les jeux qui prennent en charge nativement les contrôles de souris sur le matériel Switch, ce qui est rare.\n\nLorsqu'il est activé, la fonctionnalité de l'écran tactile peut ne pas fonctionner.\n\nLaissez sur OFF si vous n'êtes pas sûr.", "RegionTooltip": "Changer la région du système", "LanguageTooltip": "Changer la langue du système", "TimezoneTooltip": "Changer le fuseau horaire du système", "TimeTooltip": "Changer l'heure du système", - "VSyncToggleTooltip": "Synchronisation verticale de l'émulateur. Généralement un limiteur d'FPS pour la majorité des jeux, le désactiver peut accélérer les jeux pour rendre les écrans de chargement plus court, mais augemente le risque de crash lors des chargements.\n\nPeut être activer ou desactiver en jeu avec un raccourci de votre choix. Nous vous recommandons de le laisser.\n\nLaissez activer, si vous n'êtes pas sûr.", + "VSyncToggleTooltip": "La synchronisation verticale de la console émulée. Essentiellement un limiteur de trame pour la majorité des jeux ; le désactiver peut entraîner un fonctionnement plus rapide des jeux ou prolonger ou bloquer les écrans de chargement.\n\nPeut être activé ou désactivé en jeu avec un raccourci clavier de votre choix (F1 par défaut). Nous recommandons de le faire si vous envisagez de le désactiver.\n\nLaissez activé si vous n'êtes pas sûr.", "PptcToggleTooltip": "Sauvegarde les fonctions JIT afin qu'elles n'aient pas besoin d'être à chaque fois recompiler lorsque le jeu se charge.\n\nRéduit les lags et accélère considérablement le temps de chargement après le premier lancement d'un jeu.\n\nLaissez par défaut si vous n'êtes pas sûr.", "FsIntegrityToggleTooltip": "Vérifie si des fichiers sont corrompus lors du lancement d'un jeu, et si des fichiers corrompus sont détectés, affiche une erreur de hachage dans la console.\n\nN'a aucun impact sur les performances et est destiné à aider le dépannage.\n\nLaissez activer en cas d'incertitude.", "AudioBackendTooltip": "Modifie le backend utilisé pour donnée un rendu audio.\n\nSDL2 est préféré, tandis que OpenAL et SoundIO sont utilisés comme backend secondaire. Le backend Dummy (Factice) ne rends aucun son.\n\nLaissez sur SDL2 si vous n'êtes pas sûr.", @@ -467,10 +578,10 @@ "GraphicsBackendThreadingTooltip": "Exécute des commandes du backend graphiques sur un second thread.\n\nAccélère la compilation des shaders, réduit les crashs et les lags, améliore les performances sur les pilotes GPU sans support de multithreading. Légère augementation des performances sur les pilotes avec multithreading intégrer.\n\nRéglez sur Auto en cas d'incertitude.", "GalThreadingTooltip": "Exécute des commandes du backend graphiques sur un second thread.\n\nAccélère la compilation des shaders, réduit les crashs et les lags, améliore les performances sur les pilotes GPU sans support de multithreading. Légère augementation des performances sur les pilotes avec multithreading intégrer.\n\nRéglez sur Auto en cas d'incertitude.", "ShaderCacheToggleTooltip": "Enregistre un cache de shaders sur le disque dur, réduit le lag lors de multiples exécutions.\n\nLaissez Activer si vous n'êtes pas sûr.", - "ResolutionScaleTooltip": "Échelle de résolution appliquer au rendu du jeu", + "ResolutionScaleTooltip": "Multiplie la résolution de rendu du jeu.\n\nQuelques jeux peuvent ne pas fonctionner avec cette fonctionnalité et sembler pixelisés même lorsque la résolution est augmentée ; pour ces jeux, vous devrez peut-être trouver des mods qui suppriment l'anti-aliasing ou qui augmentent leur résolution de rendu interne. Pour utiliser cette dernière option, vous voudrez probablement sélectionner \"Native\".\n\nCette option peut être modifiée pendant qu'un jeu est en cours d'exécution en cliquant sur \"Appliquer\" ci-dessous ; vous pouvez simplement déplacer la fenêtre des paramètres de côté et expérimenter jusqu'à ce que vous trouviez l'apparence souhaitée pour un jeu.\n\nGardez à l'esprit que 4x est excessif pour pratiquement n'importe quelle configuration.", "ResolutionScaleEntryTooltip": "Échelle de résolution à virgule flottante, telle que : 1.5. Les échelles non intégrales sont plus susceptibles de causer des problèmes ou des crashs.", - "AnisotropyTooltip": "Niveau de Filtrage Anisotropique (mettre sur Auto pour utiliser la valeur demandée par le jeu)", - "AspectRatioTooltip": "Ratio d'aspect appliqué à la fenêtre de rendu", + "AnisotropyTooltip": "Niveau de filtrage anisotrope. Réglez sur Auto pour utiliser la valeur demandée par le jeu.", + "AspectRatioTooltip": "Rapport d'aspect appliqué à la fenêtre du moteur de rendu.\n\nChangez cela uniquement si vous utilisez un mod de rapport d'aspect pour votre jeu, sinon les graphismes seront étirés.\n\nLaissez sur 16:9 si vous n'êtes pas sûr.", "ShaderDumpPathTooltip": "Chemin de copie des Shaders Graphiques", "FileLogTooltip": "Sauver le journal de la console dans un fichier journal sur le disque. Cela n'affecte pas les performances.", "StubLogTooltip": "Affiche les messages de log dans la console. N'affecte pas les performances.", @@ -504,7 +615,9 @@ "EnableInternetAccessTooltip": "Permet à l'application émulée de se connecter à Internet.\n\nLes jeux avec un mode LAN peuvent se connecter les uns aux autres lorsque cette option est cochée et que les systèmes sont connectés au même point d'accès. Cela inclut également les vrais consoles.\n\nCette option n'autorise PAS la connexion aux serveurs Nintendo. Elle peut faire planter certains jeux qui essaient de se connecter à l'Internet.\n\nLaissez DÉSACTIVÉ si vous n'êtes pas sûr.", "GameListContextMenuManageCheatToolTip": "Gérer la triche", "GameListContextMenuManageCheat": "Gérer la triche", - "ControllerSettingsStickRange": "Intervalle:", + "GameListContextMenuManageModToolTip": "Gérer les mods", + "GameListContextMenuManageMod": "Gérer les mods", + "ControllerSettingsStickRange": "Intervalle :", "DialogStopEmulationTitle": "Ryujinx - Arrêt de l'émulation", "DialogStopEmulationMessage": "Êtes-vous sûr de vouloir arrêter l'émulation ?", "SettingsTabCpu": "CPU", @@ -515,9 +628,7 @@ "SettingsTabCpuMemory": "Mémoire CPU", "DialogUpdaterFlatpakNotSupportedMessage": "Merci de mettre à jour Ryujinx via FlatHub.", "UpdaterDisabledWarningTitle": "Mise à jour désactivée !", - "GameListContextMenuOpenSdModsDirectory": "Ouvrir le dossier Mods d'Atmosphère", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Ouvre le répertoire alternatif de carte SD Atmosphère qui contient les Mods d'Application. Utile pour les mods qui sont conçu pour le vrai matériel.", - "ControllerSettingsRotate90": "Rotation 90° horaire", + "ControllerSettingsRotate90": "Faire pivoter de 90° à droite", "IconSize": "Taille d'icône", "IconSizeTooltip": "Changer la taille des icônes de jeu", "MenuBarOptionsShowConsole": "Afficher la console", @@ -532,38 +643,39 @@ "UserErrorNoFirmwareDescription": "Ryujinx n'a pas trouvé de firmwares installés", "UserErrorFirmwareParsingFailedDescription": "Ryujinx n'a pas pu analyser le firmware fourni. Cela est généralement dû à des clés obsolètes.", "UserErrorApplicationNotFoundDescription": "Ryujinx n'a pas pu trouver une application valide dans le chemin indiqué.", - "UserErrorUnknownDescription": "Une erreur inconnue est survenue!", + "UserErrorUnknownDescription": "Une erreur inconnue est survenue !", "UserErrorUndefinedDescription": "Une erreur inconnue est survenue ! Cela ne devrait pas se produire, merci de contacter un développeur !", "OpenSetupGuideMessage": "Ouvrir le guide d'installation", "NoUpdate": "Aucune mise à jour", - "TitleUpdateVersionLabel": "Version {0} - {1}", + "TitleUpdateVersionLabel": "Version {0}", "RyujinxInfo": "Ryujinx - Info", "RyujinxConfirm": "Ryujinx - Confirmation", "FileDialogAllTypes": "Tous les types", "Never": "Jamais", "SwkbdMinCharacters": "Doit comporter au moins {0} caractères", - "SwkbdMinRangeCharacters": "Doit contenir {0}-{1} caractères en longueur", + "SwkbdMinRangeCharacters": "Doit comporter entre {0} et {1} caractères", "SoftwareKeyboard": "Clavier logiciel", - "SoftwareKeyboardModeNumbersOnly": "Doit être uniquement des chiffres", + "SoftwareKeyboardModeNumeric": "Doit être 0-9 ou '.' uniquement", "SoftwareKeyboardModeAlphabet": "Doit être uniquement des caractères non CJK", "SoftwareKeyboardModeASCII": "Doit être uniquement du texte ASCII", - "DialogControllerAppletMessagePlayerRange": "L'application demande {0} joueur(s) avec :\n\nTYPES : {1}\n\nJOUEURS : {2}\n\n{3}Merci d'ouvrir les Paramètres et de reconfigurer les Périphériques maintenant ou appuyez sur Fermer.", - "DialogControllerAppletMessage": "L'application demande exactement {0} joueur(s) avec :\n\nTYPES : {1}\n\nJOUEURS : {2}\n\n{3}Merci d'ouvrir les Paramètres et de reconfigurer les Périphériques maintenant ou appuyez sur Fermer.", - "DialogControllerAppletDockModeSet": "Mode station d'accueil défini. Le portable est également invalide.\n\n", + "ControllerAppletControllers": "Contrôleurs pris en charge :", + "ControllerAppletPlayers": "Joueurs :", + "ControllerAppletDescription": "Votre configuration actuelle n'est pas valide. Ouvrez les paramètres et reconfigurez vos contrôles.", + "ControllerAppletDocked": "Mode station d'accueil défini. Le mode contrôle portable doit être désactivé.", "UpdaterRenaming": "Renommage des anciens fichiers...", "UpdaterRenameFailed": "Impossible de renommer le fichier : {0}", "UpdaterAddingFiles": "Ajout des nouveaux fichiers...", "UpdaterExtracting": "Extraction de la mise à jour…", "UpdaterDownloading": "Téléchargement de la mise à jour...", "Game": "Jeu", - "Docked": "Attaché", - "Handheld": "Portable", + "Docked": "Mode station d'accueil", + "Handheld": "Mode Portable", "ConnectionError": "Erreur de connexion.", "AboutPageDeveloperListMore": "{0} et plus...", "ApiError": "Erreur API.", "LoadingHeading": "Chargement {0}", "CompilingPPTC": "Compilation PTC", - "CompilingShaders": "Compilation des Shaders", + "CompilingShaders": "Compilation des shaders", "AllKeyboards": "Tous les claviers", "OpenFileDialogTitle": "Sélectionnez un fichier supporté à ouvrir", "OpenFolderDialogTitle": "Sélectionnez un dossier avec un jeu décompressé", @@ -572,13 +684,13 @@ "SettingsTabHotkeys": "Raccourcis clavier", "SettingsTabHotkeysHotkeys": "Raccourcis clavier", "SettingsTabHotkeysToggleVsyncHotkey": "Activer/désactiver la VSync :", - "SettingsTabHotkeysScreenshotHotkey": "Captures d'écran :", + "SettingsTabHotkeysScreenshotHotkey": "Capture d'écran :", "SettingsTabHotkeysShowUiHotkey": "Afficher UI :", "SettingsTabHotkeysPauseHotkey": "Suspendre :", "SettingsTabHotkeysToggleMuteHotkey": "Muet : ", "ControllerMotionTitle": "Réglages du contrôle par mouvement", - "ControllerRumbleTitle": "Paramètres de Vibration", - "SettingsSelectThemeFileDialogTitle": "Sélectionnez un Fichier de Thème", + "ControllerRumbleTitle": "Paramètres de vibration", + "SettingsSelectThemeFileDialogTitle": "Sélectionner un fichier de thème", "SettingsXamlThemeFile": "Fichier thème Xaml", "AvatarWindowTitle": "Gérer les Comptes - Avatar", "Amiibo": "Amiibo", @@ -587,46 +699,50 @@ "Writable": "Ecriture possible", "SelectDlcDialogTitle": "Sélectionner les fichiers DLC", "SelectUpdateDialogTitle": "Sélectionner les fichiers de mise à jour", + "SelectModDialogTitle": "Sélectionner le répertoire du mod", "UserProfileWindowTitle": "Gestionnaire de profils utilisateur", "CheatWindowTitle": "Gestionnaire de triches", - "DlcWindowTitle": "Gestionnaire de contenus téléchargeables", + "DlcWindowTitle": "Gérer le contenu téléchargeable pour {0} ({1})", + "ModWindowTitle": "Gérer les mods pour {0} ({1})", "UpdateWindowTitle": "Gestionnaire de mises à jour", "CheatWindowHeading": "Cheats disponibles pour {0} [{1}]", "BuildId": "BuildId:", - "DlcWindowHeading": "{0} Contenu(s) téléchargeable(s) disponible pour {1} ({2})", + "DlcWindowHeading": "{0} Contenu(s) téléchargeable(s)", + "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Éditer la sélection", "Cancel": "Annuler", "Save": "Enregistrer", "Discard": "Abandonner", - "UserProfilesSetProfileImage": "Modifier l'image du profil", + "Paused": "Suspendu", + "UserProfilesSetProfileImage": "Définir l'image de profil", "UserProfileEmptyNameError": "Le nom est requis", "UserProfileNoImageError": "L'image du profil doit être définie", - "GameUpdateWindowHeading": "{0} mise(s) à jour disponible pour {1} ({2})", - "SettingsTabHotkeysResScaleUpHotkey": "Augmenter la résolution:", + "GameUpdateWindowHeading": "Gérer les mises à jour pour {0} ({1})", + "SettingsTabHotkeysResScaleUpHotkey": "Augmenter la résolution :", "SettingsTabHotkeysResScaleDownHotkey": "Diminuer la résolution :", "UserProfilesName": "Nom :", "UserProfilesUserId": "Identifiant de l'utilisateur :", "SettingsTabGraphicsBackend": "API de Rendu", - "SettingsTabGraphicsBackendTooltip": "Interface Graphique à utiliser", + "SettingsTabGraphicsBackendTooltip": "Sélectionnez le moteur graphique qui sera utilisé dans l'émulateur.\n\nVulkan est globalement meilleur pour toutes les cartes graphiques modernes, tant que leurs pilotes sont à jour. Vulkan offre également une compilation de shaders plus rapide (moins de saccades) sur tous les fournisseurs de GPU.\n\nOpenGL peut obtenir de meilleurs résultats sur d'anciennes cartes graphiques Nvidia, sur d'anciennes cartes graphiques AMD sous Linux, ou sur des GPU avec moins de VRAM, bien que les saccades dues à la compilation des shaders soient plus importantes.\n\nRéglez sur Vulkan si vous n'êtes pas sûr. Réglez sur OpenGL si votre GPU ne prend pas en charge Vulkan même avec les derniers pilotes graphiques.", "SettingsEnableTextureRecompression": "Activer la recompression des textures", - "SettingsEnableTextureRecompressionTooltip": "Compresse certaines textures afin de réduire l'utilisation de la VRAM.\n\nRecommandé pour une utilisation avec des GPU qui ont moins de 4 Go de VRAM.\n\nLaissez DÉSACTIVÉ si vous n'êtes pas sûr.", + "SettingsEnableTextureRecompressionTooltip": "Les jeux utilisant ce format de texture incluent Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder et The Legend of Zelda: Tears of the Kingdom.\n\nLes cartes graphiques avec 4 Go ou moins de VRAM risquent probablement de planter à un moment donné lors de l'exécution de ces jeux.\n\nActivez uniquement si vous manquez de VRAM sur les jeux mentionnés ci-dessus. Laissez DÉSACTIVÉ si vous n'êtes pas sûr.", "SettingsTabGraphicsPreferredGpu": "GPU préféré", "SettingsTabGraphicsPreferredGpuTooltip": "Sélectionnez la carte graphique qui sera utilisée avec l'interface graphique Vulkan.\n\nCela ne change pas le GPU qu'OpenGL utilisera.\n\nChoisissez le GPU noté \"dGPU\" si vous n'êtes pas sûr. S'il n'y en a pas, ne pas modifier.", "SettingsAppRequiredRestartMessage": "Redémarrage de Ryujinx requis", "SettingsGpuBackendRestartMessage": "Les paramètres de l'interface graphique ou du GPU ont été modifiés. Cela nécessitera un redémarrage pour être appliqué", - "SettingsGpuBackendRestartSubMessage": "\n\nVoulez-vous redémarrer maintenant?", + "SettingsGpuBackendRestartSubMessage": "\n\nVoulez-vous redémarrer maintenant ?", "RyujinxUpdaterMessage": "Voulez-vous mettre à jour Ryujinx vers la dernière version ?", "SettingsTabHotkeysVolumeUpHotkey": "Augmenter le volume :", "SettingsTabHotkeysVolumeDownHotkey": "Diminuer le volume :", "SettingsEnableMacroHLE": "Activer les macros HLE", - "SettingsEnableMacroHLETooltip": "Émulation de haut niveau du code de Macro GPU.\n\nAméliore les performances, mais peut causer des bugs graphiques dans certains jeux.\n\nLaissez ACTIVER si vous n'êtes pas sûr.", + "SettingsEnableMacroHLETooltip": "Émulation de haut niveau du code de Macro GPU.\n\nAméliore les performances, mais peut causer des artefacts graphiques dans certains jeux.\n\nLaissez ACTIVER si vous n'êtes pas sûr.", "SettingsEnableColorSpacePassthrough": "Traversée de l'espace colorimétrique", - "SettingsEnableColorSpacePassthroughTooltip": "Dirige l'interface graphique Vulkan pour qu'il transmette les informations de couleur sans spécifier d'espace colorimétrique. Pour les utilisateurs possédant des écrans haut de gamme, cela peut entraîner des couleurs plus vives, au détriment de l'exactitude des couleurs.", + "SettingsEnableColorSpacePassthroughTooltip": "Dirige l'interface graphique Vulkan pour qu'il transmette les informations de couleur sans spécifier d'espace colorimétrique. Pour les utilisateurs possédant des écrans Wide Color Gamut, cela peut entraîner des couleurs plus vives, au détriment de l'exactitude des couleurs.", "VolumeShort": "Vol", "UserProfilesManageSaves": "Gérer les sauvegardes", - "DeleteUserSave": "Voulez-vous supprimer la sauvegarde de l'utilisateur pour ce jeu?", + "DeleteUserSave": "Voulez-vous supprimer la sauvegarde de l'utilisateur pour ce jeu ?", "IrreversibleActionNote": "Cette action n'est pas réversible.", - "SaveManagerHeading": "Gérer les sauvegardes pour {0}", + "SaveManagerHeading": "Gérer les sauvegardes pour {0} ({1})", "SaveManagerTitle": "Gestionnaire de sauvegarde", "Name": "Nom ", "Size": "Taille", @@ -635,12 +751,15 @@ "Recover": "Récupérer", "UserProfilesRecoverHeading": "Des sauvegardes ont été trouvées pour les comptes suivants", "UserProfilesRecoverEmptyList": "Aucun profil à restaurer", - "GraphicsAATooltip": "Applique l'anticrénelage au rendu du jeu", + "GraphicsAATooltip": "FXAA floute la plupart de l'image, tandis que SMAA tente de détecter les contours dentelés et de les lisser.\n\nIl n'est pas recommandé de l'utiliser en conjonction avec le filtre de mise à l'échelle FSR.\n\nCette option peut être modifiée pendant qu'un jeu est en cours d'exécution en cliquant sur \"Appliquer\" ci-dessous ; vous pouvez simplement déplacer la fenêtre des paramètres de côté et expérimenter jusqu'à ce que vous trouviez l'apparence souhaitée pour un jeu.\n\nLaissez sur NONE si vous n'êtes pas sûr.", "GraphicsAALabel": "Anticrénelage :", "GraphicsScalingFilterLabel": "Filtre de mise à l'échelle :", - "GraphicsScalingFilterTooltip": "Active la mise à l'échelle du tampon d'image", + "GraphicsScalingFilterTooltip": "Choisissez le filtre de mise à l'échelle qui sera appliqué lors de l'utilisation de la mise à l'échelle de la résolution.\n\nLe filtre bilinéaire fonctionne bien pour les jeux en 3D et constitue une option par défaut sûre.\n\nLe filtre le plus proche est recommandé pour les jeux de pixel art.\n\nFSR 1.0 est simplement un filtre de netteté, non recommandé pour une utilisation avec FXAA ou SMAA.\n\nCette option peut être modifiée pendant qu'un jeu est en cours d'exécution en cliquant sur \"Appliquer\" ci-dessous ; vous pouvez simplement déplacer la fenêtre des paramètres de côté et expérimenter jusqu'à ce que vous trouviez l'aspect souhaité pour un jeu.\n\nLaissez sur BILINEAR si vous n'êtes pas sûr.", + "GraphicsScalingFilterBilinear": "Bilinéaire", + "GraphicsScalingFilterNearest": "Le plus proche", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "Niveau ", - "GraphicsScalingFilterLevelTooltip": "Définir le niveau du filtre de mise à l'échelle", + "GraphicsScalingFilterLevelTooltip": "Définissez le niveau de netteté FSR 1.0. Plus élevé signifie plus net.", "SmaaLow": "SMAA Faible", "SmaaMedium": "SMAA moyen", "SmaaHigh": "SMAA Élevé", @@ -648,9 +767,14 @@ "UserEditorTitle": "Modifier Utilisateur", "UserEditorTitleCreate": "Créer Utilisateur", "SettingsTabNetworkInterface": "Interface Réseau :", - "NetworkInterfaceTooltip": "Interface réseau pour les fonctionnalités LAN", + "NetworkInterfaceTooltip": "L'interface réseau utilisée pour les fonctionnalités LAN/LDN.\n\nEn conjonction avec un VPN ou XLink Kai et un jeu prenant en charge le LAN, peut être utilisée pour simuler une connexion sur le même réseau via Internet.\n\nLaissez sur DEFAULT si vous n'êtes pas sûr.", "NetworkInterfaceDefault": "Par défaut", "PackagingShaders": "Empaquetage des Shaders", "AboutChangelogButton": "Voir le Changelog sur GitHub", - "AboutChangelogButtonTooltipMessage": "Cliquez pour ouvrir le changelog de cette version dans votre navigateur par défaut." -} \ No newline at end of file + "AboutChangelogButtonTooltipMessage": "Cliquez pour ouvrir le changelog de cette version dans votre navigateur par défaut.", + "SettingsTabNetworkMultiplayer": "Multijoueur", + "MultiplayerMode": "Mode :", + "MultiplayerModeTooltip": "Changer le mode multijoueur LDN.\n\nLdnMitm modifiera la fonctionnalité de jeu sans fil local/jeu local dans les jeux pour fonctionner comme s'il s'agissait d'un LAN, permettant des connexions locales sur le même réseau avec d'autres instances de Ryujinx et des consoles Nintendo Switch piratées ayant le module ldn_mitm installé.\n\nLe multijoueur nécessite que tous les joueurs soient sur la même version du jeu (par exemple, Super Smash Bros. Ultimate v13.0.1 ne peut pas se connecter à v13.0.0).\n\nLaissez DÉSACTIVÉ si vous n'êtes pas sûr.", + "MultiplayerModeDisabled": "Désactivé", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/he_IL.json b/src/Ryujinx/Assets/Locales/he_IL.json similarity index 81% rename from src/Ryujinx.Ava/Assets/Locales/he_IL.json rename to src/Ryujinx/Assets/Locales/he_IL.json index e5caf445a..848f78080 100644 --- a/src/Ryujinx.Ava/Assets/Locales/he_IL.json +++ b/src/Ryujinx/Assets/Locales/he_IL.json @@ -1,5 +1,5 @@ { - "Language": "אנגלית (ארה\"ב)", + "Language": "עִברִית", "MenuBarFileOpenApplet": "פתח יישומון", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "פתח את יישומון עורך ה- Mii במצב עצמאי", "SettingsTabInputDirectMouseAccess": "גישה ישירה לעכבר", @@ -14,7 +14,7 @@ "MenuBarFileOpenEmuFolder": "פתח את תיקיית ריוג'ינקס", "MenuBarFileOpenLogsFolder": "פתח את תיקיית קבצי הלוג", "MenuBarFileExit": "_יציאה", - "MenuBarOptions": "הגדרות", + "MenuBarOptions": "_אפשרויות", "MenuBarOptionsToggleFullscreen": "שנה מצב- מסך מלא", "MenuBarOptionsStartGamesInFullscreen": "התחל משחקים במסך מלא", "MenuBarOptionsStopEmulation": "עצור אמולציה", @@ -30,7 +30,11 @@ "MenuBarToolsManageFileTypes": "ניהול סוגי קבצים", "MenuBarToolsInstallFileTypes": "סוגי קבצי התקנה", "MenuBarToolsUninstallFileTypes": "סוגי קבצי הסרה", - "MenuBarHelp": "עזרה", + "MenuBarView": "_View", + "MenuBarViewWindow": "Window Size", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_עזרה", "MenuBarHelpCheckForUpdates": "חפש עדכונים", "MenuBarHelpAbout": "אודות", "MenuSearch": "חפש...", @@ -54,8 +58,6 @@ "GameListContextMenuManageTitleUpdatesToolTip": "פותח את חלון מנהל עדכוני המשחקים", "GameListContextMenuManageDlc": "מנהל הרחבות", "GameListContextMenuManageDlcToolTip": "פותח את חלון מנהל הרחבות המשחקים", - "GameListContextMenuOpenModsDirectory": "פתח את תקיית המודים", - "GameListContextMenuOpenModsDirectoryToolTip": "פותח את התקייה המכילה את המודים של היישום", "GameListContextMenuCacheManagement": "ניהול מטמון", "GameListContextMenuCacheManagementPurgePptc": "הוסף PPTC לתור בנייה מחדש", "GameListContextMenuCacheManagementPurgePptcToolTip": "גרום ל-PPTC להבנות מחדש בפתיחה הבאה של המשחק", @@ -72,6 +74,13 @@ "GameListContextMenuExtractDataRomFSToolTip": "חלץ את קטע ה-RomFS מתצורת היישום הנוכחית (כולל עדכונים)", "GameListContextMenuExtractDataLogo": "Logo", "GameListContextMenuExtractDataLogoToolTip": "חלץ את קטע ה-Logo מתצורת היישום הנוכחית (כולל עדכונים)", + "GameListContextMenuCreateShortcut": "ליצור קיצור דרך לאפליקציה", + "GameListContextMenuCreateShortcutToolTip": "ליצור קיצור דרך בשולחן העבודה שיפתח את אפליקציה זו", + "GameListContextMenuCreateShortcutToolTipMacOS": "ליצור קיצור דרך בתיקיית האפליקציות של macOS שיפתח את אפליקציה זו", + "GameListContextMenuOpenModsDirectory": "פתח תיקיית מודים", + "GameListContextMenuOpenModsDirectoryToolTip": "פותח את התיקייה שמכילה מודים של האפליקציה", + "GameListContextMenuOpenSdModsDirectory": "פתח תיקיית מודים של Atmosphere", + "GameListContextMenuOpenSdModsDirectoryToolTip": "פותח את תיקיית כרטיס ה-SD החלופית של Atmosphere המכילה את המודים של האפליקציה. שימושי עבור מודים שארוזים עבור חומרה אמיתית.", "StatusBarGamesLoaded": "{1}/{0} משחקים נטענו", "StatusBarSystemVersion": "גרסת מערכת: {0}", "LinuxVmMaxMapCountDialogTitle": "זוהתה מגבלה נמוכה עבור מיפויי זיכרון", @@ -87,6 +96,7 @@ "SettingsTabGeneralEnableDiscordRichPresence": "הפעלת תצוגה עשירה בדיסקורד", "SettingsTabGeneralCheckUpdatesOnLaunch": "בדוק אם קיימים עדכונים בהפעלה", "SettingsTabGeneralShowConfirmExitDialog": "הראה דיאלוג \"אשר יציאה\"", + "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", "SettingsTabGeneralHideCursor": "הסתר את הסמן", "SettingsTabGeneralHideCursorNever": "אף פעם", "SettingsTabGeneralHideCursorOnIdle": "במצב סרק", @@ -150,7 +160,7 @@ "SettingsTabGraphicsResolutionScaleNative": "מקורי (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (לא מומלץ)", "SettingsTabGraphicsAspectRatio": "יחס גובה-רוחב:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -261,6 +271,107 @@ "ControllerSettingsMotionGyroDeadzone": "שטח מת של הג'ירוסקופ:", "ControllerSettingsSave": "שמירה", "ControllerSettingsClose": "סגירה", + "KeyUnknown": "Unknown", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", "UserProfilesSelectedUserProfile": "פרופיל המשתמש הנבחר:", "UserProfilesSaveProfileName": "שמור שם פרופיל", "UserProfilesChangeProfileImage": "שנה תמונת פרופיל", @@ -292,13 +403,9 @@ "GameListContextMenuRunApplication": "הרץ יישום", "GameListContextMenuToggleFavorite": "למתג העדפה", "GameListContextMenuToggleFavoriteToolTip": "למתג סטטוס העדפה של משחק", - "SettingsTabGeneralTheme": "ערכת נושא", - "SettingsTabGeneralThemeCustomTheme": "נתיב ערכת נושא מותאמת אישית", - "SettingsTabGeneralThemeBaseStyle": "סגנון בסיס", - "SettingsTabGeneralThemeBaseStyleDark": "כהה", - "SettingsTabGeneralThemeBaseStyleLight": "בהיר", - "SettingsTabGeneralThemeEnableCustomTheme": "אפשר ערכת נושא מותאמת אישית", - "ButtonBrowse": "עיין", + "SettingsTabGeneralTheme": "ערכת נושא:", + "SettingsTabGeneralThemeDark": "כהה", + "SettingsTabGeneralThemeLight": "בהיר", "ControllerSettingsConfigureGeneral": "הגדר", "ControllerSettingsRumble": "רטט", "ControllerSettingsRumbleStrongMultiplier": "העצמת רטט חזק", @@ -332,8 +439,6 @@ "DialogUpdaterAddingFilesMessage": "מוסיף עדכון חדש...", "DialogUpdaterCompleteMessage": "העדכון הושלם!", "DialogUpdaterRestartMessage": "האם אתם רוצים להפעיל מחדש את ריוג'ינקס עכשיו?", - "DialogUpdaterArchNotSupportedMessage": "אינך מריץ ארכיטקטורת מערכת נתמכת!", - "DialogUpdaterArchNotSupportedSubMessage": "(רק מערכות x64 נתמכות!)", "DialogUpdaterNoInternetMessage": "אתם לא מחוברים לאינטרנט!", "DialogUpdaterNoInternetSubMessage": "אנא ודא שיש לך חיבור אינטרנט תקין!", "DialogUpdaterDirtyBuildMessage": "אתם לא יכולים לעדכן מבנה מלוכלך של ריוג'ינקס!", @@ -342,7 +447,7 @@ "DialogThemeRestartMessage": "ערכת הנושא נשמרה. יש צורך בהפעלה מחדש כדי להחיל את ערכת הנושא.", "DialogThemeRestartSubMessage": "האם ברצונך להפעיל מחדש?", "DialogFirmwareInstallEmbeddedMessage": "האם תרצו להתקין את הקושחה המוטמעת במשחק הזה? (קושחה {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "לא נמצאה קושחה מותקנת אבל ריוג'ינקס הצליח להתקין קושחה {0} מהמשחק שסופק. \\nהאמולטור יופעל כעת.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "לא נמצאה קושחה מותקנת אבל ריוג'ינקס הצליח להתקין קושחה {0} מהמשחק שסופק. \nהאמולטור יופעל כעת.", "DialogFirmwareNoFirmwareInstalledMessage": "לא מותקנת קושחה", "DialogFirmwareInstalledMessage": "הקושחה {0} הותקנה", "DialogInstallFileTypesSuccessMessage": "סוגי קבצים הותקנו בהצלחה!", @@ -385,7 +490,10 @@ "DialogUserProfileUnsavedChangesSubMessage": "האם ברצונך למחוק את השינויים האחרונים?", "DialogControllerSettingsModifiedConfirmMessage": "הגדרות השלט הנוכחי עודכנו.", "DialogControllerSettingsModifiedConfirmSubMessage": "האם ברצונך לשמור?", - "DialogLoadNcaErrorMessage": "{0}. קובץ שגוי: {1}", + "DialogLoadFileErrorMessage": "{0}. קובץ שגוי: {1}", + "DialogModAlreadyExistsMessage": "מוד כבר קיים", + "DialogModInvalidMessage": "התיקייה שצוינה אינה מכילה מוד", + "DialogModDeleteNoParentMessage": "נכשל למחוק: לא היה ניתן למצוא את תיקיית האב למוד \"{0}\"!\n", "DialogDlcNoDlcErrorMessage": "הקובץ שצוין אינו מכיל DLC עבור המשחק שנבחר!", "DialogPerformanceCheckLoggingEnabledMessage": "הפעלת רישום מעקב, אשר נועד לשמש מפתחים בלבד.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "לביצועים מיטביים, מומלץ להשבית את רישום המעקב. האם ברצונך להשבית את רישום המעקב כעת?", @@ -396,6 +504,8 @@ "DialogUpdateAddUpdateErrorMessage": "הקובץ שצוין אינו מכיל עדכון עבור המשחק שנבחר!", "DialogSettingsBackendThreadingWarningTitle": "אזהרה - ריבוי תהליכי רקע", "DialogSettingsBackendThreadingWarningMessage": "יש להפעיל מחדש את ריוג'ינקס לאחר שינוי אפשרות זו כדי שהיא תחול במלואה. בהתאם לפלטפורמה שלך, ייתכן שיהיה עליך להשבית ידנית את ריבוי ההליכים של ההתקן שלך בעת השימוש ב-ריוג'ינקס.", + "DialogModManagerDeletionWarningMessage": "אתה עומד למחוק את המוד: {0}\nהאם אתה בטוח שאתה רוצה להמשיך?", + "DialogModManagerDeletionAllWarningMessage": "אתה עומד למחוק את כל המודים בשביל משחק זה.\n\nהאם אתה בטוח שאתה רוצה להמשיך?", "SettingsTabGraphicsFeaturesOptions": "אפשרויות", "SettingsTabGraphicsBackendMultithreading": "אחראי גרפיקה רב-תהליכי:", "CommonAuto": "אוטומטי", @@ -430,6 +540,7 @@ "DlcManagerRemoveAllButton": "מחק הכל", "DlcManagerEnableAllButton": "אפשר הכל", "DlcManagerDisableAllButton": "השבת הכל", + "ModManagerDeleteAllButton": "מחק הכל", "MenuBarOptionsChangeLanguage": "החלף שפה", "MenuBarShowFileTypes": "הצג מזהה סוג קובץ", "CommonSort": "מיין", @@ -447,13 +558,13 @@ "CustomThemePathTooltip": "נתיב לערכת נושא לממשק גראפי מותאם אישית", "CustomThemeBrowseTooltip": "חפש עיצוב ממשק גראפי מותאם אישית", "DockModeToggleTooltip": "מצב עגינה גורם למערכת המדומה להתנהג כ-נינטנדו סוויץ' בתחנת עגינתו. זה משפר את הנאמנות הגרפית ברוב המשחקים.\n לעומת זאת, השבתה של תכונה זו תגרום למערכת המדומה להתנהג כ- נינטנדו סוויץ' נייד, ולהפחית את איכות הגרפיקה.\n\nהגדירו את שלט שחקן 1 אם אתם מתכננים להשתמש במצב עגינה; הגדירו את פקדי כף היד אם אתם מתכננים להשתמש במצב נייד.\n\nמוטב להשאיר דלוק אם אתם לא בטוחים.", - "DirectKeyboardTooltip": "תמיכה ישירה למקלדת (HID). מספק גישה בשביל משחקים למקלדת שלך כמכשיר להזנת טקסט.", - "DirectMouseTooltip": "תמיכה ישירה לעכבר (HID). מספק גישה בשביל משחקים לעכבר שלך כהתקן הצבעה.", + "DirectKeyboardTooltip": "Direct keyboard access (HID) support. Provides games access to your keyboard as a text entry device.\n\nOnly works with games that natively support keyboard usage on Switch hardware.\n\nLeave OFF if unsure.", + "DirectMouseTooltip": "Direct mouse access (HID) support. Provides games access to your mouse as a pointing device.\n\nOnly works with games that natively support mouse controls on Switch hardware, which are few and far between.\n\nWhen enabled, touch screen functionality may not work.\n\nLeave OFF if unsure.", "RegionTooltip": "שנה אזור מערכת", "LanguageTooltip": "שנה שפת מערכת", "TimezoneTooltip": "שנה את אזור הזמן של המערכת", "TimeTooltip": "שנה זמן מערכת", - "VSyncToggleTooltip": "מדמה סנכרון אנכי של קונסולה. כלומר חסם הפריימים לרוב המשחקים; השבתה שלו עלולה לגרום למשחקים לרוץ מהר יותר או לגרום למסכי טעינה לקחת יותר זמן או להתקע.\n\nניתן לשנות מצב של תפריט זה בזמן משחק עם המקש לבחירתך. אנו ממליצים לעשות זאת אם אתם מתכננים להשבית אותו.\n\nמוטב להשאיר דלוק אם לא בטוחים.", + "VSyncToggleTooltip": "Emulated console's Vertical Sync. Essentially a frame-limiter for the majority of games; disabling it may cause games to run at higher speed or make loading screens take longer or get stuck.\n\nCan be toggled in-game with a hotkey of your preference (F1 by default). We recommend doing this if you plan on disabling it.\n\nLeave ON if unsure.", "PptcToggleTooltip": "שומר את פונקציות ה-JIT המתורגמות כך שלא יצטרכו לעבור תרגום שוב כאשר משחק עולה.\n\nמפחית תקיעות ומשפר מהירות עלייה של המערכת אחרי הפתיחה הראשונה של המשחק.\n\nמוטב להשאיר דלוק אם לא בטוחים.", "FsIntegrityToggleTooltip": "בודק לקבצים שגויים כאשר משחק עולה, ואם מתגלים כאלו, מציג את מזהה השגיאה שלהם לקובץ הלוג.\n\nאין לכך השפעה על הביצועים ונועד לעזור לבדיקה וניפוי שגיאות של האמולטור.\n\nמוטב להשאיר דלוק אם לא בטוחים.", "AudioBackendTooltip": "משנה את אחראי השמע.\n\nSDL2 הוא הנבחר, למראת שOpenAL וגם SoundIO משומשים כאפשרויות חלופיות. אפשרות הDummy לא תשמיע קול כלל.\n\nמוטב להשאיר על SDL2 אם לא בטוחים.", @@ -467,10 +578,10 @@ "GraphicsBackendThreadingTooltip": "מריץ פקודות גראפיקה בתהליך שני נפרד.\n\nמאיץ עיבוד הצללות, מפחית תקיעות ומשפר ביצועים של דרייבר כרטיסי מסך אשר לא תומכים בהרצה רב-תהליכית.\n\nמוטב להשאיר על אוטומטי אם לא בטוחים.", "GalThreadingTooltip": "מריץ פקודות גראפיקה בתהליך שני נפרד.\n\nמאיץ עיבוד הצללות, מפחית תקיעות ומשפר ביצועים של דרייבר כרטיסי מסך אשר לא תומכים בהרצה רב-תהליכית.\n\nמוטב להשאיר על אוטומטי אם לא בטוחים.", "ShaderCacheToggleTooltip": "שומר זכרון מטמון של הצללות, דבר שמפחית תקיעות בריצות מסוימות.\n\nמוטב להשאיר דלוק אם לא בטוחים.", - "ResolutionScaleTooltip": "שיפור רזולוצייה המאופשרת לעיבוד מטרות.", + "ResolutionScaleTooltip": "Multiplies the game's rendering resolution.\n\nA few games may not work with this and look pixelated even when the resolution is increased; for those games, you may need to find mods that remove anti-aliasing or that increase their internal rendering resolution. For using the latter, you'll likely want to select Native.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nKeep in mind 4x is overkill for virtually any setup.", "ResolutionScaleEntryTooltip": "שיפור רזולוציית נקודה צפה, כגון 1.5. הוא שיפור לא אינטגרלי הנוטה לגרום יותר בעיות או להקריס.", - "AnisotropyTooltip": "רמת סינון אניסוטרופי (מוגדר לאוטומטי כדי להשתמש בערך המבוקש על ידי המשחק)", - "AspectRatioTooltip": "יחס גובה-רוחב הוחל על חלון המעבד.", + "AnisotropyTooltip": "Level of Anisotropic Filtering. Set to Auto to use the value requested by the game.", + "AspectRatioTooltip": "Aspect Ratio applied to the renderer window.\n\nOnly change this if you're using an aspect ratio mod for your game, otherwise the graphics will be stretched.\n\nLeave on 16:9 if unsure.", "ShaderDumpPathTooltip": "נתיב השלכת הצללות גראפיות", "FileLogTooltip": "שומר את רישומי שורת הפקודות לזיכרון, לא משפיע על ביצועי היישום.", "StubLogTooltip": "מדפיס רישומים כושלים לשורת הפקודות. לא משפיע על ביצועי היישום.", @@ -504,6 +615,8 @@ "EnableInternetAccessTooltip": "מאפשר ליישומים באמולצייה להתחבר לאינטרנט.\n\nמשחקים עם חיבור לאן יכולים להתחבר אחד לשני כשאופצייה זו מופעלת והמערכות מתחברות לאותה נקודת גישה. כמו כן זה כולל שורות פקודות אמיתיות גם.\n\nאופצייה זו לא מאפשרת חיבור לשרתי נינטנדו. כשהאופצייה דלוקה היא עלולה לגרום לקריסת היישום במשחקים מסויימים שמנסים להתחבר לאינטרנט.\n\nמוטב להשאיר כבוי אם לא בטוחים.", "GameListContextMenuManageCheatToolTip": "נהל צ'יטים", "GameListContextMenuManageCheat": "נהל צ'יטים", + "GameListContextMenuManageModToolTip": "נהל מודים", + "GameListContextMenuManageMod": "נהל מודים", "ControllerSettingsStickRange": "טווח:", "DialogStopEmulationTitle": "ריוג'ינקס - עצור אמולציה", "DialogStopEmulationMessage": "האם אתם בטוחים שאתם רוצים לסגור את האמולצייה?", @@ -515,8 +628,6 @@ "SettingsTabCpuMemory": "מצב מעבד", "DialogUpdaterFlatpakNotSupportedMessage": "בבקשה עדכן את ריוג'ינקס דרך פלאטהב.", "UpdaterDisabledWarningTitle": "מעדכן מושבת!", - "GameListContextMenuOpenSdModsDirectory": "פתח את תקיית המודים של אטמוספרה", - "GameListContextMenuOpenSdModsDirectoryToolTip": "פותח את תקיית כרטיס ה-SD החלופית של אטמוספרה המכילה את המודים של האפליקציה. שימושי עבור מודים ארוזים עבור חומרה אמיתית.", "ControllerSettingsRotate90": "סובב 90° עם בכיוון השעון", "IconSize": "גודל הסמל", "IconSizeTooltip": "שנה את גודל הסמלים של משחקים", @@ -544,12 +655,13 @@ "SwkbdMinCharacters": "לפחות {0} תווים", "SwkbdMinRangeCharacters": "באורך {0}-{1} תווים", "SoftwareKeyboard": "מקלדת וירטואלית", - "SoftwareKeyboardModeNumbersOnly": "מחויב להיות מספרי בלבד", + "SoftwareKeyboardModeNumeric": "חייב להיות בין 0-9 או '.' בלבד", "SoftwareKeyboardModeAlphabet": "מחויב להיות ללא אותיות CJK", "SoftwareKeyboardModeASCII": "מחויב להיות טקסט אסקיי", - "DialogControllerAppletMessagePlayerRange": "האפליקציה מבקשת {0} שחקנים עם:\n\nסוגים: {1}\n\nשחקנים: {2}\n\n{3}אנא פתח את ההגדרות והגדר מחדש את הקלט כעת או סגור.", - "DialogControllerAppletMessage": "האפליקציה מבקשת בדיוק {0} שחקנים עם:\n\nסוגים: {1}\n\nשחקנים: {2}\n\n{3}אנא פתח את ההגדרות והגדר מחדש את הקלט כעת או סגור.", - "DialogControllerAppletDockModeSet": "במצב עגינה. בנוסף מצב נייד לא אפשרי.\n\n", + "ControllerAppletControllers": "בקרים נתמכים:", + "ControllerAppletPlayers": "שחקנים:", + "ControllerAppletDescription": "התצורה הנוכחית אינה תקינה. פתח הגדרות והגדר מחדש את הקלטים שלך.", + "ControllerAppletDocked": "מצב עגינה מוגדר. כדאי ששליטה ניידת תהיה מושבתת.", "UpdaterRenaming": "משנה שמות של קבצים ישנים...", "UpdaterRenameFailed": "המעדכן לא הצליח לשנות את שם הקובץ: {0}", "UpdaterAddingFiles": "מוסיף קבצים חדשים...", @@ -587,17 +699,21 @@ "Writable": "ניתן לכתיבה", "SelectDlcDialogTitle": "בחרו קבצי הרחבות משחק", "SelectUpdateDialogTitle": "בחרו קבצי עדכון", + "SelectModDialogTitle": "בחר תיקיית מודים", "UserProfileWindowTitle": "ניהול פרופילי משתמש", "CheatWindowTitle": "נהל צ'יטים למשחק", "DlcWindowTitle": "נהל הרחבות משחק עבור {0} ({1})", + "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "נהל עדכוני משחקים", "CheatWindowHeading": "צ'יטים זמינים עבור {0} [{1}]", "BuildId": "מזהה בניה:", "DlcWindowHeading": "{0} הרחבות משחק", + "ModWindowHeading": "{0} מוד(ים)", "UserProfilesEditProfile": "ערוך נבחר/ים", "Cancel": "בטל", "Save": "שמור", "Discard": "השלך", + "Paused": "מושהה", "UserProfilesSetProfileImage": "הגדר תמונת פרופיל", "UserProfileEmptyNameError": "נדרש שם", "UserProfileNoImageError": "נדרשת תמונת פרופיל", @@ -607,9 +723,9 @@ "UserProfilesName": "שם:", "UserProfilesUserId": "מזהה משתמש:", "SettingsTabGraphicsBackend": "אחראי גראפיקה", - "SettingsTabGraphicsBackendTooltip": "אחראי גראפיקה לשימוש", + "SettingsTabGraphicsBackendTooltip": "Select the graphics backend that will be used in the emulator.\n\nVulkan is overall better for all modern graphics cards, as long as their drivers are up to date. Vulkan also features faster shader compilation (less stuttering) on all GPU vendors.\n\nOpenGL may achieve better results on old Nvidia GPUs, on old AMD GPUs on Linux, or on GPUs with lower VRAM, though shader compilation stutters will be greater.\n\nSet to Vulkan if unsure. Set to OpenGL if your GPU does not support Vulkan even with the latest graphics drivers.", "SettingsEnableTextureRecompression": "אפשר דחיסה מחדש של המרקם", - "SettingsEnableTextureRecompressionTooltip": " דוחס מרקמים מסויימים להפחתת השימוש בראם הוירטואלי.\n\nמומלץ לשימוש עם כרטיס גראפי בעל פחות מ-4GiB בראם הוירטואלי.\n\nמוטב להשאיר כבוי אם אינכם בטוחים.", + "SettingsEnableTextureRecompressionTooltip": "Compresses ASTC textures in order to reduce VRAM usage.\n\nGames using this texture format include Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder and The Legend of Zelda: Tears of the Kingdom.\n\nGraphics cards with 4GiB VRAM or less will likely crash at some point while running these games.\n\nEnable only if you're running out of VRAM on the aforementioned games. Leave OFF if unsure.", "SettingsTabGraphicsPreferredGpu": "כרטיס גראפי מועדף", "SettingsTabGraphicsPreferredGpuTooltip": "בחר את הכרטיס הגראפי שישומש עם הגראפיקה של וולקאן.\n\nדבר זה לא משפיע על הכרטיס הגראפי שישומש עם OpenGL.\n\nמוטב לבחור את ה-GPU המסומן כ-\"dGPU\" אם אינכם בטוחים, אם זו לא אופצייה, אל תשנו דבר.", "SettingsAppRequiredRestartMessage": "ריוג'ינקס דורש אתחול מחדש", @@ -620,8 +736,8 @@ "SettingsTabHotkeysVolumeDownHotkey": "הנמך את עוצמת הקול:", "SettingsEnableMacroHLE": "Enable Macro HLE", "SettingsEnableMacroHLETooltip": "אמולצייה ברמה גבוהה של כרטיס גראפי עם קוד מקרו.\n\nמשפר את ביצועי היישום אך עלול לגרום לגליצ'ים חזותיים במשחקים מסויימים.\n\nמוטב להשאיר דלוק אם אינך בטוח.", - "SettingsEnableColorSpacePassthrough": "Color Space Passthrough", - "SettingsEnableColorSpacePassthroughTooltip": "Directs the Vulkan backend to pass through color information without specifying a color space. For users with wide gamut displays, this may result in more vibrant colors, at the cost of color correctness.", + "SettingsEnableColorSpacePassthrough": "שקיפות מרחב צבע", + "SettingsEnableColorSpacePassthroughTooltip": "מנחה את המנוע Vulkan להעביר שקיפות בצבעים מבלי לציין מרחב צבע. עבור משתמשים עם מסכים רחבים, הדבר עשוי לגרום לצבעים מרהיבים יותר, בחוסר דיוק בצבעים האמתיים.", "VolumeShort": "שמע", "UserProfilesManageSaves": "נהל שמורים", "DeleteUserSave": "האם ברצונך למחוק את תקיית השמור למשחק זה?", @@ -635,12 +751,15 @@ "Recover": "שחזר", "UserProfilesRecoverHeading": "שמורים נמצאו לחשבונות הבאים", "UserProfilesRecoverEmptyList": "אין פרופילים לשחזור", - "GraphicsAATooltip": "מחיל החלקת-עקומות על עיבוד המשחק", + "GraphicsAATooltip": "Applies anti-aliasing to the game render.\n\nFXAA will blur most of the image, while SMAA will attempt to find jagged edges and smooth them out.\n\nNot recommended to use in conjunction with the FSR scaling filter.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on NONE if unsure.", "GraphicsAALabel": "החלקת-עקומות:", "GraphicsScalingFilterLabel": "מסנן מידת איכות:", - "GraphicsScalingFilterTooltip": "אפשר מידת איכות מסוג איגור-תמונה", + "GraphicsScalingFilterTooltip": "Choose the scaling filter that will be applied when using resolution scale.\n\nBilinear works well for 3D games and is a safe default option.\n\nNearest is recommended for pixel art games.\n\nFSR 1.0 is merely a sharpening filter, not recommended for use with FXAA or SMAA.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on BILINEAR if unsure.", + "GraphicsScalingFilterBilinear": "Bilinear", + "GraphicsScalingFilterNearest": "Nearest", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "רמה", - "GraphicsScalingFilterLevelTooltip": "קבע מידת איכות תמונה לפי רמת סינון", + "GraphicsScalingFilterLevelTooltip": "Set FSR 1.0 sharpening level. Higher is sharper.", "SmaaLow": "SMAA נמוך", "SmaaMedium": "SMAA בינוני", "SmaaHigh": "SMAA גבוהה", @@ -648,9 +767,14 @@ "UserEditorTitle": "ערוך משתמש", "UserEditorTitleCreate": "צור משתמש", "SettingsTabNetworkInterface": "ממשק רשת", - "NetworkInterfaceTooltip": "ממשק הרשת המשומש עבור יכולות לאן", + "NetworkInterfaceTooltip": "The network interface used for LAN/LDN features.\n\nIn conjunction with a VPN or XLink Kai and a game with LAN support, can be used to spoof a same-network connection over the Internet.\n\nLeave on DEFAULT if unsure.", "NetworkInterfaceDefault": "ברירת המחדל", "PackagingShaders": "אורז הצללות", "AboutChangelogButton": "צפה במידע אודות שינויים בגיטהב", - "AboutChangelogButtonTooltipMessage": "לחץ כדי לפתוח את יומן השינויים עבור גרסה זו בדפדפן ברירת המחדל שלך." -} \ No newline at end of file + "AboutChangelogButtonTooltipMessage": "לחץ כדי לפתוח את יומן השינויים עבור גרסה זו בדפדפן ברירת המחדל שלך.", + "SettingsTabNetworkMultiplayer": "רב משתתפים", + "MultiplayerMode": "מצב:", + "MultiplayerModeTooltip": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.", + "MultiplayerModeDisabled": "Disabled", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/it_IT.json b/src/Ryujinx/Assets/Locales/it_IT.json similarity index 57% rename from src/Ryujinx.Ava/Assets/Locales/it_IT.json rename to src/Ryujinx/Assets/Locales/it_IT.json index 5aff7a7ec..280ebd880 100644 --- a/src/Ryujinx.Ava/Assets/Locales/it_IT.json +++ b/src/Ryujinx/Assets/Locales/it_IT.json @@ -1,8 +1,8 @@ { "Language": "Italiano", - "MenuBarFileOpenApplet": "Apri Applet", + "MenuBarFileOpenApplet": "Apri applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Apri l'applet Mii Editor in modalità Standalone", - "SettingsTabInputDirectMouseAccess": "Accesso diretto mouse", + "SettingsTabInputDirectMouseAccess": "Accesso diretto al mouse", "SettingsTabSystemMemoryManagerMode": "Modalità di gestione della memoria:", "SettingsTabSystemMemoryManagerModeSoftware": "Software", "SettingsTabSystemMemoryManagerModeHost": "Host (veloce)", @@ -12,9 +12,9 @@ "MenuBarFileOpenFromFile": "_Carica applicazione da un file", "MenuBarFileOpenUnpacked": "Carica _gioco estratto", "MenuBarFileOpenEmuFolder": "Apri cartella di Ryujinx", - "MenuBarFileOpenLogsFolder": "Apri cartella dei Log", + "MenuBarFileOpenLogsFolder": "Apri cartella dei log", "MenuBarFileExit": "_Esci", - "MenuBarOptions": "Opzioni", + "MenuBarOptions": "_Opzioni", "MenuBarOptionsToggleFullscreen": "Schermo intero", "MenuBarOptionsStartGamesInFullscreen": "Avvia i giochi a schermo intero", "MenuBarOptionsStopEmulation": "Ferma emulazione", @@ -30,7 +30,11 @@ "MenuBarToolsManageFileTypes": "Gestisci i tipi di file", "MenuBarToolsInstallFileTypes": "Installa i tipi di file", "MenuBarToolsUninstallFileTypes": "Disinstalla i tipi di file", - "MenuBarHelp": "Aiuto", + "MenuBarView": "_View", + "MenuBarViewWindow": "Window Size", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Aiuto", "MenuBarHelpCheckForUpdates": "Controlla aggiornamenti", "MenuBarHelpAbout": "Informazioni", "MenuSearch": "Cerca...", @@ -40,31 +44,29 @@ "GameListHeaderDeveloper": "Sviluppatore", "GameListHeaderVersion": "Versione", "GameListHeaderTimePlayed": "Tempo di gioco", - "GameListHeaderLastPlayed": "Giocato l'ultima volta", + "GameListHeaderLastPlayed": "Ultima partita", "GameListHeaderFileExtension": "Estensione", "GameListHeaderFileSize": "Dimensione file", "GameListHeaderPath": "Percorso", - "GameListContextMenuOpenUserSaveDirectory": "Apri la cartella salvataggi dell'utente", - "GameListContextMenuOpenUserSaveDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco dell'utente", - "GameListContextMenuOpenDeviceSaveDirectory": "Apri la cartella dispositivo dell'utente", - "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco del dispositivo", - "GameListContextMenuOpenBcatSaveDirectory": "Apri la cartella BCAT dell'utente", - "GameListContextMenuOpenBcatSaveDirectoryToolTip": "Apre la cartella che contiene i salvataggi BCAT dell'applicazione", + "GameListContextMenuOpenUserSaveDirectory": "Apri la cartella dei salvataggi dell'utente", + "GameListContextMenuOpenUserSaveDirectoryToolTip": "Apre la cartella che contiene i dati di salvataggio dell'utente", + "GameListContextMenuOpenDeviceSaveDirectory": "Apri la cartella dei salvataggi del dispositivo", + "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Apre la cartella che contiene i dati di salvataggio del dispositivo", + "GameListContextMenuOpenBcatSaveDirectory": "Apri la cartella del salvataggio BCAT", + "GameListContextMenuOpenBcatSaveDirectoryToolTip": "Apre la cartella che contiene il salvataggio BCAT dell'applicazione", "GameListContextMenuManageTitleUpdates": "Gestisci aggiornamenti del gioco", "GameListContextMenuManageTitleUpdatesToolTip": "Apre la finestra di gestione aggiornamenti del gioco", - "GameListContextMenuManageDlc": "Gestici DLC", - "GameListContextMenuManageDlcToolTip": "Apre la finestra di gestione DLC", - "GameListContextMenuOpenModsDirectory": "Apri cartella delle mod", - "GameListContextMenuOpenModsDirectoryToolTip": "Apre la cartella che contiene le mod dell'applicazione", + "GameListContextMenuManageDlc": "Gestisci DLC", + "GameListContextMenuManageDlcToolTip": "Apre la finestra di gestione dei DLC", "GameListContextMenuCacheManagement": "Gestione della cache", - "GameListContextMenuCacheManagementPurgePptc": "Pulisci PPTC cache", - "GameListContextMenuCacheManagementPurgePptcToolTip": "Elimina la PPTC cache dell'applicazione", - "GameListContextMenuCacheManagementPurgeShaderCache": "Pulisci shader cache", - "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Elimina la shader cache dell'applicazione", - "GameListContextMenuCacheManagementOpenPptcDirectory": "Apri cartella PPTC", - "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Apre la cartella che contiene la PPTC cache dell'applicazione", - "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Apri cartella shader cache", - "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Apre la cartella che contiene la shader cache dell'applicazione", + "GameListContextMenuCacheManagementPurgePptc": "Accoda rigenerazione della cache PPTC", + "GameListContextMenuCacheManagementPurgePptcToolTip": "Esegue la rigenerazione della cache PPTC al prossimo avvio del gioco", + "GameListContextMenuCacheManagementPurgeShaderCache": "Elimina la cache degli shader", + "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Elimina la cache degli shader dell'applicazione", + "GameListContextMenuCacheManagementOpenPptcDirectory": "Apri la cartella della cache PPTC", + "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Apre la cartella che contiene la cache PPTC dell'applicazione", + "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Apri la cartella della cache degli shader", + "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Apre la cartella che contiene la cache degli shader dell'applicazione", "GameListContextMenuExtractData": "Estrai dati", "GameListContextMenuExtractDataExeFS": "ExeFS", "GameListContextMenuExtractDataExeFSToolTip": "Estrae la sezione ExeFS dall'attuale configurazione dell'applicazione (includendo aggiornamenti)", @@ -72,9 +74,16 @@ "GameListContextMenuExtractDataRomFSToolTip": "Estrae la sezione RomFS dall'attuale configurazione dell'applicazione (includendo aggiornamenti)", "GameListContextMenuExtractDataLogo": "Logo", "GameListContextMenuExtractDataLogoToolTip": "Estrae la sezione Logo dall'attuale configurazione dell'applicazione (includendo aggiornamenti)", - "StatusBarGamesLoaded": "{0}/{1} Giochi caricati", + "GameListContextMenuCreateShortcut": "Crea collegamento", + "GameListContextMenuCreateShortcutToolTip": "Crea un collegamento sul desktop che avvia l'applicazione selezionata", + "GameListContextMenuCreateShortcutToolTipMacOS": "Crea un collegamento nella cartella Applicazioni di macOS che avvia l'applicazione selezionata", + "GameListContextMenuOpenModsDirectory": "Apri la cartella delle mod", + "GameListContextMenuOpenModsDirectoryToolTip": "Apre la cartella che contiene le mod dell'applicazione", + "GameListContextMenuOpenSdModsDirectory": "Apri la cartella delle mod Atmosphere", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Apre la cartella alternativa di Atmosphere sulla scheda SD che contiene le mod dell'applicazione. Utile per le mod create per funzionare sull'hardware reale.", + "StatusBarGamesLoaded": "{0}/{1} giochi caricati", "StatusBarSystemVersion": "Versione di sistema: {0}", - "LinuxVmMaxMapCountDialogTitle": "Limite basso per le mappature di memoria rilevate", + "LinuxVmMaxMapCountDialogTitle": "Rilevato limite basso per le mappature di memoria", "LinuxVmMaxMapCountDialogTextPrimary": "Vuoi aumentare il valore di vm.max_map_count a {0}?", "LinuxVmMaxMapCountDialogTextSecondary": "Alcuni giochi potrebbero provare a creare più mappature di memoria di quanto sia attualmente consentito. Ryujinx si bloccherà non appena questo limite viene superato.", "LinuxVmMaxMapCountDialogButtonUntilRestart": "Sì, fino al prossimo riavvio", @@ -87,9 +96,10 @@ "SettingsTabGeneralEnableDiscordRichPresence": "Attiva Discord Rich Presence", "SettingsTabGeneralCheckUpdatesOnLaunch": "Controlla aggiornamenti all'avvio", "SettingsTabGeneralShowConfirmExitDialog": "Mostra dialogo \"Conferma Uscita\"", + "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", "SettingsTabGeneralHideCursor": "Nascondi il cursore:", "SettingsTabGeneralHideCursorNever": "Mai", - "SettingsTabGeneralHideCursorOnIdle": "Nascondi cursore inattivo", + "SettingsTabGeneralHideCursorOnIdle": "Quando è inattivo", "SettingsTabGeneralHideCursorAlways": "Sempre", "SettingsTabGeneralGameDirectories": "Cartelle dei giochi", "SettingsTabGeneralAdd": "Aggiungi", @@ -128,17 +138,17 @@ "SettingsTabSystemEnablePptc": "Attiva PPTC (Profiled Persistent Translation Cache)", "SettingsTabSystemEnableFsIntegrityChecks": "Attiva controlli d'integrità FS", "SettingsTabSystemAudioBackend": "Backend audio:", - "SettingsTabSystemAudioBackendDummy": "Manichino", + "SettingsTabSystemAudioBackendDummy": "Dummy", "SettingsTabSystemAudioBackendOpenAL": "OpenAL", - "SettingsTabSystemAudioBackendSoundIO": "AudioIO", + "SettingsTabSystemAudioBackendSoundIO": "SoundIO", "SettingsTabSystemAudioBackendSDL2": "SDL2", - "SettingsTabSystemHacks": "Trucchi", - "SettingsTabSystemHacksNote": " (Possono causare instabilità)", - "SettingsTabSystemExpandDramSize": "Espandi dimensione DRAM a 6GiB", + "SettingsTabSystemHacks": "Espedienti", + "SettingsTabSystemHacksNote": "Possono causare instabilità", + "SettingsTabSystemExpandDramSize": "Usa layout di memoria alternativo (per sviluppatori)", "SettingsTabSystemIgnoreMissingServices": "Ignora servizi mancanti", "SettingsTabGraphics": "Grafica", - "SettingsTabGraphicsAPI": "API Grafiche", - "SettingsTabGraphicsEnableShaderCache": "Attiva Shader Cache", + "SettingsTabGraphicsAPI": "API grafica", + "SettingsTabGraphicsEnableShaderCache": "Attiva la cache degli shader", "SettingsTabGraphicsAnisotropicFiltering": "Filtro anisotropico:", "SettingsTabGraphicsAnisotropicFilteringAuto": "Auto", "SettingsTabGraphicsAnisotropicFiltering2x": "2x", @@ -150,7 +160,7 @@ "SettingsTabGraphicsResolutionScaleNative": "Nativa (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (Non consigliato)", "SettingsTabGraphicsAspectRatio": "Rapporto d'aspetto:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -158,34 +168,34 @@ "SettingsTabGraphicsAspectRatio21x9": "21:9", "SettingsTabGraphicsAspectRatio32x9": "32:9", "SettingsTabGraphicsAspectRatioStretch": "Adatta alla finestra", - "SettingsTabGraphicsDeveloperOptions": "Opzioni da sviluppatore", - "SettingsTabGraphicsShaderDumpPath": "Percorso di dump degli shaders:", + "SettingsTabGraphicsDeveloperOptions": "Opzioni per sviluppatori", + "SettingsTabGraphicsShaderDumpPath": "Percorso di dump degli shader:", "SettingsTabLogging": "Log", "SettingsTabLoggingLogging": "Log", "SettingsTabLoggingEnableLoggingToFile": "Salva i log su file", - "SettingsTabLoggingEnableStubLogs": "Attiva Stub Logs", - "SettingsTabLoggingEnableInfoLogs": "Attiva Info Logs", - "SettingsTabLoggingEnableWarningLogs": "Attiva Warning Logs", - "SettingsTabLoggingEnableErrorLogs": "Attiva Error Logs", - "SettingsTabLoggingEnableTraceLogs": "Attiva Trace Logs", - "SettingsTabLoggingEnableGuestLogs": "Attiva Guest Logs", - "SettingsTabLoggingEnableFsAccessLogs": "Attiva Fs Access Logs", - "SettingsTabLoggingFsGlobalAccessLogMode": "Modalità log accesso globale Fs:", - "SettingsTabLoggingDeveloperOptions": "Opzioni da sviluppatore (AVVISO: Ridurrà le prestazioni)", + "SettingsTabLoggingEnableStubLogs": "Attiva log di stub", + "SettingsTabLoggingEnableInfoLogs": "Attiva log di informazioni", + "SettingsTabLoggingEnableWarningLogs": "Attiva log di avviso", + "SettingsTabLoggingEnableErrorLogs": "Attiva log di errore", + "SettingsTabLoggingEnableTraceLogs": "Attiva log di trace", + "SettingsTabLoggingEnableGuestLogs": "Attiva log del guest", + "SettingsTabLoggingEnableFsAccessLogs": "Attiva log di accesso FS", + "SettingsTabLoggingFsGlobalAccessLogMode": "Modalità log di accesso globale FS:", + "SettingsTabLoggingDeveloperOptions": "Opzioni per sviluppatori", "SettingsTabLoggingDeveloperOptionsNote": "ATTENZIONE: ridurrà le prestazioni", - "SettingsTabLoggingGraphicsBackendLogLevel": "Livello registro backend grafico:", + "SettingsTabLoggingGraphicsBackendLogLevel": "Livello di log del backend grafico:", "SettingsTabLoggingGraphicsBackendLogLevelNone": "Nessuno", "SettingsTabLoggingGraphicsBackendLogLevelError": "Errore", "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Rallentamenti", "SettingsTabLoggingGraphicsBackendLogLevelAll": "Tutto", - "SettingsTabLoggingEnableDebugLogs": "Attiva logs di debug", + "SettingsTabLoggingEnableDebugLogs": "Attiva log di debug", "SettingsTabInput": "Input", "SettingsTabInputEnableDockedMode": "Attiva modalità TV", "SettingsTabInputDirectKeyboardAccess": "Accesso diretto alla tastiera", "SettingsButtonSave": "Salva", "SettingsButtonClose": "Chiudi", "SettingsButtonOk": "OK", - "SettingsButtonCancel": "Cancella", + "SettingsButtonCancel": "Annulla", "SettingsButtonApply": "Applica", "ControllerSettingsPlayer": "Giocatore", "ControllerSettingsPlayer1": "Giocatore 1", @@ -232,8 +242,8 @@ "ControllerSettingsStickInvertXAxis": "Inverti levetta X", "ControllerSettingsStickInvertYAxis": "Inverti levetta Y", "ControllerSettingsStickDeadzone": "Zona morta:", - "ControllerSettingsLStick": "Stick sinistro", - "ControllerSettingsRStick": "Stick destro", + "ControllerSettingsLStick": "Levetta sinistra", + "ControllerSettingsRStick": "Levetta destra", "ControllerSettingsTriggersLeft": "Grilletto sinistro", "ControllerSettingsTriggersRight": "Grilletto destro", "ControllerSettingsTriggersButtonsLeft": "Pulsante dorsale sinistro", @@ -247,7 +257,7 @@ "ControllerSettingsLeftSR": "SR", "ControllerSettingsRightSL": "SL", "ControllerSettingsRightSR": "SR", - "ControllerSettingsExtraButtonsLeft": "Tasto sinitro", + "ControllerSettingsExtraButtonsLeft": "Tasto sinistro", "ControllerSettingsExtraButtonsRight": "Tasto destro", "ControllerSettingsMisc": "Varie", "ControllerSettingsTriggerThreshold": "Sensibilità dei grilletti:", @@ -261,6 +271,107 @@ "ControllerSettingsMotionGyroDeadzone": "Zona morta del giroscopio:", "ControllerSettingsSave": "Salva", "ControllerSettingsClose": "Chiudi", + "KeyUnknown": "Sconosciuto", + "KeyShiftLeft": "Maiusc sinistro", + "KeyShiftRight": "Maiusc destro", + "KeyControlLeft": "Ctrl sinistro", + "KeyMacControlLeft": "⌃ sinistro", + "KeyControlRight": "Ctrl destro", + "KeyMacControlRight": "⌃ destro", + "KeyAltLeft": "Alt sinistro", + "KeyMacAltLeft": "⌥ sinistro", + "KeyAltRight": "Alt destro", + "KeyMacAltRight": "⌥ destro", + "KeyWinLeft": "⊞ sinistro", + "KeyMacWinLeft": "⌘ sinistro", + "KeyWinRight": "⊞ destro", + "KeyMacWinRight": "⌘ destro", + "KeyMenu": "Menù", + "KeyUp": "Su", + "KeyDown": "Giù", + "KeyLeft": "Sinistra", + "KeyRight": "Destra", + "KeyEnter": "Invio", + "KeyEscape": "Esc", + "KeySpace": "Spazio", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Ins", + "KeyDelete": "Canc", + "KeyPageUp": "Pag. Su", + "KeyPageDown": "Pag. Giù", + "KeyHome": "Inizio", + "KeyEnd": "Fine", + "KeyCapsLock": "Bloc Maiusc", + "KeyScrollLock": "Bloc Scorr", + "KeyPrintScreen": "Stamp", + "KeyPause": "Pausa", + "KeyNumLock": "Bloc Num", + "KeyClear": "Clear", + "KeyKeypad0": "Tast. num. 0", + "KeyKeypad1": "Tast. num. 1", + "KeyKeypad2": "Tast. num. 2", + "KeyKeypad3": "Tast. num. 3", + "KeyKeypad4": "Tast. num. 4", + "KeyKeypad5": "Tast. num. 5", + "KeyKeypad6": "Tast. num. 6", + "KeyKeypad7": "Tast. num. 7", + "KeyKeypad8": "Tast. num. 8", + "KeyKeypad9": "Tast. num. 9", + "KeyKeypadDivide": "Tast. num. /", + "KeyKeypadMultiply": "Tast. num. *", + "KeyKeypadSubtract": "Tast. num. -", + "KeyKeypadAdd": "Tast. num. +", + "KeyKeypadDecimal": "Tast. num. sep. decimale", + "KeyKeypadEnter": "Tast. num. Invio", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "ò", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "'", + "KeyBracketRight": "ì", + "KeySemicolon": "è", + "KeyQuote": "à", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "ù", + "KeyBackSlash": "<", + "KeyUnbound": "Non assegnato", + "GamepadLeftStick": "Pulsante levetta sinistra", + "GamepadRightStick": "Pulsante levetta destra", + "GamepadLeftShoulder": "Pulsante dorsale sinistro", + "GamepadRightShoulder": "Pulsante dorsale destro", + "GamepadLeftTrigger": "Grilletto sinistro", + "GamepadRightTrigger": "Grilletto destro", + "GamepadDpadUp": "Su", + "GamepadDpadDown": "Giù", + "GamepadDpadLeft": "Sinistra", + "GamepadDpadRight": "Destra", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Grilletto sinistro 0", + "GamepadSingleRightTrigger0": "Grilletto destro 0", + "GamepadSingleLeftTrigger1": "Grilletto sinistro 1", + "GamepadSingleRightTrigger1": "Grilletto destro 1", + "StickLeft": "Levetta sinistra", + "StickRight": "Levetta destra", "UserProfilesSelectedUserProfile": "Profilo utente selezionato:", "UserProfilesSaveProfileName": "Salva nome del profilo", "UserProfilesChangeProfileImage": "Cambia immagine profilo", @@ -274,10 +385,10 @@ "ProfileImageSelectionNote": "Puoi importare un'immagine profilo personalizzata o selezionare un avatar dal firmware del sistema", "ProfileImageSelectionImportImage": "Importa file immagine", "ProfileImageSelectionSelectAvatar": "Seleziona avatar dal firmware", - "InputDialogTitle": "Finestra di dialogo ", + "InputDialogTitle": "Finestra di input", "InputDialogOk": "OK", "InputDialogCancel": "Annulla", - "InputDialogAddNewProfileTitle": "Scegli il nome profilo", + "InputDialogAddNewProfileTitle": "Scegli il nome del profilo", "InputDialogAddNewProfileHeader": "Digita un nome profilo", "InputDialogAddNewProfileSubtext": "(Lunghezza massima: {0})", "AvatarChoose": "Scegli", @@ -287,18 +398,14 @@ "ControllerSettingsAddProfileToolTip": "Aggiungi profilo", "ControllerSettingsRemoveProfileToolTip": "Rimuovi profilo", "ControllerSettingsSaveProfileToolTip": "Salva profilo", - "MenuBarFileToolsTakeScreenshot": "Fai uno screenshot", - "MenuBarFileToolsHideUi": "Nascondi UI", + "MenuBarFileToolsTakeScreenshot": "Cattura uno screenshot", + "MenuBarFileToolsHideUi": "Nascondi l'interfaccia", "GameListContextMenuRunApplication": "Esegui applicazione", "GameListContextMenuToggleFavorite": "Preferito", "GameListContextMenuToggleFavoriteToolTip": "Segna il gioco come preferito", - "SettingsTabGeneralTheme": "Tema", - "SettingsTabGeneralThemeCustomTheme": "Percorso del tema personalizzato", - "SettingsTabGeneralThemeBaseStyle": "Modalità", - "SettingsTabGeneralThemeBaseStyleDark": "Scura", - "SettingsTabGeneralThemeBaseStyleLight": "Chiara", - "SettingsTabGeneralThemeEnableCustomTheme": "Attiva tema personalizzato", - "ButtonBrowse": "Sfoglia", + "SettingsTabGeneralTheme": "Tema:", + "SettingsTabGeneralThemeDark": "Scuro", + "SettingsTabGeneralThemeLight": "Chiaro", "ControllerSettingsConfigureGeneral": "Configura", "ControllerSettingsRumble": "Vibrazione", "ControllerSettingsRumbleStrongMultiplier": "Moltiplicatore vibrazione forte", @@ -317,14 +424,14 @@ "DialogMessageFindSaveErrorMessage": "C'è stato un errore durante la ricerca dei dati di salvataggio: {0}", "FolderDialogExtractTitle": "Scegli una cartella in cui estrarre", "DialogNcaExtractionMessage": "Estrazione della sezione {0} da {1}...", - "DialogNcaExtractionTitle": "Ryujinx - Estrattore sezione NCA", + "DialogNcaExtractionTitle": "Ryujinx - Estrazione sezione NCA", "DialogNcaExtractionMainNcaNotFoundErrorMessage": "L'estrazione è fallita. L'NCA principale non era presente nel file selezionato.", - "DialogNcaExtractionCheckLogErrorMessage": "L'estrazione è fallita. Leggi il log per più informazioni.", + "DialogNcaExtractionCheckLogErrorMessage": "L'estrazione è fallita. Consulta il file di log per maggiori informazioni.", "DialogNcaExtractionSuccessMessage": "Estrazione completata con successo.", "DialogUpdaterConvertFailedMessage": "La conversione dell'attuale versione di Ryujinx è fallita.", - "DialogUpdaterCancelUpdateMessage": "Annullando l'aggiornamento!", + "DialogUpdaterCancelUpdateMessage": "Annullamento dell'aggiornamento in corso!", "DialogUpdaterAlreadyOnLatestVersionMessage": "Stai già usando la versione più recente di Ryujinx!", - "DialogUpdaterFailedToGetVersionMessage": "Si è verificato un errore durante il tentativo di ottenere informazioni sulla versione da GitHub Release. Ciò può essere causato se una nuova versione viene compilata da GitHub Actions. Riprova tra qualche minuto.", + "DialogUpdaterFailedToGetVersionMessage": "Si è verificato un errore durante il tentativo di recuperare le informazioni sulla versione da GitHub Release. Ciò può verificarsi se una nuova versione è in fase di compilazione da GitHub Actions. Riprova tra qualche minuto.", "DialogUpdaterConvertFailedGithubMessage": "La conversione della versione di Ryujinx ricevuta da Github Release è fallita.", "DialogUpdaterDownloadingMessage": "Download dell'aggiornamento...", "DialogUpdaterExtractionMessage": "Estrazione dell'aggiornamento...", @@ -332,14 +439,12 @@ "DialogUpdaterAddingFilesMessage": "Aggiunta del nuovo aggiornamento...", "DialogUpdaterCompleteMessage": "Aggiornamento completato!", "DialogUpdaterRestartMessage": "Vuoi riavviare Ryujinx adesso?", - "DialogUpdaterArchNotSupportedMessage": "Non stai usando un'architettura di sistema supportata!", - "DialogUpdaterArchNotSupportedSubMessage": "(Solo sistemi x64 sono supportati!)", "DialogUpdaterNoInternetMessage": "Non sei connesso ad Internet!", "DialogUpdaterNoInternetSubMessage": "Verifica di avere una connessione ad Internet funzionante!", "DialogUpdaterDirtyBuildMessage": "Non puoi aggiornare una Dirty build di Ryujinx!", "DialogUpdaterDirtyBuildSubMessage": "Scarica Ryujinx da https://ryujinx.org/ se stai cercando una versione supportata.", "DialogRestartRequiredMessage": "Riavvio richiesto", - "DialogThemeRestartMessage": "Il tema è stato salvato. E' richiesto un riavvio per applicare un tema.", + "DialogThemeRestartMessage": "Il tema è stato salvato. È richiesto un riavvio per applicare il tema.", "DialogThemeRestartSubMessage": "Vuoi riavviare?", "DialogFirmwareInstallEmbeddedMessage": "Vuoi installare il firmware incorporato in questo gioco? (Firmware {0})", "DialogFirmwareInstallEmbeddedSuccessMessage": "Non è stato trovato alcun firmware installato, ma Ryujinx è riuscito ad installare il firmware {0} dal gioco fornito.\nL'emulatore si avvierà adesso.", @@ -355,7 +460,7 @@ "DialogSoftwareKeyboardErrorExceptionMessage": "Errore nella visualizzazione della tastiera software: {0}", "DialogErrorAppletErrorExceptionMessage": "Errore nella visualizzazione dell'ErrorApplet Dialog: {0}", "DialogUserErrorDialogMessage": "{0}: {1}", - "DialogUserErrorDialogInfoMessage": "\nPer più informazioni su come risolvere questo errore, segui la nostra guida all'installazione.", + "DialogUserErrorDialogInfoMessage": "\nPer maggiori informazioni su come risolvere questo errore, segui la nostra guida all'installazione.", "DialogUserErrorDialogTitle": "Errore di Ryujinx ({0})", "DialogAmiiboApiTitle": "Amiibo API", "DialogAmiiboApiFailFetchMessage": "Si è verificato un errore durante il recupero delle informazioni dall'API.", @@ -365,10 +470,10 @@ "DialogProfileDeleteProfileTitle": "Eliminazione profilo", "DialogProfileDeleteProfileMessage": "Quest'azione è irreversibile, sei sicuro di voler continuare?", "DialogWarning": "Avviso", - "DialogPPTCDeletionMessage": "Stai per eliminare la PPTC cache per :\n\n{0}\n\nSei sicuro di voler proseguire?", - "DialogPPTCDeletionErrorMessage": "Errore nell'eliminazione della PPTC cache a {0}: {1}", - "DialogShaderDeletionMessage": "Stai per eliminare la Shader cache per :\n\n{0}\n\nSei sicuro di voler proseguire?", - "DialogShaderDeletionErrorMessage": "Errore nell'eliminazione della Shader cache a {0}: {1}", + "DialogPPTCDeletionMessage": "Stai per accodare la rigenerazione della cache PPTC al prossimo avvio per:\n\n{0}\n\nSei sicuro di voler proseguire?", + "DialogPPTCDeletionErrorMessage": "Errore nell'eliminazione della cache PPTC a {0}: {1}", + "DialogShaderDeletionMessage": "Stai per eliminare la cache degli shader per:\n\n{0}\n\nSei sicuro di voler proseguire?", + "DialogShaderDeletionErrorMessage": "Errore nell'eliminazione della cache degli shader a {0}: {1}", "DialogRyujinxErrorMessage": "Ryujinx ha incontrato un errore", "DialogInvalidTitleIdErrorMessage": "Errore UI: Il gioco selezionato non ha un ID titolo valido", "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Un firmware del sistema valido non è stato trovato in {0}.", @@ -385,26 +490,31 @@ "DialogUserProfileUnsavedChangesSubMessage": "Vuoi scartare le modifiche?", "DialogControllerSettingsModifiedConfirmMessage": "Le attuali impostazioni del controller sono state aggiornate.", "DialogControllerSettingsModifiedConfirmSubMessage": "Vuoi salvare?", - "DialogLoadNcaErrorMessage": "{0}. File errato: {1}", + "DialogLoadFileErrorMessage": "{0}. Errore File: {1}", + "DialogModAlreadyExistsMessage": "La mod risulta già installata", + "DialogModInvalidMessage": "La cartella specificata non contiene nessuna mod!", + "DialogModDeleteNoParentMessage": "Eliminazione non riuscita: impossibile trovare la directory superiore per la mod \"{0}\"!", "DialogDlcNoDlcErrorMessage": "Il file specificato non contiene un DLC per il titolo selezionato!", "DialogPerformanceCheckLoggingEnabledMessage": "Hai abilitato il trace logging, che è progettato per essere usato solo dagli sviluppatori.", - "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare il trace logging. Vuoi disabilitare il debug logging adesso?", - "DialogPerformanceCheckShaderDumpEnabledMessage": "Hai abilitato lo shader dumping, che è progettato per essere usato solo dagli sviluppatori.", - "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare lo shader dumping. Vuoi disabilitare lo shader dumping adesso?", + "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare il trace logging. Vuoi disabilitarlo adesso?", + "DialogPerformanceCheckShaderDumpEnabledMessage": "Hai abilitato il dump degli shader, che è progettato per essere usato solo dagli sviluppatori.", + "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare il dump degli shader. Vuoi disabilitarlo adesso?", "DialogLoadAppGameAlreadyLoadedMessage": "Un gioco è già stato caricato", "DialogLoadAppGameAlreadyLoadedSubMessage": "Ferma l'emulazione o chiudi l'emulatore prima di avviare un altro gioco.", "DialogUpdateAddUpdateErrorMessage": "Il file specificato non contiene un aggiornamento per il titolo selezionato!", "DialogSettingsBackendThreadingWarningTitle": "Avviso - Backend Threading", "DialogSettingsBackendThreadingWarningMessage": "Ryujinx deve essere riavviato dopo aver cambiato questa opzione per applicarla completamente. A seconda della tua piattaforma, potrebbe essere necessario disabilitare manualmente il multithreading del driver quando usi quello di Ryujinx.", + "DialogModManagerDeletionWarningMessage": "Stai per eliminare la mod: {0}\n\nConfermi di voler procedere?", + "DialogModManagerDeletionAllWarningMessage": "Stai per eliminare tutte le mod per questo titolo.\n\nVuoi davvero procedere?", "SettingsTabGraphicsFeaturesOptions": "Funzionalità", - "SettingsTabGraphicsBackendMultithreading": "Graphics Backend Multithreading", + "SettingsTabGraphicsBackendMultithreading": "Multithreading del backend grafico:", "CommonAuto": "Auto", - "CommonOff": "Spento", - "CommonOn": "Acceso", - "InputDialogYes": "Si", + "CommonOff": "Disattivato", + "CommonOn": "Attivo", + "InputDialogYes": "Sì", "InputDialogNo": "No", - "DialogProfileInvalidProfileNameErrorMessage": "Il nome del file contiene caratteri non validi. Riprova.", - "MenuBarOptionsPauseEmulation": "Pausa", + "DialogProfileInvalidProfileNameErrorMessage": "Il nome del file contiene dei caratteri non validi. Riprova.", + "MenuBarOptionsPauseEmulation": "Metti in pausa", "MenuBarOptionsResumeEmulation": "Riprendi", "AboutUrlTooltipMessage": "Clicca per aprire il sito web di Ryujinx nel tuo browser predefinito.", "AboutDisclaimerMessage": "Ryujinx non è affiliato con Nintendo™,\no i suoi partner, in alcun modo.", @@ -414,15 +524,15 @@ "AboutDiscordUrlTooltipMessage": "Clicca per aprire un invito al server Discord di Ryujinx nel tuo browser predefinito.", "AboutTwitterUrlTooltipMessage": "Clicca per aprire la pagina Twitter di Ryujinx nel tuo browser predefinito.", "AboutRyujinxAboutTitle": "Informazioni:", - "AboutRyujinxAboutContent": "Ryujinx è un emulatore per la Nintendo Switch™.\nPer favore supportaci su Patreon.\nRicevi tutte le ultime notizie sul nostro Twitter o su Discord.\nGli sviluppatori interessati a contribuire possono trovare più informazioni sul nostro GitHub o Discord.", + "AboutRyujinxAboutContent": "Ryujinx è un emulatore per la console Nintendo Switch™.\nSostienici su Patreon.\nRicevi tutte le ultime notizie sul nostro Twitter o su Discord.\nGli sviluppatori interessati a contribuire possono trovare più informazioni sul nostro GitHub o Discord.", "AboutRyujinxMaintainersTitle": "Mantenuto da:", - "AboutRyujinxMaintainersContentTooltipMessage": "Clicca per aprire la pagina dei Contributors nel tuo browser predefinito.", + "AboutRyujinxMaintainersContentTooltipMessage": "Clicca per aprire la pagina dei contributori nel tuo browser predefinito.", "AboutRyujinxSupprtersTitle": "Supportato su Patreon da:", "AmiiboSeriesLabel": "Serie Amiibo", "AmiiboCharacterLabel": "Personaggio", - "AmiiboScanButtonLabel": "Scannerizza", + "AmiiboScanButtonLabel": "Scansiona", "AmiiboOptionsShowAllLabel": "Mostra tutti gli amiibo", - "AmiiboOptionsUsRandomTagLabel": "Hack: Usa un tag uuid casuale", + "AmiiboOptionsUsRandomTagLabel": "Espediente: Usa un UUID del tag casuale", "DlcManagerTableHeadingEnabledLabel": "Abilitato", "DlcManagerTableHeadingTitleIdLabel": "ID Titolo", "DlcManagerTableHeadingContainerPathLabel": "Percorso del contenitore", @@ -430,6 +540,7 @@ "DlcManagerRemoveAllButton": "Rimuovi tutti", "DlcManagerEnableAllButton": "Abilita tutto", "DlcManagerDisableAllButton": "Disabilita tutto", + "ModManagerDeleteAllButton": "Elimina tutto", "MenuBarOptionsChangeLanguage": "Cambia lingua", "MenuBarShowFileTypes": "Mostra tipi di file", "CommonSort": "Ordina", @@ -437,73 +548,75 @@ "CommonFavorite": "Preferito", "OrderAscending": "Crescente", "OrderDescending": "Decrescente", - "SettingsTabGraphicsFeatures": "Funzionalità & Miglioramenti", - "ErrorWindowTitle": "Finestra errore", - "ToggleDiscordTooltip": "Attiva o disattiva Discord Rich Presence", - "AddGameDirBoxTooltip": "Inserisci la directory di un gioco per aggiungerlo alla lista", - "AddGameDirTooltip": "Aggiungi la directory di un gioco alla lista", - "RemoveGameDirTooltip": "Rimuovi la directory di gioco selezionata", + "SettingsTabGraphicsFeatures": "Funzionalità e miglioramenti", + "ErrorWindowTitle": "Finestra di errore", + "ToggleDiscordTooltip": "Scegli se mostrare o meno Ryujinx nella tua attività su Discord", + "AddGameDirBoxTooltip": "Inserisci una cartella dei giochi per aggiungerla alla lista", + "AddGameDirTooltip": "Aggiungi una cartella dei giochi alla lista", + "RemoveGameDirTooltip": "Rimuovi la cartella dei giochi selezionata", "CustomThemeCheckTooltip": "Attiva o disattiva temi personalizzati nella GUI", "CustomThemePathTooltip": "Percorso al tema GUI personalizzato", "CustomThemeBrowseTooltip": "Sfoglia per cercare un tema GUI personalizzato", - "DockModeToggleTooltip": "Attiva o disabilta modalità TV", - "DirectKeyboardTooltip": "Attiva o disattiva \"il supporto all'accesso diretto alla tastiera (HID)\" (Fornisce l'accesso ai giochi alla tua tastiera come dispositivo di immissione del testo)", - "DirectMouseTooltip": "Attiva o disattiva \"il supporto all'accesso diretto al mouse (HID)\" (Fornisce l'accesso ai giochi al tuo mouse come dispositivo di puntamento)", + "DockModeToggleTooltip": "La modalità TV fa sì che il sistema emulato si comporti come una Nintendo Switch posizionata nella sua base. Ciò migliora la qualità grafica nella maggior parte dei giochi. Al contrario, disabilitandola il sistema emulato si comporterà come una Nintendo Switch in modalità portatile, riducendo la qualità grafica.\n\nConfigura i controlli del giocatore 1 se intendi usare la modalità TV; configura i controlli della modalità portatile se intendi usare quest'ultima.\n\nNel dubbio, lascia l'opzione attiva.", + "DirectKeyboardTooltip": "Supporto per l'accesso diretto alla tastiera (HID). Fornisce ai giochi l'accesso alla tastiera come dispositivo di inserimento del testo.\n\nFunziona solo con i giochi che supportano nativamente l'utilizzo della tastiera su hardware Switch.\n\nNel dubbio, lascia l'opzione disattivata.", + "DirectMouseTooltip": "Supporto per l'accesso diretto al mouse (HID). Fornisce ai giochi l'accesso al mouse come dispositivo di puntamento.\n\nFunziona solo con i rari giochi che supportano nativamente l'utilizzo del mouse su hardware Switch.\n\nQuando questa opzione è attivata, il touchscreen potrebbe non funzionare.\n\nNel dubbio, lascia l'opzione disattivata.", "RegionTooltip": "Cambia regione di sistema", "LanguageTooltip": "Cambia lingua di sistema", "TimezoneTooltip": "Cambia fuso orario di sistema", "TimeTooltip": "Cambia data e ora di sistema", - "VSyncToggleTooltip": "Attiva o disattiva sincronizzazione verticale", - "PptcToggleTooltip": "Attiva o disattiva PPTC", - "FsIntegrityToggleTooltip": "Attiva controlli d'integrità sui file dei contenuti di gioco", - "AudioBackendTooltip": "Cambia backend audio", - "MemoryManagerTooltip": "Cambia il modo in cui la memoria guest è mappata e vi si accede. Influisce notevolmente sulle prestazioni della CPU emulata.", + "VSyncToggleTooltip": "Sincronizzazione verticale della console Emulata. Essenzialmente un limitatore di frame per la maggior parte dei giochi; disabilitarlo può far girare giochi a velocità più alta, allungare le schermate di caricamento o farle bloccare.\n\nPuò essere attivata in gioco con un tasto di scelta rapida (F1 per impostazione predefinita). Ti consigliamo di farlo se hai intenzione di disabilitarlo.\n\nLascia ON se non sei sicuro.", + "PptcToggleTooltip": "Salva le funzioni JIT tradotte in modo che non debbano essere tradotte tutte le volte che si avvia un determinato gioco.\n\nRiduce i fenomeni di stuttering e velocizza sensibilmente gli avvii successivi del gioco.\n\nNel dubbio, lascia l'opzione attiva.", + "FsIntegrityToggleTooltip": "Controlla la presenza di file corrotti quando si avvia un gioco. Se vengono rilevati dei file corrotti, verrà mostrato un errore di hash nel log.\n\nQuesta opzione non influisce sulle prestazioni ed è pensata per facilitare la risoluzione dei problemi.\n\nNel dubbio, lascia l'opzione attiva.", + "AudioBackendTooltip": "Cambia il backend usato per riprodurre l'audio.\n\nSDL2 è quello preferito, mentre OpenAL e SoundIO sono usati come ripiego. Dummy non riprodurrà alcun suono.\n\nNel dubbio, imposta l'opzione su SDL2.", + "MemoryManagerTooltip": "Cambia il modo in cui la memoria guest è mappata e vi si accede. Influisce notevolmente sulle prestazioni della CPU emulata.\n\nNel dubbio, imposta l'opzione su Host Unchecked.", "MemoryManagerSoftwareTooltip": "Usa una software page table per la traduzione degli indirizzi. Massima precisione ma prestazioni più lente.", "MemoryManagerHostTooltip": "Mappa direttamente la memoria nello spazio degli indirizzi dell'host. Compilazione ed esecuzione JIT molto più veloce.", "MemoryManagerUnsafeTooltip": "Mappa direttamente la memoria, ma non maschera l'indirizzo all'interno dello spazio degli indirizzi guest prima dell'accesso. Più veloce, ma a costo della sicurezza. L'applicazione guest può accedere alla memoria da qualsiasi punto di Ryujinx, quindi esegui solo programmi di cui ti fidi con questa modalità.", "UseHypervisorTooltip": "Usa Hypervisor invece di JIT. Migliora notevolmente le prestazioni quando disponibile, ma può essere instabile nel suo stato attuale.", - "DRamTooltip": "Espande l'ammontare di memoria sul sistema emulato da 4GiB A 6GiB", - "IgnoreMissingServicesTooltip": "Attiva o disattiva l'opzione di ignorare i servizi mancanti", - "GraphicsBackendThreadingTooltip": "Attiva il Graphics Backend Multithreading", - "GalThreadingTooltip": "Esegue i comandi del backend grafico su un secondo thread. Permette il multithreading runtime della compilazione degli shader, riduce lo stuttering e migliora le prestazioni sui driver senza supporto multithreading proprio. Varia leggermente le prestazioni di picco sui driver con multithreading. Ryujinx potrebbe aver bisogno di essere riavviato per disabilitare correttamente il multithreading integrato nel driver, o potrebbe essere necessario farlo manualmente per ottenere le migliori prestazioni.", - "ShaderCacheToggleTooltip": "Attiva o disattiva la Shader Cache", - "ResolutionScaleTooltip": "Scala della risoluzione applicata ai render targets applicabili", + "DRamTooltip": "Utilizza un layout di memoria alternativo per imitare un'unità di sviluppo di Switch.\n\nQuesta opzione è utile soltanto per i pacchetti di texture ad alta risoluzione o per le mod che aumentano la risoluzione a 4K. NON migliora le prestazioni.\n\nNel dubbio, lascia l'opzione disattivata.", + "IgnoreMissingServicesTooltip": "Ignora i servizi non implementati del sistema operativo Horizon. Può aiutare ad aggirare gli arresti anomali che si verificano avviando alcuni giochi.\n\nNel dubbio, lascia l'opzione disattivata.", + "GraphicsBackendThreadingTooltip": "Esegue i comandi del backend grafico su un secondo thread.\n\nVelocizza la compilazione degli shader, riduce lo stuttering e migliora le prestazioni sui driver grafici senza il supporto integrato al multithreading. Migliora leggermente le prestazioni sui driver che supportano il multithreading.\n\nNel dubbio, imposta l'opzione su Auto.", + "GalThreadingTooltip": "Esegue i comandi del backend grafico su un secondo thread.\n\nVelocizza la compilazione degli shader, riduce lo stuttering e migliora le prestazioni sui driver grafici senza il supporto integrato al multithreading. Migliora leggermente le prestazioni sui driver che supportano il multithreading.\n\nNel dubbio, imposta l'opzione su Auto.", + "ShaderCacheToggleTooltip": "Salva una cache degli shader su disco che riduce i fenomeni di stuttering nelle esecuzioni successive.\n\nNel dubbio, lascia l'opzione attiva.", + "ResolutionScaleTooltip": "Moltiplica la risoluzione di rendering del gioco.\n\nAlcuni giochi potrebbero non funzionare con questa opzione e sembrare pixelati anche quando la risoluzione è aumentata; per quei giochi, potrebbe essere necessario trovare mod che rimuovono l'anti-aliasing o che aumentano la risoluzione di rendering interna. Per quest'ultimo caso, probabilmente dovrai selezionare Nativo (1x).\n\nQuesta opzione può essere modificata mentre un gioco è in esecuzione facendo clic su \"Applica\" qui sotto; puoi semplicemente spostare la finestra delle impostazioni da parte e sperimentare fino a quando non trovi il tuo look preferito per un gioco.\n\nTenete a mente che 4x è troppo per praticamente qualsiasi configurazione.", "ResolutionScaleEntryTooltip": "Scala della risoluzione in virgola mobile, come 1,5. Le scale non integrali hanno maggiori probabilità di causare problemi o crash.", - "AnisotropyTooltip": "Livello del filtro anisotropico (imposta su Auto per usare il valore richiesto dal gioco)", - "AspectRatioTooltip": "Rapporto d'aspetto applicato alla finestra del renderer.", - "ShaderDumpPathTooltip": "Percorso di dump Graphics Shaders", - "FileLogTooltip": "Attiva o disattiva il logging su file", - "StubLogTooltip": "Attiva messaggi stub log", - "InfoLogTooltip": "Attiva messaggi info log", - "WarnLogTooltip": "Attiva messaggi warning log", - "ErrorLogTooltip": "Attiva messaggi error log", - "TraceLogTooltip": "Attiva messaggi trace log", - "GuestLogTooltip": "Attiva messaggi guest log", - "FileAccessLogTooltip": "Attiva messaggi file access log", - "FSAccessLogModeTooltip": "Attiva output FS access log alla console. Le modalità possibili sono 0-3", + "AnisotropyTooltip": "Livello del filtro anisotropico. Imposta su Auto per usare il valore richiesto dal gioco.", + "AspectRatioTooltip": "Proporzioni dello schermo applicate alla finestra di renderizzazione.\n\nCambialo solo se stai usando una mod di proporzioni per il tuo gioco, altrimenti la grafica verrà allungata.\n\nLasciare il 16:9 se incerto.", + "ShaderDumpPathTooltip": "Percorso di dump degli shader", + "FileLogTooltip": "Salva il log della console in un file su disco. Non influisce sulle prestazioni.", + "StubLogTooltip": "Stampa i messaggi di log relativi alle stub nella console. Non influisce sulle prestazioni.", + "InfoLogTooltip": "Stampa i messaggi di log informativi nella console. Non influisce sulle prestazioni.", + "WarnLogTooltip": "Stampa i messaggi di log relativi agli avvisi nella console. Non influisce sulle prestazioni.", + "ErrorLogTooltip": "Stampa i messaggi di log relativi agli errori nella console. Non influisce sulle prestazioni.", + "TraceLogTooltip": "Stampa i messaggi di log relativi al trace nella console. Non influisce sulle prestazioni.", + "GuestLogTooltip": "Stampa i messaggi di log del guest nella console. Non influisce sulle prestazioni.", + "FileAccessLogTooltip": "Stampa i messaggi di log relativi all'accesso ai file nella console.", + "FSAccessLogModeTooltip": "Attiva l'output dei log di accesso FS nella console. Le modalità possibili vanno da 0 a 3", "DeveloperOptionTooltip": "Usa con attenzione", - "OpenGlLogLevel": "Richiede livelli di log appropriati abilitati", - "DebugLogTooltip": "Attiva messaggi debug log", + "OpenGlLogLevel": "Richiede che i livelli di log appropriati siano abilitati", + "DebugLogTooltip": "Stampa i messaggi di log per il debug nella console.\n\nUsa questa opzione solo se specificatamente richiesto da un membro del team, dal momento che rende i log difficili da leggere e riduce le prestazioni dell'emulatore.", "LoadApplicationFileTooltip": "Apri un file explorer per scegliere un file compatibile Switch da caricare", "LoadApplicationFolderTooltip": "Apri un file explorer per scegliere un file compatibile Switch, applicazione sfusa da caricare", "OpenRyujinxFolderTooltip": "Apri la cartella del filesystem di Ryujinx", - "OpenRyujinxLogsTooltip": "Apre la cartella dove vengono scritti i log", + "OpenRyujinxLogsTooltip": "Apre la cartella dove vengono salvati i log", "ExitTooltip": "Esci da Ryujinx", - "OpenSettingsTooltip": "Apri finestra delle impostazioni", + "OpenSettingsTooltip": "Apri la finestra delle impostazioni", "OpenProfileManagerTooltip": "Apri la finestra di gestione dei profili utente", "StopEmulationTooltip": "Ferma l'emulazione del gioco attuale e torna alla selezione dei giochi", "CheckUpdatesTooltip": "Controlla la presenza di aggiornamenti di Ryujinx", - "OpenAboutTooltip": "Apri finestra delle informazioni", + "OpenAboutTooltip": "Apri la finestra delle informazioni", "GridSize": "Dimensione griglia", - "GridSizeTooltip": "Cambia la dimensione dei riquardi della griglia", - "SettingsTabSystemSystemLanguageBrazilianPortuguese": "Portoghese Brasiliano", - "AboutRyujinxContributorsButtonHeader": "Vedi tutti i Contributors", + "GridSizeTooltip": "Cambia la dimensione dei riquadri della griglia", + "SettingsTabSystemSystemLanguageBrazilianPortuguese": "Portoghese brasiliano", + "AboutRyujinxContributorsButtonHeader": "Mostra tutti i contributori", "SettingsTabSystemAudioVolume": "Volume: ", "AudioVolumeTooltip": "Cambia volume audio", - "SettingsTabSystemEnableInternetAccess": "Attiva Guest Internet Access", - "EnableInternetAccessTooltip": "Attiva il guest Internet access. Se abilitato, l'applicazione si comporterà come se la console Switch emulata fosse collegata a Internet. Si noti che in alcuni casi, le applicazioni possono comunque accedere a Internet anche con questa opzione disabilitata", - "GameListContextMenuManageCheatToolTip": "Gestisci Cheats", - "GameListContextMenuManageCheat": "Gestisci Cheats", + "SettingsTabSystemEnableInternetAccess": "Attiva l'accesso a Internet da parte del guest/Modalità LAN", + "EnableInternetAccessTooltip": "Consente all'applicazione emulata di connettersi a Internet.\n\nI giochi che dispongono di una modalità LAN possono connettersi tra di loro quando questa opzione è abilitata e sono connessi alla stessa rete, comprese le console reali.\n\nQuesta opzione NON consente la connessione ai server di Nintendo. Potrebbe causare arresti anomali in alcuni giochi che provano a connettersi a Internet.\n\nNel dubbio, lascia l'opzione disattivata.", + "GameListContextMenuManageCheatToolTip": "Gestisci trucchi", + "GameListContextMenuManageCheat": "Gestisci trucchi", + "GameListContextMenuManageModToolTip": "Gestisci mod", + "GameListContextMenuManageMod": "Gestisci mod", "ControllerSettingsStickRange": "Raggio:", "DialogStopEmulationTitle": "Ryujinx - Ferma emulazione", "DialogStopEmulationMessage": "Sei sicuro di voler fermare l'emulazione?", @@ -512,16 +625,14 @@ "SettingsTabNetwork": "Rete", "SettingsTabNetworkConnection": "Connessione di rete", "SettingsTabCpuCache": "Cache CPU", - "SettingsTabCpuMemory": "Memoria CPU", - "DialogUpdaterFlatpakNotSupportedMessage": "Per favore aggiorna Ryujinx via FlatHub.", + "SettingsTabCpuMemory": "Modalità CPU", + "DialogUpdaterFlatpakNotSupportedMessage": "Aggiorna Ryujinx tramite FlatHub.", "UpdaterDisabledWarningTitle": "Updater disabilitato!", - "GameListContextMenuOpenSdModsDirectory": "Apri cartella delle mods Atmosphere", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Apre la cartella Atmosphere della scheda SD alternativa che contiene le Mod dell'applicazione. Utile per mod confezionate per hardware reale", "ControllerSettingsRotate90": "Ruota in senso orario di 90°", - "IconSize": "Dimensioni icona", - "IconSizeTooltip": "Cambia le dimensioni dell'icona di un gioco", + "IconSize": "Dimensioni icone", + "IconSizeTooltip": "Cambia le dimensioni delle icone dei giochi", "MenuBarOptionsShowConsole": "Mostra console", - "ShaderCachePurgeError": "Errore nella pulizia della shader cache a {0}: {1}", + "ShaderCachePurgeError": "Errore nell'eliminazione della cache degli shader a {0}: {1}", "UserErrorNoKeys": "Chiavi non trovate", "UserErrorNoFirmware": "Firmware non trovato", "UserErrorFirmwareParsingFailed": "Errori di analisi del firmware", @@ -533,10 +644,10 @@ "UserErrorFirmwareParsingFailedDescription": "Ryujinx non è riuscito ad analizzare il firmware. Questo di solito è causato da chiavi non aggiornate.", "UserErrorApplicationNotFoundDescription": "Ryujinx non è riuscito a trovare un'applicazione valida nel percorso specificato.", "UserErrorUnknownDescription": "Si è verificato un errore sconosciuto!", - "UserErrorUndefinedDescription": "Si è verificato un errore sconosciuto! Non dovrebbe succedere, per favore contatta uno sviluppatore!", + "UserErrorUndefinedDescription": "Si è verificato un errore sconosciuto! Ciò non dovrebbe accadere, contatta uno sviluppatore!", "OpenSetupGuideMessage": "Apri la guida all'installazione", "NoUpdate": "Nessun aggiornamento", - "TitleUpdateVersionLabel": "Versione {0} - {1}", + "TitleUpdateVersionLabel": "Versione {0}", "RyujinxInfo": "Ryujinx - Info", "RyujinxConfirm": "Ryujinx - Conferma", "FileDialogAllTypes": "Tutti i tipi", @@ -544,17 +655,18 @@ "SwkbdMinCharacters": "Non può avere meno di {0} caratteri", "SwkbdMinRangeCharacters": "Può avere da {0} a {1} caratteri", "SoftwareKeyboard": "Tastiera software", - "SoftwareKeyboardModeNumbersOnly": "Deve essere solo numeri", + "SoftwareKeyboardModeNumeric": "Deve essere solo 0-9 o '.'", "SoftwareKeyboardModeAlphabet": "Deve essere solo caratteri non CJK", "SoftwareKeyboardModeASCII": "Deve essere solo testo ASCII", - "DialogControllerAppletMessagePlayerRange": "L'applicazione richiede {0} giocatori con:\n\nTIPI: {1}\n\nGIOCATORI: {2}\n\n{3}Apri le impostazioni e riconfigura l'input adesso o premi Chiudi.", - "DialogControllerAppletMessage": "L'applicazione richiede esattamente {0} giocatori con:\n\nTIPI: {1}\n\nGIOCATORI: {2}\n\n{3}Apri le impostazioni e riconfigura l'input adesso o premi Chiudi.", - "DialogControllerAppletDockModeSet": "Modalità TV attivata. Neanche portatile è valida.\n\n", + "ControllerAppletControllers": "Controller supportati:", + "ControllerAppletPlayers": "Giocatori:", + "ControllerAppletDescription": "La configurazione corrente non è valida. Aprire le impostazioni e riconfigurare gli input.", + "ControllerAppletDocked": "Modalità TV attivata. Gli input della modalità portatile dovrebbero essere disabilitati.", "UpdaterRenaming": "Rinominazione dei vecchi files...", - "UpdaterRenameFailed": "L'updater non è riuscito a rinominare il file: {0}", - "UpdaterAddingFiles": "Aggiunta nuovi files...", - "UpdaterExtracting": "Estrazione aggiornamento...", - "UpdaterDownloading": "Download aggiornamento...", + "UpdaterRenameFailed": "Non è stato possibile rinominare il file: {0}", + "UpdaterAddingFiles": "Aggiunta dei nuovi file...", + "UpdaterExtracting": "Estrazione dell'aggiornamento...", + "UpdaterDownloading": "Download dell'aggiornamento...", "Game": "Gioco", "Docked": "TV", "Handheld": "Portatile", @@ -562,20 +674,20 @@ "AboutPageDeveloperListMore": "{0} e altri ancora...", "ApiError": "Errore dell'API.", "LoadingHeading": "Caricamento di {0}", - "CompilingPPTC": "Compilazione PTC", - "CompilingShaders": "Compilazione Shaders", + "CompilingPPTC": "Compilazione PPTC", + "CompilingShaders": "Compilazione degli shader", "AllKeyboards": "Tutte le tastiere", "OpenFileDialogTitle": "Seleziona un file supportato da aprire", "OpenFolderDialogTitle": "Seleziona una cartella con un gioco estratto", "AllSupportedFormats": "Tutti i formati supportati", - "RyujinxUpdater": "Aggiornamento Ryujinx", + "RyujinxUpdater": "Aggiornamento di Ryujinx", "SettingsTabHotkeys": "Tasti di scelta rapida", "SettingsTabHotkeysHotkeys": "Tasti di scelta rapida", - "SettingsTabHotkeysToggleVsyncHotkey": "VSync:", - "SettingsTabHotkeysScreenshotHotkey": "Cattura Schermo:", - "SettingsTabHotkeysShowUiHotkey": "Mostra UI:", + "SettingsTabHotkeysToggleVsyncHotkey": "Attiva/disattiva VSync:", + "SettingsTabHotkeysScreenshotHotkey": "Cattura uno screenshot:", + "SettingsTabHotkeysShowUiHotkey": "Mostra l'interfaccia:", "SettingsTabHotkeysPauseHotkey": "Metti in pausa:", - "SettingsTabHotkeysToggleMuteHotkey": "Muta:", + "SettingsTabHotkeysToggleMuteHotkey": "Disattiva l'audio:", "ControllerMotionTitle": "Impostazioni dei sensori di movimento", "ControllerRumbleTitle": "Impostazioni di vibrazione", "SettingsSelectThemeFileDialogTitle": "Seleziona file del tema", @@ -587,60 +699,67 @@ "Writable": "Scrivibile", "SelectDlcDialogTitle": "Seleziona file dei DLC", "SelectUpdateDialogTitle": "Seleziona file di aggiornamento", - "UserProfileWindowTitle": "Gestisci profili degli utenti", - "CheatWindowTitle": "Gestisci cheat dei giochi", - "DlcWindowTitle": "Gestisci DLC dei giochi", - "UpdateWindowTitle": "Gestisci aggiornamenti dei giochi", - "CheatWindowHeading": "Cheat disponibiili per {0} [{1}]", + "SelectModDialogTitle": "Seleziona cartella delle mod", + "UserProfileWindowTitle": "Gestione profili utente", + "CheatWindowTitle": "Gestione trucchi", + "DlcWindowTitle": "Gestisci DLC per {0} ({1})", + "ModWindowTitle": "Gestisci mod per {0} ({1})", + "UpdateWindowTitle": "Gestione aggiornamenti", + "CheatWindowHeading": "Trucchi disponibili per {0} [{1}]", "BuildId": "ID Build", "DlcWindowHeading": "DLC disponibili per {0} [{1}]", + "ModWindowHeading": "{0} mod", "UserProfilesEditProfile": "Modifica selezionati", "Cancel": "Annulla", "Save": "Salva", "Discard": "Scarta", + "Paused": "In pausa", "UserProfilesSetProfileImage": "Imposta immagine profilo", - "UserProfileEmptyNameError": "È richiesto un nome", + "UserProfileEmptyNameError": "Il nome è obbligatorio", "UserProfileNoImageError": "Dev'essere impostata un'immagine profilo", - "GameUpdateWindowHeading": "Aggiornamenti disponibili per {0} [{1}]", - "SettingsTabHotkeysResScaleUpHotkey": "Aumentare la risoluzione:", - "SettingsTabHotkeysResScaleDownHotkey": "Diminuire la risoluzione:", + "GameUpdateWindowHeading": "Gestisci aggiornamenti per {0} ({1})", + "SettingsTabHotkeysResScaleUpHotkey": "Aumenta la risoluzione:", + "SettingsTabHotkeysResScaleDownHotkey": "Riduci la risoluzione:", "UserProfilesName": "Nome:", "UserProfilesUserId": "ID utente:", - "SettingsTabGraphicsBackend": "Backend grafica", - "SettingsTabGraphicsBackendTooltip": "Backend grafica da usare", - "SettingsEnableTextureRecompression": "Abilita Ricompressione Texture", - "SettingsEnableTextureRecompressionTooltip": "Comprime alcune texture per ridurre l'utilizzo della VRAM.\n\nL'utilizzo è consigliato con GPU con meno di 4GB di VRAM.\n\nLascia su OFF se non sei sicuro.", + "SettingsTabGraphicsBackend": "Backend grafico", + "SettingsTabGraphicsBackendTooltip": "Seleziona il backend grafico che verrà utilizzato nell'emulatore.\n\nVulkan è nel complesso migliore per tutte le schede grafiche moderne, a condizione che i relativi driver siano aggiornati. Vulkan dispone anche di una compilazione degli shader più veloce (con minore stuttering) su tutte le marche di GPU.\n\nOpenGL può ottenere risultati migliori su vecchie GPU Nvidia, su vecchie GPU AMD su Linux, o su GPU con poca VRAM, anche se lo stuttering dovuto alla compilazione degli shader sarà maggiore.\n\nNel dubbio, scegli Vulkan. Seleziona OpenGL se la GPU non supporta Vulkan nemmeno con i driver grafici più recenti.", + "SettingsEnableTextureRecompression": "Attiva la ricompressione delle texture", + "SettingsEnableTextureRecompressionTooltip": "Comprime le texture ASTC per ridurre l'utilizzo di VRAM.\n\nI giochi che utilizzano questo formato di texture includono Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder e The Legend of Zelda: Tears of the Kingdom.\n\nLe schede grafiche con 4GiB o meno di VRAM probabilmente si bloccheranno ad un certo punto durante l'esecuzione di questi giochi.\n\nAttiva questa opzione solo se sei a corto di VRAM nei giochi sopra menzionati. Nel dubbio, lascia l'opzione disattivata.", "SettingsTabGraphicsPreferredGpu": "GPU preferita", "SettingsTabGraphicsPreferredGpuTooltip": "Seleziona la scheda grafica che verrà usata con la backend grafica Vulkan.\n\nNon influenza la GPU che userà OpenGL.\n\nImposta la GPU contrassegnata come \"dGPU\" se non sei sicuro. Se non ce n'è una, lascia intatta quest'impostazione.", "SettingsAppRequiredRestartMessage": "È richiesto un riavvio di Ryujinx", "SettingsGpuBackendRestartMessage": "Le impostazioni della backend grafica o della GPU sono state modificate. Questo richiederà un riavvio perché le modifiche siano applicate", "SettingsGpuBackendRestartSubMessage": "Vuoi riavviare ora?", "RyujinxUpdaterMessage": "Vuoi aggiornare Ryujinx all'ultima versione?", - "SettingsTabHotkeysVolumeUpHotkey": "Aumentare il volume:", - "SettingsTabHotkeysVolumeDownHotkey": "Diminuire il volume:", - "SettingsEnableMacroHLE": "Abilita Macro HLE", - "SettingsEnableMacroHLETooltip": "Emulazione di alto livello del codice Macro GPU.\n\nMigliora le prestazioni, ma può causare anomalie grafiche in alcuni giochi.\n\nLasciare ON se non sei sicuro.", - "SettingsEnableColorSpacePassthrough": "Spazio colore passante", - "SettingsEnableColorSpacePassthroughTooltip": "Indica al backend Vulkan di passare le informazioni sul colore senza specificare uno spazio colore. Per gli utenti con schermi ad ampia gamma, questo può risultare in colori più vivaci, al costo della correttezza del colore.", + "SettingsTabHotkeysVolumeUpHotkey": "Alza il volume:", + "SettingsTabHotkeysVolumeDownHotkey": "Abbassa il volume:", + "SettingsEnableMacroHLE": "Attiva HLE macro", + "SettingsEnableMacroHLETooltip": "Emulazione di alto livello del codice macro della GPU.\n\nMigliora le prestazioni, ma può causare anomalie grafiche in alcuni giochi.\n\nNel dubbio, lascia l'opzione attiva.", + "SettingsEnableColorSpacePassthrough": "Passthrough dello spazio dei colori", + "SettingsEnableColorSpacePassthroughTooltip": "Indica al backend Vulkan di passare le informazioni sul colore senza specificare uno spazio dei colori. Per gli utenti con schermi ad ampia gamma, ciò può rendere i colori più vivaci, sacrificando la correttezza del colore.", "VolumeShort": "Vol", "UserProfilesManageSaves": "Gestisci i salvataggi", "DeleteUserSave": "Vuoi eliminare il salvataggio utente per questo gioco?", "IrreversibleActionNote": "Questa azione non è reversibile.", - "SaveManagerHeading": "Gestisci i salvataggi per {0}", - "SaveManagerTitle": "Gestione Salvataggi", + "SaveManagerHeading": "Gestisci salvataggi per {0} ({1})", + "SaveManagerTitle": "Gestione salvataggi", "Name": "Nome", "Size": "Dimensione", "Search": "Cerca", - "UserProfilesRecoverLostAccounts": "Recupera il tuo account", + "UserProfilesRecoverLostAccounts": "Recupera account persi", "Recover": "Recupera", "UserProfilesRecoverHeading": "Sono stati trovati dei salvataggi per i seguenti account", "UserProfilesRecoverEmptyList": "Nessun profilo da recuperare", - "GraphicsAATooltip": "Applica anti-aliasing al rendering del gioco", + "GraphicsAATooltip": "Applica anti-aliasing al rendering del gioco.\n\nFXAA sfocerà la maggior parte dell'immagine, mentre SMAA tenterà di trovare bordi frastagliati e lisciarli.\n\nNon si consiglia di usarlo in combinazione con il filtro di scala FSR.\n\nQuesta opzione può essere modificata mentre un gioco è in esecuzione facendo clic su \"Applica\" qui sotto; puoi semplicemente spostare la finestra delle impostazioni da parte e sperimentare fino a quando non trovi il tuo look preferito per un gioco.\n\nLasciare su Nessuno se incerto.", "GraphicsAALabel": "Anti-Aliasing:", "GraphicsScalingFilterLabel": "Filtro di scala:", - "GraphicsScalingFilterTooltip": "Abilita scalatura Framebuffer", + "GraphicsScalingFilterTooltip": "Scegli il filtro di scaling che verrà applicato quando si utilizza o scaling di risoluzione.\n\nBilineare funziona bene per i giochi 3D ed è un'opzione predefinita affidabile.\n\nNearest è consigliato per i giochi in pixel art.\n\nFSR 1.0 è solo un filtro di nitidezza, non raccomandato per l'uso con FXAA o SMAA.\n\nQuesta opzione può essere modificata mentre un gioco è in esecuzione facendo clic su \"Applica\" qui sotto; puoi semplicemente spostare la finestra delle impostazioni da parte e sperimentare fino a quando non trovi il tuo look preferito per un gioco.\n\nLasciare su Bilineare se incerto.", + "GraphicsScalingFilterBilinear": "Bilineare", + "GraphicsScalingFilterNearest": "Nearest", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "Livello", - "GraphicsScalingFilterLevelTooltip": "Imposta livello del filtro di scala", + "GraphicsScalingFilterLevelTooltip": "Imposta il livello di nitidezza di FSR 1.0. Valori più alti comportano una maggiore nitidezza.", "SmaaLow": "SMAA Basso", "SmaaMedium": "SMAA Medio", "SmaaHigh": "SMAA Alto", @@ -648,9 +767,14 @@ "UserEditorTitle": "Modificare L'Utente", "UserEditorTitleCreate": "Crea Un Utente", "SettingsTabNetworkInterface": "Interfaccia di rete:", - "NetworkInterfaceTooltip": "L'interfaccia di rete utilizzata per le funzionalità LAN", + "NetworkInterfaceTooltip": "L'interfaccia di rete utilizzata per le funzionalità LAN/LDN.\n\nIn combinazione con una VPN o XLink Kai e un gioco che supporta la modalità LAN, questa opzione può essere usata per simulare la connessione alla stessa rete attraverso Internet.\n\nNel dubbio, lascia l'opzione su Predefinito.", "NetworkInterfaceDefault": "Predefinito", - "PackagingShaders": "Comprimendo shader", + "PackagingShaders": "Salvataggio degli shader", "AboutChangelogButton": "Visualizza changelog su GitHub", - "AboutChangelogButtonTooltipMessage": "Clicca per aprire il changelog per questa versione nel tuo browser predefinito." -} \ No newline at end of file + "AboutChangelogButtonTooltipMessage": "Clicca per aprire il changelog per questa versione nel tuo browser predefinito.", + "SettingsTabNetworkMultiplayer": "Multigiocatore", + "MultiplayerMode": "Modalità:", + "MultiplayerModeTooltip": "Cambia la modalità multigiocatore LDN.\n\nLdnMitm modificherà la funzionalità locale wireless/local play nei giochi per funzionare come se fosse in modalità LAN, consentendo connessioni locali sulla stessa rete con altre istanze di Ryujinx e console Nintendo Switch modificate che hanno il modulo ldn_mitm installato.\n\nLa modalità multigiocatore richiede che tutti i giocatori usino la stessa versione del gioco (es. Super Smash Bros. Ultimate v13.0.1 non può connettersi con la v13.0.0).\n\nNel dubbio, lascia l'opzione su Disabilitato.", + "MultiplayerModeDisabled": "Disabilitato", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/ja_JP.json b/src/Ryujinx/Assets/Locales/ja_JP.json similarity index 80% rename from src/Ryujinx.Ava/Assets/Locales/ja_JP.json rename to src/Ryujinx/Assets/Locales/ja_JP.json index 5b31c5f20..61e963258 100644 --- a/src/Ryujinx.Ava/Assets/Locales/ja_JP.json +++ b/src/Ryujinx/Assets/Locales/ja_JP.json @@ -1,5 +1,5 @@ { - "Language": "英語 (アメリカ)", + "Language": "日本語", "MenuBarFileOpenApplet": "アプレットを開く", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "スタンドアロンモードで Mii エディタアプレットを開きます", "SettingsTabInputDirectMouseAccess": "マウス直接アクセス", @@ -14,10 +14,10 @@ "MenuBarFileOpenEmuFolder": "Ryujinx フォルダを開く", "MenuBarFileOpenLogsFolder": "ログフォルダを開く", "MenuBarFileExit": "終了(_E)", - "MenuBarOptions": "オプション", + "MenuBarOptions": "オプション(_O)", "MenuBarOptionsToggleFullscreen": "全画面切り替え", "MenuBarOptionsStartGamesInFullscreen": "全画面モードでゲームを開始", - "MenuBarOptionsStopEmulation": "エミュレーションを停止", + "MenuBarOptionsStopEmulation": "エミュレーションを中止", "MenuBarOptionsSettings": "設定(_S)", "MenuBarOptionsManageUserProfiles": "ユーザプロファイルを管理(_M)", "MenuBarActions": "アクション(_A)", @@ -30,7 +30,11 @@ "MenuBarToolsManageFileTypes": "ファイル形式を管理", "MenuBarToolsInstallFileTypes": "ファイル形式をインストール", "MenuBarToolsUninstallFileTypes": "ファイル形式をアンインストール", - "MenuBarHelp": "ヘルプ", + "MenuBarView": "_View", + "MenuBarViewWindow": "Window Size", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "ヘルプ(_H)", "MenuBarHelpCheckForUpdates": "アップデートを確認", "MenuBarHelpAbout": "Ryujinx について", "MenuSearch": "検索...", @@ -54,8 +58,6 @@ "GameListContextMenuManageTitleUpdatesToolTip": "タイトルのアップデート管理ウインドウを開きます", "GameListContextMenuManageDlc": "DLCを管理", "GameListContextMenuManageDlcToolTip": "DLC管理ウインドウを開きます", - "GameListContextMenuOpenModsDirectory": "Modディレクトリを開く", - "GameListContextMenuOpenModsDirectoryToolTip": "アプリケーションの Mod データを格納するディレクトリを開きます", "GameListContextMenuCacheManagement": "キャッシュ管理", "GameListContextMenuCacheManagementPurgePptc": "PPTC を再構築", "GameListContextMenuCacheManagementPurgePptcToolTip": "次回のゲーム起動時に PPTC を再構築します", @@ -72,6 +74,13 @@ "GameListContextMenuExtractDataRomFSToolTip": "現在のアプリケーション設定(アップデート含む)から RomFS セクションを展開します", "GameListContextMenuExtractDataLogo": "ロゴ", "GameListContextMenuExtractDataLogoToolTip": "現在のアプリケーション設定(アップデート含む)からロゴセクションを展開します", + "GameListContextMenuCreateShortcut": "アプリケーションのショートカットを作成", + "GameListContextMenuCreateShortcutToolTip": "選択したアプリケーションを起動するデスクトップショートカットを作成します", + "GameListContextMenuCreateShortcutToolTipMacOS": "選択したアプリケーションを起動する ショートカットを macOS の Applications フォルダに作成します", + "GameListContextMenuOpenModsDirectory": "Modディレクトリを開く", + "GameListContextMenuOpenModsDirectoryToolTip": "アプリケーションの Mod データを格納するディレクトリを開きます", + "GameListContextMenuOpenSdModsDirectory": "Atmosphere Mods ディレクトリを開く", + "GameListContextMenuOpenSdModsDirectoryToolTip": "アプリケーションの Mod データを格納する SD カードの Atmosphere ディレクトリを開きます. 実際のハードウェア用に作成された Mod データに有用です.", "StatusBarGamesLoaded": "{0}/{1} ゲーム", "StatusBarSystemVersion": "システムバージョン: {0}", "LinuxVmMaxMapCountDialogTitle": "メモリマッピング上限値が小さすぎます", @@ -87,6 +96,7 @@ "SettingsTabGeneralEnableDiscordRichPresence": "Discord リッチプレゼンスを有効にする", "SettingsTabGeneralCheckUpdatesOnLaunch": "起動時にアップデートを確認する", "SettingsTabGeneralShowConfirmExitDialog": "\"終了を確認\" ダイアログを表示する", + "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", "SettingsTabGeneralHideCursor": "マウスカーソルを非表示", "SettingsTabGeneralHideCursorNever": "決して", "SettingsTabGeneralHideCursorOnIdle": "アイドル時", @@ -150,7 +160,7 @@ "SettingsTabGraphicsResolutionScaleNative": "ネイティブ (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (非推奨)", "SettingsTabGraphicsAspectRatio": "アスペクト比:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -261,6 +271,107 @@ "ControllerSettingsMotionGyroDeadzone": "ジャイロ遊び:", "ControllerSettingsSave": "セーブ", "ControllerSettingsClose": "閉じる", + "KeyUnknown": "Unknown", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", "UserProfilesSelectedUserProfile": "選択されたユーザプロファイル:", "UserProfilesSaveProfileName": "プロファイル名をセーブ", "UserProfilesChangeProfileImage": "プロファイル画像を変更", @@ -292,13 +403,9 @@ "GameListContextMenuRunApplication": "アプリケーションを実行", "GameListContextMenuToggleFavorite": "お気に入りを切り替え", "GameListContextMenuToggleFavoriteToolTip": "ゲームをお気に入りに含めるかどうかを切り替えます", - "SettingsTabGeneralTheme": "テーマ", - "SettingsTabGeneralThemeCustomTheme": "カスタムテーマパス", - "SettingsTabGeneralThemeBaseStyle": "基本スタイル", - "SettingsTabGeneralThemeBaseStyleDark": "ダーク", - "SettingsTabGeneralThemeBaseStyleLight": "ライト", - "SettingsTabGeneralThemeEnableCustomTheme": "カスタムテーマを有効にする", - "ButtonBrowse": "参照", + "SettingsTabGeneralTheme": "テーマ:", + "SettingsTabGeneralThemeDark": "ダーク", + "SettingsTabGeneralThemeLight": "ライト", "ControllerSettingsConfigureGeneral": "設定", "ControllerSettingsRumble": "振動", "ControllerSettingsRumbleStrongMultiplier": "強振動の補正値", @@ -332,8 +439,6 @@ "DialogUpdaterAddingFilesMessage": "新規アップデートを追加中...", "DialogUpdaterCompleteMessage": "アップデート完了!", "DialogUpdaterRestartMessage": "すぐに Ryujinx を再起動しますか?", - "DialogUpdaterArchNotSupportedMessage": "サポート外のアーキテクチャです!", - "DialogUpdaterArchNotSupportedSubMessage": "(x64 システムのみサポートしています!)", "DialogUpdaterNoInternetMessage": "インターネットに接続されていません!", "DialogUpdaterNoInternetSubMessage": "インターネット接続が正常動作しているか確認してください!", "DialogUpdaterDirtyBuildMessage": "Dirty ビルドの Ryujinx はアップデートできません!", @@ -342,7 +447,7 @@ "DialogThemeRestartMessage": "テーマがセーブされました. テーマを適用するには再起動が必要です.", "DialogThemeRestartSubMessage": "再起動しますか", "DialogFirmwareInstallEmbeddedMessage": "このゲームに含まれるファームウェアをインストールしてよろしいですか? (ファームウェア {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "ファームウェアがインストールされていませんが, ゲームに含まれるファームウェア {0} をインストールできます.\\nエミュレータが開始します.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "ファームウェアがインストールされていませんが, ゲームに含まれるファームウェア {0} をインストールできます.\nエミュレータが開始します.", "DialogFirmwareNoFirmwareInstalledMessage": "ファームウェアがインストールされていません", "DialogFirmwareInstalledMessage": "ファームウェア {0} がインストールされました", "DialogInstallFileTypesSuccessMessage": "ファイル形式のインストールに成功しました!", @@ -385,17 +490,22 @@ "DialogUserProfileUnsavedChangesSubMessage": "変更を破棄しますか?", "DialogControllerSettingsModifiedConfirmMessage": "現在のコントローラ設定が更新されました.", "DialogControllerSettingsModifiedConfirmSubMessage": "セーブしますか?", - "DialogLoadNcaErrorMessage": "{0}. エラー発生ファイル: {1}", + "DialogLoadFileErrorMessage": "{0}. エラー発生ファイル: {1}", + "DialogModAlreadyExistsMessage": "Modはすでに存在します", + "DialogModInvalidMessage": "指定したディレクトリにはmodが含まれていません!", + "DialogModDeleteNoParentMessage": "削除に失敗しました: Mod \"{0}\" の親ディレクトリが見つかりませんでした!", "DialogDlcNoDlcErrorMessage": "選択されたファイルはこのタイトル用の DLC ではありません!", "DialogPerformanceCheckLoggingEnabledMessage": "トレースロギングを有効にします. これは開発者のみに有用な機能です.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "パフォーマンス最適化のためには,トレースロギングを無効にすることを推奨します. トレースロギングを無効にしてよろしいですか?", "DialogPerformanceCheckShaderDumpEnabledMessage": "シェーダーダンプを有効にします. これは開発者のみに有用な機能です.", "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "パフォーマンス最適化のためには, シェーダーダンプを無効にすることを推奨します. シェーダーダンプを無効にしてよろしいですか?", "DialogLoadAppGameAlreadyLoadedMessage": "ゲームはすでにロード済みです", - "DialogLoadAppGameAlreadyLoadedSubMessage": "別のゲームを起動する前に, エミュレーションを停止またはエミュレータを閉じてください.", + "DialogLoadAppGameAlreadyLoadedSubMessage": "別のゲームを起動する前に, エミュレーションを中止またはエミュレータを閉じてください.", "DialogUpdateAddUpdateErrorMessage": "選択されたファイルはこのタイトル用のアップデートではありません!", "DialogSettingsBackendThreadingWarningTitle": "警告 - バックエンドスレッディング", "DialogSettingsBackendThreadingWarningMessage": "このオプションの変更を完全に適用するには Ryujinx の再起動が必要です. プラットフォームによっては, Ryujinx のものを使用する前に手動でドライバ自身のマルチスレッディングを無効にする必要があるかもしれません.", + "DialogModManagerDeletionWarningMessage": "以下のModを削除しようとしています: {0}\n\n続行してもよろしいですか?", + "DialogModManagerDeletionAllWarningMessage": "このタイトルの Mod をすべて削除しようとしています.\n\n続行してもよろしいですか?", "SettingsTabGraphicsFeaturesOptions": "機能", "SettingsTabGraphicsBackendMultithreading": "グラフィックスバックエンドのマルチスレッド実行:", "CommonAuto": "自動", @@ -404,7 +514,7 @@ "InputDialogYes": "はい", "InputDialogNo": "いいえ", "DialogProfileInvalidProfileNameErrorMessage": "プロファイル名に無効な文字が含まれています. 再度試してみてください.", - "MenuBarOptionsPauseEmulation": "中断", + "MenuBarOptionsPauseEmulation": "一時停止", "MenuBarOptionsResumeEmulation": "再開", "AboutUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx のウェブサイトを開きます.", "AboutDisclaimerMessage": "Ryujinx は Nintendo™ および\nそのパートナー企業とは一切関係ありません.", @@ -430,6 +540,7 @@ "DlcManagerRemoveAllButton": "すべて削除", "DlcManagerEnableAllButton": "すべて有効", "DlcManagerDisableAllButton": "すべて無効", + "ModManagerDeleteAllButton": "すべて削除", "MenuBarOptionsChangeLanguage": "言語を変更", "MenuBarShowFileTypes": "ファイル形式を表示", "CommonSort": "並べ替え", @@ -447,13 +558,13 @@ "CustomThemePathTooltip": "カスタム GUI テーマのパスです", "CustomThemeBrowseTooltip": "カスタム GUI テーマを参照します", "DockModeToggleTooltip": "有効にすると,ドッキングされた Nintendo Switch をエミュレートします.多くのゲームではグラフィックス品質が向上します.\n無効にすると,携帯モードの Nintendo Switch をエミュレートします.グラフィックスの品質は低下します.\n\nドッキングモード有効ならプレイヤー1の,無効なら携帯の入力を設定してください.\n\nよくわからない場合はオンのままにしてください.", - "DirectKeyboardTooltip": "キーボード直接アクセス (HID) に対応します. キーボードをテキスト入力デバイスとして使用できます.", - "DirectMouseTooltip": "マウス直接アクセス (HID) に対応します. マウスをポインティングデバイスとして使用できます.", + "DirectKeyboardTooltip": "直接キーボード アクセス (HID) のサポートです. テキスト入力デバイスとしてキーボードへのゲームアクセスを提供します.\n\nSwitchハードウェアでキーボードの使用をネイティブにサポートしているゲームでのみ動作します.\n\nわからない場合はオフのままにしてください.", + "DirectMouseTooltip": "直接マウスアクセス (HID) のサポートです. ポインティングデバイスとしてマウスへのゲームアクセスを提供します.\n\nSwitchハードウェアでマウスの使用をネイティブにサポートしているゲームでのみ動作します.\n\n有効にしている場合, タッチスクリーン機能は動作しない場合があります.\n\nわからない場合はオフのままにしてください.", "RegionTooltip": "システムの地域を変更します", "LanguageTooltip": "システムの言語を変更します", "TimezoneTooltip": "システムのタイムゾーンを変更します", "TimeTooltip": "システムの時刻を変更します", - "VSyncToggleTooltip": "エミュレートされたゲーム機の垂直同期です. 多くのゲームにおいて, フレームリミッタとして機能します. 無効にすると, ゲームが高速で実行されたり, ロード中に時間がかかったり, 止まったりすることがあります.\n\n設定したホットキーで, ゲーム内で切り替え可能です. 無効にする場合は, この操作を行うことをおすすめします.\n\nよくわからない場合はオンのままにしてください.", + "VSyncToggleTooltip": "エミュレートされたゲーム機の垂直同期です. 多くのゲームにおいて, フレームリミッタとして機能します. 無効にすると, ゲームが高速で実行されたり, ロード中に時間がかかったり, 止まったりすることがあります.\n\n設定したホットキー(デフォルトではF1)で, ゲーム内で切り替え可能です. 無効にする場合は, この操作を行うことをおすすめします.\n\nよくわからない場合はオンのままにしてください.", "PptcToggleTooltip": "翻訳されたJIT関数をセーブすることで, ゲームをロードするたびに毎回翻訳する処理を不要とします.\n\n一度ゲームを起動すれば,二度目以降の起動時遅延を大きく軽減できます.\n\nよくわからない場合はオンのままにしてください.", "FsIntegrityToggleTooltip": "ゲーム起動時にファイル破損をチェックし,破損が検出されたらログにハッシュエラーを表示します..\n\nパフォーマンスには影響なく, トラブルシューティングに役立ちます.\n\nよくわからない場合はオンのままにしてください.", "AudioBackendTooltip": "音声レンダリングに使用するバックエンドを変更します.\n\nSDL2 が優先され, OpenAL と SoundIO はフォールバックとして使用されます. ダミーは音声出力しません.\n\nよくわからない場合は SDL2 を設定してください.", @@ -467,10 +578,10 @@ "GraphicsBackendThreadingTooltip": "グラフィックスバックエンドのコマンドを別スレッドで実行します.\n\nシェーダのコンパイルを高速化し, 遅延を軽減し, マルチスレッド非対応の GPU ドライバにおいてパフォーマンスを改善します. マルチスレッド対応のドライバでも若干パフォーマンス改善が見られます.\n\nよくわからない場合は自動に設定してください.", "GalThreadingTooltip": "グラフィックスバックエンドのコマンドを別スレッドで実行します.\n\nシェーダのコンパイルを高速化し, 遅延を軽減し, マルチスレッド非対応の GPU ドライバにおいてパフォーマンスを改善します. マルチスレッド対応のドライバでも若干パフォーマンス改善が見られます.\n\nよくわからない場合は自動に設定してください.", "ShaderCacheToggleTooltip": "ディスクシェーダーキャッシュをセーブし,次回以降の実行時遅延を軽減します.\n\nよくわからない場合はオンのままにしてください.", - "ResolutionScaleTooltip": "レンダリングに適用される解像度の倍率です", + "ResolutionScaleTooltip": "ゲームのレンダリング解像度倍率を設定します.\n\n解像度を上げてもピクセルのように見えるゲームもあります. そのようなゲームでは, アンチエイリアスを削除するか, 内部レンダリング解像度を上げる mod を見つける必要があるかもしれません. その場合, ようなゲームでは、ネイティブを選択してください.\n\nこのオプションはゲーム実行中に下の「適用」をクリックすることで変更できます. 設定ウィンドウを脇に移動して, ゲームが好みの表示になるよう試してみてください.\n\nどのような設定でも, \"4x\" はやり過ぎであることを覚えておいてください.", "ResolutionScaleEntryTooltip": "1.5 のような整数でない倍率を指定すると,問題が発生したりクラッシュしたりする場合があります.", - "AnisotropyTooltip": "異方性フィルタリングのレベルです (ゲームが要求する値を使用する場合は「自動」を設定してください)", - "AspectRatioTooltip": "レンダリングに適用されるアスペクト比です.", + "AnisotropyTooltip": "異方性フィルタリングのレベルです. ゲームが要求する値を使用する場合は「自動」を設定してください.", + "AspectRatioTooltip": "レンダリングウインドウに適用するアスペクト比です.\n\nゲームにアスペクト比を変更する mod を使用している場合のみ変更してください.\n\nわからない場合は16:9のままにしておいてください.\n", "ShaderDumpPathTooltip": "グラフィックス シェーダー ダンプのパスです", "FileLogTooltip": "コンソール出力されるログをディスク上のログファイルにセーブします. パフォーマンスには影響を与えません.", "StubLogTooltip": "stub ログメッセージをコンソールに出力します. パフォーマンスには影響を与えません.", @@ -491,7 +602,7 @@ "ExitTooltip": "Ryujinx を終了します", "OpenSettingsTooltip": "設定ウインドウを開きます", "OpenProfileManagerTooltip": "ユーザプロファイル管理ウインドウを開きます", - "StopEmulationTooltip": "ゲームのエミュレーションを停止してゲーム選択画面に戻ります", + "StopEmulationTooltip": "ゲームのエミュレーションを中止してゲーム選択画面に戻ります", "CheckUpdatesTooltip": "Ryujinx のアップデートを確認します", "OpenAboutTooltip": "Ryujinx についてのウインドウを開きます", "GridSize": "グリッドサイズ", @@ -504,9 +615,11 @@ "EnableInternetAccessTooltip": "エミュレートしたアプリケーションをインターネットに接続できるようにします.\n\nLAN モードを持つゲーム同士は,この機能を有効にして同じアクセスポイントに接続すると接続できます. 実機も含まれます.\n\n任天堂のサーバーには接続できません. インターネットに接続しようとすると,特定のゲームでクラッシュすることがあります.\n\nよくわからない場合はオフのままにしてください.", "GameListContextMenuManageCheatToolTip": "チートを管理します", "GameListContextMenuManageCheat": "チートを管理", + "GameListContextMenuManageModToolTip": "Modを管理します", + "GameListContextMenuManageMod": "Manage Mods", "ControllerSettingsStickRange": "範囲:", - "DialogStopEmulationTitle": "Ryujinx - エミュレーションを停止", - "DialogStopEmulationMessage": "エミュレーションを停止してよろしいですか?", + "DialogStopEmulationTitle": "Ryujinx - エミュレーションを中止", + "DialogStopEmulationMessage": "エミュレーションを中止してよろしいですか?", "SettingsTabCpu": "CPU", "SettingsTabAudio": "音声", "SettingsTabNetwork": "ネットワーク", @@ -515,8 +628,6 @@ "SettingsTabCpuMemory": "CPU メモリ", "DialogUpdaterFlatpakNotSupportedMessage": "FlatHub を使用して Ryujinx をアップデートしてください.", "UpdaterDisabledWarningTitle": "アップデータは無効です!", - "GameListContextMenuOpenSdModsDirectory": "Atmosphere Mods ディレクトリを開く", - "GameListContextMenuOpenSdModsDirectoryToolTip": "アプリケーションの Mod データを格納する SD カードの Atmosphere ディレクトリを開きます. 実際のハードウェア用にパッケージされた Mod データに有用です.", "ControllerSettingsRotate90": "時計回りに 90° 回転", "IconSize": "アイコンサイズ", "IconSizeTooltip": "ゲームアイコンのサイズを変更します", @@ -544,12 +655,13 @@ "SwkbdMinCharacters": "最低 {0} 文字必要です", "SwkbdMinRangeCharacters": "{0}-{1} 文字にしてください", "SoftwareKeyboard": "ソフトウェアキーボード", - "SoftwareKeyboardModeNumbersOnly": "数字のみ", + "SoftwareKeyboardModeNumeric": "0-9 または '.' のみでなければなりません", "SoftwareKeyboardModeAlphabet": "CJK文字以外のみ", "SoftwareKeyboardModeASCII": "ASCII文字列のみ", - "DialogControllerAppletMessagePlayerRange": "アプリケーションは {0} 名のプレイヤーを要求しています:\n\n種別: {1}\n\nプレイヤー: {2}\n\n{3}設定を開き各プレイヤーの入力設定を行ってから閉じるを押してください.", - "DialogControllerAppletMessage": "アプリケーションは {0} 名のプレイヤーを要求しています:\n\n種別: {1}\n\nプレイヤー: {2}\n\n{3}設定を開き各プレイヤーの入力設定を行ってから閉じるを押してください.", - "DialogControllerAppletDockModeSet": "ドッキングモードに設定されました. 携帯モードは無効になります.\n\n", + "ControllerAppletControllers": "サポートされているコントローラ:", + "ControllerAppletPlayers": "プレイヤー:", + "ControllerAppletDescription": "現在の設定は無効です. 設定を開いて入力を再設定してください.", + "ControllerAppletDocked": "ドッキングモードが設定されています. 携帯コントロールは無効にする必要があります.", "UpdaterRenaming": "古いファイルをリネーム中...", "UpdaterRenameFailed": "ファイルをリネームできませんでした: {0}", "UpdaterAddingFiles": "新規ファイルを追加中...", @@ -574,7 +686,7 @@ "SettingsTabHotkeysToggleVsyncHotkey": "VSync 切り替え:", "SettingsTabHotkeysScreenshotHotkey": "スクリーンショット:", "SettingsTabHotkeysShowUiHotkey": "UI表示:", - "SettingsTabHotkeysPauseHotkey": "中断:", + "SettingsTabHotkeysPauseHotkey": "一時停止:", "SettingsTabHotkeysToggleMuteHotkey": "ミュート:", "ControllerMotionTitle": "モーションコントロール設定", "ControllerRumbleTitle": "振動設定", @@ -587,17 +699,21 @@ "Writable": "書き込み可能", "SelectDlcDialogTitle": "DLC ファイルを選択", "SelectUpdateDialogTitle": "アップデートファイルを選択", + "SelectModDialogTitle": "modディレクトリを選択", "UserProfileWindowTitle": "ユーザプロファイルを管理", "CheatWindowTitle": "チート管理", "DlcWindowTitle": "DLC 管理", + "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "アップデート管理", "CheatWindowHeading": "利用可能なチート {0} [{1}]", "BuildId": "ビルドID:", "DlcWindowHeading": "利用可能な DLC {0} [{1}]", + "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "編集", "Cancel": "キャンセル", "Save": "セーブ", "Discard": "破棄", + "Paused": "一時停止中", "UserProfilesSetProfileImage": "プロファイル画像を設定", "UserProfileEmptyNameError": "名称が必要です", "UserProfileNoImageError": "プロファイル画像が必要です", @@ -607,9 +723,9 @@ "UserProfilesName": "名称:", "UserProfilesUserId": "ユーザID:", "SettingsTabGraphicsBackend": "グラフィックスバックエンド", - "SettingsTabGraphicsBackendTooltip": "使用するグラフィックスバックエンドです", + "SettingsTabGraphicsBackendTooltip": "エミュレーションに使用するグラフィックスバックエンドを選択します.\n\nVulkanは, 最近のグラフィックカードでドライバが最新であれば, 全体的に優れています. すべてのGPUベンダーで, シェーダーコンパイルがより高速で, スタッタリングが少ないのが特徴です.\n\n古いNvidia GPU, Linuxでの古いAMD GPU, VRAMの少ないGPUなどでは, OpenGLの方が良い結果が得られるかもしれません. ですが, シェーダーコンパイルのスタッターは大きくなります.\n\n不明な場合はVulkanに設定してください。最新のグラフィックドライバでもVulkanをサポートしていないGPUの場合は, OpenGLに設定してください.", "SettingsEnableTextureRecompression": "テクスチャの再圧縮を有効にする", - "SettingsEnableTextureRecompressionTooltip": "VRAMの使用量を削減するためテクスチャを圧縮します.\n\nGPUのVRAMが4GiB未満の場合は使用を推奨します.\n\nよくわからない場合はオフのままにしてください.", + "SettingsEnableTextureRecompressionTooltip": "VRAM使用量を減らすためにASTCテクスチャを圧縮します.\n\nこのテクスチャフォーマットを使用するゲームには, Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder, The Legend of Zelda: Tears of the Kingdomが含まれます.\n\nVRAMが4GB以下のグラフィックカードでは, これらのゲームを実行中にクラッシュする可能性があります.\n\n前述のゲームでVRAMが不足している場合のみ有効にしてください. 不明な場合はオフにしてください.", "SettingsTabGraphicsPreferredGpu": "優先使用するGPU", "SettingsTabGraphicsPreferredGpuTooltip": "Vulkanグラフィックスバックエンドで使用されるグラフィックスカードを選択します.\n\nOpenGLが使用するGPUには影響しません.\n\n不明な場合は, \"dGPU\" としてフラグが立っているGPUに設定します. ない場合はそのままにします.", "SettingsAppRequiredRestartMessage": "Ryujinx の再起動が必要です", @@ -635,12 +751,15 @@ "Recover": "復旧", "UserProfilesRecoverHeading": "以下のアカウントのセーブデータが見つかりました", "UserProfilesRecoverEmptyList": "復元するプロファイルはありません", - "GraphicsAATooltip": "ゲームのレンダリングにアンチエイリアスを適用します", + "GraphicsAATooltip": "ゲームレンダリングにアンチエイリアスを適用します.\n\nFXAAは画像の大部分をぼかし, SMAAはギザギザのエッジを見つけて滑らかにします.\n\nFSRスケーリングフィルタとの併用は推奨しません.\n\nこのオプションは, ゲーム実行中に下の「適用」をクリックして変更できます. 設定ウィンドウを脇に移動し, ゲームが好みの表示になるように試してみてください.\n\n不明な場合は「なし」のままにしておいてください.", "GraphicsAALabel": "アンチエイリアス:", "GraphicsScalingFilterLabel": "スケーリングフィルタ:", - "GraphicsScalingFilterTooltip": "フレームバッファスケーリングを有効にします", + "GraphicsScalingFilterTooltip": "解像度変更時に適用されるスケーリングフィルタを選択します.\n\nBilinearは3Dゲームに適しており, 安全なデフォルトオプションです.\n\nピクセルアートゲームにはNearestを推奨します.\n\nFSR 1.0は単なるシャープニングフィルタであり, FXAAやSMAAとの併用は推奨されません.\n\nこのオプションは, ゲーム実行中に下の「適用」をクリックすることで変更できます. 設定ウィンドウを脇に移動し, ゲームが好みの表示になるように試してみてください.\n\n不明な場合はBilinearのままにしておいてください.", + "GraphicsScalingFilterBilinear": "Bilinear", + "GraphicsScalingFilterNearest": "Nearest", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "レベル", - "GraphicsScalingFilterLevelTooltip": "スケーリングフィルタのレベルを設定", + "GraphicsScalingFilterLevelTooltip": "FSR 1.0のシャープ化レベルを設定します. 高い値ほどシャープになります.", "SmaaLow": "SMAA Low", "SmaaMedium": "SMAA Medium", "SmaaHigh": "SMAA High", @@ -648,9 +767,14 @@ "UserEditorTitle": "ユーザを編集", "UserEditorTitleCreate": "ユーザを作成", "SettingsTabNetworkInterface": "ネットワークインタフェース:", - "NetworkInterfaceTooltip": "LAN機能に使用されるネットワークインタフェース", + "NetworkInterfaceTooltip": "LAN/LDN機能に使用されるネットワークインタフェースです.\n\nVPNやXLink Kai、LAN対応のゲームと併用することで, インターネット上の同一ネットワーク接続になりすますことができます.\n\n不明な場合はデフォルトのままにしてください.", "NetworkInterfaceDefault": "デフォルト", "PackagingShaders": "シェーダーを構築中", "AboutChangelogButton": "GitHub で更新履歴を表示", - "AboutChangelogButtonTooltipMessage": "クリックして, このバージョンの更新履歴をデフォルトのブラウザで開きます." -} \ No newline at end of file + "AboutChangelogButtonTooltipMessage": "クリックして, このバージョンの更新履歴をデフォルトのブラウザで開きます.", + "SettingsTabNetworkMultiplayer": "マルチプレイヤー", + "MultiplayerMode": "モード:", + "MultiplayerModeTooltip": "LDNマルチプレイヤーモードを変更します.\n\nldn_mitmモジュールがインストールされた, 他のRyujinxインスタンスや,ハックされたNintendo Switchコンソールとのローカル/同一ネットワーク接続を可能にします.\n\nマルチプレイでは, すべてのプレイヤーが同じゲームバージョンである必要があります(例:Super Smash Bros. Ultimate v13.0.1はv13.0.0に接続できません).\n\n不明な場合は「無効」のままにしてください.", + "MultiplayerModeDisabled": "無効", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/ko_KR.json b/src/Ryujinx/Assets/Locales/ko_KR.json similarity index 78% rename from src/Ryujinx.Ava/Assets/Locales/ko_KR.json rename to src/Ryujinx/Assets/Locales/ko_KR.json index cdc617222..a92d084e0 100644 --- a/src/Ryujinx.Ava/Assets/Locales/ko_KR.json +++ b/src/Ryujinx/Assets/Locales/ko_KR.json @@ -1,8 +1,8 @@ { "Language": "한국어", "MenuBarFileOpenApplet": "애플릿 열기", - "MenuBarFileOpenAppletOpenMiiAppletToolTip": "독립 실행형 모드에서 Mii 편집기 애플릿 열기", - "SettingsTabInputDirectMouseAccess": "직접 마우스 접속", + "MenuBarFileOpenAppletOpenMiiAppletToolTip": "독립 실행형 모드로 Mii 편집기 애플릿 열기", + "SettingsTabInputDirectMouseAccess": "다이렉트 마우스 접근", "SettingsTabSystemMemoryManagerMode": "메모리 관리자 모드:", "SettingsTabSystemMemoryManagerModeSoftware": "소프트웨어", "SettingsTabSystemMemoryManagerModeHost": "호스트 (빠름)", @@ -14,7 +14,7 @@ "MenuBarFileOpenEmuFolder": "Ryujinx 폴더 열기", "MenuBarFileOpenLogsFolder": "로그 폴더 열기", "MenuBarFileExit": "_종료", - "MenuBarOptions": "옵션", + "MenuBarOptions": "옵션(_O)", "MenuBarOptionsToggleFullscreen": "전체화면 전환", "MenuBarOptionsStartGamesInFullscreen": "전체 화면 모드에서 게임 시작", "MenuBarOptionsStopEmulation": "에뮬레이션 중지", @@ -30,7 +30,11 @@ "MenuBarToolsManageFileTypes": "파일 형식 관리", "MenuBarToolsInstallFileTypes": "파일 형식 설치", "MenuBarToolsUninstallFileTypes": "파일 형식 설치 제거", - "MenuBarHelp": "도움말", + "MenuBarView": "_보기", + "MenuBarViewWindow": "창 크기", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "도움말(_H)", "MenuBarHelpCheckForUpdates": "업데이트 확인", "MenuBarHelpAbout": "정보", "MenuSearch": "검색...", @@ -46,7 +50,7 @@ "GameListHeaderPath": "경로", "GameListContextMenuOpenUserSaveDirectory": "사용자 저장 디렉터리 열기", "GameListContextMenuOpenUserSaveDirectoryToolTip": "응용프로그램의 사용자 저장이 포함된 디렉터리 열기", - "GameListContextMenuOpenDeviceSaveDirectory": "사용자 장치 디렉터리 열기", + "GameListContextMenuOpenDeviceSaveDirectory": "사용자 장치 디렉토리 열기", "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "응용프로그램의 장치 저장이 포함된 디렉터리 열기", "GameListContextMenuOpenBcatSaveDirectory": "BCAT 저장 디렉터리 열기", "GameListContextMenuOpenBcatSaveDirectoryToolTip": "응용프로그램의 BCAT 저장이 포함된 디렉터리 열기", @@ -54,8 +58,6 @@ "GameListContextMenuManageTitleUpdatesToolTip": "타이틀 업데이트 관리 창 열기", "GameListContextMenuManageDlc": "DLC 관리", "GameListContextMenuManageDlcToolTip": "DLC 관리 창 열기", - "GameListContextMenuOpenModsDirectory": "Mod 디렉터리 열기", - "GameListContextMenuOpenModsDirectoryToolTip": "응용프로그램의 Mod가 포함된 디렉터리 열기", "GameListContextMenuCacheManagement": "캐시 관리", "GameListContextMenuCacheManagementPurgePptc": "대기열 PPTC 재구성", "GameListContextMenuCacheManagementPurgePptcToolTip": "다음 게임 시작에서 부팅 시 PPTC가 다시 빌드하도록 트리거", @@ -72,6 +74,13 @@ "GameListContextMenuExtractDataRomFSToolTip": "응용 프로그램의 현재 구성에서 RomFS 추출 (업데이트 포함)", "GameListContextMenuExtractDataLogo": "로고", "GameListContextMenuExtractDataLogoToolTip": "응용프로그램의 현재 구성에서 로고 섹션 추출 (업데이트 포함)", + "GameListContextMenuCreateShortcut": "애플리케이션 바로 가기 만들기", + "GameListContextMenuCreateShortcutToolTip": "선택한 애플리케이션을 실행하는 바탕 화면 바로 가기를 만듭니다.", + "GameListContextMenuCreateShortcutToolTipMacOS": "해당 게임을 실행할 수 있는 바로가기를 macOS의 응용 프로그램 폴더에 추가합니다.", + "GameListContextMenuOpenModsDirectory": "Mod 디렉터리 열기", + "GameListContextMenuOpenModsDirectoryToolTip": "해당 게임의 Mod가 저장된 디렉터리 열기", + "GameListContextMenuOpenSdModsDirectory": "Atmosphere Mod 디렉터리 열기", + "GameListContextMenuOpenSdModsDirectoryToolTip": "해당 게임의 Mod가 포함된 대체 SD 카드 Atmosphere 디렉터리를 엽니다. 실제 하드웨어용으로 패키징된 Mod에 유용합니다.", "StatusBarGamesLoaded": "{0}/{1}개의 게임 불러옴", "StatusBarSystemVersion": "시스템 버전 : {0}", "LinuxVmMaxMapCountDialogTitle": "감지된 메모리 매핑의 하한선", @@ -87,6 +96,7 @@ "SettingsTabGeneralEnableDiscordRichPresence": "디스코드 활동 상태 활성화", "SettingsTabGeneralCheckUpdatesOnLaunch": "시작 시, 업데이트 확인", "SettingsTabGeneralShowConfirmExitDialog": "\"종료 확인\" 대화 상자 표시", + "SettingsTabGeneralRememberWindowState": "창 크기/위치 기억", "SettingsTabGeneralHideCursor": "마우스 커서 숨기기", "SettingsTabGeneralHideCursorNever": "절대 안 함", "SettingsTabGeneralHideCursorOnIdle": "유휴 상태", @@ -150,7 +160,7 @@ "SettingsTabGraphicsResolutionScaleNative": "원본(720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2배(1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3배(2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4배(2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (권장하지 않음)", "SettingsTabGraphicsAspectRatio": "종횡비 :", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -261,6 +271,107 @@ "ControllerSettingsMotionGyroDeadzone": "자이로 사각지대 :", "ControllerSettingsSave": "저장", "ControllerSettingsClose": "닫기", + "KeyUnknown": "알 수 없음", + "KeyShiftLeft": "왼쪽 Shift", + "KeyShiftRight": "오른쪽 Shift", + "KeyControlLeft": "왼쪽 Ctrl", + "KeyMacControlLeft": "왼쪽 ^", + "KeyControlRight": "오른쪽 Ctrl", + "KeyMacControlRight": "오른쪽 ^", + "KeyAltLeft": "왼쪽 Alt", + "KeyMacAltLeft": "왼쪽 ⌥", + "KeyAltRight": "오른쪽 Alt", + "KeyMacAltRight": "오른쪽 ⌥", + "KeyWinLeft": "왼쪽 ⊞", + "KeyMacWinLeft": "왼쪽 ⌘", + "KeyWinRight": "오른쪽 ⊞", + "KeyMacWinRight": "오른쪽 ⌘", + "KeyMenu": "메뉴", + "KeyUp": "↑", + "KeyDown": "↓", + "KeyLeft": "←", + "KeyRight": "→", + "KeyEnter": "엔터", + "KeyEscape": "이스케이프", + "KeySpace": "스페이스", + "KeyTab": "탭", + "KeyBackSpace": "백스페이스", + "KeyInsert": "Ins", + "KeyDelete": "Del", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "프린트 스크린", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "지우기", + "KeyKeypad0": "키패드 0", + "KeyKeypad1": "키패드 1", + "KeyKeypad2": "키패드 2", + "KeyKeypad3": "키패드 3", + "KeyKeypad4": "키패드 4", + "KeyKeypad5": "키패드 5", + "KeyKeypad6": "키패드 6", + "KeyKeypad7": "키패드 7", + "KeyKeypad8": "키패드 8", + "KeyKeypad9": "키패드 9", + "KeyKeypadDivide": "키패드 분할", + "KeyKeypadMultiply": "키패드 멀티플", + "KeyKeypadSubtract": "키패드 빼기", + "KeyKeypadAdd": "키패드 추가", + "KeyKeypadDecimal": "숫자 키패드", + "KeyKeypadEnter": "키패드 엔터", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "바인딩 해제", + "GamepadLeftStick": "L 스틱 버튼", + "GamepadRightStick": "R 스틱 버튼", + "GamepadLeftShoulder": "좌측 숄더", + "GamepadRightShoulder": "우측 숄더", + "GamepadLeftTrigger": "좌측 트리거", + "GamepadRightTrigger": "우측 트리거", + "GamepadDpadUp": "↑", + "GamepadDpadDown": "↓", + "GamepadDpadLeft": "←", + "GamepadDpadRight": "→", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "안내", + "GamepadMisc1": "기타", + "GamepadPaddle1": "패들 1", + "GamepadPaddle2": "패들 2", + "GamepadPaddle3": "패들 3", + "GamepadPaddle4": "패들 4", + "GamepadTouchpad": "터치패드", + "GamepadSingleLeftTrigger0": "왼쪽 트리거 0", + "GamepadSingleRightTrigger0": "오른쪽 트리거 0", + "GamepadSingleLeftTrigger1": "왼쪽 트리거 1", + "GamepadSingleRightTrigger1": "오른쪽 트리거 1", + "StickLeft": "좌측 스틱", + "StickRight": "우측 스틱", "UserProfilesSelectedUserProfile": "선택한 사용자 프로필 :", "UserProfilesSaveProfileName": "프로필 이름 저장", "UserProfilesChangeProfileImage": "프로필 이미지 변경", @@ -292,13 +403,9 @@ "GameListContextMenuRunApplication": "응용프로그램 실행", "GameListContextMenuToggleFavorite": "즐겨찾기 전환", "GameListContextMenuToggleFavoriteToolTip": "게임 즐겨찾기 상태 전환", - "SettingsTabGeneralTheme": "테마", - "SettingsTabGeneralThemeCustomTheme": "커스텀 테마 경로", - "SettingsTabGeneralThemeBaseStyle": "기본 스타일", - "SettingsTabGeneralThemeBaseStyleDark": "어두움", - "SettingsTabGeneralThemeBaseStyleLight": "밝음", - "SettingsTabGeneralThemeEnableCustomTheme": "사용자 정의 테마 활성화", - "ButtonBrowse": "찾아보기", + "SettingsTabGeneralTheme": "테마:", + "SettingsTabGeneralThemeDark": "어두운 테마", + "SettingsTabGeneralThemeLight": "밝은 테마", "ControllerSettingsConfigureGeneral": "구성", "ControllerSettingsRumble": "진동", "ControllerSettingsRumbleStrongMultiplier": "강력한 진동 증폭기", @@ -332,8 +439,6 @@ "DialogUpdaterAddingFilesMessage": "새 업데이트 추가 중...", "DialogUpdaterCompleteMessage": "업데이트를 완료했습니다!", "DialogUpdaterRestartMessage": "지금 Ryujinx를 다시 시작하겠습니까?", - "DialogUpdaterArchNotSupportedMessage": "지원되는 시스템 아키텍처를 실행하고 있지 않습니다!", - "DialogUpdaterArchNotSupportedSubMessage": "(64비트 시스템만 지원됩니다!)", "DialogUpdaterNoInternetMessage": "인터넷에 연결되어 있지 않습니다!", "DialogUpdaterNoInternetSubMessage": "인터넷 연결이 작동하는지 확인하세요!", "DialogUpdaterDirtyBuildMessage": "Ryujinx의 나쁜 빌드는 업데이트할 수 없습니다!\n", @@ -342,7 +447,7 @@ "DialogThemeRestartMessage": "테마가 저장되었습니다. 테마를 적용하려면 다시 시작해야 합니다.", "DialogThemeRestartSubMessage": "다시 시작하겠습니까?", "DialogFirmwareInstallEmbeddedMessage": "이 게임에 내장된 펌웨어를 설치하겠습니까? (펌웨어 {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "설치된 펌웨어가 없지만 Ryujinx가 제공된 게임에서 펌웨어 {0}을(를) 설치할 수 있었습니다.\\n이제 에뮬레이터가 시작됩니다.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "설치된 펌웨어가 없지만 Ryujinx가 제공된 게임에서 펌웨어 {0}을(를) 설치할 수 있었습니다.\n이제 에뮬레이터가 시작됩니다.", "DialogFirmwareNoFirmwareInstalledMessage": "설치된 펌웨어 없음", "DialogFirmwareInstalledMessage": "펌웨어 {0}이(가) 설치됨", "DialogInstallFileTypesSuccessMessage": "파일 형식을 성공적으로 설치했습니다!", @@ -385,7 +490,10 @@ "DialogUserProfileUnsavedChangesSubMessage": "변경사항을 저장하지 않으시겠습니까?", "DialogControllerSettingsModifiedConfirmMessage": "현재 컨트롤러 설정이 업데이트되었습니다.", "DialogControllerSettingsModifiedConfirmSubMessage": "저장하겠습니까?", - "DialogLoadNcaErrorMessage": "{0}. 오류 발생 파일 : {1}", + "DialogLoadFileErrorMessage": "{0}. 오류 발생 파일 : {1}", + "DialogModAlreadyExistsMessage": "Mod가 이미 존재합니다.", + "DialogModInvalidMessage": "지정된 디렉터리에 Mod가 없습니다!", + "DialogModDeleteNoParentMessage": "삭제 실패: \"{0}\" Mod의 상위 디렉터리를 찾을 수 없습니다!", "DialogDlcNoDlcErrorMessage": "지정된 파일에 선택한 타이틀에 대한 DLC가 포함되어 있지 않습니다!", "DialogPerformanceCheckLoggingEnabledMessage": "개발자만 사용하도록 설계된 추적 로그 기록이 활성화되어 있습니다.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "최적의 성능을 위해 추적 로그 생성을 비활성화하는 것이 좋습니다. 지금 추적 로그 기록을 비활성화하겠습니까?", @@ -396,6 +504,8 @@ "DialogUpdateAddUpdateErrorMessage": "지정된 파일에 선택한 제목에 대한 업데이트가 포함되어 있지 않습니다!", "DialogSettingsBackendThreadingWarningTitle": "경고 - 후단부 스레딩", "DialogSettingsBackendThreadingWarningMessage": "변경 사항을 완전히 적용하려면 이 옵션을 변경한 후, Ryujinx를 다시 시작해야 합니다. 플랫폼에 따라 Ryujinx를 사용할 때 드라이버 자체의 멀티스레딩을 수동으로 비활성화해야 할 수도 있습니다.", + "DialogModManagerDeletionWarningMessage": "해당 Mod를 삭제하려고 합니다: {0}\n\n정말로 삭제하시겠습니까?", + "DialogModManagerDeletionAllWarningMessage": "해당 타이틀에 대한 모든 Mod들을 삭제하려고 합니다.\n\n정말로 삭제하시겠습니까?", "SettingsTabGraphicsFeaturesOptions": "기능", "SettingsTabGraphicsBackendMultithreading": "그래픽 후단부 멀티스레딩 :", "CommonAuto": "자동", @@ -430,6 +540,7 @@ "DlcManagerRemoveAllButton": "모두 제거", "DlcManagerEnableAllButton": "모두 활성화", "DlcManagerDisableAllButton": "모두 비활성화", + "ModManagerDeleteAllButton": "모두 삭제", "MenuBarOptionsChangeLanguage": "언어 변경", "MenuBarShowFileTypes": "파일 유형 표시", "CommonSort": "정렬", @@ -447,13 +558,13 @@ "CustomThemePathTooltip": "사용자 정의 GUI 테마 경로", "CustomThemeBrowseTooltip": "사용자 정의 GUI 테마 찾아보기", "DockModeToggleTooltip": "독 모드에서는 에뮬레이트된 시스템이 도킹된 닌텐도 스위치처럼 작동합니다. 이것은 대부분의 게임에서 그래픽 품질을 향상시킵니다. 반대로 이 기능을 비활성화하면 에뮬레이트된 시스템이 휴대용 닌텐도 스위치처럼 작동하여 그래픽 품질이 저하됩니다.\n\n독 모드를 사용하려는 경우 플레이어 1의 컨트롤을 구성하세요. 휴대 모드를 사용하려는 경우 휴대용 컨트롤을 구성하세요.\n\n확실하지 않으면 켜 두세요.", - "DirectKeyboardTooltip": "직접 키보드 접속 (HID) 지원합니다. 텍스트 입력 장치로 키보드에 대한 게임 접속을 제공합니다.", - "DirectMouseTooltip": "직접 마우스 접속 (HID) 지원합니다. 포인팅 장치로 마우스에 대한 게임 접속을 제공합니다.", + "DirectKeyboardTooltip": "다이렉트 키보드 접근(HID)은 게임에서 사용자의 키보드를 텍스트 입력 장치로 사용할 수 있게끔 제공합니다.\n\n스위치 하드웨어에서 키보드 사용을 네이티브로 지원하는 게임에서만 작동합니다.\n\n이 옵션에 대해 잘 모른다면 끄기를 권장합니다.", + "DirectMouseTooltip": "다이렉트 마우스 접근(HID)은 게임에서 사용자의 마우스를 포인터 장치로 사용할 수 있게끔 제공합니다.\n\n스위치 하드웨어에서 마우스 사용을 네이티브로 지원하는 극히 일부 게임에서만 작동합니다.\n\n이 옵션이 활성화된 경우, 터치 스크린 기능이 작동하지 않을 수 있습니다.\n\n이 옵션에 대해 잘 모른다면 끄기를 권장합니다.", "RegionTooltip": "시스템 지역 변경", "LanguageTooltip": "시스템 언어 변경", "TimezoneTooltip": "시스템 시간대 변경", "TimeTooltip": "시스템 시간 변경", - "VSyncToggleTooltip": "에뮬레이트된 콘솔의 수직 동기화입니다. 기본적으로 대부분의 게임에 대한 프레임 제한 장치입니다. 비활성화하면 게임이 더 빠른 속도로 실행되거나 로딩 화면이 더 오래 걸리거나 멈출 수 있습니다.\n\n게임 내에서 선호하는 핫키로 전환할 수 있습니다. 비활성화할 계획이라면 이 작업을 수행하는 것이 좋습니다.\n\n확실하지 않으면 켜 두세요.", + "VSyncToggleTooltip": "에뮬레이트된 콘솔의 수직 동기화. 기본적으로 대부분의 게임에 대한 프레임 제한 장치로, 비활성화시 게임이 더 빠른 속도로 실행되거나 로딩 화면이 더 오래 걸리거나 멈출 수 있습니다.\n\n게임 내에서 선호하는 핫키로 전환할 수 있습니다(기본값 F1). 핫키를 비활성화할 계획이라면 이 작업을 수행하는 것이 좋습니다.\n\n이 옵션에 대해 잘 모른다면 켜기를 권장드립니다.", "PptcToggleTooltip": "게임이 불러올 때마다 번역할 필요가 없도록 번역된 JIT 기능을 저장합니다.\n\n게임을 처음 부팅한 후 끊김 현상을 줄이고 부팅 시간을 크게 단축합니다.\n\n확실하지 않으면 켜 두세요.", "FsIntegrityToggleTooltip": "게임을 부팅할 때 손상된 파일을 확인하고 손상된 파일이 감지되면 로그에 해시 오류를 표시합니다.\n\n성능에 영향을 미치지 않으며 문제 해결에 도움이 됩니다.\n\n확실하지 않으면 켜 두세요.", "AudioBackendTooltip": "오디오를 렌더링하는 데 사용되는 백엔드를 변경합니다.\n\nSDL2가 선호되는 반면 OpenAL 및 사운드IO는 폴백으로 사용됩니다. 더미는 소리가 나지 않습니다.\n\n확실하지 않으면 SDL2로 설정하세요.", @@ -467,10 +578,10 @@ "GraphicsBackendThreadingTooltip": "두 번째 스레드에서 그래픽 백엔드 명령을 실행합니다.\n\n세이더 컴파일 속도를 높이고 끊김 현상을 줄이며 자체 멀티스레딩 지원 없이 GPU 드라이버의 성능을 향상시킵니다. 멀티스레딩이 있는 드라이버에서 성능이 약간 향상되었습니다.\n\n잘 모르겠으면 자동으로 설정하세요.", "GalThreadingTooltip": "두 번째 스레드에서 그래픽 백엔드 명령을 실행합니다.\n\n세이더 컴파일 속도를 높이고 끊김 현상을 줄이며 자체 멀티스레딩 지원 없이 GPU 드라이버의 성능을 향상시킵니다. 멀티스레딩이 있는 드라이버에서 성능이 약간 향상되었습니다.\n\n잘 모르겠으면 자동으로 설정하세요.", "ShaderCacheToggleTooltip": "후속 실행에서 끊김 현상을 줄이는 디스크 세이더 캐시를 저장합니다.\n\n확실하지 않으면 켜 두세요.", - "ResolutionScaleTooltip": "적용 가능한 렌더 타겟에 적용된 해상도 스케일", + "ResolutionScaleTooltip": "게임의 렌더링 해상도를 늘립니다.\n\n일부 게임에서는 해당 기능을 지원하지 않거나 해상도가 늘어났음에도 픽셀이 자글자글해 보일 수 있습니다; 이러한 게임들의 경우 사용자가 직접 안티 앨리어싱 기능을 끄는 Mod나 내부 렌더링 해상도를 증가시키는 Mod 등을 찾아보아야 합니다. 후자의 Mod를 사용 시에는 해당 옵션을 네이티브로 두시는 것이 좋습니다.\n\n이 옵션은 게임이 구동중일 때에도 아래 Apply 버튼을 눌러서 변경할 수 있습니다; 설정 창을 게임 창 옆에 두고 사용자가 선호하는 해상도를 실험하여 고를 수 있습니다.\n\n4x 설정은 어떤 셋업에서도 무리인 점을 유의하세요.", "ResolutionScaleEntryTooltip": "1.5와 같은 부동 소수점 분해능 스케일입니다. 비통합 척도는 문제나 충돌을 일으킬 가능성이 더 큽니다.", - "AnisotropyTooltip": "비등방성 필터링 수준 (게임에서 요청한 값을 사용하려면 자동으로 설정)", - "AspectRatioTooltip": "렌더러 창에 적용된 화면비입니다.", + "AnisotropyTooltip": "비등방성 필터링 레벨. 게임에서 요청한 값을 사용하려면 자동으로 설정하세요.", + "AspectRatioTooltip": "렌더러 창에 적용될 화면비.\n\n화면비를 변경하는 Mod를 사용할 때에만 이 옵션을 바꾸세요, 그렇지 않을 경우 그래픽이 늘어나 보일 수 있습니다.\n\n이 옵션에 대해 잘 모른다면 16:9로 설정하세요.", "ShaderDumpPathTooltip": "그래픽 셰이더 덤프 경로", "FileLogTooltip": "디스크의 로그 파일에 콘솔 로깅을 저장합니다. 성능에 영향을 미치지 않습니다.", "StubLogTooltip": "콘솔에 스텁 로그 메시지를 인쇄합니다. 성능에 영향을 미치지 않습니다.", @@ -504,6 +615,8 @@ "EnableInternetAccessTooltip": "에뮬레이션된 응용프로그램이 인터넷에 연결되도록 허용합니다.\n\nLAN 모드가 있는 게임은 이 모드가 활성화되고 시스템이 동일한 접속 포인트에 연결된 경우 서로 연결할 수 있습니다. 여기에는 실제 콘솔도 포함됩니다.\n\n닌텐도 서버에 연결할 수 없습니다. 인터넷에 연결을 시도하는 특정 게임에서 충돌이 발생할 수 있습니다.\n\n확실하지 않으면 꺼두세요.", "GameListContextMenuManageCheatToolTip": "치트 관리", "GameListContextMenuManageCheat": "치트 관리", + "GameListContextMenuManageModToolTip": "Mod 관리", + "GameListContextMenuManageMod": "Mod 관리", "ControllerSettingsStickRange": "범위 :", "DialogStopEmulationTitle": "Ryujinx - 에뮬레이션 중지", "DialogStopEmulationMessage": "에뮬레이션을 중지하겠습니까?", @@ -515,8 +628,6 @@ "SettingsTabCpuMemory": "CPU 모드", "DialogUpdaterFlatpakNotSupportedMessage": "FlatHub를 통해 Ryujinx를 업데이트하세요.", "UpdaterDisabledWarningTitle": "업데이터 비활성화입니다!", - "GameListContextMenuOpenSdModsDirectory": "분위기 모드 디렉터리 열기", - "GameListContextMenuOpenSdModsDirectoryToolTip": "응용프로그램의 모드가 포함된 대체 SD 카드 분위기 디렉터리를 엽니다. 실제 하드웨어용으로 패키징된 모드에 유용합니다.", "ControllerSettingsRotate90": "시계 방향으로 90° 회전", "IconSize": "아이콘 크기", "IconSizeTooltip": "게임 아이콘 크기 변경", @@ -544,12 +655,13 @@ "SwkbdMinCharacters": "{0}자 이상이어야 함", "SwkbdMinRangeCharacters": "{0}-{1}자여야 함", "SoftwareKeyboard": "소프트웨어 키보드", - "SoftwareKeyboardModeNumbersOnly": "숫자만 가능", + "SoftwareKeyboardModeNumeric": "'0~9' 또는 '.'만 가능", "SoftwareKeyboardModeAlphabet": "한중일 문자가 아닌 문자만 가능", "SoftwareKeyboardModeASCII": "ASCII 텍스트만 가능", - "DialogControllerAppletMessagePlayerRange": "응용 프로그램은 다음을 사용하는 {0} 명의 플레이어를 요청합니다:\n\n유형: {1}\n\n플레이어: {2}\n\n{3} 지금 설정을 열고 입력을 재구성하거나 닫기를 누르세요.\n", - "DialogControllerAppletMessage": "응용 프로그램은 다음을 사용하는 정확히 {0}명의 플레이어를 요청합니다:\n\n유형: {1}\n\n플레이어: {2}\n\n{3} 지금 설정을 열고 입력을 재구성하거나 닫기를 누르세요.\n", - "DialogControllerAppletDockModeSet": "독 모드가 설정되었습니다. 휴대 모드도 유효하지 않습니다.", + "ControllerAppletControllers": "지원하는 컨트롤러:", + "ControllerAppletPlayers": "플레이어:", + "ControllerAppletDescription": "현재 설정은 유효하지 않습니다. 설정을 열어 입력 장치를 다시 설정하세요.", + "ControllerAppletDocked": "독 모드가 설정되었습니다. 핸드헬드 컨트롤은 비활성화됩니다.", "UpdaterRenaming": "이전 파일 이름 바꾸는 중...", "UpdaterRenameFailed": "업데이터가 파일 이름을 바꿀 수 없음: {0}", "UpdaterAddingFiles": "새로운 파일을 추가하는 중...", @@ -587,17 +699,21 @@ "Writable": "쓰기 가능", "SelectDlcDialogTitle": "DLC 파일 선택", "SelectUpdateDialogTitle": "업데이트 파일 선택", + "SelectModDialogTitle": "Mod 디렉터리 선택", "UserProfileWindowTitle": "사용자 프로파일 관리자", "CheatWindowTitle": "치트 관리자", "DlcWindowTitle": "{0} ({1})의 다운로드 가능한 콘텐츠 관리", + "ModWindowTitle": "{0} ({1})의 Mod 관리", "UpdateWindowTitle": "타이틀 업데이트 관리자", "CheatWindowHeading": "{0} [{1}]에 사용할 수 있는 치트", "BuildId": "빌드ID :", "DlcWindowHeading": "{0} 내려받기 가능한 콘텐츠", + "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "선택된 항목 편집", "Cancel": "취소", "Save": "저장", "Discard": "삭제", + "Paused": "일시 중지", "UserProfilesSetProfileImage": "프로파일 이미지 설정", "UserProfileEmptyNameError": "이름 필요", "UserProfileNoImageError": "프로파일 이미지를 설정해야 함", @@ -607,9 +723,9 @@ "UserProfilesName": "이름 :", "UserProfilesUserId": "사용자 ID :", "SettingsTabGraphicsBackend": "그래픽 후단부", - "SettingsTabGraphicsBackendTooltip": "사용할 그래픽 후단부", + "SettingsTabGraphicsBackendTooltip": "에뮬레이터에 사용될 그래픽 백엔드를 선택합니다.\n\nVulkan이 드라이버가 최신이기 때문에 모든 현대 그래픽 카드들에서 더 좋은 성능을 발휘합니다. 또한 Vulkan은 모든 벤더사의 GPU에서 더 빠른 쉐이더 컴파일을 지원하여 스터터링이 적습니다.\n\nOpenGL의 경우 오래된 Nvidia GPU나 오래된 AMD GPU(리눅스 한정), 혹은 VRAM이 적은 GPU에서 더 나은 성능을 발휘할 수는 있으나 쉐이더 컴파일로 인한 스터터링이 Vulkan보다 심할 수 있습니다.\n\n이 옵션에 대해 잘 모른다면 Vulkan으로 설정하세요. 사용하는 GPU가 최신 그래픽 드라이버에서도 Vulkan을 지원하지 않는다면 그 땐 OpenGL로 설정하세요.", "SettingsEnableTextureRecompression": "텍스처 재압축 활성화", - "SettingsEnableTextureRecompressionTooltip": "VRAM 사용량을 줄이기 위해 특정 텍스처를 압축합니다.\n\n4GiB VRAM 미만의 GPU와 함께 사용하는 것이 좋습니다.\n\n확실하지 않으면 꺼 두세요.", + "SettingsEnableTextureRecompressionTooltip": "ASTC 텍스처를 압축하여 VRAM 사용량을 줄입니다.\n\n애스트럴 체인, 바요네타 3, 파이어 엠블렘 인게이지, 메트로이드 프라임 리마스터, 슈퍼 마리오브라더스 원더, 젤다의 전설: 티어스 오브 더 킹덤 등이 이러한 텍스처 포맷을 사용합니다.\n\nVRAM이 4GiB 이하인 그래픽 카드로 위와 같은 게임들을 구동할시 특정 지점에서 크래시가 발생할 수 있습니다.\n\n위에 서술된 게임들에서 VRAM이 부족한 경우에만 해당 옵션을 켜고, 그 외의 경우에는 끄기를 권장드립니다.", "SettingsTabGraphicsPreferredGpu": "선호하는 GPU", "SettingsTabGraphicsPreferredGpuTooltip": "Vulkan 그래픽 후단부와 함께 사용할 그래픽 카드를 선택하세요.\n\nOpenGL이 사용할 GPU에는 영향을 미치지 않습니다.\n\n확실하지 않은 경우 \"dGPU\" 플래그가 지정된 GPU로 설정하세요. 없는 경우, 그대로 두세요.", "SettingsAppRequiredRestartMessage": "Ryujinx 다시 시작 필요", @@ -635,12 +751,15 @@ "Recover": "복구", "UserProfilesRecoverHeading": "다음 계정에 대한 저장 발견", "UserProfilesRecoverEmptyList": "복구할 프로파일이 없습니다", - "GraphicsAATooltip": "게임 렌더링에 안티 앨리어싱을 적용", + "GraphicsAATooltip": "게임 렌더에 안티 앨리어싱을 적용합니다.\n\nFXAA는 대부분의 이미지를 뿌옇게 만들지만, SMAA는 들쭉날쭉한 모서리 부분들을 찾아 부드럽게 만듭니다.\n\nFSR 스케일링 필터와 같이 사용하는 것은 권장하지 않습니다.\n\n이 옵션은 게임이 구동중일 때에도 아래 Apply 버튼을 눌러서 변경할 수 있습니다; 설정 창을 게임 창 옆에 두고 사용자가 선호하는 옵션을 실험하여 고를 수 있습니다.\n\n이 옵션에 대해 잘 모른다면 끄기를 권장드립니다.", "GraphicsAALabel": "안티 앨리어싱:", "GraphicsScalingFilterLabel": "스케일링 필터:", - "GraphicsScalingFilterTooltip": "프레임버퍼 스케일링 활성화", + "GraphicsScalingFilterTooltip": "해상도 스케일에 사용될 스케일링 필터를 선택하세요.\n\nBilinear는 3D 게임에서 잘 작동하며 안전한 기본값입니다.\n\nNearest는 픽셀 아트 게임에 추천합니다.\n\nFSR 1.0은 그저 샤프닝 필터임으로, FXAA나 SMAA와 같이 사용하는 것은 권장하지 않습니다.\n\n이 옵션은 게임이 구동중일 때에도 아래 Apply 버튼을 눌러서 변경할 수 있습니다; 설정 창을 게임 창 옆에 두고 사용자가 선호하는 옵션을 실험하여 고를 수 있습니다.\n\n이 옵션에 대해 잘 모른다면 BILINEAR로 두세요.", + "GraphicsScalingFilterBilinear": "Bilinear", + "GraphicsScalingFilterNearest": "Nearest", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "수준", - "GraphicsScalingFilterLevelTooltip": "스케일링 필터 수준 설정", + "GraphicsScalingFilterLevelTooltip": "FSR 1.0의 샤프닝 레벨을 설정하세요. 높을수록 더 또렷해집니다.", "SmaaLow": "SMAA 낮음", "SmaaMedium": "SMAA 중간", "SmaaHigh": "SMAA 높음", @@ -648,9 +767,14 @@ "UserEditorTitle": "사용자 수정", "UserEditorTitleCreate": "사용자 생성", "SettingsTabNetworkInterface": "네트워크 인터페이스:", - "NetworkInterfaceTooltip": "LAN 기능에 사용되는 네트워크 인터페이스", + "NetworkInterfaceTooltip": "LAN/LDN 기능에 사용될 네트워크 인터페이스입니다.\n\nLAN 기능을 지원하는 게임에서 VPN이나 XLink Kai 등을 동시에 사용하면, 인터넷을 통해 동일 네트워크 연결인 것을 속일 수 있습니다.\n\n이 옵션에 대해 잘 모른다면 기본값으로 설정하세요.", "NetworkInterfaceDefault": "기본", "PackagingShaders": "셰이더 패키징 중", "AboutChangelogButton": "GitHub에서 변경 로그 보기", - "AboutChangelogButtonTooltipMessage": "기본 브라우저에서 이 버전의 변경 로그를 열려면 클릭합니다." -} \ No newline at end of file + "AboutChangelogButtonTooltipMessage": "기본 브라우저에서 이 버전의 변경 로그를 열려면 클릭합니다.", + "SettingsTabNetworkMultiplayer": "멀티 플레이어", + "MultiplayerMode": "모드 :", + "MultiplayerModeTooltip": "LDN 멀티플레이어 모드를 변경합니다.\n\nLdnMitm은 로컬 무선/로컬 플레이 기능을 수정하여 LAN 모드에 있는 것처럼 만들어 로컬이나 동일한 네트워크 상에 있는 다른 Ryujinx 인스턴스나 커펌된 닌텐도 스위치 콘솔(ldn_mitm 모듈 설치 필요)과 연결할 수 있습니다.\n\n멀티플레이어 모드는 모든 플레이어들이 동일한 게임 버전을 요구합니다. 예를 들어 슈퍼 스매시브라더스 얼티밋 v13.0.1 사용자는 v13.0.0 사용자와 연결할 수 없습니다.\n\n해당 옵션에 대해 잘 모른다면 비활성화해두세요.", + "MultiplayerModeDisabled": "비활성화됨", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/pl_PL.json b/src/Ryujinx/Assets/Locales/pl_PL.json similarity index 65% rename from src/Ryujinx.Ava/Assets/Locales/pl_PL.json rename to src/Ryujinx/Assets/Locales/pl_PL.json index 7edf41e84..9d1bd7b44 100644 --- a/src/Ryujinx.Ava/Assets/Locales/pl_PL.json +++ b/src/Ryujinx/Assets/Locales/pl_PL.json @@ -1,112 +1,122 @@ { - "Language": "Angielski (USA)", + "Language": "Polski", "MenuBarFileOpenApplet": "Otwórz Aplet", - "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Otwórz aplet Mii Editor w trybie Indywidualnym", - "SettingsTabInputDirectMouseAccess": "Bezpośredni Dostęp do Myszy", - "SettingsTabSystemMemoryManagerMode": "Tryb Menedżera Pamięci:", + "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Otwórz aplet Mii Editor w trybie indywidualnym", + "SettingsTabInputDirectMouseAccess": "Bezpośredni dostęp do myszy", + "SettingsTabSystemMemoryManagerMode": "Tryb menedżera pamięci:", "SettingsTabSystemMemoryManagerModeSoftware": "Oprogramowanie", - "SettingsTabSystemMemoryManagerModeHost": "Host (szybko)", - "SettingsTabSystemMemoryManagerModeHostUnchecked": "Host Niesprawdzony (najszybciej, niebezpiecznie)", - "SettingsTabSystemUseHypervisor": "Użyj Hiperwizora", + "SettingsTabSystemMemoryManagerModeHost": "Gospodarz (szybki)", + "SettingsTabSystemMemoryManagerModeHostUnchecked": "Gospodarza (NIESPRAWDZONY, najszybszy, niebezpieczne)", + "SettingsTabSystemUseHypervisor": "Użyj Hipernadzorcy", "MenuBarFile": "_Plik", - "MenuBarFileOpenFromFile": "_Załaduj Aplikację z Pliku", - "MenuBarFileOpenUnpacked": "Załaduj _Rozpakowaną Grę", - "MenuBarFileOpenEmuFolder": "Otwórz Folder Ryujinx", - "MenuBarFileOpenLogsFolder": "Otwórz Folder Logów", + "MenuBarFileOpenFromFile": "_Załaduj aplikację z pliku", + "MenuBarFileOpenUnpacked": "Załaduj _rozpakowaną grę", + "MenuBarFileOpenEmuFolder": "Otwórz folder Ryujinx", + "MenuBarFileOpenLogsFolder": "Otwórz folder plików dziennika zdarzeń", "MenuBarFileExit": "_Wyjdź", - "MenuBarOptions": "Opcje", - "MenuBarOptionsToggleFullscreen": "Przełącz Tryb Pełnoekranowy", - "MenuBarOptionsStartGamesInFullscreen": "Uruchamiaj Gry w Trybie Pełnoekranowym", - "MenuBarOptionsStopEmulation": "Zatrzymaj Emulację", + "MenuBarOptions": "_Opcje", + "MenuBarOptionsToggleFullscreen": "Przełącz na tryb pełnoekranowy", + "MenuBarOptionsStartGamesInFullscreen": "Uruchamiaj gry w trybie pełnoekranowym", + "MenuBarOptionsStopEmulation": "Zatrzymaj emulację", "MenuBarOptionsSettings": "_Ustawienia", - "MenuBarOptionsManageUserProfiles": "_Zarządzaj Profilami Użytkowników", + "MenuBarOptionsManageUserProfiles": "_Zarządzaj profilami użytkowników", "MenuBarActions": "_Akcje", - "MenuBarOptionsSimulateWakeUpMessage": "Symuluj Wiadomość Budzenia", + "MenuBarOptionsSimulateWakeUpMessage": "Symuluj wiadomość wybudzania", "MenuBarActionsScanAmiibo": "Skanuj Amiibo", "MenuBarTools": "_Narzędzia", - "MenuBarToolsInstallFirmware": "Zainstaluj Firmware", - "MenuBarFileToolsInstallFirmwareFromFile": "Zainstaluj Firmware z XCI lub ZIP", - "MenuBarFileToolsInstallFirmwareFromDirectory": "Zainstaluj Firmware z Katalogu", - "MenuBarToolsManageFileTypes": "Zarządzaj rodzajem plików", - "MenuBarToolsInstallFileTypes": "Instalacja typów plików", - "MenuBarToolsUninstallFileTypes": "Odinstaluj rodzaje plików", - "MenuBarHelp": "Pomoc", - "MenuBarHelpCheckForUpdates": "Sprawdź Aktualizacje", - "MenuBarHelpAbout": "O Aplikacji", + "MenuBarToolsInstallFirmware": "Zainstaluj oprogramowanie", + "MenuBarFileToolsInstallFirmwareFromFile": "Zainstaluj oprogramowanie z XCI lub ZIP", + "MenuBarFileToolsInstallFirmwareFromDirectory": "Zainstaluj oprogramowanie z katalogu", + "MenuBarToolsManageFileTypes": "Zarządzaj rodzajami plików", + "MenuBarToolsInstallFileTypes": "Typy plików instalacyjnych", + "MenuBarToolsUninstallFileTypes": "Typy plików dezinstalacyjnych", + "MenuBarView": "_View", + "MenuBarViewWindow": "Window Size", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Pomoc", + "MenuBarHelpCheckForUpdates": "Sprawdź aktualizacje", + "MenuBarHelpAbout": "O programie", "MenuSearch": "Wyszukaj...", - "GameListHeaderFavorite": "Ulub", + "GameListHeaderFavorite": "Ulubione", "GameListHeaderIcon": "Ikona", "GameListHeaderApplication": "Nazwa", - "GameListHeaderDeveloper": "Deweloper", + "GameListHeaderDeveloper": "Twórca", "GameListHeaderVersion": "Wersja", - "GameListHeaderTimePlayed": "Czas Gry", - "GameListHeaderLastPlayed": "Ostatnio Grane", - "GameListHeaderFileExtension": "Rozsz. Pliku", - "GameListHeaderFileSize": "Rozm. Pliku", + "GameListHeaderTimePlayed": "Czas w grze:", + "GameListHeaderLastPlayed": "Ostatnio grane", + "GameListHeaderFileExtension": "Rozszerzenie pliku", + "GameListHeaderFileSize": "Rozmiar pliku", "GameListHeaderPath": "Ścieżka", - "GameListContextMenuOpenUserSaveDirectory": "Otwórz Katalog Zapisów Użytkownika", - "GameListContextMenuOpenUserSaveDirectoryToolTip": "Otwiera katalog, który zawiera Zapis Użytkownika Aplikacji", - "GameListContextMenuOpenDeviceSaveDirectory": "Otwórz Katalog Urządzeń Użytkownika", - "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Otwiera katalog, który zawiera Zapis Urządzenia Aplikacji", - "GameListContextMenuOpenBcatSaveDirectory": "Otwórz Katalog BCAT Użytkownika", - "GameListContextMenuOpenBcatSaveDirectoryToolTip": "Otwiera katalog, który zawiera Zapis BCAT Aplikacji", - "GameListContextMenuManageTitleUpdates": "Zarządzaj Aktualizacjami Tytułów", - "GameListContextMenuManageTitleUpdatesToolTip": "Otwiera okno zarządzania Aktualizacjami Tytułu", - "GameListContextMenuManageDlc": "Zarządzaj DLC", - "GameListContextMenuManageDlcToolTip": "Otwiera okno zarządzania DLC", - "GameListContextMenuOpenModsDirectory": "Otwórz Katalog Modów", - "GameListContextMenuOpenModsDirectoryToolTip": "Otwiera katalog zawierający Mody Aplikacji", + "GameListContextMenuOpenUserSaveDirectory": "Otwórz katalog zapisów użytkownika", + "GameListContextMenuOpenUserSaveDirectoryToolTip": "Otwiera katalog, który zawiera zapis użytkownika dla tej aplikacji", + "GameListContextMenuOpenDeviceSaveDirectory": "Otwórz katalog zapisów urządzenia", + "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Otwiera katalog, który zawiera zapis urządzenia dla tej aplikacji", + "GameListContextMenuOpenBcatSaveDirectory": "Otwórz katalog zapisu BCAT obecnego użytkownika", + "GameListContextMenuOpenBcatSaveDirectoryToolTip": "Otwiera katalog, który zawiera zapis BCAT dla tej aplikacji", + "GameListContextMenuManageTitleUpdates": "Zarządzaj aktualizacjami", + "GameListContextMenuManageTitleUpdatesToolTip": "Otwiera okno zarządzania aktualizacjami danej aplikacji", + "GameListContextMenuManageDlc": "Zarządzaj dodatkową zawartością (DLC)", + "GameListContextMenuManageDlcToolTip": "Otwiera okno zarządzania dodatkową zawartością", "GameListContextMenuCacheManagement": "Zarządzanie Cache", - "GameListContextMenuCacheManagementPurgePptc": "Dodaj Rekompilację PPTC do Kolejki", + "GameListContextMenuCacheManagementPurgePptc": "Zakolejkuj rekompilację PPTC", "GameListContextMenuCacheManagementPurgePptcToolTip": "Zainicjuj Rekompilację PPTC przy następnym uruchomieniu gry", - "GameListContextMenuCacheManagementPurgeShaderCache": "Wyczyść Cache Shaderów", - "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Usuwa cache shaderów aplikacji", - "GameListContextMenuCacheManagementOpenPptcDirectory": "Otwórz Katalog PPTC", - "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Otwiera katalog, który zawiera cache PPTC aplikacji", - "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Otwórz Katalog Cache Shaderów", - "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Otwiera katalog, który zawiera cache shaderów aplikacji", - "GameListContextMenuExtractData": "Wyodrębnij Dane", + "GameListContextMenuCacheManagementPurgeShaderCache": "Wyczyść pamięć podręczną cieni", + "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Usuwa pamięć podręczną cieni danej aplikacji", + "GameListContextMenuCacheManagementOpenPptcDirectory": "Otwórz katalog PPTC", + "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Otwiera katalog, który zawiera pamięć podręczną PPTC aplikacji", + "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Otwórz katalog pamięci podręcznej cieni", + "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Otwiera katalog, który zawiera pamięć podręczną cieni aplikacji", + "GameListContextMenuExtractData": "Wypakuj dane", "GameListContextMenuExtractDataExeFS": "ExeFS", "GameListContextMenuExtractDataExeFSToolTip": "Wyodrębnij sekcję ExeFS z bieżącej konfiguracji aplikacji (w tym aktualizacje)", "GameListContextMenuExtractDataRomFS": "RomFS", "GameListContextMenuExtractDataRomFSToolTip": "Wyodrębnij sekcję RomFS z bieżącej konfiguracji aplikacji (w tym aktualizacje)", "GameListContextMenuExtractDataLogo": "Logo", - "GameListContextMenuExtractDataLogoToolTip": "Wyodrębnij sekcję Logo z bieżącej konfiguracji aplikacji (w tym aktualizacje)", - "StatusBarGamesLoaded": "{0}/{1} Załadowane Gry", - "StatusBarSystemVersion": "Wersja Systemu: {0}", - "LinuxVmMaxMapCountDialogTitle": "Wykryto niski limit dla mapowania pamięci", - "LinuxVmMaxMapCountDialogTextPrimary": "Czy chciałbyś zwiększyć wartość vm.max_map_count do {0}", - "LinuxVmMaxMapCountDialogTextSecondary": "Niektóre gry mogą próbować stworzyć więcej mapowań pamięci niż obecnie, jest to dozwolone. Ryujinx napotka crash, gdy dojdzie do takiej sytuacji.", + "GameListContextMenuExtractDataLogoToolTip": "Wyodrębnij sekcję z logiem z bieżącej konfiguracji aplikacji (w tym aktualizacje)", + "GameListContextMenuCreateShortcut": "Utwórz skrót aplikacji", + "GameListContextMenuCreateShortcutToolTip": "Utwórz skrót na pulpicie, który uruchamia wybraną aplikację", + "GameListContextMenuCreateShortcutToolTipMacOS": "Utwórz skrót w folderze 'Aplikacje' w systemie macOS, który uruchamia wybraną aplikację", + "GameListContextMenuOpenModsDirectory": "Otwórz katalog modów", + "GameListContextMenuOpenModsDirectoryToolTip": "Otwiera katalog zawierający mody dla danej aplikacji", + "GameListContextMenuOpenSdModsDirectory": "Otwórz katalog modów Atmosphere", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Otwiera alternatywny katalog Atmosphere na karcie SD, który zawiera mody danej aplikacji. Przydatne dla modów przygotowanych pod prawdziwy sprzęt.", + "StatusBarGamesLoaded": "{0}/{1} Załadowane gry", + "StatusBarSystemVersion": "Wersja systemu: {0}", + "LinuxVmMaxMapCountDialogTitle": "Wykryto niski limit dla przypisań pamięci", + "LinuxVmMaxMapCountDialogTextPrimary": "Czy chcesz zwiększyć wartość vm.max_map_count do {0}", + "LinuxVmMaxMapCountDialogTextSecondary": "Niektóre gry mogą próbować przypisać sobie więcej pamięci niż obecnie, jest to dozwolone. Ryujinx ulegnie awarii, gdy limit zostanie przekroczony.", "LinuxVmMaxMapCountDialogButtonUntilRestart": "Tak, do następnego ponownego uruchomienia", "LinuxVmMaxMapCountDialogButtonPersistent": "Tak, permanentnie ", - "LinuxVmMaxMapCountWarningTextPrimary": "Maksymalna ilość mapowania pamięci jest mniejsza niż zalecana.", + "LinuxVmMaxMapCountWarningTextPrimary": "Maksymalna ilość przypisanej pamięci jest mniejsza niż zalecana.", "LinuxVmMaxMapCountWarningTextSecondary": "Obecna wartość vm.max_map_count ({0}) jest mniejsza niż {1}. Niektóre gry mogą próbować stworzyć więcej mapowań pamięci niż obecnie jest to dozwolone. Ryujinx napotka crash, gdy dojdzie do takiej sytuacji.\n\nMożesz chcieć ręcznie zwiększyć limit lub zainstalować pkexec, co pozwala Ryujinx na pomoc w tym zakresie.", "Settings": "Ustawienia", - "SettingsTabGeneral": "Interfejs Użytkownika", + "SettingsTabGeneral": "Interfejs użytkownika", "SettingsTabGeneralGeneral": "Ogólne", "SettingsTabGeneralEnableDiscordRichPresence": "Włącz Bogatą Obecność Discord", - "SettingsTabGeneralCheckUpdatesOnLaunch": "Sprawdź Aktualizacje przy Uruchomieniu", - "SettingsTabGeneralShowConfirmExitDialog": "Pokaż Okno Dialogowe \"Potwierdzenia Wyjścia\"", + "SettingsTabGeneralCheckUpdatesOnLaunch": "Sprawdzaj aktualizacje przy uruchomieniu", + "SettingsTabGeneralShowConfirmExitDialog": "Pokazuj okno dialogowe \"Potwierdź wyjście\"", + "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", "SettingsTabGeneralHideCursor": "Ukryj kursor:", "SettingsTabGeneralHideCursorNever": "Nigdy", - "SettingsTabGeneralHideCursorOnIdle": "Ukryj Kursor Podczas Bezczynności", + "SettingsTabGeneralHideCursorOnIdle": "Gdy bezczynny", "SettingsTabGeneralHideCursorAlways": "Zawsze", - "SettingsTabGeneralGameDirectories": "Katalogi Gier", + "SettingsTabGeneralGameDirectories": "Katalogi gier", "SettingsTabGeneralAdd": "Dodaj", "SettingsTabGeneralRemove": "Usuń", "SettingsTabSystem": "System", "SettingsTabSystemCore": "Główne", - "SettingsTabSystemSystemRegion": "Region Systemu:", + "SettingsTabSystemSystemRegion": "Region systemu:", "SettingsTabSystemSystemRegionJapan": "Japonia", - "SettingsTabSystemSystemRegionUSA": "USA", + "SettingsTabSystemSystemRegionUSA": "Stany Zjednoczone", "SettingsTabSystemSystemRegionEurope": "Europa", "SettingsTabSystemSystemRegionAustralia": "Australia", "SettingsTabSystemSystemRegionChina": "Chiny", "SettingsTabSystemSystemRegionKorea": "Korea", "SettingsTabSystemSystemRegionTaiwan": "Tajwan", - "SettingsTabSystemSystemLanguage": "Język Systemu:", + "SettingsTabSystemSystemLanguage": "Język systemu:", "SettingsTabSystemSystemLanguageJapanese": "Japoński", - "SettingsTabSystemSystemLanguageAmericanEnglish": "Amerykański Angielski", + "SettingsTabSystemSystemLanguageAmericanEnglish": "Angielski (Stany Zjednoczone)", "SettingsTabSystemSystemLanguageFrench": "Francuski", "SettingsTabSystemSystemLanguageGerman": "Niemiecki", "SettingsTabSystemSystemLanguageItalian": "Włoski", @@ -117,16 +127,16 @@ "SettingsTabSystemSystemLanguagePortuguese": "Portugalski", "SettingsTabSystemSystemLanguageRussian": "Rosyjski", "SettingsTabSystemSystemLanguageTaiwanese": "Tajwański", - "SettingsTabSystemSystemLanguageBritishEnglish": "Brytyjski Angielski", + "SettingsTabSystemSystemLanguageBritishEnglish": "Angielski (Wielka Brytania)", "SettingsTabSystemSystemLanguageCanadianFrench": "Kanadyjski Francuski", - "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Hiszpański Latynoamerykański", - "SettingsTabSystemSystemLanguageSimplifiedChinese": "Chiński Uproszczony", - "SettingsTabSystemSystemLanguageTraditionalChinese": "Chiński Tradycyjny", - "SettingsTabSystemSystemTimeZone": "Strefa Czasowa Systemu:", - "SettingsTabSystemSystemTime": "Czas Systemu:", - "SettingsTabSystemEnableVsync": "Włącz synchronizację pionową", - "SettingsTabSystemEnablePptc": "PPTC (Profilowany Cache Trwałych Tłumaczeń)", - "SettingsTabSystemEnableFsIntegrityChecks": "Kontrole Integralności Systemu Plików", + "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Hiszpański (Ameryka Łacińska)", + "SettingsTabSystemSystemLanguageSimplifiedChinese": "Chiński (Uproszczony)", + "SettingsTabSystemSystemLanguageTraditionalChinese": "Chiński (Tradycyjny)", + "SettingsTabSystemSystemTimeZone": "Strefa czasowa systemu:", + "SettingsTabSystemSystemTime": "Czas systemu:", + "SettingsTabSystemEnableVsync": "Synchronizacja pionowa", + "SettingsTabSystemEnablePptc": "PPTC (Profilowana pamięć podręczna trwałych łłumaczeń)", + "SettingsTabSystemEnableFsIntegrityChecks": "Sprawdzanie integralności systemu plików", "SettingsTabSystemAudioBackend": "Backend Dżwięku:", "SettingsTabSystemAudioBackendDummy": "Atrapa", "SettingsTabSystemAudioBackendOpenAL": "OpenAL", @@ -138,31 +148,31 @@ "SettingsTabSystemIgnoreMissingServices": "Ignoruj Brakujące Usługi", "SettingsTabGraphics": "Grafika", "SettingsTabGraphicsAPI": "Graficzne API", - "SettingsTabGraphicsEnableShaderCache": "Włącz Cache Shaderów", - "SettingsTabGraphicsAnisotropicFiltering": "Filtrowanie Anizotropowe:", - "SettingsTabGraphicsAnisotropicFilteringAuto": "Automatyczny", + "SettingsTabGraphicsEnableShaderCache": "Włącz pamięć podręczną cieni", + "SettingsTabGraphicsAnisotropicFiltering": "Filtrowanie anizotropowe:", + "SettingsTabGraphicsAnisotropicFilteringAuto": "Automatyczne", "SettingsTabGraphicsAnisotropicFiltering2x": "2x", "SettingsTabGraphicsAnisotropicFiltering4x": "4x", "SettingsTabGraphicsAnisotropicFiltering8x": "8x", "SettingsTabGraphicsAnisotropicFiltering16x": "16x", - "SettingsTabGraphicsResolutionScale": "Skala Rozdzielczości:", + "SettingsTabGraphicsResolutionScale": "Skalowanie rozdzielczości:", "SettingsTabGraphicsResolutionScaleCustom": "Niestandardowa (Niezalecane)", "SettingsTabGraphicsResolutionScaleNative": "Natywna (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", - "SettingsTabGraphicsAspectRatio": "Współczynnik Proporcji:", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (niezalecane)", + "SettingsTabGraphicsAspectRatio": "Format obrazu:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", "SettingsTabGraphicsAspectRatio16x10": "16:10", "SettingsTabGraphicsAspectRatio21x9": "21:9", "SettingsTabGraphicsAspectRatio32x9": "32:9", "SettingsTabGraphicsAspectRatioStretch": "Rozciągnij do Okna", - "SettingsTabGraphicsDeveloperOptions": "Opcje Programistyczne", - "SettingsTabGraphicsShaderDumpPath": "Ścieżka Zrzutu Shaderów Grafiki:", - "SettingsTabLogging": "Logowanie", - "SettingsTabLoggingLogging": "Logowanie", - "SettingsTabLoggingEnableLoggingToFile": "Włącz Logowanie do Pliku", + "SettingsTabGraphicsDeveloperOptions": "Opcje programisty", + "SettingsTabGraphicsShaderDumpPath": "Ścieżka do zgranych cieni graficznych:", + "SettingsTabLogging": "Dziennik zdarzeń", + "SettingsTabLoggingLogging": "Dziennik zdarzeń", + "SettingsTabLoggingEnableLoggingToFile": "Włącz rejestrowanie zdarzeń do pliku", "SettingsTabLoggingEnableStubLogs": "Wlącz Skróty Logów", "SettingsTabLoggingEnableInfoLogs": "Włącz Logi Informacyjne", "SettingsTabLoggingEnableWarningLogs": "Włącz Logi Ostrzeżeń", @@ -170,18 +180,18 @@ "SettingsTabLoggingEnableTraceLogs": "Włącz Logi Śledzenia", "SettingsTabLoggingEnableGuestLogs": "Włącz Logi Gości", "SettingsTabLoggingEnableFsAccessLogs": "Włącz Logi Dostępu do Systemu Plików", - "SettingsTabLoggingFsGlobalAccessLogMode": "Tryb Globalnych Logów Systemu Plików:", - "SettingsTabLoggingDeveloperOptions": "Opcje programistyczne (OSTRZEŻENIE: Zmniejszą wydajność)", - "SettingsTabLoggingDeveloperOptionsNote": "UWAGA: Zredukuje wydajność", - "SettingsTabLoggingGraphicsBackendLogLevel": "Ilość Logów Backendu Graficznego:", - "SettingsTabLoggingGraphicsBackendLogLevelNone": "Żadne", + "SettingsTabLoggingFsGlobalAccessLogMode": "Tryb globalnego dziennika zdarzeń systemu plików:", + "SettingsTabLoggingDeveloperOptions": "Opcje programisty (UWAGA: wpływa na wydajność)", + "SettingsTabLoggingDeveloperOptionsNote": "UWAGA: Pogrorszy wydajność", + "SettingsTabLoggingGraphicsBackendLogLevel": "Poziom rejestrowania do dziennika zdarzeń Backendu Graficznego:", + "SettingsTabLoggingGraphicsBackendLogLevelNone": "Nic", "SettingsTabLoggingGraphicsBackendLogLevelError": "Błędy", "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Spowolnienia", - "SettingsTabLoggingGraphicsBackendLogLevelAll": "Wszystkie", - "SettingsTabLoggingEnableDebugLogs": "Włącz Logi Debugowania", + "SettingsTabLoggingGraphicsBackendLogLevelAll": "Wszystko", + "SettingsTabLoggingEnableDebugLogs": "Włącz dzienniki zdarzeń do debugowania", "SettingsTabInput": "Sterowanie", - "SettingsTabInputEnableDockedMode": "Tryb Zadokowany", - "SettingsTabInputDirectKeyboardAccess": "Bezpośredni Dostęp do Klawiatury", + "SettingsTabInputEnableDockedMode": "Tryb zadokowany", + "SettingsTabInputDirectKeyboardAccess": "Bezpośredni dostęp do klawiatury", "SettingsButtonSave": "Zapisz", "SettingsButtonClose": "Zamknij", "SettingsButtonOk": "OK", @@ -197,10 +207,10 @@ "ControllerSettingsPlayer7": "Gracz 7", "ControllerSettingsPlayer8": "Gracz 8", "ControllerSettingsHandheld": "Przenośny", - "ControllerSettingsInputDevice": "Urządzenie Wejściowe", + "ControllerSettingsInputDevice": "Urządzenie wejściowe", "ControllerSettingsRefresh": "Odśwież", "ControllerSettingsDeviceDisabled": "Wyłączone", - "ControllerSettingsControllerType": "Typ Kontrolera", + "ControllerSettingsControllerType": "Typ kontrolera", "ControllerSettingsControllerTypeHandheld": "Przenośny", "ControllerSettingsControllerTypeProController": "Pro Kontroler", "ControllerSettingsControllerTypeJoyConPair": "Para JoyCon-ów", @@ -218,7 +228,7 @@ "ControllerSettingsButtonY": "Y", "ControllerSettingsButtonPlus": "+", "ControllerSettingsButtonMinus": "-", - "ControllerSettingsDPad": "Pad Kierunkowy", + "ControllerSettingsDPad": "Krzyżak (D-Pad)", "ControllerSettingsDPadUp": "Góra", "ControllerSettingsDPadDown": "Dół", "ControllerSettingsDPadLeft": "Lewo", @@ -261,79 +271,174 @@ "ControllerSettingsMotionGyroDeadzone": "Deadzone Żyroskopu:", "ControllerSettingsSave": "Zapisz", "ControllerSettingsClose": "Zamknij", - "UserProfilesSelectedUserProfile": "Wybrany Profil Użytkownika:", - "UserProfilesSaveProfileName": "Zapisz Nazwę Profilu", - "UserProfilesChangeProfileImage": "Zmień Obraz Profilu", - "UserProfilesAvailableUserProfiles": "Dostępne Profile Użytkowników:", - "UserProfilesAddNewProfile": "Utwórz Profil", - "UserProfilesDelete": "Usuwać", + "KeyUnknown": "Unknown", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", + "UserProfilesSelectedUserProfile": "Wybrany profil użytkownika:", + "UserProfilesSaveProfileName": "Zapisz nazwę profilu", + "UserProfilesChangeProfileImage": "Zmień obrazek profilu", + "UserProfilesAvailableUserProfiles": "Dostępne profile użytkownika:", + "UserProfilesAddNewProfile": "Utwórz profil", + "UserProfilesDelete": "Usuń", "UserProfilesClose": "Zamknij", "ProfileNameSelectionWatermark": "Wybierz pseudonim", "ProfileImageSelectionTitle": "Wybór Obrazu Profilu", "ProfileImageSelectionHeader": "Wybierz zdjęcie profilowe", "ProfileImageSelectionNote": "Możesz zaimportować niestandardowy obraz profilu lub wybrać awatar z firmware'u systemowego", "ProfileImageSelectionImportImage": "Importuj Plik Obrazu", - "ProfileImageSelectionSelectAvatar": "Wybierz Awatar z Firmware'u", + "ProfileImageSelectionSelectAvatar": "Wybierz domyślny awatar z oprogramowania konsoli", "InputDialogTitle": "Okno Dialogowe Wprowadzania", "InputDialogOk": "OK", "InputDialogCancel": "Anuluj", - "InputDialogAddNewProfileTitle": "Wybierz Nazwę Profilu", - "InputDialogAddNewProfileHeader": "Wprowadź Nazwę Profilu", - "InputDialogAddNewProfileSubtext": "(Maksymalna Długość: {0})", - "AvatarChoose": "Wybierz", - "AvatarSetBackgroundColor": "Ustaw Kolor Tła", + "InputDialogAddNewProfileTitle": "Wybierz nazwę profilu", + "InputDialogAddNewProfileHeader": "Wprowadź nazwę profilu", + "InputDialogAddNewProfileSubtext": "(Maksymalna długość: {0})", + "AvatarChoose": "Wybierz awatar", + "AvatarSetBackgroundColor": "Ustaw kolor tła", "AvatarClose": "Zamknij", - "ControllerSettingsLoadProfileToolTip": "Załaduj Profil", - "ControllerSettingsAddProfileToolTip": "Dodaj Profil", - "ControllerSettingsRemoveProfileToolTip": "Usuń Profil", - "ControllerSettingsSaveProfileToolTip": "Zapisz Profil", - "MenuBarFileToolsTakeScreenshot": "Zrób Zrzut Ekranu", - "MenuBarFileToolsHideUi": "Ukryj UI", + "ControllerSettingsLoadProfileToolTip": "Wczytaj profil", + "ControllerSettingsAddProfileToolTip": "Dodaj profil", + "ControllerSettingsRemoveProfileToolTip": "Usuń profil", + "ControllerSettingsSaveProfileToolTip": "Zapisz profil", + "MenuBarFileToolsTakeScreenshot": "Zrób zrzut ekranu", + "MenuBarFileToolsHideUi": "Ukryj interfejs użytkownika", "GameListContextMenuRunApplication": "Uruchom aplikację ", - "GameListContextMenuToggleFavorite": "Przełącz Ulubione", + "GameListContextMenuToggleFavorite": "Przełącz na ulubione", "GameListContextMenuToggleFavoriteToolTip": "Przełącz status Ulubionej Gry", - "SettingsTabGeneralTheme": "Motyw", - "SettingsTabGeneralThemeCustomTheme": "Ścieżka Niestandardowych Motywów", - "SettingsTabGeneralThemeBaseStyle": "Styl Podstawowy", - "SettingsTabGeneralThemeBaseStyleDark": "Ciemny", - "SettingsTabGeneralThemeBaseStyleLight": "Jasny", - "SettingsTabGeneralThemeEnableCustomTheme": "Włącz Niestandardowy Motyw", - "ButtonBrowse": "Przeglądaj", + "SettingsTabGeneralTheme": "Motyw:", + "SettingsTabGeneralThemeDark": "Ciemny", + "SettingsTabGeneralThemeLight": "Jasny", "ControllerSettingsConfigureGeneral": "Konfiguruj", "ControllerSettingsRumble": "Wibracje", - "ControllerSettingsRumbleStrongMultiplier": "Mocny Mnożnik Wibracji", - "ControllerSettingsRumbleWeakMultiplier": "Słaby Mnożnik Wibracji", - "DialogMessageSaveNotAvailableMessage": "Nie ma danych zapisu dla {0} [{1:x16}]", - "DialogMessageSaveNotAvailableCreateSaveMessage": "Czy chcesz utworzyć dane zapisu dla tej gry?", + "ControllerSettingsRumbleStrongMultiplier": "Mnożnik mocnych wibracji", + "ControllerSettingsRumbleWeakMultiplier": "Mnożnik słabych wibracji", + "DialogMessageSaveNotAvailableMessage": "Nie ma zapisanych danych dla {0} [{1:x16}]", + "DialogMessageSaveNotAvailableCreateSaveMessage": "Czy chcesz utworzyć zapis danych dla tej gry?", "DialogConfirmationTitle": "Ryujinx - Potwierdzenie", - "DialogUpdaterTitle": "Ryujinx - Aktualizator", + "DialogUpdaterTitle": "Ryujinx - Asystent aktualizacji", "DialogErrorTitle": "Ryujinx - Błąd", - "DialogWarningTitle": "Ryujinx - Uwaga", + "DialogWarningTitle": "Ryujinx - Ostrzeżenie", "DialogExitTitle": "Ryujinx - Wyjdź", "DialogErrorMessage": "Ryujinx napotkał błąd", "DialogExitMessage": "Czy na pewno chcesz zamknąć Ryujinx?", "DialogExitSubMessage": "Wszystkie niezapisane dane zostaną utracone!", - "DialogMessageCreateSaveErrorMessage": "Wystąpił błąd podczas tworzenia określonych danych zapisu: {0}", - "DialogMessageFindSaveErrorMessage": "Wystąpił błąd podczas znajdowania określonych danych zapisu: {0}", - "FolderDialogExtractTitle": "Wybierz folder do rozpakowania", - "DialogNcaExtractionMessage": "Wyodrębnianie sekcji {0} z {1}...", - "DialogNcaExtractionTitle": "Ryujinx - Ekstraktor Sekcji NCA", - "DialogNcaExtractionMainNcaNotFoundErrorMessage": "Niepowodzenie ekstrakcji. W wybranym pliku nie było głównego NCA.", - "DialogNcaExtractionCheckLogErrorMessage": "Niepowodzenie ekstrakcji. Przeczytaj plik dziennika, aby uzyskać więcej informacji.", - "DialogNcaExtractionSuccessMessage": "Ekstrakcja zakończona pomyślnie.", + "DialogMessageCreateSaveErrorMessage": "Wystąpił błąd podczas tworzenia określonych zapisanych danych: {0}", + "DialogMessageFindSaveErrorMessage": "Wystąpił błąd podczas próby znalezienia określonych zapisanych danych: {0}", + "FolderDialogExtractTitle": "Wybierz folder, do którego chcesz rozpakować", + "DialogNcaExtractionMessage": "Wypakowywanie sekcji {0} z {1}...", + "DialogNcaExtractionTitle": "Ryujinx - Asystent wypakowania sekcji NCA", + "DialogNcaExtractionMainNcaNotFoundErrorMessage": "Niepowodzenie podczas wypakowywania. W wybranym pliku nie było głównego NCA.", + "DialogNcaExtractionCheckLogErrorMessage": "Niepowodzenie podczas wypakowywania. Przeczytaj plik dziennika, aby uzyskać więcej informacji.", + "DialogNcaExtractionSuccessMessage": "Wypakowywanie zakończone pomyślnie.", "DialogUpdaterConvertFailedMessage": "Nie udało się przekonwertować obecnej wersji Ryujinx.", - "DialogUpdaterCancelUpdateMessage": "Anulowanie Aktualizacji!", + "DialogUpdaterCancelUpdateMessage": "Anulowanie aktualizacji!", "DialogUpdaterAlreadyOnLatestVersionMessage": "Używasz już najnowszej wersji Ryujinx!", - "DialogUpdaterFailedToGetVersionMessage": "Wystąpił błąd podczas próby uzyskania informacji o wydaniu z GitHub Release. Może to być spowodowane nową wersją kompilowaną przez GitHub Actions. Spróbuj ponownie za kilka minut.", + "DialogUpdaterFailedToGetVersionMessage": "Wystąpił błąd podczas próby uzyskania informacji o obecnej wersji z GitHub Release. Może to być spowodowane nową wersją kompilowaną przez GitHub Actions. Spróbuj ponownie za kilka minut.", "DialogUpdaterConvertFailedGithubMessage": "Nie udało się przekonwertować otrzymanej wersji Ryujinx z Github Release.", - "DialogUpdaterDownloadingMessage": "Pobieranie Aktualizacji...", + "DialogUpdaterDownloadingMessage": "Pobieranie aktualizacji...", "DialogUpdaterExtractionMessage": "Wypakowywanie Aktualizacji...", "DialogUpdaterRenamingMessage": "Zmiana Nazwy Aktualizacji...", "DialogUpdaterAddingFilesMessage": "Dodawanie Nowej Aktualizacji...", "DialogUpdaterCompleteMessage": "Aktualizacja Zakończona!", "DialogUpdaterRestartMessage": "Czy chcesz teraz zrestartować Ryujinx?", - "DialogUpdaterArchNotSupportedMessage": "Nie używasz obsługiwanej architektury systemu!", - "DialogUpdaterArchNotSupportedSubMessage": "(Obsługiwane są tylko systemy x64!)", "DialogUpdaterNoInternetMessage": "Nie masz połączenia z Internetem!", "DialogUpdaterNoInternetSubMessage": "Sprawdź, czy masz działające połączenie internetowe!", "DialogUpdaterDirtyBuildMessage": "Nie możesz zaktualizować Dirty wersji Ryujinx!", @@ -342,7 +447,7 @@ "DialogThemeRestartMessage": "Motyw został zapisany. Aby zastosować motyw, konieczne jest ponowne uruchomienie.", "DialogThemeRestartSubMessage": "Czy chcesz uruchomić ponownie?", "DialogFirmwareInstallEmbeddedMessage": "Czy chcesz zainstalować firmware wbudowany w tę grę? (Firmware {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "Nie znaleziono zainstalowanego firmware'u, ale Ryujinx był w stanie zainstalować firmware {0} z dostarczonej gry.\n\nEmulator uruchomi się teraz.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "Nie znaleziono zainstalowanego oprogramowania, ale Ryujinx był w stanie zainstalować oprogramowanie {0} z dostarczonej gry.\n\nEmulator uruchomi się teraz.", "DialogFirmwareNoFirmwareInstalledMessage": "Brak Zainstalowanego Firmware'u", "DialogFirmwareInstalledMessage": "Firmware {0} został zainstalowany", "DialogInstallFileTypesSuccessMessage": "Pomyślnie zainstalowano typy plików!", @@ -385,7 +490,10 @@ "DialogUserProfileUnsavedChangesSubMessage": "Czy chcesz odrzucić zmiany?", "DialogControllerSettingsModifiedConfirmMessage": "Aktualne ustawienia kontrolera zostały zaktualizowane.", "DialogControllerSettingsModifiedConfirmSubMessage": "Czy chcesz zapisać?", - "DialogLoadNcaErrorMessage": "{0}. Błędny Plik: {1}", + "DialogLoadFileErrorMessage": "{0}. Błędny plik: {1}", + "DialogModAlreadyExistsMessage": "Modyfikacja już istnieje", + "DialogModInvalidMessage": "Podany katalog nie zawiera modyfikacji!", + "DialogModDeleteNoParentMessage": "Nie udało się usunąć: Nie można odnaleźć katalogu nadrzędnego dla modyfikacji \"{0}\"!", "DialogDlcNoDlcErrorMessage": "Określony plik nie zawiera DLC dla wybranego tytułu!", "DialogPerformanceCheckLoggingEnabledMessage": "Masz włączone rejestrowanie śledzenia, które jest przeznaczone tylko dla programistów.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Aby uzyskać optymalną wydajność, zaleca się wyłączenie rejestrowania śledzenia. Czy chcesz teraz wyłączyć rejestrowanie śledzenia?", @@ -396,6 +504,8 @@ "DialogUpdateAddUpdateErrorMessage": "Określony plik nie zawiera aktualizacji dla wybranego tytułu!", "DialogSettingsBackendThreadingWarningTitle": "Ostrzeżenie — Wątki Backend", "DialogSettingsBackendThreadingWarningMessage": "Ryujinx musi zostać ponownie uruchomiony po zmianie tej opcji, aby działał w pełni. W zależności od platformy może być konieczne ręczne wyłączenie sterownika wielowątkowości podczas korzystania z Ryujinx.", + "DialogModManagerDeletionWarningMessage": "Zamierzasz usunąć modyfikacje: {0}\n\nCzy na pewno chcesz kontynuować?", + "DialogModManagerDeletionAllWarningMessage": "Zamierzasz usunąć wszystkie modyfikacje dla wybranego tytułu: {0}\n\nCzy na pewno chcesz kontynuować?", "SettingsTabGraphicsFeaturesOptions": "Funkcje", "SettingsTabGraphicsBackendMultithreading": "Wielowątkowość Backendu Graficznego:", "CommonAuto": "Auto", @@ -430,7 +540,8 @@ "DlcManagerRemoveAllButton": "Usuń Wszystkie", "DlcManagerEnableAllButton": "Włącz Wszystkie", "DlcManagerDisableAllButton": "Wyłącz Wszystkie", - "MenuBarOptionsChangeLanguage": "Zmień Język", + "ModManagerDeleteAllButton": "Usuń wszystko", + "MenuBarOptionsChangeLanguage": "Zmień język", "MenuBarShowFileTypes": "Pokaż typy plików", "CommonSort": "Sortuj", "CommonShowNames": "Pokaż Nazwy", @@ -447,13 +558,13 @@ "CustomThemePathTooltip": "Ścieżka do niestandardowego motywu GUI", "CustomThemeBrowseTooltip": "Wyszukaj niestandardowy motyw GUI", "DockModeToggleTooltip": "Tryb Zadokowany sprawia, że emulowany system zachowuje się jak zadokowany Nintendo Switch. Poprawia to jakość grafiki w większości gier. I odwrotnie, wyłączenie tej opcji sprawi, że emulowany system będzie zachowywał się jak przenośny Nintendo Switch, zmniejszając jakość grafiki.\n\nSkonfiguruj sterowanie gracza 1, jeśli planujesz używać trybu Zadokowanego; Skonfiguruj sterowanie przenośne, jeśli planujesz używać trybu przenośnego.\n\nPozostaw WŁĄCZONY, jeśli nie masz pewności.", - "DirectKeyboardTooltip": "Obsługa bezpośredniego dostępu klawiatury (HID). Zapewnia dostęp gier do klawiatury jako urządzenia do wprowadzania tekstu.", - "DirectMouseTooltip": "Obsługa bezpośredniego dostępu myszy (HID). Zapewnia grom dostęp do myszy jako urządzenia wskazującego.", + "DirectKeyboardTooltip": "Obsługa bezpośredniego dostępu do klawiatury (HID). Zapewnia dostęp gier do klawiatury jako urządzenia do wprowadzania tekstu.\n\nDziała tylko z grami, które natywnie wspierają użycie klawiatury w urządzeniu Switch hardware.\n\nPozostaw wyłączone w razie braku pewności.", + "DirectMouseTooltip": "Obsługa bezpośredniego dostępu do myszy (HID). Zapewnia dostęp gier do myszy jako urządzenia wskazującego.\n\nDziała tylko z grami, które natywnie obsługują przyciski myszy w urządzeniu Switch, które są nieliczne i daleko między nimi.\n\nPo włączeniu funkcja ekranu dotykowego może nie działać.\n\nPozostaw wyłączone w razie wątpliwości.", "RegionTooltip": "Zmień Region Systemu", - "LanguageTooltip": "Zmień Język Systemu", + "LanguageTooltip": "Zmień język systemu", "TimezoneTooltip": "Zmień Strefę Czasową Systemu", - "TimeTooltip": "Zmień Czas Systemu", - "VSyncToggleTooltip": "Pionowa synchronizacja emulowanej konsoli. Zasadniczo ogranicznik klatek dla większości gier; wyłączenie jej może spowodować, że gry będą działać z większą szybkością, ekrany wczytywania wydłużą się lub nawet utkną.\n\nMoże być przełączana w grze za pomocą preferowanego skrótu klawiszowego. Zalecamy to zrobić, jeśli planujesz ją wyłączyć.\n\nW razie wątpliwości pozostaw WŁĄCZONĄ", + "TimeTooltip": "Zmień czas systemowy", + "VSyncToggleTooltip": "Synchronizacja pionowa emulowanej konsoli. Zasadniczo ogranicznik klatek dla większości gier; wyłączenie jej może spowodować, że gry będą działać z większą szybkością, ekrany wczytywania wydłużą się lub nawet utkną.\n\nMoże być przełączana w grze za pomocą preferowanego skrótu klawiszowego. Zalecamy to zrobić, jeśli planujesz ją wyłączyć.\n\nW razie wątpliwości pozostaw WŁĄCZONĄ.", "PptcToggleTooltip": "Zapisuje przetłumaczone funkcje JIT, dzięki czemu nie muszą być tłumaczone za każdym razem, gdy gra się ładuje.\n\nZmniejsza zacinanie się i znacznie przyspiesza uruchamianie po pierwszym uruchomieniu gry.\n\nJeśli nie masz pewności, pozostaw WŁĄCZONE", "FsIntegrityToggleTooltip": "Sprawdza pliki podczas uruchamiania gry i jeśli zostaną wykryte uszkodzone pliki, wyświetla w dzienniku błąd hash.\n\nNie ma wpływu na wydajność i ma pomóc w rozwiązywaniu problemów.\n\nPozostaw WŁĄCZONE, jeśli nie masz pewności.", "AudioBackendTooltip": "Zmienia backend używany do renderowania dźwięku.\n\nSDL2 jest preferowany, podczas gdy OpenAL i SoundIO są używane jako rezerwy. Dummy nie będzie odtwarzać dźwięku.\n\nW razie wątpliwości ustaw SDL2.", @@ -467,10 +578,10 @@ "GraphicsBackendThreadingTooltip": "Wykonuje polecenia backend'u graficznego w drugim wątku.\n\nPrzyspiesza kompilację shaderów, zmniejsza zacinanie się i poprawia wydajność sterowników GPU bez własnej obsługi wielowątkowości. Nieco lepsza wydajność w sterownikach z wielowątkowością.\n\nUstaw na AUTO, jeśli nie masz pewności.", "GalThreadingTooltip": "Wykonuje polecenia backend'u graficznego w drugim wątku.\n\nPrzyspiesza kompilację shaderów, zmniejsza zacinanie się i poprawia wydajność sterowników GPU bez własnej obsługi wielowątkowości. Nieco lepsza wydajność w sterownikach z wielowątkowością.\n\nUstaw na AUTO, jeśli nie masz pewności.", "ShaderCacheToggleTooltip": "Zapisuje pamięć podręczną shaderów na dysku, co zmniejsza zacinanie się w kolejnych uruchomieniach.\n\nPozostaw WŁĄCZONE, jeśli nie masz pewności.", - "ResolutionScaleTooltip": "Skala Rozdzielczości zastosowana do odpowiednich celów renderowania", + "ResolutionScaleTooltip": "Multiplies the game's rendering resolution.\n\nA few games may not work with this and look pixelated even when the resolution is increased; for those games, you may need to find mods that remove anti-aliasing or that increase their internal rendering resolution. For using the latter, you'll likely want to select Native.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nKeep in mind 4x is overkill for virtually any setup.", "ResolutionScaleEntryTooltip": "Skala rozdzielczości zmiennoprzecinkowej, np. 1,5. Skale niecałkowite częściej powodują problemy lub awarie.", - "AnisotropyTooltip": "Poziom filtrowania anizotropowego (ustaw na Auto, aby użyć wartości wymaganej przez grę)", - "AspectRatioTooltip": "Współczynnik proporcji zastosowany do okna renderowania.", + "AnisotropyTooltip": "Level of Anisotropic Filtering. Set to Auto to use the value requested by the game.", + "AspectRatioTooltip": "Aspect Ratio applied to the renderer window.\n\nOnly change this if you're using an aspect ratio mod for your game, otherwise the graphics will be stretched.\n\nLeave on 16:9 if unsure.", "ShaderDumpPathTooltip": "Ścieżka Zrzutu Shaderów Grafiki", "FileLogTooltip": "Zapisuje logowanie konsoli w pliku dziennika na dysku. Nie wpływa na wydajność.", "StubLogTooltip": "Wyświetla w konsoli skrótowe komunikaty dziennika. Nie wpływa na wydajność.", @@ -504,6 +615,8 @@ "EnableInternetAccessTooltip": "Pozwala emulowanej aplikacji na łączenie się z Internetem.\n\nGry w trybie LAN mogą łączyć się ze sobą, gdy ta opcja jest włączona, a systemy są połączone z tym samym punktem dostępu. Dotyczy to również prawdziwych konsol.\n\nNie pozwala na łączenie się z serwerami Nintendo. Może powodować awarie niektórych gier, które próbują połączyć się z Internetem.\n\nPozostaw WYŁĄCZONE, jeśli nie masz pewności.", "GameListContextMenuManageCheatToolTip": "Zarządzaj Kodami", "GameListContextMenuManageCheat": "Zarządzaj Kodami", + "GameListContextMenuManageModToolTip": "Zarządzaj modyfikacjami", + "GameListContextMenuManageMod": "Zarządzaj modyfikacjami", "ControllerSettingsStickRange": "Zasięg:", "DialogStopEmulationTitle": "Ryujinx - Zatrzymaj Emulację", "DialogStopEmulationMessage": "Czy na pewno chcesz zatrzymać emulację?", @@ -515,10 +628,8 @@ "SettingsTabCpuMemory": "Pamięć CPU", "DialogUpdaterFlatpakNotSupportedMessage": "Zaktualizuj Ryujinx przez FlatHub.", "UpdaterDisabledWarningTitle": "Aktualizator Wyłączony!", - "GameListContextMenuOpenSdModsDirectory": "Otwórz Katalog Modów Atmosphere", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Otwiera alternatywny katalog Atmosphere na karcie SD, który zawiera modyfikacje aplikacji. Przydatne dla modów, które są pakowane dla prawdziwego sprzętu.", "ControllerSettingsRotate90": "Obróć o 90° w Prawo", - "IconSize": "Rozmiar Ikon", + "IconSize": "Rozmiar ikon", "IconSizeTooltip": "Zmień rozmiar ikon gry", "MenuBarOptionsShowConsole": "Pokaż Konsolę", "ShaderCachePurgeError": "Błąd podczas czyszczenia cache shaderów w {0}: {1}", @@ -544,12 +655,13 @@ "SwkbdMinCharacters": "Musi mieć co najmniej {0} znaków", "SwkbdMinRangeCharacters": "Musi mieć długość od {0}-{1} znaków", "SoftwareKeyboard": "Klawiatura Oprogramowania", - "SoftwareKeyboardModeNumbersOnly": "Mogą być tylko liczby ", + "SoftwareKeyboardModeNumeric": "Może składać się jedynie z 0-9 lub '.'", "SoftwareKeyboardModeAlphabet": "Nie może zawierać znaków CJK", "SoftwareKeyboardModeASCII": "Musi zawierać tylko tekst ASCII", - "DialogControllerAppletMessagePlayerRange": "Aplikacja żąda {0} graczy z:\n\nTYPY: {1}\n\nGRACZE: {2}\n\n{3}Otwórz Ustawienia i ponownie skonfiguruj Sterowanie lub naciśnij Zamknij.", - "DialogControllerAppletMessage": "Aplikacja żąda dokładnie {0} graczy z:\n\nTYPY: {1}\n\nGRACZE: {2}\n\n{3}Otwórz teraz Ustawienia i ponownie skonfiguruj Sterowanie lub naciśnij Zamknij.", - "DialogControllerAppletDockModeSet": "Ustawiono tryb Zadokowane. Przenośny też jest nieprawidłowy.\n\n", + "ControllerAppletControllers": "Obsługiwane Kontrolery:", + "ControllerAppletPlayers": "Gracze:", + "ControllerAppletDescription": "Twoja aktualna konfiguracja jest nieprawidłowa. Otwórz ustawienia i skonfiguruj swoje wejścia.", + "ControllerAppletDocked": "Ustawiony tryb zadokowany. Sterowanie przenośne powinno być wyłączone.", "UpdaterRenaming": "Zmienianie Nazw Starych Plików...", "UpdaterRenameFailed": "Aktualizator nie mógł zmienić nazwy pliku: {0}", "UpdaterAddingFiles": "Dodawanie Nowych Plików...", @@ -587,17 +699,21 @@ "Writable": "Zapisywalne", "SelectDlcDialogTitle": "Wybierz pliki DLC", "SelectUpdateDialogTitle": "Wybierz pliki aktualizacji", + "SelectModDialogTitle": "Wybierz katalog modów", "UserProfileWindowTitle": "Menedżer Profili Użytkowników", "CheatWindowTitle": "Menedżer Kodów", "DlcWindowTitle": "Menedżer Zawartości do Pobrania", + "ModWindowTitle": "Zarządzaj modami dla {0} ({1})", "UpdateWindowTitle": "Menedżer Aktualizacji Tytułu", "CheatWindowHeading": "Kody Dostępne dla {0} [{1}]", "BuildId": "Identyfikator wersji:", "DlcWindowHeading": "{0} Zawartości do Pobrania dostępna dla {1} ({2})", + "ModWindowHeading": "{0} Mod(y/ów)", "UserProfilesEditProfile": "Edytuj Zaznaczone", "Cancel": "Anuluj", "Save": "Zapisz", "Discard": "Odrzuć", + "Paused": "Wstrzymano", "UserProfilesSetProfileImage": "Ustaw Obraz Profilu", "UserProfileEmptyNameError": "Nazwa jest wymagana", "UserProfileNoImageError": "Należy ustawić obraz profilowy", @@ -607,9 +723,9 @@ "UserProfilesName": "Nazwa:", "UserProfilesUserId": "ID Użytkownika:", "SettingsTabGraphicsBackend": "Backend Graficzny", - "SettingsTabGraphicsBackendTooltip": "Używalne Backendy Graficzne", + "SettingsTabGraphicsBackendTooltip": "Select the graphics backend that will be used in the emulator.\n\nVulkan is overall better for all modern graphics cards, as long as their drivers are up to date. Vulkan also features faster shader compilation (less stuttering) on all GPU vendors.\n\nOpenGL may achieve better results on old Nvidia GPUs, on old AMD GPUs on Linux, or on GPUs with lower VRAM, though shader compilation stutters will be greater.\n\nSet to Vulkan if unsure. Set to OpenGL if your GPU does not support Vulkan even with the latest graphics drivers.", "SettingsEnableTextureRecompression": "Włącz Rekompresję Tekstur", - "SettingsEnableTextureRecompressionTooltip": "Kompresuje niektóre tekstury w celu zmniejszenia zużycia pamięci VRAM.\n\nZalecane do użytku z GPU, które mają mniej niż 4 GiB pamięci VRAM.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.", + "SettingsEnableTextureRecompressionTooltip": "Compresses ASTC textures in order to reduce VRAM usage.\n\nGames using this texture format include Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder and The Legend of Zelda: Tears of the Kingdom.\n\nGraphics cards with 4GiB VRAM or less will likely crash at some point while running these games.\n\nEnable only if you're running out of VRAM on the aforementioned games. Leave OFF if unsure.", "SettingsTabGraphicsPreferredGpu": "Preferowane GPU", "SettingsTabGraphicsPreferredGpuTooltip": "Wybierz kartę graficzną, która będzie używana z backendem graficznym Vulkan.\n\nNie wpływa na GPU używane przez OpenGL.\n\nW razie wątpliwości ustaw flagę GPU jako \"dGPU\". Jeśli żadnej nie ma, pozostaw nietknięte.", "SettingsAppRequiredRestartMessage": "Wymagane Zrestartowanie Ryujinx", @@ -620,8 +736,8 @@ "SettingsTabHotkeysVolumeDownHotkey": "Zmniejsz Głośność:", "SettingsEnableMacroHLE": "Włącz Macro HLE", "SettingsEnableMacroHLETooltip": "Wysokopoziomowa emulacja kodu GPU Macro.\n\nPoprawia wydajność, ale może powodować błędy graficzne w niektórych grach.\n\nW razie wątpliwości pozostaw WŁĄCZONE.", - "SettingsEnableColorSpacePassthrough": "Color Space Passthrough", - "SettingsEnableColorSpacePassthroughTooltip": "Directs the Vulkan backend to pass through color information without specifying a color space. For users with wide gamut displays, this may result in more vibrant colors, at the cost of color correctness.", + "SettingsEnableColorSpacePassthrough": "Przekazywanie przestrzeni kolorów", + "SettingsEnableColorSpacePassthroughTooltip": "Nakazuje API Vulkan przekazywać informacje o kolorze bez określania przestrzeni kolorów. Dla użytkowników z wyświetlaczami o szerokim zakresie kolorów może to skutkować bardziej żywymi kolorami, kosztem ich poprawności.", "VolumeShort": "Głoś", "UserProfilesManageSaves": "Zarządzaj Zapisami", "DeleteUserSave": "Czy chcesz usunąć zapis użytkownika dla tej gry?", @@ -635,12 +751,15 @@ "Recover": "Odzyskaj", "UserProfilesRecoverHeading": "Znaleziono zapisy dla następujących kont", "UserProfilesRecoverEmptyList": "Brak profili do odzyskania", - "GraphicsAATooltip": "Stosuje antyaliasing do renderowania gry", + "GraphicsAATooltip": "Applies anti-aliasing to the game render.\n\nFXAA will blur most of the image, while SMAA will attempt to find jagged edges and smooth them out.\n\nNot recommended to use in conjunction with the FSR scaling filter.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on NONE if unsure.", "GraphicsAALabel": "Antyaliasing:", "GraphicsScalingFilterLabel": "Filtr skalowania:", - "GraphicsScalingFilterTooltip": "Włącza skalowanie bufora ramki", + "GraphicsScalingFilterTooltip": "Choose the scaling filter that will be applied when using resolution scale.\n\nBilinear works well for 3D games and is a safe default option.\n\nNearest is recommended for pixel art games.\n\nFSR 1.0 is merely a sharpening filter, not recommended for use with FXAA or SMAA.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on BILINEAR if unsure.", + "GraphicsScalingFilterBilinear": "Dwuliniowe", + "GraphicsScalingFilterNearest": "Najbliższe", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "Poziom", - "GraphicsScalingFilterLevelTooltip": "Ustaw poziom filtra skalowania", + "GraphicsScalingFilterLevelTooltip": "Ustaw poziom ostrzeżenia FSR 1.0. Wyższy jest ostrzejszy.", "SmaaLow": "SMAA Niskie", "SmaaMedium": "SMAA Średnie", "SmaaHigh": "SMAA Wysokie", @@ -648,9 +767,14 @@ "UserEditorTitle": "Edytuj użytkownika", "UserEditorTitleCreate": "Utwórz użytkownika", "SettingsTabNetworkInterface": "Interfejs sieci:", - "NetworkInterfaceTooltip": "Interfejs sieciowy używany do funkcji LAN", + "NetworkInterfaceTooltip": "Interfejs sieciowy używany dla funkcji LAN/LDN.\n\nw połączeniu z VPN lub XLink Kai i grą z obsługą sieci LAN, może być użyty do spoofowania połączenia z tą samą siecią przez Internet.\n\nZostaw DOMYŚLNE, jeśli nie ma pewności.", "NetworkInterfaceDefault": "Domyślny", "PackagingShaders": "Pakuje Shadery ", "AboutChangelogButton": "Zobacz listę zmian na GitHubie", - "AboutChangelogButtonTooltipMessage": "Kliknij, aby otworzyć listę zmian dla tej wersji w domyślnej przeglądarce." -} \ No newline at end of file + "AboutChangelogButtonTooltipMessage": "Kliknij, aby otworzyć listę zmian dla tej wersji w domyślnej przeglądarce.", + "SettingsTabNetworkMultiplayer": "Gra Wieloosobowa", + "MultiplayerMode": "Tryb:", + "MultiplayerModeTooltip": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.", + "MultiplayerModeDisabled": "Wyłączone", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/pt_BR.json b/src/Ryujinx/Assets/Locales/pt_BR.json similarity index 76% rename from src/Ryujinx.Ava/Assets/Locales/pt_BR.json rename to src/Ryujinx/Assets/Locales/pt_BR.json index 8909a84fe..a8c244b65 100644 --- a/src/Ryujinx.Ava/Assets/Locales/pt_BR.json +++ b/src/Ryujinx/Assets/Locales/pt_BR.json @@ -30,7 +30,11 @@ "MenuBarToolsManageFileTypes": "Gerenciar tipos de arquivo", "MenuBarToolsInstallFileTypes": "Instalar tipos de arquivo", "MenuBarToolsUninstallFileTypes": "Desinstalar tipos de arquivos", - "MenuBarHelp": "A_juda", + "MenuBarView": "_View", + "MenuBarViewWindow": "Window Size", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Ajuda", "MenuBarHelpCheckForUpdates": "_Verificar se há atualizações", "MenuBarHelpAbout": "_Sobre", "MenuSearch": "Buscar...", @@ -54,8 +58,6 @@ "GameListContextMenuManageTitleUpdatesToolTip": "Abre a janela de gerenciamento de atualizações", "GameListContextMenuManageDlc": "Gerenciar DLCs", "GameListContextMenuManageDlcToolTip": "Abre a janela de gerenciamento de DLCs", - "GameListContextMenuOpenModsDirectory": "Abrir diretório de mods", - "GameListContextMenuOpenModsDirectoryToolTip": "Abre o diretório que contém modificações (mods) do jogo", "GameListContextMenuCacheManagement": "Gerenciamento de cache", "GameListContextMenuCacheManagementPurgePptc": "Limpar cache PPTC", "GameListContextMenuCacheManagementPurgePptcToolTip": "Deleta o cache PPTC armazenado em disco do jogo", @@ -72,21 +74,29 @@ "GameListContextMenuExtractDataRomFSToolTip": "Extrai a seção RomFS do jogo (incluindo atualizações)", "GameListContextMenuExtractDataLogo": "Logo", "GameListContextMenuExtractDataLogoToolTip": "Extrai a seção Logo do jogo (incluindo atualizações)", + "GameListContextMenuCreateShortcut": "Criar atalho da aplicação", + "GameListContextMenuCreateShortcutToolTip": "Criar um atalho de área de trabalho que inicia o aplicativo selecionado", + "GameListContextMenuCreateShortcutToolTipMacOS": "Crie um atalho na pasta Aplicativos do macOS que abre o Aplicativo selecionado", + "GameListContextMenuOpenModsDirectory": "Abrir pasta de Mods", + "GameListContextMenuOpenModsDirectoryToolTip": "Abre a pasta que contém os mods da aplicação ", + "GameListContextMenuOpenSdModsDirectory": "Abrir diretório de mods Atmosphere", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.", "StatusBarGamesLoaded": "{0}/{1} jogos carregados", "StatusBarSystemVersion": "Versão do firmware: {0}", - "LinuxVmMaxMapCountDialogTitle": "Low limit for memory mappings detected", - "LinuxVmMaxMapCountDialogTextPrimary": "Would you like to increase the value of vm.max_map_count to {0}", - "LinuxVmMaxMapCountDialogTextSecondary": "Some games might try to create more memory mappings than currently allowed. Ryujinx will crash as soon as this limit gets exceeded.", - "LinuxVmMaxMapCountDialogButtonUntilRestart": "Yes, until the next restart", - "LinuxVmMaxMapCountDialogButtonPersistent": "Yes, permanently", - "LinuxVmMaxMapCountWarningTextPrimary": "Max amount of memory mappings is lower than recommended.", - "LinuxVmMaxMapCountWarningTextSecondary": "The current value of vm.max_map_count ({0}) is lower than {1}. Some games might try to create more memory mappings than currently allowed. Ryujinx will crash as soon as this limit gets exceeded.\n\nYou might want to either manually increase the limit or install pkexec, which allows Ryujinx to assist with that.", + "LinuxVmMaxMapCountDialogTitle": "Limite baixo para mapeamentos de memória detectado", + "LinuxVmMaxMapCountDialogTextPrimary": "Você gostaria de aumentar o valor de vm.max_map_count para {0}", + "LinuxVmMaxMapCountDialogTextSecondary": "Alguns jogos podem tentar criar mais mapeamentos de memória do que o atualmente permitido. Ryujinx irá falhar assim que este limite for excedido.", + "LinuxVmMaxMapCountDialogButtonUntilRestart": "Sim, até a próxima reinicialização", + "LinuxVmMaxMapCountDialogButtonPersistent": "Sim, permanentemente", + "LinuxVmMaxMapCountWarningTextPrimary": "A quantidade máxima de mapeamentos de memória é menor que a recomendada.", + "LinuxVmMaxMapCountWarningTextSecondary": "O valor atual de vm.max_map_count ({0}) é menor que {1}. Alguns jogos podem tentar criar mais mapeamentos de memória do que o permitido no momento. Ryujinx vai falhar assim que este limite for excedido.\n\nTalvez você queira aumentar o limite manualmente ou instalar pkexec, o que permite que Ryujinx ajude com isso.", "Settings": "Configurações", "SettingsTabGeneral": "Geral", "SettingsTabGeneralGeneral": "Geral", "SettingsTabGeneralEnableDiscordRichPresence": "Habilitar Rich Presence do Discord", "SettingsTabGeneralCheckUpdatesOnLaunch": "Verificar se há atualizações ao iniciar", "SettingsTabGeneralShowConfirmExitDialog": "Exibir diálogo de confirmação ao sair", + "SettingsTabGeneralRememberWindowState": "Lembrar tamanho/posição da Janela", "SettingsTabGeneralHideCursor": "Esconder o cursor do mouse:", "SettingsTabGeneralHideCursorNever": "Nunca", "SettingsTabGeneralHideCursorOnIdle": "Esconder o cursor quando ocioso", @@ -150,7 +160,7 @@ "SettingsTabGraphicsResolutionScaleNative": "Nativa (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (não recomendado)", "SettingsTabGraphicsAspectRatio": "Proporção:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -223,15 +233,15 @@ "ControllerSettingsDPadDown": "Baixo", "ControllerSettingsDPadLeft": "Esquerda", "ControllerSettingsDPadRight": "Direita", - "ControllerSettingsStickButton": "Button", - "ControllerSettingsStickUp": "Up", - "ControllerSettingsStickDown": "Down", - "ControllerSettingsStickLeft": "Left", - "ControllerSettingsStickRight": "Right", - "ControllerSettingsStickStick": "Stick", - "ControllerSettingsStickInvertXAxis": "Invert Stick X", - "ControllerSettingsStickInvertYAxis": "Invert Stick Y", - "ControllerSettingsStickDeadzone": "Deadzone:", + "ControllerSettingsStickButton": "Botão", + "ControllerSettingsStickUp": "Cima", + "ControllerSettingsStickDown": "Baixo", + "ControllerSettingsStickLeft": "Esquerda", + "ControllerSettingsStickRight": "Direita", + "ControllerSettingsStickStick": "Analógico", + "ControllerSettingsStickInvertXAxis": "Inverter eixo X", + "ControllerSettingsStickInvertYAxis": "Inverter eixo Y", + "ControllerSettingsStickDeadzone": "Zona morta:", "ControllerSettingsLStick": "Analógico esquerdo", "ControllerSettingsRStick": "Analógico direito", "ControllerSettingsTriggersLeft": "Gatilhos esquerda", @@ -261,6 +271,107 @@ "ControllerSettingsMotionGyroDeadzone": "Zona morta do giroscópio:", "ControllerSettingsSave": "Salvar", "ControllerSettingsClose": "Fechar", + "KeyUnknown": "Unknown", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", "UserProfilesSelectedUserProfile": "Perfil de usuário selecionado:", "UserProfilesSaveProfileName": "Salvar nome de perfil", "UserProfilesChangeProfileImage": "Mudar imagem de perfil", @@ -289,16 +400,12 @@ "ControllerSettingsSaveProfileToolTip": "Salvar perfil", "MenuBarFileToolsTakeScreenshot": "Salvar captura de tela", "MenuBarFileToolsHideUi": "Esconder Interface", - "GameListContextMenuRunApplication": "Run Application", + "GameListContextMenuRunApplication": "Executar Aplicativo", "GameListContextMenuToggleFavorite": "Alternar favorito", "GameListContextMenuToggleFavoriteToolTip": "Marca ou desmarca jogo como favorito", - "SettingsTabGeneralTheme": "Tema", - "SettingsTabGeneralThemeCustomTheme": "Diretório de tema customizado", - "SettingsTabGeneralThemeBaseStyle": "Estilo base", - "SettingsTabGeneralThemeBaseStyleDark": "Escuro", - "SettingsTabGeneralThemeBaseStyleLight": "Claro", - "SettingsTabGeneralThemeEnableCustomTheme": "Habilitar tema customizado", - "ButtonBrowse": "Procurar", + "SettingsTabGeneralTheme": "Tema:", + "SettingsTabGeneralThemeDark": "Escuro", + "SettingsTabGeneralThemeLight": "Claro", "ControllerSettingsConfigureGeneral": "Configurar", "ControllerSettingsRumble": "Vibração", "ControllerSettingsRumbleStrongMultiplier": "Multiplicador de vibração forte", @@ -332,8 +439,6 @@ "DialogUpdaterAddingFilesMessage": "Adicionando nova atualização...", "DialogUpdaterCompleteMessage": "Atualização concluída!", "DialogUpdaterRestartMessage": "Deseja reiniciar o Ryujinx agora?", - "DialogUpdaterArchNotSupportedMessage": "Você não está rodando uma arquitetura de sistema suportada!", - "DialogUpdaterArchNotSupportedSubMessage": "(Apenas sistemas x64 são suportados!)", "DialogUpdaterNoInternetMessage": "Você não está conectado à Internet!", "DialogUpdaterNoInternetSubMessage": "Por favor, certifique-se de que você tem uma conexão funcional à Internet!", "DialogUpdaterDirtyBuildMessage": "Você não pode atualizar uma compilação Dirty do Ryujinx!", @@ -342,7 +447,7 @@ "DialogThemeRestartMessage": "O tema foi salvo. Uma reinicialização é necessária para aplicar o tema.", "DialogThemeRestartSubMessage": "Deseja reiniciar?", "DialogFirmwareInstallEmbeddedMessage": "Gostaria de instalar o firmware incluso neste jogo? (Firmware {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "Nenhum firmware instalado foi encontrado, mas Ryujinx conseguiu instalar o firmware {0} do jogo fornecido.\nO emulador será reiniciado.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "No installed firmware was found but Ryujinx was able to install firmware {0} from the provided game.\nThe emulator will now start.", "DialogFirmwareNoFirmwareInstalledMessage": "Firmware não foi instalado", "DialogFirmwareInstalledMessage": "Firmware {0} foi instalado", "DialogInstallFileTypesSuccessMessage": "Tipos de arquivo instalados com sucesso!", @@ -385,7 +490,10 @@ "DialogUserProfileUnsavedChangesSubMessage": "Deseja descartar as alterações?", "DialogControllerSettingsModifiedConfirmMessage": "As configurações de controle atuais foram atualizadas.", "DialogControllerSettingsModifiedConfirmSubMessage": "Deseja salvar?", - "DialogLoadNcaErrorMessage": "{0}. Arquivo com erro: {1}", + "DialogLoadFileErrorMessage": "{0}. Errored File: {1}", + "DialogModAlreadyExistsMessage": "Mod already exists", + "DialogModInvalidMessage": "The specified directory does not contain a mod!", + "DialogModDeleteNoParentMessage": "Failed to Delete: Could not find the parent directory for mod \"{0}\"!", "DialogDlcNoDlcErrorMessage": "O arquivo especificado não contém DLCs para o título selecionado!", "DialogPerformanceCheckLoggingEnabledMessage": "Os logs de depuração estão ativos, esse recurso é feito para ser usado apenas por desenvolvedores.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Para melhor performance, é recomendável desabilitar os logs de depuração. Gostaria de desabilitar os logs de depuração agora?", @@ -396,6 +504,8 @@ "DialogUpdateAddUpdateErrorMessage": "O arquivo especificado não contém atualizações para o título selecionado!", "DialogSettingsBackendThreadingWarningTitle": "Alerta - Threading da API gráfica", "DialogSettingsBackendThreadingWarningMessage": "Ryujinx precisa ser reiniciado após mudar essa opção para que ela tenha efeito. Dependendo da sua plataforma, pode ser preciso desabilitar o multithreading do driver de vídeo quando usar o Ryujinx.", + "DialogModManagerDeletionWarningMessage": "You are about to delete the mod: {0}\n\nAre you sure you want to proceed?", + "DialogModManagerDeletionAllWarningMessage": "You are about to delete all mods for this title.\n\nAre you sure you want to proceed?", "SettingsTabGraphicsFeaturesOptions": "Recursos", "SettingsTabGraphicsBackendMultithreading": "Multithreading da API gráfica:", "CommonAuto": "Automático", @@ -430,6 +540,7 @@ "DlcManagerRemoveAllButton": "Remover todos", "DlcManagerEnableAllButton": "Habilitar todos", "DlcManagerDisableAllButton": "Desabilitar todos", + "ModManagerDeleteAllButton": "Delete All", "MenuBarOptionsChangeLanguage": "Mudar idioma", "MenuBarShowFileTypes": "Mostrar tipos de arquivo", "CommonSort": "Ordenar", @@ -447,13 +558,13 @@ "CustomThemePathTooltip": "Diretório do tema customizado", "CustomThemeBrowseTooltip": "Navegar até um tema customizado", "DockModeToggleTooltip": "Habilita ou desabilita modo TV", - "DirectKeyboardTooltip": "Habilita ou desabilita \"acesso direto ao teclado (HID)\" (Permite que o jogo acesse o seu teclado como dispositivo de entrada de texto)", - "DirectMouseTooltip": "Habilita ou desabilita \"acesso direto ao mouse (HID)\" (Permite que o jogo acesse o seu mouse como dispositivo apontador)", + "DirectKeyboardTooltip": "Direct keyboard access (HID) support. Provides games access to your keyboard as a text entry device.\n\nOnly works with games that natively support keyboard usage on Switch hardware.\n\nLeave OFF if unsure.", + "DirectMouseTooltip": "Direct mouse access (HID) support. Provides games access to your mouse as a pointing device.\n\nOnly works with games that natively support mouse controls on Switch hardware, which are few and far between.\n\nWhen enabled, touch screen functionality may not work.\n\nLeave OFF if unsure.", "RegionTooltip": "Mudar a região do sistema", "LanguageTooltip": "Mudar o idioma do sistema", "TimezoneTooltip": "Mudar o fuso-horário do sistema", "TimeTooltip": "Mudar a hora do sistema", - "VSyncToggleTooltip": "Habilita ou desabilita a sincronia vertical", + "VSyncToggleTooltip": "Emulated console's Vertical Sync. Essentially a frame-limiter for the majority of games; disabling it may cause games to run at higher speed or make loading screens take longer or get stuck.\n\nCan be toggled in-game with a hotkey of your preference (F1 by default). We recommend doing this if you plan on disabling it.\n\nLeave ON if unsure.", "PptcToggleTooltip": "Habilita ou desabilita PPTC", "FsIntegrityToggleTooltip": "Habilita ou desabilita verificação de integridade dos arquivos do jogo", "AudioBackendTooltip": "Mudar biblioteca de áudio", @@ -467,10 +578,10 @@ "GraphicsBackendThreadingTooltip": "Habilita multithreading do backend gráfico", "GalThreadingTooltip": "Executa comandos do backend gráfico em uma segunda thread. Permite multithreading em tempo de execução da compilação de shader, diminui os travamentos, e melhora performance em drivers sem suporte embutido a multithreading. Pequena variação na performance máxima em drivers com suporte a multithreading. Ryujinx pode precisar ser reiniciado para desabilitar adequadamente o multithreading embutido do driver, ou você pode precisar fazer isso manualmente para ter a melhor performance.", "ShaderCacheToggleTooltip": "Habilita ou desabilita o cache de shader", - "ResolutionScaleTooltip": "Escala de resolução aplicada às texturas de renderização", + "ResolutionScaleTooltip": "Multiplies the game's rendering resolution.\n\nA few games may not work with this and look pixelated even when the resolution is increased; for those games, you may need to find mods that remove anti-aliasing or that increase their internal rendering resolution. For using the latter, you'll likely want to select Native.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nKeep in mind 4x is overkill for virtually any setup.", "ResolutionScaleEntryTooltip": "Escala de resolução de ponto flutuante, como 1.5. Valores não inteiros tem probabilidade maior de causar problemas ou quebras.", - "AnisotropyTooltip": "Nível de filtragem anisotrópica (deixe em Auto para usar o valor solicitado pelo jogo)", - "AspectRatioTooltip": "Taxa de proporção aplicada à janela do renderizador.", + "AnisotropyTooltip": "Level of Anisotropic Filtering. Set to Auto to use the value requested by the game.", + "AspectRatioTooltip": "Aspect Ratio applied to the renderer window.\n\nOnly change this if you're using an aspect ratio mod for your game, otherwise the graphics will be stretched.\n\nLeave on 16:9 if unsure.", "ShaderDumpPathTooltip": "Diretòrio de despejo de shaders", "FileLogTooltip": "Habilita ou desabilita log para um arquivo no disco", "StubLogTooltip": "Habilita ou desabilita exibição de mensagens de stub", @@ -504,6 +615,8 @@ "EnableInternetAccessTooltip": "Habilita acesso à internet do programa convidado. Se habilitado, o aplicativo vai se comportar como se o sistema Switch emulado estivesse conectado a Internet. Note que em alguns casos, aplicativos podem acessar a Internet mesmo com essa opção desabilitada", "GameListContextMenuManageCheatToolTip": "Gerenciar Cheats", "GameListContextMenuManageCheat": "Gerenciar Cheats", + "GameListContextMenuManageModToolTip": "Manage Mods", + "GameListContextMenuManageMod": "Manage Mods", "ControllerSettingsStickRange": "Intervalo:", "DialogStopEmulationTitle": "Ryujinx - Parar emulação", "DialogStopEmulationMessage": "Tem certeza que deseja parar a emulação?", @@ -515,8 +628,6 @@ "SettingsTabCpuMemory": "Memória da CPU", "DialogUpdaterFlatpakNotSupportedMessage": "Por favor, atualize o Ryujinx pelo FlatHub.", "UpdaterDisabledWarningTitle": "Atualizador desabilitado!", - "GameListContextMenuOpenSdModsDirectory": "Abrir diretório de mods Atmosphere", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Abre o diretório alternativo Atmosphere no cartão SD que contém mods para o aplicativo", "ControllerSettingsRotate90": "Rodar 90° sentido horário", "IconSize": "Tamanho do ícone", "IconSizeTooltip": "Muda o tamanho do ícone do jogo", @@ -544,12 +655,13 @@ "SwkbdMinCharacters": "Deve ter pelo menos {0} caracteres", "SwkbdMinRangeCharacters": "Deve ter entre {0}-{1} caracteres", "SoftwareKeyboard": "Teclado por Software", - "SoftwareKeyboardModeNumbersOnly": "Must be numbers only", - "SoftwareKeyboardModeAlphabet": "Must be non CJK-characters only", - "SoftwareKeyboardModeASCII": "Must be ASCII text only", - "DialogControllerAppletMessagePlayerRange": "O aplicativo requer {0} jogador(es) com:\n\nTIPOS: {1}\n\nJOGADORES: {2}\n\n{3}Por favor, abra as configurações e reconfigure os controles agora ou clique em Fechar.", - "DialogControllerAppletMessage": "O aplicativo requer exatamente {0} jogador(es) com:\n\nTIPOS: {1}\n\nJOGADORES: {2}\n\n{3}Por favor, abra as configurações e reconfigure os controles agora ou clique em Fechar.", - "DialogControllerAppletDockModeSet": "Modo TV ativado. Portátil também não é válido.\n\n", + "SoftwareKeyboardModeNumeric": "Deve ser somente 0-9 ou '.'", + "SoftwareKeyboardModeAlphabet": "Apenas devem ser caracteres não CJK.", + "SoftwareKeyboardModeASCII": "Deve ser apenas texto ASCII", + "ControllerAppletControllers": "Supported Controllers:", + "ControllerAppletPlayers": "Players:", + "ControllerAppletDescription": "Your current configuration is invalid. Open settings and reconfigure your inputs.", + "ControllerAppletDocked": "Docked mode set. Handheld control should be disabled.", "UpdaterRenaming": "Renomeando arquivos antigos...", "UpdaterRenameFailed": "O atualizador não conseguiu renomear o arquivo: {0}", "UpdaterAddingFiles": "Adicionando novos arquivos...", @@ -587,17 +699,21 @@ "Writable": "Gravável", "SelectDlcDialogTitle": "Selecionar arquivos de DLC", "SelectUpdateDialogTitle": "Selecionar arquivos de atualização", + "SelectModDialogTitle": "Select mod directory", "UserProfileWindowTitle": "Gerenciador de perfis de usuário", "CheatWindowTitle": "Gerenciador de Cheats", "DlcWindowTitle": "Gerenciador de DLC", + "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "Gerenciador de atualizações", "CheatWindowHeading": "Cheats disponíveis para {0} [{1}]", - "BuildId": "BuildId:", + "BuildId": "ID da Build", "DlcWindowHeading": "{0} DLCs disponíveis para {1} ({2})", + "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Editar selecionado", "Cancel": "Cancelar", "Save": "Salvar", "Discard": "Descartar", + "Paused": "Paused", "UserProfilesSetProfileImage": "Definir imagem de perfil", "UserProfileEmptyNameError": "É necessário um nome", "UserProfileNoImageError": "A imagem de perfil deve ser definida", @@ -607,9 +723,9 @@ "UserProfilesName": "Nome:", "UserProfilesUserId": "ID de usuário:", "SettingsTabGraphicsBackend": "Backend gráfico", - "SettingsTabGraphicsBackendTooltip": "Backend gráfico a ser usado", + "SettingsTabGraphicsBackendTooltip": "Select the graphics backend that will be used in the emulator.\n\nVulkan is overall better for all modern graphics cards, as long as their drivers are up to date. Vulkan also features faster shader compilation (less stuttering) on all GPU vendors.\n\nOpenGL may achieve better results on old Nvidia GPUs, on old AMD GPUs on Linux, or on GPUs with lower VRAM, though shader compilation stutters will be greater.\n\nSet to Vulkan if unsure. Set to OpenGL if your GPU does not support Vulkan even with the latest graphics drivers.", "SettingsEnableTextureRecompression": "Habilitar recompressão de texturas", - "SettingsEnableTextureRecompressionTooltip": "Comprime certas texturas para reduzir o uso da VRAM.\n\nRecomendado para uso com GPUs com menos de 4GB VRAM.\n\nEm caso de dúvida, deixe DESLIGADO.", + "SettingsEnableTextureRecompressionTooltip": "Compresses ASTC textures in order to reduce VRAM usage.\n\nGames using this texture format include Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder and The Legend of Zelda: Tears of the Kingdom.\n\nGraphics cards with 4GiB VRAM or less will likely crash at some point while running these games.\n\nEnable only if you're running out of VRAM on the aforementioned games. Leave OFF if unsure.", "SettingsTabGraphicsPreferredGpu": "GPU preferencial", "SettingsTabGraphicsPreferredGpuTooltip": "Selecione a placa de vídeo que será usada com o backend gráfico Vulkan.\n\nNão afeta a GPU que OpenGL usará.\n\nSelecione \"dGPU\" em caso de dúvida. Se não houver nenhuma, não mexa.", "SettingsAppRequiredRestartMessage": "Reinicialização do Ryujinx necessária", @@ -620,8 +736,8 @@ "SettingsTabHotkeysVolumeDownHotkey": "Diminuir volume:", "SettingsEnableMacroHLE": "Habilitar emulação de alto nível para Macros", "SettingsEnableMacroHLETooltip": "Habilita emulação de alto nível de códigos Macro da GPU.\n\nMelhora a performance, mas pode causar problemas gráficos em alguns jogos.\n\nEm caso de dúvida, deixe ATIVADO.", - "SettingsEnableColorSpacePassthrough": "Color Space Passthrough", - "SettingsEnableColorSpacePassthroughTooltip": "Directs the Vulkan backend to pass through color information without specifying a color space. For users with wide gamut displays, this may result in more vibrant colors, at the cost of color correctness.", + "SettingsEnableColorSpacePassthrough": "Passagem de Espaço Cor", + "SettingsEnableColorSpacePassthroughTooltip": "Direciona o backend Vulkan para passar informações de cores sem especificar um espaço de cores. Para usuários com telas de ampla gama, isso pode resultar em cores mais vibrantes, ao custo da correção de cores.", "VolumeShort": "Vol", "UserProfilesManageSaves": "Gerenciar jogos salvos", "DeleteUserSave": "Deseja apagar o jogo salvo do usuário para este jogo?", @@ -635,12 +751,15 @@ "Recover": "Recuperar", "UserProfilesRecoverHeading": "Jogos salvos foram encontrados para as seguintes contas", "UserProfilesRecoverEmptyList": "Nenhum perfil para recuperar", - "GraphicsAATooltip": "Aplica anti-serrilhamento à renderização do jogo", + "GraphicsAATooltip": "Applies anti-aliasing to the game render.\n\nFXAA will blur most of the image, while SMAA will attempt to find jagged edges and smooth them out.\n\nNot recommended to use in conjunction with the FSR scaling filter.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on NONE if unsure.", "GraphicsAALabel": "Anti-serrilhado:", "GraphicsScalingFilterLabel": "Filtro de escala:", - "GraphicsScalingFilterTooltip": "Habilita escala do Framebuffer", + "GraphicsScalingFilterTooltip": "Choose the scaling filter that will be applied when using resolution scale.\n\nBilinear works well for 3D games and is a safe default option.\n\nNearest is recommended for pixel art games.\n\nFSR 1.0 is merely a sharpening filter, not recommended for use with FXAA or SMAA.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on BILINEAR if unsure.", + "GraphicsScalingFilterBilinear": "Bilinear", + "GraphicsScalingFilterNearest": "Nearest", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "Nível", - "GraphicsScalingFilterLevelTooltip": "Define o nível do filtro de escala", + "GraphicsScalingFilterLevelTooltip": "Set FSR 1.0 sharpening level. Higher is sharper.", "SmaaLow": "SMAA Baixo", "SmaaMedium": "SMAA Médio", "SmaaHigh": "SMAA Alto", @@ -648,9 +767,14 @@ "UserEditorTitle": "Editar usuário", "UserEditorTitleCreate": "Criar usuário", "SettingsTabNetworkInterface": "Interface de rede:", - "NetworkInterfaceTooltip": "A interface de rede usada para recursos LAN (rede local)", + "NetworkInterfaceTooltip": "The network interface used for LAN/LDN features.\n\nIn conjunction with a VPN or XLink Kai and a game with LAN support, can be used to spoof a same-network connection over the Internet.\n\nLeave on DEFAULT if unsure.", "NetworkInterfaceDefault": "Padrão", - "PackagingShaders": "Packaging Shaders", - "AboutChangelogButton": "View Changelog on GitHub", - "AboutChangelogButtonTooltipMessage": "Click to open the changelog for this version in your default browser." -} \ No newline at end of file + "PackagingShaders": "Empacotamento de Shaders", + "AboutChangelogButton": "Ver mudanças no GitHub", + "AboutChangelogButtonTooltipMessage": "Clique para abrir o relatório de alterações para esta versão no seu navegador padrão.", + "SettingsTabNetworkMultiplayer": "Multiplayer", + "MultiplayerMode": "Modo:", + "MultiplayerModeTooltip": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.", + "MultiplayerModeDisabled": "Disabled", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/ru_RU.json b/src/Ryujinx/Assets/Locales/ru_RU.json similarity index 52% rename from src/Ryujinx.Ava/Assets/Locales/ru_RU.json rename to src/Ryujinx/Assets/Locales/ru_RU.json index a2128e52e..75fd4fe12 100644 --- a/src/Ryujinx.Ava/Assets/Locales/ru_RU.json +++ b/src/Ryujinx/Assets/Locales/ru_RU.json @@ -1,69 +1,71 @@ { - "Language": "Русский", + "Language": "Русский (RU)", "MenuBarFileOpenApplet": "Открыть апплет", - "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Открыть апплет Mii Editor в автономном режиме", - "SettingsTabInputDirectMouseAccess": "Прямой доступ к мыши", - "SettingsTabSystemMemoryManagerMode": "Режим диспетчера памяти:", + "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Открывает апплет Mii Editor в автономном режиме", + "SettingsTabInputDirectMouseAccess": "Прямой ввод мыши", + "SettingsTabSystemMemoryManagerMode": "Режим менеджера памяти:", "SettingsTabSystemMemoryManagerModeSoftware": "Программное обеспечение", "SettingsTabSystemMemoryManagerModeHost": "Хост (быстро)", "SettingsTabSystemMemoryManagerModeHostUnchecked": "Хост не установлен (самый быстрый, небезопасный)", - "SettingsTabSystemUseHypervisor": "Использовать Гипервизор", + "SettingsTabSystemUseHypervisor": "Использовать Hypervisor", "MenuBarFile": "_Файл", - "MenuBarFileOpenFromFile": "_Загрузить приложение из файла", - "MenuBarFileOpenUnpacked": "Загрузить _Распакованную игру", + "MenuBarFileOpenFromFile": "_Добавить приложение из файла", + "MenuBarFileOpenUnpacked": "Добавить _распакованную игру", "MenuBarFileOpenEmuFolder": "Открыть папку Ryujinx", - "MenuBarFileOpenLogsFolder": "Открыть папку журналов", + "MenuBarFileOpenLogsFolder": "Открыть папку с логами", "MenuBarFileExit": "_Выход", - "MenuBarOptions": "Опции", + "MenuBarOptions": "_Настройки", "MenuBarOptionsToggleFullscreen": "Включить полноэкранный режим", - "MenuBarOptionsStartGamesInFullscreen": "Запустить игру в полноэкранном режиме", + "MenuBarOptionsStartGamesInFullscreen": "Запускать игры в полноэкранном режиме", "MenuBarOptionsStopEmulation": "Остановить эмуляцию", "MenuBarOptionsSettings": "_Параметры", - "MenuBarOptionsManageUserProfiles": "_Управление профилями пользователей", + "MenuBarOptionsManageUserProfiles": "_Менеджер учетных записей", "MenuBarActions": "_Действия", "MenuBarOptionsSimulateWakeUpMessage": "Имитировать сообщение пробуждения", "MenuBarActionsScanAmiibo": "Сканировать Amiibo", "MenuBarTools": "_Инструменты", - "MenuBarToolsInstallFirmware": "Установить прошивку", + "MenuBarToolsInstallFirmware": "Установка прошивки", "MenuBarFileToolsInstallFirmwareFromFile": "Установить прошивку из XCI или ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Установить прошивку из папки", "MenuBarToolsManageFileTypes": "Управление типами файлов", "MenuBarToolsInstallFileTypes": "Установить типы файлов", "MenuBarToolsUninstallFileTypes": "Удалить типы файлов", - "MenuBarHelp": "Помощь", - "MenuBarHelpCheckForUpdates": "Проверка обновления", + "MenuBarView": "_Вид", + "MenuBarViewWindow": "Размер окна", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Помощь", + "MenuBarHelpCheckForUpdates": "Проверить наличие обновлений", "MenuBarHelpAbout": "О программе", "MenuSearch": "Поиск...", - "GameListHeaderFavorite": "Избранные", + "GameListHeaderFavorite": "Избранное", "GameListHeaderIcon": "Значок", "GameListHeaderApplication": "Название", "GameListHeaderDeveloper": "Разработчик", "GameListHeaderVersion": "Версия", - "GameListHeaderTimePlayed": "Время воспроизведения", - "GameListHeaderLastPlayed": "Последняя игра", + "GameListHeaderTimePlayed": "Время в игре", + "GameListHeaderLastPlayed": "Последний запуск", "GameListHeaderFileExtension": "Расширение файла", "GameListHeaderFileSize": "Размер файла", "GameListHeaderPath": "Путь", - "GameListContextMenuOpenUserSaveDirectory": "Открыть папку сохранений пользователя", - "GameListContextMenuOpenUserSaveDirectoryToolTip": "Открывает папку, содержащую пользовательские сохранения", + "GameListContextMenuOpenUserSaveDirectory": "Открыть папку с сохранениями", + "GameListContextMenuOpenUserSaveDirectoryToolTip": "Открывает папку с пользовательскими сохранениями", "GameListContextMenuOpenDeviceSaveDirectory": "Открыть папку сохраненных устройств", "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Открывает папку, содержащую сохраненные устройства", "GameListContextMenuOpenBcatSaveDirectory": "Открыть папку сохраненных BCAT", - "GameListContextMenuOpenBcatSaveDirectoryToolTip": "Открывает папку, содержащую сохраненные BCAT.", - "GameListContextMenuManageTitleUpdates": "Управление обновлениями названий", - "GameListContextMenuManageTitleUpdatesToolTip": "Открывает окно управления обновлением заголовков", + "GameListContextMenuOpenBcatSaveDirectoryToolTip": "Открывает папку, содержащую сохраненные BCAT", + "GameListContextMenuManageTitleUpdates": "Управление обновлениями", + "GameListContextMenuManageTitleUpdatesToolTip": "Открывает окно управления обновлениями приложения", "GameListContextMenuManageDlc": "Управление DLC", "GameListContextMenuManageDlcToolTip": "Открывает окно управления DLC", - "GameListContextMenuOpenModsDirectory": "Открыть папку с модами", - "GameListContextMenuOpenModsDirectoryToolTip": "Открывает папку, содержащую моды приложений и игр", "GameListContextMenuCacheManagement": "Управление кэшем", - "GameListContextMenuCacheManagementPurgePptc": "Перестройка очереди PPTC", - "GameListContextMenuCacheManagementPurgePptcToolTip": "Запускает перестройку PPTC во время запуска следующей игры.", + "GameListContextMenuCacheManagementPurgePptc": "Перестроить очередь PPTC", + "GameListContextMenuCacheManagementPurgePptcToolTip": "Запускает перестройку PPTC во время следующего запуска игры.", "GameListContextMenuCacheManagementPurgeShaderCache": "Очистить кэш шейдеров", "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Удаляет кеш шейдеров приложения", "GameListContextMenuCacheManagementOpenPptcDirectory": "Открыть папку PPTC", "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Открывает папку, содержащую PPTC кэш приложений и игр", - "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Открыть папку кэша шейдеров", + "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Открыть папку с кэшем шейдеров", "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Открывает папку, содержащую кэш шейдеров приложений и игр", "GameListContextMenuExtractData": "Извлечь данные", "GameListContextMenuExtractDataExeFS": "ExeFS", @@ -72,31 +74,39 @@ "GameListContextMenuExtractDataRomFSToolTip": "Извлечение раздела RomFS из текущих настроек приложения (включая обновления)", "GameListContextMenuExtractDataLogo": "Логотип", "GameListContextMenuExtractDataLogoToolTip": "Извлечение раздела с логотипом из текущих настроек приложения (включая обновления)", - "StatusBarGamesLoaded": "{0}/{1} Игр загружено", - "StatusBarSystemVersion": "Версия системы: {0}", + "GameListContextMenuCreateShortcut": "Создать ярлык приложения", + "GameListContextMenuCreateShortcutToolTip": "Создает ярлык на рабочем столе, с помощью которого можно запустить игру или приложение", + "GameListContextMenuCreateShortcutToolTipMacOS": "Создает ярлык игры или приложения в папке Программы macOS", + "GameListContextMenuOpenModsDirectory": "Открыть папку с модами", + "GameListContextMenuOpenModsDirectoryToolTip": "Открывает папку, содержащую моды для приложений и игр", + "GameListContextMenuOpenSdModsDirectory": "Открыть папку с модами Atmosphere", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Открывает папку Atmosphere на альтернативной SD-карте, которая содержит моды для приложений и игр. Полезно для модов, сделанных для реальной консоли.", + "StatusBarGamesLoaded": "{0}/{1} игр загружено", + "StatusBarSystemVersion": "Версия прошивки: {0}", "LinuxVmMaxMapCountDialogTitle": "Обнаружен низкий лимит разметки памяти", - "LinuxVmMaxMapCountDialogTextPrimary": "Вы хотите увеличить значение vm.max_map_count до {0}", + "LinuxVmMaxMapCountDialogTextPrimary": "Хотите увеличить значение vm.max_map_count до {0}", "LinuxVmMaxMapCountDialogTextSecondary": "Некоторые игры могут создавать большую разметку памяти, чем разрешено на данный момент по умолчанию. Ryujinx вылетит при превышении этого лимита.", "LinuxVmMaxMapCountDialogButtonUntilRestart": "Да, до следующего перезапуска", "LinuxVmMaxMapCountDialogButtonPersistent": "Да, постоянно", "LinuxVmMaxMapCountWarningTextPrimary": "Максимальная разметка памяти меньше, чем рекомендуется.", - "LinuxVmMaxMapCountWarningTextSecondary": "Текущее значение vm.max_map_count ({0}) меньше, чем {1}. Некоторые игры могут попытаться создать большую разметку памяти, чем разрешено в данный момент. Ryujinx вылетит как только этот лимит будет превышен.\n\nВозможно, вы захотите вручную увеличить лимит или установить pkexec, что позволит Ryujinx помочь справиться с превышением лимита.", + "LinuxVmMaxMapCountWarningTextSecondary": "Текущее значение vm.max_map_count ({0}) меньше, чем {1}. Некоторые игры могут попытаться создать большую разметку памяти, чем разрешено в данный момент. Ryujinx вылетит как только этот лимит будет превышен.\n\nВозможно, вам потребуется вручную увеличить лимит или установить pkexec, что позволит Ryujinx помочь справиться с превышением лимита.", "Settings": "Параметры", - "SettingsTabGeneral": "Пользовательский интерфейс", + "SettingsTabGeneral": "Интерфейс", "SettingsTabGeneralGeneral": "Общее", - "SettingsTabGeneralEnableDiscordRichPresence": "Включить Discord Rich Presence", + "SettingsTabGeneralEnableDiscordRichPresence": "Статус активности в Discord", "SettingsTabGeneralCheckUpdatesOnLaunch": "Проверять наличие обновлений при запуске", - "SettingsTabGeneralShowConfirmExitDialog": "Показать диалоговое окно \"Подтвердить выход\"", - "SettingsTabGeneralHideCursor": "Скрыть курсор", + "SettingsTabGeneralShowConfirmExitDialog": "Подтверждать выход из приложения", + "SettingsTabGeneralRememberWindowState": "Запомнить размер/положение окна", + "SettingsTabGeneralHideCursor": "Скрывать курсор", "SettingsTabGeneralHideCursorNever": "Никогда", - "SettingsTabGeneralHideCursorOnIdle": "Скрыть курсор в режиме ожидания", + "SettingsTabGeneralHideCursorOnIdle": "В простое", "SettingsTabGeneralHideCursorAlways": "Всегда", "SettingsTabGeneralGameDirectories": "Папки с играми", "SettingsTabGeneralAdd": "Добавить", "SettingsTabGeneralRemove": "Удалить", "SettingsTabSystem": "Система", "SettingsTabSystemCore": "Основные настройки", - "SettingsTabSystemSystemRegion": "Регион Системы:", + "SettingsTabSystemSystemRegion": "Регион прошивки:", "SettingsTabSystemSystemRegionJapan": "Япония", "SettingsTabSystemSystemRegionUSA": "США", "SettingsTabSystemSystemRegionEurope": "Европа", @@ -104,7 +114,7 @@ "SettingsTabSystemSystemRegionChina": "Китай", "SettingsTabSystemSystemRegionKorea": "Корея", "SettingsTabSystemSystemRegionTaiwan": "Тайвань", - "SettingsTabSystemSystemLanguage": "Язык системы:", + "SettingsTabSystemSystemLanguage": "Язык прошивки:", "SettingsTabSystemSystemLanguageJapanese": "Японский", "SettingsTabSystemSystemLanguageAmericanEnglish": "Английский (США)", "SettingsTabSystemSystemLanguageFrench": "Французский", @@ -119,38 +129,38 @@ "SettingsTabSystemSystemLanguageTaiwanese": "Тайванский", "SettingsTabSystemSystemLanguageBritishEnglish": "Английский (Британия)", "SettingsTabSystemSystemLanguageCanadianFrench": "Французский (Канада)", - "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Испанский (Латиноамериканский)", - "SettingsTabSystemSystemLanguageSimplifiedChinese": "Китайский упрощённый", - "SettingsTabSystemSystemLanguageTraditionalChinese": "Китайский традиционный", - "SettingsTabSystemSystemTimeZone": "Часовой пояс системы:", - "SettingsTabSystemSystemTime": "Время системы:", - "SettingsTabSystemEnableVsync": "Включить вертикальную синхронизацию", - "SettingsTabSystemEnablePptc": "Включить PPTC (Profiled Persistent Translation Cache)", - "SettingsTabSystemEnableFsIntegrityChecks": "Включить проверку целостности FS", - "SettingsTabSystemAudioBackend": "Аудио бэкэнд:", - "SettingsTabSystemAudioBackendDummy": "Муляж", + "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Испанский (Латинская Америка)", + "SettingsTabSystemSystemLanguageSimplifiedChinese": "Китайский (упрощённый)", + "SettingsTabSystemSystemLanguageTraditionalChinese": "Китайский (традиционный)", + "SettingsTabSystemSystemTimeZone": "Часовой пояс прошивки:", + "SettingsTabSystemSystemTime": "Системное время в прошивке:", + "SettingsTabSystemEnableVsync": "Вертикальная синхронизация", + "SettingsTabSystemEnablePptc": "Использовать PPTC (Profiled Persistent Translation Cache)", + "SettingsTabSystemEnableFsIntegrityChecks": "Проверка целостности файловой системы", + "SettingsTabSystemAudioBackend": "Аудио бэкенд:", + "SettingsTabSystemAudioBackendDummy": "Без звука", "SettingsTabSystemAudioBackendOpenAL": "OpenAL", "SettingsTabSystemAudioBackendSoundIO": "SoundIO", "SettingsTabSystemAudioBackendSDL2": "SDL2", "SettingsTabSystemHacks": "Хаки", - "SettingsTabSystemHacksNote": " (Эти многие настройки вызывают нестабильность)", - "SettingsTabSystemExpandDramSize": "Увеличение размера DRAM до 6GiB", + "SettingsTabSystemHacksNote": "Возможна нестабильная работа", + "SettingsTabSystemExpandDramSize": "Использовать альтернативный макет памяти (для разработчиков)", "SettingsTabSystemIgnoreMissingServices": "Игнорировать отсутствующие службы", "SettingsTabGraphics": "Графика", "SettingsTabGraphicsAPI": "Графические API", - "SettingsTabGraphicsEnableShaderCache": "Включить кэш шейдеров", + "SettingsTabGraphicsEnableShaderCache": "Кэшировать шейдеры", "SettingsTabGraphicsAnisotropicFiltering": "Анизотропная фильтрация:", "SettingsTabGraphicsAnisotropicFilteringAuto": "Автоматически", "SettingsTabGraphicsAnisotropicFiltering2x": "2x", "SettingsTabGraphicsAnisotropicFiltering4x": "4x", "SettingsTabGraphicsAnisotropicFiltering8x": "8x", "SettingsTabGraphicsAnisotropicFiltering16x": "16x", - "SettingsTabGraphicsResolutionScale": "Масштаб:", - "SettingsTabGraphicsResolutionScaleCustom": "Пользовательский (не рекомендуется)", - "SettingsTabGraphicsResolutionScaleNative": "Родной (720p/1080p)", + "SettingsTabGraphicsResolutionScale": "Масштабирование:", + "SettingsTabGraphicsResolutionScaleCustom": "Пользовательское (не рекомендуется)", + "SettingsTabGraphicsResolutionScaleNative": "Нативное (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (не рекомендуется)", "SettingsTabGraphicsAspectRatio": "Соотношение сторон:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -159,7 +169,7 @@ "SettingsTabGraphicsAspectRatio32x9": "32:9", "SettingsTabGraphicsAspectRatioStretch": "Растянуть до размеров окна", "SettingsTabGraphicsDeveloperOptions": "Параметры разработчика", - "SettingsTabGraphicsShaderDumpPath": "Путь дампа графического шейдера:", + "SettingsTabGraphicsShaderDumpPath": "Путь дампа графических шейдеров", "SettingsTabLogging": "Журналирование", "SettingsTabLoggingLogging": "Журналирование", "SettingsTabLoggingEnableLoggingToFile": "Включить запись в файл", @@ -172,16 +182,16 @@ "SettingsTabLoggingEnableFsAccessLogs": "Включить журналы доступа файловой системы", "SettingsTabLoggingFsGlobalAccessLogMode": "Режим журнала глобального доступа файловой системы:", "SettingsTabLoggingDeveloperOptions": "Параметры разработчика", - "SettingsTabLoggingDeveloperOptionsNote": "ВНИМАНИЕ: Снижает производительность", + "SettingsTabLoggingDeveloperOptionsNote": "ВНИМАНИЕ: эти настройки снижают производительность", "SettingsTabLoggingGraphicsBackendLogLevel": "Уровень журнала бэкенда графики:", - "SettingsTabLoggingGraphicsBackendLogLevelNone": "Ничего", + "SettingsTabLoggingGraphicsBackendLogLevelNone": "Нет", "SettingsTabLoggingGraphicsBackendLogLevelError": "Ошибка", "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Замедления", "SettingsTabLoggingGraphicsBackendLogLevelAll": "Всё", "SettingsTabLoggingEnableDebugLogs": "Включить журнал отладки", "SettingsTabInput": "Управление", - "SettingsTabInputEnableDockedMode": "Включить режим закрепления", - "SettingsTabInputDirectKeyboardAccess": "Прямой доступ с клавиатуры", + "SettingsTabInputEnableDockedMode": "Стационарный режим", + "SettingsTabInputDirectKeyboardAccess": "Прямой ввод клавиатуры", "SettingsButtonSave": "Сохранить", "SettingsButtonClose": "Закрыть", "SettingsButtonOk": "Ок", @@ -202,10 +212,10 @@ "ControllerSettingsDeviceDisabled": "Отключить", "ControllerSettingsControllerType": "Тип контроллера", "ControllerSettingsControllerTypeHandheld": "Портативный", - "ControllerSettingsControllerTypeProController": "Pro Контроллер", - "ControllerSettingsControllerTypeJoyConPair": "JoyCon Пара", - "ControllerSettingsControllerTypeJoyConLeft": "JoyCon Левый", - "ControllerSettingsControllerTypeJoyConRight": "JoyCon Правый", + "ControllerSettingsControllerTypeProController": "Pro Controller", + "ControllerSettingsControllerTypeJoyConPair": "JoyCon (пара)", + "ControllerSettingsControllerTypeJoyConLeft": "JoyCon (левый)", + "ControllerSettingsControllerTypeJoyConRight": "JoyCon (правый)", "ControllerSettingsProfile": "Профиль", "ControllerSettingsProfileDefault": "По умолчанию", "ControllerSettingsLoad": "Загрузить", @@ -218,19 +228,19 @@ "ControllerSettingsButtonY": "Y", "ControllerSettingsButtonPlus": "+", "ControllerSettingsButtonMinus": "-", - "ControllerSettingsDPad": "Направляющая панель", + "ControllerSettingsDPad": "Кнопки направления", "ControllerSettingsDPadUp": "Вверх", "ControllerSettingsDPadDown": "Вниз", "ControllerSettingsDPadLeft": "Влево", "ControllerSettingsDPadRight": "Вправо", - "ControllerSettingsStickButton": "Кнопка", + "ControllerSettingsStickButton": "Нажатие на стик", "ControllerSettingsStickUp": "Вверх", "ControllerSettingsStickDown": "Вниз", "ControllerSettingsStickLeft": "Влево", "ControllerSettingsStickRight": "Вправо", "ControllerSettingsStickStick": "Стик", - "ControllerSettingsStickInvertXAxis": "Инвертировать X ось", - "ControllerSettingsStickInvertYAxis": "Инвертировать Y ось", + "ControllerSettingsStickInvertXAxis": "Инвертировать ось X", + "ControllerSettingsStickInvertYAxis": "Инвертировать ось Y", "ControllerSettingsStickDeadzone": "Мёртвая зона:", "ControllerSettingsLStick": "Левый стик", "ControllerSettingsRStick": "Правый стик", @@ -252,58 +262,155 @@ "ControllerSettingsMisc": "Разное", "ControllerSettingsTriggerThreshold": "Порог срабатывания:", "ControllerSettingsMotion": "Движение", - "ControllerSettingsMotionUseCemuhookCompatibleMotion": "Используйте движение, совместимое с CemuHook", + "ControllerSettingsMotionUseCemuhookCompatibleMotion": "Включить совместимость с CemuHook", "ControllerSettingsMotionControllerSlot": "Слот контроллера:", "ControllerSettingsMotionMirrorInput": "Зеркальный ввод", - "ControllerSettingsMotionRightJoyConSlot": "Правый JoyCon слот:", + "ControllerSettingsMotionRightJoyConSlot": "Слот правого JoyCon:", "ControllerSettingsMotionServerHost": "Хост сервера:", "ControllerSettingsMotionGyroSensitivity": "Чувствительность гироскопа:", "ControllerSettingsMotionGyroDeadzone": "Мертвая зона гироскопа:", "ControllerSettingsSave": "Сохранить", "ControllerSettingsClose": "Закрыть", + "KeyUnknown": "Неизвестно", + "KeyShiftLeft": "Левый Shift", + "KeyShiftRight": "Правый Shift", + "KeyControlLeft": "Левый Ctrl", + "KeyMacControlLeft": "Левый ⌃", + "KeyControlRight": "Правый Ctrl", + "KeyMacControlRight": "Правый ⌃", + "KeyAltLeft": "Левый Alt", + "KeyMacAltLeft": "Левый ⌥", + "KeyAltRight": "Правый Alt", + "KeyMacAltRight": "Правый ⌥", + "KeyWinLeft": "Левый ⊞", + "KeyMacWinLeft": "Левый ⌘", + "KeyWinRight": "Правый ⊞", + "KeyMacWinRight": "Правый ⌘", + "KeyMenu": "Меню", + "KeyUp": "Вверх", + "KeyDown": "Вниз", + "KeyLeft": "Влево", + "KeyRight": "Вправо", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Пробел", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Очистить", + "KeyKeypad0": "Блок цифр 0", + "KeyKeypad1": "Блок цифр 1", + "KeyKeypad2": "Блок цифр 2", + "KeyKeypad3": "Блок цифр 3", + "KeyKeypad4": "Блок цифр 4", + "KeyKeypad5": "Блок цифр 5", + "KeyKeypad6": "Блок цифр 6", + "KeyKeypad7": "Блок цифр 7", + "KeyKeypad8": "Блок цифр 8", + "KeyKeypad9": "Блок цифр 9", + "KeyKeypadDivide": "/ (блок цифр)", + "KeyKeypadMultiply": "* (блок цифр)", + "KeyKeypadSubtract": "- (блок цифр)", + "KeyKeypadAdd": "+ (блок цифр)", + "KeyKeypadDecimal": ". (блок цифр)", + "KeyKeypadEnter": "Enter (блок цифр)", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Не привязано", + "GamepadLeftStick": "Кнопка лев. стика", + "GamepadRightStick": "Кнопка пр. стика", + "GamepadLeftShoulder": "Левый бампер", + "GamepadRightShoulder": "Правый бампер", + "GamepadLeftTrigger": "Левый триггер", + "GamepadRightTrigger": "Правый триггер", + "GamepadDpadUp": "Вверх", + "GamepadDpadDown": "Вниз", + "GamepadDpadLeft": "Влево", + "GamepadDpadRight": "Вправо", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Кнопка Xbox", + "GamepadMisc1": "Прочее", + "GamepadPaddle1": "Доп.кнопка 1", + "GamepadPaddle2": "Доп.кнопка 2", + "GamepadPaddle3": "Доп.кнопка 3", + "GamepadPaddle4": "Доп.кнопка 4", + "GamepadTouchpad": "Тачпад", + "GamepadSingleLeftTrigger0": "Левый триггер 0", + "GamepadSingleRightTrigger0": "Правый триггер 0", + "GamepadSingleLeftTrigger1": "Левый триггер 1", + "GamepadSingleRightTrigger1": "Правый триггер 1", + "StickLeft": "Левый стик", + "StickRight": "Правый стик", "UserProfilesSelectedUserProfile": "Выбранный пользовательский профиль:", "UserProfilesSaveProfileName": "Сохранить пользовательский профиль", - "UserProfilesChangeProfileImage": "Изменить изображение профиля", + "UserProfilesChangeProfileImage": "Изменить аватар", "UserProfilesAvailableUserProfiles": "Доступные профили пользователей:", "UserProfilesAddNewProfile": "Добавить новый профиль", "UserProfilesDelete": "Удалить", "UserProfilesClose": "Закрыть", - "ProfileNameSelectionWatermark": "Выберите псевдоним", + "ProfileNameSelectionWatermark": "Укажите никнейм", "ProfileImageSelectionTitle": "Выбор изображения профиля", - "ProfileImageSelectionHeader": "Выберите изображение профиля", - "ProfileImageSelectionNote": "Вы можете импортировать собственное изображение профиля или выбрать аватар из системной прошивки.", - "ProfileImageSelectionImportImage": "Импорт файла изображения", - "ProfileImageSelectionSelectAvatar": "Выберите аватар прошивки", + "ProfileImageSelectionHeader": "Выбор аватара", + "ProfileImageSelectionNote": "Вы можете импортировать собственное изображение или выбрать аватар из системной прошивки.", + "ProfileImageSelectionImportImage": "Импорт изображения", + "ProfileImageSelectionSelectAvatar": "Встроенные аватары", "InputDialogTitle": "Диалоговое окно ввода", "InputDialogOk": "ОК", "InputDialogCancel": "Отмена", - "InputDialogAddNewProfileTitle": "Выберите имя профиля", - "InputDialogAddNewProfileHeader": "Пожалуйста, введите имя профиля", + "InputDialogAddNewProfileTitle": "Выберите никнейм", + "InputDialogAddNewProfileHeader": "Пожалуйста, введите никнейм", "InputDialogAddNewProfileSubtext": "(Максимальная длина: {0})", - "AvatarChoose": "Выбор аватара", + "AvatarChoose": "Выбрать аватар", "AvatarSetBackgroundColor": "Установить цвет фона", "AvatarClose": "Закрыть", "ControllerSettingsLoadProfileToolTip": "Загрузить профиль", - "ControllerSettingsAddProfileToolTip": "Добавить профил", + "ControllerSettingsAddProfileToolTip": "Добавить профиль", "ControllerSettingsRemoveProfileToolTip": "Удалить профиль", "ControllerSettingsSaveProfileToolTip": "Сохранить профиль", "MenuBarFileToolsTakeScreenshot": "Сделать снимок экрана", - "MenuBarFileToolsHideUi": "Скрыть UI", + "MenuBarFileToolsHideUi": "Скрыть интерфейс", "GameListContextMenuRunApplication": "Запуск приложения", - "GameListContextMenuToggleFavorite": "Переключить Избранное", - "GameListContextMenuToggleFavoriteToolTip": "Переключить любимый статус игры", - "SettingsTabGeneralTheme": "Тема", - "SettingsTabGeneralThemeCustomTheme": "Пользовательский путь к теме", - "SettingsTabGeneralThemeBaseStyle": "Базовый стиль", - "SettingsTabGeneralThemeBaseStyleDark": "Тёмная", - "SettingsTabGeneralThemeBaseStyleLight": "Светлая", - "SettingsTabGeneralThemeEnableCustomTheme": "Включить пользовательскую тему", - "ButtonBrowse": "Обзор", + "GameListContextMenuToggleFavorite": "Добавить в избранное", + "GameListContextMenuToggleFavoriteToolTip": "Добавляет игру в избранное и помечает звездочкой", + "SettingsTabGeneralTheme": "Тема:", + "SettingsTabGeneralThemeDark": "Темная", + "SettingsTabGeneralThemeLight": "Светлая", "ControllerSettingsConfigureGeneral": "Настройка", "ControllerSettingsRumble": "Вибрация", "ControllerSettingsRumbleStrongMultiplier": "Множитель сильной вибрации", "ControllerSettingsRumbleWeakMultiplier": "Множитель слабой вибрации", - "DialogMessageSaveNotAvailableMessage": "Нет сохраненных данных для {0} [{1:x16}]", + "DialogMessageSaveNotAvailableMessage": "Нет сохранений для {0} [{1:x16}]", "DialogMessageSaveNotAvailableCreateSaveMessage": "Создать сохранение для этой игры?", "DialogConfirmationTitle": "Ryujinx - Подтверждение", "DialogUpdaterTitle": "Ryujinx - Обновление", @@ -311,215 +418,219 @@ "DialogWarningTitle": "Ryujinx - Предупреждение", "DialogExitTitle": "Ryujinx - Выход", "DialogErrorMessage": "Ryujinx обнаружил ошибку", - "DialogExitMessage": "Вы уверены, что хотите закрыть Ryujinx?", - "DialogExitSubMessage": "Все несохраненные данные будут потеряны!", + "DialogExitMessage": "Вы уверены, что хотите выйти из Ryujinx?", + "DialogExitSubMessage": "Все несохраненные данные будут потеряны", "DialogMessageCreateSaveErrorMessage": "Произошла ошибка при создании указанных данных сохранения: {0}", "DialogMessageFindSaveErrorMessage": "Произошла ошибка при поиске указанных данных сохранения: {0}", "FolderDialogExtractTitle": "Выберите папку для извлечения", - "DialogNcaExtractionMessage": "Извлечение {0} раздел от {1}...", - "DialogNcaExtractionTitle": "Ryujinx - Экстрактор разделов NCA", + "DialogNcaExtractionMessage": "Извлечение {0} раздела из {1}...", + "DialogNcaExtractionTitle": "Ryujinx - Извлечение разделов NCA", "DialogNcaExtractionMainNcaNotFoundErrorMessage": "Ошибка извлечения. Основной NCA не присутствовал в выбранном файле.", "DialogNcaExtractionCheckLogErrorMessage": "Ошибка извлечения. Прочтите файл журнала для получения дополнительной информации.", "DialogNcaExtractionSuccessMessage": "Извлечение завершено успешно.", "DialogUpdaterConvertFailedMessage": "Не удалось преобразовать текущую версию Ryujinx.", - "DialogUpdaterCancelUpdateMessage": "Отмена обновления!", - "DialogUpdaterAlreadyOnLatestVersionMessage": "Вы уже используете самую последнюю версию Ryujinx!", + "DialogUpdaterCancelUpdateMessage": "Отмена обновления...", + "DialogUpdaterAlreadyOnLatestVersionMessage": "Вы используете самую последнюю версию Ryujinx", "DialogUpdaterFailedToGetVersionMessage": "Произошла ошибка при попытке получить информацию о выпуске от GitHub Release. Это может быть вызвано тем, что в данный момент в GitHub Actions компилируется новый релиз. Повторите попытку позже.", "DialogUpdaterConvertFailedGithubMessage": "Не удалось преобразовать полученную версию Ryujinx из Github Release.", "DialogUpdaterDownloadingMessage": "Загрузка обновления...", "DialogUpdaterExtractionMessage": "Извлечение обновления...", "DialogUpdaterRenamingMessage": "Переименование обновления...", "DialogUpdaterAddingFilesMessage": "Добавление нового обновления...", - "DialogUpdaterCompleteMessage": "Обновление завершено!", - "DialogUpdaterRestartMessage": "Вы хотите перезапустить Ryujinx сейчас?", - "DialogUpdaterArchNotSupportedMessage": "Вы используете не поддерживаемую системную архитектуру!", - "DialogUpdaterArchNotSupportedSubMessage": "(Поддерживаются только x64 системы)", - "DialogUpdaterNoInternetMessage": "Вы не подключены к интернету!", - "DialogUpdaterNoInternetSubMessage": "Убедитесь, что у вас есть работающее подключение к интернету!", - "DialogUpdaterDirtyBuildMessage": "Вы не можете обновить Dirty Build!", + "DialogUpdaterCompleteMessage": "Обновление завершено", + "DialogUpdaterRestartMessage": "Перезапустить Ryujinx?", + "DialogUpdaterNoInternetMessage": "Вы не подключены к интернету", + "DialogUpdaterNoInternetSubMessage": "Убедитесь, что у вас работает подключение к интернету", + "DialogUpdaterDirtyBuildMessage": "Вы не можете обновлять Dirty Build", "DialogUpdaterDirtyBuildSubMessage": "Загрузите Ryujinx по адресу https://ryujinx.org/ если вам нужна поддерживаемая версия.", "DialogRestartRequiredMessage": "Требуется перезагрузка", "DialogThemeRestartMessage": "Тема сохранена. Для применения темы требуется перезапуск.", - "DialogThemeRestartSubMessage": "Вы хотите перезапустить?", + "DialogThemeRestartSubMessage": "Хотите перезапустить", "DialogFirmwareInstallEmbeddedMessage": "Хотите установить прошивку, встроенную в эту игру? (Прошивка {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "Установленная прошивка не найдена, но Ryujinx удалось установить прошивку {0} из предоставленной игры.\nТеперь эмулятор запустится.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "Установленная прошивка не была найдена, но Ryujinx удалось установить прошивку {0} из предоставленной игры.\nТеперь эмулятор запустится.", "DialogFirmwareNoFirmwareInstalledMessage": "Прошивка не установлена", "DialogFirmwareInstalledMessage": "Прошивка {0} была установлена", - "DialogInstallFileTypesSuccessMessage": "Успешно установлены типы файлов!", + "DialogInstallFileTypesSuccessMessage": "Типы файлов успешно установлены", "DialogInstallFileTypesErrorMessage": "Не удалось установить типы файлов.", - "DialogUninstallFileTypesSuccessMessage": "Успешно удалены типы файлов!", + "DialogUninstallFileTypesSuccessMessage": "Типы файлов успешно удалены", "DialogUninstallFileTypesErrorMessage": "Не удалось удалить типы файлов.", - "DialogOpenSettingsWindowLabel": "Открыть окно настроек", + "DialogOpenSettingsWindowLabel": "Открывает окно параметров", "DialogControllerAppletTitle": "Апплет контроллера", - "DialogMessageDialogErrorExceptionMessage": "Ошибка отображения диалогового окна сообщений: {0}", + "DialogMessageDialogErrorExceptionMessage": "Ошибка отображения сообщения: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "Ошибка отображения программной клавиатуры: {0}", "DialogErrorAppletErrorExceptionMessage": "Ошибка отображения диалогового окна ErrorApplet: {0}", "DialogUserErrorDialogMessage": "{0}: {1}", "DialogUserErrorDialogInfoMessage": "\nДля получения дополнительной информации о том, как исправить эту ошибку, следуйте нашему Руководству по установке.", - "DialogUserErrorDialogTitle": "Ошибка Ryujinx! ({0})", + "DialogUserErrorDialogTitle": "Ошибка Ryujinx ({0})", "DialogAmiiboApiTitle": "Amiibo API", "DialogAmiiboApiFailFetchMessage": "Произошла ошибка при получении информации из API.", - "DialogAmiiboApiConnectErrorMessage": "Не удалось подключиться к серверу Amiibo API. Служба может быть недоступна, или вам может потребоваться проверить, подключено ли ваше интернет-соединение к сети.", + "DialogAmiiboApiConnectErrorMessage": "Не удалось подключиться к серверу Amiibo API. Служба может быть недоступна или вам может потребоваться проверить ваше интернет-соединение.", "DialogProfileInvalidProfileErrorMessage": "Профиль {0} несовместим с текущей системой конфигурации ввода.", "DialogProfileDefaultProfileOverwriteErrorMessage": "Профиль по умолчанию не может быть перезаписан", "DialogProfileDeleteProfileTitle": "Удаление профиля", "DialogProfileDeleteProfileMessage": "Это действие необратимо. Вы уверены, что хотите продолжить?", "DialogWarning": "Внимание", - "DialogPPTCDeletionMessage": "Вы собираетесь удалить кэш PPTC для:\n\n{0}\n\nВы уверены, что хотите продолжить?", + "DialogPPTCDeletionMessage": "Вы собираетесь перестроить кэш PPTC при следующем запуске для:\n\n{0}\n\nВы уверены, что хотите продолжить?", "DialogPPTCDeletionErrorMessage": "Ошибка очистки кэша PPTC в {0}: {1}", "DialogShaderDeletionMessage": "Вы собираетесь удалить кэш шейдеров для:\n\n{0}\n\nВы уверены, что хотите продолжить?", "DialogShaderDeletionErrorMessage": "Ошибка очистки кэша шейдеров в {0}: {1}", "DialogRyujinxErrorMessage": "Ryujinx обнаружил ошибку", - "DialogInvalidTitleIdErrorMessage": "Ошибка пользовательского интерфейса: выбранная игра не имеет действительного идентификатора названия.", - "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Действительная системная прошивка не найдена в {0}.", + "DialogInvalidTitleIdErrorMessage": "Ошибка пользовательского интерфейса: выбранная игра не имеет действительного ID.", + "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Валидная системная прошивка не найдена в {0}.", "DialogFirmwareInstallerFirmwareInstallTitle": "Установить прошивку {0}", - "DialogFirmwareInstallerFirmwareInstallMessage": "Будет установлена версия системы {0}.", - "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nЭто заменит текущую версию системы {0}.", + "DialogFirmwareInstallerFirmwareInstallMessage": "Будет установлена версия прошивки {0}.", + "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nЭто заменит текущую версию прошивки {0}.", "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nПродолжить?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Установка прошивки...", - "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Версия системы {0} успешно установлена.", + "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Прошивка версии {0} успешно установлена.", "DialogUserProfileDeletionWarningMessage": "Если выбранный профиль будет удален, другие профили не будут открываться.", - "DialogUserProfileDeletionConfirmMessage": "Вы хотите удалить выбранный профиль", + "DialogUserProfileDeletionConfirmMessage": "Удалить выбранный профиль?", "DialogUserProfileUnsavedChangesTitle": "Внимание - Несохраненные изменения", - "DialogUserProfileUnsavedChangesMessage": "Вы внесли изменения в этот профиль пользователя которые не были сохранены.", - "DialogUserProfileUnsavedChangesSubMessage": "Вы хотите отменить изменения?", - "DialogControllerSettingsModifiedConfirmMessage": "Текущие настройки контроллера обновлены.", - "DialogControllerSettingsModifiedConfirmSubMessage": "Вы хотите сохранить?", - "DialogLoadNcaErrorMessage": "{0}. Файл с ошибкой: {1}", - "DialogDlcNoDlcErrorMessage": "Указанный файл не содержит DLC для выбранной игры!", + "DialogUserProfileUnsavedChangesMessage": "В эту учетную запись внесены изменения, которые не были сохранены.", + "DialogUserProfileUnsavedChangesSubMessage": "Отменить изменения?", + "DialogControllerSettingsModifiedConfirmMessage": "Текущие настройки управления обновлены.", + "DialogControllerSettingsModifiedConfirmSubMessage": "Сохранить?", + "DialogLoadFileErrorMessage": "{0}. Файл с ошибкой: {1}", + "DialogModAlreadyExistsMessage": "Мод уже существует", + "DialogModInvalidMessage": "Выбранная папка не содержит модов", + "DialogModDeleteNoParentMessage": "Невозможно удалить: не удалось найти папку мода \"{0}\"", + "DialogDlcNoDlcErrorMessage": "Указанный файл не содержит DLC для выбранной игры", "DialogPerformanceCheckLoggingEnabledMessage": "У вас включено ведение журнала отладки, предназначенное только для разработчиков.", - "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Для оптимальной производительности рекомендуется отключить ведение журнала отладки. Вы хотите отключить ведение журнала отладки сейчас?", - "DialogPerformanceCheckShaderDumpEnabledMessage": "У вас включен сброс шейдеров, который предназначен только для разработчиков.", - "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Для оптимальной производительности рекомендуется отключить сброс шейдеров. Вы хотите отключить сброс шейдеров сейчас?", + "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Для оптимальной производительности рекомендуется отключить ведение журнала отладки. Хотите отключить ведение журнала отладки?", + "DialogPerformanceCheckShaderDumpEnabledMessage": "У вас включен дамп шейдеров, который предназначен только для разработчиков.", + "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Для оптимальной производительности рекомендуется отключить дамп шейдеров. Хотите отключить дамп шейдеров?", "DialogLoadAppGameAlreadyLoadedMessage": "Игра уже загружена", "DialogLoadAppGameAlreadyLoadedSubMessage": "Пожалуйста, остановите эмуляцию или закройте эмулятор перед запуском другой игры.", - "DialogUpdateAddUpdateErrorMessage": "Указанный файл не содержит обновления для выбранного заголовка!", + "DialogUpdateAddUpdateErrorMessage": "Указанный файл не содержит обновлений для выбранного приложения", "DialogSettingsBackendThreadingWarningTitle": "Предупреждение: многопоточность в бэкенде", - "DialogSettingsBackendThreadingWarningMessage": "Ryujinx необходимо перезапустить после изменения этой опции, чтобы она полностью применилась. В зависимости от вашей платформы вам может потребоваться вручную отключить собственную многопоточность вашего драйвера при использовании Ryujinx.", + "DialogSettingsBackendThreadingWarningMessage": "Для применения этой настройки необходимо перезапустить Ryujinx. В зависимости от используемой вами операционной системы вам может потребоваться вручную отключить многопоточность драйвера при использовании Ryujinx.", + "DialogModManagerDeletionWarningMessage": "Вы сейчас удалите мод: {0}\n\nВы уверены, что хотите продолжить?", + "DialogModManagerDeletionAllWarningMessage": "Вы сейчас удалите все выбранные моды для этой игры.\n\nВы уверены, что хотите продолжить?", "SettingsTabGraphicsFeaturesOptions": "Функции & Улучшения", "SettingsTabGraphicsBackendMultithreading": "Многопоточность графического бэкенда:", "CommonAuto": "Автоматически", - "CommonOff": "Выключен", - "CommonOn": "Включен", + "CommonOff": "Выключено", + "CommonOn": "Включено", "InputDialogYes": "Да", "InputDialogNo": "Нет", "DialogProfileInvalidProfileNameErrorMessage": "Имя файла содержит недопустимые символы. Пожалуйста, попробуйте еще раз.", - "MenuBarOptionsPauseEmulation": "Пауза", + "MenuBarOptionsPauseEmulation": "Пауза эмуляции", "MenuBarOptionsResumeEmulation": "Продолжить", - "AboutUrlTooltipMessage": "Нажмите, чтобы открыть веб-сайт Ryujinx в браузере по умолчанию.", + "AboutUrlTooltipMessage": "Нажмите, чтобы открыть веб-сайт Ryujinx", "AboutDisclaimerMessage": "Ryujinx никоим образом не связан ни с Nintendo™, ни с кем-либо из ее партнеров.", - "AboutAmiiboDisclaimerMessage": "Amiibo API (www.amiibo api.com) используется\n нашей эмуляции Amiibo.", - "AboutPatreonUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx Patreon в браузере по умолчанию.", - "AboutGithubUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx GitHub в браузере по умолчанию.", - "AboutDiscordUrlTooltipMessage": "Нажмите, чтобы открыть приглашение на сервер Ryujinx Discord в браузере по умолчанию.", - "AboutTwitterUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx в Twitter в браузере по умолчанию.", + "AboutAmiiboDisclaimerMessage": "Amiibo API (www.amiiboapi.com) используется для эмуляции Amiibo.", + "AboutPatreonUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx на Patreon", + "AboutGithubUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx на GitHub", + "AboutDiscordUrlTooltipMessage": "Нажмите, чтобы открыть приглашение на сервер Ryujinx в Discord", + "AboutTwitterUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx в X (бывший Twitter)", "AboutRyujinxAboutTitle": "О программе:", - "AboutRyujinxAboutContent": "Ryujinx — это эмулятор Nintendo Switch™.\nПожалуйста, поддержите нас на Patreon.\nУзнавайте все последние новости в нашем Twitter или Discord.\nРазработчики, заинтересованные в участии, могут узнать больше на нашем GitHub или в Discord.", - "AboutRyujinxMaintainersTitle": "Поддерживается:", - "AboutRyujinxMaintainersContentTooltipMessage": "Нажмите, чтобы открыть страницу Contributors в браузере по умолчанию.", - "AboutRyujinxSupprtersTitle": "Поддерживается на Patreon:", + "AboutRyujinxAboutContent": "Ryujinx — это эмулятор Nintendo Switch™.\nПожалуйста, поддержите нас на Patreon.\nЧитайте последние новости в наших X (Twitter) или Discord.\nРазработчики, заинтересованные в участии, могут ознакомиться с проектом на GitHub или в Discord.", + "AboutRyujinxMaintainersTitle": "Разработка:", + "AboutRyujinxMaintainersContentTooltipMessage": "Нажмите, чтобы открыть страницу с участниками", + "AboutRyujinxSupprtersTitle": "Поддержка на Patreon:", "AmiiboSeriesLabel": "Серия Amiibo", "AmiiboCharacterLabel": "Персонаж", "AmiiboScanButtonLabel": "Сканировать", "AmiiboOptionsShowAllLabel": "Показать все Amiibo", "AmiiboOptionsUsRandomTagLabel": "Хак: Использовать случайный тег Uuid", - "DlcManagerTableHeadingEnabledLabel": "Велючено", - "DlcManagerTableHeadingTitleIdLabel": "Идентификатор заголовка", + "DlcManagerTableHeadingEnabledLabel": "Включено", + "DlcManagerTableHeadingTitleIdLabel": "ID приложения", "DlcManagerTableHeadingContainerPathLabel": "Путь к контейнеру", "DlcManagerTableHeadingFullPathLabel": "Полный путь", - "DlcManagerRemoveAllButton": "Убрать все", + "DlcManagerRemoveAllButton": "Удалить все", "DlcManagerEnableAllButton": "Включить все", "DlcManagerDisableAllButton": "Отключить все", - "MenuBarOptionsChangeLanguage": "Изменить язык", - "MenuBarShowFileTypes": "Показать типы файлов", - "CommonSort": "Сортировать", - "CommonShowNames": "Показать названия", - "CommonFavorite": "Избранные", + "ModManagerDeleteAllButton": "Удалить все", + "MenuBarOptionsChangeLanguage": "Сменить язык", + "MenuBarShowFileTypes": "Показывать форматы файлов", + "CommonSort": "Сортировка", + "CommonShowNames": "Показывать названия", + "CommonFavorite": "Избранное", "OrderAscending": "По возрастанию", "OrderDescending": "По убыванию", "SettingsTabGraphicsFeatures": "Функции", "ErrorWindowTitle": "Окно ошибки", - "ToggleDiscordTooltip": "Включает или отключает отображение в Discord статуса \"Сейчас играет\"", - "AddGameDirBoxTooltip": "Введите папку игры для добавления в список", - "AddGameDirTooltip": "AДобавить папку с игрой в список", + "ToggleDiscordTooltip": "Включает или отключает отображение статуса \"Играет в игру\" в Discord", + "AddGameDirBoxTooltip": "Введите путь к папке с играми для добавления ее в список выше", + "AddGameDirTooltip": "Добавить папку с играми в список", "RemoveGameDirTooltip": "Удалить выбранную папку игры", - "CustomThemeCheckTooltip": "Включить или отключить пользовательские темы в графическом интерфейсе", - "CustomThemePathTooltip": "Путь к пользовательской теме интерфейса", + "CustomThemeCheckTooltip": "Включить или отключить пользовательские темы", + "CustomThemePathTooltip": "Путь к пользовательской теме для интерфейса", "CustomThemeBrowseTooltip": "Просмотр пользовательской темы интерфейса", - "DockModeToggleTooltip": "\"Стационарный\" режим запускает эмулятор, как если бы Nintendo Switch находилась в доке, что улучшает графику и разрешение в большинстве игр. И наоборот, при отключении этого режима эмулятор будет запускать игры в \"Портативном\" режиме, снижая качество графики.\n\nНастройте управление для Игрока 1 если планируете использовать в \"Стационарном\" режиме; настройте портативное управление если планируете использовать эмулятор в \"Портативном\" режиме.\n\nОставьте включенным если не уверены.", - "DirectKeyboardTooltip": "Включить или отключить «поддержку прямого доступа к клавиатуре (HID)» (предоставляет играм доступ к клавиатуре как к устройству ввода текста)", - "DirectMouseTooltip": "Включить или отключить «поддержку прямого доступа к мыши (HID)» (предоставляет играм доступ к вашей мыши как указывающему устройству)", - "RegionTooltip": "Изменение региона системы", - "LanguageTooltip": "Изменение языка системы", - "TimezoneTooltip": "Изменение часового пояса системы", - "TimeTooltip": "Изменение системного времени", - "VSyncToggleTooltip": "Эмуляция вертикальной синхронизации консоли, которая ограничивает количество кадров в секунду в большинстве игр; отключение может привести к тому, что игры будут запущены с более высокой частотой кадров, но загрузка игры может занять больше времени, либо игра не запустится вообще.\n\nМожно включать и выключать эту настройку непосредственно в игре с помощью горячих клавиш. Если планируете отключить вериткальную синхронизацию, мы рекомендуем настроить горячие клавиши.\n\nРекомендуется оставить включенным.", - "PptcToggleTooltip": "Сохранение преобразованных JIT-функций таким образом, чтобы их не нужно преобразовывать по новой каждый раз при загрузке игры.\n\nУменьшает статтеры и значительно ускоряет последующую загрузку игр.\n\nРекомендуется оставить включенным.", - "FsIntegrityToggleTooltip": "Проверяет поврежденные файлы при загрузке игры и если поврежденные файлы обнаружены, отображает ошибку о поврежденном хэше в журнале.\n\nНе влияет на производительность и необходим для содействия в устранении неполадок.\n\nРекомендуется оставить включенным.", - "AudioBackendTooltip": "Изменяет используемый аудио-бэкенд для рендера звука.\n\nSDL2 является предпочтительным, в то время как OpenAL и SoundIO используются в качестве резервных. При выборе \"Заглушки\" звук будет отсутствовать.\n\nРекомендуется использование SDL2.", - "MemoryManagerTooltip": "Изменение разметки и доступа к гостевой памяти. Значительно влияет на производительность процессора.\n\nРекомендуется оставить \"Хост не установлен\"", - "MemoryManagerSoftwareTooltip": "Использует таблицу страниц для преобразования адресов. Самая высокая точность, но самая низкая производительность.", - "MemoryManagerHostTooltip": "Прямая разметка памяти в адресном пространстве хоста. Значительно более быстрая JIT-компиляция и запуск.", - "MemoryManagerUnsafeTooltip": "Производит прямую разметку памяти, но не маскирует адрес в гостевом адресном пространстве перед получением доступа. Быстрее, но менее безопасно. Гостевое приложение может получить доступ к памяти из любой точки Ryujinx, поэтому в этом режиме рекомендуется запускать только те программы, которым вы доверяете.", - "UseHypervisorTooltip": "Использует Гипервизор вместо JIT. Значительно увеличивает производительность, но может быть работать нестабильно.", - "DRamTooltip": "Использует альтернативный макет MemoryMode для имитации использования Nintendo Switch для разработчика.\n\nПолезно только для пакетов текстур с высоким разрешением или модов добавляющих разрешение 4К. Не улучшает производительность.\n\nРекомендуется оставить выключенным.", - "IgnoreMissingServicesTooltip": "Игнорирует нереализованные сервисы Horizon OS. Это поможет избежать вылеты при загрузке определенных игр.\n\nРекомендуется оставить выключенным.", - "GraphicsBackendThreadingTooltip": "Выполняет команды графического бэкенда на втором потоке.\n\nУскоряет компиляцию шейдеров, уменьшает статтеры и повышает производительность на драйверах GPU без поддержки многопоточности. Производительность на драйверах с многопоточностью немного выше.\n\nРекомендуется оставить в Авто.", - "GalThreadingTooltip": "Выполняет команды графического бэкенда на во втором потоке.\n\nУскоряет компиляцию шейдеров, уменьшает статтеры и повышает производительность на драйверах GPU без поддержки многопоточности. Производительность на драйверах с многопоточностью немного выше.\n\nРекомендуется оставить в Авто.", - "ShaderCacheToggleTooltip": "Сохраняет кэш шейдеров на диске, который уменьшает статтеры при последующих запусках.\n\nРекомендуется оставить включенным.", - "ResolutionScaleTooltip": "Масштабирование разрешения", + "DockModeToggleTooltip": "\"Стационарный\" режим запускает эмулятор, как если бы Nintendo Switch находилась в доке, что улучшает графику и разрешение в большинстве игр. И наоборот, при отключении этого режима эмулятор будет запускать игры в \"Портативном\" режиме, снижая качество графики.\n\nНастройте управление для Игрока 1 если планируете использовать в \"Стационарном\" режиме; настройте портативное управление если планируете использовать эмулятор в \"Портативном\" режиме.\n\nРекомендуется оставить включенным.", + "DirectKeyboardTooltip": "Поддержка прямого ввода с клавиатуры (HID). Предоставляет игре прямой доступ к клавиатуре в качестве устройства ввода текста.\nРаботает только с играми, которые изначально поддерживают использование клавиатуры с Switch.\nРекомендуется оставить выключенным.", + "DirectMouseTooltip": "Поддержка прямого ввода мыши (HID). Предоставляет игре прямой доступ к мыши в качестве указывающего устройства.\nРаботает только с играми, которые изначально поддерживают использование мыши совместно с железом Switch.\nРекомендуется оставить выключенным.", + "RegionTooltip": "Сменяет регион прошивки", + "LanguageTooltip": "Меняет язык прошивки", + "TimezoneTooltip": "Меняет часовой пояс прошивки", + "TimeTooltip": "Меняет системное время прошивки", + "VSyncToggleTooltip": "Эмуляция вертикальной синхронизации консоли, которая ограничивает количество кадров в секунду в большинстве игр; отключение может привести к тому, что игры будут запущены с более высокой частотой кадров, но загрузка игры может занять больше времени, либо игра не запустится вообще.\n\nМожно включать и выключать эту настройку непосредственно в игре с помощью горячих клавиш (F1 по умолчанию). Если планируете отключить вертикальную синхронизацию, рекомендуем настроить горячие клавиши.\n\nРекомендуется оставить включенным.", + "PptcToggleTooltip": "Сохраняет скомпилированные JIT-функции для того, чтобы не преобразовывать их по новой каждый раз при запуске игры.\n\nУменьшает статтеры и значительно ускоряет последующую загрузку игр.\n\nРекомендуется оставить включенным.", + "FsIntegrityToggleTooltip": "Проверяет файлы при загрузке игры и если обнаружены поврежденные файлы, выводит сообщение о поврежденном хэше в журнале.\n\nНе влияет на производительность и необходим для помощи в устранении неполадок.\n\nРекомендуется оставить включенным.", + "AudioBackendTooltip": "Изменяет используемый аудио бэкенд для рендера звука.\n\nSDL2 является предпочтительным вариантом, в то время как OpenAL и SoundIO используются в качестве резервных.\n\nРекомендуется использование SDL2.", + "MemoryManagerTooltip": "Меняет разметку и доступ к гостевой памяти. Значительно влияет на производительность процессора.\n\nРекомендуется оставить \"Хост не установлен\"", + "MemoryManagerSoftwareTooltip": "Использует таблицу страниц для преобразования адресов. \nСамая высокая точность, но самая низкая производительность.", + "MemoryManagerHostTooltip": "Прямая разметка памяти в адресном пространстве хоста. \nЗначительно более быстрые запуск и компиляция JIT.", + "MemoryManagerUnsafeTooltip": "Производит прямую разметку памяти, но не маскирует адрес в гостевом адресном пространстве перед получением доступа. \nБыстро, но небезопасно. Гостевое приложение может получить доступ к памяти из Ryujinx, поэтому в этом режиме рекомендуется запускать только те программы, которым вы доверяете.", + "UseHypervisorTooltip": "Использует Hypervisor вместо JIT. Значительно увеличивает производительность, но может работать нестабильно.", + "DRamTooltip": "Использует альтернативный макет MemoryMode для имитации использования Nintendo Switch в режиме разработчика.\n\nПолезно только для пакетов текстур с высоким разрешением или модов добавляющих разрешение 4К. Не улучшает производительность.\n\nРекомендуется оставить выключенным.", + "IgnoreMissingServicesTooltip": "Игнорирует нереализованные сервисы Horizon в новых прошивках. Эта настройка поможет избежать вылеты при запуске определенных игр.\n\nРекомендуется оставить выключенным.", + "GraphicsBackendThreadingTooltip": "Выполняет команды графического бэкенда на втором потоке.\n\nУскоряет компиляцию шейдеров, уменьшает статтеры и повышает производительность на драйверах видеоадаптера без поддержки многопоточности. Производительность на драйверах с многопоточностью немного выше.\n\nРекомендуется оставить Автоматически.", + "GalThreadingTooltip": "Выполняет команды графического бэкенда на втором потоке.\n\nУскоряет компиляцию шейдеров, уменьшает статтеры и повышает производительность на драйверах видеоадаптера без поддержки многопоточности. Производительность на драйверах с многопоточностью немного выше.\n\nРекомендуется оставить Автоматически.", + "ShaderCacheToggleTooltip": "Сохраняет кэш шейдеров на диске, для уменьшения статтеров при последующих запусках.\n\nРекомендуется оставить включенным.", + "ResolutionScaleTooltip": "Увеличивает разрешение рендера игры.\n\nНекоторые игры могут не работать с этой настройкой и выглядеть смазано даже когда разрешение увеличено. Для таких игр может потребоваться установка модов, которые убирают сглаживание или увеличивают разрешение рендеринга. \nДля использования последнего, вам нужно будет выбрать опцию \"Нативное\".\n\nЭта опция может быть изменена во время игры по нажатию кнопки \"Применить\" ниже. Вы можете просто переместить окно настроек в сторону и поэкспериментировать, пока не подберете подходящие настройки для конкретной игры.\n\nИмейте в виду, что \"4x\" является излишеством.", "ResolutionScaleEntryTooltip": "Масштабирование разрешения с плавающей запятой, например 1,5. Неинтегральное масштабирование с большой вероятностью вызовет сбои в работе.", - "AnisotropyTooltip": "Уровень анизотропной фильтрации (установите значение «Авто», чтобы использовать значение в игре по умолчанию)", - "AspectRatioTooltip": "Соотношение сторон, применяемое к окну.", - "ShaderDumpPathTooltip": "Путь дампа графических шейдеров", - "FileLogTooltip": "Включает или отключает ведение журнала в файл на диске. Не влияет на производительность.", + "AnisotropyTooltip": "Уровень анизотропной фильтрации. \n\nУстановите значение Автоматически, чтобы использовать значение по умолчанию игры.", + "AspectRatioTooltip": "Соотношение сторон окна рендерера.\n\nИзмените эту настройку только если вы используете мод для соотношения сторон, иначе изображение будет растянуто.\n\nРекомендуется настройка 16:9.", + "ShaderDumpPathTooltip": "Путь с дампами графических шейдеров", + "FileLogTooltip": "Включает ведение журнала в файл на диске. Не влияет на производительность.", "StubLogTooltip": "Включает ведение журнала-заглушки. Не влияет на производительность.", - "InfoLogTooltip": "Включает печать сообщений информационного журнала. Не влияет на производительность.", - "WarnLogTooltip": "Включает печать сообщений журнала предупреждений. Не влияет на производительность.", - "ErrorLogTooltip": "Включает печать сообщений журнала ошибок. Не влияет на производительность.", + "InfoLogTooltip": "Включает вывод сообщений информационного журнала в консоль. Не влияет на производительность.", + "WarnLogTooltip": "Включает вывод сообщений журнала предупреждений в консоль. Не влияет на производительность.", + "ErrorLogTooltip": "Включает вывод сообщений журнала ошибок. Не влияет на производительность.", "TraceLogTooltip": "Выводит сообщения журнала трассировки в консоли. Не влияет на производительность.", - "GuestLogTooltip": "Включает печать сообщений гостевого журнала. Не влияет на производительность.", - "FileAccessLogTooltip": "Включает печать сообщений журнала доступа к файлам", + "GuestLogTooltip": "Включает вывод сообщений гостевого журнала. Не влияет на производительность.", + "FileAccessLogTooltip": "Включает вывод сообщений журнала доступа к файлам.", "FSAccessLogModeTooltip": "Включает вывод журнала доступа к файловой системе. Возможные режимы: 0-3", "DeveloperOptionTooltip": "Используйте с осторожностью", "OpenGlLogLevel": "Требует включения соответствующих уровней ведения журнала", "DebugLogTooltip": "Выводит журнал сообщений отладки в консоли.\n\nИспользуйте только в случае просьбы разработчика, так как включение этой функции затруднит чтение журналов и ухудшит работу эмулятора.", - "LoadApplicationFileTooltip": "Открыть файловый менеджер для выбора файла, совместимого с Nintendo Switch.", - "LoadApplicationFolderTooltip": "Открыть файловый менеджер для выбора распакованного приложения, совместимого с Nintendo Switch.", - "OpenRyujinxFolderTooltip": "Открывает папку файловой системы Ryujinx. ", - "OpenRyujinxLogsTooltip": "Открывает папку, в которую записываются журналы", + "LoadApplicationFileTooltip": "Открывает файловый менеджер для выбора файла, совместимого с Nintendo Switch.", + "LoadApplicationFolderTooltip": "Открывает файловый менеджер для выбора распакованного приложения, совместимого с Nintendo Switch.", + "OpenRyujinxFolderTooltip": "Открывает папку с файлами Ryujinx. ", + "OpenRyujinxLogsTooltip": "Открывает папку в которую записываются логи", "ExitTooltip": "Выйти из Ryujinx", - "OpenSettingsTooltip": "Открыть окно настроек", - "OpenProfileManagerTooltip": "Открыть диспетчер профилей", + "OpenSettingsTooltip": "Открывает окно параметров", + "OpenProfileManagerTooltip": "Открыть менеджер учетных записей", "StopEmulationTooltip": "Остановка эмуляции текущей игры и возврат к списку игр", - "CheckUpdatesTooltip": "Проверка наличия обновления Ryujinx", - "OpenAboutTooltip": "Открыть окно «О программе»", + "CheckUpdatesTooltip": "Проверяет наличие обновлений для Ryujinx", + "OpenAboutTooltip": "Открывает окно «О программе»", "GridSize": "Размер сетки", - "GridSizeTooltip": "Изменение размера элементов сетки", + "GridSizeTooltip": "Меняет размер сетки элементов", "SettingsTabSystemSystemLanguageBrazilianPortuguese": "Португальский язык (Бразилия)", "AboutRyujinxContributorsButtonHeader": "Посмотреть всех участников", "SettingsTabSystemAudioVolume": "Громкость: ", "AudioVolumeTooltip": "Изменяет громкость звука", - "SettingsTabSystemEnableInternetAccess": "Включить гостевой доступ в Интернет/сетевой режим", + "SettingsTabSystemEnableInternetAccess": "Гостевой доступ в интернет/сетевой режим", "EnableInternetAccessTooltip": "Позволяет эмулированному приложению подключаться к Интернету.\n\nПри включении этой функции игры с возможностью сетевой игры могут подключаться друг к другу, если все эмуляторы (или реальные консоли) подключены к одной и той же точке доступа.\n\nНЕ разрешает подключение к серверам Nintendo. Может вызвать сбой в некоторых играх, которые пытаются подключиться к Интернету.\n\nРекомендутеся оставить выключенным.", - "GameListContextMenuManageCheatToolTip": "Управление читами", + "GameListContextMenuManageCheatToolTip": "Открывает окно управления читами", "GameListContextMenuManageCheat": "Управление читами", + "GameListContextMenuManageModToolTip": "Открывает окно управления модами", + "GameListContextMenuManageMod": "Управление модами", "ControllerSettingsStickRange": "Диапазон:", - "DialogStopEmulationTitle": "Ryujinx - Остановить эмуляцию", + "DialogStopEmulationTitle": "Ryujinx - Остановка эмуляции", "DialogStopEmulationMessage": "Вы уверены, что хотите остановить эмуляцию?", - "SettingsTabCpu": "ЦП", + "SettingsTabCpu": "Процессор", "SettingsTabAudio": "Аудио", "SettingsTabNetwork": "Сеть", "SettingsTabNetworkConnection": "Подключение к сети", - "SettingsTabCpuCache": "Кэш ЦП", - "SettingsTabCpuMemory": "Память ЦП", + "SettingsTabCpuCache": "Кэш процессора", + "SettingsTabCpuMemory": "Режим процессора", "DialogUpdaterFlatpakNotSupportedMessage": "Пожалуйста, обновите Ryujinx через FlatHub.", - "UpdaterDisabledWarningTitle": "Обновление выключено!", - "GameListContextMenuOpenSdModsDirectory": "Открыть папку с модами Atmosphere", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Открывает альтернативную папку SD-карты Atmosphere, которая содержит моды для приложений и игр. Полезно для модов, сделанных для реальной консоли.", + "UpdaterDisabledWarningTitle": "Средство обновления отключено", "ControllerSettingsRotate90": "Повернуть на 90° по часовой стрелке", - "IconSize": "Размер иконки", - "IconSizeTooltip": "Изменить размер игровых иконок", + "IconSize": "Размер обложек", + "IconSizeTooltip": "Меняет размер обложек", "MenuBarOptionsShowConsole": "Показать консоль", "ShaderCachePurgeError": "Ошибка очистки кэша шейдеров в {0}: {1}", "UserErrorNoKeys": "Ключи не найдены", @@ -531,11 +642,11 @@ "UserErrorNoKeysDescription": "Ryujinx не удалось найти ваш 'prod.keys' файл", "UserErrorNoFirmwareDescription": "Ryujinx не удалось найти ни одной установленной прошивки", "UserErrorFirmwareParsingFailedDescription": "Ryujinx не удалось распаковать выбранную прошивку. Обычно это вызвано устаревшими ключами.", - "UserErrorApplicationNotFoundDescription": "Ryujinx не удалось найти действительное приложение по указанному пути.", - "UserErrorUnknownDescription": "Произошла неизвестная ошибка!", - "UserErrorUndefinedDescription": "Произошла неизвестная ошибка! Такого не должно происходить. Пожалуйста, свяжитесь с разработчиками!", + "UserErrorApplicationNotFoundDescription": "Ryujinx не удалось найти валидное приложение по указанному пути.", + "UserErrorUnknownDescription": "Произошла неизвестная ошибка", + "UserErrorUndefinedDescription": "Произошла неизвестная ошибка. Этого не должно происходить, пожалуйста, свяжитесь с разработчиками.", "OpenSetupGuideMessage": "Открыть руководство по установке", - "NoUpdate": "Нет обновлений", + "NoUpdate": "Без обновлений", "TitleUpdateVersionLabel": "Version {0} - {1}", "RyujinxInfo": "Ryujinx - Информация", "RyujinxConfirm": "Ryujinx - Подтверждение", @@ -544,12 +655,13 @@ "SwkbdMinCharacters": "Должно быть не менее {0} символов.", "SwkbdMinRangeCharacters": "Должно быть {0}-{1} символов", "SoftwareKeyboard": "Программная клавиатура", - "SoftwareKeyboardModeNumbersOnly": "Должны быть только цифры", + "SoftwareKeyboardModeNumeric": "Должно быть в диапазоне 0-9 или '.'", "SoftwareKeyboardModeAlphabet": "Не должно быть CJK-символов", "SoftwareKeyboardModeASCII": "Текст должен быть только в ASCII кодировке", - "DialogControllerAppletMessagePlayerRange": "Приложение запрашивает {0} игроков с:\n\nТИПЫ: {1}\n\nИГРОКИ: {2}\n\n{3}Пожалуйста, откройте \"Настройки\" и перенастройте сейчас или нажмите \"Закрыть\".", - "DialogControllerAppletMessage": "Приложение запрашивает ровно {0} игроков с:\n\nТИПЫ: {1}\n\nИГРОКИ: {2}\n\n{3}Пожалуйста, откройте \"Настройки\" и перенастройте Ввод или нажмите \"Закрыть\".", - "DialogControllerAppletDockModeSet": "Установлен стационарный режим. Портативный режим недоступен.", + "ControllerAppletControllers": "Поддерживаемые геймпады:", + "ControllerAppletPlayers": "Игроки:", + "ControllerAppletDescription": "Текущая конфигурация некорректна. Откройте параметры и перенастройте управление.", + "ControllerAppletDocked": "Используется стационарный режим. Управление в портативном режиме должно быть отключено.", "UpdaterRenaming": "Переименование старых файлов...", "UpdaterRenameFailed": "Программе обновления не удалось переименовать файл: {0}", "UpdaterAddingFiles": "Добавление новых файлов...", @@ -558,8 +670,8 @@ "Game": "Игра", "Docked": "Стационарный режим", "Handheld": "Портативный режим", - "ConnectionError": "Ошибка соединения!", - "AboutPageDeveloperListMore": "{0} и больше...", + "ConnectionError": "Ошибка соединения", + "AboutPageDeveloperListMore": "{0} и другие...", "ApiError": "Ошибка API.", "LoadingHeading": "Загрузка {0}", "CompilingPPTC": "Компиляция PTC", @@ -571,11 +683,11 @@ "RyujinxUpdater": "Ryujinx - Обновление", "SettingsTabHotkeys": "Горячие клавиши", "SettingsTabHotkeysHotkeys": "Горячие клавиши", - "SettingsTabHotkeysToggleVsyncHotkey": "Переключить VSync:", - "SettingsTabHotkeysScreenshotHotkey": "Скриншот:", - "SettingsTabHotkeysShowUiHotkey": "Показать UI:", - "SettingsTabHotkeysPauseHotkey": "Пауза:", - "SettingsTabHotkeysToggleMuteHotkey": "Приглушить:", + "SettingsTabHotkeysToggleVsyncHotkey": "Вертикальная синхронизация:", + "SettingsTabHotkeysScreenshotHotkey": "Сделать скриншот:", + "SettingsTabHotkeysShowUiHotkey": "Показать интерфейс:", + "SettingsTabHotkeysPauseHotkey": "Пауза эмуляции:", + "SettingsTabHotkeysToggleMuteHotkey": "Выключить звук:", "ControllerMotionTitle": "Настройки управления движением", "ControllerRumbleTitle": "Настройки вибрации", "SettingsSelectThemeFileDialogTitle": "Выбрать файл темы", @@ -586,71 +698,83 @@ "Usage": "Применение", "Writable": "Доступно для записи", "SelectDlcDialogTitle": "Выберите файлы DLC", - "SelectUpdateDialogTitle": "Выберите файлы обновления", - "UserProfileWindowTitle": "Менеджер профилей пользователей", + "SelectUpdateDialogTitle": "Выберите файлы обновлений", + "SelectModDialogTitle": "Выбрать папку с модами", + "UserProfileWindowTitle": "Менеджер учетных записей", "CheatWindowTitle": "Менеджер читов", - "DlcWindowTitle": "Управление загружаемым контентом для {0} ({1})", - "UpdateWindowTitle": "Менеджер обновления названий", - "CheatWindowHeading": "Читы доступны для {0} [{1}]", + "DlcWindowTitle": "Управление DLC для {0} ({1})", + "ModWindowTitle": "Управление модами для {0} ({1})", + "UpdateWindowTitle": "Менеджер обновлений игр", + "CheatWindowHeading": "Доступные читы для {0} [{1}]", "BuildId": "ID версии:", - "DlcWindowHeading": "{0} Загружаемый контент", + "DlcWindowHeading": "{0} DLC", + "ModWindowHeading": "Моды для {0} ", "UserProfilesEditProfile": "Изменить выбранные", "Cancel": "Отмена", "Save": "Сохранить", "Discard": "Отменить", - "UserProfilesSetProfileImage": "Установить изображение профиля", - "UserProfileEmptyNameError": "Имя обязательно", - "UserProfileNoImageError": "Изображение профиля должно быть установлено", - "GameUpdateWindowHeading": "Обновление доступно для {0} ({1})", + "Paused": "Приостановлено", + "UserProfilesSetProfileImage": "Установить аватар", + "UserProfileEmptyNameError": "Необходимо ввести никнейм", + "UserProfileNoImageError": "Необходимо установить аватар", + "GameUpdateWindowHeading": "Доступные обновления для {0} ({1})", "SettingsTabHotkeysResScaleUpHotkey": "Увеличить разрешение:", "SettingsTabHotkeysResScaleDownHotkey": "Уменьшить разрешение:", - "UserProfilesName": "Имя:", + "UserProfilesName": "Никнейм:", "UserProfilesUserId": "ID пользователя:", - "SettingsTabGraphicsBackend": "Бэкенд графики", - "SettingsTabGraphicsBackendTooltip": "Использовать графический бэкенд", - "SettingsEnableTextureRecompression": "Включить пережатие текстур", - "SettingsEnableTextureRecompressionTooltip": "Сжимает некоторые текстуры для уменьшения использования видеопамяти.\n\nРекомендуется для GPU с 4 гб видеопамяти и менее.\n\nРекомендуется оставить выключенным.", - "SettingsTabGraphicsPreferredGpu": "Предпочтительный GPU", - "SettingsTabGraphicsPreferredGpuTooltip": "Выберите видеокарту, которая будет использоваться с графическим бэкендом Vulkan.\n\nНе влияет на GPU, который будет использовать OpenGL.\n\nУстановите графический процессор, помеченный как \"dGPU\", если вы не уверены. Если его нет, оставьте нетронутым.", + "SettingsTabGraphicsBackend": "Графический бэкенд", + "SettingsTabGraphicsBackendTooltip": "Выберает бэкенд, который будет использован в эмуляторе.\n\nVulkan является лучшим выбором для всех современных графических карт с актуальными драйверами. В Vulkan также включена более быстрая компиляция шейдеров (меньше статтеров) для всех видеоадаптеров.\n\nПри использовании OpenGL можно достичь лучших результатов на старых видеоадаптерах Nvidia и AMD в Linux или на видеоадаптерах с небольшим количеством видеопамяти, хотя статтеров при компиляции шейдеров будет больше.\n\nРекомендуется использовать Vulkan. Используйте OpenGL, если ваш видеоадаптер не поддерживает Vulkan даже с актуальными драйверами.", + "SettingsEnableTextureRecompression": "Пережимать текстуры", + "SettingsEnableTextureRecompressionTooltip": "Сжатие ASTC текстур для уменьшения использования VRAM. \n\nИгры, использующие этот формат текстур: Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder и The Legend of Zelda: Tears of the Kingdom. \nНа видеоадаптерах с 4GiB видеопамяти или менее возможны вылеты при запуске этих игр. \n\nВключите, только если у вас заканчивается видеопамять в вышеупомянутых играх. \n\nРекомендуется оставить выключенным.", + "SettingsTabGraphicsPreferredGpu": "Предпочтительный видеоадаптер", + "SettingsTabGraphicsPreferredGpuTooltip": "Выберает видеоадаптер, который будет использоваться графическим бэкендом Vulkan.\n\nЭта настройка не влияет на видеоадаптер, который будет использоваться с OpenGL.\n\nЕсли вы не уверены что нужно выбрать, используйте графический процессор, помеченный как \"dGPU\". Если его нет, оставьте выбор по умолчанию.", "SettingsAppRequiredRestartMessage": "Требуется перезапуск Ryujinx", "SettingsGpuBackendRestartMessage": "Графический бэкенд или настройки графического процессора были изменены. Требуется перезапуск для вступления в силу изменений.", "SettingsGpuBackendRestartSubMessage": "Перезапустить сейчас?", - "RyujinxUpdaterMessage": "Вы хотите обновить Ryujinx до последней версии?", + "RyujinxUpdaterMessage": "Обновить Ryujinx до последней версии?", "SettingsTabHotkeysVolumeUpHotkey": "Увеличить громкость:", "SettingsTabHotkeysVolumeDownHotkey": "Уменьшить громкость:", - "SettingsEnableMacroHLE": "Включить Macro HLE", - "SettingsEnableMacroHLETooltip": "Высокоуровневая эмуляции макроса GPU.\n\nПовышает производительность, но может вызывать графические сбои в некоторых играх.\n\nРекомендуется оставить включенным.", - "SettingsEnableColorSpacePassthrough": "Пропуск цветового пространства", - "SettingsEnableColorSpacePassthroughTooltip": "Направляет бэкэнд Vulkan на передачу информации о цвете без указания цветового пространства. Для пользователей с экранами с расширенной гаммой данная настройка приводит к получению более ярких цветов за счет снижения корректности цветопередачи.", + "SettingsEnableMacroHLE": "Использовать макрос высокоуровневой эмуляции видеоадаптера", + "SettingsEnableMacroHLETooltip": "Высокоуровневая эмуляции макрокода видеоадаптера.\n\nПовышает производительность, но может вызывать графические артефакты в некоторых играх.\n\nРекомендуется оставить включенным.", + "SettingsEnableColorSpacePassthrough": "Пропускать цветовое пространство", + "SettingsEnableColorSpacePassthroughTooltip": "Направляет бэкенд Vulkan на передачу информации о цвете без указания цветового пространства. Для пользователей с экранами с расширенной гаммой данная настройка приводит к получению более ярких цветов за счет снижения корректности цветопередачи.", "VolumeShort": "Громкость", "UserProfilesManageSaves": "Управление сохранениями", - "DeleteUserSave": "Вы хотите удалить сохранение пользователя для этой игры?", + "DeleteUserSave": "Удалить сохранения для этой игры?", "IrreversibleActionNote": "Данное действие является необратимым.", "SaveManagerHeading": "Редактирование сохранений для {0} ({1})", "SaveManagerTitle": "Менеджер сохранений", "Name": "Название", "Size": "Размер", "Search": "Поиск", - "UserProfilesRecoverLostAccounts": "Восстановить утерянные аккаунты", + "UserProfilesRecoverLostAccounts": "Восстановить учетные записи", "Recover": "Восстановление", "UserProfilesRecoverHeading": "Были найдены сохранения для следующих аккаунтов", - "UserProfilesRecoverEmptyList": "Нет профилей для восстановления", - "GraphicsAATooltip": "Применяет сглаживание к рейдеру игры.", + "UserProfilesRecoverEmptyList": "Нет учетных записей для восстановления", + "GraphicsAATooltip": "Применимое сглаживание для рендера.\n\nFXAA размывает большую часть изображения, SMAA попытается найти \"зазубренные\" края и сгладить их.\n\nНе рекомендуется использовать вместе с масштабирующим фильтром FSR.\n\nЭта опция может быть изменена во время игры по нажатию \"Применить\" ниже; \nВы можете просто переместить окно настроек в сторону и поэкспериментировать, пока не найдёте подходящую настройку игры.\n\nРекомендуется использовать \"Нет\".", "GraphicsAALabel": "Сглаживание:", - "GraphicsScalingFilterLabel": "Масштабирующий фильтр:", - "GraphicsScalingFilterTooltip": "Включает масштабирование кадрового буфера", + "GraphicsScalingFilterLabel": "Интерполяция:", + "GraphicsScalingFilterTooltip": "Фильтрация текстур, которая будет применяться при масштабировании.\n\nБилинейная хорошо работает для 3D-игр и является настройкой по умолчанию.\n\nСтупенчатая рекомендуется для пиксельных игр.\n\nFSR это фильтр резкости, который не рекомендуется использовать с FXAA или SMAA.\n\nЭта опция может быть изменена во время игры по нажатию кнопки \"Применить\" ниже; \nВы можете просто переместить окно настроек в сторону и поэкспериментировать, пока не подберете подходящие настройки для конкретной игры.\n\nРекомендуется использовать \"Билинейная\".", + "GraphicsScalingFilterBilinear": "Билинейная", + "GraphicsScalingFilterNearest": "Ступенчатая", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "Уровень", - "GraphicsScalingFilterLevelTooltip": "Установить уровень фильтра масштабирования", + "GraphicsScalingFilterLevelTooltip": "Выбор режима работы FSR 1.0. Выше - четче.", "SmaaLow": "SMAA Низкое", "SmaaMedium": "SMAA Среднее", "SmaaHigh": "SMAA Высокое", "SmaaUltra": "SMAA Ультра", "UserEditorTitle": "Редактирование пользователя", "UserEditorTitleCreate": "Создание пользователя", - "SettingsTabNetworkInterface": "Сетевой Интерфейс", - "NetworkInterfaceTooltip": "Сетевой интерфейс, используемый для функций LAN", + "SettingsTabNetworkInterface": "Сетевой интерфейс:", + "NetworkInterfaceTooltip": "Сетевой интерфейс, используемый для функций LAN/LDN.\n\nМожет использоваться для игры через интернет в сочетании с VPN или XLink Kai и игрой с поддержкой LAN.\n\nРекомендуется использовать \"По умолчанию\".", "NetworkInterfaceDefault": "По умолчанию", "PackagingShaders": "Упаковка шейдеров", "AboutChangelogButton": "Список изменений на GitHub", - "AboutChangelogButtonTooltipMessage": "Нажмите, чтобы открыть список изменений для этой версии в браузере." -} \ No newline at end of file + "AboutChangelogButtonTooltipMessage": "Нажмите, чтобы открыть список изменений для этой версии", + "SettingsTabNetworkMultiplayer": "Мультиплеер", + "MultiplayerMode": "Режим:", + "MultiplayerModeTooltip": "Меняет многопользовательский режим LDN.\n\nLdnMitm модифицирует функциональность локальной беспроводной/игры на одном устройстве в играх, позволяя играть с другими пользователями Ryujinx или взломанными консолями Nintendo Switch с установленным модулем ldn_mitm, находящимися в одной локальной сети друг с другом.\n\nМногопользовательская игра требует наличия у всех игроков одной и той же версии игры (т.е. Super Smash Bros. Ultimate v13.0.1 не может подключиться к v13.0.0).\n\nРекомендуется оставить отключенным.", + "MultiplayerModeDisabled": "Отключено", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx/Assets/Locales/th_TH.json b/src/Ryujinx/Assets/Locales/th_TH.json new file mode 100644 index 000000000..629442269 --- /dev/null +++ b/src/Ryujinx/Assets/Locales/th_TH.json @@ -0,0 +1,780 @@ +{ + "Language": "ภาษาไทย", + "MenuBarFileOpenApplet": "เปิด Applet", + "MenuBarFileOpenAppletOpenMiiAppletToolTip": "เปิด Mii Editor Applet ในโหมดสแตนด์อโลน", + "SettingsTabInputDirectMouseAccess": "เข้าถึงเมาส์ได้โดยตรง", + "SettingsTabSystemMemoryManagerMode": "โหมดจัดการหน่วยความจำ:", + "SettingsTabSystemMemoryManagerModeSoftware": "ซอฟต์แวร์", + "SettingsTabSystemMemoryManagerModeHost": "โฮสต์ (เร็ว)", + "SettingsTabSystemMemoryManagerModeHostUnchecked": "ไม่ได้ตรวจสอบโฮสต์ (เร็วที่สุด, แต่ไม่ปลอดภัย)", + "SettingsTabSystemUseHypervisor": "ใช้งาน Hypervisor", + "MenuBarFile": "ไฟล์", + "MenuBarFileOpenFromFile": "โหลดแอปพลิเคชั่นจากไฟล์", + "MenuBarFileOpenUnpacked": "โหลดเกมที่คลายแพ็กแล้ว", + "MenuBarFileOpenEmuFolder": "เปิดโฟลเดอร์ Ryujinx", + "MenuBarFileOpenLogsFolder": "เปิดโฟลเดอร์ Logs", + "MenuBarFileExit": "_ออก", + "MenuBarOptions": "_ตัวเลือก", + "MenuBarOptionsToggleFullscreen": "สลับการแสดงผลแบบเต็มหน้าจอ", + "MenuBarOptionsStartGamesInFullscreen": "เริ่มเกมในโหมดเต็มหน้าจอ", + "MenuBarOptionsStopEmulation": "หยุดการจำลอง", + "MenuBarOptionsSettings": "_ตั้งค่า", + "MenuBarOptionsManageUserProfiles": "_จัดการโปรไฟล์ผู้ใช้งาน", + "MenuBarActions": "การดำเนินการ", + "MenuBarOptionsSimulateWakeUpMessage": "จำลองข้อความปลุก", + "MenuBarActionsScanAmiibo": "สแกนหา Amiibo", + "MenuBarTools": "_เครื่องมือ", + "MenuBarToolsInstallFirmware": "ติดตั้งเฟิร์มแวร์", + "MenuBarFileToolsInstallFirmwareFromFile": "ติดตั้งเฟิร์มแวร์จาก ไฟล์ XCI หรือ ไฟล์ ZIP", + "MenuBarFileToolsInstallFirmwareFromDirectory": "ติดตั้งเฟิร์มแวร์จากไดเร็กทอรี", + "MenuBarToolsManageFileTypes": "จัดการประเภทไฟล์", + "MenuBarToolsInstallFileTypes": "ติดตั้งตามประเภทของไฟล์", + "MenuBarToolsUninstallFileTypes": "ถอนการติดตั้งตามประเภทของไฟล์", + "MenuBarView": "_View", + "MenuBarViewWindow": "Window Size", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_ช่วยเหลือ", + "MenuBarHelpCheckForUpdates": "ตรวจสอบอัปเดต", + "MenuBarHelpAbout": "เกี่ยวกับ", + "MenuSearch": "กำลังค้นหา...", + "GameListHeaderFavorite": "ชื่นชอบ", + "GameListHeaderIcon": "ไอคอน", + "GameListHeaderApplication": "ชื่อ", + "GameListHeaderDeveloper": "ผู้พัฒนา", + "GameListHeaderVersion": "เวอร์ชั่น", + "GameListHeaderTimePlayed": "เล่นไปแล้ว", + "GameListHeaderLastPlayed": "เล่นล่าสุด", + "GameListHeaderFileExtension": "นามสกุลไฟล์", + "GameListHeaderFileSize": "ขนาดไฟล์", + "GameListHeaderPath": "ที่อยู่ไฟล์", + "GameListContextMenuOpenUserSaveDirectory": "เปิดไดเร็กทอรี่บันทึกของผู้ใช้", + "GameListContextMenuOpenUserSaveDirectoryToolTip": "เปิดไดเร็กทอรี่ซึ่งมีการบันทึกผู้ใช้ของแอปพลิเคชัน", + "GameListContextMenuOpenDeviceSaveDirectory": "เปิดไดเร็กทอรี่บันทึกของอุปกรณ์", + "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "เปิดไดเรกทอรี่ซึ่งมีบันทึกอุปกรณ์ของแอปพลิเคชัน", + "GameListContextMenuOpenBcatSaveDirectory": "เปิดไดเรกทอรี่บันทึก BCAT", + "GameListContextMenuOpenBcatSaveDirectoryToolTip": "เปิดไดเรกทอรี่ซึ่งมีการบันทึก BCAT ของแอปพลิเคชัน", + "GameListContextMenuManageTitleUpdates": "จัดการอัปเดตตามหัวข้อ", + "GameListContextMenuManageTitleUpdatesToolTip": "เปิดหน้าต่างการจัดการการอัพเดตหัวข้อ", + "GameListContextMenuManageDlc": "จัดการ DLC", + "GameListContextMenuManageDlcToolTip": "เปิดหน้าต่างจัดการ DLC", + "GameListContextMenuCacheManagement": "จัดการ แคช", + "GameListContextMenuCacheManagementPurgePptc": "เพิ่มเข้าคิวงาน PPTC ที่สร้างใหม่", + "GameListContextMenuCacheManagementPurgePptcToolTip": "ทริกเกอร์ PPTC ให้สร้างใหม่ในเวลาบูตเมื่อเปิดตัวเกมครั้งถัดไป", + "GameListContextMenuCacheManagementPurgeShaderCache": "ล้างแคช พื้นผิวและแสงเงา", + "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "ลบแคช พื้นผิวและแสงเงา ของแอปพลิเคชัน", + "GameListContextMenuCacheManagementOpenPptcDirectory": "เปิดไดเรกทอรี่ PPTC", + "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "เปิดไดเร็กทอรี่ PPTC แคช ของแอปพลิเคชัน", + "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "เปิดไดเรกทอรี่ แคช พื้นผิวและแสงเงา", + "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "เปิดไดเรกทอรี่ แคช พื้นผิวและแสงเงา ของแอปพลิเคชัน", + "GameListContextMenuExtractData": "แยกส่วนข้อมูล", + "GameListContextMenuExtractDataExeFS": "ExeFS", + "GameListContextMenuExtractDataExeFSToolTip": "แยกส่วน ExeFS ออกจากการกำหนดค่าปัจจุบันของแอปพลิเคชัน (รวมถึงการอัปเดต)", + "GameListContextMenuExtractDataRomFS": "RomFS", + "GameListContextMenuExtractDataRomFSToolTip": "แยกส่วน RomFS ออกจากการกำหนดค่าปัจจุบันของแอปพลิเคชัน (รวมถึงการอัพเดต)", + "GameListContextMenuExtractDataLogo": "โลโก้", + "GameListContextMenuExtractDataLogoToolTip": "แยกส่วน โลโก้ ออกจากการกำหนดค่าปัจจุบันของแอปพลิเคชัน (รวมถึงการอัปเดต)", + "GameListContextMenuCreateShortcut": "สร้างทางลัดของแอปพลิเคชัน", + "GameListContextMenuCreateShortcutToolTip": "สร้างทางลัดบนเดสก์ท็อปที่เรียกใช้แอปพลิเคชันที่เลือก", + "GameListContextMenuCreateShortcutToolTipMacOS": "สร้างทางลัดในโฟลเดอร์ Applications ของ macOS ที่เรียกใช้ Application ที่เลือก", + "GameListContextMenuOpenModsDirectory": "เปิดไดเร็กทอรี่ Mods", + "GameListContextMenuOpenModsDirectoryToolTip": "เปิดไดเร็กทอรี่ Mods ของแอปพลิเคชัน", + "GameListContextMenuOpenSdModsDirectory": "เปิดไดเร็กทอรี่ Mods Atmosphere", + "GameListContextMenuOpenSdModsDirectoryToolTip": "เปิดไดเร็กทอรี่ Atmosphere ของการ์ด SD สำรองซึ่งมี Mods ของแอปพลิเคชัน มีประโยชน์สำหรับ Mods ที่บรรจุมากับฮาร์ดแวร์จริง", + "StatusBarGamesLoaded": "เกมส์โหลดแล้ว {0}/{1}", + "StatusBarSystemVersion": "เวอร์ชั่นของระบบ: {0}", + "LinuxVmMaxMapCountDialogTitle": "ตรวจพบขีดจำกัดต่ำสุด สำหรับการแมปหน่วยความจำ", + "LinuxVmMaxMapCountDialogTextPrimary": "คุณต้องการที่จะเพิ่มค่า vm.max_map_count ไปยัง {0}", + "LinuxVmMaxMapCountDialogTextSecondary": "บางเกมอาจพยายามสร้างการแมปหน่วยความจำมากกว่าที่ได้รับอนุญาตในปัจจุบัน รียูจินซ์ จะปิดตัวลงเมื่อเกินขีดจำกัดนี้", + "LinuxVmMaxMapCountDialogButtonUntilRestart": "ใช่, จนกว่าจะรีสตาร์ทครั้งถัดไป", + "LinuxVmMaxMapCountDialogButtonPersistent": "ใช่, อย่างถาวร", + "LinuxVmMaxMapCountWarningTextPrimary": "จำนวนสูงสุดของการแม็ปหน่วยความจำ ต่ำกว่าที่แนะนำ", + "LinuxVmMaxMapCountWarningTextSecondary": "ค่าปัจจุบันของ vm.max_map_count ({0}) มีค่าต่ำกว่า {1} บางเกมอาจพยายามสร้างการแมปหน่วยความจำมากกว่าที่ได้รับอนุญาตในปัจจุบัน รียูจินซ์ จะปิดตัวลงเมื่อเกินขีดจำกัดนี้\n\nคุณอาจต้องการเพิ่มขีดจำกัดด้วยตนเองหรือติดตั้ง pkexec ซึ่งอนุญาตให้ ริวจินซ์ เพื่อช่วยเหลือคุณได้", + "Settings": "ตั้งค่า", + "SettingsTabGeneral": "หน้าจอผู้ใช้", + "SettingsTabGeneralGeneral": "ทั่วไป", + "SettingsTabGeneralEnableDiscordRichPresence": "เปิดใช้งาน Discord Rich Presence", + "SettingsTabGeneralCheckUpdatesOnLaunch": "ตรวจหาการอัปเดตเมื่อเปิดโปรแกรม", + "SettingsTabGeneralShowConfirmExitDialog": "แสดง \"ยืนยันการออก\" กล่องข้อความโต้ตอบ", + "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", + "SettingsTabGeneralHideCursor": "ซ่อน เคอร์เซอร์:", + "SettingsTabGeneralHideCursorNever": "ไม่มี", + "SettingsTabGeneralHideCursorOnIdle": "เมื่อไม่ได้ใช้", + "SettingsTabGeneralHideCursorAlways": "ตลอดเวลา", + "SettingsTabGeneralGameDirectories": "ไดเรกทอรี่ของเกม", + "SettingsTabGeneralAdd": "เพิ่ม", + "SettingsTabGeneralRemove": "เอาออก", + "SettingsTabSystem": "ระบบ", + "SettingsTabSystemCore": "แกนกลาง", + "SettingsTabSystemSystemRegion": "ภูมิภาคของระบบ:", + "SettingsTabSystemSystemRegionJapan": "ญี่ปุ่น", + "SettingsTabSystemSystemRegionUSA": "สหรัฐอเมริกา", + "SettingsTabSystemSystemRegionEurope": "ยุโรป", + "SettingsTabSystemSystemRegionAustralia": "ออสเตรเลีย", + "SettingsTabSystemSystemRegionChina": "จีน", + "SettingsTabSystemSystemRegionKorea": "เกาหลี", + "SettingsTabSystemSystemRegionTaiwan": "ไต้หวัน", + "SettingsTabSystemSystemLanguage": "ภาษาของระบบ:", + "SettingsTabSystemSystemLanguageJapanese": "ญี่ปุ่น", + "SettingsTabSystemSystemLanguageAmericanEnglish": "อังกฤษ (อเมริกัน)", + "SettingsTabSystemSystemLanguageFrench": "ฝรั่งเศส", + "SettingsTabSystemSystemLanguageGerman": "เยอรมัน", + "SettingsTabSystemSystemLanguageItalian": "อิตาลี", + "SettingsTabSystemSystemLanguageSpanish": "สเปน", + "SettingsTabSystemSystemLanguageChinese": "จีน", + "SettingsTabSystemSystemLanguageKorean": "เกาหลี", + "SettingsTabSystemSystemLanguageDutch": "ดัตช์", + "SettingsTabSystemSystemLanguagePortuguese": "โปรตุเกส", + "SettingsTabSystemSystemLanguageRussian": "รัสเซีย", + "SettingsTabSystemSystemLanguageTaiwanese": "จีนตัวเต็ม (ไต้หวัน)", + "SettingsTabSystemSystemLanguageBritishEnglish": "อังกฤษ (บริติช)", + "SettingsTabSystemSystemLanguageCanadianFrench": "ฝรั่งเศส (แคนาดา)", + "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "สเปน (ลาตินอเมริกา)", + "SettingsTabSystemSystemLanguageSimplifiedChinese": "จีน (ตัวย่อ)", + "SettingsTabSystemSystemLanguageTraditionalChinese": "จีน (ดั้งเดิม)", + "SettingsTabSystemSystemTimeZone": "เขตเวลาของระบบ:", + "SettingsTabSystemSystemTime": "เวลาของระบบ:", + "SettingsTabSystemEnableVsync": "VSync", + "SettingsTabSystemEnablePptc": "PPTC (แคชโปรไฟล์การแปลแบบถาวร)", + "SettingsTabSystemEnableFsIntegrityChecks": "ตรวจสอบความถูกต้องของ FS", + "SettingsTabSystemAudioBackend": "ระบบเสียงเบื้องหลัง:", + "SettingsTabSystemAudioBackendDummy": "Dummy", + "SettingsTabSystemAudioBackendOpenAL": "OpenAL", + "SettingsTabSystemAudioBackendSoundIO": "SoundIO", + "SettingsTabSystemAudioBackendSDL2": "SDL2", + "SettingsTabSystemHacks": "แฮ็ก", + "SettingsTabSystemHacksNote": "อาจทำให้เกิดข้อผิดพลาดได้", + "SettingsTabSystemExpandDramSize": "ใช้รูปแบบหน่วยความจำสำรอง (โหมดนักพัฒนา)", + "SettingsTabSystemIgnoreMissingServices": "ไม่สนใจบริการที่ขาดหายไป", + "SettingsTabGraphics": "กราฟิก", + "SettingsTabGraphicsAPI": "กราฟฟิก API", + "SettingsTabGraphicsEnableShaderCache": "เปิดใช้งาน แคชพื้นผิวและแสงเงา", + "SettingsTabGraphicsAnisotropicFiltering": "ตัวกรองแบบ Anisotropic:", + "SettingsTabGraphicsAnisotropicFilteringAuto": "อัตโนมัติ", + "SettingsTabGraphicsAnisotropicFiltering2x": "2x", + "SettingsTabGraphicsAnisotropicFiltering4x": "4x", + "SettingsTabGraphicsAnisotropicFiltering8x": "8x", + "SettingsTabGraphicsAnisotropicFiltering16x": "16x", + "SettingsTabGraphicsResolutionScale": "อัตราส่วนความละเอียด:", + "SettingsTabGraphicsResolutionScaleCustom": "กำหนดเอง (ไม่แนะนำ)", + "SettingsTabGraphicsResolutionScaleNative": "พื้นฐานของระบบ (720p/1080p)", + "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", + "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (ไม่แนะนำ)", + "SettingsTabGraphicsAspectRatio": "อัตราส่วนภาพ:", + "SettingsTabGraphicsAspectRatio4x3": "4:3", + "SettingsTabGraphicsAspectRatio16x9": "16:9", + "SettingsTabGraphicsAspectRatio16x10": "16:10", + "SettingsTabGraphicsAspectRatio21x9": "21:9", + "SettingsTabGraphicsAspectRatio32x9": "32:9", + "SettingsTabGraphicsAspectRatioStretch": "ยืดภาพเพื่อให้พอดีกับหน้าต่าง", + "SettingsTabGraphicsDeveloperOptions": "ตัวเลือกนักพัฒนา", + "SettingsTabGraphicsShaderDumpPath": "ที่เก็บ ดัมพ์ไฟล์ พื้นผิวและแสงเงา:", + "SettingsTabLogging": "ประวัติ", + "SettingsTabLoggingLogging": "ประวัติ", + "SettingsTabLoggingEnableLoggingToFile": "เปิดใช้งาน ประวัติ ไปยังไฟล์", + "SettingsTabLoggingEnableStubLogs": "เปิดใช้งาน ประวัติ", + "SettingsTabLoggingEnableInfoLogs": "เปิดใช้งาน ประวัติการใช้งาน", + "SettingsTabLoggingEnableWarningLogs": "เปิดใช้งาน ประวัติคำเตือน", + "SettingsTabLoggingEnableErrorLogs": "เปิดใช้งาน ประวัติข้อผิดพลาด", + "SettingsTabLoggingEnableTraceLogs": "เปิดใช้งาน ประวัติการติดตาม", + "SettingsTabLoggingEnableGuestLogs": "เปิดใช้งาน บันทึกของผู้เยี่ยมชม", + "SettingsTabLoggingEnableFsAccessLogs": "เปิดใช้งาน ประวัติการเข้าถึง Fs", + "SettingsTabLoggingFsGlobalAccessLogMode": "โหมด ประวัติการเข้าถึงส่วนกลาง:", + "SettingsTabLoggingDeveloperOptions": "ตัวเลือกนักพัฒนา", + "SettingsTabLoggingDeveloperOptionsNote": "คำเตือน: จะทำให้ประสิทธิภาพลดลง", + "SettingsTabLoggingGraphicsBackendLogLevel": "ระดับการบันทึกประวัติ กราฟิกเบื้องหลัง:", + "SettingsTabLoggingGraphicsBackendLogLevelNone": "ไม่มี", + "SettingsTabLoggingGraphicsBackendLogLevelError": "ผิดพลาด", + "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "ช้าลง", + "SettingsTabLoggingGraphicsBackendLogLevelAll": "ทั้งหมด", + "SettingsTabLoggingEnableDebugLogs": "เปิดใช้งาน ประวัติแก้ไขข้อบกพร่อง", + "SettingsTabInput": "ป้อนข้อมูล", + "SettingsTabInputEnableDockedMode": "ด็อกโหมด", + "SettingsTabInputDirectKeyboardAccess": "เข้าถึงคีย์บอร์ดโดยตรง", + "SettingsButtonSave": "บันทึก", + "SettingsButtonClose": "ปิด", + "SettingsButtonOk": "ตกลง", + "SettingsButtonCancel": "ยกเลิก", + "SettingsButtonApply": "นำไปใช้", + "ControllerSettingsPlayer": "ผู้เล่น", + "ControllerSettingsPlayer1": "ผู้เล่นคนที่ 1", + "ControllerSettingsPlayer2": "ผู้เล่นคนที่ 2", + "ControllerSettingsPlayer3": "ผู้เล่นคนที่ 3", + "ControllerSettingsPlayer4": "ผู้เล่นคนที่ 4", + "ControllerSettingsPlayer5": "ผู้เล่นคนที่ 5", + "ControllerSettingsPlayer6": "ผู้เล่นคนที่ 6", + "ControllerSettingsPlayer7": "ผู้เล่นคนที่ 7", + "ControllerSettingsPlayer8": "ผู้เล่นคนที่ 8", + "ControllerSettingsHandheld": "แฮนด์เฮลด์โหมด", + "ControllerSettingsInputDevice": "อุปกรณ์ป้อนข้อมูล", + "ControllerSettingsRefresh": "รีเฟรช", + "ControllerSettingsDeviceDisabled": "ปิดการใช้งาน", + "ControllerSettingsControllerType": "ประเภทของคอนโทรลเลอร์", + "ControllerSettingsControllerTypeHandheld": "แฮนด์เฮลด์", + "ControllerSettingsControllerTypeProController": "โปรคอนโทรลเลอร์", + "ControllerSettingsControllerTypeJoyConPair": "จับคู่ จอยคอน", + "ControllerSettingsControllerTypeJoyConLeft": "จอยคอน ด้านซ้าย", + "ControllerSettingsControllerTypeJoyConRight": "จอยคอน ด้านขวา", + "ControllerSettingsProfile": "โปรไฟล์", + "ControllerSettingsProfileDefault": "ค่าเริ่มต้น", + "ControllerSettingsLoad": "โหลด", + "ControllerSettingsAdd": "เพิ่ม", + "ControllerSettingsRemove": "เอาออก", + "ControllerSettingsButtons": "ปุ่มกด", + "ControllerSettingsButtonA": "A", + "ControllerSettingsButtonB": "B", + "ControllerSettingsButtonX": "X", + "ControllerSettingsButtonY": "Y", + "ControllerSettingsButtonPlus": "+", + "ControllerSettingsButtonMinus": "-", + "ControllerSettingsDPad": "ปุ่มลูกศร", + "ControllerSettingsDPadUp": "ขึ้น", + "ControllerSettingsDPadDown": "ลง", + "ControllerSettingsDPadLeft": "ซ้าย", + "ControllerSettingsDPadRight": "ขวา", + "ControllerSettingsStickButton": "ปุ่ม", + "ControllerSettingsStickUp": "ขึ้น", + "ControllerSettingsStickDown": "ลง", + "ControllerSettingsStickLeft": "ซ้าย", + "ControllerSettingsStickRight": "ขวา", + "ControllerSettingsStickStick": "จอยสติ๊ก", + "ControllerSettingsStickInvertXAxis": "กลับทิศทางของแกน X", + "ControllerSettingsStickInvertYAxis": "กลับทิศทางของแกน Y", + "ControllerSettingsStickDeadzone": "โซนที่ไม่ทำงานของ จอยสติ๊ก:", + "ControllerSettingsLStick": "จอยสติ๊ก ด้านซ้าย", + "ControllerSettingsRStick": "จอยสติ๊ก ด้านขวา", + "ControllerSettingsTriggersLeft": "ทริกเกอร์ ด้านซ้าย", + "ControllerSettingsTriggersRight": "ทริกเกอร์ ด้านขวา", + "ControllerSettingsTriggersButtonsLeft": "ปุ่มทริกเกอร์ ด้านซ้าย", + "ControllerSettingsTriggersButtonsRight": "ปุ่มทริกเกอร์ ด้านขวา", + "ControllerSettingsTriggers": "ทริกเกอร์", + "ControllerSettingsTriggerL": "L", + "ControllerSettingsTriggerR": "R", + "ControllerSettingsTriggerZL": "ZL", + "ControllerSettingsTriggerZR": "ZR", + "ControllerSettingsLeftSL": "SL", + "ControllerSettingsLeftSR": "SR", + "ControllerSettingsRightSL": "SL", + "ControllerSettingsRightSR": "SR", + "ControllerSettingsExtraButtonsLeft": "ปุ่มกดเสริม ด้านซ้าย", + "ControllerSettingsExtraButtonsRight": "ปุ่มกดเสริม ด้านขวา", + "ControllerSettingsMisc": "การควบคุมเพิ่มเติม", + "ControllerSettingsTriggerThreshold": "ตั้งค่าขีดจำกัดของ ทริกเกอร์:", + "ControllerSettingsMotion": "การเคลื่อนไหว", + "ControllerSettingsMotionUseCemuhookCompatibleMotion": "ใช้การเคลื่อนไหวที่เข้ากันได้กับ CemuHook", + "ControllerSettingsMotionControllerSlot": "ช่องเสียบ คอนโทรลเลอร์:", + "ControllerSettingsMotionMirrorInput": "นำเข้าการสะท้อน การควบคุม", + "ControllerSettingsMotionRightJoyConSlot": "ช่องเสียบ จอยคอน ด้านขวา:", + "ControllerSettingsMotionServerHost": "เจ้าของเซิร์ฟเวอร์:", + "ControllerSettingsMotionGyroSensitivity": "ความไวของไจโร:", + "ControllerSettingsMotionGyroDeadzone": "ส่วนไม่ทำงานของไจโร:", + "ControllerSettingsSave": "บันทึก", + "ControllerSettingsClose": "ปิด", + "KeyUnknown": "Unknown", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", + "UserProfilesSelectedUserProfile": "โปรไฟล์ผู้ใช้งานที่เลือก:", + "UserProfilesSaveProfileName": "บันทึกชื่อโปรไฟล์", + "UserProfilesChangeProfileImage": "เปลี่ยนรูปโปรไฟล์", + "UserProfilesAvailableUserProfiles": "โปรไฟล์ผู้ใช้ที่ใช้งานได้:", + "UserProfilesAddNewProfile": "สร้างโปรไฟล์ใหม่", + "UserProfilesDelete": "ลบ", + "UserProfilesClose": "ปิด", + "ProfileNameSelectionWatermark": "เลือก ชื่อเล่น", + "ProfileImageSelectionTitle": "เลือก รูปโปรไฟล์ ของคุณ", + "ProfileImageSelectionHeader": "เลือก รูปโปรไฟล์", + "ProfileImageSelectionNote": "คุณสามารถนำเข้ารูปโปรไฟล์ที่กำหนดเอง หรือ เลือกอวาต้าจากเฟิร์มแวร์ระบบได้", + "ProfileImageSelectionImportImage": "นำเข้า ไฟล์รูปภาพ", + "ProfileImageSelectionSelectAvatar": "เลือก รูปอวาต้า เฟิร์มแวร์", + "InputDialogTitle": "กล่องโต้ตอบการป้อนข้อมูล", + "InputDialogOk": "ตกลง", + "InputDialogCancel": "ยกเลิก", + "InputDialogAddNewProfileTitle": "เลือก ชื่อโปรไฟล์", + "InputDialogAddNewProfileHeader": "กรุณาใส่ชื่อโปรไฟล์", + "InputDialogAddNewProfileSubtext": "(ความยาวสูงสุด: {0})", + "AvatarChoose": "เลือก รูปอวาต้า ของคุณ", + "AvatarSetBackgroundColor": "ตั้งค่าสีพื้นหลัง", + "AvatarClose": "ปิด", + "ControllerSettingsLoadProfileToolTip": "โหลด โปรไฟล์", + "ControllerSettingsAddProfileToolTip": "เพิ่ม โปรไฟล์", + "ControllerSettingsRemoveProfileToolTip": "ลบ โปรไฟล์", + "ControllerSettingsSaveProfileToolTip": "บันทึก โปรไฟล์", + "MenuBarFileToolsTakeScreenshot": "ถ่ายภาพหน้าจอ", + "MenuBarFileToolsHideUi": "ซ่อน UI", + "GameListContextMenuRunApplication": "เรียกใช้แอปพลิเคชัน", + "GameListContextMenuToggleFavorite": "สลับรายการโปรด", + "GameListContextMenuToggleFavoriteToolTip": "สลับสถานะเกมที่ชื่นชอบ", + "SettingsTabGeneralTheme": "ธีม:", + "SettingsTabGeneralThemeDark": "มืด", + "SettingsTabGeneralThemeLight": "สว่าง", + "ControllerSettingsConfigureGeneral": "กำหนดค่า", + "ControllerSettingsRumble": "การสั่นไหว", + "ControllerSettingsRumbleStrongMultiplier": "เพิ่มความแรงการสั่นไหว", + "ControllerSettingsRumbleWeakMultiplier": "ลดความแรงการสั่นไหว", + "DialogMessageSaveNotAvailableMessage": "ไม่มีข้อมูลบันทึกไว้สำหรับ {0} [{1:x16}]", + "DialogMessageSaveNotAvailableCreateSaveMessage": "คุณต้องการสร้างข้อมูลบันทึกสำหรับเกมนี้หรือไม่?", + "DialogConfirmationTitle": "ริวจินซ์ - ยืนยัน", + "DialogUpdaterTitle": "รียูจินซ์ - อัพเดต", + "DialogErrorTitle": "รียูจินซ์ - ผิดพลาด", + "DialogWarningTitle": "รียูจินซ์ - คำเตือน", + "DialogExitTitle": "รียูจินซ์ - ออก", + "DialogErrorMessage": "รียูจินซ์ พบข้อผิดพลาด", + "DialogExitMessage": "คุณแน่ใจหรือไม่ว่าต้องการปิด ริวจินซ์ หรือไม่?", + "DialogExitSubMessage": "ข้อมูลที่ไม่ได้บันทึกทั้งหมดจะสูญหาย!", + "DialogMessageCreateSaveErrorMessage": "มีข้อผิดพลาดในการสร้างข้อมูลการบันทึกที่ระบุ: {0}", + "DialogMessageFindSaveErrorMessage": "มีข้อผิดพลาดในการค้นหาข้อมูลที่บันทึกไว้ที่ระบุ: {0}", + "FolderDialogExtractTitle": "เลือกโฟลเดอร์ที่จะแตกไฟล์เข้าไป", + "DialogNcaExtractionMessage": "กำลังแตกไฟล์ {0} จากส่วน {1}...", + "DialogNcaExtractionTitle": "รียูจินซ์ - เครื่องมือแตกไฟล์ของ NCA", + "DialogNcaExtractionMainNcaNotFoundErrorMessage": "เกิดความล้มเหลวในการแตกไฟล์เนื่องจากไม่พบ NCA หลักในไฟล์ที่เลือก", + "DialogNcaExtractionCheckLogErrorMessage": "เกิดความล้มเหลวในการแตกไฟล์ โปรดอ่านไฟล์บันทึกเพื่อดูข้อมูลเพิ่มเติม", + "DialogNcaExtractionSuccessMessage": "การแตกไฟล์เสร็จสมบูรณ์แล้ว", + "DialogUpdaterConvertFailedMessage": "ไม่สามารถแปลงเวอร์ชั่น รียูจินซ์ ปัจจุบันได้", + "DialogUpdaterCancelUpdateMessage": "ยกเลิกการอัพเดต!", + "DialogUpdaterAlreadyOnLatestVersionMessage": "คุณกำลังใช้ รียูจินซ์ เวอร์ชั่นที่อัปเดตล่าสุด!", + "DialogUpdaterFailedToGetVersionMessage": "เกิดข้อผิดพลาดขณะพยายามรับข้อมูลเวอร์ชั่นจาก GitHub Release ปัญหานี้อาจเกิดขึ้นได้หากมีการรวบรวมเวอร์ชั่นใหม่โดย GitHub Actions โปรดลองอีกครั้งในอีกไม่กี่นาทีข้างหน้า", + "DialogUpdaterConvertFailedGithubMessage": "ไม่สามารถแปลงเวอร์ชั่น รียูจินซ์ ที่ได้รับจาก Github Release", + "DialogUpdaterDownloadingMessage": "กำลังดาวน์โหลดอัปเดต...", + "DialogUpdaterExtractionMessage": "กำลังแตกไฟล์อัปเดต...", + "DialogUpdaterRenamingMessage": "กำลังลบไฟล์เก่า...", + "DialogUpdaterAddingFilesMessage": "กำลังเพิ่มไฟล์อัปเดตใหม่...", + "DialogUpdaterCompleteMessage": "อัปเดตเสร็จสมบูรณ์แล้ว!", + "DialogUpdaterRestartMessage": "คุณต้องการรีสตาร์ท รียูจินซ์ ตอนนี้หรือไม่?", + "DialogUpdaterNoInternetMessage": "คุณไม่ได้เชื่อมต่อกับอินเทอร์เน็ต!", + "DialogUpdaterNoInternetSubMessage": "โปรดตรวจสอบว่าคุณมีการเชื่อมต่ออินเทอร์เน็ตว่ามีการใช้งานได้หรือไม่!", + "DialogUpdaterDirtyBuildMessage": "คุณไม่สามารถอัปเดต Dirty build ของ รียูจินซ์ ได้!", + "DialogUpdaterDirtyBuildSubMessage": "โปรดดาวน์โหลด รียูจินซ์ ได้ที่ https://ryujinx.org/ หากคุณกำลังมองหาเวอร์ชั่นที่รองรับ", + "DialogRestartRequiredMessage": "จำเป็นต้องรีสตาร์ทเพื่อให้การอัพเดตสามารถให้งานได้", + "DialogThemeRestartMessage": "บันทึกธีมแล้ว จำเป็นต้องรีสตาร์ทเพื่อใช้ธีม", + "DialogThemeRestartSubMessage": "คุณต้องการรีสตาร์ทหรือไม่?", + "DialogFirmwareInstallEmbeddedMessage": "คุณต้องการติดตั้งเฟิร์มแวร์ที่ฝังอยู่ในเกมนี้หรือไม่? (เฟิร์มแวร์ {0})", + "DialogFirmwareInstallEmbeddedSuccessMessage": "ไม่พบเฟิร์มแวร์ที่ติดตั้งไว้ แต่ รียูจินซ์ สามารถติดตั้งเฟิร์มแวร์ได้ {0} จากเกมที่ให้มา\nตอนนี้โปรแกรมจำลองจะเริ่มทำงาน", + "DialogFirmwareNoFirmwareInstalledMessage": "ไม่มีการติดตั้งเฟิร์มแวร์", + "DialogFirmwareInstalledMessage": "เฟิร์มแวร์ติดตั้งแล้ว {0}", + "DialogInstallFileTypesSuccessMessage": "ติดตั้งตามประเภทของไฟล์สำเร็จแล้ว!", + "DialogInstallFileTypesErrorMessage": "ติดตั้งตามประเภทของไฟล์ไม่สำเร็จ", + "DialogUninstallFileTypesSuccessMessage": "ถอนการติดตั้งตามประเภทของไฟล์สำเร็จแล้ว!", + "DialogUninstallFileTypesErrorMessage": "ไม่สามารถถอนการติดตั้งตามประเภทของไฟล์ได้", + "DialogOpenSettingsWindowLabel": "เปิดหน้าต่างการตั้งค่า", + "DialogControllerAppletTitle": "แอพเพล็ตคอนโทรลเลอร์", + "DialogMessageDialogErrorExceptionMessage": "เกิดข้อผิดพลาดในการแสดงกล่องโต้ตอบข้อความ: {0}", + "DialogSoftwareKeyboardErrorExceptionMessage": "เกิดข้อผิดพลาดในการแสดงซอฟต์แวร์แป้นพิมพ์: {0}", + "DialogErrorAppletErrorExceptionMessage": "เกิดข้อผิดพลาดในการแสดงกล่องโต้ตอบ ข้อผิดพลาด แอปเพล็ต: {0}", + "DialogUserErrorDialogMessage": "{0}: {1}", + "DialogUserErrorDialogInfoMessage": "\nสำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีแก้ไขข้อผิดพลาดนี้ โปรดทำตามคำแนะนำในการตั้งค่าของเรา", + "DialogUserErrorDialogTitle": "ข้อผิดพลาด รียูจินซ์ ({0})", + "DialogAmiiboApiTitle": "อะมิโบ API", + "DialogAmiiboApiFailFetchMessage": "เกิดข้อผิดพลาดขณะเรียกข้อมูลจาก API", + "DialogAmiiboApiConnectErrorMessage": "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ อะมิโบ API บ้างบริการอาจหยุดทำงาน หรือไม่คุณต้องทำการตรวจสอบว่าการเชื่อมต่ออินเทอร์เน็ตของคุณอยู่ในสถานะเชื่อมต่ออยู่หรือไม่", + "DialogProfileInvalidProfileErrorMessage": "โปรไฟล์ {0} เข้ากันไม่ได้กับระบบการกำหนดค่าอินพุตปัจจุบัน", + "DialogProfileDefaultProfileOverwriteErrorMessage": "ไม่สามารถเขียนทับโปรไฟล์เริ่มต้นได้", + "DialogProfileDeleteProfileTitle": "กำลังลบโปรไฟล์", + "DialogProfileDeleteProfileMessage": "การดำเนินการนี้ไม่สามารถย้อนกลับได้ คุณแน่ใจหรือไม่ว่าต้องการดำเนินการต่อหรือไม่?", + "DialogWarning": "คำเตือน", + "DialogPPTCDeletionMessage": "คุณกำลังจะจัดคิวการสร้าง PPTC ใหม่ในการบูตครั้งถัดไป:\n\n{0}\n\nคุณแน่ใจหรือไม่ว่าต้องการดำเนินการต่อหรือไม่?", + "DialogPPTCDeletionErrorMessage": "มีข้อผิดพลาดในการล้างแคช PPTC {0}: {1}", + "DialogShaderDeletionMessage": "คุณกำลังจะลบ เชเดอร์แคช:\n\n{0}\n\nคุณแน่ใจหรือไม่ว่าต้องการดำเนินการต่อหรือไม่?", + "DialogShaderDeletionErrorMessage": "เกิดข้อผิดพลาดในการล้าง เชเดอร์แคช {0}: {1}", + "DialogRyujinxErrorMessage": "รียูจินซ์ พบข้อผิดพลาด", + "DialogInvalidTitleIdErrorMessage": "ข้อผิดพลาดของ UI: เกมที่เลือกไม่มีชื่อ ID ที่ถูกต้อง", + "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "ไม่พบเฟิร์มแวร์ของระบบที่ถูกต้อง {0}.", + "DialogFirmwareInstallerFirmwareInstallTitle": "ติดตั้งเฟิร์มแวร์ {0}", + "DialogFirmwareInstallerFirmwareInstallMessage": "นี่คื่อเวอร์ชั่นของระบบ {0} ที่ได้รับการติดตั้งเมื่อเร็วๆ นี้", + "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nสิ่งนี้จะแทนที่เวอร์ชั่นของระบบปัจจุบัน {0}.", + "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nคุณต้องการดำเนินการต่อหรือไม่?", + "DialogFirmwareInstallerFirmwareInstallWaitMessage": "กำลังติดตั้งเฟิร์มแวร์...", + "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "การติดตั้งเวอร์ชั่นระบบ {0} เรียบร้อยแล้ว", + "DialogUserProfileDeletionWarningMessage": "จะไม่มีโปรไฟล์อื่นให้เปิดหากโปรไฟล์ที่เลือกถูกลบ", + "DialogUserProfileDeletionConfirmMessage": "คุณต้องการลบโปรไฟล์ที่เลือกหรือไม่?", + "DialogUserProfileUnsavedChangesTitle": "คำเตือน - มีการเปลี่ยนแปลงที่ไม่ได้บันทึก", + "DialogUserProfileUnsavedChangesMessage": "คุณได้ทำการเปลี่ยนแปลงโปรไฟล์ผู้ใช้นี้โดยไม่ได้รับการบันทึก", + "DialogUserProfileUnsavedChangesSubMessage": "คุณต้องการยกเลิกการเปลี่ยนแปลงของคุณหรือไม่?", + "DialogControllerSettingsModifiedConfirmMessage": "การตั้งค่าคอนโทรลเลอร์ปัจจุบันได้รับการอัปเดตแล้ว", + "DialogControllerSettingsModifiedConfirmSubMessage": "คุณต้องการบันทึกหรือไม่?", + "DialogLoadFileErrorMessage": "{0} ไฟล์เกิดข้อผิดพลาด: {1}", + "DialogModAlreadyExistsMessage": "มีม็อดอยู่แล้ว", + "DialogModInvalidMessage": "ไดเร็กทอรีที่ระบุไม่มี ม็อดอยู่!", + "DialogModDeleteNoParentMessage": "ไม่สามารถลบ: ไม่พบไดเร็กทอรีหลักสำหรับ ม็อด \"{0}\"!", + "DialogDlcNoDlcErrorMessage": "ไฟล์ที่ระบุไม่มี DLC สำหรับชื่อที่เลือก!", + "DialogPerformanceCheckLoggingEnabledMessage": "คุณได้เปิดใช้งานการบันทึกการติดตาม ซึ่งออกแบบมาเพื่อให้นักพัฒนาใช้เท่านั้น", + "DialogPerformanceCheckLoggingEnabledConfirmMessage": "เพื่อประสิทธิภาพสูงสุด ขอแนะนำให้ปิดใช้งานการบันทึกการติดตาม คุณต้องการปิดใช้การบันทึกการติดตามตอนนี้หรือไม่?", + "DialogPerformanceCheckShaderDumpEnabledMessage": "คุณได้เปิดใช้งาน การดัมพ์เชเดอร์ ซึ่งออกแบบมาเพื่อให้นักพัฒนาใช้งานเท่านั้น", + "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "เพื่อประสิทธิภาพสูงสุด ขอแนะนำให้ปิดใช้การดัมพ์เชเดอร์ คุณต้องการปิดการใช้งานการ ดัมพ์เชเดอร์ ตอนนี้หรือไม่?", + "DialogLoadAppGameAlreadyLoadedMessage": "ทำการโหลดเกมเรียบร้อยแล้ว", + "DialogLoadAppGameAlreadyLoadedSubMessage": "โปรดหยุดการจำลอง หรือปิดโปรแกรมจำลองก่อนที่จะเปิดเกมอื่น", + "DialogUpdateAddUpdateErrorMessage": "ไฟล์ที่ระบุไม่มีการอัพเดตสำหรับชื่อเรื่องที่เลือก!", + "DialogSettingsBackendThreadingWarningTitle": "คำเตือน - การทำเธรดแบ็กเอนด์", + "DialogSettingsBackendThreadingWarningMessage": "รียูจินซ์ ต้องรีสตาร์ทหลังจากเปลี่ยนตัวเลือกนี้จึงจะใช้งานได้อย่างสมบูรณ์ คุณอาจต้องปิดการใช้งาน มัลติเธรด ของไดรเวอร์ของคุณด้วยตนเองเมื่อใช้ รียูจินซ์ ทั้งนี้ขึ้นอยู่กับแพลตฟอร์มของคุณ", + "DialogModManagerDeletionWarningMessage": "คุณกำลังจะลบ ม็อด: {0}\n\nคุณแน่ใจหรือไม่ว่าต้องการดำเนินการต่อ?", + "DialogModManagerDeletionAllWarningMessage": "คุณกำลังจะลบม็อดทั้งหมดสำหรับชื่อนี้\n\nคุณแน่ใจหรือไม่ว่าต้องการดำเนินการต่อ?", + "SettingsTabGraphicsFeaturesOptions": "คุณสมบัติ", + "SettingsTabGraphicsBackendMultithreading": "มัลติเธรด กราฟิกเบื้องหลัง:", + "CommonAuto": "อัตโนมัติ", + "CommonOff": "ปิดการใช้งาน", + "CommonOn": "เปิดใช้งาน", + "InputDialogYes": "ใช่", + "InputDialogNo": "ไม่ใช่", + "DialogProfileInvalidProfileNameErrorMessage": "ชื่อไฟล์ประกอบด้วยอักขระที่ไม่ถูกต้อง กรุณาลองอีกครั้ง", + "MenuBarOptionsPauseEmulation": "หยุดชั่วคราว", + "MenuBarOptionsResumeEmulation": "ดำเนินการต่อ", + "AboutUrlTooltipMessage": "คลิกเพื่อเปิดเว็บไซต์ รียูจินซ์ บนเบราว์เซอร์เริ่มต้นของคุณ", + "AboutDisclaimerMessage": "ทางผู้พัฒนาโปรแกรม รียูจินซ์ ไม่มีส่วนเกี่ยวข้องกับทางบริษัท Nintendo™\nหรือพันธมิตรใดๆ ทั้งสิ้น!", + "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) ถูกใช้\nในการจำลอง อะมิโบ ของเรา", + "AboutPatreonUrlTooltipMessage": "คลิกเพื่อเปิดหน้า เพทรีออน ของ รียูจินซ์ บนเบราว์เซอร์เริ่มต้นของคุณ", + "AboutGithubUrlTooltipMessage": "คลิกเพื่อเปิดหน้า กิตฮับ ของ ริวจินซ์ บนเบราว์เซอร์เริ่มต้นของคุณ", + "AboutDiscordUrlTooltipMessage": "คลิกเพื่อเปิดคำเชิญเข้าสู่เซิร์ฟเวอร์ ดิสคอร์ด ของ รียูจินซ์ บนเบราว์เซอร์เริ่มต้นของคุณ", + "AboutTwitterUrlTooltipMessage": "คลิกเพื่อเปิดหน้าเพจ ทวิตเตอร์ ของ รียูจินซ์ บนเบราว์เซอร์เริ่มต้นของคุณ", + "AboutRyujinxAboutTitle": "เกี่ยวกับ:", + "AboutRyujinxAboutContent": "รียูจินซ์ เป็นอีมูเลเตอร์สำหรับ Nintendo Switch™\nโปรดสนับสนุนเราบน เพทรีออน\nรับข่าวสารล่าสุดทั้งหมดบน ทวิตเตอร์ หรือ ดิสคอร์ด ของเรา\nนักพัฒนาที่สนใจจะมีส่วนร่วมสามารถดูข้อมูลเพิ่มเติมได้ที่ กิตฮับ หรือ ดิสคอร์ด ของเรา", + "AboutRyujinxMaintainersTitle": "ได้รับการดูแลรักษาโดย:", + "AboutRyujinxMaintainersContentTooltipMessage": "คลิกเพื่อเปิดหน้าผู้ร่วมให้ข้อมูลในเบราว์เซอร์เริ่มต้นของคุณ", + "AboutRyujinxSupprtersTitle": "ลายนามผู้สนับสนุนบน เพทรีออน:", + "AmiiboSeriesLabel": "อะมิโบซีรีส์", + "AmiiboCharacterLabel": "ตัวละคร", + "AmiiboScanButtonLabel": "สแกนเลย", + "AmiiboOptionsShowAllLabel": "แสดง อะมิโบ ทั้งหมด", + "AmiiboOptionsUsRandomTagLabel": "แฮ็ค: ใช้แท็กสุ่ม Uuid", + "DlcManagerTableHeadingEnabledLabel": "เปิดใช้งานแล้ว", + "DlcManagerTableHeadingTitleIdLabel": "ชื่อไอดี", + "DlcManagerTableHeadingContainerPathLabel": "ที่เก็บไฟล์ คอนเทนเนอร์", + "DlcManagerTableHeadingFullPathLabel": "ที่เก็บไฟล์แบบเต็ม", + "DlcManagerRemoveAllButton": "ลบทั้งหมด", + "DlcManagerEnableAllButton": "เปิดใช้งานทั้งหมด", + "DlcManagerDisableAllButton": "ปิดใช้งานทั้งหมด", + "ModManagerDeleteAllButton": "ลบทั้งหมด", + "MenuBarOptionsChangeLanguage": "เปลี่ยนภาษา", + "MenuBarShowFileTypes": "แสดงประเภทของไฟล์", + "CommonSort": "เรียงลำดับ", + "CommonShowNames": "แสดงชื่อ", + "CommonFavorite": "สิ่งที่ชื่นชอบ", + "OrderAscending": "จากน้อยไปมาก", + "OrderDescending": "จากมากไปน้อย", + "SettingsTabGraphicsFeatures": "คุณสมบัติ และ การเพิ่มประสิทธิภาพ", + "ErrorWindowTitle": "หน้าต่างแสดงข้อผิดพลาด", + "ToggleDiscordTooltip": "เลือกว่าจะแสดง รียูจินซ์ ในกิจกรรม ดิสคอร์ด \"ที่กำลังเล่นอยู่\" ของคุณหรือไม่?", + "AddGameDirBoxTooltip": "ป้อนไดเรกทอรี่เกมที่จะทำการเพิ่มลงในรายการ", + "AddGameDirTooltip": "เพิ่มไดเรกทอรี่เกมลงในรายการ", + "RemoveGameDirTooltip": "ลบไดเรกทอรี่เกมที่เลือก", + "CustomThemeCheckTooltip": "ใช้ธีม Avalonia แบบกำหนดเองสำหรับ GUI เพื่อเปลี่ยนรูปลักษณ์ของเมนูโปรแกรมจำลอง", + "CustomThemePathTooltip": "ไปยังที่เก็บไฟล์ธีม GUI แบบกำหนดเอง", + "CustomThemeBrowseTooltip": "เรียกดูธีม GUI ที่กำหนดเอง", + "DockModeToggleTooltip": "ด็อกโหมด ทำให้ระบบจำลองการทำงานเสมือน Nintendo ที่กำลังเชื่อมต่ออยู่ด็อก สิ่งนี้จะปรับปรุงความเสถียรภาพของกราฟิกในเกมส่วนใหญ่ ในทางกลับกัน การปิดใช้จะทำให้ระบบจำลองทำงานเหมือนกับ Nintendo Switch แบบพกพา ส่งผลให้คุณภาพกราฟิกลดลง\n\nกำหนดค่าส่วนควบคุมของผู้เล่น 1 หากวางแผนที่จะใช้ด็อกโหมด กำหนดค่าการควบคุมแบบ แฮนด์เฮลด์ หากวางแผนที่จะใช้โหมดแฮนด์เฮลด์\n\nเปิดทิ้งไว้หากคุณไม่แน่ใจ", + "DirectKeyboardTooltip": "รองรับการเข้าถึงแป้นพิมพ์โดยตรง (HID) ให้เกมเข้าถึงคีย์บอร์ดของคุณเป็นอุปกรณ์ป้อนข้อความ\n\nใช้งานได้กับเกมที่รองรับการใช้งานคีย์บอร์ดบนฮาร์ดแวร์ของ Switch เท่านั้น\n\nหากคุณไม่แน่ใจปล่อยให้ปิดอย่างนั้น", + "DirectMouseTooltip": "รองรับการเข้าถึงเมาส์โดยตรง (HID) ให้เกมเข้าถึงเมาส์ของคุณเป็นอุปกรณ์ชี้ตำแหน่ง\n\nใช้งานได้เฉพาะกับเกมที่รองรับการควบคุมเมาส์บนฮาร์ดแวร์ของ Switch เท่านั้น ซึ่งมีอยู่ไม่มากนัก\n\nเมื่อเปิดใช้งาน ฟังก์ชั่นหน้าจอสัมผัสอาจไม่ทำงาน\n\nหากคุณไม่แน่ใจปล่อยให้ปิดอย่างนั้น", + "RegionTooltip": "เปลี่ยนภูมิภาคของระบบ", + "LanguageTooltip": "เปลี่ยนภาษาของระบบ", + "TimezoneTooltip": "เปลี่ยนโซนเวลาของระบบ", + "TimeTooltip": "เปลี่ยนเวลาของระบบ", + "VSyncToggleTooltip": "Vertical Sync ของคอนโซลจำลอง โดยพื้นฐานแล้วเป็นตัวจำกัดเฟรมสำหรับเกมส่วนใหญ่ การปิดใช้งานอาจทำให้เกมทำงานด้วยความเร็วสูงขึ้น หรือทำให้หน้าจอการโหลดใช้เวลานานขึ้นหรือค้าง\n\nสามารถสลับได้ในเกมด้วยปุ่มลัดตามที่คุณต้องการ (F1 เป็นค่าเริ่มต้น) เราขอแนะนำให้ทำเช่นนี้หากคุณวางแผนที่จะปิดการใช้งาน\n\nหากคุณไม่แน่ใจให้ปล่อยไว้อย่างนั้น", + "PptcToggleTooltip": "บันทึกฟังก์ชั่น JIT ที่แปลแล้ว ดังนั้นจึงไม่จำเป็นต้องแปลทุกครั้งที่โหลดเกม\n\nลดอาการกระตุกและเร่งความเร็วการบูตได้อย่างมากหลังจากการบูตครั้งแรกของเกม\n\nปล่อยไว้หากคุณไม่แน่ใจ", + "FsIntegrityToggleTooltip": "ตรวจสอบไฟล์ที่เสียหายเมื่อบูตเกม และหากตรวจพบไฟล์ที่เสียหาย จะแสดงข้อผิดพลาดของแฮชในบันทึก\n\nไม่มีผลกระทบต่อประสิทธิภาพการทำงานและมีไว้เพื่อช่วยในการแก้ไขปัญหา\n\nปล่อยไว้หากคุณไม่แน่ใจ", + "AudioBackendTooltip": "เปลี่ยนแบ็กเอนด์ที่ใช้ในการเรนเดอร์เสียง\n\nSDL2 เป็นที่ต้องการ ในขณะที่ OpenAL และ SoundIO ถูกใช้เป็นทางเลือกสำรอง ดัมมี่จะไม่มีเสียง\n\nปล่อยไว้หากคุณไม่แน่ใจ", + "MemoryManagerTooltip": "เปลี่ยนวิธีการแมปและเข้าถึงหน่วยความจำของผู้เยี่ยมชม ส่งผลอย่างมากต่อประสิทธิภาพการทำงานของ CPU ที่จำลอง\n\nตั้งค่าเป็น ไม่ทำการตรวจสอบ โฮสต์ หากคุณไม่แน่ใจ", + "MemoryManagerSoftwareTooltip": "ใช้ตารางหน้าซอฟต์แวร์สำหรับการแปลที่อยู่ ความแม่นยำสูงสุดแต่ประสิทธิภาพช้าที่สุด", + "MemoryManagerHostTooltip": "แมปหน่วยความจำในพื้นที่ที่อยู่โฮสต์โดยตรง การคอมไพล์และดำเนินการ JIT เร็วขึ้นมาก", + "MemoryManagerUnsafeTooltip": "แมปหน่วยความจำโดยตรง แต่อย่าปิดบังที่อยู่ภายในพื้นที่ที่อยู่ของผู้เยี่ยมชมก่อนที่จะเข้าถึง เร็วกว่า แต่ต้องแลกกับความปลอดภัย แอปพลิเคชั่นผู้เยี่ยมชมสามารถเข้าถึงหน่วยความจำได้จากทุกที่ใน รียูจินซ์ ดังนั้นให้รันเฉพาะโปรแกรมที่คุณเชื่อถือในโหมดนี้", + "UseHypervisorTooltip": "ใช้ Hypervisor แทน JIT ปรับปรุงประสิทธิภาพอย่างมากเมื่อพร้อมใช้งาน แต่อาจไม่เสถียรในสถานะปัจจุบัน", + "DRamTooltip": "ใช้เค้าโครง MemoryMode ทางเลือกเพื่อเลียนแบบโมเดลการพัฒนาสวิตช์\n\nสิ่งนี้มีประโยชน์สำหรับแพ็กพื้นผิวที่มีความละเอียดสูงกว่าหรือม็อดที่มีความละเอียด 4k เท่านั้น ไม่ปรับปรุงประสิทธิภาพ\n\nปล่อยให้ปิดหากคุณไม่แน่ใจ", + "IgnoreMissingServicesTooltip": "ละเว้นบริการ Horizon OS ที่ยังไม่ได้ใช้งาน วิธีนี้อาจช่วยในการหลีกเลี่ยงข้อผิดพลาดเมื่อบู๊ตเกมบางเกม\n\nปล่อยให้ปิดหากคุณไม่แน่ใจ", + "GraphicsBackendThreadingTooltip": "ดำเนินการคำสั่งแบ็กเอนด์กราฟิกบนเธรดที่สอง\n\nเร่งความเร็วการคอมไพล์เชเดอร์ ลดการกระตุก และปรับปรุงประสิทธิภาพการทำงานของไดรเวอร์ GPU โดยไม่ต้องรองรับมัลติเธรดในตัว ประสิทธิภาพที่ดีขึ้นเล็กน้อยสำหรับไดรเวอร์ที่มีมัลติเธรด\n\nตั้งเป็น อัตโนมัติ หากคุณไม่แน่ใจ", + "GalThreadingTooltip": "ดำเนินการคำสั่งแบ็กเอนด์กราฟิกบนเธรดที่สอง\n\nเร่งความเร็วการคอมไพล์เชเดอร์ ลดการกระตุก และปรับปรุงประสิทธิภาพการทำงานของไดรเวอร์ GPU โดยไม่ต้องรองรับมัลติเธรดในตัว ประสิทธิภาพที่ดีขึ้นเล็กน้อยสำหรับไดรเวอร์ที่มีมัลติเธรด\n\nตั้งเป็น อัตโนมัติ หากคุณไม่แน่ใจ", + "ShaderCacheToggleTooltip": "บันทึกแคชเชเดอร์ของดิสก์ซึ่งช่วยลดการกระตุกในการรันครั้งต่อๆ ไป\n\nปล่อยไว้หากคุณไม่แน่ใจ", + "ResolutionScaleTooltip": "คูณความละเอียดการเรนเดอร์ของเกม\n\nเกมบางเกมอาจไม่สามารถใช้งานได้และดูเป็นพิกเซลแม้ว่าความละเอียดจะเพิ่มขึ้นก็ตาม สำหรับเกมเหล่านั้น คุณอาจต้องค้นหาม็อดที่ลบรอยหยักของภาพหรือเพิ่มความละเอียดในการเรนเดอร์ภายใน หากต้องการใช้อย่างหลัง คุณอาจต้องเลือก Native\n\nตัวเลือกนี้สามารถเปลี่ยนแปลงได้ในขณะที่เกมกำลังทำงานอยู่โดยคลิก \"นำมาใช้\" ด้านล่าง คุณสามารถย้ายหน้าต่างการตั้งค่าไปด้านข้างและทดลองจนกว่าคุณจะพบรูปลักษณ์ที่คุณต้องการสำหรับเกม\n\nโปรดทราบว่า 4x นั้นเกินความจำเป็นสำหรับการตั้งค่าแทบทุกประเภท", + "ResolutionScaleEntryTooltip": "สเกลความละเอียดจุดทศนิยม เช่น 1.5 ไม่ใช่จำนวนเต็มของสเกล มีแนวโน้มที่จะก่อให้เกิดปัญหาหรือความผิดพลาดได้", + "AnisotropyTooltip": "ระดับของการกรองแบบ Anisotropic ตั้งค่าเป็นอัตโนมัติเพื่อใช้ค่าที่เกมร้องขอ", + "AspectRatioTooltip": "อัตราส่วนภาพที่ใช้กับหน้าต่างตัวแสดงภาพ\n\nเปลี่ยนสิ่งนี้หากคุณใช้ตัวดัดแปลงอัตราส่วนกว้างยาวสำหรับเกมของคุณ ไม่เช่นนั้นกราฟิกจะถูกยืดออก\n\nทิ้งไว้ที่ 16:9 หากไม่แน่ใจ", + "ShaderDumpPathTooltip": "ที่เก็บ ดัมพ์ไฟล์ พื้นผิวและแสงเงา", + "FileLogTooltip": "บันทึก ประวัติคอนโซลลงในไฟล์บันทึกบนดิสก์ จะไม่ส่งผลกระทบต่อประสิทธิภาพการทำงาน", + "StubLogTooltip": "พิมพ์ข้อความประวัติในคอนโซล จะไม่ส่งผลกระทบต่อประสิทธิภาพการทำงาน", + "InfoLogTooltip": "พิมพ์ข้อความบันทึกข้อมูลในคอนโซล จะไม่ส่งผลกระทบต่อประสิทธิภาพการทำงาน", + "WarnLogTooltip": "พิมพ์ข้อความประวัติแจ้งตือนในคอนโซล จะไม่ส่งผลกระทบต่อประสิทธิภาพการทำงาน", + "ErrorLogTooltip": "พิมพ์ข้อความบันทึกข้อผิดพลาดในคอนโซล จะไม่ส่งผลกระทบต่อประสิทธิภาพการทำงาน", + "TraceLogTooltip": "พิมพ์ข้อความประวัติการติดตามในคอนโซล ไม่ส่งผลกระทบต่อประสิทธิภาพการทำงาน", + "GuestLogTooltip": "พิมพ์ข้อความประวัติของผู้เยี่ยมชมในคอนโซล ไม่ส่งผลกระทบต่อประสิทธิภาพการทำงาน", + "FileAccessLogTooltip": "พิมพ์ข้อความบันทึกการเข้าถึงไฟล์ในคอนโซล", + "FSAccessLogModeTooltip": "เปิดใช้งาน เอาต์พุตประวัติการเข้าถึง FS ไปยังคอนโซล โหมดที่เป็นไปได้คือ 0-3", + "DeveloperOptionTooltip": "โปรดใช้ด้วยความระมัดระวัง", + "OpenGlLogLevel": "จำเป็นต้องเปิดใช้งานระดับบันทึกที่เหมาะสม", + "DebugLogTooltip": "พิมพ์ข้อความประวัติการแก้ไขข้อบกพร่องในคอนโซล\n\nใช้สิ่งนี้เฉพาะเมื่อได้รับคำแนะนำจากเจ้าหน้าที่โดยเฉพาะเท่านั้น เนื่องจากจะทำให้บันทึกอ่านยากและทำให้ประสิทธิภาพของโปรแกรมจำลองแย่ลง", + "LoadApplicationFileTooltip": "เปิด File Explorer เพื่อเลือกไฟล์ที่เข้ากันได้กับ Switch ที่จะโหลด", + "LoadApplicationFolderTooltip": "เปิดตัวสำรวจไฟล์เพื่อเลือกไฟล์ที่เข้ากันได้กับ Switch ที่จะโหลด", + "OpenRyujinxFolderTooltip": "เปิดโฟลเดอร์ระบบไฟล์ Ryujinx", + "OpenRyujinxLogsTooltip": "เปิดโฟลเดอร์ ที่เก็บไฟล์ประวัติ", + "ExitTooltip": "ออกจากโปรแกรม รียูจินซ์", + "OpenSettingsTooltip": "เปิดหน้าต่างการตั้งค่า", + "OpenProfileManagerTooltip": "เปิดหน้าต่างตัวจัดการโปรไฟล์ผู้ใช้", + "StopEmulationTooltip": "หยุดการจำลองของเกมที่เปิดอยู่ในปัจจุบันและกลับไปยังการเลือกเกม", + "CheckUpdatesTooltip": "ตรวจสอบการอัปเดตของ รียูจินซ์", + "OpenAboutTooltip": "เปิดหน้าต่าง เกี่ยวกับ", + "GridSize": "ขนาดตาราง", + "GridSizeTooltip": "เปลี่ยนขนาด ของตาราง", + "SettingsTabSystemSystemLanguageBrazilianPortuguese": "บราซิล โปรตุเกส", + "AboutRyujinxContributorsButtonHeader": "ดูผู้มีส่วนร่วมทั้งหมด", + "SettingsTabSystemAudioVolume": "ระดับเสียง: ", + "AudioVolumeTooltip": "ปรับระดับเสียง", + "SettingsTabSystemEnableInternetAccess": "การเข้าถึงอินเทอร์เน็ตของผู้เยี่ยมชม/โหมด LAN", + "EnableInternetAccessTooltip": "อนุญาตให้แอปพลิเคชันจำลองเชื่อมต่ออินเทอร์เน็ต\n\nเกมที่มีโหมด LAN สามารถเชื่อมต่อระหว่างกันได้เมื่อเปิดใช้งานและระบบเชื่อมต่อกับจุดเชื่อมต่อเดียวกัน รวมถึงคอนโซลจริงด้วย\n\nไม่อนุญาตให้มีการเชื่อมต่อกับเซิร์ฟเวอร์ Nintendo อาจทำให้เกิดการหยุดทำงานในบางเกมที่พยายามเชื่อมต่ออินเทอร์เน็ต\n\nปล่อยให้ปิดหากคุณไม่แน่ใจ", + "GameListContextMenuManageCheatToolTip": "ฟังชั่นจัดการสูตรโกง", + "GameListContextMenuManageCheat": "จัดการสูตรโกง", + "GameListContextMenuManageModToolTip": "จัดการ ม็อด", + "GameListContextMenuManageMod": "จัดการ ม็อด", + "ControllerSettingsStickRange": "ขอบเขต:", + "DialogStopEmulationTitle": "รียูจินซ์ - หยุดการจำลอง", + "DialogStopEmulationMessage": "คุณแน่ใจหรือไม่ว่าต้องการหยุดการจำลองหรือไม่?", + "SettingsTabCpu": "หน่วยประมวลผลกลาง", + "SettingsTabAudio": "เสียง", + "SettingsTabNetwork": "เครือข่าย", + "SettingsTabNetworkConnection": "การเชื่อมต่อเครือข่าย", + "SettingsTabCpuCache": "ซีพียู แคช", + "SettingsTabCpuMemory": "โหมดซีพียู", + "DialogUpdaterFlatpakNotSupportedMessage": "โปรดอัปเดต รียูจินซ์ ผ่านช่องทาง FlatHub", + "UpdaterDisabledWarningTitle": "ปิดใช้งานการอัปเดตแล้ว!", + "ControllerSettingsRotate90": "หมุน 90 องศา ตามเข็มนาฬิกา", + "IconSize": "ขนาดไอคอน", + "IconSizeTooltip": "เปลี่ยนขนาดของไอคอนเกม", + "MenuBarOptionsShowConsole": "แสดง คอนโซล", + "ShaderCachePurgeError": "เกิดข้อผิดพลาดในการล้างแคชเชเดอร์ {0}: {1}", + "UserErrorNoKeys": "ไม่พบ คีย์", + "UserErrorNoFirmware": "ไม่พบ เฟิร์มแวร์", + "UserErrorFirmwareParsingFailed": "เกิดข้อผิดพลาดในการวิเคราะห์เฟิร์มแวร์", + "UserErrorApplicationNotFound": "ไม่พบ แอปพลิเคชัน", + "UserErrorUnknown": "ข้อผิดพลาดที่ไม่รู้จัก", + "UserErrorUndefined": "ข้อผิดพลาดที่ไม่ได้ระบุ", + "UserErrorNoKeysDescription": "รียูจินซ์ ไม่พบไฟล์ 'prod.keys' ในเครื่องของคุณ", + "UserErrorNoFirmwareDescription": "รียูจินซ์ ไม่พบ เฟิร์มแวร์ที่ติดตั้งไว้ในเครื่องของคุณ", + "UserErrorFirmwareParsingFailedDescription": "รียูจินซ์ ไม่สามารถวิเคราะห์เฟิร์มแวร์ที่ให้มาได้ ซึ่งมักมีสาเหตุมาจากคีย์ที่ล้าสมัย", + "UserErrorApplicationNotFoundDescription": "รียูจินซ์ ไม่พบแอปพลิเคชันที่ถูกต้องในที่เก็บไฟล์ที่กำหนด", + "UserErrorUnknownDescription": "เกิดข้อผิดพลาดที่ไม่รู้จัก!", + "UserErrorUndefinedDescription": "เกิดข้อผิดพลาดที่ไม่สามารถระบุได้! สิ่งนี้ไม่ควรเกิดขึ้น โปรดติดต่อผู้พัฒนา!", + "OpenSetupGuideMessage": "เปิดคู่มือการตั้งค่า", + "NoUpdate": "ไม่มีการอัปเดต", + "TitleUpdateVersionLabel": "เวอร์ชั่น {0}", + "RyujinxInfo": "รียูจินซ์ – ข้อมูล", + "RyujinxConfirm": "รียูจินซ์ - ยืนยัน", + "FileDialogAllTypes": "ทุกประเภท", + "Never": "ไม่มี", + "SwkbdMinCharacters": "ต้องมีความยาวของตัวอักษรอย่างน้อย {0} ตัว", + "SwkbdMinRangeCharacters": "ต้องมีความยาวของตัวอักษร {0}-{1} ตัว", + "SoftwareKeyboard": "ซอฟต์แวร์ ของคีย์บอร์ด", + "SoftwareKeyboardModeNumeric": "ต้องเป็น 0-9 หรือ '.' เท่านั้น", + "SoftwareKeyboardModeAlphabet": "ต้องเป็นตัวอักษรที่ไม่ใช่ CJK เท่านั้น", + "SoftwareKeyboardModeASCII": "ต้องเป็นตัวอักษร ASCII เท่านั้น", + "ControllerAppletControllers": "คอนโทรลเลอร์ที่รองรับ:", + "ControllerAppletPlayers": "ผู้เล่น:", + "ControllerAppletDescription": "การกำหนดค่าปัจจุบันของคุณไม่ถูกต้อง เปิดการตั้งค่าและกำหนดค่าอินพุตของคุณใหม่", + "ControllerAppletDocked": "ตั้งค่าด็อกโหมด ควรปิดใช้งานการควบคุมแบบแฮนด์เฮลด์", + "UpdaterRenaming": "กำลังเปลี่ยนชื่อไฟล์เก่า...", + "UpdaterRenameFailed": "โปรแกรมอัปเดตไม่สามารถเปลี่ยนชื่อไฟล์ได้: {0}", + "UpdaterAddingFiles": "กำลังเพิ่มไฟล์ใหม่...", + "UpdaterExtracting": "กำลังแยกการอัปเดต...", + "UpdaterDownloading": "กำลังดาวน์โหลดอัปเดต...", + "Game": "เกมส์", + "Docked": "ด็อก", + "Handheld": "แฮนด์เฮลด์", + "ConnectionError": "การเชื่อมต่อล้มเหลว", + "AboutPageDeveloperListMore": "{0} และอื่นๆ ...", + "ApiError": "ข้อผิดพลาดของ API", + "LoadingHeading": "กำลังโหลด {0}", + "CompilingPPTC": "กำลังคอมไพล์ PTC", + "CompilingShaders": "กำลังคอมไพล์ พื้นผิวและแสงเงา", + "AllKeyboards": "คีย์บอร์ดทั้งหมด", + "OpenFileDialogTitle": "เลือกไฟล์ที่สนับสนุนเพื่อเปิด", + "OpenFolderDialogTitle": "เลือกโฟลเดอร์ที่มีเกมที่แตกไฟล์แล้ว", + "AllSupportedFormats": "รูปแบบที่รองรับทั้งหมด", + "RyujinxUpdater": "อัปเดต รียูจินซ์", + "SettingsTabHotkeys": "ปุ่มลัดของคีย์บอร์ด", + "SettingsTabHotkeysHotkeys": "ปุ่มลัดของคีย์บอร์ด", + "SettingsTabHotkeysToggleVsyncHotkey": "สลับเป็น VSync:", + "SettingsTabHotkeysScreenshotHotkey": "ภาพหน้าจอ:", + "SettingsTabHotkeysShowUiHotkey": "แสดง UI:", + "SettingsTabHotkeysPauseHotkey": "หยุดชั่วคราว:", + "SettingsTabHotkeysToggleMuteHotkey": "ปิดเสียง:", + "ControllerMotionTitle": "ตั้งค่าควบคุมการเคลื่อนไหว", + "ControllerRumbleTitle": "ตั้งค่าการสั่นไหว", + "SettingsSelectThemeFileDialogTitle": "เลือกไฟล์ธีม", + "SettingsXamlThemeFile": "ไฟล์ธีมรูปแบบ XAML", + "AvatarWindowTitle": "จัดการบัญชี - อวาต้า", + "Amiibo": "อะมิโบ", + "Unknown": "ไม่รู้จัก", + "Usage": "การใช้งาน", + "Writable": "สามารถเขียนได้", + "SelectDlcDialogTitle": "เลือกไฟล์ DLC", + "SelectUpdateDialogTitle": "เลือกไฟล์อัพเดต", + "SelectModDialogTitle": "เลือกไดเรกทอรี Mods", + "UserProfileWindowTitle": "จัดการโปรไฟล์ผู้ใช้", + "CheatWindowTitle": "จัดการสูตรโกง", + "DlcWindowTitle": "จัดการเนื้อหาที่ดาวน์โหลดได้สำหรับ {0} ({1})", + "ModWindowTitle": "Manage Mods for {0} ({1})", + "UpdateWindowTitle": "จัดการอัปเดตหัวข้อ", + "CheatWindowHeading": "สูตรโกงมีให้สำหรับ {0} [{1}]", + "BuildId": "รหัสบิวด์:", + "DlcWindowHeading": "{0} เนื้อหาที่สามารถดาวน์โหลดได้", + "ModWindowHeading": "{0} ม็อด", + "UserProfilesEditProfile": "แก้ไขที่เลือกแล้ว", + "Cancel": "ยกเลิก", + "Save": "บันทึก", + "Discard": "ละทิ้ง", + "Paused": "หยุดชั่วคราว", + "UserProfilesSetProfileImage": "ตั้งค่ารูปโปรไฟล์", + "UserProfileEmptyNameError": "จำเป็นต้องระบุชื่อ", + "UserProfileNoImageError": "จำเป็นต้องตั้งค่ารูปโปรไฟล์", + "GameUpdateWindowHeading": "จัดการอัพเดตสำหรับ {0} ({1})", + "SettingsTabHotkeysResScaleUpHotkey": "เพิ่มความละเอียด:", + "SettingsTabHotkeysResScaleDownHotkey": "ลดความละเอียด:", + "UserProfilesName": "ชื่อ:", + "UserProfilesUserId": "รหัสผู้ใช้:", + "SettingsTabGraphicsBackend": "กราฟิกเบื้องหลัง", + "SettingsTabGraphicsBackendTooltip": "เลือกกราฟิกเบื้องหลังที่จะใช้ในโปรแกรมจำลอง\n\nโดยรวมแล้ว Vulkan นั้นดีกว่าสำหรับกราฟิกการ์ดรุ่นใหม่ทั้งหมด ตราบใดที่ไดรเวอร์ยังอัพเดทอยู่เสมอ Vulkan ยังมีคุณสมบัติการคอมไพล์เชเดอร์ที่เร็วขึ้น (ลดอาการกระตุก) ของผู้จำหน่าย GPU ทุกราย\n\nOpenGL อาจได้รับผลลัพธ์ที่ดีกว่าบน Nvidia GPU รุ่นเก่า, AMD GPU รุ่นเก่าบน Linux หรือบน GPU ที่มี VRAM ต่ำกว่า แม้ว่าการคอมไพล์เชเดอร์ จะทำให้อาการกระตุกมากขึ้นก็ตาม\n\nตั้งค่าเป็น Vulkan หากไม่แน่ใจ ตั้งค่าเป็น OpenGL หาก GPU ของคุณไม่รองรับ Vulkan แม้จะมีไดรเวอร์กราฟิกล่าสุดก็ตาม", + "SettingsEnableTextureRecompression": "เปิดใช้งาน การบีบอัดพื้นผิวอีกครั้ง", + "SettingsEnableTextureRecompressionTooltip": "บีบอัดพื้นผิว ASTC เพื่อลดการใช้งาน VRAM\n\nเกมที่ใช้รูปแบบพื้นผิวนี้ ได้แก่ Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder และ The Legend of Zelda: Tears of the Kingdom\n\nกราฟิกการ์ดที่มี 4 กิกะไบต์ VRAM หรือน้อยกว่ามีแนวโน้มที่จะให้แคชในบางจุดขณะเล่นเกมเหล่านี้\n\nเปิดใช้งานเฉพาะในกรณีที่ VRAM ของคุณใกล้หมดในเกมที่กล่าวมาข้างต้น ปล่อยให้ปิดหากไม่แน่ใจ", + "SettingsTabGraphicsPreferredGpu": "GPU ที่ต้องการ", + "SettingsTabGraphicsPreferredGpuTooltip": "เลือกกราฟิกการ์ดที่จะใช้กับแบ็กเอนด์กราฟิก Vulkan\n\nไม่ส่งผลต่อ GPU ที่ OpenGL จะใช้\n\nตั้งค่าเป็น GPU ที่ถูกตั้งค่าสถานะเป็น \"dGPU\" หากคุณไม่แน่ใจ หากไม่มีก็ปล่อยทิ้งไว้โดยไม่มีใครแตะต้องมัน", + "SettingsAppRequiredRestartMessage": "จำเป็นต้องรีสตาร์ท รียูจินซ์", + "SettingsGpuBackendRestartMessage": "การตั้งค่ากราฟิกเบื้องหลังหรือ GPU ได้รับการแก้ไขแล้ว สิ่งนี้จะต้องมีการรีสตาร์ทจึงจะสามารถใช้งานได้", + "SettingsGpuBackendRestartSubMessage": "คุณต้องการรีสตาร์ทตอนนี้หรือไม่?", + "RyujinxUpdaterMessage": "คุณต้องการอัพเดต รียูจินซ์ เป็นเวอร์ชั่นล่าสุดหรือไม่?", + "SettingsTabHotkeysVolumeUpHotkey": "เพิ่มระดับเสียง:", + "SettingsTabHotkeysVolumeDownHotkey": "ลดระดับเสียง:", + "SettingsEnableMacroHLE": "เปิดใช้งาน มาโคร HLE", + "SettingsEnableMacroHLETooltip": "การจำลองระดับสูงของโค้ดมาโคร GPU\n\nปรับปรุงประสิทธิภาพ แต่อาจทำให้เกิดข้อผิดพลาดด้านกราฟิกในบางเกม\n\nปล่อยไว้หากคุณไม่แน่ใจ", + "SettingsEnableColorSpacePassthrough": "ทะลุผ่านพื้นที่สี", + "SettingsEnableColorSpacePassthroughTooltip": "สั่งให้แบ็กเอนด์ Vulkan ส่งผ่านข้อมูลสีโดยไม่ต้องระบุค่าของสี สำหรับผู้ใช้ที่มีการแสดงกระจายตัวของสี อาจส่งผลให้สีสดใสมากขึ้น โดยต้องแลกกับความถูกต้องของสี", + "VolumeShort": "ระดับเสียง", + "UserProfilesManageSaves": "จัดการบันทึก", + "DeleteUserSave": "คุณต้องการลบบันทึกผู้ใช้สำหรับเกมนี้หรือไม่?", + "IrreversibleActionNote": "การดำเนินการนี้ไม่สามารถย้อนกลับได้", + "SaveManagerHeading": "จัดการบันทึกสำหรับ {0} ({1})", + "SaveManagerTitle": "จัดการบันทึก", + "Name": "ชื่อ", + "Size": "ขนาด", + "Search": "ค้นหา", + "UserProfilesRecoverLostAccounts": "กู้คืนบัญชีที่สูญหาย", + "Recover": "กู้คืน", + "UserProfilesRecoverHeading": "พบบันทึกสำหรับบัญชีดังต่อไปนี้", + "UserProfilesRecoverEmptyList": "ไม่มีโปรไฟล์ที่สามารถกู้คืนได้", + "GraphicsAATooltip": "ใช้การลดรอยหยักกับการเรนเดอร์เกม\n\nFXAA จะเบลอภาพส่วนใหญ่ ในขณะที่ SMAA จะพยายามค้นหาขอบหยักและปรับให้เรียบ\n\nไม่แนะนำให้ใช้ร่วมกับตัวกรองสเกล FSR\n\nตัวเลือกนี้สามารถเปลี่ยนแปลงได้ในขณะที่เกมกำลังทำงานอยู่โดยคลิก \"นำไปใช้\" ด้านล่าง คุณสามารถย้ายหน้าต่างการตั้งค่าไปด้านข้างและทดลองจนกว่าคุณจะพบรูปลักษณ์ที่คุณต้องการสำหรับเกม\n\nปล่อยไว้ที่ NONE หากไม่แน่ใจ", + "GraphicsAALabel": "ลดการฉีกขาดของภาพ:", + "GraphicsScalingFilterLabel": "ปรับขนาดตัวกรอง:", + "GraphicsScalingFilterTooltip": "เลือกตัวกรองสเกลที่จะใช้เมื่อใช้สเกลความละเอียด\n\nBilinear ทำงานได้ดีกับเกม 3D และเป็นตัวเลือกเริ่มต้นที่ปลอดภัย\n\nแนะนำให้ใช้เกมภาพพิกเซลที่ใกล้เคียงที่สุด\n\nFSR 1.0 เป็นเพียงตัวกรองความคมชัด ไม่แนะนำให้ใช้กับ FXAA หรือ SMAA\n\nตัวเลือกนี้สามารถเปลี่ยนแปลงได้ในขณะที่เกมกำลังทำงานอยู่โดยคลิก \"นำไปใช้\" ด้านล่าง คุณสามารถย้ายหน้าต่างการตั้งค่าไปด้านข้างและทดลองจนกว่าคุณจะพบรูปลักษณ์ที่คุณต้องการสำหรับเกม", + "GraphicsScalingFilterBilinear": "Bilinear", + "GraphicsScalingFilterNearest": "Nearest", + "GraphicsScalingFilterFsr": "FSR", + "GraphicsScalingFilterLevelLabel": "ระดับ", + "GraphicsScalingFilterLevelTooltip": "ตั้งค่าระดับความคมชัด FSR 1.0 สูงกว่าจะคมชัดกว่า", + "SmaaLow": "SMAA ต่ำ", + "SmaaMedium": "SMAA ปานกลาง", + "SmaaHigh": "SMAA สูง", + "SmaaUltra": "SMAA สูงมาก", + "UserEditorTitle": "แก้ไขผู้ใช้", + "UserEditorTitleCreate": "สร้างผู้ใช้", + "SettingsTabNetworkInterface": "เชื่อมต่อเครือข่าย:", + "NetworkInterfaceTooltip": "อินเทอร์เฟซเครือข่ายที่ใช้สำหรับคุณสมบัติ LAN/LDN\n\nเมื่อใช้ร่วมกับ VPN หรือ XLink Kai และเกมที่รองรับ LAN สามารถใช้เพื่อปลอมการเชื่อมต่อเครือข่ายเดียวกันผ่านทางอินเทอร์เน็ต\n\nปล่อยให้เป็น ค่าเริ่มต้น หากคุณไม่แน่ใจ", + "NetworkInterfaceDefault": "ค่าเริ่มต้น", + "PackagingShaders": "รวม Shaders เข้าด้วยกัน", + "AboutChangelogButton": "ดูประวัติการเปลี่ยนแปลงบน GitHub", + "AboutChangelogButtonTooltipMessage": "คลิกเพื่อเปิดประวัติการเปลี่ยนแปลงสำหรับเวอร์ชั่นนี้ บนเบราว์เซอร์เริ่มต้นของคุณ", + "SettingsTabNetworkMultiplayer": "ผู้เล่นหลายคน", + "MultiplayerMode": "โหมด:", + "MultiplayerModeTooltip": "เปลี่ยนโหมดผู้เล่นหลายคนของ LDN\n\nLdnMitm จะปรับเปลี่ยนฟังก์ชันการเล่นแบบไร้สาย/ภายใน จะให้เกมทำงานเหมือนกับว่าเป็น LAN ช่วยให้สามารถเชื่อมต่อภายในเครือข่ายเดียวกันกับอินสแตนซ์ Ryujinx อื่น ๆ และคอนโซล Nintendo Switch ที่ถูกแฮ็กซึ่งมีโมดูล ldn_mitm ติดตั้งอยู่\n\nผู้เล่นหลายคนต้องการให้ผู้เล่นทุกคนอยู่ในเกมเวอร์ชันเดียวกัน (เช่น Super Smash Bros. Ultimate v13.0.1 ไม่สามารถเชื่อมต่อกับ v13.0.0)\n\nปล่อยให้ปิดการใช้งานหากไม่แน่ใจ", + "MultiplayerModeDisabled": "Disabled", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/tr_TR.json b/src/Ryujinx/Assets/Locales/tr_TR.json similarity index 79% rename from src/Ryujinx.Ava/Assets/Locales/tr_TR.json rename to src/Ryujinx/Assets/Locales/tr_TR.json index 3f70a781d..f74baaa18 100644 --- a/src/Ryujinx.Ava/Assets/Locales/tr_TR.json +++ b/src/Ryujinx/Assets/Locales/tr_TR.json @@ -14,7 +14,7 @@ "MenuBarFileOpenEmuFolder": "Ryujinx Klasörünü aç", "MenuBarFileOpenLogsFolder": "Logs Klasörünü aç", "MenuBarFileExit": "_Çıkış", - "MenuBarOptions": "Seçenekler", + "MenuBarOptions": "_Seçenekler", "MenuBarOptionsToggleFullscreen": "Tam Ekran Modunu Aç", "MenuBarOptionsStartGamesInFullscreen": "Oyunları Tam Ekran Modunda Başlat", "MenuBarOptionsStopEmulation": "Emülasyonu Durdur", @@ -30,7 +30,11 @@ "MenuBarToolsManageFileTypes": "Dosya uzantılarını yönet", "MenuBarToolsInstallFileTypes": "Dosya uzantılarını yükle", "MenuBarToolsUninstallFileTypes": "Dosya uzantılarını kaldır", - "MenuBarHelp": "Yardım", + "MenuBarView": "_Görüntüle", + "MenuBarViewWindow": "Pencere Boyutu", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Yardım", "MenuBarHelpCheckForUpdates": "Güncellemeleri Denetle", "MenuBarHelpAbout": "Hakkında", "MenuSearch": "Ara...", @@ -54,8 +58,6 @@ "GameListContextMenuManageTitleUpdatesToolTip": "Oyun Güncelleme Yönetim Penceresini Açar", "GameListContextMenuManageDlc": "DLC'leri Yönet", "GameListContextMenuManageDlcToolTip": "DLC yönetim penceresini açar", - "GameListContextMenuOpenModsDirectory": "Mod Dizinini Aç", - "GameListContextMenuOpenModsDirectoryToolTip": "Uygulamanın modlarının bulunduğu dizini açar", "GameListContextMenuCacheManagement": "Önbellek Yönetimi", "GameListContextMenuCacheManagementPurgePptc": "PPTC Yeniden Yapılandırmasını Başlat", "GameListContextMenuCacheManagementPurgePptcToolTip": "Oyunun bir sonraki açılışında PPTC'yi yeniden yapılandır", @@ -72,6 +74,13 @@ "GameListContextMenuExtractDataRomFSToolTip": "Uygulamanın geçerli yapılandırmasından RomFS kısmını ayıkla (Güncellemeler dahil)", "GameListContextMenuExtractDataLogo": "Simge", "GameListContextMenuExtractDataLogoToolTip": "Uygulamanın geçerli yapılandırmasından Logo kısmını ayıkla (Güncellemeler dahil)", + "GameListContextMenuCreateShortcut": "Uygulama Kısayolu Oluştur", + "GameListContextMenuCreateShortcutToolTip": "Seçilmiş uygulamayı çalıştıracak bir masaüstü kısayolu oluştur", + "GameListContextMenuCreateShortcutToolTipMacOS": "Create a shortcut in macOS's Applications folder that launches the selected Application", + "GameListContextMenuOpenModsDirectory": "Mod Dizinini Aç", + "GameListContextMenuOpenModsDirectoryToolTip": "Opens the directory which contains Application's Mods", + "GameListContextMenuOpenSdModsDirectory": "Open Atmosphere Mods Directory", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.", "StatusBarGamesLoaded": "{0}/{1} Oyun Yüklendi", "StatusBarSystemVersion": "Sistem Sürümü: {0}", "LinuxVmMaxMapCountDialogTitle": "Bellek Haritaları İçin Düşük Limit Tespit Edildi ", @@ -87,6 +96,7 @@ "SettingsTabGeneralEnableDiscordRichPresence": "Discord Zengin İçerik'i Etkinleştir", "SettingsTabGeneralCheckUpdatesOnLaunch": "Her Açılışta Güncellemeleri Denetle", "SettingsTabGeneralShowConfirmExitDialog": "\"Çıkışı Onayla\" Diyaloğunu Göster", + "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", "SettingsTabGeneralHideCursor": "İşaretçiyi Gizle:", "SettingsTabGeneralHideCursorNever": "Hiçbir Zaman", "SettingsTabGeneralHideCursorOnIdle": "Hareketsiz Durumda", @@ -150,7 +160,7 @@ "SettingsTabGraphicsResolutionScaleNative": "Yerel (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (Tavsiye Edilmez)", "SettingsTabGraphicsAspectRatio": "En-Boy Oranı:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -200,9 +210,9 @@ "ControllerSettingsInputDevice": "Giriş Cihazı", "ControllerSettingsRefresh": "Yenile", "ControllerSettingsDeviceDisabled": "Devre Dışı", - "ControllerSettingsControllerType": "Kontrolcü Tipi", + "ControllerSettingsControllerType": "Kumanda Tipi", "ControllerSettingsControllerTypeHandheld": "Portatif Mod", - "ControllerSettingsControllerTypeProController": "Profesyonel Denetleyici", + "ControllerSettingsControllerTypeProController": "Profesyonel Kumanda", "ControllerSettingsControllerTypeJoyConPair": "JoyCon Çifti", "ControllerSettingsControllerTypeJoyConLeft": "JoyCon Sol", "ControllerSettingsControllerTypeJoyConRight": "JoyCon Sağ", @@ -253,7 +263,7 @@ "ControllerSettingsTriggerThreshold": "Tetik Eşiği:", "ControllerSettingsMotion": "Hareket", "ControllerSettingsMotionUseCemuhookCompatibleMotion": "CemuHook uyumlu hareket kullan", - "ControllerSettingsMotionControllerSlot": "Kontrolcü Yuvası:", + "ControllerSettingsMotionControllerSlot": "Kumanda Yuvası:", "ControllerSettingsMotionMirrorInput": "Girişi Aynala", "ControllerSettingsMotionRightJoyConSlot": "Sağ JoyCon Yuvası:", "ControllerSettingsMotionServerHost": "Sunucu Sahibi:", @@ -261,6 +271,107 @@ "ControllerSettingsMotionGyroDeadzone": "Gyro Ölü Bölgesi:", "ControllerSettingsSave": "Kaydet", "ControllerSettingsClose": "Kapat", + "KeyUnknown": "Unknown", + "KeyShiftLeft": "Sol Shift", + "KeyShiftRight": "Sağ Shift", + "KeyControlLeft": "Sol Ctrl", + "KeyMacControlLeft": "⌃ Sol", + "KeyControlRight": "Sağ Control", + "KeyMacControlRight": "⌃ Sağ", + "KeyAltLeft": "Sol Alt", + "KeyMacAltLeft": "⌥ Sol", + "KeyAltRight": "Sağ Alt", + "KeyMacAltRight": "⌥ Sağ", + "KeyWinLeft": "⊞ Sol", + "KeyMacWinLeft": "⌘ Sol", + "KeyWinRight": "⊞ Sağ", + "KeyMacWinRight": "⌘ Sağ", + "KeyMenu": "Menü", + "KeyUp": "Yukarı", + "KeyDown": "Aşağı", + "KeyLeft": "Sol", + "KeyRight": "Sağ", + "KeyEnter": "Enter", + "KeyEscape": "Esc", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Geri tuşu", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Sağ", + "GamepadMinus": "-", + "GamepadPlus": "4", + "GamepadGuide": "Rehber", + "GamepadMisc1": "Diğer", + "GamepadPaddle1": "Pedal 1", + "GamepadPaddle2": "Pedal 2", + "GamepadPaddle3": "Pedal 3", + "GamepadPaddle4": "Pedal 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Sol Tetik 0", + "GamepadSingleRightTrigger0": "Sağ Tetik 0", + "GamepadSingleLeftTrigger1": "Sol Tetik 1", + "GamepadSingleRightTrigger1": "Sağ Tetik 1", + "StickLeft": "Sol Çubuk", + "StickRight": "Sağ çubuk", "UserProfilesSelectedUserProfile": "Seçili Kullanıcı Profili:", "UserProfilesSaveProfileName": "Profil İsmini Kaydet", "UserProfilesChangeProfileImage": "Profil Resmini Değiştir", @@ -292,13 +403,9 @@ "GameListContextMenuRunApplication": "Uygulamayı Çalıştır", "GameListContextMenuToggleFavorite": "Favori Ayarla", "GameListContextMenuToggleFavoriteToolTip": "Oyunu Favorilere Ekle/Çıkar", - "SettingsTabGeneralTheme": "Tema", - "SettingsTabGeneralThemeCustomTheme": "Özel Tema Yolu", - "SettingsTabGeneralThemeBaseStyle": "Temel Stil", - "SettingsTabGeneralThemeBaseStyleDark": "Karanlık", - "SettingsTabGeneralThemeBaseStyleLight": "Aydınlık", - "SettingsTabGeneralThemeEnableCustomTheme": "Özel Tema Etkinleştir", - "ButtonBrowse": "Göz At", + "SettingsTabGeneralTheme": "Tema:", + "SettingsTabGeneralThemeDark": "Karanlık", + "SettingsTabGeneralThemeLight": "Aydınlık", "ControllerSettingsConfigureGeneral": "Ayarla", "ControllerSettingsRumble": "Titreşim", "ControllerSettingsRumbleStrongMultiplier": "Güçlü Titreşim Çoklayıcı", @@ -332,8 +439,6 @@ "DialogUpdaterAddingFilesMessage": "Yeni Güncelleme Ekleniyor...", "DialogUpdaterCompleteMessage": "Güncelleme Tamamlandı!", "DialogUpdaterRestartMessage": "Ryujinx'i şimdi yeniden başlatmak istiyor musunuz?", - "DialogUpdaterArchNotSupportedMessage": "Sistem mimariniz desteklenmemektedir!", - "DialogUpdaterArchNotSupportedSubMessage": "(Sadece x64 sistemleri desteklenmektedir!)", "DialogUpdaterNoInternetMessage": "İnternete bağlı değilsiniz!", "DialogUpdaterNoInternetSubMessage": "Lütfen aktif bir internet bağlantınız olduğunu kontrol edin!", "DialogUpdaterDirtyBuildMessage": "Ryujinx'in Dirty build'lerini güncelleyemezsiniz!", @@ -342,7 +447,7 @@ "DialogThemeRestartMessage": "Tema kaydedildi. Temayı uygulamak için yeniden başlatma gerekiyor.", "DialogThemeRestartSubMessage": "Yeniden başlatmak ister misiniz", "DialogFirmwareInstallEmbeddedMessage": "Bu oyunun içine gömülü olan yazılımı yüklemek ister misiniz? (Firmware {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "Yüklü firmware bulunamadı ancak Ryujinx sağlanan oyundan {0} firmware sürümünü yükledi.\nEmülatör şimdi başlatılacak.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "No installed firmware was found but Ryujinx was able to install firmware {0} from the provided game.\nThe emulator will now start.", "DialogFirmwareNoFirmwareInstalledMessage": "Yazılım Yüklü Değil", "DialogFirmwareInstalledMessage": "Yazılım {0} yüklendi", "DialogInstallFileTypesSuccessMessage": "Dosya uzantıları başarıyla yüklendi!", @@ -350,7 +455,7 @@ "DialogUninstallFileTypesSuccessMessage": "Dosya uzantıları başarıyla kaldırıldı!", "DialogUninstallFileTypesErrorMessage": "Dosya uzantıları kaldırma işlemi başarısız oldu.", "DialogOpenSettingsWindowLabel": "Seçenekler Penceresini Aç", - "DialogControllerAppletTitle": "Kontrolcü Applet'i", + "DialogControllerAppletTitle": "Kumanda Applet'i", "DialogMessageDialogErrorExceptionMessage": "Mesaj diyaloğu gösterilirken hata: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "Mesaj diyaloğu gösterilirken hata: {0}", "DialogErrorAppletErrorExceptionMessage": "Applet diyaloğu gösterilirken hata: {0}", @@ -383,9 +488,12 @@ "DialogUserProfileUnsavedChangesTitle": "Uyarı - Kaydedilmemiş Değişiklikler", "DialogUserProfileUnsavedChangesMessage": "Kullanıcı profilinizde kaydedilmemiş değişiklikler var.", "DialogUserProfileUnsavedChangesSubMessage": "Yaptığınız değişiklikleri iptal etmek istediğinize emin misiniz?", - "DialogControllerSettingsModifiedConfirmMessage": "Güncel kontrolcü seçenekleri güncellendi.", + "DialogControllerSettingsModifiedConfirmMessage": "Geçerli kumanda seçenekleri güncellendi.", "DialogControllerSettingsModifiedConfirmSubMessage": "Kaydetmek istiyor musunuz?", - "DialogLoadNcaErrorMessage": "{0}. Hatalı Dosya: {1}", + "DialogLoadFileErrorMessage": "{0}. Hatalı Dosya: {1}", + "DialogModAlreadyExistsMessage": "Mod zaten var", + "DialogModInvalidMessage": "The specified directory does not contain a mod!", + "DialogModDeleteNoParentMessage": "Silme Başarısız: \"{0}\" Modu için üst dizin bulunamadı! ", "DialogDlcNoDlcErrorMessage": "Belirtilen dosya seçilen oyun için DLC içermiyor!", "DialogPerformanceCheckLoggingEnabledMessage": "Sadece geliştiriler için dizayn edilen Trace Loglama seçeneği etkin.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "En iyi performans için trace loglama'nın devre dışı bırakılması tavsiye edilir. Trace loglama seçeneğini şimdi devre dışı bırakmak ister misiniz?", @@ -396,6 +504,8 @@ "DialogUpdateAddUpdateErrorMessage": "Belirtilen dosya seçilen oyun için güncelleme içermiyor!", "DialogSettingsBackendThreadingWarningTitle": "Uyarı - Backend Threading", "DialogSettingsBackendThreadingWarningMessage": "Bu seçeneğin tamamen uygulanması için Ryujinx'in kapatıp açılması gerekir. Kullandığınız işletim sistemine bağlı olarak, Ryujinx'in multithreading'ini kullanırken driver'ınızın multithreading seçeneğini kapatmanız gerekebilir.", + "DialogModManagerDeletionWarningMessage": "You are about to delete the mod: {0}\n\nAre you sure you want to proceed?", + "DialogModManagerDeletionAllWarningMessage": "You are about to delete all mods for this title.\n\nAre you sure you want to proceed?", "SettingsTabGraphicsFeaturesOptions": "Özellikler", "SettingsTabGraphicsBackendMultithreading": "Grafik Backend Multithreading:", "CommonAuto": "Otomatik", @@ -430,6 +540,7 @@ "DlcManagerRemoveAllButton": "Tümünü kaldır", "DlcManagerEnableAllButton": "Tümünü Aktif Et", "DlcManagerDisableAllButton": "Tümünü Devre Dışı Bırak", + "ModManagerDeleteAllButton": "Hepsini Sil", "MenuBarOptionsChangeLanguage": "Dili Değiştir", "MenuBarShowFileTypes": "Dosya Uzantılarını Göster", "CommonSort": "Sırala", @@ -446,14 +557,14 @@ "CustomThemeCheckTooltip": "Emülatör pencerelerinin görünümünü değiştirmek için özel bir Avalonia teması kullan", "CustomThemePathTooltip": "Özel arayüz temasının yolu", "CustomThemeBrowseTooltip": "Özel arayüz teması için göz at", - "DockModeToggleTooltip": "Docked modu emüle edilen sistemin yerleşik Nintendo Switch gibi davranmasını sağlar. Bu çoğu oyunda grafik kalitesini arttırır. Diğer yandan, bu seçeneği devre dışı bırakmak emüle edilen sistemin elde Ninendo Switch gibi davranmasını sağlayıp grafik kalitesini düşürür.\n\nDocked modu kullanmayı düşünüyorsanız 1. Oyuncu kontrollerini; Handheld modunu kullanmak istiyorsanız Handheld kontrollerini konfigüre edin.\n\nEmin değilseniz aktif halde bırakın.", - "DirectKeyboardTooltip": "Doğrudan Klavye Erişimi (HID) desteği. Oyunların klavyenizi metin giriş cihazı olarak kullanmasını sağlar.", - "DirectMouseTooltip": "Doğrudan Fare Erişimi (HID) desteği. Oyunların farenizi işaret aygıtı olarak kullanmasını sağlar.", + "DockModeToggleTooltip": "Docked modu emüle edilen sistemin yerleşik Nintendo Switch gibi davranmasını sağlar. Bu çoğu oyunda grafik kalitesini arttırır. Diğer yandan, bu seçeneği devre dışı bırakmak emüle edilen sistemin portatif Ninendo Switch gibi davranmasını sağlayıp grafik kalitesini düşürür.\n\nDocked modu kullanmayı düşünüyorsanız 1. Oyuncu kontrollerini; Handheld modunu kullanmak istiyorsanız portatif kontrollerini konfigüre edin.\n\nEmin değilseniz aktif halde bırakın.", + "DirectKeyboardTooltip": "Direct keyboard access (HID) support. Provides games access to your keyboard as a text entry device.\n\nOnly works with games that natively support keyboard usage on Switch hardware.\n\nLeave OFF if unsure.", + "DirectMouseTooltip": "Direct mouse access (HID) support. Provides games access to your mouse as a pointing device.\n\nOnly works with games that natively support mouse controls on Switch hardware, which are few and far between.\n\nWhen enabled, touch screen functionality may not work.\n\nLeave OFF if unsure.", "RegionTooltip": "Sistem Bölgesini Değiştir", "LanguageTooltip": "Sistem Dilini Değiştir", "TimezoneTooltip": "Sistem Saat Dilimini Değiştir", "TimeTooltip": "Sistem Saatini Değiştir", - "VSyncToggleTooltip": "Emüle edilen konsolun Dikey Senkronizasyonu. Çoğu oyun için kare sınırlayıcı işlevi görür, bu seçeneği devre dışı bırakmak bazı oyunların normalden yüksek hızda çalışmasını ve yükleme ekranlarının daha uzun sürmesini veya sıkışıp kalmasını sağlar.\n\nTercih ettiğiniz bir kısayol ile oyun içindeyken etkinleştirilip devre dışı bırakılabilir. Bu seçeneği devre dışı bırakmayı düşünüyorsanız bir kısayol atamanızı öneririz.\n\nEmin değilseniz aktif halde bırakın.", + "VSyncToggleTooltip": "Emulated console's Vertical Sync. Essentially a frame-limiter for the majority of games; disabling it may cause games to run at higher speed or make loading screens take longer or get stuck.\n\nCan be toggled in-game with a hotkey of your preference (F1 by default). We recommend doing this if you plan on disabling it.\n\nLeave ON if unsure.", "PptcToggleTooltip": "Çevrilen JIT fonksiyonlarını oyun her açıldığında çevrilmek zorunda kalmaması için kaydeder.\n\nTeklemeyi azaltır ve ilk açılıştan sonra oyunların ilk açılış süresini ciddi biçimde hızlandırır.\n\nEmin değilseniz aktif halde bırakın.", "FsIntegrityToggleTooltip": "Oyun açarken hatalı dosyaların olup olmadığını kontrol eder, ve hatalı dosya bulursa log dosyasında hash hatası görüntüler.\n\nPerformansa herhangi bir etkisi yoktur ve sorun gidermeye yardımcı olur.\n\nEmin değilseniz aktif halde bırakın.", "AudioBackendTooltip": "Ses çıkış motorunu değiştirir.\n\nSDL2 tercih edilen seçenektir, OpenAL ve SoundIO ise alternatif olarak kullanılabilir. Dummy seçeneğinde ses çıkışı olmayacaktır.\n\nEmin değilseniz SDL2 seçeneğine ayarlayın.", @@ -467,10 +578,10 @@ "GraphicsBackendThreadingTooltip": "Grafik arka uç komutlarını ikinci bir iş parçacığında işletir.\n\nKendi multithreading desteği olmayan sürücülerde shader derlemeyi hızlandırıp performansı artırır. Multithreading desteği olan sürücülerde çok az daha iyi performans sağlar.\n\nEmin değilseniz Otomatik seçeneğine ayarlayın.", "GalThreadingTooltip": "Grafik arka uç komutlarını ikinci bir iş parçacığında işletir.\n\nKendi multithreading desteği olmayan sürücülerde shader derlemeyi hızlandırıp performansı artırır. Multithreading desteği olan sürücülerde çok az daha iyi performans sağlar.\n\nEmin değilseniz Otomatik seçeneğine ayarlayın.", "ShaderCacheToggleTooltip": "Sonraki çalışmalarda takılmaları engelleyen bir gölgelendirici disk önbelleğine kaydeder.", - "ResolutionScaleTooltip": "Uygulanabilir grafik hedeflerine uygulanan çözünürlük ölçeği", + "ResolutionScaleTooltip": "Multiplies the game's rendering resolution.\n\nA few games may not work with this and look pixelated even when the resolution is increased; for those games, you may need to find mods that remove anti-aliasing or that increase their internal rendering resolution. For using the latter, you'll likely want to select Native.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nKeep in mind 4x is overkill for virtually any setup.", "ResolutionScaleEntryTooltip": "Küsüratlı çözünürlük ölçeği, 1.5 gibi. Küsüratlı ölçekler hata oluşturmaya ve çökmeye daha yatkındır.", - "AnisotropyTooltip": "Eşyönsüz doku süzmesi seviyesi (Oyun tarafından istenen değeri kullanmak için Otomatik seçeneğine ayarlayın)", - "AspectRatioTooltip": "Grafik penceresine uygulanan en-boy oranı.", + "AnisotropyTooltip": "Level of Anisotropic Filtering. Set to Auto to use the value requested by the game.", + "AspectRatioTooltip": "Aspect Ratio applied to the renderer window.\n\nOnly change this if you're using an aspect ratio mod for your game, otherwise the graphics will be stretched.\n\nLeave on 16:9 if unsure.", "ShaderDumpPathTooltip": "Grafik Shader Döküm Yolu", "FileLogTooltip": "Konsol loglarını diskte bir log dosyasına kaydeder. Performansı etkilemez.", "StubLogTooltip": "Stub log mesajlarını konsola yazdırır. Performansı etkilemez.", @@ -504,6 +615,8 @@ "EnableInternetAccessTooltip": "Emüle edilen uygulamanın internete bağlanmasını sağlar.\n\nLAN modu bulunan oyunlar bu seçenek ile birbirine bağlanabilir ve sistemler aynı access point'e bağlanır. Bu gerçek konsolları da kapsar.\n\nNintendo sunucularına bağlanmayı sağlaMAZ. Internete bağlanmaya çalışan baz oyunların çökmesine sebep olabilr.\n\nEmin değilseniz devre dışı bırakın.", "GameListContextMenuManageCheatToolTip": "Hileleri yönetmeyi sağlar", "GameListContextMenuManageCheat": "Hileleri Yönet", + "GameListContextMenuManageModToolTip": "Modları Yönet", + "GameListContextMenuManageMod": "Modları Yönet", "ControllerSettingsStickRange": "Menzil:", "DialogStopEmulationTitle": "Ryujinx - Emülasyonu Durdur", "DialogStopEmulationMessage": "Emülasyonu durdurmak istediğinizden emin misiniz?", @@ -515,8 +628,6 @@ "SettingsTabCpuMemory": "CPU Hafızası", "DialogUpdaterFlatpakNotSupportedMessage": "Lütfen Ryujinx'i FlatHub aracılığıyla güncelleyin.", "UpdaterDisabledWarningTitle": "Güncelleyici Devre Dışı!", - "GameListContextMenuOpenSdModsDirectory": "Atmosphere Mod Dizini", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Uygulama Modlarını içeren alternatif SD kart Atmosfer dizinini açar. Gerçek donanım için paketlenmiş modlar için kullanışlıdır.", "ControllerSettingsRotate90": "Saat yönünde 90° Döndür", "IconSize": "Ikon Boyutu", "IconSizeTooltip": "Oyun ikonlarının boyutunu değiştirmeyi sağlar", @@ -544,19 +655,20 @@ "SwkbdMinCharacters": "En az {0} karakter uzunluğunda olmalı", "SwkbdMinRangeCharacters": "{0}-{1} karakter uzunluğunda olmalı", "SoftwareKeyboard": "Yazılım Klavyesi", - "SoftwareKeyboardModeNumbersOnly": "Sadece Numara Olabilir", + "SoftwareKeyboardModeNumeric": "Sadece 0-9 veya '.' olabilir", "SoftwareKeyboardModeAlphabet": "Sadece CJK-characters olmayan karakterler olabilir", "SoftwareKeyboardModeASCII": "Sadece ASCII karakterler olabilir", - "DialogControllerAppletMessagePlayerRange": "Uygulama belirtilen türde {0} oyuncu istiyor:\n\nTÜRLER: {1}\n\nOYUNCULAR: {2}\n\n{3}Lütfen şimdi seçeneklerden giriş aygıtlarını ayarlayın veya Kapat'a basın.", - "DialogControllerAppletMessage": "Uygulama belirtilen türde tam olarak {0} oyuncu istiyor:\n\nTÜRLER: {1}\n\nOYUNCULAR: {2}\n\n{3}Lütfen şimdi seçeneklerden giriş aygıtlarını ayarlayın veya Kapat'a basın.", - "DialogControllerAppletDockModeSet": "Docked mode etkin. Handheld geçersiz.\n\n", + "ControllerAppletControllers": "Desteklenen Kumandalar:", + "ControllerAppletPlayers": "Oyuncular:", + "ControllerAppletDescription": "Halihazırdaki konfigürasyonunuz geçersiz. Ayarları açın ve girişlerinizi yeniden konfigüre edin.", + "ControllerAppletDocked": "Docked mod ayarlandı. Portatif denetim devre dışı bırakılmalı.", "UpdaterRenaming": "Eski dosyalar yeniden adlandırılıyor...", "UpdaterRenameFailed": "Güncelleyici belirtilen dosyayı yeniden adlandıramadı: {0}", "UpdaterAddingFiles": "Yeni Dosyalar Ekleniyor...", "UpdaterExtracting": "Güncelleme Ayrıştırılıyor...", "UpdaterDownloading": "Güncelleme İndiriliyor...", "Game": "Oyun", - "Docked": "Yerleştirildi", + "Docked": "Docked", "Handheld": "El tipi", "ConnectionError": "Bağlantı Hatası.", "AboutPageDeveloperListMore": "{0} ve daha fazla...", @@ -587,17 +699,21 @@ "Writable": "Yazılabilir", "SelectDlcDialogTitle": "DLC dosyalarını seç", "SelectUpdateDialogTitle": "Güncelleme dosyalarını seç", + "SelectModDialogTitle": "Mod Dizinini Seç", "UserProfileWindowTitle": "Kullanıcı Profillerini Yönet", "CheatWindowTitle": "Oyun Hilelerini Yönet", "DlcWindowTitle": "Oyun DLC'lerini Yönet", + "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "Oyun Güncellemelerini Yönet", "CheatWindowHeading": "{0} için Hile mevcut [{1}]", "BuildId": "BuildId:", "DlcWindowHeading": "{0} için DLC mevcut [{1}]", + "ModWindowHeading": "{0} Mod(lar)", "UserProfilesEditProfile": "Seçiliyi Düzenle", "Cancel": "İptal", "Save": "Kaydet", "Discard": "Iskarta", + "Paused": "Durduruldu", "UserProfilesSetProfileImage": "Profil Resmi Ayarla", "UserProfileEmptyNameError": "İsim gerekli", "UserProfileNoImageError": "Profil resmi ayarlanmalıdır", @@ -607,9 +723,9 @@ "UserProfilesName": "İsim:", "UserProfilesUserId": "Kullanıcı Adı:", "SettingsTabGraphicsBackend": "Grafik Arka Ucu", - "SettingsTabGraphicsBackendTooltip": "Kullanılacak Grafik Arka Uç", + "SettingsTabGraphicsBackendTooltip": "Select the graphics backend that will be used in the emulator.\n\nVulkan is overall better for all modern graphics cards, as long as their drivers are up to date. Vulkan also features faster shader compilation (less stuttering) on all GPU vendors.\n\nOpenGL may achieve better results on old Nvidia GPUs, on old AMD GPUs on Linux, or on GPUs with lower VRAM, though shader compilation stutters will be greater.\n\nSet to Vulkan if unsure. Set to OpenGL if your GPU does not support Vulkan even with the latest graphics drivers.", "SettingsEnableTextureRecompression": "Yeniden Doku Sıkıştırılmasını Aktif Et", - "SettingsEnableTextureRecompressionTooltip": "4GB VRAM'in Altında Sistemler için önerilir.\n\nEmin değilseniz kapalı bırakın", + "SettingsEnableTextureRecompressionTooltip": "Compresses ASTC textures in order to reduce VRAM usage.\n\nGames using this texture format include Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder and The Legend of Zelda: Tears of the Kingdom.\n\nGraphics cards with 4GiB VRAM or less will likely crash at some point while running these games.\n\nEnable only if you're running out of VRAM on the aforementioned games. Leave OFF if unsure.", "SettingsTabGraphicsPreferredGpu": "Kullanılan GPU", "SettingsTabGraphicsPreferredGpuTooltip": "Vulkan Grafik Arka Ucu ile kullanılacak Ekran Kartını Seçin.\n\nOpenGL'nin kullanacağı GPU'yu etkilemez.\n\n Emin değilseniz \"dGPU\" olarak işaretlenmiş GPU'ya ayarlayın. Eğer yoksa, dokunmadan bırakın.\n", "SettingsAppRequiredRestartMessage": "Ryujinx'i Yeniden Başlatma Gerekli", @@ -635,12 +751,15 @@ "Recover": "Kurtar", "UserProfilesRecoverHeading": "Aşağıdaki hesaplar için kayıtlar bulundu", "UserProfilesRecoverEmptyList": "Kurtarılacak profil bulunamadı", - "GraphicsAATooltip": "Oyuna Kenar Yumuşatma Ekler", + "GraphicsAATooltip": "Applies anti-aliasing to the game render.\n\nFXAA will blur most of the image, while SMAA will attempt to find jagged edges and smooth them out.\n\nNot recommended to use in conjunction with the FSR scaling filter.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on NONE if unsure.", "GraphicsAALabel": "Kenar Yumuşatma:", "GraphicsScalingFilterLabel": "Ölçekleme Filtresi:", - "GraphicsScalingFilterTooltip": "Çerçeve Arabellek Filtresini Açar", + "GraphicsScalingFilterTooltip": "Choose the scaling filter that will be applied when using resolution scale.\n\nBilinear works well for 3D games and is a safe default option.\n\nNearest is recommended for pixel art games.\n\nFSR 1.0 is merely a sharpening filter, not recommended for use with FXAA or SMAA.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on BILINEAR if unsure.", + "GraphicsScalingFilterBilinear": "Bilinear", + "GraphicsScalingFilterNearest": "Nearest", + "GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterLevelLabel": "Seviye", - "GraphicsScalingFilterLevelTooltip": "Ölçekleme Filtre Seviyesini Belirle", + "GraphicsScalingFilterLevelTooltip": "Set FSR 1.0 sharpening level. Higher is sharper.", "SmaaLow": "Düşük SMAA", "SmaaMedium": "Orta SMAA", "SmaaHigh": "Yüksek SMAA", @@ -648,9 +767,14 @@ "UserEditorTitle": "Kullanıcıyı Düzenle", "UserEditorTitleCreate": "Kullanıcı Oluştur", "SettingsTabNetworkInterface": "Ağ Bağlantısı:", - "NetworkInterfaceTooltip": "LAN özellikleri için kullanılan ağ bağlantısı", + "NetworkInterfaceTooltip": "The network interface used for LAN/LDN features.\n\nIn conjunction with a VPN or XLink Kai and a game with LAN support, can be used to spoof a same-network connection over the Internet.\n\nLeave on DEFAULT if unsure.", "NetworkInterfaceDefault": "Varsayılan", "PackagingShaders": "Gölgeler Paketleniyor", "AboutChangelogButton": "GitHub'da Değişiklikleri Görüntüle", - "AboutChangelogButtonTooltipMessage": "Kullandığınız versiyon için olan değişiklikleri varsayılan tarayıcınızda görmek için tıklayın" -} \ No newline at end of file + "AboutChangelogButtonTooltipMessage": "Kullandığınız versiyon için olan değişiklikleri varsayılan tarayıcınızda görmek için tıklayın", + "SettingsTabNetworkMultiplayer": "Çok Oyunculu", + "MultiplayerMode": "Mod:", + "MultiplayerModeTooltip": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.", + "MultiplayerModeDisabled": "Devre Dışı", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Locales/uk_UA.json b/src/Ryujinx/Assets/Locales/uk_UA.json similarity index 72% rename from src/Ryujinx.Ava/Assets/Locales/uk_UA.json rename to src/Ryujinx/Assets/Locales/uk_UA.json index a119fb4b7..976edfb1b 100644 --- a/src/Ryujinx.Ava/Assets/Locales/uk_UA.json +++ b/src/Ryujinx/Assets/Locales/uk_UA.json @@ -1,50 +1,54 @@ { - "Language": "Yкраїнська", + "Language": "Українська", "MenuBarFileOpenApplet": "Відкрити аплет", - "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Відкрийте аплет Mii Editor в автономному режимі", + "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Відкрити аплет Mii Editor в автономному режимі", "SettingsTabInputDirectMouseAccess": "Прямий доступ мишею", - "SettingsTabSystemMemoryManagerMode": "Режим диспетчера пам'яті:", + "SettingsTabSystemMemoryManagerMode": "Режим диспетчера пам’яті:", "SettingsTabSystemMemoryManagerModeSoftware": "Програмне забезпечення", "SettingsTabSystemMemoryManagerModeHost": "Хост (швидко)", "SettingsTabSystemMemoryManagerModeHostUnchecked": "Неперевірений хост (найшвидший, небезпечний)", - "SettingsTabSystemUseHypervisor": "Use Hypervisor", + "SettingsTabSystemUseHypervisor": "Використовувати гіпервізор", "MenuBarFile": "_Файл", "MenuBarFileOpenFromFile": "_Завантажити програму з файлу", "MenuBarFileOpenUnpacked": "Завантажити _розпаковану гру", "MenuBarFileOpenEmuFolder": "Відкрити теку Ryujinx", "MenuBarFileOpenLogsFolder": "Відкрити теку журналів змін", "MenuBarFileExit": "_Вихід", - "MenuBarOptions": "Опції", - "MenuBarOptionsToggleFullscreen": "Перемкнути на весь екран", + "MenuBarOptions": "_Параметри", + "MenuBarOptionsToggleFullscreen": "На весь екран", "MenuBarOptionsStartGamesInFullscreen": "Запускати ігри на весь екран", "MenuBarOptionsStopEmulation": "Зупинити емуляцію", "MenuBarOptionsSettings": "_Налаштування", - "MenuBarOptionsManageUserProfiles": "_Керування профілями користувачів", + "MenuBarOptionsManageUserProfiles": "_Керувати профілями користувачів", "MenuBarActions": "_Дії", "MenuBarOptionsSimulateWakeUpMessage": "Симулювати повідомлення про пробудження", "MenuBarActionsScanAmiibo": "Сканувати Amiibo", "MenuBarTools": "_Інструменти", - "MenuBarToolsInstallFirmware": "Встановити прошивку", - "MenuBarFileToolsInstallFirmwareFromFile": "Встановити прошивку з XCI або ZIP", - "MenuBarFileToolsInstallFirmwareFromDirectory": "Встановити прошивку з теки", - "MenuBarToolsManageFileTypes": "Manage file types", - "MenuBarToolsInstallFileTypes": "Install file types", - "MenuBarToolsUninstallFileTypes": "Uninstall file types", - "MenuBarHelp": "Довідка", + "MenuBarToolsInstallFirmware": "Установити прошивку", + "MenuBarFileToolsInstallFirmwareFromFile": "Установити прошивку з XCI або ZIP", + "MenuBarFileToolsInstallFirmwareFromDirectory": "Установити прошивку з теки", + "MenuBarToolsManageFileTypes": "Керувати типами файлів", + "MenuBarToolsInstallFileTypes": "Установити типи файлів", + "MenuBarToolsUninstallFileTypes": "Видалити типи файлів", + "MenuBarView": "_View", + "MenuBarViewWindow": "Window Size", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Допомога", "MenuBarHelpCheckForUpdates": "Перевірити оновлення", - "MenuBarHelpAbout": "Про програму", + "MenuBarHelpAbout": "Про застосунок", "MenuSearch": "Пошук...", - "GameListHeaderFavorite": "Вибране", + "GameListHeaderFavorite": "Обране", "GameListHeaderIcon": "Значок", "GameListHeaderApplication": "Назва", "GameListHeaderDeveloper": "Розробник", "GameListHeaderVersion": "Версія", "GameListHeaderTimePlayed": "Зіграно часу", - "GameListHeaderLastPlayed": "Остання гра", + "GameListHeaderLastPlayed": "Востаннє зіграно", "GameListHeaderFileExtension": "Розширення файлу", "GameListHeaderFileSize": "Розмір файлу", "GameListHeaderPath": "Шлях", - "GameListContextMenuOpenUserSaveDirectory": "Відкрити каталог збереження користувача", + "GameListContextMenuOpenUserSaveDirectory": "Відкрити теку збереження користувача", "GameListContextMenuOpenUserSaveDirectoryToolTip": "Відкриває каталог, який містить збереження користувача програми", "GameListContextMenuOpenDeviceSaveDirectory": "Відкрити каталог пристроїв користувача", "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Відкриває каталог, який містить збереження пристрою програми", @@ -54,8 +58,6 @@ "GameListContextMenuManageTitleUpdatesToolTip": "Відкриває вікно керування оновленням заголовка", "GameListContextMenuManageDlc": "Керування DLC", "GameListContextMenuManageDlcToolTip": "Відкриває вікно керування DLC", - "GameListContextMenuOpenModsDirectory": "Відкрити каталог модифікацій", - "GameListContextMenuOpenModsDirectoryToolTip": "Відкриває каталог, який містить модифікації програм", "GameListContextMenuCacheManagement": "Керування кешем", "GameListContextMenuCacheManagementPurgePptc": "Очистити кеш PPTC", "GameListContextMenuCacheManagementPurgePptcToolTip": "Видаляє кеш PPTC програми", @@ -72,26 +74,34 @@ "GameListContextMenuExtractDataRomFSToolTip": "Видобуває розділ RomFS із поточної конфігурації програми (включаючи оновлення)", "GameListContextMenuExtractDataLogo": "Логотип", "GameListContextMenuExtractDataLogoToolTip": "Видобуває розділ логотипу з поточної конфігурації програми (включаючи оновлення)", - "StatusBarGamesLoaded": "{0}/{1} Ігор завантажено", + "GameListContextMenuCreateShortcut": "Створити ярлик застосунку", + "GameListContextMenuCreateShortcutToolTip": "Створити ярлик на робочому столі, який запускає вибраний застосунок", + "GameListContextMenuCreateShortcutToolTipMacOS": "Створити ярлик у каталозі macOS програм, що запускає обраний Додаток", + "GameListContextMenuOpenModsDirectory": "Відкрити теку з модами", + "GameListContextMenuOpenModsDirectoryToolTip": "Відкриває каталог, який містить модифікації Додатків", + "GameListContextMenuOpenSdModsDirectory": "Відкрити каталог модифікацій Atmosphere", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Відкриває альтернативний каталог SD-карти Atmosphere, що містить модифікації Додатків. Корисно для модифікацій, зроблених для реального обладнання.", + "StatusBarGamesLoaded": "{0}/{1} ігор завантажено", "StatusBarSystemVersion": "Версія системи: {0}", - "LinuxVmMaxMapCountDialogTitle": "Low limit for memory mappings detected", - "LinuxVmMaxMapCountDialogTextPrimary": "Would you like to increase the value of vm.max_map_count to {0}", - "LinuxVmMaxMapCountDialogTextSecondary": "Some games might try to create more memory mappings than currently allowed. Ryujinx will crash as soon as this limit gets exceeded.", - "LinuxVmMaxMapCountDialogButtonUntilRestart": "Yes, until the next restart", - "LinuxVmMaxMapCountDialogButtonPersistent": "Yes, permanently", - "LinuxVmMaxMapCountWarningTextPrimary": "Max amount of memory mappings is lower than recommended.", - "LinuxVmMaxMapCountWarningTextSecondary": "The current value of vm.max_map_count ({0}) is lower than {1}. Some games might try to create more memory mappings than currently allowed. Ryujinx will crash as soon as this limit gets exceeded.\n\nYou might want to either manually increase the limit or install pkexec, which allows Ryujinx to assist with that.", + "LinuxVmMaxMapCountDialogTitle": "Виявлено низьку межу для відображення памʼяті", + "LinuxVmMaxMapCountDialogTextPrimary": "Бажаєте збільшити значення vm.max_map_count на {0}", + "LinuxVmMaxMapCountDialogTextSecondary": "Деякі ігри можуть спробувати створити більше відображень памʼяті, ніж дозволено наразі. Ryujinx завершить роботу, щойно цей ліміт буде перевищено.", + "LinuxVmMaxMapCountDialogButtonUntilRestart": "Так, до наст. перезапуску", + "LinuxVmMaxMapCountDialogButtonPersistent": "Так, назавжди", + "LinuxVmMaxMapCountWarningTextPrimary": "Максимальна кількість відображення памʼяті менша, ніж рекомендовано.", + "LinuxVmMaxMapCountWarningTextSecondary": "Поточне значення vm.max_map_count ({0}) менше за {1}. Деякі ігри можуть спробувати створити більше відображень пам’яті, ніж дозволено наразі. Ryujinx завершить роботу, щойно цей ліміт буде перевищено.\n\nВи можете збільшити ліміт вручну або встановити pkexec, який дозволяє Ryujinx допомогти з цим.", "Settings": "Налаштування", "SettingsTabGeneral": "Інтерфейс користувача", "SettingsTabGeneralGeneral": "Загальні", "SettingsTabGeneralEnableDiscordRichPresence": "Увімкнути розширену присутність Discord", "SettingsTabGeneralCheckUpdatesOnLaunch": "Перевіряти наявність оновлень під час запуску", "SettingsTabGeneralShowConfirmExitDialog": "Показати діалогове вікно «Підтвердити вихід».", - "SettingsTabGeneralHideCursor": "Hide Cursor:", - "SettingsTabGeneralHideCursorNever": "Never", - "SettingsTabGeneralHideCursorOnIdle": "Приховати курсор у режимі очікування", - "SettingsTabGeneralHideCursorAlways": "Always", - "SettingsTabGeneralGameDirectories": "Каталоги ігор", + "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", + "SettingsTabGeneralHideCursor": "Сховати вказівник:", + "SettingsTabGeneralHideCursorNever": "Ніколи", + "SettingsTabGeneralHideCursorOnIdle": "Сховати у режимі очікування", + "SettingsTabGeneralHideCursorAlways": "Завжди", + "SettingsTabGeneralGameDirectories": "Тека ігор", "SettingsTabGeneralAdd": "Додати", "SettingsTabGeneralRemove": "Видалити", "SettingsTabSystem": "Система", @@ -150,7 +160,7 @@ "SettingsTabGraphicsResolutionScaleNative": "Стандартний (720p/1080p)", "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (Не рекомендується)", "SettingsTabGraphicsAspectRatio": "Співвідношення сторін:", "SettingsTabGraphicsAspectRatio4x3": "4:3", "SettingsTabGraphicsAspectRatio16x9": "16:9", @@ -158,7 +168,7 @@ "SettingsTabGraphicsAspectRatio21x9": "21:9", "SettingsTabGraphicsAspectRatio32x9": "32:9", "SettingsTabGraphicsAspectRatioStretch": "Розтягнути до розміру вікна", - "SettingsTabGraphicsDeveloperOptions": "Налаштування виробника", + "SettingsTabGraphicsDeveloperOptions": "Параметри розробника", "SettingsTabGraphicsShaderDumpPath": "Шлях скидання графічного шейдера:", "SettingsTabLogging": "Налагодження", "SettingsTabLoggingLogging": "Налагодження", @@ -172,9 +182,9 @@ "SettingsTabLoggingEnableFsAccessLogs": "Увімкнути журнали доступу Fs", "SettingsTabLoggingFsGlobalAccessLogMode": "Режим журналу глобального доступу Fs:", "SettingsTabLoggingDeveloperOptions": "Параметри розробника (УВАГА: знизиться продуктивність)", - "SettingsTabLoggingDeveloperOptionsNote": "WARNING: Will reduce performance", + "SettingsTabLoggingDeveloperOptionsNote": "УВАГА: Знижує продуктивність", "SettingsTabLoggingGraphicsBackendLogLevel": "Рівень журналу графічного сервера:", - "SettingsTabLoggingGraphicsBackendLogLevelNone": "Ні", + "SettingsTabLoggingGraphicsBackendLogLevelNone": "Немає", "SettingsTabLoggingGraphicsBackendLogLevelError": "Помилка", "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Уповільнення", "SettingsTabLoggingGraphicsBackendLogLevelAll": "Все", @@ -223,15 +233,15 @@ "ControllerSettingsDPadDown": "Вниз", "ControllerSettingsDPadLeft": "Вліво", "ControllerSettingsDPadRight": "Вправо", - "ControllerSettingsStickButton": "Button", - "ControllerSettingsStickUp": "Up", - "ControllerSettingsStickDown": "Down", - "ControllerSettingsStickLeft": "Left", - "ControllerSettingsStickRight": "Right", - "ControllerSettingsStickStick": "Stick", - "ControllerSettingsStickInvertXAxis": "Invert Stick X", - "ControllerSettingsStickInvertYAxis": "Invert Stick Y", - "ControllerSettingsStickDeadzone": "Deadzone:", + "ControllerSettingsStickButton": "Кнопка", + "ControllerSettingsStickUp": "Уверх", + "ControllerSettingsStickDown": "Униз", + "ControllerSettingsStickLeft": "Ліворуч", + "ControllerSettingsStickRight": "Праворуч", + "ControllerSettingsStickStick": "Стик", + "ControllerSettingsStickInvertXAxis": "Обернути вісь стику X", + "ControllerSettingsStickInvertYAxis": "Обернути вісь стику Y", + "ControllerSettingsStickDeadzone": "Мертва зона:", "ControllerSettingsLStick": "Лівий джойстик", "ControllerSettingsRStick": "Правий джойстик", "ControllerSettingsTriggersLeft": "Тригери ліворуч", @@ -261,14 +271,115 @@ "ControllerSettingsMotionGyroDeadzone": "Мертва зона гіроскопа:", "ControllerSettingsSave": "Зберегти", "ControllerSettingsClose": "Закрити", + "KeyUnknown": "Unknown", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", "UserProfilesSelectedUserProfile": "Вибраний профіль користувача:", "UserProfilesSaveProfileName": "Зберегти ім'я профілю", "UserProfilesChangeProfileImage": "Змінити зображення профілю", "UserProfilesAvailableUserProfiles": "Доступні профілі користувачів:", "UserProfilesAddNewProfile": "Створити профіль", - "UserProfilesDelete": "Delete", + "UserProfilesDelete": "Видалити", "UserProfilesClose": "Закрити", - "ProfileNameSelectionWatermark": "Choose a nickname", + "ProfileNameSelectionWatermark": "Оберіть псевдонім", "ProfileImageSelectionTitle": "Вибір зображення профілю", "ProfileImageSelectionHeader": "Виберіть зображення профілю", "ProfileImageSelectionNote": "Ви можете імпортувати власне зображення профілю або вибрати аватар із мікропрограми системи", @@ -289,16 +400,12 @@ "ControllerSettingsSaveProfileToolTip": "Зберегти профіль", "MenuBarFileToolsTakeScreenshot": "Зробити знімок екрана", "MenuBarFileToolsHideUi": "Сховати інтерфейс", - "GameListContextMenuRunApplication": "Run Application", + "GameListContextMenuRunApplication": "Запустити додаток", "GameListContextMenuToggleFavorite": "Перемкнути вибране", "GameListContextMenuToggleFavoriteToolTip": "Перемкнути улюблений статус гри", - "SettingsTabGeneralTheme": "Тема", - "SettingsTabGeneralThemeCustomTheme": "Користувацький шлях до теми", - "SettingsTabGeneralThemeBaseStyle": "Базовий стиль", - "SettingsTabGeneralThemeBaseStyleDark": "Темна", - "SettingsTabGeneralThemeBaseStyleLight": "Світла", - "SettingsTabGeneralThemeEnableCustomTheme": "Увімкнути користуваьку тему", - "ButtonBrowse": "Огляд", + "SettingsTabGeneralTheme": "Тема:", + "SettingsTabGeneralThemeDark": "Темна", + "SettingsTabGeneralThemeLight": "Світла", "ControllerSettingsConfigureGeneral": "Налаштування", "ControllerSettingsRumble": "Вібрація", "ControllerSettingsRumbleStrongMultiplier": "Множник сильної вібрації", @@ -332,8 +439,6 @@ "DialogUpdaterAddingFilesMessage": "Додавання нового оновлення...", "DialogUpdaterCompleteMessage": "Оновлення завершено!", "DialogUpdaterRestartMessage": "Перезапустити Ryujinx зараз?", - "DialogUpdaterArchNotSupportedMessage": "Ви використовуєте не підтримувану архітектуру системи!", - "DialogUpdaterArchNotSupportedSubMessage": "(Підтримуються лише системи x64!)", "DialogUpdaterNoInternetMessage": "Ви не підключені до Інтернету!", "DialogUpdaterNoInternetSubMessage": "Будь ласка, переконайтеся, що у вас є робоче підключення до Інтернету!", "DialogUpdaterDirtyBuildMessage": "Ви не можете оновити брудну збірку Ryujinx!", @@ -342,13 +447,13 @@ "DialogThemeRestartMessage": "Тему збережено. Щоб застосувати тему, потрібен перезапуск.", "DialogThemeRestartSubMessage": "Ви хочете перезапустити", "DialogFirmwareInstallEmbeddedMessage": "Бажаєте встановити прошивку, вбудовану в цю гру? (Прошивка {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "Встановлену прошивку не знайдено, але Ryujinx вдалося встановити прошивку {0} з наданої гри.\\nТепер запуститься емулятор.", + "DialogFirmwareInstallEmbeddedSuccessMessage": "Встановлену прошивку не знайдено, але Ryujinx вдалося встановити прошивку {0} з наданої гри.\nТепер запуститься емулятор.", "DialogFirmwareNoFirmwareInstalledMessage": "Прошивка не встановлена", "DialogFirmwareInstalledMessage": "Встановлено прошивку {0}", - "DialogInstallFileTypesSuccessMessage": "Successfully installed file types!", - "DialogInstallFileTypesErrorMessage": "Failed to install file types.", - "DialogUninstallFileTypesSuccessMessage": "Successfully uninstalled file types!", - "DialogUninstallFileTypesErrorMessage": "Failed to uninstall file types.", + "DialogInstallFileTypesSuccessMessage": "Успішно встановлено типи файлів!", + "DialogInstallFileTypesErrorMessage": "Не вдалося встановити типи файлів.", + "DialogUninstallFileTypesSuccessMessage": "Успішно видалено типи файлів!", + "DialogUninstallFileTypesErrorMessage": "Не вдалося видалити типи файлів.", "DialogOpenSettingsWindowLabel": "Відкрити вікно налаштувань", "DialogControllerAppletTitle": "Аплет контролера", "DialogMessageDialogErrorExceptionMessage": "Помилка показу діалогового вікна повідомлення: {0}", @@ -380,12 +485,15 @@ "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Версію системи {0} успішно встановлено.", "DialogUserProfileDeletionWarningMessage": "Якщо вибраний профіль буде видалено, інші профілі не відкриватимуться", "DialogUserProfileDeletionConfirmMessage": "Ви хочете видалити вибраний профіль", - "DialogUserProfileUnsavedChangesTitle": "Warning - Unsaved Changes", - "DialogUserProfileUnsavedChangesMessage": "You have made changes to this user profile that have not been saved.", - "DialogUserProfileUnsavedChangesSubMessage": "Do you want to discard your changes?", + "DialogUserProfileUnsavedChangesTitle": "Увага — Незбережені зміни", + "DialogUserProfileUnsavedChangesMessage": "Ви зробили зміни у цьому профілю користувача які не було збережено.", + "DialogUserProfileUnsavedChangesSubMessage": "Бажаєте скасувати зміни?", "DialogControllerSettingsModifiedConfirmMessage": "Поточні налаштування контролера оновлено.", "DialogControllerSettingsModifiedConfirmSubMessage": "Ви хочете зберегти?", - "DialogLoadNcaErrorMessage": "{0}. Файл з помилкою: {1}", + "DialogLoadFileErrorMessage": "{0}. Файл з помилкою: {1}", + "DialogModAlreadyExistsMessage": "Модифікація вже існує", + "DialogModInvalidMessage": "Вказаний каталог не містить модифікації!", + "DialogModDeleteNoParentMessage": "Не видалено: Не знайдено батьківський каталог для модифікації \"{0}\"!", "DialogDlcNoDlcErrorMessage": "Зазначений файл не містить DLC для вибраного заголовку!", "DialogPerformanceCheckLoggingEnabledMessage": "Ви увімкнули журнал налагодження, призначений лише для розробників.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Для оптимальної продуктивності рекомендується вимкнути ведення журналу налагодження. Ви хочете вимкнути ведення журналу налагодження зараз?", @@ -396,6 +504,8 @@ "DialogUpdateAddUpdateErrorMessage": "Зазначений файл не містить оновлення для вибраного заголовка!", "DialogSettingsBackendThreadingWarningTitle": "Попередження - потокове керування сервером", "DialogSettingsBackendThreadingWarningMessage": "Ryujinx потрібно перезапустити після зміни цього параметра, щоб він застосовувався повністю. Залежно від вашої платформи вам може знадобитися вручну вимкнути власну багатопотоковість драйвера під час використання Ryujinx.", + "DialogModManagerDeletionWarningMessage": "Ви збираєтесь видалити модифікацію: {0}\n\nВи дійсно бажаєте продовжити?", + "DialogModManagerDeletionAllWarningMessage": "Ви збираєтесь видалити всі модифікації для цього Додатка.\n\nВи дійсно бажаєте продовжити?", "SettingsTabGraphicsFeaturesOptions": "Особливості", "SettingsTabGraphicsBackendMultithreading": "Багатопотоковість графічного сервера:", "CommonAuto": "Авто", @@ -430,8 +540,9 @@ "DlcManagerRemoveAllButton": "Видалити все", "DlcManagerEnableAllButton": "Увімкнути всі", "DlcManagerDisableAllButton": "Вимкнути всі", + "ModManagerDeleteAllButton": "Видалити все", "MenuBarOptionsChangeLanguage": "Змінити мову", - "MenuBarShowFileTypes": "Show File Types", + "MenuBarShowFileTypes": "Показати типи файлів", "CommonSort": "Сортувати", "CommonShowNames": "Показати назви", "CommonFavorite": "Вибрані", @@ -447,13 +558,13 @@ "CustomThemePathTooltip": "Шлях до користувацької теми графічного інтерфейсу", "CustomThemeBrowseTooltip": "Огляд користувацької теми графічного інтерфейсу", "DockModeToggleTooltip": "У режимі док-станції емульована система веде себе як приєднаний Nintendo Switch. Це покращує точність графіки в більшості ігор. І навпаки, вимкнення цього призведе до того, що емульована система поводитиметься як портативний комутатор Nintendo, погіршуючи якість графіки.\n\nНалаштуйте елементи керування для гравця 1, якщо плануєте використовувати режим док-станції; налаштуйте ручні елементи керування, якщо плануєте використовувати портативний режим.\n\nЗалиште увімкненим, якщо не впевнені.", - "DirectKeyboardTooltip": "Підтримка прямого доступу з клавіатури (HID). Надає іграм доступ до клавіатури як пристрою для введення тексту.", - "DirectMouseTooltip": "Підтримка прямого доступу миші (HID). Надає іграм доступ до миші як вказівного пристрою.", + "DirectKeyboardTooltip": "Підтримка прямого доступу до клавіатури (HID). Надає іграм доступ до клавіатури для вводу тексту.\n\nПрацює тільки з іграми, які підтримують клавіатуру на обладнанні Switch.\n\nЗалиште вимкненим, якщо не впевнені.", + "DirectMouseTooltip": "Підтримка прямого доступу до миші (HID). Надає іграм доступ до миші, як пристрій вказування.\n\nПрацює тільки з іграми, які підтримують мишу на обладнанні Switch, їх небагато.\n\nФункціонал сенсорного екрана може не працювати, якщо функція ввімкнена.\n\nЗалиште вимкненим, якщо не впевнені.", "RegionTooltip": "Змінити регіон системи", "LanguageTooltip": "Змінити мову системи", "TimezoneTooltip": "Змінити часовий пояс системи", "TimeTooltip": "Змінити час системи", - "VSyncToggleTooltip": "Емульована вертикальна синхронізація консолі. По суті, обмежувач кадрів для більшості ігор; його вимкнення може призвести до того, що ігри працюватимуть на вищій швидкості, екрани завантаження триватимуть довше чи зупинятимуться.\n\nМожна перемикати в грі гарячою клавішею за вашим бажанням. Ми рекомендуємо зробити це, якщо ви плануєте вимкнути його.\n\nЗалиште увімкненим, якщо не впевнені.", + "VSyncToggleTooltip": "Емульована вертикальна синхронізація консолі. По суті, обмежувач кадрів для більшості ігор; його вимкнення може призвести до того, що ігри працюватимуть на вищій швидкості, екрани завантаження триватимуть довше чи зупинятимуться.\n\nМожна перемикати в грі гарячою клавішею (За умовчанням F1). Якщо ви плануєте вимкнути функцію, рекомендуємо зробити це через гарячу клавішу.\n\nЗалиште увімкненим, якщо не впевнені.", "PptcToggleTooltip": "Зберігає перекладені функції JIT, щоб їх не потрібно було перекладати кожного разу, коли гра завантажується.\n\nЗменшує заїкання та значно прискорює час завантаження після першого завантаження гри.\n\nЗалиште увімкненим, якщо не впевнені.", "FsIntegrityToggleTooltip": "Перевіряє наявність пошкоджених файлів під час завантаження гри, і якщо виявлено пошкоджені файли, показує помилку хешу в журналі.\n\nНе впливає на продуктивність і призначений для усунення несправностей.\n\nЗалиште увімкненим, якщо не впевнені.", "AudioBackendTooltip": "Змінює серверну частину, яка використовується для відтворення аудіо.\n\nSDL2 є кращим, тоді як OpenAL і SoundIO використовуються як резервні варіанти. Dummy не матиме звуку.\n\nВстановіть SDL2, якщо не впевнені.", @@ -461,16 +572,16 @@ "MemoryManagerSoftwareTooltip": "Використовує програмну таблицю сторінок для перекладу адрес. Найвища точність, але найповільніша продуктивність.", "MemoryManagerHostTooltip": "Пряме відображення пам'яті в адресному просторі хосту. Набагато швидша компіляція та виконання JIT.", "MemoryManagerUnsafeTooltip": "Пряме відображення пам’яті, але не маскує адресу в гостьовому адресному просторі перед доступом. Швидше, але ціною безпеки. Гостьова програма може отримати доступ до пам’яті з будь-якого місця в Ryujinx, тому запускайте в цьому режимі лише програми, яким ви довіряєте.", - "UseHypervisorTooltip": "Use Hypervisor instead of JIT. Greatly improves performance when available, but can be unstable in its current state.", + "UseHypervisorTooltip": "Використання гіпервізор замість JIT. Значно покращує продуктивність, коли доступний, але може бути нестабільним у поточному стані.", "DRamTooltip": "Використовує альтернативний макет MemoryMode для імітації моделі розробки Switch.\n\nЦе корисно лише для пакетів текстур з вищою роздільною здатністю або модифікацій із роздільною здатністю 4K. НЕ покращує продуктивність.\n\nЗалиште вимкненим, якщо не впевнені.", "IgnoreMissingServicesTooltip": "Ігнорує нереалізовані служби Horizon OS. Це може допомогти в обході збоїв під час завантаження певних ігор.\n\nЗалиште вимкненим, якщо не впевнені.", "GraphicsBackendThreadingTooltip": "Виконує команди графічного сервера в другому потоці.\n\nПрискорює компіляцію шейдерів, зменшує затримки та покращує продуктивність драйверів GPU без власної підтримки багатопоточності. Трохи краща продуктивність на драйверах з багатопотоковістю.\nВстановіть значення «Авто», якщо не впевнені", "GalThreadingTooltip": "Виконує команди графічного сервера в другому потоці.\n\nПрискорює компіляцію шейдерів, зменшує затримки та покращує продуктивність драйверів GPU без власної підтримки багатопоточності. Трохи краща продуктивність на драйверах з багатопотоковістю.\n\nВстановіть значення «Авто», якщо не впевнені.", "ShaderCacheToggleTooltip": "Зберігає кеш дискового шейдера, що зменшує затримки під час наступних запусків.\n\nЗалиште увімкненим, якщо не впевнені.", - "ResolutionScaleTooltip": "Масштаб роздільної здатності, застосована до відповідних цілей візуалізації", + "ResolutionScaleTooltip": "Множить роздільну здатність гри.\n\nДеякі ігри можуть не працювати з цією функцією, і виглядатимуть піксельними; для цих ігор треба знайти модифікації, що зупиняють згладжування або підвищують роздільну здатність. Для останніх модифікацій, вибирайте \"Native\".\n\nЦей параметр можна міняти коли гра запущена кліком на \"Застосувати\"; ви можете перемістити вікно налаштувань і поекспериментувати з видом гри.\n\nМайте на увазі, що 4x це занадто для будь-якого комп'ютера.", "ResolutionScaleEntryTooltip": "Масштаб роздільної здатності з плаваючою комою, наприклад 1,5. Не інтегральні масштаби, швидше за все, спричинять проблеми або збій.", - "AnisotropyTooltip": "Рівень анізотропної фільтрації (встановіть на «Авто», щоб використовувати значення, яке вимагає гра)", - "AspectRatioTooltip": "Співвідношення сторін, застосоване до вікна візуалізації.", + "AnisotropyTooltip": "Рівень анізотропної фільтрації. Встановіть на «Авто», щоб використовувати значення, яке вимагає гра.", + "AspectRatioTooltip": "Співвідношення сторін застосовано до вікна рендера.\n\nМіняйте тільки, якщо використовуєте модифікацію співвідношення сторін для гри, інакше графіка буде розтягнута.\n\nЗалиште на \"16:9\", якщо не впевнені.", "ShaderDumpPathTooltip": "Шлях скидання графічних шейдерів", "FileLogTooltip": "Зберігає журнал консолі у файл журналу на диску. Не впливає на продуктивність.", "StubLogTooltip": "Друкує повідомлення журналу-заглушки на консолі. Не впливає на продуктивність.", @@ -504,6 +615,8 @@ "EnableInternetAccessTooltip": "Дозволяє емульованій програмі підключатися до Інтернету.\n\nІгри з режимом локальної мережі можуть підключатися одна до одної, якщо це увімкнено, і системи підключені до однієї точки доступу. Сюди входять і справжні консолі.\n\nНЕ дозволяє підключатися до серверів Nintendo. Може призвести до збою в деяких іграх, які намагаються підключитися до Інтернету.\n\nЗалиште вимкненим, якщо не впевнені.", "GameListContextMenuManageCheatToolTip": "Керування читами", "GameListContextMenuManageCheat": "Керування читами", + "GameListContextMenuManageModToolTip": "Керування модами", + "GameListContextMenuManageMod": "Керування модами", "ControllerSettingsStickRange": "Діапазон:", "DialogStopEmulationTitle": "Ryujinx - Зупинити емуляцію", "DialogStopEmulationMessage": "Ви впевнені, що хочете зупинити емуляцію?", @@ -515,8 +628,6 @@ "SettingsTabCpuMemory": "Пам'ять ЦП", "DialogUpdaterFlatpakNotSupportedMessage": "Будь ласка, оновіть Ryujinx через FlatHub.", "UpdaterDisabledWarningTitle": "Програму оновлення вимкнено!", - "GameListContextMenuOpenSdModsDirectory": "Відкрити каталог модифікацій Atmosphere", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Відкриває альтернативний каталог SD-карти Atmosphere, який містить модифікації програми. Корисно для модифікацій, упакованих для реального обладнання.", "ControllerSettingsRotate90": "Повернути на 90° за годинниковою стрілкою", "IconSize": "Розмір значка", "IconSizeTooltip": "Змінити розмір значків гри", @@ -544,12 +655,13 @@ "SwkbdMinCharacters": "Мінімальна кількість символів: {0}", "SwkbdMinRangeCharacters": "Має бути {0}-{1} символів", "SoftwareKeyboard": "Програмна клавіатура", - "SoftwareKeyboardModeNumbersOnly": "Must be numbers only", - "SoftwareKeyboardModeAlphabet": "Must be non CJK-characters only", - "SoftwareKeyboardModeASCII": "Must be ASCII text only", - "DialogControllerAppletMessagePlayerRange": "Програма запитує {0} гравця(ів) з:\n\nТИПИ: {1}\n\nГРАВЦІ: {2}\n\n{3}Будь ласка, відкрийте «Налаштування» та повторно налаштуйте «Введення» або натисніть «Закрити».", - "DialogControllerAppletMessage": "Програма запитує рівно стільки гравців: {0} з:\n\nТИПАМИ: {1}\n\nГРАВЦІВ: {2}\n\n{3}Будь ласка, відкрийте «Налаштування» та повторно налаштуйте «Введення» або натисніть «Закрити».", - "DialogControllerAppletDockModeSet": "Встановлено режим док-станції. Ручний також недійсний.\n", + "SoftwareKeyboardModeNumeric": "Повинно бути лише 0-9 або “.”", + "SoftwareKeyboardModeAlphabet": "Повинно бути лише не CJK-символи", + "SoftwareKeyboardModeASCII": "Повинно бути лише ASCII текст", + "ControllerAppletControllers": "Підтримувані контролери:", + "ControllerAppletPlayers": "Гравці:", + "ControllerAppletDescription": "Поточна конфігурація невірна. Відкрийте налаштування та переналаштуйте Ваші дані.", + "ControllerAppletDocked": "Встановлений режим в док-станції. Вимкніть портативні контролери.", "UpdaterRenaming": "Перейменування старих файлів...", "UpdaterRenameFailed": "Програмі оновлення не вдалося перейменувати файл: {0}", "UpdaterAddingFiles": "Додавання нових файлів...", @@ -587,42 +699,46 @@ "Writable": "Можливість запису", "SelectDlcDialogTitle": "Виберіть файли DLC", "SelectUpdateDialogTitle": "Виберіть файли оновлення", + "SelectModDialogTitle": "Виберіть теку з модами", "UserProfileWindowTitle": "Менеджер профілів користувачів", "CheatWindowTitle": "Менеджер читів", "DlcWindowTitle": "Менеджер вмісту для завантаження", + "ModWindowTitle": "Керувати модами для {0} ({1})", "UpdateWindowTitle": "Менеджер оновлення назв", "CheatWindowHeading": "Коди доступні для {0} [{1}]", - "BuildId": "BuildId:", + "BuildId": "ID збірки:", "DlcWindowHeading": "Вміст для завантаження, доступний для {1} ({2}): {0}", + "ModWindowHeading": "{0} мод(ів)", "UserProfilesEditProfile": "Редагувати вибране", "Cancel": "Скасувати", "Save": "Зберегти", "Discard": "Скасувати", + "Paused": "Призупинено", "UserProfilesSetProfileImage": "Встановити зображення профілю", - "UserProfileEmptyNameError": "Назва обов'язкова", - "UserProfileNoImageError": "Зображення профілю обов'язкове", + "UserProfileEmptyNameError": "Імʼя обовʼязкове", + "UserProfileNoImageError": "Зображення профілю обовʼязкове", "GameUpdateWindowHeading": "{0} Доступні оновлення для {1} ({2})", - "SettingsTabHotkeysResScaleUpHotkey": "Збільшити роздільну здатність:", - "SettingsTabHotkeysResScaleDownHotkey": "Зменшити роздільну здатність:", - "UserProfilesName": "Ім'я", + "SettingsTabHotkeysResScaleUpHotkey": "Збільшити роздільність:", + "SettingsTabHotkeysResScaleDownHotkey": "Зменшити роздільність:", + "UserProfilesName": "Імʼя", "UserProfilesUserId": "ID користувача:", "SettingsTabGraphicsBackend": "Графічний сервер", - "SettingsTabGraphicsBackendTooltip": "Графічний сервер для використання", + "SettingsTabGraphicsBackendTooltip": "Виберіть backend графіки, що буде використовуватись в емуляторі.\n\n\"Vulkan\" краще для всіх сучасних відеокарт, якщо драйвери вчасно оновлюються. У Vulkan також швидше компілюються шейдери (менше \"заїкання\" зображення) на відеокартах всіх компаній.\n\n\"OpenGL\" може дати кращі результати на старих відеокартах Nvidia, старих відеокартах AMD на Linux, або на відеокартах з маленькою кількістю VRAM, але \"заїкання\" через компіляцію шейдерів будуть частіші.\n\nЯкщо не впевнені, встановіть на \"Vulkan\". Встановіть на \"OpenGL\", якщо Ваша відеокарта не підтримує Vulkan навіть на останніх драйверах.", "SettingsEnableTextureRecompression": "Увімкнути рекомпресію текстури", - "SettingsEnableTextureRecompressionTooltip": "Стискає певні текстури, щоб зменшити використання VRAM.\n\nРекомендовано для використання з графічними процесорами, які мають менш ніж 4 ГБ відеопам’яті.\n\nЗалиште вимкненим, якщо не впевнені.", + "SettingsEnableTextureRecompressionTooltip": "Стискає текстури ASTC, щоб зменшити використання VRAM.\n\nЦим форматом текстур користуються такі ігри, як Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder і The Legend of Zelda: Tears of the Kingdom.\n\nЦі ігри, скоріше всього крашнуться на відеокартах з розміром VRAM в 4 Гб і менше.\n\nВмикайте тільки якщо у Вас закінчується VRAM на цих іграх. Залиште на \"Вимкнути\", якщо не впевнені.", "SettingsTabGraphicsPreferredGpu": "Бажаний GPU", - "SettingsTabGraphicsPreferredGpuTooltip": "Виберіть відеокарту, яка використовуватиметься з графічним сервером Vulkan.\n\nНе впливає на графічний процесор, який використовуватиме OpenGL.\n\nЯкщо не впевнені, встановіть графічний процесор, позначений як «dGPU». Якщо такого немає, залиште це.", + "SettingsTabGraphicsPreferredGpuTooltip": "Виберіть відеокарту, яка використовуватиметься з графічним сервером Vulkan.\n\nНе впливає на графічний процесор, який використовуватиме OpenGL.\n\nВстановіть графічний процесор, позначений як «dGPU», якщо не впевнені. Якщо такого немає, не чіпайте.", "SettingsAppRequiredRestartMessage": "Необхідно перезапустити Ryujinx", "SettingsGpuBackendRestartMessage": "Налаштування графічного сервера або GPU було змінено. Для цього знадобиться перезапуск", - "SettingsGpuBackendRestartSubMessage": "Ви хочете перезапустити зараз?", - "RyujinxUpdaterMessage": "Хочете оновити Ryujinx до останньої версії?", + "SettingsGpuBackendRestartSubMessage": "Бажаєте перезапустити зараз?", + "RyujinxUpdaterMessage": "Бажаєте оновити Ryujinx до останньої версії?", "SettingsTabHotkeysVolumeUpHotkey": "Збільшити гучність:", "SettingsTabHotkeysVolumeDownHotkey": "Зменшити гучність:", "SettingsEnableMacroHLE": "Увімкнути макрос HLE", "SettingsEnableMacroHLETooltip": "Високорівнева емуляція коду макросу GPU.\n\nПокращує продуктивність, але може викликати графічні збої в деяких іграх.\n\nЗалиште увімкненим, якщо не впевнені.", - "SettingsEnableColorSpacePassthrough": "Color Space Passthrough", - "SettingsEnableColorSpacePassthroughTooltip": "Directs the Vulkan backend to pass through color information without specifying a color space. For users with wide gamut displays, this may result in more vibrant colors, at the cost of color correctness.", - "VolumeShort": "Гуч", + "SettingsEnableColorSpacePassthrough": "Наскрізний колірний простір", + "SettingsEnableColorSpacePassthroughTooltip": "Дозволяє серверу Vulkan передавати інформацію про колір без вказівки колірного простору. Для користувачів з екранами з широкою гамою це може призвести до більш яскравих кольорів, але шляхом втрати коректності передачі кольору.", + "VolumeShort": "Гуч.", "UserProfilesManageSaves": "Керувати збереженнями", "DeleteUserSave": "Ви хочете видалити збереження користувача для цієї гри?", "IrreversibleActionNote": "Цю дію не можна скасувати.", @@ -634,23 +750,31 @@ "UserProfilesRecoverLostAccounts": "Відновлення втрачених облікових записів", "Recover": "Відновити", "UserProfilesRecoverHeading": "Знайдено збереження для наступних облікових записів", - "UserProfilesRecoverEmptyList": "No profiles to recover", - "GraphicsAATooltip": "Applies anti-aliasing to the game render", - "GraphicsAALabel": "Anti-Aliasing:", - "GraphicsScalingFilterLabel": "Scaling Filter:", - "GraphicsScalingFilterTooltip": "Enables Framebuffer Scaling", - "GraphicsScalingFilterLevelLabel": "Level", - "GraphicsScalingFilterLevelTooltip": "Set Scaling Filter Level", - "SmaaLow": "SMAA Low", - "SmaaMedium": "SMAA Medium", - "SmaaHigh": "SMAA High", - "SmaaUltra": "SMAA Ultra", - "UserEditorTitle": "Edit User", - "UserEditorTitleCreate": "Create User", - "SettingsTabNetworkInterface": "Network Interface:", - "NetworkInterfaceTooltip": "The network interface used for LAN features", - "NetworkInterfaceDefault": "Default", - "PackagingShaders": "Packaging Shaders", - "AboutChangelogButton": "View Changelog on GitHub", - "AboutChangelogButtonTooltipMessage": "Click to open the changelog for this version in your default browser." -} \ No newline at end of file + "UserProfilesRecoverEmptyList": "Немає профілів для відновлення", + "GraphicsAATooltip": "Застосовує згладження до рендера гри.\n\nFXAA розмиє більшість зображення, а SMAA спробує знайти нерівні краї та згладити їх.\n\nНе рекомендується використовувати разом з фільтром масштабування FSR.\n\nЦю опцію можна міняти коли гра запущена кліком на \"Застосувати; ви можете відсунути вікно налаштувань і поекспериментувати з видом гри.\n\nЗалиште на \"Немає\", якщо не впевнені.", + "GraphicsAALabel": "Згладжування:", + "GraphicsScalingFilterLabel": "Фільтр масштабування:", + "GraphicsScalingFilterTooltip": "Виберіть фільтр масштабування, що використається при збільшенні роздільної здатності.\n\n\"Білінійний\" добре виглядає в 3D іграх, і хороше налаштування за умовчуванням.\n\n\"Найближчий\" рекомендується для ігор з піксель-артом.\n\n\"FSR 1.0\" - це просто фільтр різкості, не рекомендується використовувати разом з FXAA або SMAA.\n\nЦю опцію можна міняти коли гра запущена кліком на \"Застосувати; ви можете відсунути вікно налаштувань і поекспериментувати з видом гри.\n\nЗалиште на \"Білінійний\", якщо не впевнені.", + "GraphicsScalingFilterBilinear": "Білінійний", + "GraphicsScalingFilterNearest": "Найближчий", + "GraphicsScalingFilterFsr": "FSR", + "GraphicsScalingFilterLevelLabel": "Рівень", + "GraphicsScalingFilterLevelTooltip": "Встановити рівень різкості в FSR 1.0. Чим вище - тим різкіше.", + "SmaaLow": "SMAA Низький", + "SmaaMedium": "SMAA Середній", + "SmaaHigh": "SMAA Високий", + "SmaaUltra": "SMAA Ультра", + "UserEditorTitle": "Редагувати користувача", + "UserEditorTitleCreate": "Створити користувача", + "SettingsTabNetworkInterface": "Мережевий інтерфейс:", + "NetworkInterfaceTooltip": "Мережевий інтерфейс, що використовується для LAN/LDN.\n\nРазом з VPN або XLink Kai, і грою що підтримує LAN, може імітувати з'єднання в однаковій мережі через Інтернет.", + "NetworkInterfaceDefault": "Стандартний", + "PackagingShaders": "Пакування шейдерів", + "AboutChangelogButton": "Переглянути журнал змін на GitHub", + "AboutChangelogButtonTooltipMessage": "Клацніть, щоб відкрити журнал змін для цієї версії у стандартному браузері.", + "SettingsTabNetworkMultiplayer": "Мережева гра", + "MultiplayerMode": "Режим:", + "MultiplayerModeTooltip": "Змінити LDN мультиплеєру.\n\nLdnMitm змінить функціонал бездротової/локальної гри в іграх, щоб вони працювали так, ніби це LAN, що дозволяє локальні підключення в тій самій мережі з іншими екземплярами Ryujinx та хакнутими консолями Nintendo Switch, які мають встановлений модуль ldn_mitm.\n\nМультиплеєр вимагає, щоб усі гравці були на одній і тій же версії гри (наприклад Super Smash Bros. Ultimate v13.0.1 не зможе під'єднатися до v13.0.0).\n\nЗалиште на \"Вимкнено\", якщо не впевнені, ", + "MultiplayerModeDisabled": "Вимкнено", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx/Assets/Locales/zh_CN.json b/src/Ryujinx/Assets/Locales/zh_CN.json new file mode 100644 index 000000000..66f59ecd0 --- /dev/null +++ b/src/Ryujinx/Assets/Locales/zh_CN.json @@ -0,0 +1,780 @@ +{ + "Language": "简体中文", + "MenuBarFileOpenApplet": "打开小程序", + "MenuBarFileOpenAppletOpenMiiAppletToolTip": "打开独立的 Mii 小程序", + "SettingsTabInputDirectMouseAccess": "直通鼠标操作", + "SettingsTabSystemMemoryManagerMode": "内存管理模式:", + "SettingsTabSystemMemoryManagerModeSoftware": "软件管理", + "SettingsTabSystemMemoryManagerModeHost": "本机映射 (较快)", + "SettingsTabSystemMemoryManagerModeHostUnchecked": "跳过检查的本机映射 (最快,但不安全)", + "SettingsTabSystemUseHypervisor": "使用 Hypervisor 虚拟化", + "MenuBarFile": "文件(_F)", + "MenuBarFileOpenFromFile": "加载游戏文件(_L)", + "MenuBarFileOpenUnpacked": "加载解包后的游戏(_U)", + "MenuBarFileOpenEmuFolder": "打开 Ryujinx 系统目录", + "MenuBarFileOpenLogsFolder": "打开日志目录", + "MenuBarFileExit": "退出(_E)", + "MenuBarOptions": "选项(_O)", + "MenuBarOptionsToggleFullscreen": "切换全屏", + "MenuBarOptionsStartGamesInFullscreen": "全屏模式启动游戏", + "MenuBarOptionsStopEmulation": "停止模拟", + "MenuBarOptionsSettings": "设置(_S)", + "MenuBarOptionsManageUserProfiles": "管理用户账户(_M)", + "MenuBarActions": "操作(_A)", + "MenuBarOptionsSimulateWakeUpMessage": "模拟唤醒消息", + "MenuBarActionsScanAmiibo": "扫描 Amiibo", + "MenuBarTools": "工具(_T)", + "MenuBarToolsInstallFirmware": "安装系统固件", + "MenuBarFileToolsInstallFirmwareFromFile": "从 XCI 或 ZIP 文件中安装系统固件", + "MenuBarFileToolsInstallFirmwareFromDirectory": "从文件夹中安装系统固件", + "MenuBarToolsManageFileTypes": "管理文件扩展名", + "MenuBarToolsInstallFileTypes": "关联文件扩展名", + "MenuBarToolsUninstallFileTypes": "取消关联扩展名", + "MenuBarView": "视图(_V)", + "MenuBarViewWindow": "窗口大小", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "帮助(_H)", + "MenuBarHelpCheckForUpdates": "检查更新", + "MenuBarHelpAbout": "关于", + "MenuSearch": "搜索…", + "GameListHeaderFavorite": "收藏", + "GameListHeaderIcon": "图标", + "GameListHeaderApplication": "名称", + "GameListHeaderDeveloper": "制作商", + "GameListHeaderVersion": "版本", + "GameListHeaderTimePlayed": "游玩时长", + "GameListHeaderLastPlayed": "最近游玩", + "GameListHeaderFileExtension": "扩展名", + "GameListHeaderFileSize": "大小", + "GameListHeaderPath": "路径", + "GameListContextMenuOpenUserSaveDirectory": "打开用户存档目录", + "GameListContextMenuOpenUserSaveDirectoryToolTip": "打开储存游戏用户存档的目录", + "GameListContextMenuOpenDeviceSaveDirectory": "打开系统数据目录", + "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "打开储存游戏系统数据的目录", + "GameListContextMenuOpenBcatSaveDirectory": "打开 BCAT 数据目录", + "GameListContextMenuOpenBcatSaveDirectoryToolTip": "打开储存游戏 BCAT 数据的目录", + "GameListContextMenuManageTitleUpdates": "管理游戏更新", + "GameListContextMenuManageTitleUpdatesToolTip": "打开游戏更新管理窗口", + "GameListContextMenuManageDlc": "管理 DLC", + "GameListContextMenuManageDlcToolTip": "打开 DLC 管理窗口", + "GameListContextMenuCacheManagement": "缓存管理", + "GameListContextMenuCacheManagementPurgePptc": "清除 PPTC 缓存文件", + "GameListContextMenuCacheManagementPurgePptcToolTip": "删除游戏的 PPTC 缓存文件,下次启动游戏时重新编译生成 PPTC 缓存文件", + "GameListContextMenuCacheManagementPurgeShaderCache": "清除着色器缓存文件", + "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "删除游戏的着色器缓存文件,下次启动游戏时重新生成着色器缓存文件", + "GameListContextMenuCacheManagementOpenPptcDirectory": "打开 PPTC 缓存目录", + "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "打开储存游戏 PPTC 缓存文件的目录", + "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "打开着色器缓存目录", + "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "打开储存游戏着色器缓存文件的目录", + "GameListContextMenuExtractData": "提取数据", + "GameListContextMenuExtractDataExeFS": "ExeFS", + "GameListContextMenuExtractDataExeFSToolTip": "从游戏的当前状态中提取 ExeFS 分区 (包括更新)", + "GameListContextMenuExtractDataRomFS": "RomFS", + "GameListContextMenuExtractDataRomFSToolTip": "从游戏的当前状态中提取 RomFS 分区 (包括更新)", + "GameListContextMenuExtractDataLogo": "图标", + "GameListContextMenuExtractDataLogoToolTip": "从游戏的当前状态中提取图标 (包括更新)", + "GameListContextMenuCreateShortcut": "创建游戏快捷方式", + "GameListContextMenuCreateShortcutToolTip": "创建一个直接启动此游戏的桌面快捷方式", + "GameListContextMenuCreateShortcutToolTipMacOS": "在 macOS 的应用程序目录中创建一个直接启动此游戏的快捷方式", + "GameListContextMenuOpenModsDirectory": "打开 MOD 目录", + "GameListContextMenuOpenModsDirectoryToolTip": "打开存放游戏 MOD 的目录", + "GameListContextMenuOpenSdModsDirectory": "打开大气层系统 MOD 目录", + "GameListContextMenuOpenSdModsDirectoryToolTip": "打开存放适用于大气层系统的游戏 MOD 的目录,对于为真实硬件打包的 MOD 非常有用", + "StatusBarGamesLoaded": "{0}/{1} 游戏加载完成", + "StatusBarSystemVersion": "系统固件版本:{0}", + "LinuxVmMaxMapCountDialogTitle": "检测到操作系统内存映射最大数量被设置的过低", + "LinuxVmMaxMapCountDialogTextPrimary": "你想要将操作系统 vm.max_map_count 的值增加到 {0} 吗", + "LinuxVmMaxMapCountDialogTextSecondary": "有些游戏可能会尝试创建超过当前系统允许的内存映射最大数量,若超过当前最大数量,Ryujinx 模拟器将会闪退。", + "LinuxVmMaxMapCountDialogButtonUntilRestart": "确定,临时保存(重启后失效)", + "LinuxVmMaxMapCountDialogButtonPersistent": "确定,永久保存", + "LinuxVmMaxMapCountWarningTextPrimary": "内存映射的最大数量低于推荐值。", + "LinuxVmMaxMapCountWarningTextSecondary": "vm.max_map_count ({0}) 的当前值小于 {1}。 有些游戏可能会尝试创建超过当前系统允许的内存映射最大数量,若超过当前最大数量,Ryujinx 模拟器将会闪退。\n\n你可以手动增加内存映射最大数量,或者安装 pkexec,它可以辅助 Ryujinx 完成内存映射最大数量的修改操作。", + "Settings": "设置", + "SettingsTabGeneral": "用户界面", + "SettingsTabGeneralGeneral": "常规", + "SettingsTabGeneralEnableDiscordRichPresence": "启用 Discord 在线状态展示", + "SettingsTabGeneralCheckUpdatesOnLaunch": "启动时检查更新", + "SettingsTabGeneralShowConfirmExitDialog": "退出游戏时需要确认", + "SettingsTabGeneralRememberWindowState": "记住窗口大小和位置", + "SettingsTabGeneralHideCursor": "隐藏鼠标指针:", + "SettingsTabGeneralHideCursorNever": "从不隐藏", + "SettingsTabGeneralHideCursorOnIdle": "自动隐藏", + "SettingsTabGeneralHideCursorAlways": "始终隐藏", + "SettingsTabGeneralGameDirectories": "游戏目录", + "SettingsTabGeneralAdd": "添加", + "SettingsTabGeneralRemove": "删除", + "SettingsTabSystem": "系统", + "SettingsTabSystemCore": "核心", + "SettingsTabSystemSystemRegion": "系统区域:", + "SettingsTabSystemSystemRegionJapan": "日本", + "SettingsTabSystemSystemRegionUSA": "美国", + "SettingsTabSystemSystemRegionEurope": "欧洲", + "SettingsTabSystemSystemRegionAustralia": "澳大利亚", + "SettingsTabSystemSystemRegionChina": "中国", + "SettingsTabSystemSystemRegionKorea": "韩国", + "SettingsTabSystemSystemRegionTaiwan": "台湾地区", + "SettingsTabSystemSystemLanguage": "系统语言:", + "SettingsTabSystemSystemLanguageJapanese": "日语", + "SettingsTabSystemSystemLanguageAmericanEnglish": "英语(美国)", + "SettingsTabSystemSystemLanguageFrench": "法语", + "SettingsTabSystemSystemLanguageGerman": "德语", + "SettingsTabSystemSystemLanguageItalian": "意大利语", + "SettingsTabSystemSystemLanguageSpanish": "西班牙语", + "SettingsTabSystemSystemLanguageChinese": "中文(简体)——无效", + "SettingsTabSystemSystemLanguageKorean": "韩语", + "SettingsTabSystemSystemLanguageDutch": "荷兰语", + "SettingsTabSystemSystemLanguagePortuguese": "葡萄牙语", + "SettingsTabSystemSystemLanguageRussian": "俄语", + "SettingsTabSystemSystemLanguageTaiwanese": "中文(繁体)——无效", + "SettingsTabSystemSystemLanguageBritishEnglish": "英语(英国)", + "SettingsTabSystemSystemLanguageCanadianFrench": "加拿大法语", + "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "拉美西班牙语", + "SettingsTabSystemSystemLanguageSimplifiedChinese": "简体中文(推荐)", + "SettingsTabSystemSystemLanguageTraditionalChinese": "繁体中文(推荐)", + "SettingsTabSystemSystemTimeZone": "系统时区:", + "SettingsTabSystemSystemTime": "系统时钟:", + "SettingsTabSystemEnableVsync": "启用垂直同步", + "SettingsTabSystemEnablePptc": "开启 PPTC 缓存", + "SettingsTabSystemEnableFsIntegrityChecks": "启用文件系统完整性检查", + "SettingsTabSystemAudioBackend": "音频处理引擎:", + "SettingsTabSystemAudioBackendDummy": "无", + "SettingsTabSystemAudioBackendOpenAL": "OpenAL", + "SettingsTabSystemAudioBackendSoundIO": "SoundIO", + "SettingsTabSystemAudioBackendSDL2": "SDL2", + "SettingsTabSystemHacks": "修改", + "SettingsTabSystemHacksNote": "会导致模拟器不稳定", + "SettingsTabSystemExpandDramSize": "使用开发机的内存布局(开发人员使用)", + "SettingsTabSystemIgnoreMissingServices": "忽略缺失的服务", + "SettingsTabGraphics": "图形", + "SettingsTabGraphicsAPI": "图形 API", + "SettingsTabGraphicsEnableShaderCache": "启用着色器缓存", + "SettingsTabGraphicsAnisotropicFiltering": "各向异性过滤:", + "SettingsTabGraphicsAnisotropicFilteringAuto": "自动", + "SettingsTabGraphicsAnisotropicFiltering2x": "2x", + "SettingsTabGraphicsAnisotropicFiltering4x": "4x", + "SettingsTabGraphicsAnisotropicFiltering8x": "8x", + "SettingsTabGraphicsAnisotropicFiltering16x": "16x", + "SettingsTabGraphicsResolutionScale": "分辨率缩放:", + "SettingsTabGraphicsResolutionScaleCustom": "自定义(不推荐)", + "SettingsTabGraphicsResolutionScaleNative": "原生 (720p/1080p)", + "SettingsTabGraphicsResolutionScale2x": "2 倍 (1440p/2160p)", + "SettingsTabGraphicsResolutionScale3x": "3 倍 (2160p/3240p)", + "SettingsTabGraphicsResolutionScale4x": "4 倍 (2880p/4320p) (不推荐)", + "SettingsTabGraphicsAspectRatio": "宽高比:", + "SettingsTabGraphicsAspectRatio4x3": "4:3", + "SettingsTabGraphicsAspectRatio16x9": "16:9", + "SettingsTabGraphicsAspectRatio16x10": "16:10", + "SettingsTabGraphicsAspectRatio21x9": "21:9", + "SettingsTabGraphicsAspectRatio32x9": "32:9", + "SettingsTabGraphicsAspectRatioStretch": "拉伸以适应窗口", + "SettingsTabGraphicsDeveloperOptions": "开发者选项", + "SettingsTabGraphicsShaderDumpPath": "图形着色器转储路径:", + "SettingsTabLogging": "日志", + "SettingsTabLoggingLogging": "日志", + "SettingsTabLoggingEnableLoggingToFile": "将日志写入文件", + "SettingsTabLoggingEnableStubLogs": "启用存根日志", + "SettingsTabLoggingEnableInfoLogs": "启用信息日志", + "SettingsTabLoggingEnableWarningLogs": "启用警告日志", + "SettingsTabLoggingEnableErrorLogs": "启用错误日志", + "SettingsTabLoggingEnableTraceLogs": "启用跟踪日志", + "SettingsTabLoggingEnableGuestLogs": "启用访客日志", + "SettingsTabLoggingEnableFsAccessLogs": "启用文件访问日志", + "SettingsTabLoggingFsGlobalAccessLogMode": "文件系统全局访问日志模式:", + "SettingsTabLoggingDeveloperOptions": "开发者选项", + "SettingsTabLoggingDeveloperOptionsNote": "警告:会降低模拟器性能", + "SettingsTabLoggingGraphicsBackendLogLevel": "图形引擎日志级别:", + "SettingsTabLoggingGraphicsBackendLogLevelNone": "无", + "SettingsTabLoggingGraphicsBackendLogLevelError": "错误", + "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "减速", + "SettingsTabLoggingGraphicsBackendLogLevelAll": "全部", + "SettingsTabLoggingEnableDebugLogs": "启用调试日志", + "SettingsTabInput": "输入", + "SettingsTabInputEnableDockedMode": "主机模式", + "SettingsTabInputDirectKeyboardAccess": "直通键盘控制", + "SettingsButtonSave": "保存", + "SettingsButtonClose": "关闭", + "SettingsButtonOk": "确定", + "SettingsButtonCancel": "取消", + "SettingsButtonApply": "应用", + "ControllerSettingsPlayer": "玩家", + "ControllerSettingsPlayer1": "玩家 1", + "ControllerSettingsPlayer2": "玩家 2", + "ControllerSettingsPlayer3": "玩家 3", + "ControllerSettingsPlayer4": "玩家 4", + "ControllerSettingsPlayer5": "玩家 5", + "ControllerSettingsPlayer6": "玩家 6", + "ControllerSettingsPlayer7": "玩家 7", + "ControllerSettingsPlayer8": "玩家 8", + "ControllerSettingsHandheld": "掌机模式", + "ControllerSettingsInputDevice": "输入设备", + "ControllerSettingsRefresh": "刷新", + "ControllerSettingsDeviceDisabled": "禁用", + "ControllerSettingsControllerType": "手柄类型", + "ControllerSettingsControllerTypeHandheld": "掌机", + "ControllerSettingsControllerTypeProController": "Pro 手柄", + "ControllerSettingsControllerTypeJoyConPair": "双 JoyCon 手柄", + "ControllerSettingsControllerTypeJoyConLeft": "左 JoyCon 手柄", + "ControllerSettingsControllerTypeJoyConRight": "右 JoyCon 手柄", + "ControllerSettingsProfile": "配置文件", + "ControllerSettingsProfileDefault": "默认设置", + "ControllerSettingsLoad": "加载", + "ControllerSettingsAdd": "新建", + "ControllerSettingsRemove": "删除", + "ControllerSettingsButtons": "基础按键", + "ControllerSettingsButtonA": "A", + "ControllerSettingsButtonB": "B", + "ControllerSettingsButtonX": "X", + "ControllerSettingsButtonY": "Y", + "ControllerSettingsButtonPlus": "+", + "ControllerSettingsButtonMinus": "-", + "ControllerSettingsDPad": "方向键", + "ControllerSettingsDPadUp": "上", + "ControllerSettingsDPadDown": "下", + "ControllerSettingsDPadLeft": "左", + "ControllerSettingsDPadRight": "右", + "ControllerSettingsStickButton": "按下摇杆", + "ControllerSettingsStickUp": "上", + "ControllerSettingsStickDown": "下", + "ControllerSettingsStickLeft": "左", + "ControllerSettingsStickRight": "右", + "ControllerSettingsStickStick": "摇杆", + "ControllerSettingsStickInvertXAxis": "摇杆左右反转", + "ControllerSettingsStickInvertYAxis": "摇杆上下反转", + "ControllerSettingsStickDeadzone": "死区:", + "ControllerSettingsLStick": "左摇杆", + "ControllerSettingsRStick": "右摇杆", + "ControllerSettingsTriggersLeft": "左扳机", + "ControllerSettingsTriggersRight": "右扳机", + "ControllerSettingsTriggersButtonsLeft": "左扳机键", + "ControllerSettingsTriggersButtonsRight": "右扳机键", + "ControllerSettingsTriggers": "扳机", + "ControllerSettingsTriggerL": "L", + "ControllerSettingsTriggerR": "R", + "ControllerSettingsTriggerZL": "ZL", + "ControllerSettingsTriggerZR": "ZR", + "ControllerSettingsLeftSL": "SL", + "ControllerSettingsLeftSR": "SR", + "ControllerSettingsRightSL": "SL", + "ControllerSettingsRightSR": "SR", + "ControllerSettingsExtraButtonsLeft": "左背键", + "ControllerSettingsExtraButtonsRight": "右背键", + "ControllerSettingsMisc": "其他", + "ControllerSettingsTriggerThreshold": "扳机阈值:", + "ControllerSettingsMotion": "体感", + "ControllerSettingsMotionUseCemuhookCompatibleMotion": "使用 CemuHook 兼容的体感协议", + "ControllerSettingsMotionControllerSlot": "手柄槽位:", + "ControllerSettingsMotionMirrorInput": "镜像操作", + "ControllerSettingsMotionRightJoyConSlot": "右 JoyCon 槽位:", + "ControllerSettingsMotionServerHost": "服务器地址:", + "ControllerSettingsMotionGyroSensitivity": "陀螺仪敏感度:", + "ControllerSettingsMotionGyroDeadzone": "陀螺仪死区:", + "ControllerSettingsSave": "保存", + "ControllerSettingsClose": "关闭", + "KeyUnknown": "未知", + "KeyShiftLeft": "左侧Shift", + "KeyShiftRight": "右侧Shift", + "KeyControlLeft": "左侧Ctrl", + "KeyMacControlLeft": "左侧⌃", + "KeyControlRight": "右侧Ctrl", + "KeyMacControlRight": "右侧⌃", + "KeyAltLeft": "左侧Alt", + "KeyMacAltLeft": "左侧⌥", + "KeyAltRight": "右侧Alt", + "KeyMacAltRight": "右侧⌥", + "KeyWinLeft": "左侧⊞", + "KeyMacWinLeft": "左侧⌘", + "KeyWinRight": "右侧⊞", + "KeyMacWinRight": "右侧⌘", + "KeyMenu": "菜单键", + "KeyUp": "上", + "KeyDown": "下", + "KeyLeft": "左", + "KeyRight": "右", + "KeyEnter": "回车键", + "KeyEscape": "Esc", + "KeySpace": "空格键", + "KeyTab": "Tab", + "KeyBackSpace": "退格键", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "清除键", + "KeyKeypad0": "小键盘0", + "KeyKeypad1": "小键盘1", + "KeyKeypad2": "小键盘2", + "KeyKeypad3": "小键盘3", + "KeyKeypad4": "小键盘4", + "KeyKeypad5": "小键盘5", + "KeyKeypad6": "小键盘6", + "KeyKeypad7": "小键盘7", + "KeyKeypad8": "小键盘8", + "KeyKeypad9": "小键盘9", + "KeyKeypadDivide": "小键盘/", + "KeyKeypadMultiply": "小键盘*", + "KeyKeypadSubtract": "小键盘-", + "KeyKeypadAdd": "小键盘+", + "KeyKeypadDecimal": "小键盘.", + "KeyKeypadEnter": "小键盘回车键", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "未分配", + "GamepadLeftStick": "左摇杆按键", + "GamepadRightStick": "右摇杆按键", + "GamepadLeftShoulder": "左肩键L", + "GamepadRightShoulder": "右肩键R", + "GamepadLeftTrigger": "左扳机键ZL", + "GamepadRightTrigger": "右扳机键ZR", + "GamepadDpadUp": "上键", + "GamepadDpadDown": "下键", + "GamepadDpadLeft": "左键", + "GamepadDpadRight": "右键", + "GamepadMinus": "-键", + "GamepadPlus": "+键", + "GamepadGuide": "主页键", + "GamepadMisc1": "截图键", + "GamepadPaddle1": "其他按键1", + "GamepadPaddle2": "其他按键2", + "GamepadPaddle3": "其他按键3", + "GamepadPaddle4": "其他按键4", + "GamepadTouchpad": "触摸板", + "GamepadSingleLeftTrigger0": "左扳机0", + "GamepadSingleRightTrigger0": "右扳机0", + "GamepadSingleLeftTrigger1": "左扳机1", + "GamepadSingleRightTrigger1": "右扳机1", + "StickLeft": "左摇杆", + "StickRight": "右摇杆", + "UserProfilesSelectedUserProfile": "选定的用户账户:", + "UserProfilesSaveProfileName": "保存名称", + "UserProfilesChangeProfileImage": "更换头像", + "UserProfilesAvailableUserProfiles": "现有用户账户:", + "UserProfilesAddNewProfile": "新建账户", + "UserProfilesDelete": "删除", + "UserProfilesClose": "关闭", + "ProfileNameSelectionWatermark": "输入昵称", + "ProfileImageSelectionTitle": "选择头像", + "ProfileImageSelectionHeader": "选择合适的头像图片", + "ProfileImageSelectionNote": "您可以导入自定义头像,或从模拟器系统固件中选择预设头像", + "ProfileImageSelectionImportImage": "导入图像文件", + "ProfileImageSelectionSelectAvatar": "选择预设头像", + "InputDialogTitle": "输入对话框", + "InputDialogOk": "完成", + "InputDialogCancel": "取消", + "InputDialogAddNewProfileTitle": "选择用户名称", + "InputDialogAddNewProfileHeader": "请输入账户名称", + "InputDialogAddNewProfileSubtext": "(最大长度:{0})", + "AvatarChoose": "保存选定头像", + "AvatarSetBackgroundColor": "设置背景色", + "AvatarClose": "关闭", + "ControllerSettingsLoadProfileToolTip": "加载配置文件", + "ControllerSettingsAddProfileToolTip": "新增配置文件", + "ControllerSettingsRemoveProfileToolTip": "删除配置文件", + "ControllerSettingsSaveProfileToolTip": "保存配置文件", + "MenuBarFileToolsTakeScreenshot": "保存截屏", + "MenuBarFileToolsHideUi": "隐藏菜单栏和状态栏", + "GameListContextMenuRunApplication": "启动游戏", + "GameListContextMenuToggleFavorite": "收藏", + "GameListContextMenuToggleFavoriteToolTip": "切换游戏的收藏状态", + "SettingsTabGeneralTheme": "主题:", + "SettingsTabGeneralThemeDark": "深色(暗黑)", + "SettingsTabGeneralThemeLight": "浅色(亮色)", + "ControllerSettingsConfigureGeneral": "配置", + "ControllerSettingsRumble": "震动", + "ControllerSettingsRumbleStrongMultiplier": "强震动幅度", + "ControllerSettingsRumbleWeakMultiplier": "弱震动幅度", + "DialogMessageSaveNotAvailableMessage": "没有{0} [{1:x16}]的游戏存档", + "DialogMessageSaveNotAvailableCreateSaveMessage": "是否创建该游戏的存档?", + "DialogConfirmationTitle": "Ryujinx - 确认", + "DialogUpdaterTitle": "Ryujinx - 更新", + "DialogErrorTitle": "Ryujinx - 错误", + "DialogWarningTitle": "Ryujinx - 警告", + "DialogExitTitle": "Ryujinx - 退出", + "DialogErrorMessage": "Ryujinx 模拟器发生错误", + "DialogExitMessage": "是否关闭 Ryujinx 模拟器?", + "DialogExitSubMessage": "未保存的进度将会丢失!", + "DialogMessageCreateSaveErrorMessage": "创建指定存档时出错:{0}", + "DialogMessageFindSaveErrorMessage": "查找指定存档时出错:{0}", + "FolderDialogExtractTitle": "选择要提取到的文件夹", + "DialogNcaExtractionMessage": "提取 {1} 的 {0} 分区...", + "DialogNcaExtractionTitle": "Ryujinx - NCA 分区提取", + "DialogNcaExtractionMainNcaNotFoundErrorMessage": "提取失败,所选文件中没有 NCA 文件", + "DialogNcaExtractionCheckLogErrorMessage": "提取失败,请查看日志文件获取详情", + "DialogNcaExtractionSuccessMessage": "提取成功!", + "DialogUpdaterConvertFailedMessage": "无法切换当前 Ryujinx 版本。", + "DialogUpdaterCancelUpdateMessage": "取消更新!", + "DialogUpdaterAlreadyOnLatestVersionMessage": "您使用的 Ryujinx 模拟器是最新版本。", + "DialogUpdaterFailedToGetVersionMessage": "尝试从 Github 获取版本信息时无效,可能由于 GitHub Actions 正在编译新版本。\n请过一会再试。", + "DialogUpdaterConvertFailedGithubMessage": "无法切换至从 Github 接收到的新版 Ryujinx 模拟器。", + "DialogUpdaterDownloadingMessage": "下载更新中...", + "DialogUpdaterExtractionMessage": "正在提取更新...", + "DialogUpdaterRenamingMessage": "正在重命名更新...", + "DialogUpdaterAddingFilesMessage": "安装更新中...", + "DialogUpdaterCompleteMessage": "更新成功!", + "DialogUpdaterRestartMessage": "是否立即重启 Ryujinx 模拟器?", + "DialogUpdaterNoInternetMessage": "没有连接到网络", + "DialogUpdaterNoInternetSubMessage": "请确保互联网连接正常。", + "DialogUpdaterDirtyBuildMessage": "无法更新非官方版本的 Ryujinx 模拟器!", + "DialogUpdaterDirtyBuildSubMessage": "如果想使用受支持的版本,请您在 https://ryujinx.org/ 下载官方版本。", + "DialogRestartRequiredMessage": "需要重启模拟器", + "DialogThemeRestartMessage": "主题设置已保存,需要重启模拟器才能生效。", + "DialogThemeRestartSubMessage": "是否要重启模拟器?", + "DialogFirmwareInstallEmbeddedMessage": "要安装游戏文件中内嵌的系统固件吗?(固件版本 {0})", + "DialogFirmwareInstallEmbeddedSuccessMessage": "Ryujinx 模拟器已经从当前游戏文件中安装了系统固件 {0} 。\n模拟器现在可以正常运行了。", + "DialogFirmwareNoFirmwareInstalledMessage": "未安装系统固件", + "DialogFirmwareInstalledMessage": "已安装系统固件 {0}", + "DialogInstallFileTypesSuccessMessage": "关联文件类型成功!", + "DialogInstallFileTypesErrorMessage": "关联文件类型失败!", + "DialogUninstallFileTypesSuccessMessage": "成功解除文件类型关联!", + "DialogUninstallFileTypesErrorMessage": "解除文件类型关联失败!", + "DialogOpenSettingsWindowLabel": "打开设置窗口", + "DialogControllerAppletTitle": "控制器小窗口", + "DialogMessageDialogErrorExceptionMessage": "显示消息对话框时出错:{0}", + "DialogSoftwareKeyboardErrorExceptionMessage": "显示软件键盘时出错:{0}", + "DialogErrorAppletErrorExceptionMessage": "显示错误对话框时出错:{0}", + "DialogUserErrorDialogMessage": "{0}: {1}", + "DialogUserErrorDialogInfoMessage": "\n有关修复此错误的更多信息,可以查看我们的安装指南。", + "DialogUserErrorDialogTitle": "Ryujinx 错误 ({0})", + "DialogAmiiboApiTitle": "Amiibo API", + "DialogAmiiboApiFailFetchMessage": "从 API 获取信息时出错。", + "DialogAmiiboApiConnectErrorMessage": "无法连接到 Amiibo API 服务器,服务可能已关闭,或者没有连接互联网。", + "DialogProfileInvalidProfileErrorMessage": "配置文件 {0} 与当前输入配置系统不兼容。", + "DialogProfileDefaultProfileOverwriteErrorMessage": "不允许覆盖默认配置文件", + "DialogProfileDeleteProfileTitle": "删除配置文件", + "DialogProfileDeleteProfileMessage": "删除后不可恢复,确认删除吗?", + "DialogWarning": "警告", + "DialogPPTCDeletionMessage": "您即将删除:\n\n{0} 的 PPTC 缓存文件\n\n确定吗?", + "DialogPPTCDeletionErrorMessage": "清除 {0} 的 PPTC 缓存文件时出错:{1}", + "DialogShaderDeletionMessage": "您即将删除:\n\n{0} 的着色器缓存文件\n\n确定吗?", + "DialogShaderDeletionErrorMessage": "清除 {0} 的着色器缓存文件时出错:{1}", + "DialogRyujinxErrorMessage": "Ryujinx 模拟器发生错误", + "DialogInvalidTitleIdErrorMessage": "用户界面错误:所选游戏没有有效的游戏 ID", + "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "在路径 {0} 中找不到有效的 Switch 系统固件。", + "DialogFirmwareInstallerFirmwareInstallTitle": "安装系统固件 {0}", + "DialogFirmwareInstallerFirmwareInstallMessage": "即将安装系统固件版本 {0} 。", + "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\n替换当前系统固件版本 {0} 。", + "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n是否继续?", + "DialogFirmwareInstallerFirmwareInstallWaitMessage": "安装系统固件中...", + "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "成功安装系统固件版本 {0} 。", + "DialogUserProfileDeletionWarningMessage": "删除后将没有可用的账户", + "DialogUserProfileDeletionConfirmMessage": "是否删除所选账户", + "DialogUserProfileUnsavedChangesTitle": "警告 - 有未保存的更改", + "DialogUserProfileUnsavedChangesMessage": "您对该账户的更改尚未保存。", + "DialogUserProfileUnsavedChangesSubMessage": "确定要放弃更改吗?", + "DialogControllerSettingsModifiedConfirmMessage": "当前的输入设置已更新", + "DialogControllerSettingsModifiedConfirmSubMessage": "是否保存?", + "DialogLoadFileErrorMessage": "{0}. 错误的文件:{1}", + "DialogModAlreadyExistsMessage": "MOD 已存在", + "DialogModInvalidMessage": "指定的目录找不到 MOD 文件!", + "DialogModDeleteNoParentMessage": "删除失败:找不到 MOD 的父目录“{0}”!", + "DialogDlcNoDlcErrorMessage": "选择的文件不是当前游戏的 DLC!", + "DialogPerformanceCheckLoggingEnabledMessage": "您启用了跟踪日志,该功能仅供开发人员使用。", + "DialogPerformanceCheckLoggingEnabledConfirmMessage": "为了获得最佳性能,建议禁用跟踪日志记录。您是否要立即禁用?", + "DialogPerformanceCheckShaderDumpEnabledMessage": "您启用了着色器转储,该功能仅供开发人员使用。", + "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "为了获得最佳性能,建议禁用着色器转储。您是否要立即禁用?", + "DialogLoadAppGameAlreadyLoadedMessage": "游戏已经启动", + "DialogLoadAppGameAlreadyLoadedSubMessage": "请停止模拟或关闭模拟器,再启动另一个游戏。", + "DialogUpdateAddUpdateErrorMessage": "选择的文件不是当前游戏的更新!", + "DialogSettingsBackendThreadingWarningTitle": "警告 - 图形引擎多线程", + "DialogSettingsBackendThreadingWarningMessage": "更改此选项后,必须重启 Ryujinx 模拟器才能生效。\n\n当启用图形引擎多线程时,根据显卡不同,您可能需要手动禁用显卡驱动程序自身的多线程(线程优化)。", + "DialogModManagerDeletionWarningMessage": "您即将删除 MOD:{0} \n\n确定吗?", + "DialogModManagerDeletionAllWarningMessage": "您即将删除该游戏的所有 MOD,\n\n确定吗?", + "SettingsTabGraphicsFeaturesOptions": "功能", + "SettingsTabGraphicsBackendMultithreading": "图形引擎多线程:", + "CommonAuto": "自动(推荐)", + "CommonOff": "关闭", + "CommonOn": "打开", + "InputDialogYes": "是", + "InputDialogNo": "否", + "DialogProfileInvalidProfileNameErrorMessage": "文件名包含无效字符,请重试。", + "MenuBarOptionsPauseEmulation": "暂停", + "MenuBarOptionsResumeEmulation": "继续", + "AboutUrlTooltipMessage": "在浏览器中打开 Ryujinx 模拟器官网。", + "AboutDisclaimerMessage": "Ryujinx 与 Nintendo™ 以及其合作伙伴没有任何关联。", + "AboutAmiiboDisclaimerMessage": "我们的 Amiibo 模拟使用了\nAmiiboAPI (www.amiiboapi.com)。", + "AboutPatreonUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Patreon 赞助页。", + "AboutGithubUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 GitHub 代码库。", + "AboutDiscordUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Discord 邀请链接。", + "AboutTwitterUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Twitter 主页。", + "AboutRyujinxAboutTitle": "关于:", + "AboutRyujinxAboutContent": "Ryujinx 是一款 Nintendo Switch™ 模拟器。\n您可以在 Patreon 上赞助 Ryujinx。\n关注 Twitter 或 Discord 可以获取模拟器最新动态。\n如果您对开发感兴趣,欢迎来 GitHub 或 Discord 加入我们!", + "AboutRyujinxMaintainersTitle": "开发维护人员名单:", + "AboutRyujinxMaintainersContentTooltipMessage": "在浏览器中打开贡献者页面", + "AboutRyujinxSupprtersTitle": "感谢 Patreon 上的赞助者:", + "AmiiboSeriesLabel": "Amiibo 系列", + "AmiiboCharacterLabel": "角色", + "AmiiboScanButtonLabel": "扫描", + "AmiiboOptionsShowAllLabel": "显示所有 Amiibo", + "AmiiboOptionsUsRandomTagLabel": "修改:使用随机生成的Amiibo ID", + "DlcManagerTableHeadingEnabledLabel": "已启用", + "DlcManagerTableHeadingTitleIdLabel": "游戏 ID", + "DlcManagerTableHeadingContainerPathLabel": "容器路径", + "DlcManagerTableHeadingFullPathLabel": "完整路径", + "DlcManagerRemoveAllButton": "全部删除", + "DlcManagerEnableAllButton": "全部启用", + "DlcManagerDisableAllButton": "全部停用", + "ModManagerDeleteAllButton": "全部刪除", + "MenuBarOptionsChangeLanguage": "更改界面语言", + "MenuBarShowFileTypes": "主页显示的文件类型", + "CommonSort": "排序", + "CommonShowNames": "显示名称", + "CommonFavorite": "收藏", + "OrderAscending": "升序", + "OrderDescending": "降序", + "SettingsTabGraphicsFeatures": "功能与优化", + "ErrorWindowTitle": "错误窗口", + "ToggleDiscordTooltip": "选择是否在 Discord 中显示您的游玩状态", + "AddGameDirBoxTooltip": "输入要添加的游戏目录", + "AddGameDirTooltip": "添加游戏目录到列表中", + "RemoveGameDirTooltip": "移除选中的目录", + "CustomThemeCheckTooltip": "使用自定义的 Avalonia 主题作为模拟器菜单的外观", + "CustomThemePathTooltip": "自定义主题的目录", + "CustomThemeBrowseTooltip": "查找自定义主题", + "DockModeToggleTooltip": "启用 Switch 的主机模式(电视模式、底座模式),就是模拟 Switch 连接底座的情况;若禁用主机模式,则使用 Switch 的掌机模式,就是模拟手持 Switch 运行游戏的情况。\n对于绝大多数游戏而言,主机模式会比掌机模式,画质更高,同时性能消耗也更高。\n\n简而言之,想要更好画质则启用主机模式;电脑硬件性能不足则禁用主机模式。\n\n如果使用主机模式,请选择“玩家 1”的手柄设置;如果使用掌机模式,请选择“掌机模式”的手柄设置。\n\n如果不确定,请保持开启状态。", + "DirectKeyboardTooltip": "直接键盘访问(HID)支持,游戏可以直接访问键盘作为文本输入设备。\n\n仅适用于在 Switch 硬件上原生支持键盘的游戏。\n\n如果不确定,请保持关闭状态。", + "DirectMouseTooltip": "直接鼠标访问(HID)支持,游戏可以直接访问鼠标作为指针输入设备。\n\n只适用于在 Switch 硬件上原生支持鼠标控制的游戏,这种游戏很少。\n\n启用后,触屏功能可能无法正常工作。\n\n如果不确定,请保持关闭状态。", + "RegionTooltip": "更改系统区域", + "LanguageTooltip": "更改系统语言", + "TimezoneTooltip": "更改系统时区", + "TimeTooltip": "更改系统时间", + "VSyncToggleTooltip": "模拟控制台的垂直同步,开启后会降低大部分游戏的帧率。关闭后,可以获得更高的帧率,但也可能导致游戏画面加载耗时更长或卡住。\n\n在游戏中可以使用热键进行切换(默认为 F1 键)。\n\n如果不确定,请保持开启状态。", + "PptcToggleTooltip": "缓存已编译的游戏指令,这样每次游戏加载时就无需重新编译。\n\n可以减少卡顿和启动时间,提高游戏响应速度。\n\n如果不确定,请保持开启状态。", + "FsIntegrityToggleTooltip": "启动游戏时检查游戏文件的完整性,并在日志中记录损坏的文件。\n\n对性能没有影响,用于排查故障。\n\n如果不确定,请保持开启状态。", + "AudioBackendTooltip": "更改音频处理引擎。\n\n推荐选择“SDL2”,另外“OpenAL”和“SoundIO”可以作为备选,选择“无”将没有声音。\n\n如果不确定,请设置为“SDL2”。", + "MemoryManagerTooltip": "更改模拟器内存映射和访问的方式,对模拟器 CPU 的性能影响很大。\n\n如果不确定,请设置为“跳过检查的本机映射”。", + "MemoryManagerSoftwareTooltip": "使用软件内存页进行内存地址映射,最准确但是速度最慢。", + "MemoryManagerHostTooltip": "直接映射内存页到电脑内存,使得即时编译和执行的效率更高。", + "MemoryManagerUnsafeTooltip": "直接映射内存页到电脑内存,并且不检查内存溢出,使得效率更高,但牺牲了安全。\n游戏程序可以访问模拟器内存的任意地址,所以不安全。\n建议此模式下只运行您信任的游戏程序。", + "UseHypervisorTooltip": "使用 Hypervisor 虚拟机代替即时编译,在可用的情况下能大幅提高性能,但目前可能还不稳定。", + "DRamTooltip": "模拟 Switch 开发机的内存布局。\n\n不会提高性能,某些高清纹理包或 4k 分辨率 MOD 可能需要使用此选项。\n\n如果不确定,请保持关闭状态。", + "IgnoreMissingServicesTooltip": "开启后,游戏会忽略未实现的系统服务,从而继续运行。\n少部分新发布的游戏由于使用了新的未知系统服务,可能需要此选项来避免闪退。\n模拟器更新完善系统服务之后,则无需开启此选项。\n\n如果不确定,请保持关闭状态。", + "GraphicsBackendThreadingTooltip": "在第二个线程上执行图形引擎指令。\n\n可以加速着色器编译,减少卡顿,提高 GPU 的性能。\n\n如果不确定,请设置为“自动”。", + "GalThreadingTooltip": "在第二个线程上执行图形引擎指令。\n\n可以加速着色器编译,减少卡顿,提高 GPU 的性能。\n\n如果不确定,请设置为“自动”。", + "ShaderCacheToggleTooltip": "模拟器将已编译的着色器保存到硬盘,可以减少游戏再次渲染相同图形导致的卡顿。\n\n如果不确定,请保持开启状态。", + "ResolutionScaleTooltip": "将游戏的渲染分辨率乘以一个倍数。\n\n有些游戏可能不适用这项设置,而且即使提高了分辨率仍然看起来像素化;对于这些游戏,您可能需要找到移除抗锯齿或提高内部渲染分辨率的 MOD。当使用这些 MOD 时,建议设置为“原生”。\n\n在游戏运行时,通过点击下面的“应用”按钮可以使设置生效;你可以将设置窗口移开,并试验找到您喜欢的游戏画面效果。\n\n请记住,对于几乎所有人而言,4倍分辨率都是过度的。", + "ResolutionScaleEntryTooltip": "建议设置为整数倍,带小数的分辨率缩放倍数(例如1.5),非整数倍的缩放容易导致问题或闪退。", + "AnisotropyTooltip": "各向异性过滤等级,可以提高倾斜视角纹理的清晰度。\n当设置为“自动”时,使用游戏自身设定的等级。", + "AspectRatioTooltip": "游戏渲染窗口的宽高比。\n\n只有当游戏使用了修改宽高比的 MOD 时才需要修改这个设置,否则图像会被拉伸。\n\n如果不确定,请保持为“16:9”。", + "ShaderDumpPathTooltip": "转储图形着色器的路径", + "FileLogTooltip": "将控制台日志保存到硬盘文件,不影响性能。", + "StubLogTooltip": "在控制台中显示存根日志,不影响性能。", + "InfoLogTooltip": "在控制台中显示信息日志,不影响性能。", + "WarnLogTooltip": "在控制台中显示警告日志,不影响性能。", + "ErrorLogTooltip": "在控制台中显示错误日志,不影响性能。", + "TraceLogTooltip": "在控制台中显示跟踪日志。", + "GuestLogTooltip": "在控制台中显示访客日志,不影响性能。", + "FileAccessLogTooltip": "在控制台中显示文件访问日志。", + "FSAccessLogModeTooltip": "在控制台中显示文件系统访问日志,可选模式为 0-3。", + "DeveloperOptionTooltip": "请谨慎使用", + "OpenGlLogLevel": "需要启用适当的日志级别", + "DebugLogTooltip": "在控制台中显示调试日志。\n\n仅在特别需要时使用此功能,因为它会导致日志信息难以阅读,并降低模拟器性能。", + "LoadApplicationFileTooltip": "选择 Switch 游戏文件并加载", + "LoadApplicationFolderTooltip": "选择解包后的 Switch 游戏目录并加载", + "OpenRyujinxFolderTooltip": "打开 Ryujinx 模拟器系统目录", + "OpenRyujinxLogsTooltip": "打开日志存放的目录", + "ExitTooltip": "退出 Ryujinx 模拟器", + "OpenSettingsTooltip": "打开设置窗口", + "OpenProfileManagerTooltip": "打开用户账户管理窗口", + "StopEmulationTooltip": "停止运行当前游戏,并回到主界面", + "CheckUpdatesTooltip": "检查 Ryujinx 新版本", + "OpenAboutTooltip": "打开关于窗口", + "GridSize": "网格尺寸", + "GridSizeTooltip": "调整网格项目的大小", + "SettingsTabSystemSystemLanguageBrazilianPortuguese": "巴西葡萄牙语", + "AboutRyujinxContributorsButtonHeader": "查看所有贡献者", + "SettingsTabSystemAudioVolume": "音量:", + "AudioVolumeTooltip": "调节音量", + "SettingsTabSystemEnableInternetAccess": "启用网络连接(局域网)", + "EnableInternetAccessTooltip": "允许模拟的游戏程序访问网络。\n\n当多个模拟器或实体 Switch 连接到同一个网络时,带有局域网模式的游戏便可以相互通信。\n\n即使开启此选项也无法访问 Nintendo 服务器,有可能导致某些尝试联网的游戏闪退。\n\n如果不确定,请保持关闭状态。", + "GameListContextMenuManageCheatToolTip": "管理当前游戏的金手指", + "GameListContextMenuManageCheat": "管理金手指", + "GameListContextMenuManageModToolTip": "管理当前游戏的 MOD", + "GameListContextMenuManageMod": "管理 MOD", + "ControllerSettingsStickRange": "范围:", + "DialogStopEmulationTitle": "Ryujinx - 停止模拟", + "DialogStopEmulationMessage": "确定要停止模拟?", + "SettingsTabCpu": "CPU", + "SettingsTabAudio": "音频", + "SettingsTabNetwork": "网络", + "SettingsTabNetworkConnection": "网络连接", + "SettingsTabCpuCache": "CPU 缓存", + "SettingsTabCpuMemory": "CPU 模式", + "DialogUpdaterFlatpakNotSupportedMessage": "请通过 FlatHub 更新 Ryujinx 模拟器。", + "UpdaterDisabledWarningTitle": "已禁用更新!", + "ControllerSettingsRotate90": "顺时针旋转 90°", + "IconSize": "图标尺寸", + "IconSizeTooltip": "更改游戏图标的显示尺寸", + "MenuBarOptionsShowConsole": "显示控制台", + "ShaderCachePurgeError": "清除 {0} 的着色器缓存文件时出错:{1}", + "UserErrorNoKeys": "找不到密钥Keys", + "UserErrorNoFirmware": "未安装系统固件", + "UserErrorFirmwareParsingFailed": "固件文件解析出错", + "UserErrorApplicationNotFound": "找不到游戏程序", + "UserErrorUnknown": "未知错误", + "UserErrorUndefined": "未定义错误", + "UserErrorNoKeysDescription": "Ryujinx 模拟器找不到“prod.keys”密钥文件", + "UserErrorNoFirmwareDescription": "Ryujinx 模拟器未安装 Switch 系统固件", + "UserErrorFirmwareParsingFailedDescription": "Ryujinx 模拟器无法解密当前固件,一般是由于使用了旧版的密钥导致的。", + "UserErrorApplicationNotFoundDescription": "Ryujinx 模拟器在所选路径中找不到有效的游戏程序。", + "UserErrorUnknownDescription": "出现未知错误!", + "UserErrorUndefinedDescription": "出现未定义错误!此类错误不应出现,请联系开发者!", + "OpenSetupGuideMessage": "打开安装指南", + "NoUpdate": "无更新(或不加载游戏更新)", + "TitleUpdateVersionLabel": "游戏更新的版本 {0}", + "RyujinxInfo": "Ryujinx - 信息", + "RyujinxConfirm": "Ryujinx - 确认", + "FileDialogAllTypes": "全部类型", + "Never": "从不", + "SwkbdMinCharacters": "不少于 {0} 个字符", + "SwkbdMinRangeCharacters": "必须为 {0}-{1} 个字符", + "SoftwareKeyboard": "软键盘", + "SoftwareKeyboardModeNumeric": "只能输入 0-9 或 \".\"", + "SoftwareKeyboardModeAlphabet": "仅支持非中文字符", + "SoftwareKeyboardModeASCII": "仅支持 ASCII 字符", + "ControllerAppletControllers": "支持的手柄:", + "ControllerAppletPlayers": "玩家:", + "ControllerAppletDescription": "您当前的输入配置无效。打开设置并重新设置您的输入选项。", + "ControllerAppletDocked": "已经设置为主机模式,应禁用掌机手柄操控。", + "UpdaterRenaming": "正在重命名旧文件...", + "UpdaterRenameFailed": "更新过程中无法重命名文件:{0}", + "UpdaterAddingFiles": "安装更新中...", + "UpdaterExtracting": "正在提取更新...", + "UpdaterDownloading": "下载更新中...", + "Game": "游戏", + "Docked": "主机模式", + "Handheld": "掌机模式", + "ConnectionError": "连接错误。", + "AboutPageDeveloperListMore": "{0} 等开发者...", + "ApiError": "API 错误。", + "LoadingHeading": "正在启动 {0}", + "CompilingPPTC": "编译 PPTC 缓存中", + "CompilingShaders": "编译着色器中", + "AllKeyboards": "所有键盘", + "OpenFileDialogTitle": "选择支持的游戏文件并加载", + "OpenFolderDialogTitle": "选择包含解包游戏的目录并加载", + "AllSupportedFormats": "所有支持的格式", + "RyujinxUpdater": "Ryujinx 更新", + "SettingsTabHotkeys": "快捷键", + "SettingsTabHotkeysHotkeys": "键盘快捷键", + "SettingsTabHotkeysToggleVsyncHotkey": "开启或关闭垂直同步:", + "SettingsTabHotkeysScreenshotHotkey": "保存截屏:", + "SettingsTabHotkeysShowUiHotkey": "隐藏菜单栏和状态栏:", + "SettingsTabHotkeysPauseHotkey": "暂停:", + "SettingsTabHotkeysToggleMuteHotkey": "静音:", + "ControllerMotionTitle": "体感设置", + "ControllerRumbleTitle": "震动设置", + "SettingsSelectThemeFileDialogTitle": "选择主题文件", + "SettingsXamlThemeFile": "Xaml 主题文件", + "AvatarWindowTitle": "管理账户 - 头像", + "Amiibo": "Amiibo", + "Unknown": "未知", + "Usage": "用法", + "Writable": "可写入", + "SelectDlcDialogTitle": "选择 DLC 文件", + "SelectUpdateDialogTitle": "选择更新文件", + "SelectModDialogTitle": "选择 MOD 目录", + "UserProfileWindowTitle": "管理用户账户", + "CheatWindowTitle": "金手指管理器", + "DlcWindowTitle": "管理 {0} ({1}) 的 DLC", + "ModWindowTitle": "管理 {0} ({1}) 的 MOD", + "UpdateWindowTitle": "游戏更新管理器", + "CheatWindowHeading": "适用于 {0} [{1}] 的金手指", + "BuildId": "游戏版本 ID:", + "DlcWindowHeading": "{0} 个 DLC", + "ModWindowHeading": "{0} 个 MOD", + "UserProfilesEditProfile": "编辑所选", + "Cancel": "取消", + "Save": "保存", + "Discard": "放弃", + "Paused": "已暂停", + "UserProfilesSetProfileImage": "选择头像", + "UserProfileEmptyNameError": "必须输入名称", + "UserProfileNoImageError": "必须设置头像", + "GameUpdateWindowHeading": "管理 {0} ({1}) 的更新", + "SettingsTabHotkeysResScaleUpHotkey": "提高分辨率:", + "SettingsTabHotkeysResScaleDownHotkey": "降低分辨率:", + "UserProfilesName": "名称:", + "UserProfilesUserId": "用户 ID:", + "SettingsTabGraphicsBackend": "图形渲染引擎:", + "SettingsTabGraphicsBackendTooltip": "选择模拟器中使用的图像渲染引擎。\n\n安装了最新显卡驱动程序的所有现代显卡基本都支持 Vulkan,Vulkan 能够提供更快的着色器编译(较少的卡顿)。\n\n在旧版 Nvidia 显卡上、Linux 上的旧版 AMD 显卡,或者显存较低的显卡上,OpenGL 可能会取得更好的效果,但着色器编译更慢(更多的卡顿)。\n\n如果不确定,请设置为“Vulkan”。如果您的 GPU 已安装了最新显卡驱动程序也不支持 Vulkan,那请设置为“OpenGL”。", + "SettingsEnableTextureRecompression": "启用纹理压缩", + "SettingsEnableTextureRecompressionTooltip": "压缩 ASTC 纹理以减少 VRAM (显存)的占用。\n\n使用此纹理格式的游戏包括:异界锁链(Astral Chain),蓓优妮塔3(Bayonetta 3),火焰纹章Engage(Fire Emblem Engage),密特罗德 究极(Metroid Prime Remased),超级马力欧兄弟 惊奇(Super Mario Bros. Wonder)以及塞尔达传说 王国之泪(The Legend of Zelda: Tears of the Kingdom)。\n\n显存小于4GB的显卡在运行这些游戏时可能会偶发闪退。\n\n只有当您在上述游戏中的显存不足时才需要启用此选项。\n\n如果不确定,请保持关闭状态。", + "SettingsTabGraphicsPreferredGpu": "首选 GPU:", + "SettingsTabGraphicsPreferredGpuTooltip": "选择 Vulkan 图形引擎使用的 GPU。\n\n此选项不会影响 OpenGL 使用的 GPU。\n\n如果不确定,建议选择\"独立显卡(dGPU)\"。如果没有独立显卡,则无需改动此选项。", + "SettingsAppRequiredRestartMessage": "Ryujinx 模拟器需要重启", + "SettingsGpuBackendRestartMessage": "您修改了图形引擎或 GPU 设置,需要重启模拟器才能生效", + "SettingsGpuBackendRestartSubMessage": "是否要立即重启模拟器?", + "RyujinxUpdaterMessage": "是否更新 Ryujinx 到最新的版本?", + "SettingsTabHotkeysVolumeUpHotkey": "音量加:", + "SettingsTabHotkeysVolumeDownHotkey": "音量减:", + "SettingsEnableMacroHLE": "启用 HLE 宏加速", + "SettingsEnableMacroHLETooltip": "GPU 宏指令的高级模拟。\n\n提高性能表现,但一些游戏可能会出现图形错误。\n\n如果不确定,请保持开启状态。", + "SettingsEnableColorSpacePassthrough": "色彩空间直通", + "SettingsEnableColorSpacePassthroughTooltip": "使 Vulkan 图形引擎直接传输原始色彩信息。对于宽色域 (例如 DCI-P3) 显示器的用户来说,可以产生更鲜艳的颜色,代价是会损失部分色彩准确度。", + "VolumeShort": "音量", + "UserProfilesManageSaves": "管理存档", + "DeleteUserSave": "确定删除此游戏的用户存档吗?", + "IrreversibleActionNote": "删除后不可恢复。", + "SaveManagerHeading": "管理 {0} ({1}) 的存档", + "SaveManagerTitle": "存档管理器", + "Name": "名称", + "Size": "大小", + "Search": "搜索", + "UserProfilesRecoverLostAccounts": "恢复丢失的账户", + "Recover": "恢复", + "UserProfilesRecoverHeading": "找到了这些用户的存档数据", + "UserProfilesRecoverEmptyList": "没有可以恢复的用户数据", + "GraphicsAATooltip": "抗锯齿是一种图形处理技术,用于减少图像边缘的锯齿状现象,使图像更加平滑。\n\nFXAA(快速近似抗锯齿)是一种性能开销相对较小的抗锯齿方法,但可能会使得整体图像看起来有些模糊。\n\nSMAA(增强型子像素抗锯齿)则更加精细,它会尝试找到锯齿边缘并平滑它们,相比 FXAA 有更好的图像质量,但性能开销可能会稍大一些。\n\n如果开启了 FSR(FidelityFX Super Resolution,超级分辨率锐画技术)来提高性能或图像质量,不建议再启用抗锯齿,因为它们会产生不必要的图形处理开销,或者相互之间效果不协调。\n\n在游戏运行时,通过点击下面的“应用”按钮可以使设置生效;你可以将设置窗口移开,并试验找到您喜欢的游戏画面效果。\n\n如果不确定,请保持为“无”。", + "GraphicsAALabel": "抗锯齿:", + "GraphicsScalingFilterLabel": "缩放过滤:", + "GraphicsScalingFilterTooltip": "选择在分辨率缩放时将使用的缩放过滤器。\n\nBilinear(双线性过滤)对于3D游戏效果较好,是一个安全的默认选项。\n\nNearest(最近邻过滤)推荐用于像素艺术游戏。\n\nFSR(超级分辨率锐画)只是一个锐化过滤器,不推荐与 FXAA 或 SMAA 抗锯齿一起使用。\n\n在游戏运行时,通过点击下面的“应用”按钮可以使设置生效;你可以将设置窗口移开,并试验找到您喜欢的游戏画面效果。\n\n如果不确定,请保持为“Bilinear(双线性过滤)”。", + "GraphicsScalingFilterBilinear": "Bilinear(双线性过滤)", + "GraphicsScalingFilterNearest": "Nearest(最近邻过滤)", + "GraphicsScalingFilterFsr": "FSR(超级分辨率锐画技术)", + "GraphicsScalingFilterLevelLabel": "等级", + "GraphicsScalingFilterLevelTooltip": "设置 FSR 1.0 的锐化等级,数值越高,图像越锐利。", + "SmaaLow": "SMAA 低质量", + "SmaaMedium": "SMAA 中质量", + "SmaaHigh": "SMAA 高质量", + "SmaaUltra": "SMAA 超高质量", + "UserEditorTitle": "编辑用户", + "UserEditorTitleCreate": "创建用户", + "SettingsTabNetworkInterface": "网络接口:", + "NetworkInterfaceTooltip": "用于局域网(LAN)/本地网络发现(LDN)功能的网络接口。\n\n结合 VPN 或 XLink Kai 以及支持局域网功能的游戏,可以在互联网上伪造为同一网络连接。\n\n如果不确定,请保持为“默认”。", + "NetworkInterfaceDefault": "默认", + "PackagingShaders": "整合着色器中", + "AboutChangelogButton": "在 Github 上查看更新日志", + "AboutChangelogButtonTooltipMessage": "点击这里在浏览器中打开此版本的更新日志。", + "SettingsTabNetworkMultiplayer": "多人联机游玩", + "MultiplayerMode": "联机模式:", + "MultiplayerModeTooltip": "修改 LDN 多人联机游玩模式。\n\nldn_mitm 联机插件将修改游戏中的本地无线和本地游玩功能,使其表现得像局域网一样,允许和其他安装了 ldn_mitm 插件的 Ryujinx 模拟器和破解的任天堂 Switch 主机在同一网络下进行本地连接,实现多人联机游玩。\n\n多人联机游玩要求所有玩家必须运行相同的游戏版本(例如,任天堂明星大乱斗特别版 v13.0.1 无法与 v13.0.0 版本联机)。\n\n如果不确定,请保持为“禁用”。", + "MultiplayerModeDisabled": "禁用", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx/Assets/Locales/zh_TW.json b/src/Ryujinx/Assets/Locales/zh_TW.json new file mode 100644 index 000000000..fc838d251 --- /dev/null +++ b/src/Ryujinx/Assets/Locales/zh_TW.json @@ -0,0 +1,780 @@ +{ + "Language": "繁體中文 (台灣)", + "MenuBarFileOpenApplet": "開啟小程式", + "MenuBarFileOpenAppletOpenMiiAppletToolTip": "在獨立模式下開啟 Mii 編輯器小程式", + "SettingsTabInputDirectMouseAccess": "滑鼠直接存取", + "SettingsTabSystemMemoryManagerMode": "記憶體管理員模式:", + "SettingsTabSystemMemoryManagerModeSoftware": "軟體模式", + "SettingsTabSystemMemoryManagerModeHost": "主體模式 (快速)", + "SettingsTabSystemMemoryManagerModeHostUnchecked": "主體略過檢查模式 (最快,不安全)", + "SettingsTabSystemUseHypervisor": "使用 Hypervisor", + "MenuBarFile": "檔案(_F)", + "MenuBarFileOpenFromFile": "從檔案載入應用程式(_L)", + "MenuBarFileOpenUnpacked": "載入未封裝的遊戲(_U)", + "MenuBarFileOpenEmuFolder": "開啟 Ryujinx 資料夾", + "MenuBarFileOpenLogsFolder": "開啟日誌資料夾", + "MenuBarFileExit": "結束(_E)", + "MenuBarOptions": "選項(_O)", + "MenuBarOptionsToggleFullscreen": "切換全螢幕模式", + "MenuBarOptionsStartGamesInFullscreen": "使用全螢幕模式啟動遊戲", + "MenuBarOptionsStopEmulation": "停止模擬", + "MenuBarOptionsSettings": "設定(_S)", + "MenuBarOptionsManageUserProfiles": "管理使用者設定檔(_M)", + "MenuBarActions": "動作(_A)", + "MenuBarOptionsSimulateWakeUpMessage": "模擬喚醒訊息", + "MenuBarActionsScanAmiibo": "掃描 Amiibo", + "MenuBarTools": "工具(_T)", + "MenuBarToolsInstallFirmware": "安裝韌體", + "MenuBarFileToolsInstallFirmwareFromFile": "從 XCI 或 ZIP 安裝韌體", + "MenuBarFileToolsInstallFirmwareFromDirectory": "從資料夾安裝韌體", + "MenuBarToolsManageFileTypes": "管理檔案類型", + "MenuBarToolsInstallFileTypes": "安裝檔案類型", + "MenuBarToolsUninstallFileTypes": "移除檔案類型", + "MenuBarView": "檢視(_V)", + "MenuBarViewWindow": "視窗大小", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "說明(_H)", + "MenuBarHelpCheckForUpdates": "檢查更新", + "MenuBarHelpAbout": "關於", + "MenuSearch": "搜尋...", + "GameListHeaderFavorite": "我的最愛", + "GameListHeaderIcon": "圖示", + "GameListHeaderApplication": "名稱", + "GameListHeaderDeveloper": "開發者", + "GameListHeaderVersion": "版本", + "GameListHeaderTimePlayed": "遊玩時數", + "GameListHeaderLastPlayed": "最近遊玩", + "GameListHeaderFileExtension": "副檔名", + "GameListHeaderFileSize": "檔案大小", + "GameListHeaderPath": "路徑", + "GameListContextMenuOpenUserSaveDirectory": "開啟使用者存檔資料夾", + "GameListContextMenuOpenUserSaveDirectoryToolTip": "開啟此應用程式的使用者存檔資料夾", + "GameListContextMenuOpenDeviceSaveDirectory": "開啟裝置存檔資料夾", + "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "開啟此應用程式的裝置存檔資料夾", + "GameListContextMenuOpenBcatSaveDirectory": "開啟 BCAT 存檔資料夾", + "GameListContextMenuOpenBcatSaveDirectoryToolTip": "開啟此應用程式的 BCAT 存檔資料夾", + "GameListContextMenuManageTitleUpdates": "管理遊戲更新", + "GameListContextMenuManageTitleUpdatesToolTip": "開啟遊戲更新管理視窗", + "GameListContextMenuManageDlc": "管理 DLC", + "GameListContextMenuManageDlcToolTip": "開啟 DLC 管理視窗", + "GameListContextMenuCacheManagement": "快取管理", + "GameListContextMenuCacheManagementPurgePptc": "佇列 PPTC 重建", + "GameListContextMenuCacheManagementPurgePptcToolTip": "下一次啟動遊戲時,觸發 PPTC 進行重建", + "GameListContextMenuCacheManagementPurgeShaderCache": "清除著色器快取", + "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "刪除應用程式的著色器快取", + "GameListContextMenuCacheManagementOpenPptcDirectory": "開啟 PPTC 資料夾", + "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "開啟此應用程式的 PPTC 快取資料夾", + "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "開啟著色器快取資料夾", + "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "開啟此應用程式的著色器快取資料夾", + "GameListContextMenuExtractData": "提取資料", + "GameListContextMenuExtractDataExeFS": "ExeFS", + "GameListContextMenuExtractDataExeFSToolTip": "從應用程式的目前配置中提取 ExeFS 分區 (包含更新)", + "GameListContextMenuExtractDataRomFS": "RomFS", + "GameListContextMenuExtractDataRomFSToolTip": "從應用程式的目前配置中提取 RomFS 分區 (包含更新)", + "GameListContextMenuExtractDataLogo": "Logo", + "GameListContextMenuExtractDataLogoToolTip": "從應用程式的目前配置中提取 Logo 分區 (包含更新)", + "GameListContextMenuCreateShortcut": "建立應用程式捷徑", + "GameListContextMenuCreateShortcutToolTip": "建立桌面捷徑,啟動選取的應用程式", + "GameListContextMenuCreateShortcutToolTipMacOS": "在 macOS 的應用程式資料夾中建立捷徑,啟動選取的應用程式", + "GameListContextMenuOpenModsDirectory": "開啟模組資料夾", + "GameListContextMenuOpenModsDirectoryToolTip": "開啟此應用程式模組的資料夾", + "GameListContextMenuOpenSdModsDirectory": "開啟 Atmosphere 模組資料夾", + "GameListContextMenuOpenSdModsDirectoryToolTip": "開啟此應用程式模組的另一個 SD 卡 Atmosphere 資料夾。適用於為真實硬體封裝的模組。", + "StatusBarGamesLoaded": "{0}/{1} 遊戲已載入", + "StatusBarSystemVersion": "系統版本: {0}", + "LinuxVmMaxMapCountDialogTitle": "檢測到記憶體映射的低限值", + "LinuxVmMaxMapCountDialogTextPrimary": "您是否要將 vm.max_map_count 的數值增至 {0}?", + "LinuxVmMaxMapCountDialogTextSecondary": "某些遊戲可能會嘗試建立超過目前允許的記憶體映射。一旦超過此限制,Ryujinx 就會崩潰。", + "LinuxVmMaxMapCountDialogButtonUntilRestart": "是的,直到下次重新啟動", + "LinuxVmMaxMapCountDialogButtonPersistent": "是的,永久設定", + "LinuxVmMaxMapCountWarningTextPrimary": "記憶體映射的最大值低於建議值。", + "LinuxVmMaxMapCountWarningTextSecondary": "目前 vm.max_map_count ({0}) 的數值小於 {1}。某些遊戲可能會嘗試建立比目前允許值更多的記憶體映射。一旦超過此限制,Ryujinx 就會崩潰。\n\n您可能需要手動提高上限,或者安裝 pkexec,讓 Ryujinx 協助提高上限。", + "Settings": "設定", + "SettingsTabGeneral": "使用者介面", + "SettingsTabGeneralGeneral": "一般", + "SettingsTabGeneralEnableDiscordRichPresence": "啟用 Discord 動態狀態展示", + "SettingsTabGeneralCheckUpdatesOnLaunch": "啟動時檢查更新", + "SettingsTabGeneralShowConfirmExitDialog": "顯示「確認結束」對話方塊", + "SettingsTabGeneralRememberWindowState": "記住視窗大小/位置", + "SettingsTabGeneralHideCursor": "隱藏滑鼠游標:", + "SettingsTabGeneralHideCursorNever": "從不", + "SettingsTabGeneralHideCursorOnIdle": "閒置時", + "SettingsTabGeneralHideCursorAlways": "總是", + "SettingsTabGeneralGameDirectories": "遊戲資料夾", + "SettingsTabGeneralAdd": "新增", + "SettingsTabGeneralRemove": "刪除", + "SettingsTabSystem": "系統", + "SettingsTabSystemCore": "核心", + "SettingsTabSystemSystemRegion": "系統區域:", + "SettingsTabSystemSystemRegionJapan": "日本", + "SettingsTabSystemSystemRegionUSA": "美國", + "SettingsTabSystemSystemRegionEurope": "歐洲", + "SettingsTabSystemSystemRegionAustralia": "澳洲", + "SettingsTabSystemSystemRegionChina": "中國", + "SettingsTabSystemSystemRegionKorea": "韓國", + "SettingsTabSystemSystemRegionTaiwan": "台灣 (中華民國)", + "SettingsTabSystemSystemLanguage": "系統語言:", + "SettingsTabSystemSystemLanguageJapanese": "日文", + "SettingsTabSystemSystemLanguageAmericanEnglish": "英文 (美國)", + "SettingsTabSystemSystemLanguageFrench": "法文", + "SettingsTabSystemSystemLanguageGerman": "德文", + "SettingsTabSystemSystemLanguageItalian": "義大利文", + "SettingsTabSystemSystemLanguageSpanish": "西班牙文", + "SettingsTabSystemSystemLanguageChinese": "中文 (中國)", + "SettingsTabSystemSystemLanguageKorean": "韓文", + "SettingsTabSystemSystemLanguageDutch": "荷蘭文", + "SettingsTabSystemSystemLanguagePortuguese": "葡萄牙文", + "SettingsTabSystemSystemLanguageRussian": "俄文", + "SettingsTabSystemSystemLanguageTaiwanese": "中文 (台灣)", + "SettingsTabSystemSystemLanguageBritishEnglish": "英文 (英國)", + "SettingsTabSystemSystemLanguageCanadianFrench": "加拿大法文", + "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "美洲西班牙文", + "SettingsTabSystemSystemLanguageSimplifiedChinese": "簡體中文", + "SettingsTabSystemSystemLanguageTraditionalChinese": "正體中文 (建議)", + "SettingsTabSystemSystemTimeZone": "系統時區:", + "SettingsTabSystemSystemTime": "系統時鐘:", + "SettingsTabSystemEnableVsync": "垂直同步", + "SettingsTabSystemEnablePptc": "PPTC (剖析式持久轉譯快取, Profiled Persistent Translation Cache)", + "SettingsTabSystemEnableFsIntegrityChecks": "檔案系統完整性檢查", + "SettingsTabSystemAudioBackend": "音效後端:", + "SettingsTabSystemAudioBackendDummy": "虛設 (Dummy)", + "SettingsTabSystemAudioBackendOpenAL": "OpenAL", + "SettingsTabSystemAudioBackendSoundIO": "SoundIO", + "SettingsTabSystemAudioBackendSDL2": "SDL2", + "SettingsTabSystemHacks": "補釘修正", + "SettingsTabSystemHacksNote": "可能導致模擬器不穩定", + "SettingsTabSystemExpandDramSize": "使用替代的記憶體配置 (開發者專用)", + "SettingsTabSystemIgnoreMissingServices": "忽略缺少的模擬器功能", + "SettingsTabGraphics": "圖形", + "SettingsTabGraphicsAPI": "圖形 API", + "SettingsTabGraphicsEnableShaderCache": "啟用著色器快取", + "SettingsTabGraphicsAnisotropicFiltering": "各向異性過濾:", + "SettingsTabGraphicsAnisotropicFilteringAuto": "自動", + "SettingsTabGraphicsAnisotropicFiltering2x": "2 倍", + "SettingsTabGraphicsAnisotropicFiltering4x": "4 倍", + "SettingsTabGraphicsAnisotropicFiltering8x": "8 倍", + "SettingsTabGraphicsAnisotropicFiltering16x": "16 倍", + "SettingsTabGraphicsResolutionScale": "解析度比例:", + "SettingsTabGraphicsResolutionScaleCustom": "自訂 (不建議使用)", + "SettingsTabGraphicsResolutionScaleNative": "原生 (720p/1080p)", + "SettingsTabGraphicsResolutionScale2x": "2 倍 (1440p/2160p)", + "SettingsTabGraphicsResolutionScale3x": "3 倍 (2160p/3240p)", + "SettingsTabGraphicsResolutionScale4x": "4 倍 (2880p/4320p) (不建議使用)", + "SettingsTabGraphicsAspectRatio": "顯示長寬比例:", + "SettingsTabGraphicsAspectRatio4x3": "4:3", + "SettingsTabGraphicsAspectRatio16x9": "16:9", + "SettingsTabGraphicsAspectRatio16x10": "16:10", + "SettingsTabGraphicsAspectRatio21x9": "21:9", + "SettingsTabGraphicsAspectRatio32x9": "32:9", + "SettingsTabGraphicsAspectRatioStretch": "拉伸以適應視窗", + "SettingsTabGraphicsDeveloperOptions": "開發者選項", + "SettingsTabGraphicsShaderDumpPath": "圖形著色器傾印路徑:", + "SettingsTabLogging": "日誌", + "SettingsTabLoggingLogging": "日誌", + "SettingsTabLoggingEnableLoggingToFile": "啟用日誌到檔案", + "SettingsTabLoggingEnableStubLogs": "啟用 Stub 日誌", + "SettingsTabLoggingEnableInfoLogs": "啟用資訊日誌", + "SettingsTabLoggingEnableWarningLogs": "啟用警告日誌", + "SettingsTabLoggingEnableErrorLogs": "啟用錯誤日誌", + "SettingsTabLoggingEnableTraceLogs": "啟用追蹤日誌", + "SettingsTabLoggingEnableGuestLogs": "啟用客體日誌", + "SettingsTabLoggingEnableFsAccessLogs": "啟用檔案系統存取日誌", + "SettingsTabLoggingFsGlobalAccessLogMode": "檔案系統全域存取日誌模式:", + "SettingsTabLoggingDeveloperOptions": "開發者選項", + "SettingsTabLoggingDeveloperOptionsNote": "警告: 會降低效能", + "SettingsTabLoggingGraphicsBackendLogLevel": "圖形後端日誌等級:", + "SettingsTabLoggingGraphicsBackendLogLevelNone": "無", + "SettingsTabLoggingGraphicsBackendLogLevelError": "錯誤", + "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "減速", + "SettingsTabLoggingGraphicsBackendLogLevelAll": "全部", + "SettingsTabLoggingEnableDebugLogs": "啟用偵錯日誌", + "SettingsTabInput": "輸入", + "SettingsTabInputEnableDockedMode": "底座模式", + "SettingsTabInputDirectKeyboardAccess": "鍵盤直接存取", + "SettingsButtonSave": "儲存", + "SettingsButtonClose": "關閉", + "SettingsButtonOk": "確定", + "SettingsButtonCancel": "取消", + "SettingsButtonApply": "套用", + "ControllerSettingsPlayer": "玩家", + "ControllerSettingsPlayer1": "玩家 1", + "ControllerSettingsPlayer2": "玩家 2", + "ControllerSettingsPlayer3": "玩家 3", + "ControllerSettingsPlayer4": "玩家 4", + "ControllerSettingsPlayer5": "玩家 5", + "ControllerSettingsPlayer6": "玩家 6", + "ControllerSettingsPlayer7": "玩家 7", + "ControllerSettingsPlayer8": "玩家 8", + "ControllerSettingsHandheld": "手提模式", + "ControllerSettingsInputDevice": "輸入裝置", + "ControllerSettingsRefresh": "重新整理", + "ControllerSettingsDeviceDisabled": "已停用", + "ControllerSettingsControllerType": "控制器類型", + "ControllerSettingsControllerTypeHandheld": "手提模式", + "ControllerSettingsControllerTypeProController": "Pro 控制器", + "ControllerSettingsControllerTypeJoyConPair": "雙 JoyCon", + "ControllerSettingsControllerTypeJoyConLeft": "左 JoyCon", + "ControllerSettingsControllerTypeJoyConRight": "右 JoyCon", + "ControllerSettingsProfile": "設定檔", + "ControllerSettingsProfileDefault": "預設", + "ControllerSettingsLoad": "載入", + "ControllerSettingsAdd": "新增", + "ControllerSettingsRemove": "刪除", + "ControllerSettingsButtons": "按鍵", + "ControllerSettingsButtonA": "A", + "ControllerSettingsButtonB": "B", + "ControllerSettingsButtonX": "X", + "ControllerSettingsButtonY": "Y", + "ControllerSettingsButtonPlus": "+", + "ControllerSettingsButtonMinus": "-", + "ControllerSettingsDPad": "方向鍵", + "ControllerSettingsDPadUp": "上", + "ControllerSettingsDPadDown": "下", + "ControllerSettingsDPadLeft": "左", + "ControllerSettingsDPadRight": "右", + "ControllerSettingsStickButton": "按鍵", + "ControllerSettingsStickUp": "上", + "ControllerSettingsStickDown": "下", + "ControllerSettingsStickLeft": "左", + "ControllerSettingsStickRight": "右", + "ControllerSettingsStickStick": "搖桿", + "ControllerSettingsStickInvertXAxis": "搖桿左右反向", + "ControllerSettingsStickInvertYAxis": "搖桿上下反向", + "ControllerSettingsStickDeadzone": "無感帶:", + "ControllerSettingsLStick": "左搖桿", + "ControllerSettingsRStick": "右搖桿", + "ControllerSettingsTriggersLeft": "左扳機", + "ControllerSettingsTriggersRight": "右扳機", + "ControllerSettingsTriggersButtonsLeft": "左扳機鍵", + "ControllerSettingsTriggersButtonsRight": "右扳機鍵", + "ControllerSettingsTriggers": "板機", + "ControllerSettingsTriggerL": "L", + "ControllerSettingsTriggerR": "R", + "ControllerSettingsTriggerZL": "ZL", + "ControllerSettingsTriggerZR": "ZR", + "ControllerSettingsLeftSL": "SL", + "ControllerSettingsLeftSR": "SR", + "ControllerSettingsRightSL": "SL", + "ControllerSettingsRightSR": "SR", + "ControllerSettingsExtraButtonsLeft": "左背鍵", + "ControllerSettingsExtraButtonsRight": "右背鍵", + "ControllerSettingsMisc": "其他", + "ControllerSettingsTriggerThreshold": "扳機閾值:", + "ControllerSettingsMotion": "體感", + "ControllerSettingsMotionUseCemuhookCompatibleMotion": "使用與 CemuHook 相容的體感", + "ControllerSettingsMotionControllerSlot": "控制器插槽:", + "ControllerSettingsMotionMirrorInput": "鏡像輸入", + "ControllerSettingsMotionRightJoyConSlot": "右 JoyCon 插槽:", + "ControllerSettingsMotionServerHost": "伺服器主機位址:", + "ControllerSettingsMotionGyroSensitivity": "陀螺儀靈敏度:", + "ControllerSettingsMotionGyroDeadzone": "陀螺儀無感帶:", + "ControllerSettingsSave": "儲存", + "ControllerSettingsClose": "關閉", + "KeyUnknown": "未知", + "KeyShiftLeft": "左 Shift", + "KeyShiftRight": "右 Shift", + "KeyControlLeft": "左 Ctrl", + "KeyMacControlLeft": "左 ⌃", + "KeyControlRight": "右 Ctrl", + "KeyMacControlRight": "右 ⌃", + "KeyAltLeft": "左 Alt", + "KeyMacAltLeft": "左 ⌥", + "KeyAltRight": "右 Alt", + "KeyMacAltRight": "右 ⌥", + "KeyWinLeft": "左 ⊞", + "KeyMacWinLeft": "左 ⌘", + "KeyWinRight": "右 ⊞", + "KeyMacWinRight": "右 ⌘", + "KeyMenu": "功能表", + "KeyUp": "上", + "KeyDown": "下", + "KeyLeft": "左", + "KeyRight": "右", + "KeyEnter": "Enter 鍵", + "KeyEscape": "Esc 鍵", + "KeySpace": "空白鍵", + "KeyTab": "Tab 鍵", + "KeyBackSpace": "Backspace 鍵", + "KeyInsert": "Insert 鍵", + "KeyDelete": "Delete 鍵", + "KeyPageUp": "向上捲頁鍵", + "KeyPageDown": "向下捲頁鍵", + "KeyHome": "Home 鍵", + "KeyEnd": "End 鍵", + "KeyCapsLock": "Caps Lock 鍵", + "KeyScrollLock": "Scroll Lock 鍵", + "KeyPrintScreen": "Print Screen 鍵", + "KeyPause": "Pause 鍵", + "KeyNumLock": "Num Lock 鍵", + "KeyClear": "清除", + "KeyKeypad0": "數字鍵 0", + "KeyKeypad1": "數字鍵 1", + "KeyKeypad2": "數字鍵 2", + "KeyKeypad3": "數字鍵 3", + "KeyKeypad4": "數字鍵 4", + "KeyKeypad5": "數字鍵 5", + "KeyKeypad6": "數字鍵 6", + "KeyKeypad7": "數字鍵 7", + "KeyKeypad8": "數字鍵 8", + "KeyKeypad9": "數字鍵 9", + "KeyKeypadDivide": "數字鍵除號", + "KeyKeypadMultiply": "數字鍵乘號", + "KeyKeypadSubtract": "數字鍵減號", + "KeyKeypadAdd": "數字鍵加號", + "KeyKeypadDecimal": "數字鍵小數點", + "KeyKeypadEnter": "數字鍵 Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "未分配", + "GamepadLeftStick": "左搖桿按鍵", + "GamepadRightStick": "右搖桿按鍵", + "GamepadLeftShoulder": "左肩鍵", + "GamepadRightShoulder": "右肩鍵", + "GamepadLeftTrigger": "左扳機", + "GamepadRightTrigger": "右扳機", + "GamepadDpadUp": "上", + "GamepadDpadDown": "下", + "GamepadDpadLeft": "左", + "GamepadDpadRight": "右", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "快顯功能表鍵", + "GamepadMisc1": "其他按鍵", + "GamepadPaddle1": "其他按鍵 1", + "GamepadPaddle2": "其他按鍵 2", + "GamepadPaddle3": "其他按鍵 3", + "GamepadPaddle4": "其他按鍵 4", + "GamepadTouchpad": "觸控板", + "GamepadSingleLeftTrigger0": "左扳機 0", + "GamepadSingleRightTrigger0": "右扳機 0", + "GamepadSingleLeftTrigger1": "左扳機 1", + "GamepadSingleRightTrigger1": "右扳機 1", + "StickLeft": "左搖桿", + "StickRight": "右搖桿", + "UserProfilesSelectedUserProfile": "選取的使用者設定檔:", + "UserProfilesSaveProfileName": "儲存設定檔名稱", + "UserProfilesChangeProfileImage": "變更設定檔圖像", + "UserProfilesAvailableUserProfiles": "可用的使用者設定檔:", + "UserProfilesAddNewProfile": "建立設定檔", + "UserProfilesDelete": "刪除", + "UserProfilesClose": "關閉", + "ProfileNameSelectionWatermark": "選擇暱稱", + "ProfileImageSelectionTitle": "設定檔圖像選取", + "ProfileImageSelectionHeader": "選擇設定檔圖像", + "ProfileImageSelectionNote": "您可以匯入自訂的設定檔圖像,或從系統韌體中選取大頭貼。", + "ProfileImageSelectionImportImage": "匯入圖像檔案", + "ProfileImageSelectionSelectAvatar": "選取韌體大頭貼", + "InputDialogTitle": "輸入對話方塊", + "InputDialogOk": "確定", + "InputDialogCancel": "取消", + "InputDialogAddNewProfileTitle": "選擇設定檔名稱", + "InputDialogAddNewProfileHeader": "請輸入設定檔名稱", + "InputDialogAddNewProfileSubtext": "(最大長度: {0})", + "AvatarChoose": "選擇大頭貼", + "AvatarSetBackgroundColor": "設定背景顏色", + "AvatarClose": "關閉", + "ControllerSettingsLoadProfileToolTip": "載入設定檔", + "ControllerSettingsAddProfileToolTip": "新增設定檔", + "ControllerSettingsRemoveProfileToolTip": "刪除設定檔", + "ControllerSettingsSaveProfileToolTip": "儲存設定檔", + "MenuBarFileToolsTakeScreenshot": "儲存擷取畫面", + "MenuBarFileToolsHideUi": "隱藏 UI", + "GameListContextMenuRunApplication": "執行應用程式", + "GameListContextMenuToggleFavorite": "加入/移除為我的最愛", + "GameListContextMenuToggleFavoriteToolTip": "切換遊戲的我的最愛狀態", + "SettingsTabGeneralTheme": "佈景主題:", + "SettingsTabGeneralThemeDark": "深色", + "SettingsTabGeneralThemeLight": "淺色", + "ControllerSettingsConfigureGeneral": "配置", + "ControllerSettingsRumble": "震動", + "ControllerSettingsRumbleStrongMultiplier": "強震動調節", + "ControllerSettingsRumbleWeakMultiplier": "弱震動調節", + "DialogMessageSaveNotAvailableMessage": "沒有 {0} [{1:x16}] 的存檔", + "DialogMessageSaveNotAvailableCreateSaveMessage": "您想為這款遊戲建立存檔嗎?", + "DialogConfirmationTitle": "Ryujinx - 確認", + "DialogUpdaterTitle": "Ryujinx - 更新程式", + "DialogErrorTitle": "Ryujinx - 錯誤", + "DialogWarningTitle": "Ryujinx - 警告", + "DialogExitTitle": "Ryujinx - 結束", + "DialogErrorMessage": "Ryujinx 遇到了錯誤", + "DialogExitMessage": "您確定要關閉 Ryujinx 嗎?", + "DialogExitSubMessage": "所有未儲存的資料將會遺失!", + "DialogMessageCreateSaveErrorMessage": "建立指定的存檔時出現錯誤: {0}", + "DialogMessageFindSaveErrorMessage": "尋找指定的存檔時出現錯誤: {0}", + "FolderDialogExtractTitle": "選擇要解壓到的資料夾", + "DialogNcaExtractionMessage": "從 {1} 提取 {0} 分區...", + "DialogNcaExtractionTitle": "Ryujinx - NCA 分區提取器", + "DialogNcaExtractionMainNcaNotFoundErrorMessage": "提取失敗。所選檔案中不存在主 NCA 檔案。", + "DialogNcaExtractionCheckLogErrorMessage": "提取失敗。請閱讀日誌檔案了解更多資訊。", + "DialogNcaExtractionSuccessMessage": "提取成功。", + "DialogUpdaterConvertFailedMessage": "無法轉換目前的 Ryujinx 版本。", + "DialogUpdaterCancelUpdateMessage": "取消更新!", + "DialogUpdaterAlreadyOnLatestVersionMessage": "您已經在使用最新版本的 Ryujinx!", + "DialogUpdaterFailedToGetVersionMessage": "嘗試從 GitHub Release 取得發布資訊時發生錯誤。如果 GitHub Actions 正在編譯新版本,則可能會出現這種情況。請幾分鐘後再試一次。", + "DialogUpdaterConvertFailedGithubMessage": "無法轉換從 Github Release 接收到的 Ryujinx 版本。", + "DialogUpdaterDownloadingMessage": "正在下載更新...", + "DialogUpdaterExtractionMessage": "正在提取更新...", + "DialogUpdaterRenamingMessage": "重新命名更新...", + "DialogUpdaterAddingFilesMessage": "加入新更新...", + "DialogUpdaterCompleteMessage": "更新成功!", + "DialogUpdaterRestartMessage": "您現在要重新啟動 Ryujinx 嗎?", + "DialogUpdaterNoInternetMessage": "您沒有連線到網際網路!", + "DialogUpdaterNoInternetSubMessage": "請確認您的網際網路連線正常!", + "DialogUpdaterDirtyBuildMessage": "您無法更新非官方版本的 Ryujinx!", + "DialogUpdaterDirtyBuildSubMessage": "如果您正在尋找受官方支援的版本,請從 https://ryujinx.org/ 下載 Ryujinx。", + "DialogRestartRequiredMessage": "需要重新啟動", + "DialogThemeRestartMessage": "佈景主題設定已儲存。需要重新啟動才能套用主題。", + "DialogThemeRestartSubMessage": "您要重新啟動嗎", + "DialogFirmwareInstallEmbeddedMessage": "您想安裝遊戲內建的韌體嗎? (韌體 {0})", + "DialogFirmwareInstallEmbeddedSuccessMessage": "未找到已安裝的韌體,但 Ryujinx 可以從現有的遊戲安裝韌體{0}。\n模擬器現在可以執行。", + "DialogFirmwareNoFirmwareInstalledMessage": "未安裝韌體", + "DialogFirmwareInstalledMessage": "已安裝韌體{0}", + "DialogInstallFileTypesSuccessMessage": "成功安裝檔案類型!", + "DialogInstallFileTypesErrorMessage": "無法安裝檔案類型。", + "DialogUninstallFileTypesSuccessMessage": "成功移除檔案類型!", + "DialogUninstallFileTypesErrorMessage": "無法移除檔案類型。", + "DialogOpenSettingsWindowLabel": "開啟設定視窗", + "DialogControllerAppletTitle": "控制器小程式", + "DialogMessageDialogErrorExceptionMessage": "顯示訊息對話方塊時出現錯誤: {0}", + "DialogSoftwareKeyboardErrorExceptionMessage": "顯示軟體鍵盤時出現錯誤: {0}", + "DialogErrorAppletErrorExceptionMessage": "顯示錯誤對話方塊時出現錯誤: {0}", + "DialogUserErrorDialogMessage": "{0}: {1}", + "DialogUserErrorDialogInfoMessage": "\n有關如何修復此錯誤的更多資訊,請參閱我們的設定指南。", + "DialogUserErrorDialogTitle": "Ryujinx 錯誤 ({0})", + "DialogAmiiboApiTitle": "Amiibo API", + "DialogAmiiboApiFailFetchMessage": "從 API 取得資訊時出現錯誤。", + "DialogAmiiboApiConnectErrorMessage": "無法連接 Amiibo API 伺服器。服務可能已停機,或者您可能需要確認網際網路連線是否在線上。", + "DialogProfileInvalidProfileErrorMessage": "設定檔 {0} 與目前輸入配置系統不相容。", + "DialogProfileDefaultProfileOverwriteErrorMessage": "無法覆蓋預設設定檔", + "DialogProfileDeleteProfileTitle": "刪除設定檔", + "DialogProfileDeleteProfileMessage": "此動作不可復原,您確定要繼續嗎?", + "DialogWarning": "警告", + "DialogPPTCDeletionMessage": "您將在下一次啟動時佇列重建以下遊戲的 PPTC:\n\n{0}\n\n您確定要繼續嗎?", + "DialogPPTCDeletionErrorMessage": "在 {0} 清除 PPTC 快取時出錯: {1}", + "DialogShaderDeletionMessage": "您將刪除以下遊戲的著色器快取:\n\n{0}\n\n您確定要繼續嗎?", + "DialogShaderDeletionErrorMessage": "在 {0} 清除著色器快取時出錯: {1}", + "DialogRyujinxErrorMessage": "Ryujinx 遇到錯誤", + "DialogInvalidTitleIdErrorMessage": "UI 錯誤: 所選遊戲沒有有效的遊戲 ID", + "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "在 {0} 中未發現有效的系統韌體。", + "DialogFirmwareInstallerFirmwareInstallTitle": "安裝韌體 {0}", + "DialogFirmwareInstallerFirmwareInstallMessage": "將安裝系統版本 {0}。", + "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\n這將取代目前的系統版本 {0}。", + "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n您確定要繼續嗎?", + "DialogFirmwareInstallerFirmwareInstallWaitMessage": "正在安裝韌體...", + "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "成功安裝系統版本 {0}。", + "DialogUserProfileDeletionWarningMessage": "如果刪除選取的設定檔,將無法開啟其他設定檔", + "DialogUserProfileDeletionConfirmMessage": "您是否要刪除所選設定檔", + "DialogUserProfileUnsavedChangesTitle": "警告 - 未儲存的變更", + "DialogUserProfileUnsavedChangesMessage": "您對該使用者設定檔所做的變更尚未儲存。", + "DialogUserProfileUnsavedChangesSubMessage": "您確定要放棄變更嗎?", + "DialogControllerSettingsModifiedConfirmMessage": "目前控制器設定已更新。", + "DialogControllerSettingsModifiedConfirmSubMessage": "您想要儲存嗎?", + "DialogLoadFileErrorMessage": "{0}。出錯檔案: {1}", + "DialogModAlreadyExistsMessage": "模組已經存在", + "DialogModInvalidMessage": "指定資料夾不包含模組!", + "DialogModDeleteNoParentMessage": "刪除失敗: 無法找到模組「{0}」的父資料夾!", + "DialogDlcNoDlcErrorMessage": "指定檔案不包含所選遊戲的 DLC!", + "DialogPerformanceCheckLoggingEnabledMessage": "您已啟用追蹤日誌,該功能僅供開發者使用。", + "DialogPerformanceCheckLoggingEnabledConfirmMessage": "為獲得最佳效能,建議停用追蹤日誌。您是否要立即停用追蹤日誌嗎?", + "DialogPerformanceCheckShaderDumpEnabledMessage": "您已啟用著色器傾印,該功能僅供開發者使用。", + "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "為獲得最佳效能,建議停用著色器傾印。您是否要立即停用著色器傾印嗎?", + "DialogLoadAppGameAlreadyLoadedMessage": "已載入此遊戲", + "DialogLoadAppGameAlreadyLoadedSubMessage": "請停止模擬或關閉模擬器,然後再啟動另一款遊戲。", + "DialogUpdateAddUpdateErrorMessage": "指定檔案不包含所選遊戲的更新!", + "DialogSettingsBackendThreadingWarningTitle": "警告 - 後端執行緒處理中", + "DialogSettingsBackendThreadingWarningMessage": "變更此選項後,必須重新啟動 Ryujinx 才能完全生效。使用 Ryujinx 的多執行緒功能時,可能需要手動停用驅動程式本身的多執行緒功能,這取決於您的平台。", + "DialogModManagerDeletionWarningMessage": "您將刪除模組: {0}\n\n您確定要繼續嗎?", + "DialogModManagerDeletionAllWarningMessage": "您即將刪除此遊戲的所有模組。\n\n您確定要繼續嗎?", + "SettingsTabGraphicsFeaturesOptions": "功能", + "SettingsTabGraphicsBackendMultithreading": "圖形後端多執行緒:", + "CommonAuto": "自動", + "CommonOff": "關閉", + "CommonOn": "開啟", + "InputDialogYes": "是", + "InputDialogNo": "否", + "DialogProfileInvalidProfileNameErrorMessage": "檔案名稱包含無效字元。請重試。", + "MenuBarOptionsPauseEmulation": "暫停", + "MenuBarOptionsResumeEmulation": "繼續", + "AboutUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 網站。", + "AboutDisclaimerMessage": "Ryujinx 和 Nintendo™\n或其任何合作夥伴完全沒有關聯。", + "AboutAmiiboDisclaimerMessage": "我們在 Amiibo 模擬中\n使用了 AmiiboAPI (www.amiiboapi.com)。", + "AboutPatreonUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 Patreon 網頁。", + "AboutGithubUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 GitHub 網頁。", + "AboutDiscordUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 Discord 邀請連結。", + "AboutTwitterUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 Twitter 網頁。", + "AboutRyujinxAboutTitle": "關於:", + "AboutRyujinxAboutContent": "Ryujinx 是一款 Nintendo Switch™ 模擬器。\n請在 Patreon 上支持我們。\n關注我們的 Twitter 或 Discord 取得所有最新消息。\n對於有興趣貢獻的開發者,可以在我們的 GitHub 或 Discord 上了解更多資訊。", + "AboutRyujinxMaintainersTitle": "維護者:", + "AboutRyujinxMaintainersContentTooltipMessage": "在預設瀏覽器中開啟貢獻者的網頁", + "AboutRyujinxSupprtersTitle": "Patreon 支持者:", + "AmiiboSeriesLabel": "Amiibo 系列", + "AmiiboCharacterLabel": "角色", + "AmiiboScanButtonLabel": "掃描", + "AmiiboOptionsShowAllLabel": "顯示所有 Amiibo", + "AmiiboOptionsUsRandomTagLabel": "補釘修正:使用隨機標記的 Uuid", + "DlcManagerTableHeadingEnabledLabel": "已啟用", + "DlcManagerTableHeadingTitleIdLabel": "遊戲 ID", + "DlcManagerTableHeadingContainerPathLabel": "容器路徑", + "DlcManagerTableHeadingFullPathLabel": "完整路徑", + "DlcManagerRemoveAllButton": "全部刪除", + "DlcManagerEnableAllButton": "全部啟用", + "DlcManagerDisableAllButton": "全部停用", + "ModManagerDeleteAllButton": "全部刪除", + "MenuBarOptionsChangeLanguage": "變更語言", + "MenuBarShowFileTypes": "顯示檔案類型", + "CommonSort": "排序", + "CommonShowNames": "顯示名稱", + "CommonFavorite": "我的最愛", + "OrderAscending": "從小到大", + "OrderDescending": "從大到小", + "SettingsTabGraphicsFeatures": "功能與改進", + "ErrorWindowTitle": "錯誤視窗", + "ToggleDiscordTooltip": "啟用或關閉 Discord 動態狀態展示", + "AddGameDirBoxTooltip": "輸入要新增到清單中的遊戲資料夾", + "AddGameDirTooltip": "新增遊戲資料夾到清單中", + "RemoveGameDirTooltip": "移除選取的遊戲資料夾", + "CustomThemeCheckTooltip": "為圖形使用者介面使用自訂 Avalonia 佈景主題,變更模擬器功能表的外觀", + "CustomThemePathTooltip": "自訂 GUI 佈景主題的路徑", + "CustomThemeBrowseTooltip": "瀏覽自訂 GUI 佈景主題", + "DockModeToggleTooltip": "底座模式可使模擬系統表現為底座的 Nintendo Switch。這可以提高大多數遊戲的圖形保真度。反之,停用該模式將使模擬系統表現為手提模式的 Nintendo Switch,從而降低圖形品質。\n\n如果計劃使用底座模式,請配置玩家 1 控制;如果計劃使用手提模式,請配置手提控制。\n\n如果不確定,請保持開啟狀態。", + "DirectKeyboardTooltip": "支援直接鍵盤存取 (HID)。遊戲可將鍵盤作為文字輸入裝置。\n\n僅適用於在 Switch 硬體上原生支援使用鍵盤的遊戲。\n\n如果不確定,請保持關閉狀態。", + "DirectMouseTooltip": "支援滑鼠直接存取 (HID)。遊戲可將滑鼠作為指向裝置使用。\n\n僅適用於在 Switch 硬體上原生支援滑鼠控制的遊戲,這類遊戲很少。\n\n啟用後,觸控螢幕功能可能無法使用。\n\n如果不確定,請保持關閉狀態。", + "RegionTooltip": "變更系統區域", + "LanguageTooltip": "變更系統語言", + "TimezoneTooltip": "變更系統時區", + "TimeTooltip": "變更系統時鐘", + "VSyncToggleTooltip": "模擬遊戲機的垂直同步。對大多數遊戲來說,它本質上是一個幀率限制器;停用它可能會導致遊戲以更高的速度執行,或使載入畫面耗時更長或卡住。\n\n可以在遊戲中使用快速鍵進行切換 (預設為 F1)。如果您打算停用,我們建議您這樣做。\n\n如果不確定,請保持開啟狀態。", + "PptcToggleTooltip": "儲存已轉譯的 JIT 函數,這樣每次載入遊戲時就無需再轉譯這些函數。\n\n減少遊戲首次啟動後的卡頓現象,並大大加快啟動時間。\n\n如果不確定,請保持開啟狀態。", + "FsIntegrityToggleTooltip": "在啟動遊戲時檢查損壞的檔案,如果檢測到損壞的檔案,則在日誌中顯示雜湊值錯誤。\n\n對效能沒有影響,旨在幫助排除故障。\n\n如果不確定,請保持開啟狀態。", + "AudioBackendTooltip": "變更用於繪製音訊的後端。\n\nSDL2 是首選,而 OpenAL 和 SoundIO 則作為備用。虛設 (Dummy) 將沒有聲音。\n\n如果不確定,請設定為 SDL2。", + "MemoryManagerTooltip": "變更客體記憶體的映射和存取方式。這會極大地影響模擬 CPU 效能。\n\n如果不確定,請設定為主體略過檢查模式。", + "MemoryManagerSoftwareTooltip": "使用軟體分頁表進行位址轉換。精度最高,但效能最差。", + "MemoryManagerHostTooltip": "直接映射主體位址空間中的記憶體。更快的 JIT 編譯和執行速度。", + "MemoryManagerUnsafeTooltip": "直接映射記憶體,但在存取前不封鎖客體位址空間內的位址。速度更快,但相對不安全。訪客應用程式可以從 Ryujinx 中的任何地方存取記憶體,因此只能使用該模式執行您信任的程式。", + "UseHypervisorTooltip": "使用 Hypervisor 取代 JIT。使用時可大幅提高效能,但在目前狀態下可能不穩定。", + "DRamTooltip": "利用另一種 MemoryMode 配置來模仿 Switch 開發模式。\n\n這僅對高解析度紋理套件或 4K 解析度模組有用。不會提高效能。\n\n如果不確定,請保持關閉狀態。", + "IgnoreMissingServicesTooltip": "忽略未實現的 Horizon OS 服務。這可能有助於在啟動某些遊戲時避免崩潰。\n\n如果不確定,請保持關閉狀態。", + "GraphicsBackendThreadingTooltip": "在第二個執行緒上執行圖形後端指令。\n\n在本身不支援多執行緒的 GPU 驅動程式上,可加快著色器編譯、減少卡頓並提高效能。在支援多執行緒的驅動程式上效能略有提升。\n\n如果不確定,請設定為自動。", + "GalThreadingTooltip": "在第二個執行緒上執行圖形後端指令。\n\n在本身不支援多執行緒的 GPU 驅動程式上,可加快著色器編譯、減少卡頓並提高效能。在支援多執行緒的驅動程式上效能略有提升。\n\n如果不確定,請設定為自動。", + "ShaderCacheToggleTooltip": "儲存磁碟著色器快取,減少後續執行時的卡頓。\n\n如果不確定,請保持開啟狀態。", + "ResolutionScaleTooltip": "使用倍數提升遊戲的繪製解析度。\n\n少數遊戲可能無法使用此功能,即使提高解析度也會顯得像素化;對於這些遊戲,您可能需要找到去除反鋸齒或提高內部繪製解析度的模組。對於後者,您可能需要選擇原生。\n\n此選項可在遊戲執行時透過點選下方的「套用」進行變更;您只需將設定視窗移到一旁,然後進行試驗,直到找到您喜歡的遊戲效果。\n\n請記住,4 倍幾乎對任何設定都是過度的。", + "ResolutionScaleEntryTooltip": "浮點解析度刻度,如 1.5。非整數刻度更容易出現問題或崩潰。", + "AnisotropyTooltip": "各向異性過濾等級。設定為自動可使用遊戲要求的值。", + "AspectRatioTooltip": "套用於繪製器視窗的長寬比。\n\n只有在遊戲中使用長寬比模組時才可變更,否則圖形會被拉伸。\n\n如果不確定,請保持 16:9 狀態。", + "ShaderDumpPathTooltip": "圖形著色器傾印路徑", + "FileLogTooltip": "將控制台日誌儲存到磁碟上的日誌檔案中。不會影響效能。", + "StubLogTooltip": "在控制台中輸出日誌訊息。不會影響效能。", + "InfoLogTooltip": "在控制台中輸出資訊日誌訊息。不會影響效能。", + "WarnLogTooltip": "在控制台中輸出警告日誌訊息。不會影響效能。", + "ErrorLogTooltip": "在控制台中輸出錯誤日誌訊息。不會影響效能。", + "TraceLogTooltip": "在控制台中輸出追蹤日誌訊息。不會影響效能。", + "GuestLogTooltip": "在控制台中輸出客體日誌訊息。不會影響效能。", + "FileAccessLogTooltip": "在控制台中輸出檔案存取日誌訊息。", + "FSAccessLogModeTooltip": "啟用檔案系統存取日誌輸出到控制台中。可能的模式為 0 到 3", + "DeveloperOptionTooltip": "謹慎使用", + "OpenGlLogLevel": "需要啟用適當的日誌等級", + "DebugLogTooltip": "在控制台中輸出偵錯日誌訊息。\n\n只有在人員特別指示的情況下才能使用,因為這會導致日誌難以閱讀,並降低模擬器效能。", + "LoadApplicationFileTooltip": "開啟檔案總管,選擇與 Switch 相容的檔案來載入", + "LoadApplicationFolderTooltip": "開啟檔案總管,選擇與 Switch 相容且未封裝的應用程式來載入", + "OpenRyujinxFolderTooltip": "開啟 Ryujinx 檔案系統資料夾", + "OpenRyujinxLogsTooltip": "開啟日誌被寫入的資料夾", + "ExitTooltip": "結束 Ryujinx", + "OpenSettingsTooltip": "開啟設定視窗", + "OpenProfileManagerTooltip": "開啟使用者設定檔管理員視窗", + "StopEmulationTooltip": "停止模擬目前遊戲,返回遊戲選擇介面", + "CheckUpdatesTooltip": "檢查 Ryujinx 的更新", + "OpenAboutTooltip": "開啟關於視窗", + "GridSize": "網格尺寸", + "GridSizeTooltip": "調整網格的大小", + "SettingsTabSystemSystemLanguageBrazilianPortuguese": "巴西葡萄牙文", + "AboutRyujinxContributorsButtonHeader": "查看所有貢獻者", + "SettingsTabSystemAudioVolume": "音量:", + "AudioVolumeTooltip": "調節音量", + "SettingsTabSystemEnableInternetAccess": "訪客網際網路存取/區域網路模式", + "EnableInternetAccessTooltip": "允許模擬應用程式連線網際網路。\n\n當啟用此功能且系統連線到同一接入點時,具有區域網路模式的遊戲可相互連線。這也包括真正的遊戲機。\n\n不允許連接 Nintendo 伺服器。可能會導致某些嘗試連線網際網路的遊戲崩潰。\n\n如果不確定,請保持關閉狀態。", + "GameListContextMenuManageCheatToolTip": "管理密技", + "GameListContextMenuManageCheat": "管理密技", + "GameListContextMenuManageModToolTip": "管理模組", + "GameListContextMenuManageMod": "管理模組", + "ControllerSettingsStickRange": "範圍:", + "DialogStopEmulationTitle": "Ryujinx - 停止模擬", + "DialogStopEmulationMessage": "您確定要停止模擬嗎?", + "SettingsTabCpu": "CPU", + "SettingsTabAudio": "音訊", + "SettingsTabNetwork": "網路", + "SettingsTabNetworkConnection": "網路連線", + "SettingsTabCpuCache": "CPU 快取", + "SettingsTabCpuMemory": "CPU 模式", + "DialogUpdaterFlatpakNotSupportedMessage": "請透過 Flathub 更新 Ryujinx。", + "UpdaterDisabledWarningTitle": "更新已停用!", + "ControllerSettingsRotate90": "順時針旋轉 90°", + "IconSize": "圖示大小", + "IconSizeTooltip": "變更遊戲圖示的大小", + "MenuBarOptionsShowConsole": "顯示控制台", + "ShaderCachePurgeError": "在 {0} 清除著色器快取時出錯: {1}", + "UserErrorNoKeys": "找不到金鑰", + "UserErrorNoFirmware": "找不到韌體", + "UserErrorFirmwareParsingFailed": "韌體解析錯誤", + "UserErrorApplicationNotFound": "找不到應用程式", + "UserErrorUnknown": "未知錯誤", + "UserErrorUndefined": "未定義錯誤", + "UserErrorNoKeysDescription": "Ryujinx 無法找到您的「prod.keys」檔案", + "UserErrorNoFirmwareDescription": "Ryujinx 無法找到已安裝的任何韌體", + "UserErrorFirmwareParsingFailedDescription": "Ryujinx 無法解析所提供的韌體。這通常是由於金鑰過時造成的。", + "UserErrorApplicationNotFoundDescription": "Ryujinx 無法在指定路徑下找到有效的應用程式。", + "UserErrorUnknownDescription": "發生未知錯誤!", + "UserErrorUndefinedDescription": "發生未定義錯誤! 這種情況不應該發生,請聯絡開發人員!", + "OpenSetupGuideMessage": "開啟設定指南", + "NoUpdate": "沒有更新", + "TitleUpdateVersionLabel": "版本 {0}", + "RyujinxInfo": "Ryujinx - 資訊", + "RyujinxConfirm": "Ryujinx - 確認", + "FileDialogAllTypes": "全部類型", + "Never": "從不", + "SwkbdMinCharacters": "長度必須至少為 {0} 個字元", + "SwkbdMinRangeCharacters": "長度必須為 {0} 到 {1} 個字元", + "SoftwareKeyboard": "軟體鍵盤", + "SoftwareKeyboardModeNumeric": "必須是 0 到 9 或「.」", + "SoftwareKeyboardModeAlphabet": "必須是「非中日韓字元」 (non CJK)", + "SoftwareKeyboardModeASCII": "必須是 ASCII 文字", + "ControllerAppletControllers": "支援的控制器:", + "ControllerAppletPlayers": "玩家:", + "ControllerAppletDescription": "您目前的配置無效。開啟設定並重新配置輸入。", + "ControllerAppletDocked": "已設定底座模式。手提控制應該停用。", + "UpdaterRenaming": "正在重新命名舊檔案...", + "UpdaterRenameFailed": "更新程式無法重新命名檔案: {0}", + "UpdaterAddingFiles": "正在加入新檔案...", + "UpdaterExtracting": "正在提取更新...", + "UpdaterDownloading": "正在下載更新...", + "Game": "遊戲", + "Docked": "底座模式", + "Handheld": "手提模式", + "ConnectionError": "連線錯誤。", + "AboutPageDeveloperListMore": "{0} 等人...", + "ApiError": "API 錯誤。", + "LoadingHeading": "正在載入 {0}", + "CompilingPPTC": "正在編譯 PTC", + "CompilingShaders": "正在編譯著色器", + "AllKeyboards": "所有鍵盤", + "OpenFileDialogTitle": "選取支援的檔案格式", + "OpenFolderDialogTitle": "選取未封裝遊戲的資料夾", + "AllSupportedFormats": "所有支援的格式", + "RyujinxUpdater": "Ryujinx 更新程式", + "SettingsTabHotkeys": "鍵盤快速鍵", + "SettingsTabHotkeysHotkeys": "鍵盤快捷鍵", + "SettingsTabHotkeysToggleVsyncHotkey": "切換垂直同步:", + "SettingsTabHotkeysScreenshotHotkey": "擷取畫面:", + "SettingsTabHotkeysShowUiHotkey": "顯示 UI:", + "SettingsTabHotkeysPauseHotkey": "暫停:", + "SettingsTabHotkeysToggleMuteHotkey": "靜音:", + "ControllerMotionTitle": "體感控制設定", + "ControllerRumbleTitle": "震動設定", + "SettingsSelectThemeFileDialogTitle": "選取佈景主題檔案", + "SettingsXamlThemeFile": "Xaml 佈景主題檔案", + "AvatarWindowTitle": "管理帳戶 - 大頭貼", + "Amiibo": "Amiibo", + "Unknown": "未知", + "Usage": "用途", + "Writable": "可寫入", + "SelectDlcDialogTitle": "選取 DLC 檔案", + "SelectUpdateDialogTitle": "選取更新檔", + "SelectModDialogTitle": "選取模組資料夾", + "UserProfileWindowTitle": "使用者設定檔管理員", + "CheatWindowTitle": "密技管理員", + "DlcWindowTitle": "管理 {0} 的可下載內容 ({1})", + "ModWindowTitle": "管理 {0} 的模組 ({1})", + "UpdateWindowTitle": "遊戲更新管理員", + "CheatWindowHeading": "可用於 {0} [{1}] 的密技", + "BuildId": "組建識別碼:", + "DlcWindowHeading": "{0} 個可下載內容", + "ModWindowHeading": "{0} 模組", + "UserProfilesEditProfile": "編輯所選", + "Cancel": "取消", + "Save": "儲存", + "Discard": "放棄變更", + "Paused": "暫停", + "UserProfilesSetProfileImage": "設定設定檔圖像", + "UserProfileEmptyNameError": "名稱為必填", + "UserProfileNoImageError": "必須設定設定檔圖像", + "GameUpdateWindowHeading": "管理 {0} 的更新 ({1})", + "SettingsTabHotkeysResScaleUpHotkey": "提高解析度:", + "SettingsTabHotkeysResScaleDownHotkey": "降低解析度:", + "UserProfilesName": "名稱:", + "UserProfilesUserId": "使用者 ID:", + "SettingsTabGraphicsBackend": "圖形後端", + "SettingsTabGraphicsBackendTooltip": "選擇模擬器將使用的圖形後端。\n\n只要驅動程式是最新的,Vulkan 對所有現代顯示卡來說都更好用。Vulkan 還能在所有 GPU 廠商上實現更快的著色器編譯 (減少卡頓)。\n\nOpenGL 在舊式 Nvidia GPU、Linux 上的舊式 AMD GPU 或 VRAM 較低的 GPU 上可能會取得更好的效果,不過著色器編譯的卡頓會更嚴重。\n\n如果不確定,請設定為 Vulkan。如果您的 GPU 使用最新的圖形驅動程式也不支援 Vulkan,請設定為 OpenGL。", + "SettingsEnableTextureRecompression": "開啟材質重新壓縮", + "SettingsEnableTextureRecompressionTooltip": "壓縮 ASTC 紋理,以減少 VRAM 占用。\n\n使用這種紋理格式的遊戲包括 Astral Chain、Bayonetta 3、Fire Emblem Engage、Metroid Prime Remastered、Super Mario Bros. Wonder 和 The Legend of Zelda: Tears of the Kingdom。\n\n使用 4GB 或更低 VRAM 的顯示卡在執行這些遊戲時可能會崩潰。\n\n只有在上述遊戲的 VRAM 即將耗盡時才啟用。如果不確定,請保持關閉狀態。", + "SettingsTabGraphicsPreferredGpu": "優先選取的 GPU", + "SettingsTabGraphicsPreferredGpuTooltip": "選擇將與 Vulkan 圖形後端一起使用的顯示卡。\n\n不會影響 OpenGL 將使用的 GPU。\n\n如果不確定,請設定為標記為「dGPU」的 GPU。如果沒有,則保持原狀。", + "SettingsAppRequiredRestartMessage": "需要重新啟動 Ryujinx", + "SettingsGpuBackendRestartMessage": "圖形後端或 GPU 設定已修改。這需要重新啟動才能套用。", + "SettingsGpuBackendRestartSubMessage": "您現在要重新啟動嗎?", + "RyujinxUpdaterMessage": "您想將 Ryujinx 升級到最新版本嗎?", + "SettingsTabHotkeysVolumeUpHotkey": "提高音量:", + "SettingsTabHotkeysVolumeDownHotkey": "降低音量:", + "SettingsEnableMacroHLE": "啟用 Macro HLE", + "SettingsEnableMacroHLETooltip": "GPU 巨集程式碼的進階模擬。\n\n可提高效能,但在某些遊戲中可能會導致圖形閃爍。\n\n如果不確定,請保持開啟狀態。", + "SettingsEnableColorSpacePassthrough": "色彩空間直通", + "SettingsEnableColorSpacePassthroughTooltip": "指示 Vulkan 後端在不指定色彩空間的情況下傳遞色彩資訊。對於使用廣色域顯示器的使用者來說,這可能會帶來更鮮艷的色彩,但代價是犧牲色彩的正確性。", + "VolumeShort": "音量", + "UserProfilesManageSaves": "管理存檔", + "DeleteUserSave": "您想刪除此遊戲的使用者存檔嗎?", + "IrreversibleActionNote": "此動作將無法復原。", + "SaveManagerHeading": "管理 {0} 的存檔 ({1})", + "SaveManagerTitle": "存檔管理員", + "Name": "名稱", + "Size": "大小", + "Search": "搜尋", + "UserProfilesRecoverLostAccounts": "復原遺失的帳戶", + "Recover": "復原", + "UserProfilesRecoverHeading": "發現下列帳戶有一些存檔", + "UserProfilesRecoverEmptyList": "無設定檔可復原", + "GraphicsAATooltip": "對遊戲繪製進行反鋸齒處理。\n\nFXAA 會模糊大部分圖像,而 SMAA 則會嘗試找出鋸齒邊緣並將其平滑化。\n\n不建議與 FSR 縮放濾鏡一起使用。\n\n此選項可在遊戲執行時透過點選下方的「套用」進行變更;您只需將設定視窗移到一旁,然後進行試驗,直到找到您喜歡的遊戲效果。\n\n如果不確定,請選擇無狀態。", + "GraphicsAALabel": "反鋸齒:", + "GraphicsScalingFilterLabel": "縮放過濾器:", + "GraphicsScalingFilterTooltip": "選擇使用解析度縮放時套用的縮放過濾器。\n\n雙線性 (Bilinear) 濾鏡適用於 3D 遊戲,是一個安全的預設選項。\n\n建議像素美術遊戲使用近鄰性 (Nearest) 濾鏡。\n\nFSR 1.0 只是一個銳化濾鏡,不建議與 FXAA 或 SMAA 一起使用。\n\n此選項可在遊戲執行時透過點選下方的「套用」進行變更;您只需將設定視窗移到一旁,然後進行試驗,直到找到您喜歡的遊戲效果。\n\n如果不確定,請保持雙線性 (Bilinear) 狀態。", + "GraphicsScalingFilterBilinear": "雙線性 (Bilinear)", + "GraphicsScalingFilterNearest": "近鄰性 (Nearest)", + "GraphicsScalingFilterFsr": "FSR", + "GraphicsScalingFilterLevelLabel": "日誌等級", + "GraphicsScalingFilterLevelTooltip": "設定 FSR 1.0 銳化等級。越高越清晰。", + "SmaaLow": "低階 SMAA", + "SmaaMedium": "中階 SMAA", + "SmaaHigh": "高階 SMAA", + "SmaaUltra": "超高階 SMAA", + "UserEditorTitle": "編輯使用者", + "UserEditorTitleCreate": "建立使用者", + "SettingsTabNetworkInterface": "網路介面:", + "NetworkInterfaceTooltip": "用於 LAN/LDN 功能的網路介面。\n\n與 VPN 或 XLink Kai 以及支援區域網路的遊戲配合使用,可用於在網路上偽造同網際網路連線。\n\n如果不確定,請保持預設狀態。", + "NetworkInterfaceDefault": "預設", + "PackagingShaders": "封裝著色器", + "AboutChangelogButton": "在 GitHub 上檢視更新日誌", + "AboutChangelogButtonTooltipMessage": "在預設瀏覽器中開啟此版本的更新日誌。", + "SettingsTabNetworkMultiplayer": "多人遊戲", + "MultiplayerMode": "模式:", + "MultiplayerModeTooltip": "變更 LDN 多人遊戲模式。\n\nLdnMitm 將修改遊戲中的本機無線/本機遊戲功能,使其如同區域網路一樣執行,允許與其他安裝了 ldn_mitm 模組的 Ryujinx 實例和已破解的 Nintendo Switch 遊戲機進行本機同網路連線。\n\n多人遊戲要求所有玩家使用相同的遊戲版本 (例如,Super Smash Bros. Ultimate v13.0.1 無法連接 v13.0.0)。\n\n如果不確定,請保持 Disabled (停用) 狀態。", + "MultiplayerModeDisabled": "已停用", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx.Ava/Assets/Styles/Styles.xaml b/src/Ryujinx/Assets/Styles/Styles.xaml similarity index 99% rename from src/Ryujinx.Ava/Assets/Styles/Styles.xaml rename to src/Ryujinx/Assets/Styles/Styles.xaml index 5e6ab6faf..b3a6f59c8 100644 --- a/src/Ryujinx.Ava/Assets/Styles/Styles.xaml +++ b/src/Ryujinx/Assets/Styles/Styles.xaml @@ -14,6 +14,9 @@ + + + diff --git a/src/Ryujinx.Ava/Assets/Styles/Themes.xaml b/src/Ryujinx/Assets/Styles/Themes.xaml similarity index 100% rename from src/Ryujinx.Ava/Assets/Styles/Themes.xaml rename to src/Ryujinx/Assets/Styles/Themes.xaml diff --git a/src/Ryujinx.Ava/Common/ApplicationHelper.cs b/src/Ryujinx/Common/ApplicationHelper.cs similarity index 97% rename from src/Ryujinx.Ava/Common/ApplicationHelper.cs rename to src/Ryujinx/Common/ApplicationHelper.cs index 91ca8f4d5..14773114c 100644 --- a/src/Ryujinx.Ava/Common/ApplicationHelper.cs +++ b/src/Ryujinx/Common/ApplicationHelper.cs @@ -18,8 +18,9 @@ using Ryujinx.Ava.UI.Helpers; using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.HLE.Loaders.Processes.Extensions; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using System; using System.Buffers; using System.IO; @@ -226,7 +227,11 @@ namespace Ryujinx.Ava.Common return; } - (Nca updatePatchNca, _) = ApplicationLibrary.GetGameUpdateData(_virtualFileSystem, mainNca.Header.TitleId.ToString("x16"), programIndex, out _); + IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks + ? IntegrityCheckLevel.ErrorOnInvalid + : IntegrityCheckLevel.None; + + (Nca updatePatchNca, _) = mainNca.GetUpdateData(_virtualFileSystem, checkLevel, programIndex, out _); if (updatePatchNca != null) { patchNca = updatePatchNca; diff --git a/src/Ryujinx.Ava/Common/ApplicationSort.cs b/src/Ryujinx/Common/ApplicationSort.cs similarity index 100% rename from src/Ryujinx.Ava/Common/ApplicationSort.cs rename to src/Ryujinx/Common/ApplicationSort.cs diff --git a/src/Ryujinx.Ava/Common/KeyboardHotkeyState.cs b/src/Ryujinx/Common/KeyboardHotkeyState.cs similarity index 94% rename from src/Ryujinx.Ava/Common/KeyboardHotkeyState.cs rename to src/Ryujinx/Common/KeyboardHotkeyState.cs index b24016404..6e4920988 100644 --- a/src/Ryujinx.Ava/Common/KeyboardHotkeyState.cs +++ b/src/Ryujinx/Common/KeyboardHotkeyState.cs @@ -5,7 +5,7 @@ namespace Ryujinx.Ava.Common None, ToggleVSync, Screenshot, - ShowUi, + ShowUI, Pause, ToggleMute, ResScaleUp, diff --git a/src/Ryujinx.Ava/Common/Locale/LocaleExtension.cs b/src/Ryujinx/Common/Locale/LocaleExtension.cs similarity index 86% rename from src/Ryujinx.Ava/Common/Locale/LocaleExtension.cs rename to src/Ryujinx/Common/Locale/LocaleExtension.cs index 40661bf3a..b5964aa85 100644 --- a/src/Ryujinx.Ava/Common/Locale/LocaleExtension.cs +++ b/src/Ryujinx/Common/Locale/LocaleExtension.cs @@ -21,7 +21,7 @@ namespace Ryujinx.Ava.Common.Locale var builder = new CompiledBindingPathBuilder(); - builder.SetRawSource(LocaleManager.Instance) + builder .Property(new ClrPropertyInfo("Item", obj => (LocaleManager.Instance[keyToUse]), null, @@ -32,7 +32,10 @@ namespace Ryujinx.Ava.Common.Locale var path = builder.Build(); - var binding = new CompiledBindingExtension(path); + var binding = new CompiledBindingExtension(path) + { + Source = LocaleManager.Instance + }; return binding.ProvideValue(serviceProvider); } diff --git a/src/Ryujinx.Ava/Common/Locale/LocaleManager.cs b/src/Ryujinx/Common/Locale/LocaleManager.cs similarity index 70% rename from src/Ryujinx.Ava/Common/Locale/LocaleManager.cs rename to src/Ryujinx/Common/Locale/LocaleManager.cs index 64f3a7e86..96f648761 100644 --- a/src/Ryujinx.Ava/Common/Locale/LocaleManager.cs +++ b/src/Ryujinx/Common/Locale/LocaleManager.cs @@ -1,7 +1,7 @@ using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -16,8 +16,10 @@ namespace Ryujinx.Ava.Common.Locale private readonly Dictionary _localeStrings; private Dictionary _localeDefaultStrings; private readonly ConcurrentDictionary _dynamicValues; + private string _localeLanguageCode; public static LocaleManager Instance { get; } = new(); + public event Action LocaleChanged; public LocaleManager() { @@ -28,28 +30,22 @@ namespace Ryujinx.Ava.Common.Locale Load(); } - public void Load() + private void Load() { - // Load the system Language Code. - string localeLanguageCode = CultureInfo.CurrentCulture.Name.Replace('-', '_'); + var localeLanguageCode = !string.IsNullOrEmpty(ConfigurationState.Instance.UI.LanguageCode.Value) ? + ConfigurationState.Instance.UI.LanguageCode.Value : CultureInfo.CurrentCulture.Name.Replace('-', '_'); - // If the view is loaded with the UI Previewer detached, then override it with the saved one or default. + // Load en_US as default, if the target language translation is missing or incomplete. + LoadDefaultLanguage(); + LoadLanguage(localeLanguageCode); + + // Save whatever we ended up with. if (Program.PreviewerDetached) { - if (!string.IsNullOrEmpty(ConfigurationState.Instance.Ui.LanguageCode.Value)) - { - localeLanguageCode = ConfigurationState.Instance.Ui.LanguageCode.Value; - } - else - { - localeLanguageCode = DefaultLanguageCode; - } + ConfigurationState.Instance.UI.LanguageCode.Value = _localeLanguageCode; + + ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); } - - // Load en_US as default, if the target language translation is incomplete. - LoadDefaultLanguage(); - - LoadLanguage(localeLanguageCode); } public string this[LocaleKeys key] @@ -104,6 +100,15 @@ namespace Ryujinx.Ava.Common.Locale } } + public bool IsRTL() + { + return _localeLanguageCode switch + { + "ar_SA" or "he_IL" => true, + _ => false + }; + } + public string UpdateAndGetDynamicValue(LocaleKeys key, params object[] values) { _dynamicValues[key] = values; @@ -115,21 +120,44 @@ namespace Ryujinx.Ava.Common.Locale private void LoadDefaultLanguage() { - _localeDefaultStrings = LoadJsonLanguage(); + _localeDefaultStrings = LoadJsonLanguage(DefaultLanguageCode); } public void LoadLanguage(string languageCode) { - foreach (var item in LoadJsonLanguage(languageCode)) + var locale = LoadJsonLanguage(languageCode); + + if (locale == null) { - this[item.Key] = item.Value; + _localeLanguageCode = DefaultLanguageCode; + locale = _localeDefaultStrings; } + else + { + _localeLanguageCode = languageCode; + } + + foreach (var item in locale) + { + _localeStrings[item.Key] = item.Value; + } + + OnPropertyChanged("Item"); + + LocaleChanged?.Invoke(); } - private static Dictionary LoadJsonLanguage(string languageCode = DefaultLanguageCode) + private static Dictionary LoadJsonLanguage(string languageCode) { var localeStrings = new Dictionary(); - string languageJson = EmbeddedResources.ReadAllText($"Ryujinx.Ava/Assets/Locales/{languageCode}.json"); + string languageJson = EmbeddedResources.ReadAllText($"Ryujinx/Assets/Locales/{languageCode}.json"); + + if (languageJson == null) + { + // We were unable to find file for that language code. + return null; + } + var strings = JsonHelper.Deserialize(languageJson, CommonJsonContext.Default.StringDictionary); foreach (var item in strings) diff --git a/src/Ryujinx/Common/ThemeManager.cs b/src/Ryujinx/Common/ThemeManager.cs new file mode 100644 index 000000000..8c52c2a66 --- /dev/null +++ b/src/Ryujinx/Common/ThemeManager.cs @@ -0,0 +1,14 @@ +using System; + +namespace Ryujinx.Ava.Common +{ + public static class ThemeManager + { + public static event EventHandler ThemeChanged; + + public static void OnThemeChanged() + { + ThemeChanged?.Invoke(null, EventArgs.Empty); + } + } +} diff --git a/src/Ryujinx.Ava/Input/AvaloniaKeyboard.cs b/src/Ryujinx/Input/AvaloniaKeyboard.cs similarity index 99% rename from src/Ryujinx.Ava/Input/AvaloniaKeyboard.cs rename to src/Ryujinx/Input/AvaloniaKeyboard.cs index fbaaaabab..ff88de79e 100644 --- a/src/Ryujinx.Ava/Input/AvaloniaKeyboard.cs +++ b/src/Ryujinx/Input/AvaloniaKeyboard.cs @@ -195,7 +195,7 @@ namespace Ryujinx.Ava.Input public void Clear() { - _driver?.ResetKeys(); + _driver?.Clear(); } public void Dispose() { } diff --git a/src/Ryujinx.Ava/Input/AvaloniaKeyboardDriver.cs b/src/Ryujinx/Input/AvaloniaKeyboardDriver.cs similarity index 98% rename from src/Ryujinx.Ava/Input/AvaloniaKeyboardDriver.cs rename to src/Ryujinx/Input/AvaloniaKeyboardDriver.cs index e9e71b99b..9f87e821a 100644 --- a/src/Ryujinx.Ava/Input/AvaloniaKeyboardDriver.cs +++ b/src/Ryujinx/Input/AvaloniaKeyboardDriver.cs @@ -94,7 +94,7 @@ namespace Ryujinx.Ava.Input return _pressedKeys.Contains(nativeKey); } - public void ResetKeys() + public void Clear() { _pressedKeys.Clear(); } diff --git a/src/Ryujinx.Ava/Input/AvaloniaKeyboardMappingHelper.cs b/src/Ryujinx/Input/AvaloniaKeyboardMappingHelper.cs similarity index 100% rename from src/Ryujinx.Ava/Input/AvaloniaKeyboardMappingHelper.cs rename to src/Ryujinx/Input/AvaloniaKeyboardMappingHelper.cs diff --git a/src/Ryujinx.Ava/Input/AvaloniaMouse.cs b/src/Ryujinx/Input/AvaloniaMouse.cs similarity index 100% rename from src/Ryujinx.Ava/Input/AvaloniaMouse.cs rename to src/Ryujinx/Input/AvaloniaMouse.cs diff --git a/src/Ryujinx.Ava/Input/AvaloniaMouseDriver.cs b/src/Ryujinx/Input/AvaloniaMouseDriver.cs similarity index 100% rename from src/Ryujinx.Ava/Input/AvaloniaMouseDriver.cs rename to src/Ryujinx/Input/AvaloniaMouseDriver.cs diff --git a/src/Ryujinx/Modules/Updater/Updater.cs b/src/Ryujinx/Modules/Updater/Updater.cs index f8ce4c0b9..9f186f2b3 100644 --- a/src/Ryujinx/Modules/Updater/Updater.cs +++ b/src/Ryujinx/Modules/Updater/Updater.cs @@ -1,92 +1,75 @@ -using Gtk; +using Avalonia.Controls; +using Avalonia.Threading; +using FluentAvalonia.UI.Controls; using ICSharpCode.SharpZipLib.GZip; using ICSharpCode.SharpZipLib.Tar; using ICSharpCode.SharpZipLib.Zip; +using Ryujinx.Ava; +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.UI.Helpers; using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; -using Ryujinx.Ui; -using Ryujinx.Ui.Common.Models.Github; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Common.Models.Github; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.NetworkInformation; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Ryujinx.Modules { - public static class Updater + internal static class Updater { private const string GitHubApiUrl = "https://api.github.com"; - private const int ConnectionCount = 4; - - internal static bool Running; + private static readonly GithubReleasesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly string _homeDir = AppDomain.CurrentDomain.BaseDirectory; private static readonly string _updateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update"); private static readonly string _updatePublishDir = Path.Combine(_updateDir, "publish"); + private const int ConnectionCount = 4; private static string _buildVer; private static string _platformExt; private static string _buildUrl; private static long _buildSize; + private static bool _updateSuccessful; + private static bool _running; - private static readonly GithubReleasesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + private static readonly string[] _windowsDependencyDirs = Array.Empty(); - // On Windows, GtkSharp.Dependencies adds these extra dirs that must be cleaned during updates. - private static readonly string[] _windowsDependencyDirs = { "bin", "etc", "lib", "share" }; - - private static HttpClient ConstructHttpClient() + public static async Task BeginParse(Window mainWindow, bool showVersionUpToDate) { - HttpClient result = new(); - - // Required by GitHub to interact with APIs. - result.DefaultRequestHeaders.Add("User-Agent", "Ryujinx-Updater/1.0.0"); - - return result; - } - - public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate) - { - if (Running) + if (_running) { return; } - Running = true; - mainWindow.UpdateMenuItem.Sensitive = false; - - int artifactIndex = -1; + _running = true; // Detect current platform if (OperatingSystem.IsMacOS()) { - _platformExt = "osx_x64.zip"; - artifactIndex = 1; + _platformExt = "macos_universal.app.tar.gz"; } else if (OperatingSystem.IsWindows()) { _platformExt = "win_x64.zip"; - artifactIndex = 2; } else if (OperatingSystem.IsLinux()) { - _platformExt = "linux_x64.tar.gz"; - artifactIndex = 0; - } - - if (artifactIndex == -1) - { - GtkDialog.CreateErrorDialog("Your platform is not supported!"); - - return; + var arch = RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "arm64" : "x64"; + _platformExt = $"linux_{arch}.tar.gz"; } Version newVersion; @@ -98,9 +81,14 @@ namespace Ryujinx.Modules } catch { - GtkDialog.CreateWarningDialog("Failed to convert the current Ryujinx version.", "Cancelling Update!"); Logger.Error?.Print(LogClass.Application, "Failed to convert the current Ryujinx version!"); + await ContentDialogHelper.CreateWarningDialog( + LocaleManager.Instance[LocaleKeys.DialogUpdaterConvertFailedMessage], + LocaleManager.Instance[LocaleKeys.DialogUpdaterCancelUpdateMessage]); + + _running = false; + return; } @@ -108,9 +96,8 @@ namespace Ryujinx.Modules try { using HttpClient jsonClient = ConstructHttpClient(); - string buildInfoUrl = $"{GitHubApiUrl}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest"; - // Fetch latest build information + string buildInfoUrl = $"{GitHubApiUrl}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest"; string fetchedJson = await jsonClient.GetStringAsync(buildInfoUrl); var fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse); _buildVer = fetched.Name; @@ -125,9 +112,13 @@ namespace Ryujinx.Modules { if (showVersionUpToDate) { - GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", ""); + await ContentDialogHelper.CreateUpdaterInfoDialog( + LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], + ""); } + _running = false; + return; } @@ -135,20 +126,29 @@ namespace Ryujinx.Modules } } - if (_buildUrl == null) + // If build not done, assume no new update are available. + if (_buildUrl is null) { if (showVersionUpToDate) { - GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", ""); + await ContentDialogHelper.CreateUpdaterInfoDialog( + LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], + ""); } + _running = false; + return; } } catch (Exception exception) { Logger.Error?.Print(LogClass.Application, exception.Message); - GtkDialog.CreateErrorDialog("An error occurred when trying to get release information from GitHub Release. This can be caused if a new release is being compiled by GitHub Actions. Try again in a few minutes."); + + await ContentDialogHelper.CreateErrorDialog( + LocaleManager.Instance[LocaleKeys.DialogUpdaterFailedToGetVersionMessage]); + + _running = false; return; } @@ -159,8 +159,13 @@ namespace Ryujinx.Modules } catch { - GtkDialog.CreateWarningDialog("Failed to convert the received Ryujinx version from GitHub Release.", "Cancelling Update!"); - Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from GitHub Release!"); + Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from Github!"); + + await ContentDialogHelper.CreateWarningDialog( + LocaleManager.Instance[LocaleKeys.DialogUpdaterConvertFailedGithubMessage], + LocaleManager.Instance[LocaleKeys.DialogUpdaterCancelUpdateMessage]); + + _running = false; return; } @@ -169,11 +174,12 @@ namespace Ryujinx.Modules { if (showVersionUpToDate) { - GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", ""); + await ContentDialogHelper.CreateUpdaterInfoDialog( + LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], + ""); } - Running = false; - mainWindow.UpdateMenuItem.Sensitive = true; + _running = false; return; } @@ -196,13 +202,39 @@ namespace Ryujinx.Modules _buildSize = -1; } - // Show a message asking the user if they want to update - UpdateDialog updateDialog = new(mainWindow, newVersion, _buildUrl); - updateDialog.Show(); + await Dispatcher.UIThread.InvokeAsync(async () => + { + // Show a message asking the user if they want to update + var shouldUpdate = await ContentDialogHelper.CreateChoiceDialog( + LocaleManager.Instance[LocaleKeys.RyujinxUpdater], + LocaleManager.Instance[LocaleKeys.RyujinxUpdaterMessage], + $"{Program.Version} -> {newVersion}"); + + if (shouldUpdate) + { + await UpdateRyujinx(mainWindow, _buildUrl); + } + else + { + _running = false; + } + }); } - public static void UpdateRyujinx(UpdateDialog updateDialog, string downloadUrl) + private static HttpClient ConstructHttpClient() { + HttpClient result = new(); + + // Required by GitHub to interact with APIs. + result.DefaultRequestHeaders.Add("User-Agent", "Ryujinx-Updater/1.0.0"); + + return result; + } + + private static async Task UpdateRyujinx(Window parent, string downloadUrl) + { + _updateSuccessful = false; + // Empty update dir, although it shouldn't ever have anything inside it if (Directory.Exists(_updateDir)) { @@ -213,22 +245,100 @@ namespace Ryujinx.Modules string updateFile = Path.Combine(_updateDir, "update.bin"); - // Download the update .zip - updateDialog.MainText.Text = "Downloading Update..."; - updateDialog.ProgressBar.Value = 0; - updateDialog.ProgressBar.MaxValue = 100; + TaskDialog taskDialog = new() + { + Header = LocaleManager.Instance[LocaleKeys.RyujinxUpdater], + SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterDownloading], + IconSource = new SymbolIconSource { Symbol = Symbol.Download }, + ShowProgressBar = true, + XamlRoot = parent, + }; - if (_buildSize >= 0) + taskDialog.Opened += (s, e) => { - DoUpdateWithMultipleThreads(updateDialog, downloadUrl, updateFile); - } - else + if (_buildSize >= 0) + { + DoUpdateWithMultipleThreads(taskDialog, downloadUrl, updateFile); + } + else + { + DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile); + } + }; + + await taskDialog.ShowAsync(true); + + if (_updateSuccessful) { - DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile); + bool shouldRestart = true; + + if (!OperatingSystem.IsMacOS()) + { + shouldRestart = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance[LocaleKeys.RyujinxUpdater], + LocaleManager.Instance[LocaleKeys.DialogUpdaterCompleteMessage], + LocaleManager.Instance[LocaleKeys.DialogUpdaterRestartMessage]); + } + + if (shouldRestart) + { + List arguments = CommandLineState.Arguments.ToList(); + string executableDirectory = AppDomain.CurrentDomain.BaseDirectory; + + // On macOS we perform the update at relaunch. + if (OperatingSystem.IsMacOS()) + { + string baseBundlePath = Path.GetFullPath(Path.Combine(executableDirectory, "..", "..")); + string newBundlePath = Path.Combine(_updateDir, "Ryujinx.app"); + string updaterScriptPath = Path.Combine(newBundlePath, "Contents", "Resources", "updater.sh"); + string currentPid = Environment.ProcessId.ToString(); + + arguments.InsertRange(0, new List { updaterScriptPath, baseBundlePath, newBundlePath, currentPid }); + Process.Start("/bin/bash", arguments); + } + else + { + // Find the process name. + string ryuName = Path.GetFileName(Environment.ProcessPath) ?? string.Empty; + + // Migration: Start the updated binary. + // TODO: Remove this in a future update. + if (ryuName.StartsWith("Ryujinx.Ava")) + { + ryuName = ryuName.Replace(".Ava", ""); + } + + // Some operating systems can see the renamed executable, so strip off the .ryuold if found. + if (ryuName.EndsWith(".ryuold")) + { + ryuName = ryuName[..^7]; + } + + // Fallback if the executable could not be found. + if (ryuName.Length == 0 || !Path.Exists(Path.Combine(executableDirectory, ryuName))) + { + ryuName = OperatingSystem.IsWindows() ? "Ryujinx.exe" : "Ryujinx"; + } + + ProcessStartInfo processStart = new(ryuName) + { + UseShellExecute = true, + WorkingDirectory = executableDirectory, + }; + + foreach (string argument in CommandLineState.Arguments) + { + processStart.ArgumentList.Add(argument); + } + + Process.Start(processStart); + } + + Environment.Exit(0); + } } } - private static void DoUpdateWithMultipleThreads(UpdateDialog updateDialog, string downloadUrl, string updateFile) + private static void DoUpdateWithMultipleThreads(TaskDialog taskDialog, string downloadUrl, string updateFile) { // Multi-Threaded Updater long chunkSize = _buildSize / ConnectionCount; @@ -252,6 +362,7 @@ namespace Ryujinx.Modules // TODO: WebClient is obsolete and need to be replaced with a more complex logic using HttpClient. using WebClient client = new(); #pragma warning restore SYSLIB0014 + webClients.Add(client); if (i == ConnectionCount - 1) @@ -271,7 +382,7 @@ namespace Ryujinx.Modules Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage); Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage); - updateDialog.ProgressBar.Value = totalProgressPercentage / ConnectionCount; + taskDialog.SetProgressBarState(totalProgressPercentage / ConnectionCount, TaskDialogProgressState.Normal); }; client.DownloadDataCompleted += (_, args) => @@ -282,6 +393,8 @@ namespace Ryujinx.Modules { webClients[index].Dispose(); + taskDialog.Hide(); + return; } @@ -299,18 +412,24 @@ namespace Ryujinx.Modules File.WriteAllBytes(updateFile, mergedFileBytes); + // On macOS, ensure that we remove the quarantine bit to prevent Gatekeeper from blocking execution. + if (OperatingSystem.IsMacOS()) + { + using Process xattrProcess = Process.Start("xattr", new List { "-d", "com.apple.quarantine", updateFile }); + + xattrProcess.WaitForExit(); + } + try { - InstallUpdate(updateDialog, updateFile); + InstallUpdate(taskDialog, updateFile); } catch (Exception e) { Logger.Warning?.Print(LogClass.Application, e.Message); Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater."); - DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile); - - return; + DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile); } } }; @@ -329,14 +448,14 @@ namespace Ryujinx.Modules webClient.CancelAsync(); } - DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile); + DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile); return; } } } - private static void DoUpdateWithSingleThreadWorker(UpdateDialog updateDialog, string downloadUrl, string updateFile) + private static void DoUpdateWithSingleThreadWorker(TaskDialog taskDialog, string downloadUrl, string updateFile) { using HttpClient client = new(); // We do not want to timeout while downloading @@ -362,101 +481,118 @@ namespace Ryujinx.Modules byteWritten += readSize; - updateDialog.ProgressBar.Value = ((double)byteWritten / totalBytes) * 100; + taskDialog.SetProgressBarState(GetPercentage(byteWritten, totalBytes), TaskDialogProgressState.Normal); + updateFileStream.Write(buffer, 0, readSize); } - InstallUpdate(updateDialog, updateFile); + InstallUpdate(taskDialog, updateFile); } - private static void DoUpdateWithSingleThread(UpdateDialog updateDialog, string downloadUrl, string updateFile) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double GetPercentage(double value, double max) { - Thread worker = new(() => DoUpdateWithSingleThreadWorker(updateDialog, downloadUrl, updateFile)) + return max == 0 ? 0 : value / max * 100; + } + + private static void DoUpdateWithSingleThread(TaskDialog taskDialog, string downloadUrl, string updateFile) + { + Thread worker = new(() => DoUpdateWithSingleThreadWorker(taskDialog, downloadUrl, updateFile)) { Name = "Updater.SingleThreadWorker", }; + worker.Start(); } - private static async void InstallUpdate(UpdateDialog updateDialog, string updateFile) + [SupportedOSPlatform("linux")] + [SupportedOSPlatform("macos")] + private static void ExtractTarGzipFile(TaskDialog taskDialog, string archivePath, string outputDirectoryPath) + { + using Stream inStream = File.OpenRead(archivePath); + using GZipInputStream gzipStream = new(inStream); + using TarInputStream tarStream = new(gzipStream, Encoding.ASCII); + + TarEntry tarEntry; + + while ((tarEntry = tarStream.GetNextEntry()) is not null) + { + if (tarEntry.IsDirectory) + { + continue; + } + + string outPath = Path.Combine(outputDirectoryPath, tarEntry.Name); + + Directory.CreateDirectory(Path.GetDirectoryName(outPath)); + + using FileStream outStream = File.OpenWrite(outPath); + tarStream.CopyEntryContents(outStream); + + File.SetUnixFileMode(outPath, (UnixFileMode)tarEntry.TarHeader.Mode); + File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc)); + + Dispatcher.UIThread.Post(() => + { + if (tarEntry is null) + { + return; + } + + taskDialog.SetProgressBarState(GetPercentage(tarEntry.Size, inStream.Length), TaskDialogProgressState.Normal); + }); + } + } + + private static void ExtractZipFile(TaskDialog taskDialog, string archivePath, string outputDirectoryPath) + { + using Stream inStream = File.OpenRead(archivePath); + using ZipFile zipFile = new(inStream); + + double count = 0; + foreach (ZipEntry zipEntry in zipFile) + { + count++; + if (zipEntry.IsDirectory) + { + continue; + } + + string outPath = Path.Combine(outputDirectoryPath, zipEntry.Name); + + Directory.CreateDirectory(Path.GetDirectoryName(outPath)); + + using Stream zipStream = zipFile.GetInputStream(zipEntry); + using FileStream outStream = File.OpenWrite(outPath); + + zipStream.CopyTo(outStream); + + File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc)); + + Dispatcher.UIThread.Post(() => + { + taskDialog.SetProgressBarState(GetPercentage(count, zipFile.Count), TaskDialogProgressState.Normal); + }); + } + } + + private static void InstallUpdate(TaskDialog taskDialog, string updateFile) { // Extract Update - updateDialog.MainText.Text = "Extracting Update..."; - updateDialog.ProgressBar.Value = 0; + taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterExtracting]; + taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal); - if (OperatingSystem.IsLinux()) + if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) { - using Stream inStream = File.OpenRead(updateFile); - using Stream gzipStream = new GZipInputStream(inStream); - using TarInputStream tarStream = new(gzipStream, Encoding.ASCII); - updateDialog.ProgressBar.MaxValue = inStream.Length; - - await Task.Run(() => - { - TarEntry tarEntry; - - if (!OperatingSystem.IsWindows()) - { - while ((tarEntry = tarStream.GetNextEntry()) != null) - { - if (tarEntry.IsDirectory) - { - continue; - } - - string outPath = Path.Combine(_updateDir, tarEntry.Name); - - Directory.CreateDirectory(Path.GetDirectoryName(outPath)); - - using FileStream outStream = File.OpenWrite(outPath); - tarStream.CopyEntryContents(outStream); - - File.SetUnixFileMode(outPath, (UnixFileMode)tarEntry.TarHeader.Mode); - File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc)); - - TarEntry entry = tarEntry; - - Application.Invoke(delegate - { - updateDialog.ProgressBar.Value += entry.Size; - }); - } - } - }); - - updateDialog.ProgressBar.Value = inStream.Length; + ExtractTarGzipFile(taskDialog, updateFile, _updateDir); + } + else if (OperatingSystem.IsWindows()) + { + ExtractZipFile(taskDialog, updateFile, _updateDir); } else { - using Stream inStream = File.OpenRead(updateFile); - using ZipFile zipFile = new(inStream); - updateDialog.ProgressBar.MaxValue = zipFile.Count; - - await Task.Run(() => - { - foreach (ZipEntry zipEntry in zipFile) - { - if (zipEntry.IsDirectory) - { - continue; - } - - string outPath = Path.Combine(_updateDir, zipEntry.Name); - - Directory.CreateDirectory(Path.GetDirectoryName(outPath)); - - using Stream zipStream = zipFile.GetInputStream(zipEntry); - using FileStream outStream = File.OpenWrite(outPath); - zipStream.CopyTo(outStream); - - File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc)); - - Application.Invoke(delegate - { - updateDialog.ProgressBar.Value++; - }); - } - }); + throw new NotSupportedException(); } // Delete downloaded zip @@ -464,79 +600,74 @@ namespace Ryujinx.Modules List allFiles = EnumerateFilesToDelete().ToList(); - updateDialog.MainText.Text = "Renaming Old Files..."; - updateDialog.ProgressBar.Value = 0; - updateDialog.ProgressBar.MaxValue = allFiles.Count; + taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterRenaming]; + taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal); - // Replace old files - await Task.Run(() => + // NOTE: On macOS, replacement is delayed to the restart phase. + if (!OperatingSystem.IsMacOS()) { + // Replace old files + double count = 0; foreach (string file in allFiles) { + count++; try { File.Move(file, file + ".ryuold"); - Application.Invoke(delegate + Dispatcher.UIThread.InvokeAsync(() => { - updateDialog.ProgressBar.Value++; + taskDialog.SetProgressBarState(GetPercentage(count, allFiles.Count), TaskDialogProgressState.Normal); }); } catch { - Logger.Warning?.Print(LogClass.Application, "Updater was unable to rename file: " + file); + Logger.Warning?.Print(LogClass.Application, LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.UpdaterRenameFailed, file)); } } - Application.Invoke(delegate + Dispatcher.UIThread.InvokeAsync(() => { - updateDialog.MainText.Text = "Adding New Files..."; - updateDialog.ProgressBar.Value = 0; - updateDialog.ProgressBar.MaxValue = Directory.GetFiles(_updatePublishDir, "*", SearchOption.AllDirectories).Length; + taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterAddingFiles]; + taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal); }); - MoveAllFilesOver(_updatePublishDir, _homeDir, updateDialog); - }); + MoveAllFilesOver(_updatePublishDir, _homeDir, taskDialog); - Directory.Delete(_updateDir, true); + Directory.Delete(_updateDir, true); + } - updateDialog.MainText.Text = "Update Complete!"; - updateDialog.SecondaryText.Text = "Do you want to restart Ryujinx now?"; - updateDialog.Modal = true; + _updateSuccessful = true; - updateDialog.ProgressBar.Hide(); - updateDialog.YesButton.Show(); - updateDialog.NoButton.Show(); + taskDialog.Hide(); } public static bool CanUpdate(bool showWarnings) { #if !DISABLE_UPDATER - if (RuntimeInformation.OSArchitecture != Architecture.X64) - { - if (showWarnings) - { - GtkDialog.CreateWarningDialog("You are not running a supported system architecture!", "(Only x64 systems are supported!)"); - } - - return false; - } - if (!NetworkInterface.GetIsNetworkAvailable()) { if (showWarnings) { - GtkDialog.CreateWarningDialog("You are not connected to the Internet!", "Please verify that you have a working Internet connection!"); + Dispatcher.UIThread.InvokeAsync(() => + ContentDialogHelper.CreateWarningDialog( + LocaleManager.Instance[LocaleKeys.DialogUpdaterNoInternetMessage], + LocaleManager.Instance[LocaleKeys.DialogUpdaterNoInternetSubMessage]) + ); } return false; } - if (Program.Version.Contains("dirty") || !ReleaseInformation.IsValid()) + if (Program.Version.Contains("dirty") || !ReleaseInformation.IsValid) { if (showWarnings) { - GtkDialog.CreateWarningDialog("You cannot update a Dirty build of Ryujinx!", "Please download Ryujinx at https://ryujinx.org/ if you are looking for a supported version."); + Dispatcher.UIThread.InvokeAsync(() => + ContentDialogHelper.CreateWarningDialog( + LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildMessage], + LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildSubMessage]) + ); } return false; @@ -546,13 +677,21 @@ namespace Ryujinx.Modules #else if (showWarnings) { - if (ReleaseInformation.IsFlatHubBuild()) + if (ReleaseInformation.IsFlatHubBuild) { - GtkDialog.CreateWarningDialog("Updater Disabled!", "Please update Ryujinx via FlatHub."); + Dispatcher.UIThread.InvokeAsync(() => + ContentDialogHelper.CreateWarningDialog( + LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], + LocaleManager.Instance[LocaleKeys.DialogUpdaterFlatpakNotSupportedMessage]) + ); } else { - GtkDialog.CreateWarningDialog("Updater Disabled!", "Please download Ryujinx at https://ryujinx.org/ if you are looking for a supported version."); + Dispatcher.UIThread.InvokeAsync(() => + ContentDialogHelper.CreateWarningDialog( + LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], + LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildSubMessage]) + ); } } @@ -566,7 +705,7 @@ namespace Ryujinx.Modules var files = Directory.EnumerateFiles(_homeDir); // All files directly in base dir. // Determine and exclude user files only when the updater is running, not when cleaning old files - if (Running) + if (_running && !OperatingSystem.IsMacOS()) { // Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list. var oldFiles = Directory.EnumerateFiles(_homeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName); @@ -592,8 +731,9 @@ namespace Ryujinx.Modules return files.Where(f => !new FileInfo(f).Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System)); } - private static void MoveAllFilesOver(string root, string dest, UpdateDialog dialog) + private static void MoveAllFilesOver(string root, string dest, TaskDialog taskDialog) { + int total = Directory.GetFiles(root, "*", SearchOption.AllDirectories).Length; foreach (string directory in Directory.GetDirectories(root)) { string dirName = Path.GetFileName(directory); @@ -603,27 +743,64 @@ namespace Ryujinx.Modules Directory.CreateDirectory(Path.Combine(dest, dirName)); } - MoveAllFilesOver(directory, Path.Combine(dest, dirName), dialog); + MoveAllFilesOver(directory, Path.Combine(dest, dirName), taskDialog); } + double count = 0; foreach (string file in Directory.GetFiles(root)) { + count++; + File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true); - Application.Invoke(delegate + Dispatcher.UIThread.InvokeAsync(() => { - dialog.ProgressBar.Value++; + taskDialog.SetProgressBarState(GetPercentage(count, total), TaskDialogProgressState.Normal); }); } } public static void CleanupUpdate() { - foreach (string file in EnumerateFilesToDelete()) + foreach (string file in Directory.GetFiles(_homeDir, "*.ryuold", SearchOption.AllDirectories)) { - if (Path.GetExtension(file).EndsWith(".ryuold")) + File.Delete(file); + } + + // Migration: Delete old Ryujinx binary. + // TODO: Remove this in a future update. + if (!OperatingSystem.IsMacOS()) + { + string[] oldRyuFiles = Directory.GetFiles(_homeDir, "Ryujinx.Ava*", SearchOption.TopDirectoryOnly); + // Assume we are running the new one if the process path is not available. + // This helps to prevent an infinite loop of restarts. + string currentRyuName = Path.GetFileName(Environment.ProcessPath) ?? (OperatingSystem.IsWindows() ? "Ryujinx.exe" : "Ryujinx"); + + string newRyuName = Path.Combine(_homeDir, currentRyuName.Replace(".Ava", "")); + if (!currentRyuName.Contains("Ryujinx.Ava")) { - File.Delete(file); + foreach (string oldRyuFile in oldRyuFiles) + { + File.Delete(oldRyuFile); + } + } + // Should we be running the old binary, start the new one if possible. + else if (File.Exists(newRyuName)) + { + ProcessStartInfo processStart = new(newRyuName) + { + UseShellExecute = true, + WorkingDirectory = _homeDir, + }; + + foreach (string argument in CommandLineState.Arguments) + { + processStart.ArgumentList.Add(argument); + } + + Process.Start(processStart); + + Environment.Exit(0); } } } diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs index 597d00f30..6c83cedcf 100644 --- a/src/Ryujinx/Program.cs +++ b/src/Ryujinx/Program.cs @@ -1,144 +1,99 @@ -using Gtk; +using Avalonia; +using Avalonia.Threading; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.Windows; using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.GraphicsDriver; using Ryujinx.Common.Logging; using Ryujinx.Common.SystemInterop; +using Ryujinx.Graphics.Vulkan.MoltenVK; using Ryujinx.Modules; using Ryujinx.SDL2.Common; -using Ryujinx.Ui; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Common.SystemInfo; -using Ryujinx.Ui.Widgets; -using SixLabors.ImageSharp.Formats.Jpeg; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Common.SystemInfo; using System; -using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Threading.Tasks; -namespace Ryujinx +namespace Ryujinx.Ava { - partial class Program + internal partial class Program { - public static double WindowScaleFactor { get; private set; } - + public static double WindowScaleFactor { get; set; } + public static double DesktopScaleFactor { get; set; } = 1.0; public static string Version { get; private set; } - - public static string ConfigurationPath { get; set; } - - public static string CommandLineProfile { get; set; } - - private const string X11LibraryName = "libX11"; - - [LibraryImport(X11LibraryName)] - private static partial int XInitThreads(); + public static string ConfigurationPath { get; private set; } + public static bool PreviewerDetached { get; private set; } + public static bool UseHardwareAcceleration { get; private set; } [LibraryImport("user32.dll", SetLastError = true)] public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type); - [LibraryImport("libc", SetLastError = true)] - private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite); + private const uint MbIconwarning = 0x30; - private const uint MbIconWarning = 0x30; - - static Program() + public static void Main(string[] args) { - if (OperatingSystem.IsLinux()) - { - NativeLibrary.SetDllImportResolver(typeof(Program).Assembly, (name, assembly, path) => - { - if (name != X11LibraryName) - { - return IntPtr.Zero; - } - - if (!NativeLibrary.TryLoad("libX11.so.6", assembly, path, out IntPtr result)) - { - if (!NativeLibrary.TryLoad("libX11.so", assembly, path, out result)) - { - return IntPtr.Zero; - } - } - - return result; - }); - } - } - - static void Main(string[] args) - { - Version = ReleaseInformation.GetVersion(); + Version = ReleaseInformation.Version; if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134)) { - MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MbIconWarning); + _ = MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nRyujinx supports Windows 10 version 1803 and newer.\n", $"Ryujinx {Version}", MbIconwarning); } + PreviewerDetached = true; + + Initialize(args); + + LoggerAdapter.Register(); + + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + } + + public static AppBuilder BuildAvaloniaApp() + { + return AppBuilder.Configure() + .UsePlatformDetect() + .With(new X11PlatformOptions + { + EnableMultiTouch = true, + EnableIme = true, + EnableInputFocusProxy = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP") == "gamescope", + RenderingMode = UseHardwareAcceleration ? + new[] { X11RenderingMode.Glx, X11RenderingMode.Software } : + new[] { X11RenderingMode.Software }, + }) + .With(new Win32PlatformOptions + { + WinUICompositionBackdropCornerRadius = 8.0f, + RenderingMode = UseHardwareAcceleration ? + new[] { Win32RenderingMode.AngleEgl, Win32RenderingMode.Software } : + new[] { Win32RenderingMode.Software }, + }) + .UseSkia(); + } + + private static void Initialize(string[] args) + { // Parse arguments CommandLineState.ParseArguments(args); - // Hook unhandled exception and process exit events. - GLib.ExceptionManager.UnhandledException += (GLib.UnhandledExceptionArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); - AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); - AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit(); - - // Make process DPI aware for proper window sizing on high-res screens. - ForceDpiAware.Windows(); - WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor(); + if (OperatingSystem.IsMacOS()) + { + MVKInitialization.InitializeResolver(); + } // Delete backup files after updating. Task.Run(Updater.CleanupUpdate); Console.Title = $"Ryujinx Console {Version}"; - // NOTE: GTK3 doesn't init X11 in a multi threaded way. - // This ends up causing race condition and abort of XCB when a context is created by SPB (even if SPB do call XInitThreads). - if (OperatingSystem.IsLinux()) - { - if (XInitThreads() == 0) - { - throw new NotSupportedException("Failed to initialize multi-threading support."); - } - - Environment.SetEnvironmentVariable("GDK_BACKEND", "x11"); - setenv("GDK_BACKEND", "x11", 1); - } - - if (OperatingSystem.IsMacOS()) - { - string baseDirectory = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); - string resourcesDataDir; - - if (Path.GetFileName(baseDirectory) == "MacOS") - { - resourcesDataDir = Path.Combine(Directory.GetParent(baseDirectory).FullName, "Resources"); - } - else - { - resourcesDataDir = baseDirectory; - } - - static void SetEnvironmentVariableNoCaching(string key, string value) - { - int res = setenv(key, value, 1); - Debug.Assert(res != -1); - } - - // On macOS, GTK3 needs XDG_DATA_DIRS to be set, otherwise it will try searching for "gschemas.compiled" in system directories. - SetEnvironmentVariableNoCaching("XDG_DATA_DIRS", Path.Combine(resourcesDataDir, "share")); - - // On macOS, GTK3 needs GDK_PIXBUF_MODULE_FILE to be set, otherwise it will try searching for "loaders.cache" in system directories. - SetEnvironmentVariableNoCaching("GDK_PIXBUF_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gdk-pixbuf-2.0", "2.10.0", "loaders.cache")); - - SetEnvironmentVariableNoCaching("GTK_IM_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gtk-3.0", "3.0.0", "immodules.cache")); - } - - string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); - Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}"); + // Hook unhandled exception and process exit events. + AppDomain.CurrentDomain.UnhandledException += (sender, e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); + AppDomain.CurrentDomain.ProcessExit += (sender, e) => Exit(); // Setup base data directory. AppDataManager.Initialize(CommandLineState.BaseDirPathArg); @@ -153,53 +108,76 @@ namespace Ryujinx DiscordIntegrationModule.Initialize(); // Initialize SDL2 driver - SDL2Driver.MainThreadDispatcher = action => + SDL2Driver.MainThreadDispatcher = action => Dispatcher.UIThread.InvokeAsync(action, DispatcherPriority.Input); + + ReloadConfig(); + + WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor(); + + // Logging system information. + PrintSystemInfo(); + + // Enable OGL multithreading on the driver, and some other flags. + DriverUtilities.InitDriverConfig(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off); + + // Check if keys exists. + if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys"))) { - Application.Invoke(delegate + if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys")))) { - action(); - }); - }; + MainWindow.ShowKeyErrorOnLoad = true; + } + } - // Sets ImageSharp Jpeg Encoder Quality. - SixLabors.ImageSharp.Configuration.Default.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder() + if (CommandLineState.LaunchPathArg != null) { - Quality = 100, - }); + MainWindow.DeferLoadApplication(CommandLineState.LaunchPathArg, CommandLineState.LaunchApplicationId, CommandLineState.StartFullscreenArg); + } + } - string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); - string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json"); + public static void ReloadConfig() + { + string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName); + string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName); // Now load the configuration as the other subsystems are now registered - ConfigurationPath = File.Exists(localConfigurationPath) - ? localConfigurationPath - : File.Exists(appDataConfigurationPath) - ? appDataConfigurationPath - : null; + if (File.Exists(localConfigurationPath)) + { + ConfigurationPath = localConfigurationPath; + } + else if (File.Exists(appDataConfigurationPath)) + { + ConfigurationPath = appDataConfigurationPath; + } if (ConfigurationPath == null) { // No configuration, we load the default values and save it to disk ConfigurationPath = appDataConfigurationPath; + Logger.Notice.Print(LogClass.Application, $"No configuration file found. Saving default configuration to: {ConfigurationPath}"); ConfigurationState.Instance.LoadDefault(); ConfigurationState.Instance.ToFileFormat().SaveConfig(ConfigurationPath); } else { + Logger.Notice.Print(LogClass.Application, $"Loading configuration from: {ConfigurationPath}"); + if (ConfigurationFileFormat.TryLoad(ConfigurationPath, out ConfigurationFileFormat configurationFileFormat)) { ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); } else { - ConfigurationState.Instance.LoadDefault(); + Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location: {ConfigurationPath}"); - Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}"); + ConfigurationState.Instance.LoadDefault(); } } - // Check if graphics backend was overridden. + UseHardwareAcceleration = ConfigurationState.Instance.EnableHardwareAcceleration.Value; + + // Check if graphics backend was overridden if (CommandLineState.OverrideGraphicsBackend != null) { if (CommandLineState.OverrideGraphicsBackend.ToLower() == "opengl") @@ -212,6 +190,12 @@ namespace Ryujinx } } + // Check if docked mode was overriden. + if (CommandLineState.OverrideDockedMode.HasValue) + { + ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value; + } + // Check if HideCursor was overridden. if (CommandLineState.OverrideHideCursor is not null) { @@ -224,113 +208,11 @@ namespace Ryujinx }; } - // Check if docked mode was overridden. - if (CommandLineState.OverrideDockedMode.HasValue) + // Check if hardware-acceleration was overridden. + if (CommandLineState.OverrideHardwareAcceleration != null) { - ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value; + UseHardwareAcceleration = CommandLineState.OverrideHardwareAcceleration.Value; } - - // Logging system information. - PrintSystemInfo(); - - // Enable OGL multithreading on the driver, when available. - BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading; - DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off); - - // Initialize Gtk. - Application.Init(); - - // Check if keys exists. - bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")); - bool hasCommonProdKeys = AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys")); - if (!hasSystemProdKeys && !hasCommonProdKeys) - { - UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys); - } - - // Show the main window UI. - MainWindow mainWindow = new(); - mainWindow.Show(); - - if (OperatingSystem.IsLinux()) - { - int currentVmMaxMapCount = LinuxHelper.VmMaxMapCount; - - if (LinuxHelper.VmMaxMapCount < LinuxHelper.RecommendedVmMaxMapCount) - { - Logger.Warning?.Print(LogClass.Application, $"The value of vm.max_map_count is lower than {LinuxHelper.RecommendedVmMaxMapCount}. ({currentVmMaxMapCount})"); - - if (LinuxHelper.PkExecPath is not null) - { - var buttonTexts = new Dictionary() - { - { 0, "Yes, until the next restart" }, - { 1, "Yes, permanently" }, - { 2, "No" }, - }; - - ResponseType response = GtkDialog.CreateCustomDialog( - "Ryujinx - Low limit for memory mappings detected", - $"Would you like to increase the value of vm.max_map_count to {LinuxHelper.RecommendedVmMaxMapCount}?", - "Some games might try to create more memory mappings than currently allowed. " + - "Ryujinx will crash as soon as this limit gets exceeded.", - buttonTexts, - MessageType.Question); - - int rc; - - switch ((int)response) - { - case 0: - rc = LinuxHelper.RunPkExec($"echo {LinuxHelper.RecommendedVmMaxMapCount} > {LinuxHelper.VmMaxMapCountPath}"); - if (rc == 0) - { - Logger.Info?.Print(LogClass.Application, $"vm.max_map_count set to {LinuxHelper.VmMaxMapCount} until the next restart."); - } - else - { - Logger.Error?.Print(LogClass.Application, $"Unable to change vm.max_map_count. Process exited with code: {rc}"); - } - break; - case 1: - rc = LinuxHelper.RunPkExec($"echo \"vm.max_map_count = {LinuxHelper.RecommendedVmMaxMapCount}\" > {LinuxHelper.SysCtlConfigPath} && sysctl -p {LinuxHelper.SysCtlConfigPath}"); - if (rc == 0) - { - Logger.Info?.Print(LogClass.Application, $"vm.max_map_count set to {LinuxHelper.VmMaxMapCount}. Written to config: {LinuxHelper.SysCtlConfigPath}"); - } - else - { - Logger.Error?.Print(LogClass.Application, $"Unable to write new value for vm.max_map_count to config. Process exited with code: {rc}"); - } - break; - } - } - else - { - GtkDialog.CreateWarningDialog( - "Max amount of memory mappings is lower than recommended.", - $"The current value of vm.max_map_count ({currentVmMaxMapCount}) is lower than {LinuxHelper.RecommendedVmMaxMapCount}." + - "Some games might try to create more memory mappings than currently allowed. " + - "Ryujinx will crash as soon as this limit gets exceeded.\n\n" + - "You might want to either manually increase the limit or install pkexec, which allows Ryujinx to assist with that."); - } - } - } - - if (CommandLineState.LaunchPathArg != null) - { - mainWindow.RunApplication(CommandLineState.LaunchPathArg, CommandLineState.StartFullscreenArg); - } - - if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false)) - { - Updater.BeginParse(mainWindow, false).ContinueWith(task => - { - Logger.Error?.Print(LogClass.Application, $"Updater Error: {task.Exception}"); - }, TaskContinuationOptions.OnlyOnFaulted); - } - - Application.Run(); } private static void PrintSystemInfo() @@ -338,8 +220,7 @@ namespace Ryujinx Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}"); SystemInfo.Gather().Print(); - var enabledLogs = Logger.GetEnabledLevels(); - Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogs.Count == 0 ? "" : string.Join(", ", enabledLogs))}"); + Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(Logger.GetEnabledLevels().Count == 0 ? "" : string.Join(", ", Logger.GetEnabledLevels()))}"); if (AppDataManager.Mode == AppDataManager.LaunchMode.Custom) { diff --git a/src/Ryujinx/Ryujinx.csproj b/src/Ryujinx/Ryujinx.csproj index 9890b761b..6718b7fcc 100644 --- a/src/Ryujinx/Ryujinx.csproj +++ b/src/Ryujinx/Ryujinx.csproj @@ -1,5 +1,4 @@ - net8.0 win-x64;osx-x64;linux-x64 @@ -7,11 +6,17 @@ true 1.0.0-dirty $(DefineConstants);$(ExtraDefineConstants) - - true + - + Ryujinx.ico true + true + app.manifest + + + + true false @@ -19,37 +24,57 @@ partial + + + true + + - - - - - - + + + + + + + + + + - + + + + + + - + + - - - + + - + Always alsoft.ini @@ -63,7 +88,7 @@ - + Always @@ -73,32 +98,70 @@ - - - false - Ryujinx.ico - - - - - - - - - - + + Designer + + + + MSBuild:Compile + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs b/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs similarity index 66% rename from src/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs rename to src/Ryujinx/UI/Applet/AvaHostUIHandler.cs index 42a2909dc..5be8930d7 100644 --- a/src/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs +++ b/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs @@ -8,35 +8,45 @@ using Ryujinx.Ava.UI.Windows; using Ryujinx.HLE; using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System; using System.Threading; namespace Ryujinx.Ava.UI.Applet { - internal class AvaHostUiHandler : IHostUiHandler + internal class AvaHostUIHandler : IHostUIHandler { private readonly MainWindow _parent; - public IHostUiTheme HostUiTheme { get; } + public IHostUITheme HostUITheme { get; } - public AvaHostUiHandler(MainWindow parent) + public AvaHostUIHandler(MainWindow parent) { _parent = parent; - HostUiTheme = new AvaloniaHostUiTheme(parent); + HostUITheme = new AvaloniaHostUITheme(parent); } - public bool DisplayMessageDialog(ControllerAppletUiArgs args) + public bool DisplayMessageDialog(ControllerAppletUIArgs args) { - string message = LocaleManager.Instance.UpdateAndGetDynamicValue( - args.PlayerCountMin == args.PlayerCountMax ? LocaleKeys.DialogControllerAppletMessage : LocaleKeys.DialogControllerAppletMessagePlayerRange, - args.PlayerCountMin == args.PlayerCountMax ? args.PlayerCountMin.ToString() : $"{args.PlayerCountMin}-{args.PlayerCountMax}", - args.SupportedStyles, - string.Join(", ", args.SupportedPlayers), - args.IsDocked ? LocaleManager.Instance[LocaleKeys.DialogControllerAppletDockModeSet] : ""); + ManualResetEvent dialogCloseEvent = new(false); - return DisplayMessageDialog(LocaleManager.Instance[LocaleKeys.DialogControllerAppletTitle], message); + bool okPressed = false; + + Dispatcher.UIThread.InvokeAsync(async () => + { + var response = await ControllerAppletDialog.ShowControllerAppletDialog(_parent, args); + if (response == UserResult.Ok) + { + okPressed = true; + } + + dialogCloseEvent.Set(); + }); + + dialogCloseEvent.WaitOne(); + + return okPressed; } public bool DisplayMessageDialog(string title, string message) @@ -75,6 +85,8 @@ namespace Ryujinx.Ava.UI.Applet await _parent.SettingsWindow.ShowDialog(window); + _parent.SettingsWindow = null; + opened = false; }); @@ -98,12 +110,46 @@ namespace Ryujinx.Ava.UI.Applet return okPressed; } - public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action onTextEntered) + public void DisplayInputDialog(SoftwareKeyboardUIArgs args, Action onTextEntered) { - onTextEntered?.Invoke("MeloNX"); - return; + ManualResetEvent dialogCloseEvent = new(false); + + bool okPressed = false; + bool error = false; + string inputText = args.InitialText ?? ""; + + Dispatcher.UIThread.InvokeAsync(async () => + { + try + { + _parent.ViewModel.AppHost.NpadManager.BlockInputUpdates(); + var response = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args); + + if (response.Result == UserResult.Ok) + { + inputText = response.Input; + okPressed = true; + } + } + catch (Exception ex) + { + error = true; + + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogSoftwareKeyboardErrorExceptionMessage, ex)); + } + finally + { + dialogCloseEvent.Set(); + } + }); + + dialogCloseEvent.WaitOne(); + _parent.ViewModel.AppHost.NpadManager.UnblockInputUpdates(); + + onTextEntered(error ? null : inputText); } + public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value) { device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value); diff --git a/src/Ryujinx.Ava/UI/Applet/AvaloniaDynamicTextInputHandler.cs b/src/Ryujinx/UI/Applet/AvaloniaDynamicTextInputHandler.cs similarity index 95% rename from src/Ryujinx.Ava/UI/Applet/AvaloniaDynamicTextInputHandler.cs rename to src/Ryujinx/UI/Applet/AvaloniaDynamicTextInputHandler.cs index 2411659f7..0e7cfb8e6 100644 --- a/src/Ryujinx.Ava/UI/Applet/AvaloniaDynamicTextInputHandler.cs +++ b/src/Ryujinx/UI/Applet/AvaloniaDynamicTextInputHandler.cs @@ -5,7 +5,7 @@ using Avalonia.Threading; using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Windows; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System; using System.Threading; using HidKey = Ryujinx.Common.Configuration.Hid.Key; @@ -41,17 +41,12 @@ namespace Ryujinx.Ava.UI.Applet private void TextChanged(string text) { - TextChangedEvent?.Invoke(text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, true); + TextChangedEvent?.Invoke(text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, false); } private void SelectionChanged(int selection) { - if (_hiddenTextBox.SelectionEnd < _hiddenTextBox.SelectionStart) - { - _hiddenTextBox.SelectionStart = _hiddenTextBox.SelectionEnd; - } - - TextChangedEvent?.Invoke(_hiddenTextBox.Text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, true); + TextChangedEvent?.Invoke(_hiddenTextBox.Text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, false); } private void AvaloniaDynamicTextInputHandler_TextInput(object sender, string text) diff --git a/src/Ryujinx.Ava/UI/Applet/AvaloniaHostUiTheme.cs b/src/Ryujinx/UI/Applet/AvaloniaHostUITheme.cs similarity index 92% rename from src/Ryujinx.Ava/UI/Applet/AvaloniaHostUiTheme.cs rename to src/Ryujinx/UI/Applet/AvaloniaHostUITheme.cs index 4ee177d72..016fb4842 100644 --- a/src/Ryujinx.Ava/UI/Applet/AvaloniaHostUiTheme.cs +++ b/src/Ryujinx/UI/Applet/AvaloniaHostUITheme.cs @@ -1,13 +1,13 @@ using Avalonia.Media; using Ryujinx.Ava.UI.Windows; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System; namespace Ryujinx.Ava.UI.Applet { - class AvaloniaHostUiTheme : IHostUiTheme + class AvaloniaHostUITheme : IHostUITheme { - public AvaloniaHostUiTheme(MainWindow parent) + public AvaloniaHostUITheme(MainWindow parent) { FontFamily = OperatingSystem.IsWindows() && OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000) ? "Segoe UI Variable" : parent.FontFamily.Name; DefaultBackgroundColor = BrushToThemeColor(parent.Background); diff --git a/src/Ryujinx/UI/Applet/ControllerAppletDialog.axaml b/src/Ryujinx/UI/Applet/ControllerAppletDialog.axaml new file mode 100644 index 000000000..b2c22f6bb --- /dev/null +++ b/src/Ryujinx/UI/Applet/ControllerAppletDialog.axaml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx/UI/Applet/ControllerAppletDialog.axaml.cs b/src/Ryujinx/UI/Applet/ControllerAppletDialog.axaml.cs new file mode 100644 index 000000000..6b999b1f4 --- /dev/null +++ b/src/Ryujinx/UI/Applet/ControllerAppletDialog.axaml.cs @@ -0,0 +1,137 @@ +using Avalonia.Controls; +using Avalonia.Styling; +using Avalonia.Svg.Skia; +using Avalonia.Threading; +using FluentAvalonia.UI.Controls; +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.Windows; +using Ryujinx.Common; +using Ryujinx.HLE.HOS.Applets; +using Ryujinx.HLE.HOS.Services.Hid; +using System.Linq; +using System.Threading.Tasks; + +namespace Ryujinx.Ava.UI.Applet +{ + internal partial class ControllerAppletDialog : UserControl + { + private const string ProControllerResource = "Ryujinx/Assets/Icons/Controller_ProCon.svg"; + private const string JoyConPairResource = "Ryujinx/Assets/Icons/Controller_JoyConPair.svg"; + private const string JoyConLeftResource = "Ryujinx/Assets/Icons/Controller_JoyConLeft.svg"; + private const string JoyConRightResource = "Ryujinx/Assets/Icons/Controller_JoyConRight.svg"; + + public static SvgImage ProControllerImage => GetResource(ProControllerResource); + public static SvgImage JoyconPairImage => GetResource(JoyConPairResource); + public static SvgImage JoyconLeftImage => GetResource(JoyConLeftResource); + public static SvgImage JoyconRightImage => GetResource(JoyConRightResource); + + public string PlayerCount { get; set; } = ""; + public bool SupportsProController { get; set; } + public bool SupportsLeftJoycon { get; set; } + public bool SupportsRightJoycon { get; set; } + public bool SupportsJoyconPair { get; set; } + public bool IsDocked { get; set; } + + private readonly MainWindow _mainWindow; + + public ControllerAppletDialog(MainWindow mainWindow, ControllerAppletUIArgs args) + { + if (args.PlayerCountMin == args.PlayerCountMax) + { + PlayerCount = args.PlayerCountMin.ToString(); + } + else + { + PlayerCount = $"{args.PlayerCountMin} - {args.PlayerCountMax}"; + } + + SupportsProController = (args.SupportedStyles & ControllerType.ProController) != 0; + SupportsLeftJoycon = (args.SupportedStyles & ControllerType.JoyconLeft) != 0; + SupportsRightJoycon = (args.SupportedStyles & ControllerType.JoyconRight) != 0; + SupportsJoyconPair = (args.SupportedStyles & ControllerType.JoyconPair) != 0; + + IsDocked = args.IsDocked; + + _mainWindow = mainWindow; + + DataContext = this; + + InitializeComponent(); + } + + public ControllerAppletDialog(MainWindow mainWindow) + { + _mainWindow = mainWindow; + DataContext = this; + + InitializeComponent(); + } + + public static async Task ShowControllerAppletDialog(MainWindow window, ControllerAppletUIArgs args) + { + ContentDialog contentDialog = new(); + UserResult result = UserResult.Cancel; + ControllerAppletDialog content = new(window, args); + + contentDialog.Title = LocaleManager.Instance[LocaleKeys.DialogControllerAppletTitle]; + contentDialog.Content = content; + + void Handler(ContentDialog sender, ContentDialogClosedEventArgs eventArgs) + { + if (eventArgs.Result == ContentDialogResult.Primary) + { + result = UserResult.Ok; + } + } + + contentDialog.Closed += Handler; + + Style bottomBorder = new(x => x.OfType().Name("DialogSpace").Child().OfType()); + bottomBorder.Setters.Add(new Setter(IsVisibleProperty, false)); + + contentDialog.Styles.Add(bottomBorder); + + await ContentDialogHelper.ShowAsync(contentDialog); + + return result; + } + + private static SvgImage GetResource(string path) + { + SvgImage image = new(); + + if (!string.IsNullOrWhiteSpace(path)) + { + SvgSource source = SvgSource.LoadFromStream(EmbeddedResources.GetStream(path)); + + image.Source = source; + } + + return image; + } + + public void OpenSettingsWindow() + { + if (_mainWindow.SettingsWindow == null) + { + Dispatcher.UIThread.InvokeAsync(async () => + { + _mainWindow.SettingsWindow = new SettingsWindow(_mainWindow.VirtualFileSystem, _mainWindow.ContentManager); + _mainWindow.SettingsWindow.NavPanel.Content = _mainWindow.SettingsWindow.InputPage; + _mainWindow.SettingsWindow.NavPanel.SelectedItem = _mainWindow.SettingsWindow.NavPanel.MenuItems.ElementAt(1); + + await ContentDialogHelper.ShowWindowAsync(_mainWindow.SettingsWindow, _mainWindow); + _mainWindow.SettingsWindow = null; + this.Close(); + }); + } + } + + public void Close() + { + ((ContentDialog)Parent)?.Hide(); + } + } +} + diff --git a/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml b/src/Ryujinx/UI/Applet/ErrorAppletWindow.axaml similarity index 94% rename from src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml rename to src/Ryujinx/UI/Applet/ErrorAppletWindow.axaml index 6186b7d93..51f370519 100644 --- a/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml +++ b/src/Ryujinx/UI/Applet/ErrorAppletWindow.axaml @@ -34,7 +34,7 @@ Height="80" MinWidth="50" Margin="5,10,20,10" - Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" /> + Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common" /> + Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common" /> ShowInputDialog(string title, SoftwareKeyboardUiArgs args) + public static async Task<(UserResult Result, string Input)> ShowInputDialog(string title, SoftwareKeyboardUIArgs args) { ContentDialog contentDialog = new(); diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml similarity index 92% rename from src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml rename to src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml index b8fe7e76f..dd0926fc9 100644 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml +++ b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml @@ -16,7 +16,7 @@ Click="CreateApplicationShortcut_Click" Header="{locale:Locale GameListContextMenuCreateShortcut}" IsEnabled="{Binding CreateShortcutEnabled}" - ToolTip.Tip="{locale:Locale GameListContextMenuCreateShortcutToolTip}" /> + ToolTip.Tip="{OnPlatform Default={locale:Locale GameListContextMenuCreateShortcutToolTip}, macOS={locale:Locale GameListContextMenuCreateShortcutToolTipMacOS}}" /> + + + ApplicationLibrary.LoadAndSaveMetaData(viewModel.SelectedApplication.IdString, appMetadata => { appMetadata.Favorite = viewModel.SelectedApplication.Favorite; }); @@ -76,19 +74,9 @@ namespace Ryujinx.Ava.UI.Controls { if (viewModel?.SelectedApplication != null) { - if (!ulong.TryParse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber)) - { - Dispatcher.UIThread.InvokeAsync(async () => - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]); - }); + var saveDataFilter = SaveDataFilter.Make(viewModel.SelectedApplication.Id, saveDataType, userId, saveDataId: default, index: default); - return; - } - - var saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveDataType, userId, saveDataId: default, index: default); - - ApplicationHelper.OpenSaveDir(in saveDataFilter, titleIdNumber, viewModel.SelectedApplication.ControlHolder, viewModel.SelectedApplication.TitleName); + ApplicationHelper.OpenSaveDir(in saveDataFilter, viewModel.SelectedApplication.Id, viewModel.SelectedApplication.ControlHolder, viewModel.SelectedApplication.Name); } } @@ -98,7 +86,7 @@ namespace Ryujinx.Ava.UI.Controls if (viewModel?.SelectedApplication != null) { - await TitleUpdateWindow.Show(viewModel.VirtualFileSystem, ulong.Parse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber), viewModel.SelectedApplication.TitleName); + await TitleUpdateWindow.Show(viewModel.VirtualFileSystem, viewModel.SelectedApplication); } } @@ -108,7 +96,7 @@ namespace Ryujinx.Ava.UI.Controls if (viewModel?.SelectedApplication != null) { - await DownloadableContentManagerWindow.Show(viewModel.VirtualFileSystem, ulong.Parse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber), viewModel.SelectedApplication.TitleName); + await DownloadableContentManagerWindow.Show(viewModel.VirtualFileSystem, viewModel.SelectedApplication); } } @@ -120,8 +108,8 @@ namespace Ryujinx.Ava.UI.Controls { await new CheatWindow( viewModel.VirtualFileSystem, - viewModel.SelectedApplication.TitleId, - viewModel.SelectedApplication.TitleName, + viewModel.SelectedApplication.IdString, + viewModel.SelectedApplication.Name, viewModel.SelectedApplication.Path).ShowDialog(viewModel.TopLevel as Window); } } @@ -133,7 +121,7 @@ namespace Ryujinx.Ava.UI.Controls if (viewModel?.SelectedApplication != null) { string modsBasePath = ModLoader.GetModsBasePath(); - string titleModsPath = ModLoader.GetTitleDir(modsBasePath, viewModel.SelectedApplication.TitleId); + string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString); OpenHelper.OpenFolder(titleModsPath); } @@ -146,12 +134,22 @@ namespace Ryujinx.Ava.UI.Controls if (viewModel?.SelectedApplication != null) { string sdModsBasePath = ModLoader.GetSdModsBasePath(); - string titleModsPath = ModLoader.GetTitleDir(sdModsBasePath, viewModel.SelectedApplication.TitleId); + string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.IdString); OpenHelper.OpenFolder(titleModsPath); } } + public async void OpenModManager_Click(object sender, RoutedEventArgs args) + { + var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; + + if (viewModel?.SelectedApplication != null) + { + await ModManagerWindow.Show(viewModel.SelectedApplication.Id, viewModel.SelectedApplication.Name); + } + } + public async void PurgePtcCache_Click(object sender, RoutedEventArgs args) { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; @@ -160,15 +158,15 @@ namespace Ryujinx.Ava.UI.Controls { UserResult result = await ContentDialogHelper.CreateConfirmationDialog( LocaleManager.Instance[LocaleKeys.DialogWarning], - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, viewModel.SelectedApplication.TitleName), + LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, viewModel.SelectedApplication.Name), LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogNo], LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); if (result == UserResult.Yes) { - DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "cpu", "0")); - DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "cpu", "1")); + DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "0")); + DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "1")); List cacheFiles = new(); @@ -208,14 +206,14 @@ namespace Ryujinx.Ava.UI.Controls { UserResult result = await ContentDialogHelper.CreateConfirmationDialog( LocaleManager.Instance[LocaleKeys.DialogWarning], - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, viewModel.SelectedApplication.TitleName), + LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, viewModel.SelectedApplication.Name), LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogNo], LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); if (result == UserResult.Yes) { - DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "shader")); + DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader")); List oldCacheDirectories = new(); List newCacheFiles = new(); @@ -263,7 +261,7 @@ namespace Ryujinx.Ava.UI.Controls if (viewModel?.SelectedApplication != null) { - string ptcDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "cpu"); + string ptcDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu"); string mainDir = Path.Combine(ptcDir, "0"); string backupDir = Path.Combine(ptcDir, "1"); @@ -284,7 +282,7 @@ namespace Ryujinx.Ava.UI.Controls if (viewModel?.SelectedApplication != null) { - string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "shader"); + string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader"); if (!Directory.Exists(shaderCacheDir)) { @@ -305,7 +303,7 @@ namespace Ryujinx.Ava.UI.Controls viewModel.StorageProvider, NcaSectionType.Code, viewModel.SelectedApplication.Path, - viewModel.SelectedApplication.TitleName); + viewModel.SelectedApplication.Name); } } @@ -319,7 +317,7 @@ namespace Ryujinx.Ava.UI.Controls viewModel.StorageProvider, NcaSectionType.Data, viewModel.SelectedApplication.Path, - viewModel.SelectedApplication.TitleName); + viewModel.SelectedApplication.Name); } } @@ -333,7 +331,7 @@ namespace Ryujinx.Ava.UI.Controls viewModel.StorageProvider, NcaSectionType.Logo, viewModel.SelectedApplication.Path, - viewModel.SelectedApplication.TitleName); + viewModel.SelectedApplication.Name); } } @@ -344,7 +342,7 @@ namespace Ryujinx.Ava.UI.Controls if (viewModel?.SelectedApplication != null) { ApplicationData selectedApplication = viewModel.SelectedApplication; - ShortcutHelper.CreateAppShortcut(selectedApplication.Path, selectedApplication.TitleName, selectedApplication.TitleId, selectedApplication.Icon); + ShortcutHelper.CreateAppShortcut(selectedApplication.Path, selectedApplication.Name, selectedApplication.IdString, selectedApplication.Icon); } } @@ -354,7 +352,7 @@ namespace Ryujinx.Ava.UI.Controls if (viewModel?.SelectedApplication != null) { - await viewModel.LoadApplication(viewModel.SelectedApplication.Path); + await viewModel.LoadApplication(viewModel.SelectedApplication); } } } diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml b/src/Ryujinx/UI/Controls/ApplicationGridView.axaml similarity index 93% rename from src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml rename to src/Ryujinx/UI/Controls/ApplicationGridView.axaml index bbdb4c4a7..98a1c004b 100644 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml +++ b/src/Ryujinx/UI/Controls/ApplicationGridView.axaml @@ -4,7 +4,6 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" @@ -33,11 +32,10 @@ SelectionChanged="GameList_SelectionChanged"> - + VerticalAlignment="Top" + Orientation="Horizontal" /> @@ -82,7 +80,7 @@ diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml.cs b/src/Ryujinx/UI/Controls/ApplicationGridView.axaml.cs similarity index 98% rename from src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml.cs rename to src/Ryujinx/UI/Controls/ApplicationGridView.axaml.cs index 821d6fd9f..ee15bc8d5 100644 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml.cs +++ b/src/Ryujinx/UI/Controls/ApplicationGridView.axaml.cs @@ -3,7 +3,7 @@ using Avalonia.Input; using Avalonia.Interactivity; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; using System; namespace Ryujinx.Ava.UI.Controls diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml b/src/Ryujinx/UI/Controls/ApplicationListView.axaml similarity index 92% rename from src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml rename to src/Ryujinx/UI/Controls/ApplicationListView.axaml index 9004f7518..f99cf316e 100644 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml +++ b/src/Ryujinx/UI/Controls/ApplicationListView.axaml @@ -85,18 +85,18 @@ @@ -109,13 +109,13 @@ Spacing="5"> + Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common" /> - \ No newline at end of file + diff --git a/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml.cs b/src/Ryujinx/UI/Controls/UpdateWaitWindow.axaml.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml.cs rename to src/Ryujinx/UI/Controls/UpdateWaitWindow.axaml.cs diff --git a/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs b/src/Ryujinx/UI/Helpers/ApplicationOpenedEventArgs.cs similarity index 93% rename from src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs rename to src/Ryujinx/UI/Helpers/ApplicationOpenedEventArgs.cs index cd63a99b0..bc5622b54 100644 --- a/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs +++ b/src/Ryujinx/UI/Helpers/ApplicationOpenedEventArgs.cs @@ -1,5 +1,5 @@ using Avalonia.Interactivity; -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; namespace Ryujinx.Ava.UI.Helpers { diff --git a/src/Ryujinx.Ava/UI/Helpers/BitmapArrayValueConverter.cs b/src/Ryujinx/UI/Helpers/BitmapArrayValueConverter.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Helpers/BitmapArrayValueConverter.cs rename to src/Ryujinx/UI/Helpers/BitmapArrayValueConverter.cs diff --git a/src/Ryujinx.Ava/UI/Helpers/ButtonKeyAssigner.cs b/src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs similarity index 69% rename from src/Ryujinx.Ava/UI/Helpers/ButtonKeyAssigner.cs rename to src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs index 7e8ba7342..4f2b8daae 100644 --- a/src/Ryujinx.Ava/UI/Helpers/ButtonKeyAssigner.cs +++ b/src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs @@ -1,11 +1,8 @@ -using Avalonia.Controls; using Avalonia.Controls.Primitives; -using Avalonia.LogicalTree; using Avalonia.Threading; using Ryujinx.Input; using Ryujinx.Input.Assigner; using System; -using System.Linq; using System.Threading.Tasks; namespace Ryujinx.Ava.UI.Helpers @@ -15,12 +12,12 @@ namespace Ryujinx.Ava.UI.Helpers internal class ButtonAssignedEventArgs : EventArgs { public ToggleButton Button { get; } - public bool IsAssigned { get; } + public Button? ButtonValue { get; } - public ButtonAssignedEventArgs(ToggleButton button, bool isAssigned) + public ButtonAssignedEventArgs(ToggleButton button, Button? buttonValue) { Button = button; - IsAssigned = isAssigned; + ButtonValue = buttonValue; } } @@ -69,7 +66,7 @@ namespace Ryujinx.Ava.UI.Helpers assigner.ReadInput(); - if (assigner.HasAnyButtonPressed() || assigner.ShouldCancel() || (keyboard != null && keyboard.IsPressed(Key.Escape))) + if (assigner.IsAnyButtonPressed() || assigner.ShouldCancel() || (keyboard != null && keyboard.IsPressed(Key.Escape))) { break; } @@ -78,15 +75,11 @@ namespace Ryujinx.Ava.UI.Helpers await Dispatcher.UIThread.InvokeAsync(() => { - string pressedButton = assigner.GetPressedButton(); + Button? pressedButton = assigner.GetPressedButton(); if (_shouldUnbind) { - SetButtonText(ToggledButton, "Unbound"); - } - else if (pressedButton != "") - { - SetButtonText(ToggledButton, pressedButton); + pressedButton = null; } _shouldUnbind = false; @@ -94,17 +87,8 @@ namespace Ryujinx.Ava.UI.Helpers ToggledButton.IsChecked = false; - ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton != null)); + ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton)); - static void SetButtonText(ToggleButton button, string text) - { - ILogical textBlock = button.GetLogicalDescendants().First(x => x is TextBlock); - - if (textBlock != null && textBlock is TextBlock block) - { - block.Text = text; - } - } }); } diff --git a/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs b/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs similarity index 88% rename from src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs rename to src/Ryujinx/UI/Helpers/ContentDialogHelper.cs index 086de953d..15b7ddd14 100644 --- a/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs +++ b/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs @@ -18,6 +18,7 @@ namespace Ryujinx.Ava.UI.Helpers public static class ContentDialogHelper { private static bool _isChoiceDialogOpen; + private static ContentDialogOverlayWindow _contentDialogOverlayWindow; private async static Task ShowContentDialog( string title, @@ -310,16 +311,20 @@ namespace Ryujinx.Ava.UI.Helpers public static async Task ShowAsync(ContentDialog contentDialog) { ContentDialogResult result; - - ContentDialogOverlayWindow contentDialogOverlayWindow = null; + bool isTopDialog = true; Window parent = GetMainWindow(); + if (_contentDialogOverlayWindow != null) + { + isTopDialog = false; + } + if (parent is MainWindow window) { parent.Activate(); - contentDialogOverlayWindow = new() + _contentDialogOverlayWindow = new ContentDialogOverlayWindow { Height = parent.Bounds.Height, Width = parent.Bounds.Width, @@ -331,14 +336,19 @@ namespace Ryujinx.Ava.UI.Helpers void OverlayOnPositionChanged(object sender, PixelPointEventArgs e) { - contentDialogOverlayWindow.Position = parent.PointToScreen(new Point()); + if (_contentDialogOverlayWindow is null) + { + return; + } + + _contentDialogOverlayWindow.Position = parent.PointToScreen(new Point()); } - contentDialogOverlayWindow.ContentDialog = contentDialog; + _contentDialogOverlayWindow.ContentDialog = contentDialog; bool opened = false; - contentDialogOverlayWindow.Opened += OverlayOnActivated; + _contentDialogOverlayWindow.Opened += OverlayOnActivated; async void OverlayOnActivated(object sender, EventArgs e) { @@ -349,12 +359,12 @@ namespace Ryujinx.Ava.UI.Helpers opened = true; - contentDialogOverlayWindow.Position = parent.PointToScreen(new Point()); + _contentDialogOverlayWindow.Position = parent.PointToScreen(new Point()); result = await ShowDialog(); } - result = await contentDialogOverlayWindow.ShowDialog(parent); + result = await _contentDialogOverlayWindow.ShowDialog(parent); } else { @@ -363,31 +373,39 @@ namespace Ryujinx.Ava.UI.Helpers async Task ShowDialog() { - if (contentDialogOverlayWindow is not null) + if (_contentDialogOverlayWindow is not null) { - result = await contentDialog.ShowAsync(contentDialogOverlayWindow); + result = await contentDialog.ShowAsync(_contentDialogOverlayWindow); - contentDialogOverlayWindow!.Close(); + _contentDialogOverlayWindow!.Close(); } else { result = ContentDialogResult.None; - Logger.Warning?.Print(LogClass.Ui, "Content dialog overlay failed to populate. Default value has been returned."); + Logger.Warning?.Print(LogClass.UI, "Content dialog overlay failed to populate. Default value has been returned."); } return result; } - if (contentDialogOverlayWindow is not null) + if (isTopDialog && _contentDialogOverlayWindow is not null) { - contentDialogOverlayWindow.Content = null; - contentDialogOverlayWindow.Close(); + _contentDialogOverlayWindow.Content = null; + _contentDialogOverlayWindow.Close(); + _contentDialogOverlayWindow = null; } return result; } + public static Task ShowWindowAsync(Window dialogWindow, Window mainWindow = null) + { + mainWindow ??= GetMainWindow(); + + return dialogWindow.ShowDialog(_contentDialogOverlayWindow ?? mainWindow); + } + private static Window GetMainWindow() { if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime al) diff --git a/src/Ryujinx.Ava/UI/Helpers/Glyph.cs b/src/Ryujinx/UI/Helpers/Glyph.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Helpers/Glyph.cs rename to src/Ryujinx/UI/Helpers/Glyph.cs diff --git a/src/Ryujinx.Ava/UI/Helpers/GlyphValueConverter.cs b/src/Ryujinx/UI/Helpers/GlyphValueConverter.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Helpers/GlyphValueConverter.cs rename to src/Ryujinx/UI/Helpers/GlyphValueConverter.cs diff --git a/src/Ryujinx/UI/Helpers/KeyValueConverter.cs b/src/Ryujinx/UI/Helpers/KeyValueConverter.cs new file mode 100644 index 000000000..5b0d6ee1c --- /dev/null +++ b/src/Ryujinx/UI/Helpers/KeyValueConverter.cs @@ -0,0 +1,184 @@ +using Avalonia.Data.Converters; +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Common.Configuration.Hid; +using Ryujinx.Common.Configuration.Hid.Controller; +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace Ryujinx.Ava.UI.Helpers +{ + internal class KeyValueConverter : IValueConverter + { + public static KeyValueConverter Instance = new(); + + private static readonly Dictionary _keysMap = new() + { + { Key.Unknown, LocaleKeys.KeyUnknown }, + { Key.ShiftLeft, LocaleKeys.KeyShiftLeft }, + { Key.ShiftRight, LocaleKeys.KeyShiftRight }, + { Key.ControlLeft, LocaleKeys.KeyControlLeft }, + { Key.ControlRight, LocaleKeys.KeyControlRight }, + { Key.AltLeft, LocaleKeys.KeyAltLeft }, + { Key.AltRight, LocaleKeys.KeyAltRight }, + { Key.WinLeft, LocaleKeys.KeyWinLeft }, + { Key.WinRight, LocaleKeys.KeyWinRight }, + { Key.Up, LocaleKeys.KeyUp }, + { Key.Down, LocaleKeys.KeyDown }, + { Key.Left, LocaleKeys.KeyLeft }, + { Key.Right, LocaleKeys.KeyRight }, + { Key.Enter, LocaleKeys.KeyEnter }, + { Key.Escape, LocaleKeys.KeyEscape }, + { Key.Space, LocaleKeys.KeySpace }, + { Key.Tab, LocaleKeys.KeyTab }, + { Key.BackSpace, LocaleKeys.KeyBackSpace }, + { Key.Insert, LocaleKeys.KeyInsert }, + { Key.Delete, LocaleKeys.KeyDelete }, + { Key.PageUp, LocaleKeys.KeyPageUp }, + { Key.PageDown, LocaleKeys.KeyPageDown }, + { Key.Home, LocaleKeys.KeyHome }, + { Key.End, LocaleKeys.KeyEnd }, + { Key.CapsLock, LocaleKeys.KeyCapsLock }, + { Key.ScrollLock, LocaleKeys.KeyScrollLock }, + { Key.PrintScreen, LocaleKeys.KeyPrintScreen }, + { Key.Pause, LocaleKeys.KeyPause }, + { Key.NumLock, LocaleKeys.KeyNumLock }, + { Key.Clear, LocaleKeys.KeyClear }, + { Key.Keypad0, LocaleKeys.KeyKeypad0 }, + { Key.Keypad1, LocaleKeys.KeyKeypad1 }, + { Key.Keypad2, LocaleKeys.KeyKeypad2 }, + { Key.Keypad3, LocaleKeys.KeyKeypad3 }, + { Key.Keypad4, LocaleKeys.KeyKeypad4 }, + { Key.Keypad5, LocaleKeys.KeyKeypad5 }, + { Key.Keypad6, LocaleKeys.KeyKeypad6 }, + { Key.Keypad7, LocaleKeys.KeyKeypad7 }, + { Key.Keypad8, LocaleKeys.KeyKeypad8 }, + { Key.Keypad9, LocaleKeys.KeyKeypad9 }, + { Key.KeypadDivide, LocaleKeys.KeyKeypadDivide }, + { Key.KeypadMultiply, LocaleKeys.KeyKeypadMultiply }, + { Key.KeypadSubtract, LocaleKeys.KeyKeypadSubtract }, + { Key.KeypadAdd, LocaleKeys.KeyKeypadAdd }, + { Key.KeypadDecimal, LocaleKeys.KeyKeypadDecimal }, + { Key.KeypadEnter, LocaleKeys.KeyKeypadEnter }, + { Key.Number0, LocaleKeys.KeyNumber0 }, + { Key.Number1, LocaleKeys.KeyNumber1 }, + { Key.Number2, LocaleKeys.KeyNumber2 }, + { Key.Number3, LocaleKeys.KeyNumber3 }, + { Key.Number4, LocaleKeys.KeyNumber4 }, + { Key.Number5, LocaleKeys.KeyNumber5 }, + { Key.Number6, LocaleKeys.KeyNumber6 }, + { Key.Number7, LocaleKeys.KeyNumber7 }, + { Key.Number8, LocaleKeys.KeyNumber8 }, + { Key.Number9, LocaleKeys.KeyNumber9 }, + { Key.Tilde, LocaleKeys.KeyTilde }, + { Key.Grave, LocaleKeys.KeyGrave }, + { Key.Minus, LocaleKeys.KeyMinus }, + { Key.Plus, LocaleKeys.KeyPlus }, + { Key.BracketLeft, LocaleKeys.KeyBracketLeft }, + { Key.BracketRight, LocaleKeys.KeyBracketRight }, + { Key.Semicolon, LocaleKeys.KeySemicolon }, + { Key.Quote, LocaleKeys.KeyQuote }, + { Key.Comma, LocaleKeys.KeyComma }, + { Key.Period, LocaleKeys.KeyPeriod }, + { Key.Slash, LocaleKeys.KeySlash }, + { Key.BackSlash, LocaleKeys.KeyBackSlash }, + { Key.Unbound, LocaleKeys.KeyUnbound }, + }; + + private static readonly Dictionary _gamepadInputIdMap = new() + { + { GamepadInputId.LeftStick, LocaleKeys.GamepadLeftStick }, + { GamepadInputId.RightStick, LocaleKeys.GamepadRightStick }, + { GamepadInputId.LeftShoulder, LocaleKeys.GamepadLeftShoulder }, + { GamepadInputId.RightShoulder, LocaleKeys.GamepadRightShoulder }, + { GamepadInputId.LeftTrigger, LocaleKeys.GamepadLeftTrigger }, + { GamepadInputId.RightTrigger, LocaleKeys.GamepadRightTrigger }, + { GamepadInputId.DpadUp, LocaleKeys.GamepadDpadUp}, + { GamepadInputId.DpadDown, LocaleKeys.GamepadDpadDown}, + { GamepadInputId.DpadLeft, LocaleKeys.GamepadDpadLeft}, + { GamepadInputId.DpadRight, LocaleKeys.GamepadDpadRight}, + { GamepadInputId.Minus, LocaleKeys.GamepadMinus}, + { GamepadInputId.Plus, LocaleKeys.GamepadPlus}, + { GamepadInputId.Guide, LocaleKeys.GamepadGuide}, + { GamepadInputId.Misc1, LocaleKeys.GamepadMisc1}, + { GamepadInputId.Paddle1, LocaleKeys.GamepadPaddle1}, + { GamepadInputId.Paddle2, LocaleKeys.GamepadPaddle2}, + { GamepadInputId.Paddle3, LocaleKeys.GamepadPaddle3}, + { GamepadInputId.Paddle4, LocaleKeys.GamepadPaddle4}, + { GamepadInputId.Touchpad, LocaleKeys.GamepadTouchpad}, + { GamepadInputId.SingleLeftTrigger0, LocaleKeys.GamepadSingleLeftTrigger0}, + { GamepadInputId.SingleRightTrigger0, LocaleKeys.GamepadSingleRightTrigger0}, + { GamepadInputId.SingleLeftTrigger1, LocaleKeys.GamepadSingleLeftTrigger1}, + { GamepadInputId.SingleRightTrigger1, LocaleKeys.GamepadSingleRightTrigger1}, + { GamepadInputId.Unbound, LocaleKeys.KeyUnbound}, + }; + + private static readonly Dictionary _stickInputIdMap = new() + { + { StickInputId.Left, LocaleKeys.StickLeft}, + { StickInputId.Right, LocaleKeys.StickRight}, + { StickInputId.Unbound, LocaleKeys.KeyUnbound}, + }; + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + string keyString = ""; + LocaleKeys localeKey; + + switch (value) + { + case Key key: + if (_keysMap.TryGetValue(key, out localeKey)) + { + if (OperatingSystem.IsMacOS()) + { + localeKey = localeKey switch + { + LocaleKeys.KeyControlLeft => LocaleKeys.KeyMacControlLeft, + LocaleKeys.KeyControlRight => LocaleKeys.KeyMacControlRight, + LocaleKeys.KeyAltLeft => LocaleKeys.KeyMacAltLeft, + LocaleKeys.KeyAltRight => LocaleKeys.KeyMacAltRight, + LocaleKeys.KeyWinLeft => LocaleKeys.KeyMacWinLeft, + LocaleKeys.KeyWinRight => LocaleKeys.KeyMacWinRight, + _ => localeKey + }; + } + + keyString = LocaleManager.Instance[localeKey]; + } + else + { + keyString = key.ToString(); + } + break; + case GamepadInputId gamepadInputId: + if (_gamepadInputIdMap.TryGetValue(gamepadInputId, out localeKey)) + { + keyString = LocaleManager.Instance[localeKey]; + } + else + { + keyString = gamepadInputId.ToString(); + } + break; + case StickInputId stickInputId: + if (_stickInputIdMap.TryGetValue(stickInputId, out localeKey)) + { + keyString = LocaleManager.Instance[localeKey]; + } + else + { + keyString = stickInputId.ToString(); + } + break; + } + + return keyString; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs b/src/Ryujinx/UI/Helpers/LocalizedNeverConverter.cs similarity index 97% rename from src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs rename to src/Ryujinx/UI/Helpers/LocalizedNeverConverter.cs index b61a924f4..26fe36c4c 100644 --- a/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs +++ b/src/Ryujinx/UI/Helpers/LocalizedNeverConverter.cs @@ -1,7 +1,7 @@ using Avalonia.Data.Converters; using Avalonia.Markup.Xaml; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System; using System.Globalization; diff --git a/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs b/src/Ryujinx/UI/Helpers/LoggerAdapter.cs similarity index 95% rename from src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs rename to src/Ryujinx/UI/Helpers/LoggerAdapter.cs index 0b1789880..fc728b495 100644 --- a/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs +++ b/src/Ryujinx/UI/Helpers/LoggerAdapter.cs @@ -20,6 +20,7 @@ namespace Ryujinx.Ava.UI.Helpers private static RyuLogger.Log? GetLog(AvaLogLevel level) { + return null; return level switch { AvaLogLevel.Verbose => RyuLogger.Debug, @@ -39,12 +40,12 @@ namespace Ryujinx.Ava.UI.Helpers public void Log(AvaLogLevel level, string area, object source, string messageTemplate) { - GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(level, area, messageTemplate, source, null)); + GetLog(level)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, null)); } public void Log(AvaLogLevel level, string area, object source, string messageTemplate, params object[] propertyValues) { - GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(level, area, messageTemplate, source, propertyValues)); + GetLog(level)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, propertyValues)); } private static string Format(AvaLogLevel level, string area, string template, object source, object[] v) diff --git a/src/Ryujinx.Ava/UI/Helpers/MiniCommand.cs b/src/Ryujinx/UI/Helpers/MiniCommand.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Helpers/MiniCommand.cs rename to src/Ryujinx/UI/Helpers/MiniCommand.cs diff --git a/src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs b/src/Ryujinx/UI/Helpers/NotificationHelper.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs rename to src/Ryujinx/UI/Helpers/NotificationHelper.cs diff --git a/src/Ryujinx.Ava/UI/Helpers/OffscreenTextBox.cs b/src/Ryujinx/UI/Helpers/OffscreenTextBox.cs similarity index 91% rename from src/Ryujinx.Ava/UI/Helpers/OffscreenTextBox.cs rename to src/Ryujinx/UI/Helpers/OffscreenTextBox.cs index a055f3353..dd736037e 100644 --- a/src/Ryujinx.Ava/UI/Helpers/OffscreenTextBox.cs +++ b/src/Ryujinx/UI/Helpers/OffscreenTextBox.cs @@ -1,11 +1,14 @@ using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; +using System; namespace Ryujinx.Ava.UI.Helpers { public class OffscreenTextBox : TextBox { + protected override Type StyleKeyOverride => typeof(TextBox); + public static RoutedEvent GetKeyDownRoutedEvent() { return KeyDownEvent; diff --git a/src/Ryujinx.Ava/UI/Helpers/TimeZoneConverter.cs b/src/Ryujinx/UI/Helpers/TimeZoneConverter.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Helpers/TimeZoneConverter.cs rename to src/Ryujinx/UI/Helpers/TimeZoneConverter.cs diff --git a/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs b/src/Ryujinx/UI/Helpers/UserErrorDialog.cs similarity index 98% rename from src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs rename to src/Ryujinx/UI/Helpers/UserErrorDialog.cs index fc82bd6b1..9a44b862b 100644 --- a/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs +++ b/src/Ryujinx/UI/Helpers/UserErrorDialog.cs @@ -1,6 +1,6 @@ using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Helper; using System.Threading.Tasks; namespace Ryujinx.Ava.UI.Helpers diff --git a/src/Ryujinx.Ava/UI/Helpers/UserResult.cs b/src/Ryujinx/UI/Helpers/UserResult.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Helpers/UserResult.cs rename to src/Ryujinx/UI/Helpers/UserResult.cs diff --git a/src/Ryujinx.Ava/UI/Helpers/Win32NativeInterop.cs b/src/Ryujinx/UI/Helpers/Win32NativeInterop.cs similarity index 87% rename from src/Ryujinx.Ava/UI/Helpers/Win32NativeInterop.cs rename to src/Ryujinx/UI/Helpers/Win32NativeInterop.cs index 4834df802..01478cb3d 100644 --- a/src/Ryujinx.Ava/UI/Helpers/Win32NativeInterop.cs +++ b/src/Ryujinx/UI/Helpers/Win32NativeInterop.cs @@ -8,6 +8,8 @@ namespace Ryujinx.Ava.UI.Helpers [SupportedOSPlatform("windows")] internal partial class Win32NativeInterop { + internal const int GWLP_WNDPROC = -4; + [Flags] public enum ClassStyles : uint { @@ -29,22 +31,7 @@ namespace Ryujinx.Ava.UI.Helpers [SuppressMessage("Design", "CA1069: Enums values should not be duplicated")] public enum WindowsMessages : uint { - Mousemove = 0x0200, - Lbuttondown = 0x0201, - Lbuttonup = 0x0202, - Lbuttondblclk = 0x0203, - Rbuttondown = 0x0204, - Rbuttonup = 0x0205, - Rbuttondblclk = 0x0206, - Mbuttondown = 0x0207, - Mbuttonup = 0x0208, - Mbuttondblclk = 0x0209, - Mousewheel = 0x020A, - Xbuttondown = 0x020B, - Xbuttonup = 0x020C, - Xbuttondblclk = 0x020D, - Mousehwheel = 0x020E, - Mouselast = 0x020E, + NcHitTest = 0x0084, } [UnmanagedFunctionPointer(CallingConvention.Winapi)] @@ -121,5 +108,8 @@ namespace Ryujinx.Ava.UI.Helpers IntPtr hMenu, IntPtr hInstance, IntPtr lpParam); + + [LibraryImport("user32.dll", SetLastError = true)] + public static partial IntPtr SetWindowLongPtrW(IntPtr hWnd, int nIndex, IntPtr value); } } diff --git a/src/Ryujinx.Ava/UI/Models/CheatNode.cs b/src/Ryujinx/UI/Models/CheatNode.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Models/CheatNode.cs rename to src/Ryujinx/UI/Models/CheatNode.cs diff --git a/src/Ryujinx.Ava/UI/Models/ControllerModel.cs b/src/Ryujinx/UI/Models/ControllerModel.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Models/ControllerModel.cs rename to src/Ryujinx/UI/Models/ControllerModel.cs diff --git a/src/Ryujinx.Ava/UI/Models/DeviceType.cs b/src/Ryujinx/UI/Models/DeviceType.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Models/DeviceType.cs rename to src/Ryujinx/UI/Models/DeviceType.cs diff --git a/src/Ryujinx.Ava/UI/Models/DownloadableContentModel.cs b/src/Ryujinx/UI/Models/DownloadableContentModel.cs similarity index 79% rename from src/Ryujinx.Ava/UI/Models/DownloadableContentModel.cs rename to src/Ryujinx/UI/Models/DownloadableContentModel.cs index 9e400441d..1409d9713 100644 --- a/src/Ryujinx.Ava/UI/Models/DownloadableContentModel.cs +++ b/src/Ryujinx/UI/Models/DownloadableContentModel.cs @@ -1,3 +1,4 @@ +using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.ViewModels; using System.IO; @@ -24,6 +25,9 @@ namespace Ryujinx.Ava.UI.Models public string FileName => Path.GetFileName(ContainerPath); + public string Label => + Path.GetExtension(FileName)?.ToLower() == ".xci" ? $"{LocaleManager.Instance[LocaleKeys.TitleBundledDlcLabel]} {FileName}" : FileName; + public DownloadableContentModel(string titleId, string containerPath, string fullPath, bool enabled) { TitleId = titleId; diff --git a/src/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs b/src/Ryujinx/UI/Models/Generic/LastPlayedSortComparer.cs similarity index 96% rename from src/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs rename to src/Ryujinx/UI/Models/Generic/LastPlayedSortComparer.cs index 8340d39df..224f78f45 100644 --- a/src/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs +++ b/src/Ryujinx/UI/Models/Generic/LastPlayedSortComparer.cs @@ -1,4 +1,4 @@ -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; using System; using System.Collections.Generic; diff --git a/src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs b/src/Ryujinx/UI/Models/Generic/TimePlayedSortComparer.cs similarity index 96% rename from src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs rename to src/Ryujinx/UI/Models/Generic/TimePlayedSortComparer.cs index d53ff566f..f0fb035d1 100644 --- a/src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs +++ b/src/Ryujinx/UI/Models/Generic/TimePlayedSortComparer.cs @@ -1,4 +1,4 @@ -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; using System; using System.Collections.Generic; diff --git a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs new file mode 100644 index 000000000..49d0f551b --- /dev/null +++ b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs @@ -0,0 +1,606 @@ +using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Common.Configuration.Hid; +using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Common.Configuration.Hid.Controller.Motion; +using System; + +namespace Ryujinx.Ava.UI.Models.Input +{ + public class GamepadInputConfig : BaseModel + { + public bool EnableCemuHookMotion { get; set; } + public string DsuServerHost { get; set; } + public int DsuServerPort { get; set; } + public int Slot { get; set; } + public int AltSlot { get; set; } + public bool MirrorInput { get; set; } + public int Sensitivity { get; set; } + public double GyroDeadzone { get; set; } + + public float WeakRumble { get; set; } + public float StrongRumble { get; set; } + + public string Id { get; set; } + public ControllerType ControllerType { get; set; } + public PlayerIndex PlayerIndex { get; set; } + + private StickInputId _leftJoystick; + public StickInputId LeftJoystick + { + get => _leftJoystick; + set + { + _leftJoystick = value; + OnPropertyChanged(); + } + } + + private bool _leftInvertStickX; + public bool LeftInvertStickX + { + get => _leftInvertStickX; + set + { + _leftInvertStickX = value; + OnPropertyChanged(); + } + } + + private bool _leftInvertStickY; + public bool LeftInvertStickY + { + get => _leftInvertStickY; + set + { + _leftInvertStickY = value; + OnPropertyChanged(); + } + } + + private bool _leftRotate90; + public bool LeftRotate90 + { + get => _leftRotate90; + set + { + _leftRotate90 = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _leftStickButton; + public GamepadInputId LeftStickButton + { + get => _leftStickButton; + set + { + _leftStickButton = value; + OnPropertyChanged(); + } + } + + private StickInputId _rightJoystick; + public StickInputId RightJoystick + { + get => _rightJoystick; + set + { + _rightJoystick = value; + OnPropertyChanged(); + } + } + + private bool _rightInvertStickX; + public bool RightInvertStickX + { + get => _rightInvertStickX; + set + { + _rightInvertStickX = value; + OnPropertyChanged(); + } + } + + private bool _rightInvertStickY; + public bool RightInvertStickY + { + get => _rightInvertStickY; + set + { + _rightInvertStickY = value; + OnPropertyChanged(); + } + } + + private bool _rightRotate90; + public bool RightRotate90 + { + get => _rightRotate90; + set + { + _rightRotate90 = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _rightStickButton; + public GamepadInputId RightStickButton + { + get => _rightStickButton; + set + { + _rightStickButton = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _dpadUp; + public GamepadInputId DpadUp + { + get => _dpadUp; + set + { + _dpadUp = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _dpadDown; + public GamepadInputId DpadDown + { + get => _dpadDown; + set + { + _dpadDown = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _dpadLeft; + public GamepadInputId DpadLeft + { + get => _dpadLeft; + set + { + _dpadLeft = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _dpadRight; + public GamepadInputId DpadRight + { + get => _dpadRight; + set + { + _dpadRight = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonL; + public GamepadInputId ButtonL + { + get => _buttonL; + set + { + _buttonL = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonMinus; + public GamepadInputId ButtonMinus + { + get => _buttonMinus; + set + { + _buttonMinus = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _leftButtonSl; + public GamepadInputId LeftButtonSl + { + get => _leftButtonSl; + set + { + _leftButtonSl = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _leftButtonSr; + public GamepadInputId LeftButtonSr + { + get => _leftButtonSr; + set + { + _leftButtonSr = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonZl; + public GamepadInputId ButtonZl + { + get => _buttonZl; + set + { + _buttonZl = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonCapture; + public GamepadInputId ButtonCapture + { + get => _buttonCapture; + set + { + _buttonCapture = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonA; + public GamepadInputId ButtonA + { + get => _buttonA; + set + { + _buttonA = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonB; + public GamepadInputId ButtonB + { + get => _buttonB; + set + { + _buttonB = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonX; + public GamepadInputId ButtonX + { + get => _buttonX; + set + { + _buttonX = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonY; + public GamepadInputId ButtonY + { + get => _buttonY; + set + { + _buttonY = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonR; + public GamepadInputId ButtonR + { + get => _buttonR; + set + { + _buttonR = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonPlus; + public GamepadInputId ButtonPlus + { + get => _buttonPlus; + set + { + _buttonPlus = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _rightButtonSl; + public GamepadInputId RightButtonSl + { + get => _rightButtonSl; + set + { + _rightButtonSl = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _rightButtonSr; + public GamepadInputId RightButtonSr + { + get => _rightButtonSr; + set + { + _rightButtonSr = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonZr; + public GamepadInputId ButtonZr + { + get => _buttonZr; + set + { + _buttonZr = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonHome; + public GamepadInputId ButtonHome + { + get => _buttonHome; + set + { + _buttonHome = value; + OnPropertyChanged(); + } + } + + private float _deadzoneLeft; + public float DeadzoneLeft + { + get => _deadzoneLeft; + set + { + _deadzoneLeft = MathF.Round(value, 3); + OnPropertyChanged(); + } + } + + private float _deadzoneRight; + public float DeadzoneRight + { + get => _deadzoneRight; + set + { + _deadzoneRight = MathF.Round(value, 3); + OnPropertyChanged(); + } + } + + private float _rangeLeft; + public float RangeLeft + { + get => _rangeLeft; + set + { + _rangeLeft = MathF.Round(value, 3); + OnPropertyChanged(); + } + } + + private float _rangeRight; + public float RangeRight + { + get => _rangeRight; + set + { + _rangeRight = MathF.Round(value, 3); + OnPropertyChanged(); + } + } + + private float _triggerThreshold; + public float TriggerThreshold + { + get => _triggerThreshold; + set + { + _triggerThreshold = MathF.Round(value, 3); + OnPropertyChanged(); + } + } + + private bool _enableMotion; + public bool EnableMotion + { + get => _enableMotion; + set + { + _enableMotion = value; + OnPropertyChanged(); + } + } + + private bool _enableRumble; + public bool EnableRumble + { + get => _enableRumble; + set + { + _enableRumble = value; + OnPropertyChanged(); + } + } + + public GamepadInputConfig(InputConfig config) + { + if (config != null) + { + Id = config.Id; + ControllerType = config.ControllerType; + PlayerIndex = config.PlayerIndex; + + if (config is not StandardControllerInputConfig controllerInput) + { + return; + } + + LeftJoystick = controllerInput.LeftJoyconStick.Joystick; + LeftInvertStickX = controllerInput.LeftJoyconStick.InvertStickX; + LeftInvertStickY = controllerInput.LeftJoyconStick.InvertStickY; + LeftRotate90 = controllerInput.LeftJoyconStick.Rotate90CW; + LeftStickButton = controllerInput.LeftJoyconStick.StickButton; + + RightJoystick = controllerInput.RightJoyconStick.Joystick; + RightInvertStickX = controllerInput.RightJoyconStick.InvertStickX; + RightInvertStickY = controllerInput.RightJoyconStick.InvertStickY; + RightRotate90 = controllerInput.RightJoyconStick.Rotate90CW; + RightStickButton = controllerInput.RightJoyconStick.StickButton; + + DpadUp = controllerInput.LeftJoycon.DpadUp; + DpadDown = controllerInput.LeftJoycon.DpadDown; + DpadLeft = controllerInput.LeftJoycon.DpadLeft; + DpadRight = controllerInput.LeftJoycon.DpadRight; + ButtonL = controllerInput.LeftJoycon.ButtonL; + ButtonMinus = controllerInput.LeftJoycon.ButtonMinus; + LeftButtonSl = controllerInput.LeftJoycon.ButtonSl; + LeftButtonSr = controllerInput.LeftJoycon.ButtonSr; + ButtonZl = controllerInput.LeftJoycon.ButtonZl; + ButtonCapture = controllerInput.LeftJoycon.ButtonCapture; + + ButtonA = controllerInput.RightJoycon.ButtonA; + ButtonB = controllerInput.RightJoycon.ButtonB; + ButtonX = controllerInput.RightJoycon.ButtonX; + ButtonY = controllerInput.RightJoycon.ButtonY; + ButtonR = controllerInput.RightJoycon.ButtonR; + ButtonPlus = controllerInput.RightJoycon.ButtonPlus; + RightButtonSl = controllerInput.RightJoycon.ButtonSl; + RightButtonSr = controllerInput.RightJoycon.ButtonSr; + ButtonZr = controllerInput.RightJoycon.ButtonZr; + ButtonHome = controllerInput.RightJoycon.ButtonHome; + + DeadzoneLeft = controllerInput.DeadzoneLeft; + DeadzoneRight = controllerInput.DeadzoneRight; + RangeLeft = controllerInput.RangeLeft; + RangeRight = controllerInput.RangeRight; + TriggerThreshold = controllerInput.TriggerThreshold; + + if (controllerInput.Motion != null) + { + EnableMotion = controllerInput.Motion.EnableMotion; + GyroDeadzone = controllerInput.Motion.GyroDeadzone; + Sensitivity = controllerInput.Motion.Sensitivity; + + if (controllerInput.Motion is CemuHookMotionConfigController cemuHook) + { + EnableCemuHookMotion = true; + DsuServerHost = cemuHook.DsuServerHost; + DsuServerPort = cemuHook.DsuServerPort; + Slot = cemuHook.Slot; + AltSlot = cemuHook.AltSlot; + MirrorInput = cemuHook.MirrorInput; + } + } + + if (controllerInput.Rumble != null) + { + EnableRumble = controllerInput.Rumble.EnableRumble; + WeakRumble = controllerInput.Rumble.WeakRumble; + StrongRumble = controllerInput.Rumble.StrongRumble; + } + } + } + + public InputConfig GetConfig() + { + var config = new StandardControllerInputConfig + { + Id = Id, + Backend = InputBackendType.GamepadSDL2, + PlayerIndex = PlayerIndex, + ControllerType = ControllerType, + LeftJoycon = new LeftJoyconCommonConfig + { + DpadUp = DpadUp, + DpadDown = DpadDown, + DpadLeft = DpadLeft, + DpadRight = DpadRight, + ButtonL = ButtonL, + ButtonMinus = ButtonMinus, + ButtonSl = LeftButtonSl, + ButtonSr = LeftButtonSr, + ButtonZl = ButtonZl, + ButtonCapture = ButtonCapture, + }, + RightJoycon = new RightJoyconCommonConfig + { + ButtonA = ButtonA, + ButtonB = ButtonB, + ButtonX = ButtonX, + ButtonY = ButtonY, + ButtonPlus = ButtonPlus, + ButtonSl = RightButtonSl, + ButtonSr = RightButtonSr, + ButtonR = ButtonR, + ButtonZr = ButtonZr, + ButtonHome = ButtonHome, + }, + LeftJoyconStick = new JoyconConfigControllerStick + { + Joystick = LeftJoystick, + InvertStickX = LeftInvertStickX, + InvertStickY = LeftInvertStickY, + Rotate90CW = LeftRotate90, + StickButton = LeftStickButton, + }, + RightJoyconStick = new JoyconConfigControllerStick + { + Joystick = RightJoystick, + InvertStickX = RightInvertStickX, + InvertStickY = RightInvertStickY, + Rotate90CW = RightRotate90, + StickButton = RightStickButton, + }, + Rumble = new RumbleConfigController + { + EnableRumble = EnableRumble, + WeakRumble = WeakRumble, + StrongRumble = StrongRumble, + }, + Version = InputConfig.CurrentVersion, + DeadzoneLeft = DeadzoneLeft, + DeadzoneRight = DeadzoneRight, + RangeLeft = RangeLeft, + RangeRight = RangeRight, + TriggerThreshold = TriggerThreshold, + }; + + if (EnableCemuHookMotion) + { + config.Motion = new CemuHookMotionConfigController + { + EnableMotion = EnableMotion, + MotionBackend = MotionInputBackendType.CemuHook, + GyroDeadzone = GyroDeadzone, + Sensitivity = Sensitivity, + DsuServerHost = DsuServerHost, + DsuServerPort = DsuServerPort, + Slot = Slot, + AltSlot = AltSlot, + MirrorInput = MirrorInput, + }; + } + else + { + config.Motion = new StandardMotionConfigController + { + EnableMotion = EnableMotion, + MotionBackend = MotionInputBackendType.GamepadDriver, + GyroDeadzone = GyroDeadzone, + Sensitivity = Sensitivity, + }; + } + + return config; + } + } +} diff --git a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs new file mode 100644 index 000000000..b5f53508b --- /dev/null +++ b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs @@ -0,0 +1,141 @@ +using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Common.Configuration.Hid; + +namespace Ryujinx.Ava.UI.Models.Input +{ + public class HotkeyConfig : BaseModel + { + private Key _toggleVsync; + public Key ToggleVsync + { + get => _toggleVsync; + set + { + _toggleVsync = value; + OnPropertyChanged(); + } + } + + private Key _screenshot; + public Key Screenshot + { + get => _screenshot; + set + { + _screenshot = value; + OnPropertyChanged(); + } + } + + private Key _showUI; + public Key ShowUI + { + get => _showUI; + set + { + _showUI = value; + OnPropertyChanged(); + } + } + + private Key _pause; + public Key Pause + { + get => _pause; + set + { + _pause = value; + OnPropertyChanged(); + } + } + + private Key _toggleMute; + public Key ToggleMute + { + get => _toggleMute; + set + { + _toggleMute = value; + OnPropertyChanged(); + } + } + + private Key _resScaleUp; + public Key ResScaleUp + { + get => _resScaleUp; + set + { + _resScaleUp = value; + OnPropertyChanged(); + } + } + + private Key _resScaleDown; + public Key ResScaleDown + { + get => _resScaleDown; + set + { + _resScaleDown = value; + OnPropertyChanged(); + } + } + + private Key _volumeUp; + public Key VolumeUp + { + get => _volumeUp; + set + { + _volumeUp = value; + OnPropertyChanged(); + } + } + + private Key _volumeDown; + public Key VolumeDown + { + get => _volumeDown; + set + { + _volumeDown = value; + OnPropertyChanged(); + } + } + + public HotkeyConfig(KeyboardHotkeys config) + { + if (config != null) + { + ToggleVsync = config.ToggleVsync; + Screenshot = config.Screenshot; + ShowUI = config.ShowUI; + Pause = config.Pause; + ToggleMute = config.ToggleMute; + ResScaleUp = config.ResScaleUp; + ResScaleDown = config.ResScaleDown; + VolumeUp = config.VolumeUp; + VolumeDown = config.VolumeDown; + } + } + + public KeyboardHotkeys GetConfig() + { + var config = new KeyboardHotkeys + { + ToggleVsync = ToggleVsync, + Screenshot = Screenshot, + ShowUI = ShowUI, + Pause = Pause, + ToggleMute = ToggleMute, + ResScaleUp = ResScaleUp, + ResScaleDown = ResScaleDown, + VolumeUp = VolumeUp, + VolumeDown = VolumeDown, + }; + + return config; + } + } +} diff --git a/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs b/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs new file mode 100644 index 000000000..104cd9d8f --- /dev/null +++ b/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs @@ -0,0 +1,448 @@ +using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Common.Configuration.Hid; +using Ryujinx.Common.Configuration.Hid.Keyboard; + +namespace Ryujinx.Ava.UI.Models.Input +{ + public class KeyboardInputConfig : BaseModel + { + public string Id { get; set; } + public ControllerType ControllerType { get; set; } + public PlayerIndex PlayerIndex { get; set; } + + private Key _leftStickUp; + public Key LeftStickUp + { + get => _leftStickUp; + set + { + _leftStickUp = value; + OnPropertyChanged(); + } + } + + private Key _leftStickDown; + public Key LeftStickDown + { + get => _leftStickDown; + set + { + _leftStickDown = value; + OnPropertyChanged(); + } + } + + private Key _leftStickLeft; + public Key LeftStickLeft + { + get => _leftStickLeft; + set + { + _leftStickLeft = value; + OnPropertyChanged(); + } + } + + private Key _leftStickRight; + public Key LeftStickRight + { + get => _leftStickRight; + set + { + _leftStickRight = value; + OnPropertyChanged(); + } + } + + private Key _leftStickButton; + public Key LeftStickButton + { + get => _leftStickButton; + set + { + _leftStickButton = value; + OnPropertyChanged(); + } + } + + private Key _rightStickUp; + public Key RightStickUp + { + get => _rightStickUp; + set + { + _rightStickUp = value; + OnPropertyChanged(); + } + } + + private Key _rightStickDown; + public Key RightStickDown + { + get => _rightStickDown; + set + { + _rightStickDown = value; + OnPropertyChanged(); + } + } + + private Key _rightStickLeft; + public Key RightStickLeft + { + get => _rightStickLeft; + set + { + _rightStickLeft = value; + OnPropertyChanged(); + } + } + + private Key _rightStickRight; + public Key RightStickRight + { + get => _rightStickRight; + set + { + _rightStickRight = value; + OnPropertyChanged(); + } + } + + private Key _rightStickButton; + public Key RightStickButton + { + get => _rightStickButton; + set + { + _rightStickButton = value; + OnPropertyChanged(); + } + } + + private Key _dpadUp; + public Key DpadUp + { + get => _dpadUp; + set + { + _dpadUp = value; + OnPropertyChanged(); + } + } + + private Key _dpadDown; + public Key DpadDown + { + get => _dpadDown; + set + { + _dpadDown = value; + OnPropertyChanged(); + } + } + + private Key _dpadLeft; + public Key DpadLeft + { + get => _dpadLeft; + set + { + _dpadLeft = value; + OnPropertyChanged(); + } + } + + private Key _dpadRight; + public Key DpadRight + { + get => _dpadRight; + set + { + _dpadRight = value; + OnPropertyChanged(); + } + } + + private Key _buttonL; + public Key ButtonL + { + get => _buttonL; + set + { + _buttonL = value; + OnPropertyChanged(); + } + } + + private Key _buttonMinus; + public Key ButtonMinus + { + get => _buttonMinus; + set + { + _buttonMinus = value; + OnPropertyChanged(); + } + } + + private Key _leftButtonSl; + public Key LeftButtonSl + { + get => _leftButtonSl; + set + { + _leftButtonSl = value; + OnPropertyChanged(); + } + } + + private Key _leftButtonSr; + public Key LeftButtonSr + { + get => _leftButtonSr; + set + { + _leftButtonSr = value; + OnPropertyChanged(); + } + } + + private Key _buttonZl; + public Key ButtonZl + { + get => _buttonZl; + set + { + _buttonZl = value; + OnPropertyChanged(); + } + } + + private Key _buttonCapture; + public Key ButtonCapture + { + get => _buttonCapture; + set + { + _buttonCapture = value; + OnPropertyChanged(); + } + } + + private Key _buttonA; + public Key ButtonA + { + get => _buttonA; + set + { + _buttonA = value; + OnPropertyChanged(); + } + } + + private Key _buttonB; + public Key ButtonB + { + get => _buttonB; + set + { + _buttonB = value; + OnPropertyChanged(); + } + } + + private Key _buttonX; + public Key ButtonX + { + get => _buttonX; + set + { + _buttonX = value; + OnPropertyChanged(); + } + } + + private Key _buttonY; + public Key ButtonY + { + get => _buttonY; + set + { + _buttonY = value; + OnPropertyChanged(); + } + } + + private Key _buttonR; + public Key ButtonR + { + get => _buttonR; + set + { + _buttonR = value; + OnPropertyChanged(); + } + } + + private Key _buttonPlus; + public Key ButtonPlus + { + get => _buttonPlus; + set + { + _buttonPlus = value; + OnPropertyChanged(); + } + } + + private Key _rightButtonSl; + public Key RightButtonSl + { + get => _rightButtonSl; + set + { + _rightButtonSl = value; + OnPropertyChanged(); + } + } + + private Key _rightButtonSr; + public Key RightButtonSr + { + get => _rightButtonSr; + set + { + _rightButtonSr = value; + OnPropertyChanged(); + } + } + + private Key _buttonZr; + public Key ButtonZr + { + get => _buttonZr; + set + { + _buttonZr = value; + OnPropertyChanged(); + } + } + + private Key _buttonHome; + public Key ButtonHome + { + get => _buttonHome; + set + { + _buttonHome = value; + OnPropertyChanged(); + } + } + + public KeyboardInputConfig(InputConfig config) + { + if (config != null) + { + Id = config.Id; + ControllerType = config.ControllerType; + PlayerIndex = config.PlayerIndex; + + if (config is not StandardKeyboardInputConfig keyboardConfig) + { + return; + } + + LeftStickUp = keyboardConfig.LeftJoyconStick.StickUp; + LeftStickDown = keyboardConfig.LeftJoyconStick.StickDown; + LeftStickLeft = keyboardConfig.LeftJoyconStick.StickLeft; + LeftStickRight = keyboardConfig.LeftJoyconStick.StickRight; + LeftStickButton = keyboardConfig.LeftJoyconStick.StickButton; + + RightStickUp = keyboardConfig.RightJoyconStick.StickUp; + RightStickDown = keyboardConfig.RightJoyconStick.StickDown; + RightStickLeft = keyboardConfig.RightJoyconStick.StickLeft; + RightStickRight = keyboardConfig.RightJoyconStick.StickRight; + RightStickButton = keyboardConfig.RightJoyconStick.StickButton; + + DpadUp = keyboardConfig.LeftJoycon.DpadUp; + DpadDown = keyboardConfig.LeftJoycon.DpadDown; + DpadLeft = keyboardConfig.LeftJoycon.DpadLeft; + DpadRight = keyboardConfig.LeftJoycon.DpadRight; + ButtonL = keyboardConfig.LeftJoycon.ButtonL; + ButtonMinus = keyboardConfig.LeftJoycon.ButtonMinus; + LeftButtonSl = keyboardConfig.LeftJoycon.ButtonSl; + LeftButtonSr = keyboardConfig.LeftJoycon.ButtonSr; + ButtonZl = keyboardConfig.LeftJoycon.ButtonZl; + ButtonCapture = keyboardConfig.LeftJoycon.ButtonCapture; + + ButtonA = keyboardConfig.RightJoycon.ButtonA; + ButtonB = keyboardConfig.RightJoycon.ButtonB; + ButtonX = keyboardConfig.RightJoycon.ButtonX; + ButtonY = keyboardConfig.RightJoycon.ButtonY; + ButtonR = keyboardConfig.RightJoycon.ButtonR; + ButtonPlus = keyboardConfig.RightJoycon.ButtonPlus; + RightButtonSl = keyboardConfig.RightJoycon.ButtonSl; + RightButtonSr = keyboardConfig.RightJoycon.ButtonSr; + ButtonZr = keyboardConfig.RightJoycon.ButtonZr; + ButtonHome = keyboardConfig.RightJoycon.ButtonHome; + } + } + + public InputConfig GetConfig() + { + var config = new StandardKeyboardInputConfig + { + Id = Id, + Backend = InputBackendType.WindowKeyboard, + PlayerIndex = PlayerIndex, + ControllerType = ControllerType, + LeftJoycon = new LeftJoyconCommonConfig + { + DpadUp = DpadUp, + DpadDown = DpadDown, + DpadLeft = DpadLeft, + DpadRight = DpadRight, + ButtonL = ButtonL, + ButtonMinus = ButtonMinus, + ButtonZl = ButtonZl, + ButtonSl = LeftButtonSl, + ButtonSr = LeftButtonSr, + ButtonCapture = ButtonCapture, + }, + RightJoycon = new RightJoyconCommonConfig + { + ButtonA = ButtonA, + ButtonB = ButtonB, + ButtonX = ButtonX, + ButtonY = ButtonY, + ButtonPlus = ButtonPlus, + ButtonSl = RightButtonSl, + ButtonSr = RightButtonSr, + ButtonR = ButtonR, + ButtonZr = ButtonZr, + ButtonHome = ButtonHome, + }, + LeftJoyconStick = new JoyconConfigKeyboardStick + { + StickUp = LeftStickUp, + StickDown = LeftStickDown, + StickRight = LeftStickRight, + StickLeft = LeftStickLeft, + StickButton = LeftStickButton, + }, + RightJoyconStick = new JoyconConfigKeyboardStick + { + StickUp = RightStickUp, + StickDown = RightStickDown, + StickLeft = RightStickLeft, + StickRight = RightStickRight, + StickButton = RightStickButton, + }, + Version = InputConfig.CurrentVersion, + }; + + return config; + } + } +} diff --git a/src/Ryujinx/UI/Models/ModModel.cs b/src/Ryujinx/UI/Models/ModModel.cs new file mode 100644 index 000000000..ee28ca5f5 --- /dev/null +++ b/src/Ryujinx/UI/Models/ModModel.cs @@ -0,0 +1,32 @@ +using Ryujinx.Ava.UI.ViewModels; +using System.IO; + +namespace Ryujinx.Ava.UI.Models +{ + public class ModModel : BaseModel + { + private bool _enabled; + + public bool Enabled + { + get => _enabled; + set + { + _enabled = value; + OnPropertyChanged(); + } + } + + public bool InSd { get; } + public string Path { get; } + public string Name { get; } + + public ModModel(string path, string name, bool enabled, bool inSd) + { + Path = path; + Name = name; + Enabled = enabled; + InSd = inSd; + } + } +} diff --git a/src/Ryujinx.Ava/UI/Models/PlayerModel.cs b/src/Ryujinx/UI/Models/PlayerModel.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Models/PlayerModel.cs rename to src/Ryujinx/UI/Models/PlayerModel.cs diff --git a/src/Ryujinx.Ava/UI/Models/ProfileImageModel.cs b/src/Ryujinx/UI/Models/ProfileImageModel.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Models/ProfileImageModel.cs rename to src/Ryujinx/UI/Models/ProfileImageModel.cs diff --git a/src/Ryujinx.Ava/UI/Models/SaveModel.cs b/src/Ryujinx/UI/Models/SaveModel.cs similarity index 94% rename from src/Ryujinx.Ava/UI/Models/SaveModel.cs rename to src/Ryujinx/UI/Models/SaveModel.cs index 7b476932b..181295b06 100644 --- a/src/Ryujinx.Ava/UI/Models/SaveModel.cs +++ b/src/Ryujinx/UI/Models/SaveModel.cs @@ -3,8 +3,8 @@ using LibHac.Ncm; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.Windows; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common.Helper; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -46,14 +46,14 @@ namespace Ryujinx.Ava.UI.Models TitleId = info.ProgramId; UserId = info.UserId; - var appData = MainWindow.MainWindowViewModel.Applications.FirstOrDefault(x => x.TitleId.ToUpper() == TitleIdString); + var appData = MainWindow.MainWindowViewModel.Applications.FirstOrDefault(x => x.IdString.ToUpper() == TitleIdString); InGameList = appData != null; if (InGameList) { Icon = appData.Icon; - Title = appData.TitleName; + Title = appData.Name; } else { diff --git a/src/Ryujinx/UI/Models/StatusInitEventArgs.cs b/src/Ryujinx/UI/Models/StatusInitEventArgs.cs new file mode 100644 index 000000000..4b08737e9 --- /dev/null +++ b/src/Ryujinx/UI/Models/StatusInitEventArgs.cs @@ -0,0 +1,16 @@ +using System; + +namespace Ryujinx.Ava.UI.Models +{ + internal class StatusInitEventArgs : EventArgs + { + public string GpuBackend { get; } + public string GpuName { get; } + + public StatusInitEventArgs(string gpuBackend, string gpuName) + { + GpuBackend = gpuBackend; + GpuName = gpuName; + } + } +} diff --git a/src/Ryujinx.Ava/UI/Models/StatusUpdatedEventArgs.cs b/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs similarity index 71% rename from src/Ryujinx.Ava/UI/Models/StatusUpdatedEventArgs.cs rename to src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs index 7f04c0eed..ee5648faf 100644 --- a/src/Ryujinx.Ava/UI/Models/StatusUpdatedEventArgs.cs +++ b/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs @@ -6,23 +6,19 @@ namespace Ryujinx.Ava.UI.Models { public bool VSyncEnabled { get; } public string VolumeStatus { get; } - public string GpuBackend { get; } public string AspectRatio { get; } public string DockedMode { get; } public string FifoStatus { get; } public string GameStatus { get; } - public string GpuName { get; } - public StatusUpdatedEventArgs(bool vSyncEnabled, string volumeStatus, string gpuBackend, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus, string gpuName) + public StatusUpdatedEventArgs(bool vSyncEnabled, string volumeStatus, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus) { VSyncEnabled = vSyncEnabled; VolumeStatus = volumeStatus; - GpuBackend = gpuBackend; DockedMode = dockedMode; AspectRatio = aspectRatio; GameStatus = gameStatus; FifoStatus = fifoStatus; - GpuName = gpuName; } } } diff --git a/src/Ryujinx.Ava/UI/Models/TempProfile.cs b/src/Ryujinx/UI/Models/TempProfile.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Models/TempProfile.cs rename to src/Ryujinx/UI/Models/TempProfile.cs diff --git a/src/Ryujinx.Ava/UI/Models/TimeZone.cs b/src/Ryujinx/UI/Models/TimeZone.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Models/TimeZone.cs rename to src/Ryujinx/UI/Models/TimeZone.cs diff --git a/src/Ryujinx/UI/Models/TitleUpdateModel.cs b/src/Ryujinx/UI/Models/TitleUpdateModel.cs new file mode 100644 index 000000000..46f6f46d8 --- /dev/null +++ b/src/Ryujinx/UI/Models/TitleUpdateModel.cs @@ -0,0 +1,21 @@ +using Ryujinx.Ava.Common.Locale; + +namespace Ryujinx.Ava.UI.Models +{ + public class TitleUpdateModel + { + public uint Version { get; } + public string Path { get; } + public string Label { get; } + + public TitleUpdateModel(uint version, string displayVersion, string path) + { + Version = version; + Label = LocaleManager.Instance.UpdateAndGetDynamicValue( + System.IO.Path.GetExtension(path)?.ToLower() == ".xci" ? LocaleKeys.TitleBundledUpdateVersionLabel : LocaleKeys.TitleUpdateVersionLabel, + displayVersion + ); + Path = path; + } + } +} diff --git a/src/Ryujinx.Ava/UI/Models/UserProfile.cs b/src/Ryujinx/UI/Models/UserProfile.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Models/UserProfile.cs rename to src/Ryujinx/UI/Models/UserProfile.cs diff --git a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindow.cs b/src/Ryujinx/UI/Renderer/EmbeddedWindow.cs similarity index 61% rename from src/Ryujinx.Ava/UI/Renderer/EmbeddedWindow.cs rename to src/Ryujinx/UI/Renderer/EmbeddedWindow.cs index fa55c8d3f..0930e7795 100644 --- a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindow.cs +++ b/src/Ryujinx/UI/Renderer/EmbeddedWindow.cs @@ -3,8 +3,8 @@ using Avalonia.Controls; using Avalonia.Input; using Avalonia.Platform; using Ryujinx.Common.Configuration; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using SPB.Graphics; using SPB.Platform; using SPB.Platform.GLX; @@ -141,80 +141,10 @@ namespace Ryujinx.Ava.UI.Renderer _wndProcDelegate = delegate (IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam) { - if (VisualRoot != null) + switch (msg) { - if (msg == WindowsMessages.Lbuttondown || - msg == WindowsMessages.Rbuttondown || - msg == WindowsMessages.Lbuttonup || - msg == WindowsMessages.Rbuttonup || - msg == WindowsMessages.Mousemove) - { - Point rootVisualPosition = this.TranslatePoint(new Point((long)lParam & 0xFFFF, (long)lParam >> 16 & 0xFFFF), this).Value; - Pointer pointer = new(0, PointerType.Mouse, true); - -#pragma warning disable CS0618 // Type or member is obsolete (As of Avalonia 11, the constructors for PointerPressedEventArgs & PointerEventArgs are marked as obsolete) - switch (msg) - { - case WindowsMessages.Lbuttondown: - case WindowsMessages.Rbuttondown: - { - bool isLeft = msg == WindowsMessages.Lbuttondown; - RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton; - PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonPressed : PointerUpdateKind.RightButtonPressed); - - var evnt = new PointerPressedEventArgs( - this, - pointer, - this, - rootVisualPosition, - (ulong)Environment.TickCount64, - properties, - KeyModifiers.None); - - RaiseEvent(evnt); - - break; - } - case WindowsMessages.Lbuttonup: - case WindowsMessages.Rbuttonup: - { - bool isLeft = msg == WindowsMessages.Lbuttonup; - RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton; - PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonReleased : PointerUpdateKind.RightButtonReleased); - - var evnt = new PointerReleasedEventArgs( - this, - pointer, - this, - rootVisualPosition, - (ulong)Environment.TickCount64, - properties, - KeyModifiers.None, - isLeft ? MouseButton.Left : MouseButton.Right); - - RaiseEvent(evnt); - - break; - } - case WindowsMessages.Mousemove: - { - var evnt = new PointerEventArgs( - PointerMovedEvent, - this, - pointer, - this, - rootVisualPosition, - (ulong)Environment.TickCount64, - new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.Other), - KeyModifiers.None); - - RaiseEvent(evnt); - - break; - } - } -#pragma warning restore CS0618 - } + case WindowsMessages.NcHitTest: + return -1; } return DefWindowProc(hWnd, msg, wParam, lParam); @@ -227,13 +157,15 @@ namespace Ryujinx.Ava.UI.Renderer lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate), style = ClassStyles.CsOwndc, lpszClassName = Marshal.StringToHGlobalUni(_className), - hCursor = CreateArrowCursor(), + hCursor = CreateArrowCursor() }; RegisterClassEx(ref wndClassEx); WindowHandle = CreateWindowEx(0, _className, "NativeWindow", WindowStyles.WsChild, 0, 0, 640, 480, control.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + SetWindowLongPtrW(control.Handle, GWLP_WNDPROC, wndClassEx.lpfnWndProc); + Marshal.FreeHGlobal(wndClassEx.lpszClassName); return new PlatformHandle(WindowHandle, "HWND"); diff --git a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowOpenGL.cs b/src/Ryujinx/UI/Renderer/EmbeddedWindowOpenGL.cs similarity index 96% rename from src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowOpenGL.cs rename to src/Ryujinx/UI/Renderer/EmbeddedWindowOpenGL.cs index 769a1c91a..3842301de 100644 --- a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowOpenGL.cs +++ b/src/Ryujinx/UI/Renderer/EmbeddedWindowOpenGL.cs @@ -3,7 +3,7 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.OpenGL; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using SPB.Graphics; using SPB.Graphics.Exceptions; using SPB.Graphics.OpenGL; @@ -75,7 +75,7 @@ namespace Ryujinx.Ava.UI.Renderer throw; } - Logger.Warning?.Print(LogClass.Ui, $"Failed to {(!unbind ? "bind" : "unbind")} OpenGL context: {e}"); + Logger.Warning?.Print(LogClass.UI, $"Failed to {(!unbind ? "bind" : "unbind")} OpenGL context: {e}"); } } diff --git a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowVulkan.cs b/src/Ryujinx/UI/Renderer/EmbeddedWindowVulkan.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowVulkan.cs rename to src/Ryujinx/UI/Renderer/EmbeddedWindowVulkan.cs diff --git a/src/Ryujinx.Ava/UI/Renderer/OpenTKBindingsContext.cs b/src/Ryujinx/UI/Renderer/OpenTKBindingsContext.cs similarity index 100% rename from src/Ryujinx.Ava/UI/Renderer/OpenTKBindingsContext.cs rename to src/Ryujinx/UI/Renderer/OpenTKBindingsContext.cs diff --git a/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml b/src/Ryujinx/UI/Renderer/RendererHost.axaml similarity index 76% rename from src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml rename to src/Ryujinx/UI/Renderer/RendererHost.axaml index bb96b10d2..e0b586b45 100644 --- a/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml +++ b/src/Ryujinx/UI/Renderer/RendererHost.axaml @@ -1,11 +1,12 @@ - - \ No newline at end of file + diff --git a/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml.cs b/src/Ryujinx/UI/Renderer/RendererHost.axaml.cs similarity index 97% rename from src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml.cs rename to src/Ryujinx/UI/Renderer/RendererHost.axaml.cs index 12c18e4a7..d055d9ea4 100644 --- a/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml.cs +++ b/src/Ryujinx/UI/Renderer/RendererHost.axaml.cs @@ -1,7 +1,7 @@ using Avalonia; using Avalonia.Controls; using Ryujinx.Common.Configuration; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System; namespace Ryujinx.Ava.UI.Renderer diff --git a/src/Ryujinx.Ava/UI/Renderer/SPBOpenGLContext.cs b/src/Ryujinx/UI/Renderer/SPBOpenGLContext.cs similarity index 96% rename from src/Ryujinx.Ava/UI/Renderer/SPBOpenGLContext.cs rename to src/Ryujinx/UI/Renderer/SPBOpenGLContext.cs index 5ff756f24..63bf6cf7c 100644 --- a/src/Ryujinx.Ava/UI/Renderer/SPBOpenGLContext.cs +++ b/src/Ryujinx/UI/Renderer/SPBOpenGLContext.cs @@ -29,6 +29,8 @@ namespace Ryujinx.Ava.UI.Renderer _context.MakeCurrent(_window); } + public bool HasContext() => _context.IsCurrent; + public static SPBOpenGLContext CreateBackgroundContext(OpenGLContextBase sharedContext) { OpenGLContextBase context = PlatformHelper.CreateOpenGLContext(FramebufferFormat.Default, 3, 3, OpenGLContextFlags.Compat, true, sharedContext); diff --git a/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs similarity index 64% rename from src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs rename to src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs index 70ede4c12..f8fd5b7de 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs @@ -1,9 +1,11 @@ using Avalonia.Media.Imaging; using Avalonia.Platform; +using Avalonia.Styling; using Avalonia.Threading; +using Ryujinx.Ava.Common; using Ryujinx.Ava.Common.Locale; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System; using System.Net.Http; using System.Net.NetworkInformation; @@ -11,7 +13,7 @@ using System.Threading.Tasks; namespace Ryujinx.Ava.UI.ViewModels { - public class AboutWindowViewModel : BaseModel + public class AboutWindowViewModel : BaseModel, IDisposable { private Bitmap _githubLogo; private Bitmap _discordLogo; @@ -86,23 +88,39 @@ namespace Ryujinx.Ava.UI.ViewModels public AboutWindowViewModel() { Version = Program.Version; - - if (ConfigurationState.Instance.Ui.BaseStyle.Value == "Light") - { - GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_GitHub_Light.png?assembly=Ryujinx.Ui.Common"))); - DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Discord_Light.png?assembly=Ryujinx.Ui.Common"))); - PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Patreon_Light.png?assembly=Ryujinx.Ui.Common"))); - TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Twitter_Light.png?assembly=Ryujinx.Ui.Common"))); - } - else - { - GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_GitHub_Dark.png?assembly=Ryujinx.Ui.Common"))); - DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Discord_Dark.png?assembly=Ryujinx.Ui.Common"))); - PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Patreon_Dark.png?assembly=Ryujinx.Ui.Common"))); - TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Twitter_Dark.png?assembly=Ryujinx.Ui.Common"))); - } - + UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value); Dispatcher.UIThread.InvokeAsync(DownloadPatronsJson); + + ThemeManager.ThemeChanged += ThemeManager_ThemeChanged; + } + + private void ThemeManager_ThemeChanged(object sender, EventArgs e) + { + Dispatcher.UIThread.Post(() => UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value)); + } + + private void UpdateLogoTheme(string theme) + { + bool isDarkTheme = theme == "Dark" || (theme == "Auto" && App.DetectSystemTheme() == ThemeVariant.Dark); + + string basePath = "resm:Ryujinx.UI.Common.Resources."; + string themeSuffix = isDarkTheme ? "Dark.png" : "Light.png"; + + GithubLogo = LoadBitmap($"{basePath}Logo_GitHub_{themeSuffix}?assembly=Ryujinx.UI.Common"); + DiscordLogo = LoadBitmap($"{basePath}Logo_Discord_{themeSuffix}?assembly=Ryujinx.UI.Common"); + PatreonLogo = LoadBitmap($"{basePath}Logo_Patreon_{themeSuffix}?assembly=Ryujinx.UI.Common"); + TwitterLogo = LoadBitmap($"{basePath}Logo_Twitter_{themeSuffix}?assembly=Ryujinx.UI.Common"); + } + + private Bitmap LoadBitmap(string uri) + { + return new Bitmap(Avalonia.Platform.AssetLoader.Open(new Uri(uri))); + } + + public void Dispose() + { + ThemeManager.ThemeChanged -= ThemeManager_ThemeChanged; + GC.SuppressFinalize(this); } private async Task DownloadPatronsJson() diff --git a/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs similarity index 80% rename from src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs rename to src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs index c41e8bcc2..8f09568a6 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs @@ -9,7 +9,7 @@ using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Models.Amiibo; +using Ryujinx.UI.Common.Models.Amiibo; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -17,6 +17,7 @@ using System.IO; using System.Linq; using System.Net.Http; using System.Text; +using System.Text.Json; using System.Threading.Tasks; namespace Ryujinx.Ava.UI.ViewModels @@ -64,7 +65,7 @@ namespace Ryujinx.Ava.UI.ViewModels _amiiboSeries = new ObservableCollection(); _amiibos = new AvaloniaList(); - _amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png"); + _amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.UI.Common/Resources/Logo_Amiibo.png"); _ = LoadContentAsync(); } @@ -188,17 +189,25 @@ namespace Ryujinx.Ava.UI.ViewModels _httpClient.Dispose(); } - private bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson) + private static bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson) { + if (string.IsNullOrEmpty(json)) + { + amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson); + + return false; + } + try { - amiiboJson = JsonHelper.Deserialize(json, _serializerContext.AmiiboJson); + amiiboJson = JsonHelper.Deserialize(json, _serializerContext.AmiiboJson); return true; } - catch + catch (JsonException exception) { - amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson); + Logger.Error?.Print(LogClass.Application, $"Unable to deserialize amiibo data: {exception}"); + amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson); return false; } @@ -208,27 +217,41 @@ namespace Ryujinx.Ava.UI.ViewModels { bool localIsValid = false; bool remoteIsValid = false; - AmiiboJson amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson); + AmiiboJson amiiboJson = new(); try { - localIsValid = TryGetAmiiboJson(File.ReadAllText(_amiiboJsonPath), out amiiboJson); + try + { + if (File.Exists(_amiiboJsonPath)) + { + localIsValid = TryGetAmiiboJson(await File.ReadAllTextAsync(_amiiboJsonPath), out amiiboJson); + } + } + catch (Exception exception) + { + Logger.Warning?.Print(LogClass.Application, $"Unable to read data from '{_amiiboJsonPath}': {exception}"); + } if (!localIsValid || await NeedsUpdate(amiiboJson.LastUpdated)) { remoteIsValid = TryGetAmiiboJson(await DownloadAmiiboJson(), out amiiboJson); } } - catch + catch (Exception exception) { if (!(localIsValid || remoteIsValid)) { + Logger.Error?.Print(LogClass.Application, $"Couldn't get valid amiibo data: {exception}"); + // Neither local or remote files are valid JSON, close window. ShowInfoDialog(); Close(); } else if (!remoteIsValid) { + Logger.Warning?.Print(LogClass.Application, $"Couldn't update amiibo data: {exception}"); + // Only the local file is valid, the local one should be used // but the user should be warned. ShowInfoDialog(); @@ -388,11 +411,18 @@ namespace Ryujinx.Ava.UI.ViewModels private async Task NeedsUpdate(DateTime oldLastModified) { - HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/")); - - if (response.IsSuccessStatusCode) + try { - return response.Content.Headers.LastModified != oldLastModified; + HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/")); + + if (response.IsSuccessStatusCode) + { + return response.Content.Headers.LastModified != oldLastModified; + } + } + catch (HttpRequestException exception) + { + Logger.Error?.Print(LogClass.Application, $"Unable to check for amiibo data updates: {exception}"); } return false; @@ -400,21 +430,33 @@ namespace Ryujinx.Ava.UI.ViewModels private async Task DownloadAmiiboJson() { - HttpResponseMessage response = await _httpClient.GetAsync("https://amiibo.ryujinx.org/"); - - if (response.IsSuccessStatusCode) + try { - string amiiboJsonString = await response.Content.ReadAsStringAsync(); + HttpResponseMessage response = await _httpClient.GetAsync("https://amiibo.ryujinx.org/"); - using (FileStream amiiboJsonStream = File.Create(_amiiboJsonPath, 4096, FileOptions.WriteThrough)) + if (response.IsSuccessStatusCode) { - amiiboJsonStream.Write(Encoding.UTF8.GetBytes(amiiboJsonString)); + string amiiboJsonString = await response.Content.ReadAsStringAsync(); + + try + { + using FileStream dlcJsonStream = File.Create(_amiiboJsonPath, 4096, FileOptions.WriteThrough); + dlcJsonStream.Write(Encoding.UTF8.GetBytes(amiiboJsonString)); + } + catch (Exception exception) + { + Logger.Warning?.Print(LogClass.Application, $"Couldn't write amiibo data to file '{_amiiboJsonPath}: {exception}'"); + } + + return amiiboJsonString; } - return amiiboJsonString; + Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data. Response status code: {response.StatusCode}"); + } + catch (HttpRequestException exception) + { + Logger.Error?.Print(LogClass.Application, $"Failed to request amiibo data: {exception}"); } - - Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data. Response status code: {response.StatusCode}"); await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle], LocaleManager.Instance[LocaleKeys.DialogAmiiboApiFailFetchMessage], @@ -422,9 +464,7 @@ namespace Ryujinx.Ava.UI.ViewModels "", LocaleManager.Instance[LocaleKeys.RyujinxInfo]); - Close(); - - return DefaultJson; + return null; } private void Close() diff --git a/src/Ryujinx/UI/ViewModels/AppListFavoriteComparable.cs b/src/Ryujinx/UI/ViewModels/AppListFavoriteComparable.cs new file mode 100644 index 000000000..e80984508 --- /dev/null +++ b/src/Ryujinx/UI/ViewModels/AppListFavoriteComparable.cs @@ -0,0 +1,43 @@ +using Ryujinx.UI.App.Common; +using System; + +namespace Ryujinx.Ava.UI.ViewModels +{ + /// + /// Implements a custom comparer which is used for sorting titles by favorite on a UI. + /// Returns a sorted list of favorites in alphabetical order, followed by all non-favorites sorted alphabetical. + /// + public readonly struct AppListFavoriteComparable : IComparable + { + /// + /// The application data being compared. + /// + private readonly ApplicationData app; + + /// + /// Constructs a new with the specified application data. + /// + /// The app data being compared. + public AppListFavoriteComparable(ApplicationData app) + { + ArgumentNullException.ThrowIfNull(app, nameof(app)); + this.app = app; + } + + /// + public readonly int CompareTo(object o) + { + if (o is AppListFavoriteComparable other) + { + if (app.Favorite == other.app.Favorite) + { + return string.Compare(app.Name, other.app.Name, StringComparison.OrdinalIgnoreCase); + } + + return app.Favorite ? -1 : 1; + } + + throw new InvalidCastException($"Cannot cast {o.GetType()} to {nameof(AppListFavoriteComparable)}"); + } + } +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/BaseModel.cs b/src/Ryujinx/UI/ViewModels/BaseModel.cs similarity index 100% rename from src/Ryujinx.Ava/UI/ViewModels/BaseModel.cs rename to src/Ryujinx/UI/ViewModels/BaseModel.cs diff --git a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs similarity index 82% rename from src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs rename to src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs index cdecae77d..c919a7ad1 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs @@ -6,7 +6,6 @@ using DynamicData; using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; -using LibHac.FsSystem; using LibHac.Tools.Fs; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; @@ -17,11 +16,13 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.Loaders.Processes.Extensions; +using Ryujinx.HLE.Utilities; +using Ryujinx.UI.App.Common; using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Threading.Tasks; using Application = Avalonia.Application; using Path = System.IO.Path; @@ -38,7 +39,8 @@ namespace Ryujinx.Ava.UI.ViewModels private AvaloniaList _selectedDownloadableContents = new(); private string _search; - private readonly ulong _titleId; + private readonly ApplicationData _applicationData; + private readonly IStorageProvider _storageProvider; private static readonly DownloadableContentJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); @@ -90,20 +92,25 @@ namespace Ryujinx.Ava.UI.ViewModels get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count); } - public IStorageProvider StorageProvider; - - public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ulong titleId) + public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ApplicationData applicationData) { _virtualFileSystem = virtualFileSystem; - _titleId = titleId; + _applicationData = applicationData; if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - StorageProvider = desktop.MainWindow.StorageProvider; + _storageProvider = desktop.MainWindow.StorageProvider; } - _downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json"); + _downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationData.IdBaseString, "dlc.json"); + + if (!File.Exists(_downloadableContentJsonPath)) + { + _downloadableContentContainerList = new List(); + + Save(); + } try { @@ -124,12 +131,7 @@ namespace Ryujinx.Ava.UI.ViewModels { if (File.Exists(downloadableContentContainer.ContainerPath)) { - using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath); - - PartitionFileSystem partitionFileSystem = new(); - partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure(); - - _virtualFileSystem.ImportTickets(partitionFileSystem); + using IFileSystem partitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(downloadableContentContainer.ContainerPath, _virtualFileSystem); foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList) { @@ -158,6 +160,9 @@ namespace Ryujinx.Ava.UI.ViewModels } } + // NOTE: Try to load downloadable contents from PFS last to preserve enabled state. + AddDownloadableContent(_applicationData.Path); + // NOTE: Save the list again to remove leftovers. Save(); Sort(); @@ -194,7 +199,7 @@ namespace Ryujinx.Ava.UI.ViewModels { Dispatcher.UIThread.InvokeAsync(async () => { - await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogLoadNcaErrorMessage], ex.Message, containerPath)); + await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogLoadFileErrorMessage], ex.Message, containerPath)); }); } @@ -203,7 +208,7 @@ namespace Ryujinx.Ava.UI.ViewModels public async void Add() { - var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions + var result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle], AllowMultiple = true, @@ -220,25 +225,23 @@ namespace Ryujinx.Ava.UI.ViewModels foreach (var file in result) { - await AddDownloadableContent(file.Path.LocalPath); + if (!AddDownloadableContent(file.Path.LocalPath)) + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogDlcNoDlcErrorMessage]); + } } } - private async Task AddDownloadableContent(string path) + private bool AddDownloadableContent(string path) { - if (!File.Exists(path) || DownloadableContents.FirstOrDefault(x => x.ContainerPath == path) != null) + if (!File.Exists(path) || _downloadableContentContainerList.Any(x => x.ContainerPath == path)) { - return; + return true; } - using FileStream containerFile = File.OpenRead(path); - - PartitionFileSystem partitionFileSystem = new(); - partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure(); - bool containsDownloadableContent = false; - - _virtualFileSystem.ImportTickets(partitionFileSystem); + using IFileSystem partitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(path, _virtualFileSystem); + bool success = false; foreach (DirectoryEntryEx fileEntry in partitionFileSystem.EnumerateEntries("/", "*.nca")) { using var ncaFile = new UniqueRef(); @@ -253,26 +256,26 @@ namespace Ryujinx.Ava.UI.ViewModels if (nca.Header.ContentType == NcaContentType.PublicData) { - if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != _titleId) + if (nca.GetProgramIdBase() != _applicationData.IdBase) { - break; + continue; } var content = new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), path, fileEntry.FullPath, true); DownloadableContents.Add(content); - SelectedDownloadableContents.Add(content); + Dispatcher.UIThread.InvokeAsync(() => SelectedDownloadableContents.Add(content)); - OnPropertyChanged(nameof(UpdateCount)); - Sort(); - - containsDownloadableContent = true; + success = true; } } - if (!containsDownloadableContent) + if (success) { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogDlcNoDlcErrorMessage]); + OnPropertyChanged(nameof(UpdateCount)); + Sort(); } + + return success; } public void Remove(DownloadableContentModel model) diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs new file mode 100644 index 000000000..6ee79a371 --- /dev/null +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -0,0 +1,84 @@ +using Avalonia.Svg.Skia; +using Ryujinx.Ava.UI.Models.Input; +using Ryujinx.Ava.UI.Views.Input; + +namespace Ryujinx.Ava.UI.ViewModels.Input +{ + public class ControllerInputViewModel : BaseModel + { + private GamepadInputConfig _config; + public GamepadInputConfig Config + { + get => _config; + set + { + _config = value; + OnPropertyChanged(); + } + } + + private bool _isLeft; + public bool IsLeft + { + get => _isLeft; + set + { + _isLeft = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(HasSides)); + } + } + + private bool _isRight; + public bool IsRight + { + get => _isRight; + set + { + _isRight = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(HasSides)); + } + } + + public bool HasSides => IsLeft ^ IsRight; + + private SvgImage _image; + public SvgImage Image + { + get => _image; + set + { + _image = value; + OnPropertyChanged(); + } + } + + public readonly InputViewModel ParentModel; + + public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config) + { + ParentModel = model; + model.NotifyChangesEvent += OnParentModelChanged; + OnParentModelChanged(); + Config = config; + } + + public async void ShowMotionConfig() + { + await MotionInputView.Show(this); + } + + public async void ShowRumbleConfig() + { + await RumbleInputView.Show(this); + } + + public void OnParentModelChanged() + { + IsLeft = ParentModel.IsLeft; + IsRight = ParentModel.IsRight; + Image = ParentModel.Image; + } + } +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs similarity index 89% rename from src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs rename to src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 0177c7f96..2d1edf2e0 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -8,7 +8,7 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.Views.Input; +using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common; using Ryujinx.Common.Configuration; @@ -19,7 +19,7 @@ using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; using Ryujinx.Input; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -30,15 +30,15 @@ using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.Gamepad using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; using Key = Ryujinx.Common.Configuration.Hid.Key; -namespace Ryujinx.Ava.UI.ViewModels +namespace Ryujinx.Ava.UI.ViewModels.Input { - public class ControllerInputViewModel : BaseModel, IDisposable + public class InputViewModel : BaseModel, IDisposable { private const string Disabled = "disabled"; - private const string ProControllerResource = "Ryujinx.Ui.Common/Resources/Controller_ProCon.svg"; - private const string JoyConPairResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConPair.svg"; - private const string JoyConLeftResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConLeft.svg"; - private const string JoyConRightResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConRight.svg"; + private const string ProControllerResource = "Ryujinx.UI.Common/Resources/Controller_ProCon.svg"; + private const string JoyConPairResource = "Ryujinx.UI.Common/Resources/Controller_JoyConPair.svg"; + private const string JoyConLeftResource = "Ryujinx.UI.Common/Resources/Controller_JoyConLeft.svg"; + private const string JoyConRightResource = "Ryujinx.UI.Common/Resources/Controller_JoyConRight.svg"; private const string KeyboardString = "keyboard"; private const string ControllerString = "controller"; private readonly MainWindow _mainWindow; @@ -48,11 +48,10 @@ namespace Ryujinx.Ava.UI.ViewModels private int _controllerNumber; private string _controllerImage; private int _device; - private InputViewModel _configuration; + private object _configViewModel; private string _profileName; private bool _isLoaded; - private bool _isLeft; - private bool _isRight; + private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); public IGamepadDriver AvaloniaKeyboardDriver { get; } @@ -64,47 +63,24 @@ namespace Ryujinx.Ava.UI.ViewModels public AvaloniaList ProfilesList { get; set; } public AvaloniaList DeviceList { get; set; } - public event EventHandler ConfigurationChanged; - // XAML Flags public bool ShowSettings => _device > 0; public bool IsController => _device > 1; public bool IsKeyboard => !IsController; - public bool IsRight - { - get => _isRight; set - { - _isRight = value; - - _configuration.IsRight = IsRight; - } - } - public bool IsLeft - { - get => _isLeft; set - { - _isLeft = value; - - _configuration.IsLeft = IsLeft; - } - } + public bool IsRight { get; set; } + public bool IsLeft { get; set; } public bool IsModified { get; set; } + public event Action NotifyChangesEvent; - public InputViewModel Configuration + public object ConfigViewModel { - get => _configuration; + get => _configViewModel; set { - _configuration = value; - - _configuration.IsLeft = IsLeft; - _configuration.IsRight = IsRight; - _configuration.ControllerImage = _controllerImage; + _configViewModel = value; OnPropertyChanged(); - - ConfigurationChanged?.Invoke(this, EventArgs.Empty); } } @@ -192,9 +168,25 @@ namespace Ryujinx.Ava.UI.ViewModels { _controllerImage = value; - if (_configuration != null) - _configuration.ControllerImage = value; OnPropertyChanged(); + OnPropertyChanged(nameof(Image)); + } + } + + public SvgImage Image + { + get + { + SvgImage image = new(); + + if (!string.IsNullOrWhiteSpace(_controllerImage)) + { + SvgSource source = SvgSource.LoadFromStream(EmbeddedResources.GetStream(_controllerImage)); + + image.Source = source; + } + + return image; } } @@ -239,7 +231,7 @@ namespace Ryujinx.Ava.UI.ViewModels public InputConfig Config { get; set; } - public ControllerInputViewModel(UserControl owner) : this() + public InputViewModel(UserControl owner) : this() { if (Program.PreviewerDetached) { @@ -262,7 +254,7 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public ControllerInputViewModel() + public InputViewModel() { PlayerIndexes = new ObservableCollection(); Controllers = new ObservableCollection(); @@ -289,12 +281,12 @@ namespace Ryujinx.Ava.UI.ViewModels if (Config is StandardKeyboardInputConfig keyboardInputConfig) { - Configuration = new KeyboardInputViewModel(new InputConfiguration(keyboardInputConfig)); + ConfigViewModel = new KeyboardInputViewModel(this, new KeyboardInputConfig(keyboardInputConfig)); } if (Config is StandardControllerInputConfig controllerInputConfig) { - Configuration = new GamePadInputViewModel(new InputConfiguration(controllerInputConfig), async () => { await MotionInputView.Show(this); }, async () => { await RumbleInputView.Show(this); }); + ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig)); } } @@ -557,6 +549,7 @@ namespace Ryujinx.Ava.UI.ViewModels ButtonZl = Key.Q, ButtonSl = Key.Unbound, ButtonSr = Key.Unbound, + ButtonCapture = Key.G, }, LeftJoyconStick = new JoyconConfigKeyboardStick @@ -578,6 +571,7 @@ namespace Ryujinx.Ava.UI.ViewModels ButtonZr = Key.O, ButtonSl = Key.Unbound, ButtonSr = Key.Unbound, + ButtonHome = Key.B, }, RightJoyconStick = new JoyconConfigKeyboardStick { @@ -617,6 +611,7 @@ namespace Ryujinx.Ava.UI.ViewModels ButtonZl = ConfigGamepadInputId.LeftTrigger, ButtonSl = ConfigGamepadInputId.Unbound, ButtonSr = ConfigGamepadInputId.Unbound, + ButtonCapture = ConfigGamepadInputId.Capture, }, LeftJoyconStick = new JoyconConfigControllerStick { @@ -636,6 +631,7 @@ namespace Ryujinx.Ava.UI.ViewModels ButtonZr = ConfigGamepadInputId.RightTrigger, ButtonSl = ConfigGamepadInputId.Unbound, ButtonSr = ConfigGamepadInputId.Unbound, + ButtonHome = ConfigGamepadInputId.Home, }, RightJoyconStick = new JoyconConfigControllerStick { @@ -737,7 +733,7 @@ namespace Ryujinx.Ava.UI.ViewModels return; } - if (Configuration == null) + if (ConfigViewModel == null) { return; } @@ -748,28 +744,37 @@ namespace Ryujinx.Ava.UI.ViewModels return; } - - bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; - - if (validFileName) - { - string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); - - InputConfig config = null; - - config = Configuration.GetConfig(); - - config.ControllerType = Controllers[_controller].Type; - - string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig); - - await File.WriteAllTextAsync(path, jsonString); - - LoadProfiles(); - } else { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]); + bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; + + if (validFileName) + { + string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); + + InputConfig config = null; + + if (IsKeyboard) + { + config = (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig(); + } + else if (IsController) + { + config = (ConfigViewModel as ControllerInputViewModel).Config.GetConfig(); + } + + config.ControllerType = Controllers[_controller].Type; + + string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig); + + await File.WriteAllTextAsync(path, jsonString); + + LoadProfiles(); + } + else + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]); + } } } @@ -820,16 +825,18 @@ namespace Ryujinx.Ava.UI.ViewModels if (device.Type == DeviceType.Keyboard) { - var inputConfig = Configuration.Config as InputConfiguration; + var inputConfig = (ConfigViewModel as KeyboardInputViewModel).Config; inputConfig.Id = device.Id; } else { - var inputConfig = Configuration.Config as InputConfiguration; + var inputConfig = (ConfigViewModel as ControllerInputViewModel).Config; inputConfig.Id = device.Id.Split(" ")[0]; } - var config = Configuration.GetConfig(); + var config = !IsController + ? (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig() + : (ConfigViewModel as ControllerInputViewModel).Config.GetConfig(); config.ControllerType = Controllers[_controller].Type; config.PlayerIndex = _playerId; @@ -860,14 +867,13 @@ namespace Ryujinx.Ava.UI.ViewModels public void NotifyChanges() { - OnPropertyChanged(nameof(Configuration)); + OnPropertyChanged(nameof(ConfigViewModel)); OnPropertyChanged(nameof(IsController)); OnPropertyChanged(nameof(ShowSettings)); OnPropertyChanged(nameof(IsKeyboard)); OnPropertyChanged(nameof(IsRight)); OnPropertyChanged(nameof(IsLeft)); - - Configuration?.NotifyChanges(); + NotifyChangesEvent?.Invoke(); } public void Dispose() diff --git a/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs new file mode 100644 index 000000000..0b530eb09 --- /dev/null +++ b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs @@ -0,0 +1,73 @@ +using Avalonia.Svg.Skia; +using Ryujinx.Ava.UI.Models.Input; + +namespace Ryujinx.Ava.UI.ViewModels.Input +{ + public class KeyboardInputViewModel : BaseModel + { + private KeyboardInputConfig _config; + public KeyboardInputConfig Config + { + get => _config; + set + { + _config = value; + OnPropertyChanged(); + } + } + + private bool _isLeft; + public bool IsLeft + { + get => _isLeft; + set + { + _isLeft = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(HasSides)); + } + } + + private bool _isRight; + public bool IsRight + { + get => _isRight; + set + { + _isRight = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(HasSides)); + } + } + + public bool HasSides => IsLeft ^ IsRight; + + private SvgImage _image; + public SvgImage Image + { + get => _image; + set + { + _image = value; + OnPropertyChanged(); + } + } + + public readonly InputViewModel ParentModel; + + public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config) + { + ParentModel = model; + model.NotifyChangesEvent += OnParentModelChanged; + OnParentModelChanged(); + Config = config; + } + + public void OnParentModelChanged() + { + IsLeft = ParentModel.IsLeft; + IsRight = ParentModel.IsRight; + Image = ParentModel.Image; + } + } +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/MotionInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs similarity index 97% rename from src/Ryujinx.Ava/UI/ViewModels/MotionInputViewModel.cs rename to src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs index 0b12a51f6..c9ed8f2d4 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/MotionInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ava.UI.ViewModels +namespace Ryujinx.Ava.UI.ViewModels.Input { public class MotionInputViewModel : BaseModel { diff --git a/src/Ryujinx.Ava/UI/ViewModels/RumbleInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs similarity index 92% rename from src/Ryujinx.Ava/UI/ViewModels/RumbleInputViewModel.cs rename to src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs index 49de19937..8ad33cf4c 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/RumbleInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ava.UI.ViewModels +namespace Ryujinx.Ava.UI.ViewModels.Input { public class RumbleInputViewModel : BaseModel { diff --git a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs similarity index 91% rename from src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs rename to src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index fc2d1500e..a151e9996 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -3,7 +3,6 @@ using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input; using Avalonia.Media; -using Avalonia.Media.Imaging; using Avalonia.Platform.Storage; using Avalonia.Threading; using DynamicData; @@ -26,22 +25,21 @@ using Ryujinx.HLE; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Input.HLE; using Ryujinx.Modules; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using SixLabors.ImageSharp.PixelFormats; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; +using SkiaSharp; using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Globalization; using System.IO; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using Image = SixLabors.ImageSharp.Image; using Key = Ryujinx.Input.Key; using MissingKeyException = LibHac.Common.Keys.MissingKeyException; using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; @@ -98,18 +96,18 @@ namespace Ryujinx.Ava.UI.ViewModels private bool _canUpdate = true; private Cursor _cursor; private string _title; - private string _currentEmulatedGamePath; + private ApplicationData _currentApplicationData; private readonly AutoResetEvent _rendererWaitEvent; private WindowState _windowState; private double _windowWidth; private double _windowHeight; private bool _isActive; + private bool _isSubMenuOpen; public ApplicationData ListSelectedApplication; public ApplicationData GridSelectedApplication; - private string TitleName { get; set; } internal AppHost AppHost { get; set; } public MainWindowViewModel() @@ -140,7 +138,7 @@ namespace Ryujinx.Ava.UI.ViewModels InputManager inputManager, UserChannelPersistence userChannelPersistence, LibHacHorizonManager libHacHorizonManager, - IHostUiHandler uiHandler, + IHostUIHandler uiHandler, Action showLoading, Action switchToGameControl, Action setMainContent, @@ -318,6 +316,17 @@ namespace Ryujinx.Ava.UI.ViewModels } } + public bool IsSubMenuOpen + { + get => _isSubMenuOpen; + set + { + _isSubMenuOpen = value; + + OnPropertyChanged(); + } + } + public bool ShowAll { get => _showAll; @@ -359,7 +368,7 @@ namespace Ryujinx.Ava.UI.ViewModels public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0; - public bool CreateShortcutEnabled => !ReleaseInformation.IsFlatHubBuild(); + public bool CreateShortcutEnabled => !ReleaseInformation.IsFlatHubBuild; public string LoadHeading { @@ -687,10 +696,10 @@ namespace Ryujinx.Ava.UI.ViewModels public bool StartGamesInFullscreen { - get => ConfigurationState.Instance.Ui.StartFullscreen; + get => ConfigurationState.Instance.UI.StartFullscreen; set { - ConfigurationState.Instance.Ui.StartFullscreen.Value = value; + ConfigurationState.Instance.UI.StartFullscreen.Value = value; ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); @@ -700,10 +709,10 @@ namespace Ryujinx.Ava.UI.ViewModels public bool ShowConsole { - get => ConfigurationState.Instance.Ui.ShowConsole; + get => ConfigurationState.Instance.UI.ShowConsole; set { - ConfigurationState.Instance.Ui.ShowConsole.Value = value; + ConfigurationState.Instance.UI.ShowConsole.Value = value; ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); @@ -745,10 +754,10 @@ namespace Ryujinx.Ava.UI.ViewModels public Glyph Glyph { - get => (Glyph)ConfigurationState.Instance.Ui.GameListViewMode.Value; + get => (Glyph)ConfigurationState.Instance.UI.GameListViewMode.Value; set { - ConfigurationState.Instance.Ui.GameListViewMode.Value = (int)value; + ConfigurationState.Instance.UI.GameListViewMode.Value = (int)value; OnPropertyChanged(); OnPropertyChanged(nameof(IsGrid)); @@ -760,9 +769,9 @@ namespace Ryujinx.Ava.UI.ViewModels public bool ShowNames { - get => ConfigurationState.Instance.Ui.ShowNames && ConfigurationState.Instance.Ui.GridSize > 1; set + get => ConfigurationState.Instance.UI.ShowNames && ConfigurationState.Instance.UI.GridSize > 1; set { - ConfigurationState.Instance.Ui.ShowNames.Value = value; + ConfigurationState.Instance.UI.ShowNames.Value = value; OnPropertyChanged(); OnPropertyChanged(nameof(GridSizeScale)); @@ -774,10 +783,10 @@ namespace Ryujinx.Ava.UI.ViewModels internal ApplicationSort SortMode { - get => (ApplicationSort)ConfigurationState.Instance.Ui.ApplicationSort.Value; + get => (ApplicationSort)ConfigurationState.Instance.UI.ApplicationSort.Value; private set { - ConfigurationState.Instance.Ui.ApplicationSort.Value = (int)value; + ConfigurationState.Instance.UI.ApplicationSort.Value = (int)value; OnPropertyChanged(); OnPropertyChanged(nameof(SortName)); @@ -790,7 +799,7 @@ namespace Ryujinx.Ava.UI.ViewModels { get { - return ConfigurationState.Instance.Ui.GridSize.Value switch + return ConfigurationState.Instance.UI.GridSize.Value switch { 1 => 78, 2 => 100, @@ -805,7 +814,7 @@ namespace Ryujinx.Ava.UI.ViewModels { get { - return ConfigurationState.Instance.Ui.GridSize.Value switch + return ConfigurationState.Instance.UI.GridSize.Value switch { 1 => 120, 2 => ShowNames ? 210 : 150, @@ -818,10 +827,10 @@ namespace Ryujinx.Ava.UI.ViewModels public int GridSizeScale { - get => ConfigurationState.Instance.Ui.GridSize; + get => ConfigurationState.Instance.UI.GridSize; set { - ConfigurationState.Instance.Ui.GridSize.Value = value; + ConfigurationState.Instance.UI.GridSize.Value = value; if (value < 2) { @@ -862,10 +871,10 @@ namespace Ryujinx.Ava.UI.ViewModels public bool IsAscending { - get => ConfigurationState.Instance.Ui.IsAscendingOrder; + get => ConfigurationState.Instance.UI.IsAscendingOrder; private set { - ConfigurationState.Instance.Ui.IsAscendingOrder.Value = value; + ConfigurationState.Instance.UI.IsAscendingOrder.Value = value; OnPropertyChanged(); OnPropertyChanged(nameof(SortMode)); @@ -921,7 +930,7 @@ namespace Ryujinx.Ava.UI.ViewModels public RendererHost RendererHostControl { get; private set; } public bool IsClosing { get; set; } public LibHacHorizonManager LibHacHorizonManager { get; internal set; } - public IHostUiHandler UiHandler { get; internal set; } + public IHostUIHandler UiHandler { get; internal set; } public bool IsSortedByFavorite => SortMode == ApplicationSort.Favorite; public bool IsSortedByTitle => SortMode == ApplicationSort.Title; public bool IsSortedByDeveloper => SortMode == ApplicationSort.Developer; @@ -930,10 +939,10 @@ namespace Ryujinx.Ava.UI.ViewModels public bool IsSortedByType => SortMode == ApplicationSort.FileType; public bool IsSortedBySize => SortMode == ApplicationSort.FileSize; public bool IsSortedByPath => SortMode == ApplicationSort.Path; - public bool IsGridSmall => ConfigurationState.Instance.Ui.GridSize == 1; - public bool IsGridMedium => ConfigurationState.Instance.Ui.GridSize == 2; - public bool IsGridLarge => ConfigurationState.Instance.Ui.GridSize == 3; - public bool IsGridHuge => ConfigurationState.Instance.Ui.GridSize == 4; + public bool IsGridSmall => ConfigurationState.Instance.UI.GridSize == 1; + public bool IsGridMedium => ConfigurationState.Instance.UI.GridSize == 2; + public bool IsGridLarge => ConfigurationState.Instance.UI.GridSize == 3; + public bool IsGridHuge => ConfigurationState.Instance.UI.GridSize == 4; #endregion @@ -944,8 +953,8 @@ namespace Ryujinx.Ava.UI.ViewModels return SortMode switch { #pragma warning disable IDE0055 // Disable formatting - ApplicationSort.Title => IsAscending ? SortExpressionComparer.Ascending(app => app.TitleName) - : SortExpressionComparer.Descending(app => app.TitleName), + ApplicationSort.Title => IsAscending ? SortExpressionComparer.Ascending(app => app.Name) + : SortExpressionComparer.Descending(app => app.Name), ApplicationSort.Developer => IsAscending ? SortExpressionComparer.Ascending(app => app.Developer) : SortExpressionComparer.Descending(app => app.Developer), ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending), @@ -956,8 +965,8 @@ namespace Ryujinx.Ava.UI.ViewModels : SortExpressionComparer.Descending(app => app.FileSize), ApplicationSort.Path => IsAscending ? SortExpressionComparer.Ascending(app => app.Path) : SortExpressionComparer.Descending(app => app.Path), - ApplicationSort.Favorite => !IsAscending ? SortExpressionComparer.Ascending(app => app.Favorite) - : SortExpressionComparer.Descending(app => app.Favorite), + ApplicationSort.Favorite => IsAscending ? SortExpressionComparer.Ascending(app => new AppListFavoriteComparable(app)) + : SortExpressionComparer.Descending(app => new AppListFavoriteComparable(app)), _ => null, #pragma warning restore IDE0055 }; @@ -982,7 +991,14 @@ namespace Ryujinx.Ava.UI.ViewModels { if (arg is ApplicationData app) { - return string.IsNullOrWhiteSpace(_searchText) || app.TitleName.ToLower().Contains(_searchText.ToLower()); + if (string.IsNullOrWhiteSpace(_searchText)) + { + return true; + } + + CompareInfo compareInfo = CultureInfo.CurrentCulture.CompareInfo; + + return compareInfo.IndexOf(app.Name, _searchText, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0; } return false; @@ -1111,7 +1127,7 @@ namespace Ryujinx.Ava.UI.ViewModels IsLoadingIndeterminate = false; break; case LoadState.Loaded: - LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, TitleName); + LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, _currentApplicationData.Name); IsLoadingIndeterminate = true; CacheLoadStatus = ""; break; @@ -1131,7 +1147,7 @@ namespace Ryujinx.Ava.UI.ViewModels IsLoadingIndeterminate = false; break; case ShaderCacheLoadingState.Loaded: - LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, TitleName); + LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, _currentApplicationData.Name); IsLoadingIndeterminate = true; CacheLoadStatus = ""; break; @@ -1143,27 +1159,20 @@ namespace Ryujinx.Ava.UI.ViewModels })); } - private unsafe void PrepareLoadScreen() + private void PrepareLoadScreen() { using MemoryStream stream = new(SelectedIcon); - using var bitmap = WriteableBitmap.Decode(stream); + using var gameIconBmp = SKBitmap.Decode(stream); - using var l = bitmap.Lock(); - var buffer = new byte[l.RowBytes * l.Size.Height]; - - Marshal.Copy(l.Address, buffer, 0, buffer.Length); - - var pixels = MemoryMarshal.Cast(buffer.AsSpan()); - - var dominantColor = IconColorPicker.GetFilteredColor(pixels, l.Size.Width, l.Size.Height).ToPixel(); + var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp); const float ColorMultiple = 0.5f; - Color progressFgColor = Color.FromRgb(dominantColor.R, dominantColor.G, dominantColor.B); + Color progressFgColor = Color.FromRgb(dominantColor.Red, dominantColor.Green, dominantColor.Blue); Color progressBgColor = Color.FromRgb( - (byte)(dominantColor.R * ColorMultiple), - (byte)(dominantColor.G * ColorMultiple), - (byte)(dominantColor.B * ColorMultiple)); + (byte)(dominantColor.Red * ColorMultiple), + (byte)(dominantColor.Green * ColorMultiple), + (byte)(dominantColor.Blue * ColorMultiple)); ProgressBarForegroundColor = new SolidColorBrush(progressFgColor); ProgressBarBackgroundColor = new SolidColorBrush(progressBgColor); @@ -1173,6 +1182,7 @@ namespace Ryujinx.Ava.UI.ViewModels { RendererHostControl.WindowCreated += RendererHost_Created; + AppHost.StatusInitEvent += Init_StatusBar; AppHost.StatusUpdatedEvent += Update_StatusBar; AppHost.AppExit += AppHost_AppExit; @@ -1189,13 +1199,25 @@ namespace Ryujinx.Ava.UI.ViewModels { UserChannelPersistence.ShouldRestart = false; - await LoadApplication(_currentEmulatedGamePath); + await LoadApplication(_currentApplicationData); } else { // Otherwise, clear state. UserChannelPersistence = new UserChannelPersistence(); - _currentEmulatedGamePath = null; + _currentApplicationData = null; + } + } + + private void Init_StatusBar(object sender, StatusInitEventArgs args) + { + if (ShowMenuAndStatusBar && !ShowLoadProgress) + { + Dispatcher.UIThread.InvokeAsync(() => + { + GpuNameText = args.GpuName; + BackendText = args.GpuBackend; + }); } } @@ -1221,8 +1243,6 @@ namespace Ryujinx.Ava.UI.ViewModels GameStatusText = args.GameStatus; VolumeStatusText = args.VolumeStatus; FifoStatusText = args.FifoStatus; - GpuNameText = args.GpuName; - BackendText = args.GpuBackend; ShowStatusSeparator = true; }); @@ -1254,7 +1274,7 @@ namespace Ryujinx.Ava.UI.ViewModels public void LoadConfigurableHotKeys() { - if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi, out var showUiKey)) + if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI, out var showUiKey)) { ShowUiKey = new KeyGesture(showUiKey); } @@ -1359,11 +1379,11 @@ namespace Ryujinx.Ava.UI.ViewModels public void OpenLogsFolder() { - string logPath = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "Logs"); - - new DirectoryInfo(logPath).Create(); - - OpenHelper.OpenFolder(logPath); + string logPath = AppDataManager.GetOrCreateLogsDir(); + if (!string.IsNullOrEmpty(logPath)) + { + OpenHelper.OpenFolder(logPath); + } } public void ToggleDockMode() @@ -1388,13 +1408,18 @@ namespace Ryujinx.Ava.UI.ViewModels } } + public void DumpProcessState() + { + AppHost?.Device?.DumpProcessExecutionState(); + } + public static void ChangeLanguage(object languageCode) { LocaleManager.Instance.LoadLanguage((string)languageCode); if (Program.PreviewerDetached) { - ConfigurationState.Instance.Ui.LanguageCode.Value = (string)languageCode; + ConfigurationState.Instance.UI.LanguageCode.Value = (string)languageCode; ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); } } @@ -1472,7 +1497,15 @@ namespace Ryujinx.Ava.UI.ViewModels if (result.Count > 0) { - await LoadApplication(result[0].Path.LocalPath); + if (ApplicationLibrary.TryGetApplicationsFromFile(result[0].Path.LocalPath, + out List applications)) + { + await LoadApplication(applications[0]); + } + else + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.MenuBarFileOpenFromFileError]); + } } } @@ -1486,11 +1519,17 @@ namespace Ryujinx.Ava.UI.ViewModels if (result.Count > 0) { - await LoadApplication(result[0].Path.LocalPath); + ApplicationData applicationData = new() + { + Name = Path.GetFileNameWithoutExtension(result[0].Path.LocalPath), + Path = result[0].Path.LocalPath, + }; + + await LoadApplication(applicationData); } } - public async Task LoadApplication(string path, bool startFullscreen = false, string titleName = "") + public async Task LoadApplication(ApplicationData application, bool startFullscreen = false) { if (AppHost != null) { @@ -1510,7 +1549,7 @@ namespace Ryujinx.Ava.UI.ViewModels Logger.RestartTime(); - SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(path, ConfigurationState.Instance.System.Language); + SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(application.Path, ConfigurationState.Instance.System.Language, application.Id); PrepareLoadScreen(); @@ -1519,7 +1558,8 @@ namespace Ryujinx.Ava.UI.ViewModels AppHost = new AppHost( RendererHostControl, InputManager, - path, + application.Path, + application.Id, VirtualFileSystem, ContentManager, AccountManager, @@ -1537,17 +1577,17 @@ namespace Ryujinx.Ava.UI.ViewModels CanUpdate = false; - LoadHeading = TitleName = titleName; + LoadHeading = application.Name; - if (string.IsNullOrWhiteSpace(titleName)) + if (string.IsNullOrWhiteSpace(application.Name)) { LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, AppHost.Device.Processes.ActiveApplication.Name); - TitleName = AppHost.Device.Processes.ActiveApplication.Name; + application.Name = AppHost.Device.Processes.ActiveApplication.Name; } SwitchToRenderer(startFullscreen); - _currentEmulatedGamePath = path; + _currentApplicationData = application; Thread gameThread = new(InitializeGame) { Name = "GUI.WindowThread" }; gameThread.Start(); @@ -1588,7 +1628,7 @@ namespace Ryujinx.Ava.UI.ViewModels { LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, version.VersionString); - hasApplet = version.Major > 3; + hasApplet = true; } else { diff --git a/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs new file mode 100644 index 000000000..8321bf894 --- /dev/null +++ b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs @@ -0,0 +1,336 @@ +using Avalonia; +using Avalonia.Collections; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Platform.Storage; +using Avalonia.Threading; +using DynamicData; +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.Models; +using Ryujinx.Common.Configuration; +using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; +using Ryujinx.HLE.HOS; +using System; +using System.IO; +using System.Linq; + +namespace Ryujinx.Ava.UI.ViewModels +{ + public class ModManagerViewModel : BaseModel + { + private readonly string _modJsonPath; + + private AvaloniaList _mods = new(); + private AvaloniaList _views = new(); + private AvaloniaList _selectedMods = new(); + + private string _search; + private readonly ulong _applicationId; + private readonly IStorageProvider _storageProvider; + + private static readonly ModMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + + public AvaloniaList Mods + { + get => _mods; + set + { + _mods = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(ModCount)); + Sort(); + } + } + + public AvaloniaList Views + { + get => _views; + set + { + _views = value; + OnPropertyChanged(); + } + } + + public AvaloniaList SelectedMods + { + get => _selectedMods; + set + { + _selectedMods = value; + OnPropertyChanged(); + } + } + + public string Search + { + get => _search; + set + { + _search = value; + OnPropertyChanged(); + Sort(); + } + } + + public string ModCount + { + get => string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], Mods.Count); + } + + public ModManagerViewModel(ulong applicationId) + { + _applicationId = applicationId; + + _modJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationId.ToString("x16"), "mods.json"); + + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + _storageProvider = desktop.MainWindow.StorageProvider; + } + + LoadMods(applicationId); + } + + private void LoadMods(ulong applicationId) + { + Mods.Clear(); + SelectedMods.Clear(); + + string[] modsBasePaths = [ModLoader.GetSdModsBasePath(), ModLoader.GetModsBasePath()]; + + foreach (var path in modsBasePaths) + { + var inSd = path == ModLoader.GetSdModsBasePath(); + var modCache = new ModLoader.ModCache(); + + ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId); + + foreach (var mod in modCache.RomfsDirs) + { + var modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd); + if (Mods.All(x => x.Path != mod.Path.Parent.FullName)) + { + Mods.Add(modModel); + } + } + + foreach (var mod in modCache.RomfsContainers) + { + Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd)); + } + + foreach (var mod in modCache.ExefsDirs) + { + var modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd); + if (Mods.All(x => x.Path != mod.Path.Parent.FullName)) + { + Mods.Add(modModel); + } + } + + foreach (var mod in modCache.ExefsContainers) + { + Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd)); + } + } + + Sort(); + } + + public void Sort() + { + Mods.AsObservableChangeSet() + .Filter(Filter) + .Bind(out var view).AsObservableList(); + + _views.Clear(); + _views.AddRange(view); + + SelectedMods = new(Views.Where(x => x.Enabled)); + + OnPropertyChanged(nameof(ModCount)); + OnPropertyChanged(nameof(Views)); + OnPropertyChanged(nameof(SelectedMods)); + } + + private bool Filter(object arg) + { + if (arg is ModModel content) + { + return string.IsNullOrWhiteSpace(_search) || content.Name.ToLower().Contains(_search.ToLower()); + } + + return false; + } + + public void Save() + { + ModMetadata modData = new(); + + foreach (ModModel mod in Mods) + { + modData.Mods.Add(new Mod + { + Name = mod.Name, + Path = mod.Path, + Enabled = SelectedMods.Contains(mod), + }); + } + + JsonHelper.SerializeToFile(_modJsonPath, modData, _serializerContext.ModMetadata); + } + + public void Delete(ModModel model) + { + var isSubdir = true; + var pathToDelete = model.Path; + var basePath = model.InSd ? ModLoader.GetSdModsBasePath() : ModLoader.GetModsBasePath(); + var modsDir = ModLoader.GetApplicationDir(basePath, _applicationId.ToString("x16")); + + if (new DirectoryInfo(model.Path).Parent?.FullName == modsDir) + { + isSubdir = false; + } + + if (isSubdir) + { + var parentDir = String.Empty; + + foreach (var dir in Directory.GetDirectories(modsDir, "*", SearchOption.TopDirectoryOnly)) + { + if (Directory.GetDirectories(dir, "*", SearchOption.AllDirectories).Contains(model.Path)) + { + parentDir = dir; + break; + } + } + + if (parentDir == String.Empty) + { + Dispatcher.UIThread.Post(async () => + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( + LocaleKeys.DialogModDeleteNoParentMessage, + model.Path)); + }); + return; + } + } + + Logger.Info?.Print(LogClass.Application, $"Deleting mod at \"{pathToDelete}\""); + Directory.Delete(pathToDelete, true); + + Mods.Remove(model); + OnPropertyChanged(nameof(ModCount)); + Sort(); + } + + private void AddMod(DirectoryInfo directory) + { + string[] directories; + + try + { + directories = Directory.GetDirectories(directory.ToString(), "*", SearchOption.AllDirectories); + } + catch (Exception exception) + { + Dispatcher.UIThread.Post(async () => + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( + LocaleKeys.DialogLoadFileErrorMessage, + exception.ToString(), + directory)); + }); + return; + } + + var destinationDir = ModLoader.GetApplicationDir(ModLoader.GetSdModsBasePath(), _applicationId.ToString("x16")); + + // TODO: More robust checking for valid mod folders + var isDirectoryValid = true; + + if (directories.Length == 0) + { + isDirectoryValid = false; + } + + if (!isDirectoryValid) + { + Dispatcher.UIThread.Post(async () => + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogModInvalidMessage]); + }); + return; + } + + foreach (var dir in directories) + { + string dirToCreate = dir.Replace(directory.Parent.ToString(), destinationDir); + + // Mod already exists + if (Directory.Exists(dirToCreate)) + { + Dispatcher.UIThread.Post(async () => + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( + LocaleKeys.DialogLoadFileErrorMessage, + LocaleManager.Instance[LocaleKeys.DialogModAlreadyExistsMessage], + dirToCreate)); + }); + + return; + } + + Directory.CreateDirectory(dirToCreate); + } + + var files = Directory.GetFiles(directory.ToString(), "*", SearchOption.AllDirectories); + + foreach (var file in files) + { + File.Copy(file, file.Replace(directory.Parent.ToString(), destinationDir), true); + } + + LoadMods(_applicationId); + } + + public async void Add() + { + var result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions + { + Title = LocaleManager.Instance[LocaleKeys.SelectModDialogTitle], + AllowMultiple = true, + }); + + foreach (var folder in result) + { + AddMod(new DirectoryInfo(folder.Path.LocalPath)); + } + } + + public void DeleteAll() + { + foreach (var mod in Mods) + { + Delete(mod); + } + + Mods.Clear(); + OnPropertyChanged(nameof(ModCount)); + Sort(); + } + + public void EnableAll() + { + SelectedMods = new(Mods); + } + + public void DisableAll() + { + SelectedMods.Clear(); + } + } +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs similarity index 93% rename from src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs rename to src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index 604e34067..1afb6df56 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -7,17 +7,17 @@ using Ryujinx.Audio.Backends.SDL2; using Ryujinx.Audio.Backends.SoundIo; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common.Configuration; -using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.GraphicsDriver; using Ryujinx.Common.Logging; using Ryujinx.Graphics.Vulkan; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Time.TimeZone; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Configuration.System; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Configuration.System; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -46,9 +46,7 @@ namespace Ryujinx.Ava.UI.ViewModels private bool _isVulkanAvailable = true; private bool _directoryChanged; private readonly List _gpuIds = new(); - private KeyboardHotkeys _keyboardHotkeys; private int _graphicsBackendIndex; - private string _customThemePath; private int _scalingFilter; private int _scalingFilterLevel; @@ -133,6 +131,7 @@ namespace Ryujinx.Ava.UI.ViewModels public bool EnableDiscordIntegration { get; set; } public bool CheckUpdatesOnStart { get; set; } public bool ShowConfirmExit { get; set; } + public bool RememberWindowState { get; set; } public int HideCursor { get; set; } public bool EnableDockedMode { get; set; } public bool EnableKeyboard { get; set; } @@ -142,6 +141,7 @@ namespace Ryujinx.Ava.UI.ViewModels public bool EnableInternetAccess { get; set; } public bool EnableFsIntegrityChecks { get; set; } public bool IgnoreMissingServices { get; set; } + public bool EnableServiceLLE { get; set; } public bool ExpandDramSize { get; set; } public bool EnableShaderCache { get; set; } public bool EnableTextureRecompression { get; set; } @@ -160,7 +160,6 @@ namespace Ryujinx.Ava.UI.ViewModels public bool IsOpenAlEnabled { get; set; } public bool IsSoundIoEnabled { get; set; } public bool IsSDL2Enabled { get; set; } - public bool EnableCustomTheme { get; set; } public bool IsCustomResolutionScaleActive => _resolutionScale == 4; public bool IsScalingFilterActive => _scalingFilter == (int)Ryujinx.Common.Configuration.ScalingFilter.Fsr; @@ -170,20 +169,6 @@ namespace Ryujinx.Ava.UI.ViewModels public string TimeZone { get; set; } public string ShaderDumpPath { get; set; } - public string CustomThemePath - { - get - { - return _customThemePath; - } - set - { - _customThemePath = value; - - OnPropertyChanged(); - } - } - public int Language { get; set; } public int Region { get; set; } public int FsGlobalAccessLogMode { get; set; } @@ -253,21 +238,7 @@ namespace Ryujinx.Ava.UI.ViewModels get => new(_networkInterfaces.Keys); } - public AvaloniaList MultiplayerModes - { - get => new(Enum.GetNames()); - } - - public KeyboardHotkeys KeyboardHotkeys - { - get => _keyboardHotkeys; - set - { - _keyboardHotkeys = value; - - OnPropertyChanged(); - } - } + public HotkeyConfig KeyboardHotkey { get; set; } public int NetworkInterfaceIndex { @@ -421,14 +392,19 @@ namespace Ryujinx.Ava.UI.ViewModels EnableDiscordIntegration = config.EnableDiscordIntegration; CheckUpdatesOnStart = config.CheckUpdatesOnStart; ShowConfirmExit = config.ShowConfirmExit; + RememberWindowState = config.RememberWindowState; HideCursor = (int)config.HideCursor.Value; GameDirectories.Clear(); - GameDirectories.AddRange(config.Ui.GameDirs.Value); + GameDirectories.AddRange(config.UI.GameDirs.Value); - EnableCustomTheme = config.Ui.EnableCustomTheme; - CustomThemePath = config.Ui.CustomThemePath; - BaseStyleIndex = config.Ui.BaseStyle == "Light" ? 0 : 1; + BaseStyleIndex = config.UI.BaseStyle.Value switch + { + "Auto" => 0, + "Light" => 1, + "Dark" => 2, + _ => 0 + }; // Input EnableDockedMode = config.System.EnableDockedMode; @@ -436,22 +412,24 @@ namespace Ryujinx.Ava.UI.ViewModels EnableMouse = config.Hid.EnableMouse; // Keyboard Hotkeys - KeyboardHotkeys = config.Hid.Hotkeys.Value; + KeyboardHotkey = new HotkeyConfig(config.Hid.Hotkeys.Value); // System Region = (int)config.System.Region.Value; Language = (int)config.System.Language.Value; TimeZone = config.System.TimeZone; - DateTime currentDateTime = DateTime.Now; - + DateTime currentHostDateTime = DateTime.Now; + TimeSpan systemDateTimeOffset = TimeSpan.FromSeconds(config.System.SystemTimeOffset); + DateTime currentDateTime = currentHostDateTime.Add(systemDateTimeOffset); CurrentDate = currentDateTime.Date; - CurrentTime = currentDateTime.TimeOfDay.Add(TimeSpan.FromSeconds(config.System.SystemTimeOffset)); + CurrentTime = currentDateTime.TimeOfDay; EnableVsync = config.Graphics.EnableVsync; EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks; ExpandDramSize = config.System.ExpandRam; IgnoreMissingServices = config.System.IgnoreMissingServices; + EnableServiceLLE = config.System.EnableServiceLLE; // CPU EnablePptc = config.System.EnablePtc; @@ -507,17 +485,22 @@ namespace Ryujinx.Ava.UI.ViewModels config.EnableDiscordIntegration.Value = EnableDiscordIntegration; config.CheckUpdatesOnStart.Value = CheckUpdatesOnStart; config.ShowConfirmExit.Value = ShowConfirmExit; + config.RememberWindowState.Value = RememberWindowState; config.HideCursor.Value = (HideCursorMode)HideCursor; if (_directoryChanged) { List gameDirs = new(GameDirectories); - config.Ui.GameDirs.Value = gameDirs; + config.UI.GameDirs.Value = gameDirs; } - config.Ui.EnableCustomTheme.Value = EnableCustomTheme; - config.Ui.CustomThemePath.Value = CustomThemePath; - config.Ui.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark"; + config.UI.BaseStyle.Value = BaseStyleIndex switch + { + 0 => "Auto", + 1 => "Light", + 2 => "Dark", + _ => "Auto" + }; // Input config.System.EnableDockedMode.Value = EnableDockedMode; @@ -525,7 +508,7 @@ namespace Ryujinx.Ava.UI.ViewModels config.Hid.EnableMouse.Value = EnableMouse; // Keyboard Hotkeys - config.Hid.Hotkeys.Value = KeyboardHotkeys; + config.Hid.Hotkeys.Value = KeyboardHotkey.GetConfig(); // System config.System.Region.Value = (Region)Region; @@ -541,6 +524,7 @@ namespace Ryujinx.Ava.UI.ViewModels config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks; config.System.ExpandRam.Value = ExpandDramSize; config.System.IgnoreMissingServices.Value = IgnoreMissingServices; + config.System.EnableServiceLLE.Value = EnableServiceLLE; // CPU config.System.EnablePtc.Value = EnablePptc; diff --git a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs similarity index 65% rename from src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs rename to src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs index 5090a8c70..e9b39dfe1 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs @@ -1,4 +1,3 @@ -using Avalonia; using Avalonia.Collections; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Platform.Storage; @@ -6,7 +5,7 @@ using Avalonia.Threading; using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; -using LibHac.FsSystem; +using LibHac.Ncm; using LibHac.Ns; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; @@ -17,12 +16,17 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.App.Common; +using Ryujinx.HLE.Loaders.Processes.Extensions; +using Ryujinx.HLE.Utilities; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common.Configuration; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using Application = Avalonia.Application; +using ContentType = LibHac.Ncm.ContentType; using Path = System.IO.Path; using SpanHelpers = LibHac.Common.SpanHelpers; @@ -33,7 +37,7 @@ namespace Ryujinx.Ava.UI.ViewModels public TitleUpdateMetadata TitleUpdateWindowData; public readonly string TitleUpdateJsonPath; private VirtualFileSystem VirtualFileSystem { get; } - private ulong TitleId { get; } + private ApplicationData ApplicationData { get; } private AvaloniaList _titleUpdates = new(); private AvaloniaList _views = new(); @@ -73,18 +77,18 @@ namespace Ryujinx.Ava.UI.ViewModels public IStorageProvider StorageProvider; - public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId) + public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ApplicationData applicationData) { VirtualFileSystem = virtualFileSystem; - TitleId = titleId; + ApplicationData = applicationData; if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { StorageProvider = desktop.MainWindow.StorageProvider; } - TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json"); + TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, ApplicationData.IdBaseString, "updates.json"); try { @@ -92,7 +96,7 @@ namespace Ryujinx.Ava.UI.ViewModels } catch { - Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {TitleId} at {TitleUpdateJsonPath}"); + Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {ApplicationData.IdBaseString} at {TitleUpdateJsonPath}"); TitleUpdateWindowData = new TitleUpdateMetadata { @@ -108,6 +112,9 @@ namespace Ryujinx.Ava.UI.ViewModels private void LoadUpdates() { + // Try to load updates from PFS first + AddUpdate(ApplicationData.Path, true); + foreach (string path in TitleUpdateWindowData.Paths) { AddUpdate(path); @@ -124,26 +131,11 @@ namespace Ryujinx.Ava.UI.ViewModels public void SortUpdates() { - var list = TitleUpdates.ToList(); - - list.Sort((first, second) => - { - if (string.IsNullOrEmpty(first.Control.DisplayVersionString.ToString())) - { - return -1; - } - - if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString())) - { - return 1; - } - - return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1; - }); + var sortedUpdates = TitleUpdates.OrderByDescending(update => update.Version); Views.Clear(); Views.Add(new BaseModel()); - Views.AddRange(list); + Views.AddRange(sortedUpdates); if (SelectedUpdate == null) { @@ -162,38 +154,62 @@ namespace Ryujinx.Ava.UI.ViewModels } } - private void AddUpdate(string path) + private void AddUpdate(string path, bool ignoreNotFound = false, bool selected = false) { - if (File.Exists(path) && TitleUpdates.All(x => x.Path != path)) + if (!File.Exists(path) || TitleUpdates.Any(x => x.Path == path)) { - using FileStream file = new(path, FileMode.Open, FileAccess.Read); + return; + } - try + IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks + ? IntegrityCheckLevel.ErrorOnInvalid + : IntegrityCheckLevel.None; + + try + { + using IFileSystem pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(path, VirtualFileSystem); + + Dictionary updates = pfs.GetContentData(ContentMetaType.Patch, VirtualFileSystem, checkLevel); + + Nca patchNca = null; + Nca controlNca = null; + + if (updates.TryGetValue(ApplicationData.Id, out ContentMetaData content)) { - var pfs = new PartitionFileSystem(); - pfs.Initialize(file.AsStorage()).ThrowIfFailure(); - (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, pfs, TitleId.ToString("x16"), 0); + patchNca = content.GetNcaByType(VirtualFileSystem.KeySet, ContentType.Program); + controlNca = content.GetNcaByType(VirtualFileSystem.KeySet, ContentType.Control); + } - if (controlNca != null && patchNca != null) + if (controlNca != null && patchNca != null) + { + ApplicationControlProperty controlData = new(); + + using UniqueRef nacpFile = new(); + + controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); + nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure(); + + var displayVersion = controlData.DisplayVersionString.ToString(); + var update = new TitleUpdateModel(content.Version.Version, displayVersion, path); + + TitleUpdates.Add(update); + + if (selected) { - ApplicationControlProperty controlData = new(); - - using UniqueRef nacpFile = new(); - - controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); - nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure(); - - TitleUpdates.Add(new TitleUpdateModel(controlData, path)); + Dispatcher.UIThread.InvokeAsync(() => SelectedUpdate = update); } - else + } + else + { + if (!ignoreNotFound) { Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage])); } } - catch (Exception ex) - { - Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadNcaErrorMessage, ex.Message, path))); - } + } + catch (Exception ex) + { + Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadFileErrorMessage, ex.Message, path))); } } @@ -222,7 +238,7 @@ namespace Ryujinx.Ava.UI.ViewModels foreach (var file in result) { - AddUpdate(file.Path.LocalPath); + AddUpdate(file.Path.LocalPath, selected: true); } SortUpdates(); diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs b/src/Ryujinx/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs similarity index 93% rename from src/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs rename to src/Ryujinx/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs index 89b591229..b07bf78b9 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs @@ -9,14 +9,14 @@ using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Ava.UI.Models; using Ryujinx.HLE.FileSystem; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; +using SkiaSharp; using System; using System.Buffers.Binary; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using Color = Avalonia.Media.Color; +using Image = SkiaSharp.SKImage; namespace Ryujinx.Ava.UI.ViewModels { @@ -130,9 +130,12 @@ namespace Ryujinx.Ava.UI.ViewModels stream.Position = 0; - Image avatarImage = Image.LoadPixelData(DecompressYaz0(stream), 256, 256); + Image avatarImage = Image.FromPixelCopy(new SKImageInfo(256, 256, SKColorType.Rgba8888, SKAlphaType.Premul), DecompressYaz0(stream)); - avatarImage.SaveAsPng(streamPng); + using (SKData data = avatarImage.Encode(SKEncodedImageFormat.Png, 100)) + { + data.SaveTo(streamPng); + } _avatarStore.Add(item.FullPath, streamPng.ToArray()); } @@ -151,7 +154,7 @@ namespace Ryujinx.Ava.UI.ViewModels reader.ReadInt64(); // Padding byte[] input = new byte[stream.Length - stream.Position]; - stream.Read(input, 0, input.Length); + stream.ReadExactly(input, 0, input.Length); uint inputOffset = 0; diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs b/src/Ryujinx/UI/ViewModels/UserProfileImageSelectorViewModel.cs similarity index 100% rename from src/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs rename to src/Ryujinx/UI/ViewModels/UserProfileImageSelectorViewModel.cs diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs b/src/Ryujinx/UI/ViewModels/UserProfileViewModel.cs similarity index 88% rename from src/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs rename to src/Ryujinx/UI/ViewModels/UserProfileViewModel.cs index 70274847f..0b65e6d13 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/UserProfileViewModel.cs @@ -1,7 +1,7 @@ -using Microsoft.IdentityModel.Tokens; using Ryujinx.Ava.UI.Models; using System; using System.Collections.ObjectModel; +using System.Linq; namespace Ryujinx.Ava.UI.ViewModels { @@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.ViewModels { Profiles = new ObservableCollection(); LostProfiles = new ObservableCollection(); - IsEmpty = LostProfiles.IsNullOrEmpty(); + IsEmpty = !LostProfiles.Any(); } public ObservableCollection Profiles { get; set; } diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/UserSaveManagerViewModel.cs similarity index 100% rename from src/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs rename to src/Ryujinx/UI/ViewModels/UserSaveManagerViewModel.cs diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml new file mode 100644 index 000000000..c248a3f67 --- /dev/null +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -0,0 +1,799 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs new file mode 100644 index 000000000..1352bc6fb --- /dev/null +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs @@ -0,0 +1,204 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.LogicalTree; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.ViewModels.Input; +using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Input; +using Ryujinx.Input.Assigner; +using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; + +namespace Ryujinx.Ava.UI.Views.Input +{ + public partial class ControllerInputView : UserControl + { + private ButtonKeyAssigner _currentAssigner; + + public ControllerInputView() + { + InitializeComponent(); + + foreach (ILogical visual in SettingButtons.GetLogicalDescendants()) + { + if (visual is ToggleButton button and not CheckBox) + { + button.IsCheckedChanged += Button_IsCheckedChanged; + } + } + } + + protected override void OnPointerReleased(PointerReleasedEventArgs e) + { + base.OnPointerReleased(e); + + if (_currentAssigner != null && _currentAssigner.ToggledButton != null && !_currentAssigner.ToggledButton.IsPointerOver) + { + _currentAssigner.Cancel(); + } + } + + private void Button_IsCheckedChanged(object sender, RoutedEventArgs e) + { + if (sender is ToggleButton button) + { + if ((bool)button.IsChecked) + { + if (_currentAssigner != null && button == _currentAssigner.ToggledButton) + { + return; + } + + bool isStick = button.Tag != null && button.Tag.ToString() == "stick"; + + if (_currentAssigner == null) + { + _currentAssigner = new ButtonKeyAssigner(button); + + this.Focus(NavigationMethod.Pointer); + + PointerPressed += MouseClick; + + var viewModel = DataContext as ControllerInputViewModel; + + IKeyboard keyboard = (IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations. + IButtonAssigner assigner = CreateButtonAssigner(isStick); + + _currentAssigner.ButtonAssigned += (sender, e) => + { + if (e.ButtonValue.HasValue) + { + var buttonValue = e.ButtonValue.Value; + viewModel.ParentModel.IsModified = true; + + switch (button.Name) + { + case "ButtonZl": + viewModel.Config.ButtonZl = buttonValue.AsHidType(); + break; + case "ButtonL": + viewModel.Config.ButtonL = buttonValue.AsHidType(); + break; + case "ButtonMinus": + viewModel.Config.ButtonMinus = buttonValue.AsHidType(); + break; + case "LeftStickButton": + viewModel.Config.LeftStickButton = buttonValue.AsHidType(); + break; + case "LeftJoystick": + viewModel.Config.LeftJoystick = buttonValue.AsHidType(); + break; + case "DpadUp": + viewModel.Config.DpadUp = buttonValue.AsHidType(); + break; + case "DpadDown": + viewModel.Config.DpadDown = buttonValue.AsHidType(); + break; + case "DpadLeft": + viewModel.Config.DpadLeft = buttonValue.AsHidType(); + break; + case "DpadRight": + viewModel.Config.DpadRight = buttonValue.AsHidType(); + break; + case "LeftButtonSr": + viewModel.Config.LeftButtonSr = buttonValue.AsHidType(); + break; + case "LeftButtonSl": + viewModel.Config.LeftButtonSl = buttonValue.AsHidType(); + break; + case "RightButtonSr": + viewModel.Config.RightButtonSr = buttonValue.AsHidType(); + break; + case "RightButtonSl": + viewModel.Config.RightButtonSl = buttonValue.AsHidType(); + break; + case "ButtonZr": + viewModel.Config.ButtonZr = buttonValue.AsHidType(); + break; + case "ButtonR": + viewModel.Config.ButtonR = buttonValue.AsHidType(); + break; + case "ButtonPlus": + viewModel.Config.ButtonPlus = buttonValue.AsHidType(); + break; + case "ButtonA": + viewModel.Config.ButtonA = buttonValue.AsHidType(); + break; + case "ButtonB": + viewModel.Config.ButtonB = buttonValue.AsHidType(); + break; + case "ButtonX": + viewModel.Config.ButtonX = buttonValue.AsHidType(); + break; + case "ButtonY": + viewModel.Config.ButtonY = buttonValue.AsHidType(); + break; + case "RightStickButton": + viewModel.Config.RightStickButton = buttonValue.AsHidType(); + break; + case "RightJoystick": + viewModel.Config.RightJoystick = buttonValue.AsHidType(); + break; + case "ButtonCapture": + viewModel.Config.ButtonCapture = buttonValue.AsHidType(); + break; + case "ButtonHome": + viewModel.Config.ButtonHome = buttonValue.AsHidType(); + break; + } + } + }; + + _currentAssigner.GetInputAndAssign(assigner, keyboard); + } + else + { + if (_currentAssigner != null) + { + _currentAssigner.Cancel(); + _currentAssigner = null; + button.IsChecked = false; + } + } + } + else + { + _currentAssigner?.Cancel(); + _currentAssigner = null; + } + } + } + + private void MouseClick(object sender, PointerPressedEventArgs e) + { + bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed; + + _currentAssigner?.Cancel(shouldUnbind); + + PointerPressed -= MouseClick; + } + + private IButtonAssigner CreateButtonAssigner(bool forStick) + { + IButtonAssigner assigner; + + var controllerInputViewModel = DataContext as ControllerInputViewModel; + + assigner = new GamepadButtonAssigner( + controllerInputViewModel.ParentModel.SelectedGamepad, + (controllerInputViewModel.ParentModel.Config as StandardControllerInputConfig).TriggerThreshold, + forStick); + + return assigner; + } + + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnDetachedFromVisualTree(e); + _currentAssigner?.Cancel(); + _currentAssigner = null; + } + } +} diff --git a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/InputView.axaml similarity index 83% rename from src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml rename to src/Ryujinx/UI/Views/Input/InputView.axaml index 6813d4c88..b4940941c 100644 --- a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/InputView.axaml @@ -5,33 +5,26 @@ xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - xmlns:views="clr-namespace:Ryujinx.Ava.UI.Views.Input;assembly=Ryujinx.Ava" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" + xmlns:views="clr-namespace:Ryujinx.Ava.UI.Views.Input" + xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" d:DesignHeight="800" d:DesignWidth="800" - x:Class="Ryujinx.Ava.UI.Views.Input.ControllerInputView" - x:DataType="viewModels:ControllerInputViewModel" + x:Class="Ryujinx.Ava.UI.Views.Input.InputView" + x:DataType="viewModels:InputViewModel" + x:CompileBindings="True" mc:Ignorable="d" Focusable="True"> - + - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml.cs b/src/Ryujinx/UI/Windows/AboutWindow.axaml.cs similarity index 98% rename from src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml.cs rename to src/Ryujinx/UI/Windows/AboutWindow.axaml.cs index 7f28ad352..c32661b0c 100644 --- a/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/AboutWindow.axaml.cs @@ -7,7 +7,7 @@ using FluentAvalonia.UI.Controls; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System.Threading.Tasks; using Button = Avalonia.Controls.Button; diff --git a/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml b/src/Ryujinx/UI/Windows/AmiiboWindow.axaml similarity index 99% rename from src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml rename to src/Ryujinx/UI/Windows/AmiiboWindow.axaml index caf7c1f3f..c587aa873 100644 --- a/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml +++ b/src/Ryujinx/UI/Windows/AmiiboWindow.axaml @@ -72,4 +72,4 @@ Click="CancelButton_Click" /> - \ No newline at end of file + diff --git a/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml.cs b/src/Ryujinx/UI/Windows/AmiiboWindow.axaml.cs similarity index 97% rename from src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml.cs rename to src/Ryujinx/UI/Windows/AmiiboWindow.axaml.cs index 57106638a..8829cb10b 100644 --- a/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/AmiiboWindow.axaml.cs @@ -1,7 +1,7 @@ using Avalonia.Interactivity; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ui.Common.Models.Amiibo; +using Ryujinx.UI.Common.Models.Amiibo; namespace Ryujinx.Ava.UI.Windows { diff --git a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml b/src/Ryujinx/UI/Windows/CheatWindow.axaml similarity index 100% rename from src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml rename to src/Ryujinx/UI/Windows/CheatWindow.axaml diff --git a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs b/src/Ryujinx/UI/Windows/CheatWindow.axaml.cs similarity index 88% rename from src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs rename to src/Ryujinx/UI/Windows/CheatWindow.axaml.cs index c2de67ab2..8f4c3cebd 100644 --- a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/CheatWindow.axaml.cs @@ -1,9 +1,11 @@ using Avalonia.Collections; +using LibHac.Tools.FsSystem; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Models; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common.Configuration; using System; using System.Collections.Generic; using System.Globalization; @@ -34,14 +36,17 @@ namespace Ryujinx.Ava.UI.Windows public CheatWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName, string titlePath) { LoadedCheats = new AvaloniaList(); + IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks + ? IntegrityCheckLevel.ErrorOnInvalid + : IntegrityCheckLevel.None; Heading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.CheatWindowHeading, titleName, titleId.ToUpper()); - BuildId = ApplicationData.GetApplicationBuildId(virtualFileSystem, titlePath); + BuildId = ApplicationData.GetBuildId(virtualFileSystem, checkLevel, titlePath); InitializeComponent(); string modsBasePath = ModLoader.GetModsBasePath(); - string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId); + string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, titleId); ulong titleIdValue = ulong.Parse(titleId, NumberStyles.HexNumber); _enabledCheatsPath = Path.Combine(titleModsPath, "cheats", "enabled.txt"); diff --git a/src/Ryujinx.Ava/UI/Windows/ContentDialogOverlayWindow.axaml b/src/Ryujinx/UI/Windows/ContentDialogOverlayWindow.axaml similarity index 100% rename from src/Ryujinx.Ava/UI/Windows/ContentDialogOverlayWindow.axaml rename to src/Ryujinx/UI/Windows/ContentDialogOverlayWindow.axaml diff --git a/src/Ryujinx.Ava/UI/Windows/ContentDialogOverlayWindow.axaml.cs b/src/Ryujinx/UI/Windows/ContentDialogOverlayWindow.axaml.cs similarity index 91% rename from src/Ryujinx.Ava/UI/Windows/ContentDialogOverlayWindow.axaml.cs rename to src/Ryujinx/UI/Windows/ContentDialogOverlayWindow.axaml.cs index 2b12d72f1..0e2410247 100644 --- a/src/Ryujinx.Ava/UI/Windows/ContentDialogOverlayWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/ContentDialogOverlayWindow.axaml.cs @@ -9,7 +9,6 @@ namespace Ryujinx.Ava.UI.Windows { InitializeComponent(); - ExtendClientAreaToDecorationsHint = true; TransparencyLevelHint = new[] { WindowTransparencyLevel.Transparent }; WindowStartupLocation = WindowStartupLocation.Manual; SystemDecorations = SystemDecorations.None; diff --git a/src/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml b/src/Ryujinx/UI/Windows/DownloadableContentManagerWindow.axaml similarity index 99% rename from src/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml rename to src/Ryujinx/UI/Windows/DownloadableContentManagerWindow.axaml index 99cf28e77..98aac09ce 100644 --- a/src/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml +++ b/src/Ryujinx/UI/Windows/DownloadableContentManagerWindow.axaml @@ -97,7 +97,7 @@ MaxLines="2" TextWrapping="Wrap" TextTrimming="CharacterEllipsis" - Text="{Binding FileName}" /> + Text="{Binding Label}" /> x.OfType().Name("DialogSpace").Child().OfType()); @@ -47,7 +46,7 @@ namespace Ryujinx.Ava.UI.Windows contentDialog.Styles.Add(bottomBorder); - await ContentDialogHelper.ShowAsync(contentDialog); + await contentDialog.ShowAsync(); } private void SaveAndClose(object sender, RoutedEventArgs routedEventArgs) diff --git a/src/Ryujinx.Ava/UI/Windows/IconColorPicker.cs b/src/Ryujinx/UI/Windows/IconColorPicker.cs similarity index 78% rename from src/Ryujinx.Ava/UI/Windows/IconColorPicker.cs rename to src/Ryujinx/UI/Windows/IconColorPicker.cs index 21096fdf6..dd6a55d4d 100644 --- a/src/Ryujinx.Ava/UI/Windows/IconColorPicker.cs +++ b/src/Ryujinx/UI/Windows/IconColorPicker.cs @@ -1,5 +1,4 @@ -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; +using SkiaSharp; using System; using System.Collections.Generic; @@ -36,35 +35,36 @@ namespace Ryujinx.Ava.UI.Windows } } - public static Color GetFilteredColor(Span image, int width, int height) + public static SKColor GetFilteredColor(SKBitmap image) { - var color = GetColor(image, width, height).ToPixel(); + var color = GetColor(image); + // We don't want colors that are too dark. // If the color is too dark, make it brighter by reducing the range // and adding a constant color. - int luminosity = GetColorApproximateLuminosity(color.R, color.G, color.B); + int luminosity = GetColorApproximateLuminosity(color.Red, color.Green, color.Blue); if (luminosity < CutOffLuminosity) { - color = Color.FromRgb( - (byte)Math.Min(CutOffLuminosity + color.R, byte.MaxValue), - (byte)Math.Min(CutOffLuminosity + color.G, byte.MaxValue), - (byte)Math.Min(CutOffLuminosity + color.B, byte.MaxValue)); + color = new SKColor( + (byte)Math.Min(CutOffLuminosity + color.Red, byte.MaxValue), + (byte)Math.Min(CutOffLuminosity + color.Green, byte.MaxValue), + (byte)Math.Min(CutOffLuminosity + color.Blue, byte.MaxValue)); } return color; } - public static Color GetColor(Span image, int width, int height) + public static SKColor GetColor(SKBitmap image) { var colors = new PaletteColor[TotalColors]; - var dominantColorBin = new Dictionary(); - int w = width; + var buffer = GetBuffer(image); + int w = image.Width; int w8 = w << 8; - int h8 = height << 8; + int h8 = image.Height << 8; #pragma warning disable IDE0059 // Unnecessary assignment int xStep = w8 / ColorsPerLine; @@ -74,17 +74,18 @@ namespace Ryujinx.Ava.UI.Windows int i = 0; int maxHitCount = 0; - for (int y = 0; y < height; y++) + for (int y = 0; y < image.Height; y++) { - int yOffset = y * width; + int yOffset = y * image.Width; - for (int x = 0; x < width && i < TotalColors; x++) + for (int x = 0; x < image.Width && i < TotalColors; x++) { int offset = x + yOffset; - byte cb = image[offset].B; - byte cg = image[offset].G; - byte cr = image[offset].R; + SKColor pixel = buffer[offset]; + byte cr = pixel.Red; + byte cg = pixel.Green; + byte cb = pixel.Blue; var qck = GetQuantizedColorKey(cr, cg, cb); @@ -120,12 +121,22 @@ namespace Ryujinx.Ava.UI.Windows } } - return Color.FromRgb(bestCandidate.R, bestCandidate.G, bestCandidate.B); + return new SKColor(bestCandidate.R, bestCandidate.G, bestCandidate.B); } - public static Bgra32[] GetBuffer(Image image) + public static SKColor[] GetBuffer(SKBitmap image) { - return image.TryGetSinglePixelSpan(out var data) ? data.ToArray() : Array.Empty(); + var pixels = new SKColor[image.Width * image.Height]; + + for (int y = 0; y < image.Height; y++) + { + for (int x = 0; x < image.Width; x++) + { + pixels[x + y * image.Width] = image.GetPixel(x, y); + } + } + + return pixels; } private static int GetColorScore(Dictionary dominantColorBin, int maxHitCount, PaletteColor color) diff --git a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml b/src/Ryujinx/UI/Windows/MainWindow.axaml similarity index 95% rename from src/Ryujinx.Ava/UI/Windows/MainWindow.axaml rename to src/Ryujinx/UI/Windows/MainWindow.axaml index 0d9a59499..de0f60bcc 100644 --- a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml +++ b/src/Ryujinx/UI/Windows/MainWindow.axaml @@ -14,8 +14,8 @@ WindowState="{Binding WindowState}" Width="{Binding WindowWidth}" Height="{Binding WindowHeight}" - MinWidth="1092" - MinHeight="672" + MinWidth="800" + MinHeight="500" d:DesignHeight="720" d:DesignWidth="1280" x:DataType="viewModels:MainWindowViewModel" @@ -39,15 +39,14 @@ + - - + @@ -158,7 +157,7 @@ FontWeight="Bold" IsVisible="{Binding ShowLoadProgress}" Text="{Binding LoadHeading}" - TextAlignment="Left" + TextAlignment="Start" TextWrapping="Wrap" MaxWidth="500" /> @@ -202,4 +201,4 @@ Grid.Row="2" /> - \ No newline at end of file + diff --git a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs similarity index 71% rename from src/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs rename to src/Ryujinx/UI/Windows/MainWindow.axaml.cs index 68fbc5de7..348412e78 100644 --- a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs @@ -2,8 +2,10 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Interactivity; +using Avalonia.Platform; using Avalonia.Threading; using FluentAvalonia.UI.Controls; +using LibHac.Tools.FsSystem; using Ryujinx.Ava.Common; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Input; @@ -18,12 +20,12 @@ using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.Input.HLE; using Ryujinx.Input.SDL2; using Ryujinx.Modules; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using System; -using System.IO; +using System.Collections.Generic; using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; @@ -35,12 +37,14 @@ namespace Ryujinx.Ava.UI.Windows internal static MainWindowViewModel MainWindowViewModel { get; private set; } private bool _isLoading; + private bool _applicationsLoadedOnce; private UserChannelPersistence _userChannelPersistence; private static bool _deferLoad; private static string _launchPath; + private static string _launchApplicationId; private static bool _startFullscreen; - internal readonly AvaHostUiHandler UiHandler; + internal readonly AvaHostUIHandler UiHandler; public VirtualFileSystem VirtualFileSystem { get; private set; } public ContentManager ContentManager { get; private set; } @@ -56,6 +60,9 @@ namespace Ryujinx.Ava.UI.Windows public static bool ShowKeyErrorOnLoad { get; set; } public ApplicationLibrary ApplicationLibrary { get; set; } + public readonly double StatusBarHeight; + public readonly double MenuBarHeight; + public MainWindow() { ViewModel = new MainWindowViewModel(); @@ -64,20 +71,22 @@ namespace Ryujinx.Ava.UI.Windows DataContext = ViewModel; - SetWindowSizePosition(); - InitializeComponent(); Load(); - UiHandler = new AvaHostUiHandler(this); + UiHandler = new AvaHostUIHandler(this); ViewModel.Title = $"Ryujinx {Program.Version}"; // NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point. - double barHeight = MenuBar.MinHeight + StatusBarView.StatusBar.MinHeight; + StatusBarHeight = StatusBarView.StatusBar.MinHeight; + MenuBarHeight = MenuBar.MinHeight; + double barHeight = MenuBarHeight + StatusBarHeight; Height = ((Height - barHeight) / Program.WindowScaleFactor) + barHeight; Width /= Program.WindowScaleFactor; + SetWindowSizePosition(); + if (Program.PreviewerDetached) { InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL2GamepadDriver()); @@ -87,6 +96,29 @@ namespace Ryujinx.Ava.UI.Windows } } + /// + /// Event handler for detecting OS theme change when using "Follow OS theme" option + /// + private void OnPlatformColorValuesChanged(object sender, PlatformColorValues e) + { + if (Application.Current is App app) + { + app.ApplyConfiguredTheme(); + } + } + + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + if (PlatformSettings != null) + { + /// + /// Unsubscribe to the ColorValuesChanged event + /// + PlatformSettings.ColorValuesChanged -= OnPlatformColorValuesChanged; + } + } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); @@ -139,18 +171,17 @@ namespace Ryujinx.Ava.UI.Windows { ViewModel.SelectedIcon = args.Application.Icon; - string path = new FileInfo(args.Application.Path).FullName; - - ViewModel.LoadApplication(path).Wait(); + ViewModel.LoadApplication(args.Application).Wait(); } args.Handled = true; } - internal static void DeferLoadApplication(string launchPathArg, bool startFullscreenArg) + internal static void DeferLoadApplication(string launchPathArg, string launchApplicationId, bool startFullscreenArg) { _deferLoad = true; _launchPath = launchPathArg; + _launchApplicationId = launchApplicationId; _startFullscreen = startFullscreenArg; } @@ -190,7 +221,14 @@ namespace Ryujinx.Ava.UI.Windows LibHacHorizonManager.InitializeBcatServer(); LibHacHorizonManager.InitializeSystemClients(); - ApplicationLibrary = new ApplicationLibrary(VirtualFileSystem); + IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks + ? IntegrityCheckLevel.ErrorOnInvalid + : IntegrityCheckLevel.None; + + ApplicationLibrary = new ApplicationLibrary(VirtualFileSystem, checkLevel) + { + DesiredLanguage = ConfigurationState.Instance.System.Language, + }; // Save data created before we supported extra data in directory save data will not work properly if // given empty extra data. Luckily some of that extra data can be created using the data from the @@ -263,7 +301,7 @@ namespace Ryujinx.Ava.UI.Windows } } - private void CheckLaunchState() + private async Task CheckLaunchState() { if (OperatingSystem.IsLinux() && LinuxHelper.VmMaxMapCount < LinuxHelper.RecommendedVmMaxMapCount) { @@ -271,23 +309,11 @@ namespace Ryujinx.Ava.UI.Windows if (LinuxHelper.PkExecPath is not null) { - Dispatcher.UIThread.Post(async () => - { - if (OperatingSystem.IsLinux()) - { - await ShowVmMaxMapCountDialog(); - } - }); + await Dispatcher.UIThread.InvokeAsync(ShowVmMaxMapCountDialog); } else { - Dispatcher.UIThread.Post(async () => - { - if (OperatingSystem.IsLinux()) - { - await ShowVmMaxMapCountWarning(); - } - }); + await Dispatcher.UIThread.InvokeAsync(ShowVmMaxMapCountWarning); } } @@ -297,19 +323,47 @@ namespace Ryujinx.Ava.UI.Windows { _deferLoad = false; - ViewModel.LoadApplication(_launchPath, _startFullscreen).Wait(); + if (ApplicationLibrary.TryGetApplicationsFromFile(_launchPath, out List applications)) + { + ApplicationData applicationData; + + if (_launchApplicationId != null) + { + applicationData = applications.Find(application => application.IdString == _launchApplicationId); + + if (applicationData != null) + { + await ViewModel.LoadApplication(applicationData, _startFullscreen); + } + else + { + Logger.Error?.Print(LogClass.Application, $"Couldn't find requested application id '{_launchApplicationId}' in '{_launchPath}'."); + await Dispatcher.UIThread.InvokeAsync(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.ApplicationNotFound)); + } + } + else + { + applicationData = applications[0]; + await ViewModel.LoadApplication(applicationData, _startFullscreen); + } + } + else + { + Logger.Error?.Print(LogClass.Application, $"Couldn't find any application in '{_launchPath}'."); + await Dispatcher.UIThread.InvokeAsync(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.ApplicationNotFound)); + } } } else { ShowKeyErrorOnLoad = false; - Dispatcher.UIThread.Post(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys)); + await Dispatcher.UIThread.InvokeAsync(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys)); } if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false)) { - Updater.BeginParse(this, false).ContinueWith(task => + await Updater.BeginParse(this, false).ContinueWith(task => { Logger.Error?.Print(LogClass.Application, $"Updater Error: {task.Exception}"); }, TaskContinuationOptions.OnlyOnFaulted); @@ -331,13 +385,24 @@ namespace Ryujinx.Ava.UI.Windows private void SetWindowSizePosition() { - PixelPoint savedPoint = new(ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX, - ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY); + if (!ConfigurationState.Instance.RememberWindowState) + { + ViewModel.WindowHeight = (720 + StatusBarHeight + MenuBarHeight) * Program.WindowScaleFactor; + ViewModel.WindowWidth = 1280 * Program.WindowScaleFactor; - ViewModel.WindowHeight = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight * Program.WindowScaleFactor; - ViewModel.WindowWidth = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth * Program.WindowScaleFactor; + WindowState = WindowState.Normal; + WindowStartupLocation = WindowStartupLocation.CenterScreen; - ViewModel.WindowState = ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized.Value ? WindowState.Maximized : WindowState.Normal; + return; + } + + PixelPoint savedPoint = new(ConfigurationState.Instance.UI.WindowStartup.WindowPositionX, + ConfigurationState.Instance.UI.WindowStartup.WindowPositionY); + + ViewModel.WindowHeight = ConfigurationState.Instance.UI.WindowStartup.WindowSizeHeight * Program.WindowScaleFactor; + ViewModel.WindowWidth = ConfigurationState.Instance.UI.WindowStartup.WindowSizeWidth * Program.WindowScaleFactor; + + ViewModel.WindowState = ConfigurationState.Instance.UI.WindowStartup.WindowMaximized.Value ? WindowState.Maximized : WindowState.Normal; if (CheckScreenBounds(savedPoint)) { @@ -365,13 +430,17 @@ namespace Ryujinx.Ava.UI.Windows private void SaveWindowSizePosition() { - ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight.Value = (int)Height; - ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth.Value = (int)Width; + ConfigurationState.Instance.UI.WindowStartup.WindowMaximized.Value = WindowState == WindowState.Maximized; - ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX.Value = Position.X; - ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY.Value = Position.Y; + // Only save rectangle properties if the window is not in a maximized state. + if (WindowState != WindowState.Maximized) + { + ConfigurationState.Instance.UI.WindowStartup.WindowSizeHeight.Value = (int)Height; + ConfigurationState.Instance.UI.WindowStartup.WindowSizeWidth.Value = (int)Width; - ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized.Value = WindowState == WindowState.Maximized; + ConfigurationState.Instance.UI.WindowStartup.WindowPositionX.Value = Position.X; + ConfigurationState.Instance.UI.WindowStartup.WindowPositionY.Value = Position.Y; + } MainWindowViewModel.SaveConfig(); } @@ -382,6 +451,11 @@ namespace Ryujinx.Ava.UI.Windows Initialize(); + /// + /// Subscribe to the ColorValuesChanged event + /// + PlatformSettings.ColorValuesChanged += OnPlatformColorValuesChanged; + ViewModel.Initialize( ContentManager, StorageProvider, @@ -402,9 +476,15 @@ namespace Ryujinx.Ava.UI.Windows ViewModel.RefreshFirmwareStatus(); - LoadApplications(); + // Load applications if no application was requested by the command line + if (!_deferLoad) + { + LoadApplications(); + } +#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CheckLaunchState(); +#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } private void SetMainContent(Control content = null) @@ -413,6 +493,12 @@ namespace Ryujinx.Ava.UI.Windows if (MainContent.Content != content) { + // Load applications while switching to the GameLibrary if we haven't done that yet + if (!_applicationsLoadedOnce && content == GameLibrary) + { + LoadApplications(); + } + MainContent.Content = content; } } @@ -426,7 +512,6 @@ namespace Ryujinx.Ava.UI.Windows GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache; GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression; GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE; - GraphicsConfig.EnableMacroJit = false; #pragma warning restore IDE0055 } @@ -483,7 +568,10 @@ namespace Ryujinx.Ava.UI.Windows return; } - SaveWindowSizePosition(); + if (ConfigurationState.Instance.RememberWindowState) + { + SaveWindowSizePosition(); + } ApplicationLibrary.CancelLoading(); InputManager.Dispose(); @@ -507,6 +595,7 @@ namespace Ryujinx.Ava.UI.Windows public void LoadApplications() { + _applicationsLoadedOnce = true; ViewModel.Applications.Clear(); StatusBarView.LoadProgressBar.IsVisible = true; @@ -523,12 +612,12 @@ namespace Ryujinx.Ava.UI.Windows _ = fileType switch { #pragma warning disable IDE0055 // Disable formatting - "NSP" => ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NSP, - "PFS0" => ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.PFS0, - "XCI" => ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.XCI, - "NCA" => ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NCA, - "NRO" => ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NRO, - "NSO" => ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NSO, + "NSP" => ConfigurationState.Instance.UI.ShownFileTypes.NSP.Value = !ConfigurationState.Instance.UI.ShownFileTypes.NSP, + "PFS0" => ConfigurationState.Instance.UI.ShownFileTypes.PFS0.Value = !ConfigurationState.Instance.UI.ShownFileTypes.PFS0, + "XCI" => ConfigurationState.Instance.UI.ShownFileTypes.XCI.Value = !ConfigurationState.Instance.UI.ShownFileTypes.XCI, + "NCA" => ConfigurationState.Instance.UI.ShownFileTypes.NCA.Value = !ConfigurationState.Instance.UI.ShownFileTypes.NCA, + "NRO" => ConfigurationState.Instance.UI.ShownFileTypes.NRO.Value = !ConfigurationState.Instance.UI.ShownFileTypes.NRO, + "NSO" => ConfigurationState.Instance.UI.ShownFileTypes.NSO.Value = !ConfigurationState.Instance.UI.ShownFileTypes.NSO, _ => throw new ArgumentOutOfRangeException(fileType), #pragma warning restore IDE0055 }; @@ -548,7 +637,8 @@ namespace Ryujinx.Ava.UI.Windows Thread applicationLibraryThread = new(() => { - ApplicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs, ConfigurationState.Instance.System.Language); + ApplicationLibrary.DesiredLanguage = ConfigurationState.Instance.System.Language; + ApplicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs); _isLoading = false; }) diff --git a/src/Ryujinx/UI/Windows/ModManagerWindow.axaml b/src/Ryujinx/UI/Windows/ModManagerWindow.axaml new file mode 100644 index 000000000..0ed05ce3f --- /dev/null +++ b/src/Ryujinx/UI/Windows/ModManagerWindow.axaml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx/UI/Windows/ModManagerWindow.axaml.cs b/src/Ryujinx/UI/Windows/ModManagerWindow.axaml.cs new file mode 100644 index 000000000..98f694db8 --- /dev/null +++ b/src/Ryujinx/UI/Windows/ModManagerWindow.axaml.cs @@ -0,0 +1,139 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Styling; +using FluentAvalonia.UI.Controls; +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.Models; +using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.UI.Common.Helper; +using System.Threading.Tasks; +using Button = Avalonia.Controls.Button; + +namespace Ryujinx.Ava.UI.Windows +{ + public partial class ModManagerWindow : UserControl + { + public ModManagerViewModel ViewModel; + + public ModManagerWindow() + { + DataContext = this; + + InitializeComponent(); + } + + public ModManagerWindow(ulong titleId) + { + DataContext = ViewModel = new ModManagerViewModel(titleId); + + InitializeComponent(); + } + + public static async Task Show(ulong titleId, string titleName) + { + ContentDialog contentDialog = new() + { + PrimaryButtonText = "", + SecondaryButtonText = "", + CloseButtonText = "", + Content = new ModManagerWindow(titleId), + Title = string.Format(LocaleManager.Instance[LocaleKeys.ModWindowTitle], titleName, titleId.ToString("X16")), + }; + + Style bottomBorder = new(x => x.OfType().Name("DialogSpace").Child().OfType()); + bottomBorder.Setters.Add(new Setter(IsVisibleProperty, false)); + + contentDialog.Styles.Add(bottomBorder); + + await contentDialog.ShowAsync(); + } + + private void SaveAndClose(object sender, RoutedEventArgs e) + { + ViewModel.Save(); + ((ContentDialog)Parent).Hide(); + } + + private void Close(object sender, RoutedEventArgs e) + { + ((ContentDialog)Parent).Hide(); + } + + private async void DeleteMod(object sender, RoutedEventArgs e) + { + if (sender is Button button) + { + if (button.DataContext is ModModel model) + { + var result = await ContentDialogHelper.CreateConfirmationDialog( + LocaleManager.Instance[LocaleKeys.DialogWarning], + LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogModManagerDeletionWarningMessage, model.Name), + LocaleManager.Instance[LocaleKeys.InputDialogYes], + LocaleManager.Instance[LocaleKeys.InputDialogNo], + LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); + + if (result == UserResult.Yes) + { + ViewModel.Delete(model); + } + } + } + } + + private async void DeleteAll(object sender, RoutedEventArgs e) + { + var result = await ContentDialogHelper.CreateConfirmationDialog( + LocaleManager.Instance[LocaleKeys.DialogWarning], + LocaleManager.Instance[LocaleKeys.DialogModManagerDeletionAllWarningMessage], + LocaleManager.Instance[LocaleKeys.InputDialogYes], + LocaleManager.Instance[LocaleKeys.InputDialogNo], + LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); + + if (result == UserResult.Yes) + { + ViewModel.DeleteAll(); + } + } + + private void OpenLocation(object sender, RoutedEventArgs e) + { + if (sender is Button button) + { + if (button.DataContext is ModModel model) + { + OpenHelper.OpenFolder(model.Path); + } + } + } + + private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) + { + foreach (var content in e.AddedItems) + { + if (content is ModModel model) + { + var index = ViewModel.Mods.IndexOf(model); + + if (index != -1) + { + ViewModel.Mods[index].Enabled = true; + } + } + } + + foreach (var content in e.RemovedItems) + { + if (content is ModModel model) + { + var index = ViewModel.Mods.IndexOf(model); + + if (index != -1) + { + ViewModel.Mods[index].Enabled = false; + } + } + } + } + } +} diff --git a/src/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml b/src/Ryujinx/UI/Windows/SettingsWindow.axaml similarity index 95% rename from src/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml rename to src/Ryujinx/UI/Windows/SettingsWindow.axaml index a0a75f611..de3c2291a 100644 --- a/src/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml +++ b/src/Ryujinx/UI/Windows/SettingsWindow.axaml @@ -76,7 +76,7 @@ Tag="CpuPage"> @@ -101,6 +101,9 @@ + - \ No newline at end of file + diff --git a/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs b/src/Ryujinx/UI/Windows/TitleUpdateWindow.axaml.cs similarity index 74% rename from src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs rename to src/Ryujinx/UI/Windows/TitleUpdateWindow.axaml.cs index 7ece63355..af917e7f3 100644 --- a/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/TitleUpdateWindow.axaml.cs @@ -1,21 +1,22 @@ +using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Interactivity; using Avalonia.Styling; using FluentAvalonia.UI.Controls; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common.Helper; using System.Threading.Tasks; -using Button = Avalonia.Controls.Button; namespace Ryujinx.Ava.UI.Windows { public partial class TitleUpdateWindow : UserControl { - public TitleUpdateViewModel ViewModel; + public readonly TitleUpdateViewModel ViewModel; public TitleUpdateWindow() { @@ -24,22 +25,22 @@ namespace Ryujinx.Ava.UI.Windows InitializeComponent(); } - public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ulong titleId) + public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ApplicationData applicationData) { - DataContext = ViewModel = new TitleUpdateViewModel(virtualFileSystem, titleId); + DataContext = ViewModel = new TitleUpdateViewModel(virtualFileSystem, applicationData); InitializeComponent(); } - public static async Task Show(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) + public static async Task Show(VirtualFileSystem virtualFileSystem, ApplicationData applicationData) { ContentDialog contentDialog = new() { PrimaryButtonText = "", SecondaryButtonText = "", CloseButtonText = "", - Content = new TitleUpdateWindow(virtualFileSystem, titleId), - Title = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.GameUpdateWindowHeading, titleName, titleId.ToString("X16")), + Content = new TitleUpdateWindow(virtualFileSystem, applicationData), + Title = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.GameUpdateWindowHeading, applicationData.Name, applicationData.IdBaseString), }; Style bottomBorder = new(x => x.OfType().Name("DialogSpace").Child().OfType()); @@ -47,7 +48,7 @@ namespace Ryujinx.Ava.UI.Windows contentDialog.Styles.Add(bottomBorder); - await ContentDialogHelper.ShowAsync(contentDialog); + await contentDialog.ShowAsync(); } private void Close(object sender, RoutedEventArgs e) @@ -59,9 +60,15 @@ namespace Ryujinx.Ava.UI.Windows { ViewModel.Save(); - if (VisualRoot is MainWindow window) + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime al) { - window.LoadApplications(); + foreach (Window window in al.Windows) + { + if (window is MainWindow mainWindow) + { + mainWindow.LoadApplications(); + } + } } ((ContentDialog)Parent).Hide(); diff --git a/src/Ryujinx.Ava/app.manifest b/src/Ryujinx/app.manifest similarity index 100% rename from src/Ryujinx.Ava/app.manifest rename to src/Ryujinx/app.manifest diff --git a/src/Ryujinx.Ava/rd.xml b/src/Ryujinx/rd.xml similarity index 100% rename from src/Ryujinx.Ava/rd.xml rename to src/Ryujinx/rd.xml From 14ce5102fbf7a1c0a9e495dacb16aed0e338e5ec Mon Sep 17 00:00:00 2001 From: Stossy11 <69031796+stossy11@users.noreply.github.com> Date: Sat, 8 Mar 2025 21:06:46 +1100 Subject: [PATCH 2/3] Fix emulation --- src/MeloNX/MeloNX.xcodeproj/project.pbxproj | 25 +++--- .../UserInterfaceState.xcuserstate | Bin 4969761 -> 5073914 bytes .../MeloNX/App/Views/Main/ContentView.swift | 5 +- .../DescriptorSetCollection.cs | 76 ++---------------- .../ShaderCollection.cs | 2 +- 5 files changed, 21 insertions(+), 87 deletions(-) diff --git a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj index ce9b31ccd..9af36c2ef 100644 --- a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj +++ b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj @@ -32,13 +32,6 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 4E12B3A12D798BD100FB2271 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4E80A9852CD6F54500029585 /* Project object */; - proxyType = 1; - remoteGlobalIDString = BD43C6212D1B248D003BBC42; - remoteInfo = com.Stossy11.MeloNX.RyujinxAg; - }; 4E80A99E2CD6F54700029585 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4E80A9852CD6F54500029585 /* Project object */; @@ -294,7 +287,6 @@ buildRules = ( ); dependencies = ( - 4E12B3A22D798BD100FB2271 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 4E80A98F2CD6F54500029585 /* MeloNX */, @@ -482,11 +474,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 4E12B3A22D798BD100FB2271 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = BD43C6212D1B248D003BBC42 /* com.Stossy11.MeloNX.RyujinxAg */; - targetProxy = 4E12B3A12D798BD100FB2271 /* PBXContainerItemProxy */; - }; 4E80A99F2CD6F54700029585 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4E80A98C2CD6F54500029585 /* MeloNX */; @@ -704,6 +691,8 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); GCC_OPTIMIZATION_LEVEL = fast; GENERATE_INFOPLIST_FILE = YES; @@ -815,6 +804,10 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); MARKETING_VERSION = "$(VERSION)"; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; @@ -889,6 +882,8 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); GCC_OPTIMIZATION_LEVEL = fast; GENERATE_INFOPLIST_FILE = YES; @@ -1000,6 +995,10 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); MARKETING_VERSION = "$(VERSION)"; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; diff --git a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate index 90507c9d7284e89c0defb14b6cd239fca5b648ee..1371a5adac57597b282e296346544c7db7c225a2 100644 GIT binary patch literal 5073914 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

}X<2FY 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 z\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

VQN*)j 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�ihY36I1HkHiU&#F;{x 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�j&Je+G|ro9dzd=mvJ@HUC>khq4ALQF&j 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�WAy6doiW^ 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

br!cEW@sSPY?avR=*DPW<1mRmf6^>pYQ7TD=S%p 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

*lXE$$h>S1 zHedEG2rW;H?v`gmZ_9I03Y#vkLp>VM5W6myZ@FB{nu4D>IOr zvQ(fsI$fz#zsDL{smqo98N?7KvxYOA<086Pc@3Yx@)mA%<$WIE9jlU(9GO?8CM{o} zw^f|S#)?$o8yeG##Vlhby4bi5pTBW4Zgk^L+}=j-*yzqS-bdz*|MGms*sh1|ZfpBmcCnZ9+~f{6+y0QZybnSPF?OyhCB58tf8ImZD)D9(j8sw?8^Xr{!TZ#b0lN%j-75{ z=T3Gb^UnPoL~lFY+)mx?JdW;moo9$o0X11}D-S}Jk-Ov7$oaPVQ{{e42pw|OU@p%UZ z<2Dc2wY7qMA6Vg!*nSYwX5B$zUbayBcdOH-IBxJ&-hq94_ zoY?h{e23&ZB-bIi4z)zThxB`>1CvGk4_Kk^sr73e?xU@QHO6C$SS^PJ-Rr& zh3)*v9`@t*4tvL8c@N8bSl+`gdCfcY_KO_9==YZ>xanVH`sE8s(*}F}vH@@SxkPta+1^hfo^_HKvwcn zfI`UetKENfTfbJK0o~B`ufrJ082qhY=P;i|xSwB-q3fe5$d1oDS`~dBZH~>34rK%j z(dkj0`hC{WQC%M0$!_*?g4;ppScp$ah%SzOj?X`q8aH|@18(n_cN}wP$Lb;Tv4%9J z8G1X`3jH2yPe)`qHlDToj=hd2LgwR5u=()?>_T_PPocNt=eUDSkGrko|M4LRo%jg5 zo{;Z^Tz;1|bV9BZxzO(k{hlaDBl5;gnmm-5p?-m z1fA%LE`OWEQdY2!BiP}$-#E`ju5guyJPtx9-P}o?p490{ou1U?$+Wn`lV6gLZ|F@w zba8SB!x_a`CgAo?ddJC`$b0f9e&!c`MQwl|EIgsjrn-vX}zBL7@v10HE!Tc z9!gM)x^$rr{Tak)ba_UXXY6=pAv?IvP41wJGj==k|IdHMOWyEb5cxmxx7HjC-7{=rM=cZz}b9?dL z^YKW7cb(Vc`O?_qy#3Gjpf|QYKNnk{UySe3`L%4|2i)cPi`?KAcX@&?{XT2R@3V$3 zL?adDsYF$DalvjE>~^66jc7^>yyJqr7v#Ml?}eGnW*&OGums&*(A@>yUHG0O+zCP# zV_~a{)zHI5*)Qt$qKp^ixg^UayzkaJV^k*1Z{>+Zs`?D+4*n!MfKOr^6Xo&8veuv(!_F^=1u<6wW zEMf_Ey(-^Txvt7}Rj#XN(eG9LUj37|LFig?@}j$Iy1P~yIj&Ws25#$G3;N?baLsq% znwz?2vupm=HQ&!`D_D*Dx%Nj8`YS3K$dAwat1kNdt3ACL$3#}4)4z23mrnoEDYy11SWpMO0QZuEK%a^W4<8`BJ#uYXHx+M&1WUC`Zi-CgfRA7-+R zOZ*pvZlt0NZPD!w8E?pQLzWwQyJ3?XfAJ&;{rw4%@!r3q6O-7aCmUapo5B>MB>MPU zzQ2cKufJEahIPpC_YQWk2b=wUi>JKcHSdDZO@HgA`?(pHc*Mv3-}J_tdcC;_pLcUV zZu6#1ZeHg(uY%AmH+L%u$wZ@I%;MX19dhB5+O+_Kv(pMPr#)0xFwyyKR= zZXHGDTfgx;XV9D9X${@d-7VeS`imPu=(g{~?G%*2R<}p7p3~^|j*NHYxg*ORz1^|N zopShY-f2sFy!TFLd}r=-V>~mMjqk&q<*dS8-qFV$`R+UnLU-+TH^iqTM2@?uNK1Nb zcDFM1X-E^A<8R${KYpJzo;o2M?xVw+D86FqcET3_=e-LzfTpP>zb|@?jhLF%UQS za4~jx=)3fABb(UDb`En5oj%m*L!CZ+#T)+PLlAlthcBo~b!wrDM-6C1Q(DjpxA(|9 z9?APi-beC2n$JR(ptnbIJksx@wYcd=GCexMgCO*87<>I&8*lh`5jOw#D(`~OW8FRW zoqnvh$BD>*O&@cWi$D02zxW$D9^3t~ z+j{&g2tE0P&(Zah%w*#${H-U&DMeY_&y%j``pM6n!{h!5DpEjX6E$PO1wy~4l=;G-?eE!oTxY4J-;r5<-$5VIq>?34;7MZBTKyT0DqTgrn zNr)`Za#Mqz*z4IIWPTnEn?Em2Gj#X77kYc%p9$FXx!Zcal;y0%uFvIrF4uFpp3C+8 z68e3v-{&`i(2IaH6hwC~boZhHa=g&P3%B*6K5ZDnM5Ztuo4xS2UaaDK*5iI&Tns`l zW08fz_`H`5(dWx93}7hz^fU+VJZFC67Kmw6t9UL_|LY0<^2jQIRl*>R(< z@{k|zc-4Yd$o#4u9q5eS{8nq|mF`~Y?p1#VGLKzc3qr3yCOsADgl=EU_*$OVvb@&Y zYn!~jgd7sM<#NSmjaZaH09988~NUh!Cr6HvVl#=@n#SEIf%{P{DXf7 z-n`{~5PJI&{?=Rf^EN(-NR0b`>y2;q`gS=!@9odH&9^prdz&}>7lhuqxpyf@O**oo z%Xhkb=MLYMB!c0LVl29NXSa7g|J_XHFrP(u$2)tyJBiHi&Ty6s=(7Xux2WquVGlMwKV3EK&6q)h1CtCkurs ziuXn>NomT`gf_IN6TRrm0Q3=6zNq`LSJWHa;x2MTea1^(2jOToiF$| zy&OOn(d`!9=SM%m@0{Tr-VwuIF`^)Ij2OfsE_#a*AN|HiOj2ZtQGmMiV*v+|Ic97! zQ-N0KE@pr97IO$wS%ytxu3`;qv1?5EV#*a$u9$MgyoP>b>Nn<{ARH?)87PMCV(Bhc zRpf}Jhgc19Td_Ja68{dwnu(i=WwTiRRxIDoSR2`l`|*3M;n-omq69uKb~E%Dy9Yy= z!E836)7UzVt<%`LjD4JwoZ>Iu1mQSoNY9t(B2G4Zew^I6(KugI81IPFhW5xDr!!sY zj^5(*MR##@7iS2=Sj>KI2I06-$;3BwL$`5dj4MxES>oy~u1(_pgIfy4CNAC^`jiAD zB0KphND<0Xfy(G3BvWW2_6q4Nv;#ea^bk76Z+O4|p)VY=TR6ab!_{${Vebm-F+2i$ zgzX>R&X3qSd<9#FZ*ZSSJmzT-j`uN1Ny`^xBqzFzr^|TmFkU&DGKTR?LKpGu7SC?+ z=CP0^EXO1Eyq;rL0& zi|*pP%lLYWUyWvbhfU-6q&I!BYkc|Q%N1X)_;STx&kt;28y9&QgcF4DolB6CG`Ot< zI!KTQyCtw&0{7(iSi=csv6G{m$My*x@*xN(j717k^ED+YgYQy8TP3VT9qQ4V!RR!h zP7~@h;cVuzfJJQJ2v2yW4BTEK??@zXB6$M6ZMJXWsBx32gq^Am*dH&o-mC&vx)DHvPJ}=>N05*++os~Bq1jaXoN13wxAVl=|E@P zUQ+K!+8cS3E@vgH`5wI`b#qC#pu42FB}*#3r5cU*r}F+(>)5~#Y-TIl(M76@T;Upb zxsQ%h=_j>(sdG@C>eQkxa-?=wslUZ`scn{e67yNaQdZz^rFK85ce0zk+zG;IyfKYl z(^SOgrD;b;2IBjaW+Cn}jhjnzh+jC$8FZOOmucK#ntMSw?I&a=8(*P|wE6J)X$w<~ zl9a(a(%LI+cVtf6o4yP{Z)u02yR^DXJC^aR;a468;dHi2my3GzN4M!@Oeaq|S<>k( zolVj`3&QCmlaSBw-t?c7oRs9JIHf4dH`Jgu`baNd`dQd3{g3RyzXR#zNPmpq_#K<2 ze;tIsh(dH?5f^{!3-|LyYSQrqRq@6z^!mkSeBKvlIEPKX@O{b<4R@Kr&G`-1aE9#U zq#(M?pvw&IFhe!kGL;$3Mi&|Emci#|Sk5ZGXFcAL!Co2uMCJ_F`J3D5EyDwJmqB+K zp7A0GfB7k2Q43prIhO<63c?w6n^DG$@??}Hquw&wBx3{G)1QHOZ^ohc&SV_PB384O z4eVeS?lPl3GRlLp)SHoHC zmc?#ad|$JKiBBTDBa6IQ)mhx1j3VO>@6WwLeT^8MCX-FStvjMiR5yg#e=XT8N8?r|UAnXLZ?;cU9d7LNq@K4eQpT6COEKiTBV)|$bL zVLX$NBb&R*wgB5@vstzyoaF+Sxr)D)&HZG1!gF2*;p{2##_W2{J`|sqeJLy0&LPg@ zF0;G2?EeMf908vY3ti^WWe#_kBQ;;soNsA^E^>6j=jZ57FZwb7@5o`V9P5xd#}8~~ z8+yyJ3;pJBb2$zoOOES7_$#;fRXWPh7MZ`=!Wo_h;hZ6Kmoq(j%bAISRKlh?zo9xc zv1?BGa>|ucuAFlDP1bNu{pQqf&WWt$BzMtWPTl2v6@+uikt-5Wa9g<&ksaTGTt#tH zxonop-^%6tnX4`ha6h?5u!D>IgU`zy6Mg1RL1v0jocicAw@!2GG`B8uccUl08O36b za)RH{MecL>{M=V?qq%Qz3-8Dij|9k^CoxG$j^6U5MR$30mnRchC{Js~v7Xbs4#Ihp zq1(JN=9MR}EP3^o*Cu(Vu#_!q!+Z1o$Zqy>p1=5;+x*K@UZ9VB^5x5iz4Fx~g2u>^ zuN@uegw68JWEm@2!#ez}eC{XTetzO-+<$&=%&*t{)$w`xyW%$U+a&)~RP>yRK`0B*sDN4WG*m>Aq+=v1;(J? z0uz~xECn`ll4n8q>x2|Q=C6mcgacefcV9n8Z(qL&!UbdUIW{erlGLQdt_9^QC|5zb z3d&WmHu^27--350*2*QQ@J5VStZmN*Y3i(@wd_N0i zAQSGVP%TEXikd=|l%wr+CD7+k> zU-*06XyG5&f_D`Di@%Y%@Ez{)0KFA{itY;QuJ9Y)1>quz$wveFvzTAFAB2nQwy2Cn zflX{>F9$e;K8ngzEGqUYrn6$%(L*sk6e~e# zyuVmQ>{hG?-dpTf+-5QFDyGL`?}Ko0dla{S@oapBt&7*d*2U}5jFz;b4ZW~?@oCIw z5ldN%E{p53_+}1rIS7}COf+;+!fqw(Rw6!$NJ28aqeL3yEm4JUs7_7vR-!%)(VgFG z4VP%ax9G3L5_D4HZV)aR8$Fbiy<~S}EGbV(SxWxGQI7K`k9f>eY+CXquY+)@cqAn` zsmO?qOX;|jeoDzystaS7$sF`hN)M&hu@UbtwT&HI55lFrw{&joQrf#p>$7xgdNYFA zxX;qIE^X`5wk~b!(kJ+x)BJ(EEPXo&mkEeYEaLJRx-6s1GAYPP89LDwUHI+Qa2dOm z8NgtMF%s`6Gah-%>|_^v*oWTA{EY7WUTe6F?#ldzOl2Mh;j;QJn*(nu+XHVXyPs=( z2*Tw)M|b7)R?hp&<)tijv1z#o8qoy1mXoiXT;=2{Cs(8l(%9!zQD~@)LX^u z=&qvfD(bFcernN;S^UV=AY4fgm1M7^+e$K4lBbd^mGo9=9^PNc`z!6|Acr{25sspZ zN)Py#r@Z4s5U#A_%KE7+U*(cS;C3swrX6xr?n!TKSJ`Hjm$DJxfy&$1iN96Z{Zu~A zNlx)L2v_mODtfKb2%lGF0B*C&6c(}x--#-2uF82X@h7*@Wffgkafem@3&K?sQiS4^ zLKjsl;Pb0~Lk((E5AUdIud1Vvx#~D3Fd4m7oq>L{?B}YI0SRtD0QZnxWrn`mNTM@vPw|e&-D5xQGs_ z-NSCx>{jhb5U!q-N_0S%)yJ}c#pts7K2CEMH(31@cBuY72-k>8bYc;QWaL4oHFR1- zr!^{5mFm=_IsI79D!xY-HGW_V+xd|_xV;+QQA6Gu^45^I#xq{<8okx{5QJ;$uBPs4 z>aM2mcFlB@q!puChaPImUQ4&NWUM7mEm>;mtyVj{zn1scn#g3PGM$;sMi;eqv6llJ zonzb#!gb>iCO*2Tn*^Uo%YvP0(B2mgv{-wTA1qN0z!{aeH-t<8ctKmjIdTHKITB*op4yokVZ- z{@@lbv1z@x{KtnNT;Hzs<*P53-(?Ngm#h9)=(oOp>ldIly_tgU>g%rlV&tf=hx!|E zTlM#I5#NFOz615$RDGM(_qQ7Oem3}oD7c>nIcUaErs4A%Y(bw5j&PQ{+z-MLk{ zP9t<0q05LAq$VvnsYo|^(g$5c48rF}jKGaXjAJ6+5wVNC$Q*HyL;Ql?B95cqh*P-f z2w5VY2H}SB$b-Ea_C@A~KV$Pokw}H^8s$ZAjS5l;n>K1pQ<~EfyEc-qkz9@BY9v=9 zx7kR)jr7}S5kK)4Z-Q{+sKg*PA#~8#JvFvlW4krZz&8wGDY|TYfIm2oE*rlH!cC$R zi*&g6CU$6&i$WBkI3=l0J9OGar%iO)WGKTK#TaI@iOXE&I=X0bhktm;W1ivmns`T3 zd7H}HRNkf;$xJr%)>MwB`fZvYH{DdGruFE>JnYr;9s5u;g%nf zgc6jd9J**(g=*BK4)t++Exn_qye;KzDR0Y3Okp~DYbi%d{kB}lVq|K$pKC$*+ep~! z+wyqBw^OnCx2Jd%gj?yZRb=$mDh5fhX)CwYDm!*kJYSF3MnLwh=+ zn^x=jh2J^DIpk=ihgNQ@)ot8y>$vE;bqZ3G4u7k4Zu0Rp?x%H2blrLfzvA;+-$S3R z-v{9~HfxidR1`p`ZFJg3r)_lErUtdCODhJknzd{|7j3rU^V{sgjkY;}+iT+;ZQNO# zXUN><6>s=22)ET++mF$2+o(iGmbMuvLtE_Cb|W&keH(<^*}PqTYN5M!?a*7h&J4z; z?c7$o8O&l1c5NqLJGt7))lRNmb}dA=z-Z?Tb*HQs|()dungD_I7I@ z!Em;70bRC#8H78;AU3+}kcq++qaMw$Lx_Bwh;M|nHS+fm+*jc7u1^wv?1j{5EByWP=Eca*8)1lDm1 zdv*E@Z|Kw%n|E5sZgkh_GvY={_lQ1#;%>^>nvAixjM_$*==^t$JZ1> zH=X-2odqmr8FF;iLua?uc?&;r1zmT3z`r~V!d?8WE}syE=(wLQxzKf&5zNHrb=i(S zyBx!2UGDQJ2zQN!PP^)~t4_P>vTJJ6@dbIPLQne8A6;}EiqG#l8aLW?B5tp%cXV}U zT@N60*Pr=?qv)-xo9n8(uDa`bo{PAh?-Ejg1`K35zoOf2GIo=vn=IY**3Bl}it-Ij zX^!`HYegH{F^us{Vk+}k$P)C?O}=h7u~+w~#K7%#m!tbs|`qf$qKo-Rn>v zf2+Iu>E40PbY(8y*j=wZ0(@SNl(@|vHtA7}8q~(k^>F(=`Z9o#=(2|{d$_|M^V!BV zZg2}-^srlx|9}1yp7V;gct=lr^~{LOJ+qRXoan7*estGUcRh&(o1i>Y|?8bzMH*%maOo<4s$CA_ltq8`c*{_{bcW_+kP_klc&Ed{q@#A4&LA2 z`}==IF7l8M-8O1|H`muX)G&AUr7GWBlDg?ro562gM>TVLl~0RnW;)gV0h6H+7NU>y$b$anOh7o)M~V0Sgxdj~JVrh}Iu-(a~0%QaZ8!DqR^W&RAp zLp~xodC}RBGL%OTL)_93w=~2p4QWOT#-q<6fANG5L3pShhbF)tLvvD^a=87WZRtQ~ zdee^q3}Pay(CJW}4%O+<{T$?He!(pa{Wk~?OU&n_Ko`U8Hq36rGLe-WxVvHAF-+cJ z@(z=C*tfK%9eNuk$1wd4bI-$iBGa%LY{ktDv)AyHc*F2E*nId(4xzi@m(bhrYdj9Z zBWyY%5>c@0h#1&)gnT398X?yRx%?JuctlZ3Pzv3Q7{+{7u$r~VF~aU6+}4QQ9OEXs z9`T%4ybZ!5{jHI{dn4lz#{G;eh^|LYU?Dzl5N^+$Tvo=F>;NOYs^yg zJ4U}_zUMdY2jQ`iakpa=@EJ+b!C3b+)^20%HZ~^>7|(iiIrcc$xPdOmeMEc`k)8b5 zVO$Z)Ql3gwp&>oc={TK^)9JVgOkyh2S;ii2bB_n;V%$?+@S1mg2*Tst-gxgAFYkDH z$IClDH+d<5-p0!@Uccjgx5vBb@iL8X!BAFWukjCq@C0v|kPn+r=*|>$H(?ceo3M_( z*mS}v&S2LG=dtSq`6kFUL9U5%O>~WJTCfCE~Pi~AGo!k<)H`zNTyR*qNk$Li5=CcUBOps=KKn^fomC>9Oflw>9-^3Q+{RPL*$}TvO$mD%aF5=-2PD zhNt#s9y>XWyPbN2TiitlQ{B^4yG^y*w2#P01Nx!MX>(Y|MszvtH?DJ&_d$4iRO~Q4 zHVH{gQj(FGQs{KLPN(a1dIXJVN^`n0mMv`OM|3fLKRiE(A~@)=xt_S#$nT$3t5a^ zXD-LCGv%8p*G#!)$~Dt%&b-W3{z5miQc-{sl%^bV%+kXww>7ISt!T?oCNY&6%w`3v zS<41~;8GBt?TxduQiO`=bGANb>vHx$rZ62h=eJkGvvoRKr?YiA`v~rE_6e@=A_&h( zL27g{Cj*)A`E%UpoLsoQIo>g+5G`?Mb7Y>=o{s2kj+>jKyE(nk-JJf&GG`w8p5ylB zeoT5~p4*8Dtm7!Uo2$3Ee{+kML3o}`=eezUv4}&6c*r+Tu6c6JlWU%S=jnHze&9GuzmS4(8cyp55lzZQd!~24TOq8lGPnUCwXE00yJW`Szc`iLLy`dF(L% zPi}LU`#j{oAiN+UI$faC1v*`jmF(msHzkQ+IHMSgE*4B?8g6vK9OknK?^q!30(lq6 zyWk9GadQjwwm^;r`d#3=z2GJ?EsR7O%3!aBe!oB+`+G66kYeH`QvXLx{4SLk$wPFF@IDlv#fQgRVNW169hmF{z8JKWt$cem2rt?Y?+tdw`9 zyes8hxrVj4xs`fbDaT6vuJpZLxeJ+AUgAvhst!j=ptXhZ7SGld#(b3)N6zFYr zT5@C4)oyEbdF;BnGIm`p-)gy5%e7jr)&Ha5t^%zp+bsZ3k?u7&-6aB|lr$ou2#83B zgn*=obVxUXh*Ce&h)5{i-3`*U>F#cjI?uUyZr2{)81LGbt1koii6P8kCl_$H|2*I^ zz6Y~)Fxx%Nw%csG%}z>DzULPv@ej72t0kEAL!+=gK=bBpE5u+gv&3>UXa1 z_S~$K>*?#3JDCCBFTs?iqR%^QT?<_%>cHl63T<}Jjo^Oj=QdGgJZYo1*5 zpmT$3Ki{)A@*Wya(cd>pK*PcSXSVXxHzGOzvuo39?s zbac0RHF{gUfdkldwcA>Kg=^fvu5095Bi9;JxO*Z7@JxWj!n{M#l4L03SgIctu zD?RXi*kHd6L-`ebY>;Wgey*dl4Q^|L9yaJY1GL0qJbju1>u?D+tk#CD!Tjbgz*Ot3H;4x2w$X4BKElg#;rXCHDW2@b_ z{y-bt($?S6_12lVsjY5mtG~5%EgRU3``POLx9NJ@Csf7fZEKG{w++H(+h*`Lo6zYt zoo>_VHeGHz#aYgCFNkc9M}7)Y1YK+|iO=8u8E$m@7r4Fc-m%@CZSR51+xyUuf#_|! zo7=9t?Yi4OlF_)G?fZEYM0TX07!4VKZgUhegUIfH7({S$y9-c=qLfCLyLGwS9qz78JH|7KKhVW) zyY04{-(ijT9oES1MJ&ZTcFVh4-re%~;Tpb-gbsnelo1K0%-RYGAW{ zo%oRv=yab>_vv(>F89r59t&7cbP(D97BPu~F7_wF=kJfgjqXp4+uQFQ``y|83dp>_ z5>=><-uAn>{kq$)yZw!5jN92ih0RX&}wXbXd}D$mwg=I9M6Nu;TXgsE)jHjSeJ+0;o)~F z#dox#4Z1jNx5IWj+?`(ZWdPoBSl+|(9+vm;a#peiy&ab0uznA_xx+h<>G0Jca>VT& z$;Fqn#T$;S;yBNO$kF8J?x?#ws<)$g`Gl(2^k_|LQwO^qmG7urN98&y*U@1NXB7WK zH%E_fho}6RqPPRMmat`m>Y?+N{$co{@arltfn(A`Phoos>}C-rdBZJq2$eGPx1Mu%i~5*SE4H3ak>|Mk@@sMe&T2JcKSE;d)jyVw3|LH%ju;Y z=2;LqW3MwMk@?JEY<^}N7t!6B=jiRs>mYJA2{t{Og=}Oe2X;Lx-&wiN%5_$*vu^XO ze$VRnY-0v7jWz7#U-oej9h`MfXYF>@Zf9=3N-=*X8*NxWn_6X~2(6g}TU zUu;2FY~_g+ zm#Wi~`RvDSUb+)RF2997FYEGh779{?D%7Dq4f&2%w5Bb+8H-LY>-4ftFE3yb?(p(* zwsAIyT!~8p5~GVN$w-MCy^ToGUv*nom!P|=yU^R!eVoIlSKZdt$Jq7ibL@IezH4$_lk1vX*K(7G z{Cr3)Ix-A*duQ z9a~*L#8INTito{lw@HZi-Uvxc1~Mb_4OwqgK+YRo=tfWa&>y|s@ON+g!f%X3)*I{C zz$Rq4A;S&5-T0Ti96+8MM|coKZramtutsj`y!y=Bu|^4*f_mRz^wx;2&wOy&>Pat>SFjzKKk*KIj&N0EY5yh|x6QkiPh z#NWEzjPGcLd%pcUJJIXy7eVBX&%2WrecrMA9p9%rm8go%?&$Q6PVeaSjxO&EWH3K7 zjzyg04Cm3s9lPD}`FGsHoqIgw3Epwn_wMdH$b2^^@9_b8yITPL-Yr5gWV!n_KjLQY z+UxFxAaYOUd%3asy_Woh?(VtGdwRR~CyTM^y>0AZ7yn|{d-C0r>z-Wqwa&3WhP5l&MItn-`~2w2lssc5bo#x>mc$VFID&! zpZB02`g|~kX)I$U2hr&Roj%a%16@A2#a-?Pk%s}PDNPy5p^JxK;qxC>$BjO$Lw&sC z;Shd7=7+->$^X#X!|~|%q3`5FH~mnShZ{H>MEnM83_ULZ_i>73*9}7PeKx- zzh_^dlV`Si=Dwbtzzsc5kBradc`nOyn>=q%M+Pzmn?Cp6=Qe#lnLk*`Cbr`H@Z5gS z4|5ECJeTjk)a0i)CHVw7{;NnOs?dsw^I*Q(2o#Ym;u<7f! zc$-+*^|gGj<$5jGYq?$*LBFr{`??hM>BBg5_gZ(aXCcRHJ-l9q+j_m7U0mcIZtAto zUOx{aZ(8(qFR%L5(|huFvX=uK<`~C0#Tm}=DhS_7M=8E#5Odhi-5`u1V+?s>$P(id zKI3z0(Snw=qBU)4&rnA5JL8$g4E|;|^2N9rgm1?r5lM+cj<++AnXKfeAYW0JZ)ijl z+R>3NbfX8;@y55G1!2s1q#!4``G_y5PeZ!WkAVzk1iFl=%a~)C$p)@-3thx~fZbyL z|L4EpbrAYJ)-aZL#EL^+3LtZ=!W2bsu|7t3u|7q2vC1J!tmf!D)<68qy&#M&bL?V# z&5!&K-Nn{h?0GC;BL}f*?4v|;f>X#BTdp{A#gQwHe&gsjj(+1LrwBE$SDfzjqAvr` zK^(iqv0EIw#hHkEit{uGxYOvTN`(_6g1(OtZ` z=q}zOmT&-l`~B50zBk3MgEz$gi_Ki%O%Nu~T>`x&@csm8cn_N=xSxa-s7PmY zop2{7@OcUUL!XHfla>$2#~0`{kxmooG?6Y7HNhPw`i>tN!7A3W0bL~8hR;vrMicGh zAV=_y#O^F{Ok_?Rm-x83#Cl5{qTj?RNsTOti%<)?@rb*mZl9~L?Z0wpuz9e!bkt>N@NzS0(B>GKqB?yzgO?Ey;cS&`Z^ef~@S_ik4 z^c#MlEkhWCdroSzq*Iu~d={~k<(vz`h&M(G@EKLmXGEV7T}B2nmI=7Ih)yFqjp#I@ z%gA2bVdN0*E%G7={T6E&zKbrx_sNUT58Y^3loEJH=oZ57X^qTbdpe@Gup7DyeYZp1 zh5eBw{1bhLmxC}W4(}mzR3}EWnEmK3N^eouxyj2QOlH$$Nr(_da#A8+GP#n;l}xT= z`c07M-ThX$qaDC_q7qP>k|?%TRu01iDD^JL7SqDgIy@Gw_ZS z@}`hCg}f<_a}qa~LT@Q9p}Q2iOQE|Iw}UXH??lR+RHO}~&_hbuQ|dOAjH%>FB}*#3 zrK*DWr}F+(o#;YWy3>>1=pxlr{$eHzSd5NS=_i#;sh$O4>IfOgj2=?!A@zq8#`{x$ zgxylNzMG&UbLps^h={B8=>EuZ#OFF%!TZ#9l^Zsx2a+#|^m|hot zmo-eEkR+rcEjmuGpY$@NZ%9`LF$6uN*F*Y=Ou_rpPseWQ_XlAH@6C`EyJYaL4EoGa z3!7xHe}=)h&kVNCFc({AuyuwttY;&eahDm~T!u$H<-Z`z_%^!CsLPD*Fk@=+Q126<<0mvvzdq9GA==P8FiOYcNy1mg6Bb)DLuBz)EGTv zl0B1dGs&1)p3Jgj)?4PxczJGl&1m}se~>vx1%Fn=tF;WoLN7aWy-vR^W5P+ zddRGYEHR0L_h(6j-Le$Hd$SD1E?K-Qi$1gHGmA~K*gwlX+-Fu>XHAZ+v)VdqHnNkG z_i&e4-CWjsG~iplN0(W3nbjR;?aO#JvyGkTBI`cvmh}kHoa7ANkxkxg@@A7aTZAZ5 zpto#tWYcdpH#gW59O#rb=+=tIkMY5dsCX@ma_kbuCq_UO=Wje+5N5T zzMt7wup0N1{YntNtLt}*@&!Kc-InO{-Co%2-N{U46*_%ar|;_YU0uF=m}4C0S`g-V zi(I@-jaIew%YJ<(f^e&{#HPYgkp9JAQY%^=Ka zublaiIcIllo^vHf(Ou44=q=~{Aj}m5o91#`xl)pvwAeM5e7WSxC08!Fa{1quOTW4F zo2w=r7{h#YmrHlK)*(l(UF=~WHp}%i2;YlI9O5J6dui}@-pfQ*-r;lFpx5{8^4@y% z`JUT+&nE9Z48q*8iANUR;{&`mcQHPq6f)py8BjX1;{Gc*5 zs7)Qdrw4B71Dk%(51W242>Cvc>jSwykn4lxtYR(eImMeG%;P@uWF{N$B1fM56r?bp z(|}g!G*5dv;cw*`$Y6#tjAdL4!n}ITn+Bhkw;1}&Yxlf$X-zwRMyGjonpdZJb(!}s zX7V>~A@2eH<5dvm3(!SAyXEuw`FvmVB_Sj^-jVMUK11ew<@kb%=q+D0beB(e`RY)Q zu8d_3?kj%`a_}X(%`anqdGgDWUvK$sl7AD2xWpB_H~$TMAM)P`!UAzfN)#!`NEX~> z0euvZsX%k=RX}G2hNFi9dMGfB8F+tzIoPehu^{}=dq2!YalGq8J%0EN_W02LAO6Nj zZ2jR9Z2jRXHnWW#?BX~Nc){x+Ech1j(Pcqh7IcRNGf|XpX-W%pQP6G$?N+cOUFb$n zyrZDJ1?4R$Z@~pDVkvqnxEkFR)LlW{72JaFM4^Ce*s4%V^iW9lLb@#^V_|s;%Ticx zg>&Hjg}uMizXr|zE?#*z+Dz~mqop`sP9ry zofg$;QJogmWl?un)Q&~vE-G(PH&9eozr`9BJwh}mIfL$sy1k-Txq-h~Oy*)T7fVZe z++49N=&sni5AS|x$;@(``+lqJR7e+9eG0eoK#obo%HLPO; zb}cSnak+}iRa~y(4|&3KUIbx@3>3#+B^uF$=CniyCEQa9_f(<}{cy`APV+hlKT1M6 z@?e*bKE?hYHKrN88O%_A<#)z2k;%+u8#?_+ryuF`qcfc2BA0OwB@(gK!Te^;YsXbXQV$C3RPFEWQ&Z5A!StKTbnQ^zgCl zAM5sG89$ciV_81d+s7~Q{!-pwDic}AMs{+L3tg1@l1fyiF5jTzQu-++U#V%VVJkb> zjU1(paU9!~vRNs&^hs>|@A@PKsY!?X`6M@a(EleNQXg;pWC0u5i`)F<5|4whbPSS{ zihLB~BT7*oU6$5mX*-r~z>iGjFLY7*AM94z=a*j0GFIXprPp(fo5)=HF89$}>8I$f zw3{ofyH5jT`7|T?{`6Z0FbkPKeGr77MaWAmfnm-r=RQebDe&^fJH22IomiJgk|HBfW+vc zY%)^fM$4ur6It<&vhtRdx2(KnYf>9GS5|LjbE-O>nK}=^S_9~YIZz%UQ zHZS)(OVC}pUFfacKF(p&a{iB$dyHMnJ;$!)w=p)1teI`OsU%LX^d(72Q_Fdf2sML+n~n zKEKTxR+OuvTop$#hH*?_9VdAdgkQPauVNC1_~_s(_w<$BzOvg_ZuzSU^kg#gS%dAr z(&twfxfg_$-X=B~$-#SkfUPPOr359ZNHcU=NvD-`TB#R(=+8h#Gnbe$tt@ZlY-A@VdaEo)W&Kw6-L6~^nfy*`Sh)kgW3S4mgRqJ>RCyPh zS7}N=bXR38daE*tdDygy+p4k|yH?qbU8~4fMXoAxRgtU8f4mC9ssS<3P1VxWr3uYx zi5yk+P}OZ!?S?z9`U}%p#8OtUnjP$BF9$fp%OI@gjnyjAkRQ-zHGNjoWwog+VL5KD znog_fw3<$<>9X1l++nr5ybi+ZDJjLL=%RXgzQpHOccay7;P$F}NA+*`33paq=IXyP z9KBU{bJfS8yXuqqgFn$<^)o?OLnk$CRihlO8OcIqtRYVgS!&v(W^Ce;nq1hlruWvg zY0dn6NJVP$HTAGx%@%x*K5EKWb1vK1$3c!DN6qtGf6n4vWE4u@D4e65AUd-4|(g?rvZ&-Xj#|?DcKtB!SYtV;r{K<6OR|7d3EMXZd*v>g_bB~8S3Brc{RzvsGQ2z}Rl9xRH=6G-8@A-i?3}ytQ`JF$Q#tih)SiZ*Bg0P9bn#3m&Ns*(8yK0hw zOxUbRIciXwx_pDb)x`ZYX-7voGX-yKqSvNxig8R7VgsTvW882(3^e? zMVC!=+0-32oysaMa)s;YqN&}Q{{QDc<{2+|9fZxiqnW*$y^qYz@=<_7=&e}^bk|IG ze#13vR)%ls%XDnj>}C))k5CZZHkYxvJk4ckuD9kkX+E1Z>|r0?+x!r|GtG~2kLSF^ z_n}2x65uXd=%a;vEh=NL7VYW8kI2!&U9}j*U~JZ60c+X7X13vPwQxTzj&q7LLHJ!9 zyzx7|e)l~-@4KP=icP+o!+PB1cW&;xOI+m!57Fg!y8O-^wv0y>D)1Fm(1qV)4O{yB zmcFko8`79&ct=ZnwfrA4w;aa=CZo5O)6j3rS^R@6Eq8J)2)|Fr2UJDo?kJYSF1MYx0QZdbzwZq*^lpBt8-lB3OZ=@ z1iQ7eTdUVW_`|z=O*eG;!&qiB4_*H7FK4-c8*CjDJGAy)Y8^!iQjvz7nmwm;IHp8U!bY}$4jHf=kTzuClY z_Tu}{_5?a^tK+u%X(v;=EEK0470^RFJ+%9VMtFa_=D4SJ?x~&kw!4g7+Iv@feYQ_c zE(-Gn6|r@DTer7$dt0~fMIZVzkkQO#87o=CR&?23mwul$Y=4qRLD(TZnaGMRI@qm) z-8%Sx(jh+uDS~%&khg=p9pvrsJwMPEy>;k}?mFnMgYG)?W+JOO8-yKg)$twl&{6h| zy6q@qM|nER(ot_6FXH_jy}wf&;*o$vBq4$>Iu)Q0MJY`gblgclon-3tGt*eWV)W2S z51qEL6YuY|54&~xF9M@YP3`G}RMqsxtzcZdm{DF6Lk++MyUF7X@h$BR! zw=QyY(Qg+w*X0s2{rEO+@5j$+!7q5jk4JeNgk6)758ZVwi{83^Nqt&l)2{95NN4QY zRlcrrb(O2DTwVWW4)a;aVeSWExA>$a4e4=P-E`0`FLvu@w{GsKoBQuJiY092Ahz#z zjpsqwJvOOHM?p&R37=uB?v=~nZx4BU6r%(mqqiP%^w4jQ@>D>k9xWNdTbXz@-W7nRiv1?EHddbyGu3mEWN=g(dNQG{C)utWY=t&>s=wa#D?({+*{bcI50ekh+S-E|bze#*fod_@)X z@RJ^XYC?0o|EC|Y+fQTh-k)w_m%-jOSf7J4Vw1u4A6yytIoQ^NJ7Md=wjMlyK@4Fi z?sBl38@z_~Y+^UM9IVU1?r`vV{tLn(S;6iAkz;)9Ems4$IGn6s9QUXvEJ9V>r4P zHimIbWD0-c_J(=KFnNc`J51hT(VXBkdK)IkF#Y-s*KpW%WcoEO?@|GK{W=0~`1K?< z|1C9z(A{reqPO3w@GUm|&29bG1-t&%9lQP}-*0mLCf9Fr`Hj}_w}mWW8OM1Ngu|2I zZiiQKAxZBZ#7{V{;V6=N0ZMV^O8|{`y@8L}l{x1{x zD2eU=SDmJ`XCQ-_%0J9y0k-FA83o)8{-{gx+3qG>CEJBW}~+;Zf=b3{Dx~dMt5UYA=8-S===9{c+>CS z;tjvgVK+B|aBLiOH&$78)vt1i7Cu?{EXWiH;dKibDS>6o#HMJf^d8Sl97@$WaS-l zkc*;JMW^F+I$o#aTha=5IKCZy7{?~IvIAX=-^&5q==fu}z452ACrDEma+PLy$?JQHP^sJDrO@&1Y4KXDH8SimBd zunb*HjOHX~xXKN5JW)TBb<7B-~{sNyjxg~CMaxaE58Q+P?Zf^2swy~3g=yI|yC%ePR*Me}$Tjb(> z@}i3=h4A@PO7JnIDT8-RvDcK2$UNmoy3rH8P3ebzr?@%4;TlenWy&nv-jtg`_(vl0 zA@d*I8P7_NqPstCp|?No2jSEhL}AmZDM?LQ>^fDxsd7z~YpPsRze2xL^*gmDT^YlC z*07#UY()oCk6<^y%NkBS9fW_n|38cHHM;z>3qLaqUH&6_6pHUxO&-j71 zbim)5(VsyK!Trowg05%AAr(GvW)bu`^Gj?tvlVR^j813jbf!*c>T>3vOlKy`*vB(o z@Hz-*>0(w)e7@gg4QIL0SxIqwv%F)LJDXJ+nP+`YIVzyHS(VZ6tQyopmRX(oA1krf ztT#dUx6FT+$L4?k#9!#{?^WpS@Ad4*rhi}JDmS>z-5~rYE)kNE65IWgmF(o83_kmx zzWmHEhBJ-{Ohy;~%x4Ejh(^AD&fs?bxx;-P@gxXm+i!Li+GCU1K5w?WoIQi(Y~dI- zpZ$=Rc5A{dyxt6ED8Hf)zsnlV+s}1$Ht#uln5T#N2}y$Y&rgos=9j{I=a0e-%=fPOdYr!< zd(6L#+noO*2p8CTL3(VxAS=1aLp}=NCKuGD3C(Fq2XwhWmkYWvgg@EMUJjs(1$J9t zw*{v;$3?E-9Sh}MDDOgf7p5jH8PMB8ITq@7p_^Nn3z-&{$L%frg?Svr8y2ObICbcP z?iRVrMS5E_l4&f#ri)gviZ$4Ek$j8fS|ryZxfb2!0grhago|~vxGUFg z`~z)pOMa6zT&(NGGjUUk-PB@#Yq9U$;tg!Z{VaC>OLV>D6RP6#mb6EoO9o-HB{TS& zP3UxqPM7F(i7uC%;whOM4*m(mwQK zAbMNs=9cPisqU7JWHfGP>3$vs;j$DIqag#(?J^mc$+JwBWqMm?lV$$};qnBeBLm*M zJPX;#&c~Fa0$)*!I@CuW%VkGhmqED7cVbl$>S3!@ zf1-y~vaiT<0+Tx-X*a<7$lts7V;>$>->{N3tmA4BZuHiT#qeF)DBH&GX-#kJzHtg}XX9#Q-Du~HyEw!VqB+6!AlwuK zx3$SzH$_N;9yetqGkGabdphwW-LcuGz6{_ee#RYa@{UdNZjyJCyqh-Q-Zt59lU_H; zu}N>6_Hh82HtBA25(;3a&0X<^&6~Lpgj?Ps1G?K{k1cxJQj{;Ki#@kAz@A$g(-ir( z$hAeTEplzK-Ij4oWHP$ha)zftxHaHyVk5^^J#2NiTT|eUww6TKTff3RZLN;KwY3S& zX-O;ohpx9?<9QHn^Lg7+qt9*cW3z1)smyoibem4M>2#YexAkWbgZZ5W9Oo2g(Z#mQ z`21}*xx;-P;T_xE+4ii+y!~Brk{i8k&xd}u7orHVY_COU#$&JT=YnvD%sX;n^BpZ1 zi0*bwKyN$#U?Dc$;kI^cV+Xsi>kj#L$hAYR9dhk>6@)wWyHmeAW08Y0e1p5)*_w8A zLKSjyEP+!YsH?#fP4N}$VKb@+j{3}Ga8*fo}^Ok)PKSk8WQx=W|K zbh_&rH@MARUI*dsl$7FAK1Ub3zoZgXsX=Yr-fr*ME$?o5cgwr`SB5hRz3rC6Z?}ei zyEWYHrgzJmK>` z$hAkVJ#y`Fn|qqml2+(u&m6Y0mjfI|jy-zV%Gg^j?deB6@Bh~5rq3}wl6IiD2z_`>2#k?_vvz96{=H{ru1Sa|1cL_>|2b_ z-?tJsx^F#hZ=ZMUb7%YRBlEt;Jmo+1w%^U|*WG^I?TY~UzG; z_<}F7*};zZ4jl9y@cXRc!JqNB4!WO%llX%_*^M_I((9o-_`E}vaGQs0a;Po+8HAfV zwqIEQg0Nhy6SV!Xqh=`A9>0Gnv)s?#Kc3cH}5md4^4oyySHd9u2VTQTdL_ zbyTjSavd#zevj(+XmM)Oozdv-sP2wVLyn_*IJywGb#xP3Im1od)KQxqeH4Vpd_RxH zBo6UONI|^u*kHyn1AQLT=P_L#JHc)41!1(Ci`HqhPNQ`it;^`FxWniixVPxabfpKn zi0;Qge15bWjsBGpct^Bbh~B_vWRBj>PV^S-=Av~MeF)t}MCr z?oR6NWFq7^sfUxcJDHx`l)>Hleb(@#%}&_=bg%gK2Lqf zCsd~vZtj#$PwDiOPEYCb)Xxm#Hzu>3b6n&Kx;S-<|Nne9dg?LHc!77EewSRxeEI|O z;^t24?Q{|Jd-@|jMwZjx(37dy>-5ziJR|d&eAxU<8-77|XZ}QQXJ)bjo1WRt9`$c7gU=(w3w|<{BJi8v7 zo%OfQ9^?qoxSw-xQ;?c8$LF2<34NZMz${j?j$`QboKDZ_^qelw-RBWcg7ADSGEkN; zsE97kSHtI@{~9;ycUi;p-{KwTe`N$RpZ_1fGakL2pMrkR|Am`AFU$F@TnfSqak1Bh zuaNn|SZsdbC=Y}1qV6unLvI%olM$O<%+H4uq6l`qDBnf7F3NRLu8VH-qJA&x_hJXe zu$X^2&MD4v0Uca)PZ#ZW(QX(23&KlTsX=FSd1*8=`3GHI+QCWA@H7Z7yZ6g>xEz}# zgd`&c?@$t*Ue@VlonEdsHxGe8wc`wU*`6aJ| z@XA~0?MfVUcSU!8yEVL$l=u0Pwv1#Mdble4Roz~d@v1ymWx1-is~z$FtKNTgEaRET zWd7h!ba8bH+u6k-j-unM`nf98wX}SQ@7%S|(8D!7_$}7(S{=OqT0`u1&HvMD-h1r~ zcDd$V*Y$Z_pVw`2-Tv1<<#TL(y#=WIF$_0%eLjm=$~ts;U6ShM?a8vf1y1gmmO?ht0a#L?NPvQMHz5iA~3}Onw{nw*{1m4oI=-c!Tk_rN z&qSs(i`mF=%U#`CiS2IL?AAr@@sKAx55n92)@}E5J0VGkPz-Opt=HR=@p-q`v5|xL zKHYwRyS(G(?xZ9Q>B){R@96T5JG@hZ8uX$s1JK2tpYi#3hBJyWjKe$b*z3*?WWMt+ zdpUsK?i@pRcXW5>4Ci}(frPMrZI!R(Z@ac?%fQ+`}Vq@h@?az$9;EoKQmde+5HOCrY_&m2!HFo`?=qd zE_CHjyz#zXAH>GzJ;+W@Z1TYO=|LUbmYpi7T)pDUJvsk^TQ7*L{aqiuq66@_$g(O^SwLmc54c6}t@Be@>Q^;oXQ@zL*N{XPyUNL9YackXd_deIjh zJRX7F9^38lI5zPp2%jWJmrn}tIpxviljd}zCvNb`6zuTCcj?JI7OFI861mUy9*y~w!yy4koZ2s&N&x7!}?w9loxZ5YH#DL#?HS4vma__7yx72Iwy~3caeIE3 zHGCoO3wdA4`!WVGiG$u=%JEXaFC#=Dliy|yUsjPTy>1D?8Z5 zaUKLwL0U49nQXjEF5V|E1t>&OzNIP6`Ht^tO*=Z$nXYuFC*xVkY2E};Z)K%CKky5) z*}-wnaGr}i3Zi1fA`bCLKq8WmgM55QVM_5SpHmK*Vhm;~^H|6dma~QJ>|zi5cosyx z?Y(bTpdQ}!b`N?poJlNTG5>OeXijp8t6b+M|M3cMjhPCa#?)!dchP0c{1im)nDWMK zfUGfx@+%`4&F|cPNiuV*SQa z^c~B)W2Z!qvCHrU6{$o+Y#O@*o#=vHW7{>he6i(=h>k zsY!<%acmby*Ku-FoRZX{3C(HA4|Jm^edy0XY#GNJNKt{<4$A>?jo)|gX@taC8#SR`J|M{7igCV`PjkPkdS8+a&%9Rl6Um!s7XL68y(N+(k$w{`XC*Qvisoq$l{hUQ(Fkuy zJeyry52BL9Mt4cvWfHw5$xMDe#imKhQl1LfHHmyl{-<1E*> z$sOcKqK70ec^yP0bxTRJqwA!Fa8pU$R8oH{>6cWZD()w#`%kLtr29FK&x^c;J|oGo zS)?FEsDe%-I*sTwqRYtlw5Bb+8OuhtupM1Q_Tcj)hj62jBO`RI;SJ&*!+?WHtGkdgvgTdrD@vWOhr|kxA_1UJ#XBm&p^8nQZ7X zd1-1;n|5@=4$1p4grWS(aHg;VohH|5a-AmM&q0oGj4QkeqEh7GJw8AeDL$ky#rTL) zxV;qKkwV@S@}`hCMQ47bJ9@ZC<~rc=n2Vg_5e9z>FFO^)W=^A7e+IeRjg$Lo6$ik z_ms+RsqB{OWDu1)CWWX)3p!!@)cQ<4k-u5PdZIbcC9Yzt)DL;g(;zBMY%-$LG&)VA z(=>%CN(o9*k!JkHNdAW|(oA47Q~8UTxV<#qkw)G$@}`kD&1ueZ0llS>BaMF3+~N*0 zrA8hZ&bTw&?P1CupbUmBwMy3Ga(`}LiGRqUwmFV-|N2a`#dkaI2_|C&-oW! zqpi1xyyarPll9Krz^woybO!bXNIr%j+30>Pjs3= zrx|pbQI{EG6ORPEM?sp?k~ZifV<$X6V-MVD#(oUM92r-#8ksY$;|n&Tw~SlST}Ity z+{JD#@iGWMNJ}}|F@-PD?FTYuk|&cane>*)PBLYpFqNr_c{A0dHg)JsANn(h(Trmv z`p6_-ro-4*rh7c#5praD6@-}s-oVZ>yQR#zC{8KLQUUjqIhqDErYUxq*^HUbV=tMX z1Ys7pnI%4{$wo=+Jxe26(UuPMM3-4~nPmXpi7ZPv$Psjr#on^mTNcmH@(aIm6?0_y zJqWWV;$39Unv4|aE$jQ}E^7vKmo*ErWUYk0vrb|iCy+Ut8_HIchV(^u+4Poe8Z%hR zSJ-K`Eo@^4JCQG&T-oHxCRaB7X47vr{bqX{gxQl*5c|sBgyyuQ4La~0)-b!hWw*EN zLvT;o&+#k>bLcWhQnHc*UFNX=9L;FKK>QubVGlVbFq4m%%g21iZgiSMr#W<*<2*le ziOc*MggM_P5BVvCE^?NjG;TC!6qTulIdaOIQ{J5N<{ZWd++0q*<&-0*esfM`Ix^+_ zf}{Kugt_c1S7FSMYb17_%R8FuBD%}<5WVGk8icuHW2d=Oks5o=oeq1=EnjZAa?6!l zuH0@jcLN&Jl;M2J*X(6KKjJ;et%Ka|DYw1lwzu5ZgD_8gN)ba3hGO@5^qFS`8~L6C zT;Vo%xsP4tdCtGQ4#K<%$&60(>NKxT^OmM86{tu(x-pMWScoq2E@u^=vyKh8y}ahg zD{o$T^U9m|H-6_1ddn+EUj63%nJ;cg4$AUFBYK>_zvz}^bj zTLHIRpf@Y|fpgrz?hEL%U_6qOom^C+Hg&0wT@`Fe8`{yAY3Q_|P7CU^;3`(Lmi6r9 z46lN)P{5n$qEK8Ckcf9lirXt>jzaPllDCk&g{o7N57Aqp2I#Jk?h5IyPz&5np-_y{?QEM_ToSH#YW9OgXUfg-OSrkBuY<7I|A<9GbXiQ7#oS@BjFhAu9qEEDiuJeG)n zxk~D>%r2UtCf%`0F*QL^8*QGMyJt~!#0u;hsma_L!E$Kv8dN2@OmeQqfw1%ao zvznhcjV?;rTPb@hb%pEPa&}X?R%x4`N_z|6!(`h-KmeXaqYq-O5zw;yr%fCYric<<*l&^s2mv^J(YvA_E z*To#=-C6lj$XtFL6L53o^;Uic`Yk_)dB{?J3ukb973`}*X=JW25j(GNfE(zp!gKUi z;dKy3CBjal+*Z^FWF{;28YN$pTv2jG$raTU{YL3GstqGq!MErxN_SC5kR$3mZY$~{ ze*|I0H%Uy0d#-3_zRMa`%tlV~;C?DLVJctn9iCV5GWx9ei2s7H(z_%jH#)7P(@Hw6 zq{~WGs7_6q(T~L}VoRVDwCMPG-hD0RphH8R~5Oc$W_H{ z`aWw|MZZ-J^JfrNjYmfEQh>q~LkCseQ&oGbYHwBRFqrimLzh+W@;V5s{SRGMOG|zV zQHzGyL$&6#rz2hH#!%*>(`q`crqgO)@Fko0n(w(3gw@|74)M`N^&~_{PAbyi_Ntqs zy1doptuAl%XzJ4ly;YAvchz-QU3b+xFqRek$ekdpkq|x9klnXd!x}Qykf(+$HS|{F z2#1rhZhJDts&zb>m@E+cUnpwz>=hoD3P5ss^fjl*bFb5sf)IrVF*jvqQ ze8VpGV0Sh3?YpaCtLJFD&YYaiw)GSoiF8Dy#b zGqTi{rS?_y_F-zu(wgzOwGV$n&vj(1BTpS!>XajjN;IS+o#{$gcA<8rC6Gox4F;Hx_QHuA8c>hq`*GYiD({WB$5%$xldRhVxAkSLFHe10>g%okddy$n{Pln06lXZc1>9JDUDW@V|AMf=8^q@wblgBc4diPO zO;`Fc5br?)IU0;-5_Z?X&KhjS{WtLbH8{W_{8j_^)8Gdsq7L=YMWZHoexsJOp*@{2M=&XVVH)!u>Su#R~Rw7SC(?1bsG(OER*NlZxoHnNFMOw3#lOwV*X^>BCgE zu$`UgqS;C|aSrm;vZ5W+>CJ)0m|!XCmY2A zp5o}Ph3;BZMUEDFXyLY6G^Qh?aJMaHF$X(q;kR0>W-VXfep*}z!j|#KK}kHXWi#~I zvM0ls$!yl6)0R4IsneFaY^xJ9>Zn~8$troC@U$L*&8IielH|)IiIu4?{)|b&+>l-`{!Zvo=CN^=2 zPeSaqjeKq7Y9m)0x!SnRHu`O&-!@g~!bFy_fv@dnZSA4$MSkOV?r@hELD()tr|opwPN(g1kc+(JryNZf!+0j4 zi*_^kh`G$?Q{0~KvWD&CZ6|L#dE1@jH0RJ;J2~3vx7}6TbUT^a|BrM;VPEYhV}|x; zu=5V@k_X*&sEFP=RHG?&+Mzo=vDXfLvDXgrb&#urTpi@<;5Iv~r^a!@fE{48krlcPW9LcNxSybk}7)dh7BP`>@k4ZmY|Ae&!YlpVTUUGQx`+e(6NKGTqRVbY zs76h6*{uu18N~utU=Q8au!*nP#tsg01UJ`Br`>egO{d*-+3j@@c6W!}-{f6#P>+V_ z!nat%?k#CUdphCvx|^eWZ{+R1n58UdC3@?=7TtCCZggcq$ zPJ8RLcN^N_4tsZI5FfFV@7Rkje2X>oE!MEN8}0oQZm;(_%+W{QKJxaFw@+N+o%eNHeLJALzQfR4-_gv*PW!s8zMo^Seb-~J zedX&bS6{jM%GLJ@*SX29And1`epx6>RccThIr{0LpWEu!g6>Q}*Zn?b0gLck{k~u$ zn{hw=E(c+MUH8vNc|5OwYxLQ_KX%rC9-puYo%Yvhf1UQ%W&fj`;3QXh9)trjkcq75 zVnA*@e?URp=z!w5y#eMJ;LZkgMdkrL=}kZMHefLN9Wa7X$TDClySWjB1MO>IHe?>y z2Rk45701!tz~9i@z&pGM!a;UA$ZZWuL=r;mb&!0628ApE!-oL(cOv zm(bggYv^}~cYBDN9wN)o*kq;}_BC`SG7tR)J0F&ULg;Q-b@VpuLt0^{!}`*nfegl8 zhsifgu3>TwlWUmU9H!r4`W?1~Q#=X6;qRck;kp~1204aj!)*=EMM=ugh<0?u&W3kq z2*Vl0SjO`uW*qSbA?eWP2z`#w<%oK8pfhf6gic53bc9Yv=yJp&+~J7jxVI69`J1Qc zV#L4v7lb1{f21278Hf0oW29RcS)5YHJhB`W(A&tW)IfJ5>kv(S^fz)AIvHtKBi+}i z^tho>ZIN-5Jfmb8WhbL{u#=^tIM(RNJ)O05<@F=G1lIEi!~hEjh^(OKjs)~Ut?Dx^Vl`4 zV*`2{`!%{7tGlr~*~KqB4?^Ev4aeElxHe3}osQG(I2p&wGhUYQdK+&i<1tno3;}2qA<8?OvA$l0EhY7KWjrk`e#NH<4r7=@jh`A={ zal&rwV}kup_=~@TaH3sLOp0Ake2)*vLUwXef_gN^?kAdeVpn?L1}DlqQPzomXW|dY zIq?X`ImsE$qqm8Ecj8rU1mPsVJ4x0_NeGc)k_?k%n54H!>BvYXJx%!>zcpn$JNb@1+zG;|W}I4*nt0ySZuDdn z(^70A!vv zgkg+CZ`0h{G~G?p-Lz@UU_D285QNk1YI-4>G6LOBmvOp0(`A{ix9N5={Yencc$?&; z#Jn@oke2imrvjCzN?q#H2z|_uZ^i=bYsR6QIL1$$!p>&A2*R1}f2RANnUKWz zt(op;W=1lTl{%Plre0@m!SiOGqGPCLaYUg)V35a+W)s6-`&> zGM`V;#VmW9<@vK#vz9N|h&g82*Q_hZJnIHGxsBdtd8cRTZkFz5J>gjpeiWeq4Y8|_ z7V$l|f^fEOXUjNSp4qa@*4u15ncbZ3j9?Vzojnfk%q!<^ET!~An9V{dbMW8OJGa1L|L(c_%wK{(ew=Gy<T<3-oV$}Vyb8j30dJy35!+o7W7P<_*E^&HIk4LHKbj%)0u@F^X+~95|-hX<{v`W z^MA%o&39At{nmW%=ln-J!To&V{y)+6Cw&-;=Y6sgeSWeXJNx7U7kP|M7wB|>P8aBM z!8;@&Bm*UAO9wimiv>OL{004SqYH-O_7<39fje8U0ht$U;%l~{w*_u)f$kRQZoz&I z;C4QJgUnQ+D<82H-F_PgsG4H~9G@uc^7|bw6GKs0oKp(!% z8ZJDEeJ%W(r?}lkax8j_*u=%o7Ujb`u*f^GD2mGXtwruvOd}SIfLw=GAt%x(?CkVYNP2 zuVgiA`2x>ht+&1ef~mcs~@Ac)p}d~ivNP}b2&bbg}FY@NO{^b zk@cLyKGw*(M#eSrtdV6+2RhT0VN7QxA2Ek{xUn@~@eRA!!y%4xf|JO%HVJmMwg83k z9;}sPZAB{MuGTi97w&28D8}NJ*7~irAG3f(EWr-fnsJ?8*X6|X*44lbtZPX(?0wxB z7UH(neUA5F-Ph=Hoi5kyiE2AlC-DHsnRW8}z%ODD@f0EOfU)cN>->#|AxY*nr#Gu$v3qg zTN_>n;g|m-7VhWEJhWmov+=wyH>1xlf8-3e_#+56zKKpZ>U5({H|la@8q$%0d{m35TUH!a~? zuJBI~Zr0sq-EEGI9Gms9*==o3PG-vBZa3GaE_SxrZ*6WzN4nsCHqYZAcX$zmUwhuy zsnF-wxhX*{>d+aTey!85b^5g~zaGm3CNZC{_=R7&iY~tX9nb&z9&YsOM?AqCThj9Z zGH=OBc5_lJ^Nx?0gM0JM)^LYzcPwTZE0AT! zKCT7fH*b*zU4J9|ltl`eo*yqkXTc%+^Z3}OhAS;2a~WD`5l z1w`B~=*^TbLcbDJm?fYN2%fHy^{(v`#g}v^VZ@*mo z<=QXT{vs5o6lKuO{t?V)87o-`UKQ~TZ24}R+h@8=J3h>!dE zp)k7sVG;}QydSeS{(B**-$U-)XQis6|V3c) zi=7>+jCbIWci>PHn&Y<)xt~Kl=|evjW5z>zJ^TiqcQ^xX^RS&9u0R7C%L!#2iQL>qt&yK9ZOG6hd!DN}#(V zx;s*yD7+I#MzRvSI`T&l9!*R^bbD0Bqw*Y;<*43{+R4$icsGw8%gu6U$@5g`TckXbHC+PCHE|32kgeT(j0X6v$UHArT zc*5RJG@}KrX@@yZbV1$|AM**HvIxDMSb^?NxVaO$JF%V(96{edy@Q#4s)reVazj7u z;u6n;@TBfe>g}ZYPe#Z@VeIr|aY|Aedp#-NNx4qSbyBXAz37X6P7Y!rJ2=G^u5**y z=-{NiowT=;_I4`3J)LUGP^Pf}eV)?iDP5kj|5MlajaNZ<`fa>RrxTEr6r>_GIfz21 zr*(Q-r>C0{gF8IkhTcr!Yqs$Xx;VXu?{TB258?JspTHca|&O&68k)BpJ(m! z?3aASVNP?7pZWji>i4XE&;AjF=j1t;9rt@q2j_Hft^xLTu05UTN)PProW9SQ_1vGB z@qB#VCq4NogIUhkr#teVm-qZI#xoIpo|panLS#QL`+1$7*X4O#p7;FoXF1O=T;gsJ zUeM!(T)52(I=fJqVwA-1UMNpRs!$zwcERso7{m}{xG<72jAH_mnaXt5p|1<~gYf6X z6r>5mS;V*K@MpdK{D4P14#HpFA{lP$msF%iC%>dazF*|}MXq1u`lSx_Xh>s*@(G*R z%|3qMAUgQv0vEZ=)gZj+mM@l|8QswBMO|K;i7qd0U@!ammEXC;J)ZCnFZeeIFU98r zbb3jrmvnlmB&8{bo490`m%1>Ak6C~&E-hsRpRtDZxVcN_xFqi-c`wO($-Q0rja%sL zk{p-xd+8y6Bh#<%l8^e>*RP*qhF@<6;bl9&oRPBV?y}pwthdWe>583R9>FN=_3}9E z^|E}I<+?1_Wx0H#HN3o&@7RNGt^}kc1DVK*99Q&k#cf?FN@ZH2>nlC!Lx23%7598) z5>s(MSGJ++tMPab&%0UzeO|4Non7rgZ>FHrt2(`^)2q6?x{A+P%MMQQlGj0a?SJUv zT5LT3T0-3DwGg*=%^cU<*|mzue61?gsfFHruQj};-)oI%f-KhtF`sX-uj_9h^Yt3o z`Sr=HMt9eDp||V%IE|fNcU#wQ^9T2^*BkQPkn4tAH{|k-*6@aYZ|L_%7NY3DNOX5Y zcQp7Ku+{+1py{??aqe1txK)8}ux{Otfg za|t*1n@(@)^rlX4>e4q_!<+8VH(JA+?(Jqt+R+hR-0V&-JpZN}y*Zd+nB%5fxVfG$ zk@@CkwxGA0ZtkY;ZhE(G>h9)#WVv}G2!Gf2@0qDWS7iQuD`$BegtwBQyIXp@m7ScF z!cK2}NL}jDfJVr7ORigT-ID8;esAgbmVR%|LZ`P*Vqdp(cT0D-o(JJ=Ic~p&-QA8$ z3i9D@eWNw>jn?pXW&GCdhBTo$EttqRT;v{}cP9b*ypxVxl%)c0?v74bW z`ZI_jOlAc~Il(D(apwY_f5(m9xyEnY!W@5uBtzyuQjr=r_lMs8_yGO>k&PV4@<%l~ zF%A3r<1{kgO@p1^ZOTA&cXv8^yE~he*y-JE>|iImu-Cit-IeRETzBQV>o)J|_pW~L z{u6}vl2Vj9=TCG^iN&>`72ks&ch(QACCeQrWm@oUk1;=UlBKYzdE%r z$Nj+!L+1OV7{hqsVJvp~cp{UTioHIT@3CBu<$5gFd=`1xTz<0_GBd9&nGjP%{=C_7c)MMkcs^0^Qk_c z>hfuO1~C*j_f)4(b^27NPj&h9OWfhpuW@frF9qSVw}^u-p1ng7JpY*+eU^$enB$pS zcvgej$owpt`snSMn|r3aXD!g(v$n|cYz+E-c7WSK_)h|4{-*)`n8R1-?jODVbC{$2 zik<%R7ms+%Q~n9U=kh(5>$zOd<$A8)=lXrF-{<+LM=$K_`Nu3^5lhj*b9;MkZ_n-R z`F5@a;fs)h=<-Ef+R+hRzOernpRkZEe1|=}*v~OeaEdeB;NKv8sneG_eW}xz5t5OT z_sC8Ky3&K*=;Gx-hTukDj$$kmFvm-IU&{MZ-k0C-EpG0m-d@V_Qok<`aRixO{t<-# z#w8c_^=}`{@b50{{NI;B_$mdudzBl#y(&NycKWIzjj`8P&9T>4^1YJlm0YjndgV4> z&1N3+(T#7ihOZv-f>%NKIzW!s_Ws&!y-rM8ilXb+Rj5ua{MPFjTG1Bw^Lhrletn(4 zgYZAk`!7VF|7F3>{;Nzi+Mv__bo!r8|I_7v!x+hEX0evjoa1M7@!u6Z|G%5K(f{t^ z_WpYqM1oYLAuZ|2NM^E;licK^0EMVaFXpn1i$Uan|05Gov|%K(n8zo4%6fLOo4tI` z5B$hg?r@I>{KHFL2az`dWO}14jcHFOy3&K8j9@h5n7~G^2az}5B!ao#EJzWmP@j%; zVJy>_$!r#~m}RVB6Gu41d4AyrH@VFpJP#tV-lYVkDTgj%Ri+v>`H*NDV2)Vw#*#Od zys;)Rh3V)m)*N&fOLwt!7i$sU@H4N1$Xj;xRt5C%mh5lo_AMFTlIJa1-qPFK|HJ%m zN617LvXO&a9MQ?FlqTje~F76x15;r|=FK%1Lvlf}- zJ`N)BLh@4^-NkE%-r{v;2vf1scr*EkIoNAF`Fxu-5>Kvpa>e@*{l?R8yc66DBJmTE z72U4dT*oXBd9U|;VfLFRXwV(0IC!d7(m&QbLC&PlFgr|&%B z8P9o%y(W?`kz9%7N+eezx0y)4iS(POFpcTY4E!BPw1nlXLI;W5QzCmyWN(Rf@p}+S zoPuKLGI2vX(+yoFp2A|5@eSW&4~Y+PinE;OXKn`(-(rm<(PCSH_36_bP}18JP0E1zC(WO z>)nBv;oW`Mc^Hre-Gv3vTUeB;*lE~|80qt#LBpSaJX+wKD;eH}>&~@Y%{{)ewo|iNQ`b?S= zJ4;%F+H^#xNp+f3r%830bTs3bz&yU>0vEZAE|UI+=O_IGH=6V>++I?1By(rUG9YuZ z%w#18dQ0Z!lIbp)?vfRyIBv(cStH37@GVz^NblpkT&Dd)3{6@13$Y~v?><`P%9jV@E_GNn6A`8tTC zN={iSPzhb6vbR+BmZ~oGX+%@ZkxJfF@}`nE)pTYu8@;8HBb9zrxw%wJkSW!7xV`uO zM@A}RhWBQ%krUiQcd6ZFYQ3e7O$xGMr>S$1hkV#;YWY&jm0GUUa;0ud2RhRg-K1X6 z4;<$tXOJVcy{EpxP3$a9LQ;{2bjX+{FMcPD`$?n!G$rufr7>?By{0+HS@fCaF8>CR z_v4Zpclmx%$`OTm-~W(k8X)ugvc5l(HOTq?muzAS+u4cU-rtM6d;drN;%}btjOYCS z@BSA=e5*B*HWsmwBW--L;ou%tRFGe$)xqQqg ze99uWvK#M1I^CwzZ93hi(`~wQ$d^7Dc9mWS>GhVrG;*Y`N)2k!oc@eqJd>D;-%7s_ zx08N3D>;T4GuTare0W}lI@F^by&1a}bLcdOPIF9VDl?eHQg(2io7_eh zIqvfiH=5%aFL)J1a+)KjygB8~DR0iali1n*IcKu*Ie@Dk}H>7x#Y_2Hgm@%0q>BHT6CZ< z0~n0=Ah!;3yQkdtmfPNP&*eM*3L<%ukbykdeI9-0X+RtLGl-A)l*KH=uJWwsOTJ?3%?>qem&%OTlxRQ9T!N7t_x%$D>?96 z1xiqwa=4!YUD0)c-TZ{-75EE%7L0|R75soKltrfnby`rT1$9}l3C(FicP6lr&1^*% z1;54f3+}^>7CeaCD`<{_?yTSoWG?tRh!hHV6TKCRgMJGoBoVR{%1uprVPA!|A#>sX zVdsU*&0+`Jo6FZ+z`lyVkIcn8V&}y_<9l>h{Acu5{4x)MNC`VF@dmMY zn>g5O3HeIMRYI;3a+PqKCG=ZDza=Wrk})hqcO`UJVjXgn*oNCGv6I8xz}=Sko2S@W zNxxMxE(u74`zcwRu1sSwo>%fa^jY#0S9rveAX4fbbXrQMrF2?Km!-0jgItuPKEoNs zSaeZpGM-;*CT_IUJU+o3rGDTbGM75aaZaMQQs>c~@3lrsUFIsUf=KDql%+M}S(Ox}~zUXi5yNXp8&tP1Z=+0Ssm+c39SoW&a5xK;Pxpa+JSa?OxE9$c13tsVG5UKPI zS@@7>8la0x&G7t6ZnRQ6I?@GmRQi|&$XsbLOL23R^j7I}^jql*zC@Nv$N4jeR8E3@ zRc?sPm6u`Xm9Ow`5UHZOD(|AVD#^);omMG9Daud|d#xg06}hU&RYk5UZnKJhtLV4N zP?qp5XSvQzZgUqMRB=yL?5(Q3Reh73#4rL~R$atKHlxd`C;5$Af&bFMy;rk`YKcg} zd!!*Pxv7j!tLe0wPOG(`6>VuxKc=&dZ`g${s(sG^4snzdxV>uTs3vc9d8^A?{Vie> z54}}SjP9!IuDb53r=&3T8N{dTMh`V)uc6x-GS-l%hAcJoR%00EuVMZg%UHoGR29a83tfkjlW$?UOEpVH)`Y@8&%)`yq+RjeC<41H^OP9XS8maXwPlHJ9v}7O? zx~QE4&##@2f)t@R=BRC7wL2km?QZm-H+ri*0R7f>bH3XesVz(GMYz4%SA)ohZ;%<8 zKkUg2HgE*peRvJMefT@if=Hb>*lC>vyhCE_wT^ssn>$8TXBPRFJKRKFLR4OxW|27 z1(E1v=rmfV(K?OJO&|yuBhlXNdT;RoRp`ug^iWUsdb+JIV|{t*%Tix&^=n}M`sT0Sliu{DKLZ(z zF6u923Cmf>26S9sKlSCS|922+kbtD5;63DMkeO`QT?0F75KT+k(4J2Ctp@I=!B9pp zinW-rfnFQFgXcBOjoWNkp4zmg9d54S1ST_$dFZmCE*rYThU@u(`#j_^x@hZOR(O814!F@~-ROxqnk{4rGB;bnDn3VV&Avdt%{Jkt zo5|AbG>?La@2y6f+gI~u$lUxh?7aDJK_upX=q@HXdW%U-F6=a>Eai!!680J+UyNKa za>d9M<2GaT8>8QtQ7mRJzo5Gq-NoENju<_}xUHDyL8L_-(&KJhDjo?)gx*?3&~K}hxan51v?@+xhGAc=zDMTP39<9m)#-@tS`SBW zt;aA2J8iw1HLT+c?6tLgt>tPhS8KUiyUo`6ZLQzdw}VKV_++IVwWvcq8lrDblJ8P9}-Ph+i(_Oo9EN3q_ zgGl?>5 z*I_1W*u)mLBS(ktIe^`Du(J+-@hXUP^f$HRo4k$R>gawtrX)4* z9>HyPyuv;H3nHD~z|D2~fGlLE0J`j?%TDgFQ&n0sh3U*f7o9%F^E)kKDJ%F4b9Az= zPG^z1)6ZPwGJ5Ou8@lVHyH0ocGl+DKM>c9=SDk0GgJ02Y7a6nbWKGX(jiCJ9ONc1cGk5K?dV7s zy5qOHx}UD27|VFR#Ejka+AYNMx)q=>cGAuJ)U5;VvYU6Jo15#V({4KLrqgb^?6w4V z*iG(k@^(AQ6J+i7lGj0``~QeVY;@P%?R8I#-|X(ry35?X92KaDo9kX3-F5$vXzJ6D zzRYGDcGdk=5b2Q-d3&@+#vbzYkfn#-dhBEu$GL)ed)(kAx3Jfq=IvfJ{AGqr;vPnSvgA>Y?XimSO&$t6774>Sf+unb2h~bM^;cLLs{AkAq>8+6gT6ZY2IjrQ(MKL%os z-tzXAx3|2#*YO2zuD9NL%h6lEy}#jGWa@p97eS=Y`;?_EX6UnlW84cOedD6LzG=~0 z-w!B6CG50sHEK``d+jS0b9q=v@lB2f)atzS#fb?WUrUB(?#W?J1z!A(a zFe!FEFq)p|Zs2(IHgF0HvD1NW%Xe5K1MPL-7VLGPd;{egDAz!_2Hxf__xUS`4ARY@ zyi}zw^=X70gY11!2RdPAgWS@fIV@u(G7i%FAip!n{S4CoApH;8$BiH|I02=pO*7o) zU^g&$3^Q4QcVh5v4r1QH$2re0{EEzjWgQY5IfoRWF!n#BBxTUskczmwA=RnH00uLZ z;f%!Z4$+(MwMK^MZOC-w81fOi8{)TzJPIO1?P+LHVi=8ihnj1sJVRv}`ZwOup>A_n zT#^H7|d^?^u`~nxb$MYaE!d^xsA}jfDTO*247F~|e<%r5O zz|Ka@$L)_;j4npl{Rqz=VfQ24-H45B#vCK;Ys7VA9`QTwZNy#lHsUYzJK_n?kY!{t z3egz%HF60ukGvB^M#UiuQRr?|6ZAH!1w9#sosJsE1SVmxqvRVU*C@G0$u;U*^gBww zqxN$vh>VU!8nTm%yc9qOqbp!R=CJ z8q$(Bw4($48HAe~qth`u9i!7Rx*W3}cR0p7JZ29+2a&OF@D{ol8=rSbLWJbFy|LyP zn+|!$)}R(2QWw3AZG`T|HbZw~TOrffk?4Eu_n2v1T+A>on%>M}1G*chw{hklcZgrG z({X?DfQS5zy^fb}yjU5$`Cnh1p9ZpO^7Ru6z zuJk|`6Zy-m)8`6ruyay0d6NMoAP99>Kv!Dz-YomuF3vVJDZH~Ab7 zaJ!RV@;Zo2kz-0+5@2^z>}*P5D&QTMQk5F`ttswjN()-kmT8!Aie9HY#Pg;m!EH{> zM1CsbotWz8rgo+qJsE^9r|NR5JDfU$&pF8%&ZCQ|zvB5*Z}2;JxQ98W+1Ir9ka=2K z((?g&o0bjzPIGh9@*>N$+PJ-GAMrI8ka>Cr%F&Wx=x+LK^frAyYxo8`o&Ftr*oVDN zmv6dU)8(2j*Yqdoce;M3zX~EVQc;Qq=x&DYX0$_&8G4w}2e&n2EQ|0C%f>qDY3$E*>IM&?=LnaC9MHft8To29#1^I5<)&ha9Me3Y89 zv}ZE9{Yb`-sb3@(+k)bjTO^MqZT90l_!yAU)4%{e3YjeHSt{v53q2=wf6d5|fONNQK)Q=^Z2G9Vzcfc}G^JD%H{3$hzomr0z!QZe$bO z&d4cj=VlNYl>j}Al6{nJN69!!o>8)l(%Y!rc>gHxA9bIHJmx9S@tqj0i_ssGnoszQ z?C5y3en!hTx;6hYlo5_ZQRf3*Fj`Vfd0qCARFE| zrYi#(hua*pm@ORS3fF_k*l4^*d=iozU5?e|SUZl*L1|j?2fFYZtdX&H8|(AO{*RvY z!8^tdU^%OhdF(niptrHx(A`)!H&%CJ_an>LdqHHJzQ^UJGJhfSxQ$#0BIDm7CAu50 zxAFNXz_--ErsL~SkDq9OeBc`ia*fyTc>Rvo@A$Fkbo?3YH9>b1bT=U;a!k;} z1lvt;TNBb#7~g>jZfb(fCRD=Tn(#A?_=R5?!d9;FJcvy6c@vYN&xu(nNLk9`<|gWN zqE093bfPXNcB2Qq7{+{#bBeR*V&Y|d{zNxA@ecQSgm+9z%_qn_DI=M2bCdKoDJS}! zlo#LaNwQ3;N*hLEuSw^E$Yhx(e~Qf~H>Nwfn>-4=O&-qzY&zM$Ba^qVjUCu^vV4=} znk?63xhA{KDf*qF-zhQ3LAa%u(&@FlvO zTAgP6MsM8vR69%^&IBeimFX;HA3B|?)2TY0dW{?0<}Po7$h0IBr8wW9i)m%}o*$^p zkGQ>Q-Z4$yY4T2!cUnINFbKU(8-ebo>28|trcGomXM)J|Xr!YQdYCTzblpyuak@Oy zWtpM388Pwx8QwqRQ$8abImksGbTOj})u>4W8l&SG`k5iqj5%z0LARIa8lAZ8FpTGY@kNThDxft!LSKRvg|VJ|B<@H#e&o zUsICu=yH}WXSu^!4e88uW-%9C%!d57!hhIw&Jcz%0=v$UZ;o7Z zz?NRk0l)C8jpj>JloIH=e&=| z%$F45N9yr2jj+|cR{X)A^k5u1ou|`zI-R$a<*Z^2ySWlX<|p7oLUiG`SR?aOl7@6- z#O=-Zj`{M=mv_Fr^J`Iu`si)G9P{-%|5utL)BJy#%|7h4ATi#spe{CFFqW0*Zoz)^ zw%`a?vFQT0wcr(YT^L~3h4L+wYoS~VMXKo?Pe(;c55O;2=-et zfywA&iA+nb@HU7n)!9GA%hS;&feTI#(^XW)Cj)Vr4Iap`I7vGipS zSr(s!*m{|*m)Uw*0luOHB`J;Fm$jrF9qB@Ebh%8I%LXuxWt`^{SJA~XyDhWZvWGn3 zIqq(mcPy88xxCBeU7nqshEdRWS<^EUcdR0{#Y)s06na}d9{sMK z!Zc*@`>c`GmxGAkUX84=*P8Eg zU&$JL{(3jMek(ihj`eO~{c~O+^M-(E=xu|W+n~D*zS|pgw;>_2Y{-GWH~h{JmLv1V z=%l3>wb9*1y>0xHzvzQaH;!Q(6PUyl8o9wp9Zkrm=k9C|!mz&-Ok7e=s;(>GJqNA zbhA!3>vZ#aHnN3n9OYgR*^-QpNQEx8q$d+@bW1jJk_YeDBJUP?x5&Gt5lwJ&TlBW2 z6}sD^yDhrg(jMQ5ElWAc>maf<4SLur`&Qjg*x2EjlrXMI7Ga zeRQ!cJGuCr!W2Wt+w`+dzHL1i$8=^f7df`AU^Q#m!&M&flo!ajJud#v_78A7+x71^ zStHvU^B)tL#|AcI_w5&X!t)@q<3mzl`yJl9<5RNY26xE3L)IPk-_Z>@cl4$&{Tav* z^tQv@?HJ1hcCeeh?B^iCL7%%9vXOo0arYJMvFBZqkQ}$a=Szz472i>g^87$O+M&}uI^CnwJp&oc zFh<}O_N?ayx4DNd_SkKY-TW47WY60mvNsy;Zm)Ojm3Obad*$7mpMn%ZZ+qp~tKYqD zV{d6>+S{0(xVgRd+Iv5U?DK|wUtsfne=!u@?VF9>_AOuoHr;oaqu6!dN$k2$zI}4- zmutUV`{R?42#F~`61IhT5eAxa#S!&aiPIP4? zlbFg3Y;|BUOIgk~&ZE-#9AOV@EKqac8i-WbO%TF|<32yJ8cN~=W zpu7j=JvfdDOh#`9XQI1oZpLm$ce0259Kt(}$$L!RWAYx0MI7Rxw_|b~)9*1i zcPuF~9m|K?JJycTtiv0Q$0akRXn^jHw?}WsyYL?qvFY)tOlKx`JucsIxsJd}$jO-4{^Unwr66S~PZL`4 z2W_#{$!_$Z7sHs3PEYFeq)tz6V+Xt0%Nd>qkyEMpgbe87)MsQT7oU?Kx92xmBd6p& zCGRPDPc`Q^en)Sox^7yzNRGKQU=|e>B|)6vVbV$IHQL%ZtKh@-0_(s z+~pN-gUH!v#Nb0hl9Gat`37%1JA#=kMW1K&c~+NaZ}KLHoO=g1cTT70bb3yw=X7~4 z5AN_>0ZLJiKKzR=&JAKHKL4B>JvR=wcg{P`O=myu?3~Q!j&TCLopW>NE~2}0*SNv0 zAaY)R=QE*`^R_xakY$|WWe~X_;{|yx$a29Z7s~SkKhYYSUhv)vHoee+P7Gr_lbDMA zE-Yj*`nVv|g{MK};s@yLqT9Nthl_f+n47$K|HUsUjC;E1y%$&Ddw$WoF6!~(9qe%_ z9;rx+tuNX7lC3X&OGPU4Bh|6{rN8-ye*DKsba_damnJZu?L6Qy&(OssyZJ5Fh~Hw3 zT#iLt+}&mGxGe8wc`wU*xhP*z0=-@S4&7bW-DTZfu0%@)5QVKSzX&2%^l(M?E4sZR z;}vSXM8b#D;4=DpX_VwY>)bxohws$i3A_P^E>_j%3M*JfkuYqq|&lGUtZ1Mc#g zo4fXqCp-@#*Q24!>$<$|4zDLAC)KG%U3781A$Gg|D=lcnA9%-gd9TZRUEb@{naLdV zc3qC^`n~Svt}jQX>&I|=H&RfDdU(T)S?u6?5V;u>-QD~Mz1>VhE{bE*n-4rxZ#SVS&H0Va3}-!?*orQ0?`9tdIl^(= z-fi!=Bkvt~@5p;60SSqqw>!zv-5uTC(cPU-a65PE(2Xf`)=UAZ1*#u$NL2-i5~Ck@qQa*z5h49OZWRRfI$plGWNP}_xs*@e;0>2 z$_ey%|7H+*@Ge=&L2hjSpa5S|gs*UO4@%)359ECy?*n-sw5KCo(CY&^9_Z~sANnHG z1KmBa<%2sxj!<_V7^9dNLu$b3HtFThH_3j-S^> z*Ux|BciP}@J?}wp`r>|`FGbfc;*tWN_u>om`Qm$Q_M!!?_y?W7(CG`EzR=~1DNJW3 z%Q?VH-UN}C@1Tp9vGDmX-^Y!s6lOX`KAN?8OSW6u)~`b zY-9`D*uilgpwl-xeXG;AafwF)5|Ww%)TaTB(Z$>5w4^nE(hj%hw^$=@<$WvfTY2Bk zXCaHx+uN1s?yc_L>hA3(&Ie%-kdANog#koykOx8dP6ASso=kko7nGqK<@te1RG|fJ zX-_A5(uaTP&usQ`jr%;}X%I$}BU&_K5R1fQ=Szz46(#VuqE+TcYEX+FEaNyg@OjbW z@;)iaLSc$goSHPCF->Vr8~#G>=<-IN#4cowet^Rq<0NO$UGz&_#ov545i-ADacw=_X7@6JQt?>-O07$4)!F}y8CTYA%v{}{w%7PFM)tYkH7kuQc^ zG31INSB!f+Aschx~x{IT? zINl%Ubr8mlk4@vI;S z>N@WAAbc+x3HXqZr1)F!Wy1ZumyH}$L)Y)kW;H(Vz0>IPz5Bcg!gvXZkQJTA(`h`N z#?xiIlDNZoWvD@G#xR~q=px<>e11GP8gC(sS%!DSb7%3cB6GZ(+{Vqt(_6g9=r`UA zULni-DJY2Bd*5E~Pe$hV?*w6do5%l*(&#RJ9rPCeXa2yZ@!eMZKJ=v@c8xDze7WMw z6<@CS>(Os~{l?$Ul^{$IhqUM}f$kFIM2-Z7a9atAQJyBW;V;~C0-Gi9w-WScAVY9J z3D)r-2tPCSLQ5yfik5ZTBs_OhRYT;OF8hB^&(8tODm zL`YJSlbNq*N^@GGi||j{(UC56!|jFM5y~6N8_F9lXC-UUTPR1U-*6jlI+Q8A9)yWw z^BML^+zM|eoX-U4NEdEx~TGZty+)vVe=sM|n9^mtm zeTY7jWx!_1zM(Yr(P=WBCevv$T_)>5XSyumvEzgk2Or@_L6x= za(9;eBVs<_*a8u1Iw(7{LU=_9*+WVesH zGnaEg`0+dF^5azG;&XKQaYY)^gunR*JAC{fBN@XuCNQ7v==5Wqeyr1v&vTJ0T;pjF zru={cd`S^>k+KA(_>OW^!0n~_Lvy$2o=VQrj#|OcLSW)HKQX2!AV$`$?0XT;!n^-k3(OY1ZTO(wxU_ zrgO66gQW)AcZJOX>^%ZmucN$+B&pl0+X4BF4E4y=cir75|*MtL(<;YVtqw~Y1BT}Ity)Llm3?TkH{$_{P?VWtnz zLnhfX={A#$ndHeNOD4T#+JpCJ^8QQ@c*GN)@q$-Dm{}K@Q<8>sWF-eW&a9uz@@4*m zehgzIV~`{B3}#`w%r?t>m6TZZEAX^#S zR5qJs^S843er9VxW86=+L2Tve!im|jnHX!oo3f*c3o!g%KzxW z5ax1}6P!jD*)QVrvtP%JX1~h=ydy_S(jaq=^kn2y^p+zBy33)v9Qi0f75-oZD>)m4 zIb)C+-R6`rr#v}j$*H%THpw{-x0G`|8}Z(pTiMP|E^(WCJmeK`gD_V#^pQ)xTwi0a zTn%Z$ugH<>PukG|o8_9!0-{*T3jD2H?kCr7_Hh9BpW7RA>os>Bd|vL(xXs))$vvJ$ zEWyp?KE_GTa1~wV)@5#YnEQ1Q=1EKuzM=%W$YZxWK0i+dDp8f{ct;+4<>`&gdH$t8 z1JPTaVdyu{XvQK-p4FTR!p{TJ@(nV7K7e`b;U>Dv`wn``8%ljY*^QE9H&CzAPzKmlc zy3DtZgB-yP=JW4RK0D;|UCJMexWpqqACniI=GSR{o#rn`c`8zwpXta{W-uFF+bp=7eH`F%5PtC?S@8Y; z;tL8>3>|#op1!c#7k2xi8h;bTVXp8n2*0%bmvKl=Mha4hD%7Dq4Y1XhzwtYN@IS_& z(=T=UrB1(G%u-gcik(~v!b0!!0g2E>p=5kSD$5v=4}ub z@tr85iz1(pfz0IMb97upKYo)nEYglajAk4Yk)y~Q=3~1eHY;+1tN0ESxy?QNt)lLy zXmnx{o1A!KQN0!&g3l|u7`It;J4d+AE$#$iF*jFCr^R$yOsBC;`%MFkK&V& zulOZ&__gl7jzc`;_&O=caa&(!;cI*czIIbz+wAM=_*-B9LNk7&6{GORul4%%+aN6A z^Gc+`ZI;MQQ7TdeH&>!9?QvfvdZNn`x-8L;F)ZOM7r2ZrO5DWfmvEyc9`TeHc*i&P z`X)0nf0LE$2i=vNfZj?@WhvXR zX~|veVIOuaDPKvsO3GDIu2Rv_Zz=tjdXG$e$Is}llmrFB|br=@jS`W_E?9E9J# z%g1~}Y099BZ-2n&fBPeD^xN9h!#lqHmjTH9?O=v70=<1Z4&8mLyKkp5oy}Yd!tY}9 zDdlL*aCG~fjNi#qMwT*qD`S%~@o`IKa*zw}Et8l06r>_GsY895(wvs)ql|oI7GbY4 zhdIVc)gacys~$2o8@d$E&*vt zkDDu3l5Z(X6?9onm*w1HxnJqdTow?8F3Q=hoX;<}j*V<#JKj;wUge%4bGcW%3BvE+ zL2uv3M8Ds^$NR|g{bzhf3;tsrO`o!YS^uU-73_h534whF8$7G_(OaW zqRSt$^A#m+?3`t4~bWt%4 z>Bz{ZWX0`O^p1-1R+P7*ycK_<0gcgH#pdX)qV6i{uHv5zW)Vku9)y)XMh}%_ucX^b zGFFnOk}Q?BBk%w!I>uCf{hiu0~x|_yrZhTRpqTJZ`Gab zW*>U1Do0iQR&{e#Pa#v)mqGZW+xxLFb@?CO@Z%nC2Vu2%WJY(@ilDb@UsIWe*tFU& z{7Q4|T1~!ca#fS7nq1W;Fqvu0KsVK{2VwPSyhnW8uHRe@tLve9D$?MVs^_K*)o@eQ z-Bk7Z_Q92OMl2%evxYuv=(0vBYETYbXr5FHFR0yKipxB zp-f>7SGj>MYTV-?|Nr@Jw8kskUQO?)8G~%Nvzjv3{G5E~t)`o+SrpyXEI~<1qraNn z(Me5P)w~;owL%K;BQn;Kr!G$DY7bx#-d}qJqi|2Py|+#hGT~iy^jPOR>`|u)9q5d$>)5)E zt?NuPuDo@}Fb+BD%28L2y85jF>dRGMuKIt_miBaHJgYgvMXqq2Tj-#^d#dlAesWJg zy-QZ=&;_^o(^wV|#byq0nQKA#^E<@leLf%=DM(3bvSYWOb^5bTf7a>Gb*WDS8qtRS zEMp~W(8bT2*vbxevk$lTvv>R~Zv%N7$lD+$vGJX5ptlAI(Om=GHPBsy; z)}e=nvNzOiLm3;&(@>U%dTZDT?{Db+4JR_0sZ3`kv(ZJvJ?!TYr#Xj?8|tT#e2vmm zn38-;S>$N+BQ>yHBbznq&OnARoKg5&joeS8xh%jy50<`eXlQ_HX9%o7uma?wU=&?KPW*`)?+5GntzmpG7R@7>|SSxA>$WC22^94t~o+J__QH39AL>F}0Ql~9-+HyD}8N)c-L(8q);~`JbMax&b4Z>E@h(T=JUMuftC2uQv zTglt1Fhwbj-df4gO24h#bgS=?sa13SWdZhT^)v{7_lDn#Ve{WRGaB9fz7W0rzLag) z^!JmT#;(7g$F9H2*IKUDaiE^wJ^+~jr;{*f4O{G$o&=!ri6(B~hz{9`41*pHk0L#Kb}^bei3(Pf)=affZ< zkd&NMrxvlAl+5QOb) z-OkqSY~3z7pOBtRe2U%M{Xh+BQ;%QJWjkHAYe^SIuz}5NLl^Dr*3NG24snzdxVv`V z(O%y6^0t?^{RezVh~C=E(O$ppQ;`Ol+83n`-I&65yrDxPa#4Zi=&pmi?4Y*}y&1_Y zY}#QS3s{6*JIL2Tt`2f_kgLNLu5*h!LD*3@9kWrA@>HY>a&*)~$De74Tk6;kU3VOd zo9gJMI{I53qgcuc+)u~LLD)&xo$^x}pVz4g`s~yZn{^t)c$TBnPCD(R(@whVbdVz) z<7yCg4#>=BWJedBKgZ{H{sK4JxfpKGZ?cA+-C5_~k-77q{6z=!*10SC?c9T2$kKTl zTeuN~UF_8*2QqhQht0bz<1o7GaudCExfg_8-@&F`-B#DcBqcd^?J8eaxw^{LRj#gO z(QjA%cCAb+hA*^o3}R!mzx}PhQ;?E0xSzkv(1~%( z$LIaM4}Jc9iTgp=?OkG#8l862X*ZpA(`C1U6ru>_Xv6>pF%(^N8;#HJHW4@4Z922? zj&4Uefy~{`aE^=Ut=n~U*G+fb?(rZ9|CfMl{6K4lvxW;n*j=~XW$Z3bcUijYt-DRS z|40+s(E;!6-i5#UA7hxx3}&;KWvoOW-R0~4ItY8%t4Au*k{&sF@91T(USA<|uWu;Dcj&EG1$5U-cfEe3I=&OV zhOz=%^$y6ux9GOFjJ@UQElY2`^|ndxb?oN?m+;=+*YKU`eJcq2#2`Ki@qOs?F{yEv zee}^srald@S0A1A>4zTr=%LR9Cgc5mW@5KKhlB7R@BJqe1@Nwa^!QIr?D3EN|M`~z z*!rJ^*!rJktY;%z*oM3O$L{}l>pzdtXaMRmeK)fe{rwxAjFiTE{vE_pjv!+{ zdHTuH&-?pjAuEOX9^aRKm9b~P8o1Mbb@_|G=}s^7+fTp!hA{$r_B+l4+*Ut5^w&dw zH`QMc{q@j4A$IHUZ}-h{aeXzseq1bxxL?$zh87yNzIvuRj!8#p$otxa@ z9&dwiNK%UNH6_u7-(wAjl&2z9s76h^V~D&%{g!nFvaC0NRq6DR=fG$Vqa)dh^(TFb0U^es6#fZh&ZNy5}u%1nL z#|U{x$U8#b5l?x}EA%!p8oC>)yOFvZ`5u`lNmFb!ashf6Df=khj*@YdJfmb8rMFQn z@cvQWKWY#|7{&-jF$P_XTFVADvxoiYc$9ud$u~MN*~!lr6h@BGr745$M%!$38@kbh z-t@)a8tr~Yk7FW}*^M`j(d(F;_`ER{s6+#NpT=~@U5;^cV`egk`7B45V{|#j9gf+{ zwICdukO)c8#n_MW`C~sJ1DW{@?-*;Zu{Dr+Y#r+HGkP1_1pSV6b7Ox)ma+YDdt(pq zCB@Lkqq}hj(c8FVT;~Ng9rq>(#|K2iuH)q!FV}dv#>+MSbM!l2zvBy0 zosJAecjI+8ehPAoU%(>V*7!}F#&=-6@4$FBHQr_u{H+PTpA%vd2lq1}4-M(baD3i` zW$1IlE{=1HyFoZHHaeZC(}_BrsLP3INl!-d@;z;7PbYLS@qhUIiG6UR69+H|@0hrj z4ahuk3)|R<-X`utzY`DRrYFiW@ktO)3MqiSCUr*UN!zjc^3C} zmFU4VbU9@+$2f^Dr#uhBsqsiaCURnjsre|%SCpV6RcL`ur|NX7PN(*yH+|{H7?yCB z3tUDQQ*UyI`#j<)Zf~l0Op|w-ywl{JmX++}LT}UZqq}Lko2I*I#i&h3Ca{sKK{#Cx z(`BEo+vze+muI>x)Acre3f@26`=@VbC%f6peh#9G>5qBF%OITbF0s(@4E@ZIZ$=p! z(43aEMvfVs`5W8Ku-S~+EN2yK*?_+_!~M)S%rQ;`;Y{~G(;H{%b!H=c-pro3&6%T^ z&Pvwc=4PJbB3HPJE@$d;raPP!gOrryTgsw~Srzg5v#L>(I@HHIX4z}jf5<#*2*VhO z-e!$Mzq8!jtf|N{YcpFbL=9ZcZHZHYYx*$bn7gAe`&|=T@c-x|};4sHH!RsJgn4H}BcVJ<0zM(Wa zSm>S>+HIlT7S^K=t2oUaUIyVJ+b>E;TC(#MC8$j!exVt*TGW>Ibfhm+(CH$bF4F0u z)vRR$n>fg=AoM$|q2FN*qf(#?zsDLzr6VJsk`=cXi)C4?x5X#%{>9$E_-zm_iAD_Uxx}7J z?776AOEQs@Jmf>aOMLDU{VpkmJWG0ErzJXAqJt$mSh5svU$T`Q>}D^|f^ey~F8vN~ zT-t;VbY=i!n2)zCb$?6kyj0$$@-Dr^6|QrW7eTlz5g(C?v}8e#%k;R+cX(Mbs?!ZU zEbEQUmi1>KLm18|#^N2z-$Pt`&0mjn;6*G-fh~dFW=v-5^{U zn}kG2f*dP9AwBMDWnK#K1MX>MeHzdhx3jV>?de1pX5fu0Uj^Z+_wl`2rO#FRT&2rZ z<*3KcbVR4Cbh=8Xt8}?)7$X_YEH-hQd+1`-6Wr&j|NneS3)O)(&L^-oJJn6L3#! zy?5QmWW&4G>2X~J?6Ix|f72aXue0?!Td$kL5|*=))!2RAUaoPUM?4L}^#QtEugmqZ zNKAHqqz1ZJZ@2Y!Ti=LZXokC6?;Y#gAn*E#OlB(6(cAjD=+1AqhJL#>T)z~V)*nIN z8`GgE)A|K_cMoqkTb7Pv)9GN%Ey4l~^ydF6>Z^izbce9U!=xwvVyZIDn zgK&$#yG7P5?~?!-w#cwW2EW@HZb?B(8YcEFNuC~s`rd#J@)2&g+w^gpKa&47s>t(KSliNYKEiPI4hVS`-%E+;;Ef+v4rL5f7_)X+@2V{ZZCz;+uj&`Znyh(->2=P8Hdfb>vX$Lx9fDf zF1H`xFh{w<+aTPLi7aG87d!Ic^LG@)E$k>talB(k3tA!bjyANVJ$l>G1^w>mj@#KG z%Z{mR=6VqBwAaq;$h`9}Y`$|ThtSj=yZ=x_vmy_J__(9g(*uz`ZJIr=wi<(#xjA)OvCN%@s2(6 z?vZzoyn9Y_mJ8@@j~sjSyT^BOkDK=Ut>NDH`Hb?|Ywu9JVedI?zAq(Tpu2q)(A&N$ zG{UC)+R*{K?(2eG_sO?Uu6=UtlWU*b+_!|~tmF(YgK&R@G^8UVpQ3~P?rFc>_ST{+T(5y z|3g3iLkEZ5(_y~oYfAmB@$NMsmU0mh?k9o$+AUvUi6Lvdcw-a_dk%%v8PJi6y zi8-u8pC@#A;yjOd8iXf5AQ>N#icEY;RFaQ}UjY_f$v{+}tU>os#2}eov(%12UZ|!O!%1nrhItsg-0_TaG!@kcqTEqDTBK` zQq~)aFmR(2XA0>g+%UGn6T; zL8oVRdRC`rk8q5WoaR;#o{K>?a*_vKoGVBnic*|!aC_&xHPD&dp{gcZ2Y}z0QA*H=OT`&Cjpq1iCwa551j#9E2BQV$%z5>p}|b zdLb2dy&&HOxh}|cL9PowP?;a8PDe(v2zPs7BU{*x4lcN-3wFC;w+n9hVqCtY7R_mo z?JxevMCP%9&79#XH@JSXJQCpMF6s1=PA}>7k}fZOg*)_Ht>L9Av|u=+ z(1qV(4KGb*8Z()L+q>i)mzE&!r3+l*3fIuvB{z5JKDxUk&!uO)2*S(yyPOxDT(;Ha z@#x{Q>{sF-;}v{>G+PdSKHledx;+=CXh&R-@x9I=-TxEAm~9K}s_6 zDOr)@Y5~5W5N_#e16tvxuDYqK?eVw#Mr(Lg|5yKG5UcRUYkIww8lQKqC~n|dCF;?d zKN-LXMl+7-=<=E_{Z?yuZ4E~QKQBXcVxo)dcDwHLuYX8LQc~a@*X?!vTV%doj`CDQ zZ`Z4#yX(5UUYGiGW-J@9)s5I>!=2vH?F|`k$a6!M8+yB8lN;MO&JAwiy*KXhfJZ@i z^L-MNjE_i9CbFQ9n=;*OhP`g;?B-DPa8nOAXD}P@zqt^*-8>zHx4idO4vOJjxAb`H zXY6sy{_&fg;-Hf|-}5_qxFh?W zQ^1wiJ|GqODM2Z|qa6O0-)Rl+>Hpr(G^9V?cu%kQ9tPokpLahIZs5M})%`rU%lq!~ z{!jc$3tG`0UEbH_eLLR&kC`0g2*=UIeY@TF`S&k#jho!TJ095U!Nw zb#8H&XT0Q15I)k!Bbgo*#a@qe_NWPZc%+9%9q5erKkAO%9?i#lA4eyGcRkkQ<9yiT zvHc%6#(h4v_2YlB_2WVK9z7n%1Sa7wAG^87hd9a!E~3lFx_s;oA3qPmCm-?!g(-$E zp4jb)-JX=CJQb;ecRZ2ziM&tbebSqM=!f2($niwKPu$#-k;wF9Id1RCs~~)ulCSWF zr+t~l4z8lRr|$BZ-kwDx5$Uk$vrK%-XV~?be9z>1Cf75$p4Fi~4QPaJo=syN+u6ll zv>*ovDfX{n=0ewDy5`-^o z_98LK$c0Y*CTsXYr!RE*q72_tfx7&~M5ZtuUA&l!&wmkx8-1|?xA($3UbwRtw~+b8 zJs$8Fy}fvWeqX!|Lcie}zLe!s5dLV-R+ICEqK#Udi=Ju2);o?<@Vj+QZEtd>x;R=^_qGX5>BTg5ayv*I zBqSd-XvYYau$5ixWj_~q$YY-JoR_=~62Fs}RHP+6*~m#A@=}pD^k+Du7|S$fGMl-q z<_H(L!gX%pZ@u%1w?X1)(Ri1v)S(Oi;q#&`Ad1Z#;4;^O#L?d&F7NXJ$w)y;Qj?uh zw4^nEqKoJq@%hoa(SzRf#XF)eVGY2)TRqMji%FRI*m4lPZ-NM=CFZtT;wvkh<1Zp+~GbCaeL9cBf7lN<&7?H^vq-> z2YQR17u`iKgzlmjqcMZ{lAZh+gfa9GL-rWDjUi(Ud1A~#Z!x~c`(t>2jC~y7fBei5 zj-iVf|L}+>ya~dX0XmMUpO`YmtVk=m(+fSs)I-dV`3&!mIT5?X+>H0eijG}kc~>lb z#?ogjo5Zqzte*72*0E+_>sYpqwS;A?WEER+bFt3z2Uoa_E@SC3mOJ#@tYPd3WhhT2 zbP>A-c8gt)hBTo$-Vs~g*z(4fH}({!F%!MTmLs-)W4pQ7i;yYyF5F(6_sBqHydlnX zzT*V<&|Td3(OcYTBqbX*jhl-+e4WPEX?$JAuS)|O(UDPn!?&zM7x6dY^W*=B8;!pkw-?_#;=8l>kB~Y3Q=an* zy(MsS33Qi0cL|~q1Gkf)B3+rp2F~y@2ovfyp^ORTNhnJ~y(P3s!rqKwIy3R!gmanC z0)F5p_OPF0oZuAtNGMaH#Mmp5&JvYG4~g`Us1Eh<{zOf&TO#+L$a@o=#cd|?uEcsw z91D9SwtwOhl*ZPH+hXg)o#{hA1~Qn>S;Q*Vu%4~xGO;cbyTio4a5D&##3La|&_xov zC9zwQbYvt8+3}7f@+OftiM&Z#(wcVYElC%2mqd3-beE(r{w9*F<5z4IM$khjd#Kw` z#!#M6mQZiu8N5IA{_rLL@rHLn81Xj~iGnU7naGO2he!bmqvMEvA~HorFq@^UKo1c; zM7FU5?~m-oZjpOInACfdmc}kgy(_6cllI3ZN$sC>Iqoy5t&<+c)=6!h^c)wt#1-6S zGB=kjK8XlPgD#WlGMPI}R*+f@W*8&UMY2z^Te1mEW-2rAj%4yClQ)^X$qsUeBj_!e z9Le;X%*`eH9hs6n4Z`GZFL@D~F$!-;{xi3NFvW*tKzAvMqPG;Ks7)JenxX@p=z?8S z$d^K{6mq4IE5!o7W(mvCO^WNh4#JdCiH_S%DMw1Xr%X;tY?iVDb!k9jWK7u^-;>h) zq||@Pe#~SidQJH*2vfyIpQ+N5pEA_PU8d^I5QgKusm3vpFOWHvtf{v0Cvv8`$=}@L z0so@6R4@3Cw?UXX3)#s@Za%{IrY?luQWvKba-=RtYkYTVcbEDAw}UWET=L<)X}l|q zJZWS}qq8(CS;dbW;TXp`$tg~ApJ(`cNTb`dx=pLww7N|j2l>+0#8zo_kXCPL2O>w> zF?`BcX0eX#{KOvi206h-(31Ow8uNr+bjJHWKKVac`QJ0 z=@+Bl^egxVSTgG^#B`-G3SdhXL#jY9U z%P3byx%@_Jn6U@?&8Xju1DMMX{K5q;@h8{OLB_|}Eu-Bs{uhLqGSY~_=rYr6RoTf$!OjE;8?67ydoT ze1Jo^z0BT`S>DX@W|lYe8{P$BmiN(H7CEx$H%n~XbQYPiz90mU9&F6u36>FDpyvyvdWd!ZD#$Q^IYU@5N1n30m@Q=%2Y!K z+1yh$yJfRmwsuV7Coc1V*Fl)w_SyBBJp&(6o=UW)3*G63t+Eeg1f%$ZX}G!UI?b-r z>^jY^%k2AchuMGTEDwV)M>0~PiyZ06L{@T;8@HFkJ8~38-W=`eNN2jDw;XORM?Z9z zL!KP+Ic$|P9eT(qd(Mf-m{XpdvgG`OD_rH@Aj}m7o92p!O>@N}4w=bA zJ_=F_9p}<Ki5&*Q!e+E+k5@?YM9$DxxFj*Fh(+k z1*~Tyw$5$q+_uhb>)hA4!7cvgMG)pmKyp%%mTc%Uk1q4rF;8il@G+k;4qfE2TOPaR znaLdH^A+BaN8UX0=8-qg34Y}?ddnk69{uKVJ9+*@rabS0@T1g}qXXmdhL2A1C#p+ZEpHW?(hZyD?L{B@Vb{F!<&`V1TzTcnyMk4$VI3#AAB6cnBoQIWa9jCw zkS`~8%V)QI?kQhOrt%$oIgah~=`-KcAk6*eZVwYEg&Qw8PEi*J*y8 z=GSR{UFM&SJIwzjtJ%k0{y`V{pYWVlya~br0dB8=cNB<$yaftUn4%O%Zw1_30o@g- zi0%qhL#6^<(RYEhcvFFYgRr1C6f8k=hA|i271Ucn?=Sd0`>|<3w^i^Q7x)9a7L>1$ zT!rK+Bv+w$Bt$=jBIvVFWBM?Z5sXHTLX)svAzc^xnynn*5J&h0-&N=m?x)ao{tCjv zanW_*w)Dg26`p}U3$J7o|Kl*%&}m_v7S?HDT^4?gJ1p`Z@ySL#8qx$^6lsOe_q(iN zkmwNjXaDx1_)A zl5V=BOeG7`h+){PKo(Eysv}7PNx+t3ypI++JDlDC^G3c0=Z}z34-K^j3BV`Yk(>(a2KvYkuNt5SFu7xh%+Bt}iw(w}E5m zuG}^BR_+!rg0Q?z%f}`j2}wePk0?qBN@Kh7)u}}tdg8OoujYF;vyHv%=YQy;{8=vW zI0!2Q$XDS*d~b!2WTYew>9Ajg5iG?!h;~JX!D9uNsYHw%uX%}p~s4P ztXPs7bYu$Cu~|i%Rs0g4UvV+ZaB~&CqvBf5a1NO({(=1}>b0W3>54bG&0X#zOC{a; zjn=SIZS-AfHZoVb!rLIMoQh)TuCm@L*QX(!7|c+HGZK4N{uucx%T-yf%5qiKZ)N>f z)^FwQ=+y7AhE)=wyDGY?k{&s#=%I@3s<^8vWvM_*+*1{sRq2CUsxpR8`J4$%;s?C3 zYBZ9P34K=8XH{KRZAuS%Gaj8*)oE3oR@G(IrL5o^ws3+M{D&^8y~hXm{Aw|YLwvlW znp>z=nsUfotrBjon%=6pxoUOMUA0Cup&9z~`>bI#om8_`b@x?0Gj6DQS7fX%Pjy+U z+obv~_V6p$uxWMgt!~rmceodXHKG!i1SH0OHPVs+ebkVzMn^_5j){DM95v>#fQ78( zAg6FsHO_Gn-&Nx-|L};%L0HpUTcoQ=ha+{8>nfMntM5o-D^JNC9ioGgtelh z%UZgu6_3;urVZ`sgf42?t(MQP)sKM;VL0AV%U-pvlFvQm_4)T9pftkVd4*0E=u{)}KWpWr6z z_}n_vnTcF=e#1_6p7MhKg0QZes{0`^h(&VjR<{u4sYF$3;D+nApf&C2fWGVQ=1*)= z*W2nP!2b1YUeDiBy^2(!E#2rzABLjGdZQS_R92yfdN!+Pvw9b}gwL;cotylPchq|j zg!Pk>0-5WlAsrdXLN;=cn~#vCeraL-`gNAZ6?2GLhx~qnt zu@Lvva2+;lxC!6Ya6kX!Fh_Y3gpD#&nI`zWMnlkNqsh!?EgSe5oi@^GBb_$VWut5S z#Vwu%VdHodp*W?`MdJ$i{KoFCvAb(rhx&L&u!+5zlt$(z6R>%cL)<`jO)0PvN%oL_!*Ov0Nl&hs&E#+$IHe2eqrG8r;<#rIZibY0r*GhM-@*_tp zJ+yLLt;$o6?zr1l!x@FmTKTS4)0xFw+)t~0JPE?qNyv=PYh4L_wr)mehB1;k=(M#? zTkEv7F8xkx*m@J2Il!eLZ1W*8h>b4VB*f>pNs1e7lbUpRN1K||L1w?#8n$UfQ}ouR z75Z({9yi@amNuWUj6>L~Z5(87+Zda-oz3^?uIgP+)g-a7mb-F47i2ihjAWgvR!D0@fUc9gM`Je_3e zq_ET8X--R8(-vKH`jpR^zzk-i<4*eNBvYpgJPyLn{^mMIK@Xkv&^aU- z-rqS5cJte;VQ25{yb!x|_O8zQ?EEV>>1_Wl?-LbUcgcdSyV$x*A&O9(lGMP>b?HT4 z1~3v`cF|=Qci3enYdOO?E~1MrSFu}{TioG35Alw!@^+QCtGrz^kcq75t!r*{*Hw32 zb=S2p4d~BYY}NHr5O&i;H`%-CwwsLIRyiKbfG(X=&pzEqxcx_?>-K@b^jjk?GY8b^zg18`s`5@oAj`M zk8Zfn9=7f=6K6Vb2If{T zYg3PgG{HN1wnE;X6Pe5urlGf3qit?xDNh zdh6}|y`zzoY}mASF7l8UyY`l^w_LsD>Md9A4s=F8y?Zc~wH)LWXE?`2bkN&wz3tZ9 zZoMA|VITL@rxv{#!x!kYk3Re8vXA}yoaQVKdC6W-8K^No+t5{bcX2+x{~4m#4oh{q@$rC*I%R`}BvYH zvf~|t26S8rm&7*vDM%RdKfJGVBHRuaj-mtWf`ou z!DsOP!QMakCI9h;cR@JhJ))qCA(_ZZ4hm2h9S_mZ5SfOIU^YuxfgXnFVaPUi;Qd4P zVz(jpf^ew!4lRvchI-dfeGb*Q&!M&+dKg;|we`?*T;LK{aF@f}+_3m0 zA|wsE9Hz@*?r>N^YB88$j6@g1KE-asCNP<)%)mQ_$vaHmVeoBV-zJgEv7qGA41*!$>`hOiKp5e`Gf7HnIWUJMtUsGSa(7>T~2p zY%EqjWjS9r}INaMTvAaE-sv z#i+a3ZPX*4@SIn8$7p#+%R5@$(YeS&KJ+$Pj?wxZ?dC?8LZ;CzaeJc|vyYoWIK~_N z{%Sa;HocgH?#3)ZZ(~-nm7lTcm}4C0Bz7Gm-x#^Z$Tdc;kE8G*F^ENOs?&kK3}7&B z>th{!JQ2HnY`2fy)5q@rYgx}v{EkjP z(dj2T{p24W@|dSV_~{3vq7qf9fi6C+M?;#>oL0EKPrc()c|Vo+Q+Yp~#T@3Nw@>Bx zRKK4tV+AsOdVuRe_*pdU^;u24;j_8e{IfIs8-!zZH#RzY8yknz*mSJh8k--xjxCH` z$I3TWuCa2Bm1}G_deVn}%;tNJ;%>)Y2#bf$2G$pj%!UX#_=7S(8ahP z*~xD9aS*pR&O62(N8WL-c+J}&93P;!@osLs?#BDu9rloX^K z6{$jXbTH9w6YVz9ZWG%xnO$7rA#Z|kl0GNtbCND6*?&?6D$|Cp^q@CG7|uvWGlg%^ z=_H*_(&?n#?8P1Wjn;6|8U6{v$q|y13SCUjKxW+NGt2Lb5 z885W}y$Tvf-8FI~#YsOOaJ43%S zzU2^if^cRObT?CXGZP}mOg+qWTQk#>mufVo87;BdOy4!L5B(X0`}g5GAAM8C8BZO?Yovt^mxo=;eby=LDF!Z|X}DTK}E3}8CCoAV8No3oam zu<4wWoZ>XUW7j$I&5>)4Tyy2}yR6|{{m#|z+yoS$F5MW+Fh(*49n5u4bL}?QZgc0c zm&ZXkFEP5Dmye26L6`G7F_aO^#=Xz8!@T9JV*}sw1N->{ozBzgJe|&a!ZTj-Ul7iZ zNd{_An|kPCeiNG0inesX?alX&`SQ+}cfP#yzvL?xp||;R%-8Sy)wt>TGR;52-$D3g z9PIUFeZ1kzh1mSdi@XTJ1-e@h7riY=L`H17pfE+T>w=Qlb%A^f$#9V~E93+%SQZVTQ8;a6E{#&9MxAKQPW&#(6I3x9H**Fm^2D$$9B ztrkW|Mhdc19-S`K=|Y_@Y)(ts(2l-LWD{HX5nU|Y%{~tDGe>cI3%z5ZybI-BDDT(r z5rq%Y+t+e@t>3TXlMtD{&PyEzV6U&Y;|+^Gz~+m}(Hh+?8i?K&4Pz2EUF5bFEyk{k zmSfjN@-32Ukz9-9T6C5RT;fU)E`Fah6v5ptu0nNcp@YTlX|dfF+ikI1UObh(T;p*N z`kmEqiS3t!WT60+sYZKx(3^hPYRO2(@CnoT7M(89=@OkT*~bA6ahP*F3c{tyNkv+8 zu{1N;$VndZ;r5n#$5MHh%DYtFrCsPoPxQ7_j-~otI+&rzv~(U@xrn`%rNbMRb;st* zR`Wk}x9kt}w(KhZ2H|p>E_YkYqhZ(Ov9RlM`IgJIT(0GEEiXk`Do_dCEdQKEtYQu8 zkz=_YmbUSA32{FwN}}r((^!JfTd@~?t~i6uRy^fJ z5UxysPFL!5rA}Asa%B#3^AV+K!pD5ZICQb{3w-{{nYhuF^KpACyoLyy}lWb%-@{C=Bwh93*D_MkKR^Qp(!?9<+fJ!q7VJB z>nizH$+b$ZRdTIbfqqx%chx#haz6-He~7zX9g>Wc=wP*bT5Y%0c3WM5mQ3Y4bh-LC zSGj>MzkQ!1BqcA!u*0`ys7iHeQHRzHL8ss9^jn>NJB=C4W-cq)&28@T54!mF3D0@O zn;={h;P%#d#~OLp$h$_~HH9cbarCyPEV^5xyEVG=+pXc6&V0_d9OGdSuGPa@+1KiJ zt&D5sSu4w0y{%o3_pkN-wWm1E@0{ZTf1r!CZ-a2%dwf6~;-lkr`dKH_x`y<^-`u)U z=wY26)=g&?-oNfk?6%Ior|Z0TeNybQ-n-W8bA1hLvflpdM=}OmuV0F-*V}siMmDj9 zZ5-kV*SW_7{^dV(={H)#4R+j+fb7(#5xUsW0=sQ!M@PEQ9q-uC7kM`ok_?{p56@7n~7;pNn8Q$>Sa`tnLcR{#OcN_J#(fcBcgYqXKr_ zDBni8Hp;b8u8o5khJH4VW+}Tl$6ws$F8`o|jduIqZr|JO`wwwX-?!xxX0jN4ey`8( zb@{#hzrV$uAlwv%*u*0tDM&?H(vz10)I_J7bh=5Wn{>I!9d5GYrXIM7O|$rkJ?LW7 z|2WJsPT=-7oxwXcT@1n>FwfS4tvL3r`mT$9Mo8{Up*XFC-KtG%R4#F+^+>(uQ zRHqhokzan1*K9?nTXnisr(1Qo)g5lNw$G7e+Y0o(&F%ddlibMs;}GVuh2PNKk9zy@9{=zz2)EnR z@3Ds46BCk@N@7TdE&hjUA*m08w{L2%b1>w%9q(-MZb-GihI}1^S;*_KY z9ht&(W}yqe#TxEhh#TFxjFqg$J9f&uQ{J8O?)-zxxVfEr+bPFR{qFR)z4JaY{S=!V z)W%*v&Bhykx`NGjrJ@+R+f@g>?P^FTY`SYG!?EkG(b#pDe7oe@CD$&wcDc=6o7u*8 zF7YY|cPAn(8OV&kgWWpV?VfhqZMWTam!%tD@e{|ni0yYj3c@|_6OZ&{q7;>>MonzB zrzy>8Ne_DC=Jx1xk52dKbdN6gEX5t}`Gzf=;06Doi@oph0nvy_9NgYs@7Nn6@7{7$ zpb}Nk+g>-fw=TNdE6?60G(&%T=b)3lw%Qkxzu~IuLs89^A0S=4IKD^y`1JO4|&OJ-UZ>o=;-pGE)UxAU}_4} zhW2zq7YFTj(B~iQ$3TWK9Pc=2uY=zr^TG9e$0qc4a2xtP=yne7MwWw@c@u>HOGkM+ zBlG_@a*_u@cqlfyJCq*19m+xxs$$baHK|Qq?0QJPLvkIG>yTWBK108U^m}MBt2xGB z= zM{h^cpx+}Ianna+IZ}}hjK^L_jwAEYq}cpuBl@GeqZ82E(J3s#rbqoda`XqbunoH& zmG7urN98&y*HO25RKG{{d-QP-9t+7&4g5QBtOc!UhYpUpr(rBc z{3S72$c`?5sX}vFF&Ov$iyeOXoT*G_7IRp^E_C{fPJhwqFTZn+i(KMf5FU?8Zt_w9 zT^uh)Ny<>3O1Qn_-f>*sK?A(;*KgRyLG<~nK7ZBauP=k} zRBYnm=1%GKlul3S^pq}7mBSsLs!St#Gmi!6;?xqBL$0*+bK79>Jhp-^^6z13c}y?_gf)!@|&%GTg?Bs6NIN@AmeFyPRnxICZ}7`hQ54) zO;3C8X`7y&$YfTqo{ju~{Z8*;Kl(T=--G1v_`KiC;0AuT$?t6$fZcze#(chF5v$PU@4Ebb1G_jIgl7Yy z@FBW5YqzsL|7=2%kdzd7$60%wt%l5JYf*>#=px$w)~ivf?h!>*Ksk=X+wW^Ex{} z2R)qE!}-;$#rw~HkKN8+3c?HCd*LI>;$0W?c%cLKxM2SavvHpnY<*!nw!W~3!yMx{ zCvle-+}y?Y_<(4{N0%3MdC?tS%uH#z(4AiB;-cLy+U?>nMlyy^@s5k~UX=Huycf5y zjUDLiq8u0Xd(q8ZJcLXaZwBEXZtst5RHrxI@W+pw<9QHXN{sFyOf7A)WxQk z8q%1i*!7Zpm*l!6*Cn|wO=c=Hn1yaGo#sBzc**M^ye!9MJzS1SY~0f20_gg31>DqS zH+9)}UH12Rxg~9IKbPJAWnEvs%maMhm3Zj$N(O9pr972rjZUxV^omZe=<>=?Mlgym zSjh=aaRy!ZE!Oag&%bgNH+tn3ZtseB{OQjAOoq&VrXmgL(c7O{(C?o)$&D<3)}#m1 zu-BizBlFd?*!*fMhNHWy)6v`2IeddnukK(MdpW@WxWaAj@(;GV`ieKa3&LyiT=Uu2 zn$Qs)T+_id9bEHW*S!7O$9%@;Y`|NuzfU4$yPlsy*y4HvI@1k1UzhdzRP20x0bjG2 zrP%!X5B!3+UO&$t{KYNwc>Ny#1>udvl%xzcyJ52%RjEO3>fz>Yc*l+A$a`ZP6L1GN z>~}-2H~dZCaLYI5@+Ds((~TWm;B658vZ#TXF<_9DpGg-+_ zPV9Npo;T&YDc4Q8ZpwADEgjI$&93P4=4$qFl;ix095?lF({?v?ee+=u-ikqpd%Bg9 zH2AJtdB{gW3eyH%-`d0heBP}a==0W#AiVAG>2^|5Pyn6Y*6D4X-qz*qTGXXJ?HJB- zzTsPRar--b{_QRN$WC_S9k<=t?SGK@_P;#A&E3}9?bqn{@Ars;EPtn`EN<^_d;Prz zng4zogm-LyCqH%2-JMS8?M`<_VADHp>&|p$G8?dhgXASRuh5NaCh?hZlFF85z zdH1TL&wH)u!Dv2V0Xn^>(|bC-r^|br*~WGbb1ew($09BX(8c`-KL36y-01xbWX3!0 z*P|ga-)~BDTA{c5?a}Xjf7|!n^nF?UHfwl)700mGKM9ffpBC8spD)>p?*91&z5R2F z>)7<4XT0DQud(X``5wsiK&}UJJ#d>3^!q@+4+_(a!AxTzi&@4>bnw7EJ+RvYyFJ*& ztss1ujAH2WVH3L33tc{(%p#Vu1NZ*W4iAs;8)rDj1^y1gNAIK4M>>6^(?`ikNgC4e z5mo8OK!%`;N2Bp+=i{Sl_z5j6wTG57fbf6Qucs!m-OkplxqT|QpC?`DPEXwb6K{N?*C(%n@Tt#x znjE+JG&jYmMP1z7)BX%%D4(Fqr@DOV4xi3rBNw>DpXlQ0O?>{-dpzJ@p5h(P?DZ@o zGC#{oc54JUThi?Q!~y; zyAN^G?_~1Ztl_&#bi-cnzQY^dy$T{hGK$cUPIRXiefXFe%wi7n_>!;K%r5qFfL}Pt zZ=B&p5P2^NxhYO5%2I*4G@vofXu(*va*n@w7DV2UL2OcyosyKHDedS;7y2@QK@4FW zi&@QDHn5HD{KRgKb1R5MiBBRzbP**bX-H2dvXTSuh$3$kd85c1r4?;xkKUrl5v3bF z>5WWLrm&7*c^pJOh~Nz$v}Fv7*op2wIECImILmEb@*i(_7eu1IM-=3XDpypwqRJJu z0EH<=30gCP*(_xRt5|~$qVB+MQSBCWKlg&jhp8z|9a>`h5Bu{O(^<|p?BOuSIDxG` zyuc-{@J|ql77d+7(`huFMoU9FGLo5s)M7Bh7>O>Teah!dU@}v2d(pfjn!M5EjV5oj zgB;=rdW$AUH2p?9&F{z*?P(B+o|q!oEBYwBA^OkQJjRD)KzA{UqPG~OsEtiyxUCo+ zu&du>jl{5P4EbWn6+^BVa>ZD{*DPTf|KmEZgGfww8#6ZXNQe$%x~G_Si)pu*ZaHRs z##{Si~g@ACaFz*eX_8Do}}r^g^exbQ(*iu|8)!llX$K*vw_F zasyrXE!K$NVvWRl$YY-2_F{QQYQJ`&Qa{@H(4Wb>>5YDIC902D~?=o-zO^3 ziHUCFR--*V=uJQ5h^vRVZY%C5xZ}9rqU*TZ`H4OFuDB=pjo)!U@!mt%@fy$(pBHZ| z`iwUpo5lN)ot#0Z@pKwbr}1MdEGv{KUI(qlpi22=7Szm}khG_!X~t7etciEy)MyH;KRPByKv1EJ?Cc zm7dru$tGk@@+OFcHV=!_1l@(b&|BD_&#-AYm-#GUA$ASr3*`#s3grsjW~kp#zu`Ha z29Zco@}j$l?jmK7BT@sm6{$mOhTv`^&FHB3T-IezHus(PTNujdvt#MoVN) z)|U2kLT|~squ*qGaMQ_TNj9DDIE}rMCr9Sw9k6-wrR+v`$mSB3)v__U4}7| zG3X-I=lJ|olX0V|W-uG?NVS&($eikDj_?b5OLYqUraFt8P9;mK7eOR-gyPsM^~cDZ z`Y1L}6NAj?E=>vamZmKAuxXl(bfzoav1=On(#VxYt~7G_jn+sS{ie}xnw1>pChvks z+StS+AxY3dTKAOJZfWh7HW!T;&uVm;_7E4igf7$m7evy~yVj~&t#r5qKhOjVlD z7oDclX*!*zo4_QdFpWiQ<0?0}g)Y+F=OK@I#!K8@I`2p?Z+dyt%bPwAc`1P2(icN_ z>2;T0cj?R1hS4nJAb$su40^~Qdj{QRkTHWi8Dze7>G?m4yV-NfJgTJ`VU7n!JOuEcu$ILOwKn-f6i_8tNTV|i{ z_gEvD+tLB=$lQ&Y%t7YNU-A`t%e)lbWp;C!b(eV!vSdDjzO%$35A~5b%R+W?krzQE ztM0PuEo%Z2k&%MfG;2|cQ-ZL4ne0`w_&fWy34A&tbZa$ z)_d44tJ})@E{J4HiobzuZYrD2vgO8iWh;gI@jI=NY?bKE687;MJ}=v2^qD;xiOE8C z++22@X4h$Uoo3f%_Lj7v9etU|CbsY+y2!p8pP${0X8)O^9LGDdzv2xt=Xj4OxVap9 z%Mlyh<2rNv&k%2AOj$dRi7jc9_+a*g2&rZJN__^w>;C)aA$vL5%J+Z%K1 zHFt4*Uhd|&&D=K0J%Xvsz|H0Ufvs$3Kf27V%iQkJ@3Tg7{~JW|q#!lv&_y1* za`6%QDTH_Au~(js$egDu-RXti^7Kc)d4@0yS@O(h8-MUNh2&nuh_eHJcBHCob!q3E=*P7CX_ur3SFWDfKAhCTevJszNo!cY1C&;JiMTI4-G zz&nb3M1Ev0QkbHYKyO9LqTeEwaMML(DbktG`4)Q>c^E{B%3QPQ z39whm#&|=?CD^>=6B2(FdG++q!D!U7BC>I@@m#aj3bXRUDdMh`Iso1of+bXvlyOvvpUCYT= zPOfrtm6NO7MJ{ud>p`Uahh(4x?zVglYEus#ly^_%?N;7y<=t}mnH=OM&x1&X53qfO z8>_IR3qPL22RMc<9;fzG4ieIsVD?y}^y((qG8!Gk2 z=9SiQ1l?8o6TMaXi)TTkvP~&yQ2_jVjd{>qDBqGH9R4I$DtIT2rKCj9_^jYORHmmZI z*FmIe5_DQsr&V=YRhL!skdFeCrv+mf&m?qFbvi!3>RjAt)rGjds@_r6omD-~NltN^ zvs~a0++EeH=&$NuL8RLI`2K1Y(ML7kQEek(P)Vw50?7o9bPe z%xd&i{RFT>B)vQ4+>QbL}3}-pt@Ga~3j!kUgM|QFs@2DwnO?hj| zTk~J^QPU07bOSa2KgZi3QtLgUAXBaMl%*r%Sc5mzdKyG(Cni62&|U3L=&g2lM(_nw zna)gRW8d2H)t0NaT(#w@?T%_6#m2Qy@;HdpiBC4%d7Yw^pfozDQyaV0v0I(SjNyBJ z;|7m{NZk+6XI=MOHxorDP6JxfhW6O1Zg2Y1pHCRe*XXpaPV4Hlt}g3t!{1TepE$-} zL8M+>5}=EE5t5UNv}7PN-cc_n^44oYGg{CJz14Gb^>kOS3%aY<6PfBwM&I>L;7#?D z;0^U#Gm3?5M|bu0R^R*UpTXZ_eVf*ITlN3LrVRq#Cj}YFLU!__;|4lz;IkXZ)L=NX zSi*Aj&_E9jw&MF5cz=UExTgkpgGfW~ZCDDsH1w{9vN!CP|4HM(r1%SLu=RDhZcVkjdRjoljAtP524#8QAv;Pnz*YbdTUaWTG*zE zO`Ei*Bc1U#(L}x`ay5~wiCj&-WFd=L%0aI2Ul3^;omj-hZ8gCc!}B20EGBWtOdj%45L-1XLwPFF05{i6r_FTQOsCDpGLDJ3!)6Qk zflK_!b#&3}Z|?Dce|gFayra3i&E;(_Z}S}F;v@9dT#n}YZC;EL$kez#c}M~LcSJqwUDcYTrJ<@1ELXwoK&S9 z?zUw=1~LR4v~*7`?bgz6et$L6@<;9lkyf!uMRsi8N}sLj(u%$e;0xw3pRcf0t5tl< zT6S<6owm|xE1kBw$3HycaS&AyeypTn!>^qGGQ$)$xWlv$1)b-*^~A+UlFZwW(?>LORZF`ZzZz+mmU{H( zGp1wvcHgj#gPh|cPk0kV+6P3zR_)`FfJCIHI67^w)Al-TU!R6Fp&4EIgf*;ZBf4n6 zmF@h*9`@t*+IvTPdE3j|Uf%XE`H#0jq=Vi%$k9Q+9ikHxnL1>n3O%q_hwt%*4zGhq zN1JynMq_l>u_t=#*pE+{h1=>l54(2!3cGfcucKTYyw3H|XXj4Xtn=qg zU@1E7tkcdq?X1hrJK4=%PV#pU>5`BnBt;ipQseWxWWv`^A)2?o->$@P*?LDGk z*KYE4ldGFt-Q?<42>o``Z?{skWfXI9x81(sTh^h2Ztkg@-MZPW+d=*bBHhzc7F~94 zO+N;r%kDE-$!hj-6gzbPl?(jA6|V9yi1dhoPJ8IIhfaH>BLkVqN@40Slo5`jcdWICkUOmU)4Ly%w z^Ip-(gzkD3M{m8#P#2r_>Od##+N&FO?Im9?xq8XfORipSv)5vlu>#%n`ir+gq<1u8 z5(hbY>!G*X>Ya+5R7BUk8`6a4_^#gF=|x}MPw%hLb?*m3q)&j)>ys9J_9=kP`ZS<1 zeb8wio%YdbA6@pD$QMlIYqs(y*SU!<`rPCHKmT9cXrC9jy*}R2*PZpvj?8^?^AY*c zTVFTVS9g7N*S8Gia65jBHPUw}2e=(X`o$$5y6q=pKY9Ae(ob*wY|?KPKXQa)cyGUx zoZ>Y1dB#g#2a*0!iB2r^(O;(iHL+KJo%J7t9{TH{{{$xE{rzWPxBl+GzxNJ^kJ}vJ zT?6zupaS+7VE+LF8G@|`e2J|GEM_%pSkHIt<{VeK!7U!5%K^F^;0_0VNE)h8om%K( zpxp-AZD2E6(uVeU$3S@p$~#crfpeJ00`xX;3A!7oyMekJ_$~e>2Hp%JgJNQ zAlV1$c94vNV7(2Fi}w%q{=xYuKp~3YZ)R`_bTPOUZSnUoxF>zk@nHQ7mT&N8 zj&qg^Ttbe)x4Db$2HR{%64H~2tmMFV4RJq1N>P^b^uQa3=yk|ReBO|UJPsm5KOg}a zahF5g+|a7jpf*j=M2DjCz zKArFz=;Sxh$xU^#StsAs$?vn%Z06#AIvoolo!{a^3gGiPS4W?nf2JJ+8A22~?X1(z zI_<2>&Rf{dPEPP3h;)gNn)lE}m-q4cU9#dvyL?O@yrWAU>LGKNpJ+r=^wy;X`t8yh zH{C^+E~8n=Y3$WCEi!j)jLo~wVH>*ZdIr69y~x8L(#@vb-XIpSiGy9c$=6M;ZgO># ztDD>Grr&P*?N)+@^kfqL9q6`@B`ik=-P}_*yLGc$x4rxwM7n39G`j5GfZyqWF1wFo z0gKtiVeHWTB!6(3Yuw;T5b2Q!o%Yaa51sb-kSt^)2cJ@vE_A0Cy67>0!3<+0V{m&t zyrYM_J>=~nZ;$;P&l~#X$L9T7GaTLZi$ZVx7P1kW_H$ePj$+q-C$Vck`TEJ#PpAmi4yZ{(+S7^A zOkp~+u+@O2EN3O#IFC*T=yZTi2R!B}FL)V52FBxk%2SbV(8a(Sd`BJX(EztM&^rdo zJ5b(%@(!H9B&MRbfpQGg??AupfeVmn;9hPAkwFQu*PtqR!=TC7e9$?b2a&$wDnUGKlfme#jCwbAU@+<=-GO^ey5LA6pHLkcxNth!W^@s7{CKbm(_{PhEcG zR|c?x)vQAoLu1&=4tBE-w>Q)~hRQos-l6gi`yX!-8@&yaW0-!2y+cxD8kU<%w8mb; z*5eJsV`1~*U+@FE8{P)J4e!7}Y&zU+4WEWxhtI;U!{r+;*KoOp%QgHIXSu*1=w?JZ z3R0Yse2E+*>^{P6ji`=09?^sz3}pnP8OLnqvVg@b5U_^QT+Zk zhBFE`H&Uk~bvja~BXv1)7w&N6e$MeYh>UuV^yp&Lhh)X)k8-1<^5FJHdB>r<*dTiV{JXw)?+VlgInC?K6W3Mg0y7d19G5Ce}6SHE-xjh zO>g=!5M7M3+c>+88_NVH4a9arY&}zAm0SJCdf5Gt_ky4$P$*Jn+bmf zk%{q0MoLm4$3#6$%uH6?(!|Q>dSX4?)I>Km(RWS!oep%y{Y;#Tt|z_>B9ju}^Co3S zpOZevW|QhtpHAp>l1?Y-bdoM7jbS_!na?)v@sLO8V$yT||MUL~B9qR^U49GgvDhu^?d zzk#XyIfU<;>VBqP;W{^i$h3Fx#%X$;)*7ETZ4_>EnoXvyVmJG6bJN`Zv_JWqf6?W1 zT~2q0)02{oZ>df#bTQp-(|!K*hBToWE%1)%_L@EgnWxWS7E$PJ`a<+OeHkl|W%^P6 z3L-O7P=N1{dB$wEb2W&}4A9-ol;~~dyJV**Hl10V5|qNOGv%8p*G#!)$~Chc`kkrY zncbMlX3pR@H}f|4c!&;Wz78U@>^948v)(2bKhhIj&YI3j)}YH-C%DDkATrwx&Q6FO zX8SG8PD45}@IHAchfZhfbhb`s*XJi1)0Fm%Aev2VK^L=kv6llJ<``~ows*{tcaFSs zbj*lW&Kydf$9HjgSxBXk$#Hyx$7s2+^Orcra4 zi(R7@V%I47qU4H_D@v{?w;6SX>)Z??b9FN}GoSMn<*A4qbL~FYZO#3GU+9aj=Z<9p zlkr`17qOHTxSzQfgUCEx&&$mh_`G>PqR)A4vDv&ajAuDIou^ZOcQrCkm-F^>h$CF$ zMG%>vkxXPk7xQ!C^XKQqjrx16k@;?KzIV)bXY-pO^Zb^yq78bR-vRy3?@D)MnLmvf zt_G0>_F9k?nHT(q%@-`=Ai7&{4ZSV6%|Ah8p-mUMt%Zq6LNe^SP`-t7EtG4aTnkI1 z--Y^J_%**WgectY!ZoaCBRW{NE{<)Rk!pf|c)G?Ue=<0$8_ z!=lUF;T{k9D~K!(NQF)p>vXYB7w6^^@>7s6sY`zbF%(@a9?du=GKJ~5y~Wny)C|i?iTBAvF;Y%4I)e8kePBcXE=ITBKs2EE|qbqJWFL+s<)*T@&2XW zzw|fS@H_44NN04hbSg8L&0?0JKc@liy^4z%1<)!$BpJdf# zYSWuFoW>2TvcqccSnVCFegA6xuh#o&`B&G(&a3sdT5qd=#pbKq(vH3iVm3Bj?JcWq zym})sY(?hPvaY@tMApc;CdA%r(vpD>u=^U{yCw&IUu!-=)-^v+5Bsl?VT}xHenxj| zS|ZDuHvG;gR&a_JL1eABtkwV8M)X0(weqZ$Wv#cbJ;wze@H&XB`yX~)_ZDxXlXV%% zhHls8#=h%xvraebzCfmRJ#ahg=CS}itkc6fo2}b|_pjT<9v%ge_1?R_6z+Pxcdggu zdiT8EJ+2?id={~jL-=>Z-%X9IzsM!7avgUWosg8IA`O|)Wwb7%v*RA3?H}ElZuCSK z(fzSo^iceJ5%^tQ1iRcVM#H#VgizhKvm@@XG3}HAUnL#wyxXB%K5%VYi|M^dGqcQ*D_BMORW_PwZCo*r& zLtYA?x6N*Dv+g$QZgWXW<90UpU=F*v7euxsB|o~|BI6c$w#c$YZ(D4#Wg#0m$YH#9 z%W+O}n!osmS3$(zPmOGiO9B$3kF7Fot&F|4>TGKV^srSATL&`?@83EGyKQyHv4aDPbX}>Z3?#DHj70pVL2<=#(A!Di@Q8Vm)mr?%^hx!$NQA0 zBHy5k?RML4x9xSPM*|w+9oyyIF7I}Ew@+XaQ_(Z$Xm`3b*=oxjo=9q-i7 zPMLPD<0yY{1wHK4!_Fr>$NP8w7esd1ZC6&jcULFuvdg=6>2udoY_iM#yDsBCciDP( zY;3*T*1J;>AvI}mm%H8E?g~_*3boPYZe8wnhr3%bkd>@qJ-XPv8N2P?$sYD|2=CY} z?{0bb$h+qaV(~V5+at#w{qAvddy*m3o;;?OlD)(z4GmqYp+~;<=T6ib6n(75ZU)8=_y2MzM?#CYo8AG{ea!}*=?VD+UNfF zZRIMDgUJ5>Vf+31+@FPfl%X6AXiiIh!&dvd(4C%)U;#SauhacH-M@_;>}D@#coakq zyh~a#po;^U`G_3k;uGB70q-~Dqj$x8t~rvy4aq@P1F z9qPw)7PAaJ9MZ#~?d-z)4;{d6hur^R?>$@&yBzke!}>hj6`LHk|KX*qz}AOPVC%!S zK75TE+~zL-1QCBPHF6{k>BvYnba_OVN8I6&;?$xiedv!ajts?aM@BP_iA=#ej>vmN z-XroJIl?hcqPHV*9MSI)H+SR;G9CRNZtrMG8ZrQHIC`AFgUGR@e2ngnl|paF%JLn} zu<5auw4yb3Jtp5VxsJ(oOs->5%x4ixILgByay$+x2zeK`bzBF>b7HsSc02B#j=TTk z!&%NY4rBY{`aJ$Dh@6N;gw%Y(rxfE0Y;~dnmH38wbU>#kbb3OkCq^)ev5aRfTe!o0 z{zMlip7Mf!c^yPfzJc32=^ZEKJt^-=c~2IkFh$YZ$r9-9r0!1Y?qqq~&dGi(Q`%(%Y$}c>gKyKXsgwoaQX&@tZiMi_-yb5}U*%MaQT0b6URB z)oDq4I?)w5P7h!(wmWUJ(`(p{-@xg;9Kd&-c0Z>tah2;qSfehWH0uef1uD`GZ@i$_3+M597yiX0aW_8yq8q(|j}&nu0v z$(7!W!(Cok$woHgy;t^gh@;4SMb;}eyP63(uV%ycS8abaFSfs`x2r{QcUMc$j28UL zZ?wVpUhRl(uXe>fU+qO7W@68)I=L1HU0?f#w)mZ1lku7kuU+9Lceux^AadRB`?_1Y zZqw_@vFY^?`L4@#U9RhLUH^*mRHQP$FdX-JeFdvohaA_pvx_~P<}dyWA~$q;BNlJt zyKY2C&3mMy3?0zxjfMEU8~f4c4V&D!A4F~jyh$2#dQ+!2b$U~mH}g}7BDjT{^%=xa zMxcwEcDw2GZ~DF7oX#ww@Q$0uIElma!6dd0QX1<-7eNh}^N) zop(t~2IRPtosY?l&F<8sAx&sT3w+ld_j9KQz3IzRyz#DH?J^mkJucdOEv zpK)_{2Q!S3OhT7;b$Qnv-d)Z<9`lTU(8WEw-ShePViT7HB*r`L+3VhC$b9b$O7bOo zyH_6l-m6R%WVzRh;jH2mFN4T^neUgP0X><9?(VNfZ}+3w&joCH|1wv(j$I$f_du=( zay^jiL5O}I==VW-ic**M=ueW=qvb@}I8#33H3$isKkp&q*Uvk^Z3&*r$% zKYybw-tp%QW+U^T^H{)Q^!DdUboZz3{)}cLXL%7s{(6sM)Tcj-(CuF`K9c8=ERXc| z$R>~8$1Oc7#g};RqjFTBB8~Z#*8EO4deR4dJd*FxZtV5w4)^&JIUfDXe?jE$0Gs`t zg?tpG2%q7*{&qiqSLR!);r{>j#=rIY_f>q}<2P}ek8Se!0}4Yp==Q0MPvvd@m*3Ww~h@lK;B<}LL-Jg5w^Udh=xlW%SLYL3o;qwc~{aoG`ZzJoAPsmRp zKBXACd*QoZl%X7M;f1^}I?#zO$nips7rJ}Vj{yuurWZ23Sj++b3L^jL9FfdyS|j~rCcxNdMVdSxB0R@T&42d#ZwfO1cPogzw)yK1DS_@@yU*8pdtHYX*z|P|deMh| z*!8u1ujP6z*K4_6N2A}@`hC5POF2-d0EPLKax~yqTJt*{=*s{GGmH^L zb3X|Gmxy#^rx;&Qg}VGkTZS@@iA*7i`7B}yn>ZDOZv@EsMr`7efW#yv1tIT}mM_`J8G(C1q=d22W4xX800jIGnyI*qN<*t(3Jgyf{eEyVteMl_{4x`=JJ*gijY zdpgmT9(YIW#VkYS*sEB>dh`~1GrEhdyV$$f!;K((`z^BKzTR%ZXx5?Iw`GhYPaIj| z=q-*-;(W~KRHh2v8>c!o`Ht3frW-vO#8BL29DT%*Db8{16-Q@rUIk%XJ;c>R+;>QZ z_s30z-Qt$Sd*hB}F5VSak8$^5kGS^t_fx~TuY)k2t>b0D*6}ivi#+6`0Htwr@f!0p zzwkS{jHk=w^%@h)?Xo7}-W;>#Of-uUvye~)xzL~rr4pu70G zi?6%*x$&Eb-<;vtD*h?-kU;hXx=kQs0(lb1l0a_>M&tbnyg$J@qS;6celrQSp^F69 zxrN_Dg2y~V#|iY4P`-qpQk6Q?qXBXxY(Xn*m(XSj`!JP-EMYmTa6bumup9mRo2y~M zr$Ly=8x#3GC8~vcP1J$T_+2HMh`UVWE)(tL7$-Ty6?Bmq|Y0L%cVMO_O9NCtp&DDpbRMNq*!f^pQlSBvEWeXGspDha`GP za+Mo+f0BDV2*RWhyff!enm}n>fV7?#c2{ zgwH5WS#+69m&qzqm-ftHHgnNMGP@0a zfcuQtI#L^3M{FJWndY>l749vy0v1@AiQp=TEuGDg+&Pi_alAoHiWhj%F$_(6AY8|9rh22uyEwy_} zeIp3p4Jkxfs$=_i_4#fW1~P@|tY;fL*@La#J;5o?a4QJY{12V_d#Pa>ou)~}yQC#O zA5(^3Y0dBGB28zy(UU&($L*!@jx_S7k=Nf@4b#N1h3)7q&0chuMt5m+m*yC5=e@*y zLRH$MhxcTEPq%4hOe;@XS<>n)Z2`PLt@o$>j_>(_dep~nBCRgc_GJKr8N+yVoK`<+ zWlDRIXF-@Q7H^}6bb3gan)mSjbnj!gbnZW$_okbUUDA11I(??oXF8jtvw!;7#KqR> zvtjG>woYG|Pbo%mD&gkRx1tU0=#DPa>oUDNOh1;ToZ&owpo{d^v0M7PJm4=L;~g2~ z%^+_Ec{5}tE7{Ro201e5H-nqYP!O3iRLAXQn7{@u1z|>S$oLUo(U{)oF5^V>mT?-( z*osXv?qoN6v1>;8GRl=vu8eYJd=-T62fWE!WT6yw_?ch$6}R=i4&LvD-QKs``|j!e zRoo2158{xD4=IE`Kd3-0n$wd0j9@h5u+;}MnZsPxaF{db^aGuKaEm+K=OO>>uj(Lm5Am=R;XC>n(F^ygzd)J|a6g$weOgCNk?Hb2VyGo1bWmjx*~gvrL&6 zv6Ew*L=Tzukoh+E@czt?uv-@QpT&Fq?bI-fU9xyr7JX)!g-x>9Kg$VDW9uycVC$^5 z&Kj2lB;p;?;pVayrzBre30-E@Wmb2XwIN-Z%K{doi>xcLTh{e#WHa0Fj;!)#l{c%r zS)cNpm+0-I|Dn5&boY_&K8i^WM$)>k#zu^7Zyg%Cr zMlptQOkfha$hL_sZ07)n(Q!8YWRov@3UX3_!W2c0?CvUiIc%5RX4%`&gWmLGAigWR z`^i3q>C9w5-k3wLIdb9ia#W%U4e)!)(F=E(!_E17siD7@8s=EST6CF1mpR;Fj)U9` z!kq7rjFjjiXBvEd&WvOt3)%3Foc79D3z>7)p)U2&Th1ovE~oBtwxkt9SN5& z{D^KpmhoeGK9=QUy?tzxk56-(fA|;g%@yzlv3QRU$x3$eQII0&BbQ9MI%BU~I?FW& zJ>=3uu61m{`*Ur@Zn^FUVQ%lu{W+EKuH1Ue-5Pu3wtw!~xX;|S&b=2~=RSOkDJSrgycj>k1q4*GLJjVlb?#Tqa$6=MIO85v0I)23}zT3@s2$5=8-p#ym@xA zn|n`)^EpIU@Q4gE? zTd85*Ml`{$dF9J1S6;dD%9VE#Q<=dmbd&cQuYxdNY~qptIr8ZtUux3emhzQE*ZIE1 zP33b_`FvMCzt4QlX^H#EHxXUud%)`;%Bjxu^JYTxj+s+CJ%Zm;N}YG&fi`Q z3lyU`Zl^$Jrn8NkL0B*$xzTMw84Jo&P?myvD`=B~QLJST`|#d^hd9D9?(u}@ybQuZ zv3Q$!=%bKKh00^ELOLtd20awgL!o{Q#QO^k$8LpIav=x{C&q0S_O8NuEL;M66t;ii z*8GmG3y;Uvg{Lx?1uSMMF`VWywlD0xh5zJl++bmui^y8U_Z0aGIg3=}8>&)+@6cNj z-&>>sjqtriWGyn9vB*$Fh9WW)(OZ#OL@^I}itNUBe;Oa}`Lr_fe>#!%_)UB&Pf=Nl z>a3`@7fpgYD*6feD1hHf(IVKisGBPK13#kMqQCGfx+&Tg`HHUQ5IQJ&j*G}q^bYrV z$bUijS%eSB%ty%hncMly_k5;%e`7WLtQ5ZEv!QI^D1Y#XCqY=uZ>m@_++;B~S?mkS z@ipFCtQOx>7nzI6T5JF-kh9o2Hej=2TiJo$itXbdNBDBt}^GnMJgWHwQ3W)J((ZE@We z*KKj#7QYmPU&!=DdTjMYX}+R76{*b+c>fna(FnKnh4+4OmB&F?!n;Z&$0jARVEYnf z&}9ktSE4yB`HfC=r8_+t!Dzg-#8PxxLZ>BS&}E6e96;_8@|JiOge7Gy`95|lX}6Nu z`54`m^xY*3QiRWtw`5bA;TB5D;qR}8C3RO)cO`XKvJ2hlf&NNv;z|&fiiP)-au20i zF&r67$x}*}Qr=(c2Df+-gr(z=0GpP6hotDGwA(D5AN`j8lv3!Yw0=rgK)%w0nZpv6 zvkEy%Z)O`iIL>|CRB1Q$Wx$*Gt}orsmnlibyOhKmztroObMbj!?#69?d7j(+%j+O4 z6OsYCX8Z+^ZGWIHS6q(DM#Lbm) zb7k~a<}$kT_gBL*x4098U%kzTl*LwG4P!ND(QR27%gR$$ma=*)Ym>5-s7EVW`X z?G0ZSr!HNYgzmm}mtX7c>ox4=3^x7x0)KEByM8TSMY$@n8RG=qqoX# zuCnebuS9p1*AdNW^!<(7`^KC6P1W!lZ}?^bd$}EiRbr#NDtfEp{Z%rM2b)%LTUEZ~ zE6QQlD)Lp4tBPDzKe)$39`PgyztzFFcKgvgQfgVa>DL4#HY*kd2(^qE=oC;PY#_(ORG5_G)=Y zt*>Z>JF6vgt@d<8Z?)W9E#3KhtYIzP`FpHkEm>;KL*KRB-gk+}gUsJ`Vj}A~h3>x7 z+joERC_i8( z?N-}vwe42>Vi11+Hif8#F28TbK!%{p@9qD63|l$JHSF;H9scGi&-o_^>%=7^I<2GA zIy$XWm`^E2aVpV-5sYRWx~MaS>A2B4QOsu%-cd*1I`Y<$x6UQ5;O6S+t&jDCmb!YYTLbT}>-}{*(S>gGpcj46Mcuh9 zU@>c0kB;l=r>=Z;Uk72mkPLi4X5^@shkV$sp3VHN)v#VOTF{C%_^x{Hr(Qn>GMLqP zav}!+2((%O7?5qdWX@El2o=S3y`mKo|96RBLUjF`SSYPJ)WhhGp^j5zLx~s3d`n9M{d&aQ=TQzutER;vL4PdzpCBF9he z>Zi#}#b!S(V=t#T%LOjset!Cszj?~@AZ%#EhThn)HFjw@g4xVv9XoNC4ej30TN^$L z{4XJN+DNC3blJ!qHu5`eBzGfu8-0eXjhfP&mi$Irbl0d8UFm`E^!Hc8Mlv^A!7AKb zqxI;nQ4Cwyjx3FKb3F(f$3o|g%i=Z~k3!##y}7ZsHA%(?WF{1=2jM@Y~6e8|V-AustUMIChdvrd23>CbIxM@Ks29)6z9L5^@7UHokS zpY8v%{eQm74Q}Hd&E)m>SHouVHcLZV+(R?HHIt*6ew$?@2QoD)kNa*m6niy0fj2Zy zhs~RRPX~0@d>DFbKAJh$w7Gj~9*td_$6(jy@->&Mxm^D4YS{b{Pk7EhLHLVqekn{9 zYV!j>BF8Uw|HWaOJobk}k$vb0={zFWGzU*Dw|GXL72x$NQ^y8BgczrNyi5Vm>;o3?UW ztum3BtYkyJR&uqHtCd`>^xI0mt@PWf0ezW;y;`~3RtGrDF?7(%ZmsOr%5JUh2H|hX zDNQ4E`CD(sF%ez-sCObCM6%E)7Cm|t<%mGbe1YwLx7qK_Xiq1)(gWZ1yZiZlG~<}SHoUQ&UfX5H=e7G1x7qGH8q<+3 zxVd)In8_TLpv!i;Z08Q!?cib%wtt&=Bt#eOli~B*r^3G{?bDGF?`UtY_LY&jeO0Pc z3%#}f0sXdjbL|@`kBLmd4R+d$9Xjpg5Jx%ANv`u>5O&sSXPtJ|Y3G!LyvuuJrxd^NE3MH*=MHqH z8$IcR+w1Hdo#pK;Z)bTsZ(tK!&|7CYI_tOdKHPL?nL6JK!Y=Xo7<+YTgEw@E!RB3F z1!33J=&oxn^wu>WrLk$(ntX>{yZ(S(yUN#9uC8)*m8+}U>^hopOh7kX&+<3_@;V5+ zy@4Fv^w7<1bxTSH3Zv_8WvM_Vd{?)+)Tbftr`vFJ-R&Arg0Q>K>z)FAcF&5+T&r+*yxw$lT+7GLZ$n z^~iyKd*mT6vh=7zE5=~29_NFwr_4P+#O6I4&>h|N9E;w1PGS)@?di69Ze=?=v1?EH zddk&PuAXxBe1U#@>bKYb_<-Wn!rk_2N^@GGgI?~bm)&~Vtye#maWx2g$3mCAGm?*j z=(2Y;n$V2i48ab)M=_bH%wQHP*pE(o>$JB{dtc)Qx4FwdLD(l5pHhr3&_$mzl;dkE z^DS<#k9YKuw~xGi-%32_S0LxH%X37`(?qV{c@6R-(Yv;@2!S|zn~O47;HCxe>EIzx53}zmIklo47wcrEC`3hBO$sR zV*4SV;deBo7WJ{i5H~cW6>a#P_Vi;qIvt|ZAvzthj%YUFH$3DJw}NnJ5|R@^7en78 zJ@4}&S;>xf43*d4U=4@LJM;(Y;pT?wZD><;H&k~+bvN`khOvZWJPE>KsnEkP*@x+N zn2f{Z879jxy$w5s_Yd>_VJ~^b>mVHdKi=dmbTK?LACZIn6hguC8#%QafA(Q=KR%rs^)o84UJzaShFpF||VZH>{vm=Cbq7`u&ePh+amm$|HC zC$=ARp8Nb0gkux(4q3@VJ_=&1u_Y-@8LHC~osQM%Se=gT#{dR1lqsy?5?8r_F2>&D zA&+>%bKKro?-(cVIC;m(J1!@=_yoO;D}?UG>293v#(ja?8P|mwZ0A-Gj@QF@*~ja4 zyo}@J886Fty^WuP_mB7f@q5|NK@M{izlrg>82^+P{2PQ5-Xab* zZPIjRp}R@Co3wyMEMY%)gK%n|_ic$={ zOp$MjTvOzlBG;5w=x2(4rgUH|>+u_$a-Ki9f*eyG@F$OgaO(d^jhmY4rl#f~7rtw% z`+{aWmH1z~NZ|W2DIV~4u1vzUWjXUI20t{HO8kZZ;n^gBbpGcNOA z5YEg%VRScBcQe02j+uIx>9%Ipq%qwY!f-}mvzfkYW)$;Tg!`F!ItXXQBO9OM^JdjX zpR-!hnPH4%Av&F<(^)#5rOR16*~320@^=u$rfu=Dd&0bDCrGISbg0?&e%XZ*#8lI0&O` z8ud1DiBCf88YN$pTv2jG$ra@`qx2i4->5SDL_emZyC~g7Ek%wfJw&;!sLdSW7Vb9c zIWMuTY2KITq?+q1#%Rnfz45-7frrAFWY@$h+zK0=?1 zKBF9Us7D8Mx=5#sbh=2Fi$*b)@yullceu}==wi`R{{Qp;#f>h0gSYUG#kt9g%!>2cZD*khUfmvyBFwq7<1TQ8f>3Rbg@X!dfId)R)N_bz+Me?hq14K9~?xva~5&+>1P zb9pVkr!Mtrh~Ad_-sLT5h41zESHtDgn1Kw-Wmqo5a@{Up%rfLzzKWy#6@)8vvZ4Ur z(Vf|BN5+*pTna!Nx3fIx= zN;y`#tCdfA9)zpjCOvL;RW3duKfY^KX}+R7`d{@s^U&+6bNIYfFVW{}yRS~e$K=6g zt980sr>k|kT9>PTqA^Wr&j_N~gxg=Oi`BdE`Ku3bm}8v8JJz`UHE$vFnz+O#5qevb z9Nn$a-I{lK54X3bCY_neHf{&u+JxwKt&D5sSu4w0y{)y$+MbMJHc@!*+6DMMtX;xx zj&Ph)T;eJ>(8oIY)@8w7>&jArO31OUHg%|r&DQl}G~<}a6nxh@_p@#pD_PASLAc%< z*XwnC34GrA`nb*YHd)_`u}r|tt=~WlTiJ&$*Xz>XXARe1=AR&pexDD?iY}t<7VYz+ z^WiraU4+l@j%a&DH%I2^U-^x;=qp{4|RvWTWnKtNlgNz&G z*&xdXy=}0`hP(V5gc}o*81LPf48NI;5pq$8Pw{)$ScY=A%Z>WjDAUGa*lVNCHm*Yt z8}+bpKZo%CjVG|%rU38VRD}k3*Cst~>We)#*?-eo+~+1+Z@Pf3H(li(5BQ6}gD}Qj z#<;nd56H|%e1a}xbQ$9gW4_`?1~P=<=px2$F?NgbdySdKOy=MnG4jU98zXPb8P0JL zy~W58qu&@e7jp-hHpj*7Z7$C*jKCWUdeY`Uc#9q5Ez zx5&3et}SwHk!#Bmma~dA=w{2aAl&*6sYpXQtb}h?SCZ2=WWY_KDU*|X4@LlgdXU0n@+dsbek@>O=2q3S;`(B@r38- zV%vW~xZUS(kA)lE9uK#--8;6sv+bWE^Y+jAf>P*hds+0my&{#7WqV78vI2W;e-VT` zWZqE%oA2n(6m+*^C3@Sjj=k7)huhlm2bZ~uU3bX0Q?8wI?UZY0O7y!^zdO@XoI3oD zyWQEB0Srb5JKfVxyX~~w&en{^6r**x4gTfn8!l&wp)(f z`rYlfz1vOimTC7Xo(AEb)YxlJUA$q>d~CkwRuJxe3*GH~7rpIGPi}0ww)x{1 zb+3GT#!@Y9tb(?#;(UacjX73Iza+5pUM~=OE*z30Tz6!#93CM)5_vND?Metqw z%JDUoaXOMj4#Y#|1BrNtWa#Zch<*>eM>=FV@EPCJ9eW+vh0F(&VDp0& zX@>3&_CRk3`!Wuj9&}p=7qNt8*!7@%2jw~_*Fm`sUPHeJ^?UGM5FScQc1q!H4^^cG z-=PD4hc!H8w?lS2^c#~n$ipB!tjog*NzeP}@^Ep!r8+HXj~xzor5^(s%uuGV2Av+( z>0zB7KEx4@bCT=)7lcPL^AS1F#gR|QPa!^~7;f)~cN~%Th`dMSJ<^8X>44sj$ZbHMH9VFayB-U% z>oNI`$#qPwV{#pHo5#MUGF8ycv5_of6>Et`j$?K|=C+RQ<1Bv%;c;Cbf0Nk6#djS~ zMH2^+LrxL9g!v-#) z+fy>0lIN5xr}TEpCa0>=h<0?qdrx(t8$FoFETWjt3RbfYeVmf%)XN||ZLiZhJN*HA zIIV}%1t^U7pZ*-Xop%4Hz4!Dc+~#TTI<3dkkAm=wJ(Ztmh8u(3|9mQH~b@sm?Jg0|qvY*rKIT_E%b553XdONoP??31L=Pq%D zYuvzZ=G>hiJg(hze^kX1$oFBt@YA%6woh17WC1-)MAg3r4!h3PCOhNHO43vTYhGydUK5MGRpE-&ixqC32p zhJ4ha9u3gN#iscDi!J$$wzS7PF52tjTx7nuki{%RZx>gi--~YU;zne-cpkU+M>>l0 z6Egp?goE4yu0l0x@*TbK#>=O;#gibsqR%V( zyrRo1S^1P=xVbAjy`s}AI=!OHE3I&cSANI6U75;m_MwX_M>vkpzv4!(T;LMkam6iM zO-xc`zM7H{y8 zR(u#y1S{no4UI>9KVU12ly)p zZzZDudblO~E#2Od@s>QdWVxlcTTk%*+unaW74PyM>BzwQ=;C%M%21APsg90s>*uz7 zwAL1a@;=5QEYeHX1D(h!aH$EKw^^OyY9H3JDJGBN4Wnx-grl^ch=zZ?wrDH z-nq;3AiNu&M7X)Tx%hya-`H&Lm?tV@5cE1iS=!Q-2 z_o5H|u4?jbn55M6DTG56f==7mZAL{g>E+5Wi z0slwAeTMH`|7`&O+I!FMW$(TD*?W)dy;oTgl4K^U>@EC_kg~EOq=f7(l5CNL?7i;S z{owWV`kkNid|w`P99?VJ&S~BRY41fNCc3y6AD@3ODQ@&$YC^o@UUh0A^Syf1rxAL) z*Bt%cYlEAE5a_b0Iu-QE8Mz1`o#@7VPIO>S|AyV&)Cd=KP$ zAlC!A9=Od1`hB3^2YGpio{VBDGnma>bnw7EJ+RvYyFFOXpF!G(2`PXsAJ(NkozUgO z5lm+m-|+)>c=!{0Ilv)~aGuBL^pQ><>GV+|l8~H~WTPDK(w$!D;!!^a@G*lKhTD7O z9gpOFB<~}6A8lk4ThQAhIUecv(JtKdBbgrk6{LL}ot)U~@%wng63;u#;#AAW7jA0J(25)Tub9Q7BP~VH_0!5!qbB~=(-yR*9q#Ap=ji(BId0?go+U(|&oX1PXO*Z*TXgzNr_Xfy zOqb6F@(Dv2&r%L^jFaf%*&q1)XBTm!&#vM2o_WV}clJCrGCz-yo=oWNd3N;sJP-Mh z<#`=?FbR7-{|%X6WWeSx+As*+y_k&NUd&(_Hhtl?UToz@e!{LV)B(#r?dz8>D@e zg(@_`=e_z6eZCsUOuk_yyV2<@oxalPD_y?2z-6v-KS=vJKE;TlG`e_Q5ug9MI&SoJ zUFzcnO~1&6l2lb>j~)hweR+8H~m_c*XudXqaf`Yd%Y=x%x^|x^EbP=gznxv zMsIIk1Zm$Uz@~3Al9{Yz$F6VXdn?ylx!%h4)@{Dk?_2%8?Z9U&VhelN&moSYgSYPK zt=-<*?d{(|7$l)Go%xVYnZazn;d}ORkiWRiT^{g~H$fOJAUes&OEID-O%*x9H@17wcfgl6b1b{ljTy92t5-4$74k3!$E_wr8=#z~0G zahmfHGg*)B;^-~TK@M|)|FCJC2Rz~l&w?4&}I z&S4%4Sd0$h+AXf#;@U0l7Ti<36ck67@f!0k-O*({`^THh|JcOO*dgAp9N{=8ImKVR z3c~n0jjz-AI*p%_)P$rXFI9P;59p6B;tyg7ZZ!T#Ml%lYh%aw^dE?6)e;eCzbMf^S zUyk_tjemec$mF+K!vygtfV~oYh&Lqo37aQ)8H5SbqPv6z(Obe|RKunTThI!-CTxdY z6UvuRu7q+Wlq;dzOgMwte2H!n{=t1-@Hz++1;~*|4~g7XqNHS^6uM4Si@Mau-%8Y; zPISfnB$|S*6J6zD5GM9{iBq7@#JR9p;+oW<3p!1#)5JPWtjom1_>|9>#!7zUcg~`V z#Fy~-iLc{E6W_w^CH9Ua?kq_LWKNQWY~)05N%EoJB!wx8EJ+&Cmzmfr$)7=(ROY1F zv3b(Yj6iouXQ8*G^H_yVle(>>zp#s6v1?NKlFF4-uB37$eTsgQ>Nn}zAWW8(inPSt zChJZw`k;ek?kSnwlG!cUSk`hS2$M%gm&r3zj3{)OyeZx2$tWgbhvd_l&q5Zng!LRm zr^$7iT&Kyea*Z3@`AQ^=HJ3uky4gemQnvNGO~asoC_d4RvsUCLMJEmbsO@!G;|rFvgTox-B&X3qD)*GiZmH~+>P`@*PE9R(Fqm=JKJ@~= z<42Bif`56)6P^cQ8e64_NgU#lmLljhjZV|(G)-;lQlEx&U=UxijBn6Inl-FrBb(WZ z+e_meY2-~KZyI^i+~q!x&|8}S&!OKmZ-OvwfJ|vKQGw3bEA6*>A1!$`#5L$`$TmKZiKNy&#MvA}8+FZ?1-s(v(975%(0a zTf}Y=w;UP9T8?vt|AH``?bGQqT`ICtf>Jc1HSOq#tEz(>JFjZO~hKInwJlz3+DVZpf5= zEMIc~du2$1H)Lpq%`?p5dvurKAbQJijLX?(qS5~>Q&OpCe_3JlU!>n64$0Kx?O?TO1AV;<&xUFm{ z$VypiQJ4DIEStZTtrK18hWp7jonN`mlOW9Q^RlN#pV{+Lk~+M@d+0Q~PP6MYyDqbT z$|%M#lQsO#S{s#m+5f?fX8(`-ct?&5WJcy3*~v*B^p>L#y33)v98r{_83Xu| zZCnh(oH5CbZga|*Q=Xi%{-kWnT`#H#8+~zJ1c*&a}%oPoN+8q$R3w8A^`$eTyr zJo4t5$YiFWw>)#uT^`-#(OsU!_)g?GAB1@WY?ZeLddMq#Uft%EF|Ry%WyzRZsa0)%-(?h-+{EPSJyNBKK zr^9>m_rWgty(_;y^XoIeP4e46|8Ka@{I<^j3|srX)v!Pu;**fXxXS`=u0TbqP@Ved zvVblNxWfWn8OCx}uo_(y*nr&%Y~e?KW+&cJK;8oK7Ld2VBcAXay%mt7pneOwxq`8f zsbF^8UcqjB!5X}w;L{*1l$sJWMt6m}qqjo68O{`JT4)Bdn1fvl$yZ3OLUI+7tI$D? zaGaAo4#L98$ww*5QUSMBSO9aFiQCSTrdq&_&UZ^kgC{IdFSLy`yMB z|f@p9<1_)uoCkgr&V9L4oe+;+uvU3@p^ zxyfzr@&JFUM0DIwiMY7w62;JUiLuPV=au*YeU>=HAKc=}+=A~kj4c(P0jowOCpaC{5<+e(7gpH!e6`!!qU1ct-I0*kfU@O+*avy&bz-|@oRJU_nv&Fnq$4j?(P>qkR@G_MHngK7zQ5t9l1?SN$XOR(&uNuxWL- zRedpbt-cJqR+q23T-D{OE?4z4{K*9_p_>|+C`DzeQ4=|8=%I$&s?mb?7=f;9Okp~+ z@V9Dw&9|(={nYq92y5!PW**Am^J=z6pEdhnvzn8c#!7TrQ>Qg`T2q%be`OyB_=EdF zSSvyXGNX%HIq~_m^5aHp6~*n<@{U^WtX5ZKuGO8M^hR&B`lH`kAM**a)cTSiIETGz zXF=xLy|8)h73@WKwa=rs+E;iGgmr9M$8FV#Lp%~-*E;gmk*kheexEh0Qvvvf(V;VZ(W> zU>CRekNfDN;Zy$q^WA8p0JqmDHr~<5oi!?f%#BJ@7B|;OZ;h&=-$u2lgDj1D@HuX; zk-Zu{2*SoPH!g?G8xLj zSF(}KY~@D|V)v$ha~JPz`j|IC*en_`k-3?y&1}|8PQS+*HnY9oV-1^i;XU-$%-?P1 z?wa-IBV=v%6-)UV8Jfw^OmEHB;+~s*k37w`a2k6y*LQQBG;fc4Xs+w#`;f7P4qK!o zBt01^L?xn;>kZ&sKJCm5HL1z-Fy<+DfObblOUn zt-8~T-V9|HKeLlx(M2n}wetC`+(N70_?@$ON9$O`MdsECNlY^I*4n+b)?I7ewa!Rp z%F~ulS;Ag!2Vt9}=(dfFZRBYqOB=nlu}Pb;%;8&B;=OIYV;vhf#3|13Cx7ubH_=C1 zncC*VUTt;OwkdjOtB1DT=!y5Y?Tg*oy5qLq+x9=+24OqzYNy9`S+Peu`?qUCb8Ovi z5VmeNoNmY2OlRV@{7wzrV-fr!E=h~O00+sQO z_VTuux4pdW2QZLN&|CWv=&rr)+Uu_U=lD*v|CN7&u!F5S6hsdlWbdHc4l;I-r-LjV z^w!}v-rvFdJ0>MLDM^j*Ovebi=va=5_&#*3OMP_QQ9m7J>NtbdY-Kxo=%|N|$2f`i zcl-mpb&7%ac504YI(b(oeRk4kC!2J#f2SXDpPg*o=`yzNWb00Mxz8h>1Yu`)+1btc z4c4%8UJ4L}E<5Y8vpeiuk9V2OG-jfU&hxNa=fx~#IV}M~hLvn&Gdk|7pRV$CeHn!BrX&NI$%Y*7x~q4KV7qs1_HK3B(~CazV*u{w-O-Fg z|L;y@6W;h3qjaD8o6+%-FqTq zcX_(Y(%mNA-DdZlxXbQ;@i+GDejE4I{eBSkh))Vqqk|q<$w6-NqK6(nyT>S|;{JQs zyvJPptsW~_&05yuj(R4f02Pp}r#*Uh!oBnyfgXG6vFCTl+H)H}v6llJ;t1z?%$p$W z<*mJ9l87WEM~{A+HSA@tUhmSKUf8{t-Fw-+*T=ZIUc+#2y}YBByuIY@C2udc*2^9A z+Jatt{md`yW)J)DU3fnRx_-Ylz0t$_vcLa3GWM3Iw=BK&);k~G-`o3pH=q$sXhsX{ z*;^OAhcKLxjAs%$?yaBR^7TH+Egtcd7eUxZjy|z*Q+;gL$7X$sQW5vx$1U}#g}>FO zCGMtAdphz3-q=U4eeU4%K1f7TvQUu9RHGg5(S!H-2wi@l%MXS!fn^-Q-GA^Ky7=HM zKL3MDT;)3d;2nMK)i(_?_f1CzGNZS?InZxkH`g~mvh=Ns+v_`-b(})xeiT=045)<9A5a4~I-nj6@QwjP7>>*XK4UcF(A$8C z=y$+0-1Goh25jI2kAv_ddwo5StFnL>97<1G^5C zZ=hTQ$MgI@AF2tSEXns$s}DF?U{goAZE zSjNHf43=fE-Ui!ba2EzJhH-fB;0a7(3g5Dx@A-jW*v($_F<7P{ak1ABoee319){>) zNHuEW{X^ctZbJs)y+aP+HivlE5Iqig8-zpcG1UG;3sVeR4{e66hqj?B@6m%^493k3 z{U3{1!YXt*RF^~D;n1D@8HB@P5Sw`DVwl~A*=<-V(vpshc*ih#hsirk-eHYsLUZ&s zOpamt9p>hSbw;LPBXN6vdo>*PcMuMbk2ef&%7;v6ExH@-E{E%F_(9Hb8=DTl#{(W= z*AeoKkZXioBjg&9i@X$|5RLhO&+(n}o2%i7`M9kSIvDXCb{k>05$XPIvuIgkvbijoRp*?BsZ1mNpJe1 zi;)BQgrSV!Gu+-t?-(iXNO?!fJ8}!#_zAs@+>P!=>Taa&MjpoPd={7d)Tcjs_)PZC zbo-f%qvRPS%P75#DvbA!^8QgxX--R8(-z-}QMwrQDWe$66sDu&QTiDr)2K7t<8=^@ z4$#ABJ&aC4YP^4Rdh9mZ{g3wE(etp&Xzv=W&(TM*$!PnJej9{iqGRhZ*|GH)TaPJ5 z6s0IbZR+CY#^`j6PRHnUj4sCv#~qH5dyKqe{H-ykkaf(TT;MW)@i)2~<8P0-%Yz^s z>u-;hcWh>|BF9)c#>z2Pzheth1ewN`pfUZ>%h(^#_qb@}pc-A!L%wlxjgxDfT;rbck~cy4c|bNQ(Texz!Tb0ge6EAf-P7mp>2vq=`8d{b zH3+|mf!q8d3&kl(Et=7tUW{fEQ<=g4Sjbl_WdnBmLZ@Ho^b4JS@fX+mhktn!jWIyh(rIHvJZBI5{S1 zh~VZXm!l$8sEaNq>vFO?oZN}QEM++>(8c7n`25M6@V%S-BR}IElkGM64l+-^&qJP| zx5+Qj?-VyTB|5T9$%5PS`>WxUv8+VqDUX71Y6^^AF05YG1A*=2B>v%PD!9%uK#9<%K~dl5^p_3U4<_3VTE z#_#;WpWF<>Ic{!F0uqyq2)dl3%Q^0FPGM@(pN|-XF6P*6j@{;rW*p<0gm=u5caFSs ziyV!%?=EyNezjNH&oD;}2=Uxzg>Gr-XMl(La8@}Al)gYW3jg07SuDhJ8x4EUM zLmO;5w*#H%f?emzH&?E?a?O=%?ri4rKNg~!xfgjFg!2Mo5F0t>*?nG0Qsb89RY2GC z>f@&7xv6>n);!oc>3p5e*Xev+ z&L72CK4%W=ILmo1p^N#~@%i&_;YR1*$L-Dcj{mu{|7Anw|K%bN`O(||+}!_k_dnhJ zuQX+GJOBHb`TWF{AY2fKeCT$8j0@yhAj<;1EwIUguh_tD_Taq>4seJg{LNh+@R&D2 zxG)+q(Z@ph7S_OC3%k<`x4Te|g@YN&aBQ}4Ilco6eFqk9Wjp@XLie-q7$-T!>mXd@ zjf?cUs1rVK(Ma6pBAYB)!X~!h<`%jAMHjftO?0_Pmy6utqPIb~I4zZ_Moo0F*lvq` z{^BMyrxk7Sj>Yy`JOP;(PhlD}(c9vA=x(v@7JtQ3d?yxP3c{~qV5_fc^8qu^?N>5> zCC^u~EYaH%n=FY(gnSghdzTc!cVeGVO_&zLoj~=+oCHhz*(~|G7*AksAIfEXS z=wZpf+`;>oJj8BGGvd8V`|%mxwN#Hwzs4R*?Z5PQ+~-nTFMWxvmqjB!2}wdS+~qPi zx2y`)sYN4nxlEVK+~Klre98(|vldjF8i6C{EBxhlXscC%j8}5l;^xc zZ(qytwSK>Lb6>|rrmu71_P*}PMAqRAU%v>#vH*)%e7pt<#H`Q!f}4%G|z(Yn^Y9UckY`CRK{(6ql0gnVz+PX_Kkb`W(+^@2RC^V zgx}i!TYY|;fxMKb60PXWyZA1BYpZWRWFUhW$6|E)txmty>9;hJJ@NT#Pl2 z3c{6X(ZfpFSL$}9j4S0?Da%T|t^6JDU+MiTU+{`ILAWX)I=&ODbg?QYdB{%*N}=Ob z`dKB@s$tA#Da+BrDm|>)%67be)h_I|%KfkQ-qn?`%WCghtK&*XVMMJ6sb*0|qgK;pk$`XzaFTJd>Ep47_8F zyldoLBk!8M?B@`ATO-FB{jPCyYtA6knkPZ{o!k4aG;J7xH+*-1e}Zsr9I~UkwPn!T z+KM!!6EO4G!j0aru^5f%$7FQ3QEwZ)f8z?aVbhInYvVCa@EdmBDBni8Hp;b8uJ25!3;wO-`nkbyM1rB?`QEd_kwU!GTi2-LR3MYn{>IU3j_It>C9&# zU$K%ktYtmFup8flO*-AA(@i?vq{~h2aFZQ3y$r(5Zenvb>d^pQY;HzN+Rz@ix4A3c zvAHMmZl2AT%)`xX*4t(`w^?_am!rGQtB`5)LG=AYBE0E`CV0aS3)s#%o(16+-EGm^ z7VqDZg6!CIi`&{#nzEF~u3O~WBG(qVw#c=mFCU_xErXcP7EW-HD_r9SI@n^jEq2>t zw=HjjaI0J1+L|G_&8>4;jXt;Pa_bQ;^B1pza9b?ml7N(?CL|qssftdw>2#Y;x3!@i z?r>XY`Z1o3Y-TIE*tUaRxY2F?zVq~-nI{B0yf?5wzeGyZDuT9N-V`2jPwg8OV$-cH|@v`6)zE+};lF z*dgx@d3VUWqdPt6jox<1u|vN*e7ARef=oNU&^t&b*Fqg<=QFNPPukgpfc5{fo^t=Wf9-9itmtPr`>nDt(`yP zj(7fzu6I7+Ij@3nm%p_uAxTJ%``J|d=c6EnsYpvkGMaJdV)rC`{_YvL(cN=#dw!EO-0jYGA42Bc$2h?$^tSsf`rUnz z%gD0(Z4myNkt*2h*Uypp*OSvxei`3BtXxakqO@6OtYs>~&9j?Y7r$dyCVKDXc@6dyjI3Yv^)cbW)L) zB9y@n`zleJy40s39q5dk+o#igI^Cz!eY)H?3wOA09xK?zE&f9n`yTO>7rYMq@1wZA z{ob)Z9`f!lK}kwe7QOASOf_`3U!MK)?0*OS?f(Lu?6=i^_jN!I2V_6c78wu7b3m2@ z-?5&J{K{!;df+TJJ#c|bJPX2u(TIuf!@;EJ_@Ist>gS+L2V2sQ;fzEN2la4pCUfxq zg9~s^2i?;_?>&?byBzYaL-lAtM|$%qqpShwXLvUAohYKFEJ~03S1$r7XwaKD?6EtYrgo9G2s-9EasN z{1bojJP40updwwc#SvQ^In1pfJQ|k}-;bkN$VPFhQqhtA;RqW>qZtCcL9`Q5?kLlo;y^h5v5lJY88#y)s-5zrX$F{Qr-=SkRKX#9Y zL3lhNsj%^JTOH3%PV$hCGBiP_$8~yKr^kC?zvF%J-97FWj?ZH^dpUqEjvwPBZtnOW zoZ}+iaYEh`@}7|QL^4v~)=uc{M0#|0LU$*0cOnN>=)@Sl;ShQ_Df>y?o|N&VJSSy2 zskf6~;Qc4P|Ku9hvYw4>;s!*B2N0p9=H zN7(JR#dxpZTMbXy<&<}w(&wpM*yNP`Pqm~CwmvlsTc5J^sfkQx8Z%gen>+O@`#8vN z=<<{Dxj0dt!>>4Zja%KHE5h?tZ_6-hO`&glA%q5}Te$ON8{;^^AOH zaFj-U92-MFnYIymz?b~|IYGw$gR_y0#}TGNX`*!~ZF{;`PF z>|ht?xW*0s#a4ej;TbQ2@N7J?qSLcFJ*(5RWhh5QD$|f2OlKBfqKmT&`HE$H!%E!V zS?@S2?^$`z%6s-QSGkVf&fY?IXLWa0cV{03;h%2j&%!iiAoI|}pR%9R?Kv6G$#YJY zb9y`167N6f{pW@8K%^IGcz$7-~jTiKKA%f4lPzJYop+0TsLqFWy1-E}; zHgj2mE-&cvf;+shg%iBsbr4<*(8a~r`233rNkVc`;T;$4b+H;UU#vwP-a&5{o1nXk zy1Uq#wtT{uY{yoYqLZ6?==PF~m*lx5%O$;CvdN`gxXVk|_#5xN^e?yhF9Y>G6gv&9xTbJF><$FBjaS&d~h&Nu* z>y^*&c~_S3H8#28`*h`Z+~pNFcjYB-g79iI;-kx}y1eQRuV$t+oq3n;=;Er~uKN6| z1NfN148uFF+Ux3SWWKtN4QxVhSGS?xt2@|HTK`n~RNU2je+-17C&==ZvPuDgTlw)i_P2}qC3f0v^oE$Kv8?EiOP z`lHXk2Qr3**!=H<9N{>>@jJHr`#hJp%Jm?;p`#l%yODxaq#;5E?06$9Indt?S#J1V z+;|tg+|b93W61nZNGVz%&p)#KGoDG<<)6i@XCs^Vfvx<=DK22sfBxb&cX4O`JPN{_ z^4%t;{hX9zR-ie-GmO8l*x+xUrJ*u||N{MQ@*t$;iD*XRBF z0s8!R6jNEsa(1wvL)hQ%u!jHY@?Ty4dyzXqcq=xAC`t)*ajPso|5jzHQIk4&$1Qu^ z`UIJ84PykKp|@L~qq|$WyETPre8&;)2jOj7-7ZNxMxxu>GTxTwwk)^xcH1Vmp9bL_ zw{#~Y9o~B<6IsYcIjU2Ox-_K)tzBBhHu#7dV!}sC-c6Q({@9X2f zd=Fw`uLn8FLw@9VP?9o~!)6b<(vJar%wYVj2kz&=B&IT*AMwVAdVQD)pZBmLRj|p! zj(mu_eCXyLe#v|m@(sFtsLO}$(C@N_4}a%v5I%}dEOhb6ZjXHaBj49YDM>>F?|5Xd zN41gp(K|GtF?xH{65T!0-J=e4VmJ%fiLD;Tp#Y80?PD1q%kx;4$9j8glgIn`gPYvK zdmrD$cjocKAbgULRHViC;YoIK;Vz%(Z=efjH z{H-VM=gDK9@gfMHX2Tnw>h20a=no2#RT;GLce~SHGHv| z-?)wM+>2Md4Z@ev(ZS2)*zKj=UPh?ON6bc-FTZCW2hrure|X88AbjNpUuDJ)uY8wY z6{0A`iK05~(djFlzS8Ndfec~@!Ps`j!oZez;w2hqPNf3#imU74(eJo$|D_3~HQ(o{Yh{Q-l zMlzF??Bpaj^2LxVhFme^iqVR;bf6QX`HF4q;~+;kjt*j6<}d!{pCA%58CB_uE@OVi zEWSjSF*kF7!(8V->=5%2uY*Xefat^|1^LlwES<*EX{>70pf+`B&4>JtMJz!VvA$&$ z-?5(W`2p{UC2uTwW62xqUv6_3y~UCvmVRSB=Or@5j!>F**emu@ydn0TAQH#saq>|M z-Nk8--r{s&05**?jxVrloJrUz#vv~i1XaU_Ho|^k$6eTKw*kek7l%_4YrEcjUM!3FvDMDsfo;f~_-EW)V!b7HbBPb2yTnI1&Pnu_Br!TkVyh&BSjaA} z1d*gNCY2|tEJTHxrZqNA>b*&AnzS=r8OB(?U?TQQ`X%$xM^gEcUf>CDgGjRI z#6pf_Nl8H}vQr-4fn;tfSwouOZzb!(d-R|eHcaM?$@H4+SrAF?^OC2<4J5Zo^3v49 z?#a8;j{$tlr|2@dE|ZUAHf#BVb6i9h$?cZh=O_P{JKWG%;IS;+1T*NwdV$+m+*vA3vno_=$a;20j zrCcdrq2E;cO%;vysglL#L^Anp&r+b(#7mxA~9PK_pFTDpG~&=ps#Be14in zxY0B%XpMKI8Os;QoMsYJn2z4k%t60t{)d}RBTJf}I3GmP2G}cY4P;I`6`Q9$$}Myk zMni95Y|>!UFfaKjNMY<6$`{HN$`#7xw^<{henb6+z4)9}{EF^E-G#p)hyMr|3Efus z7Y~9+BmwR=l8%hnEaGoPicp-AxSvR8X0nOB_`Jy9=ri&nh@^`{gbYNX({wsbr_*%0 zOxKVmG@~oSSk4MoqlIs_a=y>*Khh5xast= zq|Z)Ox?!*MYmhnp(;$+;=6-KAlA$rW%g`OYW$4XtY?@&jGnmC3?3zKo402_VD}!7a z+-3&-X3%ejliUp=8IzL_-DT8W#xlr}u?B7{V;x%2A9tJaGsa-EjQ&=}FPYCm+)u^> zybL0l(o+DRm+2k!nW+~O|qQkZ=UiT@6Ga>w?QOpG$LdpCwVAJ2}+@ltTJUCjJ>kzEbCJAkW~*^H?tM* z&$rxlqIL$a+byWb9#Ty4s@am@8Ua?vj@7! zIf2ReKIELo0(6{HKRIQ}d6kzzBv)J#pod&~$d!>Scz>>3*ezFMyf@d^*d>>D<XMp4FzYjiBsGUB87BUC=Plnl#mP*#HNLcQk*F4 zT1dV^aut%RkX(g&@ID{VkD09JAZPfK3%IR9Iw*7xyA`rqA@@``qzVHV!*pz4Sf7Qr zvX`@*=P_@BNRep7#8yR;l7dvY%Od5eL2bOZNHbc}2APYMr16e z!(zQ~o5kE_v5y#wyDBypn-*JuO^bbne8uD{CRZ`Jik;*%fAA--gGliR#i&G8YM_VW z&1pqj+;QY%Cq(owpk(EN&rG)z|(VlMfq&EW@#1Mut5u26JX$hT{&}oUE z*ugG-F3AJ#1cb89UKkNw-;2Zza!j2b-1(h>l(T7Hg!GT}#PVO0H6J zm6EGeY06QN%5-HU^Z169tYIBGDCM3?*{zh_O6})<5GkFFYBZxWwlA&E(qAx}6|80t zM>)YMY*qRaSGmT+AW|kFIxVBqGCD1jot)$$A7yC5P)6_>x+wEG6PV02X5#kBct;s| z%g9?s-ZBR{%rW#<<}|u1qq{P?D{~RIQ#L{cIx-qPl$E`#Zp+D7PM&hIl+#!ExOa^wBw3u3qO z?!UbEmS2rs%6nINeU`tBP0HK9LNZcf>k3iWx`M4MRHr6&s7D*zT!mqL$|xqH%L=-z z;0`M+;YY4;h70aW$in^<)yNWgF z!e=bURuyjtkxF`~Bzq;@R+6!jJe6drq_;{d@%~EQU+E~vIms!0=MQvI=>@NYNacWd zBt*x4mo-vZrpk@z$;S*v50&*$c@k6c{>rnlTjia2ZZUPvWhON*s*FNa?*gt=%Q*%>{hiso#;w8 zyrXJwSMWtC4EnRINGQP;D_gxX8;OQeAh| z^;X^ctEVOxrLbxBa#WxacC9X7b-Aj`Rb8&?A2JaAR3CyqtN+L;E^wK@kfZutY*$^^ zHKLOa-+>x#s)n1YQ3QXhMrGVjjhfV^Kf125hu`seHJ+f)n(;|PUJ6hHoz~Q8O`X=% zWzCMb!3Zg6L?2WcUCJv=2|g{jhm~bw_0wlmhNil zu2yQ&Qi7%oVje$pEr`^Pi*9SnSX-XjveedFZJX2{&J-521n;fAoNrmlZVq#dlbqus zSI|ct`RZiDUUjNdi@L~Brv@sNu1)HWU^>1Nb=_RuAK1oE>_wM#by?RP);-VTAW|e;QH&#zaQ zVnk6I@2F?5dfkz^-uv{SA9|}d5dGF0!Z2j zv|#}XQIz6Tr7dIloC)Zn;WTD4hj}c(?KSj{hVnL)x1qcZf8#WNptpu{G}LdytGMZg zGBt`pR%&3cMicRdM!#e8#wjU+?i%|}H`ZI@dbGo)jr-CcyEYz(T^q~SSgyu$HI}Qf z+ibj=wX8=sjqeAMCh!o#R^xb+C-{8%yy{%1j+-94!q$2|bv1yyiRHZt0 zZBrZh+Q`*Lt~PSD8O$&~ulB#<4IL6=^A7ds zf$lntKyMvJGYgw`a8DgpV%HAeVb>1wb&#urTpi@HT)3?iMglZ(9QqH|%25k+ar;r2RvM`w9E%iCGr&ixs{$LOuI9G&&s+4r#X zC}irqgq>UuB3gu7c+p2pIcU<=$bX_kXDlzc4 z>U~6VKF0mjD}k=-O=bx`uig>#S??+~tM@L5)Q>`lPV4KmzE11wvVJb|kdKnoW(dO> zg)Zt(z~|SWh8wLv2e((>JL!#HtWgzw2O9YfG-^U~{H;drr%^BZ(w`N0V`IHG{t%znI0tUCu}vCR zqydd_bB*18;}MKz3c75p%f{}o@hT4Ulz(}JE*jgdiO+8momj->1H7Y&y_$TD%uNbY zl;Y^ENojP~M0ZUp@DsihO-8W}TQ&JFh%`+_F?8Eh#-{Q#m8GfPn%bo47LIa-t9WnI z8~DyN{X2*>3y978_&zjCMu@v?rjKUwHTxBNHS0}31|mnZF^p#-Hfy$%W1Qp+=kd3i zxu0ftxX;5N(mW~N*j%s8yWsPhPhmPXX}*;cxXb2luK6=w@H&XJh>9*-=(2@7Y>}Mo zROc6Jp^FxFYvJ=-_`bGiNgLYZ9WCtDVjeQLSi};Rqqi1o&~J;4Y(|zAmv|XOT7FDH zY9n*Yr5xdI5NQTj{se02XtA zKk=Pw^$$<^H;A;>LF*XUt+m}+e?V>;F&JI8UdR@USFlNdX+@m*?@ zhR;Y(2J%uKowm_w8=bakOjBCWik?hjH~TnZ@9fS-qBXxw(_=>w`~Fv zkp#W94bfd&-L=(S+q4wsSNbxa!|0)%?Co^hPR4ffw3Ef}tVY@m#QWQMf4iluU^Vt^ zXU}%_Yu>zq9(PehkiTD)Oi6rImSu! z&{+?iZ*U9m?|dJ-b#cR8ythkZy5L=1?B8WN_U~ecE+;sRt-Czq1+Rlh*Qi7%7I8>U zcJfmY_t*7%blFvxUG3KOS2{5pdv#riF1jwqZe7>1fz52gJG#o-Ro<@hcKwGZJV$R` z|38O*yS@t|-QGi{ZlCfEb?C<;yrJ9EAksY%*(i(dy4OW--5b%FAq-~}W0}AtRurzTdh30bzxWq>_I`~$d%q1LeFEg`BUc}}`pDJCc71Y^o4ou?Cq^@a+04UT_0d6} zjo7WvcHB~*J3*vxNCC=Fjb`YxZ!d;3i@9uLKZiJqt@>WzH-6_{5a|~Uo%YjdKb`jb zm`_MW8nRQ0wsfE~y6D%FKJ;f0Lm7d0^pm%ry#3_ux0}5jKyUrz=%?R)r#OR5{hkDo z{t3y2z4~{-8~X3V<^!VgDY_f*6?z+xpVHWLfZG~S3%d@ehg}EAH$bidat)Acz(l4n zotfyyZ?8rMyb2-%qY#}~$T86F1KrlZWVqvjh0yiDa#Wxa{?@?yG@>c)XW#^MJ@797 z1(88MZ%~Ln2W7!#gMOeqP0;Beoet9JAYBgX$3O-%iPc=@53Zq$L4V`(2R*=z4tk2) z8{{2>-Pz#Jka_SIWaLZqHrUM#*4<#;4bIQkxSheBn8prn1d$=J$&7A?$T&ovA+ik7 z+Yp-!nZsK4aRBcfa)e`?;5LtW#)}{_G$1N5(1+h+jri@=$WVI?ZA>%V?oc^~cA+~x zvDwgt_zn#99T>WW?f6?m-OtcdoaH?4g2*s$9H!S{b?|w^`rtN)*<{#UHn15tH_Yu1 zyUKO$q03>q9Oe#(zej|k6sIJ*7;ZPeyBZn(6IH0rFL=jrdkr6k%)>`9hVkfa_!RUz zd?vGzW%w@s3?d_y^_>S5$xxUG@@29Z(m@$bN>l(?x;HXG${jq?2* zm52PepHcOh$R-Zs^G4l8pQGLekHsi zv42Soy}vHCC>%a*cJHWA!^$zhlqyDu|5xh%EU2 zkNbuq6hjB&+|xL_jkDXh8uVu)m(b<77eQov9O9wN@fj&dVXEQY$J=3iBU;mz4s>E5 zv(V{yosQS(_)TnKJ3BeS?I1ECA&E(fE+(YlQ__%*FK~MkykmmA6XcyB?}VDvqAq%y z&=}oK(A@;xO=!bNR&a*rL1bcb^e|EOiMpLA<3xET$}&-J6EEQX6TN@pfBcVkL1fZ< zL?t@9nDjXr$jn#dMaPr$<2P6%le#kj-?>Q((8DA>OxnygynoUj>^A9P5Si?~lM7>) z$=)?tpOf2Rlgaj?qZo^KOqqox=Ka%(QjvPtbXp^t&r+jP54x7+kAxTooZS;AHhq0j01oUY61_Mee}56MI>@{pfzDNadB zQH?g}bcRl6=yb*qhT#rpjAj;_xxp>&poRi$u&zZzsDMx9fx?tCp$mT5O+JfBVF)4n5~1^?rFB&X4`G{cy{nO zh|Ebu8nR;hIr^ManYwhKGh>*_3}$1iIm=neYIgA(I-R4_IXd-wtdTj-c)_b6GB*~f z_?|M9Ll<)^QI(&mNp0NTT<@4G?_7E3$~$)=lbMFz=E^ZwzjJ-J=Pp8~xd-_>h|G(N zz2^OhH_V%Y&F5X>-ykwyck|yzZ}St98k^2{Tk~^c*ZKLe>wNj<%QauF`EvO^*2w%; zw52_|nZKSBT;wu;AjfjLa1U;D;UV1KLho4U z&KCZM%nRQIkwxzj4ZSUjjeZw>Kmuf0l!dai#$JmyBJ<)X*nDvzYM{HtZP44|jts)4 zi`~}Z>C9v{c3mvrV!0N}wOFpj=g{wB{Vu)|M3w}k;49qilH!!4G&)$~o|f2ciQSge zWf(j76J0KO8$^~SBr&>Nnw?^NM=cs-hovp)L>Ic#lMyULr%QFZRHsXKvYUMz;5?6l z$g*UFe1a~PrR8%nkeRHwJ-@{oStjo?d6&t%tUe8Cg5H+Nu}r_qe7Bdm>18r48_zl} zVXx&W@rLD%u=(-@>_vCWe?xD}ukue2Sz*%^QHhRSSH#AyE96@t*9y5-$hE?4uK0!` zd`koRGL6M7V8rl%NXru>DGXt{loFma>9_oZ>7Ou+_@z z{Ken=8$?#cN2jZFx=N?3KIaQE@g-kVi5~Q(AG%mIgyD>0EE8~htGr{CysPA0CGVR z%UbVRtIxGJu*o|6uS-l)Y`rcowq9rJb>C5nGW@_VxVd#b=|g`;pv!f-T;~qg&0{-% zbC(C`V%<~hw(b>gco#(0N5MPR%e!9Q_42OIMQ-w;xAle4-Fn@v*WLP()TbYdu+{oU zL1cp-Hpsp~w;N>KAkPL_Ht21`GQ59-_is4GSuSAD4ffn%&kgq6@H&WWj7kh*qu-4_ zccXqcMv!Y`HSDypD?M;q8;3BAk&I>*cH6j(!yMxzXVCpd-EX|b9qt8@P5R$doCb8n z+cr(a{+n#RX%j~|fqUHa|NqT1ULf;knf)efWOFRykeuvP$7Y*rQ5T=TxiQUXiFa&n zPbX%hugwe4>*ggaXBBH%j~tt~;9Z-4<5dvZk^;A~r4ED8^%hyT$hcLWt+H(WgjA#< zC&jSk){>N>3_sA2RvDT*dNG+j z?B@`=*lxG&K7ac;E^?Va@Qxk!+7S<#cO>LPK0g^c*OWKTA9vBz$E?6&7?3Q?5ec*h=j_sF|P z-aVb@LU;7GM~*%E-Q(u=3`V9si*S2;?gx>*ACMhy*xQvUY~}*G+v_g(>TU0nAhIti ziLvRvWJLHFyY7>3pIrOo@_Ve2eLqm1pQwy(_Dx_Vo7l<@wzYWMNYrB8aXhHnap86dONU`6|CkmfAA;Qxrx7f;4Zp7@Q}wm<#`Y}m^3Kl(gk z_anYfM_SODA?WmoPLJsHh%WseYvjm67ULFa~`uF5$0zTv; zyyIvQiXrpSl9Zw>dOKPH{T{7CHDo#3iHW$mqxL!$1(}bP#^%QcvjE*4+lJnb?dA+N zJ$8%R+~q!YJucsIxsJJsfvi$7isd1Dxdo zzhSfE{?>8dz2pDz6!&xD6Uxzw-uS!|v(e{?_3Yt1mw19sPw4cdPEYFcVx;WV!pMSC~ZuDely5Sus7qJwXPp)J&>(JZDE$Hr~?oRGzFV}*|serT;r!ga0 zi*8TJcv_y*vYgi2X`7tRfLl6UnzDHB>GD*h5-sRR7rHZm!3;wmr{z0+0(+f)%rjmD zku!3fi9&Q@VzV<@D8M%qp&0(w8TWIh3e~BB`#vM z&eowmjcAQ7&+785J3Kp(SsdmVC(*@OyPfsd`Ld3(jMKNABx`2k771!u<7{?Y+?&`JulyRxz5XVUas>G z(eHWvp8q$9Tu9DW{DAM=g__i+9y++t4!d2j+l6k-=OV9y$VFXVOiBhaqsxn>_=Q@y z!HfPKx@d=szDpNJGnNTVVj;WG=|!Dh)ak`bT;>n{OlPl=% zH{a>s^!D4!AaXf2Hog2YpJ3O^sj=&2`7X+yAc5-{-NKeH`Q(cX_}+*y{KHcpF5n1jHv1 zZtjXsujurOPOs?lN-^BwmG7xaYo;(AU0j*V0v5B3mAJht-f?9U@?QCizq!Lb^mfI~ zU3rG?uE=vmo-6+gB7f-bkG$yQ4_o~)2R-~D`_=c6@v1ymWx4tbwWvc|`eDn9UM&c}$Q>TdM{?Oms>&PMjX81 zMn&2%nic5ohP%3z47=Wx@1|Tg<+>@?&Ckg|X0o80n=Kf~D8@1Y zId1CV<~$bQmTsOv*Eg@?rf#~aoBr0#=e*=U+|OU>(Dh%P7>v*RYccx#Ydbdk>kqE+ zI*8oT=`Ee!(&;T--bzeTl9QgoG^QCX(Z#Ly`21U4aih0-F(BHj^cLyjzuQQ(wd2EMYn&;cw3&^vfS3&ZJXTAPEjgS3GcmKji332 z4)mlC{Tab%#-WefGTpv_y>9F5PJkZn=;6+Xe1!Mk`53$1asPL`_s(S8<{j_4qsKeP zvBw?z-+32A?nc4Zchh3)yBWwqF7l9%lGLUN&1pqvba_{ocirLLku2gg=eUS2?%M6H z-R|DxZ|?E{@3<%LJ$diRd+$?H^BH=(ml56F)7?GY-OGvZ#J!e`#a8!z3nKURa9{TO zy1g&seR=N7a$j%vC*uA0z5o7JwzHGn_|Dwlk1p=t<{rKe_h0ZD9pBf_1Nk0&LltUK zmj=l3z+F9PhwUEN?7<9{vVzsD!{2(~ejXg;2*>z0h&=ShhkAWj4WIY0Gu;@@6qe&I zAG*1RXE@I#uA|F`x_sykAHEDCj}nrPuPKBs{O)SxkPge;FX;`Sc>7exL^L1AS6X9$Zq#4U99&l~ji_&pMl2Ae+qoG-|T zT_4N$Sgyx%J(lb7FX;ENejnFo5cAo=QBH80bLimlU)b%j-5x&(B2V1^lkaGRE}slw zGSkrIlPw(Q6mIazQ|$2MRSs z5P6=M9F#+M&-M1)`=2+VD>i*Tf>DfN9Cm#!-*dU1%k^BY=Lb20ex9G?X%P800blSH zc`3j*=-^+w{cE>>?e=eFda{}`+~jc(d7;l2`h20w7xsUVhx}Be2ES5=rnI0HZRpJu zboxT4FLe514eM}+FE(?C>p|pYTs|Nnx_FtC2yXP{r?|bB>F|!1^1hV!rMxezQXMz< zQg1Kic&Xo)4QY%_F9)%ZquA?JBD~?%&)EEx+j_MD-Mu=7-d>&N1~&EktC3ePvFoch z*!8u1ujP6z*K4_6XCXVe$W1jmFcNqBdM0!5J$S8y*Y4@H-Co=6^>+RaBL5{PAEl^* z?f+{|4~8;>*=%7i2RMwa{yWD-e&bFMc@qVlzR~F$oxX|iF)2w!R!Y*Ec63A+Z@SZq zz6@Y6ZtsnEypi{fyl>=vvy z<#{X1TfM!_gZIDn{gTO|Z?Ez)h`f7`Xv9R0 zcZo=X?cUk!-8YoRci>%le!|~+=YHNbqzTO!k2k*4>$}%M7{nw(3ce&iW%-fDw4ptn z=uKY+Fo=n);y14FCpWmo9q#jpCp_n65Wbg+w4@_F8OTglvXhhC|q}VIK&Z-Azu`^qR16Rt|)JVFzS0mBL-)6OCbQ(>k(R3P3 zm(lL=kbig=gwc~xm~Sb8E~1yg=SQzVC93i>-VuEuLy$T82u3j$y+xml?xO21`Yh(K zldC}(BPyR!k`|0Xw=ralAx{ihV(KlXO=8BzEyc`8X1q6MHgb@QvQ(xTHKd5>-O=?jWy?xLa-F=|D4_eWNk*weh zwu+yeZ>WQA#J|K{{^NgmZ-V!TN_0Nqb25;bugFUQ^pQZO1l_S$ z0-YsTfF2U)A;D(0;r$8rV7CMhgD|1@CM-;Oyepv|6Sl)13GJV7KJGK2trH%>)(KDH zdzA2Zu5t}`naIs0N<IyOJui1Lm18|#^N1`xf6tmWAPcfOYANa>n(91 zexx=wO zj1f#{1AlUZTj=7W`#jHlC0!FZ%O4ys^6qv^9?d3{e^DK z!d^-L4#H&KkSrTEPu7B==q}l8^pHJiOikQg=pCWFp}e8I z;W#ER8NG#ag!&DAx5N3!6z=0@5PlpBdwpCMZ}@m3HvjlMPlGUp?oz}?Zz(H8t|{_h*A()lkSm2;DdbAggyyuO4dYqEQQU2c-?_?lbdbV5rLbEHyQOf;pQPa@ z+B1N$*#48nY~di6`GXfhm@*(LF|bw2ge2x8KBFKyO{r7Ay&9&hL=~!2gQoOjIjdNU zE>do08#~#o4! zpa9=c1UXXcA+_5|T^@Iwx-+^?J(yvP#NSFilR3=C{iHq>glTl0CM~(}d1-z^pJ^Il zvowPk$~<(MMyF|XnnsstcCeehoZ)^DrcFXJLUfTf6+S=h=eW_dnQ?n*y(6tVOIs6} z)7GIL4bfZLX6QF7o#g z7}zzPeCgy$Cs#VT(&a_J>GYefFm>t0WZZ4K#VlhbI!Nc9(%CJY-O?T8aS(o5Cq|ko^nY zW{@$1JQ-xkptlS~@cs%PdFcLKLMKGG(qyAKYE$L+JWTZ}>7dm1xIkbob>#^!DX4wqwsP-PM<8IEPKY z^zZeT@_i}SmvUv1D@z>Wk$^(9p8a0I>_Rdve+$)-Lm+1EX!`51!2}C zq$3B#DM>XN(3x(GX9lyGhpn=%Vh!uqi|;^Ioo3Z(R-I;j&I?}iCJ3{|B`swrM+J0| zttvlLliJjyA>NTq-fZ$_lQ-KGrZE$}Ws@VDezUpfY)g?T+Y#;tVfGKOSN4i{L-y&| zJiG5j_E$leLw7miqqiK1`3#%pa9cU@Vb>f5v1<$iKt{igZXhmB(&x@*HPSFF7L?Y&T_pC`~*Ew zh(=8G_LZCaN_SuB?yJOngxmS5JnfmtR;~wO?ilDcw~V>v$t_E6z2&w^?yd}DIy3QJ zzrPyhp3g#dahPMASMP&?mv(B=DCU6 z%yua}@2=jeR zN>ZbXe0Ixcw|rlcjhy7hJMzh!Pu_g;=4(t-TA;Ula^%x*J~x-I3o_-KjN8k1g?B-i zKMmfHzZpYW!a;PG-(BX{TmBn73&H}?v1x(W#3defEg)Y3xeCZtK&}FXC`xg@LpKEm zGKpkf6 z>kHWI>leHZ!h#>7(}FrJsMCVFESQWf6B+ zWD&c$$3q^Yiz0R_^8cUzzaT6c5S18sM^Sqf&4tWG^OB!}=&fi`^jq{hzDJg#jTp#M zj`Ji4zm@sh0#v6n6VTna%h21mtJ%X@Z2Ij*e&cuS`mKD$$JE|i|e$wE{nel!V>PVL^Rx6iA?-N6?9SJ7i!`2OSsVzjcJB= zlyD0rrZNMWOUz*&dMn}PO6ab{3UpUuEwYq2gTDRFYWQ6qen#f+=ChBRL0IxVbXQVu zB_n)HW^7ur5JmWw;(UjECFLq9S4p`_>euhFh9&h|vKKlnxeI%h)Llv4mAr!-CG}9! zb|qg0;rFpfg}ePe8#ensH~!Z5CHS5){6I$*bA;dVdEdW5pQRFzf~@4g&6Uz=DV>(m zX(?Tns!t=D(3vr8We2;_h2LHc{q|~D%8iyf#aS-k9i^iZ1DQ+5;eFg(X}y(BjDAZe zCq$Og`KU@a>{WUXGM9;m&C8UcA-XHm9le$5!&q!uW&w*>!ZPeyM!qs~m65BATxHy* z-(wBS=(o)6AS@f5^b|&SWp!7!9CDQX8MjsTS6VO-cUyKMQ?OZCf2-_rR_l93;2hi-qA@ke=nl;uag z{b-XP@9`!G%f}-=-dp}dl8}_Fr%tSSdHUt5gQPRVq&%+G5j69qCM0>{>~_N^(__tCC!mR-oTX z`mMBqv%Cnx$_db2W!+Uyi5!*nP&qSht8zgKQ;i0=smeC1+!Ei<%01~re+IG&Z>$oH zB&0^4RrFa!msKj!h^Dx?DmtyA(<(ZxqRT2XaEDdq;@+wpbqqSGYOAX5t6Cb|P__EVSWTX4 zvQ)E4wJmJpI9IW0HSeuv(`tWnCkU%YAub=_`%v9}ev37%{weyXE}!3C4XbydF9R5i z9M#7&i76~*4<|Xpd1S19i~s*SZm0Sq9tYviiO7#_ezyP5?)B&C%);(J@8C4&c!=$P zevS9mh(T=LN9G!`*7%B=$XTNv4QWDiTA{ZZ9dL6sx-p+cEMXb$t%ko_V;#D!v5Bp0 zXD3&96NJC$5z1HXC<7?c0EuGfVX)T@B(q*ldw4ohtq1H6^bBLqpqL$ri`TSZJxy&D2!#irb z{n`nTxprbcA~|}iof6&ooz}2+I?_{&x(vj9)jrO%Agq%N-PVz@jy!c_siU_#HmNh5 z8LVVA-dkrqz7KUabB5o!%60DX5O-NeA9ZD_n*)2*)mh!2(L-H5)NMg)yuWTo>{fRU z-dp$IAgmV?@2aQAdKs`sJ^R^46EPzP$Cj(w$!Dt^NRXS6_Gabyt5R zz7zG2@=p*puvLSv&_e^+8|b!yj1A;zAWH+iHF$>iH}w97$%ybVpWr*wFg3bp_$?*y zeP~#LO6a(uej3Wxa0+YL#!mJiM?-hj@D#RdXtRd@1!1FD#N`7L;%_x_KaJAzIbTp7 zZ)~L3M(go;jm~q4ySxa(#&K|$jon=1EMzAa1<_?=T{d=yjVscO@l0YWx@bHbpWk>P zOIXe-yrZ$b8vlvRjc;;`JLs+PL-gx+TEoWAk)=su++LH)bYdDZH~BjVo5tWXilDou zRnS}08Z@T|Huc-9VbgvLz^+Z@YbsY$xthw=bTj&Gs^6x&xf+Dcq7b6HX1Z&Z0Xdp| zMIPK%vy#-tcc7W?Kr=Vh%w~RvHEibl*=z{IaX-yAaW4p)zfTH$Uh}WfXY(KVg;um> z7&>jP)8;yDuFK{NSj|_i>)Txr6t%e83|f2Vtu? ze8@*6CpDju9(}ZuuT^90)oLgs7>yjQrZbb-*sPUXYITg?xWb>@!2S3w*09yTyyCwg zY;D8V-q^YWc4<8hx7m6LTRFt<*uC}3AZ+s<(TGU`blFCiZIa?U(dHW((gal`fF>?wmNBBnwE^mowmJ%jP2xU zCrdkC+RM@2UA2!( zJU%8Rc__wrl%g!vamVdzQJ4DIu)R07zm8ox1h|0?AMrUkv3rN_sY6p*(3&pjvV$%= z^kx)`Im3B$(ZOyV?AF2Ocle9j+`~IMxVerIWbXJ0pOP9k*D*c%?U;!yWFrUV@b^28 zVIBTP$9F;4DGf#NwoZENG=Z7SVLmI+VJH7hrw#mu9y=!>1^#wtpV8T7o&BB8Uy+vr z6r=%@*vt_w;vJp6qqD!?<$d(tMgA`N`4+u((OZ`a*t?6pyHukQdhF7V;pnZ)Sf(+9 z+011PM|sXm{^M;Bc72a%#3T-O@9G_0KSbWH-%yyMxPh*2psO3`>IS;%ud6&=f1)yN z8G}x`>awew>ZXTovUhVI-DK=0Pd8b*ZDb4EIL=kB^A~pQrjKq9g0OoG;**FZ*tUBr z(xTt)a&`CF-Fq;QA?Ts|1ST_;=`3SEXK+v5ohX+zi%vY$h^tsy!X@;i1LVz(jg zX=psY;a6JG9orAp=g@hqW*-N+#$6uZyEN2RL;vG#5Dp87PkMAZOsB(iI;;>yC`Jh? z(SnIgVLG}PHkSn~W*IASd&9hAn7qT}9VYLvTioUzdK)IkF#QgD&I@E3{t>yTioJ%< zz#E3&3BnOJAMrWgqPr2*(A$Wbw8W+(+}4PG*mcAp>^efe5ps=?YlK`Qwz7lW?B(wu z92t!ixZ9DL$x04%Fw#AZwA)C#jdaT++cKX6T;wloKT@Bg-X}Sk$ijF0NJT1Rt5J2R zM+4e30-cW1=_s9!TEHTfvYc(4=UotvjzV;F;Wt;q(I1eI#3aS-jrI<|y&C%M)o`@D zqs#CE<P@=xOZYMi7pPi5|wtK1R1=WE>;U7+J>XZOlHre~kB! zxx+mk@QBCwPK?#X*d!z)BrTt#ORm zxGdOZoOg}W=Qw?iv&lI7j~mMbY&~uhwjO8eaR)ifF;4IYZf<-)RALYxU5?k~cy~Dd zGYZmx#xz40O4|?MruC~ ze1WYdv_KCNWS^kh2{KNUXQC_<^)@jx-apa%C;mtUexfo}sg5otcB3bK7|IBAJW)Rr zWtw=F2fXHgK{!bdlk_kt0UzT1lagb%N#EkVeqS}5WS2?aHA$b7j$o5X_Mh|y_c__t zlT%^q$+n)HmF(mqH|}z>o15H_CN!r5x}2=b$?kCSFy?cD)0{&WlP_bp$=A5a-`vGJ zrpP-*-YN1W8BH~c~ubT@SrdYd|) z1#HBoQ@666o!E7%d{gC`D%VuGrat9gUh!WLPSee_{8Xd{zv6bM$>FzF!)dK(gIk(5 z1zk_`9hl~(rn#wU{?;_#&uM!(fcu&DBnYSLdU`P`;q#`qN1uLYHJom<>5Ey$esnrr zr_*&hU6<4UUCgoD z9J|d~$r{$P3GbM*19|7%;{lI&jNbePYv?yv!#Qqlj_&3LL?I>mo?9Dln!6BhnCph- zB_u0l(A_+}&GY_w4e7*SY&vf^BN>fd=gBuuu6c6JlWX2S4x*oV$M`1*=f@)*Irxga z6hH^_?KabzaSTR_>pS(E-m<#Ml_*0E$P8T zbh<#N3v{|*C983V3pTKyt3kLh7IFCiT`WvYQrzgm6u7;GY4DDP@-CEjp}Y$#Q3W@* zP;U$6Sg7BH^=N=h3;Q#VL)dFke7s>%RcyYt_5u^tw?t;I{(!dY~^_$GgI7k_K&vn4mU#k(L}s?()9U8>Wix?Gx^kNJem6sHBPX@@SB zcERT_?S&g%Ismt~)H{~Cv!$DmdFeKGup7NCb#qH~w^VmaPjCvivn(Fjs6Yp%u?yWU zlX1B`%Vk-vx8*ijo}2HeN_D(nDArw6)Rsmqn_aOF6bbAjKuf-Y9tZKcm&d58Nv;tAfd%3iBdA@i!w_?!&r zZB-WZyDBGNAHCZ=x+5S^tO6BE7*xmSMOy%2eIpF`Buxd zTCUY{t^N=FuF>zBsHCGPKjS;MrYS9GjSklI#%^ouwq`JE_$vt4#z2>A(~_Hf=yGip zn$R3KxOOCVSnIpAb_TPU%Y4>x9G$M!=~|txy~SC+|9W*9~PjqtM$rIo9cS-4xvPI+@mO zZSbAmptlXt`3ReC_=1esbwd{Hxc^rfr2#A$H|cWI50s}Ob?C}G7P16gY+8lS-?RZYx@jA3Zu$5|Hb*BWZfA2*8Zd}uoZ&?fZqe-)8Mnx@MV2jk+hUU~&FIbuM&Z3%#xa3OtY!<_ z*~MXwaT0xOk#B1v?6ox~xpBK&<=9%B@Aw{@ZEcP3z*gUZt^F8?zqQreS#@^tQbo`rY1`rpU5=2#Yz+KS8)7F*5J?g>Fn`6S~`R z0=?}x%U}G9O?SNJ4R3>Rr(Ji-w^Od2a_y9BXEyY^Q@=a&Qi)ECMt3`Pw{sS9>|DkQ z+}6&WT*AKtJMZA8cG_&GzqQl%b5|6i<9>E!r8a#Si_hD&7JcqI$T@CvF9>%>L#MlS zx?88ab-DW!Qjv!2l%g#i=!`D>?rON(=kM;18{IvW5qO8+T@80{N9NtT*~B= z@dEESV6Ow|koiCcGLZ$n9mt7(59B33vK**JC#JE38$ozb=7X6jO%n#9yMxow+rc@k zWgj*@c!(n$!>$MAJ1Eydxem&8C_ul5^m`~4pYa{F(A^>39cqajhq}@ow{>U)3-Ry3 zp^dnyLpD3)ZyoaeJame)xSvDsg79!Q%2NlQceoGwJUoH9Y+y5I(CJ~F9@gn$T^@eG zKRgM-BkvKRD8(s>F8tPNc*N%)`3X0Aq&mOg9Y+Q;44IFNVhrQa+mR{g_sC4#^buK( z?BdTL^xLc9QF|Tz9+{7h#pXv(^C$?9>F!u`^mZ%`AvQhsC0WT%PV9P2zGHG7lk1pV z$K2*I{T|cru@($v1qadHG2I=zfE>s4aLjET`d}KLw?-P z@%l_;6NmA6eoHkxuFvCdgYZOLJ|PwP(CG=Cp3vzDU7n~&WvbGUUMyxAE78S?_4xb~ zTXCZ&cC!!fIPsWg$b8}@ulZjPp48jPDCqZOOx*NISx%;>1WmBl$yLaF^1mQFW%E;c zsf6xMHAQcyTG1Puo*KslCNTxOo|5mBT&LtZCD$ppc}l;h^n2<&uY&OOM`WP@-%x~N z=-{+_I&HVpb~{~z{%qtDx;*_N2+zbJ9=be}k%APa8t(m!9nLhOHEroYCk8SLou1L@ z8J(Wl#1^)*lM~zy!m|lUOj2}lHU*!OhID*^+dJzWXXQOB?^$`z)}$77(c4)$&g%DU zbKLY%3g&-RAi`M7V=D@Rf`aI!yGy#`e&^wPnwLHQIsS2cx_dJk zSsa~!&p$d19X&b+-8LJ&zSk>9)9C@_(+?2aDgIJ$EzCGXIRv20{N zvOR9b@l~2l$gi z*z0NYoi^8LbDcKVnV7^OJ_(V{nc8%w5B(X4InLPonfIB1E}i)hS)ch9ojRjaXWVth z-{+ZsIEwz9)&H}yKHHS8_`I`|k>}ZE*xA`{_@4hE)3Y)?E7P;GJbRZ1JPM-D#UdTm zs7W1Uajp?Q|J=Li=()D&-Z}3$r)TFrz|7|su!yC|?c6Hldu}}&G0VAMxfn#9kBfbs zuZx+_FUHQ#|I7U#>VoVp#6xZu-XcAAdO^1?6rmU;u-6ObyI`&h=DJ|63q6tV1^Hfh zk2!qGAIR>4>@J+Z92c&jTNiHdEQq?8oD5_p8+LZlT^CDInsVsR#U3o@I}YOWF5X6- zmtv5ZOk|}jGQA|zOESGA%S+8^No#sBk&oEPXUO8x*ZBNPKcb_T_OK7{xb%=GnEBER zUIkH?-#~7cVs2T@n-{7M;GAiFF5klU3(Ou|mD zEMXZdScSb_G2az)T`|`cb6wHREAqV}-z&#?97J7BOJQVpRd!b^VvehI(XFcuX-_9c zF^!qn+0}WhW*r;Z!ZwZsQP;fjT6RiM1$kbR=QUYg8^#P~qjT3}dQGO+WO_}O*M3G1 zukA(OuKgE8T~AFEvbdg+EckrCy&82rF9q<9>$-5gEgdlP^)7TnZrA(JAK6_W%ut3S zzw2Khlk0YML%(iRMTc%o#f&%1bHgk*?BvF2&T==1x)}pIz3II-?eu1R5|WjC6vW@d zP5Zl9o=V8$rulA8WF?!}%680ga~I$69e;3%d+5~7Cp-_LZn^7L0^TAi$+5#*-grx{ zw^rlxZvBW3+_IBf=Xij<-%dgrLei51S>BfA?fjIb8DkmGBxG^h-fsK++jCjKVwT|@ zx9#ipe$0IPAb;^Ua=U#L`QARo8O(C~RS@-GgbH+IGG_ko5O;#8JBi7I?Cw-VZg;BD zobK4^o!<1NKlXaZe0R)s$6R;Jb!R>Dy(8Z{AF_{|LDbz?$nLJ}?!JvV?#khACUom= zVQTX(t0^4syF+4*A}%j85M- z%l*zwU^Di0|8@}dz|0RyVCN48GY{E4*n-?1e8dmf>4U=@;a`qouMf=kz+4Z^_0U`o zb@QQoAIkS(athFhUdZmD>>iH591rF2P`4gVXDKWAg5B)F&K~~3F-~%Z^IQy~9wovX zAGM=Dqmkz$c|MZmqfhvi-_W^7GJPb|M>2gR%SX@A!^Z*o_BaO(XpAf#x1cpX|FMof z?m~CGklSOOdn~)h+mPMk9hl|upUC@3GK$a~Ge23&Pn_jt5cO1c zPv!PBC8^1Yojxs1S;|w9%9!t|xt^NqskxrY_o;lJ%J=CgR`VV9_4ERlxyDUo@YLR( z+S@aGdlr+tv}G)^e72IEe1!c=6h+bm*#qDu9v#` z@(ky>7(~62&8sYwp(-_~jX7S);gxRr{ne;fJ(+;4U(II`OL5n$t!!rp`t#~U5cOKt zuk%q3pZB^g@_hXscJ_K63;7tCzLx20nZB0g>wWyeK~C`~2!r%wA}cw_O+E@zgyOtI z8M@G&p7f?K0~o{*hB1=SjAaGiayAIxh(R`L(~sGF#P6Ks92dFF;~HOx8dH`r3s9J%RHikPn92-f5pym+KjvbVv63}- zN6Z8Kg_&a>;a`p+x0q*;T};`7~-HntgKn)EUU%Aa) z9w3Xj_7>OY#|wCq*u=v-;@MZc5|}w&Y06Roxy7rBeB;%k4rYnhi|KsKAsz-{d^5){ zM;k`56xqe!f!yMM&K~}UoyI@GDb8T8@y(aOTnWsTz+4HEA>Rb@O^}x2wBS8tmq2z2 z-p3pX{q{yr02;4=D?Fe#Pj#2|cL!Uf1P;TFDNAAfKO znI@EJLYXF%Wy04%m?#D@NlqS`(43aYB2jyMexk1EXrkWq!#ff!XBB2nw2lpIMsA6= zBi}@ypwo%WlIU;l1>svMv9GsUVdl3sV&`vN48p{3AiKn=kXz!Ayx3{t@>HZURk7E^ z=1Xj@#O6wDuEe^TSiXtnn|K`S`HAEB`%iqGTiihgN%YC@t%gbLElFGo(vb2WST;jDgHtaQ~bk4UIt;xY~(~1Df3f^qLiQ%x|h;BQdY*iet$JgIe>u-Ms6u} zF69_xm(n~bCou*2rThh%q_Qi&ts171Ln^bUT7(%>nJ1N5QeERFw|O0esgq!*so%y< zQ>P{^g(*!rDpCs>rUn&~=X}LCm?QNb_VGKql=^-UrtvqBMyJxmCLZoe zqd#fnpC&ySsfjnHk!zZd@Ofztq62Bp^Is6AjX^BZk)2%Rr5LhIE6cR@n6@^ZnZ*ap zM;2-AEv?T_yP9=uWDDMr*1pmn#ms3>a+-6HlnLm7_uhNBtF`z&KUo7l>ye8Dc{5t=W29)uD5ibTjj zX3P=Mt4Ki#V`q_;bfYJI=#RT1`V*PJWTx^7-k46V=~CkJ(iNj5c9PEDQ@S4LWjdWp zH=DUEU?s9lC(CqtnC>$U@QA0pKo;rkExpfAAD0BYMN+&Yy?v!GkD1d~rYbd%Tl#v) zF1_s1H>Ej)n9o<(Rr*&!m>~<*k!=PuW-w0%vt*E420O{{J%4hR^LTHD%lMnga6Je! zzDYt7l2uZ%LwI0HFkltac_Wv2h3bD3nCNv4@(npu{aE!D!r_*}R!Q~hF1M^38J8QsgVjX#k?PP6BfZB8@hG*3>m^nRtIr@6WlDPx+iL z*~K@=BIha2a)F!thm3Q|CzqLW6`>A#o2xZ)$R!8Aw;JYp5AV-4413G99`DWdI0$pw zOK$JVEzjJ!v6I~PpSu-pvFqI9uJIbo(fc^8a45bJoPbeo{@}ZEbk+?JX4Te9-Yf0yF4E-j~&Q6&;20G z>rHt};thGnvzDJYjqLKuEwA_IeHw)M;uD3P=1WgTGGnj#%$Ltx`OKBiT=|;vF7nCO zhH zA3H6iTZJZJuZ5;zuZ7H4$XtcYRmfa^cQq{ZBfI&Pt3g;e7U|I2!ucqOzk|XuD6CI~ z?X9rA6|T)7Ht`$BxQyKwmS>Sfq$Mu}s6j)T&>Xue(upo~V+h01xgs(xB2&M!8Wxdd zk?rVVkx%%E<3U*TO=2U9q6tY%GE$Hl-7D%HMKfaFqIIZ80~#T>qB>W!6|yU8o}wM; zjQonOK_*4*s#pT#P|WPb24coy<|$^DVtd%f@0{coc3SK%c3SKqkAtvy64DToo*c-y zxQvU-r?{Dl_hTvxS%Msj%c1y(e2n)O{~UcPu1_Vrw?tv=rG$5tkY|am3}qsVS%zJg zum1vBemTFE5T4ArH%vZ`>rOZ{zT%~3+mjx_BHl_Z@9iH-n*Fjj?9Hr$@ zIuVJ{rP9Tbb?Iv8RB4?m?XJ?TX-7x&r}QjjUHTmN@OfpDAL(E(@1DVK*+{)%czGd@M z5VMr6PhaL?Uw&IPENkX+nX&V7?HP^i%FRb^<(9A&J1wVM<$mBNc4M#Q%va7_<;+#i zT;(1i-*WOT_bLd>M^Tn$$gaHX%6GvW<>gRbx5^J@A}iU(N9@GT%Db!lFYIMM`cwX4 z5LU=eb>7A2RTzdmE6ijm+u6ZBWLiO{6=YgLmK82=nX5bw!iq^KNomR)41as(#4Fe8T5^h3-}Lj;iLZYTl~mt$Ld~+(&Lzqvw!s)tBgW zH8WL9M;Y2QYa}Eqg(yl1N+E+9`c%W-YS>$iMvUYm{^TsTg0QCD*OX_?x5-Em zic_C=X+>M?s%8&*)0feVL+5JBw5CjJ%Cx2|Ykr0v*4)K!oD0HQ@kxX%Y9%KnX$VP= z?$z>+S~)Opt;RH^IW3S|EuE{?5!ux;Pc8G*>V^DjZAK=w?8%EEH z*Gr7|){8<1>)ByFGuJa~J@?cbh&k&GXB1-@&m`nl&%O0#GZ**PGi$vc`580RGebQy z)RSAiKRL`1%v0}v5Y~5h{bG1e{gIfz{vIv`VS|{Mr-4}-$gF|4Hz-XV+R%;;bfOD( z+CZloOk*apZLoyp$fm&>%;Yy%!v@cSuwfkHlZYfl$bk1Z%tj7c;Jppk<8P^-r5H^a3EF0-xqkI&k2xTZwC92Sv-VA0K-rHy*Q<#pK8=19{dm5d_oQ*DW1v_hW z3q5Egw?@(TKIKIaHg<1gvo_8}9?a0#42{juSZ<9=Qkt@ur*UiC?YCFM#@^HTau7B# zf0F{#L#LXUr-@mb$gGLCH`&OS{KkI%;2?itr%i6~fXB$T>6^qxHcb;?rlz&%M1KY{ zgyBqP8s6V@4s+3^rrz7^E&P2q^R8y)s7NE)@gA~lrhm;Avy7E&VhbPg5#RAIXE@I# zZX?TPvTXJ+2>s@2*xde`SEUBEkwx={G(kU`w?yxnx5qo0o42`no13@!d={c_&E?kI z9L?q1d>tDwQ}bWA5QOi>At!b4hIbe71$y=Fy&!BMyB2YgTZ=@bBR_W9qA*1%j=i=p zUkh`!Fjot6wdg@_`Y{06wD^SIIl})qjyYP`dyA`FN0(YAL)I-bp;Ik&s-?SHmY@`6 z(Vv#xk#);&Ie^b=c?)^AdILLam60s?8)zldRx)iR(^j%<)r=Ojq9+sB&JI3B7Oi&S z^IQFZj<)(0-D~9?t@NzbW6a#@IWL2-b%5Mj$3niXowe1awxgKFOw8DJ9`0$oj*V<#8-MUH2-{`HUfNYbH`}$O7sHr= zy|>%UPQ16>m;A_X_F(3AW^H#T2-};peTdz+xBK>4$${M3=R@z>7oj-q=tyU}q6_Wa z+g@(%<AqkeXjZAaO5tV~tR*Krc7kU>Yeb^Hi(blk>nx z*vVa;5|Wr?yiFOrv6J0&T7%E)^b^1E59hI$PEUfcb5hcxTb(nI6IphaW#1vj)a_ed*U2D*Sp7h3hyY}Zj1~H38_*>|@f{kq9L*&ub zOkHmWVK@8gCbMp-kV7{)bjw9vyuVvv?5$fH#;_BAOWnMyn;g4c!alm&fA^H6!LGae zJL+!N-78R&I@G5j?HSH^?7qAAcAv`vbg;XbyPLJUd%EAioZav8fX6)JWf1m|TMzg4 zh)q1)+rz9qic=CZ^e{sYGxU&KkE+z57Ut>E19$h>j`#GqAA~*4-?I#@@Hf%ZJUz|Q zQ)WHAz2~RsQO|$)AII?b((@E{+Eb@`y+KT5+baplkxj4En9uL8hQ0bDgI=Q;i#dAv zZ$YnF=vA*(tmPZ@sh2+WI>;eTbB>E#;aU*(PKG!3)}P*kk!|mVEMY5OvY!L|MfAV9 z$3x8A$IN|X*+-Ur;*yF2K{&89dN;5lRj7{q2G*qkjcG;;TGNh>bfG)`doxfs2M%Bm zLy_yi(TrmPlbOa$ynWz2%s$ZU1N}`6l*K?<4BWtGwqYLw?PK6)c-z3Q`Hmmi%^vpg z2X;H~Fm^WZDE2i_h680dP=*6#IPf~RxPu-He8f{;@Hz+w#UK{48I*vxNQ%FmL9!Z@ zmIxWhOg3_ohx`=6?gy2i6nZ(R0(Lg28a1gyeHzh}chSQ^ZRvpB4(div`p}<&3_+I$ z>Czxw8Z@3sOhu;#&1NnOSj;k3vWE3+Vk_I(!KZw|F23ale&$zx<97~nh$H-uw;6s8y@DNQ*lQibZ&qAm?+Ofy>0ns#)g3*G5OUj{IUp^RWO-|-{6*~32m;7<%;EEl-U zHE!}B_jt$?p7SaQ$GkyI;t-!iBq2E|Nkd3_GLe-WzDM(Ee>BvYHvXhIv z6reE0C`oC`QIRTCrxtZ-Kx3NGg4VR7BVFiDFZwcoK@4RCqZ!8pCNqth%wZl2S;BHw zv6c;NW*Z-|lh62)ulbH2+07pI@dtl$n149R2~Km4i(KJ4x46T79`TeHybi)~F^EN6 z67UvDd7D(EB|-)=lZ~9@AwPvEN(o9)mI_p+8a1gyeHzh}cWFgiI?$PJ^rR2{8ORWZ zGm5c{XA)DH!EENTfW<6hC2LsECbqJj9em0c?BZK~;Aej2H-6_Jhd9FjIL;}~a)HZS z<0k)ckB2Wl^*n_AMY`kVT@!9?=z7pOlKA!FrP&%Wd*BQ$40jBAs_PzpYs*p@I62A z3wznm0si7|{^b}aIm3A_ag`g~<}MF-%rjmF;rM_ziA_8bl9*(qAT?2>BO_VJPA>9N zfWj1`B&8`wMXFGpTGXWhjcH0>`ZJIr=)?H?*!g%nA8+RqWIn;!1i4O->jb$@@U98b zXJ(&h_K9Yn*ac@3$1#D)c=M!~c-JKFn&e%R+&RfUCQV}|b8zQmXOrI|DQ{z!lV|e* z^RchV@|uzynM{$%6q!sJjk76BSk9^-oNAt_A@Z6kuc`9#d&=Qdd!D+M4Qvj=Y3`hs z6}+v5GGb?o-M2XUY#kff5`;_Kw%t83$Ibys>| zXR8l!9o<>|ANPWAjr-R0p&#!tn4{d~K96`Bglk(d2s>RnoKd)Q?K57WKkH)P&UK@) z({q)lZqlJm>Bxu!wXXxH&$V$%?&h&dnUQu#Jz{8H8Kh zwWjw?&7x=+G7&+VXV}`u)vttFx^-v{i?;mSr`&_=fNKDG0Z@b6aVgZ>xaa zZZpp|d*7yK+kVAvKQzyW&ipQB_+bs~_QM_Q<97~nC!cW@a?2{3UW*qMP(=PMu%0~fo zZC5eOvn%>c*LLaJE?xUNq$tIChcdYH>*%v@`2k(}#ysDYqXN40O*PE(P4w9>>}7ut zeruj@t77-x)}k&ui9WOYZ~x?Q5Ps)AzyBA0*N`UI?RUENoxOkeFUPRk@5}Qpy7qk= z+Vd-?Im-nu2jLGj=}2d~p-Vp;f3Jgie&5d@=+N(n zgYXac{ZWqwG^QCk^v4nYp%-y(~jLlpXt$ob6gC|h5v(+&3> zyu=l*b1Mk{bl;yn=tW-!;J!cq<1P<)9E5-A&|d=?%rHiBmZv=DRS+I}106b~Lx*(e zkPaQ1$kiY`?Ch|e9*#{sbm*`S9iD;?9oCb>?)y7F2}z8e{H;TOJNw&C|JI?u7vjz% z&iuAl=(oK>zwH$sapw_dM;5b;l|lGVKpLV*M@A;F0z3UjkN(*Zg#Vi7-%Mm7JGq$2 zMmD2I|LW2IlH%-tdB{&8-1)zc*~w>o8H7j8bF?r;DM2aBb2R#F7vJ(j5FRtnv3Dqq zy&kK`dcGt2{AYd*!s9upKqabDgAa*5+sl3q1mTH-)TB1`Xvi1*$svyLzaTtW5@#nH z(+piY>CTh?a+DLC4#HFBIn|QZ=+dc z?gZhPM)aZ&{TYZm&-}+-9`HB_&zk4#d)WQip^U&hXQR*T{_G202jMwgJ2#3kyw613 zd0yAf>)Lr;J8!q=&2wJY&QC$t&g;|pdqH?10f|ULa@=>p*#%v@Fb})+8%NeS+6qR;kofWLz9hC6TA`;EFZK$mWO#UcL2UT+)=!kcB$v77JG zini?LBzAi992bM|mb-4Xrz2hH&hJE@UFI4$gYb4ey3qrBz1@$0xXm5z^C$@abKidh z(6Rr9Fq~6FpFQC@uY&MS2SzZ8v5es&hEMI zo-@BA6W*JPo!xsHg!hy2HmR_)`y+97e-V0ge?<^JaOZHfLgb(A8 zflOp22WEP>j_C8vYzx9iW_pyJoaoUbJ$huON6}~7*}>g;KGDp8d!M4$b_UUcbMKB`dzU3zA> z&)oUU-k%-dFLdd-JD)rAnCOQrBKyL)Tup^Odt#y7sC!{V>m~=retLb(aT0_}YE1`|}=y z8HRqpe#m2<@iK@6?HI-gMl+6!M4!D5B7Tn}@*kug4L`GBC*U9D;*igOg7vZ zEBb5$o7ombVkg2`>>T7KA0M!l5BZo+f=HYcIEzz&!W6@uaX#YT-9cS?>QibZcFJAQ7UiNb!h{Sha{2J7vE)8&J{OGekIm|yn#BVo5 z64a+5O=!;7{7v-vQBDMrgynFSum!DYhnW&apPk|?7lKHlYB)>OfzEW}4=!)Z+= zZ<*(<9`vFw1NfK!xXS|`2a&`r8OUIC$?qRT5})H4FL)h9lEk1BqZq^cOyp`1N%{tF z5*uAg+7mrXI*F;wz@5qB5+8d_rc24(nQSJrnacvqliXSIWTYT9=1J}>`68CGB8a>l zpl5GKp-XRP#GP+PpRHmo8-hp*^Q6c`7VI@eF5H=7Bb(8)6dwhVl^4;@3Q&lmlwdiZ^CkA0>boG4Is+vsMOi9fp48v-BfHrXMADciO(m*O z9bHQEF~6~&1N;?4(iWi(^=L>FzTyyil-6F;9t$E-WoU{XMcHdq8-C(ACpp9UAQD!k zE$y*a-&>D_?hExRyu?**1d)hdN1R2vqeqdx947kg7I(NGMA9{*9|IV~P)_iGM?6KB z(z`GHaO^a_9;Mf#^zKXlD)4o8^e97Y+?T;w20P6#nQ7b(A{pagr@qe}@qO+{M)zf$ zj-6(lgPmo35=1g3B{?b4lT7Z*v;ZB-q(hnXB=Z}jB_ut1l6fL4SBN zNH#mmo|UqcM@O>TS$3Vx9(}f(J?sl2Ir8ExhyLWypB#3U!+kk^=Kz19BRNaZfJW#@ z&Ug8ifA}9d;yc5UT;*s^3tH0-_vJdtY0hymh~%z@v)mo%OgG$_JNoQ0*SHx(^5|?H zXL)+i8$HQ$gj@W_Jst*;yynR}fPoBQIOfT#KY8sm?{i)Sk$fE)$!Nx*Bl)fbk^BKM zh(%m_;w=9prebIL-B-X_f%qgM3GOQ}liAEgPkc``QqVpN>QF%)Dwqa$7Iaq7P75wY zhYGo~kh4N|S|}YEabKZTtYJMmQrLZkGh?TPbC4VN72eENwxcIS+*d?@isYjpdQxOD zJNc9^*cC*IMkq!JN>P@z=ugq__z^oRmJRzXR)NacS+Q;W!XEUe*dIZpcz&u=lRDJL zeZ`~C4sr-PE8#xh#f+3_L{sdngbtO^p%OY&LWfG&S;_J^E7_7Zw8woV&v1^5*x5Vo zd&fTC(Vus^VQ26B$yKg%i#tK2R70GV>Pecpg)C+nD}zV{_f<$sNP03ck?6D4tYc#ksTdDu z6|<0?T)4Ah^x0_0m(HRH-2I+0Ms&!skJxa%!AaE=(~>Vy4QU@ddlE z+bS7(htiazBJQm613&Q#dxJ<-^Hi-w6{=GU^HhyK)3d6&RMl>)6~bAyI@G5T?yDAk zc8DYBQuR_arYZJXy%p}Pew5?rS@p9)q=q|dIIE#&HQLjOJ)Gej7r7EdYSyG9y5>7% zk(xa@Nc7oF{^J3Uc^X7&B_;=XDL_$5Ad6ac>5A^u8qXy3qn3WunvD+B+J^Vn+KEhS zeaY8+hj-L6Tdn6oq_#cOE=y|$V)wQE``S8GdogxWdqohb<9}CYC_3T$T#-6I^DDn0 zw>n3VTb*M;q^^1EHm5(s8HHKvnz61K>zc9d2du+q)jf>&*S*I>o?y1RuYyRuH;73_ zGLsFt)XR-*>bc8zydw3A;Ldu3Sj0EjQ$1PMPf2$2ke`C+QGL6w--Kqgz#i+{WBnnR zx4vxa%eKCG>&v9ROzQjW`tq#*Kkg9y`7d}KL>k1!-(`bDBqkljsZ2F=z<0hP4cyg0 z-oE!0Y0wd!XfTT(v6lvNXyEf2CL;yj+|b`i!>ZJv1Nzgj4>E2j}^aWqx z&PMWR97Q=~+1TzIFGU|4@8DBDXAd%Le2f#E;tby3_*oEX@+Pr~ha8%iw@GT!BGV=< zFmn^LHZf}xvo@KI9GiH56Z>kihV^{Meh%;#e{+@#T;>`#f=JW1k#WjArij9j-{TJIJoN&uE?; zZ*4Be<`Iffin3I~jLoal9-rU5J3ha;E;N@(^U18nyv@Jm2Y%*Pe&cs8a)s;M!u`$f z^APWOHw}fUk6ygH02#b1%XbfQh$GnHyT`G6-{*?7_$Y|9dB|&+ew+C$!fx8EWdob|fZV4 zcJDD2^R|;sJ3VSA&vx=`=dO0T&`uZH=|a1^$flia+L^hXncJDUy}yn2F^GxXwy#20 zrepT@a&CW_$GqTm5b5v+=IxM~tjM-QPI4pP4ppf~Lz>VA^LFS&7tGvYBWCVk=N;tR z;V}Oo-wyKaaFrX}3L+g-Ql0J$XEIA!fnIdfsgB;-(OWxS=RV%q@o5n0N3?VkqwHB#%xy+-VhS*}!IG)ag^c}2PD~DDrb4<{ar8O{ax*$tKD^t{w(|GmV{)aAQfo|Nl!*}shc~y=}0$k?-9i`rcNgyDYlfU-w@zb9b|LH*0sZcGsEiPk6?Q zAkrfNS#Vd6A{582dYH3^yL=Zb(xW~NkxP&597LWy?7zqBAktI+dM3xrJquHedNijc zZRm=ed-kL^Bl!(^_B2~hv-Ol?PaW!MuAV-(*BkiUUOACNueNl++k17xXZ4bS?`uVR z$)MK<%wr*oS;h)hBadF|ac8efL8Nyaa^sD?&DGmJdM{!*t60M)>_(2g_hMJQf9C*~ z`Hy=%pPAKEWjK4e$H1M;y9-`%QbFr8#(utZ@;qGQ@_SE<6U~tmjTGM zpI-Hwgl`0iR{;19^u_t7GQ0wU=9AbTE^ zjhwh|ko^oQgqa34K(>Rt(f7q7gZwQFYC}8B>3d+2LF@3QLH0A)n+AK+;L0?i1+DQe z-+hV3?3mDAkdHg|atL`J%6q#cfoLwxjhr2UPwtC3TX z!$_Yuau?s?%_EO<3p*MWk7T4k#-n6BDl_^pDhGNnYCQAtS)-P-67!And871c)X$i2 z)L!H<>J(==&+{NMIzS$yoMpvLRHK>iAjh6T55x8@-Tt+Wt1@ala4(}Q5 z-qG$I?cUMu9c`bZy=}C8`o2?S^!*?*#yw-?KBhi>nS{?9;|*i3KH`AEO9Oj{eW92p0U1QxfR#s!p zJoYDcvj=yN{T*|UHTT$?L1bJK{CC3lN+RP1A%k&x;CmgBao#!3JIDQjjK`UEoE?t4 z#{(YmB#6A9l(a<1Ku*m2etrrf-%e2&nC9;72j|K8NGjzD_rL> zI`6v-k@5CBJ_fmIjXsZ`jkk~gm{0KL@qcjvS&x4mL?-CN1bvwB7O6->NILS;i&4DK zL?$EO31*w{5ptRE1-mfkghQBZ!hgtQf*B{6al(rrGEuG*n`+jnHIUWRI@Cj6Q+pt%sdAbs zr>S-{)x1-uFpW*@$IMgBI@PRG%{uituY$-l`Av&KQgTro8BHrgdE7OvK8?o4bAtyw<{2-7$gDh!WG3dBWu95f zG1DwNnze&{=)tT*{L3*;;In2u#pld^gP6odzh)OkmuAzDM(Ee5vni&vwUy_@0|M%b~x9JbJyW)?#Fz>H+;`en8o*A zB6DRvPcHN9XI>VvqtEknWnKZ~G_M$q@UD5@<-0MFdHOQXe$_!x%u<3=lN!y{}pDQZ|3=X+0OywHveW2 zSs<4Ma$iu8A{3`Qm5|MXYBa^&3kEO-`&i)K1@2w2fW<6hC95&}g6BbGVTcSC%5z~I z>~*2p7xrNsa$mTDjch^A3qR*ezUEtg4{RHGf;ao@7O3}pnP8OvNY^Aqk`CZA>UT;|SY*SWeQq*ossd1{tRRk=3OzK ziLB*U%)G*^E6lpWtScVz1bMHJ)5?VSds!);l|_-u%2JfY9#`7O$_6y1DR#1QCw8_{ zPgZ*SsyB&^H?PWqPOQ?2RgGwcefoY?WK~ak(~kj+V=3#{$QC}~bG|}XR{gwmP)$&~JuGQJeh3>4D&FVVT!_2GAyxPpG{hhCFNo$6)k{`JkMAn#nO(x1wpC&Y? z1?F8dlF`U^&HGHi?$)eAFV<}1BXoO>dDnc$514t)>mah$%xkkE-?h2PhkVz{cWnhK zW4CK{Z|xd>=5NlTQ)}&OT^!!VTi1E(x=QH4I`3T95N})8hIVv7C)Q149t&B*TGq1( zIj@uNxFF%?Frw!>8!N2H9@d#W%=z!@r#2JeRnQ zc{e;jUK`E4u^49FsDB&VBA1Pw8NeWhGJ;X)-o~Rm4I-Q3lL|R+(y2}Mw5b-}y2)EN z4aYlu_bsw%D&Drq+cqs?2|BUqC-!rIzc|JTP9x_{^4%Plq}c0b_ifHVX0o9xn`N_E zA2)Z$U7OvtSw5TPv)P@S7qFORe8tzuX0z^X{+VCc%RYX`ome_I;TAG_JIo$uMr z9)82TTdt!ETV%WC4)>7n)wO8j+Te?(SH0cXy|BNbY+d+(+ML{+{uS z@%OsEgLlo9b?#)QGM$+$XFq3fe{=OR_bT3+>+a{;K=j(U=SCqkC=U1c#wW)(!nXjAq?s2}n^L09ZGy0jY zAOAbSi23_C$Px59UpMo0GhgQUGS8QJ{<|PzK|mDJQ4;sJz#bRKzQAr4T;mz9c+2}B zVxhbXGmr`0F3iFw=yzc$Do~lKxb21VE_B-q8zb|=8OXfQ{Vmk*!b2QIzYF!d@CLWJ z8$>K}dyBrN8NbjEH?_!3Et=07%(}>|i*DgJw#b}|UIY<~&9*oy(TRzhSe%Q36s9Qu zqb%jo^J4uj?nDoInwl-dqxc*nCV@bh9J} zxyeg@3Q!1dF6qKVHggfXS(=9I0cNsIUPeE$*ygogdF!%aT z$WB?xQ<2J4#oOy^QXBhQ|0|Q&#MK~TgAO-jz}`1h!oD}uKwlf&3>oLu1^?#*TER3vOiN zV1{B}8{PRvyV-a@h}e{XbeMh9SCqiao9d(MO}gGRjB(h@rpe60&Ntc7riHjO{~OM`>dW4m;do zhdbU8H%^kgW* z@y<@!cG~aGztQ2&b!;Y*?Oeb+JH4~>F8}f{h}ac_bYvzAeh0g9VVAo~Qy25>GS4o* z;a%R{)rbBJ!d$!TZkOHdGT$!q?OMVzR&Wx1?M}dFRK*;-b-dfRcKg=uek@=IdpW>S z>~Hre{{P><;%yMIC&0b!@jKdMe|r*>i9%FCH+$M+mwW7Tk9YRi<(^*jML&C{^A9rb zk$I1|_t?oEJK3`wZ|-sDds9%D+PK}lI^OH%_PWo#i!kTjt;o9fIA+~@nzNkeIq!pr zeNl*x4))2rFBu;q^S^OANxi!20Pt1fl26R-^(Cke=4$3fO1s8p7#HU zS@)ZD|9H%~-<(Oe%{eaP%>y^E(}PKIa|d&gm;4k&?+1%g1N|SY zLp|g;*aTS)wqOV|*~+aT;!sRNeD9EZJEWsSg=jz*`p}<2==hM159#=jz7F}uA-g*y z-=Uk_K_`do(f?LH!v9u2;&6O2@g=qR0l5y#by%*$&9R5WZIJEoAL!<=w+?&j@Sk|= z@I)q~pTie}h$H$w@)4zIgx|)I5sc+8CgARlY+w^xh-5oExx{Vm@c?&nMBXEIdDL&_ zXavQO`KYW%Wj!kE(ROs86TdKk!A!?*;^;E$^5`1e-_hOd;~x~}NCq;KgWTjJKmWrm9GCa_DD-n& zKgacX+*`+|F_YQo=J+o5AoFpVkIQ`AJsv;7DV_xpCsI+EddPla5^LGZA&zn!c~89H zKXiNIE$@SflXiD9HSXf%$9zIwcnL`qtSLd__$f(3ob(e6|Cfko&Bz&#p$k zv)kCoA?)?6j?SJ!*XQ(m&Mln#oI-qw@1HAyT<6O04b5puYks0V9qG)kbj6$J)^j0< zI3I-!n9<*3h&bN{`OeFCUcU2#7>~O+KN&NhpT-O}VE*&Fal_}2Bk%dMoaa>#aUlYk zFUWd9)(f&;u)hnHsY-Qp<8M4fTOy?iwFrS6k;llInAxU(zfzhZA!4q#tbF7aOw zaWw||y&8{%q$M30`G_po-__pO&sF_iHT%_L*v(ZlUwsxtT#H3qGLwVc?L|Bc@m#P1Aa zBvY8iOlD(-8%KB*MBKE~n`zPQP2Jx7l$`kXO<8Z+=S|secEtQQNAo9c<>n-&G9AB< zo005b7xsE{KL_#FO?$a{f+s=5E%$Rv=38};_tpg5#jV}AgIk9=iu=7~hqqqfCT_jv zE$@Sf+bPL_z20^Uw{?44-rM@PU6AVhg3PyNy)El)S#Qr_9t&B_Cbn{xTioSe9`P=S zxbp$gh>70sn8OtYi&lzH<^gx^q8>xa)@Ry4|};NKS~o-Oa>Dd`1PnqZU8V zgyz`$-PZJA4D#OHi+=nal8C$dyz8yIZtm`RE}@%y0a1|op3L`TzUMb|F9C_j!MAka zPh`J$oX0`L{iwtuF7c7~elGH$+xz(`fZg4%g1flyX79V%`z?|8ep}ij^ZljBeE$^s zy?=qr==Z*U??2@QcKff}`?nfDtc4F3l&HC?i+`t2KK8TLl9wa6y z$#D}8+{A-ol%+hCs7Y<=P>(hYU^w1;FqSDyVz9=;gVb z&r71?=em8~9D9A{9|RFE;$gQh?DmD6FFqtC zX^6m{UwHFHeR?DFi|t$sB3^!g4qw{eOSk(nEq3@))|bU7K`C_mvJ4GqNo(5jEAqbV zK`&%}xdoYD+S$uH+~*;0gNXkEq7s8xmcHd+;4RJrVe)gW(dO> z#Te}9%_`Qgjty)=w{LX&#vQ!5fo|SBM&36sc@;#wmHF)#$o$sM-|F{mQ*`jQ6L$92 z&ffOG&fd=D9B+e&clv$jZrpQc)>&^ho`EDp?d-oR;n8bXxbAZG6 z9ltxzMXsRdclv$*6_u%uUA?c3-@$vogZF+1@4F!5d%eD&%ye|}-tYDOLKd?d@4WZU z`xEH){aGFaVGxT9WF`yQ$U$!MQJzYCOEqdxn;)o4PsX!~^SlYd50c`0ALOSXg(*sL zO5)#qFoRP;=`IX=3MPK?e1>cP_i}@^K3ER2A z3tsUy2%`o>B?htaZq$#+%BSQc51;WlHEGW`qyE)FAajFX(^c@V}- zh0HN!jVWtPS!3E`OnZ!}mzZuTW_^C8KZE$4VR$R1J;t2IOzbk|p&*PEg-m>g@5QP{ z4Vq)dSOXct3>L7MWvpi-ThMbX{l>DlSWj^evD`y!cMv-U?jUwtbQ9YR#&-L$bsD=B z`iZTd*xri$3tj1sUB=c;Y~93`IkwEPWsW_U`7C5F4}vgGV(c-F>~ZWS&T#(bALcL* zdE@NoAi9lnl;h|(&O`p=4ex_6ZY<=Dn}9^f?C({Dab=F%3H`?XjUMPXu72Z=WDI}e z_ToMc!gxu^Odi}+JU11uCQUGFJhR3d%_PhjZ#rg+w}>Sy!%f6H%QbFthbKJaC3=pp z-}tFXM@GCEUmx+mpa@@4hFa960gW(2{9g2B5N3)02Q%1!x8u9V_lbQ|LL-1zz(u z2oncHAv)ep9EW(gi^SecY^KER7{hYRlK5c|Ciwt&pTtZ_+)?cV9 zDq}B6exM%BkvB;j+9Gq3#mJoG1gAO2Megx{$2{Xj5GK`6(kgVoUXzZ%K9kO3HTId* ztVzw9^eN^{X3k_$F@=AhN@kbI>@rzdd^?$*lYK``nz4*+$e2v8$qpc2 zGWn9pmrTB7@+Ffmc`V}NjpW`){wcZ9N%DderU<^D{CnJMa=T1!m&tXL{5SNSd?9`# z$@QLm6>HhRW^|NXN6BSKeueAY;x6}t@WX_Bf|)*S#So@pjt_P8;W~Wl!)xd#gN{lcHgPpOKQEOw$Icl$W0N7;a*aIjki+UV`}%E z`UmVX^#ImzhP(J)nz$q&9cE1P6(#td#<;OGE$P6|{DPj-=r@hMrJ09&NaG&TxPvqs za0h9&qMI~#f-tSTX?2=56Z%Q3pS0den~S{UN3UtCp_{ZarE`^n6?p3@MhY7 z*o8et$R1%g5&xqmb*N86r$nBUQF#4HxGjFoIc-Uz?Xh@H5-FeWmGvWBvT zvW5lu0(%XMVz*&aycKrBK12Hq&R51&&A`O|wp zy?aTo@AU2IjNPVpkN)0W=BnKW>G!Z7H<|t@C-83ib3EfEen;uw1!0B{h(-+D zXa+mVV9pE;7=RsS&_{*?_*Mqr%5W+OGv=c_`p8%lH<+<8&1gw0beYkdnS3`>Vv^xE zkjbtxxvxwglNEc)RGAj^$4)ZYNv2`gNv1KFEz<;6vksXuxrIz_A=5V8LZ;p9*o9s)+ehYm{L4e^C9}PJ6d(KeC>3e(-D{bUN$@a<2waE-S?n9cXI#m3&VnLnHPv!y02 z_LZ#^-%^bl)W%!c+-f#E%+{9nxUp>e`4>HW>U*E2BO_-1v=~+Sj-U92uITtv9e+BA z-}!?{+~yU&l|2g4sE7Bm|BQd1y$j~cJ`V3^pUQM*vJv;1-F~v~A9*53j~mXDn|ypuAqu0PJY!jfo6mEcTioSM z5a!iuUbE&kYubBeS0ZvNN!{p5cigr7$t8Zn7YT(VN0 zHjHEmhq%wXAS@6S^A(6iDzcHCoa81ipWzk@e1}d8{6G`rE$}0)k-5MEWG--&6P(5# z3+SSN9t+rE0i6_Zj|JUf!Ai8H7xq)|Z)UIpdnjnuf@UrF2>lf_XQ2SI6^cg!5|NIA z6vr(Va*Ks3Q-$j2xsZMf*;}E3xQ9aCE94FejmI4nnu2Z$?c@^P`oddZ=;sUleBsS6 zy!k~!l8_7Ce4(2!KBo}w?~9@oqXhNn!%TK_D+mkQP2tSs=L?GP74jBtfLkc6+rrIg zfqo13WhlcL#YE&SJPmynmbvgXWd1S^@zKkdNl8y8KIRiX#qE9BpINNNy??3aFWuCa z_Vnd{L0H7BMa)_xD|s+ykph^lNJ&cbKiou-pZJBYbY}pA_#HhL(QlE3EMq0!ETWGh z2RMv-DI$N7+jzgozd`74kA_8MC@MqIWTYS!Ixi|mQQZ~QTTwk1Ek#Y*F&JGH)m2el z6&=f8=&Y!_D(dZ`>)60%A~Ao_op}GNsOapgud#=(e#7^^8p#;kOfmZ|RtY^8tHBT0 zbus%Z)`dRkx0nu!`FF+qyJF*TYsKc{wu|Yy*h^mHcUb%bqG9ghc39jFi~B7W&p|Hi zptv0r_jYl&R=hB7r+962UVJLsxEh2dqL7ZeC1_mS{##?-v_Y38cXJ0l zl=8h&X$UcMsV~uUsVev#lx(I&U2AxL0CEg za+j97v^Pt8vvhiNTw31@Y4rQZbM*BL2J zO?>a`?)0KB1Cagep$uam4}PV~G@&J}FD)t%H9paa?yy7yyfhmTw2nRk<8RW-{rcZuX6e-r>AmyDmNV8 zE;j?;E_alNJmES2q4#n+`X&lG`o?#^@!fCS<~N^^ot*eheUp#;c=MZ1jAK1#c@>1^ zQ;?M$n6G?ZN>YvQu-Edn`GLB)&+$$(xl5 z@g;h#q?<~*sZ^gvxW7uxX-O*vu>iMT=}8b)PJ-Q3u1Gx^(~K6#TX_g>!QaFUE016l z`mMZ>RjkE-uPX0A-pc#XS7n*MO@PebentWG@@)~yQGv=-r8;i!+r=E_3hup%o~yX2 zD)v+*6K1Vq)+$x_9&=V{fZ3{;t;$cd!%bBAi)qYcHcME>O7vVszg13go=bSMiax5m zA$%714WvE(|;*><^RpqFvyQ+GtDofQi^kxFf(N$GlRn=A1%|xQJ zs_v?)x2s;~7I*oVN61qxIk_lLdq!ZMYHQetd#UDI)$Rmg^{B)nA@*854IvrGL`~XZ zuhqMur|RyZ`tJyxy|qL zV(;I1^ShtuL zWUg@nnQOe^eGt}+g8Qkdi<)|@X@@m+QZs_D`Gvoji~ZEx!+tJc4>iqN%dE9hW6oOU ztn~?It7W!Y1t>%r8sH9VwWck<(v|M$xt4xw*;}n8xQANatK|-AMdA)>?Ls%T9tL6U z*m$e9w`%LBwti}Rvvz(8QW(9~)=h2Q)b_ir-4ORz+i$ma3w~rE^EtrdApAZtcJsa8 z-uHEBL{pk0@Ardo3*YPZ`{9g4zuzxlC2LsEcI5qjFZ%jk<{#oC^AGv>9KHPTC1oj3 zC8|&jxA(&$4sjXxUPsS$+*BQVs*@43)-h|HZ>fzr>(s|=b<9?$4Q+7~b;j{GGnmC< zma+mp*U@jClbqus-mIgKIxl#Id#Njb-6VLwZVGZELtPo_7NHm=(0N@s>gukp-s;Ly zw>7;O&oXpXS66j)Rd*9x(OF%0RoB~fuW^$*+~)z0g0Nmva!?Ml)f>h?n4z9;)$^@- zTeuyB^`npuUDf}Htb9sN^58z}>#n}O>(@Ys^>tWZ_WH8dxA*$;*B{R7AZ(C{Z)lG> z8knPjHye1ff&2~ja)84ed}~P_+2y}imn>V*?20`v75$on8&doY!ZVk z6r?mY`JPt%ir-cfJ8d$XB`n9xO*W(BCT^sO%uQr%;wGBBM8{41cc^Jh;t-#NWI*3d zWo@d@rftzpQ(ZRoR@2|;L2vZZ^lxS$b5og{%G`7zi&=^{n?4D`X70aPA!KjXnbFK- zE(=(Myv+`y*Jj5##Tm|_-)8bQ|A1)7+dL6T@$Ke$sg8X%_xS!{4&?L5ri#t(xNyG(L;-#jAAUa&~*#lw%Ef}?xEurkI`|9w?Wu4 zAPR}eMm|1AA1zB@r!C7+jvsKpE#+-#pDp#-QlBmDwWYUO+H1?TY(O_H&vOx(Tgu#0 z=9ag)%l#nyF%CJg&mTJ?`;YeW<3TQQom<>N-d6E2b1PX}B_jo?NW*6op%{LHt;$o0 zDpW)7twv*?tz>K^W2?^$R?xOXJAoRC-!#1(W$fuaOO&-4BOTNM$+vuT93v}GZdu@K97kwGPASR&i zHhb_^8{M?gWgBm{@n)On{KuOh{7E-I>E@@9^km{AvXYJLc=M;$3}YEbcoc+f6OfL~ zWZ@I!ZTk%s&~4jqsfycf+XfxC?Ls%)c3XMd{>~rB-1Y!6w|$CU+P>m#5Vng$d=inA zZ@Wpb_$R?1ww-I0U_R)KAAzj78>-{@c+}=8iIV+{qsH zbCAbD_;W(+|L6P^q%cMKhKhVkHRS%e2TO1hKVRix5O#`+d+wA1vv(?hyXa)rPWttC zgu_ne>+~b7vBOU7=|x{A@egy*bEg%oVlC_0%QbY->Hpt*f?MwNJ_tKUAsQc&ozi%# zvz>Of)6U-P+=h1Os&i*XqnpluF@ecUWjZs_eP?fWz7>SO#33gYXodUzWjs@u#th{B zWe2;^?JxT{z#(p<<6oZfG6;YD0C|6nNo-{PwJb9K`V)Hj^=E#;UVk0P5dL5|Yq%SP zUE&de8|zX8_uR#vy10!lX6<6uE<-VA7jt%*h}pWBt;<~I<0iTs<2;wJ&o1})mq+Ni ztA4wtAv0OlOtdb8_n=CKgHcGXQ+-E?(BU5|5; zGo0fBuY>TnbQGrveX*P0HglL0oaQX@{`MBP&`r19q7ohbc1zDEWG5GHyPLe-+;%s8 zb(6VUPh{@q{<_UUFWnZgo=t3JJ3DcE-7`{>YBWI4-Q84od+I(0vvxOY_igOQoZXLN zw(e%@ewnMdi5_uDMha4siI2#No_pxGM>#4{1#kAyM~{}Y#=Z1#Cp|`B&ppi1V={j; z9W(UUf-F6Dvk%?(xPp#*db_8$dwRR4Tk5H=o-*|On6D^7Y5s>CJ?*(?Wn}4T?w)^O z)}D6KQ#ZYI-YX@()yubf>8e*R{9by^VlE3<%my|SiQi7IT|wB}&U<^ScYRvW3N!XL zWACnXrza!Pb8oZt)@kp{T;nEpxQ{%&-EW^nBq2Fw?PJzHY4KK{44Ai%H~TcEKQi{w zRi9fy*f%;Kl7xawPR=9q0N)>=p8=`R=>VM$ zu=4>Qk(JWOJV0iDi#QzM{Q=)njqi|UfHw!Y+X3s4f55vS9O!-qns?wgm~&uNs?(It z{EE2;>UUrddNH2q{KFiUBJaS}tmP!Hf^d+`gJc~f>mXSNeM$~;lb7PuMmPQjaX3gX zgWBS)L3TOFE(f_2e}_06w1lfcI5--~@x8(MDM(q&I9R`f-SJ@iAME!scm$)F#1y8X z=fV0NypQ9Y;w;y=i8~o=uY+|nBpLD!(dm#1=x2z2hIng8EqMn`S_ede2M(SOYl8)X+UF|p_k#UXv1*kvJ?G|h=+V5 zWE$aHBYbN_QFJ<@JAJVC5q3Vp?Tzs7N6bO)5ps{v=?Gnp*oJS8(9Z~a9Pua!N5&xw z*~o$1Bjp|`_egJz^w!8)$UIW!k@abWw@2FNNV!MKJ<^*abv07wBcBA}D4mYVLq+Og z&QazZ)q*a_I%+7xu)k5Ga1Wyv;@(E-dX%n5?Lgj9`#8YeARL_lnMcbyTGr9Bj@Iqy z;*{cRs#BA8=xB5=`Z54}9sMWcnZy)!@hS+%q#-+IA5)%6n0ZWVdZOzw6LGU+-0T=P zJ7zg6S;IQ^px-fWW6V|D$C&55=3Nku4Tw!f%rRE?W8K|YcQ@9K$5x;UW*A$WI_Pk0 z2Y$!fW4%4r+hg@Lb_p_!)!W!Z9OVS3Imbn=a4iV`j6r&eV2^+H<}c>52siVmZ~ZC% zpHF!kgyZBL7nOJ<#BRqWqbv>ikv8ahTo=006W<;;8s8ol$tCnL?gqEH#{(YoEC~Ib z}SF{HgXVq zm|)fkW}O%pb51np#MGE=qS+>9B^!mP!uQmr0WE38Pw07~ekX3ie}^Vs#%?FxM9ztF zPLy-v%OIQ-2YpQP%}L);iyv@Llk9F%6Pja(lLjLHB)`i^!x)MEP5P6+FxMn+PBP0R zcRX3glZ#UyJD>aqqZrFL=CGFa=wb3^wz7@$xP!^JxrhBvmUr@N-Ui_mnWq#%<|&P^ z^C|kBqJt^F@*8$G#m=VmWdRq1aB4teLh|q#rP1e9vraYZ)Lxi#syU|)$81y0Hgz&n zS;Q_5bBvQ*;tJQ%^Hlx*U4p9AUhTJpco}s51?T~rK&&WK(+cUb+13Q{AnXS0(nX$;i*SLq79dQRU z-NDT6xYwDo&YXr>Xa2)%<`T(14srw?%#?TLWv&L{KQjN537P*XOL;1xkALdXkR~*z zCHnbiJ2!X{gtMZNg4BFULCiYKth1V7H?zz+%Wh_wZI;<)^`$>!SjZ~YvVk4!VlR50 zrQg|Ua09dR@EM<@-`O>BceCpw<7^pc%Q(9a0~x|_WS;G<*>lk8Y#q$j!E7DO*6(aL zJ^K!BaE?Ca#3nBBNkmeTW6n8+sEWDfjAaG-opT=FnDhVNc*ql;1>xL$*w=lyw^`2@4iGy6QV&oleHax}vJ=jn7_Z~9^8d1jvX z2eX*V0v5B3m8@YM^3Hn^g!7Z}1+_5KeEXU2-_IYxX#V6cZUo_iuW7>ohBFEsESQ4Z zTQC#vE-=eNT`f$H+gkWBxyVa?3Q(4Mxc!A=7{>%A^EWf_t%YV-xRX8TdEo&LbCeV4 za^V@wvM3EjXh2WoTC|@1xcx=CUv!dN=zP&@-Ugw+FB~q8LNxThI2~E}l$^-BSVxO} zd+}HNKo4YIEbC%f7t6X>&x@C`f>rF`BKLT}W1a=!5^pVuPAu$si91_juS=RUi1GN| zlC^BW%uCMlFOPz7X&jRBA*slSTUnX~_p-DgeVN2R%waxqEnUqze0Qn;CM>;?brUI3zLN#jOW|rw#F~ zIc{L3E?1_&tSimB@@xF}Z>2d`R>y2B8_~>Wm z>}pkVJ|-WZQ;08-ca`^6>2#G&SLt+>ysJ9X1s$#GjeV|~gl<-OZ#j4Z`)_TyM_x718PX5iDju7r4p|Zt-6bZjg0D zJj}Ym-Zmt`yc=?0XB+HngPmRGD5WQ|pOUVEDmGR8O>>KxT05fmA$NM1MV@ zX+t}@(2bt-W;An=che>Gvq?Xj^ts7fn;!5OceYtKo0H=fHp{$O=FKv1&OjzUq6AGD z$b4kqd?yIExQi_*i6A{0k#|cezDBoO%26J>+tLhov84l@@SE5o@0NZHK;|twk$KB~ z^tbTkUJ>LHw4sn$_R`4I|^?1|rQFnHsZ2 znk_O5pP=8!Z>dck>f_sydX8+(PjqJ(`i=aPzmPf7n~~m(bR&`5Fhk^S&S1ZhS8&sj zZe?2(q7#SsBt(vFMJb8iwta)XwpFGvcDrpX-rF{jDNJJ~X5QxAZQkAH-EDi=&moR- zoEJg3Jux|{hW@wfY`f03`}f=Dv5+M!(3Ud#AZ~_MjJ&*@_-_ z#lqfp>1tOaI`S*O(H%S5CF?F7?V7oR;Wk_jYce=RMJIV|!BbDFrd>9<%OgMqA9e$Nldy+a9y+=}UjcpzA&M zuxBkB*o<4+vzG(d>z<22xYxJ$%DA^UrTCf}G{!r7W!vj+_x?mr`Z18fOh+Gk=dqY& ztibp89>p&GE#PpkUiMz%X%OyntNT9Y6S9+wyyVA>`|NR_+uA3?zFPc%zVpH-`u|u-R!rA{qKYD zKw8p~k&noV&JK9%fVU1*MCJoksZLG2eV`6 zDMtmGqN77@=+LkH#vp!Y7$X^t`#JO=2oEPB17<&59QShA%!eEDGrB%Jg7HjZDsylj zhZo{T4sSxghmUiLGhF3O5FYt}Xv8KS3CMywIg$%=95Kfca~zTXi2O%-psOSHdPGl0 zhVTb+9I@Xc_IpHMNAz`M1*=)hdM@xX2#+R5FGua|XghrG=qSeW7ZaJn-}pDjqVPFQ z(A_cjb*ww~cFeoSrZJP*nEja9kD2}0ZVqsm6P)HOPx%iW9M{2d9UPBAYVuK@N>rgb zHTj;pbfyd4@c!{WxS8X+IPPYS&u0fZKB3nWZsNpORK~YX_|^$?pXkMSRBYqqny*~@;;VFzb* zf6nckb35nalaM6n`J8^weMxD`;JtIzs6lOhKsV?5G6`>;^VT{2oYT)aZ=Un!xqTeu z9{-}7b5D4V8#w0%&b{S*5T5tu`C>GrKQpnL^Ot$d3tsUi2rtNcA;c|Q(CvlHe2jiC z6sH^&aI+U`A@7BH=<9;a7yd@(3p?3^UM?KsJeRo24Q>VDMYngcB#rr*-st(Fo4ROE z7gu7|i)Oue9dlkZ=S9EKi)OoMwo6fnhMTzLCNAZoAce8dOaG%R<*7&=I$^JuymzS| ze=vg4jAb?(If=I}>F1JuE_w5EKvZH78{J&i&E-$YL2mMrp8^!Zo0q#Vk8R|YT`x9xBJhF9G7l?ljv~_(i(Yh48twl(Cv*e{E2>VEM*-V z*@D}?A@2>heM4V29t7ddB*=VI)|;~4l=WswN>he%)WTkG>gT5WyQ!C(0~vz5ziE#* zC*yZ?b2@JS=DQ%grT<%Q>z3JXRi-LtzSRylam!8In#vsJvxwEKWdoZyz)c?Vgy*~u z!rM`Zj$65%id@Khy9xTat)JWayzQ;q9qCLLbaPubw+UocGLmZwh9+ zH;)A@!cE*e$tA9Gg9kj~DSE!I-}@n1$cFdse@-F3q$s+%?>BV62j05xt^4}9ub=zg zyzkBX3t56*@9XBiZtfrF6lXZkMK1F$2>;DUDVj3?yZJYgW1Qw37m)WsfLnN=+Xpd- zg?=AoB0IUrOJU@FP#k?ds81hc_P2b)2eLkp^}%vhv4(Z*!CoKe=YjispqB^#@g@i# z`fuq&dwiG>zoUoAaO)3$LjMol)T z^YIUKXBx6UzQo%ge3F2qd`L>O!H~;fx?B`Ap zzA)npGrjm4-+N(yFLd>y0fU%^+kW8|U+C<`T6F(nGh6YEmr;@LWkTG=OMSi6*UJoK zB0u_i=?-7^qAzm2lsv1-g0Zt(V?i>J?uxXZ|}tkgSxZ401)4E2>;kt5Jj6$QHE= zx{2zosNRa&2X93k$YAsnbuagWbkP!%n@Y5z8@=hr0LC$gc`RTNOIXG}j&q8$TtnVy zceod%i!O8Y?8qFw3c8DKkI}!UIX}{dc64AO2Y3*qi{Un6#7Cbo^cmwbieuIoW{uI7 zUomHl9+)kL*L;c*V-DdDMz9dw#MDj96|8108`#7aE(GafMZvwrDnm2uCf0P8vxfC- zMBZ4Ja0{_?8|wzQ&~NOh#3La|aC@=kjhz8~#V$r8WR5LsY*}N=8hbQj`HKn6B@*`+ z+x^AXOYGBlEB0;dG4=x<1?l3XraZ0bj_<{p%-<}~V<7IkSrQ~c)R{)pd8+(G<~uH%{`t~uh$A6Ndk=eUTj;@WFmJ;l9? z9P#Wop8dx2ZoEV!#h&A(LT~Yk;HKhrWISuoN4(4EA)X%M`Br>A$N!YikT?Dpl;ms5 z@(n%ti)qYcHf|#Ra#rEn@%Q4}@pY3R1*wT3J(>8JPson%Ch*+^6{$>B{Eia%9VMvE z4|p@dB=n!)YLG6W`%0LBqEw<9=1W+MmUN{XJ?KRr+(<&ZOgIajCS1Tu4mqa&7 zQj!O6CGl1g{Up&(5^pA{Lwy>d*Cf5sO_Bi&=Km=skvhRIxpX|#u#xtJxogDrDXa5pSWjZr( zXQGol3BtswD2mx69>{n;VG7fbH}OX7LSo(eE#WZnx9B(VZ(QUuzV*a+kvH)p^p!;B zBn6Qlh2rqo$#B$VbVkV#4*lrjtl5HseY5b4#H$_5es)F(?_z94A_@s@+T{X`;(QX z2{I&;Az4Sd&<*>TOb)*(946CSGCe1o#R`7lJi1Dzt7N)LcAZ=3EV;e%JHuh}xWp$B zNlAe`$xG0P{>)(;-jnMQ^g>HPE*;9 zRQ2(`R88p0FziFBQH*9RA2JW$O)8zHTFn;ZO|^sXImfFYOf7S2SyRiJTGrIj8vUj*w=`$44{7W}8heoD7WN>`{UA)Mo3zQ1H?2<7)<_G3X|(%xPs#D|6Z@OvArBeq%UHdxFP7n9dy2$)3(^(hXo7A2XS$$eV5ho6v2# zZ`h80)1Bl3m-v%A$eZpV{{&%Z_re0m9LgHX8p;}Wqzk$Z^%M?gCiXA1f1zH&mAEVX z7IO@D^8>eoFp`#1)W&&{-t@zqBHkGJ8aol$#X*j6l+&E$ck~?5Z{)uqO#db^iH$ze zrz1TXkw1M=O5o1)dP?uk^!iTUfzH^^^mc)&kAMZV05kSnuXndQnXPiA>C=OG^zXhwhZo_PkJF^9Pg~VMovl~b1plTt2Jhy zYYZRq5!29fu9ea-bC2&3OX#%R4pn^&|MMHfPs(awz4Npv~%7_G->Jx15ZJ<)oJ z?uS022jh-tbM!mHVYE)7?ML(?%rJU4dpU@1qJQQx&x0_xZgMBX9Q}@Pm|I7FM>x!_ zpWJ4dyDa9C+gx(HKexVe*P$K*FpJ!)uqV0y4#GU%lP3kgv&=J$ zk&I?6zQH`daF*ZsgB#q&Eb}-!?;AKfZ(eFqmj*P(4D+_64Q80vxp_Ze9A=RBVC9j~CwUTt`BI_xd`-}4zVUp5_vM?$LN>CQt!(34zT-D8qEo*a9Ok==y!jsSI0*A6 zq98Komo>kv`DM-DiLU4+zj@{#!7LVGNAfRc74FJ!j`?@82eZt7CkP9q!;TcFgYydX zp+EMnfHxLc%rbU!h@Uvd8P0J5Jr~e#L31mZ0Q*qTJ`}VE1v6j|3T8z&1#8m>bGbi zic<=A7S%`5Ml_{4@)zxk`-=`@Dl!z6q3B!|un_xLRF0y$^IO7UQ9T#^iA($&gvIP( zFbsqqAZqad)xuRKhn~tOm7_r>iD{U7iFKUdaS)bFNf8>O(~@?h@$XKVYe85x z4pEq6S=q~)P1#j^#~$`^0C~&a;1;?qdyl`-Z@G6#LUK}(5qZmHCnqwO>yFIjrla3- zpX1-8a{4W&-*RhM&qnNC`FKQAni|-t@^-3xe@5f2<-N81I=11R<#*z3<-M)^5q?I$ zTLxo>Bj=n3r4#J8lNR9bcG~bGu$Vv{%Q;Dj0cg5P&qXDv19Kxq~ zcg5fMCkQL)zfv0XUCAsf8H7~=yt#^ZR_Vq> zmZP&Or#R0=F7Y4;tIAr{+^WVTHgSkcX6#7Sym)I>bE_(ERUKBXNIS+Mb5&WZ%34*{ zs$1E{4!-9nuJRBaRei>bAgt!DYPzlV9tlZI33@S=uW(+q-R$Kg-dN2{syz+D>Iq1R z*;Eh7MhO+49F@%rNZ!Q0Z)v^<{&SH;h{lOKy zv6eU1x*deIV-p9tYR4xL?yl|KwNsKBch+vfC>F5?UDbXSgmuifj@i~pMhbijb!4rh zqdI0(rwra%rvfeML|1w+5P9niXCz-i4qd1JjO>{LB-s8^Q;*r|GLXh%o% zTu;CCK4KD6G243jsJ9M#Rc{O1uv_(x@CzsS4R5F?f4wLC|8BcgKfwL<(~+Jm=&ycG zbY8y+ees6+_PYKs^i+Q|A262%$WVU?%UQ)*)^nUYLD=9OystqmyrqG6G|+hi^K9U( z2L7&rnKn4g&&b`t&NQ$y4a}jzg)!KzhLf4b9As!HL&Jq^;t=N6@O2P2dV{x# z&AYruLhM(gyqH;|LKLAmB`HHW>`NneHX6q=^x5cE5H|Lf#(HX87(3RuG-atrd%Ul) zSvBrTcX~1&^J@GlvzU*(jTd7#8q3`H8ZtMr6HVfih@@m7Gugba>sYdVE_Y-JZe zu%Dy+%1KUf13T3$IR(&9vtsD9nNFMeE}FTsSyeirpJw`Lrk`f+Z`O~23`Uk_pW$uI z>_GE?kWw_K2Ys=Z%?II|Xg-@Sun*1k+x#mQv4ef+sQF<|AaC=toab2(wn&Z4Eo5yW zYYSQZo^aTrHg%~_JIuDlC_X_iEv7RQvut6OEtav8)%fOG#v&VfZ|UtVo6-VrZaIv} z*yEPw*m5IV*v20Aa)5)JM!zlZ@;48Iu+^Ky=3U~EjI2cATWghaS*n)Tdfn4gyf_mEoRg@J^E|i5^rp6 z4z2A?Yn`{gjU@F5>D5qaB~ zWm`Mawm9b0)_>d9f78}~)AnP$vF&Hf!8_ZoLBDN(=U-m(Itbgn!Q1GyonG5{XSpe=gnB4ZbO*2Vj~ zOk*DA)#YpC?y{U;gRrX}x@Mvv{m@^<~6UHrg4PH>0E zcyremLD=mrV)72=*G&(8TR7~d<8J2H&3)afQ;WLTiEj3;o4&iv#9iIo)lHY(zQvv0 zcC(iQ{E2S5>89H)>`J%$Jmepq1Y!5Y_%^!Rv+g6A%MQ+PlY2biQ4sc!w?|TvquU;- zNsE4a6rn5?sEi%%A#V>m+(TbIWbQE=nS1PH4|?hGBPTh{IWF)=5cZ5sF`CnZq3F5i zRLrU88oafqxAwFTJ+I=OJ#XV}J)iO~FM_a_o#79X0WF|kGg_tjJ1l%zpFeeGXgz4Wa@bVyXOC9i|9{~Nr^dnClU{WDV>-SyX9{{alfS^b^W ze>5L3p08QLa#peiUG(3`X13za{`wf;?E^~E0$mQUuLD-FmJMve&JOsE)12iz7x4Z8 z&w_AZ4BjFZdKf70z+|LArvsZH^FUb#$~sWiffM-z?;mJh0~fH3{T$>7M{(D{i(KX} zeA|QKQ8mWts&KsE%^Bb9m zp2#`!1I9A}os2w)PDaW%@;G`K`8SVvhPjS>6@;VAag=UHr9<9P&L5SH5;UY2ebLLP z!T5$ojbt=)ka3i6XVgL#vy2t2!u_MJ2jTm^&G&Oq6>odrdG9;tedoOIocF!;efdT= zzx2w`V%Izly&HT^cHrqhkYEt97f*@LcaqXj>$w;+&v~2`Wlm;LKH>s zW17;OmdG}y9UbXRS9CgNB|o9RvGLLU*y^;v-i+-)C-gH`*0CQmiK$Fy2CI>G>^62F z@7NzXjI+ny48jlMk{RcJkQcl9K}kwejtbb94|<@V5A^fF`{?fjcYW|FvzW~n?B#I~ zerU!Y>fuA@eOQ@lc=Lx{7>@n<@N>T6Yjpgfjz8SMX121Qi(KaxcX`6UyyU+i9G8GB z$U9Cq<65K7arzwRu5sP5Pvgvg+!Usvn{hIalX;xXwekK5z3GSDognW79Z&Ga2|Avj;|a@I$##6B z6V9XK3766Fgge~lK@d(1NJuKu5+MUQG1rMTsYgSaVV@`Jf8r2EGMaHr;A3<)(HkcI z!U;}smf!gUy-$3>e?jxGAIBp;d8tkpbn@{UbpP>hoZ|w{`XnYHdB{&8 zic$i(KdD1~8qt*I`1?ujout=EWvPb$c9Q>glK*CsekXa~q_&vTB(s^ch+X`E-I;U{ z^Pgn?lYZqSx}5ZgCp^O&C%p>7$@-oA2HrW@os%ol8MB+b61z0{8c%u2>mZyW-;_jT zBr{pbK@`#0rz!GI@wO@6Hbvek?dXWJr+mmVcH?}%3mp1g;Lz^^hg0mr6#Y&4gL}w5 zRrgbqV+W?D#STo(gg+O4Tqxxv3dIL$n!r6dgnv9r^3Jgovc zo>m*XG_3*c8NoOvppR)YvCGrGU@mJh_i6G@dyYP*>vQ^>xNG`5#Kq1`*Ufa@Ot(AJ zWu7kcbeX3YrzE9u=k(E-=kx=}{;9cqnx1?VrWhrV_tRFiLARfFpc7pf!^cc!8gr2M z(*-PKCzp|VhO9GWogwQCGo6tXUC+?d4Er#nEVZbMUS>4LT{FyaMmKuWo7o)ZHZOy4 zrt@Z|A;g?!dgDwxG1E@W?7={WFq{t=&qVa>H-N*LXL*P{o#|Vg6$5)PD;^1ubygvKVuFn`35tZ{WI6N&qE%g<2eELVb0qmAs2-x ziazF4qzcukNo&k;&Jvl(~I`Ihh5%?18IH*;j3Bl8@Y=iK2Qe+S_g?))Mz z^%;!pUzp1m=JLg#+~78Mk@rjA)t3p;?UzYOj()$)M{!DFf4{7TykFL#9x{LVDKdY# z4gG$(lRfD7OZ|R%lGB_G!ntoyfQI6`dh6U%c;{U2oO=~- zo9k_JAMrQ{=h=yQX~{x%q9{mVilOIu`kmK;wsgRq^Yk%q1a^Af7(V7pzT#_^;0^Qk za)2Xv%e-IE^E^4`J>Uud@*)W5>u-KGbTr@I%&&~D=Id&{uI8J={2uhCA9|bbo1H(L zQP|n}_S0_(hx7F`|8)>9NQd_(_4+i#Wt3H4%!U+pnuq13ABLL2KI4knBk$6mIEJ&A{u6}D5@Mdq3ga7GR+2K* z#C^-mb(tMp)&!j_+r&w(@-PUOo7M8zq{KcgH>2exunWt*bGf|Bb-Y~1%X`z00qA!5 zT$ZpL9WUR^R<^T)!RRQv@iiy5f$-JrxGOsf8RejORs=<87M|{j=rm~G&LAd%|(vTfJuP%)_t!|08 zuJ+c|lbD5fuKp5lTkUPDSFj2@vD!|oKE)qg!8}*r<8K~e@7BCUTFiBg`_@EJkRlYP zB(>?tDBQJ1KWp@}#+`n5I9#)mHLOQBYjm^bI43#HS$^jtmx6GuJJ+VCJe?Vj9a-yp z_WQ!&+B2Nz0`jhX9fa%Nz~8Nl#XIO|T|DGomz#XZy{;5xsX!&V;{0`XVBKogv5_sf zZ=Kn$JIE1aU-u*k*JqXFh(*3?_a-`4ID<^^*Ubfjq7#1UdQXNbCYMh2*M3X z(D8-{8PV~EX!4Sua@3~@&1p$5`ZI_jjNwy0$6jynU2X7&4d%Szd%R_Xw`}+k9dD3h z!wv3Y-WwhU;l`MR6rnh}+Ni6Iy4qNoYP6>ldfV88-t@!XZj@!?Z1m?hjKhtOgK(3# zZOVx~-Q=uI&f28+P4n2wE@ayz+oq%ZioMvRvrYd6;pT>T>t^4?W<75niFs|F$Rwul z70%l1&dqnYkN0eL|K?}tc(b#%#2_7d-lFF%nK8>PImktBbiT!%TfAw@OtxW1w>$~L zt%=D*cFbsNG^MFSJsQx6CN#r*wvOO^#_|dBZk^5yWZrrLnYaGSOI`=zH*XN1L?k5z zsqj5~Gmy_%#%9d(8+-Q6dCb#q42R!%>$c>0=Qi)$mIZIymX87yq9U#6OgDNmh#?F| z&)f97&E9YO3wyH7o@{%BoZIBwF6Z{QNQOSPJ9B$GI?{#inBDfi48RPx&qV(1{vF-^ zCG#=A?O(G5@7nIp?cVZj9CZ9`O?qJF-+sXY7O|Ku9N-{&`1WUxVUNDOg}mQBLBBiX z-SIZDarTZ}RHHq8=#LI|48@M^aNiCc?3jv~?f8~ELHJ!f?9q2QDTTfM&iub?O+U=& zJ9GZ-bL9Qbu79_b<*Z^2-|-t4xr~m#yUTqZ@=p+c|0cC*gHFHiLO0Ck`_X*BINbHU z-o9VWIyUnS+d0l@&hZCVaM$9$EK%gtzYbgvm_BEca|c*L!rmM+bZ4-E)A0$oxZWWd6Yp|B#mg z=;Mb9RHhm=G2t1i&TLZJ%>z#YeX0NyH?Mzp?GYnnt z{fq_pR`xDoE$i9D7WScEziS-sy}%#b2*Q0ah{-#=hdtSsm?*qspLguDBm3;gKKs9~ z9`4=uA-dXUuKV<~ZyGa@W1so%Gv9sg-M0;M-e=DH_Mo?YSMk>U_Gf=N%wWGx_UnDW z{oX$vXYKcQ`%fb8{!9GH9q#jxe}eEpb#!u|Cw=J82;OHbavqTBz-sn$1@|BD_5-)M z#{>R<*3%&TF$u{@Novv&AtRZ|N(H*$?LX@I$DfhwpbihFA|wNuC`cu$UVejm~45uF~%LUy94ip)o3KBAu^?myCyCNx8qBknvhk6pl!6?w|Dg(+7-WKFe6i8nz;@-#89`+KJ3R{TGBk%lxxW zem3`?bC3(&{9KYUl&2!S_=-K~_UAvaqdz|m!lSx9niy|A>a9o1;hjgl^QhSz^|qtl zc2v(t+hUK8PUKT&F`I>a%~JGyRKG_LV)u^zf;*4ug-=HaEYsU->=R+{wCga+`En^ zA~oqqPeux&wldon30koROJvf}KMmFUV?oPTl()A@qA zEMOsKaq6@;e( zbbLz3r_Aq^-8q$*4CJQ>#VJWGn$wE5bf6Q18NvIE!5dD=e`*o#KDCn7xc`*7pZb~O z{Kjc+2jS_rNQ*a|HrLZx(9`KC?D6R;nDc2FPS>RYjj_w8TQG{*Y{C0ZKM%q)-g3q} z&glG14xDwSK0O%75Qd|xGaq4R&P-wt=dcTBu5lARpV9M~XE^(8T%3JYH)ormm$P~~ ztCzESIop|T^u)PmoqKjFW^#5W_VMf-zGNQmJbN(+&zZ-$Oq8b`Iz4BH&&|U7&V9iu zzGEl5`GI{Lz;2xL?VQu;xqH})bMl@u>vOMz@O&CdBeUN`4$sSaUe@z{us7%Ra^5`8 zk7og^S;t1U;I8xLc>W+qFw65#g7EijRHYft`+XQAnSwX|zLpIf<^=Zncl-SN75?Hn zdj4I%7tHNKD(u4r`*6V?T!_LRT*!-VE;OYdI=%2I`njN=3+}owpM@+&uNU^Bn+q~u zkokhl7k=S5zTpe*yqJ{2nBzs+FPhE8t^CMO9OGByz4(a7==S2jygS#OtRxqOOSL3rg&?BNw%UD4GQU0tz1S8}4WE0uBgm73JS zH+!WKO_Aq{y}I%_n>ok7LHMWl{F$D76r>2nDTO!vDc4`_`fDsJ(bZqF{bjCy>FTfZ zT;wu;@-hgozD;c2B?-x~mse%?JI3MF3be$&T$SmnKCXVicqTFlv%b0-`+s!trEJv_91%pTgBnEZ!qI)-(i2R$$IS)SNMx-nDO-(#KDZO>*Tr_ zUzhi~uCMFox<0PAMds_WUYGT{tk*wfCVIVYrq`FVhohL^b@RJ^8h2gytzI|B>vy>y zgg5Ny4fDFuoe?ZPB9x^9cKCK3 zthZ&oE$i(=96{H&^>q6Wo(16@`*+9w-Oc+TRDT--j9!e2ktkZJ0tM-_a`wG`+nbh{`Q^x-IG~3>u+!Q+id50 zLf%KZeWcq*@;;i#B%J+7kB^RWoqu@Bb6y4EKlbMz_x+QA#3aSPCI9qcI_C1vI(}e3 z_TZmCd4e5yoCy2-Sl-9>_i+xQ$W31C;NzyWqa!+g+?W0gVhA7c6)RYc`yOv&2Rqr# zac%_R6Z`hWT~FNgM4wOe`NW-1a*>Dp)Im2-bn~P!&1gYu+R`4geX^JX+zP^{@1W`b^em zg(yOCN>YQ4^kX1;c{Ut(J^KW6d^VjKe8;^Y{5L)kocC`T%F_UE{MQcuYbXAl#vJCd zfaR=Y4SN1pzyBWNB&RtWgwONgtmk@suE*#4cy5Nzb@IFi`grdA=jQi(Dl_>UcRY8; z^M!oNF6_Ug`RkUSF+aBb)h#?U>msUBB9mJO7J8Mk><@`TkqP zCbqGI@A2LK_Xn5xlWW}IRuH~^6M0|9N1w0deXYmW-u~LzuPf1>5lmzfQ~4BgdhNc~ zORy8Kb@}>45DDHU3x%mbW17*OA$-CVma(2qY-JaF*vA2W;~r0W&Z{62BPOwVmw2S1 zIRhBUXg**PQ~8vcEaf|#8RH?3dBzL=3nFjC;4Na2iL7KNC(+~~KLzowHyYqAZ+yW{ zF7PslyqS_5~C5Jf0XNovrMUi3xBZ;#}C z#_}OE_=CUE>D$kE9ztfCc1t?Zl^*CS_Gmt19Y1l5QckK2%@kvNDx_U?d@66^KPGKkFyoFte6PNd}2XSPLlMio= zW2SM6P>lMtK-Y0}9Y+UoN>6+iF*y%<0U4F+~_KvxyI8|yyD0a&wS&V zZ#?(LYeRd?Ii5Mk(_1_{8P8ke?c-JudCv^qi;$OcRHO>ksYM;8aE#YMB)50CRehDJmy&tNiJJ*-6Ypd za(5+nSMv0@D|r^Op`YYk`2_ot{3v&WNQyY5#*U=ONM;IQzA36woto69F5T$QAnas{ zvB;ZZ0%o3K8HbTMg{&!LO(AQF7yK7QQU<(1LUK@;VwA)zQ@Sgqy-Hc1Ml@jzn>fi; zoR{itVv`bYOjVQ;G{hdHYD))t(i<~NrRP-oO*NM#m|v<@Y{vel`j+p|O{%|m6+}|& zG<90^lUhHi-IY2!QRK!fQ|l(RZc@vfTISR;r*2M5S~G&Luy3i&F^%kL%qC4)>d}~H zv_Rf8qZo~D(|pKy^qXcOD_O&Owj*yEyPReZ7lTOJ7|5Jf*0i#wl{IZX3Zm<@dP-Y` zw%EV4_Ajko(hkO5X??qC%`xp{rm~G&K_uO~q``UVN>CbeO6QH~`d}y0O=1?a`I5yf zWd(Xp_bo^Gg%kXS%;}!;lGi~be2ZATLk6;9PeNUX-Vqi+{!spK7$ebDXs)52{6F_Z zLODY74b9j8fnX$D%LdFj{06;+=Xo4NB8ezMWAqVuA3a3$5OG$--$f21Z{!qbxx!U$ zpqun%X-0cG(UpD-WC(Jmmnr=sc5nvwr}y^sm-&n9{Qs=GK_o*Q;u4>PBq13oNljYZ znV}Wlo|#5tUo={c{0NapwO z#>~;=r5g3|U1e@cJ37!AJ!jT$=IMOFJicNDt67KnW!6n*bIbfNh-A@e7BkPHpDg;x z;;t;|NKYp8nx#Ct$s%(WnX|~8r4IFIfIG9y!Y*Yo$1JjEH5yoO5_jj{Ueh#}SV5D88fQl7F3OHaHD>_RnaStK9VK^^+)?g| za#z$|WR8+K>M%d!?x^F)9VK^^J9FtOS5aCrf-l*|A-pq}cjmGqx&A`dTu;$;t{1$* zjH6SK9$iQ4I@+wG<@Ni-k?11Wo9H3P94%|KtkJSY>o!`q(Q8@HF3xZj9Yx>f9`1@Z z*W599i z^pU3>9qCLTCNc%@$nzO<&{v+#Z09@nu#W?r<53XF>+Zbn&g<^HNzqqc8S_`6ppQY~tv513r7kH0^ zBqka17Ld1qcNdViz(^Ldn?HCNL<+`3R|S)joNU<9g2mBO!P1naJS{Mzf?e?MQNaPo zTW}cmxu6*pG?#)h7nHT2tOaE)==&>ppNIStL<-rFLTSiO6uHTVy9(*HkeL)RlR{=v zs6R_E<3gu#UZJNv4^3PZ4(&NsV19k{+`xQU=`=k-3P>MPx2gliJk9okc!nGv-)C_M&D} zG(Q!nN)2iuZ&ABnv>&=HI*1|Yx9AM!vVcXbLf)bq*u*b93L?d1E+%U+S&PY9EE8GK zbum2^D@J|nUorbvOfSW{;;v#tF~?%>GlrG?&Z{6&{5_mkJes_iQ*m!B-VQrad=ww? zF_Za>*?ftfi|e=eeva}hC%M2S{^TmUDPbQ=$Xi0EB`Tqx68b6Ot`hZVNE7s0LN_IJ zQ$pqvGMA9qZw*IEjAsH%IK=HBQqmkt%3jiJN_Jy7qxpbw$Xjw5E6{DpHLOFwB@c6g zQ=H`r@|L{8tsqj$H&`kMGMAFIl&qy>E!CWs=(?1iO7-Pq>|ZJSS4uCXzQSFl)?<#P zwz7@OL8NqI3Q!T}mF`Fv%&D|DmY##1D7}T9>|q~2bByEYxwL*uzYHQ}-X=Ehl7!@> zA`QAJV;{@NTSlj4MxviG`YGeCG837^RLru>T69xJ<}xyuk-5wczGoNiEE|vkb1W-+ zS+gm-kd1u9w|s}ZWiN6G-Il$|b#4Zca&I7Sx%Wtjyyemo!P(_1(hl=1XXfQTVG7fk zkNe6k#%#-(Z8@Eke~Zi%!pzDyqAA@Nj2V@m%u?(?d3nq0xV($v=0_M_YKcX`6U z=(xh$*oO*nh)Zgs$ctH4aA$?e_;;#8ecWB43Hqz>E2lV%J}O*Bj}@F-F$Qv1d4fj1;#kI^pNjgasGo}ZsW=1gs%Td#-U%X=5+P@$D(It9 zE860$N;;|ZHLKA{C7o0%MLYBEA}S~WA#$XnISsusemst!Wts9aPt8^+V{Vx_+v=tNL%8;XGzp{W-d+E^`f;Ysg%~ zZr6B+cX4Np8uY>(Ysg;1Y-;!>YWx>OYQ9NKVk2+O97Lhpnt8~FerwjG5lv}9N93*9 zou1genro1`rmQt(tto5Gi(Eq2HT6{UpCD2z9`>)6{i~&yS{ZRyt^Al{t)djC1E28? z2XS7l8{Ed6YI|etG}wvSMJP)Je7m*lP>+V_xwd|54`u}KGX{Os{+utEi~O}WvITe6 z)>CbF*4B6J3wTFu`&s)%5UCTOyE=NSqvtx_R3|;fu!nVYRYzBKT3~a06y3VTGmWeE46?VF=xz_y_yIprTKj4gd ziO7i=)+>yB^~&SSdR3`TOZqd36|80*x~Qj%dfV8+PV8MhUDVS>Jzdl@(|XtW|6O;u z7ewm2v%cK*>oSm;cvpRW*1ya(ZgQKKL8O818pJ0diAhRw@?aMll%OL7E2 zX~^7QE8F>wUHrr`j$?)mP6v^OX4Wtt^|4zG`(h3a&7t9Jmf)=oy|v*=wdL5iT~M*3~kj_&lreT{}OlF^JsH;q=Z7k4#sS0nv2 z(oZ9IHgad9hdd47-VJDi^qdBecJv8e^4|=2LX8LV5ozIxV zm*}I}1~#)5d(!L-7x0c|SGj?{n!ibG-X#HvNlJFg;qK<{Ztm{p9ne>E8JhQGJQJD3 z6y#`b&dp_MKAUej$%7!$!Yo^OQwv?Ra9)e{m|u%7LB#J0M_QUyOLw-6A~!`SPASUp z|Nm|bA2XS0cyG(OEMOsB51*F7X z?cCK)Kkf9>&YkTlQiba1wViI->871MZr6_i3}z_9nay`x3?l8{AU$T&z9qfr&me{% zZ~HH>3+;8=UbpSPW(hlyxBX#$M&9;k`JMltt*Z{{FwYLo?@*pf)W%FZG@udY+F=xW z>7bVm)0v68I+$aJWvs-v*WtGy(lHih)=>`~o!7A`E%4@!y6!j`-F7s?jvLv6jyvvQ zF9$ftX>M?rzj=tvo$PR@l%yd&naF~^JDG2%%GAI+I@Lw~PV#s999?yq$5-g7(^BN< z^aJ~GZ>J+1_XQEL8My(yr-M4y4kI6?a)=X&e*MPvUc;vZsyf(D$|*Pw{|nLZf4eP2m6q> zn?39H6E}lM_qfR1UDochc9*q#NzABwIn1eheR?ny9d&=7vAC=Ir_5qDX4c(abblN~ zdL$z&&g)T`YBa|idkn{%dzf<%^X*~2JQXBX8>`5O6qQ9QQFz24j*o`;zJisCJ)bkj}xy?Of z==l#%dCp5@>J_0FX54EebFnkM^xn%^y`0tSXb|Zwuiq4o^wv-B9ONb+y6WAV2~1}u zI_j;X-a6{7qu$H;mS4CTMEbn+Q&@#RHZuZ z>@$hAcxNB)>ucxw=AsnksYDh08_~BLJ?MoV`}Si1llhD}czfR^$lKR0_g#a`eeVX5 zelqtBvYHvQZX&3~@v9UIuhPslsu4E|jhBJYsv+``#I;}eDNerP=!(uC%8 z!F@w}(U<EHz*)T zigfp)ySux)VbR^)9Rdm>f(Q!iYad)E-@kdEd)#A85B`JYX1jZi>W$h_z&+$xT3e&LHo_jgPS@hELGT!R>2z%`L2Y&{k zUMcvN*7U;ndd*}GYcXRlH{8oj^m@uG{04fx4MM%66O%aTxpykEl8dj%i#~c+pb}MZ zC%s$YK6-bc6QeLg?@3H&7T)iz=ic7$y@!Jw;TZbs{W=KsNl0Rnp{qW+>Z7YZ_Ryy= z`s!1hQuuF4A9MEkj>@>rJ|oaoA3gQaM_=>wO^P}Crop%R%HOvkEojXzbj1$(_NFfz zImsoias$7azK?l=Z}WV@*-Jk+*>5ys z@n%1}?e{VW^-oSdYNFHrZlnKD%;#?nhx*TE4eQvzCbqDRb6iKK{qOQS^7enuiy#ys zb3|@rj;KR@e!v|@=psUo5q21%lZfuj=K`;S&;YkFzl2AIv?7!D1X#6os*h@+g~BA2;_o(Jf6puG+J822#Hdjs9Uz%cG$U`BK^up&R< zt%2SesGouQ8R*S{oQ*v+72Y-cz7IDou^ z9^w`T>2}alo}u5taY#f`QjiXL2Y-gX2A82FG7pw@u&je+9Xy?x%wZmDIm#v6-(bBA zzKypA`;8B_$HA|79fXFYr5YU>i0=(q$P)bChL~~472L#-zj+^ohDIS8@rchS=y|Aq zhkiu?3R47q46RNr>LCBnUucgv{q5nwgwBQ)!rQ}&Q4+lkD^Eq_8P<;Bm~q%i^fKH$!;|3O57+r{oe#Iq z;n}z!ghsfP5web0#A?>zHb(5kJ&f3ou14m?8zXB|kMC)Qxkvtt*+=$cGJb<2PjH%Z zTtwIYc5rCqE$#-PQ2|krZ&VE2*{F|j-=lOeO8293V27hRF%{j7vinglgV5;c#33H> z36qQ5n?UIn3vG4Z{LnaP4Z zO*G>~H$2fzOzc8mA{fMI#xemtPt@Ac;ezz0PaFaXS=OK^zHwaA%h)OifFiHMN z8S(a{Y~;ZElPXe~8t8A5eNWQ)q`}O=43ieI6g^E^jo;>^W1K{WN#}8|ldf_dnI?Zg zO6+*D`#CQ@lOp3fH*7zd>kf8j8{cyO=tUU7W@)r(WhN zza#6^_d#fyS*PiGny#nCAjD^UL3VU7P2Oo=^9?dj>x0bG>~-1_mZOhp_B(ASd)UuG z^fNsz#i>R^-1PL$*wb`3GTp4x%{qM_$1&&hvzTqV*{0v-F3-{RjCdp^1*vfxGcw~o zW@M!h`khgQ>eQqet@(v^bjMC-m}ACt=HOmtm}!O?X2>!_{uyp%hFh7T!x{H^7ldYd zd#1N%dV8k6W~M`inR=U9jFOb09CG+u!=ah7%ryVZPK;&+W}IoJS+VfFS!vMKtn_?K z6Mm*GI-AuK-OuXJ0DNQC0py!?26r(_U$gWz>mCpICkV~f*KBtXyog?p@NBkCq=ElT6=gK@+*159Im33}CzNaCLX~!@oGmV+d!CQ0J zu%1n9;Z6{mmx!+@h40O4N^`nl#(7hj!A9J{yglsa1gEgGd3v6w-+6C?(ERAw-~5kA zOfpiE8r{q_!$h#9kNorXS{5?A^t~@vgr?99k^* zV!0Q~z4$6O(Ai@9UHmo(EeVKL z(yyq9yIpE`OZ~g0t!P6#GO)S;-QhhJg_tKp_2tv!^l9B9qf0=JC`JUMBalM?q+LbUw$d{{C=i zxmlN+b@@@Qp|9ooS}x!6S3zin-|mXo=xT+zSLkX*Lb70AEAmo+;>f$AEahp&Fl6@k zghMN2T_NiVzkwC*W5sUva)#gdhktn&gjRllw^q96m5E47a*EM`2`t3-RvzFmS1{ws zH`w*6B%~oN8OTNszC_Qf^t-A)O=*tZt?Eb@y3-TgtXhD)t8}{R2Krg0pH<#k^_V9- z3qq^yat?mgt7Tp-^XgQ5N{GTVq(An!T6TY9IJ71TpOB1{q(WM1R9yGFljp7JO9U8~=<9}$>QCj5*gO#%$}%wk{nRa1-k)P=ng|{jO`mPqaYK>-4*BJTsV$_tq_E z6>C|KZq~WSbuWX^dT*`w)_VP{*Ux%yt`C!*Oq8G$x>;YIid3R1)v1X$*H30EH+UO_ zHrUOE{FLK6s!$DiH*~@+Y|!n79`r)L8>TRq1uSL_@^09KzBb6b;dKz&DDy`5w=pex z*_fHH$VWlG<{RAJ#%XNlI9Jf~MmM#|o;Jn9teecbsW9f;WX?_BVzy1Ss6##6#3nbf zX%M3s$3$i^hxsgI11GT8P2Ssdod-PPcb*2J%>hZsj<+`JXS04bdvmilH`k>B4bjbJ z-E8j900uLZ5sYFC-rRhK7eQ!CGV)S`_Czp*;fzGyEvs3JZntb?Gg~=}jd3ZPm-xC3tJAJ#Mv+tvlI` z+uxQ7{co#??``{;w)De{+uX!9H?b{}gB-y=w_V^8SJCq}{cev&JQ9$I)P(RG+U{1i z>t=fenxfO~1JTcR{cQKv_OVQ0GJ4&<3Ega$dArQpW!}Dz102GeJ7SRqd)y)W4!ha0 zlx^%{FZ+>q$FDp>w>zHj2l|bS%_k%wIc_^r-bl9{`8lO&fy|MzM#>r~YveR$pzBCI zMXuop?l1BRdWpP+w<6trq&-Id%|AhCXPByVU;w_ia{-I7r=4cpd6{dxGawofVy~`ZC%&}`DdfOF=-ge2b zOV7Jx*d@bmyWMTKyS=$PDJihy-66ca+uOT~P>hn4p*$66gI(`l$T93-PZadNCmAX6 ztvw~EPgCUG(~6FCp*uZU%Tdmu>pi;ObC(C$@1FmE`)v@~>)U(3pe)~_lf6}_j&AnW zMK^nWcW*EH&=33AJBXnSXC%uwiF?_X7=7=vzkR>Zmw}jX-!P`Lf>pSQee2kOd){{n zd)=qgeSYiv9wP6)r?`>*cDp|ZGVhmlzpVRZ-QSSL=w*L1Iy0IX%w`@7@z#EO+`onG z*yVnAe;_#pD39+QXo=s;f!>($z%1PGfo=GW9XNt%IW&%LMH5;Cgg(Q09X&AC&pvZuYVtZyt(H zX6*5h?1${;&>}XogI(-F-b43zfNl>x=6CdaI0o_g1i$seX^{7D1~MV@;h&KC@CfvK zcpMYa?_vEOUcz!#;`WZj;&Td81~+xYP5E2Ip(8yo>k+daS%x`}nDfY1%y#4ehd6?p zIP#o-c^8C^en4zK;$!rDRKG`al85|w^QbFSuSj_K-{`#F{hogK@Ew~u{IQT%3)m8LA^Y0V(! zW42@VcRauh$9?O#ZyirbG3xRIjcJD69{2B$k7orN*@C+`F5_{19Y4x(Zt^k+op6UI zvXBk^oXAaH3Q(ADsL%H_;z#s!qB*)c@iV{R%@b>ILnmGZp_8(n{E8~bcT&ES@|~3L zWH0o3atvcqxaHGJSk4AE;T}%w z`Luq|xIKTnICRF%ok@q^$eBFIdPdeWIz3Ys@0`))nHIRYGwtZW2*xsjsd)3uEY@+1 z`#j_~p7JLz(EC|;clHzXf7Y#>b$4ge5Jr}>B{AdK9?V6@XZ`o->?3^ZtZ$vw(K+3m z`;tNwp%~@S@i`rztI8^F@j3{dk3uwJl7K`cMTYZsb>4o?*P%1r=t&>?Gms$+N3Z9X zv69uSL&xX+x9a>>bbQ{M=idgQ3+B2|96es>%S>dtVBZ%uu?6>Y;VRd;$sO+D7B0LG zLKo$|7>9Vsd(qq%Q{&qg&3y5Dx-fvj3}YnI@ZQBa_^n=a6Bkbgp-Uf-7TsO4=SzCJ zDQu0h?MB{a(nFb za&P(}=VduBk6|1O@Wy4|y!@^NL+wnS$I` zuJLaWx|)p7$VN`|aJ2;0sYz|>(SRT5io93#dsV+z<-IzdN%;2Fja=qA|Ns8GAaqT~ z*UWz{E+3PC5OQBDL|MM&JE~xZ*Ba4;X0$*j*Y@KMuIb_Wha|=RuV*12<*A6>UH9LC z>pH&P2_0W|Z`UIjh~MdT`@g=7mAKpMyE(vNj-vPLc6r?#*I%Od>w3TbJ_y~=*^Shg z;fCIC=>3M?Z+wl;Zg~5Kw{Lj+hQ4m}K!zK7yD<%Scw-Lk@WvvR;g8r*I^bJ3ed}f~77)onj&Pg{=>Fz4ZUmuQ(fE{1$al;4Zsj3AdcXBGm1v55 zx27|Tx%mFA#pvjkT({P60{L#8mKgK!~NZJfA`$N zy^Lfg3wpk%-+R?*Ktq0{HNW6C?sY^r_humPJ)PdWfPU`j=bpFj-QhkDgV24w-j9K9 z?#p~%=KC_=Pec;jA9SG`GC$ag%nxp%-v4?@3wfZO}E9z7Y!G~Cp$ZtB-PoW!iZ zn)TOrLFl15ADZ)FT+H^+Y!6eC8aMHl`!qYb@a?Die%b+D zKAp-8W;2h~c+cM&4n5t%Htq$XKa!A_GE}D-EwQIRhArJ9OM*dInPDx z?2q?B=vhqSpyOvrNsili_9u zIm}1jFP5?b9lfyc7rW8@i>us1{ulRo7ld9$MQ1O~@-iOr`3!TsG{;MMUYg-$LG1gb zyL#D|2nI2f5y#f}ihLBHIQ3|VPF~sHE4T6LXXJY2Td#cUmG8Wo#1wS$O8>89@b`{GuXOP0A;0mI zKZDRev5AWw{z*t;WcbH^{z=8x)WQz_nZ{O5<9q-7%42>HLa!5%75%-|-)pnJw$ImP zC{G1^AZtqPP+1?aIH*dW4##?X7 z;jK5{Q5pTb(eIn}T;f#_`qwW0{gM)tDnHPerr70w-ukaAJ?M>_`)?`NcpHS? z#>4mCW+NwlFK^BGwh>L}g*$jVlo3p1GSkrWTm8P>&k5}B?K!UF_wn{F_tDL}xXAlX zr|(LkpLhCs=dE{Ds7@{H@?B?i^G@b>GQX4go!`m3fegl*?+)YM-rM7Q+27mE`xbPk z5B(W{yzdvW1l_)0!7B9o{s?Eez-8RtdwJix<@b++a1evfDbBZiM-}Q)pC4#MTZS@; zsmx$DD_G4sHnN%9LHL7D$W2Ln?}H{ZqbmcM!gMwe$!_*>oRgg49CvxaYyRV15RM{q zln@!nOjdG`i}F;WDzz|26mvw8KZ^WO=CP0^EN2yKkt50pPUGDu7rDZ9ZgD3FNBxjb zDM&;5ppU4F(L+={MD;CyA2}TLFXWB-J_vspg*e0`0lN9H6$2Q_7{;U14|V#Xj2|vw z6Z-h@K@g4>mFUFcBR(b}iAly+M2mGujZAq2p*zgK+e?*nf00MgNB4 zl%xhf(VUjFrVVk2GDm+Lgk#7YBR=Mhk%Z)AzP=q8qZ$4ZU2VtFf;eq!k-mN#RSYhuh{Q`aGWqQ z$B{LTtZ`(GQ-$i(q&Cgy%ShZ`9KFPugty`>!XD$SU=^2w@JF%9LLq$bqk4SLFPQP8 z(YT3^ma~D)Y-1k>IE}|WB&=8;Eocu#2ymLo3I;pk#Gvz zkvXBP31v+vYr-e|f&LS|2*RI4#r{7@!xv;H7hh3~l9Zu573job+|ws+=@YYm@`krT zIFXqXr6e0UDMwXm;N}xG;zxd>Ib9gTRA%7!mS_oXIMFKBuow4|NZ!OBqo2h3NvzMr z-b(x_VbY_U#JWjb3YinjoLJ_>m8e2ByqS0co4AVXNs^O?(zx*?-%%NPleEXoNxGuf zB)#cNf2OkleI!}NdVDv@R&<}lUX%P6gpCHM0y<7{hxQW1p$ca*Z3@<}S~JaBBUgj!7Ki@+n#HJ4&6C+?XSE5z0`R7PP?}sXHT2>K;sB zDl^bsYWJDiu2btQ^*Ns4rc%49)H+IS*3@n^_4^?FX)^5NQ}2Ho#;two);`t2r(aN! zW(>e=pB}*+pPJ#*SG>Wu(xjshC6PBxd8$#9I@H5%(=5eq(`;l5d)Ut*d^^oGd^@C< zP-b)z(n&}sA)SQsQh>tvZpe2-b{w*wkXsBjr8zBWjWZAi z;TE`wusaNo#O;R1GM3@`mj>d=kH%v>zjLT3OS|npW1dezR$dp_jC! zsX-fh(3^e?z*}kUG3{igVV7wS@J|pY>y>#WMKm*K}t`~io$~@e2I=}IBYgx}G z^qfw=>Fh1tW86bJ_mIvVr27wdkp2U7lm0X0O|R4RjnGee{iOF+`k!e_2lSeL9J)y_ zb9$N6%bb2TbD57f)87xm8De0M8D!63HyQkXGE8DRvzUXt8TPUt-DWtaJV<}|L*b4n-Y=_@^M*U{gZ^pq4V+3w5o7Ng%xZY$Geu5pw9e_PL)+(f3QybZ#c@{;0s#B9+FoVC79M0U6KA0!7t~2X7vwdflA@ed;u$wFV#oyR(X8XhJ&wj-ne(v9Y9+Nnj=kxef#sBW}XF)iN zKC}40XGwrLvm_@aehXQ2o5gP-OL4yCJItEJds&*&g9)r<1Dn}KB<9Mp4|kE}9`a;) z#BV(1|8JW)%S&Db;V%-Ak2?5$d@+OV*wGjE@`YRa;yEvZa8@&Al{ITJ+(On==qPK5 z{1l@kWvGn2S?wlkZ8|XpnX}58Ro1MsWAWE0_9)c-UZ<=-OiUKXiPt5u^M;%fdyOZ4R zB)2=sofLUS!IL%|+!B>CtItb^9!iU&d9zEyLZ=ReK!2a@lLs`D%J1V1_ zJY8{rd32g*E&9o$pFG~m6UlD&VV8MylSemsWX>aV9+~qz<2f&aaNY!bg?r0ukNzHV zIIrF0y}+;h&L8|4g!9Rp?-LTE+kDAMiGK6tp$Nq&iQCI3Z$7u2uLkXzh|Kw9%_nO< zS@Rv_2)fRvr+nA>I|%1@fBD^Ce!b-X2yf+2g+1m^OL{8Mo7t?v_wt|S9QKsoj0K|M zCJKc4oUG&^KLz<3Jr~e#fgfl>Gg{D}!3@KV6mTO2CSb1x*0B+D6!30=U3j;EehbQ7 zQ0{_q7yOun=&Ydq7R*U*@?y^g?YW@$3l>Lj1%JYA7MzJ47QD-wAY8~z7fOWQ3#C98 zg-Xzh0gOeqLX(-sVwNFmA>9;`w{UFI@deq*g$@eqpm0%SC|sSEL@EMh4uSk3>x zW%j~nxxgi^V0VRYa)*1kyRV~?33vQ;Ylb7&*N3>w4Q^x3uU`b=BKB1z2Kp;v<|1*? zVUf(}u88i6=&p#)ipX1}6lIXP$Y5kHV&)=dF0!6Y?BgIuIL=A_3BuoePI>CloF2HR zZ|wS;8JN}IH4cAsjPscDo2!`Zn_qdvZ`e=KPq34s?z5=-ESiO^Iezeaw>}Tr4)aDW;oZ32+<5lHhkzEG4Na zKm+kvG+l^czhC*j1#F!J z?6bJ<7r)O#{^T$I=AR(!?;(dvgwRU~y_EQpJb0^wJ(eiTw^XDvOR%#NdMM$0CI01I z5H4xvlDaOL9o?3+!;;mgiH=L^xMUNW(SojwWg0VaBPExz0y{3b7B^Dz3i6iHO)2{< zrO#6OEak0I_FBqbOJ$%Kx+$fbQZkp4xs=SMDpM7|p;C5RY9gDthU}&FT-xoHE<*(> zQ3ZKRcc2rxE!~YC=(qGFW;2h4tU}(>8`y-*rC$Z%GBTI3^D_D^la7q&w~T(vaezYz=Br2RBi+AHx{Q7^X6vS?IZ}e#`FW z0Eh8rS$&jsBW3NhthdWP;cvWO&K%|3Ww~UezzpT`AxpV$D30#SH9&9Wn$nV=`GpAF zW4VoNVLLn7!+s9o_f+m4zw#LGmwU!vybQwSladoVEpIR7$KhVeZ^OSYZ-(+GIL+B0 z{O$Z8Tp<(w_Z9S8L5>RT=|pdIRAB&vf^fwTv8RgmQ}Hvt;492n(To)f^BqmF|BBO? zi7qR8r{W@HspxhquI4x=Im0gym}EjAyMkVME^Ee~#?nr^GRHLbm)K+V;*_E+<?)YtBN3nhS8V zHJ9PuYRXjeG`|JmS}}3+wJPuNW@_CE!nJ*) zwv4rPUR&q2bzVC^g^;zj9oMdk-PZ1hT(#w@Emv*1YRgsIZ>jbg)+1YO-PFE-w`zN< z_I3XM)*akv9dFjjKxtYslqDSCBJQNlO>W~h>P96RF^EMR;-c5O*~!IMe2u(yOHc}# z>kdTby35gBUHhzSpLO@JpF@DM*EzY~alX-_w@`?Bi|_{yrc9Nk~pgBsY1;kC~f%%{LUo zn@#$o(F&%lE&SgF_H@%0< zKgGsf{1hK|@l%L&WaKllU@t!nWD)lJ(|#^-75Dkm>mc0Btj)~YEHmb8X3l1LFx;cK8_p=kFqP??(M@yRH2;}j@ZXH)9qB?hdf?6GJGdEyTSO%-MQK1AI?$P}$lGEXGtg}d-L}we zi-qh&-WEr3lP%-)~t0-L$mRmQ|@vO`6ghy|mPezhxZuw~WIr zz14C7i&=)>UQ55XRxz=&R(fdVd#&nFA2a)##^F|OxRq{OEoB`W(Qzvsx7x=+4r8~i z9`Tev`6~#w{*YMMbL)6y;tR54*RA#6IzLsAy|uSne@`QRM9;0g-P+r&FKrT# zh@>RPH`>V9#_y+%p4&9XO}23pZDeiJ4ZXL~b(?L-)kdy1a{hi}*d$-VjD)!gj zd+nF7oK>trH|;O;JP3F2RtIl&&`$^bbnvFXc^vK#COt*bO$Xg{C_{NF;P=#_3e{-K z1U7M%H$k|g-E_=DX};wl_PB+Py6xDN?&!DUL}oD;zrl`fucN#j*Q2kFGI#tt z2zQdXQ!3J+mrfbT#aHB`Acb*zohGw|BV0t!o!nF>d+HnqvvxLX=K>VRoSn;Jw$5hj zT$9?kiOzi)$_Pd?g=x%0&z<$#c^CURgf~0uqw_89;$AwtlP)o^=Pu^xl8B@v#|&Na zB1@Md6hrr2YN6vU-tOY z#VGvyu6pmP_pS?Agsk1%UN^IMYe#3g(VKom;J&&o#C>&hU)^NrCPOzFy6xa3|NqXr zAlyAApQ7vT>B+?BWF-d`_zt~y*L!!pclUPpdNkk%yxDyY?zj7|LAXbBGN7j(eiJ?P z)T1u-@!RboYY#i?(VqbfVhHB!u?+Xs!+rJGio8ASuE!p32H~Djkh!OM?Kw1Pq*E(2|DW8kuG#+FvA$h80@R(cI>~Gz4r=X_FmuM?s}QIS3^3W>t1%; z%WiwwO)tCYwV0)>U=@+*x7Rr?a+$}x;tg+uaPI(f^!|ion5TDY@=%bk@pf-F-`h>} z_I~fCG)I5E-CXbX=&ko`wqSu_s*{qOt!|9^XdtK8rg{u|Lx z$NduF-F~S^Lm2z(CquuVXhCa!p*@}G%2*~anQ6>q4)a*RL2mOd2={j%{dL&C4lOZT z|IT!y2lF|`{U98Xo4mN4h{D)?gnt{M{|L7f;g%x4!*3v>I<=@v1MDW^N92x>J3{UV zyNIxh2)l@|iwHeN=rKYs5qgX`$3?Di9oO zrY#-N-4O2&=}8~#e#k85qRSzRSc12Pti(MG@#YYD{q5iIQ2h?AK}W`7XG0gWj1@%U zcQaH!L*35M^XO>kWuEgd_B!kXVk7Uc_?UZ`%)_c6^Dw{jVcqFPUq&*9@l0Y0Ive&P z2oFz8M!v+Zhuih=I@slKvko`w@QIjnxH*TrvEgPLZnoj;*uXyA-Ecb`Zg<1&Zn)hI z|A#lc<$Vwy5swNqr48-qh@2zj9AQr*2I96ycw>Zbj=0CK*zbrZJmW9yaD*L>OhPhJ zl9~`{$v`GP!pFdVr@>UiYSAUw*>N2MZ6dh{^Ljz*QC9N$urO6Yc!Zb!L;QJvAv zsQ$=1Y6!!SdDKy49%bjF^gHSmIv5=TI~#3hqvK;|qYKiSk?41{yBWO`yBTf&qxCu3 ztfS33=3~q`#++k5#cX3f=L@n?m~W^}Bbv~RwzQ`cT^Ph{mf*cHtJusoBH6_m9tPpD z?rf~L#_DIRe#UxptT)GIB?n)ko3T}?PEG3IH#hcs8q%0P%;x})gRs9P93GdMlGLCs z4fp|h$Mquu-Hsc~P=@37#_4$68rHJ|dB^Q#KQfPxhRox$pqKGE$xTs8P?~ali`yH& zh(q{|jemff8t=ag6YOb13d}metP{%O1}2zuLM_ZT;YXU%3^y^sO-vZabnJ7&T$Ztd z)vRSVSGbG!COqOfFZqWzL3rXvq{V$q^wvcEOw`XrZ%*{)#GhzEYjiVl1fv+kcqTH1 zY0O|NH-hk_fb*30A#Y{niZ+sEXioZu98G9?RkHl;ph zpVE^)n0d-f+{6?&G37WHu+J&ixX-UV=6C)L!c!BGnh@#ug6!nNtxPRNJ>;D_7X3`s z&s2R*_14rm%*X9a)y>p{97g7;GEbFx>RHZnkrzRDS~3dI0NJNaXA4I-$r;We@3g=9 z2i;Elk9R?My4_7rj=Pwify}t=>GDp`OMd*8rguf=>9S6jb-Jw6m$DpPPuJ6Qd!6n# zGhIK^-QRS*O#g%D*yD^SL?b4#`I08s+l)z=ea0rXV&)l__zgEPGY0Ybge0UPOnNf% z6&0yT9qe;vQ<~F?pRw1O6Oni3G4wN2KQr|?(_1sIa)aCGX4VHpMdn#D&ysmoTs|fN z*{DJXCL{Z-3;Y#?XMad6J|Z6S&dxzDbUQl_`LMg$RdE-yzo!u`k#}}m+B2GU$UIxt z*|N@-b@n~n;A~yb*3)czo&7cl&(Y5u_cuo`b3Wq>>~T&ZicpLa_?^$0g}u!=joIh? z$%`O7*UWPhk^wg{w}ckw=sbBeQEL*B)A(ASa=NRP}*WL+Zb z5?Pm2rxtanM@#H=iGG&2za@HEGL;!D#U7We#_wp!2Hg76_~?JB+gfV&rHyEUnV0s* zO)Pa2OV_fENOp6CW1QqPw|E_dmqj5OF-brolHyjDWuYkYF6)ebmg#4iK9_lG*+7Oc z9NjEi&PrrnCi60xmu+S%+qul!AiO*c#gTn^UuLq3^=x7b@-Dy1b#%M@Hg~bRe{3K$u(&>#z)EwjT!YzG?qDaoaT6=u#LC}!$v^xXgjan?bYc;Q6nse`ytk?t z<*7(zs$#GHesFk|+gRnTRr*<_pH<#m<;_*Q*vkQQvr0Fs9`cwc{K0cx@OKbi?akGB zsZCF&<3?6r;t@~zlfQ!S8hO_wCMmjIlakb=As;$kQ-ab|Lf$nssD;dHCL{BjNc6I1 z9|t+dMXqq2n?ZQ3+gn?Jy0oGzZffl)>}jpv!CJGfHS5}Im~*W;*Zzjt*1qC3{|4c8 zZepFASeKFP*yp;h_?mAhPD!fKnof9cT@MB@m|=`y78`IM>%6s2KkM|f&YSDJx$X^b zgYfzQ-K-Chmh@!eGrk}jIjBHe#<7VDxRDJBNk?X~kQI41e1|*SP#wK)(9eeYd`}np z5`p{PFdE<8FcIBvkbA==9*zk~3ms3gISZ2FwMl*6o>n$m`Lbfg!3=#Q>9jb{ZL*}``AbBLoH$9-(l z(Pnu!>t?eqH|Hcb-rDSLHW%g_bhBAEn;RkXW|=q3yxC1{{+VC!=H@k=#SXW~zU3?Q zyrnVCXi012-Qotfj6t_sCZgLdQ(1?+TXwPsdAFS4G`_v%SrFd(3HHC$_qXOl$6HHK zin5fa4svhpgkH7|WC-qm>lCIli@D54CtKeK;caehn;y2glWmo$MiX?sO}EL;N0uci88ST*$t|UUrONCi7UxV&vU%gk$J-$0^Qmjwk%hYyJzu zkix($6k$?OM(%)?$~tPNSP$GVhXkm(06vaEm)Zc(*rqr=ukHxLfw!cC&jQ z=efdlZX)lV4~U9x_rxF;`rVVBtmNQJ3L)>FVw6DUJrT&f$NlZm@1E7HL%)0UyXOFh zIf~ocn~~Dgq6uzlubbLCoGF-fuUYpV!kl}}x%VPw+iSMH_xTk!vDZ!POGrvSC5(I6 z_XXL>$v4!d5#HO^jJ9;3GhMOQeSSmx+{Qj{?bFXb{p|DRzPmi&5x)oF{kqxz5$<|_ zeEjzJCngywNJW0?)0=th!Hw*H7laRdOd^t!9C;5Eq%gWYP?X}7qyaiU(1O-x4wdphWMaL}v=&3Y&bZs3qP z4<*2ChfdS*lPS`#jW;#xzCGhxB`BG*g(4_YN&)87pxshjer35`PBa!`?dV zt;6~`te?Z)JnYTGA=2>;#n8>+(v;&{zN0c#@#f+2Y~%{BgYXf%Ir0^yC{INyA@7lP zxP>FSJ<^44==aD3W-^EQxa}kI9&y`8^mRn$BQJySQJIgrzoVa`m!s*)NpA8|fI_&v zqm$UoVJ@KOqi*V`JspdUS&y0ZSbofT%$&!{V76n`s6j2<#IZgMVK}3h%v5He=VSUk zc92up>oM;gyU88y<5rI8=D2%2o*8c)_ttU!9M{irZyxvN@tV{@ugANho8xZpcwhQ6 zkiiVao5zph{!Szy2X=F!6+P+400trNi6yv&6S_UIiZ$r>#4*luiL1En6Y`#L+b8sO zG8SJT^GR7x%6d}PllA$YM*K*7hBF2CcTz7W=i;rC?*61bp4`khRXk##z@AX*VDQ=t((&_pO*Qw%%^v-lil11!e^r3{?6Fr8QIU+&6#BVbZJhVkdHtN%&v|d2_vZQi9O5XtIsY5(`ura} z=LN5L&A&nTLNW@`fPT!uja<0SQ~u&_{t3bt<-M4KROt3%h_s}qFgm_imT#$!ycg?I zpKi=R=8Ljkl=Y&l7f)~seP7hm#e4i3gfHpmlKZ=)mrI|J1be(>AD2Gk3$kG+mxf?x zm$qT{OINvpnJ@hpgfF{^%WmRw7II^smkUswl9ZtwwbAe8HngJy0~m>WzC50Z%wjR_ z_p<$7K8!gopT-=Qf5)!-fM}e#yD;V;p>UWN*?l4 z2%TKliN6yZzAoSOrpR?&uIqALm*=`X*CQCnWL9zz`@3#`*B|qQXZ*$A=;B5al9Q6u zxS<rGwy8^Gb4718I-D(K** z*>85n{oT~xO?hv+mz%?|!<$Eu`KGKlWxXluP5ZiOU$@-gEgj!Vz~^}Dmbe7my^v2wGBhc^N!OTJ4yDM0Yymz246|1_2QiB&0z>QV?vR|vHS75>YrOB? z`?vS;)2#oMAmU0CQe*E|lk*%ze$=*IwaHugmdzG-4o&>p79Zb@N`gi|cOZ`fvD-uDi?Y$MM#UfK-HJ zCL8%FL{W;gb?)Vw(ww{!Dv9t07$5+KuCZo}^YN8B>sttvF;Q#$iGUFk*-?D&=) z-;(JqJHBPdxAc3R+$MBLW%?ZhM_C25ewZ8_ey!`m{sT@c^M?Xj$6EB15y z0+)FbMBK55J7&FO);swy=N)t2DTCSWnC(t2>fl?u)0?mPhT)9kdwxL9cjW6gg(L3l z#y#9o?~XgTa}sxO=Nz)R`#u>^>#kaN<#Sg)ch$UGgW7zET<^-}u59jpNgv$bUElEC zuNcfMwsR$jxEGVG*v-9<=}BJ(FbMtLn}b`pC);}qS&V$|?ce}^ahTKS_ufV1bw3~y zJ>S>seZAh->;3vPq6y9D#5cIV`|j_)T<%Xrt^2;!`}TN$C963VL_CN~Zc5|52Q6uX z@9lvZA56eaJXpamY~ojTv4{Q0`GI^N+~pBZc^*VOl*hw(BqTBVf0&J&sQFM%57m4q z?}s1J5cl~|<_~)zyN7anDCdV}diW!&*o&+l%Ie`^j&TB+J$%A{wO{g@cR|FX_wcYkPt5nkZ9I|llOfE;Z9LJ_6SbbG^<)`pJu&x_HJJIy z;~?T`GKwRwr@i?B_y5!_JzdU9wqmBIN08Ceji^_k3`jpSR#FrA;-#!h^D&-S6#GxzoEEEl*GL_Ci}Dcsoeu6XbH zI3_S3Gd|zJF3xj<+uY+h|6-@l<@`dvFS3xA0u-h+<)}zyWb>j6BarEfMabucd|s&a zVlC_0h+V#r%?sJQ(DMsDztHoGt6b-15b^K(&=58;%yY{>TN8%_11m7twDVn(Ugzrz^8O(4jb9dAISNweBU1B zINpAHJBWDa?RTjuN(tQayRuZEGS#rdciw&H-FIDZEAM*nC4K0}0MvZL ztU|xh4s#UQMmxbNev!*T_^H_<%n{=}YR61O zQc{qbbYvuwlBgR~-I$fAN)6m;%sSY4OnJpz%%9v1!dTIeb1ZN9jo~m>2AcCF{m^Hu zA?P#K2;>s$EZ2}rEV;ybir!+q;!P07PC#a49J?7UX+t|cp%b4Y``C6DdmIz^fghQQ zea4=JOk%4U+wS5-MaFR|(;j`rv9mZ+@NLJLiJOb_JMxROgFo1f9OGQ#HureQOY|Ez z;62P9w>)}|tJk=CjjPwVJ?MqK#g$3iQOsi{zRS4l*nnDb-CbP!iYwo^hwx3t%SlaI z;JtVQ`I_%BW4zV;%t3q~@lJAvt6b+6a`yYcVf-pI##`}Q(-!^3*IWGlcsu@NaAkiG;n@GNi+-;(p$TQJ>9`TeHL6|rZN%3tZRzGn% zG7^a_5}QAnnMeO885T>@z)OpZ*YI{jNifPPd9t+TKYTs|_J;*lo z0siC=H+jTUUIbwpH<(7hX<`tIEL20!Y4n;#uW9s}#!k}=K-OvGl*T=zS;BfYB9}D3 zqgEPwOmmoH91p^@0R{Moc6cxCP)1-+Y0a3{O{8@bX^(Q23tZ+7_jrh$)5$ko5>k=| z-(EU7rW?itCgII=a`cWszPE>EjZgkPoO& zBbw5J)_hC{WRiXedPr}k^xyIw<_>9pk#_l72V;eiLzlf_`=O(wg%l#k>W0HuZq#z^u z4c%Or4Lye)(Q`N!*@ZvwBMVr>QkJul6G0dmo1B!S8uE;kXXFKf-tk1nM>o|G7n`wc9Z!$4|vK8UIt+n z{bosvTgW2YEFqbYZ@}-= zvbw*la><&Elw`&pv*siZ`DnsuFa>HaC&YO=QbW5sFiiN>rgb zHED)?vvs2cb0(|>mTXHSEyvdh?S`i6efH}spn zVRn6Fx8Lmcn_b=Pb+G5`4Uk)QGiC43B-U_(=RuewJ{j;<4sYeiPF+5w3;NEX=Nx_U z_c`2l4t?j)cMf~aA)_4bI)^uN{LC)S@H7Z>$~k8; zYo;;}S?7{&Z6IZH@U-8UhoRL z&2NwSKgS;P_hkUX7|Ce#nO{%&*YPK}Q9r-g^FQG^FY#7^fOKTUJ`31I0e4p*JGsb1 zK5F643z)rtdnoV^`YI^Hf{|n+C%Lizf^M$hhq%*%4QNCYy3?OQn7`n+=(nI;3(BIP zo(mpE&jrm~(98wj24SHn#3vC+NkJ;?sgT_in#4lZvWvZ(;yPw6WY)sTakqudS=b&5 zo2{_f3KyUd6=+U-I?@?$7nXD3KJ;T0^H|0TRNMY(xANdrKPZ9Ntw4@Cmqn9FT7BO3qJ-COWamaz&EZUeBw5BaR@SPMLj(aF7 z-=bp}%OX}GqoV8i9sL&lgWc%4SPb-B%pQx$rdUCWAe&;9sYXp|)0-vi<1{z0uVVI9 z-1p@-eZ%5rEpFE0H85v!a~5xk*@|~S&c!?7j*GkF;`Ug47IRs^a#pg2pV@(Yi=X5S z=eW-kp7U=ImUxdOq$CaQyM!4^d_ZZ;Qo<}Hsv_qS`Y7=!U2x+iWLRPZbJ)lhWK}{| zC1h1%5Bs^ob>vpUUP|br#3S@l;#m-Wp#BGD|DX4zu5lB6mDE>BeU*I53+$+r-b%@) zlx#|=RZ6W=nNX`#c5))0QlH^=O3A;}-#iGy((y=7Bw5HtajN4sO1q8Hb*V>vKBpIb zvE$Oi&~NF{e21P(A4JckA0xZc_E`FL5SEEWToRC&q?Dp7<8dctRv^zZ@+@rLX_7{BjWq;*& zWK;Hf5S9y2tDIWp{l%xjj=!W~NAeRdLP^-eX*kgt9Okgv2gRo+JGT^<6Whl=_n6Y9H+(gB3Okp~+ zSi};3Le3TCTk%hh@DC?=h#RTsMk>Ay!b(wyN?IbwggGjyTPY9fR+4WeeOJBW}9#Amm@!Ta}lxg9H4< zVNP=nSy#RsgjG_KAK6wZMOms*6Sq;t+f_cs+g0RQWhHA^#|GqEuHRN2w4c915EjrMZ?tIB0 z1~Zi5Ou_DJ?B)vcsc{RL){tq9$EaE3-yp1+9Qo9gPfhvMRKI3OX0oD}nw2qI%`x~6 zYyQQ(AgmP!H(M(LH(M(UMX5@4+(Rw-)~ZWAI^%|G$*5L8zCpjWMll+9TWddhuBF#n zdab3`TCaH*gtem(mBi#kHnl%MF15>{R&BeiZI`thVJEeR@H6&S`x@S>^FFaijT!66 zw~jlm(~wrQr9EBvf*#1Zj(qD(Vj44Mmmit1)NYU)YHItot+wKa|yn za{5pnADZXGukiODj$;Dm`S3@M1z|n?)Kj;fy7l~X^<-CX1mEIs>Zw^zt$J$JQ>)&u zY{ks={@^(F_K|!)iX;o!$%XkoGT%pq(a%Q>XiQU@(+ageYDWh;GK?j-iI46FVg2~z z#%%E%2FP;)u29~Bcld()4*;Te8YGqGMTANXD82suwe?aVfKbqsezdre#!u3-EazX zS->LPRl_x`;}>=z--c&6&qW^bE(jaFM|5Ihjz($7h`z`-Nx!Rj)VO)PDE0YW6zE2(UnQK zna2AuLu36nzJj-!^zt7cJnA?q7>e5E`#PZX@GCT?+=H~o70)0*h}*t z_>pO-)qE+-S%rIPemV$S#3K)KXyLsUt!RsxTe#O2?zF{ZR!(prH)S@mQp`TX0kx#1?9OZEkw)QQwPJ_R1ofDa~ z&QC$~+zap!)NBD;m+(fT!U-LEy zKMr`0Xrvh z!99r7l^? zK`u&Bo4VAaJ`HJ1H{3xN*>;g_7yIv`-!9{jZI>0uv5TI&=(USpyXdv6JL_uxuJ+b7 z7AeV3Y04qru2oR0tDEyX!(rDJxRb6U*~Dq?;Jq*6l7Nhu@r$xlpgH#RMMpZ*lV0>i z&R@v)i|Nc^KL10{U+m@pe{q!KoWvf#c+N{?-OU``qM`q8`tMeqTF9!KjJwIHTNCur z&3?PtZ#Q+j4Pr3%+|75>%}m{vvJ>~#T`t}2t-I{I%f7p}x_hg;%)5WZ6lS9D?t1RN z7=Pb=2m0==@9u|@QTKEF_vU5XV2?OtLe4!ZBIh3Z?xF7<`tG4t54C#qKvsThIP77^ zJ?yxL+C7G#?;iT@A+sK`>fyWS8IN4lK;AuN+|!&r&DrxCen7817qNt8EN3Nqa3?)w z-BZ>*FQDI^*SHacU+VeGZ0Pw*d3^aH^>G_tw&N2z@i|?Q&zJkSjqjqD8}nPjq2Ce? zd*wr}z0BInti3+NZhD!sm)-O-TQ9Tq8pUX)v6e0T&UW^5kVDA1mwbDU72dszzn@VMK8U((G%JC{uUYcR=c;_z18mh2lDEzhu(j3 zom<@H0grjc3-r>*+c(A-e)V`>f^0Gvg-3N2>Zq+0s8K%=f0`&_k9ba z@4ou(TajAGudg@zHbDM;-ACWa$g1ypHlpvo`tGamzH0SVtM66x+*i+i?{J_0YCl2W zef8Z>&3>}#*Nm^2#jl*=Hsbq$wSOwokd6#QP=X4`y1%UZ*F(Sk8`G5D zOheE8_1a&r{q@>kw*6(>-+uca#(w+148j31kkJ6U9gq;U2H5L>NV4EY2e{1v->`sn zcyGWlPH+=54va-yGLwh=6rvPmD36>6%6FjK80anK$ zk=MX~IL$dObB!Ck4#GjnPp*gK+OM5!fna>%=5_VyaU&SG$ zAjS9qZ+)fzuLd$4{eCruNlalnGm-IEw{ZhsJxA7GN9BED;q9-};q9+$@+tE8x+~rJ zl0Nij5Z?XT&3rwFdHjz>EafLwuphTKI1z=ZPY=d3mxY*b@G{)S;Dh|d-yGo>$9cfN z$aL_#ARH1C{SJwb8yS+Dy6Aa`UWe#)h+c;b#vX^rWynZ=WEH>S+Z?ikU8pt09*3Od z40idAJN%|NP3esHz8TF}W@E;0erG$Uxx#gPbKgAXDKC)oQ27qEx1l+44@2Fo+7x@m)N_*CZq^$iub2v)xqtqQ`zoYDTR3VCD&!fyUsv&BRYECQK(w>g! zXVe(%d(;kY2I05%@NEWU|E<6Owk#E>OjULT;plAC#uVeK(_7I0ThHqu;HQoi`IQKR#0d_Vn8ETEoj6BEL;kew`*SL`^VH4gP zcZ##z!;ItOFbc&-njpy$!6z23jKn+eIu zN-pw}AN@}Fhz7`ZLQ~x7gqHM1zZ1S;IQpG1fk}9K!p|JXJ}3P5{%d4BF($EzM*{41 zVo~HWQ7#j!Qwy~w+N0l74kvz$Z(`zDwsH|UO!VFliAjc;e~|SLm67caZRt!GWc-7S ze{c^!e8phKGna+fNNqU;piayxcBpFN^hMSo5 zE%r5OG5@`{inXj`FPE^hNp?0l3U)R*2J)CJkI813oE<$(wu8xbHn}jxD1q!J_hKS$ zV)6;@2mbGg`1>Cdk_5Z_F(pm79E4N+_bJ|+V*gWQJ;iK(<2amB4l_-W@01RFN_W1* zd{bmL#Vt;mhg+GV-jvgv<04nM&Moc+;Z$=>)yGtOotlWGs690mvYna^b4+zVQ{^^w z0XvY()OSHRP5;x9q4#O2alg~_I;}Kiv5RSTG0l#r*}=4q*zq(wp4J=vPP3C~UonH< z(epIDPSfi&y-s_;W1jLn2&cbK24p^6M$=_JUFOr(nqG;j)Swo!pKiC)?Q;4lyf^(N zZ-Q`!Z+?auXXL@RGov~m(GYu>(Ux|6f}Cf_cg85j@;!DsLmo3$3!B)&K@M|_ zE?V0vJ^F7p`nUP4cA-|cqvFDjh>46z$_GJKanmGjbJ98Fu(ZkGzEa4|s zunP5O-U-54v5?cO+W01Cd2d#K24SbOp7t zkjAk zV<7UF`yJz%$YiDd{`~HkW4<}&%X+>WnLiZ0 z&tJ_x4kD}hGM+D|`6toGeEXemzw`gA`!)y{M8TdH*z*FpEpU?y%(|d0Be8=8zwsCT ze!+PzVV(uogYbX;x&LkFRuC?Xirg25$PPZ!O9~1@yYeUKUlS7P4AY4|y$Wh?v!>bHlXLla$Tb5C1ze?X1`S& zF3CzEic*47l%XTj*vtX!XUQGz2mUYY#KWvh&APNC=3Hvdr8O|y(nd6)8J+lsF^ppZ z)0xQ}Mgy5Jubb0{VkQvGJEs;#NjfvmZ`N&KFj2@OwDC#E^A5) z(Y@F_Lf5?@vGB7JicLPqO`K9lzj? zf70(yXE=|3f4a>*yuCaL`LNIBcD`IL%bU}R&rol9ckFg~Z)CFkFpq<9MKtVegzf&BpIK~N1ag&$43&NG} zq2|hDgk&ZgGGCdS(zxrDm9c}BZSe1#m7mguZuCGOEA_DQ2c|NES*&3{SGbP7`px2S zrJPopcjdDnT$O;t=wVe#(%@!SWkgS_D${d25xoRy_*B)u|{zQA$vT z^7#AJZe+E-SL=JV9juo9>OOdLwLDkLaP|NAjnkatBKlsf@74NVt=4L_*2E(rdS2s> z)}%n~HEGfJ8hx)Rg{;=t(V9i<;%X4CmG{~tm~*W;*QO&6dRsr08)$3Z>u6@c2?E2?egycm=KNqGLYW-}lKi8l( zb?M784saIl{rn~f*99cPjO+4Kh+4Subxm;N>)P`Posjc7`L1&t>)ggVx3O+A@>us1 zD_PAx{^Bt9y6zNb(7)d_4%ex@{ym}-1G%kNd%fE0^}GHf^srtJ>-Dg{6?VH`?e&8g z%uq%!iqR}*H!}MrHrXl5hj{B3Z~fAY|M43;u)|;W^CyRba6@VeQWE>yP#!sMkmCmL zY|z&Rd2GxQ5Cg-!g*R=mBz+Z!%(6?eTs<{R#EpGQ35SrBeibEEs-sK1Q^ znZagGaFcsH#Qrx$BN^^`H=CJl9a|b zvc)&Dr5>|zLtA9JRw{IBE zC`NNI2!F4JH-4A%@B49MzyHlC}!yAg!jqoCjI@koe%x2Gio-rg?v?QQ6X_qWSuyL`4!U=lwvmBnmB zKHKH9-Hx{(N3HGGxy4<4H#_WjM|Cdq(l*8foRkD@eTAbS5p&VTs!{>AMk3MoF8kY66@Blj zPa~SroW6K}mmAn+@4IBYYbOVB&$|wD6n*b{9fZ5(vO6vbNQ^!14#`Y5av+o4!&rzM zc6)F4aZYg?S?`hUp7>-XA2Qxk1R3usM@1^rfDZJa7y8{ZfI*C4JX2YNT6<)^=XbWF z?jCo!=MpmCBkw)(-Xrh5QAtZ-itzz%aj)8Y)%H8X;ojDKjQV>&pkeY|4Fr5u- zLN?wg@2GtrmHDxlM34#JMlHJ~xgXn~%N4aSa-+3_*=bL>qJ{^Mr;k^4X1`o~-UnDK<&o^T^4^mjskC-iq>F7D!lyEw5PGoP^U6I(cj`A=Nr3U|@( ziN`z*!jpD1^2N>5{mG)A~I< z68W5#&uMv{R_pYSOk*apIsGfYqvz9lKCS1|?(y_~4st69&%`Gm_0jv839Mu*f3Syr z==aPW?jhSVk9dOJolStdIGcv_xaG6@J?s9?=EWVK?TVhy>h-K%&+7H;9OfbGvvN9X zuV*(RpR?}otX$4s{$zB#RELnqwyd2{#;;_&=T#(y^{1l=HzJUw+xKIYYT&O^MzG4R3G1CQET=d>W{a;K+Mk2{V zHvG-SQMiGN_IAlk*?C_EuUb>2%U5-LD)V~~?c*x>%A_`Iq8DEy`<(2H>INrMKt;^=V5|aqr z*OlDlLuOZGc131a%F&U*e2f0Bc<;(oj z;Zr*EIl~#p1l-lNS?KrL0v57^Yv}p9Ua#x*x?ZoRz%5))OL}B;y)qxskR~)ot?QrB zmG1OpCV%lD2yaBedp9D;gqyfw#vAV8hI_ctjeZQoE!-HzXvQMv8}hxefo<$$H-~T= zH{8aJ6UgRfKq_Q<)BgOXaClQbH`TgXiK^7VE^o@_rfhEN`KF$4>iK4G`r;;UPGJk@ zg7B6--qQOmySe3dZ*`#uz378}Z%tzcvb{BjdC2$Huk2zk2RMd)Z=L2WFN5%QI`n*7 zuebGjTd%ikQx{p^mecKa48;B2c7M0!a(g0b-JXv<-d@5ojt1eK_sL2zymzND&9J9C zX1p^7H*se%tNEE<*vfYPK+bpMd*?cLxX;5Nyep5pF^ElEl97jknB%TnzFQi3-EBfk z+R%Ydk-gs+4)0Du?YnBz@Aa2gE|Z_Y;tkG^8gZGQQshH*nuA-k0_L;f!Jo-o8HvZ{PomJILeyBcAet zSG*0v2T}0u12^*^lFVcy2fm>PdC5<0+}?v9*uZg~1>wUa_)Z>X$9xa-;5Ht*hllm3 zPeU5hlpYK~rVocO8vQ=}9yjt(&kv8F=ZF9Dns-6ycZ0)6vUnuNM|Su~CXZ56fiIcN zBJAhUZuW5+dw68lM`nGT0{J~Q=i@Ax?QsDLQG`mgR`0Ppc)S&N@c0j8^Z0HMK5^Gi)Ow=U6Zt%m&l5GDsQIKY#b|(Rp2+4&b6Vm4 zp7@5Ibf6={Si*kp2jSEB*v-@GG@~^i(;odk9f4bTD%+>uF%J1YUCLV4vytuS_vs$w z_4IlWK8uZ>pXv3PUZ3gp*$0%uUZ0i2Zl8UMTF-o+&+PM=efkaJ@R?fACNPN~k;}73 zLHIlg?&P^!dR~z#nESb&pUd~Te4qcoOy)43pOEwORjgqfhmr5|Q=CE0&;NV>DbIuO zML;5wlZrIh?~CG;ME`!1IDAnVS-+6;3;TZY8C~gyykE@X7dBzPFU;{`2fNsd@BGD8 z+}8`=`HOozw>CYQi2VQEjJN*v*1xj<_f8PLj80;bkrF+>%tlV~;GLHR zaU(AWGY$E?T!_1PDVvw;*noat9zcIDUj^YS@4fQgE8qC52<+fhR&wBmUR9?Sb@-6_ zG^7d5XhA>Z@k-yXt_0!hsD!wO*KXl;0~({h*PU?>uLtopLm0|%X0w=O*z0TgzSi$+ z`M&-gJ->bzgm3ixCNna4BZD_Gc=G|JvA;JJvA;L=^=2;HIl=|x|K?c`zKuar%=*@> zZ!1s}bH1&I+1|FKHErp}x7gF$$xLM)3s{7l-^%yx-<;ws>b<>*9lpKK!ytSon|JQ+ zT>;d3r`9|9ypzv6HQ%ZEt_|%NjBMV?=G{m}<9mHKo(cTGYL4+dhz!zDf+qB01Y;P- z_snB0>-dF@Z01+~;XIeP$~_+Pgl9oylq3|P4vlF>OFp3!pV5VZOlCd{S;9}K6=e&* zvz?vX4Imps%%@6pDyoZr~NF7}|` zXt%h7Y@VZA7hWv|K(K>`FSB9 zDM=a1A&(f1Xi9V1Gl*|6M~u;oMP4zMu!7aBXCs^WiyJ{?OtoXG9aHU?v5{9yJ;ZdA zF>{fZ0u-hgA5aRt#B4)<>@}vH#FR@+na7Hbw_lL2heYv!yHA=ag(Cw zxW1FP@{3!R3e@Ez8qx&$#2w0dj$=o0p9YcfViJe6WXG)W%oBxXQ5*MZzC2%K+o6`n!B>t4okXPanjA0x<@FTKMyqsOAomlO} zYA3#dyb|jn@xvf8No?Ygki_UCi9ILLOOmvdrZHb)mr2Z&L>5WBm*hJ3m*h?mnKUW6 zDME2dQi-a_K4~qyk#sEjOF9jAk#r$$A?Z)7!1t3>UP;|yvbZEbU&-{9Okc^;ke&$i zmdrPlOg72XN~Tt_>Zp~>EhYO9HIvzEvY$DD8%ds=f>fj$HK|Q2+(z>5^rRPk=*L86 zFq?U}ljQnMzM8ch!ah^zIfY(R=rx62Q)D6w*~v)>KB6@r(*e6op;n5%4B#u=WQwJn z;Y|>kGCtl*nTPz8$BZf4(w;%MgOuO$9g~@You!ns-$;&3`3HYue<_c0mJ3|wDzZrx z5B;W+X{yS|CzX6ssgz7<5K(Q}#{=s8VYaAGv|Z?pInxfrY-!Dwb~NAN zCepfzv>VvQPIluS(jMj*$GL`l)4t|i5ScCtv56!bImt&s3R4?%q%%jlX0*i3q;r?) z)J?Y#S*5erbaG0!hIQy8o&Bb>-*oDxlUF)7lTgZs-chxzC`gE|@Xok8Cj z^qt`^^qfJ@8SFTNo-?SO;T#vR?~H0@lvTz`*k?vN$mm`&$~&WsGoHddXEbNV2SH?n zUL&Gn)`%Fy!k!~CksDb@$T~s>5&DfNPet?`F%&&VEM+;XkVnK;cCd@R>_gN~5xDKhT;wG`Wsz^B+lXvJ zGuknbAq?YN+)3m(7GsV`b40q4NH-F>i9b;{Q-G{8$vBgoGQ}kU`p9Iznd~={x|s@L z&zbBwQz_(@sSRe$!h8<**NoKic_V<~SkrMM{PKSIm9|_3azS!9~!GS|2nL}oQp)|l9R)_5dD z?X3FBnu1iQnYAecn8WY5y{xZ-$ZWF6mWZSzCo6i*CIi2J9GR^&_K~eT&9H}TX3W-! z9_Tk)U;3lxY@5+@wu@Xr{@HHvoR_=_BD32^_V}JjW zE{M!w&K%~<5g)VVFk6l^q{IE>s6=htPLBF`JBOTe*kO*3>CQLEH^*q)PYyljSjGxg z^E2z&%>n-6Z_JS6K94X<4zuKV9Yp4obI#Q0A!kTtWSH{<^pNv&zCczvWtCG_Iqf0m zSGcL1)0xR^=J7ukv4s6x4I*>NDpxkD(2}n7p+BexAMFQBJ(CfhIwU}HzV1x&%AlbPY1rj-tyX8-m(11G-Q|8 z+j&>x?YtLw6GY|GtcUo7I1fW&w=UjYhHgyPs&zS5MXJgsmm`RpU#UTy@D`C}l{ z{Dmoj`SO>cE^aLU$F%1YKBY55acB8untviQ&~JXb&c6VA%YOwu7tm_~y%x}G0edXq z#tX=$Kw5HAkq>cK1sc&5wF=l{0e4p53+%Fhn<{XSd%O!G3wp0$20{vA#)2Qwkgm8T zzjGW}&@B}l!6?Qc=YsMrXm167$2}Bu4+Y&p!M||_1^+=d1>Xjdh4foUriF?kpF;8} zq*kE{RHhnsSx7d8WK&4bh4frV&xO9EH@=TTli9?XAhNJM7S?-VyD8j^&*(-^dZFLK zzN5m^kZs{v%t5||H?x!7?BfXfEqs#G=($K5^jxGI@-0$@>d3c|6&WjcVzMeG zE5DH(SQw#mDX!% zvz0bm>FeC&b`V)68u3U-64IjIGBPWZ33pef9eOUK*D`u7qt`N%_>pPMU>Q648+TDg zu4PW4RvGtE#(k7|fE|@}6J={*-(|nTdu3-ckF}Vwti6`?EtIv_vi4clKFhuhBFn`f z7IBetIr)|=LK(_aiQ0TfeHtR0a)Z!sIhmIG1^JYdPdT;9?O+#sk!!gd$flg0%jvnC zp36PuIsXQc<<%@-g67y`dA*mnoARf*!$Y3%EQqY2-wG*7jchBVCnNH$@BtO6LUleu zzZKkRg=Xlv!gTapVH@(Tup9SZLB18_Tj4AhxD-TIbbA#`(UPtVz)e+jQx)g43bR%; zYsK@Jv!XdG-otEu130qcE8YZ=mE>E=ZTZdL$V&Msgtsfnxl%bQP>+w1Z>7$Bj-D&2 zSxL=GZlscb_f;}OrJ1b2ek-kK18$|#Kb+(o7rD&qAhL24qG8vS^-?)LGOPRn^=U*? zTF@GORPMl63}F}}8O>P6qo>NUto$eDu9Ap+$iGTsyj8_pRoddttIT5=`mVB?P5jDM zwsSLxtoj~t&|g*WRki1;>BvZk+^X7bRsB`{nr|46_p6RUR#o*?RaRBkpueiWu#qkN z#x{2F2WnP(pKR2mGvBfZnO4(ZHT_l7Up3!QwJTi1uB+YR4)=n{>M=-25|Wbv{Z_a0 z>RHiq^-s`q_3w~h^@&VoJ_}jGPspdbd#n+Q9N1Bfsx-qb)^Lk8++q#0)-Y=gnbt68 z4Rh9zX$`a0Fk6j1?880Oc*HB-29Y)0Le1F3B>{5w+rW`Ei&LITs8{nt>f<(QHbFKu z2Q%&e6x>y~mDSn?;7__mkOl$g1St^-ixQCTu0<@mySux)g++IFBPB>EDJdl=5(*;C zzW2d>v|VF7<9XkY>-ztLiMz_VtDJty>8G4K%N^!NenPM1?xUM>k9mS`zT9(OVkgVH zvwT4sFqkOJro7!P|A?pj$BQ6TLEZ{!unQG*TOlJM^jo12B`Je{2P@P--U<=ut3q$) zA#(*;E67?w)(WTig|ql>D%|015ULm-`&Usf6+gsX6~mZg#cbrDI>TAUcAQu7SFYgS zxr*LcDIs>EQdV-4kFO{~F-oB4O8TwTg0^&^6Z)t$g3*k{o>W@PCcLB4F7~3YN|(6K zP44n1e+B+eYEt3u%I>c0?#lVmS7jM0e@8tU(uk(WQQ4d;%Tl>L6Isbo%(99%RnbKi z=T-Rz^Q%&rKFC>R5>uJZW#p*xH)dJoSrDrFK02+Mg0z@rRsB|VR#oRzwSQI3vZ`5D zEr)DXd*a-x&aFCw*_db51uSAW=34athmf`EaZX^yRo!1LK3S-Mw^bX0^Qt+gnscf- zr`i&31)=KA=|NuxFbLmj^*MY`6#o0_t1?wGw{Be z^446+IySO}Z9E7})XV=n8tsx9&6l0lyZfZ?qCeE$p+*&&^ zms;jh%Uo)iORXdL_o0?MYsVu8m1xg6>{)GlU3)*?SNkv*xW}K^rP>d9%s)Y>j+xf6 zOLcTwCp97Dt>b&ElO37sv_|GS_PEXzrZWp&)X`%dGpwVNIvcRBbrX^kyI9wJ>NcPe zoiT^H-dfjN>#oH+>w0J1J$PH)WBkNPuJVj`K`0^`F-b&XlA`Ab{YIFZ-vI7={_dN+B(b6)W#2-TOjetPUeecjg2#3$(2?*)hIm!$%gse`=r8=|lJGS`nn z=K8+J`p3~r{hztU4Q_LnKY~yLyVu}5n$ivX-ayX{>{J7DYOob=ZQ!j9e&-S1+2CKi zt)aIyj807KM8i+{g0Cq+aY|AKJvY>E!!~rJ3+`;FkA`Cyk9}zSCQ_H>`5Q`Gl(G!V;Kjy z9)ucsTca@f@rFjViJ$?EXhKvFYMcst)VLkaZ|wZWz3ImQX7d04ZZXbpyq-5(MMB#H1(dQt&p{8Uv$xQAa8aT#WWz2r`-XyiOEHS0pJwyfk9juJaWgyB%q*M7A}QY5+*_L$#XFmOXLB=b?rqJz zt-0=-N74aZH@822131)t2D4ej5|*=)9q70DY0hwt-+96_Uho?4Xc3#lxW7eCKIaR* z#tyX5TMM1FkfVhREzG|~GkP%@JKJI{8`#V?cA~2m7r4Y#e#2Z^$kE~t?gyck3DIB6 z?=X{=Bhgh$yVBC%x71n7gB;<iHW?eyV8$=3}Gx2 zkh``1S}$cc=h01T-L%$CYu&Vd7lhi_A;0MxY7>V{$lAuN+t|rAzPUEKYLgdzwfPEn zw&{tPwAsrwi(+M57*Kzv+3}z@(Sj`r;vx`F<#a^~Qf$yOGzd@*jyd8AYAt(CmpwABO>hKK( z`IdUB|+v+vUZZSldPSJQ5;=&(o?6}bfQ0l&`YNgxXW+- zhB}#Jr+LiBZg+YWggU3?Q=HeiJe4q~&feJB4*QMXQ0KWUVL7YV%vN@w=g#`=e1#j_ z#`o4)A6;S)n|LJTeKL@VEM&tQy2#(9Ebi`7mFl>^OJ};#8~t?|fH`+r&0)Nu%TJs_ zPhHM&k-vG$|1-SAzIF|WPE0_rcGdzf{PWgOyO5b7y&Pg#4)+Edn^sjxRa_0rQkdwxbKs#A-))W=;t&9P@kx?q+) zzvpNE2|~T1+g*sCUW=u98%b1(bcYcyk-fS!Blx0ku~`T_gU%Rcn72ffZ= z4|-ifH@%~g2A%fKkA8aVr?mFq#MugrbZBXi&4=(lfK zDxlxK`t2J@6PjW7`tIi@Pl8at06W#sPWAhQym)IrZ|&EZHh5>hPIz0tehgp`cB0=3 zHnN579N-{F&~rci_WOf}{Ea*N>!W{M5|9Y_`-gFV|Ev^6hW;}2uSgZDq4WN7^w(W~ zz4g~~|Ncy7751>duKMe$zpnb*pZ;gjS^vlU|L$kJz&G3fT@V`Z9?{7}VIuIh0SnlM zHw-w>uUz3eH-gZ>>`cf1Ht-Qo`48s~bnYPM4oZ!=53;j^ylYTy@?lnkzM&kA(CeTX z%*GB3a`&J`EJeSAR&$IKoWi>XdDkF!50Y!pW$eSCmqBRoM|?{Y1{1|zPGjE(o5$cw z+(*{IZ-dYfJ1|5CLt+w}49Ghq2cIGDko*+F*+c3vfSEXd$YPeUo=t3F8%Ow!2k3u@ z{)apZLPOm(G!}8O14He=&@XApDD*JYc|&)y2X7v#`=NRs`cDuV7M~AEfsTjic$oPO z%R)B3rVJIaJHx8c6uUFb?hNZeZ|u*oVT{Lp!}L6C9h;GV*bdHck;{0?uv^^WMGzXE z1bZ+%C!doS?->3K1*t)8B4~hF50_(jbG&udWV9TR&n`U5^B9rBJg+tHaQN>gMWE$e7mN6R{T8s0y8Hgj3UA%4NWk2br}W;fbh zqwW0Yhy0CQ9Fvv`v}XX$8#AAUY{DDIoaF-ccgzc3Phj=7J&tvsF*1X1kOEF4N zkt$TDCb}8hpBd^Af>RzG9iHTED!IEGn{)y-JljFow;%wuI9>-+IL!6CmB92%E` z{M5r7$H_jB2f{Kg-6=Y&Ui+k{uV z;aw1#XeTCqLN4;~1%)ZXcj$SdekV4gHSKWcM14#g#z;mph1G1pJ0{xYiM!d0H%z>W zEEDf=58Y3E8-yn5c#^v(xqFhkCw+~+CduHpf}5X z>t?dfC+EdklbtnLSCgC4kKv4BEOvYHOmsha9(tdAjl0M<`TytHhsiH^&D$U}B{7+i zZ%PCWXoT~pv_MCGA2{UqfkRWqA>R~pnKG3b%wjIzvjBHaxfz6}#vltN(e>29=ya-l zQ{|f~-_*72!;VZf->HYOCsU7MFQ%IDR5PAxFa0KPXsW!^-Xl60D2B|_WSu7KG+C#0 zp&LEvjc%qbWE~sX!gky>?MHs%6hGq|nVy64)W><#`(ZbxPr@6g+lT4)Vfslfa0$CG z{dewhA3aak?~G)8L`K4VN-pfijC|;3Mm^-6q0<@D(9aD0%y8F?C>FB}z0T0h4BgC- zd4|k0WS()B^VrE5{|2F%smPBx&Xj$o+03-NGmmqcGn_--nZEOxFVOAGH@pi%v-CSF zH6b#SmE6cX>npxN=2^XvdDeXNJ8KEc(eEt%&f3LZ_G9;Er==hjsEeJNZKq}rVm#hD z+goSv;RxP2`vl%L+uLSe<|=k#PD~Q<0Uwf%^n8q-=jeCNca)|a?wq5KIZbFzOFA(c z`#i@x=Gf&qvzd!G%-M-7bAI43x}S3e9nW?5TzAiP_gvrmTz$=z!S4!(=6+293R9Hg zl%fo>%=PZMBk|##K9gcN{YEGO35cQqd(@nNEeI7F`Ze=Mb<^@If646y$M2# z&3SQjVi6ZJTx^Dm&2aH&d`@1zz>Y1>Pa(d=o-KCg;=$Of#XoW{2rV&}C1K2b$u|_F zFqMd;F->VfE6i@mP~=@QktxW#WIlRb;_M|yxx?EawA8$oCPD{(BRI4)Bko(OgQeNX zL3M_+4EwP3Fu!tz2bjUKgd`>_xsi9-R}`TbB`Ad%E$cu}`k>=wBN&B!Smxi6W%Jm| zK7PP`%TDnN=eWQhybD6h&1<>4mb+`YK9}orxjUDCM@h=ioR;Wjc{@7NnQru;7w%lX zldC~!#d~Bx&nqHmODDS09eG#GWH!28q1zQvEMf_JIm&TPBJYYz{QvCh*w>Zmk$I)8 zD`j0N>q;|SS(WP4q#6AggI-onVk+)hX^tzGv69uC4??Trp#N3&WR>$))uA5Vys9_j zuoJ6Ru#qj8=c)r7$VQWYI; z8jABaEoK>ZWRo{;`jspE%iAEd`8{HgkoQS~o;T}vb0h5g<{=Dc6qA|8Ok~}>8hvbb z=H?f?=3Nll5{;O|AwFifMW(W~-mU(9+N#^FGH=!6R++cO!pyfNKnL5> zk{&bLmWfZO#2^;3iT#|#T(;dqpWD54ySHu+^C{lBJrCZty)Z>6Mir`Kx3+hu7k#n2 z+ea{(vCLsJdvM?OgPhyB%$4 zPe<&_j&Af|D%-ityCAglBMMT7)^wmVU6FU^bY?LZz3$Y{&c(>Q^9Xi#r_4Lg^D9@l z#;YK-%h|ikf7iF@WmgF*QkiPhK;~Wj(8;cGOk@fRSj19RunK+bj!hPHu-kdNYZF0R z^t@ZIyC<-m4Qyr``rZ8lhdGM5?taV*UZaaWaWLOKc6m=??8lz3kav$+?$PBQUG6c{ zJ?`3Lrh5i37~SlNLN|M4-XrrKnfI(^JsWZ7o~J=*Z*smt_Pu7Z*G%>X2kFb9S?cX829Eyp%4w>Vjl%ydYCFsFSR^Yrt z$2fsG9rDIQcH*#|IGmagnaN6S^718mKCIuvk+h;M9q36P`ZEyS9QF+zmiMqu58p&T zhxK#VU56j?H&27m5wkp^n3(F?a|VdMZZUz(Vk9pr62Mh9l|gcau}J9%6e4Rqp}|TkC*8BsGfdINM`KckM{3J zz5G}Jcl}rnbNsOi)#%GwPICk29ea-$nA0(DJeChTajY_Rs7FIu(wcVY`Ivr>&0qnG zSjsv!vW0Ev=9qmv_96%!*Xi+8=;ye8j=Sr4CbEznvplYwg^`Z~D{b>M$(C<%kS;BHwu^D-P+R1KY{^?B+IwA83 z`*%XWC$f?Q{hrY8iNX}+JM7+x@7c%CT*FSCuu~^vk_2x(>8&S=PzLWjSqX1D>1`+L z(-1pxas(5Z!gS^n#bWe)Qokopagoco@8n(nC& zi#h#L8gKo@TYu@nK)myp;dt9GlbOnN?8Gm7Im&TPa)DpDf}VfT@0nPx{e3=;w@n&baf8JI_pGCR@fI}SNM}7}NXX9c2 z&Q_v5X5%-5LuYrfpMxAm-m~|x3ukqE_92ha@45JVND5M8x6jFY&TgO6*EyNbwMOQ1 z_V3&j^m1+%OIg8c*0BM*cRnFGDNH%^eBMr-H>dLh@YeI*dVVe2@Xqsl@V4{E_=%I) ziSy5R7liy~aOgrz5|Nms==p+vFXZDJ3gXTS`nXV?TG*Eh_T)kz%=v^4a;S0W|0EMul7ki)FU=P9pD>OPKK$d9VDzUpV`!j<4p# zyRSO`s&`-Y?yC)mqzTRF$~a~-j|D8kU02QW>Q;8Ji#tK+S_<@fO%KHaGs0Y4MNug;*x;(Nl6+$A_KW8g}m2wbA2HCysppd?z%pf z2~1`ky1A~K>oQ-L`MS*4_p+ZKFx%f^keM>b{+phETg(=GL%;1|AM*ZoliTR_w|o4F zes9?08;SS;`*$N9^4Z|in7?AUGh-=4%;bane_5V~W(?>O&HKE5J9g(!ma?l|v`^X?4i zND%rxE`5T~-Q+m?Zev=|8Xey?tGm;gg&n>-AMd;CeRr3$l1=R9JeRq~Eq>=-5W4ps zv2fQt`*F{H+)K(Qe2bahi@-N{Pq+8%$UPbE$#8E7vfdkoS>H43dy~=ky&2f&duRDO z2>p?QFDOra+S7@y=;{x%`opaLkn>Mn{J94i|FjGDK=U=3Nka91Xob z&WLUv%lug8$1*?8NiK5Z&c~gZia9=({ju5n{UMpi#;1ISynk1wD!TossPW@x2{<*>*cZ!_&0b&!_HxT7bfM(^GSPTAF%z-%}ku)zMS^Kb^sB z-e&i?Y?9<0V=wCbfuQ&f&o;K+IUw!{Om-%?lzl*sPgr2=eYC_nD zXIZfW&-C={E54yB5$Nk#BlPu5U(Y(ynW4z|Y!g3Yrq3?$|MRc%8@Kp92>lnGn8ZQO z{}S>(Nzl`O=KY^L|Eq~v{3r8&ySU8rAoM&giO}owq?qq>S)c3l`Pby9Ai8~Ci%6Q# zoDRtQT*uFQpx@`)komc+&t-is>+?VO3$uK#&*$%g(2JDV{TEsAy}ZbYyIvHc2qZ}2fLS5?75Iw)t@5@n4W*Rez!t7q! z#g{A4&C6f7AB0}%^i_QH^GZLj-1RC2sY!=kU)j4?x_Kq@E16%({Hio%u`jRO`Dz^N zFvnN2zc!oKpYbilDMcCNeQm#9w?ntDJJALGz8=pEW@C3>FGb$ht67W8uO9`WH!{CT zhJN3q!T0e-zi;&W=5zA$1$OVvL^kjPr?FFS?9`k8g3#L-c zz0GgxhTc|2zi;i<+d&Lv1kU!Gx}mpr;_Y;nuoeBj-OGMtetVf~+`#>BpYnp&ybVI{ zWO$dB^n@|%cfP52a=a^v-u&Kf$nWij-c_Ro1DVBK=Ccs@zgx~K4sn!YoWR@Po#7l8 zcoBqyq~xLoT^Yk%wy>RD?BxK5ILfgg{9YVNF^V@qINEg1aGO8)i-)`m!qHQbhL6Zd zm`}(?4vJHT@>HQZHR*s%(R0er%^A%Ke&l!l!#iVnXYBV#f~>JK zq3hUL$o)ckuJM4!K{!rabQC8Q zX-SW{#`%ogkGKq~G#M|TC<}ThGHzsx^uCC+er6Au@jB-?|cCuim!|K&Wmq;@k?QE;&);+Q<%;y7NYz3%UOvt;{Szw z@t_Ao&!+9Fp1xe~~gpeKFkk8BC%p_>HmO5m;p%WzkM)vU#x z3CuNN628EWB<#XOqFBlbR!tcl78|u;q=e<9M@yy2?-`~d% zT)`f^e~i)a~%j)ZUr8FW#2g z+ft8W471t9ZtQL9A8>YRJ*Pg+FWlf|5Ka@FSi~g>$w*0Ra!?fWOVb1Wr0IuF)95tK zaNL<@EGy7Y8vUfvPa5~9*@E3mvlCg;T*BMZX5c#-Gl=h5$7Z&%gX8!&DeX1vLt6c& zz0L2u3&QE*prdq&NP)cR(vhA5G(hHbvZj+Yovi65Fqx@LX9;`JO}bO)CEYpPmCh{F znPs~Bn8`=UDTTRx)C=c*G>f^c!5cr)???9dqd$4VGhPJY^wEexZ1kL7zv;7*lh4V6 zKGK(_92ICz8|+8=E|_=vo=iga^zKgoJy9$|Z|U8g-rectP5&4f(#w$k{~2Bf;S6S* z!QC0sV7D^Ztqfr@lZ7%gL1!73a+s?;#90}fmEn01&S-uazosa~(M!h4RHG)fkujs0 zX57v$^qlc1=9*DY8Be36y1E>3jKVnpN~7z z8Fzkc?>;`y%OD&|#aC3P8LeqY2fQ()%g_|2F$0~3=CGMP?B^gSkT-M&`{Dn=5)SJ! zEOS`au&iNO!zIu~xGd#~peutI$_Pf|uJCN;v4Dlx!SLH4oGCrIa9*ZLRK-j(d1Iy_ z3}-&eS%vQ{(>8Xn8$D;zZ>GCE#@sTQTc&qGICC^&5*yuQ{tS6D>oju<^pjaXncbDS z3*G63UNh?^vu-lWoLT0~GG|`GGFEVe`$5?6-iALh$4_Mc#B4qp!(5_R%u?k2g-cpecBg$_vt?L|LN->oHHTbnbSLSrXUNl=FCq)3R48L z&KZH7$*Jp{y3W}Jd2{xn4>Q??%sFMvDQiwybLuwdBg{AF(;)nr`F@s`tmw$^;)XxV zjk`WG*UySmiZXO&F^9Q;^FI5Jmq9pJe7rGNc5+e@-%PHm)Sv;8G(pd~^qb3W_#rTnoA$Kmav?aY~lpJ;2pUxaTR^#dd{05{CPl3;-LG_KjKT={kgk8clYPD(bwlP zeBOxO^kV>n7|IAnF@`l98f!79d|TPYUiM>N`5p%0FMJbU#KUfXk(i_;Cl$GI_ZMHGw=W7&1pEC(ahfxb zc^u>xGJhGLw0QTI-ux`ma-gK3mnI{;CF1p1%BoXIxe8&0%lo2F9m!L1!Ey^!2~2i z=7JTFxuD%E*qvVVWfWtXz+|SfhsQy<&WCkm~{ziownH+-4wpSC9ZIt8`z<51H#z(Z(A`Ev-$QA=ef)^enZ|O(Xb0e zbXz12@z8IPOyuNq@=_3aixfj&MH(>_nTyC;MAjm*7TLl!cCwqFxP$%kTeaaLdMWZM z2p4r%QM+E$9E*NHQVP(H@yy40MfdRoXYt0OPq7ol5|fIw_*RN#Ase5f=VJOTR*`Dd zq&E5})|-ClyVwwhqoZQx?Kf@1#dKfHy~Pe=FN>W-=f!ka>>@fVX1>K<@HPm4_a4zn zK`u&D4tIZNw%=8!7Io=DckJkQcJ#Xe3}zT3(BXFn@y_CQr+8-cUc3VSzIc5iX+ks1 zy+mP}2>9*8!Uh*0pm)33R z41~~0Y4a^DZ|Qt|iOi+-T3Y7PbMfBN3t7TOwy>RD?BQ+@E|ZFHD2w@&X^q`0(;pp{ z@zyflT4pESS;jld9K+knoaZ8!_#+6HjfPz=n+UsHHZ^HUkDklwx2(M=TLt@2)_rBo zv8*|kHM_Dc(M{Qj*nzU{D(kMY`YEfQvhFPF&a%I91-+Jig>K3PL?ltj2R!Bp{|4a-cCSJuIx+~mT0zeh>{JDF@|&{Z3f@}5TPys7cls^aaK-oV zwu;_X@qIqPPE`Dwq7%%*BVA{oq5bXxUJ5Uv)Dq@*Mb>Bvc8iei@4%(7Zp%2N?t zR?}fM9aig(SyppywPB3F{Hh&A-f9mqr)p36F9=tUL2S&ey4=;xuKHKBVl?`%ZU?IG zVlSt;ig#9j5`=5mxf;okw}!km!ek~Z+4%-b2r{qF6H7iktYSg4Q5!9z4eOZ9-s-_v% zibW>$T&pUzs7pQMt<|4_=(g5ShBJ~VbX;o<_O8|rglx{cVy9`qaW zD>u2rJ?ysMr42{e?T8maxL$I;M&^35)|0iKto2&a7G2lVQ@sJq#QxQ@fA#cIZ!PYs zXYcEoqu;O%*E_=FAYA`rict;c)$c-g%&ERN)?bF5sDF?XoaPKyxW*0iTwlKpq7#Ss zBt#z#LS!ZjpHqg4ct-=f+@KEnYS5Kl^koo3(S3v2Y{K0Q+}*(44bG#l1~N3TlMSBp zinl?y;d{g&HgS=~@7snOmc(2enn^>wG}L*+pK(@0XEnSWgd?Moh78CZDRX3Y{C#8z z?n{VS=m~WH#q(nze%(h8J+||Tfo8;w7zNQgV*vw&^ z*W`Ep;AIeQ>WxiPla4PaOi_wcfl5?G&rS8)bRl-2>2`Lphf|#80y=Ga6MZ(*WwYqS zLEdHw$xL=+ZI%ajHv5WlG^HN{8NzVvNVBo%y_sEU<{N6J|7IKTre@pN$!_dlvll_Q zd2$L+mre{ux6Mc6tmgi%`AOt$eu=B-q`6L-|HZ=~+`{`?)TcSEXiGPG(g!(P$kbv9 zzU3BX)WZEOyuHO8?s1?0pY?YTZkdS0BqbSU*HZ5-_1-c)=GW4lEzPT?x3^rz5#(y6 z!&V=XinM&hXMBrUwfc?{l)|32YD^p2N_Yb#k>J>?lX zY-N6};}IekX4TrPT7QkZT9?MmT34hpy)c{BC%A_5TE7j#ZQdgZ-q z(To{NR@)gc=1Aivx9ebD37;w@U{+hh(Ny`>{f@dOkgt3?x5!mcA`TR>p6gaI~?ODWbSYiyVBt< zkArYWbL|+5xWp%nH+0Ow=j6qEI_kQko;#X%M;SUcAd;?(V<{^z-;U$Cs-pKUwej9A4UnyiJ?YX9 z8M~N4m*I@UEV_(G?_G}LTkM*MPx+4O`1`I+@r`sf!>(=lJqULzK|7q)%{;q#Q@3e+ zPZW#MZ+CgS`wqGnp$z4bwY!YnW$Z3v_eeT35`Wu$F9$fpQDp0WlAk%t-#p4+b)rVd%NP ze)}(DHS2KafcT_Ej|1%30DTO|jZOv>M;`;qV}1i#(3TFkV}Lsb^kOnIn9Y0^vY737 z&w%^bw*i0i6#Wc%iJ1~4!@%@-=Rn;I%tAKo&cJ4P$H3(rv(V}BGJcSSqIBHxHo1vcs!Gsirj=qA4$#%o0cz87I?QmTVPew{Urx12*_;-|~8a1gyJsL2A9bD!wynRFh-p89q ze9E^JBZ8*1pfz3SMo)S(iXZWvj<7o;9-@m8FER6x0kV$#5dDpG=E#OL#;%NPNgLW@ zh9k{zq)n% z=ysHDN9lHyZb#{Mlx|1MJ31z@G0V|<94+%`Sx3t{TGr9_Y_#`}Hn-9JF|W}}*~C`# zJ9;PRGtdKV$VX)?H(lu$)!sb?k9;GgjuYGLMyc>_skdB?ymm z=eTqf#vI4VKF(~$?co$>xxlZ;JMI;4(CzqW*xT{3NRPbZvy&5f$A3dXoIT#|jqi_n zj(7g}Md*0^I?QzZX0~FkC%S8*xlX*z-5@+kHUe5O(vS|_PW_BhR7S^BYog<+ zjc7`9x-lHHoI0L~M6s3)=zQunykqKd&T@fE=xpl0yyQ&~o)(Rm$mRE8!_#y(&3;bv z@8Psu`#T6vH{0oXsY)xH zH{Cm?d&l%iOl1bMxEO?Il)>N6kb8#QGvuBj_e{BG$~{x=nR3s}ivDKmZ{}Czrx4## zg%-#>)9%b%fbVMNQdY1U-`7l8XP)L4&LQ(moy~Oj%uftdI~H+>M*?&`J13u`li3B4cXly~(}zQMWv4Vasj z^kg9$c4Mxd=jwNEMHC%zLiB=ILi%Lfk)3 z=6Sx8d2-B?V_rVYcb@sqbN{>|d`C%2(;A)4i{dDEc^ibke;7F`4*;j$94G z^Zjr0ojv~>%wc{}isRh*-Z$U7=6l!t_Vl1P{TRR`ma(5}=y3jR+&%wK9`KkaL3n{T zE%2rV$w)zJ+`T}q1sMtPEln7PnJ@T}dqFrVCc219!$)Mm?nKENrGqH@7^Q=#vXsX> zqU4S0L|5dE8psfw9krapT<0$yVTYpr4Z;hf;l71&utN*YW8oLHU?j6xiWx4ng9}e` znTMF+A~Rg%or~mMWOj>mzDVbbbiODnX1J&_b*P7q7q!Iv7TKLe9q7*lrZNL}E?UVp zcCv^4*xf~TchRq0!3-AJ-$k!^7laqbAU1K4W3dd2v+)_Z$xA6B=|x}6b@5>IwAgzW z+vCNHS%wUY*RY;VY(b{Qmv|b4mwdpN)SxYTU*fDK&RQ~pb^M5&OKxzRyV#W_c4evV zm+F3L9CW`l5zbty&!swB+LHx1W9d!qqxYqM^O83~cv*mRmVJn~E-QwPmo=stEwRtb z?8h?uvCMufn}n{HO=l)^n1{QTEyVkm9pLvMyj-^BIVejjhGRy{=Q5utHgb@|9OW24 zaT4!c{+K5`!<<&gyTZFy#3oEhWL_cb3Rzdkx}pbWw4x7sT``s=xNC(utk}*jbhE-; zD^BqXXVJ?_GhbPWNZK)wA$Ygnc@3}Jj9ISy8S`9umEZUSJ+CyMm5+EEgje}~S7jhX zW}LmsKCQ}!`L8NX17u$1{8jo{H5;9-(&?&2EM)~pka?BNtMs$V{j1J!o{Pw`%AKoy z`+oa1yjuR%1Na{AU3~)YTz!rU+~WnW@b1<6UGpB%NlPZOke$59yXG4TP@6u;yhheF zvaXSJ&1&rKnhk8?2d_NGH|wUc7M-p;g?`rQXPvv&UFI4$ z(ChjD-K>{+z0B)nUZ0Tn`2csWuR<5halP#8&1U_RAiN<4aY;ZTuANIU z$DONL%f%qPD<0V?fb(`m&;WDV<&C?1Z@cWou2pPi8#_73VSYrSWArMtUf_JANLqNKD4ihz_LC5V7DNP~zV3L+p~N_UrpNOyO4 z58XM`dCtXib)0vt^Fvl9VyrvBDT2r5IX+jHHBl|VK@Hc9&QG1Qr zYt|yKHF{X%CfA(j5?8s-E$;FFceOS(?^6kTTsw@}tis=~mHS$`uiekVAYz^WZryy2 z;9k}}C7M@3#CkKWk4HkxwZ0&On1M{!FF~*C^|)S->-D&PE3#hitqpOAASb!Wi{3UA zz*`%N@D;VGi(ED|L^c~_v!NNyQFFr_c5^R?*qDTTRKyN9HsU*)(uMvEU?77Tf*dx^ zKyU8v#y$K>V zzfB6VV%E)O-CPB8ZZ_xU2AFNL+5E0+#O5}*zs;kV$P}itfJH1t&YR`C`3zUNj(VFP z^NbhR*%sMs@m+2yfm&PC+9IDV^4X&1mKL<89dg|wn=P{0;@jCWnz6XSEfetVZdt>H zAYy9_a`Gv5v$YSy8N*+UN55Ow;TE>acB^c+`nPH8PTcHP{cgR>1N6J~br7-bExf%g zlCs$6Ho0t*%eJ=sKrhtW_A7R~&2G2JWZRV>VtZ`TU}xLyYP((eUDt^1vfkbj*>3NL zIk)R~yNtKXc)N_ZPh$qM-M*J&oJ7XkuX2r>+~#Evu_F=5Nrjp_yuCwjI|lM6a@;YJ z(ad5#_P1jRyV%bmj&llic055AJ7lp_4m-`WGcFnVh{{x@2DPX|eS9Z7yYVA>*eRc# z^4Te$o$}eKr=1Jfj+}NSAUCC{hPQTkYnQxt{lec&Mkc#vGY@~iYa9CBrSDxwImbo* z|7H}=gNWU3Zg(!qQGtr+d$+!K>wC9ayVcs=h3@Ft@4!av?v2{Je?#B9^}Ty0vf3^4 zJ;`{VD!7L|Ju&AVbMCRzJ#KH0UiZvJ)_WGR7`L%!H%E~59$D|XjDGjr;8qZ^SI>Lj zMbCTXv9~5}W^Y}-rzLG@PY2|)cQ1E?h~`u}`l1%(~C4``TeQ`^>q| zZuXgNpV{^e;!k{A`&O`?O>AW!2RMwJ_sMsk+t}we_PLGyYVMcE{?w!+18#nQamrwh z{hw2bDwtt^YxJ_e6J3%0{=vw2zuNoN-mmul9ms3H9`+yPCU>~cBc2k?E8YYV2eMHN zc^$CF1LOIJE%^Hbaz7yV1E)9>L>$b?aQtrvy?yW=4|#_94tn>HxejF^J0bbV&xaJG z0u69Ohej}(aj1Q05>uIhdpKmKL)+QK9`>X5A$=V>#tGCsoSu(qh&>&)m&5-di^Fzt z_%KItH;46lSO$k*B7-Au5rd5A_ed`Cpx+~fD2lg_e8Z27WD3)n#avdR-jTIzz&?(+ z&7+wq$(Pi}4v)IQqkS2QZ}g}g9<{@xcIS6nBaYhLQJEh-$r;XJhsWZOloZJLSQhN> znAt60N2^l?lN$If$wYxwSt zy$&Ldr{R4HV6VrEAgANzJ?@T=*QEh^IQ|{YXhAFVbbJVN*v9Q3;zUAnAommAI^nGo zB^b>j^mIZ_CuDoVU7R?Cot|(5Cr)!Vh&Y*nZ!zD=smx;`W;C%tjf4V}Ch zM4XC=98bydR8De}7qgu*+bOf1s?Jx`rVjP_2DMI^?Nn2KVJ7x?$~>pdbJ`u9uE5vG z;-n;tFQ+9v87V@2dNCEfU%tTW zAmU0AQj&&r==Vx7iX+=Ar74SiuQZ?;Eoe<=^n2w;enQVz)}rStmyz$48{9^|SLAy& zAO^8;dsiFMn_*1EOiZW+ZGRzibwx}#*!%akeMm1{Udx>g9 zW11r8DEUUYy{JJ9K~29Y8xb{&xy(o1s9m^^DD|W4H|jX|vE!)c$nDx&nB$tB@GEZh+H5vqzt>|E@-daDgWX-1)AhzQVP+6< zBMEOerF11y0L)8tYQu8vHu%~v74J_xS5q4MDh;q^`?8h`2inc zo|`qO#n;qB?VIwwsi&KIx~b;P8EnU0-b#R5x>X)I+%m&0Gu--?4(RpPZ`jAJ0Ssg? zX1leBr7UM1`n|Pvx)Vgi| zx9$J-a7N;0Z{G_d?zpQv+40_;GL+*h%y_3WZvBp%x$_qjn9LmJu@E`mk?)-Y9OVS3 zkjEW&bLS;*f{43s6O&A+cQ-^AmYB< z@5d(*N%(~NG^IJM=tNg~;O+Z=;_dq~zAuaWXSskq-jCu2w~_w??>knOG{+>us!bMp?)9!Ods_8 za3gwtc#WIf;Xbl>B*#Z~_(&#?;_(6B@hhXSpGV92mz~(dBeOm->*LtS@3A=_r^0NH z&GtA4Asf8;0R`*bW*n9eK~qu-}1kk?Z^KYboVJk#^DEM!M6&vNk*g(*e}O5ygN z{l#kb;NG9f`I(z~Zcon>W7g+peO{bTG3WCyFxzvpJ^z}z$oKg#48-j|ABMM|%lY|4 zCbNhQ$oKgUd~?tB{QLr!xyn;s@+OFgev9;&CE6^}@{Z2UyOcwA(e@oJyJ-DH>nGZ6 zM)yVCX#0(}-{=|4#-5|?IeI&4NAJb=9(|Z&m_J%S(XWGu7xw)^W-rY4!X91>MfNZJ z`})FtzL56|xxHA2nO3?0y2CRn+#+o8!~*Q|5y5dRgyB8;Z+6P%`12F%H6!O z*H`=T-m3>Z=2;N&S{AQk5{Gzr`*nU~@VXf-XiYmh;D-EeY{csy8H-)K*4t~Dyq3vp zH}qPq*K?4|Yc*f%`%Mze@kXX^+B2AmOk*Z;e6tGqz1hP)WccO~N4SF>zKP~l5C*Y{ zM?w;lpUO0&BVFiDPX;iEAq;0EYq=MMZzUr;?@@+wd_`kA(~V*L#RMiZhxsgIG3(jH zX|8aMn>^wP&v_AqZ^tJG@1ow@A5e@El%^~-X-QwydV3l(QS)sz-(JL0mUD=s9Ooow zILAdUb2SKK#2_c1(VBtGWjiN0%LOi>-oIXM{|Cp7xoluJZ6n$)>ykaf;nTI!fdgkxXw+Y zgD`dqGLi-RjGc$PypNn?%Qto%8q*Z@V*fxVy5d%1%O>^|{zI+UYQ>gMZ281iGq#$s zZ*V&ZBvAP)Qr=BpP9xc>?Y2eAdH)oRHP+6`i=WBZXvF0w4puvjqA4KdOL0(CbAJd$JMLfp$+5eHSR;)VBBX!2VuN;=sRABT;hF1 zVTxgo@hajwidU8D*hxJ5jAv)@&SUoY0WmOh{A{?1_--QpmwZh*F z%7vXK%13_eHIaKr^a=V-WT%PTUm|yrXbZmMM3=CuM9+gTaeUHX&cu1~oh7bS_;!*EW+=lM#Tdr1f>XQ-!lZVXv=rYU=cI!e#z;n^-=zPtnsvxE zseF=dL(fUCa|=BueZ~u32Vt^+On5ul*L;gylG$mp_Q)q$XS$;2WO`2K29qsfDa%ne z*;aP2n|&O>ca!{G+)Hv9B=;RA|B2q{J-M8dFJT#bk#F*ooI$?HuW^&xybQt=iAYW= z(vXWHd`wBoP>%BWrc#(Eg?Un_n?hzO)J@Ts-%vY+8%i;gdDwA^#q31?DGs8a6#7YV zntMT*(tcBBCq(U(?lh%4O_?9xa!PZiR5zt>DdktFpRyj`VE=xzHcUC5RoF?&H$j*x zH93(}s`v0#DtD8rJ>BWa&-~6n{$wcfPIV3$rIJyqJ3J+tS9m*hGQ6GIZd2E%A?`kP zQ<~F?w)}v1Q+qe{2u3lMznH)zrl4kOx1S~!?@)ne$TW>ROfwGirJ0EPNV9=WY+)Na z*u`b+G>uHtJme+%P5U-6(R12Q&~sYfO4`=6qXV)?E622Um{ulf|KK0424T85q{V*H z6{Z+pU=Qicn$E20`eV*?=1eylv!$ELbY|k7)9vFpzP)s3iQ+o9kaIfurnk5BS#S^O z)l2UV(&xt=q%VkU(!2TeT~I5%TIuDJUOws7Os{788O%nm>9-@B^n2Kk`%8a>W1K)u zzfBuv_?U+D!frDB$8HXAn4{=7!!z7M2H9qK9fTPJQ zKxXusU60xIm|c(AKj0JU;BT`JVK}20i{7$NWD3)<%j{d&hFr3{sqC`JE}QI!aEsX= z1YwTU6s8_>&M^+X=djltd)UuGF7b#bJR_Qy$RWa<5m~X*2zf-jhkheIq7XIcf}SJv z8ll$+z4||?h7tA`F`tF3=bjATL1k@AiFjB3=xz9Q`_(!L_?E3!GVi5$utWE!~>`9#VmQmx3NoZvKe z87Z4c+2qu7PCe(;b51vyGd>A?OelHh<)a=^IXR{#aV8mUatGtZ7#cgM<(x79LE`pqrl+%nEBXpRmi^YUY+< z?%PCT?|EdHCk8UilbQ@C6DklV>&S@SWuGo#c^E zo?YxEiW}VGE)RIjQ|$I#_22ynv%K4t(Ja7w@4AO~-NU;_Ie}T;m33Z!leZ)tn8H$4 z@*n>F&8x28gAMau38Q$P!64cFamiz_yf|}H(E_RmR{pNSS`CIW5-pW6po$Nur`41uA{PN8&-~4jR z|B^RB_`zGmKxQArMXe7Kk%V{ok{=kwG7jVZ3%K6`afnYsGLet>`2hPaPzYHUsD^$E zG@udsEzla77w~ogc^6p1F1%mh7`~SRm$2Icc3a>E&x7#8Q_|SVF-sWBqeq`p4+{Q=Qh@d#1;#>Gg#vjS}BRBC;9qQ4Nz6@dr!}*(u zxXq93^rPkMM!yARQ!p0tEGW-{Y86aIO49HlvMDH=f_g5f=Yo1JSeA0QpMrK`53bmslexa zftx7Ok)Hg_FAQWbLy>b4`4(BqO8!I5qTVj5x1t~L5q4ixjzx=8nd*E+ZQ9eBZu~@V z)G2CzMP*S`7DeSy)I3EOu#rm? zEMgy5@m{f)ya~dO-{Kw0P!WB9TopI>aeW%{E#CNeD*F3)Axn_M$7|WZCXR432#d!g z8xiQMxW0<(tGK-tFMwSX*IV(L$fmej#nmeQ4Qdtt4tG>s&EoE(_zrFdVTpveff9CC z!v0G%pb?F+zY@RFkKb_{B?j>)vslbOtYAI*EwPpDTnWOGanW;0y_VE#NxhbIFD2be z$r6;J3g6R-uJphzOR81Ut&|+f2u87v`$1UB9hb_1_ez!JQ)*$xQeEiIaNI$uiA-TG z^Rcs1axNv`QYX2D{gt}T10M5?=pZaDo6^~Ff2Czwx-Rl5EuYeAm2O50S|iue1CdQ> zJ(t#VX+4)7%U_H~&C+Lsu#9^vV~=I@UdC?9^kN7j8N)dATV^$Dk!_icY(~Ci&T);K z+`;XY(Qg^IT;@#>`mNirY)SN7R@R;xp>ty-&K+6MOo^jGrvPO?HZ;WTZgP z7Ce7)?U#M4MGSireUMslk3htu9 z4)k0>&weX6tf1!#$FPG6FM{y1RD6KD_^b6+D`pjFO&E^0%coT%5>-FRCa2{NkaZ!4OqqM0gwK^3Y|mj<}YijC>SALyZ?-BsMoHg@9f zD(>eHZmFW3Rdk0H-A~16+9x{n?7q?kF7bfJL0DOS zl{1i;Y((JpD$A~NA&T-bZoTqo+;!z0n7#6KZeivs@ySG1icp4fxE;T18&+{QRldTW zt2AQ<>)4Jgs_f+$_EhBz=eQq)U&g_kUlyknW%-oPu){Cy@Jl=VvMoQ*keXRWI`Yx1)lv znmnrIM9d0z)p6v58qSu^SC{~XB*atg?crTk&-l|BM+sigIYDz zsv(~m^7Q+)q2I3!Yy8eYX5;Q^$fm|3ma+`@QezdXQM1OYAgq~%vV2Q#Ca{oySi!&O zx8^C%AlsT3xP*Lbz7E2#;t-!iq(;AAWkgG`V$==rO@^g}LR`S!jV$9N_&6}$b) z?bQm%#s`!{&b4Y{PqjK=)>>w*H3f6lGH0#Dn5~xCYOP}fZlac(sC5h9S1tc8)Uwao zF^Nq)5|Ew(*lTU|YL}rRm8nW~n$Uw0s8w4&wdGS=&Dv{N&nC7ao7%FeeT^I3<}MF- z#FHTWTFtKu@ijg98#nUxajtWR`#cQ7I{K}XiZsZ!P6jfOg~G_V&L@<|ZP(Fn9k*Sl zHk}xQp6lqfj$Z5NwayN9A@4eJs&kHKL0C5y?ys&~>Ly05y7pMtKI%pgiQBK+8~N8= ziudXs;wVv=v7Vc#=O*gq;9cIsKI;{uIHiztJ^9vaK?ge1jXwN}Z>XMIsVAFyOVDpU znby0BeCo-k-v4VoC7M@3SYNL7Ga{S%dakeM`g*Sa4tdCnn)TZ-1beKn_xg6zAPHFs z$whAT+u#c-BijbmsDXSNw52OO_zAb&K)(&#c7s2e$3FDjK(7t-+CZ=01iX!`zmd~7 zsd*3g_l^7eMlRo!L#=Pz{WtdbOV%{az0i79O6EH8raTYLPr6t(!C*0jT0-|GL{CH#kezumx2_OPFW zLD*QvjkDqg8oR~DvTj_MVwAw!jjQ49#=V(>_G5yB37s$082$`CdNXtN(p6Qj!|Ie6QyBX8XPe6Isg{qJyxxn{A$y z6r>`OLKMM0G?#C4-(d67)WHommr?WP{D6L&ccnXeZoUdVH@C;;vT1&m>&T}0b6)Z$ z2wS{GZtBq!_ut|#?5l-+wb;l$%-X`NEnWvyvZFNVwRTAg0PjGTj`@!I_$bt zHgX`pR$n5cR;_4@tXj#cm8@FXL#q*tW*l;BHHoQAM=z~*AivfDcH*~f!`8BD?N(ZM zrW-%<6EoOL6pwgHG_QiNjl9~(tBoDEvEw#&+@?5RA)7X`Y14!@w5KE9Z_}R%tl%)m zILR68wvFD}$feEoAZ#0(xVWXZYPD6XZF1CVn+Ex`RkLj!^xW30ZP#&@7eUz0-L{iu zyOhYYT}}#9l#eMvDaue6yKL8t7T9S!{kD@wJGr(S!++@6@7ad!^x96Z?QUUz?e1fT z?cXK?xyVC4@}pLJx8D8}%JUg^*WQh^-@;M6*Zv95gYXCW{$R!*a+8-&sX{es(tw6E zM$SLT_lH4@Vl00%omtFfKC=1Y2>R_H(+-J|PY3yQP^&|FGLaRzc92a6*>uoz2R(Pt zbB8aej63YmnxQPk9y{p0quq4;fU;DeB9+i@NB7#XJ+kfCi7v>u<1qeW0+X48emgE= z3BK2k4}!3ho;&HalU_UNwNnm4WZg+lor+Km_t(k&b&`wUybU|4)yenK$sRlX#Lvv; z6fc9Yb0WOgIWO;HPo2%!xe;!nb5DNbcLp+&(TqdRo#oqkGke(2Ax?9Si(E!FUEE_A z{dSRQmvYFbi+sAM)uk#msD)j2>5Oc;=(&rYyXd*gFZ@bB)bzW$VV4_0*wr4p>bx&}^xHLx>p|GfH`whR^xRFa-SpZ`uiffU z4_SAUQ@3{fj{EE8{<_Jf+eFmrwh(*lwu}{=55n%rDZnRqulsj2!=AdEvAgfByPN3# z4{KP@CU&!z1IXEL>W1AP@{AX}3c?=p=;20s*lCYUWFZ&%`5fO-4|mc-);-M8!yG+2 zA-5iO-9v6Y^w2}jJ@n8+4?XO*hu!v2v&T_RV8=bqp>_|od%O<99|K|_w;$sYpLh9` z#>nVLd-!o3-uqGRKOW~~5cYhV3}ht-dhVGAyY1=kd+NKVzI)cB0dnstx1LSu%3x-) znQiPu-#yjosqdcp?y2vdPk4@=d&=u4J^!TkPqBzYJR*_RPpue&9sVTupKkIp2z$Ln zOkyMJUV8178?*Mx$NPMMo9X4Qd&#<&tb56zmwtOSrzQQFi=KPwwU=Id>9v<^d!5BS z_PWG_ApAK2X_3*-naPG)KiliiA5w@Se9H*j+s|9^-p^OLPIM6VHe>JfxQ*TgDM=a1 zQJF8Pj+}eTw|6JH<2HKtLeIS?GlSVIU@=Q^pS|5?@59Ktw>f&7qqqM1=)X?{IgwQ# zd+j5qJ_XQ6AN%cNzkSs0BdQkR@Xv8m!XBFpp6NJB{#(TfW{g?NU#V=p;13mbO z-V9(6Ll}lPev!*B`upV^7rDtD?(;AR`?`m|vhFL}zE!D#zWVB`ufF;=#6J7lXJ5Vb z{SDdlRjaRBeg8zQzIM@f6!PhN47c}dCO)PvZui&U8O%_IGY$Lubp`+OA8S~L@8#DE zTqcTp==awrJPX3#Qc)N^|EAa9^!l4#e{*xcwWJO0=*1YOGmE*{tD;ST!k;~=LvgPrx0b3gg^k53BhuYWqS6OxPE$fkca z^xI#i{r^Bd{pHhNt^T7K$9U|rzij%;roW#1>$$(4`|n^EzN`K>g7EjmxVPW!@prxZ zec$l+g{)@_+u4bJf4{{YWc&LA9wFZWNk~fue1ikr-T?g$aLWVU;|toN=K*>hpw|I< z9WaTh$a;XB1}tYE?r(tm8z7efS5RxfW9)Ij3tk1`ACc6i8w2p(A9I+GJ^f+EKhAQ2 z=pY;zgV@9)IVnkloCnHxU=d1CnzGcR5#QlP2DYLN_BwDNe`1b->JA)>x&!4qP~QXf zJy72RuW=KZ4Yc1u@kvBd?0Jwq`+eYWP)6i7s1$B)^r^L*IkT^Es8M!Yu54@J{xypA*P-upS4?W$?ow{8Ju(y0bq^QigI=pdyv2N)6i6 zkVwl?0(2}?0(2><|4--avb6gh8*Mw z_BcepL*y{zY7h>!%b}6zd8l58>UF4Iht}e2>d}DK{KjxbVNXNss_zM2zKaTS<2uHZ1 z5%xGj?<4GHggY9sfTb*FCHft4lGDg`#Ca|v-x05ZaAa)ak&smAcVq@Kq34nH(eub( zknhOf@lA}B?@0NMoX8ZW;r2$p3BplX$xjK~)F?MKstG?})=_31HJLe>bJQZtHp*;l!kTNOgYTPbM*)SmZ!u zmM7_Vl3SjX1U*lxf}SUJLN1ef@DqP9n4yed6mDy9q1+z_Fz#^95CMKWc5?8U$$q#tMQ{+5FzEj-Zl+0v9%_;9vj?bw?HEN>% zly;b7iaDmpddkoALGM!*vYlPXYKn}f$Z5(k^fASLr`Ye5|JQxVn;@KO&r@R(n_QIP z8-B&!rpkV*?5BEbs<)=feCn$poR*pl=zE%;r$yrLr@8HE`ktomXcZS1h_ApIW)AT&ej;Go2G_|J(=zF@pr^{@*tfu?Ur`zXr z_cDD4@}4f^>E@hn&KYlEr!(|ABP1v9kcYf{iaVJh>lw11(E$Cw=&bWICC81aU(P3I@7E(%{uc2b~DqQGwo)U*=Ct- zmRp_`kF?~cD8(toXH=vza-JpMS#D#N+nD7xW~n(#9g zFr8V=Zf*cmdAT{a8O(8y~685^dEkEE+7t46@&-}u#j9@;?v75#6 zSiFVp>|zh+cpQXF^t&Vv@?0WMzyBL9QEQ3YSmI8XltMO38uBfAUZUqEdS23sHnd|9 zi?PooPlIr&-j~|TQhQnI7MFfcOIoAfrGH}Pr6ZB+(!Uswo|mp;BYIxCmjfK;DDLAQ zZ~yZiA5)StltZn5YEm0J_4~i!Kfke(6Zj_o(c7~4BqB3rUsi(B)IqPy3e+M%ZGyl5~H}S8V`1dSP*yq2udBQVZ z@G1ybB_t#t`Ek>$isP17mBp>Bszqz`yJ{-(StXxU@?53XswFJL?W~f`D%q?$iJn*K z*>3=ct1feuYeD#*n*Y5+McShG|K_ukQ=I1#SJ3b3IK)G?s}qp~yIY+bcd@!4MR41z z^}D(PpQGp11JLv8MaXyca{fiWtL3|TH~X;L)oyRiyHuh9Epbz8>}$<1CSq2<=Nqos zi#gYrbIlpdw#IC0ZgLwpu{IT%$wmZud5;f}^IG|?tw$5SN4>Qj=|XpYL^f-ELu=Qd z)>^gJ%4e;7)~dPoI=8qRgzMzGE-|uMmx9!!B?Fnrf|~0Z(uWyr!EV;SMRL-Ro{Z>s zeF@ycdfBf3gin$0`bM;%HSOqze%JRxUhDO|egk@5@BY@`KrZX=@hS*61jHaVadCSa z8q=4NOhL{Y+|&kp+He%JZZPY{SeSF8IX9-nY#XzZoe12-#xJNzZR+wJO=*stH_CV8 zaQ?<#H>$UBE(=(UTiGa^jqY*dqafU*)+V(!$!C*%HmSKu%}qIoM6R34AsfFd9B!&a z6{=B#uTXQ-Xx!hXGrSDK&33c7FrQJGs#Hh6n>*naHp_N%4|*cs&10C%H2mAP*==vu z?`F5XSzepLY-I-r zIm|KSyi>kApYu8hcfEz0yX3JeFYhClT?HwEUGH)qeq%V?^*Pn4M-$Aks~`5f>rX~7 znz1Zl1$x=Fj*V0UVG%V=L9!{ zaIc*9rl$}^(brym?bX-bPx0;U{Q|x1wd1|A*{hb{84maQhWDzqw>v+g=H4}&3&MS} z-QJACG^Ppe$ZrUT`!Dc-H$iwno(JT4z%3pqfLRZi^}x57^ME-Ixa9+8J7Bg0 zz39ylX5$VHEMp}b*o2)Okn;ig9=OMI?C*ej2jh}}#3V&F2MbdbwGOIvP(BCcb5PBL zJ^7hmkn2I&9F)z$nasgAd~hL)S;~GM1>qt0cBm*{V>gFJGK0A+U=jK~bP%_2NVbQL za}xO;dd%w}Jp2|haeIgLdpHI1I;`izHPQ3o9{hw{4)JScej0>F(((=k zk@FEZb;O>Iw7{%K%z9)jQ!wX|S(xp}KP+b@ZsN#!u5*jKJR_P{$oZ&zk7gl)oTz#9 z11j<*)v1ktw~nfRv@_;7YL26_KKdK|(fiS5?BxKmI%=RNZ55 z6AODjX3xjucI-XOdaNk}v4dk9IfTDIc8RN)=h)34Jnp|czLh&ccp?sRKOy%MsWHOkF&VzvjH)PO%jrmiZr}KN%VVG zHfOsc&$IG8tJYcH%-MbnU?#JX%~?I4)$>_BpIy#MR-xwE7eRO~6Q$AnIXRzmtLNsk zgk`KizvoVH3fZ1J#|7kj&dr{WMO+e)68)Y}PezJR4?UmP>v_GN*X#K~*y(v$pO@45 zsjOxPyOGQJgQ#`>BKCOx8aIOQf;+xYj;3_MdlyDC4tu&_#tUxvf}6My#XTPKgf~HW z@hxH^=Zo^a7)c)T@ji0AIELxW!kZW6c+nm&ZeT0=yr{;-%UtIczK@HKQ0J2UU6REm zSzMCCr7UFQBP!F37PO`v9q5ej8%g zLp&0Y2>C|kB0nEe2;X6pexp960(y?>kDjCKFUofi^$#nMMU)()b|RA~_ZIam2(RU) zB5w9tbAF^3Ll}=)ubK6l8@(pKYv#P>ySQeyYi7IV7OveSItZ_)!0xZx{q^kRAusPE z=j-ylZg1Bc(-ift|3D|Y(jD1cpTd8rbzQCN^0_Xb>uO$);s&>a@J4)Ob3-;alHvYt zq$V91@U7n{N&|jo8k?}28*hT}W>Qj-mh|ZN=Et~&o3g!GhEI_1&2RXgmb9S@`n}l` zdEM0W&2{Mc<`u3Xmz#HZ!RsKr^%gOSjoZ7`h&~Kw5_0xC!=c|64sRXCthda1I|d0c z=k4T}?Y7x&XCWK%z5N;0aJ#o_HnWvu==Hwc-oM2i?(rZ9A0)sXKS+a{e2@eEK6r;bRG=k#exTO}dVQeR z2Y)k>$xLMlyKs*W?D2s;KDdBd5AO4br`YSm?AYDIPW*=V9?oDkt1#oklbqoRZ-VgA z+r%O!M-!0gqqWHAk$fJh^=K#d`)EIQ z`A9a8Wb;VRkM#UV&yQa6ItU*JWTG@~?Xf*R*85|-d3=$FJmUqgg7ArcpSam4*^up% zketZ(Nf|0q8Tb6e9Y4|U6LE@TJ%6s0(Nd{KrPwBQ#eF%|dmVm9+wh;QY^G7fT>W1QeL zXSsk~ytopCFV%b*iQHed;t%HF7G9d^GhRfU#(;nYgor#qIkqp?CI63AbhRX>qI0a1#a+l3EDA~ zDR}SoM(qE!`+aT3*H3sJgm2vK8~6GqGrpBKxp|lOknTT5qm$om)X<5RZf;CMhXMMOxC6ks{Qm7gO2D1zrb{ZzUlm zX-G$Iicy@Bl%_1@Xh1Vs(3;M4<41mCGHW@;WumyjZK8P<_<1p65Q}^?q&LHu$P$*Z zl|x+RdJq}oZ4zM47|AeOj7(%98}IWO)u>5r8qt`hd`}npGl(Im8ABd1W-*uf=s(6L z)Q_>93+N%n|9iN@eI5ppF=ZZ8A2DSYQ*JTk95XW?P?7JDRZLmMlvT`jbUm3#@oRzPVz8_jPDlX#~?QGP%FM&#?MF=vhg{xjz1nb#P?qO zy&S;I@$Uwa3Esv%C$N9NGaTu6h9eWmIDw246s8!(`GPSlMuvW0I5L3@6X+|!Zua5b z1TsnRJcvw~ocC~32|vPH3B8rD1a2bXCp4llP5GXdv_=*Qf1o33CX`1)-(|uVL1ZFX zCbIiPU*Sd*wW2NU>4OXtjbt=q`3v(WTFyE);zkq6A(4I)9p)%{PMjJ&C$^`=_LR5` z?kjOMYEqlJ)aN%=a)KK?4I-1o$Gs$xWs*FYHHlf1)WMud%$cM)W=mqWB{yd^`F~uBYS=g2)uI zNRbQmQ@uZ(Q?ADSrPOcAUF^l%DIW%rsgh#uR0S!*$GE>#c9u%L zRMl{QscP{vOE|=3?gx>n<(^vZsnZf7x75Y3>(p*FwSN76aAfLMw52^AuZ1Ql_MXYEGtFWyvdtvhOtQ_in*YC{$IP*b zM?zAO7QJT9#Cw#Z0s6|Uugv<&tgp=a$~*x1WFCUvGRr3O64c79R%ScMtXAf=tVhi( zZ;^xYxZy1JmSqa=EXzv%!|t=VuPo=d$p8N?3j51qe_3UkH8FOVH6?n@nicP64XHpA z^qW;~S>0FGp^RWM)0oK|>@=&p$`*%Q6yZ~3nay6ZwWd4f%x2DPvoT|~W#~8C1~%dQ z$hIA~kj*V*^G#%XiEkpiJIJ1ZL?k6S*(gd`)XV-E)u>5r>d=Zl{DoTCWs_Z&+11Rx znQiQ353lczD#8!a?Wv&$2=oCh>Xy0L`E_r+lcH$5J^d7 z98r@l>DFc0~7 zA3F*Ez|KN95}G|c!+Fdcz78TI-9)6Dh|Eht>@)IX%2A%r`GUI0H?ln)=}bQc@+U(X zhr5h4N2Kf{|3|@Hg>6-C;R2pYiG-9ilFpCr&Y$k??(XjH?hX+NQ4vW+X_Qa|5lLwU zQ9x2U*1Znyqb>7&#xusZ4)(S8zZbg>f8Y{-V21D(|DwZ4bkgAMh_@r&j_4~=1{orH zi?pU49qB@MdeH}2A`AEmdyTlG%zDY3g`)UYX5Y$O4tJe-9s0=Zx0iVoW7aIoS&6&IvKF_V#kaHgc9x?Y;{+!;%~^iO z4zgSh!mQrR>Q=JKm$d`qS&bXWYVTR?JnMNb;8wHRSGEBA&lZDN#3lpsX3I$)y_h+>eP_SVqae%?kEEnP$2oMIBSKcPQ;dl$!nbm)WEJxHTg71xx0J)TbLcRK z{&M(s4!4xUE#_OgqKX8aYgD}5Y z^UIuH*8H;Omo^px6N>PK3=r8|3hAC9%Xr*g;VVH{ zb&SV z9`GMed4ZmanYWnVWU(})Lxy4@S;$UKWGYq%J1%C&#oSM^W4M`OdN1Z%#eA!HK!hmD zQ;F)-!oM%x6}gMcUEB_e>%RB|e6zSdi!WyjNBNuE+(quUOJqgv5^|UDW(i%Du%i;&_>G4_SW@35(__w(<}8_w;>cRECb}+Z-zDqgeoFRY zFuE?O>ynd@x1{}-oQ2FKe?jJw`Y7oROTOey5SEI|dnDq0lA)hceVEH?Ht{`&a4V(s zTFR`Y%o>#hb4Hmn%5I{}7L|)UZA5u9 zN*__*vWq<&#*Id~&nR<5{mXqG2BE)89F|UqETvPBnh(fJRlHr=+oio-+V88hzDmnb zdH^$-!#oxuM`?R5ElcT-Ilx7p2VogAmMMiBFXMY<`r%f}3}HAUk++Qfmn}^l?5AuK zn&IuT{@b$t+p?o@UuDO$f=^h>=X}Xm9N`!zIE~*(+26SvgysA;%ej$qnTX)7%H<$8 zdM{Uvn#fSjos?^YJ(O!fE5@*l9b87{^7dce&6W4>%NL{w#VLtDPq(0OIwuB_+ERcMP_s@#_W3}yn}t2_<2Re3hwaytmC#Nz|9q0=gEq>BAi zX-OaYGXry0k+;fn+(ec2e9i`Ta*9h_MaNa{;3ld(;874(jYeudBs1Qtnx8@x#ZIf% zpdD_ps<*0otExV$>a(ght9rBQ7i{Dx$IwmHlbq%(Zn5e`+)p)cR!c`2IxrqRSKG(0 zoZ&ndkhj|FAgmss+v?GYiGHiQ>FQa@fm^Qb2CK_ky%hSY-h$D{TwT`cvR0S1`ewHB zH9N4^>R0)f`{Umk zTDqvEhg#*RKoj~h4fj@S4)a-r-$|_%=%m)S$WUu92RO(Pe!@O#>!h|>YFD8%qj0;m z{rlPW3$YSiMuD9#TRo4yF_4}{u&APhuw}iub*|CFqc3N*D zx~R9Dm8@b5vewf{pf~*($T+-L ze+tvFkNV&6PY^bULu#^MhYj3w12@v3IlZvM26ouM?i$G3!0sC8yun)5^Er0d;3OBg zjE)=J!u}e#odyqru;E)IA{i<1X2Tp5r36vvykU77(3BR~LBqj}U^Ek$%v9uPC_}?9 z*u+-0^CN%ok~cxv$X*-8Ku?X#+sGX^ijWl<8s#D{1t^S6jhZolx$NL9cZ0C8-W&T? zW8Z50F8*EPs`&34x14e;khcS{djK>}tZ{$o6HZgOP#`rf){F^5JO%r=-VsB0C zt%-l%#GFmsQxhFG`TxH;&qc0a#wIuTo7+LyG&bgIYQClkNX+{rCnc%zW>dRuDpS)> z*w0m72Vt}KNP-42VF=(oiz7PE|x_>|B2lCRKB3wv*IKL}guv}Ho{(^5Yzz11=e z>Bxv)Tb4mLEoE*gb4!_9)}%Id@n*|;xY3sO*i!aZcGJq;wW>f>YETP#{hi>jRX=pw zY7j%vZ>#yN;A8v-T5UkyR$JJH%&qVl;XI()(iQD zBb>%fwRTgjUj<>CcQI=lv$iRMIop`CO(o3M#%ygG&%b4db4dk8qx&4wjGRa+Kyl}W0}Atrr^!C zKXE4r+a)A7cGIpK!x_VPCL(XU^|*z0x^1_SP3X7XQBHA|-}w`H+x>&S+Q%k4GPjqt zy{zqJZQq<$w4oh+nZ{z=Uwgf@Uxl~YZ^jgx!I&`E9Los6qzqbx< zqQlqh^cihDu_Hii)JH3tj>tv6eWbb4*ojzeJJJ`u?l>}O3d9w<}Ui}qTeoVtIK1a@iGXz#z4QEmy-PI1e{(@Xx=xGw|YlW7WdG*6219^?>U9<_5P2iLDL)xV*vW?H=89aXC>>Ax8FuK;a>aQ55oR3 z_m{Q5to>!}pMgy1y1$?@;7*3rqz&yc_Yj$f=y!;Ihq$dF-?5v0{D_|Y{oioN zFI?sx`t|pJ!y(UuaHyV#CLtLqannOTBqycN{ZQQxt&DevcBBhEahpT?F`YTg$1Fq5 zGV~+NFx2})ucM!#xA+(LIrI@vf^eAGh9xE`De(TVw4^5^H{ADz+wbr%*~Aupz&#F^Z$v_LGeS2b ze1Ak5(jnJ~kg~`(q7wE!!oEk?&xktIqXFI=VaFqOaFLfmI5HJ}e zJNh$_!3ymBC_GFG2R-ZpE3Fw{;}~v!Y!dQeH)GxI*inpU5>t?O>=(F&vAP|*nXTw|>~YTWJARL2|3coechJ|k zxa30Sak7q+b)2l@TG58~_}z>fz)alVIQKVBFXPtWt#N+qwp5SQ^PD)5paVc+QnYvo+S4qxhHvRlD8(^M&?N}PkP8>{{Qw1KnWxA)Mb;^@PSNcY z`<-IHQ_f+(Q{N&!I+|*?Q=wTBc|{0?o~GYvZeyC;nC3R7`QNT-`j|GA8O&lmU$O~%owfrvK2827DWZbUT^8AKlD|g&oZBy&3r_ zL=kj6V+doBd&XquFrP&%!8d07j(juz;vd|_40kc(883oxrXA086Elm`m}bZ|Q?8kE z&FqApX7)g~nYx*&o0;C4>8+Uy@z%^`tUy0A?PHdm&iW9&&uWX`$E?{bU@=Si0{1*? z5BqQ@vwq+ZSNIz@J?kz{k$2YX!2c5?(h!Brvt^wv>ugzP_r^YF4`2`zS;+>zVheUT z+gq~_a)hHC<4F+C$%4C{(-hyEGn5g`#Ef$`vYDT72XoGFoLndizp_XH<7g*WFV z#l6k5$9b~PvzvKebC{p`gerNE4dVis6i84C9!{WW2Rx2KKzfn@il<5}B7KLtcLqI9%F?u}oqr(^-Mv$uhiM%Vuqn{P}S)tDr-dZt_g)BigD|EABCo->)d4^u ztSe<*DeKDRe1xu7>S?9DuH24(R=U5HdRcjm>)7MU|9Hv^UIpRDA&s!NkEdYvk3VAr zX8!mmF5xCVejbFYq7jqWBq9mPNI_;wQ-$i-=c>juqb04e*Hx2|chw&Bvr0d!^tsAg ztB!Gk-_Xq}-K=_y%&TNxCG#f%ZxbDFeo~%}Ohxujj&Oq~yyQ&~u6_%7S7+oybh|nW z*|59S6>t};>rkH-$h*279gunTT4Y{*6#cILl~d?_oBTKU&Lz^$y+;kr0v!rSY-z0TX~^tG-sGOW|v zx=wVZJAMP}aw5;OW6!QrR5@V!sv|Fj+rX+m>a;@^C_mq$Uk-rm-m ze|-^(Qxfm4Z$(?|XuYo2ccTaTUO$bQ%wr*o+057IV7(63>tOx&oW;F;_Ac@8zagI` zCMhXMO#up14DWwdnsQV`7ykZl_}O??ahSh&9fY61M>@>#c}NzrlatSb@C�#nm9( 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

$sI6`Wm9IA^IBf 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 z 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 z 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½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

QG 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

KCb7 zq;8S*tY9U!6{%OGUXgl5>J{0>E_Tz&A@qvUE9wZ2r3a^S8d^o2fmTr$pjVV$QCD*f z*J4vqHWf7py`uDr(ktpA^on|tA-s%zMZJn%QE&1t-e%MYK0%|Xuh1vzH%6mLlqOM{ zL?w_&68c1?l7==>IZP)PjiNM)(kQBiB`jqbwRn?Jb?6nfiq&jlGh5IuO0OvUiaNkS z4xv@FR?%8TpMp-&Iz{UgeFkT87WNf=As5k~0bIeAXcj$?JGhg(&@5WBXw9N^iqqP|6GuGbNkFrhRMOBZCWqCO9>}{NG<8&MMJC%5s>K3b4><UzbJC+_CM=wt1T+ZWsELHyP(m#(9%*Pw*t##c3C(UEGVj#M`{XyS&E-j6knAJB$08@A(zY;xvm(LaR8f z;!@BmE*0-GZVDOX;BCegQA`Q?#MQ8br7WWsTZ^khueeosmvP=@+-A0*S=?^AIKV*; z@i+ej1jZkUZt=Rs+gAM9oP%cZn#F4tuUWii@s~1yE4Y$@+{jHl#KSy-e)0On>ld$I zyngY|@jTvV{F}Ume(}Tj5PORs#TV!o|06%~Gxil9OC0fxCxJxtjMpwcogAinehTE*|Aja}##-^t#9!0|_*)%ZY;;%Mw{yxomIiJtUA zr|~+Czl`44+4#Qn<8rR%8gAt_Zs!i}VGz2F*KNFR!d)UjL{1p(GpjU!k3CD3fCtynn7jh97qgR4n33?^;Mxz9M5^m-ebV|6N zK|H`<9zmZ3eG*<^C~q*F_t7dri-aGrqlBOMnP2#o-v}d|2y80BrV6Pl{8>S33imQiq)(^r-Th`#Fi3vqfbIR`#8vd91aLf4B#kw(34(V zgg%M-BPoh4F_LSJ40bI`w48(>K@8m9q@Dxw;4A1f$dL`(DOg zCcMF<`?#M$Jj^3#n50*dUP;5yDoLv(t&+4#`iPJD49${8@im$y{YD6(=#`{bl3q!A zCFzxy8DyeUl1@oFCCy?sb6CXhET)N7tVXXSy^_4cq!wDSvn1~@Nvov2*jUnE z{2dUOtW~mB$yz0M=XmTa`AoD+J{wz0wzXtiOCHFL+{De?!mVhPd^`7|S@L5%&J#Sz zGrYi1-r!9%OV%t|vt(_O?J4;ue&!c`MX%)1=#?BsJmX0q5$%%Gv8&{4a{U+!)LB9$5P0(z@-8{%c=r-YLUgRa-=L0mFU{@3DYQhLU;d4guE#INl z1g$0nq0a<;CM02J6DFY51Us8xXA|sef_+VxK>>y6HenX?u&W8>R8Wa_6Y5#TYV2vk zPTJ6E!fy7^j(ttgZNi@cfhk9DB!Os@qEU)QDH^4m#o3(0xoDMg30H6>S8+AhqgTpZ zXq9pggLs4?JjI*5#oN5YyS#_@nW9~ab}65sS&CLE-(zzrQA88NIAVz-p7CgwqFKr` zvdAWfeDq4uDy5Y9EW+MWYO$@9_1IO)MmAwrDO=czZYjE@=$6vO0siGb4hIBI?8V8P z!l`ICQM-xSP1J7U`CLFhE~h^O&}-uL+{W$PfmRbAU@&$y(XJ-G%qzUgYrM`-bepK# z#7`N?XJ|I@E55_VCXOZq?I!9pQKyMh(P*MZ6E&Ks(ZuQGQa~Xkl=3_FHL-z4npnkZ z*07d!=r>Wbi96|_GaxWE0GmoZl0c5)Xu8pZ<2VVuQtc|$u2OYLwW(B_O0}s}jZ&}S zS_X0>_i`WiqgSe4sgLsnPx2;j@iysp>!x+v8KH(d_MXS{B`I*s#6G0?;r6%Bg zrs|ZcQ>sp>dE_$#%~CZ>oy{EdN-d{?N|vx3-BNW+)h*S|Qtd2Nv(y6|6fNo+6kPpR%|V85BjC)m!@CZ;ef#O0FJwHfbqM*w-ZcnzRNDC+RjxuSt4M+Qn|VIDmGOyK^i( zIF94dak7q+b)2l*WZfp)+2o73m`k{VE4hlRxt^QQZSvjdHTfYP<`s0B{2H$_lsB-q z$@VsRIPdd0qxga^`Ia9ULoj2}ZnCXSwzbI#=r%c(eC%p+0fo$@h+^z)@?5l&kDBS9ZuecolV|>Zj;;4ZE^?y?`3O~ZEeaiXg5W>DLv3@imgpKn{zmq^SF%O z^x^HY-ljaw^Sq2!Q{LtsKH_6W@H4;gE59+CAat9e z+mtAx(QHZ*$xI-VsZ1k_Tnf-@ie6J}Zb~^zu&*gCw6c!%Y{0&zY+@VR`IrAV91xfh zz!4ltAV+aD-Oww;zA}1pF*cQPDVNckKJ=v@ww7UE8JcBimZ4e3ARa)g46QP>%Frr9 zs|>9&w90s!chD+Bs|>9&w93#bL#vG67)=mbWoVV*eP)b9qYRBQQpg~a8R(N?Ul}u* z#XJ^M&N6CQjxHIxWNc;&TiM2TcF@UQ_VEw8W$2cnTc%c-$DmK9KAC6Y{bgQ+R+(C5 z-oQX^3Z89sUL7&VfR$)V#Hk7GV=6DeE*&=M2u|d@i6Lm(!mCXqR<8w{bgnFbEy9bj*5@mw1_1coprk zw9C>i>s{XCQ%3R`pYs*pp;y*uf(RiB&9XGhnu=CgT4iOURn~NJDWH%t7U2zMd4pNr zV3s$SrB{|-S#@ZXrBRmOr>w1PL$9nI>|_s`W&ML@S(;^c;}~?y)-7ANY~8Z8%C@oW zOSz2RT**~vm3+AJu6trD!jpLjk33}8%?s?0|IjbID#Vy zd z-eEZUUa<;OK?d+hFz3dAJoUY4sU8Z+Km+9R(mL6y{y%#!7*Jt{9oR9Z5{SvgA zZa>rQXZkf{2CQ=U$FI^{jUVD!qo`!jPkke>z1J zQ-W^!y5;MZzmf*D%GWAit9-5U*RU47@;9=J-Rz;AeH`RJ4hICz2%tO1(gVAiaUSP$ z0T*%++Re~zMn5j+dTwAKH*za?qSp+)W<1EFJcVX6G@CJ;_t9#`hiEn9V@6J5ANFb3Ul9_<5&6tR8GqT8M26LH*z0I(<8H=c(mgUq@k9ITknz5d(Y(twF zhxmg(`HR2#Cm^uk2#zEWy$bXyIGIy8mEQEBFFFr%?h69Rcx!^ZL}#E#TR_ZSA30L1wZg3S``FgUj_D6U|$8=6xdY36f($UD$~%c zK(hkP3N$OwtU$8@%?dOts6ev<%?dOt(5yhSf@W;1U=#LKu%9jtpkIN01^N~I%YPgW z2rN7by$XBM3!5su7@I1*l*`bsP`^U03a{iUuI4swN4G-V3Uw>Au|mxXAL3eIs9m9Eg<}Xtv%+X%(5z6iLd^;_E7Yt|v%+k0D4-C{ z3N4ncB^~kNbI?CwP(}Jj;vdHB+ydZ=u&rZ*}G;Xf@O3 zW@oy79@@>+ZlSW7eO z+01tKpw~>jijLxFv?|i7NUI{Pih6J&C!tf(xtz!OTtFZC(hr@AbSl!RNT;GZv9Tg= zv*;cM^B_<0G|!+}k!D4&@(%Cv9>dVA=u<}W8>0zg48iDEq+gMKMYXPOj^lWGaw>Y2=v8t)7tn{k^y5};<96=g zPVU0iO0+A{tmHwSLbnp#N^GsA-eyTXdX;#aC0dniW(#_i=vAUuiC!go zmFQKXSBb5a*jkCL%?jigx}({w6X?Zh_`7F$7qh&JS^nl({^nV+#F2= z+So-0o%qgKzH^puo8{YP{m0>ez}dcU_EGr0*~jAhW}nE(oPzf?+xwbrBeQK}_C;Jw zZ~D-m0bI>B+`vF?;a2Qrw!O^0kNdHe*$?p;k7GBppXPa9;1yow4c_Ek-s1y42i*P`ug zO=s_B9|!p-AaKr+=r`vWbeq!?&E}lN*<8q_T+S6}G-n{%%+X}dAhekC1kds!uk#MW z8Nn#N=0|>EG@(QiM>45okV8Jj%wr)HETxVnTG+rge9xRt4&r;}2GEV;>B;Gw%Z2o2 z09P}R+qjECxar(S7=nAweGYe=`#NqocNlIrcO;|uiXZSjbAyQ>h6E-uiD|gc+(O)E zuKUdWood`?uKUbg!+LCfuC34A%K`ol2%L8WM{^v#IE{0#-+7l|xAU&yMsDYB9^g@) z#5c_I4fBR#gY*3T^FG1m=6%Oc1QA9Q@k}6%Or|q~5=tqfl4Y!96|HP$J3DZXdG1i^ z4y8xn?=N+a(jNGZ(vxtP(o^w0rDtJhrB`wlZc};<*K!@#a|1WwEta}jshgF$S?L4V zUg^U;&YQf&+q}cOcz304S89u;zQ5G>mww7fbSTxK^m~5h7lKG487)e^w^H{kO+}Yd zZ?AL;Q*qx?jY{3ObS6c(bE!V1wYYI<9rdh0v(g4uZz8>?l$R-b6=Fepwiz&xu=KKEnzJLB&nrT6c z`C821#7_3IkNy13KLLRYx^WD8EI1ZD7U;3Sh8Eb+f&pBCEiJf;tGR}2xsDsTgF!sN zU^H3qBrowYukb2wpv{7h&}G3-=(0eU1-dNIWq~dWbXlOwf>2^eA{kv4Od*4OW>A18 z3rd*F@945XhXuZUfgLQ^%ocW_!-74uqs0O(798Ra{@>%@fWU=Ea3tN(X5n$1#3`J? zIb6Uc^r1huawj&j@ILP6K_22U9_IyK|0 zVK8F}CkC5Y7>hOwQ<%skv{|Ul!a`=^9W5+o4t3PCf|WGTNE55DrG>V%u$7H$WgBhi zwotc)2hnZe-vNPT0ccjHS(!IgWK_EUB>*KjS@aXmLMkQ>plOph`> z%7!r<@2KnpKI9{8r%bCdt;#-SB%kp)qxb^t%Csx{ns4}lU(m5Ega~4YCkfrkbSujw zn;fR2W0`hkvni#Faw@1~3Cq#2OvAD!HlSPCCN^VxWwuwgn=TG;kU#k=AaIdxi;kuj znk_noQ#p;((QlD{i!S6MF6MIjqv@iXxdrVO-Ns$m-=aZ0z~el@lROg;xY*yhcnxdu zMi#Hf-?`Y|x!B*i*c(~wjVyNS#rxRLA-s{r-pJyA0|Lw4yWHPh-i>284!1AwiSH=) zx0n0d%g@H&UVZ`o{_;z?jDGlr@+rroyf&+@|6z+@|7u+@|6Z+@_*0Zc}juZc}kBZc}k1 zZc}j^Zc}kLZc{M`x2bp-x2bpnx2bprx2bp$x2bpyx2bpwx2YJ0+f;mn+ftxa@r@=V;O@;uz8@?zYkvJY-kIRLk*yauveu3Lmev8{w z{)F39j>c^&LvWkQNZh6}7PqNP#BC}k;x?6&ahu9%xJ_j)Zc|x^+f>fNZ7NG~o61GF zO=Tr+Q@IqksjSCsDw}Yd%4XcAaszHtxfQpmY{P9TJ8+xIF5IT_Pu!;RKisA&5Vxu7 zj@wk7fZJ4^jN4S5f!kD_i`!IPgxgg0#%-$l<2F@S<2F?{;5Jpa;5Jov;x<+H;Wkwd z;x<)};WkxI;Wkyz<2F^V;5Jon;5Jq7;x<(u;5JpC;5JpGaGR=caGRJ zxJ^|AZc{Z5x2a0NZK_gmo2p5;P1RJ~rfNEFQ&oW5RF&X1Rr7G0sxsWBssgvET7uhD z)!{Z(jkrzKTHK~;J#JIA1-Gf%iQ81Q<2F_Mahs|?aGR=sahvKRahvL6aGUDmahvL1 zxJ~uxxJ~srxJ~tixJ~tCxJ~utxJ~s{xJ~u-xJ~uVxJ~sPxJ~uFxJ~t7+@|_b+@^X6 zZd3gnZd3g-Zc{xJx2b*yx2b*~x2Yb1+f;v!+f;vz+f@I6+f@IG+f)bRHr3&{O?3=z zQ#~HHsh)t_RHx%M)tR_Wbq;P*Jp;F?F2-%D=i)Zi3vrw3a@?l62DhnRj@wi>;5OB3 zaGUCNxJ~tD+@^X5Zd1Jnx2fKT+f*OIZL0slZEB9dZECvVHZ{lLHZ?tQo0`*bo0_w6 zo0~;o0@*OP0f|KP0e+;B!NVdn226Wa>+xhC3Bd|JW46U zc9$%p7Oj?OwWNbi^jM`p5a-ZL!YH@@Fq64RGXzA@&)=V)o1C~*x1sa@!pq) z5K0(YEsaBurFtyYW9bYEC}bu@6jQ=1bXxj5i&@GtbXvNaHLRr>Z+huwcCnj19N=I; z;4(dyokUN1aWbcHDyMNeS}i-1bJ1#9e+F;`H!zSJxtn{qm-`sZBRtA8Jj+LX%m_Z= zQ%3R`pEC;0mT9)^TYf>OWub%-OB|`Bkh!4lfDieIj~T&de1kVu_ba~dmma`J?tj-&&)240wy~WZ?4*r$ z4&dLi`v12%91ytTSbA_A$74S$PUT!|XT|wwwL+^EccRA%Jyz(k;$H6Keg^RXgL#lg zc^Yk2yuz!z!@Io4r;NmQR(NA8zT!KyS}~dw^jM+CiZs%h#AK$BK_*ktX@$47VlMM2 zrJM@tsAmPXvtkwgEnA`03awWB!@uaULXVXJ9Kn$Uaui3?4V_l@;$%+Y9CTWF9{Q~8 zOFu5>O0MM=Zsj(#T6sUOpvTJBc%7lV!JE9r+q{ETE8j<}m0$A>-!hsY#t=*xQTUBs znTS>^wOTosdFZinJ_}e#8H@Ox#b~v%8m(5YW({lE#Adc&J1aZrWG{BK(mQL=s^Lh^ zMvn$P8uVy5p9{EW<%^ zCU2}so2GL)4}F^SX}W|y*iO^cXw{@u(~}J0DfDR4qe+jZ=XjnMc#)TQ4R5PSo2HK$ z!6$sh*L=focw9G(WFOH5yg}+i`mR!E?PA$M60Id)KO0}Ewr)@ z`)RVDrgl2es!6L=J?VuWt4`rmPUCdW;7rcqY;;<68CP&6I<2~yTey|mu%A`l*(%#v z^(c>_)hex4>9IgFpF;{{jM6A4w0qv(;Ly)@tW-pR;#sI9fBUK z^;oUP>Ifoa6sUiWAMh-9Lp)3%4wX=+1SsT-tE4+<2w&qW!TYLt=4W}Bb#Vr7rQx#H@5Z<{^Z|) zz~&>+s<{Ujqet_lTt;vD(3gH(PJafVQ}d17iB8RT^B@oLG~QUV?KFF1%`fp9S~Y9c z{3Ac1N3$Nyzw#TS31SSvj76trZ>xC%DNJMs{Qt+kBAJ8SXITE0W8meHi3M@uSc zq%(=hOd*3zrlM0zA>LSvPA#RBQ$ZcJ)3Snxtv91pt5&Tq@)CNq>d~r4>ubEuP~PB8 z-a@BVZCbzJOTOYKekK%etkrf}y|LC9;?b&AtJYb}W)6C^>d~r4>wFflkTMpbPph}p z+DH@Hv~FY*`n2lPx`W-=PU``@vsSHIwOV%uXQIbCJ=W>5?p)5}d@kTZE<&eu+N`^t z8yLtP+{s-$#KSy-?X2?~z3v&bTK6iW&|{q*>-1RnHQ(?p-|;;^@FTwxf;Q{M5z9nU zNh6&Myt8!$*v>kw)@ik_fkyOLr^mY0tYIz9w9v{rbXwSg*%=J=WjIP29{a+{$g-&K=x?x3ylI^+R}yS9q1zcpdv$ zZ$Ilt@CjP2*J^zgkM(iHGoAzzNg^4Y)_Ys)^T=lgvzfzUysh=Nv%ZogEJv&L zTCMM7FM6!kV|^C~ILIOX;7|TSrw!iLh7&lElQ@GjIg3lU6x-S0jcvG`E75AhjXcg1 z=&?bM4SH;NnrC>H=XjnM&}oA<8$RGeKH^KhLZ1!aU_Tpv!FD!;qSXeiHcTfMJvQjE zL5~du6f%<{iYZ|(i>N`H4NGaDk@alA8{1$z8@ADgRvWb1cpS&0$3{Ii>anpWy*Qau zIF-}TXXAzRr61aCyq4>@9(&n%CwFl-_hUO7wc0p@;k=I?8}-PlOCJ;Gk`0&lB>9yYq%DzHrdf8tu_tf0R}UKr+AuY zu%Au#v*~T#;a#-aG=eecv1u$Jgc3$L5kwM2G;wIPX$l!+l1Dz?)+XE8G>=lsC`YSJ zT5Zx}({}XOw39Y=v70@#(?KU){2dUuS)0vAaWp5<6MZ(H%;}uX#dv3%wc4!J=KHuG zJvQsHS&z*R@(>U62#@j@I&Icw^HAR4O+Mr!K4t{=v)O(&|Hx1Lj8>bq+B^wc*{sKA zJvQsHc`DP$BAXnhGlN+yM4Qcvs9_09X~K3kuVxLcY-AH{>_JRyv5tR!@Io4FoyF! zI&B%n_jqGlblNhO5JCyVezwG7J6lrl&bDZ^MXN1(Y|&$j9$S8AG38WHNfp)9U`JaT z(Pqm!*0Yl~cCj1#*|0u~m<)dTjlPpZSGf`Hj)&v{jp}2_%xl zBqozf9{JeL)*@!3)mE*xuBDk4^w_G$Rz0?EU?ZE@%ocXg!6E+O&w#*ffgFWC+w|Gi zgA?(tww;0PYBwrREP7WCMr$2L8--NBvQ#ogS)z1)XR+aBjRp63OI@&+H^jcxk~ z+u1gfFVJe6R@=stfF9fQ*p|!$QkY08X{3{Zx3x{1ZN-#O#v*=aF;y(30o&Q8)i$lR z9pn&tZ2NzYzxbPf_?Q1U91yrY0G+lU$0?l3X`ILT^rat{)1Rxbo$Xp}*J}IIJj1i- zv0abtdTf7@mw1_1coluN591R)MVsy4@GajF#2A9Ho$cX7qt*5#3Ym!>+x6J4$M#vw zW)5?iM=3gO*JgV)^{ike&9u72otoW}N+Vd3a|#wA!K74n210u|tm?4K&ikDps?GwKTJyZD_Nj1HV5z{^D=` z;opG3ok!rE?L2`K(Q2nwJ8fm>)#$NPkDYq#yq+5v$c@~@&D@T+weu0Q+4&gH@*K}& zJ3HUxE#77rAEMRHQG}z%PCa(&u``+&#t};#@r*~Oos-BWhv^hiObNELa}nOyPH$|d z9qshSc51b=kv-_KQ;(f`?A*&f_S3}y4sr;c+K$BUPn$Q^c08wZ24`{>_S1F|w$tXF zwRvZ41JJ7N2J~ptqwR5?;7Nw?6i@RE&+;5Ep;g;(-sb~8<8ww~J8eJlGrwR*Z6Sm* zj#%_)%O#I|W>7#OGby4Nt=i_IRa*^9SV{wp*iPF9HnIsjYHLHQHm!CY$MKxNiJU}F zdT}zRa4M&v)2<8Yi%z?A+I2lQFpwL$l{@jyc6n#JwA!WBE?e29$1Xi~>9OlWKH_6W z@ClzXk}vq4(P*=443R_;jqU96#&&sQyCz~syE2(dJ~OCBk6n7~(qq>$YFSPl^{ike zt5}CNySB4~ef+;q7YFzg?`*d>w!0fz?bd2{ANr!lZasGQX8>1lC0B7Z*Pzqx+wjJA z-_IbP;7Nw?6whHlyWhk++wGn0eusC_YWE2A*d5GRLI@>{a3Y8#3axg>q1EmwWT4aT zJo1@=?d+aMDf6+T-4#@_oI3Q_y^}U}v70@#(?KVD(QNlYblRiSo^BjNFHYtZY-x`- zx940g}?%tWg_evkGnrkrKevYIvcz24J|H@9aqTJ6!Q{V0w`k9IxU zyK^i(IF92vffLcG-8*adThx9rmv9AFqEEX%?bmY?cX2oOpjEq8?RL}t7J9Vn(XL1P zdkkYZ@ACm4qEovz?S7Bi{T{XdOekT56G05|cxUaYXw|M&dl|OUu1C8b?RvCVP)QZl z)Ubr*G~tc4Ytz1g9qgoyF1)dJ+i5?<-y9AI?9i&CI~SryhaMezbX>}1^rjDe>Br^h z)Zv|V+|C``$pZ|=UOK$7j;DEs7qFcUtva;o_?{ooqeG7lJvx5jSAJtOL5xAC4sAM; zNM-_=OhuoLEOIGe4z|;wRfkp`I&|pJp+m<;HnEv4Y-JnU*?~qKd(f!kAO7XPfWXdf z97A_(rt=g|9m{9Yq*x{xRu+u9i2LL>b##pJiz04XPxgcjN#Z$ zr|opwPUlB_%n0nL^HWCg9XfVu)fvPXqS2~z9I+%YfhlC5Q)eEPR8dV0w$r(kWz@2q zI_hbp1)b{=9sG&^A9dPMr)GNtIEv#rfy?MkANtY{+u7Tn0qC~(O0Ghyy|=`i(TzqOgR{ z(Q2Po`|f8D4=|Vqd5DL3gh$b8pH};xLaTjm@Fs8Z0Uz=OevkHj#n;%;K5uZJR{ONt zH;KvUu}_bEnM`FGS!9#LbadJ`i-q{D+P8=rmS8*k{2uLF#cEpc7WZkjPpkb$a3q1~ zv0sninq33tNnwqmHk7}W4|8z_1OP5 z@9-|~F^u7S#OHWp`?cBs13`=-7~9$JjqQ&m4m;YPf>!%8S%4n<_1Le+{@+|o*4G8Sgs!OXbJ-YPh(xdAlF6I(0|Z=*+-9$k8L{m4)J%rE@PZ;VE(t`Phlb!pR; zL^6|^LLS~&m+f?UV_n6}L8~sUx|(T0k1jpB*0X_)Y+^H8*osbF-d5LM{2q1v#oqye z2aZOc1IN&vmibl^qa z;7z=(1GaPEV@B{9U!v6ktqvrRh#m+2$J||jM|JKCyq*)>6T> zrKJG^q(DNG0Hr#0cXvviw$$C--Hp1t;CA21L?~O&bM8IQ-RF5*$gGk4=Kp=OW|F;+ z9_z2*O0HrRSF@UHxPi53v;IEr=W(9E+FJiIW@r7Yyve(0wO*_B8`*>&>-AV4>9LLN z>|kdoc0-5&oi=E*A(<4K(}HyL+0cH*9<4TLwXr#RY}8|8OIp#IHnb&!c4VT{#vWK> z8~dTt#-S8ob~cV>FZRY9ZM4odYPC_Tjb>$|9vk)8sK>@bS;=7>&Ji5RQ5?%DoP#zS z&*KWNM4yeTxRx8a9qVkPb+%EfjaqGd3q3aKu~CnW@9{n#@F5@ZF`uB*#_#wIYi#2m zY+-9Cc9YrJWQ}dI#x^Bkjy9#D)h4Yr<?=fJInmo0f7YE74<<9-H*obUqhwAs2BmmvAYUq0^@8S<7wQ&VxL}!#sld z*<^k;y~3+#wMnZ@zw#S;Y|>-XpZvvoHn5RRY-W2Xc5@usY)&SH=CmLkYizSMw%P1# z?u<3IIh!2v$VZROdTgG^BqlS3sZ3)!Gtg@D0cf>(F-s_AIV(5@v$Od)j^|`fN2|?R zZN8PY=&@Ok&3AAocX2oOa4+|v)8;36k(YRxw|R$mvBox=oy}ihjcvBZHvfoLoBs;M zZqZ|l9$WO-(uh>jXiO8D(v0S`qCMJd=}r&&(vSX_oh`#DWCZ4Di*>d|t1Xi;D_iu~ zqQ@3Jwv@4yLnx<$N|s@cwuI4Ui#4|8RL@Fs8ZHt+K(+HCob@A;FzSkDHwup<<^HGxF5+N#youIRBYO7XTPvj)@*s8}?J+_|4>72ot zoW{+H5W^wN0CCkMjgC z@iO{sdlmDu?OoPkcD8A?O{?u80`%Cf$96ro$CE%JNz|i0I&Ifxds{MSM;2W%FWdXl zkNynA>})SUtL=L*8$Gt`v0abtbD2jm^I5<`O3-P0C0@U_AIVXi$Vr^TxtxdD*?uvX zqt$k;wm-t7=&@ao?Rso~lBal@XLy$9&}q9i+dt$ZKIR*~CDP}6e&%;JV|I3EwL_~N zt!aZEJM`G0$BsFMo zhaNlh*l{#rj^S92<9JTs6wXGQ9hYz^`s}!l>$w5*v*R|*&W`)hYKK-kKHx+2*rCUc zPguvNe8%T|!I$W?;}`5XJ2tW@6uUEqSmKDM9?6)Uoz2l|r&c@j8Gs%;_1LM$&LIq? zfME=$5S?~vvvUelnZ`jBq0dfzb}nEM*40k4vvV0*?bK@LgRoGZAJ zt5}6jJGI$)7k6_HkMTJA?0gdQv-3sF&d#^cYNu8^|6)CQ?9^jtq{n8qu$66WXGbV5 z6hl4IXiO8@l0iE%=|oq0lS_YwQouB(GlQAz$NtRX01jj}2QiODET)oWEaxbWCd{dv z#_62FIb6VnT*+13$NfCOgFM8;Ji?*vht0TucIqBw>zXl1Za6t!RxNF?z)45tBzg0~p941~Y`A=oGUj6PU;(W^n)q zGMl+9pp2y)f>tqyaV~nqoX-VZ$VFVtC0xp7T+S-Ain)#3xq}CIkcTikG0*ZG&tr~a zUPr5#5BMEDV*cbW*0X_)Y+^H8*vigOT&z~HTE#XZl{8w@hPIfc*ba0dhhFqXtJr}| zM330XOkpb1n9dAlvLE}SQ|x?7(J6K*hjBPZa3sfY0@hjVnVf}Iu@`eYdc@wzUEIw* z+{=C3&jV-``zTt)zQU`##(TWa2Yks_e9bplbFsgmRqV!4TwEjch|?pkF->SnGn&(a zbXuZQoOKr0nQU_CMLq)<$Vf&pnlV^!apM@zbY`GO+#!@xK_$yr&I%4?C7Q)qb8#o2 zQ{0)H#YJ4qC0xU`T*vjSVJ%w4-N$RZ&KtbRTfEIXyvuvM&j);hR&n;DxS#ojO>AZh zW+~1r#mCZsh9sj^yjJl!=n>zWT>8+Le)K1gdX7)ANFNBGnmPKSab1nIG9Cf z6|YtN>F5!!N4y^KXLAncavtY%0T*&9S7Sel*CzgE?%`haiNBwRc^vC3{spv(*DC%8 zengLWJ>vC<|CQhPoj>@KztAaOn*?ht!G4rrKT2pqQ}jvDC!rPASwa`G=!#YeS|yBS zFZ4*zBSDXZag1jI6Pd(hbV|@BVLl63$Wji$8cVRo60ETVvy))IPB;;*60}OVfg8~y zL5~DI5^mvE)^Z!Sa|b#lXp`_X&+sg-@*1!6As_KEW+%aZo$xhUCHxYKOH4qIL_HGq zNUTo-8j?&3jYvhO#MX4A6P?K>2lJ9RkUDUW`3D(d;CyMyo`v5}!hkL_HGqNPLdxd4U&siI;hW zH+Y}V&?fNP15CD!Ij*|P3V)P zPttAN#Y32#B(0LPN-`fw>-ZEslJrQ@Bk4=N;%mO)Tl7h?wvx866>aJzkVq2sNG6Sz zv_h+TTGcZj^@cDMJ?iOEPmg+qj9?_A7>z#lCNKkgPCaev&0#J}FfaAWSV|>_qE$Vu z>RrO6T!tR?^r)vty{lNo)vV?kZeT6-V2zSdhhTqTGi94p82R} zKI&~ok9vC4i}cve4t9p(>W2u3$J(mjlx8$1gLY(MUh12d`aQ`em;U5Yz%cAB_4TN) zM}0l&@6Rj_;6P?`5JePYZPnMN{xX&mMxXk}avbKT{%M?t*{QEpeXZ)>!@cNHUyu3^ z@E{NIFpuykkD*ij7kQJnc$;;6%4dAe*L=_Kn4S7s)z_*)6ZB}HM*}??v>=_9w4ya_ zXiIy#(i?3W^kEQ#8O<2>U{ChJ>@?7-fmRI;p_~fzXrM;}JsPawP*!pnhjTR6Rs(xZ z1A9(`v$>SZ(5Hbu4X)-oZpG|0(5it}4PN7Q-awBAdNk0Z!8^Rmd%VvFe1f&r;3t0O z7dEhwO`*7kF~kx_Jl0jiWVCA7oE&d~+-{pe2~`3ztPBiS2m8t%(freR(h z7BPppEMO64r=eC2mvIJqG}NP^9u3doT+ZWsF5p5gLZ^nSvF9|rnOnG*`?#M6Fh32S zz`AN^b{f8fRt>dks7FIR8tT#TSAOGn{@_pkVm%w!5{gR>&?dP)4QNJlT9A(UNzTOV zBzL1bS|w|hyf=Cz>ybQ;@l0SMlbFmDrecngwMt${2?tZjGM2Lf^OJ0TlC7)clQ{*g zlC?@+gC5CxB;U$fZsT_D;7;!1ZgfhvwvwOYd0yZR-sEG$YY>g#<$+u{gtW`=9 z_0S_lkCcWalR_g>Nux13rL?6pUC1JrKIoIu5A%~^ep2kqDb`tvb(XRRTBT@}qDP7z zDSD(VVlhi7rHrKC{N4M*A|3@tB=P`>{W>Fh`B%p;eR?o zIFqwD5BpIgZ5my}wXEefZs!i}!8&VXjWv3br+6Bz8oh!Zjr3^rE#L7yKky?z@iV{h zD>^l@&QfF0DK(B18j(sG&1gw`I-pgmR;hZVjzW*rG3>#fjAbwOW*_!tA~Vn?wTL+! z%p$C@RI`(6jinyS5rokyRjbsiS&bg4dZb>*_1wUX+{7AgMyJ$!@%oi&jio-$^Sr=| zyp7pOeV6z62X?mpTk@f^n@)S?=49}uZ+8cbphiH@bHQ%65TBMKpN&AgWY{u*~)~c~q zja$@?P@u~v;&au|9v z)}yf=jgR7J!W_e~9LGtV$%Sas_+nOb4f-^`4)fFaR_?*RX;(?qK#S~bZdA3d7r(L|3X zgBik53K+(4MqzC=nT$3~rg8uWGMf?(#@cFPcA6}ul4TspQRvY`k0yFFxr9r(jLW%# zE4hkQ=+wm8YH}BMa}SU4I8X2-=BJ7IY4Rp-p;Z&Dn*7Cj^k||-lTB=93tQR7c6Nl~ zn#N#lHPxzVW17&EHnb%JYpbc*Y1*A0^rA0XH66kf^k_Pb>C9jz`>{W>IDiA0gH}xs zp_~d1=Ln9(>@+=@Q#ciK)YLj_s#Vj=xC=d+>e2LG?&E$Q;6WbZVID!JrqA;_)>u=W zntsSfSYu7iPE%{FsWsNr8f*F+S~b9Q|>Cvni&1pe8Eont-+R=q9v}x9x zTn3|0v!N6)f-zWU&8)L#6PSor&Gti&W_mQMWEsm@!J(|=Fb+qnW?{5yb{1!I4wrB# zW~Z4o*6ez2z#KKZ4Xv7K)$DcNK#yi`@iy=9F7NR^AMhdT(5jg=*6bI4Wh0x|9Exim zOC0eeV2+xnpjGo0^g@s3dNl7tU;5FXJn|X9Ky+$uoi*QwebK4;G^R5Hv(tPo^C-p~ zHD7{O&6jf~dNkLgxgO2WuP07IQw8*4Ao#}>FEwpN}7ki^e z3q4xs(PBIkn8+k1GX;HG%w_=#(WXTOmFUw#pB9I46enVKT4>cms}?tM6Kl|;g&r;R zXt9>txScz=lY6nYT0FzEJjZLij(KTeZMFEAPxzd#(W-@3>E3XCe%pw-Egi^{` z$uS(uah%5Kn3r_(l5SqoFX0NVMyqtK(#=NtQ#_3x>3XE=k^Vd{@FFkqGWw*y$ESRT zHt9d|6Z)h_`uu^JN#DWFP+Uu`T58qOe6(y&2lQyEM@v0gb|H(dbfY`^wCsj6N;T<1(zJmfEzu zfg91Mr9Lg!VrE)C$U{7gRxPz^`3dXLqop1#^=SD8U-A`S^9|pkQ%h}HZec6iLUFC) zh{wFNGB2&tXiRfjp;arbTA7blL(rp@9MyFQVw6d03&1663QH(yV z7O;piR&Xdomy$r%35k=&uMi(Px2H`^9(QW z3h(ePTD8)u)kZe489iF*(JInoJ3H7JifbJrK%dqPNv0Xvv~EFr^l7b6>rR-T);;Nm z*=e1JR;{&aJsmw->(N?|*84My12~Y`97GX1wO))pr}Z+HqfhH&IF{o$iPJDUt^f`hkMbZwH~b>;6WbZVIJX89z&i8`d5gDM$ESS8=X}lg{EpdatyOES+BBgl zdbH7_jUH{%X-O+u(}uR_)JB^&y~(8yLl}xaZS-j~l06uY*=aKot=eeSrko1&Xro6P zJ=(0`P*!pnhjRovwb7={S)9!|T*9SX%XM6j*=ch#x1m)Vt=hcK8|cwSk2ZR=d53p- zkN5e257DWOHf`)VZR|O1eq}RTi1gVO@?$^ZFgtC{PFt(zX|RwAG`n9&P*5 zkN)J5&j564t4-TcjAmcPF`ntnU=DMcM=>QVp%ks!uHY>6Xsbutb2*Rmxqu6~h>Ovx ztvPC|Roh#*m9^ZBU{*5p$j~E0kBr;6ojbUbyU-`Y+RAvA=g=nOb>84jKIRk5 zPKGs>@g?7)RmN|jxOPd@LyvZPw9}(qGAT47l{6aD9BZpxXS8XTMJ|2Nr(HkHPdoF| z&g`@^JMFY;r&YW8EI^NTdbHD{-69sVgi^{_icamcX?GmQa{^~@CTC$@+F4ueF5_}m zVRqVG$E~bIk9K;r)1%!ByvR$u%qzUgYiQN(Z9YPqc3<%|Kl2N}VvV)4#@cOVTPQBm z8q17BtIT9NqerG5nO*5dcY4s1Y;x#@PML!k!AM3ij`2)jBIYO4{A3m}hq=r{tIQ>w zz=@p1$(+KeoW|*#!I_-Jd1#fnnrpb0TeuaolX*W6@F39=65!Q;@WG|J|KqrG{D+wZ+6-=_ISQ@XYt{ZLR&h0YwAZ7(9__E=dT!uGZbF~- zcXJPqpiTS7c#h|JfwwR_?cd>DK4cx%S^IDKE)>^6j}Cft(4#{vam15AB1zOks}3n> z)j_Kc8MH&E4&CWNPqMM*I`n5K1q@?2d!ki`BIYocc@#6B1uUcl%{pk-p^W9&k2)Mp zm}5AFQ#qdtxR8sm<~m%(4cy4%Ji(JZ#nU{)vpmQ1yugdRidG#yL8lI%@;yKBBW9_? zZ~TRI)?s@nuA^2Rwd$xx$9Cw^u{|B=NGCeeg)F+FQ%CEp<6wrMQ^!5nld+x z`>{V-b=0ck5gf@;=+RM+j(T)Fmg6{{6F3olI-Z05sG~L3QJap}a4pwy8@F=@cXBV* zSx2opKE+3Tj2<2J=%`1>&-k1#_>!;q8l5_7)6p91Xg}(>B^1{whFIb-JDnPlN*d;< zQ%kh!)PX_h(MgX^dUPsa7{e)K1S1)RPMxf?PScseOy)9=V&-!&rI?*gW~bAktVF9$ z$D&6kJvv>^6EyFPM@=xNRO>- zV>>(88S?8-1jG!nQmBTovpFXdE}#2XRSKVK#$J*u|KmofCHJ$ zK@>3uojTi(Ixj<~&MP>YFlMLoX`Id(n4``YpjBtBI^WBE=+Rk^&JXes5Az6*@)(b! zQ|FhkA9c1Lb$*9WSjVTBoz6dCjdixhI-8@;)>vn)I&Tlfb!mnkUG(UpN0*kgqBU)3 zO9t)GsY`df=6A8iy7Z%fVd&GPkkMFYT_$3UbBp{(RE4(AAt zAX=s(DRaPJRqDNML^2lcZ0~y3%hM-fH{V2;C z%bLJM_GcCca3JO<%lu?nV_9Wrm8DhI*_?wOS$brh&jnn_MO@4!T#8Ov*KsRrvBt9Q z<9?pR8p|>}S=LzA3%r6>Sz2ZN!mpT>EIqRH$kHS0FV?exjch`nuGUu9I2xi&S8J?m zI{I|gr)z7>PgnEPwFma-uGwhSRjaP!(4(s!UG?ZXiOEc1D$|(G40P%`mqjdQ3Cmbc z7_-y$SdQZ)PD87%T6MjJThXJd9$jze4({YG?&couqmdAt!`$fTOlJD z!(Qx%x#^}yH*?d?+;p4GK`f+%GL~{ED>;XA(WBe>T)>4~#KoAMZf2+3Wn9JeXw^-t zZd!HIq}xM0%p>U2&HQwGg;#l(_xP3H(4$+V$DjPgdN#0;O>Aa+D6YHN=^l?}-8Jj3 zS$DJ3y%pMYZ$l=X(58Df+H}uj9OIe5L?$trDNJP=(=j{Uwd!tmx|^Nui&?@7^y#io z_ro{}^V9uQ%uaW$x@*<_7H&n4?s|0Bqx&7)$z9ydJ=}{<-L>g%cDkFL?q;X^TfB|g z>27wqo1N}vr@PtdZg#qB)m^I|^=Uvu^yr~S4?TLMl15{i(3EuAkwsU!(U*Sc(?g#g zgDAk<^sw*r*b}XKXw}1v^f(wjdg#$Zj~=Czv6Mq7rvjaNXw&0Ftg9X;b2jI2E|+r! zS7LU0T*D1$)#G-aM~@zQ^w6Wn%e=y?yvFOi!JE9xCuq~-8@}at{@_pk!u<5u7K-a> zc6yqfo(X8xQ>&g?=+RS;p55s|PqN9O7rn_vr=CL?#b|WuIf02xVlw8Zr?uA8?DU*R zF*+(>R?oIFqwDoAa@@dTP`2TCU?()^a}&V0L<1V?7_^DYWXT zRnM>Z8a;aI(epdL=Lde|Cw}G^bn0nsWe3C%OEM|wlbwqB$u>XP)>U?Uw93{h+a8lW z5HYfg8DrHQdZ?SX(IZEXoH*i1 zAdw{MQ6HUhn$eaF+L1+9`e2Ra^uz4r3}h%;%koJjYAC$%kl@ z^D*D>E#L7y<|oHG%P~7STi6!npMt$MXVk6wE8(xX=AI?SWKfTOPuNll_KeXzlRj8!~l{Cyz@0MuQy90yJqxTSoQot~VQ^*KLG76n~kH;G8tyAxr6fp<0)7u*BT}m0| zsP_uA>aA68J$he)9=$K)a<1S?u3{BevzqI<6>WN3W4-U=F&^g$%uer@d4*RoN4>4H z-dgqkl#S@oTaVt69$VSQc6P8c6qg$!AfATUe{!|SZB7R5=!V(J?Lkj^W1Zz{m8(_m zRHmUvt{%C1g%f#2U*z8MBjXjpd$+HI}PYu2#8saW{J8 z>XEBQ?)^N#gFM8;Jc2&C&+|HOpiS<_e1bl?`sA9QTDTkm(A3gf$ z(PtUUS;3*KrH+Uj!#+VnY#OSlw$`dp6r>2oc&V0QYfMXNqq^?40F`smR|k3Mhl zHt+B*@9{n#pi`f(_=%tSg$-;B#q~8WePgh;`o@uj+3BlQU#FCpUCI?VN31+9SR(-YVdm5*sM_)bq>e2UX&f#3n<9sea zr@q?sy^)((!`H8SZVRrgz)mN*&-}3`MqDNmn`s&g5SAOGn{@_m{eRhQ6 z`X!KvHvJmY1bzDH)2}6M=}Z^2>Zesd^U-fl#-c|*J^Jaaro*U4kpC0}6=yx->a4T!MjoZI4PW{`^iOzH(hh7ZC+Uh@; zAq-~}TJ_hee=+k}z(Ptmm_;mR38j>wQ-5o#|FP)QU#I?Oau#QE4i{j4`d^KGxxZHZ zwd(&Adi2+$zaIUc<9S}-MPA}%Uf~U_t^S{(P5&?WiJ$p}Uok)Z%}@WGp}4#d0WoNm zr&V4@^vKgAPmjDTy3&pA^q?o%-4c zJU#MG;6zU1WKQ8!PD7`>3%Qc3SjCOp#9f%3ynC?5@*d<-w93;e&mNrj8G7XDk@qEE z@ipJ@E#L7yI_3SvHnwApp4|!-cK&t`fV}SV>FcUon=rKT#0S9m(vpI+&idjr0%UDjBW6)=SJ_AnT zG|uCEtg8W94bW8mP^{z6_-ReFhH4{0!Wa2~5Q7 z4Ag3%Rs$>0W1t=b^%%HuQj7HAt&LS`9jrv(RIZ z9)t84bROq(0T*%+7o*c4Z3bP-E!@gl?nj?N`V4vq^E2ov%+8>fd4*TeYS4S=F-VU= zdJOu5KlzLGY+xgs*o;nt<7h}SDKw`A*4ALNGq@w2=t@tt8m!geeHn)ygC{VNNla!6 zQ<=te_D8G12eXL9RI-etvBn0Qox#U)BKGCMS`F4}@Xg$U9)tB5d>glO2X}H8cXJOq z4YsxhKfw#Uh)#pwL7&0;41OQ;GuZqLw$27yXM?pGtksbEG(e9bdJNHHNF!27qcKfr zN;>VxLYpDh*pOWMFodC)ogu>*$sTAmM5`eSF)Ks#7^24zJ%%iylrolb2<0s2NRC3A zAt!M%XLAncVs?gH!IfNvIT~^US`E3K=h0(`9z*mP@-naRDzEW6Z}28M4f%wx`G#-# zmEZUsYi!6iwzDG?H#7!oY^YX48H5F;tJCr*JB#aXM#kCTC%ehF;2Qv>AFWYq^cvxdZbv z)cg!JJ42sDtD#yA{gSWHW2hcO^%(jc-}3`M@)JL!&roZtAVh#R1r13?p8|af%uj*! zRbX}sGSR9)tAavCFcLiq^eE7yU=Q|WEPJsxALs*8{DKI+) zS`}zjU_J^~aW#4r=ux0Y!F62E4cy30+={hT@Gy_?D9`f(`V{C>@EULN5g(&ffmQ|P zqriL=>(~8!#p%b0yg?Sm4OCR#EFAvjdm{!Bg#;{o& zfF8s27^cUtBIYocc@$H^QVwM$hjA>&aXjW_*jb#-Ib6UcXfX5v zah~8wp5keA8m7%Kd(JR>&ae;olCRKb*f*G;VZX3}jc7GotKs&R;Vsc)xE{mx7~Yl) z+L1|nI?#n|tfk@F49};K5sYLM=4bdmOkpZo4cBV;a#o;d_k5SKlqt+m2rQfNdfX=qibRbfXuVXg{wE6k!R z-RRCB1~Y`A6flh8Xj-Ugp{9lVGLcD4V>IaUb{d01u*P;p05Tv%G+Qh3oi~&-k1#_>!+MbA{jWBN`WKTc~NF zmW5l`9*P^$gr+p3IW0)XERJY}Ssc-Zwq#%yM`WV!2wg|?CKu~;L|^*RpFHvz${y^= zSoUIXrlRABnUruai?ElCSi;h&ol2K2Ui?-l6iOzAMx^4u(-mqyeca@nMa3&C_Ve$u zIR_Wdt*n^VY3|~pii*`PPNQ)+CLA02OH-PK)U@|-t5$-V@HjiURJ)SVrkLb;!$ODmn|tSt=#?5 zv~tTG>3O4n_;u@08~oaAD1&xn(w+|C_;5lvF`N{x7p@;}5N;T`LMQxANvI21)qjs% zG4l6L;pA{ixKTLOzmxnsIh;E?wOQmbm6XmaTQRm`j5w3$mKPV79$5R;G37-|if5;0 z`@)_@75kPfC@-oko;R&%@v`EIG38}T#!a47Tv1t8UNmQM@#IREjVh`vnw?s(>$f_k zXwJy8(#rC(#fyu}XOA3HIG|7NnEdR~1ICQb?l&s0clLmO14m@%4d~Z<^r*gtee=iU z&ra=9`v_cnL{a(lqKauH6(#OvdP(KN$t9%=78ko@c4|8Z7S63KSzcV5_V4$X+OqDZ z%E}hcDJmaZb5pZZ)9Ws)x|`aIl4hr749v~!*EchFKyF@UZl8huGJE^KK9N7y@*`4kLRsb`04O7;n%}&gx~VFcO%bYs&8ZR!m<_Pik6owDDrefzf}9z!t!EI zN}8jlR+cO-sVph3m|ilka$)qav85GD4SQL6-C?!YtU7Ggw36Z#ql)J&Td=?rnA&9D z;w5F}EB7cbTDq|At2K|I_8ty!ccbT(RNwCIwPyHkis^Zaf6Qb*_GcCca3Hfeh$7}N zmwDmV;Wpv6;f!#*aAvrDxI?&OxKp@uxJ%@Q=Cgo>lyESMSj-YiDPt*zgtNkZ!ehfT z!;8a*hEEA!5WXtBCVY2zQKV?=8FS0#73cUC_AaT+sm+nIPuYTs*{Qv1FP&VrtbA^9 z^>|MmyUUT2ikFsEM812mXQ#HQy~f{fud3hd)JA)hmn~a5xp=YXp`@(T725raD~u>B zTePI8e9`RGj4M0&)uHy_zu)>4n?laM3YM47PR;xm2h}dvf1P`bt;yg1|GE!;iaBV2XyNxl@>CnHYfv~ae)Fge^S+&l8j zH=S#rDq31mJa6ng`*X?slHzjTX=E4i5zaRqtmGuBa}imYKy}U@7*&q zJGb|dJu?sQ*V~_SbMteLJaX6jztVMgzyGU!ZMAKo_TEO7R84VFdDUG;E{@#wWwXXj zuDfLSXE5@_-AvU}biF^^K;$JYvMsI&_YL<8_YdcVeP9?0MOON)tmQUt4-W{B3>SpQ zg!ia=28AA7ld-aRNyQYeY1Wu8*9=nhE0Nvbvs64zvx!b8Ow7WvXk z)n8g09_~v8;oRwy?B$ik6%(dRDOymm`^`oE{w_Tu=RA>{ddGDNYyPq}dK1%ZaSKXH zcb&+{U40xmtm=8+{Z`kx;4^mZ@p*Vuc*O1pe&wKV*!8>rHat3|9;a`#*K-8KGX*T?i%c+Y=)OdB1viJq%g{o~`<8VUt5 zkqaXOyp8SbV5bZGD+t1Sh4&8c6W%vGE<8SRkWDCvBfk32iT<2qGnx>d=AYBUGa}zZ zTT>Ewc^_Z8c;(nqV`_IbYmrwS`;3L_@~Rh-Ddk0_6(zn_wV~LxT8tX8NA28JA0OG4 zqh~%fw>fE9X{p;AvAAsRqKbc*{m3eDdvh0!EL*bFT~~O4s+!r|8V1gggUE?-WLkp8 zGzm`(Pm27d8O_6!!&4*QP2`lb>e2pf9YuH1k;}@lZxm2j!Wkj z+eLTTiUKFcLEGwe5uUQk`1v1l4F#EYo9fMPa&e_Otomwu5AU+6<0kvk%)b5S=guh_ znCtf-cHjFVW0IRY(43^k?fzY6xvAX9cWGk^y3&pA^q?o%r6rK~gS|9q-kN)@(SCG#DBBzmugy)9mg^R=U!wbR-!zJN^qbDU<|NMot>ZK@W zmlyQesqO#Wk=5rM|KepidTY@a-p>E-W^9$q=2k8%H%$NbrlO}z|Kdy`dT(PZD!iZY zM(W?)U)`C{zrDN2smJWp{uGu(aAj5pX*B8%o)f0)2TCNVj@BwQLU3onga zFqLUckNi1&NVq&);h&LnvR%%lMy!l%U{z;SY5NpaRMu{9(S5D?)YAENCtkZ8oF2W6 z;(1fYR_%_p7w!I7z3B)J@>rYO;k`shw!gpK$K*2apq$(6e!Y3FH$QScds0vwu8jO^ zL3r7}y^YAO)yQ$)qXgcg1WRV8w(`a!a>_PgaY;p`HxYJRJ7Q7fZ9#ZNc=`C$JLfEo zT-3Yw+d)ihTzo>J_o}HrrKl{N>rH_3R&T+JXO=kesro(-sHl2Z;fykJDs*7Q+{pXz z36ZxZZn1CSvkyNOw|eJ3t5&V9*Kl?H1|2=1s{eF+yi@cKtCLeY4qy3O^ozsKeYolm zNok#OhU`6M>a>}&ic1eUEP7-RME_m&sY>-9tNwM|uA8&BUcn*W;M@HdM?W_hzpQd` zNojH9O=e;F+=V5}Bj0}YvlQ95%c*cfm;Kk*nw>gl_LRy!Mo!Dk8#Qf8-934e(kHL( zue;pwl$A@1EAp%FboR8#v-{@O9aq(HviH`d3+mnz%-;R^U*=&(N>t7Ga(`LDp{xwA z3?CLgJbXlC#t-KRj^wEDk>POonD7bz=QDnSdq2rzt(w&n!$(DC_2lr;|8`c#r^S@+ zK6>?MbXxB1kx81_si^9?D=weXsj_V8j84^`pfwH!C$4g$J8rTiTRboN1Q(aTkyLL= zd0AOyIJl`n!xpXEcgpI~Gy3t|JIN`HQqvkYY1*uL^`~#M%9a-U*r}{M@+3Kbs4QDl zTso$tc=5dGJC~}H5$_VqcX``YHS9jaDK3o+)4UPODl5xeC-RQ0?kTJYC#8mbq!$-X zcr!h@Wvg92_*)f@eX~v5jCTL*ZB@-%r_~vmweOx>zeC4W;doc-+-3LoU7a&BUEa0h z)!lqv7a#r1YWK%7JNhPmba{DMxf{vO@!)40-so{=vHHxbY8I=$<7<2M&dvOfM|tO3 zcQaEWz^)F+hhL#Ta16GM}IGBekQD9gORzSJ9n*FtZE z-U_`FdN1^W|26*aLq9kR|2?!Vh!2v3)SzXM5wr{12VH{x!N8y(7#@rWMg{YOMZxL8 zIl-O5s|L`2VrsUHKGDC|{4@CBf3W$UX@Jjm&8mSuD|~EZpw9^(_iqQfX7jzkv60R9 zqW`q{9{>OT=KFL~|JL9Bf4lkazE64kA6#CO>ay^OkyKZNPx`M?MUIW6y5>KnI@xY9 zf4AMDb({a)3st1mrt1?MHE!Cx<(oZeRuT2#4krjLk<58cxTS=TgZm|Xq7*ltk$ zZYT1pl2fswWWJNay|bJ(Sx{9kHCdS@rCtMz7MC1WT%K7{;jcwiFQAbRnKS1tE6%Je z%gkC@?&YYmI4g5$xwpwxA8TYTE?!=|I5qTUkeZfqU~%MwhR6n3wX7nqr%xxI_(5-v zuSv?)4II-fCHlov*Z=H`EmBrDNS~d0)4t0VSC%YwM{~=TEb)O)MdS|VEt^}Mnbm7* zg)Oz0Pt_|bR_5mR+NWerxzmkaqat@3*$ShdKKi@IR`qIM)GPXFK=%CQ3zjY~S-fb` zAxjp{Ei0Z|R#Z`X@QURN78Wg@*K5SG691e~bvKn2y(T#=D5@yVE?K&;thBhSqWU&+ zik2?zHMVqqSx(hiMwaiORrPmp;s?W5t!|sSI-}h`IZJ5Y;UCWus`ijhp&Xxr?;V=r z)7^u7KFd=dN@{1Qao zaQjc~E>U~m)nB&({q5&Dfw$GcExs1{Bq_K7pCSd3cU^0^IecpPwD9TSGs0&^E{=SP z6gkf!xScz~XL;M596mdIUO4w3-U(+p6|8%kReMqx-J-{rIsq+-d|c=g%g+D)$kEYP zrGNIBROE+5BWpf^to!ilpL~olF#jJu#t3}O6hzL@sm%WFBWwFVeAE;? z;m{`|+5X7~8^JR!d~UbfeLj5tKYTnA_<$*R`Cr}2Yc6~{a$)2|=yl$}E*!iSzA$`I z_~P&-kqaX40(|HcychYi^Z!f3m;E2S3-}+r)_mrHeNhwR^YG=7$X|x9_^&q5Zyg)i zK)?S_8|ane(}D|k-#|0|cN^$)6Q%@@T%VYnTD^fb+-(EBx$j;ZW zYUgV*wKTHjmH4!EUS{>r5ggm9`q&Y@HecPw(QP9~uWr|2b!Pk81z-1;q+_RDH=BJt z7yc7DVfn|+=8({#wwt4EI2VO34_y^{AoNh^@z4vQSDm_i>vUy(XroW+cG`mCgOs2} z&?>0DzuFC_bM)qG{u%V#eZ%?5^ZC1rtH%0gfBA)9`7OLEe06wr_?pOA|G}U975Q`c z+VFMZ>;3cp`pxY&_a6CB@_+c|HWDKyHgY|~9upJ3A@Z-d@Qwe?%*Q0TPct7=|3A(A zP2*F)+im0%Q~q}&pPt>YamuQzlisXXzd`cu|5-={BZwLg$4p zusvO7gSyfdwK{aIpMKpKTH^;|w|bX#d+5&4-JyFz_l55FbEJntkA@x#JsEmB^la#P zKhSxl>Rs47eopg2=tE~!pM*XQeeTTaYunp*-jV$n`X%(6^Q^yYbelt4ZFW0scR>(q z!%GN~f_gzi8((UW7Bq1N*1|bh>!7XoZJ9xbpp*A*SwZ)pXOI*04*CRry_3uLUT$zO zG#C~X1|x$p!Jfh1!M?%xU_vk{m>f(ErUx^F{euI7*+Ee-Cz$8`-ol_HSR5<~%7Udq zc~B873swXxgTsO&f+K^YgJXi@f)j$1gHydLJR>;EJHzvW^Meb6i-XI8D}t+ntAlHT zYlG{98-kmHn}b_}wZZMd9l>3}J;8m!1Hr?=qrv0B6V4l-37&KA_)_pn@LKS?m!G$t zL%tt;7jb!_DG)r!=(nj1)s9@aXPQTI^VgxXHox2U9a@?K-7q{c>%%nUV+ytF=> zzP9-N=v6v|x?JP;hB}2h+tViaVU1Ve%u&Tli@iB2o$I6RnN!D3D49_8z-xZ>C^aT} zYh7z@ZOuAA#fzlr9%@?m0D6Ra&K$jD+2X2?AP=bhQ{<+i*UzcD{_^Pcdxui5t!kMZ z%AL7~(}RkAd}3L9bo8Kpq15YYgZnQfMjE=Q=!N;Afpw3dO=!R@Ke37Y%*(It6t75) zj~+d^=8o4coEp8_(7Fd+;P-8YPZ{Zlv(xu1F7lfQ71O3ITfC^qw-~vn5uwy*!ZquT zj$U_Es7u}B8NJ`Q;uV==$`-p~%@wL2+MXf*t1i(&8NJ&@dxyHzJ?b8z>WlZSd6;X~ zofN&R@u4m^RNq8FXo3$`Mo*u#a@oNprH4)*RZ_8ZagiT%MINMUMz1jC?^l=_8a;J% z>9QpiyB#*8rhCKC%;}Mz6#DIs=pp;pe7pC@E{xvf0imY5K8C5GiP0lx*F4&_B z-7j%fJ=F=(TUlCjPisqVjow^&DE04;zhb5p5_uQCtonOiR&$*->n@I7XGN%K%~Mwp zz1@{H$E+PRIC{+CHOCwgI&#*oE68UGqgML;ijujR(YNGQRrE%VuDy{%UX9+!F}u$8 zu~QB2vZc{ukFP!U;IE>`o)~Hx?NShOm(in6t~qMWx>eDmP7O7^rfOtPn^x#U{+j3Y zjGE_l&AOYS2cETim$NAXqB3w&A;y_<7u?q=;IODeMR&#!s@?1Ir_ zF04IfT1oVni$fWaz2=h8rPC&qEG?P8a(eVgdaHNUET)1`+vrst6TRr(x~F%S3#;$&ftu^p zCak^Q!*$zJa;Qh>k?Dmcbg%QaVAv+l|06<@8} z_^M~)^}1tTj2`o5-L4XO6@4r8_AIZHlOwN_k>xydQgKDqZ_HIcg>E2vz4z)KdUELf z>7Hc2QnDcWNNNxIsBR-l4*8#?jck#%7p{xE0!FswBcd04R`b}_E|DUV=ZjE!-QW#~ z9`#ktQES${6+P;kQ2MSrQQdLTi@y&Ith|0z}w0O^{qoT(p*WAV0Nzwf?X!Q4m5`7_!Je24oXk2%(^;i8m z>vvCTAL&ogbIR&M1Dm(dR&{DTU@(xcJvAv zyWaD#f4IH&H5-GyJZKfYk&ZPtvS!_1(HrT!>mWvF$fpj~5xa&mc70u&7<8L9b!_d) zR?ws7*4FOxT=dqm>z=mA&^Z&bF8uaM%_-uz_oBz;);zYz32t;O+-r4+exWXrO`$>b z%6YX{?w=pM@_=23Go z=uOP18=FX&>U-F)_P7HkM~|CT6VMq_$hQ!EBnQ?Ux8_qDZ{*P)^!HbY+QD{Y^nkfF zYczVE6BO5;Cw$sGdc=ZIYTZ6pbFS*R>KizC_neESRxR4-BdR^Dbk|X?UR|{p9uj%! zjqC@zUr_n?=fC>m<#pd?M)WZrT6bJzwCj$GUVM1X?MGjZg5@=9=%~7Bt$BS8!Zo+P zcG&dj)sL-t$}QIDw^e&`w&v3=(PNyP)l_mz!AS?~RpOWHd``5axP0`8=(SF%z2)KQ z(QBQy>kb^isSF4* z-YYJz`M$2JyE9K#-Nn@db>ps&*?Y?9x3s3_KGu9%z0=%Ma|W6ms@@tM6TN$9Y`eeq z`k_wsg?H91iO3SGy@$JN?qTgg;polWTQ}NOM+TQhAItrhNyC~Kzej4iJX!O6ThqZ)`_+AlP{>xL2AlGUy|}jT84W1uyB+Q24}?#ju{m*HfD0nK`{$r7R4MA6OK70=CqjeW3Gw0C1!2R zeK8NmycqLx%sVmbVt$PIE#|M74KX`olVa0i(_?$Z4vZZUJ1TbH*lDq|V;9FRk3By2 zjMxifuZq1f_RiRcVxNwEE%yD`&trdy-5R?+F2VnI#Pqn%{x>W8#0`ua5w~~Tl(^Y( z2gg;!9T9gz+?jC~#a$bBYuvqYkHx(j_io&}xNqZri`y9=ADheC(KJYB;kaFGZQXKSe0;d!W{_@COnn!a>9EFpCx>s@JGVt#86_r z#KwuO6T2rCB<_(oA#rBnoWwsCHr6)THq|!MHs5xw?MB-g+j`q3+q1S^w!O9wZC~2Hv;Afl z?RI;Dy^g)9y_LO#y@x%^KEgi1KE+;UpJktCzsA1Ieye?reVzSD`}6i!?0fAW+7H@~ z*#B}k9Epyz98DbU9bFxL9YY-B9g`d-jta-+jzx}}9CtbHcRc2J+VP^}b;rAouN;RR zzs5;%j<_0e_2ZhywTxXE!-<1USxA9rosjd82u9*BE9ZcE&*xHse8 zkNZ6C+qj?Og?L-MH@<%Sx$znCnejv8$HwQy7sk(sr}zc&H^ko-e|P*t@lVCS5WhSA zt@uyl55@oFjBz@hDb9M%rp{K*4$dCV!Oqdn3C^j`>CS-jD(CgiTb*m14>%upZgK8% zzUh45`ML84=N~TB73WHFo$YGoYUAqU>g5{fy1;djE8jKEHP3a8YnkhI*S)SsTu-{T zyIys@?fTet&~?Q1m)qe^bf4vJ;%@8i;_l-f>>lmD(Cu>+W~m``riKM?8YZ=J9&!dzyRNdOCZuJR>~gJ(D~|o@t)ho+~}qd2aUH<+J|GTyKfD!aK*i(7VigyLYX3 zz4vMFcJHg+cfI?)2faThC<*Zi$q986nkTeN=#tPUVQ|6)2^S^gCKMzTCzK^rB+N-z zn6Nluxh?=iQ9la5=tuK!!kyuhK5!cs;V!Ou%!}|J7h41#3p{=&ex%{*gMkhD8ipEE z%YCI4gL8N-CLGxORTMIAqUO?OEM5tZzAYkxOS!fhL~Mr>_?e661~vws2yD6wKjCUF zb^tmCHV2*zJj;`jwb_xhSB}48cyXrY9#iHU!ij6jHxz0uC&RE@5RMMH+KBL2?NT?* zHAZ*t@6N*s?BG1yH=|4ojY)s8JJ18@i45`FRxhA8&mJ3Ih zG1^5f<-k*cn7}iEZTyBDxF66Tz|^le0MkYdhL<6&Q7D{3b`lJ14LoglcZq}W$Y5Z| zXe{gXYs-5ATgD9QnN?R`_sY*L18&4K!+_zMv!c0lKzp9cif_R)A!Y?!{`5sc!2vJ8 z-BDq0ue~|H64&Qw4qDv5y?1s`>|t*S-x5dA(g>Njn|Vp#*@P*qJkP^ zlw{!Pm~bB&aRTD;;W{tn5OaaNzzc!xd;$+=aZ+GMU?;bhCgpHd8eGZ?G)m!MY_22K zJnMVS!0U{~Pfz$<~>0r*o^Im`26#md~8nMq^MuxwYyYF7?K zh6q_(fHAAe<(4A~%1YrcTwLIbmQc4cG^+{aSay}|YNaQ4i~xpX8n4~Odc&rbS&aT7 zL&`DS*4I~1QaM-6{RT74l?6N-r9(L9l~rOO@H!4LjRQ`u(^|YL$j?iSj1_RKH|dVH z;p@Z1%Mto2j)q&t6~L8&Hv(^RB{gIO*p&)VCRRq7g+-_E#?=-Y@fz2mm3ItxJzi5@ zx%weI*Nc$?doH%P4?nI0mHwy~p^kb3x@lC*TfZNQ9z}~=Hfwu$i1l|qo3%nP2 zKkz}|!@x%z#jTJW3XZn}D*-MHeiQERm~9uiO|1d$4tyLKNrFg%M1o9$LY8O9@&Z|Q zljT*iyw30FMaS&vo0tQ?K5c!CzLvU~zC4guPUV#5`-|B}%$Lm$en#Qy3#9d>3r@qM zOmilzDDaI5zKO{^Epm)#_%W9T>l%4B+#9vq zgZ1RIaw>|;!}mK7A4BUsfo}po2GYVK{|L7}#dG+oX^i+W@CmR#@NM95;5)wb85aqTUj)8K zk^B(oJ`PD%x!GUHXH|PHxNyp^Iv{5fG>q~*Uu7*e$e8^QqKc%WZxQ(qxL#cbe#AY_ zz)yiA$iPp5?p2lDAY(3C6aKk`@YjMLl%(PgZ?z#}m8SR?F5p}e01?26Bm+v|*T8Rq z-vfUH{tWy@LJSG)Q>x22eh>r;3d6C-~tp;VTS%KE1lA;i;U9^-R1tJ2XVKc{iCn`0+7=-~*9agz03zD_qTyu!K~q zjhfSZUW0mtbT%$tk3J;TB|(ko5K;r&f$pxY^OYbNq(%UmfYbzN3Y z$`ho#Ldtif)+2Qwsh5zthSb;jN%bePpcQT)OP|1tZy|lCyHY9O2cYS)!Yq{o(}3x~ z44?v-30wkP3h=edfZ15`lV|Kaq-z`CEv_Z*Wzf=LPHH>&aJM#$rEopL>DRXT$v3xn zfW}y)Z98Mc6#l$BdtGmHTdxu!#h8kj5k=kg!=htxrOuJ$MxY z<^XezBAAEY^MT8OD}XBj=%&&FU?F@0O|Pe{V%=^XUqw*5>XKNgcMiqEG&TnG>j+s0 z|EsFUc{32!cm_>0HH(IOI(122Ndq$R*oQv8&j2!5n2vO zND2H*LXEM8mn*F53XXUga3exMN0x4e(T{vpt-RE&TP^(Hocz)|@yrT559{@)&v|G6 zrT^pX-DYI%cKlumAoF7H;CdfjW|9~QwMnQGz#9B9Gg4>pt~;sz+``mceT$jYNjbc0 zR7HpM^z3Y&nT1yXzeV^WnefFi`U^K|-L7@Z@RweV{H%e(4mHHAKeJ8nyWXw8YqZ;3 zblltS0qzCv8&d+MS1&IT&`HnEc6F*gXL_E}{iV6aS{rl8jrP`9|8sG0-8_f{){R9b z&6dbQ7wVC;o--JH1JaZ|{(O1dUNJge8dArPAjqSz8Bxa}J-({KLwhWj!DD(E9CsM5 z@(o7eY~-rOIh1;7C2y%V0jrG0;#lfq7s6@2Knw{DQ0u`j%gy&`?8^X&!0F?Z+uQlM z#f7{cslb<(2Rj-XOW1Bp++)!odZ0lVO9}eu%_ZB_Bg975snM+Nw2*irBQc-DYXw`) z(l%u6d0b<2S9%tBj)W#8H09G5fbArJ_@B_s!O6u?b@KFdD>GFo3A7ddp*hzdP0K6I znWzzSe%SzMKk(TK&&4jJ^a|&KCBn-jG~?rL5;Xoblm#P2RLv>+jsgftS;NoYwzD?G{rKhi$q2s-3*abjQx39b3h23SKo_{Go8uaw^Y zK@)q;n4CW$zs#Rm#91kUaf3A@K5bJlO_S+fQ6;iqE165xjbK&xU2XzE46?sfMjH z(g&455a!R+MpFH0xp>d?=nraJyXZc+>E`d^QY}Q&st|@3skU!}KfOmuIfI>y+qBjm zZ5R0{Ka|C$F>e8b+3ld%hm}EP*TS`}3KyJvGb0$Wh!QNkTz^N={Ke(U{pAnfPZG{2 zp#x4~WyQ#F1@B105H77qB?B8{nd6C-4J<4HSw$rAoB(9FYyqr5EMNodfCGTC-H8O~ zvRz2%N`Z4z7 z*T-Eda~fV#jS;vR#|Bc9n*dD#$j;s*^dX@yUu_Pw03e7mN$5{Pme!3T-j}_lgOeTx ziwMP=ev}7?7n`1xRWm6VT8{|fhb+T>k!jO;uSC$5+y+^O0wA{q+F^sCwDR)&ya^Q; z$Q|Tz-Fx-!iml&eys@}W%!hYA-ghgp`%a~}AxqrzS02=l{5(eRvrM29X z1@+)S_Yo6O|NilLh8>XQE1Fa`+3nc~<>hFkIoLNT$6xNRDy39IOdDhqUdR2B~=ZZIOZ6~TpTgDN5VM%a}ocUtoQfG&ghTm(npmEr+I(prpmIDn|Bc! z4BH!WF$v@KSs3$HDc@R!TYh~wR6mlC%>(546L`^eLwG}&iN|4t>Z0Qk5^^}|StLyO zN1}recs|F*LShau7nnyvE(v)g`1tDOz!g9$2@^?}bXtgxYmKs9gnUJaj+dWnb1>1- zH~Ep9Vs?FZS^Q(V=#ZBfVU|VGT!Siu6};z0LsQ7|YeJf@Y12_>t?#MO5v2?ZqZ)TYd>VKoUD5}C&p`p>8v=9K&} zC%}FAKHz@f0pLMk9RSNmUQYsAWC;mVNhl@3PeK_9>HwySQt|x8;uaYp6j~J)A zn|PB3fUD{UO8tkYRsZN&@7=W!#tF1z>h?U!F}u;I!z=pCHRDC-(ypec7Je z`o)+>`?SBt5o_Dpto9nCFMn=?`661FYgVL|H0_>w-`sJZwmL_-E;~wJ{u<#9aZz!X z%K#2)eR+=Am%rt{jQwuH`*O}bCz;ldAnjkwjQoTX3@}|z!WEpaUjc}MD^EleD2Q9J zasuesiU5d!1jqpHDk@+h;VKdqkg$-1t4X+qglkDy#37*Xn_9dAeV>0T%wCO2Sgfn@ zOIZ}G_`jjX2hqAx!w>~ZO~T$tnsWsg3|g{M#}EZP!^u$U@)05cl3wtVkNP^il|8r|XLgwBLJ1lbxET5yXvO%D9Ho{4rFZa#0zQKLoo4AXFRU|-oKw#cY z!dmXin5C)g$~pRPB^O7uwtMuhd_Q;PNB{42~v@4f}cjfY`u6&=?mGN=3 zka10ACd%4W&=n}?4{%oo0YCVUx-uc~e59at2~e(CErbj4(^1h57c94K+7+>+#Y9 z&%U|Wwe4z%#&88)S%&nMb5WUHSy#{>GrO{;pg$hjm0KQQ9gK6kl7x*AD&~xi!d>?+ zj4}+wEHD2Cw0$#&Vvn)n!n($+3U6(OX@a`ASht{fy05fup|-xXnt39HJL6hxEPx?+ zeXuKNewS0hgb1e+^*&U(V@+8qQ1}%n{0bC)KyQUcMb=z)htEY%K+Sz5EG{tpQslJF7#{1{Rj z^94s8Gl?9&_?uL%=uYkpxsW%sBoVc+oAibJYlMKG6G> zUl2dbDg}DK0=@qY64={Qf!?qDM#3Hv_8k{xpxU(walI^$K2{8EKSq@~VK9d(03slf zu$P3lNO+sCLSt3&9IJ-!knry5z$a>)UKc9rBvQ@Gn|a_p%E)-=`ddbAiL<;^L+2CK zZG`be3-f;R#644+_WaLX{kPS=H81zdNIp>$Q4T3wRHzg+3Bah(dnCNir!`RV6G`|0 z({$mg;aF~(+JwK)?;bs_L03#@@jtgHhqVH=K4OCAU&&Z%LrwYo1Szn{U9QR z(Uqd_IOsrSV*qrZrUB^?m7oK@rnbiQhe@<)bnrC^pD`WqDVq7w=s<0!=g#yAVLDJd zknlw?9eiFL9jH*)O*;6}po1a*gbsKc8hDBN)3ErUbvpdACKTtC=B4Hj8dg0esGSW; z_%ggE_#K9zCRm)SeSp3|CeROnX0K)e1Au|RAYd>F2S_+b!XXmAA>msR4wLX53Ez`| z3CkZjnxTjPQEmsjmTjT=+ZoZ69VRtfVtqmNQ_}=J`aEa0ckD@B#NhnG`|{I z2D7TyM3c;K-~2?zdqT$ft2gG%_6}H@Wk~bIMwsiOg=u$WTt7@;9giSqnF8Hjy&rhM5ajFd`ypUGi7pb)BC#%s4o#4E zCb2e&XYav-XcW<$`_xAe5W2l7$kh#O+mcw5#CXH!PK0NE@CVvLe4cbqzN*h_RC+)M z_qNU4rPd%Jm;vfjz|+7MU@PzpiB1wdBqorUL}ChwH6k4HRDSK}kxMv);uYO+z=LCK zrXSl=8J@}dhSV+*y)xL7Pu*D+(5naJUEji=+RZPmN1w<8bTzbH&cdI1qw1+-?J3^L zF6^NgekCoZfsT55Q6A9K3Ut&W;rl_(ed0+-Ug383*Jrop)?Y z$6KdI78oav8s~N_ZRA98+=MsyLgz@aPPXgRB@T~4!z9yo6HoPPzGx?Cl&J@i{h#ql z8jByo$u|JhFZD3+9q>Ky1Mnko1o(->dL-5-u>pw5kle?FW&-* zTM|%9R`W<=YG9Q12NWKUwjb<^XsLzA&cZb&2TN_B4vFa`w&c^Z0Z7$WB(`M&KZ>pO z_g!}^jSzWLBVjceCrv;}B(^pP#L|ojq)h~YxGi^uzd||!x8az;N0ydAE1)%r?MQ4- z;<OZkaZEz*}o$7j~6z+yR-$WB!&5 zBTTnwVQ#o`uJhW@`gET=>#vNullwy-@7G`pWB~sQFSA~V42pgweOvly^xf$gr9VDD zh<%!#a~#}l8KfIw7T6e;p%An%!uXnH1f&VLdjcC_Vows`LkA;l0*O72&fS(#Xyp?T z(UpKPCTAH(Vz(e8Ow6dx2(w&-PzKR-H;88F-ys@vOs;QMuk^lyhNTbll}_W2rlx0> z%8LNE}Pzg?x2A@USk#(cj0P7DD_9WZ8*)L4AxA;?mbo`bOjp>a*p@pUS7#JyB!` zao7S{7}x`mVLt8M78Rr?={Sw zqawI-T!@T19^t(UalZ__0_-+~_iOmgT=X9jCy`i6Vi}2fn()4X#1azyM=`uCZz3Sy zH-xuocomW83o^VAy=iD#_Hmy;Te7?dybpW;dNMbpO(@307;tUci zNSsOHB_v)-;w%y`1NT~?(3-rikjn$dinrDRZMGG_S<4K*mOzG2p#ggXv z*)1-@%psOg)JF*XbDbStYS7`Wg}B4bf+^Zspi#88MaD#&W->)bRt~5MOYuvxeddP} zj?2ih!gS!7F6%U4I_LmK7GJZ@1R$6;X+{>bz#BE5-bCUG5^p&QPg`f9VIZ3(PxBC& zbq}4sxz{z^Q#!?<`Xfp!W|!YM=Pv$<8_+V8(G%*1`%OJ@(Fo5SQp`?Z$=%m zQD%iIZoLjz0xSit2W|kC0XG8B!L7?lyp6=$NnAACqhU22 zgkZvYJ8BM^m=!`vBMNjUCWf^pG2BP+bPzW%F>E|T45y43)|-OxVG{2NC5FdLVt8EF zWmb{>l01b2_{d132ocpBQeF80A0R=lJ24H8j6kC6B%i+ut0>#KStu?r-j&ug`kOjSP7BF)u8b?-L80}TZ=1tcJEYp&$}gt*#FoF^GUQYkF`F# z<}2H}Uv$sS2cLfH&Rf?YjEkpILX?2dQ4(KqVVTk%6a1jmCyr6<<3j}+fTm{t4C)EHbn+OohEf;**-B|ANF9k8Y7!e?{QmswBN>k!>dtUUKZ? zMm!Z3q%_0|+#%M)#Kek#1jv8_r~q`Or%BvO;l~*t?ch!jn~rLNHmuQQY)hQ90$KxYfVMz8 zpgnLda2{|ziMvRAnZ#E}+)d)EB)&%C>m;HbL(selx{QTFZBiv4W4ofY!j6jVreBZk zfg|X0k4cwrYj)J9OqZXXq03W6m$5@w1fY$_4kdAK2wldG;9IM3Yotz>`jN1U9Ox2% z*e!58nr%qa8HeXD!ZntkvEzYk65k>5T|UhLCXl#~MEHZ9MMbs8{T=gUt>+>(({_LN0f7=^cKevDOk2+t*&N0HwjTWY{fAa@#-qy$QP@he^ z?h^J`5XLPu2`{ZHkmLfR+~o|MT%{4_=csVjQ(~vEp7MT#o`P+jCh+H{dB-t0o%0R@ z-AX6oWsD}?x#cZO+?g91!&?95t2HpYQ1@-~&0nm+OKOpgU68|9a zPZIwkDTXA0B#|VEB$*_IqxlH&fon~~eu`_K>Gh~_FucOSxsqydt`tiW{D(lfQqmd9 zJ!O>p6H5&=^w^(CvV>AD)OVe7f7fd%Ry&epMgQeLuuxTW%;1J&lVW0QDy}i(+GIc> z$wrc$Pc49zBnL_Q7B$uT*#CXM4;u#8ZIB##!Wd--<4Rb@!M^1-H(q2SN%7GbH-2>Z zDS&BBc}Yq*9T?ZfT?>qBgP9O%p$^}1fK7{h6ICca&;re=#YBRG+ zO-aHch0P@OBnf)^(VR4G(DiK@i0DcHjvfZHN)1V>8J$^ey}2WRL2Z42zCb3>59kkM z0Ru>?MN%D-&L(WhD%B&YK1mHCm{oh1=aK9(E#JE5WkS^^KP;l7(yR^IuR+PuSsHtW zeeE}lA0yc|{DDZK4SV9$Q>?8BC81NS)X1RNf)g`ngE%g5UN za-DM}eCYeXou3d{Is+|hE;<#Hu&n}^30wkj7nlV=$+khkwgmtJ<`8!Fm70;%oTL^c zrIM6JQaVX3Noqw>YmR0f;tL{S8#+O-^QG--+y@D_F-f?+>3k`5KSRQ&iiB-9vw%TY zu&p4eZ3qe5ZsS|4aO-wh641=`BT1M-9IF2X4YvxH$7}H5J*Y~JhFNm0CFxv}&SN&@ zW^f-#=abZx4c}vKj&@YrI6Pt41GYywVW!FTz{9{JBy}LEBT1e3Dl7rp<2reECaKG5 zL7q<`%S@h6MO7A`TD_!>pL^|-{W}V zz_*9m4n>&oq5=`vb{KWUW9qi;Jf<#Xn4GzjIkQ^?XSy4OJKNfJBQWT^ihZ$8671XK z7%>f>P@GqBJQNJ2p9hC+?*jWEv`q^BKr?P7%m{;mFCYms#X1F#IJ$9b`xp^@f{4N> zco<3W7ma4z+P>s&uol6-0=@Dt?{;Ya@fcALRm+HeF{hwfLJ6fs9 z*uxFRE<0(AU0M9;mA{y)L(i(JB?@!f&oY=BOKkqFd<8SOyGyqaCaRU~oGOklYXkx5H@AJ%C^_+F?1cvzGD=ys}8jZ$*WRj+w^r36}XheRYkucMe9bPP;C39Ck z`*^0MD7*4GwuZk#E&@;DnC`-lJirIw9STS)B&mq6P6qOIU7(mGOq~AvyQtbrkY(rs z_Nmc${bF@=&NFv)f9SpsJ`*~B(!R5<3)styFy+z0jQ?TtqusK5`4*-xNZz!(PX9<< zzz$X44$Z!j!R=V!3I^ld?b&{=uF#KzyzQiuw|y?6nWvMt{c`-iLMLzd8iKs%kyNIU z_njocALnSkw)O=GyfBiy10U&P5y;3Z%e@G|fU0L|L|D)1WcI!W_Mx}2mdNV<}wt4LZv(n6B1Cg~cIu4Qh< zv_uFuqkjeuaoeFhGdC|Xx%v9aA?}rDxcQWE^H(f>AOP%Nle9RLn_)d@+-!#lVTTE! z9ls;#I+8%o_`4L`+|ZTis>Mwu4u}Vs9exIW!*8~*?Jx`MzmjwVNz3^3ci<0_ZX^l& z+?`|#+abopI8;s;{OOPY8Nev}O(a2t-pp4mfK_MJ6(rqqI>MKf4!e}5{*bc7|CLvlF*DgzDtwsZmEF1RImPbn(?Tchp2ecPQO{0!j zm2qH<7^=)|2CF)1vnq3Yq=hYiA6DCrdI$`?y^^0D4K#kf;}|hv&#^*$QF25k3&^Iq z7=whT>2XacJDTgX?SQ)PNP{Sc&FyFju)4pVq`NiR#=y!djkaGS35y<&Htg+ai@>lA z!foz#B(084+m4O~Z96(4XlI}cfYEbD2G9-Y4)h>t4M}TBx`(8DNy5O={Ukj=(t{DS z&97wI+;e-&bWrx_#ErW7|BtR6P?Sx&e#oHfqEld6SCX{$ai55ik3!gv zB7?9W&UXFxa}+Fd9ni=f=m#2QJ4$il2g(4b-HvI%bYKQh0bsD)0X_0jk{%=JagsKW zw2`DINZLfwW|E#H=_ydQV;17$o^8NExHboXy3E%c^Kk@aKW$R>GbFuC(knbIz55Jj zpDNCFEHyaW0TpRW2xmKPG&tJldZ^ufU+(FVd zlAgsi2Q%g>!pD-NohP5I??L1baKfAlx3~KMNXX|&dV!?veDy(KozB*vBRE$7`!=ux zL2(vj_nAD8NM&8t?`?|;OY`!() z$hjS(ur&-8$1_}1Tq#>XbIByV1j6RiZK(5!B*D!*lC8b(H^{&k8vk>}g;)Ge1cowS zMclhI;(is8vSIDm#wx(Bh)D6l-m>EI+{r$FcYIc)sA+bG>G+z{@i8}y03I!O>;d)~ z%>6cgzoRqv9*wy_CJCEOLJq-M2CjTZW$yP7`29%ch9>hyHO#%AyU1Du`xN*L_#F5G z_!9UE_!>As(wijhCFw1~N42DPNP3r~eI&gX$=v)(&m#vI_D1&gd28ozE};MO#2p8P z)+Fu^{wsENlyXNm?3zg#59c9ajse4PXc~?kwPJ zpe_LYI<7v@0BA_kCnW7B=~I$EBk6OJz98vKlD;Ad2HXLTrZM6RBJH?lXrF)TY{1v! zpfEFOA2dn(aOD{IA7?oGRB?73%mmHOj>EL>p%BiF%ivq9P%|(a;=1ccdnQTWko2wg zHxI0Bb6LW~cU&eO%|c}|C&cvw`jZ6n{Chqf0AP&t2a@nb?W0aoABPDZp71b4KGH~- zO~*KV3km}FMB>l=)Cjhy+ z2Jjn6zn=~oK-|U1GDJ$;lxS@J&63Q_>pb1RxhALPkQH6#Kd5T}aYaU$;%H&=f9jc# zcQE7idG)TWd028_-D>!ZcpOyvIH>ZKWF3bwY1Hta$0+pCl@bW!ZO2;a6bA!>={fE) zU^bq|c^mEgivP3c>v5;&fIhJG_$@U0d=65j$!e!YQ2u~iFUs_h4 zQ&8pbR5cunsLcWKxD}PgxU6c%_?W5?Xu`o3c9exuVNa;LD`OM&J^#WVfCgdM{^F@| z*p7P?nZ5(%(VO@iigkFqioz2!ptY_3%;iy4rIUV?5{^d1n{^_Vo&Q3HLYVkzw5%7= zy)-7?f|ISlGr%_BS>QPUYF^w6z;<8<$!?PI`E)PI2_z?yoJ4Xm$tfh)Ah{+p@lM1C z#x)W53a+6sNE!OII2ZL}iU znnhP_svFSp$O{Z;`J8A5bgk75GExu@|6Dc0Dn1^%PdrrkN=}Z)82UhxQw>gzcR~?D zwBerJ*{&3P=D55hLRKEv#uM@Nkb97Hd;rcvNp~T+rAE?iNXG6c zN1L>cZ-&6l5m6XPcObb{bdrw8K)XiL@vRZG4bT?A0D63T;9TH5l3SD9mgIIMwvgm2mA+w+ag@aK78hj@7S?Po_J+;vFrVJ<3E3J(&*ujfGmd8EmWk1{u25W$UZ`PuN= zegc7?G-8r7aI#rr+0n;{={W4&_-zK2K8IML+-p?29lv+zR61Ux(tMKP<_CNCa*`(< zgGygQ;9Zea>LdP`bu{Pgco+fN&K~Tz9uG?}{!L&HuorlXcA(c*d+56l~oNvyLdC1;BfyNEcqic4PBir*NFy8jyY*8 z8Bs`FMA0bncY`7)XS+^q>LL927kZ!#4WIcD-8aT503sj(G5~SuQ~?WM1uzzJG09U% z22mE0TtxT^xLiW=RFX?c_H#6L!~qwr%&*_6GXsY)d51IUU&6IS^S!w{i}O#++~WYkzB< z1AXLMe!2FcHA^47NM~E;P$SH+XklKZS{Hvjs$a?NlYg+z>v~v47}q!9^?d)&?8tn3X$0S1Scp9r2Kb7~nJJEgGMza(Wjb>aXCB1mrC3{pYIRQ1 zDRZGlnKzPrB~vDr9LqNxoid#lBk&YN1Vu1-h#14X*qF|E&qn)Nwuc+P|>%0v+d6Q(l&!}E7s z1JS~%)yjKf8PA73`9DFe&gFQOJ5ZFM*6R&w9e>iO)hL+shysm5ug;YQy)Mgko%$Sv zNJ*9<52Dv-6uSy1tARBDH!rBm&U*mn&HDhT!p;XszKP`JB;QQ(3X*Rj8S4LSB;QW* zN|Nv3N7o^~V2XVNJtoKmb#e)SV(&C5c1@)T`tTWsJ!K60JPQppcjpTv-xbQR828sq zQ0GqEehI+Q{vFAyNM6lUIr9n?;Etv?~!Gu*dLWT$yI;U>bIQ3bQAJfdx4@kzAj7J;Mb;TiYJR%C?)GZ`q$Ixh;>Pp}~ z0Kw-<1d@PcAO)xa)FgQW$xo0BBlt;@pCb9`2r}iDFv)bIF_h~ZrVn#hvvY^5J`#OO zC)7>a6zvEt02*m9@5XMb8t^qXz6yKd)bGdPIv05|$a1SemM8eVGJUjGdtrRhMw<=@ zE+=LQH1S}!C07@NC%2vO$I_0Tc(9anbwdNlLS~pEUEP5mKu-XwxvMwO2j~lA0{wvg zBtJ*;^CUykZYLSN;zg2olKc|MyGVYSqZxqsf+*58B$OguBXA!S2~T4Fk7Vposek57 ze(wxLo+^rT<+2PwBX{MIygP&#9KHvp8W8m}@3*32-UNZ<4%+CkXcTqL3*Yp9=#d^3bKa@@*YY2FzN6EcYk?7FVYD#YaypGq zP93o2szx`Qe@X3I@s;p!zarPQNbfqcjuz><#JjpK;aY-Phc2-%nl90)0zx=MP~3!= zRv0nK892c{^q380A7!>cT}zlC@saWIdBwTqg&3U7@)b=gn~c43i}L-GeR;>jl!%Mx zK3&`tp{kqKr)#awl>0TNJV^3KruF&tF_@AggI*ublu&^_u7)We=B|LWU5@~d0*?WY z1E9!HNdA=M&q)59MDjNze@pUVl3_V~Px22W|48x?l7C{t`xNm76W*6$gm)14L3lr#gooWwb;46D zX9(|<5gt@}o$!7q`Ik__!`Qnxb3>_jCu@YKh@{|C zD*wJ6=RONrb|PPAMw^K-g;2l>Wy2wl-DXT9BJM4jW7+Og(>=}^@DfU$f$LD z%fYWEZ}EZ1!U@ma80np3)=?9U@DxQSJa;puDpJ&Fgx9cJcx_{N-QC8Bi3!i$nh8&_ zqPCgv-26FJ#1&3>$H8;%^L3tccSJOube?l}!SAjb&nehy{VY;ykYZz=Q`(b)J+zNz z5xTo0aE}O{QxZwBN9Q>=)Ol@`)!h$4`vWin+)&)z7~gge0tS=fASIp@7b$L1JfwI@ zNr+%Qeiy?qRPa>;ZFqiQSbE{#!n{Zj4$RB&sACB${_(B&zw~YMws9g_9noY@@KMdxp-cN=mlt zzm<<*nsr}-CUiM^57Vq0BOY!j>~3h~?%6;9AYcwK7nldkC#5DSwMeN=N*z+r0nR3+ zE-Cd$sZUA+js}WzFwMFb#%N#q;puU{?p}mrV^SI#G^@Y^@Iy?a!NgSBp5fV3#k1~P zS(HG5bl*lwqY$2TFpa-Cu&37U z?j4pqd(#7BT7TR=3e&!bIChzJ#4%+Da+}QUvylHR^8D1 z`Acu^4}cF1GR8IcC%}GE#_*TklrE&4r;+g(QaX{+8QGN}!K66=Bp4T@1SuxXN1)I2 zY@0?Wf9cKrH7OnN7TV}6B(rjUbzgdOA3`kLZF-Z^(IAo$e}_oA4ISXi$8Nv)s$2T- z(wriHK~7nIaZ!4Y9IWY02hnOjs{h!V`;fsL9Z&FMZ|=*|ALV^9)s~Hgq0A&6m=9VQm=KX$CS<+*`To~_?7nGk zdXqy}eY+kD)WU5x&mhDxl#2?5&hpw^ zS(3`}dm1nuv5wXSy=N?bUx;g$>eoEk5JM33muZ4NhZOj7!s@z=l#7lo=sgp-K_H?l zfvfNvg5EQU6y7GXQqYg9PSATUMkqtj!>h9n54-)X4~v-}cnkler|~79?&T9F`bq~E z7Z+47>pd46vOYV!^`Z>!Jq=yS~22cUa1fb`8xFBbdGJ%v_Qu0Xg zk%E4Ll9)_NJ}DQIGKFRLY{VBVyTP0Mp-u&i$Jafq-a~d5nCg28tM9^VtiE4*MtwhJ z!utl6&@8-{k%Di%qeGiJy?K`NtyQ>nvucl1C589&^sE8yCdE(6w39Esp~rdF840snx(CBb?~_u7gt@1B*0UrjkB}tp zR{g_Y;c+~@iDTmI!@%}z1fC#eIw>ToK~?C8YO? zQRs38PF~i;_pDQr{m`v~{}?i-TaSjetiP6|aIKl6ObU4vV}XTayc7o^M~WgaQ>BgV)$Z^oK7 zKW5zk)+iCmTKIw|SklXSVo zg=sk@B?Z2;8HEL@C8fnBFzqT*xwx`jO-AJw=lRkyd-m#|UzVn8wLOhV$F#xxjD9Vw zOMB&*7_SxiZ-Hv_Du4=DNV$fTYe`vzt1KhDHo(quVlgS#1zKgh&O%DrgR?S+4bSe? zGjsT$q1nTFW%cSYJaf>%?Ebw*!wijhU}Wa7%Z{ITPp);$I*Sf zH4sBhpcYUYm5A=6T{~MJe!h{ETS>uS4*W);2;p?a(TAVC^$|e>L=@J2mXmTr^zP$@ zaxWG_KzO0ed!fyPdv1#8H=HSRZ23lWY*}xeX)|(ji?Ju)q$s`TXr04*ZdK>N1a=+P zy1M`4&JmJ}C|$$b#poKhoRn116oWd3)(P}N@cYWj@{1;g53G2*qi`{%uW51K9ysX< z^a9Xzz0mZ%eSu7%9{?@hn?=g)q^u<64pQzU3p0Oyzrc$$>W2G0nX@_Z_o z7uTB|0~P;d1jBGTU=6+KEm%S^{4yGiv9kIR;|)|`li7>25OC=XEBdOV~|Y-gKWum z^*EZ|GpxA0G}p&V9`UWW3-ok*Al)8%woLsfyqi3S65NhTX~8`kTBr8~Ql2H{IX>Ni z>*(dr2fDBp^q55bavrLOj(-?2eE6tf$#+rV9*#Mv4pEJo9 zo(UKa-d8yjEWmb?@&X@UBV{|M>kdhgJzK+rL%a4uuEn%igCA%<-n{@?r}u5(9pGJ3 z(1KqiWhW^wk+O@Fm+>gKZQ(opC|#%@#fcCutI*zs4fwHx(?2^u56*1)6Z27hgC_Qx zF*$!iewjbBh;vd>Tnc?O*{6y1VP!dGzU~#7m5*a%HovdHm&>K52dld0&vrHNg*{<3ZgC}nLO!i4fJ62w; zws-wr)w|%vsHtUR|BhN#-C)?r@`5QjMVUqUW%)S;`7^btkm|?7yuTa0?e(xWmY~GM zB)GVZK?EhJfCaDuv49P*1DJeBhy&sQCn;}|vWJwtq`XDS+oZfh3K}BJ)AvYupQCXj zzJ^suNDS4a5^CTcG^r0vO$uK)H@wEaIipFPDorY(3EDAhQVC5-`7lJ2N@&ivKw}9l zbWMtn3F)MK#F`ZTDj#DmBf-@yyz#WfW3W3kr6!>rPTG^QpOjA_WE0K<&L`zFQocOt z!(j+lC%|Gz=m+#C|v( zB#bt~jENRTTJWEW1`P(T3e;a0cWK)_>m${vgmH-DA}%UaubhDsjP4I4&FclFQ z;@lh&`;(L(qMP&y)46xtjbJl?3IOVR!X*Hdz69v*373)bBPlT! zbTWPy)9OEBSp6O>q0uZ{X5FYxWeJy~1V$ml7)khskqRyyUZNDGd^hM_A$XNi!Wx|-RUzB;-^@#}d75w! zTGOM*o5sdWrQG!I2Oa<(1l9o$0nq*v9tIvERU%a;RUuU+)k3P3)L2q&q}oY!a1@Ur zzF;U-K5qb^(_8*_8B@pWpwc-6kEw zc1U;)(2k@!NpPr7$m z!pDgGGftTK@)KY`@F}T@q$ZJ?%vV1LzR*}yO(7LK4*vUt5((cR%gmzRMq@-de%wd9 z>Sd-rnmhGv=?=$igGIkL!oVzuWZus*x9tAyP}XIO-#EACduO$76@^8ALVCZNb@Vf2 zdoroD^nsv+-2xkKk(^Jbm$D62<1N!g~bL{A~gI&53a8#wUNfaElI7<46F_yHSOq|D<>u*a1tU4 zWni@hsrUj@v{k-|wYfupffMThX8{<{Ppk{n1L^|}NNq?eq*xPDo057Csm(}j9>Ku; zE(QaujSL1(8VK8InmNFL5ss)V9J#l0IPaop%CBzjqmp;kRD*X5PKVAd ztajn;l+}LBzx~hf@2TS7#A22yFozRMNbMBDzlnan1#>vDOcxjWk<`u*8T<#v@HBM) zkd^~`An`I>V*#AVB61d~T}jR0)7e0P)NZ8qIqB4!I3JN;#R-FC6JaYPUIAQ5YIjn5 zklK^4E&vwl)Z2^H-lqfgCN4piAu+pE;1?CMDBO}rU#+-lSjj~XQ2!lMRiUxOqQZ)cLsj37yO z(^{@k;q|>5!Pgpb$r(7gTO-`8W5kv1a)nDqC~e2`@Jn20a4^*V#D{ebW-B-mx;=C7 zP>qAflRC(>f-gJ<2X91R7y{uOJcd*_g+}GzEhYzVMbKw}ZNRg@bHMY!3#1Mqbr`85 zNJT$^WE@56=tvI6yBND?s6&kp9C-R*fm9a!8>+Q}6JNobA{AJ{>TunAWHblzb12l! z|C|Y&2z}Tvfz`1F75h$%ii1qx%A!e+Ub4|R_>jTD!);Tsoa&0d&zy}jez!;VDKZxROWle%$H zp;DNBle9s5bsA3DMor>Ddv$sw{SKV!x-`7lGx5AOY>&W9ze)Wy`ki@A`*_wqrh8ZBL zO`B9)#i^uo>c|0@^)Fy|t6)M^->8iA6n*I@DS#BAjAL<_dbz=dgHDVM^*7P@uj=hL z81=o8lR}c4P^MQHymw``>l7pz%y3ByklYQ(0yA6^H1edYfop(kfknV#;5uLluoSqS z)CHt2B=u@iuOanXQWufBnAGb?T|(+oj)s-uV1|Q|8~lCxq}y;G40pZBaQK2bKIg;) zch?z$J7olSKlflX=%fcoy&;s~9^zZ8a0|-3yu&<_x{QPw`d<*7JzU_S#U^b=RcZtW z%{^%osW*|j90D)tN#H3`ZzfgyHhoRaZ$&+GO;-cl@=jI;Hy0HK_7EBh35J!pQA*Y#j4# zue_(4H9c$W{xJ)pP~}HRZ@*FK8ohm@(c7wH6#8(M^~b|;UmF~E5a}F(9Au9B7C5YP z+`SsdJw_^wT5#NJq&{*Cj)R(>1T{UJ6oZ&# zfz*3Qy^mCMp9e`@N9se7REL)^sqS85FgK+aJetZ1e7sFpkIBB=Db)<;CdXEVyEFsrFr_9p zMQdq;Cc~7P3}rmI82}wTxdi~lJQ><|ayrlwXa!)b_Hj}-kh+o7CrE`DMGJqDR0zQ<9dpEdoL)H9!tH+&;`|AKDiWs{3b;SgBc z^x@3&8MoQFw0Chq9(+h)ZAILkUYb*qm0#rZgA2?xd&&I_N=@!h>N6pfnmo{;)Z{^^ zB`a!3JCeFBfFUUS0im7~#%swV@z`iY&xD!`{XQ9wK1b^Fd^!dgOX>@x?mFofWAa6a zJdYCw;U(t)699}|Y$p{=`XXP2x}OYnpJ{L>srX>}zdu)+T!<_?k*}g?l(sWlnD^7X zjPdu*{-NutTPEz&X)t-J5vDX+m?GDAZC_f~Uzk7Y5n=k5&%!PaUx1ffj`U`5QK3@U zVoaW{=^iiRly#5fnXG%f5~+JAUxe2-hTxOu7%?%SCS&;<=10wM##a{;K6!`DC32_0 z!z4&J`tj}fbB=>%ldnQT3jnD4$x!u~X0>aJaD*0rgw(f4eTP)-v+;bom(;iS;6VbA z-S8bal3^F{i<>mdHcax3q`rxAFnv+gH>&eRO@?V;8d-Y`4(WSLBg=3=?eD9YP@Gem zmmYr3A7V%=EJT4z(KzB}gCq99FSw+9LP36RTJeO7;X8~u*VNq9l7e!-{>QKRd7t3c z9LcLuAW*P%I#`1f%o-=J1?~Y@w%-RpIZu87co2YU@h++RNQH02`=owA>W8F$L@LIb zJ|T5K2U(B!g6ZHfco?Jh9dq^T$&ekApCsCxVde9$FaLf||ZT~Fr&40t5JN$QuReg#>Ryca-E z{hHK6%m*jcz)FU#ko=*MuqNa_(1hFpQ^1_W z?8)Wx*(eJyDi|HfFgCQ>*7)F0jStLk!6#Q!=oc8$ z?l^>hiW(D>VgaC!q{KoxLilUf95_NW{7x2yEEZCK)@&@C%4AWGBK%Xpz9}xijmW?( zDPACfEHR}1N){0-5lH=o)W5P_X(8)r2Ifr5Eb|riEY|XlVX^W8U&yr}B`XCat1Vwm zNkQZ_Nd1k}NJmzF4b$@aU9+A>_343iKl!=50w#FmFr{AAlYeSYj%O3qSj_`xo9ehK zr3oTJ=f;4bMbNp*EiE^fB^7Efft5(1k)@fr=vsg!OXXOQ(^)TxDg`skxREw&dj7<+ z#yaVwG6{B02g!q;w3QV8bUh%JYNvB%eMM#dpp{L7vGvr%;?hEYdj8%BqOBMBQuB-bt=gxxY+Q!@b+Ga;zsTRYYH4;} zSz6_FUC8wGP0T4TC}R-<@gzaZlAtoBz`3k0S)^=NpYW;=Z;HAncU^5Ip}#cO+?=6u zF+2>#lG5UfS*}D;FH@T6>ZJuv+a5!`H2O4~nAxrlA)-*XKFuYAX@h-}a{T4~fyG6= zAprD_StTmMC?lmk-m4qllSdj-&IQf`&IdXGm=jCEus}*@pbO9y$RLZAEU{#FNJRgFntqUiVS+m%$8ru zBxr+{LPswZW8GMwrW@g<1U3*^721^}8f6?(u8x zQFcBRsSTzO(wk=#x}1TNxvULZ&OSz=ACDHe0I|XRPq`Yn211OrK$!n2i-GIN(vU1D z{B*L^V=d4EZKpX|(vGGDE=9oW0YeKk)-PGkAxnKj3lym5{XlyQQT5hT1!=4W8L0;d zdoE_H`CQO0KT8l7UW_X~>iygFd%O!!$|HEz&lro< zAuk$@do~%|)8cqOKz||`$ad8T;b5)&p{V8*6l3_b>Cq@od!ruuqo|1Bq4Sh2D9jzW z)&k=rDO-VOfNj9Dz;nR!zze{3va}>iE3&jEOB=GZB}+T9v?t5C9PmY8Cjgr}Wf$-= z@CvXSc$F;Yk);D!I+3L_S-Oy=D_MGyr5CS1Pd3+(vvm@*$a}0#;CvNh$F4kISx$aI zmBoM|xsp;Jb^t8(<>_S2E`S&0=ao$!=g)-#k1^%c9BjFcu!btYJ0}^JoCP`lvfkKJ z2@A`+;h}NG(|o1Vuy#zlAKYu+MKi5~c9yb_EawM?qy49)^A-dJX?ZA4^n~DtKQtfy zh%6nWJ)G^Tli5A9hfx!Qj6|#6szF8pY5@PjD+xAz$``oaV&%#}tMHpJ_ETWZYx@hN z93V>u=l2j7 z39^rW#H<*vmm-%kmsofne#OJTnHe0RmC*6XMHt__OuvQzh=yFmwHg?$siBgkfS2i8 zAcNt21i4s1mMpRiIEq}XVKoTSkc&JtS_Ar4Kjup|j?q~ynbnz_HDFhpLIs{gb$Iur ze$@<(mR6KsoL@8}wJ^W5w74{#l~!|+J{xKU*a{+TSkJ81Y#~j84OjiD{2DGpg7iPZ zVb2;h@v@D$67I#1T0m`}4saH5Hc%J%f9$;nd{ouezfVzT&h(jxm_SHRh!{wPV55VG zh%^xqLr6lA5+opCx$qSg6|rIO4I3&dDk3Ua5PL(#a#0bnBX+K0`9FI~GD&7)MDP3F z-+TXjcyi{Af z=|xR@ChiwnI+?hC==;RZ9J6H`9WhSFnx&IAR#M7#{QqyA{;k$&)KHUnkkRHhaD5n1 zkEu89nb`s(z(tm=nn|M4$#^ydbb14_mb4?7&GcUApFL;`m#oHI!BjS)Le{`yM?x znH{uur~HB3kEt8cqFbb~zRl)+iT{vodT{f;M1{+E8s9E7H_>LJuBV5$FFX`YQay8? zQA@JnkgRQnzG$(I0UFmJaS@yq(ii5t=na=_vt?sz-R5k#lz1M=oKG?)DdtkmhD(V{ zWt%123E}lBY`A2L)|rWyL^|H3vdwH{F`L4K9#CMvr{KF>;^~^k8!k1xJY0svWk}HM zU6g2=?#;5DDBB!!dJEht+g#ZmGfMv7w|P;b(av|9QkYA7mu&OQafNIrnSB3n^PHQ3F;HNJ_@QAv#F#1{bLIq@agPLpk+Y^Te1hHPgpcos{RZK+c8 zQrT>31~XNir&ZQ|g<}x>s%BD|Z=X=8O8VE#$>V1S-;Th19*h1$Kg60}s|ap3S>`K< zA0#{l*Tu}kapSi0jPY~BQ*zPnL?Xsn;@e#CpcXL|c`jJ~(@d*<2i}$KEZMGKU|xe% zFXDUrxFr(teNH}*?QGf3F%dt6t+Fka?K-1=yftPos=kxCeOx`A>2o?jRb*{roeR-0 z1MKI-uT2KG^5HZ19I%}ezXa^(#IIn7Z0E|hM7Hx}J72a7WWznbh#1BQO2l9e9?iWf zbN(a8Y-8#yHGeKKf3Cskp@?ZAr=$;3i&_g~PWu>NgQ@XYD_%mrP;iB2O3VZXPCs#S z&E)Y|m$9;#T7Q{m%r!TE|B{@fmf;~Wsg-OO*Rw^EFh7Em4rV!yu|+~hmf{>0U&2z&^5FF54BdUCEf5v@axv%z>+9<4M5({X3yasT3J=ASo@DYVSYv>22ShIcW6N zk3aHS;+!e$8DJiYOfn|AiIWv8&X}+7f3k4HVUJz3D|f~Gr%qi~3I^Y`oEjS}AyzowO;SKg0mZFf1OTwi{D&mAmh8twN zky0derN1!--1Jw*fF#W3q`oEtdUVpka0v7OQ{`UJ8~VtGs$C}AEwZ6xZHvvH8=>A%XYUJ1S(`(v0H<{L?UBYhX#R3oJ@w}WxGeVdu6-N3<6VO zT4)ehDck-35re=iiflUc>{uQ8=<6a&H=?4y1qXqD1P6f!IW>bol8hs^s<9(xKRU{!NjlS9 z?_~sE1ZM%3brP0!66zak?_t@P%6UY#M;APs(bJ4u{LAQh+L7T83ttI;I3x1S;u*nj z%6x4Gmrtomt-V)hOdh8BOx~9Qb5={M*1;Lp=tAC4w2O_b9)JgBdsem= z7IbddNmujZql7fBcB>CzD}1!z>jmE|_}28P$M`Lq<2u=%TYv_CenIciwO1vh=S4U3 zd!u>Ir1iwWB#xUZR&p@a7i4?Uq{^yKbJ5Hutt>y7ST)nkO=k2Q-IH*bs-Lr_QdD?bYb!MRQ2nG$tyL5z||w zeO2_A+=LDpCS`|LO_(*Jdf4QNlg!iU(dKT_yTrr*ZLvSjRnk9UGhhQJVfrS009ydL zCL!0Pk6;^o44=TK@R@9{%l3wBZ_2hwwzp(^Tef#(!@y>)db4ayp}a2}R`eE=1%_@C zhHesuu5qZ$K%De7`5RUCEqn*xhki@?kCXcX)We+}e`lAI^;kA)!M(QCE z^yUUbWiT}=GOQ}J9q-<~DfN^YtiqX96Z{QVs4}YmwzFvG)9z@|qMf5fi-Z)87}aKi zq#cHJJ32u-A22`OE&vI#Z8a}Iux%6DQ`Ze^^M9_^CD*?wH+D~vNUU$?d-q$yas74etpgfUZ152yNR znXgx5bs2ZnSX$P#d-u|!qF(uV#iiZ47Q5HC%=1MQNOOei+cC&-nUzReveu6 zW>g(qK6@?=4sSGGCOP3uKBwq^K9hK|l2xswC znQv|+3uYJ0{l{tJr<$$6@y9Eslm*wJvFOgcuW~r|Kk#FRRZTd!sHCc->xAwV`Pso> z!6jjbme))=xS*&sKfk1~dr4_=*Mj`QqSDfWu2Ervaf`cG@_pC*c-8M3F5A~-zA4RZ z53wddBF%7aMa?8`8&;aTdtEpQ4n;M!w{{}m#4FB$;o^MTs38^fE$rH@TfdULg8Y(_ zyyE`Fee-(v>)kJ}f4`#Q{zZLzm*)5C*SH}?tBiK|D(yzm7587^+n0|$peOW#-p~j7 zLO-CFwi^J4!az6-2EpMl7>M691X|77(fBF z8wQ@Oyok2>gPVESEF;ieOleFHX~Mr}1AG<1r&z@K{xM~{rD(W&QWx_T51}9cS4xU_75iDdd zY|Y4loy|(ZfkT3)A-!D}wWKL22A|nRU-2>lvyV^J%({37{y~;URLwFAh~wnit*Kl? zwHv_Wc9SBquFJQ3Q!%4vc7j(u7`7;EvHiiTtPZc9SeHw&a*M>>0+SYgo~GVg6tg zX*9tW-Nz#rC-}|`8fE?d9Q{U%x^kBOK`ZOWqVS3HVl-?tVm)Pb4nyzjVHw;4 z#@@Y6cDL+a+5NI7$lgZwwz4P6-cI&p*;8aslRZQBEZK8p&y~HC?0K?xk-b3nBH2r1 z?b(l|?b_ z;}=3^jorf}e60m&JnlTRXsQMauuDO=?#11U3rgc!YOjXV@WoG~sIsUEgRnSm8gGWv z2sDvKNo7H|imGmL(|9+W#@;omd8zFTR4q< zXPg z=$c;<*DGmn52umcL>dL<<@pFCZaLiHG&(ksMq#(Yt`jON;-(P@r?FrBG=gm`zX^G? z4X45S)_8rtsHD8OqL{vm5{NZ^v~M3yqjUT;3JNEbPpFzu7&ncya2omX(jh^w-;Ju^8#l_z@ha2iZ1$8YOhyH1!;7{84T52w*L zej4b?(vr%O`0eB9a2oyNr%_zcwY;dXd;D^Y4X1Hv{50sd-K+Au1;^899P-&{Rr8I$bMwKyM*me2!}V%)SEm)$UH;eCiK64__^WmCR|+{ z6EYH|e)#!O;p^gr6AwnIAO6e+;X`q13qvlAZd|sOPghc76| z=vb?FoNFZS`dz z$qlw1AAB-$9YuaYKSSJP|-d-m<`zRA}+ws?3-ykA3Zf(T6$nj-}-CHkwb7Y7; z+#WkPrVO!-+pm*-jO@o68Gf(_;p$fnOF5Whd(7qbPs0XyM)t9?m&sl(`}q1Yd_Ek$ zo(y>>T%^_6k29k9{I=^CG{^`|S6j76RtX9}iyul^-N~B^}v(`xWefuVt^2eX8u!%`{i-!x%>}A6ip)yCu5yd><}Q z`yYt@BkY8K$v#2$NwOa=`;_`3-W3iXk&>xEdtUcbE8>YpQlG7;ZXl`T)=@Q&L{7Fv ziFmS!_|9*yr4lo$gvrjRh|Lgja-c!@SR#&2KQa8+L~@es(|BxxJ5l+?g(Zdkdl%;Q z@7=#&UUApbetEt7^e@gUEb3KU+AqJPTmL>K89lasb@P_%&v~1+6Fu4{r?hC1oWXbT zFIRFVL9!rQ_8GFzk$v8Rg6JaUhO3agAAvf-{(v)kg6uW2&zAkfdKV=*KO8b8b<6H6|p%NWk7@Qe{@lfh+Gs@ z3(I2rjLDx{kY8F+j<=8>SMnpM^(bm+me@AXbIC{Z+i2NOmi-hn*t|D(B>$qHs7oFj zE@JX=1TBMcKsP&8_W80)_S5PMy)qm=BDbK>S%F?F^nW0`wO^F`7f__=tBd+;;g8M%@O*^4Z_C~dc)Rx8kI&_Hr09;5#%g5TlUjsUo88Q`mOie zaJI=P(B$*re7HdNGh|;RJF(8GFUY0g@bv_FS(G4IEgN%4xhkrDk;uu{MG5jO6EVh+ z!jM^e1)3wsI~s(KCCKP2%xqEcNv!1iWM}^I7Ov+T?2moPOPK3ZZOGV3H}zrnPbpB~;hu0ci}qpB8(++qJ(Immufu(4fn zM9&%BU_*IDAm-jr@ZShfwKWTz`v(>)mjcXu7^k6W@I(bCeZR~bf)gXLx+97SLgE19j$#4e0Ve#A}`@M16;p}jZ z9Zn?Z9Ken2Fi&=d-TP&KQ1(^zWq3+Bd_)YUgdG+{$#A8S;ika!hB7=os%nwQ9nOl9 z;R7b(_6n?w`aLD03!5v$h%StTZ;lMFq!M_KF=coyzg;K$YS|x-tvEVFbYX{^3Azk! z0ov^v*&mgCt?cXS%P^t~BVq{3@a`xX^4|KGefhpvGJG&fhL4$uA2;sHD8)b34$*-1 z!Z$~T&roT+$CxsFf!|(~{R!Ehj3dKW!#Q@KgLgnDb$A`#kRAQ|wCp&n&(@dWTjB8a zWXS%SwaRxrqFDRelHMOQXil8hRxJ{_!$(mv+z^yuBh#@1O0hO#NFGi1Wz=B3@Xe7S z-eZTK;>hr4e%mGc^RmAXM~1(LbHsgWk~G2bj_mK&mtk=@d_)XE8J0%LaFY?m zXWdE{P^9RL4vMN;Byvj6C>g$OBJLb;Kk@2C>>CxaIWip7AbfLVIE+f8^nxx-%J4c@ zaC2zZlL0Sf6fjn&;1Rwj`v|KO*JPWyCR_UNGp@lkIVmb)bFPURgm2C@Ig3g!HrM3Fy6X`&1)Z|Ql+*rM zJ;OZZf^bGD%(kXn1Zc;Ui)H^@_Ag}rQugijMR!>^e5CfKU`-h2DJaLP$-b0_2(lU;mVJlpKg#~E`eJ)DoNdZu1X>I0 z;BncR9Q;=H?`8j?zSy1$hp!U>;dv^zRvWQy7>(X&N-qV)SSyc6SW&d4Pi~5pBTL$G25uT}6%CAw9|Hbt6 zhpO-63PuYs75!K%z)0lOJ)0ND6)wd)22`LMP+14_Xmb|mgel#fg!s4Q?h1~kg=<#mPGm7oQdu^mpZa@>8n@g!E%G6Xo#~B<_(@o*5J?qIj zH7i`Q)NEp-GE-5HskyTDl4X-+mu1zHb?W{xWZlHzkXjT~^N5HE9}yED>ZgA|RQQmT znzXP|do>6jOR^0GbtqLtBgPff;Gm$K^#yfgIHS~|#2yC2VT3G}*}7$UWO?gX1l`!E zQ8p#0Xg9GrfMeN-_$g@f=1f z#!hXUiHI)s;kwRfwKowz-1nw+lrFl2sKDBY&5_~y2H~3{L)2jE%dur>qNlzZY;39Z z8(TyLroKUlH(?XJB`Zx$9lv%@Nes z4Z=4^P&=t2j$o|eD|HvY{UR${R*q?GFZU!|y-S(KX|P6VEnBomYXz-=1&|$O?I){~ zto`drEX@`UUsrp=JEIy~uF;Vf%)BSHK}M*gKO?%deWJoQLv(4VyV~?am(k2mnoAS< zA7d>-8h&9~9KSFP#g~TS>ny8_5#4Kj(#Q3Dpi5LQNQ?M|Y50X{T_7I{WaY~$lvOON zq`v5iV~H-xFSH7b=stBh*EJAbEWa=<$}hBvOh5hho~J)(5b;m?g=xFt7p9^6(vBkE zplMwmGOyD{hMYoK-7vV*(0yrU4v%J7DyzHM@r-8=2Tm{Q%LJRu3U4|LqYn65aY0U(5U)n5LJ!SQh)mv5{Bl3;oTV8Kc z=<(I5w=4*LSo;21MMtG}!PvJN%n{A${r zsV0RU8>e;&eptJr@b~M@H$4YEcHB5VM5lS?ZnXL(WQ*_DgfoT`zq7>6EC(speC0r%za9KylI#Slq`j-fW80?(&MvWVzMvcKnobNmPq&BGEEm8H0 zL{7V-ZosvM1h2!z_b+G=F`^XfhJq#y$Fv8cGOCMHfB1+N{3BtLJnd0gYzY{0h9=|} zv#=7Ae9QD9`+W4x^o{!f z*qkxDp?VC(sW0?~GDJnDeQRWR10TMTRc4Og$tsV#GC%EKp;dm?xH4Z+WMzK&>{-!FjWI#*8=Xlur*X(y!f5-F$7nZCC=7YI-YE0vc!9FYqh;228f5^L;ulEW=fW ztV&r`vL?uyNYHdNYx*AiPSZ3`mZzgi*>cdDBx^GJmUH2cUvSidf@33ly&hRUo#(p` z3O@rkBDnv2&5+r%*v^4Rx2xuuC#}sUt5q`(sNhgOgXf^lJ_U6vl6d^OW90ccbF66) zjb}k;Rn6p)w&1(Px;7OwQYaH<;Pi^Avn#7cl#e$rj^$yR<`l8s4y%=Ib67K+P%6qPJ7>awKzQZym7EX4O(+LEjB$j+?vxfIKe1N&w^~gI7-J7 zJV92Ctl6^W$eJhXWYe1WgHFH~{^9}l2YSwgigTvXKQsx`{H)fYt zNd2N!cKVSt>*1z*+{g#!deSk5{vm6=IUNBbWi61SmATRJ@7rK9{TOmO)|3Kemp(?8 z%yF!&(@eg9xWQz4IiWF%gBmM+JSP=U2~{uwCdyhU>vUOX$U0NjB3WnA$6J}7%$*aC zWNFHP zokTQCI9lCr=!T4{xsxW3pB%NP$*9S*CiR~@vxW^uYGzckH4URj`*}kqOfdWH$Ig52 zI_+3j%!ZeF4mHIjZ?TWj7jt1AoCFx{>8Hp#N7iCl=gL|l>pT+%+dX|gEC9i2vd)*a zOx7c^UYGTS*>fkmZllOv!v<^&O5AnQWYea-`9c9E=`gF6(l^TnUu zurmE(61m!Ba4R1!flC4RBpuHr9nU2FO29K&Dhp@k5?PnZx=hyPvaTRT^jl@pujkw- zKg!l3{3aP$SF%@~bz^9+y2fu`4K-dw5o@POvx{W?%`E@J_p5Ap@$NzxD-ed+V=nz} zSy!3kJ+gR(InT@d$&Dt{?s4G#zRn6s{z#bX-( z`x{NBKTeVH-O`_kwO`yF=e|5|-M2kozaY8A2RA-==(^BGlj-Zjah{G9=h_jip5OEQ z!TaCx=IYyuCS>p~`-U4$raw!5IC-^u%%!u06uGZ~n^`yRXxAHWv)5VpccvTm1khpgqY z?v!Gi|6Qr>qBLJt%9H`PK~{N|-0>Az7>c6Gnjyd`UA3Wb6~GN5A+~(e^g3L))&ryu}OO z{=@S?XcWl6)eOc-iWTS1U5f*k9o^^4)h*|=xuVsIwv9)DjAZglHKL-!?a`Byl;9|^ zhST6EaFrPaj&C#yG#JG*vWb}+P9`IV6C64wtsWzp44k-(PO{d@+PK>)I3u4#N=*iI z%8UXigd!-066gxuWUZ6+xU45+Jt^xcS?gsz9qz^%2N0d^oN-Y2cnHT}H{M`+@U!O6 ztN(S~IAdVA8)vZb#547}amL_CH-0AEje|$EoNKxo+1z49N?jg1pzy7A;#UDDaM z@Yxpk59qqYWjWUE*WPUY%5+l3)Nq_>vEnSbDsM)|-UF8}9J{R`ch3vUVszsfq`_cY z*NtZeyYXw0Zv3_B#tR#DxDg-ZL?l5S0-iI0{@4K3>EzTh{yL zwK=l3m_MKWcUa<4)0i38L`DIu1ZBa8ay5;5H}Fnn7T>tgX8>2;duJtTd^a?tTy43-`&wWZNd|WAiOWe+IU`(dD1W`t(0y5O{O+wjM!+T?D`C>@K7&)i<7tE9e5Z137g?PSvzEXEsNVP-^$|V%lEQ=FunK#qDFf0 z*3jpSZ5-*vKZbhozv#t|7XN*{`0Ge7MrJ$f_u}sx_Tt%fy?A-7Uc3uQ|B6(Dz4#Yd zKbcfGcl(=;3!WTJRu^QRSHl;W&H8iu3i!tCH6A>ht_vPrk9q_r$p! z8~5VOwxoeIU)zf_6HPC6w2buPphf;*qh8ER;4oeKX7V{R9WvzDLykSoX%^q#EyrHmI{dfJJ!f*0Co|6!f>xHf zzZ^Dm>@0`9S#!^sg@o>IqTj-YA}9vDf=s-E%x+LBhb4zY4yPP0IT#*11T~{#=7FJO zy}4(H*9?`b{_o5^XC6vT2O%M&8#1x^GY^x)Cx_ph9u9-$2*}aNbnZX@>Y*}UW!*e( z=$=aW7FpE3(sRvAK4%8E^NrkBWc}QBfv7M`oqT0JW1j7LEfvlFV^X4&$Lh zj(y~4E62WaB+8K_M>{#%6T>K}Oj=m*I4OKQo}+O(9m(cTiusfCU*~jYqI`mLN0}$e zQGcOn=DY@q%5hz-qH0|dLs4ZeK)|OVRimgfC5KrQo4HVqwB1rvi-^oEgpi^-ixa$x z%yZ;OmxFOJ(>BIl9P^FGqnKg>n?hQ7lJEWE@ySbTb~{4+M{EIR?jpu4V`*HGg{k_l*P3 zMaF^W<>*$=V9mtwsONU>!$k+u^!Se$2R@_7W*qoDR-Zm`{pjQq_Bky3 z%(Lfx`tq%vO`kRf>-KP*uVTe%KlhV!Za=AKV*Dxh~j?CXkDQJrR!pX04^p&HZ>BzsgXpz-Ij{b5~ z|9frGEao_}Y^D@6psc;*7+{WeISy@>Et=&bbb^VFftlq7ZZl+YO|ozzviyLZHBb)h zuR(GgF2`Uwjxa&@hBhIQ8Cx`KU-MaxA#w~08l!Sd`+s&N1kEh6J~b=dbZo9@Rt99s zaikn9btDaeDR&ouT&Jx54gbuC^3I7~i z2~clYL_N#3i&Q?=*fG@^YFZ20XLzF*Yi4!f zmqHWN)IJ~36qu|d&1n&!FOHI9>TcVsS-3!1y-WsZoh)v5WZ~On9Rvr%AW zT8`0j93#gVIgXWMY* zCuL25i7-iyN;#_Jm|(ue>ByQA(o_@WnDn2Zsj_BLWHTz(#L_xlmbM%?%JIkDm#d+?NmBl-?G{;Y>i-ZpLjOJ8cNsj|2~k#(vO6+Lc`o}8Q# z)KtfFYBW{We50wRG}crZqyM7C8a@7<5gz}{TlumUnK$t{rnA(&=U@uPzv2A{&TZIW z@Hn#0=QpDlvv57K&XeN=IcA#E3jn=X^Y7P-my(n58G?H8GC5|MW_yJkvzw54zmV0cwxfF`g1g=1l8jIojIDUl?VZk zA~Y`CFUP4yG7rk}52F#HmhbJBo_d(H9yN&@QR9tdJtD_^ITo1H$6&1-IM0{tzVdmB zL|!l%ph~jV!_%+%9&QF))3^~q}W04$ZnHVn;6~z-&KCgt2rrTu8 zadvQ4-?7*zpQRz?^M8GnT=amk*$fz_DZD2~{rwlSwwRyjRFQjgjg(Krk>pd7!8Zss zvCrf<*QEP}97}e`Ny^$mM#Y&NPan`$PNIrrwr)t{Cgd&Y&@H6bBDtylI%n|t~5s`O|NQ}BFRo6 zw7DKekz}Vr8l*!8Foa|?D|fXV*T`|L9M{Qly&N}~pgGVHu-J_v$;N8W&XwavIc}3< z71RB4yv+wwi2nx{n@5cp*(GLJSVr}_0=GZ1O9AH~`v5u6vNy}IOpaURxYhVwzL4L= zyRLYPZ&l}Mm9<~-2BP3sHIvGG`-DRAwn3ic8b3R@Tzqmh%gR&ZyKTJ9aKhw?yK_UK zVY}^3+52(HP45X-s(Y{^x0uuZFhCCG{GMp!a%CUJkH)YHMjXTm4)+~$EH@F40KDrv z<+#g?ehF1`@$}5Q66+ohh;`%O?|jdC_DISw)|3wwn2jruJqnHnyol^$U<}}&-7Uuo zIqs3;UODcQW2GGT6QhOc2ByW23mt=>D>$!2OQI|v2q{ixCfAu7HddN*c+=S7JnF}F zOpCmvsxth#xz3H3mbY&d#=JGOfA!SL;KO~5e>O?eL?ozBxng`qq82b=Z0rrX?}{bg#PH= z_Sxoo5k53Bm=?jn_@o?9nUBlh2szd>I2a-C*3HB0Aj7^&@`%N z&*~Q$_voX4(1ja!zNiu8kNbDy=(T+}R@PC2OT(`H6q0z_2-jRjuG35Ah!|hqt?u_c zkzY2cnU01JlZ`Wy{gNE7$nmNiukmfL>%GdiuLb+wMmb(LIsILo>Cbm$)0N($$foLwvq5 zU*G>^;fBK=yJ%PLiuq5Sx;7N2w)=e$>3&<}c(Z=@`zX@=>|tjlcwBHa6JUmC8(zOJ zDE3!I;&it?dUCQoI5fXydLKh`0wd`v?Rih5sTitVTO3@App|1LQj*Ssv*8?AY$jD~ z56iYjwnt=p)L1!f2A5B%N)36=sUgD#oz<{dcmz4*5VDVdqb$G6@lQE6Q>>hpe2*G_ z@87)^CdWo*mMH{nI>#=@`{wA7g49_L`8oBI!+$nja|{)2Om{|omYau`s9N+c&sj!*yBZag$- zc{w!toK9RdGoa<{C&%aJ$Zdq+GoGE|*w~RpHfE=TSyO{6WojBGoKHGMCSlWt3!qSr zFXb?+Idh7kM2@fIY`xohF6RIe>1{GVYvpjmA?F}C7!Cn$IOOz%UUKY^<7+v-k%I|> z@8tMi4zrrm=(n7{;bZ^s@lcMzn+~k!l*6p%bcR=RHr8Q{t<)y9%pWVM###JnHQ88; zMyawU?eM7aEoXS7p^lKF{%Xz~yo7qzj`d6JO^4R@7~^fuaY%U_QVlk*GC9m@&YW^N zc55|fP8E?So7B*ZIgA%M6Je4ZyX5#q4zrpw=XjW6^rjrY$?+etnloo6MK%LsO)TBF z=EYB2yinQa!Sk|KJv{v5$GC@WZjR@i7>&^6| z2JwAi=gN6}voZD_AvyPi%Vd@Lj{oS@Nl>c z?lRxhIAy5Yo8&K*CUTXUmdV<1dAw!5Q{$8;&JHbIcBAn`c3L>Js=RV)RZUIj;e8MP zgC_J;xPbmL-@-TrtP@!M4Qztj*ZdC^^Vx7Q6UuyZ|EG#c$16Y4DBp^vuklOavbAYW z*+OkDuke3JZX3g8Yg^_!@ek#;`~6`z8s1ysk|mb;%Hx!5_si4VOSd^(h<5RZi`_58 zZV2VWaCwr;eDmT66l;&;pj#8@C_VWc+unG}n5w>Djx%)5x}x<>NGk?vR`C;z)f@-8)b zciY{(@t>QJWG}KaK69|%y*cS4XLmUdh~#Y^^mHD$yLk_4GVdW|H!PC(k(>;b^I$m- ziR3-P@VmH%@F5GM_?r(<6Du=s7b? z-u>#gUL4IPQpBa~hUNV>a`s;%is@{*U@}tp7F@Jo6AK#4kTJ@u z24Lui&JAXpW9@v}@!N2QEG9WLPKI%_IevWJteU*&TxuWxjG5QYa9$J2e0~0GUa_lG z@AChQjCaMmPMB{Ue~-f7SNL0#MJ{$*t{p6JfD=$Nxo+@) z7Z`kU{Sbfz*c-69a`%C@urFX`)q!j$F)*+@UZGhQkOL2}i*wI2y1Za*u&Aa4cXmLL zJXAm>RKWz82$Ntk91l}qDolgvPz^KS1eggmFbihGiGViGoeT5eBsdvPfm7ihFdr6x z;51kWr^6X=CM<%p;A}Vt7Q?x)1kQu=;R3i2E`p_SF84jzXm;7NE2*2B}V0iJC7UVslyK{slk5 z&#()AfnVV__`OAo{aQdvXa%id57-m-0vp)D0tYz31#a+w7kuD{03^WP&<6H_wy-ZG zLK3ut_K*x6AO%t(4bmY4G9e4HAqP4_E>O_@I>G*s2c4k{SPzv4Q z05}j1f`j1@=m9;U7xacc&=>kae;5FV!az6-2EpMl7>M#0fA z8jgW6a4d|4Vrpg^S@5xD+mf z%i#*R60U-);TpIWu7m602DlM!f}3F(+yb}4ZE!o>0n6b|xC`!v6>tyS3-`fFxE~&X z2VoUF1gqg;SObs1qwpB4g>~>aJONL_Q?MSMh7IrxJPXgk^Y8+^2rt3Q@Cv*Nufaxm z9o~R9VH3OsZ^JwAF8mWV!+Y>Pd;nYEL)Z!*!8Z69K7mi+Gx!|7fG=S?d<8q;YxoAf zh40{d_yK-|o$xRC34VrM@C*D3zrpVUC>RAt!)Q1L#=x;K7LJ257zgDr9x9*`s$c?4gh?GE z0?dROm<6-pM3@6}VIG_WC&MXlD*OZH!vYYT1`FYII0MdvMQ|3J4d=jOI2V?{d2l{l z02jhVuoNzaOW;zt3@(Q&;7Yg(u7+#iTDT6bha2EVxCw5CWpE4J3b(=Sa0e`hJK-+4 z8&<$Qa4*~kE8%{403L)@@DQwqhhYso0*}IDuol+A`t2hYO` z@FKhfFT*SFD!c|8;dOWe-h@r?7Q7Abz`O8I*bMK%`|ts5fe&FTd<5IzWB3F;*Qk zg9Q$7f(zW>0WbK#4*^Jky`c^418renNQ5M42kjvlIzS4fLK>t)24q4OWJ3;ggk0DU zIspaVKMy)X7s!VKD1;&?h7#xs-Jle@!vSz090Ui$A|S(fk)vnSPSdmad-lrgr{IV zJPjM*8F&_+gXiG|coANLm*Ew76<&jl@H)H!Z^9;c3*Lrz;9dA9Y=-yXefR*jz=yCE zK7wuVF?<4_!e{U~d;wp=cK8Z*z}N5%d<)+(8R+Nu1N;a(;a~6*{0zI`7x)!^gWvJ@ zTgW*@&S`R1%XxyFHFD0DbB>(z#d0o@^L#lkl#?0N zOXOs+%@uN9CFeDAUMJ@ba^588GC6OR^L9Cx%XycaE9AUa&XsaLAm=JMSIfCZ&PU~3 zE9c{KJ}KvVIXB4ptenrw`J$XJ%lWFD8|8dM&P{T@E$6#(ZkF?XIk(8URnBd4ej?{* za(*G_b~$&*`Hh_4$@znvJLUXI&Ruf;D(CNVwUn#1Tzkr8lgpCJDVJL=uUvk)669(l zS6jIf{TxZC&NUpQxS}fNRxz3mCLb;a8b%|V;$#sQX zSIKpaT-V8UgIqVswM?#C<+@$2<#OF6*9y7rm20J356HDjuGMm_k?T>p*2?v`Tu;ii zUak#tJuBDqa=j?m%W}Oc*G9SCkZY4%Z_D+rT$|;3U#=~3ZIx@AT%XAGnOtAUwOy_q za(yG$cXIt8*G{>9l53Y-zsmKy+%4s9E%%;s+vK+7cFOIR+bg$U?gY8p$lX@%M7i6^ zoh)~X+-Y)W$eks3j@-F&cal3#?k;i{$Xz6NiQL`f?k@L%avv;r54n5E-AC?zau1Mu zpxlGx9xV3|xrfRGSId2Z+%LVBlmT3 z-yru*axatnR=IDNd%4_q$-P4Ed*xm!_XBdTl6$q>Yvg`Z?zM71F87miua|p++|SDW zyxcF!{j%Jz%DqwUH{{+V_uF#6EB9u(-BB&TFbMiJT`eOd7SdNAJe}mplc$S31@aWhQzB0{dAiGUpgaf5(?gzK^7N6XpF9KP87R*nc?Qcf zM4qAY43}r5Jfq|pEzcNv#>!JBPq{o5@>Iz)QJ%^2Op#}rJk|1?AWw}vv*np1&pdff zmgiJ?=F1~_7RqymJd5NxTb{-8ERpAYc`lS^sXUj+bD2C>$a9rE*T{37JU7U5lRV4h zxmBLqA@3r2&z5(wyi4RgU)~GlT`KP-@?IwI74lvs?=|vXC+`jN-X!lbd2f~Xc6pb} zdzZW`}ywA(~qP#E5`>MPf<$Xim zP4d1i@4NDDmiK*mx5&Fy-fi-JBJXGNej)F6d3VVBjlAE<`-8kY<^4(CUGn}a@9*-p zl&`gXd&*~%&yvq6pIbh!e17>7m^?w`TEH>K)!+U4U%uLd_&|LD&KJVM#?uzzR~iH zk#DSgW%8BFS0P`Od=urHEZ-FQrpZ?=-wE>7$TwTQIr7bu?_~K-m2bX$l5e4WXUMlm zzO&_9EZ-9O&X?~(`IgFeiF}vIcZGac$#;!>*U5K-d^gFrOuk#?yIsEJ^4%rh3i4+>$hS(q)$*;8?@{^I%J;Z@Ps+Dmz76s{E8p|-y(r(y^1UkGM)}^5Zj@TCI3YEC(A!Y{%P`8%YTCWHS*7ve~$d~%V z@G9U}AVGmP3ba)qQGs>}BrA}jK$-#>3S=peqd=|#ofODZpo;vKt z0+%RonF3cRaFqhrC~%zuHz;tE0?QP*Re{?TSgycb3an7zUIkVv@PGoV6j-gm8U-Fz zV66g=EAXTO>lN6bz_SWGufU56ysW^h3T#y14FxtS@U{Z)DzI6B_Z8Tpz*YseDe#E` zpDFN#0^1eXp};o^e5b$<3hY$iCk1vX@T&s9E1{(lS}S2sCD@c;DZ!}(w-UTc@GBuf z32l_nRtbqpXs3i^C8Q`JO$ixF$WlU%5^|N$NeOvM=%R!IB@`*4LaxDrMxVU!X^D`8CN&R$+CEdSQ92kZ%Z zfeq|nfdic20ylWT3qHWZ$O}LM>6Wk2T z;1;+QZiCz54p+lA=37g<8cpKhEqn*x!w>Ky?1X>8Pw+GBf?wcQ_ziw< z(V}w;XbG*LHS7U{1AWy*c;lwKF}8Sg+xe#cF-P@p#!8q zDx^U=WI!flK{n(-N63Z!pcCv5c|gHCcY%B;fI=vOVkm*G&<#qVI~)K9!a;B_90EO{ zC-j2e&5 z*TQvhJ=_2{!cA~9EQ4F%R=5prhdW?7+zEHV-LL}gfqUUTSPA#T1MncMf`?!=JPd2# z5qK0HgSD^@9)~C3Nq7p@!_%+!x!)+Y=^I42Ye0Rz_;)nd=EdskFXQ| z1wX;hunT^HU*R|Sy+w;IEubZ|g4VDH>NQMrO0;!M&>5u`LkOkS0105k3_JdBaKjcAYpzvMtp#Tb@2#TQux2A6^D~KEh5fv33U>sx=5fRY=R0b6h6&XemaYIx@WE2?&6;T;Q zM)Ci3{7kv?PzvJ~k@mLUVkATorU zgA5}h$SATLS%IuXRw1jAHORThdB|&#^O4sf7a)RMi2MU`5%PNEV&o0TCCD3*Hz99E zE=AsgycKyHavAb=RAB9|jqAXg&)guD~^XXGm6UC7nQzaZ~M-h*6&ycf9^c^`5e z@_yuc-#K7o7^xgGfwatHEh z$Y+tyA$K94NA5=c9k~bj59ABT7m<6BFCq6KUq-_ zhCGe@9Qg(EOXL~ke~@1xzeb)#euF%R{4erbBp zkv)(-k-d<;k$sSTk^PYUkpqwek%N$fkqO8|WD>$J&~OkJ@em&gkPwNG7)g-H$P{EM zG7UKdITSezIUG3xnU2grjznf6vyj=yQOMEAF~}U`SY$4895N3%9ytM-kDQ2{gq)0= zf-FEzMNUIbN6tXbM9xAMB4;Bh(nK;OM+&4w79op~K4b~96zNBnAp^)DGK8Fi3?n1R zD6$+`fviMUA*+!!$hpXQ$ZL`Fk=G#?Ac945b`5y8J@_pn{1SppKSNIY`=kQ zzmseq$o9v{_Df{@i)8zE%l5a+_TQB4e15gI9NFno+39-O z>2tEv!?M$_W#=tq=Lxd&EZMm!JD(>zUnx7^B0GOccK(sOm^K=cHLWcJw$e0AiECBu5XcDZ;)L-FS~wEcKx;NwuS6=uZ|vfq1TzuRTM2V}peWdBWM|Gi}YX|n$*vj3>; z|2EnGgR=kUW&iKV{?Ez*Tgm|k%K zP7Yim2VNuxzFQ9bgdF${Iq;`)(BI2Jd&ogkHp&=8FmI=8`IA13GvrPDyO!%@) zctR#_C=+*2#U2TqeC;CVfaI z-6NA8l}XP@V{2(ll*VjnG^KH#G_I7!Ez-DG8jnfi_u}jzjwjAsaTbg7dU4((&h6qn zAkI_bZX)iU;!YL!WO0YYeUrG?iTfFGza#E1#e21Q`-^vkcxQ;WLcGhwyHUKm#rwW^ z&xyaa_!GsSEq+t{*NXp7;(tW^FNyyn@qaJD4ifkh%$1-|f{P@0j|88T;2RP=CE+F# z?kV9^2~U=ANWwQs_d`6~3% z=SW;ie1XL8lK9^w{))u^Ey>Fy*;SHQk`pB9m*iqeu94(+Ngj~oDVe;9Ox{x_PnF3h z%j6-M{3e-volL${CVxjJ|5B#BTBhtLQx2CYr^}S(GUaVD<%2TiZkh6ZnerQ%x|K|w zAX8__)KsRPD^stKsW;2iFUr&(%GBSiH>UPN`YUDnJ~I7KnSPo~ zAC>8Elj$Fn>7SSB-;?RTmKj^fjDuvxESZtYjB{ni6*A*ynej!L@tDkbUXI*ej&$Y7 zIdWtvM_wRDUL{A~Do5TgM?NVtH

Z$;?D%&X<|XWab-W=6hx49WwJlnfbKL+Eixk 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

8`0rRv=~ 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

aXCJe#hQUp>&QY2DjQWR2DQZ!O5 zq|{=}+(Eq5n7N zLKsALGvNiH_euGJlrOni7%D=_SEMvd_XVXg8 zWuUSKAL^6RAT#hGoDT*Z>*2^2?D;TZ@Qnut>Nl#rp<~du&kj$SX=FR$pPGG;QP}rs z@=>w)V!kaKtnIU}{;3OVC)o2L9N9;>n>j|DVush`6jN!0G2*()JKo3}uA(PrAJ$@U zxJAcI6DPxbg)q$!hTTj!O8Vh-p?Xk#r~%XvY6LZgnm|oSX+}zOQd*GGl9X1Y0B&ta zX-i5wQrdHv=7^UHGvTdmF%u4(&6w$6#Z0FZ%=F2^Oom~mj}=6ekC za15f3nW1P5BL#_47skv8Xe23JN$HjTm_Z5<4jXS^26;gE1ZW~D-AL(9$~TM|TxkfO zVqm5RDLpdnCXosW9A*drXYMJ!f^JHf|=DiX8JlAW)s5v ziZD86P|gqE0-=f@z70ZYKOFJGdHA+NJD{DU^e1HiDc_PZkQ8LJgGd=n$`De%CuJyO z1|Hl7GoHrdO=EW%%fn%_88gGIm>I#3H&wWc_d+OBvN)4roQbw_CWe&Zww#G~k~4cT z$_FrtI%oEwv7Z#MWfV`AgU}&TMw2oz{W*giARIp4;0zLh@DtEUQpS)nmXvWkQBOl> z49<)v1tn)eJ!(Y0%MC3vk9X0~u!W zJS%Dz=uc9{Gip|6p(dkH6M=L>zbQDP94Yf{P!sWybEt`ctBoxm$?}nZO5QaGu z(H;5*>H+nHdO^LRK2Tq%9|S+Mj+FJJY#?PLDVs>yOv)Bgwvw`ql%F`vw}_XTGlRj? zE_iz9QXr0gJNCnjIS0tn3cm6ToS&zWTi4m1Bh&aBWm^P4&AoAMjBi{UF>{_i(zN32Jf z%^Ze_vH{u%VJf?m;z5chFNL*_*lKXbixlrn!I_=dWabQV5PO$%vy97omtHiUF(+>`BxXu}0oin~p?(qA90f>8O+=m{J5>HA3DTxe-M-VPG z;9fl?iIn6_0f?8_WCjEh275qUK9qBP%(m7W>Cdt6PpJDsHUaU*=!0X>L7%Y2*AI(r znvV_jDE{ix4i#Xx(%$zHncc-DG8gYE3<_Jn$ecQo_gDcjj*&e0ZAgyHkDl0cJq&Xu zvY^hHeNKicj-C||hB*^i0^%(y36+9MLmxtApt4Xos5~hLNI6If((uEi93kZ>DaT0p zos{FGoZv8U;i)+j`H5{MI1)yiIdjs=nbRqi;44{}$tcW3T1?DD)*|JU4Q3)gcMda= z^)bkeFo-;bBO5>sNjXExS#CClnh?H)21m^vLbt>$M}1e?$(jj!{3OLUY-u&^YnEw~<2-hVu^| zY8^8}b_OtOJ!#wXX1~1{lD91BH^35}mgc|^)%#>{pI8PpR}UZy{0cy__Z8<;^N5a|hdk@A$3 ze@J=8nDK#p4a__z1vjhx_l4ld5NtAI2I+!5GKP0AQ=op278mAL*m-y2(4TPmnG3;@ z5oRCQ8T&rd2Yt8UpEmV&t=ii1>8K5%;~cmdq#u#-<{0U21`ldoAmv{t`LG9JIQ>Y$ z%sw46ubm8Y6k+~A7#%bG=lu?$k{@{jItiVEPD5v)v(PzGT}aJFsw=74NzFlOPEvD` znw!)-q`t=!0Uq22Gk>OWGqBmfjGEWPjGEu-X4DU|Fq2`JK{lZmfg>N2n$H$9|CpG` zHQe|H9OEZtdya3sG5&4$kW(bi8&TQJ`4SVI!e~&k@0sa3z;uO^bqu3jx$dfM$ z7C)*NsZ~h*l$(8^zNA(qwFYx0UBB}n3I|BkU~|R#!81rdc&eGRKI(f^9n|V}Rfodm zRGdOnU$BiDiAZqp2C+t=F&Y{}>Sv_ZB-M?HH4cKgN2x~@NEI^$v3|fNGqI3`*wbhC zjSaPSUTe`gG<&Fz+~LcYCb7uuGs97z+%0AnyKt{{l|`#hx_hnj^LIe3*;wB^-c{Jk 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

1@|%yQC9XSD1CGn}9a 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

UPm2M_w~F?!dJv932p=KBb#Cu-OdzS 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�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

f#<`c0wV6qoon2&YU)R@`mMA{3`2 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 z zIqFc41~j4x-|`bbGl<_9$r#3?U%$l~&OXhPAe<9}Smu?u$vZC#+4u;(&68uEe&^+)cpeedtE#qo=R?D(lZ>w#x`UE$4$!olKO*CQUHf{eBRoXxXraTS$mS(+zY~WZf>31Uzd^y8PMfAU9NM7>k3kpuJoW6x>#qo zbv}RHV21DqBk+!O_FA_Inb&P&2fNYRx&!EU-BFGs%etpQ_-`tTP>Lrkb^S#cVNRexTy^`+u(0)@crD-ns&IK4HMYQ-5}f;;PW=7N1q$>@fp>r zNn3QfQKuVqx>1)Kf8}?EGKuA!<04nk#l~Cw|K~rzjc$C#OT1%KRC$eID^72)D)LJ<3v^O6X$S z*VLdk^=OFO+vXkH2BLUY~^wgZjZ}HR6!5hW#6t_ zzp)x_muH78JM^|AA>O~k`*-9aFZn4*VTz)Q9rbBMQ(Dmm9q-W34w-f=VGq7@J5HmA z9eUVtkB4}_-(L-P*llMfymx13?6T9lcItEI9Bi`F{yYEUEVkYi4O{QB^{yl&BPFTH z!iSWi0+soSI_PqjE_c~+S6c?Lh^6Ra*J|vxYXh6v#!kFr*M8*P^@=w^xH}*^dfOcb z-R*XByLGoaDapx=zIS)Pn|80n8}`KD13sexy4$0-J>I{kE59-xo9>y+RHk9qJ@W05 zYmZ!eAnqY!X570&N1!<;r@_!c^_Tu&rCMl z=>Cs!d;9a@9sA|oFYkVN_kYLtxVim$+b_p{{qFBX7i8K$nq{2CUI)_S4F_6c^8;?{ zz!r3O;1qg0aE|*yc+jQ?-PXZa*!5sM?0QhXgK`~|>!4f*Kcyt4DMJeeFbQ{ia6VD^ z9vsxcLHBgfZU^mla5s;G@K9F1q&Cg5{ULoG`kisiV<9^@$PtcXt3#K#!Zn@-;o&6c z^sr73>-2CovXhfs6sIP=>BrCL;_z<_WjG@lgWL04tl?pK56gR4-oty@&mr`7SdPQ` zJ?y)E_$)FVeiMX8((xJgI`RwNaO40sKbn{v=0QW%tbdxZw2A8m?R=8DUjos9*()KW0`Qr$10-hWA$iA6a1}X?deDt z+|RLT==#``AUqx$pLaYf`aE6~n;ox913IJA<2pUA)8o24{s$u%#dOwjl^fhf7sns+ z|DXRHH+uYS5T0;*C%of?J3EmFnNQ@WAVtvIi4y4d#OHj0EGL@LpIO-J#GN2KDf7uf z*!*NC{zP{t|3Pmj=kqT%J?XYi9_A>=vFl0sPReysu2XWIijRIz>GxD}3h*_paJQ#= z(2Kt4;FNnhWw%pyJ2j3?JPyMDQlZQL@==!Z=<>f7bf+hynSveuo52F2Si&;4a0Z?J zr_=v*`ri|t@sig;csc=@smxbYM;E8-P@hILr8#czw0E4A_q4pH-2nm8q$Ps>A-I+Wd*Czh2LKd z&u?ZMJK2NVJMSImC9NxqKAvJU)1eI z886CnQI?B(yVxD?zv%rJCo`34OlKy(6Bl)HaTj|zz)4P{qKo6Jn zaH#=}@%~HSVYf@}|C0A!x{O^ed)H-sUJkLzW&2+)PbF-9xed0yZ0pNC=|evTFakGs zc^NBN!xnUTS(lgH;pJ023c@StNKZy|;rCa=D|Wk*i%-Z;A-v;?yjSGCBJY*|@dItq z+m%k}?uzcN=kA&Fs znmw=C^O`-c<)$#jD1m;j`P^&zy;c>ut_{OZ*A}r9w{>j;o7l>Bj$yZJ4}?p8y0 zcXfBSHg)k`xI3EF*y>(1vf@tf>GqzC_vE=J%RRl_v&p>;9ONRG@!osaxykJyydR6i zBqJs7k%3I;1vB{lA!w_urp`-R>U^!Ux{_;6sYwT@Up5pg#6^ zVE+e0_yb!%Sd6V7tYjlw*v1ar<%9dY;B^o_42X*^AL{a$u;ln~S#=j*Gze5)f z?e@@a4?EC_uJph=9?JVr-iPu&TtE~{(Az^f9_sg@n|rt(nI4|S?LGQ{&uM`-JX*v7 z?gioFgy`1Sz zf?DYGsZO8j^rh&-MHKQ4qdJN+Q8oUOx@OH*V=oNLsx2&HH2^BgH7gmsFrSHK~I>-pKc60`_{djty)^ zjyL-_$YE^u=2Z~B_3yyj1SBRI{?=Rf^ENZt$d3De>y2;q`gS=!@9i<%=3AS*eHNq% z;**H1bh)ChW*r;Y#FZdTj2OJj zhvXm^pP+*nr6|Lfl&1sJ*~&34@st-qns;>hPK1y6n6gymYiiJt#(Yb2Ix+;EzN6E3 zbo$N=W-*6(tl`S8Tar%N6?r zGLwz$RH7yQ7{;HBVk|m{?Ve)WEwXXK5$ zh$Spz1$v9?=HhNZcX8#3E05o7O%qpt@nWHqc(#hy7Cpq1J>Cgqj4w}oS>k`h$K>WS zs$tXkHLz*?I@F^hJ?TS#en-dgbsS$m@nwpCggd~fCnI`GBu66sCUQH8av@Wq%KX3| zEan*AkT?S+X-E%rm)Kn;)?4Dy%wi=rO}v(W*??UW%a>TL#BwE;EAbm+k=Q%T%Z5`QbnMz*jW_mkvdkS3|FlYT)>d|uMd z=rieHY?gEm^Vx<@lj=07PLt{~>3J@3g~vgfWQiz95k5s1$x7q%la<4bCaZ$mOXeNP z+*z_d$ee5dzwj%1OXlX1=`NY>l8t68ZYS9ho(E}?r=iaqEdg&tCz<09Ul;yQLq z>HbrCZ_4j*n<>33r5;m`#~vx|pK>?*uyxA&*gECYAWf=(=)@#8smMhkic*}i=rWZq zQ@O)b_36Z9{$e`1NM*NFc1sn-5|*q7?CF;OGIyxW_W+Z`y+!G%Dx`-@g1-=iF&1^%* z5&cBu3lor;kI6$mFaDO_V@(r|WDMijgf}WWO`5FuyfkGg zPhDEj9e4SE6x?Uvj&kyZ*=TIKG!x_kD$KE?mNLzG6MP40Rd0!|(uCf-n+;*u+B@kwp0XNHUU> zinMq~#9om)$Q)@vBbuVONGtRkadVN5$P$@=+lw6HuOLkR0Wv3V%pm5n3Ed?>jNXzT z=XV}r)8vnN%5&_RLcSDorI0IyTq&}l-xT^yk&lM-V;b}Mg2gOD2PrmUw-k0u@gwd( zWnv1V%arx$L|1f~axx29gd0q`2Ro!Z$O%qzhI8EHb`Yj=bE$NiN~fuGno5_cBDlj; zsmVoU`p_R;q#DWyMl+6yxV==~k!l9=rrORNBk_)7n4X`@|#-S;;|eicp-A zl%^J)(P=uJrqgM<(Tv3%rkliE)^ma1xPmUy-QX5(G~IpNUb=trj`Z@Tmp8q<=`)fU zHE%eT-}D72giPrhGJyHmEB)_5n86z|WWnYc+*XG1=q|$o^p;^U8?b2xx0T@l zcFk}YyJnCtgIpQp${<&U|9BgO8Q&!unJ7;S+-=4l^v3rfqYg50IevbmpZ1t?5W+To4a^qTD_d|tL&xXo;@f-rkb zBBaF4Wq148%TbY9=rX%5v%ACW9T>?fzTsPR;rCa=>^?vHHg>R^eRxN9du9IznX^CP z886XW_P0TpL%%uPoZoB>bI6h-18y%zXQEh#%sHM1Va_BJq#nA<*#*7j?8zu*V$+;+ zn9Drunp3`PO&3T%KL6|EM+0k7t-Q_BV9J%z6s|s!_S5x}oJCMtF zAeWoUWwTuVRxaPqTwkyl_mk^q{tLp~DaeV>%Uu(F=59+b#xj9L=rp%ZbL%v>E_46D zc6M@u4!4x|IWO_vyl;XqU%3@$WILhGKAsiqJZ5B*sZ{1rt%51@QwoV z7Ld1qyao1iki+P$zzK9$Kz9XnSKtD^69qq_Ft#c<5z&ncCt7v9qE}EU3{VQ6#rva&;(91Pi733k_)P3pd^_G-;sa9QT_yBbqAd0(VgC~SaGxb?U1A=# zF0lyTqY|rG%R1a;2{%{bcdl`h2k5edE=#z>lF>*(MXFF8U6iz2NxPM7Ofy>22Ja{- zZ%KJe%3E>{bD59cO3G1Eza`yV$(6`dazAdbR1C6E18*qxIa@f(qaZA;yVCBmwBAa` zBPF@8Y3Y0vpb&N~EnjK5O3PJRuF_rUL2vr<85=o*?_BBMxPsd%t%K74V7JnCEA5`j zq@_Lsn8>HtzKlN0{K!vS509{ zeUCSkdlQ7^ZC<`OP0(HWUg)iSek@+UdNd4A=; zAgqv#ytvy6WvM`AbWou&cB^2w3U0Z=6t;7T`@9Uoingz)&x&ctNg2x1f{t{dJGQDg zn4t`3Dl5=wMV(gEX~iAvVlV&W6nBHL(nlmAL>HA(la7pJAv+x01Y-oGEt}2BoMoCK3j?v7=-Bwx6TGpe3D(9m?otED3YnaN5K>N1Rxj6oOG zCK1JSX7VX+ubOvMlee0@)#R;qm?IoVZ`I_err&B8xQI;EUIbzFq!h1On}&n&*$sc-Bv-h~4diI( zmKxfuq0JiFtl`@rY?PU%3}YJJ)MzcbY^29Vwr}(Y*ZD698^2FXys7a=Bq13Qvf|zv z>$9;w8|$-iGg{D^w)DaNjW@A{ZR}t-`*5F)_14(kH9n4aG?urqyp82;@(%Ce-kP|# zCUP{1M*==XrY3o)jk{|y7hN~;hNjU-M_F2-yQTxsThpOT#hy*wRnsLb!=_FBd)-vN zrgAlvtEpT~&vTK>{2qkO-X#@d}^u<=qM>3kR%))n|xlWtww7E{3?_)ndahMDI6ND{7Qji*5w8%&n zvXhIv6u>)L$lF5R7V@^}OjmlKw-$1=&~FR(++qkawV20Ne#2fZ)8Gv)yJ7Q|z85VI zqPv!t&|Ax^JPN{AHf`m$TE)Pwt>R$UR`RuytCd`>-df2(y|;`1Tyr*#Q*-FhZV@p-NHqR-Z6v03XUJP*P) z3DIdAowm_w8(p@^Mow~5ipGp#Jd@Bxo9X!cHlN}~+sw!9wegNN?ySubWNveUlbk_s zZQNWN-L=tOo2y(8!nSUwZ7Ryqfhnx#G`ejkV>@};$?f%mu1huzw{|MuS7{yW@ed+%zm z$M!d|M+f_N_?Tqax;5aUQS`tPUpD5MeN#1zD{y=maDT|evdWmoPb0mMmL=s(33$7 zWdw3`wtMHPOvf#C-i)q0AHYp@c2k}Gt%J3vb^o1fxZUn@bbrXdJPE=cHtUfB-+>;!13hw+ z4}YtN`{_}UDpaFC-q=I0Jucw$dOXK%_OwaQWMn57Zmy@>?^&Nlv__Xbb=lJ$_8iCz zeqcMh&_z$X_4N5Yf94p!a2oIEX|G=IB6F|k#3T-S>y-fg_DW0=Wa(9q1`J^#yOFtf zEHYDx_UNwnQ1sS&6f;?hO?$6o6|1ppZ~1!5)myIKa`nE1etYY;_l+Rz^A71Lf$sX~ zu1|I3=%a@|O>tX&y3vzK%)w3dv00xl@%{9htYM!GY+^H4g0QbQ_RT|CYN5}*`s}OA zzT=q7eB4}Lo%YpfU!C^VW#6N?!@ehRZ+%|`VZXFwKo|Y8krSWa&yDsgL{Yq>pIhkH zh3?4QuQz?sTR%6~Pj~%>qq}}%kfq-e^xf}z5cYqcEXdryAG7(63PO^5VnAcGl-U5CgwM6Mxn4Uubz+Z>|bA^IJ% znNvIo!l56ayP>)pngTh7X2ER@%|US*;BJR@pfffb>TeAl#z@BCeul2)3U7mOSOR?B zu-xc#Sb6Huo=%KLr^9qQOsB(iIcx!6vY2)J#6$k&DZ23ctKl%8Km1+X=|3#ak7 zM!KJoe{zSrK{(3&kMhP*dL14SE~B0sW5N%vNL>eU2wVI3^jz zXobvUR&$73K{z%Vx*Hp!x3Q_nO&M%DwgQ!?f?dbTH&(8(a*dU1>~QouR=;D%vy}Z@ zMt5U%H})QKjMc-~m$R%#1s}_(}~}* zp6}SiX5^bF*F?D{$~95H6ZJb$zY`w>;Ut|-%89)u>28wlCN)HkNo}#+q>c>W6Wr~j zMc8c83jD1}-?Nn;*}=^qoScNhRKe#>?t(rik06RKS%RCJtkcOlovhQzx}1EPb6nt7 z5KalmLUwYYizx;0`BU8Jl#-O8Jl-*-H~o-#${>c|=BDUv%2;$aMR!xCFcsg4DL-*H z2&3YWheixTw^1@i$rB|@l-{Cj67^3IPJNd|B*uHECL=-$3Q~%)RG=nxsEsq_I5Rcr$cP*>-PO$e z*lwoHX11goJ?TS#{H>YpXXYfLn8s$jah6_ZCBx^w5A;$(Z$^E`24wjaienw zGYs#TyNYj+dG0zkunE1*-G=Vw>Td2H_VGJ!g7EXSl&3SFuo2yUF5^6T=E*WoZ}V(2 zFEd4`N_D(M)i`ZrU^B`Q{HWz$ADzZ}wyDw-)dpgmTe&}+6E*A{NcVfXZ zj&K}ZEU?=GyDjkf3oi2q*YS=8cY<)?ha^Vkg~^DZw}oj)kM8_dYq&5QInduidoI+; z!u6cyMG$`BPQNIQj9y?y3zx?FZYh+1Ce+6 zGFI>vZeY0^SndXvyMg8UTQ1M?ANY~;JPpDXI$5F16>e&U9#+V{!hNieaiu&fWmy>^ zC8^0nSt?K&yROv7%Gz|HF9R5iZC8$G68c>!*Giwg@)~z}fF4%9#JJSr2&nw;a3|u%?*6ss%YqOmCaXWpfGk@f8J@WhA=&R>p7T`Bs*1_4chzzI_~o z>)z*MlH$GVlH!#X{zJIe*Uf87=A zwmuf#yS_QT-|M|=y&l)k#2)MIzkV0nbS?6%2no7~f;-YnyPoZ%|A-=xp)W0IK6 zWTQMasEzN^_qO`JC2eR&U#6nd?{)gUPW|?3`29-0<{P$gidVb|!p-lXi_I~JO*|5i z2)DP{J2uO^S>Da^ZmvQ#YNEHza%|S`=EgKdrp-f`#}4eZLr-fbJ$$Y%7mZ9BT#rn_yr+qNIK^J74I zD$*4_{3!d6y8Thc?ec7wWxL+CXU6-td;j+8)TB0bsgLi(c3o^A%rHhWi70fuT|e7p z^82gd_S-z+IeOTxhaGYF0Po-N5q8_*{&#rqj@j5{hj;DJ=MH`Du*nYl?|8<`Alzx| zoyoEFPFwHHMhhox0rV4tGvwDL-?JU(m(QbJ%U?C4T1`H}Q^L z^6rv%m%O`@5|RSF?MjF4{1$7tOLx1nQ-#hZ8F$OGTbA8=+dUKS z-|hXozh?_S@FP3eg)Vmg!FB%RZyurJ-TK)h)1E@qrUk9hgWp{Z_w-{R-oIx!cH6TG z@7?n<2>04$uXpX$=iZ#yWUu}Aw!(exwe{Zd*m|$6_kPM}%wqxWa<7})dxYbhnz2kkZ+?q4+^64tZf@T! zWZJg@x3}-#ApBoqir@|Z8^<#Cas}P}?=gD&--{sJADaj^-Jgmyq{FWJ<=ZdUe!2F` zwZ9=vXiiIXvwsm=*~9;EyZhzXZ}|0W0z==y-~zyUXPz)c_#i z+|Pjq==#9dY{Tar_!WH~xR1>a#v=h)(CI;)9@ObUT^=k)MJm&X-puC<7Nd)UEAjaU z*WgAEeuvvT=pBB4HT3(d;X#=X-r^4T(Az;b=eJnHgStETf>%NKliT^J5X~6DQhwrY z5FXO)AsG+Jb4Zp$dOKv3Lv85GI40n|ho&%<>3qd{HnN#r>}5atI3&~I=-BJ9&JO27 z4~O+|xGWX${=?O<+hO;A*n1Bj#%&(H!WF*Hsj-*9izrPwD zsZCw#qc^|B8XnQz5jS^4cSqXMfwAcO$N{|RXdJxZs2e)kpHJCHgv33*S*dtw{gadRj1c0!I5`t@6^;fbG->BOBN{3RyY zvDYts@rGY^VDn$x*2yI3?qm-1b}}#Ju<1#+b+R#bJ=q+)o|NyTTqor^Dc8vv%;qyb zM>i+W^N<(($J-!0CC4c}oN`;I;**j>==xM8s!{`g>r@L`(+>A@>JxN*>MD=$d8a=_ zpQkfov(pu+LR)ltTBoOVdRmvKhck*X%w#pEILifearz2A|MU&q=;^<3d#Am_@2`e_ ze>FTK^O@A7B?Edp`P&$&Y!;TTVY@Vqyk*X#MF_`LH&ahvCDa(*G}_zpLB-tC`1$FE#Nm*;hP z-W{HQ9)uSXQj`*uMi&?CcERUgs7@{F(g5$cV6O|~k@>=8qL_}}F3d*17d~e`vRwFq z^SlbeUsF&9nSY(iHyq|qboc9j=tajvdr`j^ zJ2Hi@*p2Vp#S@(3EIPP&6T4ls+r|4q_}j-+rVG0KZ4wLk5?%hbo#ULu4gU5ocKFSA z>C(GIBL=ZZN*;82NvD@|dZ`N4s7Y;FF_@*SU=_N!^er3M#1^*U_AYtHC3!E&dr96) zfAbHI(c7i}&!OK-Z-Vf$o4zd5( z(<{^X1iN0Dja{$EcSWu%a$S+@irc($h$9?BH^0XtBe}>+0p##|tKsi%>-P%Orw6+J zeFUQ!hrjjvr_5zO?&tUY==zT&WX9+HQ5k*y(HxuoF`QA%L#Kb}^bei>q02uuvYD+M z`nR_L_{>y4TC zyc-*En>TE7<0Ln@6@)k4+)cNCGcNH-iY{;J@}@hynUhNNrXK^*#Z9~2^!Yc(GJ(lV z#XD}=>*kNhd~+9j_#b+^c?kX9JjMxRx%nUn|BOc->M;nJ|J=(TybZ!z$y})%NlAzB!*(gjkYSIav-qGnDo!-&q zoiU7OBA>C2^IYUIy0~*4pMU2LZuHLIJicpHR%b2YrD zk9+dnE04YIb)*a3k>lPVhB6$R-CMzTe9u;X#NWE-e(oLP7f#{+?|b8Yz20wy&$~Yg zw|Up(;okvisff&f&tyHvxr^@nerotoZx5rBgv{9V zVRmwo8@oP~@1a}|<$5UB!*=NRp?)8BV=`;lkM17o?%`?Vc=$V4aa#``1>rw&@bADs z5!{sDS`Gj4xBl_{{3kz!a6kXFWe%G;h|l}yPxSfE%OHFdgOC&yM5m8*`bejbbor<@ z^=LqQM(`D@S&J?nZN%q4`T;lkXcv3&jz{--h|G^3^OP6p?a`Yc{8zvKzK5IsSC)U% zQ;ts9>)&sY`QK+j_}J!;3s4u``Tf-JvECl{U?etuJd02HjL)&_WBDG-^;oXQay@pN zkM;XlzmHGxcMv}LkZkDgiSC{hMUE$Wc;dGF{%ZK734L+5PsTCBisnWXYoitB6RUA89x76 zD%|L^3}nVTp4F!jGCylZ3tFSMXC2V*v#z-5XRhVGu9 zKyS~_a1)z8f6hz(<4q90uaGNjm`$E4jiqM=P%w{pmSjpGu;Dvj7 zVYe4{d$ET*LHII4adi2zDLv?oE?<7aQdY1N_x{ojFOPDT^IYT-cZ2X%G<5n(r>}JS zDmf`hLpt(Ojs6T`D7ttxnsH2I3e#|Vue{@xyszYaCGV?!?B^%+_DYUd`h9g0H~mVc zSC4}5zl0RPUjGfl8~!_h&0oJqYIOIyAbNXUjOy6*bt~Fn*Vi4e>udR5%k^5W*K)mf zo39tLh$ZOe^&h+l!Z+{oJ~5HwjUL{(tv5-@L}_&WrZ)9xh`;rwBVFi@`+4&@x_<)hsQh%BJT#gM|5H$)4P>vLr?n9pFxag5>ZTN20!pu5P2^S$?>lDic^Z(w4gWr zn8s(!V<9V8#cI~@Bd58>p8?p&Tt+%qT4Xfth{TAGu4AOaO~r6i zG5oC<1t?50+)s>-=sLzWe#Ym;_zQi;coRfo+AL;D(ohtg#?)y{oyOE<%=$E<37r|k zH+;(mbP;n4K0oFT+-S^wxV@O(5!0Q;e2mO~e>D>GC9i`>EWO2g7yZVHK`dm6m6=L( z!(OqzL*`hof=Fze$1XxcbQiljdW+qMvDh@W+lu`;^I3>pW6Kv?uGn(LmMivg^c!2h zvCr{u5Q+0KxzJr4-Nh-19C51Rw&K*J1p^t!M5bV~IQ~|gFIdbn+)tciybU68QwopC2zBZZuvNvf~}` z8q*A! zKlqO~K_q^_yVy0peDURqFIRlI;=9fG`i-yO_$6q{2h$MKA=)@u}A5aKyOc2FFzDA!3^qD}H2`=$BkAg@-H5a@3~-HcjNciENsv2fdigEau?* zkjQ?Cmh%<*NF-mP+d<@`cZf|q5+KJ%$w^6Sa#5KExT%kt(Gq{_qn`AkKLfGhN8b36 zUK78E&r6&RH;~vSiObUnyC?3)a7HnfspvAXE)&mYDL-Z065B2D|9}1yp7V+~ zLF8la_}E?_=RoF<^N^2%=P>yRH8TDnBsq& z;VSw}q0f}MOqrO>WW&v+)M-kcrqpRlU8Zb_J51RQ_m*-h-?J56q}<6Ke11wdn({D5 z@s5;kA>}LH1d&uSr+SxY=*@4jMpEf6)d%PvrS;;EoOD$Jwxl+rOTED6Fn_9oA{|F*!-Xk^kN>h<4RHqg?NMpA& zc1vToG@Y2qKCYw7wD0f{Nzi3l`=_l;HQLhyJEZN$a7HqQam;27I!&w7v^q`uKMrt+ zpZS$XK_p#-l%zoy=`xWOH<~Ut`6!5Yq?0$Dyy@gk*M)AlxpaC2qIZypu4QP%la{LWKE0P%9@b^ z)T9|LX@kwO`deB1Gl-$MpR6l6&+{OXEfzj6TNd=0tprtRL2HJf(`-7;rqgV?%=RgB zna3*jaEE*RjV`i1;r~DX6>c>9J4C}fvgalrGW!kINcJKWM{n87qPy(6%U*?QbY>E3 zIL1FgBu5g8q1zlX=8z|cEIIU+!zMYtV;`qEi}&XEmEX9`Q{D!VobU2JACQob&__=B zayGNoEQ7O<0Z=q|7B^4>&_yn4v{FK#PeG*aN-fqXe| zQ+{tXlF#4D=lhwjB2{od`TFw}KXCz{m+v|H%paFzWG5Gu(P@62=GSR{UFL5~2Rbp3 z8T`O@cA<;>`|^E2=1!58hy%k7+ehVbVO&5@*KtUQX z1bY?Ojm!mOVe^8OXpim+4n=PTM==wd7F^CsR1`Tm|JSC|5zZSx~!a!-D9HB!iKg}O0^gWN)wepfY8I4KcyS-1$*sYPepdto~i z9>i$IF@Z_UWj#7Atkc3eE&LOQIm&S^^E8MQNkv*Rpo=2e$VndZQwX z@)qeqFZ!alB61YbZ;|1+=^`=}`H~&{5k!jGt7t~Np=fVxUUVHt&|T51=&k6VJPRVl zY+5Wfaj|Q$1lYBhe8uD{CRZ`Jin+~V6{$isdNP$2e8=}}(Fs29sBLo zNGbVBJq;qICFz$Wh*1m7l|0Y*v03M>x(& z&fssAcR%HC@fY`kNQK0BV+Fld7=q8MFrP25Nd@1h3deAl72I5fM?B$q5UKbMx~!VvkZdD56y;Y{L0Pm`z$0|FqM-}^5d4T(@YU`?r zuyxgBq$NF>$b!49S`;@|Ri{;TT2-f2by>9s?y#!dRpqVfZ&m#tvQ|CJQBH7*v*@m> zzg_hTSA$43f4iEz)#8&7IjYG~O^#~%t(Jn+$W%?HYGr7RUaEbCzNbLld`}`e5YJ5m8D${_*G@~UtsNtS! zxThNKsm4G)XAh5pNKLm{GXd$yNFmD8h^F*oIHMTLR6b!ApR$bY?B^%Ex8`Zi@hdXd zl(m+>Q!6`i*2+r(>{hE7CDB_gf45d8s^ag~lC{=gh9W~P8EVN;OK-I%5ydp*skH`w zyVipsQrmlK=STk9Bl(gY$WvRE+B&Q4?X@2Vkvi_O&c`GrBsnRuX`LdJr2@LGQ-}KK zrcM)NsxzOB>}DSaID}iOa{=$KbA>;Gh~HU_)b-xF&2g7?y{qnYX0nuZ>_wM#FY_mN zxW^No@sj_7NWD0GKqhjNkAjp!m-Td6uOjZDUQa$}0lKKSgyp!;daH4F_15DZ^)@4K zy{la3Cb!UAJ@-~mcYc#KQcrh&lQmNBc@U|e7=8Qw)kuABs=o+tsDC?%G>Cz_YETZ{ zHPBlF?{CnOUW~@34aPH($=J1ld=2DkAXfvq8f<45`f2b#{tO}w-y=C$$WAWuqJxHZ zYiPHIc57G__tbDD2RY9T^x06Kjda<_{*AJclSP8)s2 z*SNz*-?D?Vya^(W-ys^hXdIh(xY5RmaC?oD;T?_TZ7gqNc^g-!CT^~=-Wto%Sig;% z(E^zo4`(5}u~(D#@rEX~uz3@=)#Mv=*JKZRYjS{d*tCh;YH}C5Hu)R7HkGfbTutR_ zDp%9AWFRwHsXeKUPF>&qx+ z^BL>d%8%^CR?QA`gkxOdcidcaoi^8LbDcKVW%Cblhs~3aky3P~8@g!ThyDy=C?jxt z&Ap@fMC5J0k?+~U59qDAn`^!o-8Gk|`5}Hre=VY;lNPpW(HlLqkiEsP$kp*ya^($^w3HVtrGGP-rp+3 zJ+*RAt-QC@JnYiSyISe9)ln|<7q5dz>i}D~wsmV;x3+cbJmjMwg{eeqy3n0o3`Uo& zb=lgEtv_KEzi^s!=%TgVTHCGlHEwd7yLd+%dE3a_M&33lNliNR)<%vt`fcNO+T=o} zHZ|$NEH-f-Z)lr_(zIeYx@+sM+Ul+C=X}jJY}$4wyV;9f+sfBguC{Wum8nTGEF0$k9#@?fTLmx76+nblq+(ZmOM|YUgjY+s6S8;eOiv8${acx_w0& z;q%%LLZ9uYVzc&ZSjSK3w7pK->$JTt+h64dfAS=VbohWm6r}{Z=ui%y-=PX_)bFrH zI=H802KwzVhq=hoVKZlV9z;6Yt7A!I?l>8ncRa{-bl33( zdh7Tmh;)jNO*^@*PU*==X6)KYzD{y=lB<(kotmNFPWtWCj?pY<2fFK|yG}=tqmv#w zxvfsW@mCP({2mEN#K+jIv%l3j3)#tq`{~@2X?)8rd|u}(=(F=9-Ug8_ACj1y=(LMY zyXdrwF1u8w8Z~In02Z;773iYNH~9Q68*rmtwy+KF=yH?W$lT=~5BLYYb$N<@yZCN* zanoI7>6)Bkw8CCpS0Z!Qzk^6On|I4WRdm;_HG1pTfq~ex+Z3iUof+7*n|$5m>Lyn= zxw^T{Zu;$}-)=v1KZtaXO*(RukAf6I2i@IMce{1BTlYE)Wi7|hW%s+h2_ik-L6<#J zk(UD0#J%^hLys18q%+;~5wZ%=u9)}sN9(OXYBdg`}lTikR{nRcfEc> zZ@rFk8JqTc$Rq69>nV2aEnjcBddt;YuHJ65cXo1-hx+s(iqBcVmn=aCz1>r9yY;qP z?;p4tMEWEmKNYBp?fdAn&k!aupD)Uv$xTFvA$h7{=rF`g%v->B!r68{65*ZuHjI&GkKm?)u8(cUdETmo?H? zfBoX2lYX}9HwZoSlfB;`$k<<={<8GXO92W|nI_n@e+z8dzYXme&IBeil{x6RzmEIs zr@u`7FYzRZ40xCK(Zc{e3`j}@?;nr`_cXvg4e;Ipi?Pc9?;7w6r@6sDL1bVwVqoim zwjOBffwmr4n4*-R6gBBYZ~8HiQRs4@E(h9i;AgDkJQul)E(Y3dpxp-E;U0hU2=5pq z?;v>x$vY?mnaGOX2Fc-fStEnoj^AaC_+8e>pa%439zSv=hz$0I!I`Nd+26JIhxaf&U8bLA$A`!gkiX) zA&D}8S*lS4Au3}8nndc4IPO-ht9@kLpQRSu;O-pD_3nCA{HF_OqcpgN?=yr^ZW8@hl z%NV_lvB{X8_->Aw$!xrL%v^kD#w=hHJJ^ly!Cc<803s9J1$T8Mk z`R&!n*lO5pYzqc5j)_cR8t!N87c6EOE3n~MZye|QG|n#LN>YdV_+E|ci@O|W_i4Q}xl_pyD{zdXfVM*WA)roPMj#3T+MkdTjXhf_mRVB4wb$Ve8l zlZ(8#rKxUds#}^`k}{OXO--#z4Qf-5hBTo$t!PUJI@67w^r1h47|IAnGmeQ&VHz`- z&1cMGA&Xeb3RdwA-?D*CY+)Na*v&o;aEK!u=Okx1&qXft2iN(NJKW=M9`S_dyy8s| znf4CRh(T=Pk$^;eOfr&_inL@PGug;V9`aL&qLiRC<)}y%s#A-)G@vofXh|E|(}}M1 zpf~*($Pk7zim^;!GE@14SZSy1MnzFNT6iI225`R!aP$Wc=ZYk;R?(XjH?)sl|@my`rthL{@hP(OZv5+M!XBBJN zz-G3wlRfO`5Jx$|Y0hzxD_rLmcX_~Lp7An>3Wv+3PJKX0HPkF)XAo9nXyhR-1 zk&q-L=N-}zMLIH)h3w=c5BVuXQA$vXvV1@#KBPJ|`GimTocestH+)A^TF{ENbf6Pm z=^jLe_TzU3GK9bQhmnk7Jd>EhbY?P#`7B~7D_G4sHnN57>|!qmILt9la)$F<;wm?| z%{?CSgy*~pB7eO>Ok(pk2}n#bQj(gGcga9zvXO(_+7W*igwmudXRZ050$B`jwZYuUhN zwy~2v?B@_iIl*bpagi%r=N5N)z+;~AGKl;g5QA96B|eErN(xdDAuZ|2L{{D-7kMc_ zVTw_b(v+hDm8nV%KBhLGQI9Waz_&D}8Q;^Ic66jO-S~-~^rA2Q8NeX^QmAKqWq;IyL!(Px+kse9bp}M^jqRines16J6;} z4}PH!{rH`M4B;>SVI*T1&m^WWoteyGK8sk&3Rbg@jcj2%yV%PC4s(o?oZ&o|xXKM~ zbB~8S;W@8@$Ukooli0jX0uqyql%yu)T{4iFY~&y}`6x&cit|2YC{IPIP>qkMMIGw$ z1z*vSMl_*0Eono0exM6K@;`p2H^1^5e=wM#3}XbN8OKEaWg7o6n|Ul`3CmfPH>uYT;vMZxy4-`@R(=33?jn=Vi1eC#3vC+c#oXqAwTwE_$%Qh>TZrytDCkWV{_2 zZ%4-KXMFUTIgB@l@#Zi=%?Ta&fiBpe3Hq5}?}+y85@NQK)tfw!!3<>>>iwIH6r>`8djC56cQ~UM8$_n4 zHzg!3<~k)4eTY6A&m^Vnr`Kd~EYVrw-*v(!Ja5#v} zEJ1BP<#Xzz-puH;qnyCZW~n#J*{rW`ljvbl3hv>8G z+~RH!nWN?$XLDN9j*c85`s_ZBcp60Jeobe((w!ctH}?gvg2=o#h)FYkrWf{Op8c42 zGlFDgG$U*6+1ehM?OOe;b++yeVq&)ITF{F=^y7E#1d;V|iAO?` zpx*j{3}z_9cpgMHBqt@Q2~lgqa7HqQ@j+x`44iFDOL{V4uQ!fk0_M7LY7p6^-X>?8 zvXGsesJSWn%${wsXPf2(k^K3~z0Mr`H`=eWp~AhJu%UEk4! z=GdoQ`q_1r>)5qjcZ0}o{p@zO+pg`lYrE~*?!(;S9uIjEME0n;$Jw4vbj2?1(a)Y| zyudE)eG~ocb+-3^{7i53v+oVeeqSu&@;%P>nf<>03_!j8=Dt4xi80&#c5T18?;p%i z%y$3tAaWo%cFk}2Mf`?eM$Gi+Hg*P)V|j6QtSa{C*vBj&`fNA*I2c5Z7o!%n`HXs~dHgW; z==cdv2ayxy_yRk2q5cQu9;`TGEF0 z*y~f#XLotP;~;WcKc}6YwnwKs(~VO^pFPDMowi43zQNfUdvvA;zo6#XfHyH$zrPka ztDm#I>5CmYI{@|0y-j=)krX?0ZXkmh$}pYx@?Co+o8*L=yDk*5`AW-m)Ei(h+MHlSM1Q0^4Os(_T-9sS2nVlZP=5mcIc|J zt7dxD4qg2iHLpgW?Pec#=$e|>oL&2bPx+kX9N-W~IT1vzm!>XedfgsfZ-9QTpX4;> zxEMrkRHh-{VvlavqZ>PjKD*2{ZU&K?YTj(l_q3)R`te&>k(+n8&!Zr6OFy@q-ReLm zx}u+34|$Ba-g+5CZhuW@oZs$F56<&~S3$(@Sw-%|qzTUM{7i3t`xdczn*_9_ zKfg1OAv_2o_nh5JL{jY1JvHwQ=1=}+IQqGtl2q8G`)N_{zPaBY%{a{VfqDw}!-QldJ2}aNnh&S*AG4VkL>}qqQEtrsQ2`30pGVPWX8&k0%Yw*b zyY{#!#d)7HsQK8gJ+^C)?b>6reWITycI`=d?AjCi^kgQR*ur*p1(B!fJ$3ffu05@R z**;xJ^w}Qvb0~;BQ}5X))S)h4u#)JrBOK>c5P7bj=jQ(0`SY)^PtW!9{3Lemxm|mH zF^IgVL<7FzJDReC=(EdQ!>+xoi9LMTf>xOA%Y)qF4)=K!L|&=+svUOim0f#fmtLv) zD*EgR&v_L@UaR-I8{O%_FR1zYRS*UNF^ENTexWzN@*B5;@Qv8SB|eF0&+q)fV21KE z2;WRfa^4{gKQWBqjACpM#!xFpNLtd9i9ST1jb{>5f-vUWWF#}$$iX0{F@ssm4Z^q7 zdn*@t$WI~uA^L1Si&z?jv7#tUQA$vX2`pzNYgiwIv9nT!a#Wx)>c!r`CbqI82;-<1 z$61^YsZLE6u#?^F<6scRErPSSwWvc~)Qo$8LmcHq5WZa+XK&ZzOB%3_^%G z)lA|ni9Jh_h@^C200SAqUpxuIq)A9dN>Za{(!cqKk&Fq#WNIdh5JfudQ!+J^*|lVL zE!iaOT5>g$J4RQ#ngji4QT`RBEO&_f*^2 z#oi!HU5Fakx745TDNEVM0S{`S= zMYa%qcAiU^ZCH)(XhL($Hrzw>*>!GVwoz(E*|Vs&m}`_>iqcP%J&StC6P^cQ+OO%1 zJxkl29-Jfk>}3$X8xRBa-gWlw&-BJFy{le2dzLO1afy$b>71qOk6lVPhfoDMLO(L#=eYW0+X2{8|;jA9{+S;opB%EvSaRGbgd;T!TjUdcvzjK;< zPUktl$82-%<2pCF!~G!4^%-qwhq>nJ%yAy@h^M>=!rc1F-Gy%aL{IdS`&AI;35bDR z%F~=*=*_SE#_b@?8;7?^Kw{eSJN78Ax#k_plOW8O1bdXvT=S*oNB&|MBN!co`QIQ7 zA?BJt1M20sU-`!|k$;1*fW0o@tUxC0k#Ek!0t1LXo5~Dk1!2LY`5{8ibbEDmVclQ2I^rRP8g0PgcQue2m{V8Q;rPM3chhO;(J5uU?5SETl zLhMNCmPtkmQV~JDGQ$|oD8>e1**9@kHi~p)M9s3%XXBZ~lpri; zXUjP&mziwXlX3%@%5-KjCkV^yr+hB*ke@>6r@Z|sZ>HrJu`~#MM;m@ngkqG$j(jkI z<*Z~4>w~aD7MxWm%LkZQ1@$UKpKW9d+k>#8dKD}4A=R-b71gU~o)zs-MLSgSKoC|^ zvy!t)W?HEZcBqn?m7>qgw9-*d1Yu?MD%YbvUt>oqt5^9HW?K0?mx8d0dR4yVJDOro zs;F1R{#3cj4eZH>pYT1cXiEon!s;=2i#WtXz3R@Y_v3fWth#zN;**dhm{|=wRKpI{utPQMPz^Jy@jM7W za`sV5QWK)yMxc;{-VSI2$?0jhY|(KjGu( z^I6Od!dhz9vO~4Zw3Z#JWru31S<5_YEo2F1_KBVKJ!1GtQA$vX@hoEnt63L>wbiU$ znzGoT+IFb+bk?(xEo=|MI_lM_jG5N4Lv`#)9X0FhU>AEi5QLwq_vy!c!l!(WdY>NT zFvmC$YY-IG6;Pi7k<%|ANe0Yqn|Hc1!4Vw7{o$9 z^_|tXXZ7t;eY359GYG$Q_GKL6kr4I1boS-%48$&d`6vj#N<p4NFlL`_a&TH2e@d(6BM?-|%~6+OQoR>5O|c)LX+vm_x&-LHJE7@?iGg`1^0{ z&^Mo8Cg0S>zx%cTcEa~u;kVuC!7s?|+kwdK+o9;UQ8IE;h@$AVkscfAv5_7dRpTo> ztI+`5ztK$QFdw}&TFMGmbAnTxMJ~SW3LD9$QFN`F+z!I;)ch_lwfF&Z`c9VL?d2So zxyB9bQDd`joS3Afz#JQ!W8?hj*LPfDW7#&=Z)2G>mPupJZY_n3)bi-Vl$f1enHQC7?+_{POr0E;PBntb} zG&?eGD&wX_C{9VLGK@LMu&E52%CM=vnr>$op4(I=O`il|GdtcaH~A=tXEpPzX76Jk znw6&k-|!txXwLV@qFGzoqh>RCG&{tzAZ#wn=4Ri#4)(Em3tG{Jp2)EIQ2yp0M&SO< z7qW`AY(Ngp_1kOx8-Fm8F^p#t z|FSy>znAg%87P3efBy-e;?Cc9pfCNI$bZac9?MzD8rEUwS|%nvX4TTHTIS$q{$w1U z(Nf)()0lzmT6#vyUASvYIkr5)T^{k2S3%fHkF8=L-&XmNK`R-wDor`OXRYdDF0J(1 zY5;>!x0S404M)zci zwp*?B+4>}BxX2Z*1z{V1-zGkZNJ<1d-$pKNGExZhYSW0G^g_nI^9tLj(?;KI^xa0^ zZRVqA-*<&=mZ9f1YPXShn+7)ecKhb)oa_! zxNF<%+~jr;`pzqCmxScJgACf~x1CwG%SHv7qUUycZKv0EdTl4$c6O_s-D)=u`_ayR zwA+r1+8yT?qfca_Cr$ zlGwM7_N}8VI#$LUJDOw1CN!rdZD`LAbY=t#*o!;=kdj=KqC6GxtRMW{5B;!bzV8Zu z_=oXKVhZx;6p$L3`Gza(l#P58qzL-#q^C{|>B=zF?=%|s?=%tFc8Y$Mce&G6%&C+2 zuhSm(a}aauB=b%ug0QoiouhE~&a&t;*A@D%E9_!c zUDA@3_i+C%h0$*pxpt97moNAUJ$KQo@4Lb-dhKGLy3A!h3$gcI>_Qi{y4>UrX4O@n zUDfIui@3x?E?pbb7kPFy|E^0|&JOh4^#=C8TO5**oOeivoV(enZdoWqPvqH6Z{76P zO^)5{P&a*b^W1LB@Z4_aki(Cuh~Vx&rpL2>l);ZO_)!Kwen>Sw;$v#_DW4;cAHPJ+ zAIGqU3qjc39lPtRyLoi4Nge7^j~3YZ?sDwj1GDPhi$08HDl?eHV)Wa6C95&(?q=rO zuFyAK;ZJ(~Nv}WUr2y{#QxPiiHQ&>kc63CopL+8vzcGMCTnWPenaBUq;CcTm&imBB z9sk#gw)E#u{$@B6n8Xz1{6G2r?{N_NRx9k0fW#yvBiYD-Onca?9+i-554rY`YmesW zwTE7NbfPPA>M;a)^q7PF>Y+xD<;bMRUakdUPkHx@g*)_&Pa@RqnS$Kp!=Ck&O;300 z>25vCP>x2JMbD9}v|CO)>H4dk!^2x z?Cp-dy$ikHAvOB!t!D4~xKnTQ>FrLv-KqD>AncQnWTeEs`ea8QeM(Y_vXrL+U!mVV z=F+Dn`t8#NGwI{medN_=6^HTsKIgf_ZSL}bM?u*4Ez)B4ea)h;S@boFzH0UTfJ%Ib zUFd5^`%YmCa_H-MeV_6o2!D0wU(;ZJe$7i2YEcIn|0?5Ozojuv>BM?YAj4l}_^S+m z)z`1)`|C42x1UV!R=;L=kNVloe!pYx{RZdeWw=ow>SMaunG6~JzD5Hw9t2Gq3_Vb{&MjBS=j$| z5dQWCGWE?^_?w=8)9Y_~{Y|gGwW9;>|C@RJ_A9?JiMcFbG0WJ@Hg>XyeLN4s-(~!J z4ZgL99Csb;o`cBF_Aggp&^Sf z-yzGn5QKlGqzIL9_dlD`0(btiAES`_laA;-Y z;Te&W?+`-YA%w%tXt;idm!&)n_ys)=*XwY-4%h4O1uRB>!hoA zStG|Y5&ezyypi_Ow-4b+{f*p#JV##QI=9g8DE*C6XO!MXnfa*HL?}ox)EFg?QL-LY zk$SY}cLp+qzxaod=wp;@MlE9n?lwvrIRtTChToH3J_!ZcQLh}+0|jI77l z>oL!H6@+8oK;~m*J~ka0$%6N4tnA0ie(XmyqYwYF9q;B?^B?P3V?Ar^%OD(=nNoa< zdyexr@kJ0$lItXM_f1JS$zD&&hCC zB`8H%%A@zmV_1z0CZFUE=K8PR|Mi~yn~AKHp$gTI^S^be$CrFfD`v8Z-R$Ear#Q<6 z^!l${rzFHPr+h#qGUKILn48Ba!d4@l0Ya3s}rDR&X&0r@w>wOqcI;cc0!2vzhMB)B7`;aV%vW z8`;8M?CtbJ9N}^h&akU9;u4=kq#{CE(vhFa=y%3X$Y+LpX2^4fS~CVPh(D3d4B5BGxa)CuQT;J^Kbq^)-&Za(_ClHMm{s`-%Pp8JkBZ1apo=V@_^F%=0uqyy^c1H&6*14*wWvc~>S3<4 ze@4Hvmmr_n@|i8q*=o(+%rr%xm5hya)5#b)LJyXFH?b4*-=hG9 zDMmRypb~PPFW>oX=}LFh^Zivg|91v57}?DC4$a?(TJzQNO;$KxKJ(R_ujYa`h)H@f zBAW%-$U!dhlAnU8xu7G%Sk5ubW?@RQl9N2-L%$0@!7eP6?ZVIb0{Jfdf&cL{z4-(E zE*y%y7V3H7A@sb^{w;hRgp1^|=q-|xf>cC^!tO2V%y6c&7&$MpQ;W=L(RJK)vAZr# zgL^J^&&Ansx5e(ZxCq6t6N?+toR+kq3*Gn$IWLy);;GEVTogk4!Io5l8V zNnF%gqSg}mERoL=HGOXuE-6Y0bw4^KcZ<$<{{eoJ{?ENxxTsEAMY~WE4E`Nt?c;52LRHZ)dxco=##PWX_ z&m^WWhj}bS&dcSy{4`fE*X6f(%rjnMS60Yog?(J1-xV@l(E$0Zkk1OWR(wxu+9B5! zvRNUU6?$Hw=M{QhF@|wWU^VB1aHaiQX^t!PzS3+~_Tn!_Fq*OGcja2vBiogm*@}Eu zUf?EoxR2dlsozz0dsR&Iyy^q=yvqKqlJBZEv`4aEF5 zJ_=G8*{rdTYdWFU8nxEQXN`Q;sJTYXHUBb=O~_`AY}V{#5BoUCVUF@B2-l{eBn|i< zX0vuVJJ`zs4x!(*Pk4rG*S-qEbpi5S7a{$wNB6Lx}oQF_HW%J*02t{w?2wed_;ZZyxvZ&H>dT3aM$(jx_&iVaL@I-aJTjDw*CaCuoD|%k%*+E zAT8<0h@3abcSChP#auV2x8XaQ(gM4(K{gxgZ+;huY=y^*Ll97^B*oiH6VoQ0dVV+xR@daPffNyBa&-A4~zcZQ% zOvb)!nS-6);vQS}atO2D;!a!KVM}x``rrBna^Gt1Thk!3t!i&od#l=8<+Zggde|zr zt)1vfcg%UKKDPEoFI(Mz>kKw>E(o`|<2HBNRtnGCRvTGuvp3tG1mSk~-|p_)QH`b0dwDB$96pC8S>g`$9C#7og92Xb!zen`rY|8p6wgeaA!{@ zq34}?-Kp1|dfj=D!yMxT*SQshyJC}^cSu7Nc4SvB@?u`Q3Sl<81~Hd)xcjbiT*RGs zdrx-Ddbg~1=cfebvb!uFV&=QeX!pn1v)yg^fi85T7o(Yge0EP~CbQYdDb8~Vz3^jWV5FU&1p#++S8F?xYr)LyvOeDO@<8iy2D<7zt@iJ zt%2V6%6zXr_r=B8KF{9Qm}a!Xz4m$TzTf$ae;A3G?3;pn?fZ{a9N=aU?thyEBu4H1 za@;S+{UPt-PWxrKUzYpJQxUcI>uY~?Ky)q!TiZI*0Gsw zcn=Qm!z>S93Bn_9;66v(=ZJUsh`L9zke!^k*AcTjVs=N|?}+;ysm-U*fNSSGR}pJNrNf}VXB9UfErn3)_ilVhKu<}rJIY#FC`8HC5}uJ5G7 z<96=2{XAX^_dNa`dOhA5cRl_iKhcBXOkgrok->5O9$(B-^nCnj5T4NU3Gc;;3}i+g zCkjy%Gd)p?GRWt|NLH|uW8CCU5S}!rlL>LxlkR%*ecbb;d!F=;oOHL7b*V>vS|IC_ zeHnyZIQchY8P6pCWg!oO@YGwpjoF<_gk3nL*Hd~u^&a-{lsc!(|CC%#eU3V(zM>O9 z@;`c^=Ba*|>8VB7xl{W%$Ptbs_fuzihWt+lyoo+e$3ZWrAIvWpjIGY5$oy~`A&Z>1*t+T~Z>uhPtBA>HABk!|YxEzG%V&UC5SCC?qq!jk< zTm!zL5shg|bAI7>1~LSDa!$YJ%<`Of=G+?2qv!K_J+IgEdOe?AAZHmF3946?eSS4?A&XGP9V=0#>q`b;$XOe6L*KDmS==p06e*1*wQ49T_Of$9#(2 zxcU`(zxpj^d{xg^r|}=Nna4twu$%)NMmASZa)$F<#Eh@SB_m~MOmFPRwV8O;Hn#jzJR zOX1Ep%kcqU;{G?AVTW&aM87w?(VY>jM9(+%dQ-1A^?K9%Zro*+2yN`nK zo>|_L<2^m!)9XFG-qY(ndv?$L@0r`ZR+!hl9t`JS*JQRMy-o8!pL>U%&teX0KEE4;FOpFNy}#(l5GFE}8O%h#FLtvR*}gc) zVa)EuJ?zB`JNwekzI+?~zD!I~?B2^-==r5yU+VRxUSIw~Z)E*aPA|>%x5(_ zF9k5q*QF^(1u9{#uUn(v*OQUYYx%sE=WDfIFJLjtkj?93oIua7_551TuP)hlvuY#x;Z;*zJWFb5GDM%5DQJK&A ziiUhk2fFYhKhc+QxJQhs%w!Jk6vI7YoaGW%xy4=X2T?KQ95Ws2#4Jf^%25GzV^*aR zO=yn$#%x1-I?{>Z%*TCWJ_@4VN`c(pdY_6^LDp~8Ku&K>XFWUE%|4EE3VptH9y!N) zi#V8TtmM3dtYU?jK`gV3^(9^Djyc5g{8)YHhq=ZY$bZaYF8YkM2s4gl#<5ni8Z~1F zWI)fczoQr9kzs7}jJ=E%>_o4z&tMN@UqH68uLMzX-r#K#keJlyH_p4HN6&E@qUShf z7N`4Q3=c|K}=+jz}ynpu>|TRkU@fUWWYO+ zpgUujjU7m^8+)6;-XypaL?tw%gt0K^gzlM8zX|PV!Xgx>B&DcMV_MS=87KUS9{fUY zhH{3x$kgxeL?wJ4L?tqxL@7u`1U)9oLTNsr64m&Kk7l&r5uWqnzM0=eQ6=CGj^& zD$s?gEM*mIS&zC&E^>wI+(HIP>{gN&K~z$APii(v-8-qdB+X1#%HX+4D}?9Wks=XENKQ)ZNs2;zPB+FP?-VC_7DT0tM`GMBWeV(4O8c6!7-pODeM(c7dVGsa zQ#Qj+rPOcA&e*Gz!&ru%Q|dLPUQ_Bdr8%ZF$CPqOX_wx4gEVC2J#vv3wcatucgj-{ zvwWv56WPE)Jnx-{JPD#w`Tr`FJEqD`PAX7?kEzXbpqs*T0W`ON}ZaJcQMP>=hS*mU6ty12UCB~ zAm(9?sr8=5Y|`YT9F_QxYUnpjE7~C2G#&BIrs={E^qa>1rWucZ)68TJo}K0(_kyU1 zc}C1U5+N<=$&GrEf|zZ@Y$Gy>3}qpkFtf-duJSC13S(nNVHAaN&rrXij6)fRG7dkX z4zdlq(}#Y@IQ$Fy5RPCJGg!e|%raCnJj@ABbCzp752B(1VqmwU+#xC>S;&FAMCGL- zU!!(Z6XYD_|GB8P^hQomi&@4>*03IRqqcI6i+G2ku5*jKJm66fl~#sn^J9i-J0h#J z?vU0U()#tASz=D%r#>H%rj#Z>S3N4-8G}TX8arX^xIld87Jdz8Qm@8JQiT48SPL; zv&?9g8Lt!lY&mCq!m}VMQ(WrM7(Hf^Yo<2nFO&W<=`WN1GU+dq{xVHxHfm&2Bhyay zA(KqUILT=|Khw(~DzkmfY?hhLGP7(lr$yeGYvLWrEceWxQ=hN-1{r0RQD!}4?nPhv zGk}52WjpSaB_X-^0Qbluqby(ISy}oZpDbpXWd`!evY2J8WHs{0YF=4WlA4grWFrTj zowYQcomDnje?u-=<&sq{S>=*-1fv;;=VtZXtmc??19m;@R=g8gcd-XGvn9c7vwg-7 z{Dn-jnOU|ixS!t|i^_J2+uY?o4|&YfAS!!OBFHp*dfr37+4GX0k7$RUv+FgxUbE{p zyZz2?U$V<3yLo0`%05nW4*Qb*3TkCH$L#hy`>P=8J+pi-J74f41Ms}}W-^DhxZ`_g zxxmXHDn~5rSdRFl;2qK+=N$6QVQx99V;^$ZhaC1G$Jf|{9F34oj^EL54w>fIh;Z>}oTq7HRwh<o^$CnmtJ$}HPgTa9dE}ipIjJ$*y!J6~Cghj5 zIA)vods<^B^LC^&>gN54VT{0gly@8x`Io8K(Y$7q*FE#aAUkH5PagT&;92=RD_>U* zatnFndxjm%AB(ueCn2)T@1FTRH~)MV;T_0tR{8B${w-|7obulbq6)+#8)j0#ObX<~ zObQgi-3q)a3x8P28qvt}2&~u?e6r}{Eum^=|@G-Udl>af8 zeVAvVJ3&-oITw~&Vf$3r91FW^VRtQTj)m*vo`t``-3qtD916FiCnGSw!vEqOC_Ik^ zEJn_SED^Bp?g=EtVho7SnIB zvV4GN7yFhzjK%Yd&A{A?xqmVDFSdeJm{+k&+~*Nbc@abvSF5;PEpCRzlad@eR=hQX zkVA3LE54QuxO4GyJmg6bRU!##h(g9CWLzQ#xyegueq$7#RbmqV22my7K)sUh;O|R@ zWXAnUmdD*nR;30tX+|sB@&jGy#z5S=r2b0kucZAfX+KN4Z%K11X-*|?aGQJRyQIEL zKIbK`gQ)k@V;A19%TJ8P4!v(y?|at!p7s827OxD-T{l~38Sd_#MB@F#!cT`DWrvhG^eUCW-wY|6T4S+gnYZe?Eu zQRM>O#BP<7b-7#=rWhruKqWq;8ebsaa(1I!2Y#S0zcY}*j9@jV9N(3?Nd?*~J%haZe%B9l4BeO~Z7h^io?3T9g&AxZG;3Yqcj3bkpAJSude zE8XeAFZ984EBuT1r^0k*GMjlUU=jOy97I)2&HL1+8~-qkS-4-t`E1}IhdIh|PI4N% zSm_O9S}8V((Ql=cq(aY?>Z0dLKhcw3m}4bbRFY#QGpr<&N@KBym7WDrl_TWDd@5Jt zBN|{1mEE_EM$`!L(8hl8kUGO3oIPiTahRWqww8zRFieJCCIkg0o=2i zeyhp2nvAQ-xY}Lr2T|2!TRlQ1vLfT^1t>&OisS#&>h<`VZ&0&(N4nCT|Dpftf1!T$ z5zI#q)%8$)4eQy6cfGnks>`~%oU7mBP7qZiCQ+De4O!KYRSj9yFyk6#Ttj9xyz4d8 zuF-^Md{1lKzeao1uQ3~$)wmZ#eUyZ3c-}{)C`)cC*OFJQ-?1CD zJipdlyc4xnV$W)=V*~rS!BbxFI*9t@P1O1%DJe)r8f5uNNB%|*pLpIUo7sjte{uym zfAT7bs_i|fosNvixVDUI=c6EIUfYaof65npMFYC<6FuoeKYn98%g}dieb-jAwwkqf zAmiG4ucOyGdaa|^IuX*6o=m(?8Oot#%b?QuI7yd8!G$x++>3ifNF9p#1 zr^P5iXGXCHxqa50ZuH<6dLygPW?%-NnZai=`)o1p^VteEa*Feq`DfR;#hoCkZd?+Q zgp{Pl-RjD+t~=CiNF$n{cHNfPsk-ek`?>=e!e9KuNX9S@Io7prb!GSYyOg31jcGwE zJnQpe%wZ||{oD*b-@d4qJV(X2-2NH_s}&ol0$cQcXuNph#(?JNJ>fy2m%84x$CayoAcj$ z|Mq_Qa@RU_`Z1F^%x4jDuOp*6tC3M1@76hq+pKe%vz*5_Rp&BSc@u={W}pNu8OmaQ z;5W`;zPguq7=-Et#K2zb#X+|9;*$ye*2{za*3)mjq7=j1^<-Ob5VKg$D&$db1A9@g z-XV@4lX_2sQ2i{FrWVa`C-vP$eLJZ?jg_oHj`hu1U%&N#=L*-j!7ZKzp$3UbiM=J3**nY~muD zh6zc6Z>yniq2Y(5Ld}MC=*?XAAm@g!f>1;P-X|F;&~L<-6hyWWMfe)|M%1M#EpWdP z?lwZd5j~Mtgq|aIpyvoXkGPIpBL3nzFL@n=8U@542leTT+ix@zIX7C5JvI6Tvo-&=4slTHn^9j-fB99wQOT2_S*DEe&RU4 z1fgcJ2xG6!vLmNv`6<9xc)M98yxpuHGnvDDz6^O zO?;B@0m;#Cn=fz+ZDiX9?JX+sU|HD$){0 zw(Uw$kt)czT>~O$LNk2p?FJLgDAa5>mqjdPIr?w67xmj6fN$1@2x7C8eukF=l2eO%z* zAk^M$?F&;4Gqm?sdvCRG&lJ}3GqP&$R@%Fj_UCXb?cGXyx6)pA9pv317BcK0!w!1y zp!W{$q=WuD6v6k>!FSx@MG)%v5$5Ps}o4lb;>UDCLo#fRigj$_4kcn?FXQ!d8;3#*3Q0Lg#d1w3XoR0K- zN^we3nzEGRJDMY-&Ykd0b?%FPI}c(A3pj+HJL|QxUOVfxvpel<{?7mLCJ1#&NK$g} zC54bx7kzfAKxOQvOHFDskd2(?CQpJ;*Vx3vzX@GGrXY6OwFV7ojG4PeBIB-Zq^q90 z>b0wz=(-pgclB>s*G+6?2fH|dyu0ePn>@RPkxe&Qc2lccc0M5wa_Lr)D(JbJp1bL} zTRj>Oftuas;r_eb3PRoW-aRwLs7fvBQXl$m$F)}!CJDWdw9P`R%F~GA74;_LVSz9do)KbJ-X48-VDdL)ME_enTSk!JPblTlOTtl zx%h?>R7ci5W!tj{K( z%X!r7mxjVLqCa!k$~( z%R^SNmh~LqJWqnqP_>5I=}M|cLBGSg&<)uRi=sDunSzXmEnqQg(C@HKY(dY%o(G}fdLAA^ zF2ggD1$!Nyp8|YE5n3>f?firr8-5q}Jlvk5-A1%oqsC9vfa*md7^bvmLH0niP?t7Bi**&9S)7s^Qc_td6fGbRTH_4s!wa$(Sgo%#qEvyg};N)=olnM&ZFJb zXnPu69J7u#>*!AO!knWAV7Ad_8$E_`xQWr**v~#_DCPxyOEmS;yMRSlNt~`Pf5vYpl1%%4%G0d@tjwQ;WJZ zpbe39#J4l98+JZUt?`NYkkpuQycx%5BPY4|8aa26JxqKPgeKX8 z-x3Z@lIbLSoivK+tYR(u(DNkU>!jd#Ze=enM`_P?>7fBm(_TZB9!DvlKl~)$3HfPSxww zb6nsOS9lnNro}}z(^4XrX<^iwW|!0Ka+*7tmY;@C zZvWGLFVl-sjBkfI<{T%^7`}i#^WJ`%Jr;nT|Ys&X*KKzccI60NKuLLNi*> zAN|f8$r$uIa|W~V_RL*e!9Hhse^xAHJnMZvAO$J0*ID|WRUEm@s!9!NV~?}k$gH-s zrz0|%b&UJSVRn4Nq~}v)JzKW3s}o6gWIVeMGM+t*5sYFct60w_wy>9zoaZ8Dn0+k> z%_&A*B9OzJmb9TA-ksykIis1tWaKetB?r00RjzZ3ztI1jM?q+AJQ9$Yq$Ec!b5oO+ zBGjTQ@}0XK{ms?WTyM?w*4%qRXr4^ximKF`kQxxIP*eqK%VJx|~BWI9il^E%

+kujYJN&6oN7 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

@EK-%p$fg3 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

q^***Zz%o?TxQ{)0ZjCVLppk&002~=hymu zZHBKOVs@{e2jLsL@Ww8@u?uhBK{s!5@GUxh(*pgx(a#%qz3D(lI-}P&W6{kUncv9# zM&>s&nay0>`Q}dWaqvE0P>Htu%|xa$gITO*H+$L7K@R_qg1ZX4s#?PUx|HtjW^KB= zySux)ep)&eBo&lUBm@)?5Co*8QzR8>L_kSF45a&vb1|+w|D5l9zi)AKo@aBOe|g4B z-UQ)Wv57}Q5>teR^kOI@7|l37U?#Je%ctz+zaV@&84(Iml^V398^amJ92T*JFImGn zHn5TXT;c||xyu6{@s#I57%dKI$wXG%8BHJ2s#A-)G@vm$ist@kz3EGTrtl$pi{=f{ z<}n}lNBfQ)cvG|ke9uL^FS?GR>nOVZqbDa7azxKSaY|8^3RI>VHK|P$lkn!~NB9HX z$Iy3-G^EFSVq~E?WB7!{e8FWS72_}d3Bs6fA!E#f)Wb|; zHo^HZThW#dbY>jyG7&jrPGveX&{ItFj_J;rr!k9IGRG=O3*O;pB&e(Ys@ z#cJFYdpo-@$JqP%GYI3DQ=IZNzzhr=A>N6vGRU(s_M{l<++ zB9fAVjF??qyBIe+x`|t#9_TdgWb_kPKXKg^cQ&8!8G4Ot@8aqvuFP>|jw^HA@A(1y z64#ya;*uA0j3;|Mvx)aLJK4uU4k2$m`xWmlx{dcY|Dxac@kmZ8>~8!JdE@6I4>HH^ zgUsJC$HCgnCYBClV$jD@D+6!ZMUY=7cS1O*`D5Z~#LX&PZfP zIFAJ^!K@SdrV`4L@Bn)ATf3p(+6@z)= zg8LKAWDTddAB2fx_Kw8mab9BQC3aroi5v{VBrzEggh{*9YMpBuQKI9oM(S5R{*o9=W zB&$Jf>d_GIO4gkI48j|e={T7j$;M*d$=+ibx=nT|2$P#-^30T=CeBLktmKXHw&b&r zKe_zL7xM-FKKU->PA+%y2mEw93ri?{)s?nLjcxOuQ^gFj<${EO-aw)n_xty<9#eVEk zN?oVab;@6mH|1|!<4q9yP1`V)%&BBeC2J~KQ|UI9Zd0|SHNA-9eRPy+F7sG`xu*J> zZ`i;_d_SoZQh(uMn#!mKdn4_HFC$6C1)OI8F6YNKtxFjMe z$;m)*yd#b7(^R24W}K!I-SLJr{TPT2(@bUw?oQ+GH11BLuQcByLmIvLjoZ*~+=glH zVn@@+k>)>SN%J@e)25~{4X}S{y(z6O(mF4#`K3LGy-E9b5T=VoVv>=POz1vcHge#M zbUl$T-8D`syUFjpZ zD}65V;Lh~sntle~Vn@>d8-y7Wkdct=_In~ZUT7wo~zvfGF3hjD&(y=1p{+1-=!OLUs^Es_$V&zw2PMIQ8;vpRM-XJhPQPJ8P&ZNr@U z&DkB9bFM(`Ldg$xB`C?G?D z;h1d!cNh2+yH&t$6eE^3T|dM`_N0l6P)BUXM?bi zjD^g!P%%oP=R#F6*Ft(KR2MxLa$cbi(M2I$6k5+lwy=$z_=XDoihU{cJGv=!3;h(* zPocl~CkP9hZ((~^xG_VS%O-y28n?O2J-o4qE{h~4Dap}kk<=8TH07vBE#xiI0Q*ry z<|4ZEJGEhvt!!r(d(lG?JrvPHk#k%K!lG|cgr;;uk45c4(J9#3qAT#$qTX6mcSWz@ zokefpZAHDU=zSgpVX?O{_hJ!pkQ-+g({nL9SgaH^=|pe(GJp|`#`j+AU1qb2{phur zeu~{hr^R$y>~Gvz>|qcVPeL;EQ(QmA-CsNdnaPSQ#obxl+lo)-YmRa!2us8y73s-D z779~^YS@Po`Yln1dUVIGmC#X%A&f=d5)+xkmmEUo60(+%wS=rCp74y9ybi*W3CNCa zN)|^iCClQjl4e=bEK4@VOiGSn9p+Z@cbr%1EuxbGZ!D$XQuer1BmA3GsvRBaMIZX1 z=TiDD^$~NKhwrSEK1!`;Bb(XHd49z^O5MP2meN=0w~0ku5|NbTGIS#CDVkhR=awy}drc6{|VGaem?ym$=Mt=(&P^E82~UcB7)*s2Cr8RLn{? za!`<3)WOI`RafuYIWM-ysG9_)!eEMX9N3@xvIaZs=KO}F{i3GxgCVn0%D+_Y6(b8Qu1I<)rwG( zGL*x-s`bV#7uJbAgtEZ(R9gw;DWai=B z)xEp=QoOsmch_)s%^sZRO%T@7ZLKUs$bqc2WUW;kd24kH!rFD|hF)sxxwf8bk6}FW z*M6T*S<4~hs(p()+~Xhq!(3}W4Z=DpNQK;W(vt}p>c~(hJ2`P@9p7S|>8#^N>_^?W z*oC^83CV`6b!*^Ts9T46G(g97bzIjh>*}Sh@4@fbhJMF3tUHBi$Xxd*GS{_xbszAU zXF*smCUJ;QB9c&=C_Y5D^}c2|=27nySMk<*-daB)-dW!}>u12*>U&##J5fI${%xz@ zjP`V*D}CwDAoN^czx5ZgoRzq*zI~{_mF?_AH}!8|7aF*$fx8;$r-6PNxU)en@=^f3 zHqcE2-85)Ib6V1dcG#f?qgjHTZ*VIJ8^*wF8djn)EoeyUjm)vp zhs@+V?gnAwc%;X9jmuJjhInJ+0oaMgA264B_*NP(V+E_wb7TEBKE_E-a~6Fxe!_F~ z-6S9yI%;CxO;VxzChl!g8GG5JHac&jyCzN1SrhYZGK7(gVH~qr!}lD<-A&B4$}o9LSN1G)m-l8->{c+{1b#N;**G^q#!lv$Ve8- zBWsH)RKuKG=&D6M^wq+Sws2>QS#070PlB*zN{UdGTGXXJ9WdLLx^4LmLm7^aTk5vu zLKdTwmgd`1-j*BKh|DeZ+DhhDY4F}wnaD~33R8@dl%@-F*}@N)PpjM5y;d)Ru(b|b zduwZNZCwKIZ0((`tK)608`G5LbYm=bx%D*ca_di+#{%@+TEDIBMe85253SwT+8kS( zV{5Z(eG}cZNq`+_em3A~TIZNI`UwAF3fwX8$GZI5!Ab6mvUwUxK+ALy%{%`d>i`PNe-mbRSb9+10-kjQ3z+2mUYx{n9XM68#KL&4W?``d; z^C5Pk{bqKvkAs}xCr+W~_WEuAkY~KaogMVi!H#sWBYt-_?2wHd*pCk7Fz*hPX+uZ4 z(33v&MUDJLtT__gvw3ZeXuE=&6JEcJTdoj6-~6=$Mogq$Vvgbu5n= zcQoUU_NU`^>`X_!`z_h9qq92R3&Kvx$wz5q?j&<3Gw5Unoy?$<8FVs(PTtT-woZF7 zzfR8SWPY8@uhV^W)5-32(obiz=xh$1o!Pkst!al2I_sdbd3H9>&QVO|19Z^&BlOUD zF7E0)AG7Jajmx|V!Y&~??b3;{%w!Iq@)@hy!EVg5i&=L0fg>D4mtAz&MTcD;V3u8+ z+x2atV}4z$B5&8;m{ZpQ3}!qNFt@I9cQw1No46H(-D08tZg!wsNy<={R(NN({@A&0 zA0ux!dAlv)3zqX0TkzIycCOnc%)guYcQdPQ_xJ~0cMnKIR@~P;Cxs|V2})519d#dx zySnSL`y$-g{YzG`iZ$q_`*D8cB&Rvc1%BaIo&{l#4EU~km|>6iSc;x|{KOf~a}jxa zyxV28txE_Rk%(9Pe`sk*Q z%zb3;BXgfbBq13EY06N{v5)M1%%;zyAdHGhJQ9)^d7}zb6x~LZq%``CYDRlH(G|NL zC2y47jvB%&HY0PCtWmN?$r^QwJLoz}Pf;&}ux|?NUtjyzS1*0@;I6**zOOmM6$Np3e|PtHcmKxdtG^8W?PULV7{*A(FrEp# zk1YLHaR752U?v0fGC=2kmo^;WtO3p%(1Nji%0lEGAoGB)@b?4uBliHg2iTbb`X8XL z0slYq8V`eTp#2yaqN{;bsE*tN9ijNr%s!b1utI<2>vpjD4mRJx9WdX)lbM5#2Al2RMYwCQxei{>MmBRL2;WIeAu8j%cRJIJ zp?KpvpYR#qvV-01<0!}Z2|d4~-yxZ>14D{YlG4+WR_J7yPKNcQH{L(&7p`-QJN(BZo+9UPnTBV@w>;d8 zhP!{bxBETXaCldG;H=?&nZ^gq*Z@4>$o7V_$9}%Gna*fd8h>w`d zJm&K?J29&fd)d!H?CFTB{K21i|A;5ZJ3_A`bTKkL6_9zPtRrO|DeK4q3_^z^&2Qu+ z7PAJk8fjJ|H{-66-(zMYk8y&>K{(26M%AJ<&Kot7G0ealM}5Nvj^Y~_b&iW%;|90U z^Cx*hY37wC6vN-~iZ`#Ls1@{YBq zV~Zp6*rCWgb|Ly5`vuF?H9KFBijQ5=JUP;POj}-QHxqJD zkXpEVg1aX)$NML^cfvc2U^MQYFp){jXCroG!cXXZ!dbj`!X;#zU{5AIN5+X}Ffkf2 zF^h@u(7WHd4JY~*Cr)D(d-)lEKk;{bBNNSV;+-ITzcc%}8-$abHOV|DdDEn%q$49) z(C;L9C;1L0?cxwekad!blVqGE{6NHmv;BP0Fp*)qSifof>Q;&x9r9Xqv%j99` zX0p2`k7YdWoV<_gK{zEA<~*euvQHVza7HnP8Tb~aEagj9V3($><^b|e(d`u7PLX%Y z6@JIrQ}sDDq%6*#YG)60AK{!pP)68X> z9;P{OT6;R-&C|v)i@DgTX6_TXcer!tuwrJ#^-qF4DXz=7H^y3Z8LVT3p+96CVz9E zhrHrV5YBuXJYux}srWdQp5Xeeg-k-hn7E;4+y0Pp-rHy%v~N}E_0s+ z;U{MQiM*f0CN4Rsjm)3O`iZQc$ok1B#$sl*0PrUupDNM(kKV8L6_HcpUxxsDzs1-=Dc6Iid~s^lRx+qGn{9JpPBb(iSZ45mV(rzB?Fnrf;&I!%tThA$ov+*Z^7?()aQ+0$a=sqt%RFD!`LfQJ zb-q2D@BQ=5ZT^cOTwq=cLJCp@{VphlyB5@>hcJK2SLAcmF7dwA(W^}wbFJ`*95JfQ8#d0rhk6sq{V<7Kf zj*IQc;>k?o19Y}w8k0v#_qjgFUH;did{Ul1;jhFLC;M*=dEhy3V#c~QJ$c?}xUgy!gM`9Ov; zg0Z}dT+0`tyXE$CxqlCrui+c^a|suSSIab6Z6Isbd4s@_W2P^FC3VBwz ze??!+cEx&r;ug;P$~(UDj;|7ugyf{8DTjh^rN3V(_e!}}%DqzVm2$6?d!^hfnSS|#hMy40r;GOyCvDtE7HLp$ulDtE40 zf?ig6!|E7Bs6=C0(3-Y*^J-aF+ws-!F_B43LD#ESvlgAK-iExZ_ppyELHPAs$o#de zU(5QntX~(VC?zOGO*+vJ9ew={!*JKvzNfEs{`H5<RzGW};{LTVul1d*m1C_OYd2uNYt479``7MbF9-OZ+d=q^&c4Y=Rk|>e>G=C^ zyyKhCS<09E6@=?r;lKHv*Kpky%wgSb_Tk)h-nY)X)_K>uKY7R#p7SyY*C!-GIa;H` z^&N5d`tI~1ivD=hdT(0)F|+vucdwUg{UR2#liz}H!`qnohH7->U39VGQ|7Y}yR$*o z4LaChA2;Y=!w($6JT}O?;cxCE?}k@F=(k|QZ=L;ZHY(GGp7g;EeLIk`xbNGE*r9LD z-&jq+|ZyNx>EsPm0F-?$tz+<1a>Ttvqk zZ(@EM?asz~ya>Wg@kv5*+_@%ZnC?Zn$Z$7*kpe<4QCYNnZWzVu}Owa zEBKmkSkFN&^O$Ft>!vqBxLHq|y?3)c-kgO9GHlLGJ_=G8nKn0P03WiEQ`|xCo1L}A zSzDr$mukqlr5zpVf?e5SSGMSWi|)5fME6^!;mj@i+@iBBkAiS(2Ar|AJw4F-*1im7 z1fy}z){pSkt$Wb%)~j6OCiZ!&{n%$ZoO z(YB}Pb$cAL;;!xHu)P>1(am;uZLdRp8lso&X1@J6X1)C`uYzz#fOqeZc}F44az{PP zb4M%M(hWWDFrOWL7>Vz9$3hnK1|{GIyQnF^im)alO5gk+}* zGVhdmr+#+2e`f<4(-c{Dx^t&*f9E#j-}y2KccsI7ch$l>cQv93T^YhKynB~^ca32j z^H|C!6>#`q}HQy)9@>JM_ADG`iU<^Inv7r4X~ZX@r$zxXEz_s6FIGVhmlzpVRZ z-QSTe=z71N_77zy_HV!a+pm}X%W>EK&6wl<9qi&(5FSWPDQe@q1HI{sIUVrE1D|6j z4s7QDhd9D1&Tt+*AJFf?w}?vu5|f7XWFiZ?IcOgbc1EWM-$OqK^>ff&2WRjxbI|L- zjp*i}%m-yYDD%O+?B^iv{5}RbFvss@|K4oAU%^&(vWI=h`~7upqTBE9@F)5`6q7_G zB?TFg_fUlFRG~XEACmQutcPSh^eLaA>qC0-`?BGoL)gDV_V18h4*iO|4&B2X5Bqc?aJgvadPG5dE+FUOMMu45tQcq|urXv!qM;yavo>;jiCr(@oD-1m0e zP8`okA&OFhid3c=dOoh-<2{I?KLgRn@ySf%1LpD#8}W|gcKP^j^mY6qSNNS<+(Gxp z-vr@_)VTYEyHB|LL}~POLWUD|@mSx?G%QpS@qo~(?nPde-5 z1eWk6D_DhWC)e@+vo>>zGn_{+Cx1mZCv|i3IyZyxXLtUboti{3oz?t+8UB2k-?+wu zAUqYFn8YS7@zKMn92BGo`Z!eqc~4cN1~Q*A!&5S!@?D==kNKT4zf%V|#1W43BfgE( zxu}iZJ#7}JM=_R}EW}$+d+X_Ac;{*FJpBvacG}xc|G{1C-2rV?VL?U z3hdz7wD@+%pY&DqyM==WU1bID0X8st4!2D@-hx94Cr^E{`Qb9y=VCx7z-_nm(WvpsLN=XG+v6Ynt_Gdpiq=gsQ8y*RJy z^S9CMg=l!^1$i&%_=1iv==efrvZC7ywP`|gbbO&RUFktDhBK8Je2hCU{Qqp(F2*Jv zdc2r~WJJh?`CZIU4eHW>rnJC47YCt>i@La|hl}2GaU%2Bz)?m-A>cSB0+@)pg;~+mE_a(V6$$iOPm)v#f0gsXS(sN$n?qAipLaS;H~x!>`Zq&dc6;*-S6nz00y*&VjBk=OG_<<8n>*rDr*Nk&TCeLX#y$clZq?oHRLQiEF5#ogECy559lxbylae8;bt(+zXEQ374u zFpC=vX^g$OA?pnt+!&4yZj50Z^N{z(GQL9I8ynezvu|ADX%OB_LPoL>AqPcq-_6pL z!#r-<&71St!Er8PhBxitt$+mhMsJznEi=4jc7C@tyk&N`bbhNjt!RT8-kQJ%%tXhx z7GQq2?9Qz(*uZ{%;3)3Ab(y>T#lPtMmVLf$hi}ItA!cwp7x^hfaY|7JId02vyDgpQ zitq0BNM^H!b(rhz&FJa2_ujV0x6ktnGTi=+>)hfGWcnjM*{MP=rmz^j|KY4Zob|`{ zAiR@|yvTG%Pj_^C$6nlNfSKO019w`|noqeBgm=B~ZYFY)2XDJ;K6guFK6jmQ*ACt7 z!Fcp|SC4nUWCg46w!7YT*W2#?#3{~jj*DF4|95%Y-D|uF!aqaI@lWsh(|i83M}HpV zEV}qp7k^&GEbhHUG-42&xaj1bncTBe_X<)3^SCGPJ#W6}?0Yrn&17W0=i9ocvwIua z!T}C(gya0klOX&n7qw|aPew78nJmOx|MJ$qj^UkuncrVB|8d51;Zp2p`G(s5CM^>WF?Hb*C5leWc$< zqZ!A$*u6);@+t@)CnOzq>Tw}_TaO#yt&hF+@mPFckG=Ephj`m#Z+pCeMc9eQ-}56s z<9m60nX6nw&yV%{#O^(bLwwx%L?2Hg16WAKhA zdVAvTC+>c7m}AKBM206aJUNfqKKcLMk9o#R-UQ*(x3H^Evrz%_efl0t`Hmx;!|a~w z>FHH|55i|5Utu24ocm1w&&>9Dfb*WmAS2%NJU96$PASS_{?8j?HqX7``9c=+1g5DvektoqSzpTfaufFUlb6U{`d;8{7^!3IJ-#iNl95`>oQnpf&C2NEf=(izuAyH)tbo&EO+uGnaYHXCd3T z%$p$cc1UG9F_xLk;Zr_iH9OeF9`zNJDzu7b7Qm$WK9Z6Qd;qaaRm?#n4X-{lsu*j72QrOZK9h7`ln^ z14lW|PyEbj{tY5AlT)15jKFMSZsrij_>q&y8}mQxLQLJpe9Ck58!H7F$wGvD$Q!E& z`idoUtRcu8YXP65msrc#z$Uh`ot@ad*r_N#!Wj>40VSM@H z%O8ISyYYtj2eCKt?M-}plfYd4UTh?R^Ahx9An%}y1ml^&`#3wnT6B=$I=8sPJ^sNC zC3wWsAd)ZzW|2^~ggQy6lZ19Cp}P`hM=uH8nNaS8)A5dkI!*Xj5J?o5bYvz(kBN$- zzeKgDgANllpb@<>!$d=|=ZW-?NZv$Kn1;-Wyfu-`iF_A{9-!Yu&w@zen8YDIiAX|e zqWBOykoaqKmsod+edmd<;;o6jHHn=|;+;vnGf4)#ElDoSJV`#vQUNng(uuD0U;u*{ z!Z0SW7<-n)eM!DyE8E${9)9L_5J_s+lDaFYev;}ZsXLRpGihE5P#E1LZA?>|(~35< zrz7@0={UaRd+r30WU!4b4uYmOX004yfsBl>_7_dOwj^w zOVNdH^uSJ}n8`dAV4f+yVijx9a|->YILB44;l31qbDxLUm6WE2XL;as zQo1vxJ5zS27n7KRZc^HzlpisRxqQlJxYO^^MpC{EBB?S{0kcUpiVyghIedb=slLN5 zq|$9F-KMgOsSfZxSGdhx{zBeVc01Mo&wd?5Qm3OlGW#9cNNQPA%bL1Bb};oj4CQ^~ zPQ4Vpq~5?LwqlN{f53N?`UF2=CTYwwjhUrsi?^p4%{aU{%_8hX8at8ZIA^)QC2nww zJN(J>Ad)s2>B&S^@{pfG*p;-^XoI|I^^;aVY4w?QKJH4pgfCfvZqgp&Ffyl=IjziT zPjQBGJP0D`Qc((XOecG~1?W265q{)nP9tx+M|iW}myM*;Yx=i{Mhr5N1AU~=M{%5+ zzAU;=--)rvn|>K)ntnBFG1v6=A^l$DPH(2^?Oz6ak)aa4;|v`zs|-V!#B97X!zz4d z8IB=u26;35!mnKAcmBm&GsY(csYyqK?Bqh%8B5cIwzw~2XZp~OfegluWYkecdy&yy z8FiWQJnqbRncuk1tss&~H<@DM+sPD{1SBFU$w^5OS}+1L%(RnB=s9y75|V^u$eXzs zB`JemGwUaF6=crbjh@Jy`5lHalF@vIvooLN3VO+GrkVdjKbimIVGzk8a~7Gi*ugA$ zDL`S|o24?oTa$i@6|>^dm66Aw;XzB=-$w`6rRHU;RP;X{^6S-5=ldG%p@|3S$v6} zB46XIh`ovY#bciFGKgf0L2TlY0DWg`gO0N4C|hp^Gn5fHJKKjiJDb^NyU4HD`)t>^ z$shd5-$5k1bF(`)dt#E3f>fj>JsELlcDtYbU6yl@>p>)kPIK7994Ya>9Org5HRy<$=Fn-5{tQRn9Ag=e%sKWVa}M81jyv4rA9RsJk2%dSr%rOlq9C1_z#Pmc z=O(st7<0(!tvS6lS9H8Hmv`n$hPUO)L>5BqbFMlx#kZHMHC^aNPxPEizq!mU*8=QA zF8AfK2f5Z_4|08rZgSaqzgHW{?XKMJ%B`Q=`pNCi-0sYsm2BuWcU5$gyB2k^f4Ljc zgl4!i_a}VEue=B%dCbOd%trFmq#g}vjJ$c?!7k*{Z64j`8N)c{A#a{#e1*JuHnIh0 z=efkwAd=TS^O|{Hz2uFMgQB=EZ)wanZv}LccRo8fj+x~(tGs5F&tBxyb-v8#HeXrn zKt6f%={TQ`^XWKWE83vjd=vP9ndms*0v54^FWA6-e&8tX%y*e<+~hX$=X(`I^1DC( z+oVH={4(UvNgndyThA{?eqHC+bN=SEB#QSj+x)u9udDpJ%5TQ`%{af#^842FyF33+ zoWhRfzrZEr$^RyZ6fo-o#c9hZyr;mI`1=AnFQD@R+t?9A3hK7t9CqTYf>-#R8~nw; zJm66fDU^Ys=%~;<79eXO84Jl+NXA0z*vEPNZQ%qYCK)M_t#EqmVd1QpW#P(HMK6Wz zVPV}A)=lAt*sH?*nayS{qUR#1kiCex7O71=8qkq}3}y(!7=a#&cxRDCm}wDx6j_73 zMZRSdKl3n%6qUKCtVLxlDr?bfm|xM{MFZ9myER^B!MgE=6Alkz$E( zUa!!HO#bquob8$OZd@@s6!BOr7krL)uLiQ47Q=$)}d6$Vy zLf#T9S&eQ>tiyLxVk5_qw}f3SaS3@#+~zLME}4kDm}f~dFWHQiw4o>NE7=dTEortT zbyD(2{s|(b0?e#bWA2K~%tW`Pwz8K4=(yBR*oRVQ zILA#M^8&Lh?atCVEZv)7n0sj*mL87|OV4H=3s}S!cCZ_Fly*ny!UIx>=lkO7?JX%MNHgtTNp*A;VN2P+o9y%oKs;(Cs7inCn6%qrU7iuSkS z9bN>HO3td3n;O(czm*!I-%9$eq~A(*en`Bj?Yd#Tb9 zv#nybReCU#nJi>6U$7i^RoTpUm}`|?*yXCJvA0$AP}O-=d(#(hu4*@`e$G<1a{%8$ zRUKE=aaB7}^*k5(BZyRci?}2pF=)CI&MyhXRCwth3yw&Yn^_%Fn`W^m6 zzcuW1jYK5HF4xG2yfq?ZN9G#ck-3JM*U)c`Sus)LzC{cx&x7e1rRI-wh&lVv&!!bisLbMlhPOtY8m^k=t+EM(WtP zI=^t4t3jl$GwNnWzPfoSfFA0Wp*$67Oi$kBbCx1kUAgMYRoC3=uE#9u%2xLjx~c1~ zy6&p`EC0XickEF;ch<8X^{UgGsn~&fW>?Sr>s{gszhQp$-zGXSu^aW{5}$13rw~Oc zhrIQxP>s&KkIeODtuJeRS?k-E`u3&%4t8;zoBYQko??~_+||IYG)PDil2Mj^*y9FE za9)GG9N-Mz*x(^gf=I)}*n@`Y$wW?aV`dHY+)%#_ThI~nYuKIs3}Ohw&`ra|*uRE4 zZFm9wG}KQ+cQw4hZSDqg-cxD;j3ZQ}}5LcfjM(v6<J@&7O{cEC^CWUcVlggN5lbY0KFv~f_d7Rhe3D1K_Q*&zSjZO1lCz{rvAx&sb z2RhLeJvY^F(@9Kc1|K1F({I_zcJ{EJgIwks_N1w27UP)6WIkXfAM+LVp~d$c<^(4>#Vy_h zk(Q}(U(1YSA%d(e?R86g(Xu)+`>otaOPO2B+_EWV&~iAlScko6`7nsIiiiGMIjfbk zT4kp`Js6Fwt={8(reI#JmhdGjSj8Hg*=hsMY+V2ywf48Iy{WY~wLZdee&Pa`u$O+< zHq!dPAkro_GPE(fHkGJK4eVW;dNjl?wK20c_OOlpX)_G_?ssh?e%ChA=3OQrUz>yI ztZiI!Q4{lTJCsq3WjuOs`vuGJp0?i8_G{MSO>NDg?a!RyJo2`^&i~K;BZ#z%K~7|D zCu=)d{kCnyZ`wxMnSHzVbfiCn&|kZGEZ}pNV)xqVuH7cKvJJc5J~{TfeRaIOeRq1{ z&Fv>MpG9n85Bsq@?SI7Hv_FkGx4#iYI)s#^8oKCEho+cQht{;E9}{tAhwbcQF9$e; z8Fnzk4rbWl9{+Hk2R!B}FL=e9Akr~C73s_*mSZj*f5*%_KH)hpgGi?YWF#|L$wm&$ zu2UYWqT5co?WBuN@^4EQ} z^ZS@fXLIRnpF5jDXK(H7t)0!evv+oWh|FCAq7j2wq@(~PDMNW`P>Z_wp1QQd?sc)J zUEafeU1snxbNGan?B+b~>hk})^wUM3UESH$on2!RhwRw9uDa=(kAf7&zH}`?Dcsq0 zBn#QgRbB^?Zt2KNA&OEQdAqfwHM;HAo{s3Z+bAY7nQ6>M-fo|vuWmATyM)Z$-y%A( z@a=U^MOreD8MEzf_qvbabJnpFJ$FBaId%Uxi1hH*9^Tp`6W-awJA35E+j@9gkFu1< zPV}%7J$m8$>fzso9_HEOT_!MzDSXO$%(aL6dhFpa$M}(xT;pjF>6rv~_0&&K{q%Ha z&(f5mB2~~$Pu=wFMh|)uMSlh|7^=``$-oyU&)=Tf{ zxU080_BM~+OZgJJ-}`kC>7)NX1#w=VhBToo-q^=Z^sy6tmavL7m}j5w*v>BW+(*BC zZu2h>c+8t167@E|p(wi&rJJY%$Qz~8sGjI2N!}HleM3${l+j3UHdKDNWa;v!T$BLfBp2*Z$IwpXYc!&W4{ah5=8n( zqZrNUf%E!LW*X+y-y8eyz)ti(&u?7k7XNUchv<2Leg~u^9T~}tJ_Z!06lJK&|0uYt za4V}V48XsLgtQs~ zNJa`$k(TrnrzRaR$Cev7&JF(I4$f*Nf2&*+Lf%$iP=@kUqB1&eH3>V=$}YCjb*q)E zVI9tHbqHs-dJ}|Nr$!&GGZG>TpOAyxIJdQPTUX^fe&i>7L#^xZGwy6{_gZh`uOQSW z7Gb`|chaUh-q)r!cB74bXw#G4^rasIn9h83+GZ(#B5#|`*pW6ew~c|!ZL^Y{oS0)< zU9{C>TQh8{leXn(#Y}c^67y;Mgy%u1-TRnBJ8y00t?f$Vo$b7{-S>D~J8x@OpI>Ri zU`8_z-(0&{L^BUPx6^Msb8B}2`_RsP?d(Cjd)R|^{{^A;x@n&Vd)?k$?cLR0KkfC? z-kt4#p#hE1YkS?a*G>C@48i`j_YJil#TZs_nioN+Lpq9KHXS+=$xwzf5_vnU!Y*{s zZHM)2M86%*aFrYU%>(4^@DzP@l(}PJWbRm(dg!HNW7^Vz&UB*(cCX_(UIn2}39#>- z^xVl#buy<;-{7sCytPwTBJj>mgYdRa-qvXx6VPv`ZS3a|M{#y1J$Jgq748S2&hMb# z&T;Y0b(XnvMnYsJ7hh3|vXsYsJ9|UtrnI0n-qTsvo%P(=ygSR#c`{Sccjp7#@y zp1QWA4ejZK-RNq@UF~I8d(qXLyP9j)W1L4fUCp%XZSG>GU7g?UJyMg8Z~2ZNsX=XI z>!z1(4e3n;{c%?}cXhK<-Q3k}B>L&LoKwi$-CMgCr6zWwyP0;^W%npXFq4(6W-aU3 zz$Q*(mff%O7iQXB-tPM7uGbzPQV5xQ$l62J9Ozd&%5O=3aZ)hdu1&&fW>hjXCy~ zy|>x)Ud(28u$#Te+uOeOzKd>qKjc63+b0npk(zX5LEb(&$VEk(BXb{F`^efy);?32 zj;{OYsn047VgLHrzdm~Da|3tv@qP3$$38E49fbO3raB#o#Cd(^u@H0W>y3RcVki2( z2ts}%Hxv9=zo454`xqf_gia&2qMr!;M7S&BAV)Zk zULzi%n+TaBWR8%zUqB3E;?91hXoNZTlf9qW^t;JZUhy^v^?wI>`+rOr-S*E$cJ$l7 zG?l5!_tZh&{tak|Z_sb)hWg9gU)KJz_LsH)DbAql{(91zI|o+d z2h4b2E!;iO-2*$*l^*DAU|;$%mu*}QLW6WP$Q%Y0#d(ADKInUXq&s7o#8hM+GzYUC z&Vy2kC9lH690{!SM)DoRXA5?!oREEcal!2g^OUHSLgju)YS%JlNfX zd(npoW}vIVw}Q}+1eoCvy$@+jN4n9I-spOWtV5#l)*E>O*~C`%ae%|)5NW7w-86eV+1IzA>d*~v+6 z>}QnSjQSQ`M|nq-cSOk_C4ba3W}>SobB)qd)Dq-~GT$ikjdE|4zM}LMb(Zs74E*1? zNJT+v(}fW@Z@AuvFF+T=PjZiEyyQ&~8WEfKNkAf;F+wjR^G4t2Q4ksv6K@<7A`4$(55`oaGS#Vp znT^r&82ygv$1u!q%xI=ComoVqn=yxwcdSmw#z8-0^)uF8W0R4BRG8&h-Hg@ESeeJl zJXYqhr74T=YHTA0V&BG^<5=0pna#LQDaO~7q73qmYeG|WJFYn`(eJoHjAAUl!EttP zoV?@g^0)=;;ol%MUgq(#j+b@3tmD&?0bP&R)A-M*i2WOH|HkWOd_COd_kTm<&2fAO zIx&M2JPAS*V&l9CS@;BVn&6ESYGNlQw5JEXiC`#Ej6}~9^gCe{>)6O<&Tx?{*pUgh zxE+Khn(M^4#K$`(x_4r7+&fXf6Xl*L_e8lT{z_wXHqm@1_9K$PnDaz)p6LFGXm)Z9Z<_L) zSG);AQ|;MQv!9v?v!9xotmtv79;e!asgB)%Qo7II$EMgsYYL=avb(MQTXtuY` z_SV_y$bxsy&Vjeh_O{tYD2je(+pXDuV0UM?#@Vy=Jljsp?nM;S(eLbeEI{VjTd^y% zcX65vT;?h-gHW`$M0<e>n>WJXnCS5@+jyC7$ zxwt!eF-uv&YSyBIX!l1y4MKC0;eB(=VvaY>ao!x=&(Zyyfh=b~Cy;y2Ij-{;|L|`R zn(K_Y`kE`>+`{N;ZYk{KT%FCWg!#^G%Mj*c7IWpAE7x4P=KhJE=59u|xw@IFo4M|q z>#n)C`2SsZxgUh)>1SRZs?na&tmG)y_?z3@;Y|>lpNJ$R$M-a(HTqnj&jsU&##w=S9!aEn- zz}pr);1Q35(88F+CIi{{6yM%LJFw8q78c`6zM&E3x6pkH+tHm~^rau;unP-!bk&m&Di?Z?w?p)NA!7Sx4_kz&k_@pHhVX`3a z;&N0#w~H(DE!FrP9WU-cXYBG~c^BK|#ecIa@{X?)^cYp*ZJ~Jj9@HsFPC}w4E+6a zyS-fQ<#I1Sz)8;V|1&RgKM1Xeg}zo4Q?uAI(HW;2I*Y{Q$ux1Ze zxxwGu<}MF-ge+^ldu<-Pb*-7K)y-O+uU*G+PH~nCTt?q(Z{oZ^i_srluG85%Gh8Rj zy2E(yI{UQFJ?ozEoL9UJLhECYo=k+vir&}fM3(h>SYLoTM4;dGc6I$dp7D}5L1;s4 z-barc5|NRDRN)U=U~U`CZG&Cg&;|3`(2FTdXC|}pU2m9=yEZIg8HbR6;~DJg#{YO7gf<1dOMK+rWbT`iA@ip1ka<%ly3&K*3}XbN z8OH>+^CSpuPJ!+==cgBvbw}Q~tSbTzSd20)XVm4d%ah@w&=O*%Qi$gpTk_5eOOODLj3h_BIZ!1H2 zDp8qMID6Y1bh2#?>)439wjIP={r+!go7~&p2BGbCbbD3mBinX!+8)6eynVY~xBDKq z+lB42ZrAU2@7u25?RUA)!yvTd9b%G}%w*$J^t+=VMJP%I8el(mxNk>mx?sLLdeMi` zEWo$8!(BUcxx-9%xO0a)cRb)fbhT4AJ9V=&C8f?eFD<6Uj(Ku_e|)sF$pW)Cv&l69A?yJX$<0^iIoeec%O z?!+WTKf4Q~m)&3THRib6Ja&JNJ=|RbGugcoGuv&ac6kc8J?pV6dk%9GdH1G4KYR7FSD$;`wKqFCu{(QpvsX8J zt0D7VnfJ=Pw>EY81$XY9&UXF|Li=RjmzffL$4}Iv4)X5v@5R1e=yqQO{V}_JGq4x? z7PAbyy-(hKTiAxo``<<8{n^m({#@imzx(yOzZ7LL+x>QL|15TLitE^^{pNKb9v|VY z2fXz_8NBm=cOLiwZ#&>^2O7{2J8@tLV;IjQW;2KR==p$t51im4S8(5fJKX0HkAu)b z-5m4{`K{m3L3bT=*FpUp)Xzb89<0Z&G)Aun`=OhIgBVH_BN@$D+=EFsh`LO*vTpzt0ZbCac z(uMBy#O@tF&+8y`Bq6EM^AS6B#GH;)##@hg>yd7F=MnEbG8k_=GL8vM!cH97!9k92 zoC{pyDtbPmU%w$7I{G2zdenVKLuBC-?8;Hy9JP-}|G-^G-E~wyNA+{mok!hybRtvG z>(Pzq=BV8}x|7}P;{bm4bJCqB-FfmDC(-Lk-JI0TNxOIQHE)B^sTjm079Udv z`*&(E3ox5gfAgF-LFn{5yox;?Gi({}N6ZptC=>F=qIyr&z`2xp(x)#qg-@yevUGObkSix%Kx**pDxh`yDCwq|Xf}Ogcn+xu`;I0b~`Tt!{c^-r= zy7Qu$UaW=gFHS+f7tir85BQHKLFiI!J|Y!qNJj=T@i`?aLwTwp@1>upiOiQKAoHay z=+g_|BqSpRDY1Lk+c1jREJx4R z?bLO1y8aj5dfi)ZBqu%Ic_WOs-N?gdP@d)p@;T<=1ee+%3L-w0_slYer>ZZBg)YHux$Z^wrZ<_B-_ulMIFU{Vt&1*sEueg}OUtdxMfB)Cd)W>`NYK;Hx?-Den4|@Mw?|+ZLoBVcg=H@E(O z*K6Jep?}iw74?W<7TdYPL!R=2S3&4@0@9HIGrb+g?%vME*T{QYx3_hBTi)9`xvi7i z&c3bB+tXQx^KbjUZ~MM)AH)1^o8RrT+zLYf#vl; zh`Ic$hku>-?*%U7&HvitJ4vv=cXCjG!sz&pj_;JAJQb;ly}r|x9`t4qLmAFUX0sl7 z@95^vWAu4PpLg7K*Ee%FCb0>T8Qt8K`L4`&Wxo3v`6-Ay?{;838;3mJ)BC!JTjHLF=J!w+ z4|VZS4-Y3YnPu$bI)CvGceu|Zd?$}|^5_F(cx3+`r6wIZdL+}MlGLFy)7Z=@{>E94 zob^cG|D_}^pCk8w#j$h$RiX-2>Bm&&vVg^`VI3QB_J2ol_TzVu<8ekpWWlaH*30AE z*ssUV^&7*X$KUfK_T{k|J~qS0zfhkZ%w#9t|0FIteqzs_*s~`!@xCWNqt7S3=tBhk ziA29oX0eE+tiX5pMBXRc*n!MX-$Ul7=J(Wh@H7wk(8W_dJ}rYzp4zvkZHZ<#cJ}E_ zp7SaQJxf3;y!Dy4KC`3G^!Lm=pZPAHdD}B@duA7&HKskoF#Bg_|7;3#n8!l&{7k>k z%yPoUkxqhCz^LYar@f-cn&2!y6AARY_^mAAg?!2rDT)lj_c zmAAc`$Yk{UYA1)VyRS~*>{ohzb(QNp3PP`AqF=u^9D1D)nO}#yk5ycj&Ph)oaF*CytY%Xb@bX>-^9RBvAX%JMzc zsYxB&6{8s~X+t}vaD<0J_}zDL-n$=@nSyxZyFXHc)^wpey%@+~hB2IJ{K+L#YlF=dV^bIgu(rYqyw$mJmXo;kiJ z`+H{dUR_$ymJW16-uEUl8Qs1&otfzOy-n<99|t*wyzgD$60d@Atn|nnOV(Jj#*#Hw z6{?}@SbB=p5Oa;CpIAfDORQ0hWftZbYd(uu!kHi(J0726w_3Ci0iDl{_gz*$oszCem@OivXY$~L@)(?zCRy*zQ3A3k@5Xa9O17Z94{a(8L%Jm zGLwx@@vX$mOJ%<0JAU9NYElQYh*uAH#+!lOy(14b- z!JHCw!d(d>8O$*3V1jkr3Bm~zk{;(J{1Wp|XnzxWW5U+7!`>#euL&pMTS*wrTo$0` zg!)Z*l1p6W24``KKOe}k1vq@}^5)UGZk&H&(#B2By-6r11X7ro*9M}1ae|Utv ziJ$W_2q%#_$>+$NGLF-y~h>K`-oHk_)^E!XG3e4R-1SJM}>cs^G03 zc5q4QFa&S=U_29|lj zZl=&zia&^C5r;8@kCI}>A64dOex)(L(HT4Wk#0X4#t7{4N9O&}66F18J)4mCqkSC2 z*&pdRWn!}7{FM3e=9I-T&y=Mp%a63cE~e~3Zz6D4O0!Hkj)_cW7rIWB3O%H9UaAUw zgEy!8o$lD@ROX**Cei3Pm5x)bWDS3^CkUthkeui+wGLD3FtuE%%TW>Mrq)U7b_`_! zb}IEUoR!*Hsn=mAQg7iRm$}9b{^lQak@_AFf^ZslrqM?l-({K(=rWDjr#XflO>>KX zxy#!ioK}ZvKOh;&`3Ub%`x!;~5<8k!4{7C1`z_UwIqe8!PHRqS%_;3B>{r@D9OVS3 zIU9u2y-R+6pb>58hkZ$>%XD+_)^y&Q?iAjc&O6iH#M{z&TRQuc?nw|%{~qbc!YAaQ z0EPG*J*U@idb^sw9(FFhJJahUeP8-BkRc3X8ncGyMl$}9Aj z;T?3IAtz-hPbI3Lrwrbk;U`+r78x>hrW-x!gMG~4{TXzZ;ZhLJ=zSSOcuPj_$f)y- z-{Gu`{w|}LW}M0l)@CbP-(H+Jx2cYd55Z~wR@di_|gk9GL*1+H>~ zzjzjeLve{m0uo~fL&-49ki4P7*uRjxp|VuK*`XE;#=AqyS;boHU&zct?h75l{)LY7 zItYhzQH5VUgMce#&wXa0zcm``RMXU7t~ z)TJ>^abM>4bfPQWi6WZKxGS@}GV3$5J~O*BvpX~2<6#iak_g>o(M^`*q$D-=KT8HO zVYXT7)0esIM$cJe@*$~6OM2wZTAUK-HftHmq2H_x_=6U-rVH|B?S;OwPGdVVXO%Up ztXXBv`k1G@;8hULX0F*nij&YJRoJTL&pYf76LHN^mh)FDD`ScS? z@(cZ#%?5Pwsk1(H)~Ba~u-_LB=P>siW}PEUR&<*~w>fm1qcG0MA!Cl-L@8_lgQw(?J?8a2KV~2B@ zTdwrjvt0QpgxTk^U%6^g7k`(l0p^#>{Br3u*FelJR}`}5nuK$6O=kyJkvF&Aa@()m z2}wdaG7=&SW}4ex5__pT}~{Gyht)vYlP*;WYZqf0qY53c>|q z5|{WSBn9@efOizoeSu<_b%C#`$-@z(+~FRw6iiAE%(b9BDyWx&vssO^3OcLcmLOcnUKa|Xk3zn^LV57r6)Hdv%&(9h z3+b_t9t$mH1_y>^vFnAMUD(-$%Ta-Es6sWqr#fa( zxEAg#Y*z})SNK{GE)s)`*nuMEUc}6c{K!w()gtCqq$}oMq!)dNU<&dUna?8RE%GND zaCVXNybZ#ie}wZt*TLsmFssk=VqTvYq%?K;o#xo@&)edz&->D!fegm1KL0xi7d8K) zdMN6=qD3f%Hy1VUqRnVYBqJD&j*IHJ=uD!S%bFluEG8e~tYT?Nk9@^sD`uC9IlGt+ zi|MbJvy0iKVs^>z6^Dy;qc^%JCSS2348tA8bWrRhXV62jOI+m!@_+FT?*1Y+?~{PU z*r_k%`9d#We2ceyF_Pu%oW*@V z#V_OCU%T_`k12(GU-!oxzTVCW&T;`geSJR&m(Wj%cXp9Q)Rbt7;i1>t!3W^;d0(t&O6H`#M{bwTe&o(!%mbdO=YU` zJ$3k*`slfwe#`YGlEJvMoIc7eWC_bzg*_>^hlAMba%NoaU+hY`|9H+T-UQ+Da+H^$ ze0oCYue^De*LnFLXih8I(g8h{_ulfp$@1fwgbd|pFq^r|N2cF z*Okn>(oyVBr8_)9*Oher&3nlEjro6*0GYq3gv{UQ;~RVUO-H&gfI$ppI3v-|H}`^Y z<-}wpC&ej=U8$_s%HCSpTPsK5ot3?_ve{Jjw#o}w#1eczl}}^GD__TsSH90f9;4?f z`mJI&{5EmeZxe^BxU-5rsuZLMMJa_Htzti`ct@3{G@}LHP-O_RR2j`UCa{>@xVwtG ztGK(0@2iTws>o2~Q4sz%K8Z*|GUWKyoWGUj+jM+I4cg<4->%1wf9t$&A7EF$eaZ`7 z1>vglRyF^s8##peR6WHR++EdwTh)JC^>q-gX1}V%AT=5In5<+c2c@aNH&nwnQms0_ zhqC;_Z~Q?EI?{#i^kf9i`oXvO!zHeA zgTJ}WU3C0|j(;?tAI;~-AqDE%2@(G2hN=@pZ;~KwVCu%gOB|R9& zbY|hc8cSKhYRt68KCWOFYr3nZyK3sQrao)Bv!*+1X5&-JQ32i5tU@)u$1c{af&HoJ z&YF|h#I+z?D+YS5^#zsrjvx66d24m1E4r=KliujJmYuE@%{=UKEjw6C-dgL?SFLlr z3Bt8yt}SbAS!>H$I~RG#M*+;Wb{(41487EDgS%??!5nKxG6;KI`>!BeCk`obUY)`e zr4rs)#}3!A6LkhKoKcKr8Z(%Up6lqh&TbBHn4>|st{&?ap$z45W?enjHOIR3X^fn8 z-BCA!fegX-QFk=%scU|9bx~Irb@fnp3)?uw{UH2vTkHFSM`ch z66e;di+9!Yu6p{f*Pc$8c|9|)7ezFixxi(v;qH33_?LS;48rxjseTfYksLFs@9z3? z)wcunegE~{Sznj+?NI%>m_dCrZ4eV(G)P5S(vurm8|a{cJ!znW2IkVBBEKSU1N+jz zzBG`xK@WQ4>;`k#!9{L!mk0b8gnxYp_x&21_c4!O^V5j_jAJ%t_^W;X)sFmnmOGeX zLo;k>b`9liXm$;C-tc2GlNB>;ScRXcg^n9G#{3%EorcZn#!yBw26r}`$7=p$13GWG zm1CUd9A?n)2`_mQgd4p}EaD(XBN-ZHBPV(Ij57R8N4j9Hje4P{M&8@V9ygjvG%_?= zz+#rM5}6vE;ZYE7oR|W9&+q8Hv9lUGt8qX4UE|&O?;D@z5?8r_+>M{}inl?yNes-P z$)|jWH#a$nziHxcn)sV0=GMgAnwVP?fB&0z{$`(k)A4Wq=C>cIL2bP8xB4`s2@!bT zZ{GLYV1_ZAQH)_6?)=Scf0LYof$+FX4G^v`f0ib^J%)CjhIo>t(Z;I>-@z( z=&Gr_O})3NS^aKLe*YYqf0y-lS$~)HcOCw2AAWC1YkDz(Im~AfOL5olTiDJn_TZcQ zBSa~Fzkrk`f+YBrupOhvDLFF4#xH_c>jCUY~Ho9*WyhjC}~B-qjB=Ga{J=4R8}-ZkIG zZuW5id7Izk0lIDen5XEs#RsG&9ln7UpCE6G+~h^(7OjxkZvlr}=(ojWrlH>!`fag- z)vU$twM<5SN>dFx)zVJ2>_k7jwWYVVT!nYG^v;$$@V1uT*76u9uoEp`2jNz+h)aAv zBn7F^b1VI}DoG`(;J#M1s7pN>pqp0qvDGZx)yiG1^wUZ|t=!q_2*){vURymuH?3as zCJ46vRi7VU>!foS{9Q)T+FKyG~uC}=_$F}(?h;OIuaF(+j z=e51gUpx!K?Yyy_@2#DkXqS&-d_@T=@(tgj=XUyS*O@+;Yr9BBFq(1Lm3F#mXCK?0 zN2l#xp`Z5pY45J~afnAk^x9rG?RC>$=JqnTm$`irit+_D>5lztZ;tI{?_f3^GLVM? z6y|f}?NFP#=(adN6=N48?ADkhg=~?l6@NTt?=OvUZfUqpTg1kQ8(6Xb(G@ zZO1QhSI5ejXGinws2jf<9PZedru>0kI_~Bc_M}s6Qjr$#?j&<3{dUrCC%e_DHSOp~ zFZA5WPIT(e80MhgPD@yZo;&U55J$1ooz1XwCFJTXSLYh&q_a*scc3e}=-e0Qb~eM# zI_SKb!yMxzXE4Lgm$=GHd>dWfAtv6^<$V&62(#!?fyN9$&Mw3-r)c4_)=pwKHq+zOLtRR##_r{f9f;=V1`;CQ~=vcKeJf zRO1JJq88rY&5XL4Q8(Ro>w_KcW+%GYiEc7?i(&+$aA!9?bn}gLPlH)?m$iF)^wxba z!x+vCRLSi+$?pjXh^Gm#ysMAV)aMdCa}1o_p%I zS6n{eLp~xSA+nGS-So1u+-Sm>Vm(0Cn?zNk} z*ymoif^hEyMg!}5H?+>)cp7b5X z9OmQQeP!;e-@f|oYquiaAttd&jGiOxL_~7Jd_ft?Qwe8B*prA_)S(4t8XV zVWtr}jnHX?*+v}1Y$NU>bA-$h`tkd};fNQ!=4}w}Crdwf_WPO!$louTop^7*|M1R! zuXq!L`zOMl_0NQN_t$U#tb9TVDpHxM)I?st{~PXKpB~IW=Kiwwm$kpF{f~2!Go0g} zAUxn*bmRAb!vpj(ASLb^V3vOWH$1?e49G(b2CN;QQ!p zpd15Jkcu?qrX2P7mBuv1ehzF&8wN8BdpdA5?jJaj$xLM{=XoB42c_o=zNaD18sw}& zEs%ZC64oO3piSt1&^``wn5RK_aAHy--(cqr&PsN4H#j$6QyuvR4?#DBbu-xcgU2%o zxdxl_;LXT4*sKTdVlVqS#1W3+&LPPtfLRXd$XHgQ(;@N=k#C56L(FuDnGX4nC)nj7 zFL)J%hnnxubY#R{4$XnQLq8)wG7oKw%zo=PJXC)}r!kYItY9^NqMxBRg7B~u6vB*# z{Xi3brz??o>o9K}rqf~GIm|nU>2#R44LixhqOPQTmB;XOugmPH`5!M(HL>H&Jhb@bGu=O%0Dl9PH%q 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²) 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 *oR|M=%OG3XjLG7ItT09T)y52p7>q5!s7W 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�O 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എpf>T%D2p|->dE`l7zc~@Zzv$u_VWl z9M5UKKtBAsMZqrCl~b^c&yXg;!kL{(mDAx&%%m4)g1<2^6I`F5OU-sBc)59b@Q?Tj%%D`_|42T^c1FhQJW0Np$(eNH49W@px>GQm z=UHpcxH-rfxcXr9w0R7}+6Th~;JCiPLmH+v7}pDaCmG-Np2jbT2o6Vb7N@zKt}xp}{nM@FnOngt`6TtI##*I&=fN3Ed+34#|Ize3#^VB;P0b z0m%T%_dYG>wrj8D>J7TVp1qH9oION*)6*dgq_=~Z8H7$AicZvrFpPc35K{7!Qh+f7zaBE2l!BxbO?%9Y zLGlT_Vg|}sXdE=2lut-0M2a&noe06`12altQi@~<%%D)vk%3~t*3Z13c7OSchYdS# zDF5VC)?NGgQ6tQ&gv>T#=Gco_)S^$|i14P*=We-nQP|wQsvXSCLk_MixR3baT!{Vx zPo zJ0Mq5N|I8Fl+vV>A*C!SnSJQRgXl$_GyBmvKni;Fa}2%^`1O#( zq{+n8m;K5Th)s`Y1kerWoA`TTS6e$kZkGa)EH zLT(#8(I3OfnGH!Esg1!z36W|IQX(dO$s)??`D&N;^{8lkzPo9Z2a&N+(h}lhTEhuABxY z+zK=OQ(y)@n=#YPf|(vkm>HCbnRLSp$_X=OCXv$J8Z%QJ#LO&oG8tnp6!t!J4k@U` zzGKYHh31jci(~p$?83Hq?8Fb8` zT(CvPv2sJ_P3qHpe#FcR%XV*EXMBrO=w>4ZC53HF&4ddTTpu*vxFqnwmU^=~x3_~C zlpmpPysNlVP={a^SQ(i5EbtkG6o3jsOhzAw%a0_?;JHm;X0Qb_Sz(Hb<4&nQgT@Y= zJbLh$No@v?89HfL$~2)!lYlfjX2Q@2ha#XzC<=;(VxU+k4vHsbC@I58K?Od7l#!&2 zB4sowV@MfG$~eXhJh&BR_N2hfetZthjJIHBViIO%Wnw1XFoSBsjG13anP82XvkqeB zGCKL1G4?{??nAGV0(ed45q%xHLCO?TrZHyH^lK?Y|3LElmKEPMA3OZY1FYDAE486d zk>)w4VJ`g%J%j!tWjZO}lkx*Eg|QEPX{OZ-Qf6idTA`TG5BKXk%D_o)0i`1O_02~v0|Qa z2y3R#I9Tp+?fr3AKEm1}vID09QNr3m?IC#cwWO>gWj!y2vk&WJ=FA3CHf99QgrS;X z&V+quj~R1fx6jZ2dz0zAt2O*$!0_gh!I?frOkaC31*2oLESS*fwA&wdF108&mLF9( zgWpePXTk#Z{cUYEtKUY<;JV0UsARybB?AQf1A+JTaED-28$oIg%m$h z{24XdAPkQHQi9VSHM{~`R?r8&jv6l=HG#&!594o1RDx`LymRq&DgT5ZWa9I^PMcsf zLZDDmLP){?!COn%?nnT8*|H#X=;dzm!Ag2LP z!t+7-A$aN|q<~aMc_|L(@Iq$H93$nIjDVT&64+$kE>t15n0Z{ULV-^vweStz+^G1_ zg`I(5E}p_m8!=_<#W;Unx@g<_xM3Th4Si z-+OYF8x0GufB0Lo4TC>>U~p!-5%ayhnB|Kev}!b=$*PSxpU*6j{nMj%I5QLLo5Q;b zyIAK8-dPR?+;eb`<6fTd)kvdrW)T{Tp(W5#Xc@E|S^@nCt%Oi~KOp5HDUV3OiSY?3 zPf7WclxL)1HtjicW)1Qs=gbDPopEksULL*$Kf#$77S6oV@1V&G&Zt>3Ig@Uj@w0Ho zpOlx@oC$J}Gm+@!81$mfnJ6@(NqJ4m8w|d1Tr>!W)rG_PmpN16+Y~R3n%JiQ^s$pC zHJvtT@R*6i$By~`TAq}EKoJlQyqE!jN+5g>w3n23q`W8P0|3Eqyb9kB9RM0g`J0q~ zcr#LcYsEj`1d2_t+s`x5?jIoCatj&}*MqfhHoaW1xv}c5;d+Y7D-J!e|sB)tS`77<>`MpyH%rNy#(^O$5q- z2v~U?G!du;BFaMLNG(cgF;dx|L{xw(GH^&OLF%U&!HGnCflUTzB2Y2df@bH%+8f+E zHh-|&>r{zH7Y5={MFvfTixGpW!ZxOkx^mH-m#q_b7jT|8dU4J}wxEeX1rnk0u0p4< z_lr>3`>CbSQbCx+NP!mxHzg^GB#GWQXe~G7BHkC{%(=g_=Q_-j8SjwS-zht)VthTT;uDT7lGxq*fxeGO3@DT7^`g<8xBK0BIuHBVRI4 z6Vb`~`gTM&e2!nQW+6=t%k^#b%S_Uw8)!3F@)6W)}+D6%R0^ry@J!r|AbjH z^M5HPgCoYFlPBU=c@#&ChbEBfLaM;cNzi0cMN&;^PZ|^e5wm#3%#QDaTH*5eKzZ(20rV2{ze`ZsnlNP~Jpk6CUnX5qNO zO+#+C8L?z_lV-hhyRZ#Pd0?-^epti13Z0^pX0=Y5ng$;}vdWCugfv@?G&*K*odEl_ zmV;^BktPUf*w94qFyXGkh>O6~euNL?3;99*5dTgfskKS1Luy@8zb3UFso#)VpVS7V zHYBwX|4K0OCC5y73d}^~b6}>i1v5>PF!OCDX3`Ba`z@F`Kxz|f%p7(QGjR10r;V`} zaT1MFq&6e9IgcMc8J{7w1*xqVGiiDoO~eHxhn4@|v2#&Bc3K*P{v&6CBW@rK%)6OZ zH_^BS-6pj)sclGY%ZC7beZ*Zet=f@_+u{EEN53PUV3XMwJ+()kp5b2==-#cxk@-zb z-N#b*%?7RhGGdzOpdT}PQqQRL+n9x2}oQbUB z7-u43>LVreBA+TF;p`(}Uiy*RpPMl3kqW5;NFA2ub|&&mB!`dJ0TEdXjjte__6CwV zh}6LVL}XnE*BZERf^WmyoBn%1L^j4I<0y!1V((xdQS|<9-`u?L8C9!59$vMfCfT?pux}(Xeg8M(Ra4{~ zQm0vCW}btXS&B|xflkyh1A8C2oYe10{Q+Yy@<(VTsWV8OoA#Jlhve|_X3VTdV*|92 zR1{9LNS)1?*$m-Q17ik%C}jxDxMPzUGkmCC>(#E4IC=8$K?9~w8a%Omp+Yf}d(Ge7 zqtWXym@<_ooosul&F*<0a^-El@N!l=m_hjw$#sg}M>r~Z zB6uE1!+nH$1J5|A^X)w2q*_fqxdoOgj5{wQF*Y*09I69d+-@P@@r!tdGwE6N$`E6TeHeao1M!s|AG88S~!X3`5YQ79&K%tT>IE!YY(Q4Ji!OcXqQ zR4a5MkG&`u`>2+rhLRe_P5AXFOmc*i8k^>ZCaMFHci|N?2|7ZZAQbTtq(+h&#Y?+F zF#2q0qDhU(5Pax^O=dozSgci!>h zp9ag^!+MDYcE1M&Q%d@s zx`))gq{5J4`}dQ2fYgJe9^y0$kS{rDmRK8_D0bZ-&0z~^eoitpXERBYZlu|2A_zbaz}13ZNIjY6h9)Wu$s>&w>xWN-e)t@> z4Ekt3d`{RNKDoA~9QO&xw3{@zD=*yx?KLwCQ`^5~2xf8Z!OTL< zV9Tt}LpCk;2x{~u{9P{J3uRwL8O%Cn#GtOQjTs(V;!3RttzWuLE%;v1|2)lUoiyiC+36|wIA-yqZXu0Mn%~j52wj3MLsy`y&^72fbOX9c>IG7NC-ow! zmq@)#>J?J2k_tn9ozxpV&~77Na?;#O;c3`)gETiSq`95sX`W`1Cf!K$&O(~^q~5Y7 z%|DKjCOU_cQ*>^0B9kUMCxrWQ?vVNiH}gQar|K@LkJH@KMB^ZfF2XAY38D)@aQ4xK zNxetveNrFrQuzGnVrD*|pu^jl{`zviTD4e>OtQ?^`Qo& z{zd9@QeTkzlGInEz9#hzsc%VrN9ub{(+K&JVJ5nnwV{b_h0lSR4;IY)V=**Zo=nW7 z7iOZn8<>g41;W3rFcaO&LCg$9C&QYXF*68_!KD66niIxe^iXIRX<10imga^gdNh)c zGgho0J7f9S(fAHkt_M2SgP|#bJ9qy7uSJQTf;8WA8s^eeXc{z~wCtqiAT1{^{Q;Vx z(@M)lTJ8)%t9jUDrqz6Vsl$ZGtd;AH4K$jkS35Ok|vQRlcoSS7}r*~iOFt_n;7=pz>R9bjVTE?^)qpkUbu-VZr~=S1ZkQT zZemJVaD&145%&ehz|hC=`Gk#mOeF|MVolP%H_xNG|b;L4p_; z2;M#hgYPTSYLixnm%{1CC}uv?B@H*r|M$gH%vacC@F51(g6*+hFm%?4XA2sC8q|4E zrSfZk>}cjg%-2Q?Dhk_}?nAv>JYUv+-Hz$&Jv>g0u4&7Mm2tf*~Uo2n2Euc(ZSU;a4-!f?_+u+4Pz#z6Vw^P)P77?s2kKB z>H+nHzJq#^)`+ymq%|R}DQV3}Yff4V(pr+%inP|8rVsM*C^Qr^AO&XFcVi^Bv0$cM z5@vd2VkX@%Gs%LP$)vTl#>_MaF*6&TJQtm)V`dH-L|S{&zQx#!nFq}$tpjPD(%jI* zEJ5<+#)|c0XPJKNbTkHimr6KxKFyWtv9ktgHgFo|(pqR8w4Suiq;(;!D=&qykJ)6V zRX5VQX9!wx^})1qvqzq4Ip4&5f4R|7zai5Kou4xPh(Rm-EqaWXy_k_7VxF|5rW+Fi zns%7DD-1U`rYxRfe6cB{9)>iDNTXvW9E}Jl5{iPNA$XIRSSSvP zhZ0BwX?l~^hqS(=^&_o6X#+?bNZKIM1~X=MB42XM?6sZ>jyZtOfteu|%nY+k1#6Qs zF_UhX!Th3rc{}C|X+y0sbIw7`TtO#aMzYowuM8Nryj0o^2RBx&Q*-p!x{ zh=Gka^8wZ?=05a*v{9suCT$G!;Su!M%!je0jmr>xc!5o3KA>8#btaYT*XWURcSFC8 zx5lh6UF}`W;KLgu1{H;EOq=SD8{|LP`rM{k%_l`&eOby5A5eY7aG9d_5y}wUuczU< zG?$n-ob?iOqP-F`%hWUYxB!G3Z+NR?b3%FWZ_dP|iN%Z+49#SNG_g)xH%&~9?XjE+ zwpk}lY#}r-jUQVWDgqUSib2Jp640kmNz$g0HjOmQo_$Z+52Vc?Z6;~6NSjUC9FQiq zH1Z`QO>B8=`E)0zT$jzuV=Ln)NJAFV%%kiDDeGXoBSKr5iJJ66O)RPj9W}8SCUdP& z6I;_U)WpKn$JR$L^5Bbwvyc6TG`N@r+-v|fByAySOVZrY#5O~6Sb2TL>}XJ3ZwdAA>Z&fEhJo(HIAfhbBN1p-IqWXbLnH0%X>Z zwwAPYq`_`(AZ;UQn@HPC+7{BbGHSj@zT~KxWnDYP&c)|I%{B{ab|lqK{+XmnH`1)K zkY+V$+pS5n&Oy>_MJMkt#$N0;G`5rGN*doU8ViFT>qeS8X})Q0YGS>S+@Dv>B=CV? z?PL8&^B~QWG%sGt12E9c2XE4RG6WwYu*uAaNPEZnpq+K{H+|CVlZc2vS=Oi4#d2-^W1~;M{^o-?+1Av=CSZNLj6Tw#yitbi(qgSS^Ou91fuWE6fL_!c%{w&SlNL`}0&@mFJr5=q;g z=8h&Vo0C&qPGiM<@WkcN51yUIsE^Cdj%Jt5!Q)(_aEjw64%I=NGiL&u;!q~Ufdg^4 zjJk)ky`=rbOAA9q%*5J98eWq7-#eN(u0D86Q8n1or%vde@)yoFUb=JUmp9g}P}-P@ z6<5xPL1keZGi6)59cK@=^xF2@wSqo7-+{|wp)XVJtjbs;AJLZbDGoRG0XCMGr~Y5N zJ!Kjfq^X5844XIs5+MnaAq7$)4KhJBp)W~0LK?dCC~3z?`-QaQq@5t`Bx$EeJI!gn zLcV04CJtshryrK_MGY*EYk;4C&94?u^IOtH&9zL{q!(-A+8L~gYfsu4E7rtybc{7| zJ5TEX^cpT1+>^~m$Bj;`^3Q>If$uQ>)GP)q1Bs3&Y= zx-}PK2Xt?{cGZT68Fz1b)wcCCanrEAAB;ZIvHZP`Wq#W#Uv?_j09ej_%m<`9MfB z-$=urCJqm00yEbgOtTb`>ybvs%rZ1Es~@)l`Vm?Qt%6oVYoN6dDke<#-6HKaX?IBb zgS5M(-6QQjX_%OM$e7uHe91Ah#kzEgW7iGLJhEWsNmA+bE)z59hM6D>X5dF3TVp27 zLCnC;$0ZnJFD?!Z_!$@_zF#yh5!y-GGtyqCJ!aU&9OM-qJ%#>+o=+VDPgFXJ2OipCV zLZ+-_%0{N_WXeINoJ^XR$d{Zn@Y;C*tRzDNe+|-@av7vC<*|^)R5X(`=|!6Odua?S{(iASNpq=^^pQ6pdTe+GUszuo$6Gxx}g z$~^60CQUqw2|Y%&7qd$#6&3SM`}$!o?WmK4Q|u*J9F`ilE7) z>BQelQ(~J9X;SbZ{u@L#G}16;;u|n#OvM~b(;SfG2RE|vL$y9;UbV9yln2GOZT{p#lhtGkTiWbaNw$x1~ zF%vWCh8c`4eU2u61eq#XV`j92n1QE{pK6S~co_TmDP;PLOjR)U;^Eihr;`c&>yq}E znT6zYdBqHr+0Yz_$n-gxz93UIUOEq&Z^le@GS$csm_ebSBLl^PtvTt}_pcG(>}^^$ zqQZw(@po5LGBC5!h{5^UHs-S?-_N?YxAB%aEwe4Ed_F|6gPFD14_sO3r-F6*1#Xi7 z(x8uqv$q{iWpCQKz?~8^+mHs+`+6E3Gk8`Un2`+33=aaWkSLYAg5xoXA0LJ^I%a&( zz$AV==2GJQA!bG(gw2W%hC-lFGAU%jnlv(*$W)U|Uy`X7nZ6=ZZ8Fv2kZ|Nnj+y8b zn2E>d7>0E%n5mb9nHHItNjJ=(m@s4J2${aN#>_DXF#}H@f7Td#@feu#zme%1GSz3y zz^}){Ni-l+BgRaczQ!~DGLm02R;-_*@sI>g(G873KZV~JS8;5rgZ>WE+~+jRr9Ys% z&^N!H{Z{M3c7s;0 zjF{KBvU6cb>=kihsiHF zB^1HeF~H&G+>PbHPXcTSo-$^5ESu9`mb&B_Vg zk%r3;3uhAWuqJwYpo3}pBh4tJ(K#~!je*c0XfQMc8VU`AuxSY+ppj%6Or{}Z8cL>N zWExH;xNs~SMW)eY8pE7{2~Tck62^luSzy+%$8^rXXESHUTI|et%JP899%9bS$mC4A zab}){GxNzb&YCle9OTT8=;hVuMV&M7_X(@WG=WSLnKNskwPcz^rYULeXA(9c`Buw{ zH=An#+&{v#K$l8<0P({IKd0tr65Nr-o6|6uc%%8J7n!D#X&RZPa|_l!!Pktd@5%H- zhQJld2_09V_Rv%4_ST}ernY+%o~5uyr+usO{cij)WkQ4z6KOAIb|t5fF+mMmNAJu& zaZE{>V^a8;gc#)D`Xh-maXM#aVy`i-KJtN&ggr=e6lrwM>_y`zXdkp6IshGn4nc>Z zBhb%enoXuTWI|CqmrV1>gkigYObf}hh)j!_GjQQnoH=Pd37o)x3OKXG!kJ}BlfWA? zF_UhXxnaS~O)@RD#>^cDG4lwW{1lz2W9Bg$Psp^KOe^?^{S$gdrXR_)D(x|YA|T~_C{oXPQyUy1NDXaktvW&L1YT%r30XW zX3T_;DKtZ1W&}2wF*DL0GVVQ?fBSf$ww>4gRwrb0jUsyt%#1N&#@dVVTzSc z3ubUy*lmp&cLy=!hfWSeC+e8-M*N+eZjs~`MQ+jL7DH~aR1LY;R-^lGeH}gXU$n65T;Yw#Zf7`Y@asYSucpVV#NCe!ALB+}K zBDq~6x61&8dr7F20f;N)b~Q5q!o31E89u}v>4IYs*nh#uOQl|PxW2F8vg(K0@2hD5 z!o7;wr>e6))vol3F1w?B$(Fw7Zu8B!pW^xZYc3N?ZnLmxv;pr+(@i`;IL+Z}SdOK$hb z?LN6ZAUEXakI3yYhiQ&@NVIHnZ*6eK_I#5&d^U6DiH$Q)nKKRf`6jo2vN)4boN@1C za>l(cx&2|s8TbA!a%Lz-c?3pL=gcrPhLhVfa{CjL&wV6>O9Riz?eFyG43YqM7jB{rEk^OZAZY?@#3tE;D4o!@fi z<&1Y{R>d>uY((5=nSEwE>vQ|~_`uu#O&5DMT>VGA5wCAJ;mlmb;6z0qBP1eR$a-TG zvIgKlN4>n<^|T9F?n@Dd^N(cC;K_AdZ2H&a%m5j;5g1qjP3G8XF*# z^xZc>o1rbxR%jda9kiWA25)$8Ktfp;_xMwU z0Rs%qJVWD82sM58zn~Y;OXwB!8u}Z0L&CcxlqaDA2^C4GL_%c}s*q5XglZ(b$DDx+ zPstgN9QNfI4;XFcOm!P)-nW%!goas|$tcWtlr%Bpfy1VT9cDbrx`r8#$`*@9H4Gxp zJrDSM4-EbXB-G?4P9z@HNvK7_N9kUk@u-F1AK6y?p?;1QaJMgC)AoSD$2nT4?c^L? zH2X6yF%*IdLpW4D+#sCQb<%hUXo!$RLLCz7l28w%@lYT*dsJwI`Xn^S45aaBYHofr zXVeId8hz-4PnrxkQ>g0JE=6;>8Km)OY4&O5w9o5rS1BL1FT8Z>PY0j*_~V7ksV{4L zw8ehtz`F{2nQzncXs?sT4NXqKJnDe$*zIXJ8jo)HRrqF|G#=g2=mC8K^@Mssy`er( zU+7b)9|mtsX`0wb)68}^ zu+TA!G#N%3WE1-JCXcBkG_@zq3>QfQQ|~dyoO>R#(I662Fe;}Ewqk=HYBtqp&c*X0Btld)1Cyp zW8uHgzdW{MlbMn`oFQX(|2==S_GwjV^`H}#o=fxJ*KS55mz>e-E5e|A!ge z@Bz#WG$;KRxOIlAu1@pZ`WRuJaTo^56X*}3tCO2N|FOg$k8jWH zyulGOp1CX*&%EXyXE)=SN5{-a*Y>z4e57YtgyH&(C;kRcRP;Sj$oDJ;6^BYdC81JK zX{Zbdqe=LjgfS$HC1D&1<4Kr6!bB1#kuaIVlta7}nDMM=?`Ax!;&WhTiVZWI&h^`85gO zkT8pv_JH8)Id7Ux0%Zo$c=p34^HGWf#E~@LRCwN6N@zJ@$#4C0HN5{6&s%Uo*>j-T zXOOc#AHMwc$+_N53LZKz^1zk5SE8JdW+-Be;9Z5itdj=NMTKT=8aqAp9v_P^u+0W( zP|x=q4^4n3LX)7$&=hDYG!4Rxnoq*FBrG6dAqk5}SWLna5|)y%jD+P(nwf}~k~Cji zEXB9sYgs&v<(`C}Ak7LJX;x7#yf>>1SAw@@p(evnv%-d&l_adRN6i`+QL`DNj1ko* zpXU}dwvw=#gf)zs?;u<*SWCiYMor}|V+PF}F=_nNaYMTen>=;Ql*t_i%^W{w?h$Q38(mS%agcX_eUW=eZj? zc&^Jk!Ft1I$wh-$UKPwf$SfTDbm%zy!Hv2tgr6@S%D-jki(cqctx0|K!2gOYPrcWw zVby$S+uV(p{t8dwOd9(?b(q=+BOwe^$Lk}g4pbMa2Vv!24WNb)ytbDBp(N~1f(Hqn zBzTeFO@a>z7I5g3YvQt?lTpy|>SRL4 zt1}5fcF^(a<{EUo`e2azVGw!ldG&=pB>_i!C^!25sfU3oRU(WSHwxFY8qO-$(^E>PM=J>Va)A=7*25!&Q zmtWY6v%D8F3cU}q3P)5tEztb(>wwNBc6dDBv}|*MBu8`Og_OnXOLL6a+<2kpi^DY5 z7&bRv`YSwzco)MgM$dH!qhn?X8mR4iErXUrE1;FoDrhyd27)F|~BwQfjA_WMJorGKIZ*KT_ z@i$kjA3S(jI1Zkh=B)2O2>yd>cjljcvvOGz5|?3AzY^m>EOL7LY# z(!8-58ZmDcXfg^k-UUq1co!t$Z#&R|xjABINENg}=<;lC$@HxdOt z+P&*IJK8&~`zdddN88YiJsR&i`o#^dyui?SBbm_qG;r4En?7;duitLJ^1%MC3vX{4 z*w@j}cq94n=FEb}h?(pyF_XnSXu9yAl6PbDY-)yK%y{ds@D%g87^XFPc0(A(j5kXA z-ff|FP5*(&G;-$chcQ1R) zcz=q|Ymivd#Ee)v88cP0Fq2`JK{BD=P2)Y9#8UQ{8S5fu;OV`mn{&?_#@>4xiDgLS zdq%zC*S%+wSdPTX>5rLj5PS}=n1OtL?XCWp2P~gbS^Z{z)VFFD`g7IEWsu- zW|lfbMvu|kYaJfgyyM)T0>#h&X!**-%nGy5N@sm`^!zq*%flx17WK>5zy5s7Bqx|b z^5M;yg?=hntKZ@%Rsm@+MqRuaHB>6d$t{klte-cM5O2PV$L40d^;dX`)lAI1W%}j) z6T%!u7#%aH`q&604I4O1w|v2PD=cu@;FRl31I>k4UV; zU5+4LO3WNjg_+a%90BUuFjGGnGuAB3WEf_GY?uiqv7S9lDW)dMd2{#he^v4X$zxNehF$3iybP2jlqClcZqQpzDLe~t;$Ry&sM>2t%LCTuiQTV%Dk!9`+?a98HHnc=FP%0O6_uOYW-l%_NrIkdi;b` zYCa(Q@a8ln+0EdgLbw^t}-`Jntz0jMAZ6Z0{NO-O7?Vlxt(lh}g9mL#?!u{DWpI1Ip@5;H!< z?eC`Xfz4*jw6$TTz3pxqv1b-$G72+3$R>0*tWYBoJCoRj#IC@M5ANpiX<}fe8;RXB z17>_$W0P@E_#j(wM8@j5^@A3Awb(VUSM9!!7Qa4dxEY`JW*=k}j(s}piT`uG*sR|1 z2?-+?FWj%&=rPGa(Bz8HSm;Hq6W;ai~3J7PyF+ zQE1p! zTKIl<@xYT+=bMglf*E8VKAfi5+>8%i+XXi>-sHnuz7o&p1j2Ckk&GGr1)kzW7sGfV zOen(WnDIsf)gm8X$Pe;|0-!)B2nvQmNSsXK6cVSBh?IOfi8Dw-vaSn;|7&Gbm=(f*u1b=B;@n6O%8W&l);4qEwM~vccJxKEfo<9FtEWSB7 z47h~3Zt=|qWhZeyiQkgAfS1D9`{puewUER`nSoZmNG6z8zJ;8Tr_f&;ZvWZ6{ghR| zKiph-)e79d%avr`B4(eW&icIR5ELy$g0#${oLGMA;p&AfMGRsI@PT~p@aS~fa;%X9c z`dUlkIuh4&7|;IQ!qA3i~&C)A6?Z6tn2 z;&$dkAE>XvhaDt-pDFk-2%F4&80_p=U$tgVwx>Te*}SY$f1d_PYu1{47-sfCM&amY z+6}9@Z`y=bQHN$stR6nP!96E@00VqEP2n-(D^0$i>u%;pG?@>h79-oK5Rg{3<2wmG zIr~V)%oH6nKe-s@ON99rVRX!Vg~r#=H_$9-Hbl@IXf8Al0`Yf~xQE2OB<>?|KZyrO zJV@dp5>XvK%$R`(x5LbmRG3+T&w-gEHq0DN#*AkcW-<&j$R-TT;DG$a9y8y&h?zYY zoPz9vm#&fNUs=e@(mt~4>@XZG=T*5{o@Q3E4# zwT<8X(~ays%B`sD1T)A!d_#FxVNi6;gy@*@F!`|X5-?L^ZJL;gMi|aMk}(sjW5&zH zFux+q4TRA#^BWrHAr$m|FG81~%g`0*Ds&CHP9lm)z9jmQ=uct*iGd^rk%;RT$frUX zGruF=d;gQ~om7~C&1TGm*)S84jG1#;n8`5AytZNHZxX}pG4ro$nDNVPvH0b~AoASv z%LC;lF_Oe6Zsvz@$3rxUiRq3RKcoPDu<<%({E!Fu6@zdeMGT3tB*p<( zOvntF@k7eMnDIll;OI=QC8$62pV6wq5AS>Y@m{5)M-9yQRWbWib=GHHoma>E9q9Om zo+(d!`cEL}G3{L-%u!f^Is!;D`&9W%co z44a~^mq9B8N}~kqCm~ETgkjA1$&dn}pzo(asN?%Jf*L~~LroxDU^-9Y1rjfkc!@+@ zO}s+lRT8g}2m;;UFwGG!1!nwOTP#B>TP#I87|Z=&vl%nL+c0yB%6Fq&`Eet#_%w?% z8O0etq!YTG@k9OorX6Se`n$-Pp%~>67)5;!4?|-(iML6-gURPN5<*G#E{TuRpEKhS z96sLQ%y={=Kod#4N8)`FA24SoLsJaSpk#!K>VI!%{E#!~oI$$a$eBvhHlAKMpjG9S zjcyJ-Amrz}abxi}%rg7TcGjoU$+N2tENz{AW6y&XYrOK~Op84Ssy4Padil*o49-*Z zF`8#^=83@>zXdvH#6O&Hrf9K0Qb$^bNGr`qe2bpn3LQ1iOw{--0BR5`E!3<>Pxxj7 zH5<@CLEmo^ggU<87HBK94f+n+4k77%PU2rAz98`>iLXd}O(IT`Z%F)y#D5tz*aSP& z>@vQWG7mt?%l+^>K#gQEQ6pv7zn5}2P$Lz}LQRID2I+)>n$sj@vqz1)i>UF#C*r;}UYJr;jn%4j2*|z-O=k3p5+Qxqa(h0o}jv7ZiCHE|5=-f_Fa}6;#x8O12%*pQtXHHTP9?&OHPpB8v8|nk~g+7J)kyMMM4@s&`(nloK zA*n7&^+>8u5-``0IrACf@hmjuKiK}Vw*PQ^hMDMQnW-cR z_L!OBB4%b`kmq0!dG7hohKM8_r7}0?Li0#cNYc_DGm8*>scprJ^>jc|jdY-56Z{dQ zC~ugPbRbnO;J+GS)^ivJ${J`bw2mYzNsUNq%u8YI{Wltz`Isa;&hy_VVE)^&$&8sD z&X5tc{8-y@ey#3MLR^E|FY8B{n8Dwo_u1*JPl4xE#dgD+KHJjd%R=kMy<>HPncY|) zj_LnlX0L8%nqjEf6}{yvQ~eJk%vpqCJL7)@`UN@)9fOWTC!mwiDd;qGhNKoGwIrz( zNv%n0LsDCk+L6?rqz)u?CW%_tjbKIb><>E9VAP0K<}MxiDER}OU41i*NXwnI&T;2LTItQh5w&B+(g2#v-h zjUj0)Pva&~Q;jJo@4r78njmRPdv zi@{qrzsIlZObrNR9|4?NFlqw&8K{|RpvHwSB@Y;i-XqK~I%jYPASTdslQVCbss@Zj zm>CGejwS#V{ebZh3i$yOp-IqWXbLnHng&fLX(mZukn|-pMx`VZJe2(oH(t_!c2x?W`zwiD@mGXkC`1|Jt|o)+hZt zoHO657vO33@p9Iu@W>V60rOg|U3(^ejnwN%X(zPu#roI*F|BmW`0JQi<>DR>Lm2pG z12f@hprRiT2}MECPz(gm9S{e_LkT3UA!#j1$YeADGC2WpyI&b&U^!mC>`B8HOHOvI|#31)E=UyP(ePC~r zP`5jaxfj?M`jjMhl04Jh%>)ia@FC`k^1UfB2FyO}^F6FRM?J0s8dW4Xo!yl(BaP`=|48u@QNlU84t zeZF+oXZLpzF;hA;TYIwkZ(Bm@%$o0nR^MPhaQ0zyGl8>p%mkR2dD}g{0AW@mjE+D|A+VI+l<6hTrXNl_$4GiKny?J%>!-pvGV z!RNqCj14n!$!_LS7G^RGGka~A*+){WJ!THNh?!#;Kf=-i^ zNYc6V#|%<{K%ANXcZ&AbF_UCFw>CpXGH-ZV70JLLgbCv?43uCf1j1zgm89QDI?qdC z>;oeV%v>M|DM%*343Y^QGYQU+(KPR#voVd^2wR0+^?ZG9t~W7r&g}E6vp&ADpWT}> zyIp0kPWcmF9Ik@b^f;KJ3)l~weI#S%l8%|nF7EN)5#}+%=$N^Q#x3YJbO*W%-GlB! z51@z8Ba*I?gzE{{NxDJO?}FnM zVJ4$66O_lqOi*5u?%QD|sDNvj2`Xl>1eG-BUJ%@UPzjQdit(#rgGxcANqS5Y?hsAq z+DuS+1g~UUaRsBUY2M>HaXbEqQB?UYUZ)aN9bsy67yu=x2J}Ak0ZC6udPdTpytEed zp@Es_B>j~cFcXAif-w`+&>1qq>J&e^abffK7oF_+xR;O<-zvkm`UQz*AIVvtxO>^# zk2%|7)6vJzvlX_!gl9{QnIIK0IQy_+CJ0x)Q38HxVrJrYfF1ihjY~~I%@L*(!Z2on zT0ku!6!e2yLv5h8P&=qS)B);9(rc3bCJ6~R?$`U5WDCjJNX|}j4w7?n7$0-PDKoG3F!3g96 zL0>^%lU#u0f+QDWM$Cd{>x_^Kll)GmV8jA*zae9AthKz?JI|a4Lz{3z+rj1+zk@yyxpf#WkVx>hJUhzSM(P_gYg_?fQPtY!C zH?#-Z3o%CaLkCDMMRIA9%aB}_jxOLBRVE0A1~ssQU-m>i#-u@cv?urfwQL zJ=Go$&StR$7sRG8X@avuIiQ?SE+{vY2g(cOgYrW-ebgrzYidZc8_5F6BFPfTGRX?b zDu?0IUkcI$7qur%FgtIMMzfKoQ8H=TWRWJLNE2MmBu(&pBwOuB6a2nwqzSHrL9UNM zZZntx?(f@5x6Hf+{uYL^`vi# zFfBO@fD(*;!Ofu-BsV7+|82=jVeNxk8<=TDa_h{1nP9k1#!PT$XUG_Mxj>$-@3)Ov zX4Ls@?e2&r0r@+I(*_N6ZBGM2tS>9%sx1f}i1)X59#K6oBG`@#^Ah|!upOHL(F|!l;$-vA&k_Tl9%pAZbGiH#0I69M|+8JTv z^NtS>H}Ab5(K5<>!YTN$+2@F}KE-F3-&$vPv-@k*5TBVHdiQdI8PxrQZFPSgGbeP+ z3^6hDme-tuJrE`so1$X|CH-J8$Q$y3d?7!`9}0j1p&*inkvyE_5hRZ!8Ppj~^5-Ov zA$csx;}|m`h?f#G5vklv3_b^D#@jG6G1<+0m4%rM!^~wHX0DJt!5%Z$UBnEZ)gE9F zblK8#Wny2+8j3Sf4)X_LJ~tEtSnZjt_eg_2pc{hJ@rY`yiumWJ>EQC45U9 z?$CV0z|dw%mo`jyI_VCIw0%!D*`4KpEa zFv#sOh&+Wu+CuF}UP|&ZZgzlRbm4FCy0&yK1cx962!V~)F%yD3AfyNM3CSx+UP(FG(%zeABDF~T>Fr0mG7#%bC zo+u1#a5V*35%uoDy(|hOfUI_U}7H2YyGh1w& z!LaSL=gf8&IkO9+yceUWb7nUhdr00z@@`DN5S{`1Nyd^x>CYMD03q=424|26g!}>> zC3!E&`$*o;oH-7iFgSC7hE%?z88da0cl|2{1 ziq`!z4!sINh0QI9LXTK8l8zc+4XF7Ak(gK^AzXVu>`;489p)T<^*X}nsQDF*-=Oml z>iQuUp-a$Z=n8Zdx<>Lbl8=*og5;AVpCb7*$!ADDOR_u39z4-*ARf$*O(C}p)RgaR zEDO1hpFoYL4K?13n!F7eHDOt($uQI)oiHrTYm&X}QS*;$s0oFu56z2F~Kz2Do+;S^=tP5DN!VXl5W*XmxBd?*XJBj>I~(F!y^2`I|M~(P93Oywhjm zC7WCa4y|eSspYKCJ0FDo(8#UrmLIAuyc&P1VZ0-;LO()`dgdNy&V<(0ITP;U9v9KG zDZ(&kLM2Fs6i9_M$O<)r8bcpLO-PO;If~?Hl5ssVmgG2+aV0Z>qCcQ6m`xFMFTav^CVwj&cL#VqH=eUsxN_ah)^E zbk5v#agVP>7#L@RGwaY;4{d-pLYtt?5KMRIR%jc9MCmrkcSycV@;#DK0(?O7Ly}Sa zdra~Z=FASnOUap?7R#W!7E2lUUS1x$2S34?KWv;noN?Hg#iaKX}(SUpTljP^j8CdpE_yUw?-=ur$6dH!$QM_VCK{ylv;k@^P zvv5@@;@dZy6v;Q75VInpemYeN=h|SFuSUA7?^N7%nY=@eI{%uJ_lxM*f8^f z?e-a^VHRdG3^S8#n3+t<`}UZb<|1ak#vsqeAnH^28#HE-Qj?TgJfjJkL&}Gw)K7oR zAO{G8k2f%bL?CPtw3rl-<|9(-FlLrQ%M8raB?U!_On@2W3_50zE;u4%T;KAAn)Pdc zX+h;(4`+<|zK)5RjbPuHD|@`NYkq@cydQPbY;T{Rrbc#pY(h zzGF9|G;om*KOqdKA2v4=hIehi&A7Q3<`BZ1Mi?D4Kcj)vCJdGQuwS5~&@t#ZbOJgF zogzgfMIuEeMIl8cMI*&ZN+VJllkzcR1|HlFGoGp3j4wV1W}4VA(=6G|bj-p`hG7QT zgq}2o#gNj}9y9SKW^%*U@HgNXKPlTqeB+JrUx$aB!p>u$FPZZ%3=Ti+A}P&DX~C$u z3|%3mB`NLGA2q)tIIO&Znwx0cf^L)2ij>x*v|-fnS@)iSnzp30%M_?V+MuHb8G|D> zMpd6xxKH&??)yp?yiwuChRP;to|}D;RXFx}??;a&$8R->J|N}@4tAT}(FtmhfrN3Y zl8hSUkU&iblM!!O%L>n7v4nF5Vna=ME*&+UTntkXVM-$mqb9r%R2YKE3oil{g^EGN zp%PF@s1zw(Na;#SH&VKj(u0&wNa;yRFH(Aw(uc!f!lpz`czIkZn`yE1s&6b0uZ*8S zOI;?N88 z+jhY=ydyfp!Ry2d?}SEY2s3*KDMLva24aPGgSs2U8cqrx82azcQFvc$G9RAELLBK6 zbbGVB>t_3&r*fS7xncK4uMJ{_e`fX>;H*!c_H#>IderItrRx&+9o%^27e``+561e2 z@vg#N=Hw}SsE(RZY3%gWd;D|sgm*SjGX{;Z&^Ty3Gy$3jO@byvQ=qA&d``+3QpS=p zj+F7FOdw? zPSNwOgg&dQg1`wV)lOd{4>`r2I(APEvj%Wfv*CN!dfnUJm1icr_psHxaVM z;(5Vh$^XAbqA-rNn!9ZvbG?LWd!00QYp1m_k!M(q9~rs?kQgbffg84xEO08zBo%hXgx!9Rk` zNIGitw|FY2(}P?nWn}U ze*{d8v-d+3&9g7{ybngCaE`=ug0+tbg~CXQBqfTJXkHotMH%sz z{uJNTvB08#I$z#WYL!Po^?#0<%tBJ3_xa6PpR3IW^*BAURp8- zB;pG1Dh#hqn#;PWiMNr)mzkC3t5YLTy^nZ;Fgj^a#*erS-GS~xaNH61p$E`I=n?do zltfZ+#yCgHucZ7&%6U>QkaCffOQc+8()@vVDM@*tk0vxH{RXcrd{xsl4f| zVoww4rhA(ECLiX$-9wd;8hSQ1!!Twd8|j#N=wg@_=-C-z7&DPAA(ZtaTSIN2wop5$ zJ=6i}2z4R_qBl12eB|nEBgg zXw*Den8`5A47Xus1SzlWF*Djl%)rh^!kQbHnS=(e1H2)HZ#s>f3QZ&BUsAKByP=8v z62al*^%d*K&eweGsJ7cw-}1dEk@FB{A%|fu&4<2)7Lb~q)EuPdj=>_-&I`>&!muo%Oj@djI~jhg+5V;pMm% z&u&@pl9|+QCUO(jx7FO^I%c*oX4JeUX5My>^UQ#4HZa5ccPE6pe&jA_H?#-Z3o$?T zLkCFBPig^D3zAxh)WW2`LuwIHi;`N5)Z+YWhY&9%W_~fM!QAS|y7!8O9lZ8)pJYEosl0U>7+Pg;9*fDC%}58jToIOOslLXA^99WIU;5 zNv)Lrb_O{>BwtL>0f9sy@;r2b)N-W0OKN$Zz?Y!Q1|TYsS}{`q;wCnk0fBVE5fFzK zv|jSgw{35(Ps($)c()d^35dI9AEXqHeQJ+clGG!rZLWnCJl`)7a|!QlZ~z3-k4Vl_ z^f7v*=a?$)(c!{*H>4}bG4VuLh(n1cRn`>w7sBv?Ys;DXYgbb|DV))$#zD|!c0bCCaS85nW$={*0sY-R1McK6ZH`WxgG|Q=Ux=- zeNyyfNokrD%aK39us*vt>CQ3qZ)wW_>VZdGWDrW;&u?t`88r1}0T5uR}DXJ;d z3~ElQNUB7t%uC_yqgolXQb<)Z1FfQvO)#yZIyobc7&j?Wi0C|S*`)L9$uGLOL93{) zW}j}(`kd&QJn}57_`>eKIEC18QkycTkV12ftKiiooynPSDYsDUS;l)`|pP}a{ zY>JK<)bpbTLW7{e&=6=SGz=OJjetgy+L+XjNo_)EQ&O9eit%YdYD-dEk=mLuGaB*U z`=6r5rNYc4dX=!I#xhdd zlgf9TMy-HWlG>5f?&s)!_AB|+)P(wN}LIlO*<2a`rBgRIcU)84PyQS zp`0|D)XzyB0~$nUgR&d68cQm^4&cAPBRCq#1k)-yzcca(Yiob}+4oIKFOlAq5C&Dk z9d&$pJi3tCr?9g=;U&xVZJyL(!;)gTpVdA0Io|M@I`@h$iWr=I*f0}aT*u4=3^miL z>t)ai`#cR=MVCXE>IlP_iGCL<522zTT@k7TRfeiSRiSDSGNwtSP9}8QiahzE+dyqeoki+wZnlRykP6SVAl>auG;)Aw_;?)< z(MSZMyF)!lokQweQs*%sdP2PnK+Grg+e`t7&#=i12&4;+)bFLj++& zmy!ybyqwe(q{1MtB6T&XYe-#7>N@5OOt>9q79w>9stT~*MK%=;pUs?EZ{y5HDs_Nz z;6VgZf6U@chH(b@gzjgew~)HQo-^OM$eEuoihD4MI%nYTqj!_KiPX)^nZ3|HQn8Zn z)1NaxBRGt_!I{Ho9D#lzbt|dcNd1mEa|}9eaArHHJ2C}l+_A~b8RQF&oH^5V;H}LY zJJi}!@M(Cl(p7&oIpb~i0U{jxSO?9ID!09D&xOMez1y<*P#pUXoI(B(&4~(+kEF{fgTkYZNJm3E35^C7};0%GG#%ttzBJTcU4i>Bs*Ekd9)@}?L! zg!vd@m@_c~Btod^$Hy$PW+ZN2))m0i*_!8boR^sUaMu3F4*T zOiT+SZ{n|4<>fIj+RT|y8)w2fZ_0+R-X`^27H2YwGciagbUzc*i_|bX&cyUJIg`6I zUb2b$CN83T=l#*rFLDz2@^^3n;=M1wVPq{e3o)*y4xS%aj(ksAX_{?W0q6@eKyG4p^M#7YY{Yw)Wu&jxPRqOlHI z4{d-pLdbbyHbYyWtq@%5c~WuP!bMUqk&4nHjLub3uaSD4)EkVO?T81g*c5{akn)b; znBDjcxcS|Nn_IR!g4I8=Xp>>IK}uoJ1{UC^J#9{#wE5pR;9`Vs|9`&)H^v)-?1x{` zXEE%33{E|_Nxj39+8@FR=q{=EnKbG8iins{1c#qDRvcy=K6t4lU)vsaKtFscTyt{x zq&{}gj!EJ$jHY-f0ZJtG0jVftKjNk5pkEDOJtp-@rU2FzY%-f8q#=&*=@|Ut)blyb z-&uOSVwtW!70qi`F*nRUzdP$Q{Md`(WjnO(dn}}Sp+iY8oP0NB%x$di9`7pbVjVNM z#~RnRpPHB%bpV*bK2HlXPY?#)*}%*nXgr0UL4QKep}(LP&`anQ^qSN^NqtW0U!=Yu z6;AvWsaW_osc%UAhcWX8@ls$WHk)y)p6#9FvAOU$F!Qg887&*%s;9q`Tq~HxnT+C0 zY;lt_u_Z{e*l{Mdv}>G+g|m;XVottT*!$SZq-7^92PR)^Rj3+iIZ4Z%?wpDJ0Kwts z^;yrQhgjUF?@L-PbJp*FidkQ;e_FFXwmy0a90o**Z2&cd+(^qqT3*uf@lv?^SV`xM zmY+0SkNNMfI>k1|CWAAvNJAVs)BU&W4PW*J=cKs-D|}b5CQ_;EMnPC>nuVGSLrt^|H8G?K_Na+>5jE#A z%9k*TI%+PUagj8MG?`Iz8M;E6LYkKTs6he{3p4*eOM~xOgQZc;S>M+ms44qhny7h* zF!1jNY968S7QD~O(@u?<`hjswTyP|c6S-x5~@Dhd^YibEx!k`Sy*3({JW){3;&q_rWfEotpY zYfoAS(mHaOGKiPL(!`ZFQl~f=ZeAW&89%|9PBu%^l~X6JKO^U}EY4&UXX0@AK({n; zI5Bj#<4jxwlQVG*aSIk^CjXo@(0=pXLo4d^K-!yOm2q{#sGK`TK9!-W0x@ddP=jl_Pj>VT^U` z4A(QM0Va0h_%*87_i0pY;>IG(4203KGY*aM&;$s+J8lv*8JYsYY{yN5rjs^^w85ke zA#EsW!$=!W+6dA{l7_(^&DfcVcqy?1tDSEpmhpLsu|xO??0jy+&RE-R!rF{1>SP#o zR@kVslC&}Q)LCOv=Pe7vahoxSaPtOkwxF?gcNjEt{M0EeXG|G3Zt|${EAf{ut^oE`4o-HtqI`fbY!3!3LYsumd7&_o1M3cU}~ z3P)SgxOkHh1IM+wwlB79jrSKHe}O)!cNKD$ICpc5IOmKzs~f@TCLb1F0v~GNE7Ct3 zI)2F1vBSnq=`d{Eh$$mehw(+v05gn^8Gju!{PI@5{`9tCP{fZ*L>L`2;b=rakx&#A z4aGpQ5Y`_T4<(THC23!g_BClp(`S)3n=~Zob4Z&@+C0Wg65^%A%z69kPjT?sjG6g1 z%q*~7f6`WGVJ5>c^T39ghopULkC`VfVg?rq;$E9`FAi4>;$D%qkhDdN894m7H>52l zZE3o@n)vJ%OMEVK#eD3<=hTm#CFZ0*_BoE72B*_HcH#@5C!B$9XyW1T<6+t2VX&8x zww$yTpjCVksHj0JV0l$$pjA9)4cP4Xvd+je`(T%u`Omi6vS7yH^DWB+G&X1zkIX{v zQ^8rE!wuW|FaE7#|9O|C27Y~8IC(#Ld}XY!8t*FXV#Z8-RUI?@?pDUk+wSq2=;?+q zjG6da5UTs}wV{t7*zWkcP(7$V)BtKo+B(wKleU4hjihZNZ8K?GNW%$j8)@Hh7y}C#TVJ4$66W`v%OgwVk9d?+B@9Y|8;(KC{`T>ed+FI;s+x5P+l>UU=TDIg023Ev|Xg_=B2}+;RYY}khV8d z@L?=AnfZWh!O@wx4-EJIy>_z}Ckoc@d1hHTyorIIR*Ii!_L=0Y&%7&T9=WY;^U1b~ zUgH-=F2d{6Q@fdXWFPUIrZ6Akk%r)DcWu9sXU5NDMv#U})DA>0nqzw^LlZv>0p^&I zbkbmTsLS%JTbVTR{8~`NO2Ze$FT}5|K^UDhi_lmMErFIo%b?}Z3J8f${3>WQX@^NW zLfS8+9VP7;X~#)BLE1^uPLXz+NwXI5Qj%t)#WJ)q_BGNkULL;{KS7!^Hqy9L`EHbR zA(v}{vQU#@sKLtVGjJ^kHeDi4hY3K}TUZe%2 zKWe-X+>ckxQ1OP?)u1lyO&X3QUo6c5I~@yhS1nm=zw#qQ&$P8u?-`S_v3 zTAF)!)X-sr2TiIoebmq?BL@_z;qVI+Qe}MIr;ML8Y(SB^|Hm)(7(cVcsL9;1`S@{D zCXF96X4oXg1~LU5H4)CRF`(q@2RA=!acsry52cWneoIW$Ae+$p#5n77f6?;Xi|%x| zv1LHZS?%)FM$N=xJOzbnl*u%QH!a-Dyo1n`oA-$_=|{h#f+na zMt_&57VK)An~3uSadgt$LIY)#_&d;D=pJ+*dH_9y9zl;u3neX#v~bcQNQ)#binM6b zVn~Z6jg#Z}KM*e^X`ZL@G_UYENE2@(O=7aAxtaxzUUK2D4`AAE!15H9f*Fcj{ z++s;6Wlp|?5@_IF2UJAPVe%!EhRTrkD{1G`J#|Vz0+3MIwqjgo;1l(4#)-O1cKi{e zsMJa)C+bvZ>4X{xQ;WlZObPEpA3!xpyFl7S(k}5*So?(9%q`L`lXfLDSfhl7*ko9v z1UF~w`D%LWq`yCJQ*O~;J-WXs%(X+0b;!4nu=|o(8TGS|Chkgkj7iw1iqgDD5Y-f!adtAh_;? z4p2v^6KOX{`<=9#q}?LzHfeWAyGzN$8EwftiOk%sfu6 z(EOc+nGC}W@(JC~B%o^l$R0DJUBnD*eZmxT?j^w6Crl>o32A>YW?AiQ?88!%WYpE*#I(3^@SB2fqIxW^X_98W*=K{ZK6kW#z3-N9 z`*?BfUcRS#bid?;G${KgY%_N{JDP;8I%(dRq)C{?sZ*M_F(vRWg>g1WvlESaN`OeXVcqoCag~?hX-BYK8-w^x~ubAg8t}!HBfG(2t9kLc7Yf)Z`D-8)(bU;{( zk+pcH0K_e9G6UkavxB|P;gvhRZZw_iImUPU%y=uz6IW>x?wNh=JL^+6`}J)FXSVX& zIMgff=sO+0Z~}-&i17#SDhvvzP6>FR!k4Ti(PS%<@C<;kmU6HnMJrWGP34#P?Z3@P zI%+`O24v;8xBg#|QiVy(Zm}d5LKrqRi8-L0P%bDpln2TS<%9A=1t83*a%6p%tmVmC zfvgqDT8XTc$y$Z1Rmob7!xTom6sSooX0a564=r2QSf0qX8>o5DhMF3b;|S&H&Zw!M zg_?{)O(KRwM@?dNvR1c4P2vZxp(YU{nb-iM$kRBn9#o&K?~|4998GKpxskOdS?i`d zY7!L$Z^SDGR1#GP-agSv)>>r!kgTiL#CB$%_Rjj`sG6hC=5?*}oNW6=Xo*|dvpb?Du@lzU)iy?* zbpvRv=W?Ez*b8C$nqinTiG6g=@atP$NS+c0qUYxbqjLt8{KUb~5NIeg3>prNfJQ}iGffM6in7mWbI7WE@bUW)^23&PSze|{e-MN$=ZuK6N-2#ITLALq)Cj$=ip3l z8)y33iZs??S(wQ%%v`Zy<|A*S#DH3`^)urfU91&Pe9G0`Ns%VCiN{GVDLaQ@p!|yl{+*PKtOLn9 zh^&LLG${v^)4-tW3OYkZt4&Yt*O}Jl=BD0ajeKKzwKp)6gx}Zu z6miz4?&WDYUQBCY-SAKUkk-YvZE?g*QgN)$R`zGiB$d=L!|!ip%oJ;d1PuE;jaqP0 zdGvfAo5Gk$LPbBRB2)>g3{`=uLe(H}BdIzBK8z&mD6+!Wd`{LeWF1S^abz7&)(K>t z$YEf@Q(`6wDO1Xuf|KgubA*{>!^{-hB`52wEX-sSW|A74m`VDWtds39lhn*L%p|qN zAa}qZGG>z6LG8&pm8{daiR%SPI1f!H>&$e=Oj36Q?`f`>s}4#000LQOV8uM?KdFjI zUnWnQlfEB%4&*Qll>X3X&;YW2LDnzH`V}u71PwMY^EFw&$rPBuU#KHvv@>KptXt`~ z@`>$cZ0p_g&_C@4BSGRiPtsVk&p2m&s{3{yxnNBb%h~f@Qxm`Mi#H^vzC@lh5ix9K ze;qTEbJKX+g1&~nfo4IoA%f;WbD?=;okLa_Z~S9ES-&Og z0msr)ChHQ$3_Q3UW)|DKnWW|T9GF>Z!_4wzH?t`VGZ}`Ntv1YTBkMAI%ngHtNcZAQ5>kL9*m#2v$ODp&LdVF8ENu;0 z*D@bYK)BL?3q{s-WL=*r_~406W*dTR!7F%b0xdHT(EE z>!WS_ZRl3NCe>CSYWmOSIft$~;RCXdq!4qAbRq}qMBZrf;Vr-TEh!3NIQ!r;ijJ8W z9W(s)R>sWRhB=2Y*AYg?%&%zt2BDCjbOE{uU4kw{SD>rVHL`9cE2ipqWZh2I9c2BU ztUr(ysqId({=}Gp2e-q_?Npe7&1TH(vSDUVGG>luVJ5>c^U8*q*JRyokC}g5!_2u{ z7R$N37(||X=W;{1(g@P*<7Pf6KUw#a^tS9BV}GuqL8~KV#a;RT{X1#SA(>!WovY!D zJSC^s>iW_2PU_A&rB9cdikHOeZsuG~vrjE&eSD79@ai$D`S9&>lkq>+FEQ4UR_8v# z`Z)WrVdh+29W(s$R>sW4?eLG-=V>HO=R|~QiZG0sa}p#&sOX4I%K~_()dU2R$h=&}@rgN?Alcsa+@EI`UZNrRja?%u$ zg_(@P%(>nsX3q5?tB)OK&h>K zt=qj_)t`QDRd-Eybo#0RAMNzhP;(ZCVW3QhW=r)$>knzg|UA*$AX#rHssVa2`1ONW{z<9W%Uct21YOGs56LV8P556t+U&K;J^!pzY8OXeYD_f{A%dE>Fni zDY-l&m*?d2f?R$l7nszSx0Olrf1UK?XFMLi3fpWUO#%uS&wu$E`V)Es z{RO>+-a+r7zsV(>Tq4K?6AV%05=}0cT8Jf=IC6<6mjouw2gFN48rMv=q;buL&q113 zR?_@wC5@0VoiwRM8rRPa(zq5Tm)AC=aV_Q?Xj*A@L}% ztJ$d2)KQ(A<3k%%b7?beSKUMJgOA3B+hfMH1!A=3Q-xE^m~qAQ{?{b%vaO7nPd(!u zQ4_XV$Bb(y6gop)psr9is5{gH>IwCNdXtcagsdcFBOyBpIY`J!LM{?=laPmmyugfW zU&Kp_nSsco7s3Fqw`_MEil3E8(3jVPjS&j)t#E&JXfv4pEZ?;tlp~=$ z2^C1FNCLo7nS?6LnM;V5lrz_o*_oU89KZghVP}M|675X=bj+k0W}a9v^OS_DwwQV0 zBxXF&$lgZZbM-{Qi-c+xb0%ysQ*6QagE0zGaryH*k9`_K3qRGx>wt^i$DKgVu=^s zhx}>OdE=tVW;82inp$U@gbwMLNiEE{)if~U zh6~bcgBiCv&SA!_F&bGg`kq@86wncxkfrQp1v>~A_Z-ujW>ujM_I}+Nb1zNcw zn_ybG^>##_4ljQ=^=DVJ`>xY%JM?=xVWWjsZvBip{Tm0DI~tfNEhA6GIseFPliO&7nT9YrX2zf}78(bQhcK}3HW8Wx zO@^jGQ%UGdLKhOclF*HW?j-aep(hEwNI*i>hcN>WZiAWG$uKh?p93>kADI6mp?@M~ zMyF#Y)iAThikY<}^s~jx1}8D|EgE@;(f8c8p|G8V0VE7$%w2{ zY4E}AGWZ~jvg1R643(at7Tkw*iqDNJ-!dX`-sFavERbf*ML7Ev>(#+zOu1XhW=qyP`O{$>=*@QmhJ->xm7;Rdd7Kr6u1c%JWg$%@=KKp+RJA9&78=qD6uD1#v z-q|3QdkLdXNk?_MuV1LilUgi09>2d+y9(>E#zyk#CigF}zjDSIXU@2n)j6}&$unLB zHR~V@I~w;dp{meVP&KGJR0FCB)q-k6VA*mKR*^ZF8B$~Y_xJ_GZoK6*@!vwT{>q{i!<)649>VCKiFi$8TWS1 zamKwXTCoROkvZeu4T7=VLc&%qV#2^3_VybRcBQzbafknRAIv*u6byg{LU2#tlCX`0 z?Ywme1gp=MW(NsaEakr+pm86ALuNpXb#$?pp7OF^z^T@SHq<;@^HA1a#>7HUQC?zy7MoPCHAJ%!s(p zMVJLf7@afob>~l5 z^#BP6NjOBpVG@2M;RthPBjP3H%vL;|T-Ib7&v!uP%y#?)XO3Dq^Ai<5N?#md&Rj_6 zOsa7P`GoFg+|g9WY&mn(NzR-?E1pFw>YRbMcRxeIaS~22XJFag&y#SHgi|T+XRaXl zb?c6=T1IH_tS-+tIWfBFej8!#aTo^E9q3mGnZ#)l@RywBt@okdEVw#H!ud3TD`o)W z>bWEIcnZ}vwjbT*(#q|J`d&WP8ZWVP2Il^UQRk(jI=wgcYP7Cit9$!))m-t1&#uu9 z{ERzda00?jt#igx=gdWeGoR`p0}v(}VRX&}qJSZN_h2Xl3WdU;a3}(bgrZ2eOu`is zu99$#gzF?=Fb=8TO%iUA@C$PWF5HGQ3AXc1?r-opICI;|nO_sX8IRgHWMIbQYe&fFc5C`x-@5HH>?(V{_1L?0W?C@gQO~GT-%*{qM{+dYbVIGT zK4+7xXC4j1x8o&Gn>-p}f1H0MVPh-!c z@Y#$RA1h}3c!?_^lI=`XI%iUiGefML8A^h$EoVkJ$(iwJ4*|N z_q2F)aP_IbYiQ;1E`S{%kbih^qN2CaIt!BVBrhZR1#bLb;x&uHSc}|_5cxYM%bYyE zMWh`@Bz80&+jZ1LBN8uZ{vv^wG++6#h{m=pEAan>i3^7QK zkPu5k90~CxB#`imgx4heNx~ZvFdq1pf8`kB;jUqo$4N`-lx3S`o5vaa1Z&<|S@Soi zP8rUEHDdO3)}$J1ZdzFb>-pZ6HFun3%|o>E6SShfCtRHzGEH=_TYucNz8y9^MhlbXyiS7Q4{{%f-FB2{Gk96Gm)5?#4LOb1VO<% zvc#+;W=j*ECJKkl$clD^p9#ae2X&~`^2SklK$l*_tdmzBaYmhZM|IW>+@Gmj)t0Mw zcX_z<(!35+9U$v9_V<@@#&yuVVbF*Ni4)+av@F<&UoU~WV?+CGu(rCyJtcCtVH7H z24}<~lyNF$#uLIMmP_YMYH`N1tic)2awHbE;f!ZR=Q!h84Xs!ct;n45tPa&6u_%ef zxQICe&)OswC$VITbH)=HfM+9P$IKbehB{|TIM?evCDhb742a?>LkgslSc=5bB!0nL z%}`SdXUdR>d6xfvMA@?q4jC7dCz23*n^UUt9Mi9D)nC8gwc}`>V$HB*4iC|Ib};I6 zbX2E8qd`vwYV#$ur&;HQ}5soau)` ze`o+S5E=vxhK4{xp<&Q)5-XAjOjIVZ3W;BmSe3-DNUTO;brNeZXK-V&;mlauAsWw# z_#6RhS~*kOIz%J7q+=%4Ff-qZnFS=)vc=3ICo!`Ujl2epsAC4+-g7mHxX0B&-}8iJ z_gqI}T@o9oc-C|?;P*}`G+SbD%?gok&%O6^Fsu56lcyJnt!y#l>m+7E(8%FvL>)7sD1?#N zhQzk$d!7+cB#G@v?2z(q204J|E9;Jt2w)^w#N)a=>`+?e>xZ&`!bq^^JB0bbVVFzr zp}(PjNbE>rClWhjs~0}?%3z^Y7ZSUs1zLF_n_yab<#0rv>)mR7SF}f~jtho<`N8kJ zd7p(=Ub&4rc^uW*JSFP8iQg(QyY?=sFu7%XkUg!u@?(FTepoT%^_h;D?l|L2tI{ez z68zDTV6S2bgG@%pj8}0KN9=U>bFN*t zqSF_xVmG+?3{`NQSs!xs>WP|tISd1(7t|X&J&U*uTe&w(T?hLx*t~I*~k{ObSTgi#c)+0YzlE;J9C4=sR* z#K|O1A#o~+(@307;tUdJk~oXR*(A>4FpCh6(PhYMnaMOT49^6ERJ_d#Hk&as*NU0> zRN^$1zp~Eb7qmz>qqnkXG%@@C};4DkJlv*!$dg`U4Sld zobg3GgE2Z+0&TMMB;H0PjDER@T8dW)@-vT@81sM=QVTQQT@B25cO&s<8_an3bP_WI(8z<)h&pBlqA-ZW(~)JUD}|5_0lsVDHHYGo8aQP^LgrA$ao(B*N2N;;nG@-ZL$jxlH1fG=Z4~ zIAq2QIYLJ6yd$19{$7pUP}e+W(*C0R4a_Vy>MU_or{$)Ieq~&=h~4?dAH7~++6D)h zS&sd2`jLp4l{#jw8JPLRhX}kkAk0pL(J`|Tg-sAf^u4!07|8ej2KpA-25pCSkchUu zLE=pkZ;^;0;oBtMA@Nrd?~-_rF#`{7gPFZZjnQP?aNpqV-uv+rn7MDo%md1tmx}i1 ztm$PsXHtzbr>vX-5q`7f%sD4Ha}})!GhyM(H59Is_>ja$%$XYy`o?1tpQb!#kOO$% zH+HPsnR~jOd1CbXaV?QGeeuP|vL^2*2=ju&Fj4rX{|tIgA|Cm{|M{Dsy?=-PuyE#g z68}gOoIy6BbH>{dGkUFDdhGs`76UJ2A5yJd2k%M-XZ(yh{*LM_D0U%3U>ozn1z)@? z89cq(5(k_K!g=8IBat&9I%iy+Jmb*_^A=%r&cvV)3&lb4Py+M{dJX*vy@CEB(VavO z5?6PPJ`^<$Xvsfn6(I1GT|QwypMVNO1h#3&M@c`KZ~Pdy7}Vo1dIQvdgZ zz&^+(7&AVCBV@$*W~{TIYdi1N-ES_JbNP+6V8%x_>L`xtG@o?tuPa&FKG-yT-npv(UW|DF;XHs-E zJs%_iJ}~kYKp+$FSqd#9DGNziNy^56SOKln0U>24DMy+B#0DHP17f42i@nanDyOct zZ+dC(_MeLX_~!Ci0}xw`I$Isp*;>4WXURQsuC?XmLmB2=(i{K+`G*fDDta3s5kZD2 z<+5a$PONXr3%vVq{*lNTOqPF5QXYddpSWnJ&k=+*U{c1 zsqmeTzi;Y`2)>z&F#I5}Z$=$6l?}{%;#b7^=0MFt2*a51%?ag#Fr@FB2g(cK^!Vn7 z3P7Jh;L4XIRVC>wlB$tZounEh)g-AFNwrD(n!~_^C&i3!G26K&U-)dsOdTs`>RIQS zBqbd)sf8KeuMEuiqSfl!V8*wmbC~h1k4A1}^gZ7OC^RIgK1sY_tZ!qe2}#%@rZ{GN zWdw(h*D>RZM8H>tG?E&T)R?3uz>IHGsF?*bE+h$Q0W-eH85lFZNEhspQLN^VndjeX zdUNxWoVN?)sny4V8Q+dZolcJGeBXX%R_FXt(Y8BQ>L zyK{mmNd_N$dm+J;WV-~jK!#4wPzzVT^+6-w{-`|2h@_JSRD+>WKN2Z+$$KUK{lb+Iq9g*(kpHoLe96} zw5j-n-?zk_zvKWl$Ub~Iwb0w>jK$IPvN)P~7(s=jDgWRT9L*Jkxo(8fIde_tOdo?Y z^WK422=tL4AKex zDLvm%l1AEcCc;V1z}5S{Ml0%l7}nnR6-lE>;w58!;n;oOkTjO0@ywax=AmPz3~Z|Z zRc!{&96xnR(-~8Sj+;Dk{J2jTy-9vs{M%&m!+tG0{>O6h;G5@pUi*hE`o&Y-`{Ngn zUsi<4$zcE{zid!;C{k$n3}@tr6vW;c4Sg%q z@VCus9Xu12WBP{kSVoW^pYbbV)G6wyj^EOVeLb$VJbG>U=&{X~X1{EYE58zmQQA1; z%o)E@I%lRCocSROID>Qk5zhF52YxjXhB@O`5vl}LhN?hcLRF!!plVQc2zk;Bl4g=L zi=^2kVFYk4N%Kg;*xv$@h{M!Eyd<3Qt7{nuwyqBB*ASnBGYhSpSax^&K@ z7H9mBPw1TSgAH9|!x_I;&T+;Mw%)Ic(fRz~?fu|hmXO3t#`?js`*kA;qq8egoHKsC z5xk$VW6lTs`s(?>a--LO;?o>{Lr`-Bhhd@&g@!@HNm@w~%-(9=3UBW>%EFm7B&|&o zoIyUJb7qnwW;7i%r&*27?cZIxSMbBc!MX4{hR&I(MxAMn>RfGJ=XL4UEl%%0J3Q~2 z7vDQr{L^nH&I2bPd`rLCc{P&`M|(w3?)i zByA#TGf7)W+DZ~U^S2~zBMEMK2Xh84+=eq7Evo}tpP%uA(PqxOf_)cgg^8^ngGOY95NdbBnw_3Yb`=L)ztz+`js*OL5@fcSBy!hrC5WU+o& znw+iQNLvku$D3XMRK&eu;AAO86NB`k0^bL6~ra(K+Lbf*<4$ z1wesN5EKlBK%r0=Nk>UKM$%6t9Vh7oN$6uglXQwC^sY0^8Mts8&cxu4Txc@Qz&H(W z_k+=9&R|U|{*R>d{B4xw^ncz==S*sG#y=y&1mhY0nMgWk!x{gq{1G^0LM#6(eC4_2 zzkA8j7ymqnk{`dyozFinggM9yB=M55{so}VNV-JQl@#|g{>TFSi(7Y$RDh>Z;P(0A zabk5~|1t=Jo~Yx>zbp#npz6l41%nYz%2BT_E zY%w#$Nz9B!BacHP>X;dW!dQ}?k;F^J`j3Y&%<+PxKT;kuNCN!%Zl&)SnE+!3-#pKl z=?a&Odo*6vzWcG8tN%QNS;%1+DD$BO5RvqfBv+E$c~{kBzdF>%pjf6F|*nc zGRka!Fsb&RO|P7YcoFn|+dh18m5!NpMxFJJ>bzWDXmYPZ=H;h0))TT$tv}HLW;WqG zaQ=~qnJqeIyl}=DGoSdfwm+Wa@jr+#I%Y5@M#)QNIbXI(~*Isfa|^7y)L6Z(AS`n!Ww z$o*rnKh8fAITNpQ<_(&fIrE9%&Eo&oWD3ZFFgj;2+vWcr!l1tYKhOt!h|dBtKpCM- z5T5gVOVT@%-jnn

    6ogVD_Cgje=?l17594^y1DnX`dm)kU^$L0oy}>VdKsG27gj|eBqC}!hqC%odqDCUV&AdqT zCeaSec*6-#j2Z8o&Y1Dei_d`>9|vaq5-<~)ftj?zjCV;3Gu{YveVs7lUDiF!cvnUz zS2M?+%^Sr6@2Z3+j*9^p(caY|gdTw;2B*3=<6RfV>p2dLK!ClOAh*34?o$I8~?Iw-Iey0mt;A2D#z&cJZ~q7L8Uzi7hCoB1VbE|A;a(Dnu_VTk7*FCT5=WCbhQzTX zj$ zTIIj9RmTsubf~edz%O%`yWj&~3l3A551a$`#wttXv1VI*=vM)5NU`iGxgp-`(2}E% z1k7wOFf+$ZGuvV25X=~u*@2Cn5HkASNaTAXk?*}1+6V224nPM0ucZOF-)%^93YGtOLc zaOMXRS2%O#XE!->9ld-Dy@;g3+LL|Dq9fH!9Nc)wsXd^0|UoU~ zD|;rKGH_+j>DfOG2JaK6JQxjMAY*w4>uG(Dhd(fW!M)%+`J?9Uf z(eETG_etFudoCQ0!w&~%?0EYmqNXhtX9gbvu5is$h??w$V5SVrFlX$Ap?4vq^zB8V zVo-6Y1XL0#1);LEjl}IF?jUg|iMvSLP2wIB_ma4e#Qk5u)_5pUt;t@|*`2Xh!RP;b z*OGW3!JGLigEFZ~nItZ-y#e~qu~fj`5F5zf<9p)}@L)$IVMi7pVaSP8cSGzgV7v`_ zo$qTqN(^?C80@V{#P{nF5|8rUwop6szCK1GW^w%YZiu}rPMPoPZm#apI}JCV`F4A& z;H{+_&-nDX+0mE_MRw$>z=+c+*h*?fLQ9_CZ!ki} zh61S&(*JfH!dd}4a{qQappwD<6NIDWzxx#aLgexz)VDSL1BMQ&zLB2_8zJudY-5Rde6mM>x-PvQ?w zzKDI2d%lQ$Cd_>Xv+Rr5XF;<`{E5V$d2<29~24@Z!oVn$unPV`+vv3T~9LL592!#MU^8fa)AS@QJBl&N~bRGLQ5by$z_AZIP zk@!1__elJM#QP-vN#X+%A2MgYgT2I@xsb#c;psZy%wG=9JWg;%UT0t?%`kJvff@AO zBWKLuOTe8+ZQ389lb@Jl&t`v&jlW66zfTx5h#>6GNPJ4-^HdLc>@Q)QBWM0{<$Qtt zwQ=t_o-g~B&%pD^>S6OiS;3%{Pd031hjNhkg2aDF{1>G1$pz&$Y4wuCSLuOPJ_T{g zAdgQWSL6w~S+~}eUt9nCMV&iwk9us&XVS{2h}EX3t2U*5Yt7Eqs`IdMKb06Wf4~tJ z85$piAwH$8E6$klDP>^hjfI)Fz2X(ok|+2xW_;jl_*8-_L&*R8RE4TR)gdev@Tm#a zBFRQlCXzCfl!c_MBxNHhJK=3_QcjX`v6(usmk2XH^*oH!O76MFew$At{H#n;ZVNL~ zUQVrK4um@+70cjET5-k)0fmvm^=VI19w*NDbaIa~K0VRPeb9^S&iM3#dXw}HN%?pa zKD$pplJb*OB-Py+p8+sFgb&OpK#{>`5Hy&i0wfhAsSxi)sljKM0SKuuNq9ule;+&f zNH}E%gzV~Of3J@^DrQg1i%a~jwfZ*hLsVioh3lhPZFE;{ignmOWPI;VH#Q&bS0Oa^ ze$(XcjE@~QI8bpQ*@qvlLsC%-5N|pE)+YpJIR0QW24{@r0#b1|%@E8?gc*Y~vDk=% zPzmrs0l;T8GzLQU-)9^&9-2T>Ns>yDRGOqRB$Xwp9N~q8QU#JKlJp*P22QvWXQr9U z1&ntRGRk(&TmY{r1ZO_T;7povW|@OC%So#2%$Zega%Ka1akDx2Y(5*Y zv5BOrBvoV1Y=O3tRGlQ_1~1oBA08_C*#o^jdkg-7dVqh|;i2}xfOa7Pg15h7_x?W@ zFP+0d@}A|tq1WFqL?#W=wLQ|<*H5N3NK?G9&A;4=d(w1KfIR*vze3T zXnYWV_;8?-z!_t?fb_lvh)*vfY${$jrLf88BFu37k-!;axqwv9O*27lp1_X;nuuF zQb&^Ty#N2+o$*BtgOTA2CqH>w_pA5c9EmK}YU#dTn@{`olm6>W%=mJhgWFVf)n@<2 z*_SGvZq<47@pp5mFGsXbju~IXAHE!@I56W|%W!A9xaWuX)`uC6KOC6xHI@rV-P|v!V7Yxk4gH3 zq)*ulobbe$@kOG2I8b&Fb${%)`67wVnCb7p%s?u+jT&ItHA!LyXVQ!_LmiwMM$!Oh z&Wv=EGb(z~3%!WJXY)n9z*i?}5J`i16D0#*J4r)G@=Sfs1i*L*ADD>}2n9jGBn>4A zf7Ni_8w%mMM9i5HB#lfLoFSYtGb7d&GxA0E`ljBv9?K?swQW@FMrpgnnNe1o(XQI; zE8Vn<(xOx7(x^HO7w6mdoeRz&{_y2MC4n<|FZf}S1Pc&vxt_>(I?NipjuCnqg+Y12YFm3UJ2Emu_MP zRRZ7B=tKiEC>QvCMN$w+!8}e-G4TDGq!5y#QXex2Cwv{t1$@t8<2-bMq)?K=NDAjM zdI>U@3rGxDzi0y79dd^t`@z|3z3W}+=V1TR3;RQ^CpQIqdOnBnk)&2VI;Je_-Zc2swSj(&4cEXgmm_1lD6<({%Txgk_K7r zZRvtED{#t88blz;^E{E4vX7q`-e$zM(lh$3Ei{fF!3qD*Z;jRF3s-Ggej6slp6sx6 zS&7-*{@U`%rR0v0-+I`<44wp!#&4s+nH_Fk@f|P&zuDx>PHZ5f@3$M;1MP+OLHnTt z&_U=BNxMkeP0}8ckm%n>(teWQiytHjAAQN3IShM=Idj}O5A639J_lzGJ2-PRArJg* z24>O>Gl(Wk%=}2w5ogT&;wENppp$Q#W6$P?Vu9Z+l8%vdoG}B3-R~|*CrHA4)6{lo z?!)*)^S~x%9vGP6d9Ky)P1Z9L<(~Ey?_c$M3OoO>9VW^%=sEO)Bm{t`Njk%OjpYLP z`HCdG1G+9r-|(MPxsN^2Z=}%1?kTi0d&(zCIjv8C-A@>rzf7`U^jAEE5ySmz2P>Wd z^3eQslKsN}EcLaAwpILjyN%sDz|XGhf*+XSpBbkN&iEq)NzR#0+R8@@Yjsq&-|ZEd zJ@!otlQaI=tu{GawVCj6RsEUYv>7q8(&^Sc`!{e=9{10U<8igm5jpwe<-hP}&boQY z{R_hm9A^VG{#Y;IkDR_gQu+SHpyE&os3cShDh-t(>3fpSk#wFU#Ksp%f^+!;Nf^FA zk@Pb_<6jQ;5`o4a|DU+v#lXKkN!Liak?NrF?*il9%>x^t@$Y7U<~l~b8xLjk z?+Y`ZvKbJ?zaR85^a)8fNdhu&^IrJ&{sVAtVsPIf>27-PXZ(lbl$kRlTruPBljU6} zp6>iOR>`|#Ud|FPEY1j48_`vp<)@!a{N+)npBHvK9$GrG^7-WcjK6~8aR8FQ8N3}B zocZ0&EA9s~SZHfv#vdC<>H8y-?;ivOLm^No6b6Mu$gcfC(tVQtBw@ zCh2dIo-k(Mg*#y;)|x+quTAW?`H#j=VCJaVc- zbLPw(H#vhUfj_lk~5_X&K$%kGiMID zV#c-IP3ZNtZbc4sT2i<2pxi4h&K$AY9Cg*E%y?y0T&cD%)_2)5H@3jx_g!%21dhi6 zNCIb0F=yl~7H8h}il2p!QR0f~1=&c|jF6N@tyK3iG%g6i9 zm{)xga$QMh`vp|O@i_c&U?u=B2L@)!xOv5E!%P#HVax>7fsoP6p(E0GLnR3W)4$<^2lobbf%Oh9uFWByD&9-44x0$SrIT2yyn zrY6sy$ugGRnMN6$Nh{6-^t3n=(2L|6PMito>mFwUP$vi&f?mYnvjw1F5HOhJS|r!z zP1FnmhLK!{3(?JLCiT zl8hUu9?A82FI@Wo3|NFsas!evIV~Mi+LTUfrp2qRdW@)uSDhr|OdO8K@kat@Mj4!GY;oo-r{M%lgc)9U zYj9=~HYP(;psCO_XgV|lnhDKH+Yd9}9OCxbI-#+eNc&TJ&Poik^)xXGE_=*@lT zMT0Xa7zFGkxdX`^nKP&v1RNl_6UjZ8GpV}lAm9j$pWp*C3XVd@pyMQWCbm@tv!iy?YV4(17}#V#cg^XH|ul*Ssu1oVVIsaMkAa)VguM zW^EO{ZA9T-LqmqSazqe+1aP2Y^br;gFp{x!3P`pEAm9L!-5ec!AR|ad+ ziZy{K92hB@zsUu}UX7X+3eSs+|kwR?vV;+kre+h}$5r zNZzJ({~YtPQs+|pnoqivC30?-`BH%^JcTB(je!|&%cptECEJ0W(Xt=R zFlGXg&=2eib%VM?J)oXYFQ_-v2kJ|*56SQ|{YdsFIe=vNBS9nwlN>^FD4Y2h_7Y(x z5SjbL6{kSKU74IGcAli3av zWda1(K5!Dru_VWl9M5~FKvPZ5j3Rk-y5I~4AIuB{4au2ty-2SgGZ*aIYII2FvN?V@ zzsBOse5=g@S8aX`ul4BfC0*OZEGkq@4f^b~3(g?xABfBQKh7*QI5XDWOTHR*w!)49 z8f5eXnG|cGb8C^4(U?{DeP1Z9Jn0x-jv z2|`9cCjC?1K_&1LnAzaK%qA{vXR&dPW^V>((uy-ds2mua393f&Mkme$)pU2mtc9M7S-quhX6A(K|-jyBz5!4x{%r}qA6#yQ+x|KS9yY1)G?-mJbHTrYwDdIuh ztu~lQpByTo-v5@a8Q1m8&)<`Zc;={pH$x=_L=XayAdXZx;9=h{sITGs?XdvymXDwb zLfSvbO8XmeQ_x_8GyB{$;|Vi%oQ=U5Wb}hXNP=WYfmBF?bjS)voH@hg8lUCpmb-}+)5H4bt0Z4?LDSI7Gx4hiXQpFg2FdV}&M;?CFbG1y z;A@i4rn)~9G#|znnFls+o`uHE^Nl&`Z9z*oDfw-(xT!$t9!dX%6|lt9@(p6G#KtNJ z-fP*P6sSPx6IyK`dnL4Pqe#Nlu>*H%fb6d)@8Ny%+V7U82|GQJtKk z3EE+`+3Bjy1&^K0Ki=8JbHmB}vvbuMfkad?Vj0m$(Kp~mEMm*x_F0yQ@rsJX=t3C?SzLJaek635ej__#@y3 z1?O?qrpe4*E#5ua`uopcdOZ5z?`JMv^A^l)Ik@0H3eImvnY>s7fbi~w{#K}L*_5;9 z!Nt(Jq-n-*X@W}_ocYUgX}miD?l6=>QY^SU%)oIrI1^j}8x;Ed|3O{LI)eia9|EjOv*FRe;d*z{g< zMeQa)W^###Xo zeAE>(hLG<+O8!>$MzxgZ7Kpma&uBor6U>u^*d;mXs!fC1*VOQS-Ez&`(DA7L?DuFF zm_hsz%z=vWRdB{|XOxPjI}?W|mBF2aTAZxA(>#MSX~vm17H2}>czoc*nUKux zaV8{}hb@GkRKjC81oeWDJfzeor2%iEWDtU{poXM0OLfkK6o&C)d|(hI zD&fxrXF@PxD0wdC(6pZIs}^V%yRl)GAyx8R-I$y+A&5UhI8b3ga3(mUhT+b9WCFsL z3$Mne&Wlq5M92qd$?=DSGa>a2&a`mTOjDR?4>Qb}kY*5a`XNZ=hai<7(h_O~wT9Y2 zZJ~Cgv?8T7DQ!q;OA0pIlhT2dj-+%Vr8Ap>6P}neAzhr^nUEg%9GvOm;7qp!cjnU! z%%l}&LIyi9GlZ0`&X^hQCT3722+_>3XA4oVp_0;_lpc&3R18AANI@L+aq45n55|M| zzzh_BC;$p1r57o^N$JCTF}o)Or3S`KUsC#|3(Qz6077D1AtQQRgAWRCYk7ap%!Z#w zwtg9EVI~fLCSxYvRhykLMY3+r-u1J!?~fRJWMBjyk&`ri8-nm7gyWP1%#1TI^NGm^ zkD-l$nG#r5|9?NOCuAzjaQKmc8NAO9QB!|6&CG?F(hpexErb?9iy^Ga z4Ot5DFj__mqTxZL3?>Bwb|@*sNEuGb2vSCp;>nnS6YhkWH6F$yr!0QPep|?T`~+rD zVd8&Ck$91lZ4m#jUj}E=j5B*3oY_Z;=*$@`26iVq6M`~9$SL$92A?ei^@5O-q{yTw zy!jP$niP=7C-pgV7RJx>fte`ZK?pEH&XJ;#qLbpqdoj5uS~iO_*Q_?zUA4KAYm`)>XO|CmO)%cMkTyO^Q zM+gThMjzca!zN!dY?23}zp)<7C*`myTq=bp_J!#Iix=7H;&HxE|# zaS6qK%(!{Vj!*gK3B@Fz(57q#UH?EOk9m8WkPzuRcKqB zGH?~z&J}t-+SdN&@k{L|Z@9DhW$oixu%3ytJfR(}Hl19xIn$zH`}nEt7cH)ucXR2Y zb;l&fRcKe(;P}JAnNTbngFiFL;*1?@R|(fV1ftfnTlqIAr<-M5P6FS`l1oGX>(gh&q;*=Q> z^IYBRTT6`d>U^lptu3?8XWrc+2x}Y+KrFP{U@l1V^i17>J%S##X|rK^sfMvNa@V@y z0uTs5LOD`lKyZ2{6qn*KDJv{M^!^QiC@Q812)>~?07>8sUj72kta8)LR+u>eGX`h2 zVPiXlq<-j52)X>w-OwIrFSHNZPs$onz93~SDeFjCPYOy68%fzj3W^L{__W}KJ8=fd z_QVUELOGER&TMsXX1im7lX55nGiipI3l7X&BxRd3W`1-NGbj^;-Z00WE%X{Tu9LEZ zl%0$jlng>|k+O@FJ*n@`{0`$ND*W%>`NOz(c3Xqqo}Is3`=)sBJcgNPY=*h?H}nL0 zO3GeR5L52wy>RVAUzoHyK+3`NK&vpEG1Dr{=88OX%1kX=JG$+H*$p048(p*cW0O{4 zS*$i$U9~y=>|Te}5Z02Ev!r~-o2?;K2)-xfhg5fG!aBluS3WRM5Y`Fm40Ry|8JhE?Tv*0n zz@F|<51@e*F!d6jMv9N@ed~w+{(n5%H;m{1Gax>8b+fOWRqOePm>wSMW}WXncwi=8 zLx6ZEtiRP}fU7oZ)}K=3;%&Q4oVaLxt#R+)aRCU#A7R7zQh^BU&V&s$ko+SyvE~%j zCSG%za=9r?L{knx5AUJh8#(pONyM zlozD@L(0FTyd>onDX&R+L#hXp2A;SRX)fb|^yRVtim~4ob`3u(lZwTY{12&_smMA~ z@$xuQ^JkDI%}DdWL7Io8W^yJCl4tIeoWf8m2z!NIG<+Hq4Z>cMnuXM?Od8Y;!Y~rD zk(wvfeVXtr9=7ltd|!Zt#BWOmoT#CYF==eHxYH9xEZl z+NcFU8`Pa(4M(4o zXTT<{U=xn&fsqdm?@4MIC)kAdaSt}(C=`SbMlTuz85M)@L8O)=wLA}G6b-_Ml3Ib( z_ZT**>ehsN!nkA}*l=sYMRse{isq=tOI9%Ii%d;%)O*2VqjL` zy>RWr{Y_?7CAC_*U>3(8%q+wW$(gmy$LsI7z)pi#PP&@+cxb;_7PF$PHi#{fw|O*m zVY9Q3TYfm>i~cV#&46Y?vq-H)YHd>MkXo12_ella>XBNX)CQzBWX^mBdx<$S-wdC0gwY0P*zrbp zHga&L35QQ*b}?t#W^g9WID_he$(aqLHg@LBW;Z#5LP7Xm^rFETR1CuRkoqC1O_?(& z8iemBwHc|cQ{SmM4CBZ7z>I<;&{60ZsUMNroYWS)7t?yePnv*eNouQf0f=vL$_$9J zu5R{hUqm#ynW^*s?crS>Wi8U8x&;V!EVvD(4J8M}A5A*lZ{MY5y$OXv*B!2L5|6=1 zI$tjw39Im*9DRhi1y80V42n2A6<9#H|RNa`n~eoAV8 z-iuj15j@^m0BHyrRhmA6M^_6f&&$N6&RjhL?grV8*K8y7V#m+J42H3 zp+NSJ8E}arrwAncBU)RQc%f4S*bU!eSPGVsnn5lH+nHdO^KO9YN|yQawo(NEJzyNR>%N)TffFv6;TGmxweGpE{E!Vh}zDX>@CLV&P&!hW+G0RNi)e6HBMigcJIAb?Q+iRH|U8=#HQ zCQ>6vjU+XS)M!#;NF`Fy({ZH6lRAo?3|Bbqc9dNu9=f;nqjo zH-R;s)EVglSR8vWd=N7vkEVv7ncB2PiB3g!1T?H)tvOzRZj{O+o?C4YS0rzfY1@W; zCnCG;TU0&1V)UMJn_U3wC64#TyyzxrUK^yD<#1@Ov1>FbnQN5fibo=MADJI!*rAC; z5g50RZ+-Rr-8Q+3I}cRCzg`}57*U)TSxu*rwWZdRM_uG&-zE`Kf0 z&W?|EXMY-1|4`@mlk*`G!AB%V7VOYO_BNrs-gIcn;Q9c{InKC%a#B7Z=^tq&{SC}S z4l*#a(Q;_Yv<7BiD20ksGowk}=ggULZgK`Cg2)-@MPm%3RuGAA`~##OK;wxJQ!bS z9@xk`L@qG$4vvYcZ&`7QWF8?KYT{}+Hda6&;}KGil6s6khGQRzDLWj09Vhify1>;Y zoHFAI5lC{^2God^M^km^_0b#x4q(D!VLUolQW00aRfpdKk^uK96AA=gib+UL8nQ@ zzh_AOn$&Md{g%|Tq<%;0_oSX9^*nRtYuHQd&U|NbrU<4CVZSZ%0)B!s7aZ=)CFV@F z1zd5uk-?cX;|%HsCTDJvdeNCPciiO6pXkNE(2E9V9$@1ksfd;^?bH^DazP}@1wWB` zIrTa79LE2392k)RM@~PRkyGSL{1J$p@CvhJ->wB}h9~)+j>_a=i^|590F|iBP!=dF zslSqXh19FO7oL3-=Ik(Pu91pL%YVNHJPJvBMokn#kmRVTwftcH{?|HwJmIsdp9e<; zmNQWkRmf^n*j1Z_+p^u*IH=XGdGE!9f3&26mK-%v$n{5I9uD`mftsk|25N4asIf)9 zy$g0#${oLDfmUP3j#|?~?i(sR(QD zk@^Rz_euSe)CWLKR881RgqoMVhGA7HOi|kouPs zX`tLW6u`V9UDDJ1zr9IX`=s zjpC}!!|`AIk*Q<5C+iO`Ue}`Nd@T7&T6Bs+_z}gi1%Devd6`f~%9vBZZbVK|$ofZF zS$`8V!3Jhto0x&Aw~CyiqF@Govxylb^rMi+k3t?lDi(@^;-OK{XlM*HmNXC2Y@}r( zEi-9ZNXtrieukEvv>c@6WXz0*y~LQA?3@aYnvTyala|ZEjF!id3f78cU?$Blv&4a! zrKII{#>{dzF@q98)CP2-F@)D)V?AkkNqdJ!^hRhCY57PinCcEq)OHx(eU1{Q*b;fzIp1!`hH`nol{Pi}&~j+bT5S+mByTfvQtMm8UvzD=uX)Gc zyS#4eqIMO9Tz}Lh^P-!iF&^Tn6}KFksNEn9E_(_&nkc04qwc~Cr-Gw?g|0wXp=;1} z=mvBXx&_^a?vPfJv{Iy%Canx5`El7lo= z5=iqw25HiaG^iUGp;I)zC@MRVCOWfwq>0YuVT;adjy+p6Y6a1GNUKU(HIOD6<$`En zraEaxq>-v`+>R~`;kf`5Izk{B00j-Gnky#_Z7a%w#|rv!|0snMsHo zjjVsPmGw6;6Ky=hQ>$lU=5428M>mBTxXlJ;qLI*#Mjk&JdHm=WP)n#4)Ea67wT0S| z)_}Bzq%|U~F=?R9W6RkFrT(x<4!*`Qc z%a);gPZX;>=SnqC7q~*!KYE6B#d)e;wDAy6t((P}x4q(X(Gq^M$r&W{qvt~lpoP#P zXfd<|S_<(nT1HwA(t48Ci?rUP^&zb_ zI5W_ZpV7n&%%mA+_Bt@LkF){Km^tVsW>6xCK4p$QTQq6~(I-h8L>eZX+M>ULPLl?f zd8T@PCi*OlpXUQJ3BH5)i~k&HLrEJ(+Hl@`0mA$qc4tPAHZooC;WAE{`G8qJ$@y@) z@Auw+_V2iE_kvkcww_O`SbVr-bDUy) z72G!68NqaCf)}8_6)Jz=E!-I-{iCg@^WBTXj_UtHd#*-7&u&6hMkn2CWCo)|MR z*`1@NnB4drnDKXDCNLptipjuCT45#z)0PZxCZ+^w0Zy2SDeWF+V%|e1S3xK85RRz? zp*Mp_3+7Ff3u3B~7D8HBs(UjrwPE~y^T38T6I0jlWETFrw3Zaw8bfdRx#~dk>{I&qfXo!(EiwB zFaM)cAMNq8#y4t`@jPVFh zjoiHA{a|Jo%rItRK8BFck3k+kray#9Ixz#GLC|1m2!t<=IMU)t8%5e^(#DWBmb7uC zjVEmaX%pEDd~hes2uU!b;BySjNe;|RNx;m!49uh%W-x8Z#0&^9*%>q8Zek`DojeMi zXkaD|8yF5#Nt?!)LAf9XgJL>qb5h-#iJ1uFQ~AJ5f=SS1XbNdFNSjI8EZ&RhJTa&< zus1WCw9nE7ALinenGf?^-RtLXecYkZU)|oB*6e=YbFG5fTYOk(wOQn<&BQ;xet6lp zWyx794@LWYnfts8J|Oyt;V^~yz>mC&F`nS5&9(UOmP;UG_I*a?)0iwvtZ^ zKDZNRkkwB-9XRF$J_lx2IWV&(A!yp3ftfVJ3}!8vn7K&WYG=&+XkjMLA08ehH{;py z_*wir%6y)3Was~8rT-Y+NVp3)0pyYEUzXxkcJK(l(~PNAo+3 z-*+7No*508^IUB)f8q~;uf4%VG*F=G#U%O7n7?7^Ia^{pJ%OG=&qzbDY%^(FcrSeW zn14)YZ6$46dVm($aLRxdWpV|eBfIw9h<~Tk!!b4cMm;+m_rio0WwqL5bJeEw>@$;> z&F?y6=kX@reg4UodC8$gIdQx^=0!K08bYcXwAo?O1{aIdn4v=<`v_qtQ3EEH@*h`e6p$g7U z4Izonv^ngc&Cvv>=GzR~q!n!l6PFCy5Hk5koM=OhE!uc+OrM~b9@aleNkb?TP;2}u zJ2li2YDL;H(vI_H8whFO6Qq5e>P`)Hg7I#AV32@1LtUV*q#;Fw(f$?h?GC}&XQu|4 zqBH4&4m+&=4Rzcy3H?YUjGZ}DSCEItgd+6;8n=GMcZUAqRg@tONP zZ_xB6#aFrD0|F4@=)&lup(d2SF;g_Xe>0$rhmxmQaUuz3unsrDsUgL{%vlpN9&ecm zCLfrA>uh4i7aPdwlRp#y1wuhkFcboXLSdwRPa3js=SjOj8onXXp+AuJBWXX8_A_H9 z0`?MPCdR`f`*9DC-0VUkx~F*j1ZIA5VCGlK6iAr^x#IL&24~WYGl(cm&LGmb?97?j zZgK`?0$PGzG{!LM1q2WG3TaoFGjQ4oe(p8W?xa3vR>AmMJ}?tyHM9nTF9nb425C2W zFQ)VmynW^j9IM;uf-~E2%FLPVu9)Fb>iydj!&+6D)Bj*5pZ4WOTb$Wtwb|{eO})`y zpRPB)QX@8RT zfV79C{YBa%(jJrcH)&6pGe5yzV$LAZp7`|#bRD0AGfy3ydG2s$^voHUNi)nmbYKSk z^~@PFf4hkplnLlHI?))yFR}58v=^lP!AWAU?#R8P8pbqE#wLr2MdfU|H;JG`!*h&S)|dz zT3t=d#1^sI6m`|6-s;_5Lu$2te_KeS-qTusHX%7?ViA7Ca-70_6kF23jGoEF%=u6Q zGfmf}jG5SqXwBgV%ov!7t;Cqovsjop9}3LCPzsodtqC)YV1{!vv9+MuP#vf)^gi?f zR1c~THGmqDo{jYEq~{<#C+WFJ&rNzB(({u34(a*W44m-9n2BxX;ZgJ+_BS{7+hSYd zXJyj!TbR)cQntsWmw`K@m(AczT5%?}yTzH<9;6p=;!JFB_c#;VAH6vUy=aVK6bxbq zl3s}P!aSr=Gl(5R`n#l;OnuIbgmH-v%tY~o1V|*k2}kD}!5LdD0uJP|bUfiV86XPms8b-*z9i|a*fCg;lCNvA0O?m~= zE0X>m>6J(aHL8$amGo+)S0}v&(`F9rC30$F7dU5xW0&A_w5#c$O>IX;SZ|U6n>2$B z77Q4%Q|w04YdOPai<_|7jZWT&PBaEG$_24|Nv}hCU53qm=m6>OlU|Quld6vjjy(e7 z2*b?-A2siw56o}so`;M(sK^NycTm!M=M2o8Wiw2tuOYbhvEPzjpY#T#H{`wW>tnw+ znbnB&#_57t9DFdd5Huv`&w!81^o?H9J$}oJnh)CEpMZ?5!K}+x8w3`~+w9t2_Hbmr zj;-bn%v^Qrsnt(hFblc<*qeN*98S#*12Z35PEAjqQGjcn5@vpfnI|w~V1_-9KcM^2 zpU?y7A@mpY2zm_tO?orZKO((3=`BcaNqQ^NTa(^~^tPn8W6V5-y~LP7=00)ZDVE)C zV5YqTGaVB!(79X@ zIFt+GN|D}$^lqt+nYi*W&LfKlJr`}`DuOYjceMunJ+6PWu9MQBkE@QBwb=}S5?2F) zYadsO^zNj?;p@qJ>p*o)%=99?cY44~90wo3OdNuSwiEZwTdR#?%s|3c62z8xICmOT^3%v`I@ zJXdYBGP%nazR-5Z=f|!TICBG{(m!qqUn*Q;12e|+J9Te2ulP!s!Nds@Gsx%1 zA&no0G=3cOVlA`|S`Tf2HbR?7_aWVvbU)JlNe>`Bkn|wZG15Xv59Ma?!JRO(BMD~q z;B#Om%z>GR1k8-dz)YH924w>iGYF=`oiTI9P0XM|5O>iWd$u@~3gRx19!Yu>V+PfN zxF1N5CY@3rGnZlfs(D}&Ggl1E#8`v=Ez7KNw_)aYHp4)<1KovwBR!V%IMU;JFC6>0 zKTOPwA{|wr|Nap)agTAzj2R^ElVj#oy-UmG&>nC0eCfStZNb8tg_&noo9C|D47m&8q`!%oS4Pk@*1anppT)x#pAVoke;>VEAHB%Q znfMQ&dZd3w`W)UwxgfqF>2pb6%$!Npic@@37;nJ`1`6VvK_5W~-{+A&pY#RG7!26c z3Th2BkiL-gMSL15zAf^t-#hvL@mk6FjyPoiBEFNWoBdC@#^o%}x(%IFV%^As&B`t} z0TIu43%9|1q2y56TE5!eYkzd{Sh4d-$HQ@A6|d)y5tq_zjnY zq4~?Y{GCqTL5jaJLKpm9S<#1w+5-dHg#-xR{x}c(PQ~O_M*7)xy-&dK0HL;B6#az& zSC;$}{g$qH<9uBINv#3{WV;^@l>Fn7_;cFZbx*}xa&@(W{f7H=g=K%_F&(cMjE{GK z24Bz{ok26!P0&n1Cr^iI12iZX#N%sbGwE9xG^iNF&m?^->DyD?p^2Xh;|t6K8xBqU zeB-C@jGFI1CRvH>^3;F&&?}-2xd;hjDZ>C)#49BN1&t7G3YpS0y+tug1#ahwS8DBmf9#!goE2sJ|M$>HcSxfk z4bq6Rbcd8kHv&6-Kxr;uySqzC>F$tHkw%eHloq9t5QN|7nwhiDp562PE$8*xeYt<^ zqo3zEbGWa2nERghTyf8wqkR3MWU%NVxg8_76PeGMr!fAHtz*OjT(32kxqdbbe~HOd zSBdl4KmIOAT_ z5i?GnsoJ^3$L-f92bbKrCE(&QgEQ_W%r+$*wfSj4rJHYU>1ti}tb4Aik<-3T?-#k3 zL4O>9*f`^kw|>E&Icsv}vtb}R&UpsaCif~ZQwL_4GwxNPYEX5k22>LQ7~J25YC*Lj z)UOeKpC`8q-+QXaTekS_HX69^{6*)gy94dHZj2dqQqc$?X}rJtwz+$n6Dl241)wXZ-BLCiftG z56--_apsjRY!V9QU?$5jlVHP4BDwu*j~Sjb@?wn2t<;+Te?8#jz5;{13V&3`439Ws z=GP>+FlJCQa9=}$g@oLh?#{SxgmF|AjE)frz?~7yWv+?v%Hht`fBpvU3>M|P?_)E} zrQOgTXfFwQNXSb8(CQTW5;TWAc03os1$^0SBZqmBvj$O zWubBgAF7go7ytkF;f_ZY95VReQPt74KJ%G>LWB1^Z>81WB>qtNwfU+mj~Zs1nvU9Z z>Hm%BxwrexsE+fB&zoBf4+ErqzR3gOhX=4fx>1n>#%k!3>8VHq3b7 z?VrHRJ0@n{&?)k01v4FChB4#O8fpU}sqcYYz6Wyo9v?yNAXlh8)PV#bqBaTdkx++( zx+K&ip*{%>NN7kxBQ^scJT+!Ky4kPM^Wa1}Y&5oE=6%~5J>kO~%w!d2JcgQ>@fb!z z6MM{zbP_WYFvy=7bI;;|YJtZj5}K0Gj4^|PfyWdQnv>8n)4drF3C2~UV?7e^z`Nx3 zlhDGP^i^DOZ!PdcM)y_^tjYJ7&1RTOSncC66PiUrD-v3h(1!QIvG{#r-Q{^;-upXpyFTFGV?q+x!`p1*itF!1<}guWyU%6xC;7>u9dj+q3{>In8_;4c$PIW<5`Y` z33izAtmqtOJgZ}n-@zdA6!xqE)g%E9&1bxcdVwbfcQOf6Gu@lE(e7W;U%fLfB^MuI?s$a~?~d$uuX zC6OR!2U>ZyHxIvqBl0{QaJOy0+kHl?n%;cm!HLzb8?^H5Y_{p*s7=k66Ji#w=vpac z!ms59j*qUIo>rdSaUMAOuwlltr;Zub#LOE$*yPzCW=6maW5#m;G!Q~U-*Yg8Jig}; z=u>DYGz0<)o4WG{NT!xk$exz__h0Ym2C(W#bnVm4Bb7nm@HbBVedv1a@LtCJ&&^Bm0 zw1b2I5&}sGA|aTB5E4R32qPh!ga{HMnKN+0?Krc~MPE8o39mTAev9Wpe1bDkHqONG z(wPEHnKMgrIFn_ZIc?+284{xHIdj%Y&isN={0*b1a|YD{&&wplk`Tw7LBYWD3JLKf z=xc#9^+9dVn=pRc=-9Y;{?IR;1Se*M(ldPD+J0?8zN$$R12dpzSw>Gu9IJvY z;CpapgN-wrQnEAqaxjxsnDJ_CV#ccp2^;M&* z0c;6O@#+VC4D}~rCkeYq*v)(4*?SE#NVA88z1e{@Uc+(7e3c>uN$(h4_4%Md+gn{{ zuX{hF`4%t#KTXn%HrtGG)aHBdEhB0d>UHm{{3XiPdhicc8l@x6c=U($JO3liM4dF> zWN^~co^b(Y;5Qqj5wRgbGNeE%q(N3_8Z;e3v~+-kgCrpLcbJ54NkG;Q<9mdJA4oXL zq`|WjcBGk;hBSolL7HPW(ws;k&4nD&WEp7?P3R9ddBGJuZcmy}CrN`EfmggS_bgs0 z7I?*xaFT>mOd2@sUWp`}CgEJB2Top#VSG7v%p_O>Erphm03Yo~5`N;nD& zO=!sCg)Dn1%u2Vf^nDgDWY8HiH*J{tgYteyRkm^9^f-qzS;m<=HqP87;g&sT9yrMv z6bZauU=%rU@_G*aL&9wm{^U&*47~m&;V%;IX1Yh?oy*1Io!9KxJGYStMgfGEgpAmS zzrnrWl(6n7r|Luy+xtC<*sSxKF|Z-V4Xx8|(EMR}V>elpS#8T^@%F zTzMk`N$<{lTIWL52ursggCB2iQ+f2kLk6zAE17L7J8I(>k>}#HV!fKJtd+dC2c*<4gJ;RQ-xE^obkpA90X2(o1A&W-^}u^gO>1{bQwUL@wS!;CjFXU;6r^G1=t`%`1?S-ep#@E$^99uo5cGu|i|cn>2n zABhDrA2Xw2e4MRg1OiwKEFxjRn3)bI8JMXqy#Zz>!;HXY7${SqsgN6q1xb91#6rAR zgd`m^Vqp@CWDCqp$00LjK6iwSdb>aVsaXB?%NGw@H1py=wGw2wmIpj&Ch#R_x0P`^>o;8>wKQw zJcPG2q|K^$BmD5@IE6hqE{Uv zBg|ZfnfoxKW99}nkkI$O1^ofthW>>9g6=?fp?f6OBe6b-4M=QAVj~h8lh}krAg(Ei z%@{NA!R;{fcN)w*$M?WYa~oz_reLN+4ra0nGd}rE%=i=_v4tIGd-8K06a7N0W4 z+_U(gR^WsCO)C;xV@CU+T;PMdP8$;2X1X`yQwhea+B!xYz~0OU#`>)4s@_4ujqE)M{1Bpp{PxvrS7!ZF*no`?7~ehgORcwpOb;;}^W5JT0w!+Mqv< zK5Urr!Ln#v>K#qY3_A|Y;GAcG8J~_Y(+6f4Gd`UlB=mi{KwY73PyOY?1#GWL=6~|Y7*bIE|)R^%ZV2>G}Pw+i3)7OTXk5e!+JO?vbhM5UA z%uFP)pFL(KJBb+?gRB{I&*Fn(fsaaJe-Z~UW>7EinMUG35(j5KW@f_p9HV1BvFS4# zj3IH5Iq6qE!lZ9JBEw0)5N3EODLX|ziy(K%gTzlrMELh9?}cOU<85GOD2Z?vvH@mz z=|5v8*by>b#k-cfHm2jJ%hZu)PgU-`&%{ia*(Tgko5@S&4sQQ*_tx8<2Lv3u*afe^ zN{5*!^vBUh3TE(YmB7phC(n2?%&dYL9Wy*l_#7jn@3RC#BHw2jv>aLiF+*08IEuv4 zB#t3*EQ#Yt98cl|5;1uvk@y+^5%}PCm|1V1oAKF9t1dTo&fj?;|JvW@n0)xd zY=fmj>GQqGH$8tpd$3Q?_5-J*yA?W9+yNgDefV&g!ampzyqlX>a#JNUj7e^25u1G@kNcmw-H8>=df=B2;nol0Z-mUy}%biv=@oK zneNW`wt#U|6pW4$2yoQotzSGA-!}M5OeWFCLDW>DWZ^StRRl60JMeXdrA}-KZ1Qan zb$~jO=trVIi2=M9j=e80)km5qki?+uKrG+hIAjpZ7ZFH$`fOXXw{q!~ooX&CyzQI7 zzB|pp$@gQkO@Bvi7XS3&kN5L-Ew-r2#_oH1-EmMH_Z@`(hVZEZTe#Zf`-zU45Cb(h z@$eyW+A|28d`F@s{AL3+qp*R5zV8@lEHn-p4^4n3LX)7+NDLz}oWuwcBT0-RF`C2} z5@Sh>BQc&)GX?fiRhxW8`@qRp#rHr>g3Y5zN(r1+=8z`KNHgC?8r%^Q?Mbu9Nz$N1 z;2VHJ)JcO{fiEu3WD>t*(gZ?5Bz{HWicI%te8XWpnmc9^L_m=crr=@{myo!W_r^f* z^qCLKNL-#R_<(Ct=fhWyuJySkXWl8;t9Q*kQ|eaxX|VS-!=v$CYPMPCsLg;K2REGF z+3TZCwZ=~^vA-p!j?QZREU2QyiQ8AKEM8a?03ByP9I z%oQgwgA#%7U&h?C`0_38PZD>Mh?m7$eBrSB-X(E2iF-5Op?L)3PmGTB{ERPNWsCgG z9w#R~*7x|qia{$p8SMKC!jg=AB*H`54_f)bvG>bm(CPq*SeW+T=V$y1;*jCZ_#pyG z@6B9ourgOn?(Ua%_iA&@qO{3l(8`aUIBo++E`6J77iuqP_OkO^A;Mn+Tr2c?lAcz6 zCD67spDLVU_GbJ_>6kg}+!^<)h?a1hbwstKV|_#KJx zl#Y=21BpjTJVxSi5>JqbDE$;Le}aL{2HP^VCJ+9Ge4%}XD;VpCaW;x z*Ve?0A8IOR>@ef!>KtbLP$KZ_Vaz>?UpH)YC-El|&jK@kC>QvlBmigPmrVC&{62>9 zLEJHupg%MKLdN+ViRVeYz)FIa~}(>n&(m9vU`$R z`yH6mt-8sFv1S`A6-v*CUM~NPuK&_?eALn}1F96uo!0>$5PkS@n8MzS-z3AEK|z|m znJTUr@5%g%o(xwr`blWb(MJkq@U9=EfqyeG^M>#G@%sX17QzhYXZ&VBGoe|~Y-kQN z7n%pnhX`6g;uR9Fl6Z~8>m=SF@g|A4Nc@Au+a&(UX5fRT_GbLN?7bO3zLNkmf7vi| zH^rNIo`abz!wjDN)x8-%gtvF>F_YjVW|m-(mm71>;)hy+AHtJ+B;r-E7C)2={IELb z0f|pDA2VxVd?RDS?FboH zR`l6E{kP8l1dN)!?!EKBzi(n@pV{UcM{VZk9<#sk^GiOBFQv-AIF(+xWf~N%>67 zNCj+|kxJ!YCd)AM%!ZlggdZI_avFmGPgI}e)RE#9lVg7r} z`13Qxe57wXLPp*(Q=h8UdmWCMT<>|6gd_b7%=lL^+hD0sdT%Cgp`~-JA9oOzSLi+d zU1{{B^qBFlf&Ms5v0=vl9mb4Q(&WQrWXq}Yp^S33{`FvnqYoQq{2MT4q|#2BX$CXx zV1_Z{-yA|d-@hf)3Th3tfj)rRLLWjOkyMtXawL@}sRBtANqU>4N+eY#sR~I|*^Ddf zrNWGVCwt8Jcf#E>CopSy+=|VlIk+8;Mn`mG-y?ir25%{R=n_^X|=!+dCL6qeXyHL->}FT zL9IvJ8-m<7FDUkRH`{nPYSTN;!~I6V?#cc=lcvn=uT6JAD{t7~=pzL)zB*nJmN1CL3lplk|Z-X0|zr8I%b8_ZxH1;*VN^ z|2HIkND^KZYwN%J%OG=&!FefKP2@asV7OjNa{^eACmf# z)Q_Z(N$OA10LBb_@YI+Iz-B)z+$jCGzTXm%2cN*qKpSQTQ`uFNuQb-qNMmw1lU1Av zC~0ygpcF}i>^Kup);Z1uphgf-4Wr2JOaO`n0aZzYlZ1E0S^`in2&h5QrzDNa^r$JI zHjLNfj)8)J_noL-ycg?w0vZ^A7(o(VsQuqZO##ht$N)q@b4M5Z(0hNo zkGt3L-uxM7|MVLY+sgn%Kr6EimI|ehn)X-RaBcDMzD*;&&hK{}uzpB-Km;KC2;ewH zA0s?7fMrI~XamXpeRL$3>zOf<13JSDhaWc11a#FoGuGrxe-6H2Cr3mA*o&C20SmT^Y5aYi9YvgeG|NzR~15HQ!6e3k%I z3j*el1gm&itR(;igMj%YX(Y|ae9pMTxHosqMDc(;Aup1wBuyh}I`8#?d=1VZ5c(op za3%zY%$x~z#EfwbXTN&hu+xhz5?w#KwH$s?ljEI$2(wM3qc(@O*Uqmzb^Sbk?U1>R zzWzPb0cQ|@1aP3Da|TO^m@_jC&P+BqgWODpwI*Jy7{KvI3TKw+oSAKM<_(iP0jpqU zE6nJeS&fY~&{_zY`~YO~12#Y#p-s?cXbVYmNt#Cz<`R*#fTV>aEh5RCBoC7C3QrVklvknG@wt^U$1(t-R@iS zs`u0PaOtOwcLET91aP3jeBfGBz(0B-E6m`7CE#E9AyRlcKcqzAgJ~kCz+5htz`Uj< zUOW?sRXK>9A~Ud*)=VL^gx{=_Ca^FzkkJoBB0mskCa^eE0xAiWf=WYWNQx#YhNM`M zkgSO(DS@O!l9EVDCh1F%Ca@gry^|tKAhPVKNfTHV-+?q=*+{b_g*5AONRw5h2}CrZ zSG5BhlC;>4G=WW=BTXP`1c4u55ScWAt)Vs~EhT9gZ^B^@M6zZ%NndArf+ny7jCVFV z)-RvHPWt7u!o0n{;iEQzJz=IVn*o{vdqKS++FxxPE1@ zTnRttnHE@qqtPGM@1!_1fn#;dtatK^Plg$|%?4(sU}Gxe1__V|NstUFkP5*e-bm6W zl8{b>bF-DCZ6s|cX$MI=N!rDjnFf2QF*73#X6E2~U}m=sGka4ob0h~dS%w(|69#7d zNZMnMnLsBogBn3#v@!QAfhZOPMv=6SB)lrt5(s}i5O*LHP!DE4W|Cn1D_h6OMlf)| z2nPD?!(ZafeorNE1c4^o_!zw;V+h7XkuoE*=DDsHg~qREc0c{9!D3(=X>$^QmGaWFtZ2! zeZ!{;T+zK5JOd7I<_8;Q-t38kz;9uO*HLiX6!;y4jDFw|=m+R1bPPHUoq$e4r${o2N-SL(-2VAz^=(&9KLm8Z$qq!OTT`56t{*!_0*g%-qPqOqO8=!GwXC z+a#T{$IP8nm?^~kK=2XxV18f9Jq`aSou7ZCc*nGEFlq#W&+tcej|Rnpz^5c3e7eM_ zLA@aGACi6{>1w9OPJypoEJ3-sW6&VT1+qZ7NJ6l7nWW!%FV^z}!P93~CnhZa0WL1hdo!_C2RU`tSWoyyX62Pv8o14^YC?I7g(gHXyzp-oUV zoi;ZO+Q1q|Vb{||VQI}EjUV(r%rI?&kj4)}8b7EmR1c~THGmpIjiAO*6O#TQ2{ZOj zlKvv;4oP=Ox<}G|k{*!skj*rOy;_h#97|A3d)frC+YQ=00$TWqZRu|tZDf}m+GG`N zg1Vcu3F<-8V>{Xe^-e__kcMdk&F^deb0qDgL4_db6Z{c<7Nb-UG?=6(Bt7L>JOo0; z=^06{GMzL*BVl|jcg#!~1;Mos8bi`^l0df?ymuTl-XP6OlJGkr|9#OZXethwN#o{- z8lIIGwQc{sYnSa?AA|>l7Jq7zMl#zVho7D_q0httORje~wCJ_#^UCMe-giJ64gF0w z#z+q{gZQlwB)vAhkwiRoK=q$z$OokQgXWoL*r^Gc%b1ZZPMSd$KM1!512f3t2O*0e zrPEojBT2h$4FPfwnnt>?EJ>DSlGz3-L9e(_~qn6x@;wn1Q# zzD>z$$?w9S0}j!$u&uShvaujuEm(S2Yab8^C%5w zp5l98rnVV7$#qgN(>w<=S%sNk1QUAf6pWk0dv=%!F6bO)f{VLYf=d~5&k~GMK`@|F zm*jfDOfdZQU|g>CNq#@my_w*OFwQITnGeBlLzN&*#|9)fB)JjqtqN5$_|TZ-CfR`x z!L@P7;6w0xj;{55uXeWDHoN`HJx>O&p0;LMxWR|udS;vYj@mT*%x(3dwmnvDZ@K3E zhP}SQy6Chi++ai>!5pTr#~IvMkDKJCM%)zK6yrUa+vD9zs2}Y_vxUFGH z&(Z|rHK`y?3xhP4;HF?ZY-O;DCb$F4z-`t^6WkFSouJN87pN=L4eAc{fOO?<$(>2=!jl^Qda#w`t|WKQbcZH*28_?Pb&N*? zurfsMre8iT{W%LYnaWLcaQURYb{4>l2b*CuErb?9?j-jhxhKiJcrX0=U@rq$y-Dtq zEr5lby$&n{AnBcxHqq;%hJMw1P<*{tmzsByN14D1HQR(aYE!%M^NW#HIwx&DaJ#er zXM`DK@q^(u8<aLieNA$Ik_V7HkmNxm4<`8&l82D|Dak`g9>$ni1$(J6v(Em#5W$=9JuoxehMAGJ z_d>{1axjx+nAvZ`%mI=|*kcAODVl^^nx>AM&`}yc zp|f#@Ww$XiCaKaiar{7OMyJUdZ+DbLt17v^(=;0zhJ z0X@?*<(sSh^F7bgzVgcLRBq(d`gjRXI)?_qM=(bgxy1LcMCLHVHq5YjOM$s)-T$uh~fnW-deB;z(VjpXTUrV#9JU7!_nvfPS-rDF`&(Vam(sML(%p2^?AkNW*WHjkR+QCdmHUl_?xI*or z4kXVbc|OU+d*RuKbY^Ukyntj>i~swKa!4;6GVl|E5F|Z*PRx7VCg66rQb|=VRsUw- zH=PY+h4eGq@RFd*!}|hnZ%w*V0jTynkWq2+Zm*OS${gw~~pTJD84Ktxsu?Xea#985l z9L{7JXHYmWID<u$oI<-6bnKy2f|1W=S|cLLNF5|NRG>NpC%*> z#-q4nMnO0f0Y#FGf1^l_=DpDne0>H)49T(C0uWg7qXPmLXZnlX^UIjT6Vp1@_U=-8 z*4|}`j|qq+W*aR2Pv7RDczNGJsdMbo)>k^$DA?|X13)1D2;tyDAEU1gpC;ajG6!&3 z08u8Mh0GAiNc)GFX@7$=n{>`3nw%N1j6)}k^vLnjxM{)!(b{W*ILZ218h0jSC(OWe zHaLTfe#mYJYji^PLi?a^p#9JR=pb~65|n7n8h%H^6(oPnocR{^ zQga5W`!TnXUqVQY{g#ju_ylKG+BmbC-rhucQ069iTMlQkj5DYl7@R>=vC5t^zdOkp z6bVB9#3<@>7}bK1+a#|cc`b7WK6}U=lGl;ECG$D+5XPTy$4rz*&|~OtlGl^Gf#i+6 z_bG%0KFpa-ByY|ZoOz8yh9eS+kMzt4Epm0}{Ds|WFDv#(QslQa${3sp<+VcGCXb^w zqZ)tIa_1NAUu;=ivhkDr$G=O@nNY+Zp&Y1SjC9v8w4m<#ZFLS1p~(A(a{R$&xaJg! zx0Sz7@^&Z9R6t8+0*6hZNa=?nlOKvqekdNz4aF**(5g^1s5(>wLV0N?$-7A2P4XU+ z_maGiWQ2eFNk;5{kj=mgPtBRoI)*<}h%-vyOlSjqf-{F~ocWghncUNvGiP!*lU1Av z#lj_>Goi@dAGYI6XglXP6N)lHXm^Yvb0)Ma)Qx16hQH^{9uV@WM@T-F>2XtNKNufi z>lmQ`Cmwz<5)YvR@t2rP@=*sj=@R+dr@6s~4uvH==&KVebQm^ogEh}deqqm=mnLiew<;Jz^nb4m4$JLg3Co8+!gDw*50sbWe@TAD zn{eC13XuGo6icSNHDN_yytu97qWZ<7xEL2tzg+soQx+NFjAngUS(vHFW&ozJa!`4w z0x7vj$xTWg-V66Wtdfo^B`+!YvIDNdYT}TAt1w(#>3y2D6plX@MES#~|-)zzSP z3|xiPHru@CsLjGwTW_v>+C4UY|C6d^?&LX{9#>)Y&|gF2jO&~U(_iAL6fimShR?Bv zHG>&A&pKzqnqvcr{jio$E2uTp2KoSM3w;QEM9N#F6e6WCDF8!JQi_pMoRkuzlq97T zI1}ayd#N}R*2%u=6xI#j*CGY)x#E9FDQl}bDb;f@lU0}r!}28^Ghv^QQpOH5VMCq7 z3`zxI<1vUjX2xP;94X~UDbJWe*&u8pDY$6g&V0;Fg>li=F`@xPPfA4tGYe64z&-li z;%|T%E6jYsW*8{bpy|-(q*NlMGAUJfFWmdEnFeO6l7feO{`;y^7~zl^GYcFcW3gNH ze`=oZ8JOHC(pxV3r@x6Ace9O$qc)4CJ-pyup|kgzI>F0}RUY@d1I&1%KaN2#)COks zmv|~QOw244;LhNjXW-6+g}@A44FfZw*a(A=&JT-#BB3ZK8j68pp*T|BA?00C0E*hA zyhlnMQtFaYkCghPG+@lY5x2t(4k;fy*|+rlmawJxMC*n&%rv$wq)|S|!AzE62FsTW z%xos5kv(R%If)6I8HC|#Z$irZjF|(_K~kEM(meAq^F53owRL>Nz)Ume zF>@Mb&axQ>${FZK=qFNIkkXQrR=gLUeb_kzGp$K!lPxfF8Hdc6`OOhBhDgsnx2nCL zte;V<xJD!e;j_KU`Bt5r_$C* z%-n~W7cj%g;IIb}()wY@=7&9o{)V1FPoZbfbLbyZ;Lx-q#g&xyq;w#qBPpFo=}bx& zQo6Dk_~5BAgU6io3{8Hx?Ho0Q=fNj1gOrTn&Gg_5O)h~Qn?X68$tuo-V{L)XnebAi zbhqP7cv+NH&HbRuR%(0QU+vtb|$R6C^sNGqkK$C|Lg#W@Mbt<03y7(ql^8!>qEw!U(oq>VA#Ji zAKa@u+WfDGUgH>s9zi z;4vu!O+dWi+c(2Iqa}wQHqM0WFY#0cJ87m5%zO$n%$e}M5YqbLA4C120nk8b5HuM2 z1R6pL{{57cp`;8WWjHA#NEu1WC{jj~GKS5-3Af`6a{H-Yc@;hu--9z_ZJZgO5;aLV zn8`BC$TrLQu2jMYiZ%)%hgHRhfr93_MBIiyS=Wg=q+RfF*Pq)Z}3$b8JW!?-th z%s}ygJRvVqJ|kr^DN}f_59DiLW-2Le*#a{mIAq35s3T+yTk&1h{D-@?+2OLT!#w4+ zS=$beFxx~rYO{ZK!)5(m_xK`d%ty0ougN#f0cH?>gmavdf|)oSGos0dH_WPp^C{)< zBLy@1J3JNHNi(ZpW-H9-m|2aDHPBiJnf!2M^20Yk8=+0mW@rm3Dk&N%R#K*sGMyAe zwO^1jgOr)1%wo*I3Ae)xQtfyrxg~s$zTXnQ51+uyY#V0g@;k{DZ+2&VayXM^oH=ge z%n4HF*mLHzlbkt^(Y%CF#N@Mtqg)Vvk(7C)%;!y148ngUg-G$te9l~j@tfQ+PycJs zb?62u3rJZ=$|By2^*!N#7@Tn@#UopA<~|OYIrG2~GrIm$qB8mSsJ=_BG3H3Ydq+%n z=CRr4Z%1vO*RG$hX$#j%LCueOtBq<0IN%K8k8loD^fAKI1Dwe6G9t{m*pEb3&0`J{ zS;YsW@rxpIxmY6d8iw@zOhg_oHz~d*Y39B_eg>v8$j?L+f*H8YI%y&bV*?5Oh@ucq zOhj?01XL0#1(k-%km65D04af_1d$RTq=b;RewEEZtU zMD%k6jhPj^XD?pctyuJfp`lIs%s6O(CSriuW}u@s|Gp>oeNdqL?10$F+&}&GR(N{Q zL?HNx;K+hK5ssT8u%-ra(^n=Rj&=hdT93()52Mj?oN0y^>qY4A@KlyKX=XB7!fiG% zGX)z+=tsCg0wh8bBtr_MLU3i4k+PhW6{LJk%1Tn;jI1VQ4Jm6$S;v@}279S7GsDHD z9F~xl<}?=aGZAy}3CygwVP+%cdqnxFvqQ5dhcj8m8AKBXXZ%RnV9%LACpm)}K}0l0 zQRhq~Hlj$`M9OC73>@}|SW@8lZez~;f0o9)!P1(vH`gQ>|H|mtxOl$QFCN=U*Ef8M zIAR6NtY$L|CZ4h@Ar4Qbzsq? z-fQB;@7lIKR{$^38Q={g2#Jl6T612?|G@+;b6;q4sf*xHn4z4$Cb_* z{Ux5tUXwF#dd9zn8Mw^`XTHM*GWrompdX;4&@t#ZbOJgFogxJu7{GXd6qFSXk#d-n zZ%O%%lBQrymOL1q;BIKA>}wJCm1vE*CU>ja*~wOnU9%QE|y4(t>f25FmTEU2Kw#8U*gT) z6&#r#W(u(x041^jR1kWLlryCKNXk#V7oL4&5d$-4N%=WDU?#FO4jGt zem8IXvg_W@Jt)6+>?Z>=k>$-c6&$tcIU#Awul}xMcl2&nW#54|DBPvZCP!96e;j_W zSHzf!tfEIv=S|G?d$V^1N4|@ejbVoKGm*8R+7R;ik#(TDP(7$V)BtJ-H6jJU_$5+) zAq8RhWm0}4<#$r9kaCrjYitHicxuc0wjka2OxW9Wx3>KqDbkApRufFH-LC-Z9Wv0}yvf!7FtC`(-bYlX1ulh$)UP_M>aI zFUgzSv)$5wIj^p5yMyJ+?1w}OW*aOPO7FX@ubeQy{nWl2R-8Xs+vk^Vvm5{d@kb;F zD*70y29h6`NX}&-`3=@HM$Uv8jz3a3gK`+MGmmVX$%W_(3nMeg&O|PRnE;s4IkN~G z$mmBRkss*^c|qQg59AB^K}gN~O$zQ`Pf2-33hrG0kn)0*m!$kl$}8p!oNznNgxb3^ zk&*ZwoOx|>Mzz@78MSZ@X0i-3OKg}~N~()JW>z?f8Po_OHyU%#5{Y6#WKznlIDcnaCY5zT4I@0s-VU)x5^FGpL4s?Uc{&Ah($&_=-FLGvBfq=F&mv z5OkQ-{G=8jwIJ_>XCL{!PAl~-QVV4ZTAjopGp%sHPEVeOx7wFHuXYLDakXUwmm_CK znzZ`SZ1a<&HhIbiJn?JXca7)Pz{bR&gdOx5=3(AfTchXQJ{u z$C;?2E|#bg7)8ESMq%bhVLntMwK8v(gfJ_rkXkL%ITKYL#^1Jej7WevQ`PBvbQFr8 zQSY)D5GASxR1r7Oe&JJs9a3<<~vrSV+ZEmi9edzPiU3V-Co{@jr;cq&o=S)-!^vCgsjWbbr=?^$l z+c|e8svXSqfEngYlq=L8>Hu|wIzgSGE>Ksf8`PcDI;7SmwH~SUNo_!CLsA=&+L+WP zq`uE);Do2VfY>Ju=<1@KqM#1OM7tjn+Ta(&` z)DL(smi9!=HUQC<)DN=-AQs|~84!ycUhJWpe@|@JvxVP)@Dn4aot!qaTy<)}?y zsnQQZM|O|gdwiXAV#@ctJ7KQjDiUSn}1Xr7)@EF2=QrkHRh%mI|_#=fg5jtnu zJ832!W|qT@&Y1*kBtppPML{uGNd1`S3n~UtCrIs2>X6LG%#SdBjyvXA`4e;&`kB-Lqz)u?5bwpxo~R23 zW(Je`Nw&bu?>J<}%oRt-xG>_&eJy|MGiy_yJS|oZX#Uj13_Jha=7ys-mtU^;`LdAf z`cp6&4Lk4X+NgZLwg1CUdHokU9~ViG~xN z8Z*(z>tmIk{;mP+w?r4i_rS~~8)i@Cc3i8nP@~bpV@IH8l&UP zTY{tC!zk7>CZ8o5^@3=)w^K;PYhx|ZC>cb<$#o-D&2-L0zYpUrxML6{x+&BQYEG&^ zDm*HQ_qK$vU>}QTRGCz~Eakt?0!O#QA%hvwu8x@T(e+)=23R^KuRK-d%X(Y#tS~qe z-O+5*$x)m7WxhH-Gk>Rt9&y9Q&mQzEuk1_X&O{^rh~_{AfUrbkH4#Ucnh{|h#U=`K zSUQv8Q|;0H(3;~98)u^N7ze_pX(ngha1BoMr!X@fW|%Y4L!n_1a{AFovqYm@5bZ_kB2w|zSWC1I0gcpW$u_-#)Y=i4LeVdSfH;gK1~8)rIKWJaJcH8$Yb{!AFf8eH?dbJ7X@U&Wz#0<4u$4g~IC>k*z;8B4 zvmF~q=|}H`c0s$LJiO>bq;B=j5LTQ^yM?r7fFq`C(W-;k_JVB=vx>>eHP!q#!XTa zNloHe42M1XHmS*^F3Wt<+=KB)+%YrdKJ);3Na~lQenskH-uoDWr_T<}5>l6D3)1j& z#Y~!i9Z};(;dPd>&3cC}A06>{*VH+U4bsG*3Ac%{IBIjz<<`l*<@X=0G|k1@0UI%#5x>!ev}k|w4A zlV(LaOKHuNgP9sQAogiukkF5*09AzEhAKgop(;>Ss2WtA)YYV}A$2XO>quQs>IPCb zlDdgh6g0Q6nVPVdiZn6E+^2poL=1b~Ak9`AX||`NXb$F(CaXvjgSvrEni%9vx7m>< z=0oR56VnNU+|@RVQ7ee)Lh24uck-l0xgZ7^yIrL2&veqn^nvmI+%cFE(-(qgAM-J( zyGh+c>R#T9^*k{H4bmVN^-XplP0TPHGE-x?BWeVMPu(-at^I**A1(Xgtz&)hST*}J zF{8{jqaC&R^sj?omi)3)LfqKa31zSM6&;Xf9BfSFQw1P!COBq-o}xKm@WJJCyosEu z@5zu4NczW^Nq++~=nJ9KAt%jDgPHj_8XYsp=f@z8AA>Z0%nWEIGz*#y&4K1Zh>yM{ z^*d5Qu_L7ZKq}IJ$4EU+DiVMv88ZZXsWIbj@6g1s*A2{^vSH>-ibL~j4ra0pGbkGv zn1T0s+8#5pPGW{}vIK*u-z@psUQFtbr2fSFQ7wpBM(SBoFJ(SvR>Al>?wC7W4XuH2 zzk~O3j@0wK7wdUq;OMhMbAi;0*#a}$amb9B9gdKZ=j4X2t=D&1={@bM4X<+zLrzJ@ z%x<#{o<2?=I$a+0>+{FfE@6J9-~Vh%(OkbezzmaxBa0Nw9MCcIi^+#KT*w=91ZK>n zzk!*fI%Y0AY32;fz-=}#gM5Ar()ck*)Q60jOntg3_AMAMV(S*bKN7TN)|@l_m8NsgFthoA<)8kF8+P3g-(|p#MJ66I%_33|hq^Z=aq# zXOC-*R-fpzdu#iRqfSr!lF0+7D3-57Zu73AHb?F@vflOS{wi_nhS1^PUaOa$Rh{`E8idO66cCt1uHg zz{E`KK+^KrVJ7wyCozKpLF^a|B6~Bjs1(GGCanNz1$lEUG>){lNGqP{-c0OgFz&`3 zGYKX`Q=qA&6(X%LX+?N1R`bO2O8uWnD@t0iY{7?VIAp%or#rgVhb7*c(RgLI-d?+D zW!)cM;?=u4A7+?sW;$w9?(E8IUnlh4;IqW@iDlhutRhTXZ;D0q5j&qx6@b7&Q|vtU zX0#FpA1tv85Hx8e(*;c>%DkH|WAplJ*XxhG#XV^t+_h%Y4*)3*$d<#|)M4pzon0q+vSMCha}mdlZ7F�+G8t%W@ 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%0A3!kZ%4^!DfiB$^nUMX9borxCk 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

    6-vqlCzUYmU=R^##6tb?8Y!B{UR zb%+y-#5mp7Q7Lv?^6mUgrB|47mCm8VKktD(N`Ejc@MGmHMy5~j=w(@r@A)+&)hKhkc(-_1$9gv5Fz4%Go<7>UFG{RooQf#2^^{Jf437$IqZ z&9p8gUP|I+B;uuDc~5J?=+e!sU1;O^!6_5^Cnj0V!$`Yzq|NP1NwN*a>P}W`9|y0* zQby0ZH@auF>lo9C(AP84?X&j9%3KC!a9K9@fWKCxa$Bu`pZtB>aJMrMH14$~_``li z2s^@m#wnGRK5UnW$d1wz@1hTyFEc;=1sN}< zE}!;=^ds?d65B@Yj+6$&ENw_A;UJt0CK0`-J|`R+7k~U^60f9LZ=JT?kTwb#jpYJh z1*F{u84bA|G6r%7TEDS(iY&6VSc1N9LxOpw$J>g(~A4FUpn>Zl zi({o(v0+Q2Rv!+DTh!p-E4|+B5@WnFZ3)T)vH#0%NW(%Ltx0TS*bS(4j2NKKBS#D( z@n#vafz@QRnB_Qmj>L8(w&xbJA};<EB5Zt$%H_cv9X3A0$>${YB(WDa0z^5beMMq#5(ieeyCH1{GT*}mbI;xh*#+56 zVjmLwlGu;G{RRSiko$Xo5(k_W{rvzQnfv>}SbcXv$?g9AGkU(UGBLmNH;*pB6SI3U z?I$zM&#}_X-c_x}+gSr^KD_ygruFU}(mC4QkoGI`_&xNFju;3#NJm)91w6i&LJ#aK z2f|`x#BDLM(Y=&zgiHc9h8VDctNW!xPZkq3*`Cgiz9)ADD;aNq1le-QcwjLgqt%e;lsCYR{0XOK+h$ySUjnIEL z4`1L`iyIVVBp*RSMwQEIa06c4VE($*;D)8(hNa+c3TXy`Y2b$1yp6=sB;HQq7!vOw z@lIF`?i(Sn6xQ8DmBe5aHFjg%!aX>Y5IosEh{W+ECUU|dSUnyrbpjRdKW!c7Mr(K9#RWjexzX(1 zX!dTjrr8}!%>dhEWF#3T}vNwkqTk;F+P!ZXEN;;?RW-)$bP<}ndRUB_|Mu9(Un z{z|9g+^Hr$xa}m~8x9>V18T}kjop4!at11ub(|YK*&QSixng-yi#rpNMWU0$v|r#ShH#3>}+$Bp0%$d@EeC2@9zQ)BmbWWJjV=AOL+vJCvgUUi_s7_f~c4p0|*eT`oEvyZ3ZC3VW^~aRDE%B=O;LQDIL*+#PbD zdm7=SF$CD+0WJ1`7JJ}8e}u$^BrYOxF^P|o_!y|L=Q?8m&I20FRM>M9eozXDOLze8 z8J!6~i}&!aAAs}d?sNXZ9U+|{aG!fXiansDo^B*QPT~_JK1t$I5}zUw`n*H6=8I2_z3I_6}r$b;-o&mT>w17e4;TR}3oI}I)9vH97qtODUiHB_$ z9W7v^JjZAO$Lp~ZOIJ&BWZk4S_}fFwbZAvOq1ofRYsB#IRs`)a0 zJDd|AK?+w!S-T#>m5{yR$;U|ni7$}2>IwW=6c@jz7m2HB$`_|iTRkv7JahS3KwCYq zLOgKNdoUr{1N*}R_q^wR$O9ywr}Y9Onoi z6JOQ?$i!Efw!UZ3){_qML=WLaj}rZR27)}GrTUn>2WsP$a7cKTFX4J9@U)D9AdiSj zRd74gR*wWhzuQRSYkUez!=sV-I*Eu*s^Ebj54`yvHcIq@VcZ}pO2lH87zna>;K%1a z{zeRIw^n_BB!<0;6q`6FP+iYP$ZHTh^jjppP2xNJ?Hdq8I57d8D#L2oq6Z%D+x_Ki1W zZAV#AvqwDN;VFK=_pEe6n*n?FllXD8(m8}%e==^hczz`D6Na;&N&K{YO6Lgf{*#ll zCixBWJLC_@QOGgKaS~ytVHD#F62BzzD-yrvTjBinA{kaT)G4aBiqRmqlDHi;1ZS;u z*?&RjcrP^HnD-(Qx3SI%i$!RyuU6fvP0N-^iD9c`NAy5%ZB*B#s4wozUIhPm5e&19 z#2tKk8Ke%0J4u9P6#8hh;x&se}CSN2T+ycyA81uvfUJ^51kRh4%DDmUbv_rg2xg?IiCi3otT zc!xlSlK2yezf`!Y@`5CLM|0xEf8GyOQd5VPBqwA@o zr&!||NU4)yZX#gD-YgP<_JpQ<(^1;U95Nte3QuT1yc>EM$ z<5^U0$UE;{hLhzaoljB?ZUoOmR*-Z7Nf%W-Y`|;pE#bz2R;$AXqH|s$>B3WN#A}g_ z9{0}x@gig$SU}N*{BO}h+KFG29 zjs@=(xqk8 zcqtC+g$rNju--37s>2*sYK;t|IIMRoirS9vOFK@yJ4mV*#bLd>aVxyF~wtuPhz-+W2%GC+XGVEa~T=n$dPF>E}X_ z+qKA$PtS+cAgKvS-5Dl2M@BM~f09H5CrC#RNv|C$H328JNNP$FRyeh!UksPrSdy?` z{ah~fv?l+i*F#1Pxd3RWbU6IeL8a5dpwkftlYSNCY6zOl^(5Uu(v2kDL{f8-T9AbO z>UE8j-q<`|YaW~8sB0+fSWgn~S1+0S)tAT3a#BCdzsCoY4p=Z+T^o|Z_p48D&zH(i zY}32p6?8|X>P_!voZLcETawywBj^F?Nm6@~Dt^EE^nS>E5El$3lHMNzik&`?qz)u? zB#HN{Pag~!VyKqRB%Kxe)u)fbBXh^OEtZ;?TdnQk!ViZ|lB*xSr<>9Ub8C6%Fnx@f z=8jltR_)#P^qen-URktw;jpa-6M3R-Fzxr|x9j3$2oj%#j zg?VlIBwaz7+trsh7Y7oi8M#=}oj7rk)Pp3fZ)!<*>yBHg*O@qO(*wvTj|*VX2tq)l z)4`w9vmn`!97rxny-DgrQeTq#k<_200VECN6ojPL=weAPG>^qN0zU`oj$3I6gT|Oj z=eSM3KLi>NkTf`q)}}vrilDIw75x}0RR@j5H~~{0O42ZH1WO=~lQf(p1g})E<2D`K zB7Iq?VCV=qZlznxcHBmGC=uDHoDHLl1d$;MNh3)bMbd5jEuvh~L7?Hal}3|v``JKi z)7fRs*aH`JG_5`FVrTQ~UmUV$!NboqDjAn|!o;2pW*VmGQB-)xmJ!q6?$Cel`X}E1 z=#JG`#U>hiHln;uTvgz)I%>SGqsAQutu2q&HXV$*G)MXXxm{#F)fV%T$MD)lzNe2- z_@}tFw6iw-Gm`F(BD(2c;?}Q?TP^8dku(lOH+?Hf)^ZWu^qshSA1CJ)whIE{oW2M0 z4dh$MUXsR>lt|J9l9EVDCdtOPGLC{Ir^BVpL^mA~B}{ZDk~Ep5M|Gn6*nfiPB6P)g ziNBLH>7Tr{ty;Hg*I{DmJqRP;=kt1wA zFgA5OmHEIC#rmot>kz^Aor{y|B;89AFNx|qUw6hx_A_zD_&}e1b@_Ke2l;A2;Fk7X z3_(bY?@|a{(Y`t)IY@Gn1f7{ilA9zCNnVrc`YuOuIAeSq6~jmNIqOt6ofVd!Kk_S` zGsbtF+3tKW5`1A=%XbrBDnHfrwMC_N;CIAty&VL^Hb4@ua_U2vjIR?(86;&@xYqK4 zR{MGw1?$cjAC|{|g(Spi@+ePveYn1U$R@;?ePGN!FlHYZb2dpiB;`VD`M{WcCS%Sc ziOvSC47vIa zTgz$DTFVE<>=L=W;kOCPO-*8nSCZ@w)iIE1W;8(5-*AB!;9MmQaOdDbUJMd z*#`pc^K;8!*lhK)s)j_msG3&94eZB96Bz-N9+urU`EJ)hqZzx8>L2T1~jp3A2XK^BlS zkEBPq5me}2gFX;z-{V{`_v}X@2pRV+AqnNrC+Q*nmY)IhE19L@F&;iE`ulP`GFYk) ze(z|;`O{}Z;;q5KAFfz;@y;8Q+D$iDs!uS}h_TW%t-AR++YJMbtiJK{5tG)P|8V;%(?4(pQI!w*vIKNnIRavlVp zW`7L`Mx(YOvzGPE>y=L5_(9h7 z-tEUA$eJ*H<8Q>5mZFySmKJ?C?N~c%`>#Vq--uhe5%{l%z&HLPN$dFZCI~#_FOjsN z!fC3%4Kj!Omb^%3wA~hxJ|O8sl0M>F!E>=}8XHTx z#_?zI-z0sUH`$Dc`~1J4Z~X96>nj)fr{Fi=2boF|)H!;|XRLj~93ua^1=32l%-O~d zEwy;pUki3c?bhpm5Eb!|**rrLn|`p}FQc31Lfnez4SlrRzlfx-xOqNG(%0o{o{X@| zLd}zLYANI?2)9Aje;`3yN!msdn9&ZBc9OJ%R&8}huEQyhzbAB6Q7T;hJz$j>DGLegQ9e&yD( zuXJmHLpRov?4z8{RF4&Fof&H)j&R!hdaU|q@027j*1Jk{2d%BThA)j4Gf{smsh{Xh znw*l9n93Pofwob+%AvKDzE~T+($_02PgZ7fUY7CZo2^!B654bbYe#$#y?$Kl(9(=& z^zf(pyrIW!9a?w49Hr~^{r6IJW){{2d)NzXTb>s(shqDKv?sGe4v4{fgeI^XFf1g7yb<>vu+X#N_+&_a7u*!u+{> z1yrV%8(EncuVE*nQJH_D_D+y=l%!**%s_lx{Pubz9jD^ar|kg^zyJ-@&08IE(u}A|qpi-OjJL0!~BjhHMtCM^lpSFOsB>8-j z6Dr&T8fb^iJ8{7vV}bUN4v>x{*C6=IlA@@If@4#DU`fixp;hDmh4O24E*G$tdRvO2qBeNd=x$k^o%qxSQSo&<0 zXj3vU5aqEs8ZzDkSaakRl53f!WT%F(lpedIta$=~k;rDWnGIW{0Zcb&P4dO3m<`5X z0_OOOC2%)R#*us}$$A4C54yIRy9kBA;ZRvmClhB$PK|p9?1>D zVWZ#_VPhI9dM3Xk#);{W86-C%nWI_*n28&hP4YD)H{nK5q3e7GFh~<%i}A0%FkkNr z*BXsD&i)UdOyZMLD_#=Yc1l~e6@8A};AVWKe1vZo1F3N%oypLP? zX>qG1u!ZFIeEg8)4&|~S127T;u>N!lGJuJ&fzKf@4+Ag{0~mG*d`&X+S|^e_liY>m zt|WJZ1sT97Okg_%!!$h964(XVP4dko_ar%>TaZDLGyeT1WMDtPWA0LzT@W}3IYja; zBzGsd2iuOmXnU$nYy*VN4eQ{HwpMFzTawf6a@#zf2LG;o#M-oK)B2?Qhy{K{1^tfp zq(du=8m_Hgs4B*zKOjd*?oIMIhSsnp(ob#owd52}qQ_&iPe={&g5p?q`tOydBm2^c zI7`rCK2Z?wG6LMLJ$T*5C%fYTK2o?iECFHw|P>I{PDWp(c-h(D`8HR}d9=r|Nj4`s&hpvJMk;d!2+tm2C zH3G*%MrCC)4%sAzp2muk@g!SG9?vaig1(WMoOmW1i3MR71YKMJ!v+k5APj^c41^#I zgrFVbfH+B>Kynhv$t2rIo=EZ}k|&2?!!!_rY#=af_;A!=BZU#;UjFb^KG>iTY~+)C zPdIE8MZ$(Y^8Jq^-oY8D)Y+j%FcT-UNKPf$&W&IW{8y;$>8oMU5AlVfE9Tne6#dn3@ zxXEn1W*(7G`8FPGGoG^a&{FVSlCz==gWwk2%E{R<2!23vHXlDCIj3BPK@he;a2qEF z+YiDh2*M}`!YByBC zGeT5415`Q#R5}AxIs;TX15`Q#K#>6|4H$-xW)8^!;0H*aOY%Hu(Tv)7wrg~;WSCSs zL#NUtKWI457O+lSTIrl;8I8=wngJ?3KMZj)Oe$^3Xc`w+ycM;mA4z_Qn$$5q^WIAM zCIW~uz@al*g_=SOoU|kv`sopF3aue+NX8)Y;}xzMGr*xUx^ltj85tnc8St}bz%j9i z3=I-u{X241Tr+%u8oFcOskCaJ9HkOP;oPgUtL-MoSXp#;5SawGE z0ScYLq?kE%2Do$vxO4`%bOyL|h7*D~uZ%R3my`S)$!2+L>^F0F;I%A(c~p0ZY{Z~Z8BcLG3^n}F zd|XQMYLeHGyq3?vgEF2m0O&=M5v%{dr{)=^BRwOgBYpNWO>#cJw`ZRz-}HZAOaJ#w z=X-{NpUI%5#saNjIb$bmJa0(Kx~U(W`1JC)w_*U$N~B$F*0>HEt8~~1#qE~2#@8d8 zSBz{d85?i{#{mB4MKLp8HDKe_GlGpbk2=tSYer4Uo$6uL<)mO znQo~}+?ja}X9Ix9jE7htRY=BA4UDpn`CH6^$gF0-#wR3ydN#mD=7o4fqunI$A^97=6^`RfaNSJiy4<3=>#b4#mgIe;ROK-^ zrP_bN)XoF})&~MIF>$=^jy zcglnhIn(qZTQW!EU5;NrX&* zBteoPHpoPh50DI;J4Eu2Bm?1oCixc-3nr$SDdv%9J@C05N8R~*n3c^Dd?=Pm=lsnK zgqli_WW@HC?)X`Jsr*DWvjCM^j7nvVlUWFX59>FQIb1Vy3IrY+cx3eTdn;7qWX?q9 zbBuy@qMA8dC#s=!K7XzWqB?dzcsAc>N^C3s4*do`K&jdZr7I<{&6fIt_K zQj?SfQfjfn`VjIF1SDBkSfAqW&q%3F$|a->)D_ksQilBdgGMqD7Gu1#ouphG?Ho2# zmMyWP?WEBZnctv-_MxJ62-=C0y~vJ~OBsUThROV%l*>rbt;Z*Oqzh=ixTIznHqMrm^W-wGcw$|^?Y)3{*n*&yy& zn82Jhm6RT&^dzMhe>)vA!|3n5N$GP|^!K@VWbW_tV)fl?4s=+5@vXz|S@m|^X@7V( zwlw?uLuQ%)p`oakcZ&82uggK-QziJ2DV&!&3 zgsi2=g}YUVO=mr=qsD-f=TeIDX00%r9rK;=J<_w}P>WPZ!D69}H@G&SsJOV&$ybIa zk9@v0c)k~rgo$!!U-YbXqzsE9%2^w5>np~smMn1T;ULOcuaa_WxrlPsCfxllCkOk@ zdIJJaa~2%TSzypvAkJBvNf|-PNK!_TavLe5Nx7YGeJ^}jfh_z2_!*Tkp=AY>vHu0X zPS)4_p1A*Qg=~XtC*=-O?j!|KG1i2e!zeA*S#)_PyKRZd)+DDR+3HVB@t%~tS`%&x z%b0HTv&LO~S6`>QU$559h7WM~ocG#B zxf30p6rS_j*PUp$HMst|26v@6Qd1nZkuheIyACPBa9^LuyLy;>laeSb3^@=l*IBi zR8Z|~=G}Tj1?SEJ=gtD>&I0Go0_V;K=bk`H5-G`~*hra3$|N+@Yzw3c%)!Mns9emn+@50;d7}^noSvfC_JjEqY)|8s(ss* zNhgUE%C3hBs*m=>%0ByY2&^?bDZE{LHtdIN*lbQxrn0gRp9av{tcQ~ru02zoN%!`0 zx`O{FPu>_$*Ch1hAcWc1lHwvIji0=!K0#1%pUDKlYz!7;x8nl9RkNEzT0mfvWWyB6 zhAEQW1_Gk$A;n8dIw?L<{Giz(KF6qFff5~Pql0~x^lbz1dhoNzD)DNBt0 zUf%fv*`Fchmu5EX8q5AdhYd5h@*lG)WfWwG1_`ovlCqRZ;xtL!Sx_HhdkV_$#kpkdRNzr#qUmjzI@=0iR zzf|Xh#MG1wtdZt)Si{bSV64+R(&qK1I3{^`@g;q|DQt*qESMF8vky+p;8n5Ap(m@g zSE9q|z)Dqp0=A@dE&wwWhNn+R#adW;aS4;d%$bl?bP755f``Cs8=aV%e)6HMh&d3g zI_Z|pgbtnBPiT3PD3YA|sNaU%@0a2am@+w6L9T{eO3F%7ULa)^s-7=4f;5IeVfI3vc_7ykFmDJKJu4Ca)R8H)vFq&#!D@BZ!`3m z$NtI(JYooVBvN*S1CM%&zyo_HXB{e4*FLa!a-eJAOyA9o;3Wvu!5&h+t$5(sh|D*I z3VzK19>g%01w4_Bcr&uu!r3ssybFOcH@cMv!K0Ce(c^IP~zk9U~k)AM`zDqRv(`&9+!+#yz%v;@TnISIuwt+Gm3fUlt=a zFJ~vp+hf$YfjYZ&)HzTF>O|J~_sHgek&Pwi2b}CDJ)Ur(Q} z97aaRxd4U@*gQE$AiqI=hx`FK3OPm!j3kWD946&gQeX}JM#}FY*f@dYfQ?)piQyxM zGU>4K2P4KYe5lnc9c<)YWWq*nO;V1A!A5TF2-rCPXVjSC*R9e&hF>?g9%?l-E|GgV zPB1QUoRmM&3UWc_b1^P)f>cX|<3?^{WF8t;$h}6#4K>cdjohaA6)B{~$095>HbgY! z+?$Y7EBs7`j$Di%Jzika^qeF*UjZ{nx{ofOo+|GDpKu2zuSTL|? z!B-32?fZVdZ0RFccKfr-2m?BDZ#L6_$4A4>^0`-k(sV-4pz!wj7oBrxEFu*mT|K!y zQC=UeDqscsXmWcqbf{P!lwG@)+@>HbsP;(05?SMea4Sf&u55A#<75b_HAuaH8_h5s zI@Al#1UhmtqL6zx7XawU9Syl1G6n*EoqH$bF34C?FCw)jsR^XkBDFTD7n6F42_3ms zBxlG-G>=I*GIXey@<$#1Xk7WA!x4fGC#jc(Lx(#8IsyUIm;oJ)E{p{oLDa4}PGHH+ zz)2>lbxEzqtsoncL+a(EHel$e(A~Cj3y}E~Je=O)3vp5eDJJy_QtOj?C3kp4H04e; zI{a0nUVT<{c%H$)9sd4Uop*2djWsTB*Q?s}s{T<2A03a4RydA7m&Z3a&4aPh4D&CU z?4eFiaEG;lb2%7jjjhhqG@tSD)gmHVk$6#oXZ=MRoXEwO@8*-# z#^$cU!@h`8*%=#JE;4r=snn*MEx9j~dOe)6xv!FXL%E!>xtnnJyPO;z z)?5TM}Y-|vde{hHs`QvATJkZq9dkR7D9A+;^3?MQ9Ue*WsTRljNtcglABXK!zK zuKg1o$=KCE&tsUwHq_Z`vMuS}lR6nAX7+VppDdP~Y@6KfWb4x8?nNbkhgQim`?$7w z4b2!HsE$&))v3X!Vy~E%%?^2`Jm3Ik>JoxbQuI6`yx1I;up9iJcmsEtgTJjn|8j{+d z)PWUl1>`kB=GPeo>-s4VD=oZ2su>v@zw0Q#aLV0L`YA#=<+VUIZ8#g~{=AkDgbw8a zO9zoUnA9QsE#?&GwKEvOP*Sn*%m3a4$m@znhIY^E7E8PDY;xVA?T-xlbMf|lGw)tg z3+tmXBgpG+rhyAT+61umn)Lj3r zyEQl5+esZ2rIGW%@AJkQw_5VsU7eDQaKn^| z*tf<+b$;4*2VK%mDJ(QlUv~$!4;@uX(Hq zjcvw!$iKhj)qMM=xINwxHjfKYz6g0ts2?0QaiYiO{fDwINphy9Cb~SfApABiD5hb1GQmBKqqu9{nRc0*8cu9 zS72!v&^ZMs_mP@JYBEFTG_>{CNwv}Jv8U}u%YzF)kK>cr7S2OhQ{DrRxsZ8~2O)6J z=RHK~L{ibRCzA>qc@L@glA6jX9!65QS9JZk$UL$$zX_>!eJvK%$@(+H(4Uw8JvY~w z^xE8Lt~~Oc&@lSqWT(Fu#=v`F-X!lGW=*&{<~;}#H&)$48;{N?kZv*6IQaz-4NloW(UxjQ0sC`PRk5vCzq4~_1rM#FiOM{g=Hax#~=+`qpT#(iK z*U=@W=6er6leHzxrfAJq`|}P9FP=Sk#*Fse2EW_*l5=8cz7LW1lh8Z*$nZD@b&q4* zt=rHRQm9V77#_z+Z1@V<;P$^2=vG~UW*Q0_XnxOw;m%k zzg+s3@Emk5Cx;THc!&j31#%7qF-KI5R6u7TsYRp~lRAae`}o%C5QHGn`G&rw3y=|@ zYbvSJNvqBJR=fDWU;@)+=9{8Aq)uZ68za;O3!~avwrW#4)FtAL(iNzyhTQI+!XF^) zR0nbu1hF>MfYcetoz$76&LVX--_r=v7y`?Qu7v>c=a34p+eqqGQh#GG3NyU1(Vx}o z@&p}Fvq?TbPX;>Kz5)?Hq;*T(IK>ZX-*IB;sSuI(wfgJ6cFCm!iz4nb0+3KK$+ot( zlT{4-|J0Hz24G9@{}bFS_mlbnpSD8lho5*ZO__Vz8kjmDqg%KD=u_$l=>+Kv=>q8r z=>~z}I*-%`Nu5tBwDAH`A13t?PSG7nO$|)F^uH~{PI$bJg@y)R%o_OFN~eKoc&KOG zO6sC8cq7a;IF-N~!hiscL#67CU@T6++aD$MF>VA_$aqqhkop8Sf(l)mhHS`OpIE>p zO*FL1a9AYMa_KTYa0XM-B2 zOgu7FGG)b5$=$|WvdDME&|MGJKJom(4P81JYMgS-G?=n;WR=EY$jWvi)z7`N6XohARxmai>PJo)vk@`Hp z#W`{DdwP+&f~I_N`k(<;PRz4)(0B+Z3m^|e9)T=`EP^a1RUlO)RU%a;RUuU+RWsdQ zv;@f+yz$HQBNI~H?N!2f@dAImQt8}YB!)l(b+$4bG}KcBjWwv;b*NMwG}hweMN(Ih zx|$mSh&8Pzbq%R6Ry=5IMCO}91;1v1##$XT;=jQdFL=;>=amCBHY1xYoDJi{yO8%F z?~}TY)R#zI&)>pjL|_t3{x^{N@>zizX3z|M84CeA*ZBIvn_T_fE04eM%<4T0R1-C} z;%73_fO$ug|NKdBUXil4=U3~yJn`p`8{bD5K@@82L|V}9zfnUEno(ahPy@9N){Z(a z3pNlmLkB`H4nZ@tpVZe#eVtnjf@T;tHk}b{AZUh;a{GHT>RY6~P3k+OZYK5J5Nw=4a==D@ym_pGqYfMIF=A}tkFP2nY~*7QQn$JCYm)kY z7;NO%J~i0LuZPO5&+iCtJ^ykD2A)446=9#2d^peZuOjs$Qa`D1*vM~;%$tM?2BpM? zKgW6|{O9?t4cPdC)GyBl z*vRL}y?}sx1kOZ5!1G-`y>`gY{d&wgvNj;yH89nHjeL04^)vw0=rrQ|t{?sJ_P}M* zs?Xv-sG4+RG;HMeKzY558rR82elMMDd~L$Uo=hH}*isg3UM51Lk-y2aVD^l5BGXL`^*_O@)13gkD!_S+aY5hcR=ohz|*~x)Lo?RCUp;~-;nw( zse4V>$RCH~3>)Lk;{+Ua*x1L2@jZY1TKQnZ9)b-F1$-9{8)>Hq8v#@<6J{MYf;fTO z{RdL_b0f%tV07UCsfQ{aHu8~qkx{Td$d+FS%pmpPDK_Hi$VR8k3=rVY`Jm1Dpv^y$ z`V*-?^SAI-=ihI@#xJBEJ}Y2@edi1taD+!gK-!Zng4MeWoK>_&sQSpO^ZqblgB|6Z zW^t@EFNw+5TBi(b@caYfon6jb*gOVoEJ0d0@%~~P`A_JuapV+hd>OKN-pIz1zZ@s9 zP<|)%4{k9l4A?k&MzEnGqqSTB!v=iV`EXt5uY|k+Sp``Q0R;x(I8N%Hq@ExxjO|kq*c*98yfHHt|e4D&qhA{+6LR$Oxii&umSh=sdzT>KSf0| zW7c8gGn{-*S~b$n&H4LDt3lcYr18%1`3E6~blA`?BCY0G0UJl~%NYWGiv=I>Tvd#lUBD}Lk9)$UKd=;$uS;K05^6)14u(iBS>S&HKf%e z4H;fRT7A;4B<(7`wF#stq#5ct9>?n;H;{HUX^ly{Qy)4QOWNK4{_weiw*1b}MGD$M z+Cw^!)_}Bzq+!icYeFD;fE^p3{o~~0&`P&|FBsG&G@t!OU3d_LU~f z9ADkvuXXX4LHXE+?>ua%=z=+B8n#lR7Y)9CY?VQWdNy0KpyR;n+J1s%rXp2z!90}r zknxUmTdDvv^j;yYo2jD9x#V)eVq~+#%!UUs3NSeknjUMv!i$6cUcQx^3s@NW|nRPYgM`cr;M{MtW;d_vk#(uVOV42A+248utqUGccF6`Akkf*B#U zLAFD7kajC+BS;&`-|m9Ih+y0pMcQp=1#WzgM`qmkAr=Na_{_)Cf9W#lk_Sg6_1rvT z^+FRj5N@NVVKXHPH{#Q~H^1_o!HXVt_Iv2wFTcb7c2T(TGs^ol^p1Wpj4ABHj%m_y z!!6wD>9RRxyKW1PAshDZ<5e3L!k;>B+<{Zz2C{-b5*bAfW0Y!Mg;lwEJsxK%gb}H) zD*Jyza7vem2p>JBsjR)83lq#oW7c+UR19(9C3t8A)98lDzRq;tR{j-rNQ++mwGdwU z!urOomO>a0y!vY)%!l%={#w`&cf+{Q4U@t~IB5(4_bEgiO(Cq0LU6MQq$QD-Oqz|f ziKOxBuZ7n^V2l*rfVUHm<4ycpNSjRBJ)~ir8Zk}9c*|Jk>E9hfT-YJhh`lExd) z7xs;_)EY#ZgXRrjj61E>bqWU~qfuM{^j6^z$WX{I$Z!bQb0J7`;YiY)q`62-Bh5{k zhcqu~>73#=BsDc%;TZjIOW~b3Leu#SO&4HIS5WCRU7;=1RM1KMVVbTGh;=Fixe!4y zg&uxK{MOSTcn3k!c+=5BFC?9`Ow#m4NGp^e7iJ)Hc9yWBE6jwzUtgF_S{7;e%;9gr zp$qfS?V;#$NdtBK-_I{8oPtM&qAR>FmeP9FY1@CpEraLHT+?Kj^O|nhI)vw!6izqO zfLuo_y7|v;y!FwK2JTz^^hL*qzk5%EXhl~z8+kl{JXk|jeHkbB>jXL9&`|L^kMoGx zrBNCx!WCAy04W!m*)Tya#Kct)ddkqe@?TDs<^-(x$L0Y;IkY73B&m zT#kaD$M@_C3oYtbxPr8)QLeB;Fy%tUxYbf9lQxa9OeJl4xm;m|aJUyTGiFymeH;aJ%ao=T-c@k+cU$n@^goYaE3% z^*^9;bXv?k4S_C&??K)tZ7yl^NW&VX|9{pBD&!N$XJ|vZI(-+l!%Yz6|DkAg`W3Eh z<69XzzlLljZ2@Ty^XYbd1qbbsGg-l*@Ec^Ld;M8Ceha~r)WUrb?#mbjD8wj0;eOJ< zh!&Byn6yVpdyKRtq&;r>n+id-+22(7lX(PdHvCObuqIu~A7Z8RHx+{Y>-4<{<8V)g zsna3^`h=;|>T6JAhT&*=I)>p`bbg$r=tA7Xt)Qp|1OqZpk@hs7UIeL0+B2lBsBpuv z2u!|+5tsF8(WQ{fAYk%vUo0bSIe%LZa=D>TpCj%0vq7I0HN+!BpB6QWr5kI0m0fMe z>pjzEwW^-+PT|I?hCVI2)=Y!AooIdflX`XQE?Wj4&y&v`y)y6B<J@r(qw1}Z+W-y zB@B3%HEX2^6y7jCjXWZ>e$fCt*dRP*=~<#hgGnoi(ziv!aO#9(P-Swj%?PqMeuzWje*<&L7+_0T@VZ)ts-qTX=_MZOWKR1t>atAL9CGRhQ2MD zfFA@4?V)5G1#zennrMG}N*({RCCIDJrl#UmpLxUS99tf8X`4wyP^qN|zVeW5TQpDq+fp|w6K3|_|`5dR_&|Dyen1CWD| zLy#Xy+e6wnq8Gxq$9q^4i3i2dg<2#S8g5!myCfjtKqd;X|&*i)>t zeUP5wb4c4CM#qZJW!+s0dy3(K4`I&%9eZ{}w8moeqvG1Qi?OFT0aA;!L!|L)pv4zM zE+OqF(tcs=sn961V(|Q8_SEYIgYYA!UHe%d7(r(;$ko?n4~!HyLN=h-I)oKB#t9lq z@wKEKChb?!jsU`nn?jly5cV5szn={dR@?%Q%vIkq793IaZ*NNcreE;s&n8X(V(&MC z0b#{$%rtFdrP+MxsNcS=I&ACo?|0N_XKT)|7x}6?puEmTjq77b#h97bnzW;308eB# z-H}Z%BO6O`51jNQ?Ko+?a%gdH^im+li8Dct;(^F$1Q!4tC>{hE41s69cqn8TWH{tj zDv6_#cq*|_NfjzNhf1naNi|L}5=l+uC?2ify*SDI7UW_QI@1|L?8HM&Lj$Y5b1(tvewuDmkA@YVaw@d$ET~E})Xy6;4@- z1IRp!3+A33guq2#oJl2kqZd(0P5w3;0;fGZ@+ApWQtPbf??rfI?(fC1`fmF*gK7?Z zrB7g1z3rQoYUf>V_V=k~nrX4pTz70*x2Dey>OC`k(^d8>eta%Qe+R)Y*4aNgID6!a zXES9fx!COQ&77btk1UU(ERnBzK2knxylMkB7BFm-{6F%(13rrC`#vlP0xF;gq99d8 zMGS=Ar1y@1iV#Bzgcb;)ipr&=?WS$Yre{$^0Sm>Qx)dokKrDa=0)jLPB4PnW`JX#8 z>o;3Sk^KIm;ls)7?96*__RX7f&%JZ!&7H+mQz(KEU0@8n<+yRS&3)j#q;En50rOpW z-TIB@3wkvgFC2)EUPF$0UV(vVsOac7^<7QTZ;<0|9_j1IaZiZ?1JQ3`Z`Q&b7>GuO zOSAw$AV)(NM?)7!E99t8jt1nommCer(TE(4c~=PJ=uH5E_#B9j-ijX-PL3wz0O9n| z0s}q&3xR>?5BN;+^|cFt9FE>Yj;7>jMh@Jv53KoEVNbdpCX@)8$TMQi!#q}jGlLdP z!`oGgnN@kOk91+H~qPJ1QtLs=2W;2pdDE z^@yA_`=J(%=0=2vxE2p~>eMXIzf-3OR1$>Ax|%SjsLJ#rs068A;ip58NjxAsCu1uPTfWzcyPL2n8^@tXWcRX}GvH0k( zP!Z?6XoeJ`KKc}J8aM+WE+37!eDpWuc$ge5$ngj{T9V^Ya`=;@l@W`NK8ND0s5lLV zmlv?)+)qbq{?ms4Jf<5`@9CXpdrcDMJwa2US*HFyGe|{WG59R{4{`*!@mUP|r?3Ps z&XC4b@iWD+O6Nfkb2Ctt9Bs+bj#sM#u%hkB(Xq_+cT6o*Ufb0$JOJo#M+Z%R`_0SM zIIQvJ;`MjT-KgeXt_I8ya}Q7-07-TtM`v<$;cpuPjdXk5l^oq}1bZCw01g@UIEMWK zue7cOXCEJW@PodOyjUr-cB8Mlw$tr#43c}aGKk81m$8jZmD(o{=#gySFlX(`7Z4Hl z)Za0WqP^DKRj{1w_{X%;3~6`WkfPUNkJ0Bvj-q> z38dEkL2Li?GOIB?(Ryzj3Y*mvW{SQDmWt^^j^18oHKsqd4Agfu#S9=vAKrBkIr^5! zti}w(-mJpetj0jN$BY0*0;7P(fzjmXM~?pFK-~k$ftm;Nu44g&=3|h%&So_Rq4}7n z$uWc+!^oj!R5_x_5%cfAza0~5oYR;vat!rKsnTZt^$%+m8r(jlh{=#*rl5bO>x0V_ z6NZ&(sEr)MnMWYjV-~t*opVX!sb`%xt=15GRj8csyn?K)@1UDX@$j7(HXiF_s)p zkmE^mJVlOiTmmxNogn~faf-5DgCH~lYq zRIKS@BH-OM)5T~0C2|Ck;~D<=GO&sqLFAZJ=00G|T2#(TU$Z%{VFl7Z28w?oIfBU% z!Zv3eupZO_A25_0VK;=$k#NXtbC4YGZ9lF&QZdi*Vc&tdVO`UfA8N>N9s30PI*l?M zg7>mhd*6TO{K(Dr~4t|_IghJTSJj(LbcDaY(12Y8B;Ib#m^Rrm^*=M0L`#LnNN z4WzfkoaEzV53Pqb~FvXlT zmfv8B$cCv(PJE*)*eV)xjJ=v1bSSeW)$6FC-;gOfR9 zD*=e(A)ZtA$(*s(P&sCU(P$$U+B)_Y0H<>iIi4d2Cv(Q)@{Fyi)5Z(rxFM1`W9#CO z`MB=#MFHQ}i&9S4>r3fVpBy#qN-mzyV%mtk$0$?ZSD6oDPkgkYey`-j!1FDB{jN_< zZ`z23WRGp)I!BFk=U|EM9F%-=yV&Nag+;SV@Wvvtg~*YS%jtKG8QTg4j$&K6h8sfX14K`eqNCAQ-iTYcsiATq$8ai8LWui z9@#ZsP~0IbxYfh}_jyF!XE5)uX!gv|;BbD0b7)ATkqhQb37;{)<)qN4UJ)~9Xj8G{ zLsTRtO~-WZ2muw&3vqkPn0K_x;ITM{sjx2OI z?-L0?-N!=I$Ib!fk|UcO4sz@z$G0R@VKq0p@DUgF((3`k0*417{uhYI-b75pU8IlU zahmmMW&Jz)w+rp)Hm$7ZPka_fiEzJePZnVXWS&EgT(&3h8t@ua2i{To_us!9yBrlI za08GCvC%*b5DOrqCN>^01GtRy$x%QKJ2_U6<3(~n4X-r9Xt7Bs4j&{o#aO0dsfE#A zWv{J{%hoToxjBmgjm-6@I`PKnE&ISe?la7D-M}O z1wTIEG{n-Y)JcJ}Jn<;fN!iRKTNz(at|tH=dkPhC1YKi}(^xqJoCOeg zkNpPt7Wj@FGC6Q}NhODq9Gl3onH*b~YdDYIa7SV{_Y-8rwQ|_V| zv46Ul<0?7cc4Lk>Q|Xu^uBx9Y?iM~rIO}oMfa>JfPL3VCdMj`nIS|dl%e>2Y@`boN zP&sRRW{$Ypz@0!Ha=b&1cggV{e|r~DPiGDc=nrlL=7?*ALk4riAt&COInJ#4wZHSB zL6LEJ$**5Zt~6g~jyN8~T;@JsWoicxI(_-4A%l}gjykla`W3`>J);zNR5X|y013qP0r~>{fd0S$U?6}%`KRPS0A)Wp z4v+)JGP>5#&xA zrnnIFn4Y%l_yRdFAJlx^b2x>gf2UzDjX9=ZWhyz2k^_mHrZ~v#xEbX5k{n+#bChZ7 zTpaXyoGbbs7o}eg$8|#*H&44994CBS4z(Jr^ZW@2v&Rwt1ZEqA+2bIX;}(3=^y&*U#9*4|)V)n%+TZNB?9H}$tq4nJ!y}3Ufb{HI#Xq15z_vWqs zfp_+`^c?ubYhe{F;rk+-J~+sV_R{sUt&>NZMjqc7nj>x=YmO7el1C1zf$r4@O)ggQ z$N>ewlYzz+=;ZPJb&&_0xVYE30VWRw6XJOJDzF+@1FQugP0y3#2Xb5>$B*Q=NRFS# z@iXuF28tS*BW}I+*%Y@COK6T?bj@)Ya(PO!2wj1?(orZ{$EerYY`203P=h5=>>UJocgTgWND* z-}?ciq{qR4{6UUC$#IpxMQ%#mA?>Oc{7Arbg#WzH5_cSj%vb#hUsv$JFGhcw(|cHh z=#SgIIKx8mxY@Nw0Djk4eA=SaJM689~5 zmV}C~tNwdj^+F}DtG-tK2RzUAMbz|*Q4`-niTj!PL#SL#O`g?UK}kFcst=k!u<|Df zH7_3%f0WmI$uL9f*R0XO5)d57!aO02oraFIAXpZ~V z^*;79mNcpMp-rm(P zqVRCzg}Ze15zqN4;UxHaom#E>yFA8nJj8N*Pp%1!6aN^{9q2*AJtWj8f#2sI-wWui z^U%E{+z{_`j~|3X2B*YBqI)Ze0o(4epJ~uz;?he$4BYTQs=-6?!;CV}MBC3C&2jj|5!05Aa+W+gokL5%@Lj-n%<5@!`2k#)rj=v=4=D-Na9I zH8&k0X7Aw}ffhJ0T{r_NK9YooyfTpD5r&S3tmR!z@pDOdn3wZOXi=gJqzwx*xIRhy^7KkGufP}Ur zOy$I0VHye3|NS>%;;qK1icck>jqePkR;?$71q2oKp1OD&`Ufc_Iw7TEB@4BY(2n^D zsy9BDg!UwiU_!e745WBFYJADn8V`sUN$5aAM{aGUmVqR6x}FTA_%*0#12@1{4VpO~ zi6-#~CC9%3ya^!1Bz`>!ok{3ILRS*Hk?Tc7PwwU=F2(D7g6XR@_J9*no;3R>IcbV`rjrX{hf z`W*J3U)hJ{I)}19xX#h{x?C8l$pvH|;e3a4{?Yqh3fl8j|AK0eX~L&kH-MKk1Bm=a zRDsu!mn@Mf{;HqJY%-1p(F2pY0tq8Y;KW69MJ)qKK;q)x&ptddu#DG5(>{qvowog#GJFyq?R$_(&TroqZL{r3GZ>{d$~ z`^uCDTTJxk4Kq?@%&eNVb2LQfjma8s_zmC67d_Q^w|L$#k4805=+$VvVIHgThLO35 zsvw+Ek!Q@mkdie|Fh(8=ns#mm%REuvRN?%2ivPfUQ8*1xWoEtsd1 z5aFeN%`>rUq`s@kJc|VFDws{etP<&8^E?!Po{K}&n&$%xfQ7)b0K~ERIT9eeQDGDb zb4Y-~p2xdFBAXWjh!3;=H7^C0kpSVnh=h%r{&kQb{QLEuK7-kv zXG`fbm_I~EyL<-oUaY`pNFX7R2LXHrGkk_55>m=MZf1thU_R`+Za&uyTCy&LzeHFF z1}%C>2@KkCRKq%+T@UjK;49!H304wPNl4>wPXlLk36V}h#*N^5n4$bNIdI;W9C*9m zEvFtH-*>kC$odgq9jY_PkPtr_WiI+Eb1b#a10(zQTbws``SXXrc|X^Ogn-XrF6=Xy zb)O;A@EJ<@vIR4I28+vQu;4^l;4@^Ckb@CpfzNPECL#BFUbbL?&tP%+3>Nqd7WfPn z_zV{K43^sfXfF$VhCCATNhlz}PQnTjz+NwbHY~TJn+)2p7(RnV^BG9MWSPtutN73Q zaz`5$m(O5<&+xJvZCE^ghP&3G7j>VZN=qL;g9Sc=#pN?tT4Du0!z(1b%A){2g9Sdr zY7*Wo^H_rgK7+;OGg#m=Sl}~Q;4`ctVJ!)-;exloXRsJP!|NnqzLvW%Cb)ZJEkG@OlAmsHg~^!Q%26EO0B| zViD;!i(=VHoKG-nZ_{bg5{zHSPXHJ9x&=!(@5uTG%I$eC@7OXOKR*I>7IsZ6Gf9xV zToVg2Q7m)xT}>9a4>D@Cz=2RornS?DQY~@{-`1w`ngyk~bHL*l%=T>-o@njO-(L57&4gd9TTd*YaiCT#tngSpJ z#e%T91rL90BVjuU&_X+TXt_;*iODAe17}7}jtmV737i@}ZCWuo_lHz?sKPTZLiwO6(^OPdqP?SgP(8#_|pDE$|(1j)Ws5py^{Id`ZG_5>Alt6_Vt*eJI03Fn z!mZecM{fdrl!RMII77l&UWJ>IP=kc8N%*$RUFQU3$0x8ygNC&%tOQK20vqVcy&TX0 zg6yS(UV_Yn;1e34n#NoWI4I#>pdrwRgzree(E6UgZ2~j}5#vHUPr?s3f|5>n2!{+0 zFyUceZt&~2Q>QLB?|tX$Oa4EF-u(%bDn9_6(9$ULsIM~Owv|UFKR4LE?Db8Xu8vE6 z)>}y@v_>6mjUMN0wFGV2c;QD~0-H+OO2bpwgDOXO-Kz^h1ryP)~a32-kG;9exifC9ju zNN|#PCy8}PtV`luB-SJGZnzo=n}IF(5eNYAExm+o{F%giNMsAjp2n#Eg5R95+c;4P zdq}L$W614B6mH1*&u`VLbx?=kHm!=7Q!C+PbkRP2G@BCGs-n7kQ6m%AegOViLlU)Q z5w`|fcQhJk)3&33a3Md}Q;-}&B}ZHh9LCBQBsL-uS)HbYqexjcQ_1UBv8lGv2QW+dK6;{7B(Kw@(eA2hO25?GZZi7nv= zW6AQGvr)u{_)iP|(_S}^Uq0y>zxPu4x_!Vv z9uunq)ku7V#Fo5@n*fRE;73VpRpzQX@pe?s_Y1U!@6b8lU+4U9zS5W>?y2IVrHS{T znuc5r>}g_s05UrfmkD@3fW$WZZ6g4}8>(7tOJchl!OA8!$05VYCO+uPV!o8!VdP5( zhs|x1G;Oa@bl}&76lzGHgnbch8_W|4c_gRs4_GrV-ox6Bj*+hS|7ohjJW*!q^ ziqTCS4D-T-8FBGh$aKLF}FaR4xo#I7WEBk?g3yOY?1#GWMfGH4@_MLB3AahS1Wb*<3` zr@e}O`Ok=QM;nQ*9Q?%bB=&Kqjb}Dlm=20VED8 zd)k(d83|s=8d;!8MMK|n#)*xmDxDt z{k`>m?KOY-`(GS99Xz(N586mVSu1xHx|p5u#1xG-Mi$fKg*0wrCXX(N%)~4bALoZT zR^Z+O{&`YM9(I8q)-O+=y$YuG^C`w>Gl z4IBDj(6EVHbv`g9zKtKb4cHFsAn_RzgGii6VlWF^w|hUWTVMCRAI#=d#JwNP$)wH4 zUYdJ9n69g&_kI$0xkf2|Cw^Yx0lZi5j?&!wNkl|F@t|vjLVHZ&5&AialX-;RF*#y( zRA@+_kZ?=^-!F(K0bAgCH6YTRc+6G7Q4;w*<%wUCIHhDm9O^sqTQ1Jy7V10kGywIT z2=$!^^_}<)iHL=Osi%{OC`bf}GkI6Ux)aXC|emn!@x#`tfp z^Zh%Ck=}lq{vN%MwxMnPgNpFe60iE1l5Rpj^CV|Us4@w>kYoZX0+mRNB5@9h2>i?= zaX#-;8K?q4dM80~CqZ#9ATfi)^(5{l@iZIF?rt|QTQ73W9~X}I1YorE4Ue2YFDNp! zd6@BmCpzooK8aihw<-eusv;~jDtNN1f-#tUE<9oeCXD;vEN-3-Yg_gw{X^P@wGV3V zKI5I6-)X#f(7VGt>udAB`dSt7g2E(t2uUsvA?XgR)FyEuiO)h~B-H^BU06h7`rr0X zli)5Sar~8qW)l2{Bt+$t5S34A1T+Sk0B}yB3!W$O1risNNF**HaVeL$4@HgeZ4&Ew z2+kyqmcxr(riX81SZJn}yYOuiV)vT8PijXZ?ur*;(xi^O>3{yIDT!SPJ@ZM7=G#6s z4|(ulQV;ZNZ|ucdGpQ%gi^NzG<9HRWK~i55<4H^?bFG<#=zS8$=vn#P^fp#77a6ps z*-$=7!=W`ri-yoVH3uwNn)Ab=$qO&wsVctrlY}P^v@(-?mASmg?mv9~ zfQ%RKX|ia<24$4D+)P4yV-&LLjUnGeg6pb<9lqA6^ zNrF>?23M1~hL39luu*4>wIsfFLof!XATeX8zOMd3AMCC+v|9Hqc^CH7ZFcAO?+nJ+ zY?Q&h0dJOxT_+xXe$b%UO{YHDzhm=~kv8`|6HI!D{}NFuUOd1l9?;TR1Nua@E? ziAlS#`-gfpnxC7rMsuMBH21$VYP!0CT)`UCeP5 zm7L}Vc>Em$z66c~CxEX22>+y0BsxeGNEAtwNR&xbNK}pRSkhS(XSMQ;vE(4V79Mjl zX>8^{AC$ZBSkkX9=D0-SCU@reoj3iDIgIG~HKXduCO=cM<`dwoCszdE2W%m6E3ZQS zC*yAK+a%(_zcQZIF&QEIu0bMX%XSiX@VB*q+jZL5Ng@(f|M_(7 z#E(h*gv3ut+(+Vm5)T;6k=!4}!5qm0jpbl0HRkw?N#k?=bF$nqNAg&MIg%mi z54tf&G9-Pem}4S3HoMgv3K6a;{@?7%+)M+@?KR=FU#?G*lj;H>^23$uqRe z;fOJaJ2uAUQ1GOev*S64p_P-7(xMa4T&&Ck=974gM1-!6GXWv?p8Tv%KqpB2>V_bo zB{*azpryXZr1t26rpt2%u3xnx$jVH5KuhICKx@g(S}8%jZ>xU@l;fkp;u!{PQyw%iDyXUyvSsmP8(le7i}OapZqd6 zz_gJM6aaQ$1;DNFNnJ@I;)%GK{~d|vNc^6}^CbS@q7Bz_HL79ySc|1b8yA={F7ls0 z%O7p<%>%wIk_?gdqdRRtN0*8=-bO7uT!Ua6R$%RaB9T)alXn8|koXIUm&%?tpqi6i zs+nUX$xzJ@8^4y)_CYl#bFf^~El|zLh@K~ZM&e}>e@I?Xl4j+8T+;!kOIeE#lz{m(B9&msp`IJ!x8s3{Wj@rlUZnk3Z%bV(7KJ|zN z({gw{W|oZ5eKHGn)-4)sU{Xlj#=lxjj~5EUCI4s)yrhbVO1lrdUtDAISCUM8tL~jQ z(3aP&y5!$+6i7qSZq>Qo;fSZ=q)J}5>QXBBnNlk1yP8r=B;AA|pHhjW$|bswk%BOJ zN)0ZKn-eLBm#0(%ssqrvDUi4+w~VkFs*`jJ?^+Xp)=gop%ZE@KxRaz? zNvc6oAMHLyUy}OsK{N~x!3$Nw!@>~_9~RbU{^an9;Zd^(%-~n7%;fh7*Q^_=-KjxH zJu0;4f&qW+j>(nvm&oE?j$Z74+hzyWY#QqMPC@QU3Q|^5Is-@uPw7e$hD05b>XLL9N%cs&o1}ZV z#A7JR-T`++Ph;5|%lk>HuLanodttSt2g_Y>KV_I}v<)Yzfg5?GjN(lz(Mud)_zTx` zlT#4$P8p9~wIMeSD^HVzQP+qE!2}?Xq{bvYQ08uON(d^S%nie^q=W*H)+v)nYC=*| zlA7_i;lLD7$7dwnN7DT_g1JeVg+qq9Ns07jIx@vC^SU(Y|H8_=6Gy*)Sb%(IbCWX1 zC^OernHH9(cXj)7(671sq(@gR8?naQ+@vf(9gFmHr1=FYcwl22NzHY0bFJ5?dAJ2B zOHj*lqZT$=Da+VsNe`8-7BdPa>b00sELce(sRc=o@OVkmrd^a;UeC0PDe0&vj~ieL z$N(UqQ!;@pAREX5a!GoWB!7}xk%Zq6KvEl$+8Po!h4WXKG*%ePm#}21E4AZ49r#bL zawm0DAR=@V^(IN}-AQ9ZDM>>{=Q{Zu@mW^@m86a&b>h`cz-E#=hte+#DG!AK`(Nn+N zOFCa-%5hY4(x^sb4Fn5t#q};QUM6wkk*?Jq!WCbh{9L5b1X%tCg zNLr<-;8*?&**sQ+j!iSc0oHqf`XoJ0(rE9b9zB<(eQ3v^_7e*~8{s=g1^Z2G?_WfY zinTEsyAP*@IYDn3ONhi~-N)0<@Hvj;;JBwhJzNSRUie z3e{|Nsb(uwvlXiONs^x8-;MO{E;~uWD14S1_*;)`SfQG&F4b&>YPLc(TcMh*P|a4T zW-C;)6>JBgHlCyjBtfD*LsAe)6Ac4s?T+q%0krlsmYQm2vlq;NLix|ka%TXoF4b(s zwHe~ZL)K9|a!an7tx(NYmuj{`HCu5q!bqCLg8-`8ic>O~q$xZI%Jj`Y)(})ai3dCQ zmt#FvP(P$#xK78W?z0dgUNN<}5V3VSO0tsGu9+EFi2!DjG?k=jBu(dQCK8yf+tC>$ zVN%b3{vMTeAr2Wf(aND~uVk2ZvNbZ~rtZxY>Gh$e*;O~{cGUX3QRW3-WoovW7Sa8{ zz~weM@LZ2UBVPBmqt+#8udr;k>auxODSI5c+3M2GR_JDH0!c{bjN%cKq|?Tn>!JptP;|=%!{GOjbiT zTQ%KG(sR1A{Q}cQe7SSBtuEbcg>J@VNrj||wUoNq3f*jV>1Hc*vlY5|F-biCq!qf^ z3f;Vfq-AAK8{1L&J2<<4(Z)`VHkKNLxZ4rXhW)o9DPHm*#YPc<_w~>U`pA@2v)LNxe8>x4pbMHZ?vb&vH z4?u)8o1`3GMFMqd1Cl`O`DIQUsZCJ1Cau8}tTs}cX|$1N&_=Hrpp6&17e^bZ52K_e znL!Y#(9fxm&8d*h1ti%?TEX8!Ij6SLY2!tbUb+!zBees%9JGZ?qLH`9h+e7{E}`ZjyvmWHNb-n5b09qskfPqlVuDYd8O zZogbij~5*ZsoLK&w%t?z0|9Y@k@EAR#Ul-En-W2XjTZ;lGHkDWRZ2nHZ}QxPFf z4FeD%euE^K;&mjgCusvo8+liRic=9Pc1>)MI-Nh0^cG11#wb59^YMSd#ZH}PoZM6h zIER;Sjfc1RIg!w|0d3od6@E^{!--8@gzjQtT!+sNSH;U0ND>!!^xSm`wix=?l)4lv z%Se()l6e?KYtI@>%Jn>JoC-0Vn#RWh3zV7wBm$7csmVYJU%Nk(|0oZ&fT_Z!VLJ1$3Pu-4c zTyf*n9aur!IQ1QpJ|JlqNxRtsA#R*%#EtimgedGk@9(BE8?y!a*q1eNe6ZghXd4=m zc2C;XzBh;6XILO3Zk*~fZrm{bd`7(&dcTrZx%a_$f7*AzhXp!__FQpe4)~@bZrqxr zk8}%k%^ojoW{{Gh1$VVx)GK*`L?MeO|>7iU`m$(stLn+m0y3ZPY$$G?8{Ya0f}pN&1~>!tJ?5JXXvT@^Aw|K}7^#)9Rv7@fQxW0cky6+Orez_g?_0h$7EZqn`p?gt(K5Jo;l(rJ>;kaU(LjM#5T z`j$&PgrbHqN_#~6Y)WJ03uE-1Zj8QXV|2OP8KbmLt`XLmq;qb@D6JcBT8UozD_wy< zUo&MPtq(f7KXzebl-3vMM-r&u2VNZj3?%6SN!lE$Wg2`<8-~h9>J4kgC~bshjEp%E zuSty_iYo01RKpUPqbO-l0?^E9<4F36q@PLpg})sSOwiq-UrEAS3;uaylopCZhA~PD z^JR?cANy@)$Qwg0Y?%1k#i^sG?$V7>TDVb$vpBpWFDGX#t~;u4-+dcjJuoOx8gkj& z7^NXjoi@|xaW+P2h(p5|{Z@=I^6c@sD5+&c^AMQ_K=NK8=?`9AsME%u*F_tPQBf=( zCzAjHOMs=oGGI9n4aAUim1IAXE0Am=xgyDxNWO_n#G$B*Huw=jCL9hH-%oO7jW*<) zK^yWN<&QS9T(pr*aus*l$SWmntVE}B$V#J)m$9;n zRKDKT@SEDhaq=x-ju-tv8Tb+5Jmr)3Q!bu^SVT1{SHlD$0f;82DJ0)Uat)Ge^0!U^ zY8k;-xfaQ{-w?F11BcACvC|g?Y#!S8ak343Wo@1CGnKkJY8$lio>As~Uu8o3uNwdK zw?o^+o?JlhE^6;%zMM3~snhoAJ+4Jj(jezslU%zP+9;%9(;%NU4SUl&l#Il1&y(>v zT40sT($$rFoAw3Cb-ko(8lDeK<0NJ5YD)W(oCL}+>ArbjWlAq#( z_;=^trm;Zh9R9RFNN(&cUbVR{TKRYE7*u5PZ8|zBy^=m?P!(1{(2YrM3Vukx38+kR zGm^V8Ke)Zi1Ftm;iwv6XA2=#-cwn!H$WXizE>NHGCa~w6urQ<-2lkv65j?e5#LNXn zPMqU0$kL&p({DA7D7`vXZXx+TlJDmux((xQC&>?7Pp(~hZB)dr8Jn&2JApa?G30JdSMGdo+-bnjwN^gQC%+{m2*=ogRt4p~v zTj|jL+K^0dNwUA2*-CH4n^vNiN~U(xJD{UGV|O-N=^cSiB!kNWcomr->0L=~Lvp(^ zH(TjFQF$M|VNLC(_hz*#w>3!gT2uLY4&p(mW*Aok1C>4)7y=9>xjo4pNbbnr4hKf) zW(z;A^NnD((x1Q~!)&EL>B|It<5<#a`t;ttHckF5Ehi&niEg&iS=4ix@xIEOYD8Fhr(k6&$&ZoT zokz@cEw5khaXoqc>6lhK{aJ2+NgxWC13+V^Lt3ZL2NnPeN$yE-eHK-5qZ|HcW#ZZ@RcMFBY8NBqeZ1h#;$FQZ{VrYVtp9U*x_ zi4=1BaqP{;lofLN3E(T>Byb8i4V)o4kmP4b4kCFX$-yLt@U9Ti>71L4AO$Prbf|3j zVsa?SlZ@bQ{(m93oBpfoL|q~|>>B#mKeSE94z1f45qnL)f-XY*TW1v3$Ea>HYQ#03 zffh0l)j;oQ$xH6RT|Kilv`s*8P-qc1B{LwhGj28-$f%5!DkM)Kc`7$hRg2Qd)2=5< zlL6bDQI{Kl70Rdy;Mv3s#HBMZvt0(Xa0VoBMjeu;lRSgu2$E-#Jd5N=l4o;?yHM1y zTN(FgpG_Gofnm3zbh|Z|?becVXSXt%8zU?OUcwwVmdI$qn@TQsGXl`j?f4w=S#JZh zC3zmn^Le#B0L{37-O3nnxQH`;ZMM(K8Iv1YeS8Dnt1K?CH&aMd~+>R}`@o<>c9dQF<` z%9x~V+#uyMW>MCYF^o&qcGud@OVOW_&@^X@+dC-LG%n@^4%n^Z#kb0pr$4sou z0wMuO;S4C?3@G4?xg^Ju97l3I$!3x*Btym}8d-7~9Djz=&0yio%jdAeG8n zA6i$q`{855x+WgmQq!?y!ghl>43(VWQzf^Vax}MB@X&^@=e&ODuD5UYp?EVkpgo7{ z96>hU^ft*kI&%bAHRj0M?SnZyX+uRdoAqjR+SsJghAS^IzzW(xMV_=#Nb_dwa1A^J z(F!<6A+t6r^z+P7$ao)3?ZWpgV~;&g(KVn=Gj@}_!b`?x?8TOk^<7OFACdeb@A?VJ zFO^8fW*orYN4Pk&X~t*3K>%^)49Me*!vMm|@S|QPc@@d8ko+pit9jR>0AkD;U*bGM z#%7$*8F&rJuaW$&7U+HNzo26?zH^yQ2`iULeuLyU`D*@MdwHF_?s{HcXT#~TRpkaCFKs5E zB2Wo{6t+PD+o}LJlf0hf4J2qT%sC^8iLfuablPiTMaBBNF`m6Dr{DE zmODXeLym~%o7xb(c6VEC_wuHan-$xA=v3%iZ4lV*$I1gFt0X%y2y71mh>C9_d3%|g z72BhzJb)X90kQc5t$@}fZzg#Q$y@nb=wn-3-K>B}x7`S4#nuIf46|bE>dUNDeDmp7 zzWcmqvZ{tpO`G(9alg;j-6#Y7?QM#tufM0CpEw|Tb-{>HPt+SX)mxC-dZWF5+*OEq zaGtuYuNJD_p@%>!T&w|mV1C2P9(Y{uHbkav!;NY<{%S*pHaZ+xjvOSoW;KP(ijCzj z-;2_i#ZAxHo^p-JaU{Rb7AJ|*RlO{ZEf5U{;d{0?=PyzG9#m&T*aB~%_B>$dUfU#n zSCcJ_}Q4UJ5KTer+_CF#xpwev%LH z&y^37{5i>o*eH!GJn;|Sl^z)y95G`?XmHe+@W`k+LDPCg%!rD_Y(k-tnDKvH_>5`c zGeSeg7kOVWux5X^N&||nwCMLgyS*?Zp!K5B1IC8W2#J{2a$d;9!0AC#LkEQ}=rJQ? zO!(~ZiPJ(o-bygj#~Zp^E$SXIaY}HbVk>Ih-gTq2_u$rny+#F&;wAnB1`Zhdc%P9& zdkogrdPRm}iYNW3Jl_7;y4^La;Cc#|ET%`@Lsa@R>B0UTIs^q3@vONm1?L?pDZ0US z4G8!ewsar^fTO_!Lmw3oY=~kWCHWY}1{>^b0Ks=#E=24}$rXTb(%;Y*T#C#4Q4 ztwB>jKlpfTWjh4ILvmf{R`(|dZttAj{#u6fY6SGwUFn2dSnj!wdoL0RDJsE zBCuaa>{;kF6`p*=zmeSv7ECte)Yw*&e4OMHyt>w}!Viy<{1wIj!nX2nJsWRZkBYR2 zIkyC7!nP533vd7kr`tq8BKaiAr$|0c@)?rPlKeHv-*5>9$L11Do3zg++ZHS#n7-8o z(>WGQ1ISTfprw?KuZ4|((v4J4J zC;2>&0{AnwLnQw|a@pr++TaD*PUsEmGT^u-11{+H+hjY*(WD=}WI(M3cYFQ>+#0aq zc7U$ESP3A}#`Yb_@DqL}`4`q+$gi=T*R|KLB;ODznzmnX$gI5(@%PqIzy5Hr*NoqW ztY3Tk?3=qZn_E$L>21FmWq$WnrsAC~;y-z1$kx~A^uOchk9vmq&|ZJ~nKCOFoz9{u z6YnR2XfjeXui5DyJ)T(wCE1_hL6dniP?h8>By);pCQ@IX_b2&J+OY3$Q%7bkR8)@} z01;%~4%`9M2JQsv0Cj=8NWMynA1M_`F_BV{luD#Z--dAGJqJQtban?m zPkiRv0qsetN(!fGW+MG1vlA)RNvT!l{#NE=s2tIK?V8W*j+GujPf~6n1t<14T=SXm zGcu79gD{>_gOr*#g1?nH7>A5&K68k#>$map=h>cs671~YY-^Fc%x9QAlsgT|&U^xtjk-J|d7jlwLN!xd2Q(QgID)#Q+{Fhp zRbvmO-gU7DyrE2v;A`xGz<(wJ|Cv$19AGX0KPYoPDR+}{4=MFYX+X-oq%fDP zMoq7CP0TiHfVIGDq&!3l*tG?Ji)`{t4!?tg9wDXW4Z%SI4w?Bx^u;Ha#-5w|Oyodo zTIDaqt)1~U18q{wOvNap`YLn2`p_wNSL;3@=g-rJOrLB%>4SqdqrJDet6a>nRbvi+ z7jwMC%+b79=6Dy?e4tlj%6tziC<112 zp8*F+X-i5wQreT!fs~G1^iZ(PjrEh$~y zndAFXGRM#8+)I3p_^kf|{7TAWq;SS$=4IeFQhJcmuk1C)RXqW#syL)#Pg4*LxPEdRATi9BIy7RvmWkl>Vi=-m@B@ znnp%7?5<=r)M#U1DXY03B_GtQF=ah~mFA=jCWX^0vmVlEW9aqJMiv78Ssl0m&_-4( zpfwNxv;o=z?EtXFFj9t-GJ=$mgm?KVkCQUmppC3fC=S}l;)pyi@tmbj8)KL;p5Q;h z<&HM81{k!FHIS6CZnTjF3GEi?(1ph}A4JW19G&Wt!C9lRGKQ2VN#Us=vz`F(c^oN0 zWlkGeP|aBrd2ld61Om?hL8LrQ%6L*H@VCK0h)x@Uq(D{Q0JJd`hs?Aw%@+maEDU&i z_@058x%+S5Y#VA%GH4^hC^OSnnP<0$_ZWGh*N#{J7#qGM`VDq(JQP(Hbb8iY?kYYh za6gf8pdhVYb5)AaW}ek7LTMK4F13+`>@UcKkW$jda#Vwq7yW2(BOxn>lrU0w-pH&t zoi-+47i}b=A{#frw2=&?09GIsNCVP=3{oITr;sw0lxd_)CuIgH5iZ(*9n$C`$5`fJ zsi}>b%ovgU=ehDn8?U-(V>KzW+-c*rQqsmooB~$N+K_w;D-Kd-lfqL$W+8r^C6O|R z6m16CGEL3T+JwqA$;<=+{hYN0*h7neD^Q#z#C9b93~k8w}b&&{`|A*H@Vf)jw}me`3!g>7PzowetQ|b|16>p`Nwh zb&fy=OdE@I+Gq|+f=idZ#)nJiNgGJp$vUc6qlGuJj%c*;yg?hyBjBWQkIhv zO$w+hmXtUqnqN`W2##j`rhPVLUBMFWcD#09MX@k#*mT+`GIy~g$&de@{Ko7m25n^D zOp4i!HnOXijyAGy_cLYR$>#`XJ^K!zHYo|D@Kli5b%460B$1-M54lWfBfCB-Z^R9Q zAhMyKv+o5E*-9oQg%r#ZYszj6G|_1zm6Ws_fi|*Po`W{BAM!;3!OI%%2%FGnMBLZM ztHkXUAJl0h`w^oI0@vPDQ*C3*K1;Xsx+!7BQ-?PkzH6K}ZDd2JXSd<5;*-)^rw!ym zvf3yGZDe;s>8^S;8f|2E(P)E%Oh`mQRlaGXP$EipFJs`@<{?4Bec<)uO~`7H1s%0XnEZp?Ztf6*LUQ~+?_6g?9c$)pw=dH* zs_OVx4|ePkK|R#k{bO(X!!UPH$6A?>e3hwssm_=o6NXk0_eVDsX(GLgo zbEL)OviEB-xt+S5D(Qq+**nsLX71iCWi=4S*=O}?OxdTga)uN{^FQDb z^R-SJyRM5iAdItF>T0wBg`5qAoDGGX4TYQyg`E8}@CzxsN!dfnhotN!4$bmX$3dnib7X_TS{BYO#`};h;_UV(c&AQ#SMW>A%sAH|nqrS>y zuj@R=ulmq1<-Lm?pPG7lxHoO&v_^YvUFRr3SINgTm0X$$v2r@28jfkZXd|bqMjOYA zp^ZW+Ij6U4;NjNFSDcfb_9ZIx(y%!L(9|G&U-&7Y9K`!idF5p148yL-tKeNtIS9?4 z<|TsjXG)Zloihe|YZ4g3G-oV;KyuELz*7M9aSmkhSyH|xC9QO-2wk59PUW^qY1;+JPKJKM>7!LyQ5=D37nOJUSgpJyl&wo-(n;G<35s!b6!U^ z>#&bz&yo9*^CqbkNv*`AU_G#b)SF1H!lR%}lX`LxiO*5=hBa-QBeS+uE9=(9Z@3Ae zfjY^>g>G}UqM99C4Kvo;z&2nzsW+2amDFnd?M?tM=Rrn~TAftP40!{{f;~87mIa8T zdk4aPY!Ms+E#6(YuhgoA4Oa-dPwm%j&k8VhO7xA>BuU*!s5q(#7URN)(neu|>UxexsQ#-ZiR zg=+K4md{1VK6fa7JUb>Q-=&x=nBClAq_*^OOmatJ%j5d4rrc4aKFYg}Ce^=0j!7g6dYF${ZcUTk{IB{WUWJHl#+_N==@^crvT6-QVFOb@W z)UMnb`BnI{F{#}s@zmee*ts#ND2W?@V$O{PAi8s*wR54hbD_0!p|x`pNqvme?xgl0 zwI`{)NbOB(A1;xMqK3xKP1Qb|a#?FbWB1iHc7L{&qspDe&b7Nn+X_w z)FGq}0)r}lj4Z);;UK{6b!y&Vg+wRL?4gXj+@6G8`Y0KzGQaXnGzSuBw{PImM z^RBNlz498Y{A5qBC7F(g-mQOVINr_anZ}m;0m`x_$2roxk=)&yH!@P!#wC55doBX@ zxvqdcOYB?(?7`TNm$DiJ>~oEPy(#wyR*sT7hEz;BY0CZ5ufiX1lllZDe(?8c<1{Mz zo_{Wrz!?CVI~P(rmya1zJNG-_9H~!|`V^_-NPU{r@uW^5HIPf3M^P7T7*aczr8a2e z8J#vJGHpyRf3$Jcpp85~QiI%RBd=oVXd|zhpDFKFeMp+}s$=CAQiDki!63-H4X8nC zD5-cCbs5t}9-{hrcX7iYh`c)iXzn~XSYf12B6Tu+G^tP&1v} zhuveY5efT`#LA{yV>vYB6@t&}jf3cm?^)@(-nfw0kJQ;-N;hvHb{(wmYRZG@ih?T3 zgGHHBBBh%*0((Ef#UWqwpqleW0gnTtfib{XQt>pJmtN0H6!I3MqF8PKmM4#ZCBRZ(8L%9P24YBEM(T1>qe;c*SW@Fi zjpq`a=wjHaJPwA!tE!K=V(Qj0D$}-ggJt0rhgvtDefIr1{p2toCT};|+pG7uZmhI- z|EO8Iu|lsSZjU}MCgnO0!RS0A7;VZsfR)ckMW`Z|N6hCsZRA}SZ6Gq8cZQFXN#IN1 zIB){^3OETMoh9!ysrjT9kZLCtj^2x;zC`LuF2P39MH}C0pG|q^umo+qtkcFTOdA`^ zA8lN6(Z*#`SGm*1mD15henmf1eq}yKIP3Y9fSX8tmDJU|S_QyOoHe9k=EyRpjeJC` z^J}^qzD=i%wK{F&*V1T1MQW3PE$HVn-j^8qvBfl1y1KsY)9ECzJ z`B2GP43O2yb8cfVzawu#RdwOM=69yb7fBT%ce_U}Mw4E0H~%s0)dSzN+&ylg=rz!= z`3R25UUE0T54QBvcQxhrB~{^F`;)4cNbcqj#@?g2I5cej5MU@U3>XeT3+Im{)k*3m zQa6*jh19L2zRkNr5$8h@=Z`^mSHKd9D*5oow~@MoR0Q|ImcNsF<=?M&^Cuc-H6QLR zUZm}r)~wHt78=y5U6C&s%b$b}nu3nj*d!P$kj~plMYg0Ve=0DI)OSezlG)_{&kM%# z5ns-q?K+}aScxR{T~hIOZBu@fHgCH6{`Jh8p1%+kE#U@Wvhtq=76Ax4=Ofmf{{pZW zfExdR)Lo?RCUp;~ACkJ4)Q?!MK?~p5W2) zDa;j2z*iLg36Ge+m6?_QIVw8N4KQsS0uBQRI_D$SoPQL6c+UTl)RUy1A{8R}45?>H z{hCys<}v>SiW=HD|CILGl+RKd+E}0FQRQhK)l2108|Nb!uIZC}s1NsP9`lic;zk?% z1}ft%+*f=gX666kXDYxR`XKldy?&L{?@8rZ9t$7`3QVN_K&m#^XPMqLDyV|Wt8>G+ zvI}kosshzWy+G=Zq+aB2ZvhaR=8USJNd5UnP_zZLamcvd3-0uFy?;9;s?GBI`yJZU z{k6I;4%=#ke+xLu&1LHODl_`AZ(lCh1{>{8}rW4deoRlTLCrpSB> z4_6>Sn|QfZKwD&nw=W`^T@Z#23fHeFQ^6#?w{AgKF?mh_rjqkka$@!}4_6?dZSgtT zf9qYt1rca9(se}e3kqhD^EPtU;3Jw1M3J*5IUo4jHoag0Dj{wF7P^%>0=NSO za0d#W2jC7AEGB0ya^6nPJIGm^oOhD54ms;`i6tm%*z|(s+GkTi43_tk^DZsk<>b^! z=Y8eQrWaTZk}OCiXFYfR%-~Hc(MudH1S*?&sbyPN_|}I}FUUhr+p!NTyMlb6fSmV` zvp%mfW4=hv2IOp5=Dt7ypW-!o!i?s=hw4{fj$b-ZWvIH!UX;8j7b$$5V&+6YG!e1+pf zSfar2D+)Bff|)0P|Fq>l-OF7#qTojt2VEp*8+Q)!^ec+FRaXGN!j3-H2f?4{>8s>y zN6z*b1a?R$J2V!?K{p-*W$IVhtDth1Utxz|VTWH~uSU*}6M*laQo3HM?JZ6_g=MKB!SJ-{}75VGzVv9r9{6oGpp%$RnU zUr{iLoVU0QJbP;%lP?vYVr}o>8oYWP9;{^Vf@b(JQ;x*D-T-HRjGTSFybOC!?Alx3 z)ntdT?+2S{??cZ1CGs-ta4PJ0MnLm2?C>t^@Gk7|F6@ZP+Yyzw43E(-zrlZZ7uH!+bi#>vz za1%%K@yya5b;P?{uj5fiJMv!aFK`3US$3q6+o8to5aD)+a63e}9U|QRJUPdb^9gc3 zNzSLpIgXr9lXJXb`0T9RVfgGzjU|h4j>9`A@E@dAl5=XgGkkU=sA~Z=dkQ%N-T5bt zHx&}!HzA+JCB6k8;@h5s-p$88+NjLMN*+0b$T^WmK>=VVXD~U#%ii+6jLKJY!))W2 zP z1w4BRRI?q*Un|3R1HA4lH~Oi~{uhP}ynFMbcYJVFsyxw$Qw!N`9slRrH266}Y0ZrUIYW2XRSN z;EG#O4RTsE_E~WoR&Y(PK&)voIfXDK?_M9!D9#D z=;2%(W-xXjfM9?pn> zWM5DA4P@U#_SeY%0qnxRe)W~u#~oMmVf-jh1#Ud%7}PP$uS?iv7A1)dLLY^opP97u z4ui5mA0bQA5(_~d8%FkxWY1@<|^63CuL_H?pm@FzTSk`1$#Np@S6Fl#oPGMlw5ZzgK& zEg`LoU+S}eLFBkKeOitG-ZX0v;CdNE-aXCQO&ji6AJlr7wD~7#?+Yy#H1T5A3ejGP zag7Wip)a*!&o<1OCDxAlWqXdt{Bnb)ecW_)tb&@hn>FbM5^FQUKsr)5FIAI!H9Jww zdqy>u*mtqBi|hqtFXU_bzCj*ES418kqoOal0UiQ-0SN6_=<8VM>saXPSm^86FUVd@ z_7bv}lHE>rf$SpLB`)z5ini8aiQR8*4`2&jEgQO8W%78x+Ue@pA06azg6xWmu8uur zl80k5tPEWpdlnu2CpuMUj^DBK2iY~UZ|6a94meMC7!iG$+e+2daTXs-TrHzv{dS0} zsq1RxpM>{$r5AL2arcvbFCPj` z{7JclZd@-MJ&;?1dX4K1^a1(;{eb?!0J0<4vybebk^OVBgN(l9L!pP`poimzpqqTL z#dDS{biX3|H)KDj$C}Uo7ldxyqvq9&8%y@DS?CUQUT(v$>pXtxd0^y>m_THx%!rH# zi5?ROd^d1>?*_;vgn{)ztaU!lnBffx-lYKvLpCJ3UtV#Z_8l8kTLb*|}SzIuH zSlD!M)n^}c^vmNiX-A2H^aIreI1X`lon_({ll?~* z3m3PPzk)n=Sh%_@s*H3GOQM&EbKENQ?phq9kAl_Mfm3^u>_71+cokSj_ETi9{5N&S zZA9f;jD`&pw^=uFrwz9CdH5TcxW>15m^k-ahYc8y7Tvx%~olXclc+81_b0x-nOn+!{{}7~q15bgR>pB9x_$ejj2^GdbPs2Ps5(Y56Q1iRMqHc+ zI3AS3LsA|NT^zJ|+%EhOo{n{_0}%Hf*)MvUNTiU&aibhIiu-^BAKrdMf^YduB=mS3 z2fuX_31J=wVIBuz9*4kp90K2QUy)!Tp#}*xNvK6aZ4&CRi9`}f+1vzrvJ=2b;3pEUBH?Nh>aoSl@=W^l>*ghaad1RTXjDYd zw7?NTG2u^#4v37J9u#BlI2POGWYCb%MorNF?zzCjU@5f25{pYLMi9V-Ek_FOl3RA?C6 z`tZnzz)`azV#23~2KJ7Q4xK(}T6k!*<0JEvxq~CZA_D^lhQ^GUJ0mpuvg*KXc?9E~ z9R6K9cDU@bWpTfv^M5yPZ(IfJoW(UD;aX<$KY%|;xQ+xpq4XJ-pXgYn*!d@3?s|-j z3ZEX%SIM{_QAV1s)0GJcj}9_AV(!@Rm?@F7V*bwma_8@hK9+ckdDh6(u*Cb4a6Jk2 zan|uQ^oOj423PWsbv#md;`O-&sF3)pfqDSEqIft%@oXIhgTC1XC@xbOnf8>ZArL~gmxrg z$aWyXj|4}aXnYikGi|UB#9MY|blTuNQGxSBh3c0l8cz<|SU`eno@l)8*HnNumZMWw z@-^bCz5;lKgf1j-o@hM$n)uZubR(hi^F-si0Xk*z3m@Df52MLp4a)`I|Nh zblNcUL@!y5lfMx!m;;Y>(Y3DjO5v~2J7q1!8~>JT9qx7j^91ocY2chE8vi~Co_V72 zAK*|f&W=g^ha_;GX#B?{lrK*-9==FCr`E7z5)Y>&9!^O-oRWArCGkjQkN=v4!6XbJ zVJHd1NEl86=ZVJe2fhUk;Bxw6dk{Y;oP+=p9wq_#2AfEj{$GgQ#h);*RQyR2^fb}d z&YIU)uVGT>prGK+mzhG2KZ7p%g@+wq9j=MDzmhP@W0A3VOb^6EG8kk8y&Vs|J(>ip zt7(ZpuP0&&k6cM2mbHeD#i}Q#!y;L00=0nJKpmhi0Hte%-}NX7V@ViC!ebi~{+esnt%%TAP|f#d;eFPq+|+wK;!Pev4$i3!RHO z0DTZx+h7Np1j-}`gTQ((0JSiQgefdbD)q?)D^#+TXARgQS^WV_BUn3;5KKY{38DOH z7oe+Qk-|urTon|k^&y-xtc$g$H|w&!X<=N>?EyoI$G@?!OIVK!hDEaWG0XJzR_4&E zT_f-Ny>ItKwaMm$!gIX#t{X{P2cW&dj%zf~(EQ%+Q5ddd{CXRe1~Lq+aF*2yASp@a1}uE|l(Up?*^lM_jZ;Mt-@z0j7&Y>_nxXAz9g zokL+(T=5wmp)l)Y92#yMYOzisVJ5iDI+cW|a)rXI(7V=ITpVV^8VSq*W&()fTcd#( z5~4}Kzq3eqnuOUT%;7_!dVTN579o7LI97!4+2YKdk5hO~H#pD#7YvSd5nnOB&t3!; z14~GFhJVB25evEh*s{3KuC7=*Gy#`0N3|MlFS^Wa?J7@YWt_;Jo( ztu}grm$>q2d>k(%5P6xa+CS5h^&W9tE0nX9Gvb})l64~q^F0Ue799G9WAJVzfq3w4 zBVj@L2Co%IBX`{xyqF=d^2lU6in#%63Xn>|LJ}5{@FEF|Nx%<#i4RE!G5{!8eeh=C z?`#s5lCXk=?fU55LBd;n694X3s#!5lWDMU@{6sq-knl1I%Sgbwn}PL*c*b%6WiLtV z7TW2uPXt*t{Af%(7`A&mcHSfb4&_R=-ERSJldy_}RJPr&3A2tkwCjojUKcUATx8Te z&Cz_hTbbwm9?or#!m zR`?rM_#0OE8&>!muadBig!Lr6M#2UX;16%)68llKwGNB*J9B#oTZCvf>6uEx78ah# z)h<)X`jdl4Pm!?Ml}CT(ubhNu9nSMG=W)Auna8#MiJrcIV>lLKJqMg80X+Ez?;^&Y z;6noFGO^N?X9B#CgsZq=*uI3?Kpg-RU9lv@k${+kB>_?Q1b8l(fEBDHBvb|EnQ#M6 z8Ok%Ep*Iy-@AP|*l`I^(;?G=$*S@#h?wj zd!^%^$}^z}+T$c8zD5bR8p<KOg8(u1gg_EXNU$?)RO-x2 zLI^6KY&7gsOTkW<9v3V%-KTP{{Fg8tC1-Lq%rkIN65yF6%pd{kMI=GuPvM^=L>ufQ zlb}=y_JI?mv(K~Mm}Ke5xYA}F`(0(dVMe>jZ+*DYWS{5FGB0>5^GDKak#ke}Ucd77 zrAc4!zqrN=`z$~|Aj1APZ7kAhLo1`loz#88GRMGMP6C$j`acpv&MmIu7URo~%qFZi zPtCd=s?EdINZ5!Uk8r&1Y8<_vUiupTL&6pk@H~z?FK)v(=o39Mn*b}elMjt2;oWk% z8VO8x9Pnm8IRWlP0^Ey)Q~;6i1o#sP86@l?;XM)%7=~2aL&67qs11O7k&unc>x*qJ zkVgVS!=I3FN_RC*lW^wW?`kCIfq1?%ML+^@TYf~s$0Y3KF;!Xlj)C>VJ)IW6F7t*z zI&>uRHL+9;CxVQg9W*0&N>F&j;ORk=L+`&oC?v%EHZ){VP(%n8scG&vFA&0gMoNyE4t9sX9rW2VjUz7W;JXjO9q1H&VICfO;IWT*`wj`8 zdW4-5cHx`d#$9bmfGd!IQMHeR&zQjR{O{43Bz#Uw^_S!Rqb$yZPf*d<+yD=3xB?0A z021H}$bU%aUQgg?-`=W&c~#^DMioFm~735R(U z-~r%-izFN&L0>khQsd5vHGM3Jb-7{O&xvpa65#$k{r!Oi z=;HtViaCiq@d5Rp2rs}>$%~B+)i^Hny>m;8dT*}C@6yY#zlogv!)4$Fc$P`}t$%W_ zXNJs7Ub0|A-P51o$pQDcbK)&1i>U_P{<7jpyj52`Ck*@R6Cy#jH;pJuwkNhk$vezy zIEyo}wQk0du*>TIlGQj3uf%&DBaf-YW#lEc=dWOI5x?_2`XTTU$M2S2O-qr^=UfLS z8}!(_x(_AiKmqB>Yw`dz&}_ zM{^IwQLFFXY;4dcwQvmp)iBn0eN#gA!b|Vp!rtXdF^RRyY!9o76xsC3}b>K&S{rDs? zW9t-^4y+&MYv^qOokgSm#QX%};y=6)oTfV0IIq1?BMk$5$U^+>#i z#A`{s&NRD;i%=Y9H*vAKeF^X`mUVz8h_=|cZ1NK*n~t_tSVrs@fN28? zJrN2$5ehvKG5W->fp38QB%+~KB(^5;4ifJq@h%eEIB3I+(I;|@p6TNVwmNOx&5Us` z|I?-V(Z*>9ZJZ$y?}vAmLcdm!HqQH4xUY>t0Ck=S!`YU^`!EQSphS`^B(@{5Q>BOM zlj@*y#NqY(J*h5sAkC9tI@*)ifkZ#t?@8AH$P(iF9mBh0Rk+`iZp10$eouk`_Y~eW zzW6TFx+h?3>V<}ncR2jInYNg8vsnhu5qp;DI<)ELE$0IQUauQ8U`F)IF`oB(Qd6|o z%(zB+crxjB7VBbX^L{_}9W>(7@nwniq&rYe8?zb~>q&R%w1Es&oi@r_O*@qIGpey9 zwZ{%FS9cQmjqpkS25mfWCA5)*$b3>SZUD5A1nr)5Kkxw119%X42)Umoxi3=Z#51x2iWi zV;Oo^(S$Qvk$N)J2o)sFH_MQ>GVeY*`cTsw`hAsHa?L5};;02)*k=*iTVnLMt~Qbu z>$LH31!-diszCtVxNxsvXC;ZFN#vB&q}BRMdPJn8{_~ggBq4z(=?!jxX=4NMIlBlI3-myQ&KPc z-mdaI{{8QHw^ve@gEq2BbWKT3!c)K%aZ-{>(b24!b=t6FM;|Bklc1UrbqFJIGJpCJ@Ug)fQ%FQA z=l|YEN%{gk&aCmJHwL)+y60bQ*KEMc>2*Hs(4?^K3X?UyG0W`tR;EXx)qmVI{l}-& zyKq%-*Y5qiu*P?2@33*D4c0iMvxb?GT8?+LCmlD3U9BCo>a?r1`iZ~dD|rfn6`db} zU=IhACc4C59PcJ^jlT@L+&fw-5_U=Y6(?{OKasK9*!et@W^Ca!u?YxSd=ZfQU|pc1}jrC7Q$-5@(V4G>NlG z{7@*r>`jUQpShtQHoa1{R;R>K99c#TOH%C)!F*st8d@I0h z!;yVfZ~i&{6p}mnP5>_L^CWH{5vzu|rQiDbS1A3~{UngcpWKd50=GkQTi`wtUm$Tl z@3!~xJ=B*(q9vbmv;SzyEx9u)dXO7{kxWJwO)`>ak|EKPq0Ez^%#)$alOe?ykhqY< zMI^pR;$jk)koc0R#*=%ZIMjGD2iAGp7h7G8FJ+60x5|^azS^nr-MO%6uo zVMfEcXPOMr3C|R1s=7;gwmUr26)np0Op~Xfni*UT-!sUfNsa&_NnB0h8WPv?r_krg zQHEVbtaM#fu&c>)amq}oNTBib>zDkVdGqv!1MRuBQ~a~r_upXH)nq7lz0C98%0%z$ zy0N2Azuc7KPm-IjTQb+vt|k-OTV(b)JMqbQt{K6R*DBcKFQeoNqZ&){GVEZuyiVdq z9x<;Nw6W=mXamdjByZ*hm^Rh{>j6mgWGM4wDD&ivz$OwmlemRM$nrNx+(u$7iE$3v z*oxvz7u(D&exgAe@yr;!CaIWJ{b(b@K^vJQT3u-a**X=XjUsezDLPfR9mUuwAu*A} zBpw71=gAP~$t3DY=9QXnm#m`lH;sl3+Q8Ebpbax=)c3nTK^sdZmPs4$qMF@Y4HLvJ z04XQQ?~|BDVmgVuq-in)dh!PbZJ@uZ#FD1T`*6xk8=rZjfYXOs-uUy90qwRfyWvBB#fKD6clBVVE z@uR2)y4)Bs%sxMmm`ftoGqoiD2o?M|iTSi-?LSu=XHe0f+yK+Y&%iGLgm&_8z**pT z;13cDNGv3=h{R$NF=|Umv~!7bC~7+K$rts%Eh)a(!ig6QCthOO*lEy4HFDxpt}$sN z1wUVOp^cRK6{C%m#y*ymCVY)>)l+T;ZXpqlyTZGW!6{8i#Lc|D($z*v3skNPZf>ci z;lyhdb>dU*L1A4ngC9~LpHrZkQ|=@2O%ivI_!fWK9_V1O#@i$!0pow~#HZkCS!RHg zZr&Im=(mOUHn8-4VDr64cg#vSXNLY#9x%)F@K&aY4B8Yo8 zKV16KlW5V$r&X_sz4Skv%ZzqZ2RG|Ek3^r8v8d@W6mousFJ(N5A9^JEq(By@1R950 zQlO7Ht1$(kD6DK6Sigbs7D4m1fRBcU&USOVQbKU_Q(PQwc1kD^222K!Ym$OolN98d z>?QFN5;1wTkHpVN{G1Pk(oKQDO^HD7!6Q$B>P5&}{DQ=XkvCL8bQtZ4;;(ijp<@%TFkDZ7IuH>3|QPJtXwfgDbO98Q7o{*J_hBpxF1Fo{P<{GP<4rVLJD6%84jV#?u^ZP?en z=VNTjcvc3rg@|% zlEhzlkX35FYKn}?w{yd6a}+=YG!lOz@f3-t`BTKLQxLA^DR9j7|6C<3(R(;$wnXoH zvnt=L5SkX97_oWN(np{5AD@SH2>4AiDbV108IZZBtNi}#bHay(Lq}&T8=rV_!V_5Y z%spQm<0- z#u1b}<~W=0v2&C}h|)iK#2{C7KLpXaE20g=wNrlQ2ADQZ1JK1Oki#jE!zqx%DZc?{ zNkl050*Mz%@*&BWBnwG3xWpeQYRcf0^ZMVG6qdtxl2lWd!BTC|hSZ?i$>3B((RH(w zT92e!F0_$)UBzf4^(G%n>dkzOaMe>A0gXwjLsDJdy#;7O(p4m3^|(rYS}nC1DsO2t ztb5O?E!caO@UnJRWtMw14B|~AJ!F~NAWm(AYT9x&;F;9B0SM#Ndr7*6B#e#g_|y9U zNM*2(bUjJ+s{;F^cE%}#eNwx4W0HC8J}6oDR=>k*J~?EywAl8W!9Jx2ccd(6Pp$mefZ{x*6&=bsR~zluO;F zK8~YF$R+5^MbQ?*xlhlk4g(^;k7*0hh_`kg1SwOa$K@#l3H9s-A)SY5_(y6n>rg^G#A~>3wot;O}u@Eq*fkJ zR;50NZ|3u%%r4IZFObxlq&s+*bc-Y1c_kJnbqOk3$qm4Mq(T;_LJgn%i~QvQU-U@jo5-p9iX)P)*(D7%H(O zwRg2R(5Mv=s;Oz{+)Q+;J_ypWlR=UnN&Y+tY(N%C9ZBk3`4%T1l@}Qe8y2Tfw>X^) z{wuF+N)=I!%GI!KkpLM`Na{jTSCYE%ry2lB%oe9RN%vO?i}Nl{nJvyPZ`LFChe7p1 zefq3Us^7ov@$mksrp4K9mf7R2Oo8v!*WNg$cSdn^PR*--Ssdxb;vkJA6*Bj4i?dg^ zI6cbfac8rFkg*|k432XCYQOQ7@0nJ#EY~B9l6nx0A4cPPV#8as#fTZChO=jY7ZNSW!Km)FiI=N}dG-%;8 zhZatQ7EWtS(g>0QxPe=Id@r;hX(YXJh#UAvSqN#+ylHpwFMxSUYYwykS^}*A7@ag^ zTBO0fd6*<9qR}LcA?Xp4AbrMii8d%|Iz(yr>VI3(?!y)(#u*OLcs5U=)y^SG>*g3? zpxeh>%u^bo#uYJ7X?@Yrkh#Vv>xUiOvlB>qoCm=`U=T?YNeZlV^OS}Fa@t6vVck5X zAz2p=(Gw{d(E<9(dEgSt2||4#%WTHp@Vudxm3zYe_-Zyg1}c?)4kGesyv! z-cjT35T!kZIwH&-=Qv6l<|*M2g;lV}V^DIoQH>>S7IvN{X$ncun<@TyhzehBuyh}I!O^EMUpgwq?x9wO?wH&nP6Tvx685BRc#bA zMhyS+LbX%1X|FkGV*^RiuC%eKg0#UGn-i^dEqN#wAAC;ILJ#Sh_7%SQ#yHfH_BBb1_|W|%y;v^knsyLJ|G>q0j2;3G14jVF zgVT-z$4FXC(h`zhB55f}FO#&44?Pb22%JC{_+tAL|8|m=lLYS?SsBo-c%JLuKLeP? z`W)}gvZVb<(h3jliWer~Df$kf{++w~g>n%MbV%y-+qeOku5?K1^u_?PEz%KNPHzGr)gm3? zw{;|~C+Rhkz{IbUw2`Durs+y=hTGjou+U5KsD9K6b?BE*&m4S1CmIbK%#olohu|2*$;=$0Cv)6#!F?Popb6C8VILv0PSy!|^`|AXgIUt+$ zGLpA44O*QYck}q(a{9>wZw)>A-ql{1Lq$J0@}1dTPDfXOId+uM>Fz!LE=s;{Tsuqp zF6_KV(%U4x!-HnG!5llUh&lG6qOZ6CW{yt)$m#Tbz-Pecz!$)mB)v=0E|Spt`y}lq zX%9&sIGE!b6ldn(EDPR#hpo;WA2Mlt%>V4Ke#~*g!5k+^a$V#s{d5JH<9BrGIle}G z)&Bq>ulJJl3GbcN*%>tfNbU?s?tLVEM$+f}DMHH` zR~h&F7bJaI74G+p`Z#4Mg^UK??%khP?ynma*L&;gyOvKovGN0UeGwkZFc3tsUbE_Icj#8Ib82w;I<-C)tc9I>{n!k^Njt1}};&ed9^8*VS>m z&$@!#mm;@av)E)G{YqYuy*=m+!% z1^}1=I!Y3JYfLsBC+SC$PVk|FjTgIQ48;}m#r|;aACgYu#V!)E=3rfa`7b!t8A$42 z55}lWc{2Vk^nZ^5E%%x$U3ZFLZvJW{2)^Fiuq1w*# zoGS>d@8{A$r+Gn>BBRQBZA@F2G96vt`qEpk!0Q`cGA21jDSjt@p7Q_>GrGfRg-9RY z6TkhnN+iAfqDP1*V>)^)(tR+`APGx6y5D`#I222O7=t;6q_aGj5u^USe1rKJ9L)+^ zAIuQl8S{YW0EDG85RJ~5PtqSG{Yla}lFpL^>b}T>c>%BxSY!_7#rS&($v!04A{ley zn@E0u80TvLc4@^ z3hI2Bm|DgrTzt-QXK9ncBf=O7HF@_9U>nJ`NyeL(-S1P@9;Q=c$zXO&Ah{07oQj!| zq^~U_Uv(vG%VfaU$;jt3gD}p3uaf~^CnF2M1VIM8oQzx`kL0UKu1E4UBwtJNbtGR; za(z=6XB47%YaGSld)~tT(1o$gYhTI@`JdaXoiNVW;o$bSNWQ_9+jpAWUd~`##s}zB zth{239#(N5k$fY`H}N2VW0Ua-$&E;ETKU2lPEiKCJ-RUd5<6c3Uz6OJTIWq$Nlrrv#j z_S|wZ;Hd>mo8~v{y9h6nai2HN_z7jt7}v-U#-~{r%jU|JmwKSg{dR{7lwrC+dLS<2 zPZq^;GeZ=YvzAPYk0rB~aW0n38rZ2xato4MV!UM5*4MFKtqySlY9rscanS;$!$o!o8)`A1e^~Lg-#ZkoLd9Z$ZUcw4#c{b z%oq3ZKiv${s7BASX2K!TJ(^5(MOzor$h^B^q>Va^ zJQGKJjvx5x^B)5qD7hH)i}8unL*~j%UBJG>N@a3&4Ks#TJ@fuh;vobT&r?F*%>&$D4Z>+V%xIDy@^Dfz5#i6AV;pM9oK131I4PNPNk+D2Ii6(Agg=rAM?-f~GU1qH!ZFF5 z4-l{bSV(ejlKYU{m*jpV_a}J(oRrKL0XQa^OK??vu|>Xk=F21xBzY*wq&q1KNXEST zzx{2LnQQq{@eTPZunt&H@*t82ldPv?&hhk@|62Nebl}LqzL8O(Sb{9jc*|*EpIKpH zcvVYapJ|c7PxXzQF}JyYmw91PLDM?~R$!sB!P93<`@dfA%xwzY-&`NRQ*e;$`uOf+ zcQd-^4dX_$WNtC~YZy91Myn8-EX#TwMm5K{8YZG60Md*ykCOZ($w4G@a%$!ez;Qz_ z1d|+6CG^4>oHFZ$pS{`sDcA10D=uO1wNl%W*>`ljhiA^CX$~bc^b*nNsb^n zlH?gABRSP#YmA~MZP?f^0BzWsVhh?pYAQ1ZC#TA0a%wg54{Udtv|)oc<(iyo(GSk9xC6GHj)osJXk(5}8+gBiP8*Ad zmrWZsOq5n6h>^^c&pg|k9N6j*0y_Fdm{ZjmrH~PJ>bVx+I>tgl|^rQ_NW>Rbu zjULx&!}hpN8;<1EOT7ftNz~hd&4HJ>h2&u_{()^We-&T$yCZGWUF&cYGq#yH%V?Y> zI|c{MXR~ZEBqM9p{ZOR+*!b~Mo{F>0A$c)xap9Mg%Q3LQ7qGp^#UYt&a0+bm0XPM= z1;9dJ5y>x+yp&|f{$(UDCwT=Qx)@jjyoBoj$H4Y7fUjR6c@4>UQwe4-V9s~``yB(@ ztHw38*x(e{)&sARyprTqB(LUai}hX{gRYmBxMM=+#02&p-FNWd{t>~EA>k3mJE8hc z35tpy8y+)dK+v>llY)Yu`rBXdqLcMXE?+*dez5aQoWEn4|D#@8lxRYFdhU0Bpm;4#g!QtV7 zfn&o%LL++f-(w;li3#)TQW00e#^XE1advEklSy7j@_IhIR3G2-3dyh0D?9n@{?T)8 zHh2#<_6Hhq*?;=~u_8G}mlJ(cySL(W%wy#k+CsyeV<1A}oym9^>e2Gy<@hifq zaacJ-!4XvR16RZ5AAW=lk1N=Ykqo~W<2i*tJq~b?AEF?YWULMMzt7yW!H3XA!7ttn zeC7i|^YgFm-)!MsKYbm1u|Ce2eF+v-ACYwv(1_$5l5=K|-ia<4=bI!wlNkPV$>ofi|*6ZczsN)H<$9b+HYobmYZ z@FlY5;G1WRLoHdDTzHQUg$Mb5xqOK%xDQ#2xi|z=)_j0~1;9dJ5%40(yGhx*#S=%ruc=@BO_4v8GjU^c`t8gEwR(!*DN~cc5^Rp63{(|H$nL3k^`3`;i z6)oxhk9Btza(c1~xB<4GHUL6A3;H`N2Y~+0g8t6RCmCrS-;lhY6)f?@2z&yPp8KS0G}KSHAuH5|y)0pf~)LA-jJtWcQpo_z~gM^4hXxch(_P1C?&r z&%@X`0^kSyNb(7iPqO`FQvqepvim2JPgM!~c^aq8_VbK4TR7p|o$tLfdhnh0lHdic zPh0X#`}wO`<~MI;g12`%wj!wa3%MnAZum{{7Z7yOVjLvOAMvVS72k z**$)A%b z_GNP{p107?`gT0F>`N;3`JWs3pWCXPFPW|92=R>{MoI%$roj#BVhbDWM2{IUs9Np4 z#GtZgpqgkL!!{{g^8d_<~ywSDVY3S_j4(s+NDfhba#@iL;jos*JmPz_3*n^!9NV$)cc03B8sk1*O zr9CNrmCqZWq4F;s4S%kSXr+TLqQM!=9n2bK=D}niKsATC8fJ*^fP=sxQgB0bB&8F7 z3R#`~y}=tW%UH?be;>QfK8aIi-uTHI2OLYZHk@=-|1K{k)ERJ~XNNCM-Z*2H`Po~U z6%)^|+VNH2k23l{_)F8fKHK4iH-1BVe;7Tki|Fj%b>8S!25&ft=p2;R14ubgjQ8^c zqAWb{pBtO!AikYb2cJ7D;hegp;2AadL+jyC=xSXF=Ri3;2wuv8c0gupInq^gZotvH zkcPa?X$T;=orB#1=}k%>Qu>n8j}L7EAhPXH!a29=Lr&>W3a^#I zO8EGHK?&#R@oL=6Id=p1kTQUjfh>scb(WzW=5?F*$Y5RX21O5^9yB?$&D~CFH?aOl z*Q2}sty(*J>gWE`XH5%=36G2@zktqZkF(Qb;e2g60DgSBKt}+v@tnI!8BEF$oINQ+ zNg0M;!iRPRx&aX2IndoX$ehpVLCSDarjoLVl&z!`k)ppv+~pVhmGz5VADQh|u}5YH zICq!dye@xtS10bSk>NAK!{!dhoPJn%Xq4_^v%?zj>A4?|so<190~- z{pa)pa084Wg>zwZ1_Faf8A(bw)Biu3z|Mickn;#P0F#~r#~~*G7zw~}$bsXKGa48} z%EP3LA_ZOq{(gj%M@bpWB@D+wcN%gYLp5+BawcF45n$xPDic@)Os;k!AScX0#gj>K z&4taG%3u8*NVDWjM~@lKgEF3-hx()3SvU&)I*Tt8U-)PshLp!inaI0O1G7naf)xEl z?3KETM9w@^KA#(grOtT{cpi9xlt5CRBqfMHC18PJzbBCrTovqh4*U?d-#IUPv&Dz@ zPt5#a>+pxD&y8W?wM|+Y_B&^VSq94ndFuWykA1)Ov*Q6&a`ihiN9;L=Rkhrod&yai z_Skp8HPSt;oVB{A6>8XTOU`;2F2!^1xk0@S?pJ#gYT9bn#2!S>7F`KUDWj&q`aQ-W z6DhRa;C}swhR3us-ip@Ge9ETX$k53_(X*mQN6v~04(*HM?(08iO8BJk81ubp?q`9x zeNM7*7M2_)^CVK9B4rwnIU^5WnSLdC_&GLI#GZrBJ#aX3;Be&R0J#7H_&G?R$tfTu zf|N*7W{@(Ilqgc7Nr_?ZDMC@x0m&)V|F+}^*n)dz84k#7=AH%Bk9%}4gLN7P+|w=& zNKOUw@N+&wEuZi;;;a5Ku$PoMq|D{rPl0`;JVVNSHb9k2JYS)5J$HsF28lE|-vIkb zd6txUr10C?a}EIC8N~BEDKAtB;yH%CV&dUhfo~okF}mHXS>Yj*=Ej6Z2h^{>F>LXq zo5l^hu>QqiQ&ST*U275#RvXgG!0GT(rpMgt{+v7f&dip*zZN17;~_W?;yI1>esNr* zGlr{%C%QPzs76oL&3Nf!nVwn>((rRG7`5o`M~s6{T)@N+Tb|FXfk z59u~|T^W|s&GhB=M>T`F8qiGc0AL^ht^FD)8%TMbKOF)LHOOZpDVwSS`Q(nmDf2Bc z+8dEfUh{j%O3Q$UmN#iIudU4&1i`5@xvb#1%vf(_K3qM!=T@;-i{c%(e&N&PZZAvA z=Z;6&iDr+pR>^%_*D6~o*yF({3CV1Xm=NrQlJW*Ayfka>WH1vtKlVx-o!sfDNLSFz z8xcSxFawwgL;=wNRCOFF2((&BNgySW6lk7gF7Y(Z%@iBCbM?P1xzAz?v5{hkjWp(s zf@&u=au+*zV+kp#uDk*D?d<6IG@6DUGkBx+LT|hQ37u<7XiM%I?5rgvofM>RT5{I` z>q*HZC9Cpz1ByG>RNR)_&4vlZ+vnMY{yZ7KBAogyFWZLZT2YNInVBJ=pK~Fbb1{Un zNy#B4mp@GbQVrh7BPG8|@CGjn${c|Bp{D@3>hm2BEcfp(Z+dn0UE1?QYni-}ZKpL6dJsNUWd1YK6g(UaA#^2 z)x2p`W69O9vz?S;Qc8Hl>@awv^on?67b^Og8(g&TXGRiXWq~Z-guLFV^8(tjYAIJI84fRSKc^k@tqK_pHr^Yj*yGVJjD%|sVb#Ows=kw}%yMM2F z>OrZ|heMXX6qgk?N_=vFanI+~Gs|4#t&IO;<9s$u7_sWrqftlamo&V|^PbP+_HHn) zkscw*YoM#M-4)Xcc{igP%nkfS9eGW3>iD37)wDo0d~32u&1(r@q7ygr$Gm%oF~Pd` zN?et^dr?tGZU97(*A}=BXa}?hIskrvKPjJ(f{_7F`ZH2KC*=!LzT^^}P}HQ3ysrA+ zmb~uRf;zr3sN)-^j$_r1I`aCN)RBj1_}4DfkvGVs4s(qG&)BM)0m%zMPqS{;N5M$! zAkvL61HV!}Z!|E5lmn!EU+KJ&_ZTYIg)3knU6?tlfy{)raO}IAT$jY&Uw`^CAhnl=G)hzRrw=xqO`fa^#Oz+t%eQQlS z9~6akliULwd64UQGac6mYk}f9D&?rI&Jb0_1rO)AYMBv^yxFMc8KW9qa^%g`dETl zR7B_U5S;kQW5P9W1-@Bn9BRpXg_Ki#=qgf9mutc`?^PVViHk#e=0P*(tp{EMkd~77 zIsk9=3@Ja80*m-7DZi0&mJi(wYyqHxIdwm8o6)bolkz923wXv=UHD&^am|DH*5}Cc z(n$G(r&?P(&jxnk_sRHmm=xBbV~1d;Iac=zYC{*X1a1VCpO*z7nZI01AO30NOXNgj63=n~>Ux)DfgkVS;fv6a5W1d?uZ`baGyW)9o;0m7fkl z-Tk|Eaeh$O?Xb>{-_^y>|1yUeFOcjoDKw;8&}H88lc(SpZ0DcP_ks#&r23L-;oUcV zd=K>{wFWK0lL7y5UNY}pRK$I*+fHckJV@_6NbkJez#ah7JMTkMYm!=v)Y_!hA+;{4 zSCM*k5{e7m`|<8|L}?%>dnv77k!1?vPS<_7Gb*EbY&~J7|$JOt5eQf+Uh6T=VXqLIrTbUb=9=*`*<$$cj z?d#9AnqNH2(*ox=MtdAC$EDUyXZ|g0I@Mb$*yGJnO)H}sOMVONv?TRbQk!DLP8Zt9A6PNk$RB}@ei)s~w2>bG zj3l)Usdw}4C}1?H_mHY50aogiV*WT({x~!-P$I-(e;XG1B+qiujU4r1YQP~0m}i1@%&eS zmB1=eyOG+R)cZ+&fYctOK1k|ATw)E1I%s2^{~d zL%#PXbpWXYnKtYIQcqYW3?g-Km7tC7IAxXzh>m+wz|yIRtGCuV6LE8p(Gozmkvik^KFn29P?EN6Z0(HXgnr+Q3>Y`9JY_ zG6`T&mVC^A=Kla32Yv)j04GTuMJkNi7*Zc0^-)sCk~)q{oI+6tZTzhNZOQ)?ThPX1 z25oTiq#9Q3XrsW_q>Ta#spDN}qo7vBXrtg7A4>r%W~PmTYXNvDkCV!olLhsG2Bbbg z>XVi3q!ctl<+nH*Zmb8bRIGi6DMjDkLhvKPY5BpjgH{F2P>n8`!7~NT0m$Y8NY)@y zCy^S=pTgNKxWizd5K<9z``w89AT-E=^H^z*cfAGf|SQ5oOOjytf?R7PJTz66m@GJ>vW3oXT=yk9U z`n-%O#exS>O)sMwOTk0f=}BrhsZ)8x^fqYYsVkw4f`Oz2hq(+b$N$LzzXObGlB}SsCNgD;D^}j6zk6;Vhh&E^g>5rt&uYR=gq=Pna zbHupP2H$ZNh;0-+g^tE@ECy{%!w#;*)1=PkK@bVxddwm9naZb)S*U!D(Xehp3ufyk z6bYB03@n}TCkFA7iDeGr=TXf9u7(K$`ng~}0NMO3sq;wX^vQySz#@Y-o+q_Rq)!$s z!znXuEcZqM4eGRyxiDkItb{v0%JSQBthq@WE6p;iyp@?48<4DB7&;<%>?HZ-)d6Vkc#D<+}_#OsdL31K=Sg=zD}Jk_s+gf9V`CM zzE1w-erI0+Lhbqh=HKbMdR4)vMt3-^zTx?%3>5dd7I54TP~HXmd5AepcNKg~>T8~Z z`5+EGY#eGSI7I3O9?VBbeZ72x`3D?*nv3%Yh3qbX>@I-pE;tDwCS7of)QzNWB6TyV zTS(nX>KlA0;?o643n}=;9L&ENgLxaNaipHnNAu7Bh0$E-kkW;a(y<=XUFPgjmu?*= zO>&-Oa=V~~wS6pwSEHNRoD|jpEC423;MRlJto&&`0Ajlk(j$RXiPX>7I9_T>tE=P`HMV9^U30tophlA6T3 zjSQ8Sd?hNcuqi5HnZ_!w@HXIf0BXLlIRFt~*b-<(Y6_{Tq^6MyCeI)hJZ|F>5cCd} zSJ+1X+fsNBworLlhRVxfl_yj?l~>r=;XSa;V9`GvNVA1;ju?EYHyL)wofoN}%agB6ATo|MaV!I*FEajZ+E1ZIAkbm-* z$}2?73(lcf!D?orni!)ROJNjtqDhrWRd~eAGH64+BHDNs6)ofjm;~kl&jC>Lg%I(D z^8o@DkgAcoozyo;-9hSGq`pn+J6r;S{x8~CqW^6v!ey17J7y zkop0sA9CA>j2GGr+W3gnkE;Z26yTJZHVVB_z_sahZh0Yk=!v!4`}d4EQ@^cA8}K&t zGKjo;(#EH4E*`f`9q`-yq>DSPn~rf#y1QZ#(Vk*lBZD?%oi;u(?swla*TauqhIQ#L z{}#H!w@}Savl>oQFT~;#ppAVMtY!~N@)_!C1F0*8ACmexsbBDj`4}l-h)8}(OV;v; z`A5(37k-Y44sZiZ0$%`M0$%};;)UM;`vEBMuSorx)Ne>dEF8NBNd1nzPJ|E(51Lz6 z)O05wQGO6m_h2r4ySrl>9|uV*$~bd?c`K8D)?gSh+;h!!2h$!uRR!`Xx*b0pZjI`eFl^xJw4$Ji z_CzzJRMgTegTT8d`LuniXYruh27VcP%dzqI1sA7!l26f{Xzy;L!}UmXQ5&5#P8+Oo zsb^`OhFwv6$FMWpHs`N8nqL)lBJ~%JC@p9Iz$2nm)D0(bKR$O}P_nJ<#NJ{`r~LkqM25XD8%!bQ|MK7^s z{tK7P&n$Wso%d$>jTDe!K!#-!a`B`if6PMIx5x;NH;d(w+%k{|0+vgVZ*FHCLF?{-6` z7C~z3WwN}L`TFpr_nA{XtkJjONBWol7A%T%q2VJUo%eFq|3 zI=(EKT7(3YBFU_VWoi)?rt~KbiIw`S(WR;z(Ffkz161^($MbbX2!gp91@U&j4uLB1qe!FG*`j zS}W38lXeGb;EcQYP$=CZDBYs{xD>wF9^l_jS{u^tA?-=soCN(R%*k={N)`P`+T9)@ zUGuqt;Lt9eI$Y)nhN4sGqMy;tIy)e0UUUYvk#;Y$!!N+Eq_rh&0JDQj5Z4SDckR~E zztiQc)gP$iyrcdO2-wShVSvbtbKg>GBlwd<9HUaeZ@p1Gen)XkGcA?)*=`YUlD4-)4@l z;@e5<=3;`1Tku!qH$la1(7E^WHNsUdz8k=;ct2?m@NQcG1EL3M4^_I$Q|yn*5h(tP zSBpF8y!xO?h=-m9uP*tZEM6^s0M+#5YGAL5djLodDSn8wo}~36tv7$#3+QcFvOc8s ztqPW`co0q*maKTNH>(sE_vyQ`-qD;|lmqs<;?6I47(H$nX?*yG5{E=H)>7%@oDE}lTzK+*>Bh?!{6 z#^5WWjbK#t6gR-M5dwq)(96Y>fhj;ZFqO0+qzxr)7-_>v8$ntCX(Ju9F&)L3HX_aK zOl)=9c$gVuH2?EN^`i~wcwImgKS$aqSK63gLE2b?&V3o3s?)|x*jY;27}6f$L9h&1 zPTHfSJznX`wRkluU&jseoxKKF3%p9&SklIk_85P<9)PN5?{7p@M!(;2U+QJzy_LEDeDf(CZ9_7aj@kTu$~9?7q;n6j z7DI9sr#P+=?hHJXtKqd-2r5}>Kqx|btqO(QDkH#JY(q6UMm2hA?L5`jxi~aHi=^;>8sF|N35h+!C7edoYk%4)mp{dNel5%x5aPa z(07bOEyZt>77BG+ypy!Ba;e+m_i^-IF3$b88$f8d_yd4B_#@zB(k7Dze;wKtH1rf{ z)A&%R;$n#5;(fSWP`AYp!^K~aHl4Ic(h_uan@Cy`pF}f$XKIYTcx`k*n7PPf^k99x z-x-lnF@g0PhlYgXRaBTej|uHFcko|_Bk&llM`=St%wm6khlpycP-DT!zdzJpbQ>NO z9WyF4dPZbKNN5zovU3B%!lFZCF46Xl!I9IZ1s=V2s=NZHq!Xv?P93i;uECJByAZ}h`)340WT#y>6y@| z$ckhW6rVP^yOXvyu|+CPf#7oYR7l+@$~l2GG$0Kw#9 z#E>yfVkyCRD6s%FNSj64)1=KNZ4PO3NqdI0XHlXAS<{YqOG#b*Z%Ya1bHI0+XT)2c zXREce+QnN+ZZbz(Nh8vpbFo?_$lk7q*ez*}jz+{-A95uvumdmk1=8?Fa!U#1LJ53T zB5g^fTdk6NPrlUFhU6$NtxOahMs6M-jyK;TIr2$)3LO43%5wwkmx zq^%_lif0{{2tm=-IxHoV&22cgppEqgZERrLh_8OMfgBKB?3RFVUvs4mgvBdF8!w=v z7obyF?3T<2KoSVeZsgsCz#`Hx6S9SAqf(~@OO~SY%u zQX@<4`E^#GGRX&0SubPtR_2>7Esy1=4t;V(?QdT@*7XOZ?Ym3n627HU%?{UDBSmKo z>*YJ#Nzaxb%xw5rP%|@Jhh3iWmG7zLwCo|*uZmntxnDs9k4r?Hmb3URkw{DN5WgiV z4&81XYAMl3OO3?`5I1S%62B$y;OISE9E!GNC-5$?3wRHJGA`LoS~_VNq-Bz3BQ1-x zY(5nFxP;jsXU^ic1Ol2vyE&xgk@ll5eoy=tLc1m3m{+P~KWVuhGliY?)oD6}`gaTN z(%m_M*8PeeL?0b72AZV=;~)-<=ZvDM>4DqG9#{Lk)c z7auBZV2q z?Y&A@+NF1*@_V>pn6=WofHuJ0q#+LQ4rx32Q|Rx~wuZ5Lm$Y3~!Pu2{#3@5*mv-`I zxVr6H`|h7dhg{rpWUIFF*#%n-V^?ab^HQ(s{MP-4W8#|*?V9-PqTf?@w#EA?+>Ko+ zLg%FqIj#}pI>(3jad2FtYu?lOd(F|Z<3pwWP|ZN28a+N#ip41XN!w%COjHHIj*8sl zLzVk3jM5P}i-#RQCICAlN&AR2UMsQ`y1f*-eJ^SHyNv&le_uKdl|0D}KqHhQ240HL zcPZ3+DMWiIM0+VjdubqPpOA*Y<37?pBkljO_Z{F-RNvdlB1KRH6;VV4qzF<%=!o>* z1w^D6QWgk=1d`CC$N{8x1uUSbfQU3H3Z!SJZ+fvHAXSsV1?>Tek&LOfP0(6*b_@inK9hRsdb2}1S2z6tvNE@#eX)AhbMMfbu zuPdggaI!hC6&W>=zsd*eOvgaKjzQH~X9fy0$p$;kOGQS_0-)PZkPQzQ7qC!|nuo?0 z8XfCGJ!*k2)KA`BH@b*|sO4zoO>Tu*Y6XB`choAfohBRP!5RJ((miUm!Chy`cCJux z*E$?BbJu!L+?6?2P6@BrzVtiGj~^;G|CX7R5w*dr^P#6YB|3ld;Ldv8n(o?tYQyF? zeIE9}T^rFK8*`j#gLF3Qq+_lWc_+`vuUz*$ynm-pSZJ5v5bJ=c5s}t$e`m0|yo@J@ z=#ScAPGMGYUpO1i-Nsj5{f^ONC*6`ZqQ1cIfcR%+Z;689yTscAWV_6A{gKgOID{Z0 zgV*yrfTCisf1INM2%TTJ0Z5%+^Q8Bq1niA_0lMCg5>b!<8BhQ?15t>ZBU1Vs*?uS6 zA7r~qwm+fwqu>%m!6k@-OAwU`z-M5+e~oOnNvKS=TO|A^G6SOy@%iJ~_8o8-I0C>4 zx=uEvOWedSWhdZ`oZ7pQ>pQ8P-;VuP$-|rfIvOvrb9?XK(BRMzL zuXl2}k~W;TDBY9e3l9_H7H`jz;N_O{8Fc~Q{A`exCF(~Mej>q}1Phy|i@+rkijnZ- zKlY5GkQEfAXY{b*_#OBIV0Q^#QWU(TD0oRxH%PdTgyJNWAfY4)rAWA+1jm}3QMYk? zHM}g*-sZL#w(J=Rye6l>YjO%t6gkf*8fi$nMu~oi1m`t5qaQX1!fRB7m)B;*_>C<+ z)t(w;8h_nbKl%v_aAk8ML{~!LNfOGE!0U2GKLu1Fp&SX16u3@_eg=)#GCJ0EN_0)u zDS~5N&gf^M)dj2v>hjD@`KMaCO#A5iXsHpm1XU8<0B8vKknku86-dxO^~EQRb*&;) zB%x4bkVdz{Aw#P~<1U5!a|2OPSH4QS)%C=z`kk7u&N#{IXCbB)%{~&>Y3r%Zw}-aP ztU9Yxh1Ff&>*}}fXRO2Q>SslFK;6#fpmR_$x)W;^!OS4F+-cD7(Lu_gPoj}IWJql0 zCntRp-Orr96)$*spUVI;b6q?j`epovSMY;49C>9gEvXL5iylIPd!}jhaD3xu>}rXA zl?2W-jUGWl-ZD+2gRnQJ0&zGp+6s&WMggONU|B&B%u}woM{>z0*nJf zamu{0MKXN!1QMPlp*{%#9F7zMNkHzvzx`f(^lQfXvqVqBPlW#yJp-6YLLCz7lJFb} z^;n;b%V{2c8+&+szdPQZ8y@N(;@1Zeze#uqD}0=Pq*>^XC;E{$;5T4w@Oa*Dlr=mT zbG+AGhxmG0G~lmZds`#@gAkB(?!I?Whu~2E@Trai;H@7P|E}8dZoi;c*yLW;N!AcN zDK^2+QRo~xaU33eLx9uIZ(vya@NoaBtqq0m=jYeaKQt_~jbFLfa}HAr4}F+5`dddj zo|Nl95s4h*tbXmGxyA*A1mn>-^CR<H}Y-P z%s=oh!Q|*SaLN}L1cP&r!Ze(AOaV40xP=tGh=c|tbaN9V(M$2=3P;6dC@d$TAqhTQ zaiy2{^=l+FqGetGu^@@YeWmCRxC021=(mA)fOmoSfOWun;C&K6hmA>SLPAp#nvu|) zgce+51FD)qlW4xR!@^_}wz$lZ`pa76dH&O-$lcwH-eod+^yehtJ@PrpUcb$h_n=91 z6b6-VE^*K#IvR)}p*0Ce#I;1n0r4cXA)ymbf&yLbHyZ9{H0NpQVnISd1{4z7lF*I> zPTh^h9jIuyr%2@!I*?E(Qg@?ytXU2~5xGl<>PPoI@xg*#kF1GZwZ!)9WTbuR65=bf z&exvmJR5Oe{Le`pg!wzPYUhi8)!T!FIE4O=IL^^`dZk*-FV3Qa-&p&?iK=c@hSxItVrl}lfZ8OyLINh6*p)jrm0z{nWs9VSN#4) zgQ(tPR`s)8n)K-9YwolW(-QsR#*Q8($uIs)GW7`s|x{7D$ayTU6Nou|lY%qZ*)_d<6~V&IO%z#WMh1B?aWf5eO zC}T+oApyluxF#`S0Njxn-1cDCBqjns2>XSRFo8s0c1^^_|AkD6m>K4oih(zROc4=ex{q6-qjNr)gJl7xvQ zOd?@2*H{cJ0U&i_pm1ZB1Gu#kvyy}vr+kaXzWnI7PoPiJ zCXIb_KCI`upON?x=o{qI#G3P=JJmS?pn2l&?o8x?LLV+&|K2uwOPl2t#XCzD~VFn49JFk;4iv%KJHsA1J_TOP{A%gYt zZfx}!Gn)arDNGd|zHYTEXbW}Q=>>QsDZ-|?2idv{#-(uFbu`*gsAdahB$ zm^0|_JP#Gjux{INGZ>-V<%U(Zv|R@+|6#-2w0z7ZH1n(33yvA7SRYqQv=NO<3g zHe##hk2Yd!V^HVrpV5os zx{rN(-PDyq#T##PXP?-gP55_!~NJ1=;4zb`o~*j2ULo#?E`9jQ}(>hC5&q2n2!vD=-om1&jtDzju*ibgncA@ z!8OLBs)III>@#hQ#}>5lr9m49m^Q?sM;p@|v;m#A-Xg$<8;H_oa6?mEM@(fjM@fKNjqNF^B#*v4G5A@HD== z!=Ss4_+@qN)_j_(}IahQZmXXb#8&X1oG z`vV609G@dT>t}$oB*0tvii>QNE|7o_puWs`!3qwj=2%lTTVgL8g5w)QaI{^=6PcxV zu8-EoLN&+U61>81h;|K{y3j=M$mB1l`HsVTpqJUNP z=F~s@YPTUDEPC!Jf*7R@+K4M{)+ytu&bsFNx_7?Xb^S_vnpcx6mA`POjkvPtj|IDf zHsZ?Zg5#J;8+mkh;wqwR}-iO)CQg<;WP<9kZ^_sOxbfJoG0M|*I@Z<(nef;{oj_jhS-8Oel%#~XQqv7 zMUFP&kh!D#DRIw}@RJj5#6h#?hc@CmW1u0Hb=rvQf)Gw<5~bso&fj-vXU3&l-~9FaJ^UAxzI-91?D4}Mu6OA4xKTV* zrZ$TkscW;V=Jg&I%-ZZvcWu^pkc(1?3q?x^w*So><8|h^o=Z!v%}ho!NVYL1%@h<6 z6}?HqEuJ*f4Cc6fPs~ARNSDFP1G9lSz+B)BU>-0ZSU{o|iQXhyNGwL;eIynqu>{vx zgky6s$5Q>@mbm5E)*`W_&K%q6i8!d{xINr4bHpy-b6_`#IHP4re272Y3+&UGLo7#P z`9i@Q(Kuvg4#cM2orMmMK7YcmPv<6|tQ_py^~{@VP3DL<>mX?DUgwdXA@wi)+51dP ziJzaS`S|o>9+(3Z4&Dic#tC=mtXwDM#p-P zBOc6v%i&pb630KvmqQ)*%VA(Kmw6oj1X_BETLRm}R{|iI<1wM0Be5Qd{C4(uB!0v{ zZE#Qn5(~xK+2c9iod=<|Cq8-k!ZYK)N$mF8z9maa1~hr`6@!D~S%!0+=RDOp^7tdo zcU14Vf3MX1wV97jU+K<4@eNS7kvZth9PvInbC_>ux7=yaGf<_h*)^W-)%C7<`#k4Y z&zoPxwxjJlOd>^1M0D&71fg9f+7(il65?hh@Jc&5!7f5WwyS@Yr0$#>A zdt-|baQqMw+meXGoT?{7yhh@*e}A5Kd?24QzC<8wlwC${=D^KX2Y)#2iiK@%T_83kjDu>wLdQY3cb;&=ebGM!2E zW4;{d^aDJlhMQ^Ij#2Av9XAfILAmR3yOQ5T^f|?GJd;qEOkx)jkveIKpX%j(s~U;j zXxV8#o`3Xwc{~;wil5INz$C}d0tlE5%mLsA#J>T|BM}#64-$Kl*o(y8B=#Y(FV|Rr zs-_W-U#$Pz63=cxEfV_~M!Y{8@!>_zh{wO}V9R$%e9_5>$8)GIA9)e+eEn|bbHrzT zBe01?Fxx;b@=4f2;!7kBE%3lW{B|_{Id{xQumji$>>_axi7%5lm_OYO>@iI5D_Vj$k02u)dIaU%+NdD$NE9<%ajY|KKy5kEM)7wrV)|k@*$Z=utO?^``zyxWznLzddkcDgXr zoqiJPqQCmai0izOfY;?AW-!Iz4U9VI2V?G<7?DHXCp315SPBSk-cM9+%R0(e{ z?_<+}8RUJQ<_)2FL!Ebg!MP3BdC?w6*%3#{p26`YG>=z_OXx)63^&gpp)0=WZtQAF z=tkm9-W3Yu^*nh732+7y5YN^j_0TDj~#}c9w)OD4@B8XptFa9Du2`h(ta0%2|&adB#@%#y-By@1n;O!qLb?M+Xro zM3T6e#3kIpB>jC=;?jG0Usb|%G&GkxfFVo3L#zoi0f^#+SpWgE0Zfo(BrYd$1&J$3 zTt(uWB)-Kp-au7T|0Wn(*pk2@ap>RGhW=g4hU}vvr+*VxJ7(A#64yAh1nicRAv0EY zyW^^E2^%obU?0PdF%Nu1;@c#?!;=7VIAIfs?~=Ho!1Zs!Ry4kYJ7!b!8L$o5P9kVv z9f|AtQz+sDB!uIcAMt$>KPVIi=t~?j8z8Lk?w`owL_L+`vdGC5avkP#pS8beyAj!{mRcn|zDk*Erw7w3VMP zaWz1$go5mr1kPb`=-&iQw__h0b_`8{h0#!M&7`B5EXUD6-X~;|h*`3kXH2$18=u@0 zZ6JW2aFRP<5;zPT0U(MKpoJ5T0mp$8B*HcOl*Fwhen#Rp5;1pnnEE&2G^#@fC!8_2 z97@;q?@nfn&-qVuk<-5kSC||48vl*NUCy*|mA~4EQDV>GFWi|nZhKi0E!dUiFQ%p? z(VN8GB<|s2F#u|KFNt3ixcp5-U_J2xqhs9{Oe~}Og8R%#Twxa`@#^upP2$9d(adAq z40tB-5#Ujv0*POexSzxW{3!%+;^PMU93(NSFtAS|0`bfwiB&x@$@q0;4h*W-UV68D z(@{Ywmo^&gllY8T2d31WeXL)1z8OBEQ{k=5kG_fPl3Fr)T0lET^#R7>Ui4uu2i3*7-@7e?C3G@OG zAy4dsUlvTFMq(<77f4JY@yGvyh)o=95P~HU@%zLfz)=3hB-%+#A~6}il$GuOUnFgu z73;AT!9~&%12G@0xB&UZxI8gZc#B9>n%kNriST3+9iB`gJekC?B&L&?!Nvlf3>HZf zGw)@Qv_v>BiPQL4pcoP(0fhDw5z$XXhEF0AdlIJtxa*WfVm670*FjN!Ln3b4AL1I* zQPp%b5?|NDk#@me~ z9w!k(@+6m--60>@**Hbw=|W-d**{`)ztfZHe)O%9GseErx7^3SmwI|zxAO>QbFe*e zw^?V8r#eXqJG*ag&~f70E%(PJ4{kWugSr0#Z5(i%BX~PlLRvgyI2(xw{%rM5 zU!|O@HIGM2HlrmyZk7n&2640Vrc_Hj2&sm)T>Xul!a;S+KPDLG`Il_WKd-y3GT?ed z2;C?0v#1;+JJ*U99A(bJ3IEw$UmU_WhmBn=iQkcUk#{{p;-$Rli{sdvWi;PCPdovf z1Wo~`fggY~Bwi-*7ZQIZ@d}Ah@g+&bu7!&9hHa^l1YoGF4&LRee4bWec7IycQ%3RO+4U8f(dki~u zlf-L$B5#v;omuAps8d@pFN>`NcM7ht-3JsW@dk-ExmXe?MdB@zuq@9%ytQn55RFve z4q(4*WdYEHtsGDufOBJmPlH!~i?>PgBFUR13rWRDx{svdT!UR7)8g6qE&zOG8$$iC zcv1=7;z^}o@uWwJoW--@W`XV_+iH_k(ur|waDtqC=2{r&`RKn!5Q^uh^9jEq%Ll|2fwUb7$*i*6Ho3&X3hfK6|J~ zr@ql|O?v1+P(R$la((9BhI<#b0X$TEQeM=}o%FDAJ1q$Jt6}achk7t~E-Yh%mt-4e zG^5)(en+Vt$0ZW7Hl7C&Sh zeh8aL$3mcZhokg_n~Ahdz^)O-t`=K3NtM8?c;lk3%cd~rB+*Gn@Xa)M*AXPgGNhCEPsVPr_6d;u(*uK^U zZ}=eaZQpRmY~r$kuYj*fYEDuMl3Mbo-vWmW!`F%=te*D2e;Uhn9EZ$??}R5KcCJRP zSG@x|Ra*6G8Sg8LGe(()k8g2sogX~a`6li2U%%hh^`Y3ypM3x6%ZIZ(7(RF!wjUkm z2zf&A^Q0Ga!{_}o3^5EJUdfs3O(okeXy!Mg8N={h(G6c)!|5P{lu>l7hgM%41NwX3DDbmoj#uGyijJTZ?U?)mb?`b`_Mw~ z6|3FpM|cr!4CJ8#QE)P*FhJ*xR}9|p>K6~*z?i!V<{ZHxf%AuSg9SlT(|P8-YJBB= z@ggnKoWBZiuH_=+g^@Uv(KxQ0X;fJBQF_%){|X`4HPqPEg0&zeKNwFe`Y4Uall~PD zv=(0D>QFQSg4P0p)&hdo0)o~8#4*M%JMg9uQFkCB*iDnTNp|AqY zku-)mWfkxyNn=TRgE_@HjmlWokvs7BzsvH90yMPnuA>74wXsZ@6hhKC?%+K=A3_Sf zmwX6;r`4z20UIK2m3d?%unFK9!Jls-2~%%8NfStdFBU-(Jh6$U;uStabtqk7ySYU` z*-*Tb*lJDTKXZzl;uQ`$W>^$Slbu;2mcQDFQQ{!(U$|pFgdk#Y73`{8E(ryhBwW9| z#-^YG8cEYgq5@aELMj?(4%1Ce8Vcz^21(ONnnBV`o+=QH|Iko4`wG+xc`01h#tft91X4ZjPb`K8?4Sw;b=P&d;x<5by2rmbMx8E?`Y;v zqZy0v2MSk7nnx0+cM8`G+E{Qev>{>!i>0^&(1Yj=Sb$={eE{UJSOO?X(n6BJu!~7r zLef%_mXWmFqz$n&s)IJf2h1(2VBJw(!Hltr|Ew=^v>_s3uImmw;w`Ooq74zx(&mRY zL>}DQe2#F|#hL*82^b_^V^e$b~EdE3{Km&MqeCxuDf5NlT*96vyX_3A+fJH;w*Uam>)-o z-_K>la|mAXC3E5xmuST=ZlPNdF=%lpdSK~#VlmD86~aLrM$(6F(pB`sH~z-17CgKp zeZ;#$X?~n1=_-!I-s8AB)Q30<7!3piV*o^uMd+W6ByA#TGfAJ21aa~y?-~k(0pl_5 z%t+w?l*(3;wvlu~*RCf?I`!`tuObU{_Dw_>;m__6y7g`D)A+7W%!-5t<{EPbEuk<6 zt&y~y>ER6k_F@M~3e&^Ahi*lPV{xgYx5X&HAnYV*7x%UdQ%WT1bDCd;d;3Sv!-{XA zp>^B=Tcp*%8UXTHglZPw0p0~b61z#-L(*Q7_L1}jNnet*pKGi~RWk-7ZqWa25pnf! z3Q4`Ns1;3*`5|L8i*k& zmL#FTg{+u}#wG5UjfM>n08F_!k`R!_GYS?_1|YK8l)zTm3WX_2#UZmPN%Le%7WDel zwsCj&g$Ea2ez4@QHv3Fd!itjXWO=IdV>zGX(vx~F|9Dx#^|yvj`_qFd`5JW(@lav* zvyeq18yj!F7!Vc6Ys^(VhMFhMW^{`L28KnF^V!TfG~);)i)`2~kff5N@r?P&%ljlQ zPdm+T`Oj(NS2T2;kCRE@3h)~M`7A;;i&ud^fomisk(5kQ3Q4%VkVaBENf{0ydlS`J zYuz@sk~g-xkj-Sq$mT!Ciky&@AnSG7;G}>oC)$w8@mD$g-`qmCQbjL|REbX#PP_Ct z@B~R;k@Phep9F9x_ZyN9@hqrRkk7+P)zCOw1;@pJdz*YQd~3|&I|dS6ygI2anrXnz zfM}%WfO5YvXif}q*%Jo9=PUwH`KO8uN`xt_v-IFvy+uAHG;MA)St-1M)6gm!6|v8#o% z1&9XhNM48Lip!Tl3>QJlXQcmn_S~sWVY-a)?Hxn6(jE--7krNRtnUT( zk?c*fg^OPT`$;ZF^8E#_c%>LLp1>Wmaft=ufOwMcBe^)qCHT`s0Ld3nymCpBOBD)} zqv4R*eBe=1_b_b0~tV$ zTO&M}9Nck~5W+Uj5qKZ>XJsryo%oR#!nQcy!5p~FHCaLW4$T}jn$d4MN=Mjo$qyKo zE3Xk?=@gnd<2ahrDEvTjS(5o(@6uVFHso^mL>oV&q2IX!CV`8{f#V%=(-oxAIt$8@p>)+#0BtK7>XYvbNADPiI z(mrGeVi{pzc_#2WFbg1HHpy*>&)h_kmy^7eWP#+PBwr;(U%1*?9k z@3qA8ll-1c?B^TcbC>r}Vtq+tKi45~RpolZGPf5HL`fY|$t{M?GF+9-P zF)YaHx}WhLPn-&$roK57H2li7&iO2nZ=>mfAz={{!>v`HX;d{hv}*sU6UPLHPH7Mk z=^q~X?Bw9c(XHy-r5j^89qy)Cp!4fJr#p4i#9U?*%YKgY4-M)S9BTE;`R{)I;StvG z{?>?zA(5S@L|Q{5g2O^1{QO?V0qEZawKf;E^z-ZJ9~u_gCO@lL%E)t(9eFPDauimO z+?M2aY>!p}Z<5@e=@{xL`FdYRFeA=+ol&;l-PkJ zLzMI<8R>ri`^0P6jKs?xBk@-{e^9I5-u4YP?LXgY*JFE{n4;us{7e=y$TN2rB{M## zUGeys&L7XNd+LQ%W1em0L6pD=ksVG5NAG1gArK`m8EV2JA44ce9^{sWQoi9Pmw=ZH z*F!#QoNe8mkT#Mhy6i zck6eaGCDXQII^pMNQgCjs_Ri)#8Ld>m~(Jc^NAd`g{YefWIgsQalX#S3s1CwWikn;b0S56{nR7<* zpNJwyJj%nS)KTC;j&vd(<+1z`kMa}-w<-pey&(k-i2_$-G|9nStOiskc?`)|mnRP^ zUf%T%fy?YuYNPSzxMNU^f|MDh4p5g^y@ilGjz2{tUx6pVL6lIE!wLiODD0JhM3knU zNTl0yqZ(CtuG^0*-})|KmRCir?$0UL3S#_votB>JlyCCJvN=z;pZ50ACkI%Yk7?>o zJW6Y{(bhOex;Lb>(TQh*Nf%0cCZ2G2;wgU2b82A;WG*eaHq#e1 z`y0(zlzu3@Nb)3-C-bBkfa@B}0cHHpC5r-oM)BtkAX$_lz))ZqFdTRl@B=^?Q%Qb} zNCwT_RGf94(YXqQb4ILK6YHmkiTZ`mbM)-9$GsjYcIV%0lm7vs?HoUQFxu?IV8{JNdVtQnN9K= zB+qB&D9{^+%6v4w$mrO(92V-A!#r~mzYvbgVZ&Q)mxJphUV&!b;%1m?5Z+fHwiV3W z1tc#dc@ck#AiuK4AfUx0FDVoR#J3TcfZq2+CgHUP?_RyOPycPJ2L9UYw|=)x0{YOb z!&m+H!}<(pFmYmVP{7nkYee62Xl7%^>_lM~v9p8sn_HCK25qdmC)(JLhT^#cCV>OMK_Ci%yjEg>SRjs= zpWY&QHOXs8UQ6=ZB)`Ko5>VAa8-o6Ci^7>LppAD8+E~Z5v8CwIM!JJGGDv>UnKlsJ z&yT009L7L@&*zBG`Vj!(j`buXozkKl1CA5>q8}AJZTx`7&lw#Xv~gCajSc1`RxYp= z{m_jz%0Ke9D|0|AD_6KB<_JXhm0y5gN&cARjU;d4Pk#e&BY>sLW|DEa{O^4xg>z|` zIc|Akf&FKibpO0g`|sb1Zxgku{`O-AbEqueQAf3Ss@X#MO;+ zXAZSE>XtGGodt(lQfH1&a~X7(5m(EiW_hC-i^|7Sj^xis-iAq|K5Q_@_IqIt^>H** zl{)|rs80ZufG2^_WJjbyw`M9)as}XS4A}$M6HFg9wXVu zq=8qIlbl%OTotvE$sDRL$zM1zhYAUuALdY7V{lCwY*Al8p$*CVNj|`npdElH*+G)y z3*1#vp_t6hO^KzEX(NRB2shCl5IAOVK2_gIo~CH(KNcXa>`nXi?Bp03^1 zH+xnJZqv8xV!w~Vly32#o7elxW}U&F>g=8H>beIqdmMUy-A|{LAz}A>xZa`DRorRN zl>)~|)ZseGCYaazonj=e*Lx6ZvS4@kDe6d_Hf;H9W*nLsZ!}|3Ls1ALStMEF8N*?H z=m7biXan~E)YrKKrj04URNysW8ZaH00l+I!h+}FR$##;HNKPg>g=@@0RR>+n(f@5x z-@q1vBh?Tb=}a4ki=5z4S2$>6CCO>dv;obYFWPty0}ZjP3l4Q13Q!x6F_}CGJ^(h5 zoJI0i1ui&LsAknv%@(Xd3(-MxHZBKr`~v%7!R)2vn){$aHLJV%_?c&R0=od1A5hIV zB!A1F?g921>~o0Z?+OL`MB$K`eWE=vN#)&*I{MUWHzn?mN^7UKskFyrpE$Elyr((` zES+YA4exk+SJMZ-ivMW$XCBzchW=Qv|3w?3P8&x|+Q_44s3xHqP7h~^swM*|B!5rx zF)pSVv;md+&%+z)S7_)ccfcg@HSi7aEpQ0<4mb=PA^8N!CrLg<@@bNPAo&c*XSoK; zX9sPZ(En{wPhkt%IA_qt1*VPPiym!UbkN2nlFvKS#;-24F%uKhT+`y26c1}!sMj#k zESdFLa2zbAPdp250k=v1ndB=4E;qFMyeyionQ>`r5YSo)09j-gNyg8*%%9#5 zlr}E-Ur7G7FkJ8&>vLT2+QXhMUa^k!V8WgbUMpJ--7%tE+e^j;uT?PXAZqO%nCSOF zX1!|*x_z-I_{*kMngZN4ig^J*mqLMeK=)@+2=J+O!DcuA-BEKyI0%u(WUQ(b?!OYWS<#kotd8MyqbA#Y{cI`=DQ1kP`A^*<7u?XcJ7{AEDOH?l<8v3MVA*CiMurIawQ)p)`-QbO9NvTsPcmv5GI&XaIi33KY2(M4s-22)A z+riT{et(>kLNf3h4x4q3c&hW*3vIhTf4kGAS+57}yfUY8Ll3-h3~ih=M%+v14gL8| zZg*08I`NPlp>?O2-tzFpZ};bpVess)0?1Uck07NVAxTE*&z}YWfrc3zK+3?vUxr9-n)4k;^9Bm@NEt%PP@XXh z@OEEl;$buo>7D;jh1((J?Q6IL=8fgR3ScF$3V0KMOt-HlWjHDD5&a1HO^QD$0i*;v zc;jtUXWn?%+_I?Gc_WA^VSd`7r>XK1d}qhz(u$n3g6DrZ=S?_-^?DXJMUQRk^@=Z$NE7M&g<G&Xv=N@m zi1VSAHM@p}HzwXGQX*Mt{htV-oIRd(^mvYxNvy}a&cd;HdF9;aC&xaOA=um&8?#@= z@BS54SgJc-H*UW|%2YS0ZvO+j{%P!LvEz}X*C5sHknGd)Ce;xnPb$vUS%2R~0SA@@ z?VV%+iUIeLGM$teq|78F4=S@rA?%t|0w{@ngK=hgcSv?Pp~xpx=He>g2iE=*>*OXq zYM!X13Z%^8=`$whV@XY0{QdM(3x4{^`B|vDl?GTNBasvuF(}wNxj{f!(9{N_@QF1% z$Fou{#F6v_#`#H{D}E`UemuOz1j6#VuDe3~CspTNL5fLLfoi0{R`U9nNzdpHQ7iYf z{$&yp!IO|Sq8rMjx+oy7o`i6EQhlHS00o}pL&`!@7Ll@;6vWGxlCq2x$NHB^jZqzj zGO4M#WxcK&N?!j`;q@<-qPPBKQU}L`gKOfv{$)}Z{%Rve2@Jz1ukn`GUZCO)JqYZi z-WXjh>tf7;J}5v=ze&nlJPTd~`jY}JQ}7F5CPBR?4RLggG!@)cSJoKes%y9LD}rh1 zncTxwNh8oq5H|yxnB)%x0D+{uP0Bl@@B)}gRsaEYwv^zULa_j5(l{J4EM*e3x4YH* z<--pTtoo>H@0GsFkaxbFV1~JqCYW`?J=K{%`sGpwAME|}`jKHFQv%T0uyY^lW|Id_)c2O)!E`eg(pFUCqacLL4_wFMxL~W zlue{;Cgl@SAS^#6Wh?KBka-e9=1Gv?x^Y^Ef3GLyGg5Yvg7>mxrr1eI`uE3?k~Z@> zLggvBIOe5tD;QMz(4-&Kl_-jLnd1B zoGhL~h_FVq_P9^q@%|GgT02h(j=-a}k-`2U9m1xx_Lg z13aud9xoe=um*Jr_aA4CXjRqM$2cB8|L}1Csh!Mb8ciSPAB<-@d~zN-_TI0QQrDFxWw^p`faHPdEu~fo?UEv8_c47Ug6^ z8N+{+B6m+X=^F=UeM?HTlUtdD8vst$vRGS;m~Jg+-SA{APhy~dz%KeEIEBJ#QesJo z<4JG^I7>=ADTxK{Rwn&~#xEHi>uzPzMcu75(=ojk90hgP%Jos1q~FoZHExFK0A4}T zRp3ujY@`UJi2NxMWRh+e#uAfFE(~sEaxok-jAinDo(!Me_Th>FUHdlL`@n}UJ^1XE zFvG1(hU1~vDdnlo*T28jcTCrAzwVk_aroD5w`IB;%j7cXkNrb-$(cGmH- zz+~L1OL4Qa$#^s~xvsIRCAkhMso=Wg=SWG*lbub5R!?rm)nPo75iL({1o#4t0YuA_ zo05`FN(L#Jq-2qjP0CliYjdClfKWNx*<@t4B;!sEwAgo~;=#)INPU>pNB;eGHo3EL zPA$n@@DsZN-AMU{6tK=AwzF&8ty|-!cfQ3k&^jg3ul<0I-Me=V#RG!;Y@lCPYh=gK zSj2)CtmuMg!2|pQ$5y@DeHy)yyVv(C7nswEHun8zhvesTSHtUa6R5HN?wCf68(EtL zG|#!DhwJ=?Lz4WWaTQvU`x;|<7y}BzP3{jM?tX-nKbUX>oPI{L+e~AKg{8du^aZyH`IrU z9&dc>;EhA17IWqe+=FoPC33k%m3#^VeTL5wpY_wg52O|+wFDQ>0_OzC;Ql`zg;E zyINA}lFD}*QtFXfF;Bik3fzYjj^wj1kpe#=1%5;d{D>6z5h=*JNohvvehJixbMgoEt&`AT%XVNjP}I%^fBh0C8aA0z0n$}oQjwAW7byD@WK;Qe@Yf=WH z#g`quy@bLbQlBBU2KP4D%llR}Qftz()2xI3QTlTVvT#yHatE+cDM-gj83FhM0YD%S z1XxMMoUKjjv!vD`6_fKhQtPqpuYqqzn_EK}TT(($=KD!%eg4ys|FkM{i5Dr89kXo; zsSTVtV;X;zLk;I*)lz0-kU8+rRxM=?Fqc#xQX6p*+BjuC;Q?~BMS+XqlqG0<1$X>0 z{;?ET1}rDFF{w>RZOWfQ9;d7_tQrWWd10_>DevHr*+RYR$wH|^TQ#e9qqDGYOO+WT zs#U3JShW-gXT8q*p6aw0$Cd0`vS-unzl>k`dfV|&d$4Lu)_h9!bEI1~Qd=5#-tzI{ z@szD-X1mdh9wAHFrdze=O{dmtNjC6G&}K%d~$^ z8!>1|U2-_{;9$F&$O~xvXGh0B>UW{l-ukuR#Ww>i!MG8S>!aN%SJ28;ZiQ*)Hvob5 zls`!AODb$EFTREm{f}=A_;BRq+G*IozCnY+Mwg5HnXsX zIX^RzS{y$Ugp~?e>@KMT8ok@+#L7-H-akCM#^CH5T*qa=Q}0LJ2aEyNStGTK&Kl<8 zn;3Kq_YF5kJckrceb_PWdPB-MO}o^`%&$@_k~)}gPru0q-YKmr71=SytTn2;9v`w| zQmdf~t6)c3RVq}{P&XBvS`)k0Hg>h7LUarRv8F zAdgd_ic?`IUnSL#)DfimlNvy3Anyv1oQixHM_N^C3;s8$L8Oi}(yG*T7{h=4>&H_& zI8G+`80nxcA!OXC=0&fqO`F~Q_2a3~y{SDg%xvvay8&o!6k6mW1ac~PWi+X?nOdAz z={8?Kjt=hn4x7||Xk>t+gBMZ2^^Nm^lut|QKs}F29eXb?qe#WWr>Ozl0Ss8`P+%B< z{Pa`^;#BD1)DZwCNC>IpNDU>dj-rkybpom3Tq6)w&1g<4%V!v}RMx?mu@OczXCfQ0 zSw$|IlN#ZeVUeUF?=vUK=#n_^x;J$u29@|6@mYTzm__O&Qh6oK)Y-rsQX#HiD{upr zx&VzYHagZr6se2!5XDqeg`LmaJGE1xjZ+aQ)-71-Diq!X-Xe7xsnbcF0SlJ823TuY zu$iR3UMMUWB(QFcKJa9X4t42Uq3p+Y4Q2`quQAk3?rl0LCD12f|VXHa_XRC z9rn!G6@AfPRR?>pV9ddvnj_B9oYXD41*3e9_)gT^Z8T#^-G##Eq+*uLIqU;k&48Q0@l5$XVCb0qho_M&gr!AWl>hA_^yiMvmg@QJ2;*eRy-tt5NmPtx8`_v9K4=$fM? z&nFG(QpeJ5<6G*U{zt+Zj&rAtwBl%^lsV!|8)^Cqit2m0jCc;ClvdW9c%I*3llCwg zMb3#XT^+9D}7!@Fs%(83GGq(M_Cv_^BJZUsN2wE^0a z`WdMr^TYc&Bg9Qx-Z}rFV;J5d5E!Yy`=qNi)EXWf=+`M&|G+fD(z#2X&IMCV$IhlTrM}Qr#Nb&O<7(TUoC|<0Ruhh%5jyU=*j$hUZ1;ksnk-D9K zSyz}pk<=ac@~-o=-e~A0?f~X54S6JKeF13oG)VNc{=fiWAgMb^-9=c3P2ElE9#Z#` zy3aI!X&lYw+5C#R9g3}P{=Q(#x1aymik$gNgAZX$ZFo^%I+?#Tgw^vCEl!(&!Hwi| z#AiJmh#>Uv5m7_jJ`PbN0hKBZX2TU8t z_ek3TK&z)gqNjZh>;}LSDybT&c2bi_O(v`?sHQq-;|o-0+SqSy4`Qp+MjA6l2LCxy z^k@SXFXAX^x%1ItxuDTLr z{cO_41+&hNp6U#`|EZ9&DSgVV-t@wE-gUeG?twNgqQ75wsBnRE>O>k|DVa#>VdHwg zQ=He8HLju}Cw~0J8rO8zIC}S1a%kps$aZ7eK{;)8ns(_3W$Rz1mmu{xM~k0DPxvoq z_0rDOU5+oktd}Ld9I7B%{MTzE)60{3%1v^oKZ;!upVoIxhbljfD(Q$*MuZV zn^PV)o9^f59}pHE>Blc0^c(L#H6+YGsA^Dfgg>4>8W#{Ul~b(4CPx1KG8Vsb*he*C_c@z!v^;7~lO8|oiYwbAsTsUbm4TD6MM-*;#hdg4oKNc-?n5q0ZTofH-v zc z)k+t+xOO@s{syt(p3p64&Kt#FU z$J{m--)YdN>YMAAPJQ*EsILuEn+`Rv*IDGLPFd^ej_tl}C(Ug$vRLs0HPYNoZTeF5 zr>DM{rZ#;!n_BID(@0Ln?Lev)o0~#UM|?k>(@`9@HvMh3wOW~6n)yFk%`Sa|V-hn< zIZtBDUp?coBJSRgYzegDr>8!6cA?@M3nP_Bkr^j-2w!8ZQMBvj80tmdPBk-OcL)s&xJxW>y(jFtNB59BF zu86~@#{&q~>n7TUe+#5NL0AP@dr>#h{Ye|}?~jV5Cp*q*3Tc(@kk;5JC?N2zX^rU_ z7@us6v(8B=C}g2E()h*i>0bd~llBy8&6$(#J*_bvGCy6{{M)Il@`b zC=HY$?K#rwaq&T*EMbjst#N^y!Hh@Hct!3Q1}_6HL`DSw+|huvhNSuMr-m!?!whCr^JLOmKE2=nt?M11n$u{-v6*up3^mMP25UL4!=8#;g8%CS z2G#aX>GSG`lMY{r?A$TL-3(^n#zF=srR(PicNnmsh=x}N^ZK{>NNdb!gl3u;&FF!u zjK;bdY-X52GzDwAsDEzOGy_6A!x6d9cpin;q_rTeCC`{PdZ0>cbuWRc3`p>dUVNOO zjf~Df7oaQ94d@O)UT5?q?RmmV^4bfewIQu7Y3)dBZ_-8v=Z1qeGWwZY7UMc?bYRBl z#DDr0Ioik=Zqi1^tE6>wrVW1=+PHr+M$C9N(DI{)X9F`vV|2%2AAL?DTADG2w9ce; z;aLy@j3ccpY2BGO3N)`V1KK=eqS3J)e#wZ`HDNbX%=L@MEPhPRbrw%UGmbcU#&i^* zxie;x)`K)mtzJw&vj8&ar#ESR3I+X`aq@Ng{%!{1)xH?2_#vWiVun+hGfH=$A~z)?j_`s7Er2vQA@7m)4r%ZH`}J>z!l#Na8Wqq0J86ETjUdgR z)$k;O-l&{(Mc(<3sxF`!Z(nFzt^W7u}6>W^MFWmxqc^3U2eTZ!pd94UR$m z;*JOw<<0duk4zubZfrE8`v#ftwqWCDn7%F&-MOWGTx%_D6-X$wr+ z$n1^kppDGF=JrKwb=p|SjIo&itSNG|kvYtyjm+VsEpn!f5&5KzQ5an0%NSD>irvry0m zBKYJ zg^JH!mu4Iht8zHp8w#=1QG5*5=Yo4%Z;_ zZFAzW1`2eZcJ8A3TC}i#=4Vk8SxR;#?-yoBdV%Sm0gp-g7Cm|C~LMEJqOa#s|50Lf&X&XrU zkhG6T`I0p?!iA!G6M#|H7^8Ow~M5nHp)E-I7Orefi0! zMn272wrJ8Q@Xl*NXCgG7nQlxwOD4RH%rrDd+7@P*3;Rg#$qme_74!%L*Thg|Y_8E8Zo&E@ew(VXXVaPm=hR$&ZY{yOjCjn^UOi1C(AAmE! zS<)~C;ih5&?jjBMZFZBkhijZiRgNmM9peZ)Z#h(s(D`2d4zb3GoLYim$144Ov){MI3hS8#2VqL6}++pX$GCA zV9C@7JtMbVWsj}2pNM>fa5UlmHCBhSb_om7mxwFp{v$XYp;s^#Zp}$2*BmqKI%)fy z=|qp3=Ux7075B1amBOI1w8|<0lqBs-()M!^YB&pO7?*QYfrq%Vpdqs!c640M&~yh4 zO?UpJ&I}8Ooy(rCt#)f@%H#c{t= zXd|l~8tTR!fCRGI108^lKqmlFII9bQxT{Q>LYhh%covbEB+~Rn!ax&QJy4yu9AW1z zhst&No5GC2iJaPZMNa-^y<*Zv76N#wPPCDwN6qs=8$lS-rIWk(Z!VKET%0F#PMl)C(#h{HTC`<)jBMm_*+=$~;&@9Buvt}5y z0mE1*QbDuk;*gm(kf-8K0T;J=XI7uwaoJmOeicS6Qna6K@S^M>$n%l6H!;)1>`C+8NT$@~%4p;F^vS2CBlg6uSW=Q}z{3o)P zWS+S9WREOFnX^(Hy(OWLOxn++UF6ZjW{oj@>XdPCxR}Dpb4W`LnyvQlq zte+jT?ILM^I-90n_^W)Frav*zH~1X!S-%EAB;)@ZT)YV&WPFqC#dyjUXk;e4n3pBH zBzFw!k$oQkZJk|$G<0~I>|Xq7Dd2wHrr5p7ZYd0rnQUlpwkg@=J=uqz89NtOe4@{& z#lJV*f4%l8L_YXw+U!ToIu$(C$+o|>blIX_jdygry{dWnm!5OCDcMl%*;vVi&ygOP z$*#na8T)-kNF}dX8rjv*3|~*&3`b_N@xo+ZvSSfWjxyxAnYyT1-)P2?{TvGQ$X<%< z$iTE@H_!vR_R{wf(9LdwhS=gUZDcnEprNxNowHj2ErC|R^JFhW_6G>>!?l+s`$J?e zNA~h&KsUP$szb?Uw==gLuw_MSf0+L~%730Na*8$^VQ&4Fdv+hPKjK6i*)O`#MsCR- z*@H2<{D>&?M)oVf5VBVwyIvfI;&8&NeCMC!2PPQw^Ay>u6bky8fZPX) z__%4uDzVKT$*$SP_ZyRbrkizGp1b9mO$@BH{}X$=?Xf<)n+$pV(JLP4XBPUK!$alZ zjoCVHR5f@5qwYDqCWoZWhMLxA9t)ZuooC)s<16or7ip2^{MAb5S}rl%?A17~wK%Sv zG2HC8$zIb<|7O33UDq4CTC&%Xy%zLu_WNY7ou?RXHqY@-xjIB`HcyR>z$Spp%u-v( z{w&$+ki9P1pCdaMu|9tViJbizenc=v9{M*M8XEJ{-hk{rMhy4=k@p>dQB>XcVL?=E zfE84#0*Yc1IwFLGUIGFFDiBjP5K4kc==Dl(N)Z831O-J95mbsIB30d~tEBhdqadQ9 z@IQBEmM>dO`I6uNi$*y+nb~>o&A#{M+;i`H^TvWztp54x_rg)5p)MRF3*NZyI>hQ3 z(6RK@t1f(nDmsa3)<^{Mm$UOgj$HlU0I+$mSA&^T>|?mv>Qx?GK&h)&U4VwZ@SUxI z^Vs>8EbYnCfeZLv3&vPFRwfv8K|w|_TmW|pOzF75=KlxaM*wp80#xvYXu_MeEuG2I zg)Cjk(v2)IX5DS3i(|}ex)O{nt6!{s#O`7H_iju6oOL&CL{r`4$?F-h}=f<)+CvA47kYGol!E zGg4|(FhE36kjPO8JV(_dOCPfIB}+d(dOL83Zn^rCWk7YXTv3Jyj&do2Kl&tm$A|U$ zF4(rTMb9^SH=LzguBZo4Td;Ofja*r-)uxoY*ESe9^FZxdBT{@Gy5?-Tq8>t8o`GSr zTv0IMU=XadsVUy_*7&2yrj5~KqFQ06HCcv`#TPv$>M@-*hE|3)qMkxVow)$eMik~< zL}6Zblqb+0fEyCSp^H3F48ira`=eI$U|hvwy1tw)Up#*k$! zSpuruQH~mi%>B7wzO%;ze!xp)fx;e77C$~306+@ksR#?c@UIs4J5TrEdv~&{d$)ha z^PS!hd{W>2+SB)koo9YB?)Ok54TQO~QvGDkmd2fD`Sg72-De}k+*7XZ_i&V_&Gz6% ziO_w6zzT=Eqvj&@0==mz^F831iy70psLY^%f_G9*uef*bHm|wgQMCMQ&y;gM%@f+0T1QSm0!zuxX{gRMf#giaLf;kK3;33+#MJmKkK3$yf9h`rTQw z%&N@8d{L*7k%bFjvvmeI3qWH>od>=Jz5~7|%WSgDA0)8ROGO{cu%L+dFD*z?VW@{x`u$Jrp z{+afuYq(@KTi0EgpthD3zK!niow%W;rHggo`bTuL6>ZYfMAvqe=8I+xm%aZ%-_Ku} z5!$M4*Nl6eWomR?H&gVjMjJ&VCXNZamNmNBs=$QZXk2!5Lp>YKY(+QF%+{-h*(&FR z-RK99jS+1&MK{6@LSpO4!pn3JMC{%G*8q3ZM><|##>AqAJjP7h=%sp zXd}8iS+?2HMs&}L(MEJ%RP+FDBX0G60Q|_e$%5CXo1zB-gUIp@S$0=BZA1@4<|Daa z5JdE|z;FQW&JMEdB+I*e^f>@ZoN41dvh1o3v=KcHm(2Iycvlo~En(o#Zv+k*aAHZT z)n1Y3@st-23q`Z2=QIJX(#Q=nS|?xk_FU8J+ThvkhCJqiHq1ynQEww{SSWge7EgFz zzu(Kb>QpqQh(sgGeZxnNo~E$|CQj;c%QD|l5IxiAcC2{pR~C<+YwMA){QGz+L+~OL zWw+{7G>+)TPEYQjVxpJe`mn%=CY5b(>WYR1`PfM+N3X)EYxGl1(NNO|pz5O6lI4?f zN#*GEIC~2xe;WqwMQ&&UErcbHFwl8%Owj^2iLgj9}( zbdE-B`3PAMzr+I?P}o0_<>EhIDn}#OpcBjyb@+KWOOtt8B$f74mHwFDwnd*t4%5oF;AU}NvfqjqvzPgK1Z1dVe8j(7&~aX z<7D}YuLrNY$IHAdCo1zYuV^fK5`CTvVEc6v_y#xyoCYAAqamE5&ynS8vYaFftUn^% zr^#}LEN3~zw@7NUc&xYCUW(Yl;+@ki-nVS=eyDjC53zQ=L&lQjyuHQKG<5lea&$T> zHH+JbTRj8FB+GYX`JQ*PfgG|}$f8!g#VbVSKXbus+lqi<0E8isMI?*FM$>F1r&oRSw+JM)eR~=|0=6PH)L~qOsu4p6p_gU>14I9$yaKJu~ zh*o|0DK!Y?7(-mgxD?kx^IksE>AY{REdz_sE$jC6i!NxxA9)1nZKMh17>)^(1=A`^ zlei8lA!ZVCnQG+1)2CvvE)Q6vsPtS)_N@q`+p*sH!oJ(tG<3`?vi!_KdEyQfWhazl z=GiBAyuL-aq*suH=lJ@br`=PqjX|jA7bl?{vkc#?FiwqumcGoVA_VhmxrB1eTAckl zCx`ltL3}#qHDDb81swz790Sk&3R!+5%kO0QgDh9c@+Y4P9UTK59kUs2UklroVG zi!9ekz?`;iBs}OFfex6^i;X}+Jcs0TFaI@Xtkgs8Q zFTrp#-Z3!495mcK0S`*~`SqDK%|A3~K(Mdb9Apmq`^Vs7pr&K?qG|5q7Uj};yN?7n zrzKBgKE^i(`BbK=1HdOF)FQ#eyNBFNb6+5#HXW+N%=KR_c^Y#R8J*+;pkZSWjE+GJ zItGt5#vBJQ*CXZx@HGi_NVtiFx+L68!Yw4+NgtD9-T8X_61wVk}B}YDE8m z;05#oya68o**{J~TN0ii;Ykv>G(NR2&=2Sj3;+fKgGhLagaIT3k}#iyEhHRb?y;Nh zr?08xZVm|Ox-qW5Q~Tgfc2C{-)$e3yjyuj9K5^Q}iQ!>0`^+jeZsb@0 zf?Yy)W8`*#vG}4^X~;j)9OUOWBrIt96ue2uulsN_o}G>`51nQXMJ|yc zfxYp>^#q(XB64~_kKwbYPYMa0<>xbPx?jn^2Zv0U7#SK8I$>Z)q+hS_shv9bjr0$n zV7BexZA6iMriMh0m>m&m#@ma+f+J`8hnuxa3ZFhLvOjbKuBeRP68Rs*p~o*AOHvi zf=FmjLI)B$lF*5S&Lngpp{t>JVkdyJn65&M?PP2<&C`wLPIvz3SK~BK>`LIp2D#j@^+eFa!d!ZRfBi`ZkA z0?SC~NkX40*FCYTk@;&}FcePg8UW5z?5iYrk=s-y z-1bWGD(nmCyV)X$7Q|$NHZ$-jLZID11#njH5T76TWgW2{iV)n<>s@v{4+k7$gv0 z(gz7H-G%lJq17Lk{eW29Ey(6JJsWM1Ag-Q98vzFUT)GSFgN(Y44+;yM&Z~>+%W66( zj<^QMhNr%BkBMst+)V=PKfjSZ?p|#+jSyU!*)(wvBBPdE07xJXE>qmYKog)T&b!GFW*SOJmnbam>Ib^668ZzKeY_<(#wJh=W>> z)8^UZ4(G>n;+Ql@n4{nDZeyZw!#BF8%o~0JQclvFTIY=rjW_01Fq>(}CPL4~6!$WA z!bw;_!b0vbkveZIsuXX`K}N4|0n8hi@g6r1m=7!f76OX^A_4ziAp!Du2?UthDEi%?`X#*Mu6= zm(;J7?}|6JqgHp~9E~^L!Ojj6R+F%XdjaD;64sKivFdqa4>H$8GcyDfblhHG9|`bO zUL#>0AKedptnJ_YE2xCU=tyz0siV3P-JQ z9yzgOM{DcU@tsB;n|10yZeSqfRhHyXkPT<8bs7~rRuZ<7@FsVdA9d>3Rw?R;Lq=&_ z024txkN_kCNkB4?0;H1g771^Yu$_c=NI=KkNy57}$&rENOc^}mhPSM}HOcWFv&L@z z_@w4Zj!QP`_=SXB_S69-Z6`U(TA(5Bnwu%U7B><%`*rNNk?=kVA7D4$1k@&B4+#*k zRlKlEJcM)n?OZTOBK}sO9&j58ACj<_gnfMU4geEyFoRe4h=l#sfjZ*v#U+C};_q`s z1Lv+c_|8uqu^9zrZ=>OO4}=_~8a`#E&51gdK0hLrF7lnBpO& zpJf`*wj_K__apSopNqb4aPw>jQxrcQXZmwfapU^|FOl#K30VEo6dwQtl5m=Yv&nJ6iVN#IX-6&V9v514Zr}W|f}I z3cLM<0f*lhvFy~Sb?pOOkkB&ZvC^nOlbU;dq3Fs?K;pk*p_lltZLRqkew5RQv1dnZ#2D*nck#Cy zadl*uGpHj?=NcfY)`$%*r zaUk=M-59ZFXX8@31_ycCj}hCS*U5HXrvUfT&g)`3&%dj=Yz88a?4oWZsYq zh9OLV!AYnOG$7#;32;3w^U=Ej1g=@5|4PD@>R=ud9>gW{)js6P)Q!9UK*N*1L#$iI z?DPoz{T|HmW%HQO)JW6JRho{YPJCE2-fQ)WyNA~ADr|)Oc3cNMp(XNY#Z?7+$QnK2 zQB9EiuA4{GxA_nx=XaJRND`hv%BPHM*vclf)2!^(3TD$0DG`0vdrT+nbSB|160UKN zfxKqgxLz6BNPq-SU{TGqk>CaN0=xkqpf}J5=u4s-iM2>Hkyx9=IwamiVqJqa5(XeS zXd_{evE}$P(}s96f85F+_tZGrNEl<#M#A$X-eRZG6UJ7MHUd$(!Q4jN>Op{+#Cjy& z#=8@Mi6q`m;+<74&J(60^J#j)`n`ZLyHh0IVe7=b_+AJv^Im}RPME{lFwe{cW&yKF zyo<#8BsSoq2uLT))7VFBNaEeqf_*sT&Fr(p6_cEgder~H_xqR^W$vB-%*3m|8SJy% zNQ2P0vpDa+?8MeLk9rp^eKGhWulM_%biqEWQQoUYjcc^AmT5!0w}Lf}r&tp<>)DtR zFbzN94HEAs@d55JSPTZVAvUTMZEQzI?{fi68}9%+0Elm_du~eL2HgehCb2Pz50dy0 zi4T+5gv6#KHnY*j9wcYl*lTP#{H)PNb7qW|{L!xF(Z&%QZ5$=Bg*|P2SwY%3h05hw zA{uR+#?BcMA0hEkZXyWqg!3e}BC$=?(*~4#f~*&;(*}m@KpU-%PJBLvX=7BGv~dC1 zXp))x6ZCTeWOG6ciI0)^IEiifD3o(TyiOZWkoaV^pp7*Aa;A-RR}`>p|A(#qoHS7U zGELpFJp2z|gEq2^G}*4wbXvJ8W=BWwXFh1up!=Sy;q_h61`CWrqsBGbD9~sFD`~

    #xEh8U-fKE3BO?HGKn4}dUB7sqSHqEO3}t&Zl=VWxB#XNM644Kp-RLxCe{K> zKy3i>q63K?N$f;oXA--R*pY%db~R=Jas*cO>< zk{Ne)BJ^|OlR!HXdy(i(q7NTMlseHvzu$Y4i1%^)@5dk$S)Sv5PweXI-aR;U;XPmX z@Y(%NBd>F9`g#7U-|vatjWo}=O0)H#(Ea|~2F=`marnxkUwrwQ^ZlOah4MHwuC)coX2OyildN$esWa1!=HU=29@k}^~8X1)_0GT)( z**s^vni1F;N#Y<92Xl`ZrPIcc%FssQSY#B$1uzMW0}!rGM3g%5CBPpD00K$$C2=T; z!$^FV#Ni~4AaNw8Fe9mrHYRF+n-V8si=O)5Z)EN7>WHZ2k%= zE)mN8cD@s}Es3M4_96Xq(f9Q~bnH=t6PIvHaofKFEG7{S&+hzX%_CfFQcuS?}VdXt!rn6s-L(Zj~&S4J-v-Id6uZn zvlfk+j;3;og+v6;6IrvPsde(u=2?qDWoV8Pg9V9)jP4h&hnGu!b=cN3kB~Tl#}Pik z$@tH)!+nXX_zK4{0&rtx&BPNVhByrtBz}WaPwS_e5}`*Y?Zg3S;>qP2EJ*woXS1s1 z!Ggr^fbRhWsuLl16GcEGaSDl3Nem@1jKpaqzRag80A^(*;@9z0(1||+7f1{z5jWjO z{1mjfpF}KggqJLa1Yu%nNN@-q92y$jXV%1!fRMI)>%+8CK>XBiVnx!;2MLn)ST?b8vJ>qMm-B&WkWEL<2E>%)3A6{`U#=!`4T)>{DB|i#ox#r0BtkK~Rvm;vQV(1* zyo#iru8jQ4JDb!y({sqH8z)*%cJ9b;%3@)VL#J!XV9uSncfnR!J? z&m$vkvI>*H3&4v2e1s&p21#%YlHeL7y+k5{o|{SBLgH2u-y{)+_AO2kfNQhShVB}e zk|y97Xya|2Hr`>{*jw{xBiu$Cu-e=0X=6qOX=6SrdXcRYEWi$^dk2X-xf8%iNP30D zcS+n;^|Y}ZnXj@Hyh3-4-_u-UEcAsR5kkv`l=X>gl6)5hU? z7dFR@>OEs?%#Sb3n>eMH3)cVv*svVM9=-l`w2)BS0qL=!#q+_Key)@ zJ02eG0|PySO3nas%)bzM{AA0&2s_0j!m<3C^Z!|UU8;DpGOtTbLPS03Iv2o3={Mka zfF&`Ma1xYo5|nV#H4+iqgSU!)2wxSw@EnQfjWM+3T1bvDv}9cgo02)Uu8pDb0-@sf z{Bc1yW6ei|O%D$=`-BCV`)Dp?yNHQlGkMns%cq9>PcTEjIiG_iEA+)2>Nj=%5*c8{ zh>(bofGK7;na)K_@t++wJ+jZNNONce*0sVp54p^x*YwDVVc{;n4#XAq4Vw~#6){|0 z;7qJhF*qdDT+$Csu5a|OuXGaprnBh_p^_%=4Dz}Nz36dYe4#qJpBx16pDH&oo zxfzKfiE@>jv1CNrliSz|Zl#+s9!5jKkDu0vVcW2>%~*0fWaG)%z+fdm1-Jtk(oslM zNwo4&=;7oJx*7X{#2>4J8B2Z|mkjlrj5xWoNy@&|`Gc9=yjm>{jLz8FDVkRR1Z^fm zDQjuGT%~D~NX>qG+^cAJ*So*IW$oB+oy}OX5Ax{CRmFA?18T__UhpI_N;hMubp*pv z=Vb)LlLsT^P(2${@(}F!l88aeSne^yblQlk3~eMMqMkgS3jl2-j|Rp7ki^MQ!pTs= z$xy<{hS<#MGGA^hc&SbsIlB6- zz{Bv#Ymp5?(+2c#@2LL+ch^1DV($J?#RhFaDQjuoah1k&UyHq4qkZysd#w-t^#1X9=+V(>PUa@vt=G6t z8wk^bHhwbH@87K(P(uAC?=w1{p@&L-b->mqKOylFhryS_rNMs=VkH@~(324|w+n+O zLs(vRQn$%p;MC*#sitHo%U_{xlcAKZluO+ve}l8X<>Zj8$)|wRz!~5ya1Owu&xLKP=N3@2Mq&rr9?5W~rcm|r8wjigSjZl%s7b@}JZ+vI3ln}PPP zJIPyZqPmBB*8umPfkGnB%_`+3W>oEX#6@!wYa~f0I4LINP37V#IvNl?K02L zFJO*2Jgg$2-el!c=vwb z0g@V$ge4KGIMkc+FfwnZ7p#SPQ?%zIrMnFdE$R>HwQ6`-(krDEvU!}dfqhD84IqS^ z@)$|@8TXNNKOb!iJfT@F3BRUMb+B3~?QzMlS}82To!-~2o*T4x%k)7<_BMa|#m}DG z22ILhHwEEpEln3!Y34lo>5-fF_|AIAV@2dWSCvWpV{+BOH~Bi6lC0L|`Y9q{m5W%bj2bFq5PwNNQL0v@s8vFSHd5xs6#+66S!y zN5;#L@FPMN{aLn)oU#{jffXb@MUp#79(;5auv%vg+$8O*1#4`;B{OTV z26tkO?th(nXTrY0JC6-pa$iouDZCg?V+};BwKSVurOA5n-PuDX`#$#Rt%EjyOG$V@ z)=}%GyovHS!VCkUY2B2!G}h>-v&P@OfvRNRLLgV0a0E3Y)w1t)xL^6JT0gI$)%LIa zPO%AOBb9^rO*w$eI*7|EIR_-=5J}yf#Ba*yIQ58rsww3#Nl!!krW_@yd%47K%5j{H z=!+(PQ@+B^3E*qsBmiZca*Cv9Na{gSPm;Vy>P3<_#BU1paSHTt$~n{<#Ba*C+&f9~ zA*l~Z@XsKAbN>yY-4wL7*1jn}kks2r`|6=r&kpWgN)5fHM5Bt5xSw&|LHnk}0&ze* z@B@%Y5-d$WlKPW0040$$kWWnpQh-z-4M+zvNE$>^FiDF@dXuEjNRpU|?4Ans(4O}6 zz=gSYaxdj+PY>heupQik@yu(9W%(WR)1C_D{5*p@29|Q3?hN3(;EwJkodJiCwO*`; zxohWAL*gj~_`StkZ%n<2U#Aq2G?=6zy!(@`;(aTl;!}P_M%TCiHphrxryy*dg0OYU zAHY@MPv9?-hLSXlq-RMQPSOaHMw0X#r?`%!hKf%$X@8qi>tG8NkHsq467xh%DX7M& z_|&_M`z957d$b)drryn8m0!iDHg+?mKFn=|R!@Bpc!;FuN#ZG(sZD^UB)v$|_$oKY zsSsJIt@VO66`$G)wwR=`x^*z6J_Z#pjdN1*4ZOEF5PB-2)~TMH6O3=_QvjmYsU9Tx zk@ONt{(Q7OphvBx0Fv(N2E0a9B$-xt*)%|=|eRNx2<($I~Zg;a()QW3RI9nS@T2T~EWPDRu@6;bQd7l0RmvA{Tz zCXqCmq$wm#B`K7oFp{Qm3O^*ZF-L&*w<$FUTQJAVI&(xYb1bNN%n@c|j%g&}b>=0+ zR%%2AnPUzr8ZugEj=9*GM-sF=&qz!~)H-z`Ni#^A$IQ`e7{>M{gojNJ#XD;vrca5C z7;Hb*S89mBvG*-O<}0{hzO$jnQz64smy-m~VHQcV`RGaj(>gFmOPWK{+-h;ZbA+7l z-3_kp-LP9?6Mq>s#I$M0A7`&hr$ys_-(;kL6nB>GbFSZJ{d7>@pH_!{c~jG&-yCys zzi&l(Z|QBMlk7H)WasN7Ti(^JQ@Ke?My*q|sI`RUCLv7S%AL(VWP`aIdXM=CJNro@ zl3wBL59qY9xKgwMy`K6N7r-QN7&rnP1&#q<0AB*fNm@eEQj(UDgkA&RZ6!&oIK>Gh zwb8~m+TW&B*6*N=)jDmgW!l(M^Jqh|(S}UY8hhH%G<*dFM=UBjf!l~%Jr0N`=~a?m zm+Te7PP^WN|-i& zc0~bAx;C2Tf9v3Jd#*^Wmo|JZ+n|kKj5L>Br5XA9gg+;o>-Wr&d+!Qc@%@QCE@%Tf zJ(c6;?780rM>X{ijW&#>CTsn6720g=7$Kn}t+o~b*lMGVa%NKx zDeus;F{Ryxo!d!*3;Y&(Oxm3~ZM+DJq2I_)7Y03?uhFK{1lKkxw12xtsENYZwa z-XUoRNjph;m!$Vd+J!I#D8rQ2#Mm}7wk@#L!iKz9rSt)R9IA0)!?Y(2+DL0h())I_ zk>*h`wUO2ZmCTBnX(O#G(2b-$Bz?%c-2uc=_LB5bmHR1a-pIU1bZ zE9F~qE^QF9(Ihi?CJp*I4YD~6vKc1uW0DT=Q3R{gp4Hjs6Os;A2lh$ha5&f}?Ri&B z@|*lX|1;YLb>HU}wesTW;~(qnlQz~!GtO0-N4hL-Jt1je@H>0r58wRB)@9D@llBtI z3p8q6qYbP}hd}D525pqL#zTu!`x%0>a=mBQnZ2Kb=q7mfN3KV zm=4SUW&*Q-*#P7x0*1#(`huh{NrL$Jilh@Z+F0H&*#!h6;s>o(S(|A@n zNoVy=T;BO%X?u~4CYhNapr6wqo72D<=SljOr0@9X0pJszHohmxQY~nMgXT;dM_o~X z*XiE}{XT1u&!W9kKKgy$8_Nya_|iyo+*O)uzvk9%H)YU(Egr|}1Uy%W2O%9}8)*ov zr=2otT%(O|G};g=SmWO!8_YV6&E5 zot+N-oNfXzwI-RQ6p~W;=uJRf{eDj)DZM(}@98YhalfbE>FVB%8uW9&6Lkk&UjN*J zf*-GZAEe*!=?#oD4PB*K)?b}rIyh)P1r2)dseuDrOiD$q93wU5y9ANB9lH8$H9#c&^&dc)h0g^x$ATT<(Y0 zbWg=&5*3+Jmp%qn`XZWz87KXD;02OEI=}NSg5Bu|cK<>0z05dvgOQ&4Xdgx*{r%h9 z4+{Q&x$Xd5o7r~Vf!GNm3GDbMUw1HoVS&F$)@FhIS1Z+~PeCS;TmXz;`cxnk2m_`8 zF9VoRk{&_QHIlBA>_&1el1(JnCb^EGveRcEIaGG~EMq$dTUOcfP5i;@PRb2yoXSpL zYU}6ANUm#VF4Hl=r6Plf>FZFr8@Y|R)zAQg4!22YlW86vdU3_#8@S$dP z<@zLJip>9h1Th_|U$eRgU0KkDjh>F1Fs}c(BjIa@zR~8VMTXV=%t-UOt2FKEJe;|9 zPyZ|X!k2wiC*a^JYppeLR z`cq}SjhExK8-`aMM@*0S&*NTC8tanu^PhtE6Fa_uApH~yKC54aDg88d&X9Z`$$06x zDg7L9p5zAzrWS1Z-?5H>On&47m~})z0%Sk|Q~)YI{Rfg8k=&T%2T6X2r@{dZvwavPf=j&pNpdtaF6j8~y!P?ayEy zvg7+U(|ew5_aRZlx`0n-1{3)X4pPmOk3>9pfE z%mmuGZ(UimlTq8vlyNg>1A@t@13=nm)FrtM$&ZozI3K+QxK*c}wj@7M9cU+`J}wzz zKLY~Zc~DZhfA#K%FAmCmeaM3B{X*Utopv(rG1A=YD$V8RKiJ#sg+WbUd!%uX!22_J zfeMGAgp3DJ-h)PsGwozF)@Y|)88z-#e?U2C$2TmrFJ8>9tGK`Apc1k^qlK*(L#6$0 z*NZb+8DHJ|ByAe#)Mqmu$F*Zhxt-9@c#`DyPC`G!9j6*Tfhog-H|;Da9& zLUMPKdyqVxWF(vMZxH$!LyVTn@Wzi~q5o`2q3=GgQ>S@>Q^F#qhnt(V^lTOq+U&-j z2k-TnI(-UWRUf9Ux798nENFJS3FgR1b9jjve2(3CIO_8`y&LP5J5sApUM(|Y6fl}( zFOpwm#%gVUF`gdUt0RIvyLxmsm(=-=MZAb?#@mX3=a4auk1euHzdN!tv$E8XIw(&zv>0+x5H)ac9^1f;#zs>xE)r$P^PZ_)6E1o!yur) zkmof3!J$x+!${^eCo>Vj%rxl)^fJle)q#LAq4SwcGV8e_lgH~t?k|Y(nZIsl+YeID z&Er?i!UfGV0`HkF1MjoDe(M0muY}DBFm`p z61^+4v906jGOFZPO^mNHo05!$np&P5w*zH4MZYs!;wm1+aYVmwyu&RMxAbf$QJnc0 zPDM~%J2mrhlII{v<`X2(Ete?Hgr?5y%*mm2Gd%!Lpgqt5=m?1r}CzSAAQ47bE9BrhTPxEB5X>fa!WGch|{8_URqYFo^r*go2$P#()j-oX^oucXk$daDuB%z+{P zQ$psLgPIMWJ$+J0=qwi2K4GDuSY5~*gg+v~v9>H$y>0W@-)rs6ktk-g?Gm2D&M1x^fPM@GS101Q*6AMg_34+H>#KoDRic@@c!UTa8ROEN^)Yb38T zgmC6WB!>{roMddLV5s6|1fr52*9s2oCB0 zJBEldUqR(A#VJ}pT#OyuuCJ54i95kE038C#^sOov!I^82IVP)UA~+LrJM&clO~0As zEhKMc8?+wSpxdA~Nyg0V|9wa~6QW$RL2tUUK@B&xn{nctcgHn#cGep5nDsWp25|tM z?bdczX%f7ejqUo5SI-rlN7U^RFz0O-Hi#LVn^bEf7#%L;bRf)Ouw) zb}~plK=LQt53+!4k`I!6r0SWY0Ga>91v5uLZf6z&#Uvjh`BRcVl0q!K9CK)tzmgI9J zpC|cSJ{58~3vxND1FDH@ACpnCI+KiQ7D++vZzH7+DL3&&{Ig$Akmbc~hMO&`7vK%} zko-N#7Lo;)#Wm^m1Rm~zT^(kZINm=4P(g#ypO`JPe1JiyCz2)J9Rm20ER(D)VK>T7 z@7rEaP|9=~?sdkk zlVQiR#sTmLvfu_}y#)9J0RTc*7$yFZn)q1WSOW zBqLmwS>;ANYZWqol?!GDSq;D+$XZKs3dyM?r}5F(0C)%-15YOz5#|5A{LkXBJq&Wz z7FPy2)6MtS@1llw|9oy-8}a4NvTnq)wi#*Oa+QXreVf^EyLYEG7vtS$C#=GAWR63- zS?{1cm|4AzcIfgyOOyWhk}Qc$WW;y&xGiorZHX-bld?ZrUp(|Hi!_9e^+JJIPnM7c}l|o)YP=&u4Oa zs=dqy-yI7^=sn8_z3YlLUsJSy=)Kr2WEB+c!)Kiotz$M9k&PBeXQH_T`~qAi`A?Gn zBKaC0#jN(M-*o!9PKsN#pr7lga?npUHqJ9k`Y)*UUcc)DR&J*^XI=KaBSoj5?Ak_} zIsml-o%G)7(kQ zU3@CMf^2vN7;Mx$gKR|E5xG(7lhP1O89e(4ytW9GR)D{MDG~VWp~z&o zt$<?Q<}3Od!oh}vg~kM z4~rnBnLVA%;IDR}mddApv*)9t7vXfR)fZrAAt^0LY013|aya`HQXV1Y@haE9*~^jn zYAzV2CVK_25?DnF_y`T$nvX&eXRifWM3d5nl*g)r0m^8`i(s+Iw}BCo7oE$4Gfl&&HH}06U+M@)RlV++z;u zwBb=H+Bk}gPI3WE0>^+a0EpsjXyI&V;cRH(?5|0I4Q@|L2U0qc(utJLq;&ZJ$=JG` zGPY-o?Kx~Y{H=8554_u(l)g1C{GE;IFq#Ua4E+Te|P(z=hGe5srU$ne;Gtf!8=G>2O8tJE+ za-bUq@u^S_gUcmdb0Cs)9_8fFqd851W^8PX3+tOJ(Nx=+)tNf4*C-Tr2Q{ zTdkriRQD3CtVb(vqg6|tJ2Rwt4#&BvCoQGf4pryu!Aw@^8+_nTs43*h-s+o%y7|OXjJSISaK>31xC+MkR8V zA|t43O-HKa@-WhyDCxiC_uk@7Mr;fB1*c@4=SvvSrO z+l|<2@`@MDRHpOCq8cZ!axl9^vvN7_kP>Mpue12Tfj)A+O5$ zu9BQMWW!Tdw5y57P68>5Nm;@@CP^EWP?lC^R3aw>8EJ86cx5@6Ko*b<h+7qQi7gBQ(IUgM89YaVSt%j>jpjg(jI zXd@Sr-7c7O>-(rNeN@6!;9^uF_ZBx(?rk`SdqM840OGLgNWmMoO}V!NsNoHyyk6yQ zS#CpQey^=yXnA(aHflG6+pv?`&2V2iX6WTUh-{j2HXxeZhk%EHCZud41 zKuGR0`d77zi)q#O_MNhqeX1XD4e;-5uU^jWgX`*teb&FZ-DpJ;L~U+=Qg%4$-`qj? zW{7^ODR(d_JNZ=jUhkGm|K<+I+0S!wh}vAt-^d*aU>bKWo|DXlIL;kI%6p{jB4sxz z@00QYDSP{9Ye}glZJCPe|7k*#}FbS9pK-KLf z1#;peQuaGJbDo}+cINOHYAMc~r~7~5%ylidGnX4-bWZ-A_<1FJyEbPWk?{&RbGZnJ z=PoijbMgXOb{F?hBITfSXI_GDmf1Sqx?#ENdhMR+J@1E{6%N#hJpUd_e5Q?X< zL;a`t>2ZR-Vc}E#BaNNm2x#zHO})*$EXi|tO-eekO5@UYOS z=FrFiQ>RTa^B>yN;(mT3!)Nz1M-DOLE!IJ}rlH{>6GCv6gM<1;hU&}X`_F%C*O1*O_!;`sidvf>Vj?lEsKE1sW_5X^SA7c=?2S_*a1!_iI0c*r&X9tCXGu9n z%6U@0CFMI(zBfd9?s+7K7|(?Vqixxx(L}k0^|;6%F*Qz<=SJD=2)ta(<}GPQ9G(;~ zMp~i9T|Z!yn~KWK;5On`PXp3Pkw}qw7k*T37AXoTQC05C=jJ1GENiKY=>qH&0!5^# zq+kH(2c}SreB}NN%Yk3{BPkcEg_y>aBTY>I?n)TXS+sa;i}OP#zna~6-h-(hUNXeA zF)otpa$LlFUx&Zknh&^@QaV0T=iT)zz#VSXJhXORZKI9y;B~S460N&0b1(xF^038* zvVHkHcwBk6>)B|&d>$Tv@+1ZCYDX4sZgbW_lOrQXP40L#aHjHX&Q#vr*tv(4cv2G3 zWAg5EtCfPu5{a}-TbJR#qK!OwR(X%`b;6g=gNv1iagjU>hvYQ_ngcC>mZT(+l1xep zDXFBSk%Eq!VbDe%Mnsq{^4Rs^Ek;Ci+Q?+a$mWkrHI6p&I-;TR&OuXNCsMNPXd_Q^ zwje*tIWZ&83%OwYL8FblUf997WDY5;e)4()eMre8MO&q%N+%fR4MgVbl`&uC4btxg zo@27jE>uTsU`M+xIWfMF-N_xwTZV5|=%-RB zYPsB@Ja|8OJk^GM`#iWod2oaB;0EQb2Q~m3N%@nMzeqvU>^iA#q}Jk7;Rf+QZ62nn zvu~fbRqL>-3BJ90GkZhoE&m4JJ`atl`Sy9c@FRBv{Nq0$wKl1BNWFx{P}`}} zzCE;iDZV}4W?Aup+V zwIR2s1jv8_V3;5ecRScuy_?i~New3T9#SX#D|&N+tz}jGDDJrS9;5b}SNBf-?ty0a zQar}IRMb%>>RGclX-1`Gkb0k1Rs6p8yet5N7I`_OK0vA`se@T}+ZU&;myF_qItP1} z_VQNEk;Qpfajn$Lg6z)YArH-<7GbBD)JCK>W`p{(Cg;=#D<$WyAfxMC0L!`GfZu^X zfUCftz+b>MQXeAqVN#or+LY90q&6qDg(2tip?O)x<+BLp?M>LS7pS)6k4O2#y~fG8 zeA~4BeB6ZX>jMKJ<4!TA~%Ht$7#9J0I=QhE#1fcbSib zl=?`CgU!x=6q#dOLc1yQTVba)fTA8F^>I?$;-<)d9B8YFF!c#ipR5idEZ-BC3=x*! z-j$&0@NwM-_O>59dW**|Q1Gqir8 zvk1$FaLC8Nhu%g{Ysy!BN*~cJgb)VzuBzuk`8w9P53=d2XQOGkeC-vgs)w%SY84KG zmP1C4TFx<>!N_K)?P`W#$CuRhq;}vQgIB1+3sgH+hBoq{#`7`uq0vS@#!K=shbSL{ zJpTpYMPMv2j?_-1b|$q8sa;9!M(Wd~b_dbq`ynYikxUnm%Gx#vTlDH@wCVY3Po|B5 zI&C!mPn1l55~^JU!i<4h6t;eI=PxIQ&GbRo)d#EOhx<=3<6&`^=L|p)H6jF2%LvRY zb26h(Zl&#W6^&iW5IofCnQdQC?lFC1Aof6cMqzF|{>LP96twsT57Gu(gL;E+&r z1Z=Zy2rNI$FlYJGNVR|Se13#M8@zJy{a?Ge>04@lhU#YNpH4H%^5>v}=OcTKI_6?$ z9;sfW_Tr9!0gC*EqZ{ zi|Z%4ppLC5?=4#!y{S{j0E0T(o8my{*C>N^HB-oGY&FF(npxv{{s^jhibJwdhfL}id&L2Uv6~E{ zE04d8JLkuuQX#DMP7sHkcv4>=^+oOki9iymV@VCDdfG@w=Gj~@6GR4pD0hAqsW2tu zN%iBSm@|~0tJB6yr21D2+F*&!w88Okr#WOxEIr#cePO`m{rz9t_UEI`p^-T3lmCm6 z=CZ3a^&0Pc@{2FMe^@tS?-})oqm7lhWz$9h zA{_;F^lUWRD8M=^pbg`t?X?P`K^w@(QE`;8Sq1fsj+dvqU?so0)A*_Y-swbMn`Uhn zl;yNGO#vd+1^423Nr$=szSkrthq|B9vmKum>n88(JyeuO#hIw zCfxV1OYJ`I#zO#sVWB~O<;cLRWCnO^lHH8`!C^B8W5jvNkg(8@$gps~ks(vfL8JMq zB5us$_pAT1T^6OR6f;tLK7mCX=P_b>K*a2bNb^)b{Wu@vac)2D+fqlf9q!3g8YDz#S-f9)LSg@FJ-TNQKf| zL@JT`3aN`pU1Hes0`?;K)_cj=vOA#J@}+FXm-EMl8fVK3rrLNDJhaTtmKVIN-=F0j z3@Vs~%AJc!)q2@%?4VDrAax~of_cDvQdg0R_lZ>TO6>)&AakD8#J0R(F|Y(!O6qD- z*O0oFk1hw`C140geU;SLs)H>rcny~fTVAlvm0f-`Zp8Lfk6sUbe4^8B(Na5%^Rg{3 z*l47|u!FPxZ`^Ll5AQc0*kniV-H$&)8xR$6wB-exkq4ANw-M|(b}%;;F=EWUg^_VH zwF!d}esiyr5q7-acOWIA`&u^qxLv`!nl0a0!E8Q6%8&GHOa*(fvyaqGq`tvDX1_M| zMBQAOsV4=P+fwi)7r?ZExh)0o2@2o}6u=cII0_sCz94lAsar{XlhkdbzD4TWq;BUF z$C1>C9uyd^Kmoe~u-xzH(Sw~#8z0rU=s|&CqYaVN9rm=LRFF2JQPG&LqSHnUc4A3= zm(=&T6T|}vr0yaWeX^=)BNdt3BJl-j*hvQviQi4?`=oxrw2=kCOJLgAL+Xdsf;Ng! zS4sMZ2Mz5 z&+2h<84B-5HjQwcT?X63l7)>){oKiAD8w|C!lwGErb3Ki9Nvioh?*ZMm&;HHc~XcN zx8^bw!bK=-1+)g>6BNQHC`2&)D5=Lt1!sLp>Ty!Pg3D0&1n?v`1DdxM{&v@zL_I+& zPq60!n9syur zQb#68AoXIE%i+RgWS-6i^PQanKpz*P4-}GG zL~1b~%>ba7`F{V2)Ss)x{a%1e=6ko$)xG<{grt663x^zE)pf|;Zkr$C=r+9QLL-V^ z=rW2P*=z2eyWb!9!2922Y%ls@9G0TR8vs{ zQh$eZEy66WKguOtiy)GVns9RH(V_={MnGfWK>$-piXJBQDye^x`WLC!NWD&0H$D~9 zN{X5R&Cz_2u0<_@N61=>tT&MrPr+{^YY(#a{O60;A{OZUXjoA@;3>eJtR}M7CTks* zva_5Y4QuaN;vpfQuyFI>kN`hD0PW{JJvf*jb^6b$;_Yn@lHsiW{(*kBO_=tCm~R9g zkkX$OEYg?L!f(LmlA<;hZs{) zCsa{a{q8Uob;eE?veqT*%^<>}Zot!Iy@jkTmFB41!AFbsH> zthbZ(4zk`!*1O1BpR5hY+K^L>KvKhs7md>XHWl#%_*P`STeITUdtt?`&1#$#FA6ls zv?z$InBiHHXD9GiC9L@ExSNed4r(8Q58$};a#1L18Ub{@7ldJF8d>inE5F*kC>)3& z>jPwMQsrj6XcjV`#|1OhAPQduU!!O)SsRhHFR7T61522K$s-W2TzJ_Zf| zpO6(q(3-4m$od#rA17;DvOd8n4k4+HH$Km7)uGCR21U`xJWelIle9(f z=1-Bez21q-``&?~6l9aZ*)Y$*fhbA?(#hJ9tewc(nU7+kO;MK4KCtLrs|EYOdC=Gg za@?7H8l38L)24?8uURo-@Keouz1z`XA2<(Mnv1T|%$zi*&DBo_TwJ$j;-Q3oZ<}1O z&t=pD2b|f7VD*nR`Ww7DFr_}_a!iWhgA~KL z&>WLuI3vYyMv4)qFUI4f#qd6gn~}9QS^JQ+FIoGMwLe)0z%eOq0ki}_dF+@Jx55t! zA?rZ04k0Vv>j%eV`@bQmUd)39)4(sq9soMvAhP1M?GCEFz407LfM-DG;F6EGIG$%b zm(tPf*}h{b>b@9)zW8bG{h$P`EB=in>vLosMb^<|9YfaVjfi})A;ybYj3cyG%mIFm$Xj3FkFoqQ zp~gkzi_Hd+6bF;_MLXkK9Kv6f5aneU*WziY)CgNAco{q4WF1G=@!Sa_f$3!RBdfW} zHF+^4crgUG-r4732h(AS=acm%vig%XfIIs_U=gS$nyi6j4XO@Sv3NNy8JfJ9C(bxc zHf{gKP0g;p+JEB4`}R#*wreLA5#Z2T@oFQ@8dqt0`eeR-E!D@gB7Z?=>xu(j&Q`Jb zHRQ2@tBM;1;vADrt-+cmH=X3inL_C7V`Xdd;w?yxX#Nf3TKuMFTqo+r6FP7#h(BN zfkR}SO4d-ahLLp|SzjhAI&OrGHViHP|H!)z_$Z3+pWLM?B2Aho9Z>;+5W2L4UZp6C z7()sKLV`)?2s}WL4vHdDL;+DyPy{Iof?${8Z9Sxe6bq!6yOjU;?e6)@6$z32KcYdu zx7od&nZ4PW@B6+tv$Ho?i!*I-fM27HBxZ~W{6VFUHjX%G<14a^cczVRi%A>DQK_tf zv_^0OJ3o%kZTu4BGhBNb{SgG)LYl6MOpGzMmba zvT^@%=@GmU%{3x_<2ver1-W*QZs@czQ>TpsuW7V#Dg$S{6>yO8?y}B zIPe;10~r-T8_6gz8A@5Znq-K_WW;&rkcD3xpX{U4#@ySXjbz02lPhomppE3afieIz zb#hq%l$~4-K)`PvSzac~e6lPc%R;g&BFkcfHj+W6Oc%+OjcrwIHQHFhjIoSAR+l>3 zNUm$pMshu}EOnxd+G|N zEHJVE{P=%zKU6vQfc~DCWa|AR@)x)45x#6muXcmyj2)n}Px3$`4MOAYLdVZs5Zp%U z_QL$nFOJxDa-i(aKFLp_yr=bBt2>yy& zO{AA8=v}hBMQbfQlWpfEq;;FFmK=jKF^xrYt&<^Ec)`--Sh8pfmR1}Uk4Fk3^`~3A zhsVZ7B}{e^J;{*C$q9}OAT~B|28m?ZcuNj<@TS@1(PljS|Kyib-bd@2-h@=O3TR@mWAo(+IBx02-}vf!N`aJa9M<=Vf0Brtig z&LpPfCHRR;fn@-w;RCXKNS1A6+0OpAb1Wygqz1Kmc^GGGQT!o4UJcS^$7I1gQ`eTi9$zB3rBgPy z`gh0z@%;%W+z6oA?j*|(Oxb^HO|xV~-II540c^LS{gWa2lOg$&w*lLMj{scTF0y<| zmfd98LzcZ{*+-Vo9CmvrlC$0Z)Y$I9RE{Vv2%hfUy$V>w*t7h$pTs6lw#HD5}uHr ztRnMMTrk^Ki2r10{^Xy@f;c=z7LM@I)4&mEljXAYV`ff zYVV@PG%W5lBMo%Fdz!hSPi`w;ws*k_KWXfDE81a_xU1ez{sZMfX6yF| zQF{&(e5>hwjJM&2-`db!awf9L(X-JFceZA@zt;`-Uk=@cmFqc_*Ia1QGqh{(n4~7U zISq}E7|)X`nhe0ow29*rv0QDpnAj+N!p8p=WoX=W(x{jbF-e}SFPs=tirM&ODX@bn z@Ewkl3EK(B9$VN@S5aMMWg7r@@qB_zo$W??4ts9|p8C2VK%R$bB)2|LlqyDRm7FN`dd7 zI&n}+F@1-WCa7qK?~w8scHldlBnu{#no{69qy&)#aexaYPC+T~9a7qJ;{e&DAS9pC z7HCJ7(_}eAma}{mA^DUJIt860%lSKjf>PK|;ilWo6P>hww8Ba6`F-D<+pA+%>vjd` z;vA_=>1m|t#a;Kn_zQ|($R~5*D-K>=Unwxb|=Z;$) zF-?K*kW$!pNYQCM(N`()_^mIX$_kJAr6iE$H@8v0l<_!qqH$`<1hV`NvZRnDl`Ls|>Kx!DU@kBZco{(WB%LgoBoJ9L zNSH;!oPWO)lJbgit5Ogn!h7aj2G*Jz18YIeBU?n>L~Ez4L0|M>)dOzfDjeq9HLJvlyhOn6+_Aea3o$7n0b zcODm0#5}=Kg|lyQlS!Kc$HygMiGZ$?BBI9eqEbDgV#h^cNvE)G;W4q@!V{Cin%%T0 z*ZzbVJt-e><+ELYZ;=9LIhQPXybG_QJtSiO?Zg>V@O(hZXIubVemp3Uf(HdsJ_U9I zdw{(FypsYFyh!jS!9;?Y1RoN7ImPEl>d*@OpaA@qltb7yAi+=53PJ$1f>5dSX@wsh zz3(Uq{?43xg1-Xi-r{pcDGDmpn7Lz0feVphB_WUmo^P6h0fUrNB-~9x`I6TP=aD&U ze@!b~z|KYB5(#BUz)da7TH!KqMbiqxy(E;oBeVj%1x+hpl)&BfsMo~$iN-ZC|zh+N&36!;k_hM!?d$3qk0ljTi<*;gpDq_nDK-RmkyjBT6sdv8h93-I z=17G{kcuW!g@mfS3ts@tAym5^=19e?oz(le0PsL+CEz}wGEfDm3RDBClYsy4C!q!j z50LO62{lQm#VKkaslgnnHMPG@sXU7Z%u!os4qo$9c&yYhM`|O3IZ_*wP{)ZmQkxc! zIZ|7pqTBL4;=A4&XhT9h66*7AJD@!YsBestm+%vcshyE|s9vxpol`?tIty556kP$| zb>l|d(5(@dpVHs8JM_lci1ce5l-dV7Q01xpNO**VM@eV|4oV#WJfU+Cs;tSKz(J`z z#RvXMDull~2bF7ju-2N2AuHBgoinIU>#wWo9F+R3k!HB3G$XD3UmX2X=&pCS&{t!< zLaMuSQ0nt2FT$vFo^O~sLSv4mMO3gUy5t*_>D+w*= z`!d{U{#J}MH4zz2e(Wv7M?5rZ8BMF_j6|4rbxI4v1v-BYu!xL>)wvR?Y>MfI{XeJ%_pAHq%10X ze&N8LpU)ZErct@O`LP98(UA(Bp1Rj@k9O;#qlYd!Qui^_lF-wW=(y)y*FJv`IUUw> z(nZIY8g=w`P{%&z>z;0W?V8PZ$mU1K1$~d5A4up+0uy3?ShN5(bhmh=jo;3?bo3G#GYIQhB}&Z_gUr^Vst6ioh#=3Oo~2 zh$?l%E2+ObsN)Y3oLBrzP1dQyl$wH?x{8|9wj?|~v%mH+^ZRme4xL`VnVOB$>^P>e zM-FyuBn%_rS#AiqKpqLhNr)(M_DC~%nbQ2YVDLnm8SnvoNqCNgFcO~Uqy7LEnPK(_ zCjmC{pP$o^b}ud&?2%T^6BB&V)ce(|KXsb1JfxrUrdK6Aip=57w2DR=%=2-V80Dv* z+H!Jam-6d+S1gk|sUY5+J<_TmkLvn8(llCHHBF;M8h!rp1oZj!STgXrNMqQePgLB< zq){%nI;|G6scU4zsw1tAMjg?`%;sUFY@}ynN_zx5PI(t?mt zJ1zj!k=6nT23i8GfYv}802%{oCzgbk%kTpClOhNvrFD2@`mC81O6!6G@m{;toq%I5Lma3)VXWuYXGdrhu};;@xOJI>X=&MRo?r<+M1? zhKXhj5DTC!O(9__2|S@Q4I%QhaXS6HNWvX4p)-x+@Jv6GJW)y6<&Q>19Pi_`__6oI zf+wa;Ht2^HJg0#icc-5Qn_BHrBl->5UHyqpS&OPS^*}#})u+ueYFy(D(s*NL5j9>& z)TUwDx;7YLM7RrowaC#Z7n3lX=TaS$uK0 zkP<^0f4-n64Ptn%+mJ>Yrk(vYN>*swlRTIlc9 z9Xl=|DlxIvziNGjrjb!iTic&k#}>`k<;1322s5VvsUKjP|+JFXm#L)tMCR+8`rU-=1bg#}^N?X0kn2A3fX zvut!R0N)`EzC#*(hcrycN&6W%1)L_~O%l+1;On9{uOk6{dA;FBq@6=@_z`IrjO`_C zH9vw^3>7x;$F@@EN2J|w@NO~*Sgxip-KOzZ8&OMFb(HVVTd08kQB;XM-G2T!L50(a?F zd@+6fV-j|t#iT!`t*{_`ayu(5q{C-Of1C?| zNlu6JkPhb|9nM2KoQL$bKs%s42|G#HMZ%{f>?UCk342M{XYfY4;XI_X^8o%x55ZRB zjn9}e_VdTLrH(h!`x(5Ej+nydPP~ym(1kaOcnCE8X;kX7jz;hdb`W?tKmsrRnLZpq zDBvIoUzWHJksg7}qa6jqnZT4q;gA-N!(1V5$TYXFhj5&WL!AznAsr5a&OQjZr^f;C zL=Tey1O64W4<2nzPte)tYZAV>BiLs$E}7Y9iYF$S-+o2bL#KP#_Rku#yicV?rwsOa z(MU7hQ<|qgj2|}mnQne7@}IDDT>o5v2lgS9H%G5=Eo_;NMPM*g@txsAoErf4L7lsX zFbY|v^aYNF2TlD0i^%^cDO9-3rCjEQqSshR=Lg$((sLT_{R%hNBz+Zr{%ZVuc10YC6QqaW~f_9TRfW-_}nxrLQO91fTj22|wMEYmyE(BOUIA=9;84_rV=We;?Qa z!2d}9fCLK(0tq4s5(zR13a8lyZ0Dwr8|;n0cktgNs3e@ktzpk313ltjzix5*=f;gn z-%o;-TT#8jf?A)q6crTSEIRroOD3crLJetAc)mHD6K~Pye|CG2A^jVC^S$2kP3hla z2l4q+B%EfF`vI*14dx8Zi)NDhTZ44zKOrM47r=KL;l^}?-qR6rPe;T(9r8IHsyQ9^ z@hl1FNH|Zz1rjcjaEXLpIK@dMt*611e%jb_#2w+X%X+x%DqA|^jvZHmM_+2%( zv}wF*`BdFRWt210KwP^EbC>K$X@c^=^Wn{wwIRoQ?uypA~WK+oMWHc}uUdBTtWO7LCg^!S- z+v9~95YZWpalEiq$!J1?`;wv=&2VaveyS-0m%~enX0#yT)|M2_fN;)WIm`jC3@GRf zDCi6*=#2INW}##@<}Klk(U(B=mbDMJFH4ZDF02OH;HE5s)!H%7pzK# zLlkH9C(-0)Rg7gegMynyw7H2@$ryy%8iHD`%r}Q~;_Z_p`nXw@3`pk;hjh+>bj}z? zqA!VlAe4;ZnpF|~Z^x=+Kq6=GqpNIHG9rN}AQ~76i~?eS(If_t7)at>B;HM884~Xy zv8>@gWsF5~_)Qt{#`Xnl*?$u6<&X0GQKQuPPZ`r3o%=-+%Q;z$Ss z8E+yRj>2okX*G5bmd{vAVigjrl30z66V!0Vdd)bA)k#Fi;-8P+WN`at_)Xn1=`tjSho94Z$7Tn*TM6!is;vsJm)mR>%?EOd~>+HSr|#$kNJ zaci7v$~Zz|9o~LTV%=NvRWiQE**|e|HWfbrh$d$sh@5c@I1Zd3u^x%_No+vkLnJmN z@nJp{A~ypfH$y~Scw;MTO-_7-#6~3cWM@U}^`9^+=Nz}}Jc*C8S?O5VS!szEFouta zPe=-z7?U(AY+U%{SgZ_PoTnBtenIVB!5z>n&SerC^9{U8qV`_-k}m9bkJ!!uyjT)kVhgqP7sML zNDL;iC5f#_Y;D-AOr&O;m1#1zKG9_D)#|YDmQ}6`+*uHwkPp%-hB|LNn!^QLrdHf%H+G+kPC)c$*d1F06;1oN$f;o zXFiIVEt!viQxp=rkcf%U|GcruY=%pQvB_-i$#9&B8nX23shz5Rdd~0e54Sh;)s0PN zu#u*vr!@E6c&bn4i_U`aRM-q0Dyd35i{GW8*b(4YYgh zB9~su?1F5%8riTXlo_hotnNi*Q<6_~7xJny9kX9DnCF}u@c>8reuBi_Y#P~@#6K6) zm^lPL;wcP$p|3!mE zUI$i^h{hR4;`1bilQ@FJ2ofV5R`E?FXZ~DcY+1BxRxyeV;z<5TD1BD(eMcMILSnQt zp&$b9WEIPE1lSls_q5PS=1$b^Zk(gFwq4lyltgrKo>ZB+2Y_aWvmIOFu3Y8;WPV65 zSm*kK8rNf4O(qdqY(F*M|JBu zj>H%42iwV2D;xkBQ25+`trxu)~R z#M|PH8^|b&3t--WKF>@6Qh_ue9Y9b!Gn2$gB!YyekT{jZX(S@7G2Ou%IY`dDftY}{ z&BIpXjTuZC#2<@G9dBe|!ir|QvJg0%>BJjZhMqtCn7{#v57uwhj_s(p#}9s}6WWoa@FL z<-5eWh^nlIkkg}_6G$SfApjYk1z#R^5b>-9e6$gOKsO8Xg(NPz6R0Dr1uhxFJPTsm zodyP6Z@oFFOUT5H^Ox6Y=38f!P90gTjWlgMrAes&@~9o7Lf&4Na$xEEn=Wp2r;aQ{ z+p{V=}9m^G<;VIj>;gMQ8G zOX4eTQa5V=z8R>WYRZBleU(pzCS7q$Qa9@NZWiL``YnScUBg<} zc}&fD*cngcM&TVudYZAWUS>qb3K>KEa-QOZ{ zJ+sO**p{zIe4FMy$gJ|WA~jjFkdYR-hHc534a@;v0-%Po<^hOiXQB7ML*fP!Hw|5{T4HRMVXN7e_t~s$<&RHGpKZY;6TPjhA#sbdZF!5oy7fp+ z7WXkoT)h$SeR_|?4@ks>K~vTiU@M8+NYo}Jm*`7#vpz!RpEwHsSRY;3u8%JKdQt1- z^PeetbRlamvf0nsum#x%dRTJAn_AE3h|qTP&eC^oh0tMBkao8xMa2~-*~bS z>#l^3`uuX&1MgqDze>BkPaxLK513`Kcfo0(z};<8_m;bcd{d+M(Uq@H9MmRpuZIWB zvJh|2;z0bLcIAX-S9Tkc^w*0p=BV?V%+AVE91Tw=slq1bXUA8kNZiLJXGbW?ayL2W za1|GDoTDq3>eIZ@Oi&j|{M_B-T*fynetF;_3&M9lZ?BPf;MPnIg3np$oSfVEbpTp7 z3lcXA5;qGHH!F?AFG$3o#~~7-Y7UclginRy%|ehl3$j=-Mk46&8xr$0lao)9 z7hgopm`JQY7!w_XMTPoD8|w@v_Kf2Q#5j)Gm#Y#L8Iu&BfY?D&RF}y;|2!QlJm?Ga zVQpZ2dBXpFml#&AZj|f6rx5+`7L$;eG%zZ0Tzp(4-bGoi#^nCd(TPz>e^GX&i1^sp z@NtPzk%jUubkDLeXGG(XY#$Q8b{o*vrb#tx)+{PGIJofgPA(=VJHX47eK+cv?MSu{ za2IkT@mt<41AwEyBk>~Jk>-VCD6KKFF=9$oLVR%sGqTGg$4ZXUDqyD~iEu%G;L`5% z^8O`+#2;zi$-iy2vJtM%uFD004YO+i5W(39T4&b;Y5}!@IwT$?@feB6NyPZoPb6AM z6b!4CT_4F|wXz>Fwhv>gSuK$bmdqdLOP$rqZsBNc!6ZsfRx2Blxj0rUyCW*M3*RHY z>z#nkB!b>m-VFglNwku9mK#B>0kPqeM<&FNkBdal86TUJ*e85){P?7E zb0`n0T{Abnhp_X!<~yD<%+2*4FgFVZx|ti-8Xt+2qm68Md?6c;Jz!|>LNT)$hm?tW zHm2+su#-UIB@%z(7Lx=^^el;&Y2K@UpEjl-qgh-4)5cU_8i4R}_HCKu3eLWU zvy(YFq-{3y=WhTeX=FnlXG0Zd-yq4CBtMe;NeUn-kfgi#REXqkh~(@v+(&P0Gq~cX#=UsH| z9Q<8@ByGvLzZK-kxeu9WQ$1kCaw-D|Nas`qssWe>k^?=RQ-h?6Bvm5mK9VYvRE4Cf zBvmuya!yTLALMdQZDY&oo8_`poj+>u$3vw~F6T6Hw9Cgxy5EU_a+>p3g@QZ*AX{Sq z!St?&0fd}3s9j^OhbgBmcG{8j07(yWD|j5}KvGSTYI8#@(I`(&2r}=6i$n9%1`u+( zvIvxF89e;NS%|cTrzhuNNM+o&HW!we5vn&kd}+;?w&L{BbX--nZB5M5qX+BQQ7)L8+!gFrL@%mR@ zRemGCG`FYeauRXv5BB?b=ZP;Q?^03gyO;+XZGCn#Q;j6GN zvGEaOLgL3w{+BKF5gpkq;-*V|ZkjD15Ef8xAu~u9JYGbIUDY3aCdUx?&SPI z(g2d4AZZ{Uy#c^0!kCaWh@`=Hgj&FOgJ$`&Jz4&ct1B*T-WGab{YL?Br*=%{@f}tR zb|X!$r!?06G53Vm>bq;nP>Kkf++uU#8^PiV1wf42=mc|-Mk zr1@jEr!;>oPVeux`VJ)xeigSOPrA2d)9~i4!VAC2$i->4VPL@K z7#OfYyxWl7Eab@4#n?d7Y?3gCDy-b#Z^I**Txi4W@%9x)~g zfx@ssp?#W%-RwI)p+|T^w#fWibZJeg zlk>Lk9qsxDlAK?QZaco^DvfE{_cle`zHo5Y=3Z0Y|B}uLe<-T zCut=~Z;-T#k76jpc0;%DZ<4h7jQ zyX!13mm0VGBjsIsHYPjdy*-emw@Bj2q4vAAR|iOM-_EN8?B$VBH7)=|V28Z7L)F`% z>g`bV_R0WMy}c?)?~nxcMZjbeN$--hnIy;LQ2YHz4$83e@B?po96?j`JULY2$)VEj zQm5$cj~LWpf0QKW$)WZp26gxyKuuw09dE0AL8kIp^V3wG{4TqR9eXh9wKdLW^02oA zT9NbtNjyK)j!^}BTavbsw6nxTy}ctc58;B*x$T_*2zxtXLfc9Dh@_ACXefZ0?kwte zko3u&(B-s%K? zJ2bc*n&uEmUy^i~q$4DKMbg)NDh34X3xI{Vncmng#t(v_`-Y_NNCp?LCfWPHFm7(w zCf{(K!UAK0gv%OxZS?0Af+Jct9dQ%oZC`^7-a<8N{IXWh?R#X%{IVWE;2aW2d;7N2 z8h-j}OU;8Lnzn8h@z)Rd+BYGO_Z<22{ec1bk))%X|NGiQ4$`sPdC0-O9U1NB0@#jW zQo9|R*bXUdhZMF$3fm!t?Vpl#oTL*Z{X~+5B!MK6B#Be(K~h5k+c_}Kc8sMkBrxWQ zvI$f9<5H=U!1iwqCa{CN6sO3PT?=*>lE6hortAVLRpxudcU=S|lB^`1FciIpq2GY}zn;$lbJs9qF@wM$69k?`rnU{P>n_+8gFD+enk+ zDb3y%kq>7K@9VpzQ_qRkatj~uU=DLpUV%~RngY((6fmZGa!lJ~|BFg@sqtK2FH>%S zo{cHj4?F%OT_Ncz8clAX&K%cnhdFXlFS%8?0PsL=IRKJ47fLu6N;tO?041D@*)q7x zzmWuQ=MR#ulXQcmWKK~PNe$-6HI#5JD`7B4iq0Hq%pCcpjyZB08qAUVFiELS%#quO zzq)ni$PGe8w{$du7T5_UDV?MYZUhK%=e8y(lO)U}Ea8}TE@tKAcIJZ7vvWHD(8IZ% zNXjB9n1Df6pC=@`mX5NF&)?4Cg_X0d#z z?=5sAS=atP4B0$qWW%(PJ6xlUf+DghBye*h9VSbcM1{W^rGNDolU;ISQC=JhXI-1V zlNRwBYq{|xo85G6ZUVkZ(oZ$zCX(#Kr;aDt_m*^RF6PSQ&gA3}L%Gn%xtOb-i#T=e zi@|7i4YjQsW-x zE+hFK_lUBwc63xwo8aa*(Ve*~P(@J4n&ik`hMm`u9m)4HabN;X?kbYYk^Be~hjYlf zB@5@KQBgrnqgveLsjFOQ<=pj-0@h*YEt1QVT!9NfBeL5_u1HI?7lQt+iJiG@W43bv z{0D-^x$gs807Q;+KL9XeJ$D<)l}Nsi;b``2m>=4N{oXyh_{;C+}=?7Fa;=y_=`w=@wNq&&zn%oGE11CtX zMRJ`I7q+<)GFSD2b*EX3K$A@c67YJ-EWv}${!@9OP`axSguwb)p$Ef=wAElskgG-}@Y zDr+AJ`DxaNKb2V?zT>b5E0>1yIG*f?>*i*#d6FM4W{pD}=NjVJl$(d0e3Bm}xe;1S zo|jG=jc61eM#E?-Aei zM}bBpwoxH>p%uvKBl4h)^Ev^YN$x;$N0K}7(GVb1XAXSPSZO>!TS`;y#`sAxRuG>Q);Us@t$ zQSXaL9<0^&liXD?NhNP70L}dr$#80x{*^Fp-6Fch2q)zoR<4iJFAMrRzbr9+d_qK2 zNPJ|J%cEG$gQq2qi;9Q|kBylU6E-UkIdk=H1P}<%;|{QyRY;}1dNO@eTQ|x(r9ersZ$oJcUbUvw7N+3EW-p zt>+#Y+0C}J!=)Nss#KqCn9XxWn)9C0G+J=r$c%BJre%kI4LID|j^LT=gH(B!P~H`; zD%eRLRn5DsX_a`xY~JGg*z@q1Z5}kgmW^h8Z)n!{g(9*EE7yK#1n8(q&(N;DW0IP5 z)s~S7HD3MRWI)u&@WkOf#-NTu%C%ZPdEL;W8EYTWVHgX=DE zRr&M5AaKuim!^>404F}ocMA7D{~@3u$+Jl2#U%6L805nnoI`TSFD9Aa6qyI<1#2BD zzq!_-9E(Zj2ebJ1u$bfn<6VCOW|QZ4;GDo$`R#!Az~dypO!9n^c`?a+xCHr~bQW7k z@*T05WPW#CGFU9XhbKmw(5CuZ!yEVZ*>P?E{p3HP(T`&>$-k;}*BT#+l*9CFO!-e^2TBEEZ8Jar|>kWi~Q#TXm7ar$yitQpI>$%7ArSKUL0htAK}oB%_%7 z;op76SCsDMop*@j&uPi`f7>0;w|SWgOk4mPD2VKQ#NP7}a?j5P3h*Urw!oX@{UjeC z`3sT{l8i#p&JP=sxWEU=Vaf`4*%;miV5>>uBW%sS=8vCBT_n7qqR}J^Dv|t^6R{Lv zK2323&*Uzy8$%RW3wX&S1D*g@{c4RCHWX1#hmQ|gxoPpL_SV3mVEu^ z?P39Ici6>(j-G5>JMTk}cYZ4L-u*YeTt?d_->uulf-XiHp7G-LEX9ORHZDy2qvwDR z3x4UDynkc5yIm~khVptE70yDqpoeDAEXAvE$ms$@PMZn_UD(xO4UeXI(BA|e4b=1 zNogt|0NymL+cj3lOUj`6bFIYhGC6a$3`7$3}1R&VX-Tey5SMP}K z&dQy;`)i)M?w9%ROniB7@6k)z7F>#(J#DDb-QO_MAYks^-F?5`RX(X-udi0rT$FTh z;dRXKbdBB>tU-Bi>Gw$I*L51d;$7U@B+xQPA%kDREqX4}2&wgniW`|U%9UWDrVAWu zT4N2U>EW@adVjWTyur3LGlhNbY)p zpWy=cBMD1o$9p^rASY7Yq;kO_oO)P4)l>jm!!LU%I6`vzElK5qZ*lf!m&L%mBWE-D)0@Df*uqi;Duv9J(`3{h5pE-&Y?Rg00 zKk+<7!5O}p8}S3r0_TA9zy*?XNzNlVpJXf*8CI^X(^yptEP*{PX;eZ~cx2d^nAq5x z3fQo6wcXcQY92JLa0X%JnmHBFe46&|&?546dbL^eX43{uPE3j#+b=u`k0OV4=9iBa z8rCY@wy!xFFn%X~Ug59)(5nLz9?>u@fZ*kQJqs&+(fqq;{@t|TB{#pXARRT9X*6cX z+VBNgq`1$5EMRe+>uAh&Qg{|*K^`f$Gz-$~gcWaH=?1fl08naS{l(M9}#(tmj`hQ^f*zBbV>9_GqtCFHk zgLHcOCRl&ECo(*$S@XYsy2tEQ0~ypoHCNt*KOO)c_Q2yn2cRPjXq&wTl2WrUv6;Pw7{sPObcEWv%0ReO|Ia0uW%ha& zxrE^qtq}~z&U2)o>DS>#@H~KKU6+*lCGBFGy`qtMj9xHHAhXvfmOx59UAuT+v_k^T z8(xG2GJC}%Wg=&@0e_4GUH}qEX+R2kXG1=k1dInGDx^G23Ow0=+{ZL~O~WPMi|cw3 z*X8CfuCe89{cc*1i?2sj8QOVq3Wj76do_E_G}4f#H1(dI)@<&A{=>J{czy51GPNKC zT|}qZYYy_5$5n+YhFUax;i3NKq+oI-i_TlF@x@5FOwY#bwFEm$NohjLW87kv>$K7I zwrFD|GSb8`)5aUXD&S3EHLwO)3#=oh87a8@AW~Y85==@Bb{3O1K0`$xK&5K5@i}((lhTe9 zEFo$3`T{se%HyPTEP2}a3YmYa7p&99HyUkpFdA_-&(U0rrGjtjIhnnVAshbv8f_fM z&I#ZrQaX{+nUpR}8v+1tfN3Ly6udY34xo*namh>@m~rAx8=tJcvj5fhLnm#BoOk$* zz4Ni+fJPfjf*JnGFO#@Hh$4)qgyd+{C8x- zv&^*?^9OdWlhT8fp4?)Rb=v54TeOjhjPkhvCV?y<8^{4{fE~yMpuu~S(ub73r1T@D zKPdx9dBRW|-bl@A!`ozReX!Nk#z1C_!Tb?c>ePleX1ZuDNm8|bcxf3H{aEV^n$%uZFpk|Zm5l+MkCIO1Z^z3 zR1|G^H%3ZLGJ_zzp`X1U10b89A!QgT&+^gcK#)!w!%2DWPM{40I5gVuZs&;t2G74g zKI5}ay_Vj)zV_I`ADz-^!&{Gno4q@FN@Fkk%-08Y_Fu5@HnnrVn<|aYv96!7Zl0P8*T8LmS>hkkN210JP!#B=8h4 z6nGkV1{elBOG*?e(WHzd1%V;>)T2om!zrFaQbTQcb7Y(wS_HOG8?n0Dh-2EAT!ZGLdPcBtzO}@7c&) zlg!++p`X290_Kte2P2V`BtH5wfLSLj6ULK*Rc!xxnc&Ux95TUsxu?GS!Ib;5f0)s0 z!GX7A+nl(EA2Ry;3L}ljFnBqO<*CowcK>b1;WAY#e0v#F2;BNRgu3@?{T_K~4Ev_W zu#@!uZhGV}7a87VVJnMn$fGK-Yiq|71ZC5PHz{mgW6(Aa*7 zt)@2SGGn~VAFq}^wQS?k7o#{LRM}3J~yS@^2hcX?2~Jx$@7$^_k!tO z=g#*n^U~RmhfnUcA;Fz}Oh{%j8#T_fVKQm7v7(3?FXRH70*!{pk>3hV4bQ}Jbi~_C z!*l5U4_yZa%%<`v4@y`YGNx@A;&o5FE+0ac27>{S*(%QdwD z+T(8~4pUnIxot#-yoQ9O zV@rq&j}6m@ue!x2j15mRb_OKGjE&(zt?en5X<0PqAb5Ew+t`=o3k zWh*JLz#o#bjg;-20&!}GZZ-|o{x+MQ!4|stBV9M|U<0_n)ahnZl%okplk%}M4a|HQn8`*Z_nGUT_(qx>G*v3>1VPW5ZJ>1u4<=Lf9a@4)~< zew!TfTQh)=-*C4N=mrqA4#|N!FRI4b92xT4Y~p4D`+!*PA^vld_Nol!%iDNWhS>xy zZu*2<29v-Cz=yy#U_0;;@G-E1l*6PPA>}Jlz9!`xQobeSJ5I3^Ney?~gt;fIpG|oF zk!j<5oi=`C+E7a$Z5(mX2I}kwXWBr#yjZkx9F?jC$N8?G01y~IO3E?bMO54*l5(6B zsl?rF6EwQ%G&c_J*(ZUYfm5WMAO)9T;iG2&M6}u67Dy5Ai2lyeah45Na9wVLd37t) z>@n|jr;0QC{}4Go&s5Fm?>yU_)BNTsO@kiSA3hn|t@frrKDxHb=N-JP&DGsDT}N67 ze`Z)Ob}>xJnu{Up{oQOzLw{EkxBgzfj9X6GNNhK9(wM`hF^9E?oC-;2NJ>4_V`>YX zEm-$r4 zZF4Q4Hc$tsi(du}eT9^3WQBykO4j@T3mV$o*m2A1;77SVQ_)>*lSRx4Oyn z5;FqfW)31(2IZTBfEGY7&=P0`v0QA${(b_*}cIvt0a?> zLP{zrX`EX}pcBv;=mLZQp+Hxl8_*r-0rVs#oz$|VK1^x|sn3x*nbcQF-A3wnq+TMm zfH};0g)@B#wU%unn~#Wcp0eY#L`6{Ww6M+t`$l0}T-5jk%tI^m_uz!^xWrh@PlNP# z{2iY#C~5qN#4x-yBQ7c-JSl2WZ2ZK~n8b16NfF3+{D?wx*jz73cUy2tO`}^EuJN#P z0}Fc}L9K4>l0w2GMn#47ib>M{2MdLrKXXC6jkC#eO=5m$GPw$Sw8nEWBYhKaY$?aRCre=5SyH5CKF2 zQ9v|+fsJfZa!9d}Vkae+lsr=MIR%^!hvYKHYJZ!}i0!lFD$pdC>J7=ImML|T%RJdZ zlv7CcayEN#eu^Wx%y4eZny15e9bS%kE~zF`&Aba2$2^}@A5!lsami&~g3Mpx#sP6< zUJ5J&mXqpBsvoKTeDqZS?g=E98bE5`oglf)?CL;1nb+XD+$2|kxaO?2OShq`e^_IW zkKTZ&C{Khi^PD11v))sh`u8@9=pl4^e*2YH)34^Yj&PS;X0D5OxvC7wW!}V+OTAkc zN~Vr$Ai3Ut%uRB+DjhgI=Iur{thdbDSZ}HK6f+x)Ihgn8*_h23d@%1O^c+B5$0Zal1fkVKTz+vDB@D=bisTD}ANNOcg?<2J`sZ~g=x*5sp;oI+w z?GMKGD7HMpp;qG$EVN1LLpp8L{@+?5`dT7Q5=X^PWcCh;#|x*zM`Gop>h9-gFS=(l zTdt=2m&l-J+=Q6Km=Up2iI|@5c1CRY(y(4IY7nxxS zfWPBT8{2AT?R_hum$Lb>db4T?k@p(3k#D3a@RX*(={I6ue>HT}r~TfozpZ)Ke-lmDq{y-_7PGaMWgYlrZY#Q+hGnLcuGDGaRFcspIQK1CZ9S$T>!k`Qy*wR zYGYEHkop*@O-XG=Do8NMU=E*$k(|$b)Y!r&(V3$KlSWJa=v?ZU!>6^u96oJG4R&G< z9}HI%M{xLrpmMwMJ>t6_3Unp46{)Rxw>!{-R20&VnWH2hEjIgLsK94{qhQSJ@jXOp zTP-vU3yL2R!#1?Y(6A3wvk#9Kux{~zYW5ilJWXnQQXeO^10Ti29iL})0_sR=r#pdw zd?IkkARwPePh_&=O29YEEA(2sY5t>IkJR5iKqnxdkwzM5cz4o@jc;H*bGp-_4L`iP zD`3deShUDBz~eIp<*{IA-J;P3R!u`+>rytz#q?+KH6C6pp7?3?e9z*(9y-B4Zhi%P^lVia3|YH>Jy|6JU<&(AT@&2NK&InjV5&@siQc>6*&leUS|&9`Z{w=@WdQ_nz?j&-$#)_6Fn!5IeZ&y%wfz1HT%|Q=9o|vbNFJ& zz_*p-f`YNrl2ioSrtdV{=5WMyUk)bna4W{9;=M1xa>8eB)p*SA;UKFo3wTa5&r=%z z(`&9B3J%@2?zhIjeA1@#w;m{H0n#qkYg{J|ERG6i1+N2#Yv_eq2XUazi1M7gdfc3!J0GGly72X~E9;mu*7L^)rOsLL{nSAmyGeb^nK&S#HOVm+ zHnBWtmbaBM=)v#E_b&eQtK?1{hfvWDG3@&#b`F#JHmUFMEkXd>_iIu&kotbf%MNH~ z-{ZKWn(X)yJ4bgn6kx9Q!tCCQ z-YfrJ=cMXSH!}MCDI*Q0?zqd2uR8Ynw)*{@*R4BuV#>QZuP*jKo}V{h0?Yse@(xlzA$2FIyGZ?% zRCI|w25b2Fe$1tvcVpHRY=|E#2$Vii{dyeezj4# z4l(Rk2Rn61{hZYOXas%;VEaMi9U%2kiHi2MQ)(MBYYH-Z~WS!w-&$ zhVTpV#3z>ne*bD(n?CJ62!A8$=^Zol*ASWgSj2Oh?w-<|`7w15S$j6wJ7Vnt>sRN` zxO0$SFQo0uRfSsSAgLdsG0+`YYExs5zp8W>0`eP#luzo}nEeK02f?ZDN&SHv%~Lva z{CGRe;Wr!^X;K)>;rAR620Rah10#S40P^@KsW3LjNj*X8Po!E%6*xsSuFY^*{2-?^ z1{s4b8ndW7EO@UssTWF}!{Rr=!5kAwm7JMlN->#(P|T=RBVGqq0uZvN zNj*dASw8wEuo|5Ozw8{T=kEySKyTGpV1p+Xn9+67f;yx6Uf6c#OLMiFn^}p#WAS^} zNCU&_u3mQh*zkf^on9#$CWH?P+PE0YG`a>&{I(#E5A{mdnd1YEIW9VwV=2@1&u*3O zTH~J}n@{y@%zitu1C##?sh7FY?ADp%%55>neq{6&7r;Dl0Qdqp2(XFy5;zPTAr*55 zu95mHslSo>JE?z=dflNpzCm)<9N!t+AF$Ol#|bnbPTbjmh?O%DHZCtfu*GJ&J+gg9mHPYmHO4BFd zc-olieez!Y`uCs}LF+sy1%D*-H|zIEn|be#M@=E9>_&h0_vQYMcdolU+*`hKPnRz5 ze;0DP$H<8_hkqH3Ir59h$u*mbNLg9W#_V4SJNJ>*i>%&gH2zgI=CGP>hdKNoKt}bs z05FIDgFsE77El|g1JniTk=0CAAF}$A)sL+HWDOu|Ag5@6q=x43e^~q5?EfgX4aj^}rKJR zK()JaP@yQif1=U$%=%Lvg}<8UXqJ=6idTTwJ-CeLz_~rM<39~oF&)SGnH|S-@BTB$ z`k>o0JN~n9DobLVYWAN^)|$M1iLAA5>6sn>`8azSC&wHE{{;Y)uKyxnF@Pz|{!7VP zo2+%nT9>R~qWWZQz^5(;UIAW3J$qw|rz^QZK19}s$%+MuR+F_W8t1?LJt$^>%x%^d z+wosd)`o7+z3Y$cj2ICd9uZvl*$h`pvJq9pa=0?z9nOijo5}jf%r>s4ZoxN(>NWds z#m)z0eUz+NOw#O+1y;^gBWvT^c~I0J64)O@EV|Lzg`H1<-M}7TFR%~zjI2$_`WRW8 zlC>FG(FKCYiZ^we{dp3F!{{8;{xaBR(|L6m)yUf}*wZ<3YLl0rHv1V}$)$8w3_11j%*pQ9ibrp7bZ(hIh z_qva}d$|E1&;W<(Wvv>ZEwEw@DWb*;nUw%Usta>e;jf^AwFOoN)}(ibyA9$5V17nG zMci&SG{zgZ%mL5@-Q5gLKoy)?O+VEfP?fAbKw$yZ5&XL)LlXdX8^BVR4NU-KZa^)d zHc$tE%ng8X=|$GwWbH%NzGUr3*8Y5I1K=T`p>Ajb9>EWSp&3Bdfn*)08JZXV3x+13 zg>e%Dg30=X+ry#Fj0MkwTZFd^zR3zJ0c}uM2s>+*CIB2Uh;LJSvJPghaC#u~mb2`H z96~rtuuni|pbJ@tko8I44F$TA^(nH(a{+(rIl6#e$YdZF0Q(XE*&EOY=nM1%`U3-i zC&&uP`ZQUeA?q-*K1YvE=}YHH<&P`D1LU3!nr*Icvla z5J}eOo!p=R2;|~eq<}b7?hAa6_^!tTqtKOA^^F}&dVsW#@q>}B;X}nG8~bBxwtO3=jdA0Y!mR?;;uXP z52)Ykw9j}!Hzfh{jWn2K?VhIo@oksi8Qi_$h7b20+0f`ZmRWTTmhw;fHF zIn24~ZgPC}E?E=Ui(12a)Xj?ufRYaQ0LR(5rSGIgb(ji2Bx{npar+40?9fj&2YgJ{ z@qFqhWSwwp#trH@-~cCQiv<}S02v(s86EH$@Hw!btP{x!uWvG0r;ruRcN(9HKyko9 z;1F)OH@1g?BV>J%tVC8U8NHgUd&s)?-|t2RXxfM`IraDuGU$qJu#CfmB#-QRE% z)S}RmUm@`cQFsMpnDH?A;HXJSVVwts^z5m<0Fs{(#N+=-A)~?*68YKlZg?B|i13Ip zwSt0*$mHhf!^%ZCJrCc!h}{0-lERwabcHb&yByR^d%is?vT4+ao2>&8Afp_^!SO?qqMNn6>9265 zkh8dg3y!Nhhn@3eokP}_`06ftdFR56&!r_J{=RCshK%4q=&FH*Gn|e9_!Ymfa+vjLDtvE`Z^!20XzWag=| zu9CY1h>mV(8D75EUE959zEHku&}dyY1j04a(qIU{J2m?1&vi2iB4GEp9Pgyu9r;vaY8k-TyXk1Y-S~zyVwUSRk+`0QVyhUPmCj zjzD-Ff&GB~WPO{g?~ru^SvQh(6ImfPHXGhXAUiAYHUbT=Bapog&D(g7DPs$N>?(EM zMqs#uH{ch%@5~!fF1%61%aa0QQMvJsMlcpTab(>})(^N5j00XED}>y3ZUiOz5N+TD zWIowZFv9gb=z?V=zI+FfS2P-g9_IG-FzDji7iJ)v*_;jY%uIj)*yfMO3U#@IkIn($ zBry9xXzsit*atIPG$vW>iAlz{YJ6qui=D<%<*k>`TC#YtV2ro~vctiQwcJyh@BwjC zldt!AX=lW+!w>8k`-2DeS%I`G^%~bkTmoO$Xya3zHc;zeAJq9xMqC2d8VxT1bvetq z;c0Hf20RMkjT<-(z_hksY3?&LcbM~u=-Rrgtmol+L$~58Kg3nCFL8bm&E4{U?7atI z6xH@Wp0LtVchh?|0TEO%^r9#sw9uuhAR(kcAS59PC4$NUq=QIR5ky6wAV^WMBO;25 zqJWB-E+EoDKt)0Qf6mOTW(y=pzQ4ya|MxshW_Rwnv-jTloXU< z?xN`@|GDWq3`M870ycd=K#oAbqieId27Rs#`ds@Ym3~I0pHt~>Dn$#!QQJeMdmX0l z42rYqGw8FW_IaG^rf(lxy|4Knt?HRREMcOfhmRMPe&qx#J{JCJHChQTWc@AXu7U2a zWcm1bS$zC)DSLH3z7Rhu{f0{S^C<|l4+u0yrcmjo&j$%EKH)~iIt}y*(`lf&T;*kf z*yXYEK~9TL0;_?M^Fh?#Cmv#_Qh1{hmCF2SBBTyr3Q&s?u3itO&j<4gY{q<$KjTiK z*Eh(Gj85oe-C9yTvDTF7S%&HJX=IiGd3G=3Q*@)yqEY+(a}&MS)?A;AIdRu`olg_g z*W7GzX3Rd#bkp};Ii}CG#j(Vr&z*)Ei_aZ6X-lOCsq_$!n7d%EU?IMz>3jb%Z1^C} z#is{X0NC*91nCR`jrIY1_5pkL0ekkrw9R2E{eeo4Q0Y-BJw~O+sq};i8$P{I9I)YY zw|VS~qYfJ<88JA^vGlhp2OB;^9I%l_rKg->W7t)~Mh+S`m-~o&eI#TQl_L1@BcFmm z`+z{7rP2#L2r4x`?^6WjAj-z`UW}8mka1Lcj!Mr{=}-K;BZTh*Qq9l%&s6%$b@9AU z#x3*nPM)6Krt=1UU1MmEr&hiAdA*QF*5d^-rn)}U%rZ>d-D3JX;>W)p^Jcr%tFzuL z4KDa7*2D9T^#*&w5OPbdT&fwDT6|OzY&?{{BO$0_ zLkT(HJ}0<1kB`F;uwx&vV;`_%A2!X$NeCt(goIEM!bk`wA%ZVG2?3+#H>mZYgn%>; zrAQL6WVJq&?*3N{rHhU(zeEC-R&@2b^eKzRNzIxxZ<%!kpUW4m~Ryr5*O@{K0TrpUWZ+l1zqyq_!NVtuJB>uD$q%$6a{UkId z0jtXW_g@S3?TK3k7xD#3cjq-n<<+&OrXqPypXF zr~y^xuGYzrZ#t79p~Y3I838q;3^f*CP-)+hB(x%d^DTXI4cKUNO|Vf2MGtTV3<99c zzF^9}V9LG-IQx!=On{V-a61VYooz|DlZ3lSXh%Xamzap64%m1||J&j_8ArfIdjmE) zFl_XydawaLt&>sTxg?}G!^Wdm2^&k%&`+RInV$PDgFH?`M-n>m>5~xf!p=eHzX>dE^|XVs!L*%Pa%- z?~XppCwJ(!uT|&9kKYv7cjv&i9wINkTT$QpMvEJ;u}z1K-sQkX84~Qf(-?Twu+YhZ zvu@PYcNc2-95s}kF!0??LSHxP>bnP*a$n+7i|<|%`tk8A68cw&y8417`*PHnsjF`( z1i2r+A_U=NUqq386%q!JFpz|MNVu1T`$!nXmuisjAO|1^A&2ylCJZKF2ni=h7)rv) ze*<^*WqyuLCM~|FNk9&CnsrdwY?!1;Em}^>$jvXpW+V1GP3$>&_P@>=^I6ByV~s6G z*adAgEI+fP(eSKdY;9p5l#`c>HOMpXFSDtI>qB`C_5R8u?Rorh9>PuiGvpV@1rpNq zhE6A87zr7C&2Ny4kV}x?A%BpNNdl3uf`r#e*u(JC-{l9inv~W*wKJAPACZ$$)IMu? zPG0J0tn8kWj~zHB6mv#YuL9mQrRa*&5oy-DUG%p2hYeGdKejLf)n{UH`J0?|HZfg= zVXa+Ug*0nFmn;9uw(8KmNm@$Zw7z`AKWX|uy~mC&=r}GbueiJ)_5ZN9{c3nw{AzP= z!)Ex^gdpUQMM5^8!W;2}H!_@r$=rwkC{^0e3MCO-0a$?_5@`H_An-~2;EMRc74Zv$ zgp+_s2Ha4vm{BC;k}#TtJTnyQ7lq;o#rheph{Z1s=NyU^^7)@a{^y}87mD?3V1k6- z%_I~!@d&?${MFy?hs6*6h}RLG!69J`Cp}rGxjglL&C$MQE{w&m1x{L$P((s8kAv2b zHYAKCVPd6wAbv=g@k`#5~EOFn8gDV7(vg9qZ*+bn}A1$PcG{?9|djhox!(vqR4>=O4qkqP52Gf*~G&J zn}9a>GSKCk!jNW7y@$8CXq4KaW4D~*Mn=4|Lw?5C(SWr^y|ad=7mY3InV;7Q8!Q=_ zuYd2N(Xiu$5jn$hip}t->n*{d@pCvdesE~~00mP>n99Eu$u)ieglQx^_0NF_4vn9~ zq49%5;|GVv4-SprI0zgXKR7gg7+;T&Fr9=MB+MjX774RSn8VOj#-Z^u9U8yMXhJwN za}9?ENth%&S>+rWKZir(2Zv^!GY~l(8qT^L5a#7&9I0spMWh-3y75rIrD$x2Q{xAx z#t%--qa-ZgfdHq*4^GWvBrN8EP^nIh-zq3Kof_T2_j^`%@XhrmEq>4QL$S#1p|JT6 zavjTXW&B>|$BWSmK8@cx$a)f%kg$}5W&G&|$VLOx@cZzx!hb)i;s<|5$Fw&*;nNd$ z=Pazdxx-IuZ}?C1x1WvOV`3Wo8NCc97Y(dk^if zotp~K!!yc$@9Rjk+<`=wY4mG+Z^O02K0(Ew8Fyjv`xGa;NLWb%r*Qgx4gvVAx+d`1 z2PGm`z)mmPo+Dv33D1-80trarwD?IVYDQE1*mGhw z^c{`>A0%)x?r;jHV5V?Zp=HVaPB>W5NfMk>IQ`Bzvmi5<<+6D!e(-Pne&askUcUhO zm4uf_;1o_j_&0u+NLWw8E0s=x{Jp&_{?)l+0E2%uhy`*337B8pK*C1;6g1txrU4h5 zNZ5Qmz=eMRZW$EFKhV>oUs`f(je4Vb{^14%LMAF_yIw`$$sZX${)vVf9d-N@bkx~mpbk`3 zD3TAU~UCQ#IdD*y=iH-$8VfU5hqfV70P zg0v>#Z4%xg;aw88lJFi0+emnyOWcm4CT#fMssC;9Z-*mbW4i$xI~X>;sB)aezncjg z{@qFVz=^Z?_qsaR@E?GNz88(ku;D)tat{d~lJF6q-Uk^(!cGzp46S6o;y)D1GmMIL zzT!Vj=PTwqm6uDaa4~)UpxXYUSqsC=NXRG%9Pm#`fD!zRKh1;W8{qRf3A?Wg@EM0& zX7CyB2}r(*SaB|8e3#7sOiLIzB!2UL6MUHca~V*1cdoK;&+0J`KHFpZ8vD6iTK{sY z2k?0aWyx%C<|_V^b=3IMK#htv_zV=p`?AJ(nTZoP8Hl0oFpfQ>Rgi`;xqvMZs z8-JZZGXyMzEP^bCEP*VAEQ5e_eoewRB*3ZumV{Cgz&=DS@g(le0UF3tXRhJ@G>!lb z$p8(7LE~7}1C6x~&;Totok0U^zih#{Unsy?Yos(5q z)GOPJEfuBa@tj9NeqnK%H9RXbrg; z`ujuu1?`-|qT)VTMFshJnRs8q8dK6MJG&^W_%d~eWaQ`OrWX`tW&W+E?9Q(NAi&iM z@UR7hKtds5B>YCgMG`LYgiouoGYgo3$R9Q`Bdrj3onDkx&XmYK?r)|e87VETPsi>Z zllyi|>(#z%$CQ43(^7k;_3P3RyVdtezBet+j?LIJ%{}PT#^)D~%FWL&(Eq@%Egn&r zm7WQoyX;*-XMy>}_%X&GSG+TqXCfd5Kbj-?yuw%j($s$AV>}6exUDc2kce+?&#F@VI7O1GE+An^f1xMF@> z2SEly?k6#jL@S9l{xl6T6qvQ2#2^xbuLp}6FdVlGiy1J&llA*O{OPQS#U0}o4SIF@ zro&UPatB+?fKg_dTu)_=ZTh3Q_ATu?uFkx1M)Ul!9xP@+K6DgvQ*oyh=O{}y}Xa^h3rFSFwOFzSWSi0A~2O)DrMGiM)hnz>_3aYzfVPmALwOF3u+RX~-%FtKeSa;k=r}1QHWTtV3d5 z5^p4tm(UDgVSs!Qqr)4=wUC!c1p3}WBGTAkorjT_@h`B>uNr-72>?wG06PzOoy7Vi zHX!k4w$AH3nApZ1-my$YHbY@vdTv_J^x~Xx*d4xbbb7IQ(gzlmU%c!)DyM+28;qQeJ%4=ntZ`Yn*hGFzn&YHn9;V(3)3L36T3WySLXVTJA()053?o6{j zT-Iz~;a$)^S=qT+8Ju>J)@LlZ)#$9W zqoHouJ1`f9Ym(k1J)_m-6Hx-*MZ0gqFxA0itI-L!q6c`Cz7N?>VnY)3brr^!)!*c= zG>o*~X^wSxuGAI13v)*2a0hkB;@M4?P5~=QH(H^DiD3TN;=kuKU7z8Pa9f`^Zh0q8 zJ|?jdiMR1Bf9mCZupWs?G^6!DCn{e;(YIUyKZkoDjM|u72!O8=@HONc2&_RGg^%>u{@TPYQ=e=Za>5`gf%s{9 z8LOu<9e4Cww^r-k|FKP7KZ#jzW}&-l9~g}KFdxm>qPzBi%u-0~V9*P%l0BdoiG$tf zh0F6E2p=YpUy5Kg91#qR(^(1{t`2~27i5>qi^0vmu0d`Mzf zni2PpVIvT(Okhi{0I(4VpC%AKO(1-lK+GuwHiI;W03^DR*qy{4B=#h+7m2+|yqilH zK8+3=fySJIC9o~j0nYm9AwjVp!$w+_3ke2xF<~Pxl|<)7{{p*T9c%>lMMDp83<5Yb zfpBQ>-vAy2m{th9hs1#--e2jk5qLk8>&ZY25JMpFW&($jhzjo|@jm`^7z9%d3>$+; z9DH5C#z?dk!v=g7ci1?*F0}da$R0gbpY&NabcuJ02^)E48J^8>gPJuv<}T=*ociiJ zxAyuawZ}dW{!L&Z>Kp6mqawq<8KV0)-Uoi?XP#z+dhl;tVPhiHJY=XbU;}Hsz+4YC zU<0avK2YT9+>~)h0;ib+FJLQ)w>sIYz?u9N9Fp=@kO`dcti$y#7ve7YwOw{d97`<+ zE+H|?EnFD*I4i)cuNi%634}8e z_&Veb67xwcAaM*kB)7Zp-?X%XqLRFf5osCY#;4~LUokG1X1&v?Gy;K+xLyW=ooN+N z(9lUi(xlEQdY*HeHmRcva@({S$hYu!hPCTB1GNv_hTi8uVBi+~Ei4U6mI*{o(_;sMkvjdrD>-_p5wvm(hpE*^IUkCnR zVol%?5+8QPtKBIfLTGNtxa*4Y$zR@-&o;zKjvmAtu1kBYvWRj zwH1jAfpyk4Brd9up|swKs}WMy4W;!ioV0@^L)t@9ARS0tOd^c*QWBSu_&AAAz))H{ zK{`V~SJ_ZnyXsvaB4oId#IJQj`3<_`e|}oc+Rx}xi?u&~{hg_z;`GAe`aB<&n_iNW*``4m^Oa^T^br1QKB)jj zpv#_KP>@?<&(1G&c`M8L9WCdxvUPiWUn|Y(9O7#Be_LIdpX)l<;VoE)VhHL_HvAGR ze3TVvWPZ@oA&3A!P2yW_w%eM8FGn~EX5(ZyiK|F_h70EC+XRWvUduK?)_f>JI*@L= ztpzw40|8^V7D0+3V6e2zo}xIrmjAn`vWzDVL4SbOUP6s@a^#fl6ew&B(XafFkL z-e8Hs+^N+)g1~3s#zqy=tYjMkLykGKUh%eoH;bijxJxk^`TXN{=u49;YQ4dt80?2bu)Cp;V}B>6~lOMF=p|sTMWzbx(DNJi|*nI7VkjQdxj>%es9(7 zHxgtyK4!6Q;aR-b-R!rk8Zdq9$BrBN2q!y9e4E5~xWhg%pySf26 zzA8uitw$Ii7&?xU_>nVooN$H?i}f^G%zzGYr~Z+)IF^HAi7tXqG=$GKP$?2ZplT zY3$h=@K*-&x7cn$Rkt$p7t!e7B7d&k*p0Y*FRwc7#tqf~aKR%R2*0f+Cx$xApA0k3W+L- z8j0VLcmRao2EuOx;kR``^LyiH68?iE{y-A;Yg4t=WtlZ?n;YBy!Y9E)Mlj%4#Xw#-{T2h-f`B0LMw8i=j>Nl_> z09S-e#-y^pB59JY@QSzXI$%NCZD|;=9AdNKaX7@sp(Gx0qv^H`e3Q+W0#t38kSr1b z-pBZKxR>{t+ekc4vw!}_AvW7+C>qNZz}DLEYJm;B-3GdD16{X)uG>J@ZN(&>An_!L zr${_a;u#WuB=Ibl7>A-JO}CZke_L!!*Fn?I88rPT*jmY}%F%S&bQAAvh&-Kl#=F_h zw${wKyX>oQw#U%Wi@A@u*B3$-kqBG+3!g55EG6**iTdXAm1<~h%b|RwQL$lYSLlZJ zR|EFF#y^T_o`miNEuwYak%kY-s-=@z3kR&~Cyl zv!UJW$!Lb3p4GBWK*}>u4iFYhS$ydo)6g#n+zeH&gju)SlpI8R~Q-e!s}d6(1TWex3i$G~G`aUOUd{cUKgWw-XKmfeO8?MuJY zOIWMb6{S8y?YnU+W#eeJFG#BHZdSp~ZC@FeT5S7Bs=)dGtxeKlFy%W9F4m2`#0Eo~s|whL%y{W%0-w;?{yDs3bMK`}pvze0Y4 zTqG%&q=qEv30={|TEARj0~ExL^h^2G^geULvS0D`AA$O=Itgp(9OQY1-HBt?@HLsG2i zPX;mRhCdk;W*(VPvp*@t@jrI{=awqxPX^U7$7N7mlH#49CPUw?Zme`?G6?VN25}aRUNL+FES@LTHIfKUAP50KnS~9k z%Cm7n$xy?t0Y6(o?I9_U4kXnh=_Zou^QZ6vf;wZc?<6nro4ZaUx!9+mG^iP7sIdeM#Ys9zjY#6`&Y%nfHj=Ih zHV_gE8p9QU=mw31jDqAsz?p+Um4osj1tc{l2__l?v>8dwNoqk7vO6t7g(zxL;~-|( z3?Cd2$A~~~CnE-DcS>e8s6>+>Oxl5{&s zoZT4&+8nfyq_!kges*UNqT@l!xnh2@k#H0A1msDQ?j-3hk~q6F=qbnw<9Sae>AJ}7 z4C1Ec=lyw4&+a#O~qH_PDJJvanv!c8^o zQ3r?Vu;Iw=yqp?-1i5zp)yR3#-LK#{l7_jvUzhWT%Bo0or~rx0rVHf8)?Q!c+$Z)la%e|bO$%YH@6v=T7p4*hV!Lh%_A!0bO$%X)y#X@=?-oV zX#qieJQ##HxHY5=NpPk|k~E5>T#`nUl*gCe0ci`l6Wt1DEw~+i8LrDGX$(oAh|5V* z{tZrdFbC;*vMd-tjTJr9tWK{@>CSEAr1aKJTDG`?a~s?X3i_d$!w>`u?gqIV(g)HP zT1hG-sfeUv{<1#=)Hrw`1aL5xBygEEBz?d>k5k<(*a2^xG%P!*X;N8#-{mrWT=Hct z8aw&lE|(cEfF%vf%50T>g%`krhv2@_`Ii7BgF(K7hmtgor15+@%**@x6p|*;41Hs{ zfArdS@CYa>;0jlisc~#C$4<^S*ou;8Uo&N=ODIDrHbadi800(nJ(3oX^catr_YK%sculae6N4~jEfFa_b`*Es61@gyV0Q~b|=svc}; z4%qmPBK1tFFl2-B{I1M>N($ge8Q|ZyYU_`lt^^muN zL}K?qkjPagiM-Gn&%(Tfa-W4iyeuKr`2HDZ{=^9$%@A*ro+aryl2+r>5DSFqF`|3V zlk~#%fIcCd-2x;D@%S$1!T0AbUA4PQ&BeRBEt* zF1^>xoVe@m7tcQLjy@s5(7{o1rtJ(HA$XS)u<_#6wRi|JPD0F#6H7=ePQbm_lJpWr zOo-ipjdj-o8zJ?es1e^MU?b!vNPS2H$jy*jAh$vqlC++rmr2?{(ngXtk+hklSGWW- z@4C8JLYkPzW;i0c_o@-y+rqH%ewCZ}4!O&OjgWREz2?L=LQ<{{HbT0hp?jcF88$+? zK@c!`ouoJTv?rt&NpF($UZt~*kbY2p4_C}jHi&r$h|V%y#`FFz zNyw!9@3V~%rsw>;5A*cwX7&8}wWx2q1U;MZ*wBn4&)#J|?^$M1-opl#a05%;)`=Od#ysL**fCNFmg4l>9H)DAr*E zK|;<=^{%LziBMy{%V`OjgcCRjJ4pJFN6f2uHxiZUZ*HWY`d^9&8}bM0dAC zKm@*Uh7BGASK*|DtU*Js<38eEUkiDOq&+0<<L;Q2n1zOHn(5%LO@Z*f%osuAh_ z3XcOK-3Kr7K&Bb@mmld4c?W8?u^Pr1@aGWF<`B^4Z%6{W_?AC?AF|y*pHh;9>jHf~ z!7VfTeCi2F&IP{IYw5{OPd*hhKef}UCiq`=;M1YQQQt^zDwwe9F!P}~%%|m=rbWBle3k1n zUx1QDrW!Vkp@nQ1<=R)NrUWG?8EPz{58z}X$-X4}@rZd)hYs2QnxJDU6wToZ7zn08 zK(Ir>t3zi%z^g-NL1vR2Kyo0-R+4Qb2az01a)=qd3uQXa2*hz|J~FT7=$#zO|Ag~D ziB&Fo7m7%@PHRF}kR0X=9ji>}sNhCjD34jTRUv+#=kEJQm7am7+TLf?X#t*nM|=4}WFcIdk#$C4aJay);EM3B&J2Kv}Z zPPi`6XD4o%(dT1NNHR8mRM`C++wWhWpgi>InMdI*GoKFKWtREOQ<)X%j|}N(>sjrI zqy0l4T~v38JD(2y0y@~rIQVoZAPTTi=PFzLTc{BYHI~p)oCqY}NOCJqfuo1PYBVRg1<5V>(@+Q^ z)yz0rk=*)vc;>^HrsJ6pi}UpSK2tJl?XJYG^Jg6q8~jvr$1}z=AC_R2N%T}kY8P|M z$IH6hH-`=%f6(jGhuoj}Fc9{z`i?%Tr$;U1+l{EjRb)ViHG-PPh8o=!4@=Uaqpb-Y z6-?_5Lkdb*8^_%s7bUDU$#;?5jz`Sx26QA}3v`4fLs2SM0O$y74@rS^fOLd(f^>#- zA-O%tDI|9wxg*J)NbXE>7cS8iMNMZVtcU)$C9D^Y^+-b} z*dUU-IzdO+kgH=HVOePC5!^@I>)DXuBzGsd2cPCZMv~l<y>W?e`CVN zWU~yiL)_C0Iy9X)c>d^KeV^G-`>6EYS6_O7jcKTFhNF*=M}ik8M(4k*y344L$`(Z7^UL<))g(7%i>u~ie zT>J(6foOEt%a9F_jSvvtu+1c=kvx>-bdraWoI!FXU-~NKHOLlpmp6`Y=uIqVk&I_! zD(BtF)BX(+ys+(#F8hGw?8`>*vKwb4HNHa7D{Lp)h$GVcl64rX;^U_zk8pd*I_z_N z^Ce%(@Uk271<5%ikL1%mhRGRqO(thQ6scSR8xU~gFi_$!0U|;qhzwCk&Lw#?$$2E_ zlUzXZ7?KOQgodIHlXFo2+Y-j%W|*8J!{m%*lS5U{)Rz8odvt{2>7lpno_^Fl&OD3I_oW2k#9JB6$+Y50d;4e;NV_HH_E8 zBu~B`j8}M!dHdkL?uKYX>6zLK3OhaVxc`vUR~k$mV;HY+yIBU@*S*Z6b#D>W><)Y1 zJ39TQ|2!6jx5-^+t;6B)h2O+Y1vA6pvG97j)tO>g9W*?w4x0T6Rwo=$Yh&ygI90~# zgo6g_UxmYvJ;GLJo)vYuS)FjCT!**9=WKP3wxO8{Fe)5;cZQqQ3BLp1+-Y2D32#gC zOuiJncvgk1PIwBgX6DLPCmduq9Ar1V6QnZ)Vd3ypk`ZN_L-Jgb=aD?0&Jtr@9G+yCp((5dn#|w-QLcD+Arw8p6~I1*7eTNSKuSn{g5)Pj1~+<&8DBF%d;giyHor{EmD-P97)uIg(fNICv6*j(MKsmnz+l3tt80Z2Wao$m5i2M9tvq{~`HBe$K(;!(RZb z!H-)*^4jad6mpBQ6@MA`<@Ty&Xv>D;ok1z;Gxn0?fK2;#(-dwp%WU>kW<|t|xA*t% zykuJNOSxa2IMdjJDTGrI4rjvXBX}3gKi28|!z&Z>ir^nHc^>$OEBQcqAOX{osO}`;Nm>?5Z87r5q8CGy~6i6>u|lxuW^_AahGNNyzp;H ze#PD5f}4lS#-)~UiR4##7=fg}Rxyiv09PO7;%r6_LJmQ`ha86d069YP7Ls2l`3;ia zB>63p-{wo1j2wp`Jgr;YQ~3Kd$?uSiez~Aq++Rul?O$MV5kh7>v4kTrCHyxCD0uiK zlHVnHE6MMXyp0WSzp{q6X;Tk-a+y19wI7?E&AUbQ$QnHw@4l8}g(tXM;ijH;s&Y}@ zJ~uyOR7!q9iM?r(c`My>hIL8LNOK&ph8ganXHmXmOEEt7%^E%$rkxkyPqW@%_7^pA z>@wykZ)&@ensR=cQ_@M3R(g_1R`ZNjNmtt6E5hPsiGcT^!$8ChIH^uD=AAzPa7NUG zAaK8fWQC#n|ENp;*?l81CxY2Eo0y0INFd1{lFS>vN7%3eI3BH?G+m!z_(xPDA{>h1 zxdIS}hzLj|BnlD@iGd(HJtB_ek4c8lfC$4bl0PH)bCP#+n5Ztkg_oiq>zKzIanz@p zzF?NIhyRhP+*DIUk_pujjYT^Zp)Yv(42=o1gSRG$L+CE3n|r(>U(Js@S`G9xnfX?h)$5skS-*DP4YJ+@8?guLb@45 z1D2-rdLSAReQ?Vl8WDXxk%lHQcei+GQ@gB{cTQZlrK|592GNKZV3rx^sm!;wzSExd z>Zr{4Hl@qa*IxE@CmIoOtRn6=`UoTgCxgK7@ zdqkE_G~}yPlZ%r1h8j!6Xq+JIrjo4jh$%3Fe&1b7&@Td>NCf*9I&Q!viGWKIQ381Y zG7&Nf@*v3vNIppNA(Fo*`7p^pkbH!Z=3x{yU6hC^`rnp_X*j|~Icm5l#~C+%u5vC) zgzkrcj71;{am*Pv7P;U?IqN_~JP9o;xR1EkmqXwto*?-opRR;FP4X#{&sVyC5&_y1 z@gi5u00B=V0@N=8o(Y)V8IphGPuD<@b;JJ2S(49P7qDUa8WA3SjR#ZPO>6v3*P-tY zlV>jv8`H*wjo0uq8ESaq!p*1gero#NJ0iOs+?Z0B-f!c2ygT9=s*89NWig**^wC>} ze}Z+5IjLUjjsDJ|={?H#Pa?KM&4-2>-9L%gp~J>625dkT&tULWFyLO)ZiZ?jzTxY645N21{-4oYSLhT`q3P0ie>az= zujM;{OY^&%_Y?6QzTvqBI7*fXK-3?61W5f^A@3&w={FIlxj2vOqYwsaxHS2vluMiIG%_6L`n@(YLRj$dq2uuq_q3r_kJS&aEyRI zNvX*rz-fsGb64ILnXOu8HnU%Lx2{NwmnHHq){be4$m-BW3er3+kznnSXf+>F>N0>e zDeHE$!s5%r9>^-pzoIYUGJYccpfS*RhAfdF-jM;M_>#ieppjPWjG0IZvO!OBZU2aC zM}|RB99IAf7zyGX3BDZ(z8wj^9T^P)-;RtW1@#7!VkN~!N)Rc*q&TucBkd>-&K;R( z9@&O6*H$oU=hAo0`y7!HKfSHfY?oXjHbDk+(zcASHqn z&IXOV6N2Y6iWGaL+sw!gP~L?rhINbt?~VlBj_gcIG$}Ep#PX-95KMExW-4){#9t3K zGxBcSGVEU@D7U-)3)tG}y$*k-6fJ-Do}8m$n@yV;+21S!%I#ieG>t!4w6*=Pm6P_S zHtg7m^Eq4})O%6iU`HR_r`t>gNv&)%PoW86GiUcH-)2S*gPJTujczj|GudV;j%?6V zU0^ez$kk@L-pwee$#dKdcz5JzQf?%Lvq2;Cy}ZBMP71O?_x^L(K;S>}L9T#d1H3yD zbUPAsI}&s|5_CIqB4iRN^+{Y*2-> zL6xeP4H`M$0UM8!;+zc{xzGhRY9p3zy6DwTcyQ4ppFpd!8?WOAh<7AxIR+D_f<~@@ ztR$rwDJ^&uRO$qKBm)EA94glR&PXgRU(ADF#oQq;)q z^(GpWJ@Q?%%vMij76s2a7`4B%fzZ@;;?9w~jjy~B^TL_ww>)1A7uJ5B?ho4h^tYx=kKIN^hP1-VNOTpPy}y{FOUuHGbf4kc*H@ zkl#t^PD&3_dXmzMDRG;!l(k6{a8}1&xTA7%bFWBUv2LY%guhASNo5tJSsOc5kYwy6 zQjXqR%a&=}dXh0i&@;U_XIxfVGH+;7hOd_y(or`!1}Ab5S6}ecc9gR46VDHwSZ67%BZQn4`ei`d4T$M}c%lap;-{a}=W8QE`xX zh#isu0q-9`%0N=?A?03D?jvOoUkW=Kg-|z7|M6gss?UFuGMJPhfL!+FO8yOlIjV`- zu~AJ)xu3`FQ)Pz;rj?wxm;CFji9ILpDz>Hkt6XFEa%H!y%o;s57o#yhPv1Oqcvf*S zvPCZILPoVj&$LGGa-yXE3-}20mFAY#5!DvowBt)*v!lTEqrmltl9JA+$%g+o>{|T4 zsLoK-iz@(;i$Ypb6bOA3;^$GwLyGDS=>Y*cWRQ|cN){>Eqzoqo;F!ZD5Ds$0Or!eh ze_NuMO4lQ0q#iR>a+%1DuW~WdsG*J_noi0nXY9%3uU4a#j_Bfj>A z3UofoLFc1D=c7iGg8%Y(6y!q+NXaKp5t8FxJp zxu`j~WybuuxG%RjYGA~-U;pP|&yO}fR_oltRtXIaA{X_jS!RK!GF^6mbkj?@J#O20 z{K=yigC2UvoybKkLVZik7H1+Cg?9$Q*(a3K;$=-6D8Ek0qE?Xd0OvwZeFF;Jav`G_ zb)LiL;AYkC7(}a*`GeJ@Oma78{HU)nF119xNXmnJ=~_}As+c(gZ;#@jv~JEe-~^fX zQK0Ton<1}2UM1yWQYMpvK{17tsiaI}bG8NYIt2Hxn=>$KHfN8JGK17~wrA?Fe}z5U z;pnmtNtw>}%z0*Bk4+}E$ZXlXNwX`&CZj$m$LVY9CgHjkt(*d{Y1U#VqmJF{lKb??0u9X?TL|7) z=I_2a!}HQ}(+oyvoR~SAowM?c?c~zZ%s;aR=HzAOk1uk%tc%?Ny}knU#M_x86%Md-JX$@d8HOKRyjcnCbh^Y zdz~u`!z+sVfrkg%4Y)^9he=sL3NH*Abp#lI!MBiB=?VA$D3}~|3W|Q_3K%a=Lom4z zg~^4evygKTOfE!Wa$ylEi%D5R%2HC6k@7exj)g&^E}%HG*x$_KB^>pr5HAd>@WP-< z)ms=ex~7Q_(X~i%UKljmm%sX(OqisC$%OuYSC2dzZ{WvoE)jhrN;cs82WyC~2e}DS zpOj}wd5#ob7&Q83$Snq!c%GE&Vqwr|cr45%qMLf+1q1Jy{cwx>yFazOZjNn0+`=0S zE)m_rEYs3cnar-y^G6@=+5gQNUy4tkd$*4}mxxAKBifud(1Xd*$SVPtFc$``aEqrv zO((~Q>41}tq`>y`!l2Qe4cJ(BEwB*{7bBXT28NC3o{(OU-jKT?eIR`y{YY6)%FCo6 z0JxEqO{8ol1q*}fa1o6R8HSDMd(Gn@9Cg^h(x9a9!k~(|Fld6ujWhn0`*%cVJ75DI zoAbh;(Ic-CHpZZFi_xe$Y!u=I#Qk+rcwx|JcnQ(tNO_Z#%3l~X8WRc8JXN4S?~`!y zAmkxZ-Xi5~Qg~s|=*bYwBCzl9E-72D2j3xjCT^LZ_gS8v-HSKgx&7lK9mg#XZ8*7K z$c)kE^A0~lFEh_mnfStAkA^qzHTC%)_naEOd14a}&-((@x5&{)j~R1N$O*?B6rOeT zcMjugxf`oRW7;6voHj6EW4R6+tcC+i6$NS@8P7ZJhPw%_#ST(UQ9*BmU5xoJj5d!ZbdNbq|Qg)K^F)5#r@+m31NcoHuEDUPE#TN6(4idu$ z91H_Curw$syfCOz_0mM6k+h>bkkKEJ;=C|u^e0yd8(*SPnTG1Hu?Hu6NrCgh3xh_( z$B6!#lzpU>R{GR+v;gHio1nvnh!Y7SlkycQsPh{hk19knU<1hU?R5bgOwSoM5E*h0 zIo#Z?bmdJir&eE8&GOdBJ7!^uhgTqq#tepDhTmUs3sbaNma=m9u3i_nB)<2owCn;; zce}U+(Wjx~EH@Q*${7PT1RXXk(dYP?Cq?uC8@4t>Ts8d)1x(nX$v}>aI&zqaqR=4@!ho`M~oj7g>VHxju?MP00hk*V};lt zL6Bfl4v=z?ltZL^PYQgcA4uUu(HN%Bb#<}CM3~1Y9P5!{B#J7WD5_MwM9~*1QYt@DGzP3W=1#5{7!h+j z%U+n9-0tNIs+hG6qse$|X{MC*==P{v_3lRBuwNaS5i+4%is4 z|80pW!Lc5x7JaTntq#~wZB=frBxafeHXb4M2B*1_81U$;32($aiiTdueZ;-K0P+~A zHAux`o|c$Jkj13dBGtFjr%GbLnqy4XY>9bNe-_l*h82xjp+5_%r#&}q;nQ5KXbd9^ z6I305R^#M($P1+Uk&59Fz+WRw8?#0SAT^Lw>-9igVm9KI8Gw+n?oLD64tUPL_n@8w z7mwTZ>MM(eJY)h8(|0a|$pQB=gI|0jrC-19X-}OE*z#IT_7D#M^ajelZS=NIIAY#n zcwtwU;qN_SOa zz?x%t23UXIk)0ER?3|cOq}C<%MpEnX^Zp0qPvd#NiBxR)``=G-lM#rlC}0b>aR^+V?6J%K4uvNt=*sZ?VUH?TfKhQpI>?G#`^WD{Rbg@?!`u%Ys+e%}E?12m zYB)QRNfCgwyu{B8%fs!8?gvv$2Q>#Kp$dnf!qpd2x$bl4UzNO>`8L7=lZ9yvUhaSuH*(4mX97_g##J0i_gu~bmUFH4I)vC82dTfdb8?hZob>0s> z7CicDU?a9C8uf1OBkuKHklv);PAcz*9@_`fm(;eT-c{*@BNnVV*1?*2J|z~cc{{0h z8n&-myRAHksoX&f)*PF~_Ya(j9R|sOWRlvB)MQfI^QYO6;RgDokcy4OuLJbqbQngT zd{0R7>vF#b-sq7U{m!$!7ta6S`$i`E6q;qg;oZ@v`s%wsiP_sBYQx#$`|6L|hpiXg z&}SU#W5WIyY)sH$!`u(O!Yz&jnAj>?CrxL9Hym*J?h4c-r3<^9mr zs<$6{EI(Qt-iUpUROkKBW0CHDRj{!hT9`5Gu<KyBq1&KFr_2lxj6T~Tpw0J@I*8Q4{3()6 zVn4#8wx87dNdoQleKdb~%KOXxCVFp}yx>a{Hujih_IfH) z(qP|fV(*T>KQ?*m+Ydy(HNyjJAde>YTcgEwCna{j4jV&Fpl(|Tphla!Iw`2mk((cj zNVbvEg%l0s2bKNmfMZM^BsD|N_Cg#O|6_N<9})oJU;G2)DE{Vbubw;U`CJ~y$4Jd` z%l3*riEmCDms(;^k($kyo*{L3g|fY3k>nA3k&7dREA}VI&yZgr7a$Zzg47&R zN0K^<)Lc?W^QD&{zeD~&J9~Rs;&6!bCN+=LLQ?;uXM4R!>YD%kT>LoDV14DgIA8ok zKM3G7pVR_U$8hpjtFj45O_~}j-xXr5yY!;+7TLMSLkd1;@%QQ2y<>9Uj%mHxckP(c zuWwpv&$NDBIwFaxPx8HKY5&hxwu?jJNn9Al2%}J(Kg1Wm9gV=JVCQl0f{RF<=avv1 z7mY75GK_*TIEf{-nAEXcFy6}&0QYDdiII$(|0stk4*4Z<4Y>js&p70l#N7m`4`~1a zA&&zOkGqxB@uW^5wS?3MNS#RPBvK#bpbd;>+->Huv3X=3t{cyX*lzO1=<1v*xA;ul zohDGl-9_rdP8b%~p1)d+R)WvY61Tw8K8>65rPC#YAqNeaD z=m7ztnM&%cO83>{kcq-m={j4E>xYy6kO8DlBNegB=`ee7;N@}m0=r=Lkfl2FdN6x& zLvhP60&(e{OxWn&)@dK6C+}J=G~NDT!v>s{jLCtxOtTD}19wyTrETlJpLcbbvL)ue z*;{YL`&4dhIc@}WjN+z(on!wbZlvy?%r?xP*T8(3y@;3H%$|$gibG62jw9!+h7+RW zigfE~?yX*7H4mWVgN7PQ+(ew*bL>I zYr;-;+$)e*A+M2&pY$}TtN2s!@;K0OhK*-PefGM5jrVZN3>(`#K|tFxCvV%buv6w! ztyB88Xwj>=2^$}nW#AmR!$!;J;**}5*z?af#(b6ZMZ+V@Jix|I)b}Yjl>;{L-WtLh zs}0z&1QY=_#ISN<13~pThLXQvW3LVyFO;LE46}|ygxwf;c<#W<%6=vDS9o{g@3#m4 zT6o6!!h?Jv53e#D$K9MA!3D=~vt_w?+;LK0a^vQ4r*P>R<5El9X;Rnmlkp>|>np^~ z<3PvbI75TEc^r6o9C&#gczGOnc^qQTaTiH_nN&EV8%f{7sPh5HR+5F!uOcNPU;ot)#w3>NZjl@BpBEU|QYyMkvl|lFVZh9CfR^ zgAMLS{Lh{$XLaM-n&20IC#fGgVOo4Le^rL9*FX%`Wb58Pd0^}DUC_GSa1EQ?cu@EF zuB7fH^jqj)1l1~jIaM=}-T_|Y$AgD=WHL%n1 zgCX}rhLHLhsh^X&n?D^2VR8-Y{ROFr9R2rWUGXDu%dp<@Ii4)B&xv_2j}1zhz1lu} zj9<~F+YIX+pKF#G?WxSG$CiCxZEP3&ri^#aG&p?}hS@bl9$$d^ip&;gwjQrQu_BO1R1vJ|om@;C%3Bk@m?Dv&CYDv>Ias*tMk zrB6Xt7;UE8+g1EGsT!#Vz<>C~$KMg8{hwczB7Uu-qh2EQJNFkK8|zCcXEzJd_pl6s6(aJ>_xo^+U`Pf(mq(k}DJQES~K zonmWrhX1)(^-L0C=ms#9l6u-17$p9xj7ciT5sW{G#y!k^#Jzq9g7guPXx^Va{s#y; z<{YU%RlY?!3FS=R^@>j!voGiM*%$9)>?`EZtozEJeTfHikN=I;u-C(rWUh4I!Ypj%8u&2ux$7 zX|+g0N+Mem?Z$tDHL>4rbd<$@2WeQ0D$P2$>`Y4YW`8dW)69KA7w5%Z`eG56oV?*h z`id^Y@-s^smA9;my&YP)J$i?YkbVbzOd$=)rmo|l6TV61O943c&X6vo`H|+&r(Ja; zqy=1y5wiD&qIMA+3&KgreMEsnj=S!h$$h6w3X}5&7et-?xnScui{F zxSXOK?9Eivp?m2l`MP(vCc92-z2-!!H7Vcz(?BL8!M##otEOQp)HV=N0y%;UciQxJu7>ko} zq(zbz#iL*Xq=d9+(qb#!3fU3xwv$n@?ibmyE!}p~VoXf@?N6Y>ydT^!(RCEhfSNh1 z2KL526EX`jo3uF6fNggEbS`9`ZiO_!T;g?Mg%;zM*$N@I#XUmV=K@Z+ z#Jauhf0$P2akI=5p31cH`f=%8|BijOw%+Q!v`1?!OycSn*}>=SPn#{yevy48TOqA( zIW1mxp1hq3P!shSrl--`yN-#5bFbOD*L(){wMDq}@hZ5?_k2GB3Gj ze;Ud|tY~V&0Xv%yV9HuT_PY+_O7KI{!}mys`t>LDK&Yn!B&q?g}vn z(PH15gW0iPqx~>xt=$LnQCxc5F_@2$)`kc33DRz_*kC?`tAB9}<{xo#7IF@99`Y09 zXVO3`+LCrBX?Ky-p`nzJfUE19Ln$E3BCQ)~-AU^~ zT2In?k=7eSDFG}#;btB_#!yOV$bXY|H)(xMnm+4aF_c<5y1W%>eYne=mPf*pp-B@O zCuLH11PB`gI+5pl9as{adOTXt@Sb9P)DAKb@z_}AZ*%QFj6Ts9Hz|<4K)Dyte6Hw#5 zq}@l_Akqetc0XxDNK4}qOz=&Xp1_&lJjCwD5iEVE!P18@OCMe3SbD+;#|XpYlkQ}N z5)k2bV(I0CiV}*@sN)=i0E|6hENK~}W%3{x51Bw(7HOk+lvV0JR|yY7xlYo-qZ7c` z6OcEaFqyP$(uR{Zf(w+ zy>!x?YF<45zZcieH_IT&C+u{<#>b>hbcT&xR|y+DtiN^)f_*soinIqw zdx!_YHxN9s50i%1b1FH%KS6?W)u`Bb78Lzin0%Fk_aJc^9X6vuM6}!i(6*&Ip+yU#@a_M6#KSM*j(#FKY8P^U=w|QHp_thyQ9zU zA#0}8ZP@eSx$?WA;F0VjO!8R>L1a9vu@Ni zv8IUwA=&3FQQG|`8&Id0T75g99qfySkl!~oLf@}&sz&8rY~O$13!jOOCt zqluxAFi1EALGHvzNEB)FNqdyE1*APj+CtJ6@ugtP?9wO3p$)xpv@>LqwwS#jpgg>w z$Nvq~HIeB#=W`_@3p^2ljU}WlWd`fCtbMcQSMOuPfvV`T_K6(6=Zr|c0n}c0AT>Ac zuiBGcys9;Qf!Rb9ej8H=*5=A2cTpMR{++SI1w@l0w*I8 zzC|K@i^RzgBJE|;HjuWFv`wUKCJo`>SGffI42QFsI9>nSk~kB`dZfK(IGe9CYusMt zoXx~V4me&++7@RxUdCUQ$xHA#hZZxYge+Y=ObI2fL`y$|YxFVtG)@43Z;;uLs(g$g>!rjft3Cy%_ZAYYRP&q)2}7$iW+0j_`%MTEdxNt7W9 zM1^P&nD9?X`;@d@q?F-X$O+19+@K_TMo5v$K>YgjF)~W5~f8;9Xxh4Wv z3`%&Ov^~xk1h>WsgUShbCH~=MspHLk#J&C}PP|ClN7`37ty2wRAr0dI%du6m=US&0 zl>3?$*Qsql5Vl&x;x1RS?Qk6%)P%AcfK8nsNH8RXv~Ni(B~9Q@;ndU#Hy}tPO}ZW+ zs17_QhM+p}p5Ww`zK@RmxPRALi_cFzJ?-PZHyRLBC($fZ$5WY3Ibomtf9!n+d{jmE zc3=U;Mp3|m3Z$1!wq>(vO79?21ZxaQfKU=hLKTz)0)lj~7c8h0#V#sh?}7ytv4FWf z2nZGwMdf?W+`GQpAOZ6KiRSZtPcC=&&dlAJbD#5^Gw04c(y?!k`#;Tf?D}Nl&~ONf zjzfEiW{(R9ipI)9E~?yNLeOD%XwGYzQv(P(Eb0XC+-M}-n|cdBadnX1Mtk_H2cx1I z)x-Etg-oM*-_h(VX!e!C7iI<55n_^}FT#&(j~~g-v$B}xTm)Ywx&u|JVa{`OXMEGu zywn!mg(@|^6hVKzMs7_sJeX*>Cc=4+hAR^dS0=hIQxl!f1GN%Aa44hzQV1!c%I~Ri zFIDcN${*Ob37QYbboEiqho^))MowSQe0UotcJ#;-bKoIvyVHC0Zo4zR#%_DGn0a80 z!cWF84SWp7nmrTnK3TO>r*Xvn0nGKl(xe0=tpXhm1d4MW^qsrf@@*q|IL6v{9UL*M@8p%KY`ON6W zre6O=Qj|HLDV_J9(Ca&S^tekA<~kHMpXoHWXBp;j7N$FV0o%fa0u|_fwBY{!s`&T- zN%g|=2ct2o5WNZ`!ZtdZyZRB5>XT&S)76+_c#EV4H0Oe2CTh`-qau)WLDZt3zzK+b zH28cp_Cg~KCPPK?y^b05+gR3@J$Bj5LQIk&NKWFft zbLt#Xi+plA7}A7m#fvH6!WF z+9zrt?9r9}hIa^}CN(#SnsQJ)<8!XA-dBv)QO$Q;4O21$QU%#b(pe<6AW3|>3!m&3 zL``Z%(%B~jQ3KT$MD6EDr0dk5^HXSG=loT#AKKU8!6w#A(b3@Gq70IS!u`vJbiQ&y zYR8rnR6;r|9!gUopVM#5AxJF9wfn zYfc}$0r@icF9d~R8b{e;n1zEb{kl9EWuCn=Gn|HQ6vF)2J`c$#C7zaN91NWgDn^D-f#hB`6|j_@v4 zj2k!W#jr9giSbDnLz2v=84w>yDI|#vp1{^;I)IO#UNe+^nB;hf1ljI=@ zKhta3zL zB`Jrbj%@yFH8Cd!(fF82+%W7`%y`HI$V8HINrEa~%%4t%Ofl_Ndy+bw2zD!maLbI? zGa}ibTU?LrTYPWNCd=L!*LvF7tE>P+%q*+S>_}za%sTb1Y47zJd&l+9Odj0ri)X{_ zRt%hjnEB=yiDZPBn>iUl>hu7HyBOasgx!)lhuN)W4W-c0UWTi0wQAx?_Ly6Q1+>=Q zJZw#&)!dDeE6i$aG56r)UXr?##A|QH+-HKvajm@>!v<;{H^AV*vI?>qvIepi@+jmn zl6sNUn}mMs4D(W3ES~(~d?~!V5jEo2v1j7ybGbNhDfTP~a(ZGxyko()W5Ks$ z&mjric_c}rNP+~nHI5# ze~V0u*d+YKWJn50V@VoEQWj8 zLoD2e*dCCckX{hD4Y7SlnnKcbBuyo08cElabOTA#Ew>@oavNeTw;}d#w}IH`&*VP~ z>s-hzHqQd!Shx){f&e(y?>6`?|9V8Dto#c1n-TIWVn<>O{7yscD4YQEZX{_IYXO{w zSODB?l5S!xIJa}r=!$%EdcAk>%f>a}1)-1+ry+KtseZzq#ZD0RY>sJ&qWaZ`J!^@l z=9)rlCck%4$?%F1q18-7HB980LBw7UxdAerq`4%`Bk5-TbOvN5U>m$*K1mBs1O^dn zy%Z3OS%h#lu+Y(E)}Gxx8{Ko$&@FWK-B{m~UkZp_h@S}t5gYNPfLFKf>-y{mT~;i< z@W&@?qJ+_oxei3!H*l&cnq=c zp;I^U81bmT5BY#3c#bRhbTi~blI|nvVOD}#jWxu6ipsy>hWW{c`w$DSA$BWC_mhN~ zp$GZXZICa`=Y1tf51kOtdnIm}pIvwk;m`Ze4_$NPsOx)FEvT5#Yt-cBCt1(CYL$WK z5MJhY$CsyP&Fc8pU9F>@IP=_3?vC)hSE0RK+*NqM8@`5s>{~OlR8~fmG#GOXc<6(|T9ELZ}AN-F)@c#+E6v6)|Yvh>3!3T-+2mj;XjKski zi9_%|4#EF8cpq^H{y#<1(=AzS%GXCc@e?u)g0!`9lp*DW(crmN=4YhHdhvxjK*pw zg;yWZZ3uZ>;+(icH$N_Xt1zz{_z0Ikq^K4L-LkjVZ@Ij5d|5#euO$ z;xci9$nZvzUIt*t!4rr>tQJ;5B(WV6+mGvrN_uhwu-0*%Ae|vyAaDcX!2aXF{^NR( z^eRcOk%XA%8zj9+5+>%~wybtsZxn~Mj$@~RkIeps)qaN!_Iv#2^Ezj>;PDYUQK1m<27QhpTL(F3nNgvfZ z+mAyse_Xl0;c?~+`DU0SZn(lktPdm1kT*O3oKQtZ)_&aeToX)v+;xzt5O|Islk^Em zTliDB0CCez0`MtGpPdK3KW#37wtc2<~I0vH4 z{77Y@H}5#qWn%9~p56Ij$FVOD=o?M|;ufL3rQB68)oi)rmI%we)wJB`c%E$dFwDiO zy==xftPUhXg#rkJb@v|gtHUf#5yz+r`z<1Z{x|&MKb!lEEi{M`ZxsHJ#onHiF*q2Gz9i`2T9+OR7sLVl1!4qmp%tUMi8cLOvC%4 zsm3ZvI{Fm>LAmvR!tTE5A45R3#&$P2++@CNER4gU3)sa(#xL;0DCv6i#m7h>KIi!9|Yy+|+hk9NdJs&q&%y(s$gz)~I@awIyj6 zE!2+LFOB;K6)`6l7H&IEc0j&`R6-<(3{gnhP0}8cz9(rfN&86pfutY(77oFGVcB>- zhAkXt`v?p76C1bv_#;QvJqx$ruVKHC^m8yu{Kj7eSh#BZ(s(?J@irbKjCy=MNPUt} zD|Sw|#W#R7Bip922lkz&Mgs6R+T z!qPuKlNH|zx6Jo-Hty@&tNIQ|9Y4OfaOmWUqVh|cHvQqZXAgY3p!1Xs`noo`RlBY+ z{nGgJtTK4TIlN5F*3atSR?@d>^_AcE8}!SH`@_vrJiL{7cqzgxv0obBR`{idOtVze zRVCsRP%_!7hOJwC5?eR9-ceQqz8>!}tFgtqaN;J}Msfqzm~;Ufa>L_+jreR-)QKB_ zor(w5jz_FL{vyc5koJ%ckd7obBKahePbRrB$)}KfD#@o=uo2${#Q_)b-K=8|92qub zo&cAd@Sk(*9Bjm6GC+`v_(3F}5d<6YLyi(Q^3b_Md5n0}uZ853+?3>Id|Ci0B)K`s zXV*S#6r*wxerJFH1CK`tK7KUGXOest$u0O(MB(F0@u+=4a!Zn1oe;1w0e!`=fdGCu z1Uyo;;p;Y+_x0WP))%dE^Op~{U}K6^=DJ8_(uSNi`tEOgv|PVGZ9)E&@lpiXKyW`^ zMEdc73)q;>upyswl+XJdRKwACKPir%D`4ZiYN`ncF2yhQE8Y^4&*$mwC&1A0Ux=#` ze+!zr4WIL@wtua@_}fXoFpR^-Bd8t^M$DJm;_oK84Il3%xowR&Y&`3!puixe@vJl} zA&8^L^Eum=wPsW559?p#{I-U?Bm4{seIN1kkSbBzGX0H+oMv9RgO* zwzm_>SiSV0r|bzWaLcg02`wYp(b;A0Swm;FKZ$nqI(u`AvWcecO*qFYb8e(E>ukL^sqf1U^Elr{F=wm62#UL zl1yw4c-b%V=5Yy*;5tI=ZGs0k#)J%# zL+&8Cm}IdMZ>^?BB;1S2fzhT-TY;1NAor6zlH^e&k7k?3f}g@RZ4AjJCxlH~i(6)! z#(qdx7|MHjo8oJgp37%l+)$oU={R87G|utiGEYP*vu19OY0al~yy(#frkoVhtku*A zHVvWugy+mLGFb%P*ML8X^kos#pFoJ>x5W@0IRP!cwG^kw5*zH0!`yv ze#K*C30A!K_$$nV{BMc)!F+t8Ur+K4d?`ZWykKGi z7^*OhyLlK$o<1G;IYU^+8~+Q_DG9&$2kKXnDa;gl97nUfL!c5J^w;|b$uqg$pk?FT z88u#(ArXVeKEh#U<`Nr3*%BLBs^rhrPekN$c9<$9f>0+i!)8@V1hbyQM;MozYNSeu z&2aVEmMSGS$H|$Hvmh-XEg`K)o=Y;|`eu^nle~cBg;1r$b0FtJ&NEdh5$rYb0+JVz zyqx6sg)V(S@}_@3%Sw#rp+c-D5y9}pL`V`OndHSJBQ~{^OzaBj2I&rgydENPHKa z`vH#;kNSI%_en;rukh(6$YzpXCHd`IpW{qK{629jH_T5q9FfG&AfJ;A^nkzh27iih ze&ROsdB=>yTPMWx&JzawyjMngc84b4+oX7R`yZE|)_MPu7H?u-41Pr?QL)OXk;?3t zeQ45BXXk^9_uTZ}@R-eChx??72I_zVWR4L$B1YJE1i~U+Um)!4J~cqteW>OqvlW5^tEUV=i!Uu;Tq`Dc=8l((tv}0;)=CVCisDLy|ZDAM()< zJCoEn%9eC0dVzi3pP!-mSV!2FbQ;MYg*hro80RE^?tT&`{y*kRo0I%WjU1IE_##Q? zb4!4|B;@WVA$LCsUPuzWkfie?|Go74vCQV-|t#1PBd z*yr6Y{FEL41)n!5#nc#Ek{v%X6_N&Vko+ad2rzt2@;70QFx-@*TIaBBL|0^N#fUPz zMVvRPcr@N04%(9duOW*y504lJ4)LP#&T&omBuL8eYdwA^eqP`Mk!^NIKu{2^t#{1tJcPD%39i1( zugv{$aw()gWB_C!1YvxIWR+x%WCU{zlB-ym2SbLi0$a*_CI6e`oh0u9OTpBJ(&#^- z%tiiz9Y*qZthd3woV8h7kvsE<`LIbK?n#2h^XPC@d>lja?yxC^Bt-m^$}u8rxswp_ zPbwpM56R#2X@!}hw)c2a)RLy4q8Z!(C|lBX5K#0aF!LlZ^Q0Rf(;-CiK9YYR`A3p} zBKc>M_mlh!mzas7F+yxfv#sMzIL49utLgUr2KuHnsB>;#(lWoUEGPLuFbH6JAjs{j zhQ1{svY&*YoT&te>?hqv^6w-cWF=sEkYq&uL}qKPdVNWt@JSq>XCI{DYdFDb7vODw zT4bVzdx<4IiIUH9HQ;+mPeGoBz#lk7N)##e_|xYg>wz9$kW!x%+ljyelU~LxGdnq`;~;VTWR>G41lEta#u(!R$ISU@=pV^&)PF^4 zGQV$!wRb$;q2QXtXNpZ@lRU^O1Iiw5pkD3#X2M6weU?7=)#UbR!@g-0Zfuf~o0EJM zcNMyrjZN~E94k54XNb9zlwm%@`D!{|oV1l1JmdOYk|n z`u?TglS@fS5A%+a%Wx@T*TUi@my_aUC>&2pMvV+s@?=~+or}W?C4)C7gDxk7E+>O7 zCxb30-$06wluS~xNXaH8hm>5tlpr%8;L2>Ul4n6?lX4L$9Z12_H*k+8k}`>J;@_QV zoxF(0jDcb?WC$0DP2hcT6HI-2Pr*C=|xI!zwLVp#o6XPV;!Hv zk>lh_AO3R*|GA>>***~r=O-D)qHnP66WKK@(MyP@vNV2}kC<4ygzE2(Fu#_JV0be4 zv#CCtaq=N4{Ybf#wcumOC#3WzWk{_D%9FRE@~^mIwoeF&CvSs%Ny-3H29h#}KLy=R z{ss^Nt92PEc(vvPuv!XknXQ%@$pY;^J+;9F@jdfjX(gAvw57+zmen$>G8m6=tCev^ z?3jLCJC1$g{?^gkw)Fcrg4F`|PX^}~R*Rj|r$SDHfK;czNxGJld{TyzQb0-}DMh3Vvv4DY!`r}(lrya(Q*ePB!x=J) z`Au3TrDaq*ERCFp^os<-aos^NJjN;QYh=Y{Tq?FV; zXHEejPx1L1_KHa(WsEs#^gT#0g0S=YS3hZ#auKTO$khO6QZ9zHhk%@bMvWz99Dmvg z(%D3xGE$JQ{?DUNN-x|p&?lvLBqZ6gD099izSAE|-=EhmDRa~+6Ma%HvC3ddEgXFc z$BrB_w@0V5X1)ICtS38f8Xt~6DTsupfNu-*Vc19+Bwzzeell#-`@TES2YntoEg!&a zQ$V@Ji#W-P!H|L#?^^x}RbhTDs?~1J_iPmWR(y&-1Z@=#VZ$lKxT8_HJ!ZpL@^JPV z7{(On-jpyloKlK!#+jGeQZUTd@ue8ssWoE5DHCw@G%gN`n=%nH2?C0o0%n{7W}GsW zlxd_~PYP)9bW(_v8GI>-ath+gDbq0k^>Ca4nMn%%KZlf!f(^e+$}9hVHk>k_2a}(j z1(1c1MWozF$}Cc5Gbw%|eA)`zbD0@*1M>P|yNa?RERdVm!+ND5uWx=u@q{AmS}`WS z!aCt~a(Ri}&d97QEE-f&UOXJDR<&{ZGw~wU)4OzH@1hAsqk9*ZjLY+%bSW7>rl>4` zD7MSU8(7+*tSox4M;ecQWyNEPd6din2_Kmw zB~^w#%Wz5X7+ZG@mm~!)$vjeS=DUVVg134VJmGte*(FJVOOoPuNmAgFq`)OfflHDC zmm~!)NeWz&6u2Y{NLfek6x70UNm7JMLdtS6_oLj()Z+d+ zH}{j`cS%yL#ah5Y``P2<4#PlgGZ7Ak7Ok&oFi(7 zM}9 zQXT_r*qh?sEZDGH9*JFeB&4h}VdDvgjSY1UHtcOIVrYj)@^}zz*pJd9vBM*=`#lmn zJQ6!Rk|#;wv`;%c61#(xr%8E%m7rGNLbJmov1hXO;mNjpAsG-vMV}$%SyG0WJt@zh2+zBny&t#|_D+$W-RKbwF1bCi=cIW%i+4Tt{O#8BZtrT9=@zL>&o!&& zp0c@pr}cl`{z!}O8qW)V-t9fnULWo%Jm4J2u=f^$j2F%4J*xC1Jnt6{tnPWY!y~Z= zdL(w!BYCNsY63hGyWb;WUUXBi;$3T!*r-N;jw9_nY#(MRuT@6~D%nTkE=S|XvSZ@U z$g__j<+U)!#6A|6mYJ8@?Bhsz9gc||;rcgf~Ko# z2-n-;mApv`0yA%u@(wBQlJXv33a7+A9YPpRI41U)5YYAaN!di|Kz2;jL8M;x?{`e> z3;Z|(R`)^J#IgvrJKgR~ccJqLq}sj|{Ub;vV!Mg(pnrrr37HA^ikWb?t0=?k3%udln0H9` z*PU6E9yrS$atmTVK&RU=%;j_iUKaWka5t=iZn7g{XQhLU{FD^lPu`BbY7hQS%ICCD z><4&EvkdmfQPFyCfGzD45aiz2pMpFMc?R+<CdmFT6aK;c;i@xRb5x9p#y zbGPDBp#-1d1j#p*q)4m;2>shJDj>*JwQrlZqjHHGW-Gh{0&;Fg%L*wfDH?w&LqONr zHtVDqCxmVO4!6v<88NZ&klnENN8fYJ%e~vI+1~i0#s~5+gU#9acAg;MGJ7MHxvu-9 zU9(a<@1Hg8jO&ciFlp{t(Qe?-~+{xSN=^nP|8bzs$g5Y_x;RwHKE?SG1B;V#oQ zA2wPT0vo9fqHL)rS$C7#5GRdD*+U9vfu^2p!UnQHj~zBrk&Bbsk{bYQq@v$an?jJ3 zliD0|Cgdy#(yR87@&hS9lJXNNKa;YblwY_+D-^XTeJa+OVfaXGjbj`sW)`TzS)giz zI!EbK<1N@oO&}#W3p6$P=wKt&g-%W9G2&5oLp-FwUT_v@Du{M!1}T4#Dpt|0RZ5?l zgUZ`;!vKiXT*yU`i%I#Dl)p$h#GiJ6bQG|mMv;m&ng03Nfz%$jWmaX*^a*=u?}o=O zPko|SuSWM(PRq!Bg03@RBbDhmm+2d+%=*DGJM&KIdg$i*w{Pv!L_IAWHc~G|*@4_u zc)*#`rw(9BuiDJ#z5bamg3>Rqtd7#BUV)NVTh;I+Ln`(@bdhRhf!4U10+a+TH#MdZ zCq<;5MC!?`F~g(k{c#1UjcMV~V~zx*jzLA^xd8@&5=bco^gVSPqzqCHsUYO>T0xR`7mufvhqhT4q(oXLMKsB>&1b+#Wi=8)Pvh;5|K3xSR5 zavD;Xpm&$^An~v-g)AfWEK*zWDd>9Yt)#XjwRNr2ja2ab)D_$?BLoP4>OGKqNo_^y z*`%JspWX*Sh#Pc6J(tw;P6*s!e$E)MIuZta>bi1Z{T*GedFkL{=fgLw&$MvkQLD^j zk;>fm=_l&1+j~B?{H3T(omQ`OM8FL&_0*@$F*0%EDS;d3o48TaoQBjFP|ZtLH3By_ z2;8{vD64rL)gVr7YRnrrd6U$(q_$&?d0Ws8HTt;d27=nDpK$|>8whHrehB#p@-gHS z$QH<_q{fgMOKKdc@uVh@nn-FAm-rk-{d8lS__r;UlV@;YvWOt6cE$}~-J=@_ql>BK zRGrk6VBA2e{n2 z`Um7sQk|s22Dd#j@#I3q~?AJGr z%>TrMjkHs(GN(lo& zyeMc|tO*;r#{(N_2x_OfxdDJc8iLwsc1S8D4dQ?}A<&VFNWGZU_M~HM zTuN$pQhV^}0LVa6dy?9()?p*D)aM_MX`@&c7E~k${ClQ zHulzQBftijdKzc`@bk`IO4?Y#Hjw4YIZXA>xCGDpGOTZTNTY1k$Np(%B}DN@gN4U9*z%j$CH{*Y9XnZWXDv)UH^qw*wP;7k>X$a1msCl zhmu+lHsK(az;ZgBnI4ZLFnAskV>jm|aG4{cu;B17yrn&drZ|Qz5GbHszKs_l8%Tv8 zJU#3cfV7wKB{Db6g0JA@RZ@qMI-Co>F7j>E5yz8nllCqu`j{JF`}H2=eaHt8@ZmJj z;55+Sw2w%IDvTs`6se<09Ybmfsil7V#SahLFJ{ktz@5WP+QR6 zG?~UdHovHhymcdgTY zLFK>s8~)Yga=b4#H~hPa4-+Hg+cdM?8iIcgfQq95*94pA0K7QrLu{l@CUpv_*YT%_ zAv+r3IuPioq)s~#ETQ9c+%hboc(PB5KGq|U(DIog@XG4ptk!;yfBFs=eQ9Emtdf`AS?z=9oM!49xsM;fU& zk~)jj*`y+FbQ7s_Nu6gQhr@;9Kn#b+I(l&w$Z<1+#sdCxd!0iLM+XZz9Pkt72O)=} z3x8E}BJ2PWUQFt(wa$DUm!a}2xM6;>2SbKHE+=&f zsY^*+#-D-j<+ntQiI}o z2TK-ZMnozz;pdDq@1D^kb#bdZTdkWh6HAGOI?RqyXs^T^Bf)$f{IUe8x0%m-P3Pkr z6{v;-*G!<9`8oj9V7_-$Q%wN#bs%-#G+9r86$L9E@mHt{F9FybGx;R|6wf{(F^|-H!|1MK0WMu+UTSkdH&=j&I-r#I)rjsomgDNXxHveh z1EFKbt&rOww?n{%9e0v?KdBFp`XH$*Nqvaahxt-4Vh0$p<6iU@+oSvN1Ho|~A$2vW z-wL{0`Cp*Bjy2YxI@Xf9Dvalv1lCpLap$`O^Hf6Z_v7fIr_jv;NY>&6#Ca8|YZyqL zhCD+m>VJ!Y>&PTp*skZ;Y(39^ z-l%)F>ubNZeM9Q{UM3rb{5{$W!vSfXO?l+k5p!6|N7fo_3D(j;)X9LYx9<1Kg&?t^z6mw@G~m8sj`K zir<%4-#wo9<(+L&Q6e`0*l@OkL_((`XQ+wS+LdC}3qhO-Mgw>ys!k9t=~H&Q<( zmD3rWJs^nmeopEa3>&rTEIThj<^BB)_cNX4t-@K3vR%y2!*skXQJvf71W$H?6$|ij zB7W>d*w}d`soO~XlGLvNKF+Hl*O=h*HL2g62;k!^!Yu=QoCqC3T8R6qY zkcUa#L+baW?j>~}v)`bdzFgkpUe(o=KJ^Hzy1G2au&S%O#;dwIk=r3WHvXOXd4an9 zq}d%uv#P5TyxaMrUqivQer65bKAei=R}0s`I^51gsOkx3gFECS~C@Y8&_}k zt2k)56Exh3ptKV~Y3BzJ*wX`~{zmHWq#h*o4^sbR6-SKP`4I#hT&OtufmQr3(&~|x z#X7EK|0i_(8y-})WZNM-NIgVa6l-;M&>O-TQ~OUIKeD)FQtI%cicX~^C3x+*s1X0C zC@UR3x~Qx?Au(XCBCl!hpwix{1*1#L$CnkgiFURrE@{K%ib^VYZQj(fqG8x7Wkf(# zy^G5$f~pJg<(vxcRL7VKdmM1v{42ofomHgOC+&i;sShV24bJcV1rY*w?jg-aS_3Y) z7qXAEhNPX(hWwb`OK^h3JDD^KHiuBR^H<0L$ZwF}AxQLa{y|zJ(oQ1nWYQXwb_!{y zlIGtD-FXPb!RB1dqxopVk=dNaJE3d56S{U@onvz@M9T##xtfp`yc4>sxrIvB)JOeA zh`(5?AFY27Ga#WaCb-T)ueQcDtUj)DA?K0Slr-K7-E}_X0@9k3)}q$woD0<66=yaq zTpL#`yEfXHCcCh?5)g*h&I+R!&CXjN@&vf-sL9DS!7#ZH6nCXT9Hg}*trcl!^QSI| z8{qW?Y3GoJRF{7~SJ?$l&XmrT9f_W0HGgBH@0o7P@9#Qt*3BJCup%r|Iv2>gC;LM>~ZTNt#vh>ew?fSg$@{^<}QEK z+|>sseM!5Jv^K1Bh?+C{2LyAT(5T?M(Cw05LL zlNLi-ENOA1#gmp``H`+`QJfKHsC7id+C-j22AvfCW91sQ9Z)*Hte~h97UM7%TTd+? zQ96-NJC#nr@*2a7;0c9aQ{-PPqv?g=U!sB@B@>Fvi?KFGd0x}-CPwE^E*)RdWfCk$ zIab`jHLWAo(qVkXh|;o%U-RlAT}ww77MBcVx7xoMtZMY0Be!4K)!ku(IEU?GQIJCJAQ&XV&{Y}TWgPH}apP=Kc zI8Q;ICM}1wTy`t3MT__^x_x;>|I!6Y?y@L(JtQ8_83{)1+CbXHVg98HxgxGtQ5Po; zxn3cyJs)2qtwW8-x9crj%|UJUFI`~bE)Z}R2)GLb+yw&e`hc{Kq;(>#GihB&>q=TT zzH~DL1l;uzx~(3LpWs0&CapVZeMlQ2$anF7fqc6}Y@4;@8wi-JYX{_8(t42AleAu> z^$v3|GuXc@pIn07qzfiY%r8FjHqUuYa|4+;oKwGRSx{P1m{)`H34!I)rw%G9p44Rm z$a_}SU~atpZ%dHZv_s&fo~c<`{YQ-Di?Ehc*JA8eU5w>W`xlKHUnKbbmBl5a0k(x# z2hh1al{ldqcr1cHs_AbzQ*IvGqpNKt>?@7Caw0?ZLFRC80)3i%z z&az|X_AbzQ*I(SgBlrh+y$ihF1zzt0uXlmhyZ(UuNm_r>29P$8v_Yg@M%rM~hHwd! z*9!~lu8(S9Y26KQgb}`6WbByNh9PywLgFAG zS9zpeOIkjEihLG#5&#W^d?;xJCxUr(vkw9D>UKpkmC2_J{5X4F*8z9jJ$36#lRvw| zG_P*XE$1@cNM)`%sq>SCww^C8xn^_G&<(S`2sf|pOq9(r$4Ho0ceXIEMW%T@T#PjY z8QdLFOCYUxo3tKTj4&0rvuY!??p~JK30w(QyGty!FO&pCC$zn`!hYFQFyaNT*hG~c|`=7#2!0`S~W zm$5Z6xb9)NdJGqb6?G4XjDQqFMnXnGMw2#8RejD-*1Z3U~GVcbNcZ19?AZ;OOi%5fJE+Gwii6sWa98)>|Rq8sGcy@#|rNLx|++~-GB{tGwEEaxW(-kWsqC+$wsU^wpP zPeGU62LK)5KKGDz?+L+un2>|VcyI_0EFSE3wr|<$_T#2+syOuEra$sc?&INLJeL7+ z4=*!!;HQ^Qb6$Zs~vY61^#1$Se$xlslWIX4f8h;?%1M2KSAbcfhyo93Xe39IuJ$yXLEuLsp zl+5=D*zkZNd%%o6agcaO0wfWVMA{>yts-qTX=_MZOWLEP@e+!j6cmjSV)LX~M`o;W znam{=HC{qdt9wf*dcdEBk@Dn{7QBR_r+o-)RJU+~ryF{@Cwf)rWOtnOAni%gcnw8Q zFGz3FV7zL74Mh)#wTC%0O{?;ncoMyY;w9k`8rAe6eE$ z+!%)TIJbo#_=d0H1VOOZN%OCvSi@Z$Jf$cJYX3jn7$jq9Y-=5q>4MeQ$K)dlIi`HL zE3X1mC)F%zo*Q8yct=1L#nuAwZJda3_8lA}=qmX=b3S=J;PAQ(SPw zwgdI|3G){Q*Yq$ zKH*DWA#F>I{4&oQxcYs+UV?3VK(aj`*`9YG??T=q?Nib|Bkgn2wvq-SwT<=i1IQ)_ zQe4<^_k3jP<(H&=P1*sWnZNxfH1kUyH}2D~Nc)OCcVD17U`K({p(6|O$}q*4UtV-X zZ3qP)gxo!q=z5MZd%h*@8$L>;ZD*!jYprOgw2E6{v#LW3(!lw@d3K3Ky-4Y1ViAXMdebJxK>m7n+yen6#Zial-V|_^X<`Xz6E0+0t9`7-7`Y&w{id zZ5L^~`Lq?}Y|{3S_EW99Xz566NpH&ygH)v>5T1S^qz!49BiT#ZKK`^FB-*4}Kahqu zPyhLRk#vO1nQEoOhX|)ljYrKb9$nS@q1!)Pf2ddC%2_7WN>8=Qz+nh4^XtNA=6-y7 zr}nE3wV5&V!VNElQ>}Ct+T#$npK7IJA{|1JVB3m-j6#=~_Ix$lQhG ze@PJbE|W$S4=t|fmd`19lLO3NIzr_pd@{fVD{&9=tHZ=5(~+!_j(E6;P3}EF^ELw> z)BBNjFw6#~gTJRUp=TPG4kG^tA29{?XN_!N`W3iZ#J*wJ(yxSE1-Tk>4FrMlbi~8| zBJB|AQKZ)+y*}wSzH}(008(h$!1Q7GLB*suApK<0quB=PG5-Y{n2zYYU}x#$@N3H; z<)k+xy%Fiy06WB1xtuk(hS7|c%h>!1(7=hMWur!ymW~zwz-B!aCVy+16KJOcXxqeb<`qX{tJ5dr zM_HWw{CYl4CB1Rjd~o^=_-2Or0NT>0Y6y~@}3UHZyMZnIC-4( zR;2S*-|0_6o+AAm($8ZhsMR-j($}MM&an}e9xeoyEYp#L$;(`vQ7-W5>z2TzYStb~ ze-+id$*al*VqO9!q*0PX$*r zMaw)DT=A;-M~IJ+&IDjLzTp|*KVGMW!&$xeke(23L_yute>5+(rT;*BB43K8l4@o| z5ou5Vi;J^mM21TGZ;;<12O-E%N&l1dWYSYex09YqI$+SjmmZ3;dC~LUdiYZhM?|{W zh&oAklRjG*(K-JGBkDcf8e}g(*~MlvXns#@wdN>r=NA+W^99WFh772;Il4$Nc|3w% z(0VV}ytf7E9@5iE_wuJ8^xm@}0GJHY`;$JJVWvi{gH}XOo^odM@b~k$y4h?Md&zC0r;w@JDQfUGh4=f zb1fZ78GwQb>9)(tDH6OCfrP zL52g-U>y6BenKpT=tZs#8%J*`?kjA;_MKbSpVPWw&*JGRgMR<`(?79<4W~4F%d9fx zk;?QkwyN?Iy((sFdm6o|J<=-NIC>|bj>%T1vp4FUB#h&w)pUAjkAqWtXPDL4ywh<4 zPCbD1fvhy()QlX1jte=!sl9$q?FFayf>V3JslDLTUT|tJIJFm?`ZCf7lRkv>%Spe2 z^eaif$_iq6m*M^xF)U8)6`Y#!;%fer$A3oFxgeI82bwvx7o7Tn2YoZ9;; zs_}Db?`t@D9Rf~WMEWq&hcj$|Q+q8=J%aS&6M<8EEl%x?$f>_CE5CH zuIzNr`d8w9Y4z%iWb=8?h_}ilL@IOj8H2t)C%KdD){mZA@WS%)*TbLp4Dj@fRCA03 zH_NaKZZ^|;-V;jkyx+N|y5~K^gKC(tW2l8Ip5Ya2V^%fQ1Zr2V-(HzsTHse5{5si@ zbYvhzzxv2@v=x?hozWF{ft)JgbNgR&%IHD*yfB|Tqc<+?YhG&0=tKI=u#_1f#Pe(9 zb7vs#oxzlreeR5bkU@~kAmF+gLm*%&3rJr``XbW7UY3x)lrKe$I|DK9jH}U2^>ECC zz>+Q_{Wj7!3!nQ#(m&#xxUjeo@&Dps#dy{Jl3`Yyzr05Yzd}E@6cgl4TNM=+SCp0^ z+FDW6adMBpFGpmnT)cQ$RA?3Z-*; z_2f&24J$9II857T6<`s7{ITUlh5xH2@FmI&@3L@3C#183Fg<->cr*{=Lhjf}*iz zRag}vPXxLLmLYV2fO=rm+Zp&<4qwN>(g77^cs2Ei5%IjHu|ZXfof{oR`GwA*!;Y|A zbOxpiGR8wk1^kwqBXB#qpWzqYLB>SV?;!nYhTl1X4Y&e-f5e{tdmPNXdA#g3Cch%j zJgLo%;xn$pZC>yH2~%+b1izE?yZ9&EAl~rO?>?S4yfS8?q6ORlNI}MI$Q;N`5V$27 z@J2G=jbzLx{T|ZqC4B|y_mO@-=?{?ppyhpJEJAU39~tb#@R7X{o<+Qw&vZNzew@I0cTrYweSY`3&p+xQZyd6lbS-mww#GUOG~A0_=U(%12)@JTXW zhe-e%fot`|3Bg9*!!0xGLyl578##acoOO$5c0cppd9N+m*yNe%78|iVmW+rVOW(h` z4}M}+w+GfXEFToVyMh@^h})3y3EKP2>TwQQWPB=U1QJt^s>i=V$?aw}wv4ZF@(t7p?j^=#D8gopGzGSGVh=cnAHjw9&p+gJ^+>#7CZMZy^08(l`2H<9ifmxL_xSk3ZrlVB=**j92;32XzlNkbh))AAgblN)T-Lgkw_k zaHsF&D4Xw89wUspuQ3Eu!I+Zc`8Xdu6CXMlAplIs)w1{D!$g74KT+VrM1ckb`k zv&VeieU``Ki|DabeY9@R^;h?7{>-Bn46~;-eIWdK_r;?<&iD~y1Q&+qOy3vroqGC3 z{LIr$jjNCE_#CLlZB`?^51&iG#wHUsP!)h06@>;Z0$dDVreE<8C%8RW@q}aYU{tjm z#rrx1*AW74zHYcnWZnd&)%bdn{z;g3;_HJ;tqdHSuP^Ca;GOvTk^X6oyb~WB5}$bc z6fTDko{0~hi4UHM51xtdatH#bpOOAK>03#M&Dlo!mwYKa6Cbi~eAhq);GOuc6+@tZ zMfwiXe-qvb_6_*=J14%8JW~81!ZGoUhKwQoYtmsRw%3ic8Xx=tpKuOXvqs_9^Kk;{ z--e~t_>h6)L!!U=kWRtLb)+Ml$Gdv_rkQCq^6{kA_-3M_o4J8U@Q)iIVCBBqkU0>L zaUaOIZyxCi=_=_O={o5K=~blf<`t zAYkP_khy)N|3LbW{ONO$^`Zkes=E0L_}_6=`j|FO6GRSUju*W&KW zKX}}-rtknnnKvSpnRD^tw>CEDoId^LWiPD$^e-%t9m<}4Z=*eC?HD8BulPVLUMKw* z(+nOqA12gJeS~V*G;%de!hP7((M9@!YN`perkFtxG)^E(u;P7VLNC9KVGB#E3B45= zt*f{dPNMO@CGP_O{1I+4!MuInnU~spJ4yeO0Sy%VubP?6y||hu063uMLqd-42gr|* zpCCU&_LF{yj3_edkx`!v8yOAw(qAD5AV{PaCi5Wv{RbHh$vBCOA#5^@%gGSCuKl|M zdYK~nk50{OL`I{qEE;PIh{F6~N8AD;^AuEY1}hgH+{{K0Q1Q&uQ6m{AlhK$z#bc9+ z>4D5gGMbRllnnGlb282(<1EX2 z%w*EcSEpFVR2XGS@~bvv%X1Q!nn> zXVE;Pd`RYi=VQX{U1kB=8^&E_*}Kdlws%Hb(@@p)o%l@f|IAXW8n$WTFpX7AtxE^RcT;FlK=y zZ$?6r5ryY=Hnw!1_sElDXL<*w^s~_C9jnZ{k;?QRNjHf`XN}n=R^%``9M6gz znMlRS)VTrHKcwPhRzf6*3{fB|L?fdk8J)=JOhy+nVC=e)(cKRlRVdDI!Tg$!9Qqcp z(Ss4A7yr4e?!m^de%LrbM$cf_ILKes95%A*N7=H#uLW#m*>KW;jNWAQff8haBxk{w z=u1XFW*fB%8(CoASxx*6pKihia%KS=N3q>ZRtwZ37&Gu83-mb)tT_v83ACj@83Xv! zb0O!UQgD`mWDGhHP$R1yemFQwR&*o;_`1{b-|lSFE%mX7rVp;SsV%=Zx&_z9S!LoQ zm3hy-F)g`Cmw79Dy)ns^{Cb3lcUBVWu$vt&P$MfvpvGVmHEOVkVV2vkc6jO<2dP~a zGH`_3?KHQW3Gm3XvV%*7;C|M{xGiMa2uIt$USSpx;i@o4I}2nutDAYLEek+#HGIOX z?qpn3BS$-{H?AJQ#o;|?AF6p=BUj2Xhwp7~#hO=k_YMk))xd{~&DEnW<9Ivhib3ep2#3<(|3 z;pn1b)-xU*u8EH$$ruq9-_06>Z^rVaj5Z~ZQZmr9Bl&b(RK3b`$QVVlFJtgIrrFZ0 ziKyrXZU7c2YZ3$zkNVw^d&rnT#za0{ z0lANiNn~7K>;7)mL#TW;H_TRoA9Pj{(B#QvOd*5!^v+rXS!>#ksbriGdwOR*g9+>0R%qCSaU5ud9x6X1#%G-nOb?e>dwbVS>msL5Hm- z(3))WE1ro_fnR;>|LPMmZsc6e*(al|uw2b7P~9x%y&T$==F{vo3{cz1m>q6$zQ#A( z%}Z@r-;gnfFWo`LO*OMPGOpgq#aX))2ncVM2GJn~q>7BWWXvPuW-{iJv4D()d?|O$ zF8mt6sIWN5D9_qU#v(G7prbjm`zIM9y!`Ku>}DPC57}>IEM|)nly8V-1vuF1@D&th z6dhrA->g5QY}xhE&n;J?qyB;%g5X`$Y(&hLlCcbxld&9MX4@bQAPpgn$hd`!$H{n) z429t(xN*zgdDHWQaG8@b~+s~}CPsa(Oxwn#m4Y_UE zO%V=iN5<_md(Saj)ok$W>zVRej8~sz+RWwI-{#{(BZ^%}%o(hinHK_Xk->KhQ*ol$vrZW#768;m`> zD+Dh6!(=={#wz}_2c)NIRacX-=0xzwvM6UoYd>rC1>rsVq2%n zuJBR&p1U*a*5or@4Y#V$UC176;eto%-{!G%Bs5jH3XJ&loSZ@*k=0fyN#`Xnaq`=fR-y!%>39 z0dy|n&ZZLlhLhjPK(uumE5RQSI4fV0@ikkHS_O@q`cbwVD|jsoXifuRK)AD!iIi4u#w|NMF>0#*vRqV zBpu>~WI%k7Ob8|s4Km<^?$V^ekJ1oe_9F|Yr+O19KW9surU$8 zoMB^9BnU|O?s~OV_s(~}xY2w6+V_TDWWmODR+*`h%IrL&(x~jwJ!n1HpCWH#*EX55V_8l~lm2(SK)e8$N z=G=};?=&y9<=jD4^$}Lgxr?f7H3}={AS#~2T$#g)Irl-hIRAcDxs{NIsHy=~HKeLW zRCN+nolI5On8B6<3YCKd>Kp{UIjoqo7V;=nokCS-P*oR>D^_)*s_uLf|L(YA4$`*8 zTNXLb;U}(#JWo}pQq^fxbvi4?r0`e3-LAvGdfjpSuwkqj9Y>cIjOtW6c5)lH5O8pHINtF&bl6*vlxu)Ij`X4RjO)2RZUr`UWdFv zRn4d>nHk)`z=z81uD;j$6pa~!jhg>Y?)zQb+Xw#peh(+_Q&n@S!Y1dooK4vO?ggqk zi)LpXbIc+KVV<0?xB-54K83&^$$=Y^12-fGZb;5H$d^>rf~s0lRV%7Go2t&Cs&lF8 zJU@?M?}d4U<%Z-`;+%OzRcrop0sl#?dpv@tH+YSxoZVD)elVQx<*x!lohQA69;@Pg zIH~>w-sw6Nd4EAQzu_7|B!0!o0jj!?s(8QioZle_sj4ki#j_UFYOE6s(U#kQ8wT*^ z0#S48Lu^#lj;f-mDuzGBL_=;PT=xZ4#Zpz=iNFAIk!`~aAomR1S6JM#DlT!_hi`Z9 zd;8G$vU0clKHOvgxp00&ndXto+`E{Xox7^*%sU?1c+TbSXL^J)fZP^nj~y0_k>Fgp zSUK)>s!A{!Kvci_aMfBauFh4QqX56NXeMBs*(A;ZUiI@LMc$i=*Yz>VBqRFx5g8@YW$a3hM72L*13 zJ$yr9BXj;F%M|8VKMxVznf_(=YPaZ@ejPImhFz z3CqZP2MNpn7c%T(Hv0z=glQ%ZqJWeG_#l|!@0^#{Ie$RGSyJp`wxW;T;o;032JIdL z$sV&E*a7SW-T=5G-vo98ZvoKCF?-0HODID_&@F{sgUiXt1W9minzDM5gNr)if8WOsZ;3DBJ z5+*T=2K?A)-8aFH?HU#EV}p+CqAxm?*Q0B;Tr9B8JK^T`l9t!yzx8mSm0TX``e2f)GpS*(gs1VfdyT< zo~=GD9fW^JL9ec7>6b40g5G&Ox)crwTF^W2dKmqT^v?WVXRFWX=N?@_y})4$xS!_4uoDzF7qtE4FcjDYgkZl?OrWYK+nU@t*v2ciOi)u7S0oE+G9ROz`7S6&*@{S_!X#Vsj;AUN_ z-9uiy!2aKVDk-)LemSICY}atIE9pY#Hya*GzU7rCk1bifD5thA)na=XWqO7y)1}wk z!M&ffPnen3Wzy|;B)k+V)nbuk6dSAexTdjUwU&(_z#}td4CAcfzIbm3*VI2w{$5T-g901KnjGcy^>A-{JolD+%?g`0_BsgJ%X}m+76Z6Axbbj&KU{U72{$@gN>_dob|?_c;8N*j0Kprr4*k z^9*?(A@8F+Xr9%X0}~|wT(88gMMayq0p@{qzq3FRD;T4m+su_bbyBPPoYLr2oKeWtSa}Mum zkzl`n*~Xz$+9Zw)v)E89B!29V`Zdx*$+1{>38Cb*Mhv)l4(|85$Wy(uz<86To^Ky~ zzyFGA{xGWHP;%_=8f_rom1!fQlGVgrfK<6UdNroF3$at1yc@{-5=Km1U7a>Io(pZn z)kj5|ga&QIp|9f_01bggKx5!?;0p4BIX01ZGkFnP*h1b{$@`i?8*x|S{6HIVR~uW- z0@7$>D>KIH{O6q-M;meN4BCimPu^_-v=Mhx)o3Fw8lBtCKM1;D2Z8+Un|xyl8#;`q<2+VHOIG>x1@Ku%pK{wGnrRMjOa@W!gZm zvzybYBKC+#E(HeL)z0WH(c)M+@u^~IL1Kc(H@V&idxHZ~e%UJh5rb8y_AR(nzwyySZ`@`i{n zkV+N&1Z~_aXzw+>$939xRih1LylS*Dv;}AbeO`fRiQ9>4-qfox#l3-@UF1DRUN4WB z-8yXu=R_L_`p50(2ABj8{f|TRKkh@|BVaG^F#xJS97Q58k~b9cs^s;N_qbnee2U_% zHa<7DoIj(fjUSjXPV%2WYM$Eoj=2HTX>s3^_e3CV2vwwwDJ^PRj4b{ch$pnx4q2=zfpC5+$!Os$nN39`AKV zY~#-=R?`wC*_!i+iN79bMM5nSB6+usMjHasmi~EcBOXEU_%7T4Xe0h+paakm=mc~I zqJU@;E+FAT5^9rBhlIK$TtvdfTmo@wzuJiBI5g-Zz8AJ_Nw`E)8v?JUEL>IN)JD9; zppEz>66yueMto}3Xd~W*PG!Zc4FWfI(n+XK!eu-NJU}K14M@OStE)M-5sze=cug{c zAmX8)cB$0g!--U`P8b01u?{DYX}S<|m<`GIRu*_8%!yknGkH(Z&Q26r8?XNpr= zwSD88?d$h~8x`ze#6zdY@71r7E;v47!68H&N+G@>$0ghq-tP!<$7>1ie%km#qm8ar ztmYu9L9ALIF^8~on1t>m^xzS5RHu!e=R_NBV6?a+z$zm7iJPHyxRz9OafF*O0|bK5}=wB{HmG7cLG#1?ghMWzA7=g z1gPeOHhliznS|?sRsal7DhXB+Z2W0kpqX(ZUs2lh$mh*Rd??i7wmX5Z8?x8sGj zs3~#Hgr+Iezth<#A=)Sd4Idg6{orV`Gkp$O`#wGI);^_e>uw8Wp9BQC6IihO)kZ>3 zjW(QB?D05Mlc-l?N{Gi!0ts#s@alL|f?21HjB}xl1S={^=LSFm2?%K?qycuo0XP8{ zfEGO@Kn^4OG@FDR5^f{m_GeHGeo2DI*k&191d_GzhR}x@;|~5aSf`E3tWI>+$mxG) z>7s;uKWz*kp>H56V0Ls0Ky!L9-k?D@eGT zgdsd=(A~)U5{8}=b0CnNu$~)W=2#6p2Rsj~0bT&s0_#X9CIRDh7zx8kz(^fILK&A} z`D_S|1db&$lWf8kf&*)aGHKxL?<7p9d4gl7pE=$jVN@VITO@L}nFjTWC0da54rwI3H%z-=tjX98zP~l@L2?tTl zQ9gerh(o|(;0Ou#lQ511etUevcfj|!)jlI(JPCM={yd-!1*gocr-q||e#1o z+v6*ny^-)ogekF>UX3XMvFk)Uw=kK6DHt({kveT)n(vY|YM^gPm`jmQ>wm|;)3DZsK}I{V1CH#B zYM4C|I|7|Zm`}pPyo>O4Vl)X0NO-K;qa2AnQ28y~FmCX~o7wpZ?66xw*Of@TZ9)WEAImCL(67l|iye z=xx8@oAl?lb+G=j^v*x0tr*vAedukU2&tav(yx&gfiDfvNgTee@UgAh# z6acxKh$wO57yxDwx5hIhtRmrA5>}J&93MIsKu&YwI9#q;*pA09g9?70gcnFS$}5Hl z-@&f^=NAk~)G{}?PeH$H_`$q@m%eF_f<;Al>(=wE%V;FdK?U>B%^HIscFnb|MTN{D z^MQv+fI@tS8RVAo%VtY&e$}xg>H$NaE0q7}F7xEAl-Od5o}`S_NR(AP&5dgqKO!M8akgULj$N z;WZ~dkK)k0i7y!2b=Y!Jfbc5+;XFj)?HcDbC%)=u3dFQu3nUT5w5y_h6L+I?_wY61 zi}e=pHVNBEc%66O0p2BHI|;k1-+Fz7%C(FU9vD#BiOlo+NPq-J%S^b-JCA#A;N zk$@E}|9#P#_zn7st=G5VEK$jhT}Q=!PVel-SGL}JZGVShy*NRe%N!0@CgDBvp6u=M zomSTW{I=Il=3f@ZdO^G=di~c3DxTehw{$nbge=a;qVc~~>?I_ssDgMm7b{851kJdIj@@t?~X?EFju#>jg-UVhbH8YjGeE-#HU!(Ny#;s!tv=19N< zTmW1M)CTGRbxHVu1h{D*k+7EpIA|C-`wh}Ca}owf!_1)--d={SMjD?mUmy>Wgu^wC zG|X2Uq+!Mb)}IEDhPipwNW&AkCk_IyLawJwdS7tp% zVh0jC{`WPnd4m6%O(X#si9woIf2}f>H0Toe`img1**q2f1NE#^2p&{4BaCs11WraY z&j1k2_=&`ZOd-+bHE&Ny-u!zDOG_$P7%o7FSN5dlqG8Sq(RghhcHqaKCIK%JH<=dz z@T`9(u>qgdKYFp0841+pC%FMOZcBj2fu#WA(B|a;57sA0_=SXDN%)O~-%0p`gg;4) z;1W-vs1epN`;FbR_^d67wY0E~Xo7JQ>({ujj`=13pxj7eWT0`|%wKWOv4r{y+S*Q7 z8!lws8}sYv=$$xJ8wA_2vxCG7NW72-!5hFX5^IxKxB89S9#oD854mC8xFM-@Cy8}* zs;#6zGebt3A)0mDwhue|flo-hh{TIYyo7BV!p>$yo1v@4dL&+YUf8w+IAykN2XS5@ zi_2Z}daJu4<~iHG9J%VsXPVx^PxtZ91SjzpTG``MVM_Cl04VWt614?2{}}-x``Ut34V{3HhHd^GKs4KoAhrcR*#g^T zi6rp~5}T0Nl*B7Zyo$uDN%SvFX}J)^p{gx)j4g|GR@WjgOeylhlw!?Wn9_2&K|mJt zT;Rf#mMg19K$h#!x!3bG!d17l09ulG9f>V?w-wNuM10b!+6l-4>2A4MZ&)KB3m#+x z0bQ@(50!mAxg{FabmwZoHI^VfahY)fbv z%0QMBvYQvPj^pX1^uM6O!~;Lt+-P?M#A#3(2r%RmyND<#)0cj4&aTpSwQ zayJ0|Zh>sKK(<>T+bzRL>_TE!5-|X~lh}jAo_uI2FajvUg=5M?VB0d9#9k!cLgH{u zu9uQn_TQK5mhr}=vJi>A!^`!~g#)8|_9!U7YFO|Uos9mOhJMyKX$p2w+pVaOIcYlZ zAc-*~=KMps9^Be&)Hv7Q+8pdWL}Dz7aopNGEix^}pG#!gg3z~RIX3`RZ9(YU@+bgt zZhd>63++aJyt z-Sg3nAFaMQq3-H8>k0e3iOUTG_L)(J-GLATc6#X_%4UnB_C!zFoMF+Pd0`CLS7;BR zaLs^SxC1-!cPW4kB@AwbMotqT)$6aKj*oq_#ji zpgoC$Nh~7qF8=gJ;3l0m?j~`_`9K><98U*rBy|Z#0l)2dxlR)y>AF=d>(pS zHj-H0bD19D$|Urg;9I*S^_yoNJ~r`>))yf}AMAN2A>N*Zyp+FaBk5L+Hj1m}X(X9Z zO|nr9(?(K~MjLpk3p?Ib2^@F`duxwgCxPKdaB#ZscC-}{QNFmL zkxdr8c#x1ux*g}#7e!bI9~ehdE`z#F0yB&X5yDBi_{Iovo032nqxsN$67Q*$5KbD1 zqla=!Pvbv>fWbf!0EL_cVVpFC#4#k^OX7VbjwSJa636kO(8)<9z%X1%2;rns?m7}5 zAQ1|0i6(>}|6fSeNE++En)v18Lv*md+U!SE5C|u@C7Aw(L{7}6TUiJ6K^Mx zIAMIR;6tb48-Ij52@&q3=_F1haT4>;4DDqB;^cFASwIq^)k#_kG@F)r0CGi=9tIGq zPC|Zk(js6ni5QwwNt{L^P5?T628lC`;BgYCf3OjH+}JL|R*U7#VmpLXK@uOWaWkb! ztNlaeITB|Fasu*D0z|BCl>XirZA9m8=JCQ;{bgViiEw7-^6o3Z782)?xVZX_(d(%E z4Q`mt&URo20A)6x#D_^-z@P2{-o$MW4ZD!UMdyVv;`lckmiNOMmM#&QXWIX2JG^4r zE#6z*tu`CR=p&=d-f(4B_Sw*V+m_S^);`ng_RU8wxhjk?LV!Gpbug}x7WPW|R5M18 z7*^!uWzeuQuy)_sGb56|K{W@BYBXbXKr=>I8|)LoE&h%1Nj7LrqDDEU(~0&ye^;bq+JW7(HD7&sonb$Oa}uizhe37-4gn z+!()}x6Mh!-4uLiOMJsI6=urh>w#7zt|f6D@3x7kb-WXa>*>Ltm?{6!)JO77sHh7! z0CSmqGtdF(2y_BE15rRUiHKZmAn_#s3%8u3+k1CZXYk+_w2JwPUj+eobb z_lPG$s3+gyZx~rANU;-NhZ*38`{73vk%&-6hz)31zbtqh4?u}QTod2;1ppFKk_VCq z+xrHIyZBQ`^JJc1gyDUY#NFqE;Z27AXTzI3Je(0t=yda#6$2BG($Hb=NO$KVIK%U= z$q1fnWk!Z8(o&_P@DfoDqIj2%?>1#0BG{Z#;z^CgL= z*w$p1H-}Yw+b2wI-iQ%}L-U7>$tfxuTr#rk|MCEW2ibPC`iB3Ec3=l|@fC?*^BL`m zh^#+=#BXT+=znhg-a$ot<7n0o(d*>*fcJq9fDZxWV<%%|eM{m25)YDih{VGr9wG6l z-})i0tXVzIE@3N(n6YmCzGK68jQ^adan54$5&w`pO5*o{#Bz+kDrfyBfL!&+CAI!4 z%#24eLe|MF-Zk^*!_ILMy(9`e3QhngNfb$xc@$LZgQ&>}WhejYZ}?~3{7IVmi^#ej zzoLk)tP{rk1&!hqkWUK7v)T5gL;@z@0umJxRT6#tX>FhmcnY=;KkkR~!SNB^{LOW%3+meIfM zMQ}6N_N6pI*{k#(*KA+Pm72GBQuh|o>#%+3^I+Q-+~e1w8eAZ4#H6&qPD>JhB=IMV zn3Pr#k(VZrc$((7{>QwLf}D_)C~g3%IR)YC6v*flsOJ=@=M<>tlukfr65%)gOyVyj z{z~F+B>qm~A6z0DMOoE@FH#KkoWkn4Es1|>GaeEW7fGsD<7PZk5)Ix+F_RP#z#A#> zpaXcLf*@0h1D%UtwLS=(*m02*Ns@^NK{}8@(gh^du6Ei;$wB21%iORQIZ3%4oIw&& zCAIkb-@P9(co6qTH3eJ^6GR@64-6ow4oP)Mx`;o8h)x-ZTkSKFE+*-c^MW=w+|CqG z9F77$nLf}my@_k>EA1csV_hR#ia{G}0k}+QxH6p%d|KzTwrTG@)zf?AvP-rVg`tg+ zD0`35;~Zp48O^jIU0Okpe~co2mK$dbyyVRgJ%Iynf`3d-B&h)hnI>*W!GIZ$l&OKm zgRkWboYO26DWCe2GMl8vA!<1V@#~cN`k|(jc_dxF0v|j~(iN3b%PEU-G{>ts{*>|v zfERxk);C)%_Rke<%iG)|2WaBF8|dg{VRA~@U}vdt5cw^Q??qz z!#^RGvW=vcp~GVb4rNJ5fo}?Rict8iI>;>?nwBZ5O%fsVFk~))wr)uC#4g8-NA4uDX90s>B zguT=mvEen`O5S(+}nsO3f{^T!s3OhfN1T)fw z3!c{ICZ(?DGB=rm`G8c-6JQaDiGdVM3?LY2O05M%0`Lq{AxgTD)SaXrB=sbz7fHQI zx&KcQ(@O)0<3rH)%+E#nUN?H zIfox{)DmTA)08moW@=0HD)%xEpVaGtRwTud6wkYD0Q7bON!mh-)tX?J3Lhf16E_TL zmkMVh70yH|s3wslGf5Wy6ao2E_#G_xl1NHE9|T`&Pn)Nq6?2pbNfKz6M+-CR`cX+-E`aM^am^ZFa?NeMhKxyLhmlm>Q3=X8jsz5<8V& zV@^`4F8Ctv&48b{{>h5`#8fM)L8^f*EP!cIG`iMb5J~fjhJ4p^6 zG1)qAIM0PQQtv=T1>69$KtJG4AQ$Kl0FvP0xJgPU3BHYoB%DSTmncM0KW_}y z{%=aX3tNojY@Ii5W8N50^LPU>dM%kLbreZCfxIy$kT(qe_}iR@)bZ%(iF}RtsuM7Q zq}xgA!@HA!$t3k9sb96bo2d_?a`r9IuzoMh)b52lj6vMK1oy(Dt1G-0=A#;p(rfI4 ze3?{)?Nb+$bSFu z(6>n%QYp_O6%Iryx6Y1dDm;l)gwRtz1mHTP!gWafn53a36_Zp#(lC;SlT^xwBF`lC z6Z~YJ`m2TiBYw`F#R!r{V&Jl4@!bD{W088;xZI=JfE9g;pmPwk_ zW9TAez34RK#SW?id6hBEK=`K0B#kC%F4IilERg<&du|{vZ$LQ@Hh9DwM@*dL;nqlQfKAh{08(aBSs6nRr$P{0F%Yb^NV<=t zu_WD3(m0YHAZa{Fgc4R0iWvcd2l3>7iB}eP^Kr51_k~E74LA7dNYkO3FGdB!- zV?~tRdLsb8dm2g8NqUe!g(|jo#2A4Unn4nb-M{~kiM1O}85YHg4De7Zv_*)Dx_P+m zu~)Yg-FfNzcMa98kQI7aE7Ln%nUzz%+uG!EbFEk7Z(8`tWt~=rS|Mu;+KcC|g4wxn z2X^8#yFXjELbb#rpwH=jDzf|5WR%1$_m?rVrfSCQp(4TUEc|gwgpnH4JTF z9>B^I1ll!vT$|LER)IO5hyZ2adKWQigywVw$pkAxq}Ek>HJS#tKBLjb>I!J1oCdZU zq4>xPchf^BLW1Jf7tz8?Xo01xKPYb9NYa`R>1u^SwsPhQ2gR+gkn{p?UnOa6rKGDB zBH6l|i$jlEw*$b``c>{9&o07Z&9OxWTl7TE-F2Y++ z;h>>~#bwr^!-nKG=vO{c9^I?z)l?}2t*25A=-KP+YnNKTMHd~??+%mo0CwQ!VLZOZ zM0gm0Xx~cGXH0~d<$pkzE*1Bhqj2cZl2L{KPtF?-g%xh6P7VTgM3OKM#p_;LW!#3i zx3<%i-v3zqTamA0{e>G~n~Zq76=8NOQtquk0jGg8z|SP@APHXT8zf_Hug$FO!8+PK7RL&HH0-lKkv@Hx*4}| z_7Ine4p%0!>ucBER4d*&XKdaTpRBPX2`V@OZtI4!9C_ES5!?=>W=s1uGaliN)XaF3 zhblJXwpdh?pjV@raU0$$5>3*lx*11Ra3WAq1qoNS6jZ}EqINc^*s+oX6TwSg+S2q0 z_?PDr0k@^2qT9Ivuz(Hmb{oR%woD)k$Oe#fW4n!{uSoiuq;E+2mZSqDfp!mZi9RT5 z@P-YE>-fLPmWwTTWBZFiG&B#<|XgLtEYge%)fbm~2PjrgjM z0!EYc9ZBEw?ik=+l8%w2MUJX9XkdE)m207QCW!F>0q`}vBnc#m{3#;vw#hneNF>SU z1#QekUoi!+R}w-SmnBaf-|x<((~G)gf77t}&V2@LJYz7)mjb$2b95>Ye z-=(;fQ~$Q7{R8hAlA!+o9|@uIEk4IBJ{b{FyB2=zSm1uDCDN2WG^KCg!1o8|tzeK> zLmU&^M*Mgr^aMC2Hb~*0LL3tt5_@b$Vvou88cF<=gbjk~Or;zX+fEz}=R$K#Y;Rx( z&WH_hdfRT`Edb$ph^1dh`jw>LNcx?mKj4_ykkn&?Gh%xWqXdqL4WW1&4CtREUqEti zc1+}3NWS&I@0i$lwg7=mlkE%OOW-TuYmy^Ku0?Vr$)^8jL#xKQJp~0lyPoxx4Ynib z{O@&I(67jM+Lho%LT$$YFUhq@#v4U~Cnt2js^SJP9cJ_S8&I&Ll3a)6y4=8V%|DSZ zIv4-M1~kH(3Dp^Cy-=2ue6(wX84l5McB z>kRq2s<|g=X{g5OKN~xC93;0S`Fb8PF3mlWTb+x0k_Im%jr|IyjWoC;X>doZgr~sC+6n%mgtB zm<&uIIf`VA$K68+6MpbDqlZ@ol|3{uqkf)cn1wZ>W^g;Q|pR}zc$Ax$)Y1?t=PW@0* z8i+cc`|k~s6DsAUq`?tM`+$qX^+>~fNZK9%E=U?&kTj$PrM*vbBFScwEhHzAoJ?{G zANnEik#=DqOXP}*q<$qtg8 z+<;G;!k1m=GKHV^BP#lx8(=F5rJV+Wod$uO27#US3jl$g_8ZA=lG91fAlXB5CdpYO zXLAWX;ICOndo5H0D`_`j3v-&I1@YwD*-94FxFDXrzA?h=@I!73ARl`p{;Klg+I|%} z^;%;P*ssRUH6-^Txi1ERy&2G)Wat>}ec{y_#Iv_T%>1z@pc;!&4O>aO zS+kObRjkH_k`BEZlO0Oi4i*|j@?ah@PMtOoRs81(gLZ`Z?RRhkAOSm+wjBc74uNfl zz_vqR+xq~0NxqBZyGb5G@=%hCNrqw^#wA#nx7J{?_cylr*kWuA*J)z})5f@(M;k-^ zw1M6#4Wy0XRiur3(9!pyQ(0Wwp|tJyl3YgeNZuU_+)wf-lJ8;TRIO_?*e9TJ1oriY zF$utqCZ7JSVmga`2CA9E)iBS@1ZDxVNghKoe#w3O=|cc(;m=4OOEO}||9;+~-AD$q zhfN0RKA_QMTQ9Oc`}~xamuI%?joCrg==LS}nao&^hhv|63w@1mvLwCpRK~**kB-Z~ zI}H0QM_EMC{}R{sCp6l4paR+`C$8I3g@GJouA(85}@z|vLdP1C-G9<{F{c|wSE zwQs;T(AQe#kNqW*C-R}t*^??IUF{Ib_8nXtder_Z@EWic*ajdi$iAKA$s|u9c`C`% zNS;pegM8>t;0<6G`mh$ZyMebzomShwZ4*JWx1t=BZid}7mUa(@e~fh)6*rT6(p<_h2{|9X>3P! znj2Li-6s!E(0WGa4I3~xuc+8MG;dI0@7{R@1;)391*v((1w#r;|9@Z2&;A8E^aqJC5PqxOH3{WP{P zm5=GB@^Lnmt7@F7bVM4a(qSTbNr0(z)DAM0wM)=r`U9r5ehiadl3m!G&n6n6Ndw( zzzC8zll%(FTS!JiLT-bh0cN*nn50o_aamz$ao&(zXI@#+sKVru(xG`}#*ROk)^m5! zFg|V&%;wqGqj)KdasF$eh;j+Of3@l;EXym%E6WRP-cgWPRGe2j#(x65&5erc+`^x? z>j_tvy=1h#a8%(Cdr|T5T>nl|@yMZtr7Q|^b2Cd4N=x&`+-js3=jNL8ic5-Pa~nKR zzMI1Jl2Ia~a3E`xqLSj=jFH7;Ebnh;hIJBqNZE?BU=Wc>=!lJ423% z*qKD~Hj+7g*D*zVLzKMzT;34nfM?|37(eR^2V5k_Y+w!m=g2V^m;m2dFn~THc`wNy^QV|&aO}}V%080e*PaI=1%8qy zIQE7U94*A5RMO7A_vPs0GxyE-vx6a0_8VnB30J0XyQj}gUuc`Pt^dyBbsro3TNsh@ zIr>5KJRm1Hfamy9Qx~5a>cSLWHoDm0{5yx@h2LR^#E0W|K&McULxYcWY2ijq?J7G@KWb9GJW7tgFk2%94f?TG@%I0*y4B4Y1RY zMzr1>Py&YDl6>bHBX!@t8PnR-P<_q($PszF8$Uuumt zoV_&G@aOLST{Y!=5@)>MS`C9R4e&{v7GvO5a&p{>bUAIF-Jw?%q-dNjoNPKymR%G7 zLx9cc^k>6E9IIv;e|NiUTCg~6Yhu;?uauN=nugE zaORVIhUA|~{)OaUN&b!G-{G1#3jnwy&VlGnxF*iQ_(7P({)3cSq@;5wP{C?M|9#KI zS;|+6`CtT4M)IGeATc7hL67nxyYtv?J;r(p%gTz12aU)sDjeN$MBb=E{|8tBulz!F zcLtU0K6Y4MX<1R;kQRBvh7B3hVjzNs1BR507+G4_qE&Q@qT&|*inN;ZOA5wx9E7&u zzJyzwF?cME!Fg-4nn?v3+xQ_$r2bp@Q>bevo+faPC&ffcGg5l6ObS?yFRCZrDB^$p z$K6FkhMd&{2tJ2NsC+6$8H+RLWMB#@7m&gkvd(E*0;^K{ToPEF5aiB<+yIQNa}EGy z?u0UTLYX_~19$?!xqy^9q|_zlB2q3U!-?E12H!edYL`Qo$9sUOjSAa`c}3-F-I-|~uTgy6cPsX0oL{1vZ}e((WBWB5Tjg3qqBoC+%|=BPB(yn? zpc;Q-z4It`z9XeMDaeC0Ige=xtV)Y>NnmwCk~>*sYqSAv?(_lB=1ypH=Lz5>aEg?c zq+Cx*D^gmM(uS0_q_p$XhM~=!tj(D=e#KU!jrPnKH}aouHI6o1+Ux+7hzo>!LjY~K zE)JrNI$xv5^ofJW!Y~sDu7;@Qa=u8o?5;)tSmGv9Zsy%9fF`7LAf;2ad-g79a#wS` zVNH3uIF*}}j>agiy&t1EvS~%5*o9HyYR}bxeq3#Uwm>^lI+GGbN;H3p{CO92GSg2N zQo5cG^y6a94Xy8r4o4-ICiUAj`PSq!o1Tn)Ogu4bx=uf?Zbq4~`Saq<-aqa?-spWU zyy3#sfh&_6fZT9704D&^?s5a^KnCC;oV>ot7 zNl79lnMXkxFp`uMQmoa_8xYwpO>tw`ayqwbti~IuRUE|=QBo7l%n*|R2xk|BvyGHA zQjm;dav_1J%04BmLyD6=43 znT&{4cXztjHS@`CyV^vJ?6@KfZ!AW8kLj0M(;F@%&_i#yE9miZ&b@1eG4kN!v4dCs zD=kXRqXv$z>lspTV`uUU5#aRmzgF=X+qM4$c|ES@arg`PhP`QYUE$mYYeHuc z@qSLD>TolEXPLXS6rxGv6l&7+Vdui=&fU*CedvPE;WB&<{VMBM7wN$!*SEj{QVL0V zAY}T`br@fMhnq*U6GyOfloXhsL0s^A+_{i^gK5ggY$yKF%SK%Y{<}_b18n=@a=74W zxZr8H;Ayyi08RiWNhu=bE>i9$We6!lNhv0!#PBj)KcP75$TPg^SjEHLAj0Hs%-0B4-Q5sqM9K(Kc!62>s+@o}lyYkbA?pCO!9oGU?;Ko34!_RQHCFLGc#*lI^e~QNl+&Ac2 z;XYCzN&fv1hr2UQ8Ct;&Un4Zc(XCs4^j)Xz`CFG>GkcwN(wn+gaCbGzz}E;Zv(a+Z zAI>Mu4cF$qG2-OZc159D!QB(>-J*B6rWM?Hi~w3;oS_veH+|?%KrL+lwegaO9WyBi zpAwIkBrW}4nQ$)Y|86`|;P!9>APqPC4L95jH{1+2+zhuHNCz@VnMlecQYMo!g_NnJ zOe1BwK^kt|%`mxndVt3SuOy_A#)HfkGx^V=nnxN1e$s$7m=Q=CJc&_-h^D&)om%Q2 z1jDd1oRnFl%;rIW=>j*TKvV47i#>9sY6`vBAz^~aN$q)B2>dO1GwLH z)_^(&Yb@4T<8Nmn%efKm<;K8seFWJVIPjh_23{qn58Ybmom~XIsvyV1y%s0C9w%Eq zv(fz`DUXLZ9`21ebd!Fl$^9}ZOHr$PGbzg|<#@Q^W4PfwXpV;)&W0P#h8s^1xVHm4 z0EnmMq^uz22~wUU z2+$@_+>oQsu#XY=7;INw06(g8bg%AtUCy!qzWXzD(3j|F&ED+8&KIbT6r|Le++P7- zld_tWT}(9rOKbkMHfZ@A!=MF89hF#GGkAy{M4Lza=W_@&kl;`<;j%w*M%9?XY zpK&Al=RUy=u>C_WjTC+FFCj zZHQ+#i)Uz}je3Y}6WhO?H7>-KZZZaB`URxC96&?qbqpG+WX@fB{RmTfL%v41>ggc% z^aiAWJ6_@4MnGdywvd9CwpX+LOGg%e`nB9JEM59l0917PHKe>s%4?)-cC8Fg4}_Gt zZtD#P?*G;_Qr;wGH;)*zma40~buOv8=~h&f&JBPB(ro~AbUNg7 zI^=UYzYR! z`F`3MK*~pfv@x)Xv@sMNJ*ENXD%}@T$v`;m+SSs-!@=<((Y@9Kl

    {#zS8#wH^60B7d*<>>jH7iHsFLDCy?jeT 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�=h!BXL}g_%{iSr?E6<+GJn~FqOpdBu*f4A|IU& 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
    LOcgfu1C%_rHbH8^+*cp6v> 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

    l_ya^N8hpD0p8$~c#T?Fg^$|=zcGRB#s_-( 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⋘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

G^=t^kf?LrR!SuaS(Is>O1Y0 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 `G2qQqgTxOwDI}i9J=!Low{BqB&Pot70YoW&vhb z(cCKD55h`%suYtCa9@>VtmOGh-%=4fuJkLup-OtL)SQ;I#tbWsWgEV`N(VT~Db8~R z-%%x*E6H2wMG#g_MXU(F1wd0#b|tBptIYKz%` zjMY3}&0eaRRkhbaSUn1HiBBRD^D*XBy%uh#dLx=+C)MSx?)}y6rg~50tv(pvc=e5# zVfC%ZTwUhs`;oi4+SN~RiZhtcPbtWY9sH#KpJw2hpKb@?&+hx@%*gSxef?aBB2+@A zpBvB^`}z3~TG5wbjAjD%^z%IQ|MODR|M_VU*3f4S^Qw`SjJT5;Un5J6f~ZrY7~WmO z4r**d{u&o}%(Ec;B{s>B@fXkkQkc?|#a;hWgPPRlH(Jt%p^U&i{W1+b|1z7onBgx+ zgRrK%sp)QN#vvg|NX|#3BNLyKoobk0&0kTgrdl=4re;&zS50+mw#D9Rc3>ncI1_}w zs`G1lN??|L?=k#!7IycmS^avJOI*R+YQ-WxGS!l)mi}vfKuW&iTMAH=GE|@{)#=D6 z7PA32Qfn9Pqn0eSE^>{V+z!Ip-d(#G^^xE2J%+VMV7ImBu#!D^zV;0s@`RT`SSK1W zup__s7}iOFxz+gwd#dBTe(y1?V^4J|Q;nZ!NLReS&O(;48hPu;TSwkH>eV^INzMh~ zZ)*IO05|oUZ|662`OU6=`;gT5mVWz$Oni#j{ANeL^}wuu+lSnBWvuH4>&jEt&g%Y4 zPx>(ccUX53OIgk;*07G_T;M9Vc+3ml24TH-u;Y69sY+e+S+5zb=u9{4zMfk3)T(E; z_3WU&zUu3t{%7RFZtIuFz14SH^*vwTH&=fcBN@kZW@3i*=dqS!oX0KIzs>_5;il?8 z55nJLVNSoh!{2}4N2>5MwWvoUn$w#0OlAgV_`6!atM$9v`rXccUxE4jzMhS2#(WyQ zLk8@iK?C~ZnFfb&KMfNhM??E+n1#>Di%bp6Q33mD=w2GSmxlUp*pV)D$LtyoWfWsj zzu_75*~m>cax0C@w9$K{L6$~tqLDg{zQDU1xr;{T*GT?G+d0Kq?(sSZ8_U?(^NsDK zaZYmaEk!6sNlHBB4hcy@a@;@@ z^J`KZwVJ5a#B7?FO%wOkMBOGev9~65_=oXqMxCZ{`4WHM^bZDNcTLTz=@xdf8*^)V z7nz#cP1DDiV^jCiEHNoD!)6)CN)F7TS#Ip6SzEljnVW1j8Mo4GF6Qd@9>Zp8H8bC4 z>NR^5gv~!eU(M~Hx!ld$(2iaV$DK9zeDiJW=McwnSIymZbG1gSmilhl7dPEfu9m})t)(n2&9J2z zwlu?*dohcaX3_E_>bFYCSLCM%B`Je`TglR@F6y*uh-N)Kht6cf9my5JO0xR z{VC6%H+dC=ZQnu9ZDXNtzwsEh)puLFX)9OT2(q=6rEOJeP@6`WMcdZ=iTZ7qbAYp4 z!acUVgMQn|(k?pcw2Omxw{z$1^wduNc9U4j3Vajojv-?^&$o|BB9ig}ACn&QYo7%> zYF`pNYG0lTG)A`e_SD||{H9~rz9)S!hxTJx#(A!wR{MKA<^^wq@ULjZCIRp94Q}eM zf)vJ{{<5dPe&9#!>aS|Jv%hN4o{_9Yoeui%Aa4hM-$A|(y_vyE*0CA4*g@|d%+7B- zh8^zX-^32jF~<(>yW{($Ap`c+(JVXW!u@p2M|Cy_AC)iV`tb}|`UcSQ| zI@O~;LolmO4mZ(N z=C0pRimJ%mwJDv@U)S+?zUykXupRs9dX(dw;T(5^@ZVT`NrXInM`21}H~-4}ue|^M zOf7n0SN{$~-hYQ;F8|8>ue$$EWEyt&?<~~*_gWDC7Z3aYuN-ag%zyg&&&>X_zix7L zi%(*b;I6yL)GZfg*iFCP@*-b1dAj{dUChsKK8AktG4z{{VK+1AruS~^@$PO{xrKY_ z_9O_qyN&K@byurZ7YZ|jzz#=wt z1eto7U$0ZRmtJPj>v<6NjzUc0k(3mq=40%qcTK#zcW2b^-IGD6)q6N2aT~oivX8^4 z)B7y??yc|M`u6*fVQ;f4ZJw4xn<)0H0dMdrTp_8r4kc43ZvW$t@`qsZM?-M;Gfy}~ta1Ytk(>GugG zP^Vu%mf-LE>8rmz^v_8VN>YY$)Z!0h>feU8w5J2+*MA)DrvD5UvJBsN|FxJw|F=On zz`F<7#Q<{~;ARG7=PSM@4>AoX#c#AgodIrgz(44FfW8Ol+wVh$1N1&X?*n8Wn1U?i zLgs;`se%3mcEs}o&2OM*22MrBfpd{@;0k0MxE}Kxcs&RQCFXrTMBYK>HOTu1Wy5R+ zlisL3$XyJ&9fX5@uY+??1^K{zh%U^P|pil^fjU883Jngrnaf5#}_y9F?d} zO@5;Rb~9Su(QWBS7iMEuqus-3c}Fk9Tt>@0TFud0*~K30ZnW8qaTjBWAH6bDHdqQ$PA|071OGVV0pw}85NQ)b{BnqoIoeD_n^YnFWM&HwSV8$~tV81geQJdDtJ44m>DMNY8aCT+f=4?IB z?noDUV}`SbGMptG=K(K+a85u};_)u;q2`?QWTpW6o}=$MRnYgG1~jE5Zeoslb0%__ zCqX#Zt<6nBMm|M6lX>Nkd7jMks-y0_U#LS}>ZA6&$!zCl5YA6XPCPST zU-Qju{vza<@5biu#a++8fK2lr^OWbjM7{;`EU>Eu=C{E77TDK<5a0KLyqLj)4tV#1 zahThJY0PIK%UFR-3w%clE@M{<)LGzrUic0Pu&0F|p!bETaQ6#kUO1c?EJfypyE%jY z7QP9>MV?=jf^>XB7QP}v9=_#!%xO^{1~QD%_|_Lq#cmeKyJ!h3S;uwkYSBI9UGxZZ zStRo!br%Oj$L~D!2OMa&b&G-kImJG%Wm*{uN zNaR~0&yuxl!u*yT;3%gsgQa?3`Vro}v=GH{FH6hgHkPWjRIR1H=cVc`)wkb%440bS zQhh9wd)bHB@3L%|)iSrX%=60{(h@sZ_7`qzSvP!t%la~g@!0LMjcj2jhd9DXPID^= zmz&e_tmGgU>MSonQS4@USt?QuxtDjxu9o*>0D~}><)avjy342F&X&($D_4ThZ$XAD zK0^;HS}}s<9K&s|j6qxykr+3#@+%_9wK6x~ke5oxveFD!n&HY8n8ix7SlJP`v(j!> zdbi(y3|HRZE{}q6mA$M|Yn5875}@9yuW3LpMkDvC)vRMb_POdlp7&di;p$|h#C}(2 zoM>F`qT&vnC(;DTw*3>BvMjb3F*xCd4yq%i+G)+T&U|)=pwN zGg*a9e$z2rE7#h?$hP)44|o}b>jK=(I`doi9v_eby|1f^eXRSNuJpi7u5%yj+{U^o zsI^Y5b%%n`Z$E~9>oHufhxLW2j9XjZkUz1L^`7@TkKy|HEW+LRoyTy!Z_n>MhU>R; z3_DtHR_k8};f5&0#lAM!@rJ~Fj5%$nMLinP96Q<2o=(`!hMx3eFl*R|8E#N(gIXK* zu%9ESyWuovInSFQ+?a~|sI&1uX5;TS+UF)a*kpg3%xY5sic%bN+th%@G{voKl53M0 zY#P8w#xa>WEMyrgP=AxYH`~SLG-SY?Z2p38kY#fb)Y)8;Kd^_*`q?c1=F2?8ZnwlE zIWlhX{FY*r}rdgTkU(Ry=+ZHQc{qb z^kgP0Imks#e#5S|{!T-hA^+A^sJ--OF3S=dVc4Z0A znfLy~K=ikFA)eoBzk82yl5@DFy*IhXgCN}Z4k;)|F-lR6N>s;g_Q|_X-hEAJ$r$Wv zpKoZNy!)nOF8gHOw+MCjtzWYfu|EaZs&;jd2SHx8rUOdf%Z~$b9G{zTg{VJmmR9=5^=~TGO7c{6`OZF%q*n zbQ<6Jp{v~DKJp&&{=)&$k@s*y%;WI4gh+(ovdvK)O6-}OKxsOcONsqV|qF!|FNHNXUAIL8$8w@8IO7X*gDMr*e>>S0=ISS zJn|lUz~dl1Zm-AR$6X&!O(s6Yj*frHcbLy{-^+0`INl3&jt{|Jj*nw9Gnk9q$4_HV z$1h1|%rT0_Eg79=4?D(|zotF7@b!0wmPpAJv#?ziZJ&VOGV>MgY#!hx~3UfMR z-)GX1iOSjLc_bK4WKR?CgxXXWZGD5sboposrpZ zLWXD6Ia`2w`1`Xnv4gW$dB*D?JQsy%nA^Ee$c){bb1UcMI`aCTqt1DII-i5@C`<{|I&VjQ4>CM&59iJ9y!V~I zj-JlH4Z;hFNJTb0f8l#7P??`_M;G*bp#hC(&tTTzo4c@$-5fyP3*LXhH+10&@?N+X zgcp-zeize_7MU-~e9>$!n$1Pu(ZvY4aOW2*(F%LGxQcT@cqs;-QXF|Mb!7;?u}kBa zz(O{$on7qb5JxbxOZIfho-W(d<+$kma#GCkvbvYmz1)<)_y^zf-caj?S~tE!y&DY}%^LP1_l>(e2*R88annw3ro;0$^HGeF zl%Wc~yPIZs^H-YDgMqlEn{MgmB&INv*{s5TZoUb^Ti$;w7ItzgG4kG$_m;f3)Vr01 zY^Za~{BEgpOPyP_aTB-9<(8e@QumhoxYdTXn9VJBamyZVy$ZtHX()nO`aQ?+wjJEw z%n?pyG~K$aY7TJN~`7^EG)X%J-C|JWbK}omnhq1*_S@c6PEG z^S$#p2=7KgoxAaPmya;#yO~hy?&nmb8`JT=yIaxI-P5@5yDx+AUIILS?^ALRArJ28 zo}TX&rzBNr!6?Qvg_+Dl-h1AE&v$fh6Y}13)AycYe)sI^et^vPWxj7V_Yl}xxbDpLHNMmKgdimd}|L{(T>0Q2XlKc37H<)&4U@34?CDu4%3)8>%=uY;8qyduezu((ybQwUu}F!$&*gpo4L{)d=ReYjR{Ti^{-Zng z^}HWrS;l#;aFcsH<^^wq@P)iDb=tUYkPQ|7k#{z`*jnVW4Eu(>h(lC z|9UOk*vUSQ*oAm;UE zG!rnJH?uI0HzzoST5r^Pa~bn_BmbM*Jix8Jc@l(g?dolID$)isc&pd9SAtwYbkdWb za#W%^KhuQ2>B@ifq7VI;&H|RQip}g`FZ+2E)H0HC2?igXwsD>t z+{JCjwx>8z(0`oRs2`^|`ix^aXxs3gYy#QTvdm_fW+ zs1vUd&1sF>j@OBQnTtB{maq)7iDzH&HehG*%qHGWcC(jTL9Y05`GT^vWF(%6e+Dy4 zkODap*i(X>gcL)j1l6g5878PhUH+y!=9j?y5{zOzQ~pQ6eFpwiaB%>?4HB~V-h0pc zv-jS6@4fflduNM~2q7{eNivd|8JWq7BzuK;KF^EKJNKS*zUSQkJ3nL*Yd^PxFt#~k zM<+IBjh!6(j-8GS=?y_7%sz;;cq~apV){1u}^HE*}t+xVVA1`i-mKxEaYtT^i8@{l>Mgxb_uS z&vDg^YiDuoEN(vrAe*?GIg2{+Qcwo}KAxH4eZd}1@f(-0lX&-oFn)lZ;=fN+q9M!p z>2cTb^HK=kPW*DX^Y~RUfBdOOZOMlV-(!lNP56dQ9s1q=Om5c&6aC zlFnlh`b{dkq#HQE2~Km4t6b+ccaUE)`6Mff43d>con*ejWcBdPCv(@y+Txay={wnc zK4l4VNoHTk>?_$C)J^8jl5OT2wxM>iM?sj}Jjp|vq4(sTNxmPMrFaK@q)1E(QekH) z^pv73`btp=y``u|d+aKOU8S(A6r-8IRHox@QvAZ7JVvG|{tLpC_MI{|2}p`sDb-3@ z5t*ixUrIBi+|Ch>VXrCg@-_%lc|KKgGLRX&NmY=-6r%*ysYPe{&>uTaHJ0(%SE^~q zFqMo_UFI6MP$$(xp7AOOQwKyLI{Hp6ztqJkNoi!0S}v)pqHbz?OKoqd8_)=~Q_sab zsW0#*2-E02jc3wyL}qDLppP`)v5VcfX}{GNrn$*&{^lMJf-tSyOlwzZ?JBMO(q<$Z z_LVj->Zk3EInyp+F>WNSeW%@mUef-6I%)Uf-RV*yyL9?b*NmRXE}hKM%|wssJfH4I z4q`XyPH>)!{DFSc$u8ZKAoSagVS4wL-j36!!miT$meS`U5AsVdpY-k~y$sS%MV<7% zq4aJb{bziEn@+z0eW$;~RjwnK^!AnBzS7@E-SqA({R>|5ItVkUogu_L8Ah-iy=U-D z#u&&fV@33lu{mvMhn;2AQ^rZiFr!<^I0OA<)KA9Ee9KPubC~0t#Evq>#k(`*rw~Oc zM+GWVl_vCM6ys4R)5k2vt}@9wlUkY9@oNxfj*1L3nGkZSsmu$j4 zW&RHP&HNJwIK(+*l_eRe$v{@@C5wKucz+i6ouv%2$x;n@WEsLR5v}P!SGr?2+1BIT*-mqg%Ut6=YGqR^+iTRzF3aqVF<17f=sUZtvv0tSXFtjn zJfGd)fgJDiAu&maxpJf+6*+O!e&;dFA+H?u(PIubl|zp?I-$oLJsE*-GRJQA<92c! zM_xJ3^EsiZ=RiK?2YfTRKEN}% zs?eDU=p&bV%jMp3`Mz^~gPw97)9;b3efBdCZ=tIz1SPcjfVpJj>aF9P{WekLUB) zbDkHx3c|eZDX)FyjX@mrnKvy(XiF#bnzs+K%ImiCjz%tdr=r)q^Vr2c7Zr(Fo;1YJ1SM7YsC_yX6u@=wdGgtnYWJMqOOHz&sG(=DNyP~iBz0h0!eoV)= zmH$(gv4#zpKmS(FVK)V0A+G{y$cS&JKw*ke8np_jRlpq=)^{yLP<$Q zda{s{eCWH7{0ggiBEwmQy%gEVR(9|sKcU|u`Ym!A_f+&9q7n`L7In8pL`f(Q&9#^e_*Cu$X`E_Z-7wb?C_`#xsR!EMWtBDz=$#*oG{No#X;nxWPX> z;yM2YVeu41@b2PnvUoe(N%0;GMXlm$6`zE9#kU~866PwA7=4$p+Y&{nN+Y`B`4SV6 ze~Ec~!snQ)#Fwn)J9Z+!67nixza{io!abGHV~Ho|vBaw&EEyg5UD94k)}{eXkypv~ zbU`*H`!SditmZ3ZQ&Ki1WmEE7?5w1^C3mrp{Tx8;Qf{JDW-8O2Ie4bjS)K-A>3Ha) zwC}8RPI6NUJ(aFULz>VWd6pi;XeKa~xh!NU%TT}cADFX@Ov}U|4heA=W%N=e2kMl` zi+7i?^D^tvf0-lvj_k_FtjyaWEUU+|o-dmVyD4ioWlK_tDpaQ?Ef~ls#$v~1XJO{D z^RctCGAz3rJ1KjQ$GpHdSngduASQ81gqto`4*8X3L!gkz1 zCHYml%^mbyNzavJQ%T>I)b{(3VWqc0Sos~~Q@J>;vH!~Eulx(1sS*b_SEU;IsA5-D zI?|aT=&8zdK4unXuA;vx`l%wfD!#8Od$6l2$N81BJPyLDiSX{KA@)&KZdKh&RrgZ0 z7In~5)piVL3hGpyi*KjuD%Pu8 zw^Z#Ir#Zt7Q?`RCD>i{ z&r!Sj8G5Rj3$xZNKw%=tt!7hNVeXne z=*uANtmXoCV9uJCxQbb8{=)+v@gxXqy+;bNqE4;+*j26aR6(}2)T&jF;e5>rysy^1 zAgpbs+V7K)bjYr@=WExd3C*#a+Fdbo?Oya@G>fp4+6VcCQ~ZX0YkPlf_g(vM^jrIB z5Y}vsaH&iDxdak4AIvMXV|9vScXgUE6nm(%hnqoIHwL+>fqv@RU)@hx z#!6PRokJW!Uv=%L?nz`>*PiO?rS41K24Ova8|r;TJQARnda|nL-SymJy}^uNB9n0| z^=7byZJ58F`Rl1u&;0eSU{Ce_Lall-uAi97biq9J-Ccb>*I$Z#)Zd97>wCVwyy`#U zIj@7TK@{9mgXqL0IkIYCFAeOaK}WjL8~rx${syBMk8B!zj653rz>mnWfu0-axq*Bd zxP=DlHn6t_=efv>AZ)1ThDA}Qpxa&!>FB8aA*IyJ_T38hdx+L?kB-8OeuQjn!&g67?F(vhiZf)%Y0tZY=A@ z4}-9YZ?H*h+;bDpHz`3ys!)?gxa}q_X-zNsVz*7^@d-;<#h0w-Yjz>0rU6lijyg>f zkd#!o@1|MEiN2dQr4@G7v>hFgOVb{x+q4e@ac513qIT17F^}JW44b7z@69~ZYzi`K z_A~luc8RN8$IUd?Q}bx(tNBOht$AFs;qOB8km6LJDz&IXPiC`@Z&1JaPWE$-~bo6j6Jn@6@)Eg;rW*OYpK7M zg(yln%-pgH)o4mT?4;##R`V5`*v9wlM!zi&bDS5*ujShyZ1oQBA)8h)kWDMuw6eEW zZmm@k3Q~_jEW)l^`HowArgdgy*19eFXl+-1t1)anidpEX^-A>BT3@XA>%ZN^|fZRFSHO%S%#f7=w~CLd+7 z&$fDO>-n}Lk$>B%%w!>-vJCyUm0jC!u-CR{InVFh;xFu|?E~c3PCo5QBZGETQKwyf zd_(Q*xt+Ui*O?yZyWL_wX9aR;Czp0|Y4G5Vki@`x3N4@9jO) z{s=Pb@B#Yhkdky{z|K18sY7L|Q4{yv!5%wwX8=QyUx&%eU=H)x%o)tt;W;lcYe)O; z7#%m#QN|rpQ5ZMbQJs!8s7ou_(*?CU_T&=|^Ea=9u+xW_sZ(n5P#oEH@_eUm^k)!u z+-U-4?qpw`rn8u>*h#1B+~yx1q2Es4-`QPvj!F#T5J7&OOHl?rch+-f*>tXrx}6(g zZ=IVl7(I91i8@{0B@6z2m#$2~?z(K}2lnz4a_jOZdg^kAyU4N2gCOi`=C1KbObRlR zjoi5PuJY^J8}IIF7hUJ$F1vogD%PHZa)*v1uZAe-*8>8|JQdhTv#-JkORy03W?ggpXMQVh4$V+`i+aTGcBj7=`8 z(u~%0pcD4ia|&kdsjr?hnax~e*HbS&zsKx74{?ms*jvvRLD(xH-rcJxr6^Ao8lqM& zwR*KfyShJS;wZ*ofFTkh+bzF%?xd+e)^zWy%seH(=R-oah>(^J1pWJiYm@}ReVa_Co` z2DqDkt>{b-`qCde>bI3+{DxWkxtV^q`3JYs&yDt%asT&7K~~i1pPvxB>M!g5HK{{A zfbK{!Ca1KuYg=_rWj2h_&*KcG2n=t_6`U}poyvY7oG<~YA{9^cS_>*#lY zeg{0_c@PdvLq^=gK>ZGs%|N*f)bqeXs5`JYavo@R16!cyfuFOFTR}MJBYb;Y=_jteuqq84y(}b5d98uOG7T;`6176OGDq~ z1L6>m#3UsP@)_C%84T^mVBGdldl@|_cxITn{ElNd-0p_!W4Lc@cvY%nXT$Y0ybl8zf((a`W)Ulp z+wk>l<9l|qmn%UyLfsL*wGkO`BO`L)CP%o95k)A5S|i%gn*j`E6lNY_<`HHdq1Fg< zk1+R$=Rr8qen)!W$U;=68qJa6$l-W?x4|~5N$LMK{p2pbUnDk_#B$cqEF?DE4E81hfW2Ug0-TcBSe#2di z(aV^7JmwiMf^e*NkFAT_^Ba%hSh+CAkK@{)$8nt*#4PM%+>iXkA>8!1)11RMG|ryJ-QsQ#j<=`rG8vzORHPvz zS;&sMAFoZx$# zptlKnneYHvOn4cD6W=2mA0dy4?tG%TCw9V(OdNonPaK1MCr)HCpRkEts59{(_BHVW zSGa*%6aNarN%1I0d%SPbSj;qOA?|yUTbgtj&rkZ3`#j=#5Kay-^W-ReKq7L}2;a@* zHgu#L`kn0klYNJiN1@-z?rHKC z*u#_t3}G2|Jmq>2PSwv;cRe)^1t~%?s?&nj*v(XZP3?l-rs`$t4CWxash_iob*#ty zQ~wFVX;HC1|MPOnR=ONpEJ!qvkVofMh)~b({5&Z_sor`KhwR;+{4ef?V0v7Q%^H5 z@iYi$nSYi#v&=us{IgP#o-AZ1CvIn!o@cFL2M5setjpZPe6wTW`PuTCou5J!#rHD1 z0#&i6+0E$BQtV~+m#k+qzMt7U(eG^i&OX8k{^d;&&I!=(ocEE-96irbcTOA<;?CwI zMeRBD8O*2r$ju;}>zTRcnk%!p?s~31<_=*bqj58H^)z=SGMsDPx$Ds1T>Z>Fj=PyF zzq!}A#a(1D&+PMZ;obAxwBL3N=lO=_wZ(1BQ)`}D^W644_2!v-o($*7ZoWC@>wA6< z?00@CWHrAPo}WLA@z}xq>A0==zPK(5}$&| z;1jccBGXUyqMuLfabau{VCIF%G55man0sMa^tG@udRwTMh281HKt>^pg;SV@9W6Y{ zP3&ReL!R+A2p7FWRHETF7Ue;mMP;z3Mb*&bB70gS=S3ap#4Pq9yG3&Q^j#8?gsix) zPxbey=Ra*v4|+2I^L{#-3E0=C^80in=lPxM+~yx1@toH|xLB`?^}09)zVF2milX1e zB`JrV7puEiE{pAKaUI;+Vzn2~@&}Q_AR@ygU=3flGB*&vvb@E!es#;5|g+jBL%5ROCDsk z%-t*-$S~|>nY}EVioBN1V-d1h_671-c8Xt7YnfWhE+e01`d{Y8mfhhlZtZis`aByo z=!FbEH|ysz{rtZmT&|zx_PD$XH8Hc_ZVZ>3d-))Sps(d47=+Y~wq==PZk0W* z(#I;dyy_qB2jS`fJ+1clX|-EioftE(*57LVtd`sAGE}4%^=U#g2D2FNUcC$TSIcen zanxGT-+`-xv96+|~WV$X7`dMd>>xSc&*G*(Hi*PIJ-1EAP$Z*}a z=xv=|)?LJ1uan)ndpyQHu6r4TUzz`_BGknmzG_W7y3>n3^kXdc^Of)BD|Now!gluK zCcm<$uhjbLSN;pa^|`5q_pNt#>&>)&9P?O?9@l$*{YfrxnQQ!wnb$wyQ4nr;hh&tc z64j|gL-f1B`!{r;EBf8gpQXregI#S{jh;8?dBZ03y+Q2_JJ^ZcZII7~mqGY-DoSDg zuczRduYcig5N@=;jr!PVR~s{siNfeM4`8O^={f)n2 z&W-Zg^e*mXQ%rm_oAk0NJ?d=Af_HDSgH2zc|4n;2!#V!qSrBg4<7Urq&PXou;yc*v zrZ<#>47=HE-p$jP#T=INJvZ?F&G&fB3-r51zgzUXMZGO?anD=S z*-{R5wy3kE3T}3beQl|ax?AjQOAA^dn=Omk&9xx>CMr3oh5Wvm!8+{en?3x@LC$jr zck<1B+=<_748M`V*4QK=CF#gc9tu*JCJbaIOEBkFH?s9Bd@ozw!`6MMwNdKwxAbimvXPVA zlt513j$%Ca^6kgWWg$yh!I!LOGw%1>KTzviwZ2vB+rP21Zyz9^Z=drouYz#9e6|;+ zDR$s@9mDMh@XUA7$w~$E@tu8r*P6EULr>pLLSNraM{nP`neW!(+xl)hKOn#Fj&Oog zn0-e)>|;kramr8;-^`B2xQiWX?NDpSH0)xB40o7e$A3ZieH`MGfxOts_n!aWEq&ja z9`t4iBN@$DW;2fse2Z`I`ya92?+6gIo$}i` zhH*?lHaq3Ab0+HUw6~r1w)0b#p!Ux5nCA!k|Dh~;|G_gqxS=0p_QP%T@xz-S-1Qz& zNQ9ntWg{nf$WK9PU{|~BYM1$SQWK?ti@o~ag@v4!AyR~G29)ORLE|(=XY190gbWa-5oLW?r!v8 zIPLAd{Y%)I|YVj#o)`EfV<-Oc_Ebfp*l8Nx`$F_{_oe)h|6 z|1Q+puhxFq?3c~{quAU2)12WqY@XXJD2H}Ayq(dJE?CL;qO5(;2 z=;=T^I?{#ixa$MvKQIfsI$&1^WOrZ<8`y~Y2Ob3BL318VL~>+$FeCZU%fTY3bFeht zeQ+xBJE;GI7rDp7AUyOgvC-op&mXdrLlvn)O&ZaZ7PLZthxB(ye~0F>kmao8OV;uo z?&r{}AUqr(gTv8L=Wqg&k_vZyI14#xfI5ep(-PSnwy(pTabJgf&=-3P)H|K$e%pvPaH z@+Jt6$?ur_j(vb#ACuiNJ3dwvyE)41o$9C`|KXHg-$mf{8 zkIUq^OpZsxu8zk(}S|`;yIUe;+ zn){?(oO%y)oYMEH0@&}VO33O|Cp>>@9MhT2JeFdvQ|{>0YPNA4S)IDbANR_}B#`lHTibxx~uTAkBt*nnJ4e}lTGzvl<+ z?zC)9zY4-%?cvwbv}Y=^{8fIx+JWC^49_Gd4H?NyNM+p08Tp;j*BSGl(c2lloN?D@ zMlhCX%wj&Dp#B+ipLxieAUyjX?&R!8nD?w+&SpTJvsv-(v+_J^rnCA#yN|P+$4<{a z55nK{_?zc{%S3MSVK2Xx!uRr9c`DL?o(y6rqnM1Df1ANfK4Uvq`4c<&%}#!M%1hn` z;kozukXZQE&lN*{=gOkiIknEo=A3NK)yB7Ut`SYJyL0k6_X#`sJqXXgOBOtH-agMy zVKw?VZ&&B{@)Kv!)A`$&{rp|-p}!0Ixe$-Uq`_)u{=DwJc5}4znzAwt|Vjt}FqO2~i!1EV>dQNF6(idzq{?< z<@fs`j&T}0`~6W6UP*{Kuei%A#W3rYN>rsfGQQG+fs8|)D>InGGFGw{wXS^4xgh)_ zI@$5QKPqFUKU&g@;mGa}&;RiiTiK2s|M4?s{^JP0aEYfuc-2m>rY8$I$%lTgdjD1T zeYFDmy;=)5d{ur|M==IHU)A$f*<984Rkg3q!>wIihIb?t2sUVn#p=;?YU^mX05*Y)Oi8pG?AsEzOXdQy{Eat3c=H2d5}PEL>t;$) zlM8orQ&u5`CC47e5ZtdY`^mI#4 zx6FU*B)_7!TMw|$Te7(AowsFiJ1&Wk$89~_Huvq`3}GZ{-JXhkZ=3!0Y(8fP2RMov zx9#ipb#C(yYTdT8zs&ttb$Z}^e@#Qbe=TPVzQ4at&==aV<)VVW@`TWRF$mWi0?i@xockJwrZ0@Li=OVJca|Ji{ zx4!-UWB9il_ z6WiF%8D0e8Kj!==8L2VrKfa%Ta*>C8l%@$CQRkoD3}7sin2uWi%;tOS;-38OdEdPp znCV^_>e33?-ShmtkNJd8S;iX7d~X9A`H^!$c>f)u5`#D-M8EgF|GvAvpB4Sy&yR2O zzWnaD#ogZ5^L;(vm(6{B-&gzoAcimu`P|=*Z|J`LKQRA;N_ghMRMv6;eLS$M2iLg4 z(;$4Pr-vUBli0+=xA!n7g|MrKcJ;6_H8B6f`q>hjmv7J0FNJw!iVCKhF zsZKNc<8B_io5x?Wp3Ug@vG+gTgWG<5gcJD2AItAaz`N-AiJqUx=83+asQn}%iAjol zp44YB_W#8EPi_X`Q_nojg4=%D4t+eetEVFwjT?Kar>CpX*HiO8)!WmrImk)QauIua z`WN?*!85Zz%R^-v(3DoVlV^7FY#_r>>zP{5?EaYypULjI8J;I67kP2d&uh{K&p#i* zMC{=C$9%#fKI3yXa)?u$;R4q&^Yc60Aa6d2XCGMV_2xc$d-FI5-^RqQ z-rCh$yLy|2oS6S@0UFYe>B#HtXMBNuzum_7>_)A(YQ4P|M1nMwrVcIXLw_bPhgGa$ zFGo1WX)f_QSGmrkAo5NO5|Ee_WF#}$$U#x+F`O|>WE!)W&!;S7C2RSbb6n;MYQ3Y@ zJGc3p2mHV8bN=O35P3HVg=va9?|#k!{QLK!la&fIq#3PgOFzb=r}ri^mFaxUmuzAi z-}4iPki~l^_$P?G9|!M#KOY4tLRrdFg=*;O{T2*l9O}G313ABM?)T08zPaCDkJ;Zh zdlWrK$xbmUqvt606r~sDi!u|>N0DC?&qUdd9;56=k5P`G$0(NA3|$R?_6qUt%So}=1XRCS}yV-bs4irP^x@Fs|S;I=*}M;AQv zfw?|7%3tW?gSSB>+WSN$F?x!Y4Yv|47kSWMH2p+#H_;j+zi1ulMsNBegJ@gu?r3LF zKbo6~_9uU1Khf@^rw`vD8JSV%!@Ly2u0E_pb*bqrXdh%ojaB zo{wIWM%Z!mR&=H-z39Ve7O{_m{K6@I;}UigUBA)w8~p)KgGh{2*j0>-=r=}IupdDvBKwPM>XDMfjzP>tsFpf~-{SKJ}!Ev{bTE@cH@vWabc&ktO{-0>2Tnhazn z4{kGFK?+lWmUKg%cmo)Utm92*HfqINz-}G|k@)fPzW8}DQ~Zj!@%Zf-gy-YWWeLkz z$p*|Ee+ygriOWGGK~!Q8hlC_UzX`lQfxAwS3;iZ=(+OH5zXW!bpbL6Vpyvd#Ng$g9 zgBign#_$<#BY{06e4i}Tz>X8nLO%)JcEaDe&Ta1SDu^VCiF;0DH;MF>C<%H?q?bg+ zaG!}}m#8N7XiQVgpXgJ*!5$LHEYW_Bae~vF;Rg1TI6CSiPC!yJk)1rKmAD`+n8_yg zavU=yzR9y7lH@(?If>_!5z4bkjgZmGoDW|o*B$yKJF^T=g2U{DzuS&H&hp(bu8Wn)^dw6m1zrrg0!c5#uH zK_pcw)JfHjDfsuP+<7WHNc|zQN}ZYvWI}GKD^VT!rLIpSnjp*60~pCTCNrA_EM_U+ z^E=OjNSc86h(=uElLR%>WF-gYPg946xRW%#>oh&+%OKomn&Fr?%{l%JB59+Om~7;v z1XXE)=hK=st!L6sK#yr>pvSasDy<&V$}z2*N_&upJmXamNvGd*QSknBvGEBfhh(Rp;?aq*gf)t@Fc9y};GStMqWcZjb*@_w&e&i=ka+Zty&L2S}qjzW2 zS4OjB)O*GuOlKx;JENP)xChT?yv(2c%{`v;8og$cU#8f^!>pNdQ5ZdDDv2I5RY8xL z+OHS-GOJ~fSWhCR6zyjo#Wjz~_W0oE4WEb|7 z^+m7QCbI|`X47Lf&u6paY*)C(EgtZQr#ufL*`tygJIP+1Iy9si`pxeB*}KvU{rdgK zNcI)TB>P(ID!ZPu>p8o9W!HChwX^?-Tgko;`DA|^L~{6ca`?`3m_NtIcqYdwd=okC zA*ViaW*{rsDTbbM)}k&AXiQW3F`O|>WG3@4f6m3IpYsyt%q6c}9}ttcxQASN$(03l za@l__@6Kfhxz?cnTnD(oW$y7Rh~(B|ZqMh=Mt(xvRqk?Bq%u`$LSKe461S9lI%dv2 zo4Lp^_fFhRZg-RWK2P|UH$f!Ndqm?S;*pqA$S;ptdDP0IRvy{pkxd@=l}Ft?EwQ&e zZ5hR9>_eTrACepYK5rjpVRw0DmG>tOaRj;L{RchewVS+;kz-!>k}nQPkzu~{CoaD42ea6yVtoC;K>IyGs5`zSnw ziA=+;3eU%`3fom-Sr^{OW-bPi@FV0G$}X%%OZ4ow93!C{^Bg`JfAkrSNZ9P%sq2Qn;aPo>OU>O*3Ym=xG;DgBjFx0Jf2hT%3!&A>gD`h=DE z+fmA0mXc$sZ}9HYvB`sbD_w)uv_n><^7*O6Q4zk*1a zcZq=>%fv^IWm2KXGWJxa0QOtP&6F96-If{86x?Q+xh!NUEBKO=oJA&O+*KL7^4pJ* zGB>!z|Lfkv&io!^q^!Bh=AsV$Fhkj0$g$izq`}V0nYmnD8qtKV$gkW;%wJAlW-71$ z^3Q@ug%62IO59onJy!611>anSHngV;eX*koL(p%9sm#DF`7Ostg)MAn5BqR~6%KPA z`BY4f3@TWeP?k#QyW#-ssp4?tQgJjBn2fp=r!yOSt2iIEE1tqUm6A{l zy;t%~rIpC6lHFC(N2TYy=1mZ(Y-g4AR5?AF$Vv|Ev2sOfQ6KqLZc8V+(-ZY8e~mdS zpWy;ma37T)qL<3AP^U_OcUNhO?5gO$$|BYyyDBoPatu9I@qCs4f=Jb<*iF?~`0lDE zB^COuD!Z!rs7gKTxN0-(s%l5N(F6Hal}}Z7Q&k3451~%g)3|}EmvNs}-E-Bu=(}1n zQj-?BRI{&Y_Ejw>>iXTsNVP(Q6hZB3129juo%|6*s_VVFXR235X4S`|kLsVYjOEx_ zbv;!-fIF%F3n#G0>VNZuf018}4{)P3;u4=c)Ww`N++>YGn6-v|*O<&SX0U{9?8BaF zs8PfFYuHl_bJs9;4RhDH7es2t#!NN4;Pz@xLccYaV$U_rR`WQXuc<%3-x#UsmTJBZ zBDJCrjTn4H3JTH!cT-CSwYt-Xfed3b`mHsUnS94CcC#1R)UvNyM^U%dNzP(#wJxA` z?L^o??PiQ(6|$`TR}iVApE`C|rw~OcMH%E)ryU*Xj123zl{&qUU7gu1U@QjC%`qCGOL+mn8nyRNzGn!BzY)irxvv)BDQh}4To zO0rQLJ=d#^9P9PQ^Yx}PpM}^>z16H?0~>Mc^<-549ikG0I3y$)Zo9sI>t`hw`H^4! z*4R~j{nnRFeYw=vbA5H|_hk@67>3&Qw{wX%L8L)CD&d(1=4v3b1_#hbgUh(J1~+&b zL>lU;;fLs}VJ!64Fdo?{K!g%hq#EXLXlD%vFo&;@SHoSn>xKt8gPUmRt{bY=P_0Jp zu#p`!YK0jZjbIjYvDZeM*^lQNUF8nk)!Z!2_1-)qA#!VOr_CGF4bL~9guOJM&q9{78of4` zU-KROfLWWL=Nfu!eg{1^cT>&v*j$b+VvvFA)S)5GaN8|9(3M{FX9y$tlJ$IzTv}{l zJKv*j3p;CJXDxolt+Y_P<@;oz3O#UBEj`onH=YHNR`JnCD?4eGi#(J@Pp#^suU1Xa zTdNif#I9P6X9{!pge82&POk7Gh_rr(sC-B~5|Wst=&7|jt!q%1Ml{E+TFct+KSo-s z)p{^;Zv89rYvX-w^xP&BdTvt$-(MR&w()!$_tZvKZQN3uiOgg+^H{(t@o!@qCW zA3JDgf9>{ifTJ8kZtWiM7_+u}iN4zT=Gx1xeHz?n`)uSVq&Ou}zrDHJ+eQ18ti_$Q z|Asy2rTr1qX@7!$gGh($n5TpOJIKAmaO}2&8}G0bJ$CSXhhI30@2f!OR^CQkV*~WD?V{laBV$aWS8>igj#cD?7N3{5q=DQLT<@b(BrVXXwA< zt02-T;9cB#r?iy99y(1x2A#~>=}8dj93TC3u1PD}W9H7?Fn8w}n7gyxbk-|x-`If*Pf%cApT?5Imh3Skdj%2AP8)TKTR>45!onT9%D=JP3E;+yWW8MV56 z%O63cYdq|@tM_%SjhVW3WDvf+uJ+v3^Ih$y>ksT^Kla9!DcyDeimU*NvF>ACy+sMEa)z3}h5 zZ{Za8gNWZ^jP!^?bYdd69=R}Q5Bc>dN(oBgo9odGd+K3NJ^W4RVfG%w8N)bM^Anf3 z!~bhM!EN-6N(|xu$NwX?4`$Edh9g>efF~NUhb-wK6{Y1kpzm*} z)AuUo?rZM8=I;CdT4wL(cKS79Fy7a10ebG|`{=ieBj~Z8=li`3B7VCu(%+u@+jIW} zBqAxv$%d@@ccV807|JO0+u!^9f6QF;+kYwY=zo-B$g#hk`|G*CeERFVzuNt;bCX*^ z#P2>v2BfDVoiYD_EqG?Yvmi3i%?-4}f%+I&iR#p(6?z)jm;MaI%mei|P(K6ZHgGws z*~nIQu#@w=4kClRdr&IWA0)RyxlwCS0SZx`7PyT;y-;V+5GFDW-@qWX2F>S39tM%Y z@$kOEdC>FV3N)l0dK~Qe!E;#5XMBO(40cn4H}ehqkkt@(GsN8tiBA$zl8(&eATRnH zQWUo|q&t1+#{dQ~9Qzt#UqkdgWHK|D$!ydeVpl^R1(Bf%2r=_e|8A(hhT7%Ozk|rI zXt;}E@)~BoVHr_-SVbyR6}uT`H^XYv1-luhhhcgcHi4JB@_|KI(D=h(^c zD11P4V&V>m7oaq<^c#VDeo=2o0Cq>ZX2+xn`%orvz z4Z9p+k0U;18Q-y!UD(Hn{do5Xd5nga=dhnK$ioe-p1%<%+DO*1n2o3IgYs*M8>K=HX|jlS;d#E2vPM5eq; zcJh!9wWg>wMK)91*A)FvDN7})V0TkGGl{P_h76{f)o(jSrrPIJ{Y+iJm#oLkQ@_F7 zQ_o`VsTcVjIZnOCs~|G%ePlRIhSL(00$EJ6vuSoStu4ctj5(*x;S=OK&0eOdHBGH) zYE6^t^bauCbTdq^L2KI4pE1nC^V2u6gCE$7?{2!eru$~5pGJSv^*2L*GrV&~Ozdig znP(&?C2nwr{mkfrea{$#oy<^Y#zdwui}`%YG7h2647-|fieHhCe!DR;Qy(+!YGzGp(*`}wH22Jb3}z_$o2j3fzOR{I zum<_f{Fa^U;v#Q?$Sm)kl?J<*m4&?IC!`2^nx)PxH#w^xYRnqJRAwUUS)Z_oeLM{! zvlEdSJ!glOz_95(NP7LCZkYuDL16j$1Ugzj_ zPH{RQzd63~Ir^Q``+qImb+}fAwlCl*k|N#GNJt|ge3Ot6kPro=krYWqq!bB}ltwxi z9n!sM79}at-H1p?3Q}_4eeXTb^Pc@2&YE+K@f&0AKR>#m=P~YUjJjj`F#x+8BbzaL z9%Bz<6OfY zgl4Ee&fMeHvzz_6lX1r}?>N1TyUqXV+z%q-y?cCh%rsvA|&Q=g0re z6Q1!Zh)jsj8ze!$6SD9&rEp6VKI9|nQlHOgid&x`p9#y6!GsN{Ghrw8GQn+6ILax` zqwk3cv8Rd2k;_CkFfl!u$cnlX-ysjasfkr+gYReJQp_;%-ykw610`vQJxm(RaDHYi zb6HC?`kLgPCv9OHr_swK8BUVnq<@gbBw6@P$H-*8OtzcJ-aWY`?qza&y3h@`Ik^{l znmm#Pn18Z5lg&Tb{F4uJg0o!UQV^NqcBbfgN@MJ4N)PlrWfb-_#e7p@@ca~cO}Wlr z{EdB0dCGr5WNLt2O_kHsn$)Ec&1gkCI-=jH-_aZQG<7j6@cm5H@6>h3WvZU1sylTD zd)UVT)SecfeAM6@CgPcC=9(t6>1oi%^!ya2C~juDo~GAFhSSYEy$Sl8uAk{Y;%=tP zZ~8bU6NL<>n|=CaygMo$Z{jASQsXwF)QVCosu1c$nLA2`QL>9NN0h#!E@Hn?4}-`I zSf^EN*K?H9nyh&G{U=oiUJ~7{LT4F`XGKLryd9^O)yBWTrYZJvQ-PlYwHuFpDZl-KzF5(dC%u0p6XZibC_Bm@B z8`#h99OooAc#588z2sF8nf)5ClYt!gwq_SZ7JkbyGP^t<(3<{u_v~L-#%k8H8?|Pu zHTx*)&HgWl%&~_#=9<$2eb2GmIRhBaY}VrWIY&6lC9ZOtyO?c`J!21`hz^)d^dchX9 z;X7KGf>L}$L-f1wYx-igg){N|Lj5h&-@?88hFe;AhVxwH?;!F^JPJ_^8T|4-A5euF z)JDI*d`1g~GK!xWi)?`2q&DtlO;@_3uQlJ(i#|+5FKcADMuuxvBa1b%ShEeithJl9-n}*(>aWd15!}ey zkW%PrZ4Fvu{&&Z5fEV8@96_b8c`a8_scotNejF8xvvfjpp8H?v3W&=oU7Xq%0Mv$XCoD zh9g`=uN(gfBAeop0{w0B{3bbVve!*Ds7+&<(2`cjZPRe{^jNNW)L>s=x^V@v?+vLA(HVat6Dx%rIUJhWd+y3T0k9ieD zVqU|JV&anqImI-f2`y14=1ac8w;t1zz6?a)F{@dRUB&ozVzwfem|syhWHDV^_Q8@(YWR-!A#=ayPqWusa^=>`sOo*qxp% zd`wN$-!mF>?pensV%W`5^s?tX z>g>4^MD}|3-qOf!um1P;WF)fNE3>`J(c@mv@4d(k>}Kyhp7K11>0? zyoVj{D}!C_t3nMvL4Nz>v(Me^lfk}4sIzYkZeZV5+~+>`yze*kz3)X3+5Z}^BbWX5 zwcoz>Cm}iN?oWrk`R&KZ{*VUrA__C?|0{?bNJKuWVGjqsqc{B+z7`OAAo`3rYd-|f0Ng5Cpp7K?CZCi+~s}{Ib>Id ze7g2==V@NI^v!VO=A{w(C?uI$mNip53NGoL-uyatsUCJS@isSCd%?T zLs-f|ZU>RW33!XlWG5$X`tXOC^YF*W@URRI+v8z59`1^{58Kt@!HmYf4o^XkhxKsS zUJgIzRS-GiCXd7;DalEL*^j(KekxI$`g}$U%zVVmN4}#c>K&QSY0PvqA!*4=0p3T3 zN1NjLquDpj&Kz{9e;vZkG~8e zC)~>kIi5(5J^4My$O&_wC{8KLQ2}>z!d_08^Tb?!!K^3NvYw4><^X^20Ci5h2qGt6 zBQYtE?MbyxW~36|G70ZHxeha(JjexZA-hwaKlK)GlM}l+RTMLyicpfOw8TzMxtmkt znZgY8d&>JyEn_wMJ+*~Dk>9Dmxrd%l>G_mwPU-uU+NWP94)KuB=?b*wC(M8PD4sc! znqt&KA7||9%$K;gGe4lGGh@-$8S|de+nH&sWh*<`i#?q=$vI?j=6Mh~n~CC-r6M2V zR?gO?KK6dLEgcxZ&rHCs&dy{htB7VJ_H_1o5IJWT=j3-zcIWER4n3di%}}P}`EwiC zfqOdVp3WWP1ZO#q4A0Bxyt_GHgc6jdJe8@Ae$VUod?Vb_dHJ0m!6@{5UN-0Da$e8p z)je--=jSq?g{Xc0k05d(0rr2v_i~{tp1EMI3o^U#D2QCt$Hg~DLNcg6dcLCPE3&zw?<;CwDbEK~LOxf1 zWFC7k|JCGp=4u_fFdBVawX3U(ac@`M^i@4wJ<17AbB+r<2_n}5?CP3bT}we)%zrI2 zc66;N=DgOI{+RWeJGtggu1#PP3y9%2)VX$w^W5Yv?%~@1YCR1ie`MoR-6b zuFLQGJ`SMg>w3N}o9nW6=WAra9{&7-AuQ(@4}-`J{oJs>8}8&rMXFMr z&-jW?bfz2M@jbG;F%7%AVOKZ2@5UO;e`6CDc@aeZGUs3N`YRXta3g<}p#mRL4Y&Q5 zcmHJvf9*wffBnfbUIr1r-x#@>o&tFOrv7f$raq1MoVK(_hBsw*vkw!Q$sFwF=1Nwx zo{h-w=G7o_>rIl88g*{T>Q)Z&AeUQ3iJnZ~8HSL8yJp zzHXW4b^?4WxAlJ8Gq=Yhv)f0|$L$;3!M)uH(9@lixRX0?k&(=lpd6Ku--oFIDN6! z_sx4>Z}&HFlyh9>I`(w`5l@l91G7IU$)_~OxAwqIK5!=w?Bv0Z3_`63YCW*~2Qqvp zyN70Yn3D*l_=tvliRT~w#Lw8l!^zBMF2Astjcnm0mvB!H-P6PSJmg=V1(8QGd?ces z?&i@a)Ips`P5GR*xa~)s`4)XYlHa36EMXb4c_f!d>rwZSy*;wGM?2Y#+W*ADJpb7L zKONBfKc4yLI5K;j41GM#MLr7fK6-jwo4PchF-_=>T|Ks|$MSnThKbnM<0v+95pzCy zjo6s=NpkG`i92~B<0tRnHlEZ#ohSAAjCQz(CtXnM$#=}+82<#3f8&w@GyR*JkjlvJ zU(f&BjXwN{9sfHDGyiK}|4v{YTd|XW@9=;pya*ys_50NOpSta*NlC?9_TR;>Ob#^IiJhx`Fz~tb2swbJwDgV^F65Z{2<=_ z!VX?kLH{pW(}P}&U>rfy`tlKW2Ven4-w=WnXlu+lHIE#oa8hwf-p!& zVczEhs!)SQG@})5XvY|Kah)eY_*!hz@D_O~K{Y)8T5G2+?mW{l?O7EcIg5ratP#8i+cv)QL5W(Trt06PZR7Gf_L% z`5=7#HQuH&U*eh9mve~Q=p%M4;*kI|$JSHq{1oI}ilD#P`iWhS#xzHEu{+X*ZkRpx zTD&{wc@B1Cl2bxF?XC6$S;mL;^;fhYSys_S;e`5=i}N*+(aZN6`9D2 z+2ZD)C?8Rm1~kF0;_k%E=JmO_Wt$1q1 zQ!8E` zK#uVbbCZY2Fun{Ecwd5qBt;$x>?T1i+Vd^uOzZHiT z+Z4h#lp;i}6z|i9$!z2Rr!iBCyFr*TAQ7@l>G_nUsK|%dZ_2uuIb|b0qXPr5lay{J zWi*@Fj($^mf6Bw0;4GJdFjWHNmntdA(Q_(2r;<%7eWy}8RSt6D)>6qQRV#jC5#~?z zPY|Z|OzINUqYL^-ZC9yBGMZWFDfL>`vx%+vzEjIC^;PUDwOyrt%<~{jWBxR;P(Mw1 z%$Y`BX};te+(;Vtm_{#YMxaibF?e?xJ4l-Z{in@OSt{@;&Cz38&!-*5B&ITxUs%iv z^qW?8X=Ro68h>IpY0aDV2`~6B2-77ZCm-Ye=^D_4mgqN~e$(kUoqFkd;-1r~lWrO6 zq*Eu|8a7~G>C{ZOlfCTcAUA{Xtpu3mEp^`NjK1IU_ivp;Ug^`4n*tQUt);iG^!3nF zdikYyC+V9agY-S<$6$sto+->=7Q48DcV~!CBHT!ZH27XJsFgvj4DX^|hQ`=K26JWD zhQ2dg!frD>3c`%9krK~m^etqJP=<0;#atO{QkxdIvyAe~D6fn|&|}7*(PPGG=rQ9Q zR^hfY+Dpb~yb8ihv5{A%#H2trnKF_Mx18w{>L8m;vdJWyOwF*fOzLK8O$WZ>Yt+u< zE;9YjgCNYDno@Yi?>UBB}vcx4b?~tFul%y;bsm$jL zVg?IYihIf8PO@xf8{1JYi~Gp(gcm`WRnA$xKdZU3>N9J4vS9YC6)>0IaSZ*2W0-Xl zhd6>gWxW@K*Z%r=4|g{XW2fXEq0P^0#ljEJp6YClA|Gw@qOpeQx0`< zjA0_vn1x((tY$rG<=DcXL6|cgA>Nl$&pF$p=bU{Qh8}Zz-fuUCIc1geSKL$1Zy|4P@=}08yia|a^EvJ*?>Cq^Z+E^!hIwb=Zt}XDyvI1r1$;YsZ*YeP zJmEzU=F5Tn^5sLVd}`&BO+MM=(|h@kI+4QPyg6tvTV!|{BB~p-Xt-}NI^DaRmffn*-N3X=*+kDLSBUiF$~!h8jm~*?L@6YY86tekewBh zPa*jfl24(toaZ9)c{e@o;9WQH?f@3ynRovV!orEL$HMw3?3N2xq%v-%u$~IH$LxhW z(h2<))=%MaOeTs2EI}THS96j_L0H7Qi@Zfbe$ z`n?bF%zHy|bMO6%KHjsd_pWdaGZ)uW@dUg{5|WdW{K&7k{EEx3copPOTn@$S@D1ZI zXK{B~d=q9Z?oNvD=OFf8`~tq?60uRIL}F5qg&eqt5^9wwNPUK|2=6Pg7c-TxqZ0Rc z8H5qpMLZwLM=?rJno5{CQjL#jOjqnAG8=ajS;9*68}a^#8;I;izmea0iu}TWSm-&_ zb10k8cND4{rp4aE3`Ed#*b{Za?c4~$lK#GAUaDeuCBLN?Khht$m7Is3O4?1y#mKSb za?D)v2=2P%IsV`#cex*grR>IUH-@FWyHq_I<5o(2L1)w|rBp8(cLHK?; z-01sF8NfpJpr5k#S2h*)RW>tOF?U&Wm#xHyRKvZL{g^g%q8s01SAN$q^t+B>S$ULo zKV^UCFCL(N*=Ipm?sei2pEuA`Id#gt&j(bY2Iekj?sDcXr&c+$mm9+_uJa@a%j>y( z8uVN~FD1}pdC!-3OXa`Dp3B>F`M&gHAcL8JoXVf(0#~`g9rRoNfA4=0gcV*RE(s}0 z1Q}MauL^pupyvv9R>96Hs9T{nb*M)d^ju*b>Qs0cgde<(zyIJ1?BIi0tRkAtY(;J# zT;>{f^MPCWKwlr+4Z@0YtC)<`q$fMMDL^6AuW0Uyc2RLWQ*e(J=du#LRNRC*6=U%3 zO77fmIfj+=UrFwjzQS%R`6eojM30p`Uug@!vX4WY;tUtjZ>4)Y48qE9;+86>B_la` zhx`4hCt>(3bMyV^3`Qnih2V=w#pog>&&H91vxht=O9Kk8I3PASS!iE4a;zN`19 zA9huJ5N@lwT&j=8&Z?_heG1cv!hKag%c~&#C@W_8s6BT4(NYd_ljlKLBOng(a4$7- zBflC2c$Xp+qXurKMq^}ALl!kU(uHogn;L65#5v4a!;RFq#lO4^!jEI2*2ijnTnKyk z*jyi*;p3UCW*vJt&J8^ONo*34lvHFQ3o`s92Sxdax-_5(t!YaKzQV3Pk<%yk{mD-3 z<&)oVH=ms1JXiRW+qj3CZ;=@p)>NyeS~c@vXEpU-)81;@TTQoCvn2KDj$PE;j0|d- zwN_rLqMup=nZQ)cTx&MwuC)tu*V>Q1Y8^&zwe(W!AKXkW`>Y)wS=3HWO6;iir+kS$ z)czj#QhN|X7{&;uVL!EZpib?BxX0QTxyE0pRr~KC{4@C@@B?@!&= zr}q4*=RdWdPapAw7eQFZe(RXI&KtZ*dW!NH_U-o?!#W-4gnsLIf1Mu~fPU+YBpUhE zv8y^U=(&!b>&T|g@2FenB&Rux`>Lzwx+PJkZeQl(@9W+S!g>kFNpVV1jta=FUMtL5 zPk!~jp)1|#fp5B=J=L?Pdh;-Qz16H|BNuocg!NOB6*cPT#ck9tO?fI)mFjqReSOt8 zOMSi9zs^(S*1%31xVHxR@x0$^3>(y<9t~+p8}!;heht1yZVmdO#|Cp*z!L1afeahS z(C;{ge!nqn@MjPba?Gn(Di$+D)^QlXs9$)6W^qFPOjSqabYNnP$bQ zOK0@a%&wY^U=%aaQ?oVbtC@M5>8;roPI8GqxQRVA`68*O9PEUM4E#=p8F-uvFY+6R+ zzFKZ&C-&BI53>0@Ht(R$=U*`vfB(7uK7Sm9t?aHskIDS@8CA}(pnCFr!n+9 zjbWQOyg?FDl8#LHe%knc+Njk=tu|`4kxiS1$fu2b+O(t+Pdp@smY9ewX?5w@@rR|Qk0<)y|IsW zGf=k!wb*?-J+)J(-5nnA1iNZ)SMBYpyY(E!0x8H@H+n?q- zdTj6c4tCT*RvogE6Fcr;Umc3_9u<*Ohd~TuG~=-ozttFa@cs^V(_tB_SOT*P7g{Z}cmgRkuGtLA(`d%i?&Uya0^U&-&Q zsYEf8IrzT5+Rc7`$LwES;3|IvVMjOGF$ZO+OjSOnK5nFAQ`Gd^j$uc6b~Jy-NleF{ zI@(jmHEduj+u4bEzqa$Q%TkjjbfOCb_?fwQ{_7a_agZaN|u+y6qBjkNP zpbGA~Q*HFy$@kc)1+5vyIAqdEzn$!=lU;SvbEkQz+i3}Q)@cR5q33UsA?t7I(F-|# zvyF?`S?5F~Ck^SyLrF@bug>MDKt;^lSudSCVD`>E=tF-7qLYAMP18qtiFv|gtxdenn?`(wlzRQ&)G@bqOc1m#&xigPYvt5&G?_-)^rHpLg-ybSr^=yOlyN z-Spf|-EJT95$>#8P1No-oE049Nf36=h-bQ+tGmp)yX)@y=)RJ5tjEoC*HiZk=&Sox z^w#~)ApABU0f|XL2C`!QZ{MLBZRm@J>=3uEK@J$vy3Zl&iy1~U`+^^{*v`Ssk49D2&3=U&wB zl>l@0Do9Zxl)+AV>7`d4)alg_@9wpR6X?I!qaf@Z583sWS#P`St;gP;?_G~(w8UxSKv%aW{SPQix)NypNmi^Cj}@ z(*?EqsMSX{ePq)||9yN%eTFa$yX&)veb~bfNs+-1X8oZz_W6T;ez3nEZgLkh|L`~n z`x4wGm`yn4ui$=(zZ!21(e&6|Q;~+gac(UFb?lf5$_(@p0DXj4+f#uK(z*rMZJMrxgUgslJhqD9#nx!xbH!q(;d$b z^4|f2rZST`EWuoZWH@LoySTugxTQgEX^`Cxdd90D9Q+zd$xSW1e{f^$Wbha0cd&j3 z>vynvgZt1Qbq1?5Se?P@435TkK3Fb;+-M z9AbY%^fAP)h7`d!HpI+B^faU)pV5q#w4yii8zR3U@*6UlDC96?9_kOdjyZ?ENitI7 z+Zk#nL-jJWFzO5~j&~3JnN{e2=wYrQyP+~0W|zbCIL!0Iic*^L*zK?y)TB0b_?%u0 zS2;c#~|JU)p?P8u?hm8!^ZxLU*28m`uG*$kJ> zaQzQ&L2KG#cf$uWAA1;nCkRK#V1!vmG{Qbd=x2oejrf%Vn0dre%st{C%st{6FOlO& z_cHP=+~r6aj+EiZ_b5qO$I+f2osMkeAP+?-MhQZyASb`o7>*vrI40wE zM(cO9_m5u6D)c*gGwx{gEo3;_zDDbLw4O)X+2|M8+t2p)vm5z29@(jYUHtqLOOWf& zPl9kvYVl3BpOS(95JZQD;&zyn9jyhNJ&Ui`atf zCdq8lMfB*m8pFwnNyA%Y<{jMi}Zi;VeN?+_@%CE>^s#&KN z!#=0#XR7^8oyk1RJaq}?o_dJG=xeI|Og)J#r^;ZeUZw@aK^D_ekQRANv!7`V@$P9q zFn}S9#BEGdYnocq7NXv?V?j7QF1aXyzNgox5%w|NPNxsU^V1iwg4L|YcQ@T_O*h+g zIZl_~ba_pG#>*g#vgfFTBqAxv$%?F^>?O)xqQ2xCy3-SRMGa&qvWXgpJfe263$>!u zin6mP`9z&S-6(sDawAcf`7a1(WTYJG%ov1RXZZUWZqV;DhBNaatC{7gOcmrdvpss6 z*^y4jab{OWFaa6PoXIaNLl!fALo@AZraPJC-Lul7{;VwIMy*)|D1>ikmV9Tmq8;kY z>VmmvnR}MGXQ?&I?6YJ%>sAoXeiQGT?Z#*8d3IT9(gZ!u_WW%5&GyXfN$7F59%t)u z_G0uodj;D#%}ws|h^NSFj=txlBpsP}n;euuy*U;5FbL=BWv+jpn+yHSEr>qmsz3KT z>~OAG{C;9MuQ~Fc_XTpD{~jM>?|wHi^t*}Se9z7I%zV$xH~;)7=CBaG&)4^S`Oe?S zX6^^!0=+G$$4LD9fQuZ%X0l;7tMl%1@eHR6&2w;b*EqP^E|uZ7X>FWL=9>pQwK z1DMVXWD#wS=J~j#Px9gkHoEDgEeJ^^`hrZa=`YBAsJJ+v6w(Db%?Rwd+ zH^X|nT7L!EuKyR=uGjYlIc$)_h74pSC+{H34P_{czBibCLmS-S1~<5&JN=Qx2H)O> zF^t3AZE#l`)8O0PSdL0m<0C$yIbYzuH-1f5yl~Q1#Alwv- zgd|13oATg$+N94-Rj7g8ZR$y11~Qc4jAAaou#DBLXA9dn&8;BZ?ERbNu{je>=tw7~ zvINg=KEwb1_D&FPvF|Op$xB`Q{T8*h$YaZ7qL_o(wk%~8(WtlO0&aAR`L_J;U2b&C z6J7-2*4KEQ0({9tj^LZvW=GrXW1HN!dG|JbZCl9>4&Xkw+4nX*Zo3zRG2RvP21&?* zeq+2h#$CpI$VZqpMs_hBaAz^Hiy4ad`(3m!<~NRVit~7X%%9xGZekt>;r8@oBpcaL zXS+Jvi%^2nsJXoy)oF=cZ6C=zHsage?)}^U_r6y_xT7c`zK0z(X@Tc!ookJLgo7pMbo$J^{46@iM z-MX$S>p~qd`wQDfL`I!mGa@TwovjVrU%f0W~AB20|)ZUBy8-#ubEZmox z^w`(F9OR)O_O-7XcD7Id`|8nvMwnyYkEpRvfBT*X;r=)Ao$r4u_`m-XJNEzkkMf=V O-~avp|97~*^#1`qpd`8g diff --git a/src/MeloNX/MeloNX/App/Views/Main/ContentView.swift b/src/MeloNX/MeloNX/App/Views/Main/ContentView.swift index 3e9bdb4b0..3dc9e510c 100644 --- a/src/MeloNX/MeloNX/App/Views/Main/ContentView.swift +++ b/src/MeloNX/MeloNX/App/Views/Main/ContentView.swift @@ -71,8 +71,9 @@ struct ContentView: View { MoltenVKSettings(string: "MVK_USE_METAL_PRIVATE_API", value: "1"), MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_PRIVATE_API", value: "1"), MoltenVKSettings(string: "MVK_DEBUG", value: "0"), - MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "0"), - MoltenVKSettings(string: "MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS", value: "0"), + MoltenVKSettings(string: "MVK_CONFIG_LOG_LEVEL", value: "0"), + MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "1"), + // MoltenVKSettings(string: "MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS", value: "0"), // Uses more ram but makes performance higher, may add an option in settings to change or enable / disable this value (default 64) MoltenVKSettings(string: "MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE", value: "512"), ] diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetCollection.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetCollection.cs index bdbc79f92..8d7faa653 100644 --- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetCollection.cs +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetCollection.cs @@ -48,38 +48,10 @@ namespace Ryujinx.Graphics.Vulkan } public unsafe void UpdateBuffers(int setIndex, int baseBinding, ReadOnlySpan bufferInfo, DescriptorType type) -{ - - /* - - // DEBUG: Validate inputs - if (bufferInfo.Length == 0) - { - Console.WriteLine("bufferInfo is empty."); - return; - } - - // DEBUG: Check if _descriptorSets and _holder.Device are properly initialized - if (_descriptorSets == null || _descriptorSets.Length <= setIndex) - { - throw new Exception("Descriptor set at the specified index is null or out of range."); - } - - if (_holder?.Device == null) - { - throw new Exception("_holder.Device is null or uninitialized."); - } - - // DEBUG: Check each DescriptorBufferInfo in the span - foreach (var info in bufferInfo) - { - if (info.Buffer.Handle == 0) { - if (bufferInfo.Length == 0) - { - return; - } + + // Proceed if all checks pass fixed (DescriptorBufferInfo* pBufferInfo = bufferInfo) { var writeDescriptorSet = new WriteDescriptorSet @@ -89,32 +61,13 @@ namespace Ryujinx.Graphics.Vulkan DstBinding = (uint)baseBinding, DescriptorType = type, DescriptorCount = (uint)bufferInfo.Length, - PBufferInfo = pBufferInfo, + PBufferInfo = pBufferInfo }; - _holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null); + // Update descriptor sets + _holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null); } } - } - */ - - // Proceed if all checks pass - fixed (DescriptorBufferInfo* pBufferInfo = bufferInfo) - { - var writeDescriptorSet = new WriteDescriptorSet - { - SType = StructureType.WriteDescriptorSet, - DstSet = _descriptorSets[setIndex], - DstBinding = (uint)baseBinding, - DescriptorType = type, - DescriptorCount = (uint)bufferInfo.Length, - PBufferInfo = pBufferInfo - }; - - // Update descriptor sets - _holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null); - } -} public unsafe void UpdateImage(int setIndex, int bindingIndex, DescriptorImageInfo imageInfo, DescriptorType type) { @@ -137,25 +90,6 @@ namespace Ryujinx.Graphics.Vulkan public unsafe void UpdateImages(int setIndex, int baseBinding, ReadOnlySpan imageInfo, DescriptorType type) { - /* - - // DEBUG: Check if imageInfo is Empty - if (imageInfo.Length == 0) - { - - Console.WriteLine("Error: imageInfo is empty."); - return; - } - - // DEBUG: Check the values inside imageInfo - foreach (var info in imageInfo) - { - Console.WriteLine($"Buffer Handle: {info.ImageView.Handle}"); - } - Console.WriteLine($"SetIndex: {setIndex}, BaseBinding: {baseBinding}, DescriptorType: {type}, ImageInfo Count: {imageInfo.Length}"); - */ - - fixed (DescriptorImageInfo* pImageInfo = imageInfo) { var writeDescriptorSet = new WriteDescriptorSet diff --git a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs index c9aab4018..d6125066a 100644 --- a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs +++ b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs @@ -137,7 +137,7 @@ namespace Ryujinx.Graphics.Vulkan (IncoherentBufferWriteStages, IncoherentTextureWriteStages) = BuildIncoherentStages(resourceLayout.SetUsages); // Updating buffer texture bindings using template updates crashes the Adreno driver on Windows. - UpdateTexturesWithoutTemplate = gd.IsQualcommProprietary && usesBufferTextures; + UpdateTexturesWithoutTemplate = OperatingSystem.IsIOS(); // gd.IsQualcommProprietary && usesBufferTextures; _compileTask = Task.CompletedTask; _firstBackgroundUse = false; From 0bfca4c4886f7f0ea0400576241a7f5453e1fdda Mon Sep 17 00:00:00 2001 From: Stossy11 <69031796+stossy11@users.noreply.github.com> Date: Sun, 9 Mar 2025 08:00:08 +1100 Subject: [PATCH 3/3] Fix controller and logging --- .../UserInterfaceState.xcuserstate | Bin 5073914 -> 5129715 bytes .../MeloNX/App/Views/Main/Logging/Logs.swift | 4 +- .../Configuration/AppDataManager.cs | 15 ++++ .../Logging/Targets/FileLogTarget.cs | 4 +- src/Ryujinx.Common/ReleaseInformation.cs | 2 +- src/Ryujinx.Headless.SDL2/Program.cs | 8 +- src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs | 79 ++++++------------ src/Ryujinx.SDL2.Common/SDL2Driver.cs | 9 +- 8 files changed, 52 insertions(+), 69 deletions(-) diff --git a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate index 1371a5adac57597b282e296346544c7db7c225a2..8931b3380b8f65b585655af4ee5f276fbaaf064d 100644 GIT binary patch literal 5129715 zcmXWkcU;%?-v9A0OK~fRsE7(UK!##F_THd^3l&5JWT~a?EL&#F(cXJ#+RpaWrj})U zZ_80>d)M!NZrAUR`|VukT%B8d9?#dC&UHJtbFKwTyV{p6pET*MKp+rAFd>8zMh|+@ zd)AoaTaI1UzGU(2F-^xdFKYMq>c%WzvUJv%B?~%QnwKw&2n4OVv2oyl>e`BylUf$$ z{r^8`mw$3Ny{6YLZ(826GUy(EU{)Xh$p7>unxPCMl{6+YiF77&2#0bQhjRo+QcVq0 zn94M2sbe}bn8`Aha~#KW0w;13Cvys?vVzk%ot3O%E$dj%#azNwT+NN##3nX#7kBdz z5Azhy@B-U;op<<%kNJ-8Ilw`F;75MqXa42C|63-=JV7Q2>P2t#3(_wro&?4)mT`v5;S zo4Jd-(J%O3?&E$Q;6b+FR)gJY@Dn`4vus7%U~Pln|rna&^BZ^ zZZ70-v4m$DuA=|XVhwBY z?IFHB#J7js$W7eLE!@g&=n_|A~$c%B#V%^~h7WGC(^#CM1I?hxM{ z;=4mW<4eB5w}-f+kRSMwpZJ--aaSSkDs&)&h#-=|L@|VDVu&Y!B(w`Xl*7<4RKrjW zL)}xTZlR@=F%|7XYiU8V&^8vKU8r`U+J(BM(50NfiMX9mw-b6E=W_vChUyo3Dc5ox z*K-4Ruz`&{&J#SzQ#{QxXc?+ysD7cZqFv})yv?U*7Wz3~@HP9;D^#!0pV2E+uTZ_h z^a|4}Os_D#!Um&Pm|kIeh3OThSD0R5N$3@JD0+qI6{c61UST=t6{c5M85LAh!xZY6 z$3pZAYe%!N#VkRyu+^N0PGLHQ=@jPX!q%`B&BE4mF_)uTm~LUZh3OWiTi8Y(;6b+V z5Z*$Veqnlry~sp&&xV0W`t;eaX;0(@W z6#0l6 zSJ}yHyv{D(;7#7*Z8YoYcU;fU(X6LtJ@@l1-|-82_572+_}jmz>wy~#*DYMP@O}&; zf=Im6@DaGV@NuM~U-)DW;RrMfpTbn8QHxIDI)%?*CbO7LJq@&=S@>d>u#^)yiIX`S z-NILKE*G$tb!ZoU6<2c$ck%!a^9XJ#{7If-D=)Ae{lYa1f0K84kAwWckNm{X=oGF~ z_;38qA7~c-Zy?Ysj2`r700SAyForXRv5dpp?3K(!CUGQ3aWn`jmx=$E4d0ydR>Ft>UAC0=bLJCbPJP;WQXdo*zzg$BJd z$Rvwwa>&KI>z$8Ay-TR3hM8#9dp7#?UWhyD-AV^;srT`mfKI(vat3E|0T-i5@0+-p z+qr{HXwv&$bm{#FZm72&y`STGUPhbVU+^Vgv74{?22FbJWgq+bmV^Ap?}0#{06_%P z8~;F`z6?R5K0_HsEO8_;fkV)$PZ4F5qemY-`qZLHpE)$5NuM@4>B7zQIfnB%p9{E< zi&(>2*0COK`dq>lT+a>Mh*o_zawnT`Gkx4lpNG+@k4}Ab>hlsWvmI}&&zro($7t2( z06+0F|LgI0AmH-@eM1Sy-|0J$!9<}&-{DN=5Dw)q4(AAt#2xk3rms8d>yG;7;$Hfe zGKHy3V=nV(K&QSs_0_5G5;W?oQQu=(#wnc23Ra<2-z&M6>(Ha`ZD`W>F788g$gBYSY&p_1()se&9#`zDVL#7 zKeyBG1~%em`nj2Yo4J<D2FOp5Y~4#_jZblMnccJ?!N>bm{jCfACKr&_4)G z`fJj^H+|5czXts^=s%9}B$C7gl1U+zblgyXH`G6me6;GXPycGXul`f0V;1w#slQJB zJLqIN?xnvr{q^X79_O=$i@BVu(WL*)+`=7fz<2k5maS~#IiBYQUgRY->A#(wyv;kf zqyC@r8GG2vK7K}@{=f1YZm0i$fxv(O;q;<6Zf3x6bQ+LI5_$}9GXo~$eGNF8Y&02A zObHcKvXB;9X=4%XbfC$AF1lIFv7E%o=rrIgv>I>@7opRDwOoZx1Fpe48*n4H;%)}q z#Y4E60on}M&JJGVb>8AVyt4tC4ET!O=rUkmATThP5JCx~2R+ebpe6%*(}%uzTLZnP zfkPQh9Py-}(Ljv`PUH~$4jPz4F79Vw8Rh6S(9H~-Lo*r;)M%hC1DE1v2A;^Ntl$jJ z#P<*M{R4gf!0T``18+c!fj4n8x1h_w4cx=MJi?Rd>4%dzR%}; z!G3<^??7NsfFSf4q|YEt2K6U`Aq;0Eqex&3nPlNk2I(+Jhe3JdQ$Qg_6r;%i|G|-4f5gJ8w;+`VhQ^ayk zWd)~kE^D}yE4hm6&?n+HZs$%mu^I0x;$a>^zX<&z^o!6eLaT@!yn#j$AMz2O@fEw- z%Rcr80+Atv5{5g9?1^_4*^A!vp)dV#bdg#`jwX(HCXh@Dx<%?1savFOky=IOp;Kfz z8b#LAj2nt{Ly?+9Y7(hQMM@;uJx0&d|}bcxg@@(#SM$c@~|CNzrF zDDpluiqt6bS+t4V#tvTLRWyoxkN5e2Pxyi_(JS&>zQavL{>Hz7z+jCA_n|KX8O%^d zpv~Yhj3o(u2Io^iAw?8ZLMhq|)@E=8l}uqKvzSj43+SSo#VlbNCvZA?4c2S0PJ?wC zd;xB0@HOZ(SewDx48EKDc?dT%_$f3Q`~okc%ive=-Gg`YHQ%s@z3gK@-=fK2O$PtS zAN&~zL#J{m=76s1d4CAviUeH1ktHxxAo zZK4)%EP6z_p{V0H9&Msd#2bq`4V|Lab1|2oPt;{x&J|qAjoie|JjfQbih7twcof~D zytOEAElRg2y`o;_UEbq;KHw9+K(i>#qBM*8nP2!d5Ev3pFM895zVt)4A-WBTWH|0= zh-O2QNkOY2S`C@Z;pjCahg|X~qa59a%%g!u=A+jTy@oWikVUwqAxk-)6F7r2Ig7Jd z&4uVSM6V&2b3Hep*O2>p0KJCjHRK`m8lu+_y@ou=b3D%uUf~_|8lu+_y@q_u=eV&U zdJWmnPv|v7ujroW6|GmaUeSHfD_XB;y`m!+hF;NnMaPkhUeS6*>lLk6^x^0gtyi>O z(WU4WtylD1^orIiTCZrmqVhyv%mq;%)Sb)+_o$KE<1i-h*Dz-*bS2{J@|7ExjOu z>4A1b^%|Oh_cnAa;}}mONlZYmp?VF~YiK%0auj*wQ$Q8f)G&oQW}($kt%fc@tD&8A z(arI!;55$UEY9TyZsaCz<`!IzX#ee_zZ+{L8^|yY14~u0aqZmyb@g$(%F#U$< zH%zl(It_DI!ww;XOtL7Vm=dNkjau{?rq?jHHf$j+wBij8(`ndB&gLA><9ycOriNY4 z)m)EW!}J=a(J+mM=`ieBwz7@qc%Bz{5sijvG)$vmJJD#EM#D53_9^-d`<(rJ%Xhe| zVL$RK|Du!U6&M~wFuieC!v_su_*3XI{1skh z7jK};@DKQeFZh~$Xfxb98}6OOgwqQRVl;^9OF#NEfPoAmf+4u6n30TQJc;NN<8ERO zF5%pOU!D{Lx&h0Vswbn zA?7x2=MFZokvrMMJv@XyF;C;JVxHw?wzC7b6Qfa#+lhIPk8nRRd)SLsF+cHVATT0? zo`j>(2#rSQG9rp$=rSUXc(fUz&4?Uw$s?Zv3ejbRE+cdqQA!zAcvB;$Gmi!uX{Uou zx>(9`PGtqBv5Iq9&3dlH-Hf=7>(Ok4W+OBk@dQuu6uOMiWrQvxwz7@qc%B!~X~Ztx z#~qFMkT3a)-MFCB7rfCC5Z{7l7@SVbx*PG zDYg=AVymga4aH7n8ntK^t6A&}8qh3uK8w&UR=ZfeVvpl^+*hpoiaj08Vl|7^ELOAF z8@PpA*}z8b;y$+U5RdUVI>zc4yNfq?lec)AcW_g&ZYoy0*pK;yFVHVmzgYcZ_o88} zhOs~M3%~I@fAdcuFtP_4j`SW!Mi5CfLzzT6dX3a;F!2q zIa14!Q<+UYb7-NJHZ&aR=0+~%7*673^c(5^My}*+F5*(I zHgX%!@jUKq+C|$k$R5QbEKXlzhMu0join6zU4c<=T~$asoSXD^r0`hjnZw@ z00uIMC`J&E8yuBN8WWj>hNE;F<=u|*Zb#))P6cjplp7o6#zwiZQB5qMnT2RKsvW&X z9nT4z!I_+eR-;yPA$pCvjLW$mw>RoWG#d2)53+@ac$i0clqb<{)OL2D&!~5Jm-qOH z&(Ld>UZZ~CM}7(fMu*{^M)xF~Ug$MiuhDvq)@XDzv5X{DK*qG6W!vpid#fG8pU5_m)VYPaazTFz=!PS zYrMg@J%K=cIGV)wrVoAb&f@zs0IlK&5kVw_i9)}4&Em(Ch-UHLUVJ)}Ih-TNAQSE4 zwTpLO@$M_WoC;27C1-FZXK^;?;C|xIWi{taaC6u92LNztiQiuCWn9V#ISU@vv zETW5Uj^lVv;5771&@DlqgsZukTey?^xSvOPjAwa?*V)B;e2R7n->?V05`GN?#sml= z7+uB;WDr`68OCUQ{}|st#`ll$&0~%r8{avmm@0hdnCZ-AK25aK!7-f3Nvz}yR%81y zSK)ic+{6YpaxcDV%p*L_HlE`ZUga&^!x;B4=1ac94UGAbKLdfWL4-4aA=q>5SZp~q zl|!-L*i5o0qyig_wb9r)*k!C;#`^ikc5*C!{;_`cv1f7~>sZf~_>QqRatHU|8^%7& zQ}~9lFYqEed7F>7H+Y{9_?$1;%Rzj@ zINvbtzd*p*1jhHoI~#9{@wOQ6osA!fJ;o>DJH}7OcZ|=a1h+JPI`deF{^Ru@@8=%B z5m$d7Q0m!_Pe4&ph7GJl@Yd-p@OJ4+r>_e*%HTP;^f0 z$6$0$9D&Y>e!fJV6a9RNIw$6#bE3|PIw$I!sB@yui8?2C;O9;B^CtRv6Hn$8PGtpW za}KLG7vGZTTN2l?o{OB7$fOY6CKOXi74y(&f<_bO)5HRraYqxn=;k<%=LEEwa6T7s zAs4ZRwXEY(^qO!JH?x_$xSM;>Yl21-G@78%glE~xc6RUzpYSRAO!%BH_>!;K&0h4H z;I=0G76>E<5sY@p+9m6i+!u|KqZqGqv1GTE{64xR>z1rr@-JwW{J&Pe^9O(O7k>u=DFJ%Y zkNym0815@22HjE;NX8$Wl1dtr(Je){6x~uZOVKPvrxcx1rZanD<`;fNyA-`r{tE`y;8lwRJWCS4cFqnQr%ao zMyc*9^={l%>cc$3qwL@n+)?UIUgLH2O4Tb>qtuVlCiN@6=Ku%!0gY1s2n5o+!?a*R z=tE!JR9Ym1(I`!$G>y_UO4BG!qcn}uCXvojxT&-Zs?a5^hAB)%qcr!GR)?EPYeb_o zjnbBK49BvJ6VNJ6o3yhz2X~aVhD*7O+t4NL4mPlnJ8?&85AYyccnHnXG)vo#W@(zG zX_ls0nr3OQvy1onfDicyz0&kbJID|G$WQ!?c4^v8^adw}(~AKNWH>R5AeK1vo0v)( z{z(%j;oVIvppYVpabFYN*F^ULgYm!Ej+|DF7GwDzNakfyx=s{1kNgqHox}=XL4&R+#gxg5>?diTfy#{xYUdME1 zQ;!De8l-EGzK}(<)6HV^NMFVYoQNjrD>wsplfH^`(I{P`bdAz=NxzQkxq(~Q#Ab9! z*CpNEq(6x!=`ZjiJ9ra!lm0gEqfxp>=^CZ$l74`L{J<~#!@vCJKk65PCX+RptjXjU z5*Wi++{)y1CUXc!kV64_OrD1xlNZoT8+uIcLXXMEpvUCn(POe3nXJd;mFO|~9Q2rc zKJI3+Tbb-VO}-i}Cg05M+{uGHf)0~)nEVu5*@hOAwV3=`AdnHoForXdQTV0|-;|Mv zZ^}p|4d0dFyE1%N#*t)_g?q@zrfy_|C z=tXb(ZL;QJo2&)c zCaVqGWOZSitYffE*74XT>lAF0wG!K8or7(%&c`-cYq3q%rPwCxDr}Q=J+{fZ1>0n8 zz&2TTVVkV`u}#*)*e2@lii7JvX^3;?BlRa z_Q}{L`*duReKxkqJ`dYuufaCimtdRhE3r-Xb=W5RW^9vv2e!%HjBT>-!#3FuVVms7 zu}$_f*e3gVY?Hkm+ho6nZL;6OHrem<0iR%->@TrR_8x4L{T;T+{t??`|AuX{|Hd{s zLD(jz2e!%SgKcsKVw;>OY?Ct_+vJSGHaTOkO->TF$w|XDIfr1IoFlPKP8PPw$;UQ1 zCD*@5DB__h6gc2eD1=qu3_*DQuIw4cp|tgl%$P#WuNbV4K``u}$tr*e3UL zY?J#nw#nU(ZE_D{o7`WpP41uACilNUK(atyD7MM#g>CZsW1GB4Y?C(>+vLS!o4j~z zlQ$mQ7F-Wk{?Zxy!5y8zqdt;05XmtmW{tFcYq4cI2{R&0~E5!>Y5 zjcxKCz&3f0V4J)ru}$7qY?JpQw#j=1+vM%SHhJ%0o4gOPP2OkNCT};k$=io*@(y5| zyq~d6-XGW|?_X?_AA)W2!?8_%KWvj9fo<}mu}%I6Y?B{{ZSu!qoBU*KlRpXDmw#k12+vGos zZSr5hHu*cSP5$fHCjV`0lm7v>$^R7F2^7mq!{O_?%{!iE@|95PY{|~k)2*x%A zJ+VzeUu;t_2-_44!8Qdk*rs4Kwka5kZ3-q}n}Uhhrr=O)Q*acvDagh)1qIlqpcLB_ zRAHNfY1pP03Q*b)ADL5P36r6``3f5qo zf=jSX!Ijvi;5uwma5J_kxC7f1Y{oVP_hFlYhpYu}#4z*rwo1Y*VlY+Z23Z3@${P2nNfrtnB?Q<#Nq3iGi|VF|V=ti(2jQ?X6q3~W<42ip|R z$2Ns6*ru=p+Y~OrHigTvP2ow{rtmauQ+O7(DO`3#Y9JVQZ8QT=@#5RR*Vw=MEuub8|*rxCcY*Y9R zwkiA;+Z6tQZ3=(IHids-o1y@=DGI|jMZK|2(Ew~yG#J|y4Z}7?Be6|U0=6ki#5P5# z*rsSQwkbLS+Z1JDo1#2yQ&fy?iYl;8(G+Y`G#%R%)nl8YMr>2G5Ze^BW1FJI*rsS1 zwkbLh+Z3(9HbrM*o1$~EP0@werf5C3DY_in6kUUDif+UuP02afrsRBVQ?eG@lw68! zO0L2-CD&t{l3TD%$p&mwau>EKxgXn6c+u}x_Kwka*eHlRJO6Ovm(k5(E z+KO#TJF!jaQfyOt9JVPv8QYYej%`ZM#x|wrVVlx5*rxOnY*TtAwkf?1+mzmnZA$OJ zHl>@fP3e8urt~3fQ~EfzDSZapls=DbO1ER1($}y}>08*Q^nGko`U$ov{Sw=h?!h*t z-(j25AF)m8Z`h{vZ){T*gl)=tV4Jc&*rseCwkeCkHf6)HP1z`HQ#JY@C zb`rKJI}O{EorP`6R%4s8i?B`E#n`6o3T#t$Ew(AU3EPz2j%~^|VVkmhu}#?)Y*Y3a zwkdlW+mtvR|=H*~2NQ$2R5l*rvP@+mtWFHs$TurhGBBDPM+d%1^{Ldos%Kr-lBnni7Vw;Ly*ruXC zwyB83HWfp$O+_rWsffom72~l@MGCg5NXIr6hhv+H3~W=8i)|{3uuVld{=^kE*ruWm z+f>ZPHWdxnrlJ|!R4l?a72VjT;#h1`aRRofI2GGeoPljBR$-fp3$RVaI&4#M8Mdjo z8rxLdfNd&n#Wociu}#I@*rwtEY*Xon~GPkO~o#3Q}GVAsrV4v zRD6bQDt2R=ihbCo;sCa(_!-+&{DEyM{>3(xA=sue9NSd(!#0%>*rqZX+f5SD$2OG@W1Gq+uubK&*rxIYY*V=d+f=@eZ7Sc!HkBV>o61kIP32eErgAT~sr(+> zRQ`l*Du2f|mH%Lys$gtW)f3xP^~E+-gRo825NuNwgKertW1Fh6*rsX%wyBzkZK@8% zHdRMqo2qPVQ&oU%s!FjK@ppx(~Lg9*AwKqp(f&aBNdO3fokV!8X-N*rqxS+f*NdZK{vNHq}|!raB+nRF`0z z>Pl==Jr&zj&%id-bFfYId~8$Qf^Dihuub(6Y*W1)+f<)~ZK_YhHq~cgo9flrrurgm zQ++YEslEc+R9}m2s&B$J)wg4t>P^_D`d(~Py#?D;KZb3ppT;)T&taSDm$6OtPHa>C zCbp@558G6KjBTpFz&6$2V4Lc1u}$?4*rxhdY*YOgwy6nVo0>3eQ_~yU)C|BjHG{ED z%`j|JGZNd>Bw(AGL~K)&ifw8pW1E^IuuV-SwyDX(HZ{fArltbh)J(xPHPf+8O+B`$ zX~Z@)3$aa2JGQA=jBRR`VVjy0u}#eiY*TY4wy8N6+tgf$ZEDtIo0`k9P0cmfrshU$ zQ*#@(sksx|)ZBw@YFGdnzDwqtV6pgm!a2`Te*$fxtII6p9grD$JxenJdajWcJeiP zOxeR;_OYLD`Ht^7z(I7H@|XWQ>=1OC8b&|*GXS?Z)h$kqVFaTY!&p*DLyxH?lu|}H z6;x71H8o734y~p(vyc|LSH1#=l@*1zRi??~7&+(q8eu-97wVD=+9@BczlW=;`n?CfVAN`3yt7&n>lRzqI zOk@&=;+;;*C69axD5R1q^qAI48;fYCgHF2WW-(e#^Dd`pHSJ8!LZ@jLauI8|lB>9y zYq)`1&}!Od^qBTMFYqES@iN=l!7IGVPQ1BkI!)7QnoiTcWIx~X9e&SE^WLWY!Jqu= zzgj&Qt!n#_z!=6dj`1Xt!~~K_Ar)_~R;OB>YIUmBskWR7D)GCkb|$l!jW<`@gjTg3 z=uxXjtsb@Ku!?h8&3T;91zgBF{En*CruIf|Vk395i7h;Y_g4D|Pw)&{)xL}#wR+U* zQTr9U`I>Lo!(R5Wp9B2L|JwZbfB&`fb>aTD7m*AmiXjZg@Bccj>a?oML615;>h!29 zppYVpDWQ}ys_@S0=Aunq1B+-!pSn)mPo4Xz^UmtLv$_>%Ri{hm#s!prAf6${&kLdw|2quJ3!stOy z`rw^S*JgSQBN)S2#^H@kcRSN3a|lO}fmYKCnTsCN^_bqse41E5GYe^<6`iIZ!%3XX zDV)P9&Sf?3XS(~DekE6NHCj#AYWm~oFEyB>0j_A zU-3O|XZk^Y;1~YjPya6qf(b#78G6i!WhA2*O&swgFb1t=B%#%eBRPtr$)^CfGozXs zrr?fd%wjfL%~-(6=rQ9|R&W}pvywA7le0J*oo1}X8=IlijH|ebn{hic?&5Cl!5z); z&Sq#eL#r8j%y=I?W_-v;e9R|&%4dAe7ktfkXfwkboAI0fR}Mi0qtDDx!s&~5Hq$$s zsntxaW**KF=rL1|nR?93Ad@Vz$sw0QDyT)9nbT=xK20pZ{mgVfGmm8%%Q+6MW@dbrPZuj>d<4>3}!Nm+0-+K zxy(bSS&LYTH#X~7PGtr9%sL(SGs`=h<#uMRV?A2U(rVWI=rK!=S$fQRh=+NEM|q6L zc>{b0srp9{DUJ?izS*Q0(N>$#XqxDk=IAk}k}9gHVG2{3MlE&dG^dd^7SYZz9LqAiu{myM&grb=Y*wSyob_zvPByWb zySSTsxR?95p9gpto#yB?N2fV2@jAPB1Gh8hV?Nm$??7N)C}H$Kt9e?@8&4uhOdy#QQb}VXlSs##o2Sz}o#yE@ zub3%JWg4}3bMxlV%tBhwYMxf}R-wl{J?5Rq`CPz-T*MmIvW`p9YM$Rm^KRuf?%`hU z<9@ukdEVSSe=VE0jpxv6o>udAqsKfw=IvoG``FL7e8=}3K&N?s1_BL!7d33E4dNhqjZ zoXDwoXAN34Xw`5NH={>`9u0al+|C_rU?X?337s0WY4FAxp5__0vjcq^^l8||+qj(u z@2o+q2CW+Y3j`Vi1ffTx9*uf5hS7tbgwu$dowP}2x5BQKT`3m>a=w2ER@&mu{M<6g?tNB{ZA5IJ-&||(H z^G7k7IO0iQ3_8u%X8sWz$x#$gh(7c6nO{ydGw`nFYc*f1`R-%>Nt}!x^Yxgo$NbYc zot2!ynXKX>F5_~p;0A8wPTb4<&D_O(Y(cB}TFrllcXqov}$r2O_$(zOOqZ=dNk?LbR}1DHP>)0`ZV3aJ@}o| zq)pS~Jb^w<`ZR6D%{1-gHMDBds>yvc{lJgt(WFO{9!PsgZ5Ax%L{37V1*hPC z7M#TeT!>Z+v|4Z%ccaGwJr?M(;C>$9LALM^52MopZ5DV-3wH1d@9-}AEO?)f`JBD% zL#qW^HM@`IzUa}cN3$Ny0~tgFkqjmZotm|2_LiEHn82YNhCa>uG-r@Q38lE5X04jF zYVM#DJ(~4s)}wg|OF4#PS;lg7YSyOtTvl@)mvAZiG+&PUX}+G@aXZagHEY%U5-+1i zvmVWQG{4GDUgLFk@di3IYty`&ula@p9K^je|Ha?@69_B}!tE^7YN1vO$1xr~7V5E3 zkA=ykkV+a8nS@RYwOQzQ&cZ^9sG=J8ve3OOtY;35G~;#_w$RODR-wm2Jr?S*@O&=d zLM~zrYgva*3$Ni8Zsj)a;a=|Jejeg6+|I&nJcm{bUu8FXEYxG+9`>@2{d~)Je2-QO z-O)m=T7n57l>Q80AcJr}E$*kq@8ym1xzXRm)A>j2_DFu zeOla4%iFk}mQT>CMXQ$o0)f^5LFmz{N2?yKVf3IU;q;;(gYi43HI|Vil7v33`m|2u z5Zq2{CR(*>)jE#`+)Aq+t$MWT(b~*HTJVFkw$X{V)p|0ga4KhW4y$l4t?RiMZ>;qS z+)k@jt+(<7PohVw9<6$`KFe0N@f^?d0y?#7)9QCl>j!+uZoWpJ);+kN)`R@cAAvxd zR&83f4JQUY+Vp7CqiqzUi6fo_#-LN1Hf?_Av>nM&6i`SJ#gtRc3}&KLn^tWnauRy9 z>CvV~+X_zObXIZ(XR?Zm@H?mNa|B1oG;L+?K^(qSAGiw76lPZ2%&`27q_!03au7twdin;K#xUwEIOJDGRY#F z9CFcVQ3bWsF`aod&`3KSxSd5^EM+-bEn2~4=&?wTMOShaS91;5avj%m13E3b6Tfp7 zJ%CP&p5RGd7p7(>a@ZytU2+cxRp7S*KQ=T6JE?Md;C~ zN9Q`$b1|22DVK3MI(6Q}M!d1kO+3JZY{BhxKEtzY#T|8eXPsJgzR7;{===^nIuCG= zANY}<_?ch$BM|5cpiNgVdNY_P^y!Mm{dBpXE^n+WktDS0(yFT*J-YPh(xa=I8m2In zY1C4OPF;<(v50n-v7F;L9{1Dbe!5n1E?RYI)wKaVy7cJMqiZvFaX0sHFZXdj5Ah_= zqfOU~?BWgd>3R$I)8(CYxt%U=tm|vE>e8yaCwg@2(XB^!ANtad{tRFsgV3pa1hM#i z)IE;z=+r%lbad)=JKb4ilY=|zE}@1g=+Ui5cL$vqrMsKOEMY0fa4b4?ufQAY)~Wkk z*0K(_)9sCQU(0p4qwd?#s#~jWJ-T1yC0=GbJ9vdx*~x3Xj!xYl@+CTT>(u=n-*W)B z)BPuZ@pmBLM-43Y&K7I6xF2KDW3e8K^;n$51d>T1l{6-D2uG8THj4|Xq>5_X&SGzD zaXoWzM~j=$YH=55qsL-B7VEKiHRo|Y7jPjLv4)Ge3T+nO%q?tUGj3<`!#u*HJc)O< zSgXZaE&c*M7VEKCkHuf}4SU$jKKAo12l8pC#HXna?8H>A)LX;*BkFJ4;UB6i!F0C9Am+ zJ(lRPM2{u6avQgE2OHSPo!re9v{~{LPxB%#@iN}n61TJDZQkJnK0&J`-=K$c4lLDU zX)qy#5=IYt5>7AN(bBJbr3>ACuII(|&PUGqp8NNwH8<0NTj+@W47Q)a z5AYxlq19lm2J10ckHLBj?n^)V^FAN&As;b-PZ@?bgF^{pB9m}igQKyX!7n=nK_NRSVJ}r^Gq{GMe92dwz;*`z%rBhcPyPx7hMY-L^cbSY z5Iu&pp)J>OJ?&`E4cv%ML++#tU3q{fcoMfY#CC?fz>B=fn`kvet0AKaL60GN3<+lp z5sYOVxKS`EFQ&gd~zkD+=DeUOKEm`8Y&$LPj$ zyn;4EU*kRcqR-I&*w4^Uu$`g9(Q2qxL+28U9z*pQs>jd-=Cgo>EFuwohPthxS*%5y zp*iGI#4g;{P}><=&OWpns@2e6`Hhq4F;tJC|L^e!fASZ9^G_f!OrK%r(25JuX4o}c zi$25j8P<-QxScz&oncxH(`wjDyo?^h^cbecu-AEmH+hTRyp2x7v>Em}gBijoMq@9- zCgQe+O=cRlGfb;tS`Ax6CVC9hW0)Sp*0X_)Y+^H8$fJ-lv>8@G71ii7td<78U= zc7|y+OsnA+&oNRdF5yxx<8rRxN^~0Do=)7#ZFHs!U3mce8U6&%Vmrg1N2}pl z4IhLa!}S=h$MB&HV>lxiNf5z=G9GP)M=_nb#4?X$+}3d08NP&NtU{~d>nTHz;d%_; z!(R5Wp937^5S8dO+-(j2mhbqUQ=H~^{=j}l*v|;>@`&cNK&ug2jp&3PBlH+?J9ls= zcX2oOa4+|v(}>4-nrF~y#H+l<>%4*ejIf^(1Na!NMrbu65$^rROr@FF^m)Mn)S ze87hcW(fL>97Yf!*v`laxU-R3jnryn8hVV>W27D!ghkR3eqa5AN|oINRJ>rf<9sZA2X0o_!OOjv5s(iypyx1nUvpo*TH4o4A<{+=|-@eh_VfAErA!u$SPMc$rslSHZRutW~g9!C{1> zN3b5jdIXPSJQJA6BqpO%ur|R7%x3{hNX1@)?Ik#qEH>b-f^8>QtKc2fas)ks^$6A@ zxREb7%9nh_*XR_iP4FN5$zOrMsAimnKBLZ|C9Svu+ZmqdRgpwln%(v>L6|=-1F=v>v1N82uK#d7F3W!@Io4`+R~n zqlYtsF+?zyaoEr3NNi_x40F(Gv{s|nqsM4HMsH#>TgWDdT=Lk8PNUt{=zZ+x0JR+9 z8;)@t+Zp{Mzo6A1QEZ=@+Jv0qG`|M|p=WR=O|hNOb2$&KLNDVsZby$$ zJwo*ey_>RWSyO4{pmoR$?YfT&6RhYX9(<)4>F#8C5nrF}>Oph=s zNoWS^FxzC)kz|M&Tsll;TK*v^;$T8+_a z%ysB7MvpOijJbguxrv+Uz%6t{r!n{OFpuyk&+shI@jNf`Dz-DG5AUMYm;pqf#~3}v zjAsH9nZ#tKFqKH`XpB~47P5#$ma~GDtipcAxUVs`GbR_U#%MLBj(YSM)5sSbiyMouqljv1ILepk5%K>X|MFiT;HL|WZNeFxNmH7k)!61} zHTFub;%eH_9yd1DcE;Ypo!mL0`*th7-+q^>`-sL^|(vSYUk4|GhCkUO!>NM5| z8#|6Dreix}XA*-u8>`h=t;TLbkFk1;)njZ9x#Y2xdc z>&C|Z$S<5itFiwD0^@9D+!g3CPLFYVjJt+wX-ym2ave9&iF?pyoEsbWFpuykwlmI+ zje8C^Htt1UMXPar7>OR^^cbhdxY2|VN*LjcA%Y1^Lz{7Pm`fr_B$GlK?rdBZYjI=a z)}z(9JoFf+$GF2(QB4iC9HEYS8u${e#{J4~oaDbiV0?fkoWWVx&v{$jKmuhn=x z#@~w`l%;P+bHsfF7W!|9=@A4k+V?X2F*!Up~MXT{zjgLW(@p_Dp zWgcj#-HLe zzw-xw@)tTy&}PEfX2Pd@#vp zC}B6H9N-}J*vo`QzTj)VMXL!~O>99+&O?uhdQ8+~;)Ptq#azOr=rge`H`4)aCf>!} zJcPYWe1u1NlBdvWqE-_>W+0!S$3#6Q>M`+i1~Y`A3?qneCNY^Q%pw|lnP@K)?PcO3 zQbXpA0;rU zDOyd^YLb0Sx{;gEW0D?|^qACSnzy5g25J%KipdeRGhCh0TjRcvNbU;3fd zB&{ad#-s^M#D|!q$0R)_O(l|PL@^zGCdHA2TbiWJq!p}W74|a8UM6i~Gwy0q0oy2H zH%HN9k{*-vnDhyGr5W*Xf;`@$^Y_SAmC31rsy$6k11!;lxCd8 z*_=a5F6L^qnQ|>RaWnc%(PxVNOmSaRY-h>?Xf;KvDR1)*eb8fy9#iy~(vSYU&j)ylEY{- zrI9ZPMj2=_jr7YN+K1b=1?qmwd;sXfyRB|L|`h5NR)w=hB=OT!8IFY89zf zJiz6t~|hlJjBC1&eObzHjyvWo42u-$d4Gn$GEFV+lkaFQme?>#Gpr{ z9+7%P&LfU^5}3~dbc)m_ay4tnB%2)ciPR@@8#^hd0<9voinNc&pZNtnBK3&WBk~ld z`JF%b6Md$+t!d|RKH5yXlB>9yYiLV*I&mvnP19zDBPXzzD0_+ei@yVb=>eLe z)%5eYfg90dx*pT@n0^Z#>BOzv#_ilqSKQKcZKgj-PkN!x^cS(8>2K1PerPpatLgSJ zeFAz+*JHXK)2A?%NTv~m4>&!VIFit2dI~F8iM>p>m+2eXL=O3AHC?Oe_A&hn^q8*4 zbUmhj%{Lt5IN$Oe`bW?af;Tt#cNnxWMU`Ra1Wi)YNl2*ZDZzJ^hS@Fdd$>g=DWN{U;5D>eP#|~ zBtd91a~$K*XQngErCHj{x|c_I6n$nr zj{VGfhL?C5t!8O8Yd9m&W0oGX^q4h@(S#667~$wNOPg74Y1V9Fn9l+hVlT6nu^hKG zD}yYwnw8Cd^q8f`EInpba+oTrsiBr5=rrpXKk+la@F#x-0@3yoeHLeP4lS{rXsx2P zioTP(&?8!pXg#9u<9<5Rg|0k+PSM&#_oNpu@D{z%C;A=w@&TV=JJDK2YZYzG(X-Ga zT90TwqUSJ|SmqH&Jo-d0VHN3U6TOMeY#|%_iQdj`Y$sZ)Xsx1u;73lNN35r_pEj88oK_+RVO;%h6}HKC`doIy!I*TFusK_Om?4^XM^KkJ)<6evy}WnOAs~ zH+hc%e9S>tb0ar# zGk0+}_i!&=c!+M;PK;JDTE%>X9x-~v=n?Y?pYj=l_?*EEVFYd~#+wtPP0S=_Fq3!^ zn2+0vNy2tww2ILxrjVWJ5u-Jh6)Y!12Pv6XxZ*v3xEIEXf}mDJO~ zw|vL<*iP)vxU1MxXchZkATaN8^q8l|JU!-J%{5$0YueD3>$rhVXfy9#?&Dz|;ZdI9 zS!`$C^SsEbXf>}7Bhh1?9`i;qnh-(>Bb+frU`O+&q0PKG%w-{qSjKW}XWmLyvlgx9 zX*KTv2RVcu^A1x*H8s?7ggU<9INHqngz9Y61uT{KO@%9nl6FuVfh}R?jC0^zgUgb4j zN1u4N6+e(q&?bI3Be0ivdx>{j@op=A5|L;XuT{K##IGV9J>vC<*CRfYEY`A)^=u}e zT@+KoKK5fT@%9p5PXk|a46Wj|O0bWF=CnYM1U(Y;NVtGjT*yUS%;mJ^MsDI}?&5Cr zNzf;u3lGta?r4>uRf2sa*hj+0=#ijDf*uKQRN%)>0_z`N00e>%-3W7WTr5cNTw0RbfSqvoB7G4u!5D?%lr*&WE1Xcem+{w*J^$vdd$~j zz8>?x;%mO)7{~dR?>K?mn*T4__&EX#n$rS(7MzFuEVz_wv7H54EzoMgBRq;83-nl^ z$ATy6Mt6Gf6i=hm0&Nz&%{%nrLq5V@77S$=!wDu7trlptU?Gc0M2`h}EYM@YVwR9f z8cWe|rnaIE3vi&}xBJ3+!XT-~7YB=;2QX7B=Aw&ZH^LI2X6I z@CvTvDz2v;w_+~~Z|4r&)xyqbwNR^tZ}Jws(PN<=3-ws|F7MHoe)LD5g@YJL5ZWw^ zU@X(HmxcDSa0au9MXQBcEwqn?o7jvV3-ws2$HH9l*h)SH=(DhtG7h56!b%#^XQ4g| zzr=nPe$Q{5)nq{kvX7G2FXTuW=((3b1aYLOi+(rVGY+{gVq#^XG} zli1Iq=dhhcukspwc$XmbSTu^!gb+#?;fz76MPr$WR*U8^msot@MTsoOZ7s5$MXOlD zI<#7()uMwOLXSmn_)~$zCfHA+{Uo}p#EZ}> zQL996aN<4ak*G(a9*LdlLRTK(K^{V?0{1J(BcD(jzI8EY`A) z^=v?=ByEz4DPcGJIe@(+)zd&DUvV6*lC(AEKcXJQ=B~>BpX4wmG6`*xXEKWf z>?L^t3rQvwt&+7$-boR=&?8xoWId8gDWjYU_MlI44M*|jBx{rW13zLf$@Y?LFUf!L zUm%cjCR(Lvm0}+$H*h0*r09{NN6Ia9q!YJt8+Xx#$MEK)Ji+tyM4uFWQeMGkQr@F4 zTBT@}Vjn5?kum{2QuIjCBV`IxiDVj4=#w%Jx0I5EHYqDvMLHQ|VKXUtY$YG9QnX5G zYS*lj4TBTmeRoF_Z9;tey>XF)pwp_>cwBsgj<38?3o7Bg7f+y+5 z)3~!#+ev*5tx~m04I-FP=#i>NsvfCfgfoT+#xfDNl{$yH#F9iZDd>~B6nB=omUU>A zs#U6eq}oSnC3>Xlk*Y^(4YeGhj(U#bwo-rLSAOGP{tE=s0yLo+Hk0OEPP+)L(zHsm zk2L#8yB9su^hnbqtqWawfCqVq$9M{FPTGsS#9Q>{1MDU3BL?s(gBgNWX``7<40@#L zk)}u5JmQEaf%z;zr!;NSRajG7wX9=38`wetZfR)= zyV=hH>adrk4K(r<$I)u3R?C{xf|ls9Opj%HENjJuT*Sp(fe<{tD} zrq8mjJWO|bU^~mSTBg;qj~R#_%k)^L$Ff0u&R~Wxlws(!Oq*qsn9LMr5skepvzKKH zS%kY^2d1sZ_e_b^g^HI`YgAf=B&_WMH9}YIrg&RQZD0iuEus&XthGC6_4^5 zdaTf6g&r%q(VZSV#nU{4PAjxo@eX}>mya2UJ}dNDF___m5{6bQv|3>wD-uaUj}>~X z&|}3CQb}Ve%g|@VTD&m@qIJ8=+)k^zVxdlB|>akLfm3eF>p8~eA9i3Kcv+@v? z9Oes-@+Dt!oF6#JDNdu6?15ERpvNjbR_U?o8m^@^ZD`ANT+fZ%iZ-k6<9;6DQJ&#h zp5uAk)hgRrrPV5}R*fVGJyz+lYBV8)5=J;etx;E(we>?ggDGHfTk0J&+0f9 zu!K~!TCLUUofNT)V)R(8$LdnbD5ruw9H0ibwA!1q`YV3mM}Eg%R{zOg{1*tUITNkc zXtl;R*4)62=&?qRHF~VMg^qOMR&L`iy5N@9JkAq5%X7Sjy{vhIH*r^M`l8hut=8Da zn(<6Pk2QL%(PPaNrV`0CqL{@z+|n9v&YEPFvx1e_%bE>rWD_~$qt%*X8u9L~jFGVLYvQZC~vTBB8_R+*3RD0*b-k*P=KlXRmy zJ$QQPNp`QJ1Ih+Onox#Cvz`VRHIdtZ(X|t{;y?BAQ=#4(>-obv>eZXf7!gkhawN9&bv(RIm9_#d2H;1{zGLJao zNkFG{sic#^YBsWo&1`1}h1kxz63WqPT_q>bW1SxB^jP;Rzj2aNoaT4_;GaNXeN(hq ze;(&^1y^zvS7Sfx+hIHFJE7Hjt=2zJPxM%?$NCp}iI;hWS9y)s(P_QgT0f9a_>|#{ zU=sUw{bgnpwmWeHa@|VbmMt?(u+57V;g(p#x}mk`)IZCGbW4(`IcphY(5_lbM1(n*OcyaHtJPFKa0s3Sw z#VuufbF#I`-pm$uU@zJBl3m1ZD$puht8Dwo{uys@wjSAfWb2WAiqrhgAN+|vIn6i^ zx0Itz&Xrt+J~{g2w8ds}+)~c1XqBT?j&0=h;sx}`(IZEXoL6|2*La;b&?l!qpWv2q zw8;q~m{E)-9Gl6BWExuKXq96hIq77eM~)sjdgNrWmUXOW1N!8+t(;;?&?aX;2dKkd za_l9ik*_$8RykVb+DC2+TB1j;9=Uqtw&FrA;$kl03fgcJZYj3|cXAhZV=uW6^9YaP zu5zD3tK1i{kKBRik*i0p9=U_~oWTrXD8tYxSDRe7lslOz%pw|l$+ef}LEqe1Vwv(q--lt4pB6{TM zk*7!AR3e#16w{f(Y~o2qo4m!OlYu^YYp|cZP2^)cd0ORZmG=cl(IZcfJU#Nh;TXsH zmhbqUpKx1w{{;eDwb|N)b7@WsF6A;V$9A?}LtC!ndTya3dTiBWYd5;ngQs|!XLuH^ zwraK2j<#yG^*#F14}G?N#vne&ezw}r)-gn&)z+ybqsLY~wk{!+G?ucA<*Z;OI&F1Z zTm9%;eYvgq?4p?cxUH?Wv-J?w)KQOCTaN_-{&^r@kNh(@lcqG|EY9W}&PA*I^U*5* zT3XYF4(OAwPktxv;2s{to#ktluT_2@-sL^?$k!vkKkxGaAMz0c&?#S={18G3V=_~i zN+kA^Z$J47%txzyt@3loMUQ+v@_oVl0=BW89Tc*Y65LjP724$2@D*R9PyYY=e2@L) z|IQzQK!H{TS`}Qy)m(!f1$q?dQP7s_xSn>j=Vshi!Tofm3s3MQ`V@5M8G7;>ucK9g zRt3R~Vl;Xb=ux0YK{#WGU@YU9gxe~ZODyw9CIx*8^eI@zD%@4UdbBFgs=z)9DmjcE z1$q?dQBcbf>ZqrIFZqsN`HhqO!@q&RwsWwTZOv)H1ze0)+qBwd8{6*XKJ?h8$2L8- zb>#sbp4@gy*x z1thT)x3p~ynPihgE_rNYC*@S2)i$lR*~Ye?`2{_;>9I|ZZKpWR@BG1^=(D{U=i!#N zYqR}Iu0o&f`fP7Yd)(6YThVH}R@-f3doNx6N?bC=ttL<8CPbULCw(GH7kL_8kWgY9;z(#c1uFZD0w0$?F9HJ6^ zwpVe4Mvn6>T5Z>Ahkfj5i5@%j*rCUcR$RzMT+Ah0icUMU+2NLUbl?{5;%@9^$HP3r zqddt|XthJD9Un6gJ$C4^LysMU_?*EEVJO4UX@@pD+|mwj&WTyD8kTcr&c@dV`m~s=&@6eoqFtCLMmx2Wf}VH zT#H-UnS(Yv3-RT4?!jJm?qffd)S%T)t#}A)pJje66 zt6jFUORHU4?HWlCdhF6;*JwfrC5&*!5P?p+rV+y&=CY7Q*vqcvtY9Upv7KF7?b2%3 z0S=5r}>>f z(5Xb5l9rsu`CP{3*h`7Ml(?;u_S{S-v?|f6#6C)T(hEIG^eB0WmwAO(d5zc6sYIKS zfqcTJ3}*!PQerP9V;P6LDv3m^60J(?qhu9&lw_bs$r>`rVlC@fk4`1plsJkKKYU3E z2RMj6CHj=qP|r6UL#q<4cAragTF??bcI&bG0$On)7jZHA>~4))+IWLZ?z~N)t&UndPj&UP{-qfsMGU(yeG!s#R$Njp$LTN2wmAU-32H zaE#-8i%zB5l)9x-Z%*ldfk4^WoWr@;OW7q{%4J-I?UZR%b`y`FN0}aFdXzoElXRmy zJ$Q}4OeQ+9yE)S^|{SLjiuN0}aG7ASAR8JtN|nsF9q(*n0uu1)#X zT*Hmr#LaZTe#-5q++CG-MXPeH%6s!RdX(!?{x0v)mwxo;eLg^^a<^3;%qT`Pj`2)q z1~ajp@;StzRk>E>o7sXM<$9FsQJ%+E@+n{&+tH`omoE3_lvkon`4=2TpK^W5kMjez zQ+^7q%C)MvoGZ8zJu395(4*p7TGNKMT*nQ#t%`fNm-~2_M|hfNcow%+@dCC}p;d)e z6(bl)5PDSTQK3gg2%&@#&KUHmh{T&y5rZ}ri%3MD3VkY4SxzQdXjP$Ag?&^U;2?Tb z=ux3ZMHSW5P|Fb-ImS=?%rE@OUxC1$X4uOfd)adiEop^Td$ihP8+-2JZuHor#~wZQ z+)rn^(3J%zI?!E3_`0tTJ5oqJ+p{Lk3D+q(PPhCVwp!A z@hoHsZfQ?C8Ej%RTgYZBHnV3prD(NBt39@{=SNPU#~wZQ=&|Qle&ZykIE_Ag&!9PO zX|FbWFXM9b*{jdqYq6QV9k>Op_G-1)KK4Gx^XRcxkG*>AeUX=VnOAs~H+hc%e9Sa#Zlo7p>=DNIGHy|Y=tO7z&P$6h`5u4WCHWU-cY=(Jaxy>4mmE{fU9KI~<$ zz3i={9(T3(8?@T1)js>!cP@JD(_^0=`_AKhE}#_`auGW1(`KJr+UL#LcN4dB2lle> z0UqQb9-|vt?bB-ChkS${`}EkS$G%Val+PH%=L|-tecJ4EOZz4;k?G99UiR6`z69oz z$YN|~pH}1A+av zvtO(ITJ3K~d-T|^$9_Hb-%JN?p(CBRl{@K77qr>`I8X2_&+$C3^9HuF|1J8^kN$kZ zr|7X?kNuOF%oL^)$uy#vj#m5aXunqblSyGQ>142)HQ3MoO?a307ogRCt@eMxQS{jV z6<_lW$2iWne8>0vgjW0i3j_`XXu`QP=MpZ(b`D(5)wDsY16mz;6g>{;aX^m)PtuL< z^x!F;<{5h8whp|5HV5A2V+Nwn0eueG&jI^65K0)~XmvoV1GaJ?2|W(zaX^m)OGqV+ zr7UAPIvvpFKn}U&v5R6#*p2-hu%81pxU&OV9nk8)Km3ax2lY6p$H6l=lcqG|EY79{ zZtLJxXmjuy+H(W9a|gC_@GkD7D_R}Y>R@l)MvsGf9Mt3Bd-SCr{du1c(CMHy2ZI^K zXvQ&~3E0cQnam=Zx!BG@tq!KJg>3XVsK-G)4sIo%0=BW89q4pWn}d}cri!C{i9QFv z=39Q`6t;8l_dwu~R)@4YbR~Km(&LaGhpweHZD`ANTu(c0;x@E7bU&SWoF{maZaj_q zI%GSCUPG%xS{({Pk3)JK(&JDFp@b367$O+UMBLV)IcRezmPI6DFNapJl2xq1b`EKE zNUK9eaLAWCREZvk^f**a4YeGhj(T)Dq|KpU_?6%In|}gV9PyCD?m3ma_QF)S6 zoaT4_K%c`+X~}tLbNDhY$6gNG%VB#t+@721gjR>OI&2$WLZ9k+B$9+S)hk(rKGphEXR(1iwqiTg zT2*UR-N+Z{QLRU{9@Ss-4aYdnw|s|A)!J15%YT7@jDebSI2U`Vv6q@lxs0o5jaD^U z)jYzZ=ux9bjUF{m(v9x);3=Nwd0yddw5jRC06s>anoszgVT2HhRyA7H*hkGG649eZ zkD3$~vxHRASc*7_IB>z9y+5{tyZ=6QTrCXc^f@y`|vLB(U*So=OYF& zk|2T^$9VLq)u(nU)0s;wwo|KBtyZ<0*o+>vderJsn@b*B$)|vA?4*o?Xj5BBJq_4P zt-aKK&kwk(+LLHitJRUqxEwu>=y61kBUf_`*V39cw52^Axf^Yc+{;5ejJ+JOmm|;c zEWLOct&V7QWH=+x>@&|tg0(JIMXD@YUaW*Zu0Ilk@sh!47qwYTLr!!sXiavGSc%GhUQ};S=U@vv{QujU|@G+mERh?FKGnmON^r+LL zPLH}d%q5n2#IbHuXaoioMj^OMN(Fa98z{(W+jndfTX9&I*M4QF!>dNkpYSQ4F$jGcMllw*)SyknbY`GW zgFX#&u$cz8)R2r;4O%tWN5gh@P>3E4dNk~!m=bnViargM)Z>;Kv}yQ`@A-ir`30M4 z_?Q0zfkv$wwQ97F#_PBqJsS0B)T8l6ZsKM-a0~i0-pfNgj5du=^9=el>eKiFHq-bv z@6ZRW8b4wT5$MsVN24B%6PU;(CNqVp=+vl9qg!fR$Rd`p9DN#BVn2;*$tDM_8ntS) zkH$LmXw;)okH#-J%9nh_*L;IcjoLK2rN;kJaGzmS(0v?-4AGyxqETHIWIrg_xHc9b6%W% z><akIejipSXjB+ZNicTA~+31!w9?lUQ z%W>GtMtj+K24}LA^U-RfRvYi*ejY%Nje2aq^w_A!#{YU8pqqn%z@`8}=(8z;SmMxT(-4vwiM?zZO(xmo zqSYp?HXXvD%twz+dTi2T)BiYrt;q{g15Y zCw}G^e&tULquwpmYg50CPWI5nUhHRc4|>yw2(;R))#fbp*sRB9JvNUchwDKTIS)Fn!Gtp z3poaTn)GQpkyALErD)ZpRg-Nr-OWAd(WFO{9!(GMAP?~{kDyP}v#i1`HEGlI9`Ex7 z_R{nfU-KR7(5gwRCi`gG$u9J0(xd6W9$oBZANx5F2sG={97Yswsac!m!6czivp&sf zq~n&Fv(c(qt7hA1o=Y8iH0#l#YHJi3j6{#EdTiBWYZhY|OE%-k zA)iUOrLEd*tz-^!(P!&C>}TtdEaG^y+N#x7``CIddTiBWs~%f#WH~o+Gq-RnI&IZv z>w`SOldR-rUSSolVn18oWi__5^)s~Es?}CKw(7A}kF8BK)52D^(aLt(*vY;?V4F7E zdJ=*@+oI@CH1@MC5!>08hF06O+E&3-^w_4ywkoDmO%1ioU?w_kI~;G$HgC?h<2a4e zIfFAATJKL^6t8H3sdz=;Mu}zO{dTe`&r+J2Fd5-7NX`43NKI9`l<}1EtJwNd? zwzKUIHlWoutz-$b2GIjOTJ>nvqqP^Igb_|}B8kJB)9TG>O=cvc(5F?O)@*Vq#&%k@ zYSpUsXcn*#JzDi>)uVM0$8!QFauTQFwpuUZVlLrouHja0<96=g9v(oeR;^m!<9$9r zk5)Ze^=SQs)qKile2zY?Kj6)2_2#r{)4GXzHe)ZXZM3t4-RunnwrjOLm_ZCikL`MF z*JFDMsSG8JVGKv7?b>WFppYUen2J8zE3u#LvzU*&+OE}ht+snxwqJ-I+x6J4$M#FP zjLW%#E4hkmxtY7sX8XN7%40l-y=;Gh7g@y{XtiCd?e?+#SM=Df$96ro|H)tc%?AGA zU-a3&6}Pl~7urY_XbVE0HhtRcr>ze$#G+N3R&9CYGXXu?^k~zgZ6d`?VlpL^Q;l0{ zt79HVauoK`W-o0gvzXIaf>v!>wb@78o!o^UZF;on(RLsA^8gR>5c;$|&C9%kHf`_m zKKiuj)3%x~Sj+cl)uvUOeYEYM13lXGX#1~6Cwu5(FZ(zc2(+7IDS=5rW_qfh%H+)}$Yr(K)&b2*PIu$T6$SjKfM zN2_+N+U=wLMP5RWc0JnlXn&R0c%3(RlXv-qula^G{LC-t)2>hZU)W506V0@sRl8O@ zBIt`AJM`G0$BzC)6GJR<#FI!WZfS=$J4Ta7J`*Uwes+{n#dNgVq1BGXoPr)Z^w^=t zjx#uuvsl8}EaiMI!!7O5X2x`*|DDkbO!<*?yAFfI<)H0sw15Y^ytu|LywM3vKYfy zvKfa?9olqwb2_{^9n+Y}EbOJ@2>!>BEW~y?wCd2R<7%!!j}ARL^ys*O8(Gdx+{`WL z)S*qs;8zLyrzUI`rshqL~)9vW-@D&=m;m z3__co!So>ld)b-500xqT?d;TQr&c@5C`XT-dhFC=XC+lkrIGM$q z!a1DFdDza*i@6-Fc3#h8=&@6eoqFtil9fEg(>%koJjYACfj4KTHakD!OTOZ3*7FlT z^9z5l0j+j61_HYR=&?(WU3%>5NeI0NC5&)-6G>5HcBN@eLGO?dsx!BIGNlZqo zU0UtZW0xMg^w@PQ$FYdxIe`;7iIcITU2bcaHoGq2Qm)}zZsT@rXO|n>buSO1)h?}e zy^kKd^w_1xu8;YI)qKile9jkqgWKBmJKF5}lX^C@g*M#QF5B7FK_~kHf!$i|?#W>E z*saHIJ$9#%%23i6#&AZU({8u5yO1I#GL>oQv%3oW*=;|&594sO+O5^@3%LkAcI&ZQ zkKLDXIahEcSFw!ia9g|YL7Uz8v4SUfl9fD*``T?gyWd2s-CFJbmEX`~w;sFo*!>rO zvw?s3myPJN+imSOqTRdErZb2h=+miBr~P!gug+L(r&Fs=tvd6WKmmGm>d~o3XEBqQ zObMk_P(vN_ID`c(M4wK5I!|CROE?>?I<@MwkIuWe8$CMp=+vY0ejeaK9^zph=NVpM z6|eFx@9{bI()lG{@hv}~Ri{>+_R(n{ojciu9-aU7*h3e4*~k7sz(;{Sq4Xn){tP6M zVc5%_5v1d;_KZcVJzDLtjXiUiiynLQ*rUguLz&NE9L^CO&GERUJ*RU9=W#w)VlR7^ zaW&U-6I$)jYL9K~d5M?NV~-wt^w{$nuk!|P@)r8+S&duTvj%PU{KBv3vqzsjf3uNh zTF`2bR$aEy)faC|mmXbubm`F*O$@Qb5syAysf@%eb!pQzo?P;+=V_}_i!)v)AcA%^9)*bY1Q>L-=IgA z9$nwDmhbt2b^OSBbn0?jT@5tSL_0g^-~inm3^%hg*?SbWv-bqF+N;&xYq<_R_Uf@$kG;#eiJQ5F zTe%IL_G+{D37%vnFY^kkcoqBE>%R8d&fZVaYOhv%H?svj_Uf@$kG;*bu$67JvK@W) zin6Z<-kg2f?2Duy`s~wZUmWghpY7}$idOry+E-2mQ_*9e9{cpzH=Sx~sAUFoIE;lH z!?7&p6i&rn_MON1T)-vR&OWX7-N56lK#zTT?9*f4Q#{QxJj-)Dk52ov+4mtI@iAZV zHTJUaCw}G^{=jzjX|+$Q{r0gx2tD@ev0snC zU#tCE?SG#S_z*qz>#_e6R`V&J@i|}c4eR(FZTA03J)5zY{cW_fgWcH90j&;bbzl&K z(c^#~2lP0QLMlT^V;IBH>3}u|3MizAGRm=+12dV$Z02zoS{=~pfPEaekc+q&Jr3w` z;4&`f3a;cT^f_=d-kbyXpv{5DS%E$W^f~YhFYr2VU^@r2I-u2oU-=C^4(M?}j{|@4 zHyikef7!?uwy_Is4s-?r-9hvqn4Z{AcLcH6PPbOwT6O0$0X@3)=+>iqBE?K%G9{E! zK@HxVZf&{`VF3%#r~6p!r+YC=I2*0Hwd%Hy?z_;VTaRu%y6@wD9^gS9;$d{^)~5Rv zR`DwD^8xyF>(l)yU-CUapjEe4-S*Ml!A|t()}#Bs9((9wFZTytygNHJo!#JEHIGW>eO9xNq3@+e8^f{={ z!OL03a&AJagIXPYk(YQGJr3$|P>+MJ@j7qtCU5Z`t8q&Q*YGXB@GHOZJAY#{2b*a@ ztAjfOL4gSR5=lRz=ub2;#1cn5iKH@;QH&;!d?rvpF{M;7ojJ^9F{f}Ur*S%Ga3*K5 zgtJ-7`CP`eT*vj?!JXX2-Q3T^tmG+P;$^<%E57C%*6=Ogv6k=ofpz@MUud_-ek03pQ8fl`L7PhjDR&)yL3Iz2Cq6fkBMV}t}^oYWKdJG^1+v%ZI53PEXQH~xx z^yr~Sk4mbTPBk^uqEioTdMsce$8a)>v6mj_a4zR@5w_Dqs~%eQc$CM`qlX?n^yu*< zD|w2id4^|sk=J=2ZF+pj7kr7m^!SnW{KRkAP7kemXw{>egMlE=Zcwlu!FmMi5!{my zdJ#$(5yUWv!6cDR2Kof+6Fi0-ikOI2!CD0$$x$4Q9>ID9>k)h`$FYdxIRSlw&*B0u zM4RBNSjNrROYp7S#$DWpR>4{Y+eh%byoVmadIakc{1G4X39I=OeS+8W3%{aG@Fwcf zCs?20W?I=zCtCH?s;6!A97rO1^wguL9zBPUObV$CWdvE|kySazQ(5L4Lp5SSo=QUnOtDai* z{Fz_Sqo*D{f9DVWxgPrW+0NsJ05PJy;r#F3YS0T0&qE(1iA-U)g zqDP1xAq5mt#6*gj#AM2tjyESnn~*w=;%M{<(I;dPCvhgW6QWg!Rw1`@2X~@Jh#nz& zgxt%0+|L6%$fLNeke7IwS9qIu_>|B19Jdwn4Ym`aRftw0ZM3rkJwo&d(IaFxo$R5D zz39`+ZT0fz^om5AUI`4qUV5c5jN!PeUbfRqt6p05vX5S~n2jF2^ysBWuX!B8q0Hwn zj^sE_;Z#oJ9M0uD?4_5z^ty^=T*q>>>U9?{@FIHj(xaCiy;kumukku>@Fwr_316d4 zuQjaaC+ww{z4ZE*jkv2`?y8qoy|fCokI)G82-PE0kI*Rk6HN@U#4(T*GSDV;6giB? zUPA39w1iSBs6wkytwK*`F?xjR5voV%>72otoW&B(MxW42aZ91sqD|=S+<`u!`h?m~ z=tDfoO0){qD%3tgzvL_Q2-PE0kI--Vjqeqw?VS0p(CX+12Fcy8niYTKTZNh4q!F=o`>~N02U4%XPZQP4n3iIZKJg3BQPo(JEZ4aN7ufm`BhfT#s-)!dLJF zPqLDy&?kHq-kNZ?6s}G9=X`-a;rfJsi_L`p#_wnqu2r~ggzx77dW7rYYj;rZAbJo? zPeKSMiUGK#-iZujIQsO~r}t=VruPI2D5MCjdTZ7Df9TO$kKTIpUcf?*;aHAi5yzub zZ@1O^d@kTZuH-6~aWl7YE4I_yUG=^Xt$IJsJLu6{kKXU|0Uz=aAM**T`4pXcujLnh zefq5A zS!}1zt7z3nt3K=biJ#G&@F#!qHydf99dAyb4i3=G!9Y+%fS!b5I}!cS zDnhG>9LAH29uay(=n+vsAw^827=0q#R>Ul3qfNx&9Kj;&CE^55?7hf zZby#@JtFjoxSM;pm;1P%hk240c#)TQlee&!2z!b6l+SQi5$-BNs|c+kY$IYjZRio9 zM}!^`JK4o3aoNat$}2Ro^>!j_1*%uO5B%==(CS zu!>iCjn{dbk8n$Uwdwmc>-h9b^xZ%MjcC{ zMQRi2mLk15ks0JLo?P-MWD--EhE|bUMcPN?N$3%&N2DH+r*ayna|UN}7Wzb9j9ZGl z8f_wP$*)F<*D9$*DepjD(+k@gY!IbWbhq#luaM1I2>zU4dC@*}_FmLk15k@ak4 z8=croWEXpJSN(dRRX?rzr7?`*=+RG)etPs9$tXsXNfzTMz%BKgLK(HpK%aj4^s8e& z3s{Kl^wX-JR{iXw-&N?*Pmg|j^t+bpxSkuhk>%*rPn&*^@F^oY_UN{^^=DwxVNDyc%JC~czt$B`VxiJXK!QTjyLPt+1F(Z*a7&L?@z0v>wrVL=PdE6jB+=2;5e59{Eh5 zgi@-h!FHnESo9nYL91x3qR-_#&PR`EJ)-r9zL-n6l*_mreWKk~^c~!ZHqnppDEdU} z6TOmWv7Kn!iPkDwtLXLogf}=^k7zxj^@#qRKlqcs_#1tq-BxrvJJ2S2ANvDAG4>K; zFEREK6HZ_Hqg9MnF}4vio?P^Z(IZBWm;wqZVj{)p6H|#dCuTO<#QcvV(I-Zqm}9Y- znA16fGtnwWtC-uk9X(?7h|weFZtme;?&E$QK&KdOVqWAWUgjO%Zl5ylvC<*CT!uqsb(TG3XOt$P~)Z zCccJR>?Ph_;t%6+j^Y@!iq|UMKH{%p8G6L)5wA!5bzIL4+{kinZy)jY5x)^V;`NBvBYq1FG}1&f`o!^zl(IY{R1U&`>2%-nU^hBQlZfigS1JGtbDnm)bUIy69fU#tgO96#Up^PKYV}Kq5 z^cZk73s}f89LsSm;w0SG0Br`G&jnn;mDtOGo4A=NahZ==TmJqEnT z`+UHMe8k6mf=&az8k4 zGw^n_8TbGXVlM-q;%T1Y1#D-aRs*#fxQ-uLj~)Z{7^ugMqcv`W+}(LNGy;a2oW)FV-k#5=i*ySayZ(I?SuB|gXVXp{IlZ}1WJl4vi9 zt8rI}-=I~ZR*CkJxQ$lyNYo=ykHj5xu#;WvMxQ}Jgwq>s2E`DIy$rIKLH05zmEnv; zt3g@~vX4PE)S|~AJqGD9Xf|`0OC9q#j0K#CTN-pSXR{Q22I({CLTqNxHC)SeXf;Ty zLH04|S@amB#~?ihy~s(S+|nRz27Spoeq=pAVLyZZVl!LNYLHfgLkUBV z!FmkVV{in0iKHJ<^e2wNxUIoj4IV){8R#>3Jh|jyKZD)ZVA~lyjY_J}YOq#=^%%UE zQ#h5=IGr;%le1WYW`oZ|r@_~7E!S~7cW@_naUT!yBrDNsuvUY=;7h*ZYrbI(-|`)6 z`JNxpX|UTGT#rtJx6sOVy0D$W``8}{N($i4lC(+qbG?`>EhOy|B zR74r&R8Y$dW@0-@hjRpOEXj_Nyvs>iC7sGLu11d}J(BcDx}F=jk>%XP&FGY*P10jL zjvGsQj^}Y(Nw$;p7H{)D?kq{GB(0J*vI#ws^hnYpsewkCXr_g&w9(1IK+q6vhPbgI z;q)dJ+Zhs10)ud8L$n&A)sRxApvMqBhUhV5D$}T>is@9N&yYhnilfnH$cdbUy$rFJ zAxk-j3%CTWhG;e9VIJX8^cbSY5Iu%G!IP}yDV|23A+Pc-@1f0*&-k1#u$Lk0_>uMe zitP;1YRF~|(2X9+dL-+S+=F0x5<)LR=|eP$Xp=mc5u~F}@<{9_c^rkymR9M8$Pt>p93Ciz0HFJzdZg%) zlEe^_NgaE;{9;tey>XCXEcXJQ-av%DnK7m_GeF1G!-{NibN!2Iy zLss(*YtSlHt5n-aZDl)pr0S8XM`{N<*~M-;*%t^J+JoM>rJ)hT5=SyA*vrtNxT~R~ z&}yhwL+xXzeGHv}9z*pQs>jed%%zTb9D+VW7jhDAX{a_smvA2<8qd99a;_5 zYN&k-eU|6YW2hcO^%(jRFY^kkc$GK#fX{JDL%-yEeqbH;GSps%{>=t9(STM%+X6vp zVT7YcnjUF-r1d3|enioqXyQr2Ev0Fbmd-eG&?hYy`$;RNf~jbgrd67Kq@9Q!X?mpT zk#-8FavG;|24}LAi?|AH(yrzfZsj&^$9~f8=W$k`Rhm|5pYj=cr0J2SN7`3>%{Q#! zTfRe|wBK+`Y2KVPZPHrUioK-SOWGc~I1mUL7KB#Av>Ij~!_pXr9>eq)rpK@hMly=g zWRlGUN+@Lt)2YT@hS|%oLz&P2Sb$c;v>Ij~!>-^;^cbecFg=D{!?j$;_1wVC+{HsY z%p*L-)2zZ?hP}q?xT|6Bqt!62hS|q3`xy2QdJNNJm>$FG*~}IiXhff39k``o-kf3D z3=g3fq1emtXkv(E0E5wL_;4mM89j#UFb~wHp2a52D9#J%;Ns{81j`aaQmIPx1^e zgjOT$W5i(`jvgcQ7@^0Aqd1xcEaVvU8F4CZX~a2bGvactK%Wu%jJTE?xq~~=YJ^rJ z>|?|myonwo^cbPXhCx6j^y^Lt0nO1h7)d;Q9?IYbj(&Nx0 zU5|7<(g%{rAO@3!KIs{_rF3sjx;E)WOk^tdl3qy_waiAVbgk0uBYg>Hqer?P>3XD} z$N5~qgZ6p1Aen5|OJ<|0^|B0XZ zgQB4inWX$6b>?OlqGVCSeSWaLuT4iXJVH+9Cxd}Zo^vKX7<2G*R4({YG^vQUX zr*TUe+GMQaRqQ3hUNY<@<0ITv#+Q7BRvGJPrUgAR^vKX7V>@lMvx5$HqEm)8Bi+)- zFv5u;7JWv>V?QH@FoJZn8mZMt`xrSLJx1y=Qjd`{n8_?=Gl#hx%2Bwbk=l$rk+WFB z*(~LJE@l~5qt!^QM%u^7r_f`h9wYS_`5e#l0x$9sFY_Aj;+95gGx9UOLgBPF{f}Ur=im*ZAM*=H)qt9EaxWl8FdSHa1W1QJEI;$ zt5I5w`UE{j=`l)=QJ?b#U-A`S^9^hG9=A1W1KN!Gmln3NjaKYu)NZ=5ozYs2)@pPL zspv6UkI{OJ9?l5T$zUX-7=zmyJqc|_mrzL+_A zT946Jv5c#^hHJSFoknXj`T-u~A)aI<_A>evR`DutVmqU?8m-l6`xyNff1}4}Jx1#> zdLx^tXER%9rkyVKvM&&n8A31g$zprXHDkWR^08GRmny zpUhdz=Pf^Iq=be)P!HBU6vehk1lYd5p)=C-Vhf=MA*U z{E(0M7<XG?hkNq5=n}dO%tN=mil%-9UHz&)RlNHYp zlChU8d&wG2CfVeoRhCv+_K|fcdSvO5rAO8g{Es6!ilbS8PFdPyE#YjIaw(UgPu3M& z&Gp>I?P!&yRhE5Zy@noHdSvO5^%igQ4)5|F@1sxFm$;>@AJ8W2PyXU>Hef$l4Q!_k zt+KQl)1PQ!&|{1qWAqr4zyJo4$RP9?GXl3XW-Qu_DPkh}jL~Pz6s9tRnP@det1)MA zCTF3?7(K@5G3Ff3Y!7|_SUtw-G4>X2#sv5)W+PovG)S6IcX*vr@t_z<@>_ET(UtX5-xpowPm7^}xvJ;t`Ooi^IpK?gdG z)h64UlkLsP4kMZv^vRCHezKDoj_qV?m915FB~|E=tw**V*|p4ICbO8$91h_~ygAw0 zWS_w4oPoV$U&uvVjJwLVooubLwaT`S?3L(|tw**V+0XJE&+`H=@)G)Fzr!c2Mw{&K zSc^W{`efTr_HX>lMzqS-YFscq2|dW_R!TsXbyLj-;4&j3X96XZ zqSZL9#@WZXV>u2z#_2Imk8vk*5+}2mQ_yGJxm?O+Xfy5xZbYAP`i#4cyLgC)(Q2Gl zNTRgP9Uzw-xr3Gm^%$?m_(@Ergi@wZ zhCbtG;FiW8iZyJ;v)X{=Xi3*~fkk&>aZM?LjzhDc75m z8$%L9&?i@)++k#p%{a8m)hgFMa_u8`9(v^Jk*i1UVI0m8{Es79$ceb6+%q|g3%HPF z*h}s;T#LKPy#=juwaT@P+*eqI9=Uqt>XG{fZ}Jvz^9~>I8Ez@po0Gei-}oJUa`nmm zhkCZM4Xtvu%Cn8Ueng>1o*sF6m&?!%wJhznR&B<$KC%gEsPbc=1cQ6o?A4(Xuldo02R{5jQBVUhv zJ@UsemTbn6!+3HjpagC5tC-Fl=3+1TM{zU@a98;!qE)_D`PXqhdgSYouSfn(+{`W9 z%5B`v-MFoMZ%)28`A_i@FJmwH@A4k+Ao4K9)c>t{n zv?{QVg7^6VJqq+F(4*iJR`V&J@i|}f18%9nn^W)yo2aK1dnvG&f_B_hL02HCP^&_% z3T>ls5QEX9P>(`A3R6gBC}|8spTe@E#uFQS7DAUJC7{@C9Dsb+jtfs?atHf8kg3DAc1+ zkHSCsi@({xKj>4~LI-ZCP@BSofuN!Q`V{F?)C-#_iY5lFinJ=SkD@&C(W6L@B0Y+V zm`E{`n2bI})0x9uv?)4@qglX07GX0*XL1%=6=_vu8%1|;Cwdg=QKU!Fz1+wBJivqK zQ}h%s;g*WDDSDfC_!N67vX`PSa92fZ`5vu`exsco=uxCcksd|6>0}RG>}4N1P1I(h zTbkI9CM>D|iK}>(*La;bc$0Ve1h+I%n~7^! z&rjIPM0=U|FB{oHGg?j5s<;mk^hJ+iJ&N@x?oTu^#1e--#VNR@;*n@moJ$`16zfxL zKgA_fQiWE`Vr`0V=ML`VF7D$Yo@6Cj z6>C*&AH`qt6?zowQLIPtw|vK1zUK$@DRx`M^=w9);#RiPhP@QqOYwdV1cD~Ht4Sef zH7Sx2q@%|qJtpZfX*8K+F@~{Zqthg9CY4jcRAw<7eJ0JtekL8ku^fl(OwwwSR+Fwq zk4bt=(qq!~+`x@2=O%9E7Id0)KaaD5CwP&Uc$rstowxZI+nJ=*B&{ZGLXSy$Owwag z1C2D%Obc7tMmuh6asX{6_n#?25f1%Z6ttNMKFc4ItM~NOKdXxmylMs3lN*EEit&%}# zQ8loU{mRwYw83O!2nDAA+j7>?yQ7I8c$a3ZJRwn{EUo05yUhHKHM zE>QSmk=^y;bU;NDm^eJs-2OVfr+Red0&=h^9=rbjRaQYLC?M#V9t0`Jd$wQAR zdQ8z{N+Cr|q?k!eri5~;(P~N^^EiZ~IGP2V%wlY3%Bh^mQqJKLE=7+i_i!)waX%06 zAP?~{kMJl@pw*ODd5zckkdOEnTblAYU$c%M(Q1lTQ+Be8-E^{tF7~pI{T!e>5LDI! zoyv47)2U3SvLuF(ObWxuARBj9rd63%WpmM^Oph`>$_`~dhjBPZ@IQ`ZA#SVe474db ziwn4rW!O%c8!K~TWjAsQT9s*4W-Dc{unIlO^eEG#>jj&k8(ZA^(c=ej(8Fnz+l`~`Dil9Vgd!|Q?5_>WXiCe z@*1=%*Q(q;%1`5T^eES(T#xc4oXt|s;av17cU$Gxa|7Cx-@%{B zu$67JvK^f&w3+IbrUuiK2>KF0W&M_Rzah%5KoWYqa<$Ny3cBWp5R#UZ_x&l3>>M>Q1sZa4V&+shI@jNe})6}>4 zh>!V%HGIo=tmQ}C*Hqh?`VU%7)oNN0dQ8(}njX_a=tU@DgwvZo^uujU8-g~|QpjK= zmwd(7xT`ALsnV)StEvumqDPe;RsZ$aLl=A5$9@h3 zf~M;oHxA>96w!Z}Jvz^9~>I8Qz@f z+Du=|Z~Trv)BnVNrq{C-+nKJ_bgil*>4zTGdQ|IC9YZW}#FM}PbgI^-dNi42kw-rE zQayz-%BjS5s)}vaF>Lr}bQqJLA^r^lAZ%*|MXj6R$cVaKq_EP;Q zkKwMWpFyi?t*Y&#`Wx1uN3|Z+dQ^YU53J)y*7GYHXrPfM+S$Q=?4`P!gMpx$U_#NV zMyr|(MluRLYV@elqh<_a$z~im=ugZsAt+sd<1EJb^YfFYz+3u!=XZnVL^njaD^U)!0VOX11V5jUF|6 z)HKt=R<_ZKJ~dr|pjx+7>&>avrnV0e#A7eD_EI|#cU7B;R<&By+DC0U73fi`N39;U zRZORv8fux%d=}uAYLDR*PDP(ueQK9rGqsm;8Cun9Rcjx$_EGydderJst4Hlhp5keq z;aOhfb>7D<)qcoVe9bqk;d^YR)-Bckg;up%)!Ij`ear};#|%AY=rN-wA@m}YF!Y%b z!yw$!3~go%X9U^U%ZwbxGl7X{HAAZzwlU)Gd440H=SrTQ>&TwG1ER~CZfkoJ!a}La|p?#kjhZ>nVE&RW@bLx%$!0Qkp>i8c=VlT5!t$ZyUEV{VSs(BTpYt8IGfS&kTFq*s z9X)30F-wnGyVy-9d+1^>I?dK*c3&dtM*;&FN*co$&PZ%$wpO#Xnmv;^B7O^3|h@ug&uSCn4`y>Z~2b3e9sT8<44x>D;v;eP9sgU zvxEH{z;@;w3nLCY2W-*&1a9eY2 zXYNrP!|`Y}SF5?#a4mYw)nl$6b8lohH*qt!a4Y)Ebz5^+@C4e-eSsHwi??|P+nM_z ztI=w%R&(pw%og;RtH)eD<~Gy9R<_ZKK6BkxT@XFcrmioM=u@XpT`U7gAr-Caw5ltk zoC@@))1yw0x+Q3QQPUCcza4wf}8Cun8Rc9Y{kMTHq)ag;D zN8L)E;%T1YS@fxMTXo)?x)0E%?km1VpE`Z&zQ<JA2i{GEKzJU!;= zF;9ce@gFgD%$pAVH*Jij|8vYh%4&;BlH-d$B1`$m-l#|5BP*H zaZ4k9Be4y z2H3@uJi`lU6{JO{{_?6%Ioj=eiSeszC6zt~&AHfNnh`j{cOYpgz z$34{YKfOObFq`;+BH_oZw_K$wHrCeS)VlgAz*7Dp;%F zR@UIR1nUv3N3b5jZM4(DMmC{O@DBcmpA)Q2@N2xz8@$Q8e8}f~fmXpa; zJwo&dIg+C|nqxQ?eL~K_Ers|wA=-po%{Ax~qEE<;*i6X1+=o^nT7}p~NCJuI5u!(k z9wFmNA(aWFF^MS@;OB(QqJlXr!d^n`C1eTiDr6a2g=iIGA0hS;@)UZ6=nyRFBY$xrD)7 z%4J-|4cviS3cZVmd4xxKjN#Z!s9Oq+CI+oSwF;d{K6-@e5voUM5yg~HN*S}6%R<~z zs5YUEw6X?$Lf2tGp`C1FJ3G)SRIAXB(IZrkP(4ET@EM=;1z++NU!zm#ulPA50|?|` z4q*_-aXcqrJ0nl!Otcz#5qF@+NIgd0%{|=9ecaCj4CO&|8X1J2Gt$o)8AT%FNFo{g z895Q#8R@P@YBf@;k@Ym7$4EU!Hqp#7meaxtR-)6$4z{qBUY_EAJk2w_z$@6!NOv{z zJ+vCB)yRL)BTSDlJ;L^3U-n~v4&Xoz;!xaH*ePfeb{gk#K38xhwiD*Y!iI1YT7_v9 z7ET0ugy|8cM_4p5#1cn5qtPi$n=n5oEQiU=B%g9Bn1k(vRZ)XhVOoWC(}NyidW7i_ zwvFxVppSlbqEnbQVQ=szZ}ADc(I-rwurK)*cNJzkVOoW26>cBlCvh@*gzFKmNBHTS z!I_-J+2|8~DSl4)b!ZcQ8@F=@_7eUO597wdhhaP6T7{1ylPvTI*CSky@LZ-am1*QL zodU|3k2c}e)KQPUgs);Xt*pm(!nF$5D*QEGM~`ql!u1G$n|FAZ_jsQV&?#J-a6c#f zM}FcT{tXC>&?h30{W+MUI2x@Yw2H8gh-=UzLXQYNBCh8KZsaCz<`(pcxSz*(9Bm>- z5{A7**h|D1#*#!TT199TVIL9ms6>wlJtFjoSinMRSj1xViCB)G6R{3$BD(28p9p;- zb}+zmJdf=}XceJV#P{q)j|e>?^oaPGU-*^Z_?ur!#JEHIDr$fm&kKCm-Dy? z+lkaFQmaV&hbqdW_Oz)R7#;(Hz6E=rigJF5p768FeLBVK1ZXWz?%O$y4YtN{>-`jCz*m zc%Bz{kym+#Pw;a_ead%yk3OUR>+=gX6SWWfqE(buQT7pKA5rI{N0c5>dPH5!B@E_L zE<>Lvw-t232;vz{ zD)tg>FVX2_G8wI+wTiZnX#0q+Lyu@ZqV{XK^-zv6q<3xSXpQf>tqF z#n?tnC?nA$MvoXhVj>wu6w$<>PfRisaZ54U#7rX(dx^1^m@;NFmnyW1(JIC^Vmj$U zj~G2-^oZHQR(jdScJzsPhF5S)G1|m@z=!A)qfg8pY$nDn#r%j?F?egjR7{#o0$(ITh#;r$?L~ah1%cifR_1Ph2Cb@N?p{ ziR)k^_7Z0=aXaW^7f+*AoK|sP@ipI|N1PsUdc^JJ2Y%!yeny}801m>>iPt9nSdK%V zczxne;S4U|LbQt4D&9Wghw>nL#Oo2SNBpBa#^Vg*3G|6~Tk)eAgEsMLq?5r!vay-? z0t(S8UaNTfh+n}<^oZ9ZUXS=StYsbR*?>OrTX0M9185WfA}^s&ygu=7U^DTbup6!7 zwHj?7qYvOf^cbzjXgx*`;!qCbaE{;@PR1>bK8JG|%%u#$UPjx?=o`6}JJD*iR-^4> zw0(?@M~~5ZjMigx0*QhVKZZLm`pBH&}ob| zW9BfIdDOB5ea6(&gk6oXoiVmEMyoMejj@w4FQdm8J;vxU=5^lSP2S>d-a)4^+Kl;@ z@A#fS_!E7`=rcADyBcddV{K=wR%5jqdpTEdC3=k2W2_!yujM+1a6LD03wQGn5Az5i zgrd(_ea4Q$uEyHVSlbz^)mW{@&Ze9S^cbthSUtv8GM_4{S-@f%S;cBv>0l$Hr(Si)FRnZRW1CBa@2rsA#=3ehS- zs|4FfSiws4NYEoekAyX>WgY9;fIbOZa7zgTXp`_FFQHF@J_&E|4xg|atrE0Kw2j0A zI1oJ&^+?nsaS(@c7>9EN$8a)d)FV-k#3y-* z|M4`>@B**%K5i-TL%!rI^hx}$&t7aM(JdwZ6A(B~t8rS5vyE|Qau#}w(_@?-t8rS5vyX98nT8(Y^cbhdxS8ZrKq0fx zXWTp%u^4T}EvE&2#_2O|4K_1wGu>!4POEXYG45U7LyvKKjMHP>M|{jD?B-Lx;Cp_< zEsgslATVh^_D7#2eUb)YGf5|KB3dPBm1G}D_K|cGdL-$Qq({xS~S|#OSA4xUnk)%hG9!X26qn-wq(uht;+9bK9q)l|PgFf_0 z+KK%nJhCH=y$=#ivH(tkbvp57I`)!m zFUc2k372y{1l&?`8rmdJCKr22wwL50ikZz^ zv`W@0xs7%@&?8xoWId9**i1J)Y+*Z3@&bNN@=LtKyXcdwPx8m?;ak2#t7NUlAIVW1 zjUMCm7_Z0p<2iv7If;|eXZ(3w%4KLXehAldC-yS_Ztmd$9!9J2T8+1l@hPOD$9O%) z>oGoqiA*AsEc6*a6Sp+J3~k0QU?KX9*JpekjjUodT8-Cgylsqsj_1*1ydLBA82>V_ z@G7tII&bq4U*PAA|B4^^iGQ${6njYt#9gHvj8-XHrPxP`eWVOVj}$#p^hmjaE4hlR zxrUp$glsu+016@+`DZqwOY$(NsQglkGWHGfY zp@kK!M5mOsv|&3bwv*zfQruL^yVyy}`+UHM=#pYHDW9;LPqCjAol^GlJAd$JKw#>= z?8o68fla0Alxjz*wv&1mXLBPrp+~A7sd}W|#_im}o!rIU=#;8WYA_*$5=$KVr0SEJ z$arig)pk;~O4TaWPEze8brE``>XE8PY8~}7u#`rYvxbdqqLUr;(a%nv!md(nC)IXR zwMx}0^%s8SH}pu=BlW)?fAKf}@NYoigaGuJFovqvk!BxhN25oY z9%*`{9nT4z$Vr^c>70ifOS_EA8N&74iM^!V%{{oQw1;^Ft?PwAPUTF_MXL<0GVCMcUhYGW3_UXR$as*4c$i0c6n!#A5`&+Up-n~-$=FMVy=2%+ zMh;V%fmRt>W!OhXGt1B;LyrtSGFGyR)wHq(eKNY(j-QjEO~$i4hdvqlWW0jSWPHGf ze8k6Sm7&$debHm09uxJLcpwLHFo!URLphA2I1z0op2gW*%q7^%#OoNs_1w(uXf;u* ziP6NM$3#6Q#xt5Rj3t3Y#*u>CnyAf0KWAbdMHFK%6X#Qf+nTrt+nK1^0G z)MH{lI~iaXPx2K1L#K&uYvQ~3ITPP!51(N#6Mx`G+}6b3u$@U-P10)8X`Id(=rKu; zNqS5=hjTfP^SJC9jz`4phfB)2tbAvI_-sgWj{S<5=y)+F1Rw2{qdHK~ucc?Ufv=`l%f(>^j6phu=2nR;X{rj{ktQBMQ|LgGwfASZ9^G`rv);=7JTgp0`V>pe| z(I-ovtaG`LE4UJ^vb4$?#uE%jk1Rd1^vDV!l#zrHP84HsOIfK*U^2Prlci7A3<@cy z0ls%YBxt8m=9ec^Xle=(N*$<*swpQ7;k)6zV z^vKpDTaWBC(#c>VlgME@ZYjHjQmUv%pKN`yYiVEwE72-jt8ClIeuih!BU_JbJ+fcq zC0^zgUgb?b;4|D(_808s2mZodvh5}N-+;gzca?J>TIFb!V;eaaaWQ)2=#isG&ShNA z6k?TIFt~ z7d>+I$kijakA8MCz%HIdr(A7v{hVAsC-+@;^C^4y9=DZiJGnpdD}M$APSI-0ew>OP zQ}mdk$CNWUi?cb0b2*Rm(P@g?nsNg-aufG(FZxWmpNDu1cQwU!rf4-qt0{iVl*#BZ zMUN?ZOqoU=)0x3c^3iFEHdFkZDGRA#DUI06lr^kn9qri86s@LcHRVm-LXRnWOwnV? zd%VvFe8@+9j6PGo;b(q9n<@VW1WpYgkU<>EVc5>pqd6X}rk=qNu1AlldQ8=0>doB3 zt=z`#+<{J0wV67c5d;xMH2O@9#eSxaBOTkBs?}7jruxBCtI=bs9#i$0x`@TpvV=P7 zX<`*^Xfw5gEo`Nir}!UFV>?q{;1#r*`Yu1A$5cJ0>M`{t*&}xQOGn&w2h8{EYn9;%tR!MRx`DlIf^Lsn5oCiSmKChG-DV`0y@ofTQhT+!c+>G#a!l5 z$$S=KJ2SPKsnyJ_^s)^-X6i9hkD2}KWPn{fi9R!5#?P7Q=gib*=59X4US@vJUVh*g zY$sokOD8qPy;Y2bDeG2p`h{t9MCXj|!1zHu@M}d75RG~+K9tC<7 z)Ub%f)UpJ93RbWlw^X1_K{q`NU@rysQt%Yd@*-LlXjNbz1wZg3dKBnUphv;4{KoJ6 z!Jp_;cmRG*p<61{rtoA=L7zf>3eVy^F6A<`D%7gbHVPl(ar7wEqfn2+5d;xT2%$s} zM-pzSa6FU9WIFazXfK8N6j6p&g<2KbN1=Tbu0xMPJqq|@rU9EKjV^q8f`tfM%ZV>p)MIEgd45VthzVy@z9 zZoyt=*~_fkaaXhMN2^&{&9aSIiHt*!S$fRUV^#{OOdySP^qDo4Lfq0UZD!4*5`AXr zGpmLrEMqxZ&C+U?eaw1_|Dne$J!a`K>p7n11zzMOUgKSM^C^4ymhbo-dzob~v;GPQ zEDB&hv?|i7$To`3=K}O7(xXU^qDvUerCi44=u>nfcjA_cv?+Rshj|2hDGFsIVYsWJ zShOliBA){EDAJ=ykD_8qD5Z?ql%rFTHbri!sF5btuoiua)?+_KU2JCuS`}$k^f8~H zN0A;ydK7)e=X}AJe8ty%&#$^yhdw1KxTTUT zv?-a+4D6-EUP{WTz+IIrK&uk1N^GNKGu`M>qDP4yCB1B8J3HuO7tiq;eoo07e8k7- zQ=(7F=h#fiPyCElC0do*N2z_3o`@c$dX(x>dMc-JI%jYu`jon@Qnyrk4ce66!mZqf zy_DKZ>4QAPV+=>D(g-Fp2|Y^nDAl7hhsoqJg{e$qCMCF~Qf*4-Q%61elrF`7N>{Rh zHnb|$s`M3JMUPTFO7$pxlec)AcX*fg(5Y0LQnysPmmm0pKLY~G?4`_J$`0fp4&_L+ zD$}aWKFY2_k1{>V^eDTIAzaT5+{jJnQ+6+Isq9g-DH}-``jqKY7EL_Kj7O_7t;+19 zYz}kLqfC!7J<6)6W&sPSVF}H&;^&mDrHjpU)5A9Ud4^}vs!Xf0Z}^t)(4$O`GCj(E z)q=LnAED30S)+*0{@ zoX-_pi9Y4}ln>!1?&5B=D%YyqHp)jc20hC4DA%KW97!ZIo)q*c&tV2`sa%`#aw?d^ zT&l2{a<^38h*srVmD@)7P6p7UT#s@+%KyjHJj1g*hd$+R@*!@iT$}Q*`38N;|LgN3 zHdFp@Kww1xfoN5sRmItygB}%nROnH00T*%+7jp@N(Wye43b#~oJ9qE^L$Q|%d#MN_ zm@r16RfSd+_E9k%Ju395(4(S&LS|7!F(v3!p-qKbs_=6v>S%>8HD}JIfhfP zojIqW)f}zn+=?D^^q8Z^oIAOTySayZxsUsKh$qlyPB;;aVJrzGVn1`-*BslKGa0Ss zXf>ynCFn6nk2wu2rI99@S;lf!u>o!7_&IZW=w~O-^8znoJ9A#+Ewq}W)to>06FuhW zG3UP?{{{rk4Iq$x*q8m#X|6VNPr%QadlKhxF8a*XXYR#Z#&y`v-0RV5u2yqH8HpZq z^_Z*2+($Vq?|Af>r^h@!=AFzboXTmO&KaDE zPV?N>ysNo}Yq^D6v6p#nYu->Eud;nwP;u^q8l|JU!-Rlfz_knZi_N;I`)Z zIrFrcSIH9U&}Uu)&8%QOwlhzwd0NeTnOD$bo*wh`nD+*6@)mFN4)3DVJZ{s{=Iw4cfYI2_xl)T&aeO24J@O0GhWNMh(48WtMXwUL7U28 zLI}lPD&vS}H14X>b}F^1%%p-j=uxRhr5=^@siK+%ETjgVDz&L>WescTVl(>QSjj^X+B+H1f!& z2(9L8HGd_mSdAX@^_Z{6{B^8n18ua^NiVy2lBal)m#~-l_A>uH-sfZXpw)b>st)8J z4n~hEJ*xDmI*h|Pf+IN!eX367T>P9WZK|%|O7yAHr)mf{aTj-^Rh3p%_E9yOG3ZgH zN0lB`<47Wz@uZ+nRSq+li8fW`R4|9RRADn!OKC)_Dy^z)qiQDu=uxFdl^#|9<7uAZ zS)N0msyA^a#fqJ*xGn)}#6YF61IE z<`M>@Q?)kLw{bgn@E{MNPxT|%PjwKHj6$nwt*Y&#dOCVk>rt&obpeIUqKINj(5YIR zYPVEfM?Ed9z+S5DrMiQSxU1@|XjQFMwS827fF9L)RO?aw3A_1}J$%OJ=v1vuwOgw8 zbE^Li2wbo~2VgG?>}A2x9K#8mf>sN(T5vPBa4UK&&|`rf3-07D?&couWhjs1mKKa8 zjCe+)&jNiGB#}xM*=V&us|AZ#Of7mW&|`rf3mRBTBTY1;&w_Py;^!>TX2A~ncoutE z@H{W@3U8p*0<9MO#_#-r9t-qX@L!LA_%|SMVE}>bgFXun!!0d59&Hw$!I{|0LVH;_ zm`k~mYtd?a(yAn^`!IO0-(2 z)k6DNXdeqVp~pf!7V5FEn;y2Xm0t8&=(ZNRrG+n}&BFJ1pAYzu-Pp{+@7ar13$?1T zkD6mR7Cmb8sL`Y5L{8#lPT^Gaskwm5aZ5GY)ZE0)=u@Ll&7Igxja#aD6s>BssTiDK1*v=xY7HPHUOTI#nMS3jKW6^hf&t87uM}9)5McOPr zkb^jwqd1yVIgQgfgLAN*#ab=aYVrL%z)O3FUX3j3+O z5qDKIYJbKjXQ9G6d5*bGl$&5#*+HCxs+8NAbHs$D3I|uuzU5LA?wVhh6 zYPG8EqaQtL^{CaO_DP=Ne>}}IJc~}X+SK|vwIA{kU-32i)c)7!2Y%rnY-fp9OSD>Y zCTDRrdMwdni5^SN=K?O|A};1K+}095XUVPH#(mt+FrHvIBXCzsY-fp9OSD=tm1*Rm z#}Yl3=&>Z90t%T$5oJ{3=PapZ3Cmc{dhBIM8|}EOB|T`hM5`t5@*eM_#}Yl3=&|Hu zK4CYXvWG9(i=VT^&sp+kKw#az?8o8QOWlzi#c`a3R&`p{*+$(>+>9P|derGrcRP1* zCwFl-`qVv2Fd=AD7flTIQfDu9<4GZ%Oth-gs?Ij*YVcd?^r+LLPLH}e>SHP}bPb3Bh84SF=_(eN^_@G7tII&bq4U*MJ+zT#(o;a7g+uYka%Hna2~ z4(1TFTB_Aj`&c>{J(lXRRF9=sa3xo9HP>)0H*h;{X{k0#hcb*O7>>Ox9YqvwYiT?Q zXtgwr67*QA$5K6(mQ%qT<}!~;=A+Y6x3#o|6|7_fZP?4wt@PrymiA*iOSM|6)zZ)T z0zH=MvGi-c;ak4rd-n1JIxYP>Ah2x;>>d~l2<0@9u z${N<9Pvd5G(1$jS&+shv()b2%@)qu@(RLcOYSgM}ANIv>Y0{%fk0w2u4&q=AVGxI+ zPtysU!I@~&bP0per%9ittGJF^xecwFv}&@Crf6c&qe+h@J(@-{hOs1&h(1kjt7!^T z(Wa@G5=tp!4mQ(N%M!F|(yGZmnzpeWJ(~1r(xYi71MK2So**==>qd6Bnn)PVbqdAZ1%wQ(@6j6bn)9jX-YiObweVX-YUWLsx zZ=w^enzd@Sk7oO5ej7cS^=Q_k`F%d%Lq6hT_V5jUPP1ET{xu+QSs?qM&$9hEh(kG+ zG>N2PwN+?IGd~+9LMpT zfIcl})iRDGlF_3@j}|>zCXhxt8B9c8GA`!|uH-7N;}-m!722%u zb5=agFrHvIA%qi0JX)>LYK48Qn1voI^jM+Cic-p$O*s|JVLprTb5>}xVi{{#i@mI{ zmlfUgu#JASTA|g7-F(U(^jM+C3O!bQ$ya>MH+;(v{2mav(k-prhkY5uq1ekxds%rR zCvh5Qq18&QR@%qPySN)YR_d`*kCpfH07H3@hj@%&MiE6c2_%w%y{w!>CX<(uf`_^;oIL%H_1Mf|aa7pOqVNODp}HmD;TQA5WvtN_|$o$g8}|duX*%tChB~ z^51~KRRQR+N{>}~tlE$LIe-H>2z^!^gIij4D%z|%kMp?zds$^KtFGo6uIFZM;U4ZK z5K#6151;WlU-Lb`VLPj}TCLUUlhI?f9;@|OeL81wCTDRr z=Ws3;;E59JYpu$|Rft=4LF7TM&W$7(%R>#=$&)5v2wGbqGu zt*)Y)1=Q2PDpu2q+giN=+gYvEYOPkk&Ktam9;@|Ot;gzjd5`z`fDhTtSNzCN{LJ6{ z6A;*X5C?MzgYb7+ZKqYMR;^m?qxD*@LyuNHTJ>nXk(;=gTey`wc>q7B)z4{tf-u4v zjlHyvC4ponpjE3@t+vrx$$a!^)uUC9)`irth{e>RPiqV7SdTWXJ#0arR()Fg*v0d_ zfL5(qwc1AOUVcE2Ry|tvX#Is>`HkQC1AW%)&tV*nHfv7cL{7q9*4WFM^EjW2xeTq= z4B=58Lyt9jtkGl5a7GYBFd>8zK^$&rjW%n>lSMZAteK4cteHtEWz0saHCnA%iymwA zSfj_9HrnZ6Bb(@?3!T>V^9;}O9B=R@Z}B$o^D$pyJ8QIBqt)6&(POP1YxP)rBu8;H z$8apiaXcsEw$@&RHft~8TCPK%wbyeqw{t(XvsSCMTCGiF9D1zPW33)*Q%Ge3X{3{Z zPHVMU>*uU3qL{hN!(P@dp$@mTwh7x=tJPYq);`7mcp5#{>akXjwa@bcFY*#E^E&V0 z=d9hsXYAz%^jZ5~pWpZ^AaLD&*v>kw)@ilQKGt2ph3K(Pk9B&i8_cC##^qeWHQdBq z+|4~a%40mvFoGCK46$gnPOEkK6i|pB>-1Qs$GQ?qDPuO}=(Dbdr8J_=x;3mtpLP1I z>!6G6>_Dq^TCKBsJ=W>5PLFk;^95h>6<_l`zoO0h00P;ELm0%N*vtA8IFXY$ z4cl3NHWzaVdaT!Dy&miDsR>pj) z(59_{rRdY9Pg@H%)7DN0TD57_W*cp<^9Fjf>CvV~+dI6=d%VvF=+pKkKj7!IY18%( z{{{rM2N1~q*i8FT9L+Ik)vi_hHC&4x?RvE9(S8FrauYXm3%7D75AZnJv_C-vk?7MN zh5fXTC6x(i)vi_hJSx$nU5|D>+83~p8WypbT6AjHrrj;IuV(|B>Be5#?WKJePvWlH zUqGvNt=jFQeJ^^n>(Q=9`_KHsul&aE{DDp#+H|<3j>9>ElQd~o3=RMrZecaCj=+ikIx76w9bZXN%nlac*r@eHhlR*}_ zXw|7zr)_lBQI8&-dUWd1*+etTSWXM8X``DSwy=vQ(Wg_N&gZb1&bN3Qtva>pw2w~v z==>W!I`!z%qbrbo*q8m-AAP#qR@aG~gf?C0avtY%0heGiU2duCdbH}&s>?pQMiPb| zU3zrs(KU)FqKP3EeY(ao3AfaxP1g)&qEDATUB%c;ms{$pMyoEZx@@DXi_PfKrAL<@ zU0dm88{65z0MGI&ZmH{aKI9|x>C&g`Gi;{oM}9)9F0D4($7cK3d;)rG)?>3Cn@{0X zPUCdW;2hl6=Bv1xYq*(PxDR{TY%iOK@(9DwYO_|G?PIfjY@Uc7oAubN$L4Hum`pBH zm`)LMa7&x#QOgqa*{sjzCR%Vyo7bb&X00~c#^#rK1wA(Fv00DJZ}28>@iy=90ekos zx3u|t{@_pk;_raK?m%p&`!Ehit8T5jZKL}Nu0)S+J-YSizLx74!u8yMKHYcY*L1t3 zZf&|l2t}W6eY!^x%Q%wIs#~jW+vqN*0zJC*=+>jVlKE6o%>owF$ST}Yx1ZD9!A7=W zFWvUi-G{sCej2U1wd%Hw?yvaK10xm?W9<6%pqsKma9z>5GJ$m%$d6dU^oMAjcFp-RA3}Z=U0+X?q9((DTio5D5 zM5`XHdTgU-1uM~`M~@yode*R(b*yIt`t)pJCvK@no1W)+0ek7Om!5Zc7kAaO8?Ab@ z+F~194&Xra*rLZ4J+=(uP!8j8j^G$h=4{;3mU9`*rCf%+Y_XRuH*yoVaTi)`d5AdT z(PN7qTlCnHKqBKvBAM}|k&Rp0qRp0>lv0MhY_XRu3#q|fZCQ#|TeR9@A6xp-V~ZYJ z^w{zwPw_vV<{6&lMc&{8wAu0zU+^XNvc+Du{KBvN$-e=CTeaG%)z&jP3q7{#u~m<) z=W#w4a3L3QG5T!17PqwZR+@jiNN)nlt3TR-L#cJnEF_>8ak zfj`h@>t6wZz5B60_R@PKM{zXns@HaUwd&QX*FJi0Mvq=SdiChNojbUbySSTsc!0<7 zb9%Mu9Z3wa*h{ay^rnzX23cs;t5vUk^e#e=UOjsC=&hrk2A0xD6Z-V7WfPrf)7wWs z`t<74Yd^iu@fxqARj*dP_R;$rzoSR59=-qd_?v(DHz06Z0D9H-0a3Y9g6#8sSB#m^m*_O)`>}8w1Y%8XO za^|7cHm$bV$F>eOqQ^Epw&}5LGu`yCg{|!1DPH6yUgmAy;a%)yo4suNoGy=b-V zkAT4K_ObmK^w_S)c0IPAz=@p1$(+KeoXG`TjyBt`DOj^_kUes5@KKkvW zKNLOs_2}25KY~a`5k)ldB;m&T-B|x5rZSCU?4`eyGTc@Fe6;GpYjEJ`GFtNs$Z*}$8sEc?9^kY9y?FsWKQ8! zPUCcR+NsS>x3u#ruI3hQhun2qExs2tsu$pyfwNtB|FY*$4?9^kY9y?#-b>84j-r{X^+NsS>x3u$H zzT;PZ3kV#rmjQbj*pK}=n8VO&K&yevxST7{V?d7qJqE7fTCQUV*K;#>;g$v-;$eab zL7xGA1|o?ek#T4>pw)nV49un+JqGj`&|_d8mCUD#YV;Xc%1TzD%|JUH^kOdq+u6YY z|3j+*tp>j2E51gL0X+uv82FyO{J@X=#D9JM4G7$IAb!p+ZFU{S(b&r_d)ak5XW*`O zU4T}*wAy7GyB=UDdhF6;mma$w;ZYvrafT5@1o8MeyT*`0DmmE8E_>Pae-7=%zvue@ z|M)h?IgepSV@C`-(gEqHbE)(x6&+M`PCDn*fznauqg0a4sZ`|9+2%Bcvh!@iY?vJ# zH~U?`zl+P&A8>ozpRf1j;$kLGG8e7ZX|>Ki)-C08^jN3IIz85X%{P3@cPvAnb*u1} z*8Pn(>o$`^9`>@%Ue*;-N(EZ2(<;k8vf9xeJ+k!3(j%)Ao#{eXx}i^2I0NvOvb4!c zW(f9@WiMIwl64y1Rn}Q(m8DgdZDdX6R`kfyBTJ90socSx+{NAKll2I*@s_f*$(qme z*h`kZWZ6sB+q};rw93*d%RaLH;7|0((j!ZctaW6O&3ZPVPu9N_<1J-rlT}4E`eglI zpIU4ttC^O7z-+CuwaT`S>=^o^N46f>dSu6wKq5&DM4#*oM&d1HYmi&pEk zT5lig?PLAv=&@dp^?Iy7gE5@RS)7eN>o4VMyruQptiO?)xD$I>e>e9qjfc=`y;ke( zWBuE_gC6VkSg*(W4_L^DEaD?R_M^r0_d zgcCtO5*Ug$8&f!q)6r++DC}qBxm<$nY}9I_RvYi-KJ?hA$3{IiPUk@$;$a@)QD)$6 zZF~W3HonB0yoJ4N{FqNzjCZxsb~b9YQLByiv2incY}8|;9vgGn#&&k_FaM#>#xi_! zHddp}#s(U(myPzaDS$xQ5sX%wwAy4Jo01uV9-H*oq{pUI(nu$ROipDC=W_uUas^jn zFPrRT(lMlUAGTW7B+|M~_W-X%e=w@Ugb6P*|d-)e1{2 zY>p)ktu|}5*)}$x$5`~(tjA_OHebZWT*9SXhCZ7oa5J}{&E|W!m;1P%2eFyWb9j=c z&}y?*n-}vbdTiEXvmTp2=L^2%E57C%zGnr$qs`_&*}z8ZWwX6(-bo%s>_V%}TIB>1 zgdRD14!8)fTO`akUit)m#t8I0jf&f;uz+IlHh^FOZPW^O^B zt+z6jyRn_E524jot+u|!+vu@XkF9!aeV-3l$cHTABXruT&DI}T&QGjiE%vf?Jsa4_ z7Hns$R$H~&+DH?6Y}I4y|MfV=aZb=o3nv2tb9KtqCf7G7*Ec7(7m-9^FS$t!WDrBK zom{PQwaWEv$-Rp4=#i^Ot{%D9GJ)&3o*TG{Dcpx|PVO|GUXZ8v^LQEWDp#vq zt#X&~JwKpFt{%C1(;W<6UjjYMWNu?%`ha*rvxeJ+?i- zbROg(9_A5r+NRAm-<)kP@FH*VHu`LPmxX-H7kr6U+qBwdAKNye$2L8->9K7qxol%Q zJNOr!wrR6%A5~P-NE7;O`@cRXXblM5-hqy2wOy<2_OX31$>_0NkL`MFPa%~w(#hZy z&cIvRem)m4jw`qxd)YpbNqAS=Z%3=`T5W%p=a`Qk+x6J4$M%}C5ZRsZmFTfukL`MF-_HRKQo|u?(P_IjJA89?w8b}P zM_0OGFFWjIM+A|?5QkPfwAyhl=b^_AJ$C4^<3cXtVlLrQF5^lj;G45Un;pJ6JMQ6L z^x1Jg_Os(r=I|t1?a*q+CoD#f9eV80W5-fH=L^2%E51gb9l!7!zoX5L^=x1x_OjzY zc9Ms8wZnFHlu<=>K;X`L>}IFk?9^swb3kBT0D6OpI^8Vs)vT=vJ&E&8RZ#d5#^4uZM9rB8ChrDw3QptV}P)i+6xJ}-1+$OIzATZx; z^4sDz`N6nNemC4EzZY(kABNlHN8>j6vA9is5^j?}1h>gg!)@|M;5PXqahv=zahv?} zaGU&#aGU(gahv?{xJ~{9+$Mh#Zj(P5x5=N1+vMMa+vGoh+vGoj+vLx{ZStSQZSv>g zHu*2$Hu(#1oBTI%oBa21oBTz%P5!62P5u|SP5!sIP5zI#P5uhpCVvfXlm91flb?m# znkreF+iQ*bVBQ*a?}Q*aq> zQ*ae-Q*bSAQ!o*?DYyl&^x zf;VuRf_HJ7f)8<$B#uo1T@*oxZ} z{EOQZ6yP=mrMOMOZrrAz3b!e!!EFi}aGQdoxJ^L|Zc`Y9+Z1-dZ3?^KHiaR$O<^D0 zrZ5t>DeRBi6ei#{g@bXM!W7)5FcY^aJPo%gJOj5WJO{Taya2Z;ycD-7yb`x5yau-^ zyaBfpqaoQ>NQK7-p7&c|&EU&d_;U&n0<-@$DP z7veUBpWrryOL3dRuW_5g?{S;LpK+VQRk%&z@3>9jKe$cd2Hd7_3vN@m1Gg#6$88Er zaGSyk+@^3JZc}&=w<)a0Z3>UzHigZ&O;I3jQ`8=}De8>d6!pMuihAQVMG?47Q4DTV z6pz~!4Z>}ThT%3v8MsZ+sklwiXxyggY}}^keB7q!65OWf3f!jXf4EK2^|(#ZO}I_b zZMaR*ow!ZWeYj20gSbu6W4KMxEZnB(Y22phIozh`CETXyHQc7?ZQQ2l1Kg(QW89|b zGu)==E8M1N8E#Yb6K+%VD{fQt8*WqdH*Qn39=9pV!EK7R<2FTkxJ^+pZc|i_+Z0ve zHbn<;o1!}0rsyzkQ*;8iDGtDGire8f#hq}Q;_kRjaVTz69FE%*_rq<9<8Yhefw)ca zP~4_C9k(ey1-B_4h1(RLh1(R5#chf&#%+qn;Wour<2J?D;WouL;x@&%;x@&1;5Nng z;x@(8ahu{tahu|qxJ~g>xJ~i1xJ~hkxJ~h^xJ~g}xJ~iTLw<+m{+m!UeZA!v$o04eUrX&`(DM`X@N`~MzC26=# z$q3x0WF&4=awcw5avp9|auIG*ayf2OG9I@nnSk4rOu}tSCgV0GQ*oP;dvKeQ2XLE` zM{t{x8MsZ!lekUEJlv+_1>B}&0d7&m9&S^z2)8Nu6t^k)0=Fso7Pl$+5w|H> zf!ma zls?UTo=5*u{YyV!As^xvrEXFB8B6&b_bC0IA8?D(RjkGxO1H2T%}X^e-OdjFMgP(Q zG%u|}?^3->8_>E`-%@>d1rSI(f(b#}UA>4z*Il~qNlxsjW=8SQr6&Ye8KbRNWxcRj{z=I|tQd4X4XjZavNz3y6qR=c#?rPZ$Q zSjPAKz>ny)ORrse?fQpxWRZ_Py9z0ym=a3a#cuT4)qq~RnrK0{GFvRus;m>8=}s^7 zD$}bho&*v(mDA9tY$T%?%^8g09P}!?lB>|GY!Z5v=~bpz*=^jxH1sNaoF~w!Y#z_@ z9P@de1?W}wHt(QK*%y4tSA5Mkc;jU{mFZNr3Z2USMyE2J%JR^uOsBF!bSl%SOs6uP z$||U)9-Yc`Dr-ik@($=!u2Xp@yxH=eL=Z_7I+g2Gu2Z>A9)uD_H2sJr4vltev^$kFblI)T zZe4bt%Xy4NqurOH)9%X|hhDoUaU*)|)@Ju~9^@f(+WiQR@)$GGYWIu0gkHPf;%z?W z6BhF+_O)BP-OKq2t#<#)@BD#YyEn3lZEU9kZFcX$hIUu7k1A?7L@j#lKFkqx+tY@& zXtbv{edtRV;Y6U>o*0HRf>ZDg_jreUPG=-`wr4b&?a^$HW_u=Z9oKUM6VYssW_vW- zb1OEs=WcY{^AHa+i`mS5t69TZenYoCy6yQB zJKM9F9R6b`d6c8!9u4_)XntsI4p8>=YM-s!( zZLe;7b=!L;XK^-{a4DBzTYInK8gAq!rg8^&GJ~1uvv)Rgc#@}hnrC^Lw|JX(_=LrL z$`Ul%`wc(wGaBvvjV!WRkGHqCh+;}8Wfx_XV_$o<*{jW7ZT4zY8AuRqu%}9mD!X7; zmA%oZQlrX5G^rej?Nr)MgU zQKd$ebD4)GmGAN%@ACl*`H)3?gf^95@gvL8rt&v_=MVnGZYnq6y;XW|l^RuQRB11j z_EM=y`@Uou zzT5k>*r&z5zxbPf&}EZmh zROwS?J5@3CX8^GzqES^k`c!#WRo+$A8H_=rDvhe_rOI2X(yB_UDy^!ts?w_J7Bs55 zmD{)rovL)IdI-CzdJcW6p63N#RY};v#RB+z>cc4t6I+n zw5r;|zx>Be^r|YOoPAXBe{GI)f@W-~>LjfJfz@qji(b_|(W_doYHg~$uWDPW9)wQS z$qZpAX=qh_CTDRrmvAYUaXD9^TlJ0H#Le8no#<43A6ivwRsA?~coI9R)}{J&-r!B% z;%(mN18k~#30hTaRjpO^AN+}3RohjyT~*svwOv(bV^`JN(Wu&{s*BmfUMjJx>UtVz zZW{hIC9Y`;$XGZ@JzMsprx8OIe|$yI2y|9U2KD^t;F zzdrl#=V2bXSj`&NqS^lS+9^pPjcSjB37CyOm?MXLk(6i~<>_M+7RtqvTZmZKaC2s{`_ z5N+s9ANr!z!Em%XsMSHO4)!OB6jDiJBpMym=%7Xi&&HMxdTR&uIXI4MnZV85!ek!8 zehxmuqddmrJi!dSxq})Ve1!$P%DcSB`z+xzmhw4Yvy2t2WDS4tC)wE1L5&V>Wfx_X zQ^9U@I;hjZ{b+RXAWgJz65phn5PH&!Q1q(Nt46OHy=pY7i6faI4CNF~lZVl%~*P>NPHTGeP(qg9P}R-;kP0W_-d=4$FW#_@o_Ljkm> z1G*g2;+hc4k#?CQ{!OyFj2VKR4d zHyRz%=#WN-9z&x;Pcon9d5zb31N%8-KZoq+&=-8kSA5Mke9sE>IrImAvI&h2T zwzCth4rz60A5~~`s19uo9j2L<*@pL3>wVSkr4o&5HL9&{!m>f=cukzwdmuT%Zm z=v1#${dtTTtP1S$Hw|vJkG^^LFUZ;AU>euiO>&POX0tzXjm=a3agBe^3be7rv_~r4sehfj&h9SoIt0>HrP&M7j$XtO*q;#YSWm+P=;{^V>pwu zu%kwu8g**arcs;5%h9CqS|)H8cXJQ-av%3&M~x4lQR7TBX`IKiXwtXeHxCqdtxLG}=vLDZ41cn`^9~l0(#Tm}Xi60-L(h zjqdaygr4-GFJbgYr=~#+CYjM_)udIER!v$pY1O1vlU7YyHC>KQO*%E{)HIn}xsBVo z6TO=BX?ld&%;7oaU#Vkdqrl0u*t(yMiFaG8q*0ULnnlx(C zs7a%y3Uq1mwwmfV!qI@h!yO66dpc}4hwbLDPKR|mtj%F<4o4D2JPCMPhfn1+PG=;e z(CM&Fhjlu94i|AHS23PR+{jJbj5dewz;+Hlz~el@(>%jm-sTvUMB z!`dAFg75i(A6dg%e&ctvIh>6x9nK}60!k=nFW%MRdKv-(kF=pJ?PyO2bULEb5p9lW zbEH3ZawL{Gv^k>95p9kPBZXAXMvEioavozjp9{Ef*=%DwJFuT4Ivpuy4|}QM z5VZk;M}yGms7^=Q(Vh-;M5m)V9Sx;7(exvRK@7&bIywZ6j%H#%M@Mr8V>ush>gYJG zU^2II8@DqBeU9G2o!pB)M`tpN+05s8Uf@MEI{F6ob95me@)=9{j%C=<(ZBece^^Hr z`W#))26E8nsP}cWgi>}EllQC9_A4qT(<=+&ZEi(V}nwM1h>EjHAWL>lR2 zkcmbuqd1rIu%Q+kYO$dfjaoEnv7wfmxEXy~^l8zjMV}UZTJ&krr)4Iy@a|gXFb|Dd zUgLEZ^C?UC3_EJEqZX}NzGE5R^8>cjvI;wD`I~>(NgnwWP)HHQ=+~lIi%u><3vB4*SA5Nn*wM+K_?ch$jV!WRPa&F| z)a0ZlCrh!ZlQwlypObqzNE3%SLTf-^YXE`RRI5$3>eFgdtv%^OKVnE?AcN4PRg+dt zS~Y1M!Xw#}q>(PLq z|Np0rzuVG|V7k(qKJ+Dq{tO_2WKtN;NJeo9mvR}GGma~`lK*iH6S9?Ugr(oWFa52h%fk(ulSl}EN3-q_=7*mCWkGQvWqgxsbDvIIKV+_I7BUt zoCpXC45R}c2_u{cB8eiJe#8=oHi08Jg;P0=)6pyN9M0uDbP2qc30%kZ+`vR8aSL}a zjR%;{Omqs=DNv_CodTa@0k85d@9_zX`IMjeg%zyiS5~1_pjLre1?m*Im0Y$_L@_1k z=0C^;1y-U>pf>)IEGY08#{+_bf@niq>?Wu$It7Ijflfg>1w}J}fuxc~I-?lP8H_=r zp!2b%pmAsvG=ZDZBxo`Z@i33@D39?tPcQ>*f}Z6S7NAYgyS&HyEa5Yj@;NpXv!Q393b#pc6FH!pVT3HX5~QPdB=wQJXOOqe+`s zGO?XDBRGXqIgQg9i8gJ<;+?h8rj0gju4Mw(aVy?f8*i-56z<|aG-~rGnzVV6r|_oQ zyvbX<%{#n{K5g`Avj~0Ke9L!e)8BArM{K+D=>BY17Yvoo9SRL z9maD56Pd*QOydEj^B_8P(5Zt?9kl826wmVlHq+q^-o#t#@DU%QO9x##e2L9;u$d0p zbXdi2{KGmnv6*5@C}kHqbtp%t4w`g0NDYUmrH*=Rr(+Opu$_*YbkwAyCLL|3qwREz zM4yh)48V3erjkZFr!$iC7>hm~FW?f!aV@sf@j7l{GPj~hM@>3DitTiK9DO>@U?xxU z91D1r*LaWj@vb`R({U-E^EJy@!AgE*Em>saZFSVC<96~XzVM!I}j3BZmIy6P&;hGO?jx8wx&yG5F>LUxfVx>l3U`@OW$} zcp|rPJ5$gk_;EA|)+AVy;91OO4$oji!LMUO!8R1U2pbCim`~6s*oJ~_DA|rmJ?8A2_Sf^l}g0%_OCip1F0)jdPVmqB|r&Diir<3h;3L_kyI_cC& zr%u{*N+N|+Y^T#{oX)wN$5_rsn@*Q=4cBrLH)A`U9^@fxr<3h;dK8^H>C{Q5PTF*u z$IHCJ0^Z|&K42l*bXvkUe9O=Lf;OFgLz_<8blSjHaw(%6@2S&nbn2v2C!IRkPAA*x zq)#V(IvvJlI<*D_bq=5>y$D68&N_A0sk2UU;rq z(|J5sGl3h?sIx|$r*IGVVk@2X=sbrfd5WibhUc-J&M)#3Hq=?8&Kh;rsPlI$<9lqU zv+ZhAOwCU2GE_6kQF8zq1 zKLdy*4%_K6kW_4^i|ur=oh~D}l*_Q0F5|d@E4d1ty4X+`jk;*lWh!?tod>a{E)Qcr zUG(Z=J6)c|cDgL!9p1%;x_r$ye2YF^^y#8c7k#?u)5V6mtYsZpWV4lAwoybe`gGB! zi!F7jG~Y=v7@dp^BNj;eV-5blqGz| z3Rdzft60q%wCegBe_=yiZK&%eY^dwM{D%#7wV|%%=+#xPuKQ^~uddCs1O#vodXfS~TdbfPm|=s_q^M3X=wNu0*%jARs}IfF6i)ZLc4UyL^0$8$9knS?ji-F~{? z$z9yXbTsNd16{i7(tR#3@GADx{Sy}RDNFc_rF@Py-Mzi;-dpz{_?gxGiT!ln&JO;? zZo2Ozk9;)hu2FZ5y6?kV>t08FKv0jiw4*&8=!i}|bn2l~kM8uLA2IZ2AcM#tli`d& zuO1rp7|Z!w&N!}MGPiOYw=;#Q=+r}}9=_K-9^zqUF&mwFJdZ{_UgRaT>hUHE`4EkI zXw*ZW9{Tj~ZR)X{Us=UQHnEu;wy>34wCbT%4{xi7x7A}edpJl9hXR5^0tuoGT7_s8 zqE(1iAzFoWp%;Rv}u2+=f;m zT7_s8ayQelqYyg^naNz{u>fsC>?q`Q-sXK4^C?TvCq$o+@Aw1T3Hgh^`G<96k&R{{ z+p(#TB8n+tFO}3`KOqe?a+KzPpq_1MM_0PhodLuWM?486qEF9(3?YM&Xw!2v=W_uU zauFK!yprp<9*uh5iY`5M>3I*+cm!Q~+ECAzc?E5HYSUAjp4#+$gLilrU3z}TQa)!H z-}3{y^wg!NEm=HQ2GEJlbis~7H45!bH2sJn35`OBkV+cEv7ykjI2(Hjy^8T%&HuQDYqad%I)&;K`X)Ms>J+L|s7|3eh3XWlQ>ad%I)&;K zs#EAc=oFfTPN6!5>J+L|s7|3eh3XVqiB6$9h3XWlQ)m+{=oG3`?_hN5ty6EEdiNld zD56OqktC8yAr%|yJ&MuTOz+FMoN-)%X1z7*ty6EEdQakZrZAPqd4d_tWEQjWt?vCK zdi8#hH_)f|TYSXFe8OUuqEYW3(Wm!MtYIy_NxlDKJsS1asP`_)C`YT_TJ_edw^qIN z>Ajx@8fm5lo%(3fCj{@SPcQW8)0;l@C6ZVMqfsAQ>XXTE#&9OK)aPu*auNFU(WlS# z+`vTc<9_U>&jU>7K_22^H0z^HpZPq`3%rRoecr~msLu!J)aP@);Cp`HXZ)7+S;cSs z!$vkyL@_0lqEjE8`smche)?3QPal2y)NzdCoCpZ&>s|HjMt5}Tt5aW{`s&nIr@mpt zU_X5aGKe(N8O3PMK&QUva6Wd_cO2unj!E3go!rF}%wQ(7n9Urt>1#KA=iy!TeFa_m z>eAOYy6;zf%{P3@cPvArz8dw_sP7uI>AQ|Bwy>1~3el>sR(aBaf13D+iEn{aKywF%cI zT$}I&v8x`dCyy9(DPT$^xh!nFy%7Hz_><9cr3CNv7an|qjv-GtjsxZQ-? zP54vj6z*+>KhF!i$QyWL;cxLFi}(ml!hd8rKcP?fFRWlCT8013CN`5p9{K1Mu2*;| z73}8#jWp51Nm>JfA~cEUiT4x{iars2=t~${MZ}TJ5QZ|G5$F?f7QQ^}B5q_dcW@u~qf3M?5xPV?jr~N}PlWwM=o6t&#Ou7l2P{ON2%CwpnFxI%^odxG zJ`wsv=o7JuKiR-W^ojV7o#+#xPed^`6yduQQB6G!G}4Sd5&A^hOr$=M`b7336n!G~ ziPR@Dl2`_#PozGPxW{Ci@1`j7>_=Y_7gdgo0)?BMBd9RW}{Q2PLVoA z>J+I{)8D$FQ5I0Q8B{C#om!eja27GqIs48;W|KS9y)M_<&DX%#SR`ZlW}a`h^v& zM4za&=o6(+)E2g)Q&a`IMClT>mrDG8MO9IaPEk#?a1x!OJJ1o0qBV-vC|aZFaH2^d zkzr^PtxfdVXcMhXv^LRW(I#4(Xlbc*}=d3herL%(4?Qe^xKan{Ti{Ce)baMUBv{_4qak2iRnonbcu;%07(o)lNe26 zG>Oq9Mw1v#V$Q&hV(cj9aExq*AR4^3jG@c`4YotTHvD8@G^<~inL zJ29{EIt%%bMSO%-G5W+T<9k-}D;mXYCI^jTG>XY(8ydxE6k|s*rBt#HjbiGkrUP9)uB&KK+L<6z{2j3aO-#P6l?=Uz`48IiCv{#}#POUz7e5nZzyFPJfO1 zYt;V{?54ja{cWZHi@e0kyut!rMW6oOR)2l^+fIMm>A#fk`GFr<&I(rJJ@x+wjrwcU ze;eLbe@*(Au$w*jw)8*D5sq?<8`~ z#u1NBu{y=-6suFLHnACuWE7)0p9|0@R-f3*xRUG8CU!EnayR#IFLQX3r+6BjVs(nu zDORUgZDL>JJ>KU7K4l5tu?*XZ{Q+%awTb>!igY~D5B{{4E@n5E*V|oG8xVo&ctrw&Sosy#OV@u6}rUTfG%;j zaXXLl7?1M=GnmONW}{P_-Nfk<_d0Lz0Sj4*-Ne~V+?RZdHgUSdt>QO+XC1o4c~^18 zlu*hp$|$D-t>Uzb(<)A@xO$Frg64pr_-@!sd=I><_@4A4l-_6-uT8wo#1CRH>1Y%` znlsQSUZePPv7h*HT*1}o6MrMx#NWl;=n=0+ydLqhnS%|*+fe*G>?ZytUdEe>f17vE zBmOJC<{Pw$x1o3&inpQopIFV`{DVgETghb`+u2DW+QjchlX&}yuR)u5Z!2Dxgdp0W zMS>OyS|s$LFJb7C5KTW4Ng{<*(l`e_63$~R=c7%+g(tYsZp=#rpIf-VU=@V*j? z&?R9HRcMo-O@cNFM>$DrKv1I1B=#VLp6HaQQ=(3Z+9Y~siLu0y%n*h$23tw=o)XVS zr$n6+bxPDJQJcgon80<|PvULd&J?DiO`6BzU zNw$*|MmPhAWia|A>63H@`XuR-bQWi$Pm(@K`XpV*IId*^`Xt@LWbWZ!?&E$QiJiv6GU$}Dslq|2Z;d5gDs zhj)38_xXsA(QD8$zUK#iWEHDfgPjc8N-i1=(rA!IgZ|||3Mj*y8e}_z_R~NkCut1` z8XSN|gWC~I2tA1)k|>6eLMj>!)@X1B8V%NHuq_QflMA>I+Zj9_Z3b&I_!_Rqeg^9@ zcq;cZjmLPLCwPgMd4&bM%4@vN8|XB65jHc}W(I%3k1XdWe&$zfXYe|*$VQ{Vx!B5J zO$HZYCxh)|@F8lcqaJ+*H*yqxk~`25ZIVOKCRvkYyGgd2eLZjqVPDPXC)3K9e zJ4wEb%NfTNT**~vlROFE;p8c3lYBqZ&?I>VGnvIx%tNDOjgoaq)+G5|-otK^y{Y7- z{K5)WqDk^9>?YZ6lK{729r((nT+LpF5p6JX2`|pHAJr=8V$LYo4A=}7~fLv$LV%@A#d{KemFVlz4HqKtAX@U0oL zhrQ@EM57_P3^~pTngfD{wx_?>Llvw}c3Z{@_pk;$Qw_Cwb&kKp~n9 z(`lGC!wykP9Vcj}g_8k6Df*>_Dd!olkQ#JKIl|F^pj2H_+t8MF1k;t? z^dW))#1e-MrP@&HFftj=dDu{@4W-&pstu*uP^wO;0DOIObol@81 zouz7(s#U61sXHm86dOw2hYh9LP^#}ynl5R&q}fhd2Raf=Cpu$GX*#9#BZmGAWDveX zX&R+zls1CXv8yz#(zHs`C(Vx1v`Nz?Z31_2CwFl-_i!)wF`WmQf%la*mw7zPyS#_( zq}fiI?WBFkB0l0%v`PDs<@|&;Y1*V|llCX;&?jvh+tDShh~4aAFE*2QjN_c38E-7@ zB&`8K>9&-vO?ppy5lR%%B%w{ZHtB=0q4acgNgv4=ys>m`(l6yI#$zk#w{bgDn2Jv6 zI;G#wG#+3&x}?uSmvmjypF@{)UD9<)*Ckz-bY0SQN&lE7*i5=E>AIx<%v$tG*C$<* z^o?v{Gr8DLdNC#Fl3vL^bV=7GU6=G0PNGXj0D-il3*J~pZ)_){F9Yz#GQ6>jcy!7b zLMFqppNuomC_|r&3%HQ$xq*pH;zn-bW^O^V3>(ULh==jcGM?lqp5_@e%6O4Cc$2sI zkVP!!3%qR%CMmftunOA&?-Z# z46QP>%G4^eEuFEU%uuw-jHVyjWDa65$)u3MNJeok=P?%VDsuwYp;e|7({(R3{XCGbq^dX!GMlqT(L^76f*iIjP`e@QelRi_J%^c>ELoNl_OP^9S>Z4H~ zUHa6cNuTxDOP^LW>9Z9b`aHs;>_n43kMjiD^wFk|-Sl~p*LWRm`n<>cXwyfVKHBv8 zk)P0}&o9_hpFgmhzS{IX7B|)RG*0IXdZ1O`3%HES>CN?M)3-0dXwz4lzS{KFrtetB z5yg1ou${iz^vxuT*~~$szJ)BJ2yahco%$}Ln$^^@kxjI-jqT{tSC_uJ^nDy%`aa21 z=+jr9zOS-}w|NJB`r1xk+v%%MUw!)iz>nzDSD(JN)AvvyDEKIjMxWqQ>5e|Z`UIcF zd0a{_^a;L>-rR;h!TJQ-POv_~`UL9}9Em=``UL9}9Lq#9&?i`*U|oWB3C>|23(+Xp zc7n^Oq>8oJPq6(2H_?VZ!S~~if*)iD5AiUMpi{6;!7pGp!Mk{!H+YlJ`GPO`im&+w z&4M)x)+zWPb`$(xAgEt}<2iv7If?G{-~uk>BCg;{Zs104VmP6UU?gFuP9MxTC-=+o~G?&L1+<{s|lK6L7*Q$PFZXFvUR zv749pkdOG7eeB1Z-0xF9L#KW=)K8awfAD7@C?tp@If|p{hBhI(gq(>kA-aU<5~54U zRfN!=0SsgigBik5bP5?mEOEp$nKaVLK%bBqXcMAMND;b(EJd3TZ9=N3rH&3d>0%38 z*~WJC3DGA+pAef0v7eBqd4^}%%iFwzy9#*^?@q`EXcnSVh&CZM6Y>*3^A~^fPavqj zF8z<;SdPPf`k%_#oP+)JzmzMuj+?m!yXkK?{q^WSk}$%toBrd7Vm#3#lFB49$zmaS z$VK$zO6+OC)%0fo z0~y3%hA@<2=r_QdG$4+65=bMR45pCHOcs!feghU$!U|ThiY7L(nPysOrHyvBpy_}e z=r%yN0nhL(&+$AO4S1Ekyv;l8V?ST>4c~Hz!~DyC0e^>qP6LBDl4CiUGdYX1>B+@h z!nN4cz}{SsZ4K?1V8^?1# z7jPjL(UXh0giE=C-rPnX`ZAPZ495))(rC~aVu?eeL8)jmXe!ybuR)6_qL{^$pwFPC zEJL3`^{hjiLCv(#%I)02o!o^x9JB+C20e);gLbhS_ciE4KH_8cu^)W~=`+ZE4bo@O z?;J#%!AB6pk+`qH8Vx=X_cgc&XL2DIp~>JYxrz|_Gk}2%VlYF{Y48ZN8LZ9VIO3U1 z8tJ&N!5R&o!F(2wOEHUC&I(r2NE4gbOf&inZl#Sb^ck$r;2k`~!#u^)Ji{xz${t?h zE#6@t`}vx0a9@KDahQMkFAy{&z!3zY(~x618EuA~#o6@aVlLrYuA?{ZYl!s2dx4KM$bMP>qIqkB4e9^hMs|eLmnrKH_8cu^(-QeuwvFs5V2j8G4w1 z13|+y8K%iFZ_cn2IEB;EXqZOBdT|+=4D-ee3#K0-^k)DA8H6^&Y-X76`><%V8J0pS zlbFmDvYAT`^U!G6BFfNY*fKV-kp>!RViTKbMw?;V@!kx(A8m#`#^XG}E_U-0FXN_$ zy~PK7$bP=yOTOX&zoO6Zqd1ylI2MhDYcyP=;iq#3JvfuIa9_jE;bN}hYOX<>;o1z> zX82%+U_--o8a|vb#u85giD)!DjTy|uZ4IBzJQlK;5>~L1RcJF@o8j6F*JgMNt=Q0T zorc@c@VnT-Lp;ngJj-)Dk5yY7(kRs3xJBglZD1NvI~F>0~g4 zOs1hrXfB$BY7(kRs3xJBglZD1NvI~FnuKZ+s!6COp_+uYqe-YHp_+th5~@k)Q#_5m zgua3vp?i1}O+qyZ)g)AtP@4(;j-UC1KLbG{j-wmLa{?!#(+HhLXfr~a5$AC}y||3a z=}R!~YD5VA(P@NEBXk;}&4>ub6OFqXF_C1lm`XOfjL>C74h0laN*U#>X9F8?S0ftH zX@pKAbQ+<}h;8^iJ>ov@=W(9kN%R@<9J_d(H+YZt(PqTwe2Xq4{^1aZ`Ir9!K_dek z!O^&_k-ChupOI&AHs^2+*K!@bxt<%ik(;=U0faJwkwl@*NNq-HGco~vMrJUDndmao zUPdk?k5yDqNfp(sW({lc9*@*!WCxveaTj;<2#>Op$IxY@E+cJb?LeBFYz)uh3ORb7XL%5u(z?HFulU`3j3OG_!fP_{=bhMh5Z)@3J;)F zxK`muax5ovCTC$w;XS#SOVB6$I(lPI;WyKVL1+~ohF0NPg-;}z6jGVQWYS1Sv+!Bu zqE)ypg_p1ddkU|l3hl!63SWml;mzn1ZcpJFh2O;k*ipD0h3gWoOSmrKdw7l4v88Z* z!u1K)Cww1Yp-;Fz;r0`*Pq;qe`h@=%2#N@xPlP@Z$8Zuo&?iEl2wfs{iMW(rT!}^z zw{R;17{~}lqEAE;b`zmbggy}|=o6t&ggz1OEMf-pS%5wf#Vkgjh*jtlp-+T95%v^O z&n7n0hCUJ7aAOfR6!8>K^9;}8#v-2Q1ztk42z?^lS;YH%zyW^XM}FdGe&JVs!|g?A zG|Fa19Y;4#=L|F&rO~K!xe)g@>I!UT)D7q}sxQF|A{32A#Su>eiD)%St5I5w(r1)D zqq3Ps4)f4y)H0T{f|Y1AN~2L4jnZh8Mx!>+LMs}Lx`R8hpHVuEx}S%561_(4VmG>s zdXu;Kf-m`sula^=`Ht_=Y1AL+GCIH!oWO~k#L1k7HluYJeGxsmlB>9m8@Y+w=+97w z5lsxS=rmfV(K?ORX|x@UP9c*lW;2Jmlu|}HI*rz8v`(XS8m-glYV2pU{fxGs(amgQ zJGZ0L=zDm8$9Npu8T|r#c#YTjl+XAaokr_4TBp%Ejn--O0e<5Uhxs=UH0BtNr8~Ne zIh`{&oAYr~V=hCRF}5@2R&*INf{}y~P6VSE%{ZdaWsLodNh6&Ma#=_o`4mvdB8pgo zHe=SXmKvJSW{fstv>DUR7HnpWE@K|%5uWB5o@Fm@^A7Lw9`EC>#(cEdwKk+kv z@pm97@+gi*n@DXU?I-dS&O(<+T_SBJ@?x}!yoMXGnMhlS9L8`$(J4}=NSz`h8H+xV z`b64KWGa)G%sl3^0G%Rriqt7mr%0V5iz%lHn~7Y_dN!~TT_QW^qzn6ryo((?#7;Dd ze4dwig*S0mk)QE7U+^W`MA}WH-9*|=(2Na zDBFqZ&0vOLH&J#IHJnh~T9ge%*-+GYl9<3mGO?d1jiNM)vZJWEQSEIS)RjQqU8XP&`KwIjlY-s&}IBi z9%B!$@j7qtCU5aS_M+2x+ZnIR_;2`@U-*^7{L6oVpy&Wcp-r?d(cQ73Xl1(4PSeM5kz-qHQMHW}?FgCyMbzqffLx(fUN|6Rl75TymI)KGFI_>l3X{v_8=* z(I;A;=vwrN)+bt@XnmsfiPk528~1V_`b6s!txvQ*(fUN|6a5Bn@)r6;>l3X{v_8@L zM1O-m(ZBF3`b6s!txt?TG5W;l6QfT|cl3#IV=?E`lgn{eG43ixml$1Qbcq?v5bP($ zeqwZqiC`3?8BY@W#OM<<3w>hriP0w}2Yq7niP0w}pAuG}PmDe>HRuzw34LPpiD{vO zt=xk?F%P0m%#%FN%e=yee8k7>V?UqpDPQsx2l$?Z)w(fP0EPiIX`6jbhK> zJZvYn7ngB8H*h02aU1p&t4*vnv6{qc5<8A4;z=e2U1D{Kor5m1y2R=dt4plC#1^uM zBFb4tHLF=e8|`QkYcsK3Y(bycZFqxXAK)<_=LvSPo0rfk_BGz(12l{MoG;KO_6L3p z1jQXe5Jz$pM{^9`p19-CD(-Z&i94SQxPmLWimU03K5^Q_g`iE`aKeaWJPGI$mx?ZN zy2R-cr%RkJak|9WOPsyL=@Vx&aVuDf&BQgaiOtwcoV~=kr#PMBbc)j^?k;xl5D)Vd zPoqVg-Ne1h9^T|_KE{6HKI1ENiTjn`0zvUw#A^|+MZ6aATEut5hT>1=6nbzb7jh9j z(INh3ZsAsJCcY1S31$G=#M@2$81#wPCO(lQCZJJ#I@6hfHu2iT=b}w~F=glyUqK`K z#Oo8UPrN?y`o!xKuS@(^wy~Z2c$A$yh92>D68}1HpiTT+{Exl7$9}%%8@}Zibc#RB zzx)>nN(i7?f=&si(w%cSm-D!e-dxWO+=x~QS|wl7#uD!0Zfq#wVIIML66`0z zeiHOb&?`Z&1icdUO0cDbk8oQFUt&uMKciEEP6@y9Cx-$-i5ex^RpLpUjQu2@#o1iV zHC&5ciFzgKm8e&uUWxXU*q`BqGJ^F0Un z0X-7`;&1-JhLVot1Wx1(dZ16zm0X2BN%|yRi#|#EBsXIwNzJt2#*%bOYR9c5-Gxp`kFpbOl3qcZ zq&;YpWIIW3u$Q;_n0?qy($~1NBu$d+CFwA3EJ>dU0gfPuV>k(oCTKLlh9+D@Pjs4~ z(*&I+=rqB0Cfv#Z24Xi8MiPc56EvAHkz`UxWfGH_f<_bcnXrIdidoD`R#8DEYtU+f z4Nb723EE8Pq>DSakNbI+=XjnMcoBP=U{4ctnxNAJT_(K4KKAnozw#TubC5rRjJDO-m6Lp%H zfi4qgGK*XmvIN_iSV|cy&}O186YJTCHWN2vHxsvV7kBd{Pw_O*pwmR1Ch9a%n~831 z;{Vvo+kA{Z6ZM(+3;ImdXX5W1M4yTJOw?!M;XqLGQJjcA$@(OpjXufxByxZcvK=L-GaY@B^+{fUKFKBMldMm&KFQ0m zo#a~Tu$yFUlC?>`hkLP^_nqvO_E>c75>LwG)dMZ*=CYI zlvj9_cX*fgcpuwI(I!Qgl<)WvZBl;Y??6y$fFtP6X`Id(^x#a+LZ?)nQguna3|&%t zb3H>C$}ol#igzc~yOSD*PN~u8k~)!ObV4>zJWHW+N6HKXME1re1krzzjH7UH0cr=r;;eJ0t>q@G;N&D?_BOuCIe^d*>nxUWeXO&WvkOd3lfNoX`lqe+vACY@~rkns8f_+}5OKG@7K*B#kC*lX3j$j;d#FNETvYEzoG@7i@omC$ohIuvS*OW1HF+EN zVndVfXD5$gLz7=*7rW7D@*BLz`+SNGP1a}fLA03sCx7ub|8R)IfuOV_I1bxM(I>PudW4NgG8J<4Gf(45pBYPH8%&&1MdB(I(A}rD>C< zO`0}o+N5cdrcIhQY1*V|lcr6YHfh?VX_KZ++P!F#rcIhQY1*V|lcr6YHfh?VX_NK_ z+N5cdrcIhQY1*V|lcr6YHfh?VX_KZ+nl@?Lq-&F|O}aMe-O(mpn{;i`wMo||U7K`m z(zQv~CS99!ZPK+#A5IuQnX30XC2z4 zYm>eaZPK+#*CyRtl)i<#xd(01HA&Yb{c)b)8T3haPwB7m4)3y`PtYda8=U?-+N5if z{wLa`Ym=@``hS6-jAJ;NQ_v>kY|cT8j9y&ESmOwv(Yr#_e}NU-%WhGW5#OD?_ggy)yL5I2;I?aug?W5_(P1X^Ku$&gDEV zLbEB?a4olRD+3tFAfgygG%>^yM?48kM5ihCGex5*8coq>N*?(XpwpD4tfB&arsy+e z1GY1zg)Z*kP9En8p5!T>MyDw{O>t9GUgBk5;Z5G>13u&je&i>9MyDw{P0?wJPE)kW z3~(IXIG!`;!I_+eHksOFUcr@I#f{v=ZS+T@OpP*!6Tv7ZphsphDWoz9d&;zn>pA{mhEKOPF5vVxU(#Mvh>N)Crh6! zeX`cG8T-lF!dC9#UUu>rkE2hP4Q08ntUbKOJG{$#e8=}3K%XpqvVKCJEPb*LaySq) z^=OXaSh}OjR9&Xp(A2XzA5ErS#&z`OChTTvKL#^`k;IcgB1ud@r>QzkbyHI_m_jBq zn9l-oS;0zHQGrfVb(*TvRGp@3Gqr&>+Uej9?&KjJ<`Eu6o2lANeTkRRX6jzvMx&`8 z@fn|EBU5c;svcAS;7|VIZ~o=KKv1?e*|w8yJJ}j#Ym}`~wkFw^a|Je&eHB-84cBr5 zeXyNuowA1zP6RQ;5=T5*W!q797E_tSTyiL*oMkLWt8A^ZwaV5iTc7N8*iCjbEo|p@ zG|JW}`(7TzcCz)!et{R!CtIKF*U=~YL-ff$fZb&Oh}~rW%rE?kPT4w53vdLwOgo+v zxPS|}h@M=`C0t4`beeWOx=ia!FuF_|%4o(A$ylP%W|}V3CZWr;Y^Je@B8pi|2}@W? zDLPHFooTvETh9jCu$^hPGp&Dq>_bJ)3usjh*s0JnqJIew3@Efbgib_)buLq(Q3L@(_7JMx>nP*n!Xh~ zn*IO}@;FamL(_GduG94Q`G61kh>zLFem+6F>ECmJ-#N%1{1*tC5x{5-#TouH$AjnlYSEMlg~v!qI7l9nG+#8B@qaml?Xu&}GInrZaH<_8}HDJN7>0^JjHXo!mI4zZQkKszU4c<=Kw!oPc!Uk zhP#`g*Nj7fpqWQ;G{J%$;@@EXB*qOojbUbyU=ImJ=oGreP+6~ zna}Y&ud;{Ncn_PJ`2indM>9W1qnQWLWadHs2n5aQ#_^oMiJZjAoPtiX&On=4+RW;O zHnXmyH=4`}rXL{;Vi+3D8chtE%!Cw}A4 zK+tTrHTwuOnyt}ndzo!7vo)E0Iqqrpm0ZQuT*I|o$BpPSdoV*7%4o(A$ylO^CzVNP zG+U$DbIC!I+2t%_IV)JnDk{)t_8Rn=-AoIuXfpc_?&L1+V+Y=y*-xU;Y>j5W!t1=j zJ9v9$dwXVUF#3r_|m2GTCpE>%>d6b6XAf`kF1pOwhc0t;nWM`bUFPUAN0&KnYR

k-uGpDFG841hbK()azDK(5zlsF_HDMm_+;bM$X@8a24kI3kZh%s`T z(3v|hS?LTR$mTjTuHuu9Ki}RtP;&g(U9UQ#dnZ$8#+t{BYwDP%cKq|R*AEQsF1t)| z|4`LSJ?3*0f2Mi@-#1B}s;tiN^ip(Yw5c=yF>9>=vCb^As52A^s#kIq(>g=7p!yjxCW|pe z=?pG=^|NB!E5`IKo}sB;&ERS!qy^$7Uc3yih;g47Q^lC31Y!+PX;2y5`^9)*n-GY1 zFj)!2yGkdO&8~co(mat>nxb5ergpo~Y%QUwp>B{Cnwkz`ENCP&H3wM}ni@(3 zHAiJ8abXR$f*P)7u^8$h(lwL|YA6?!ic!7Ag{I~N26w72Mp9}{1UopyC=;Vxj0(2Q z9c;Yg1`iS=Mx_{4%8Y~08#HuqpMK#%efvetGd!Sgzus35K4I8^zC*6PvQ4MW{=rQH zuhy>_JZR{ReS7x1W$3^m=M5P&xZjm+PW&JK;rWB~$behaf#E?n4jDXX;J|)^iC$_> z#$<%1=9H#HW8S0BPaM4VjPH4XROgxZpExulG&QPENFCF;sbl`^*<$5kD`WM=YhHTf z$buikn+r`%m}6CFkrkSnXj*7$(1%V$U|sf=U20_SW>YIQr2T8mw0~M>YPzR&rq1d( z7ckCM*rSA|hLnB{nfw|u`8AiorEnSag3I9wAQERwTqwqqVk{D4u^3ClSSrRcF`g1* zxfF3qdkm1e6c4W)yO(r99= zXsk4Gi%K(+t9%<*QMoiVqhPccWCT~KmsAXD@ObfRUfS|XGmgRUQD3Z-W<1;t6U3n5 z;(0M%Q18;wQ-iOsT$&ffSiLQ{G&T2QvQmu)no^CHpY?nChJ(6|9lzg6Y)J^ z!jpi!ye7u$V!R>7n_|2r#@k}NBgVU8yeG!{N@|uc-o{e1d=sBW`Q1p(x~$ZEkn?H2 z+O9NPO=&0{WR!+$x4yB`yk${o)^m|RK4;*Q zqb6N&eD_brnM(5~Kc-TeznVJckY|?ccg{P(o1d7!(mSc-`l~iq8me=JwJNyCDot&R zw9 zt@;d^QI7+rVNZ-dvoaIkX}ip9Et#pMa*&ppT8|iiG?JNGzcrbuJ)Mgj;vy=Usb!0+ z4T|xX7=NpmVW42}kHlMTaha*@%HU_KFGf&myTO@omc$DrUMTSv>fP>utB=gYTS|O~ zZ9!&g%^Lt}FKS9MN~QZL$6a{ls)_p@@kHBxoys#ZQ+p{tCNfidSyRV^+qXU=HKudN z+Q&}5E+M@}H6b%ZAGIp9NMEBX(`obgjwp?~M!mV-{UzSIsq%Kqk2h5slKr*UXGY2> zP5SAb@treD!)OQ=V>MIWt|gCOn_w8_(9{lwTVM!~zpcF$hJgk;7!a5Et`gr(;=40$SWr7h;_W5AznaF1hb7)Y;vKiV z)XZaWRZU1s&3s;{`Sygw50LnQ5i60~JVCNo468IR_BiQ5~?%ug0&h9W`jKU~DL%up?;{afNr ziMx;(R!3nS-i2G@UL`YI^kL+6J2LprnJ-SSow}XUYbV#G`ro2~Iy{BCc4`=OsjdyQ z1vW~b#QhQvsCRMf>-Nd0)kzXRd0SAcx&tv;nN9?iqj?DS>i#7ha?`Bctqk+iN_>-T4v5MCw-TF@!^}V zqtxBNFgL4Vl%U)QgWx8KpDXd65F`57 zDWBK%gW}K5T>i_cuAZjMq|9T6H+77D#t~D$*&%k+f;RWHKj5XSPi;bGM)G}T(mx|J zqth~Tk;OAUmSOJ06cshqk1{E|7l=uzXgg&gsWTg);HMQ11Yd_-I_hM)5SbX=ObK5=dr2SYm^VYp; z9)W^2hzJ*@?4nW-nSmTDw3 z^?O>AnR-eD_4{Y$USU0Pe?5tr5fT?&)vP=7(I=n~slG2^ypM@^_N=XJX zQ}5u%M4IYp7~0%*xnTGK{hll9mZ*PoZm(lrxW3EgGE-0VQLn<3tjyH=(lT>bMjs06 zPg2R-F`FfC+qSq#3Eb|mhiL&x|N4+Ql2V#_e#->T>bPb`+H{yM9C;qYD5a?`BtBIQb3Ws36gSmhTu{*A zj)H>Osy;@zSKo_2QJQI4rFlSF*U9nARet8t?NYPVq=wrCGE#HB#P4q`H8)z68fpaf z8dp(yH1!k<>e+CnOPr3=!g}fj^=vycCI0Z1mzv=WK1zMD5|t4kfU3=s_-u*KQSXih zJbfiK4@#UK+yDF9lj_G|vXYJQP07a8;VsVI`I+t$7au%*g=4krZBuGgr;s{kVpGS= z_uM|?0ekSz31db&XP*CBLlaU%^ii)ui=5QlmzJ7GOjl&gM5LzEZ<|TYrUEgOVdj{_ zq;+O?T4&~39A+-V;5TP<<}qH7(61+tU#|q?30MF{Pz)tdD)D&|pD*#pB~G4yfy9d> zjxSy!aXu)bHAsA+dKbsO{>zM75e6>WCe-Q&OjgQ6 z1hTo4bJtfZ6T2K3no&RK-kncAVYIrHTRBF*n8*Cu)G@xXv26L$xOrEJXvu}K|v{RD|e=$ zJ%1uI&u3-kMcLagj*-fpd2_qYY%QH>Ae>0+Oapbo7aHkI!?D(MrhytkgPW_U+?fU^ zxFo(>;xDO}cciN7pyepTTXE;lut%;2YGzBru+ZXk6@*5MU%)*pBcv;Lgf&CdD= z!*o%@pePMdhyhiMH4;ZLUsLbm+BbB|=*;U9e`8zFnTB&Q8J%h9*_39~|Fv-9`Ins0 zxv28zy1=B)bmb|XX}G{V=EA0qd2-^y#50aFv}v8j9CTFg#Tz!)nTAUkL&YD;D^l)E z!)0lmdCTG%@6C}nFpLVD8u~zA=m-7b8n_k)z;$pvkX(C5;_phF%lp2>*GYW6#6OVu z28n+t@sHFnIN^3<68}-@%um~OW~=GU=&a7% zCh<=i>&%@Nb!Gxra}rlEtus^$8VI0q2R>IiL&2bdF!~FL^K`o{tuyyC_>AlqKalZf zzRdVD4Kw*6`b+$)Cj6PU;XgNVX&RK4Jf=oce|ZERg}D;{M&jQ}{5$n7o_)jojMRKD z@gKGcsZpD?k{Uvg&0QK}QSZu0GtYi+ajTs!d!ZkX0?J5DrFl$MQ^$N#6Tk6<8$u7( z{_vdRoC~{;J{e`0<4f8W zj%3KEU^zSuE8rPe39H~)cn+S27vM!$4KKmVphOhEx&e2(VJ*;l(||ACKKCA=!*&9B94e%j+1Rn#gZNsPV8GH^nwGCgwS3tJ9;Ts@Z-9Waw;d}T2 zeuSUkXZQtvh2P+Jz!_|y1*G9G_#6HyDC8^_E-Zu=&=PilRAwJG#mrR!f|js*x&>>5$u4UvCs)Fa09-@LNEBh4*@s{a0?cm0;j@ha5}J8Eet{k z!VrNd#NZ6*0$rgSoC#;a+0Y%%fgW%!^n~-^e7FEEgp1%}xCAbR%b*ur4p+dHa1~q) zy`c~Eg?`W{M3@AVVG7&}_rX+{2KU1QFdb&VOqd0;VGcY9 z55dFm2s{dN;W3y8^WkxL0v13K6hjG=LK&1p1yn*6R6`BaLLJmY11y9mVG%5bC9o8h z!Bemto`x0h46KAz@GLwB&%+DwBCLj&;AMCPUWGNV7G8tb;SG2b-h#K`9e5YsgZE(_ ztcMR^1AGV{!N>3kd#cd!x3;Kbb_PcXgCIrh2!9Ou)zs%BG|zJPH=%6Jm3W%_#pr%!O3t6 zoC>GG>ChR15P~q!t@NwJf0y{568~Eg1(IkXi5(=dqa=2c#4eK9O%i)ZqKzc>lEmJU z*jEzmCDB0=2TI~#NpzINVUjpP5}hP*v?Pv|#PO0iK@xUJI3?khgjW)NNt`5!QzUVk zBsxnXB#DS5Vv^`0iEffOOA_5B(L)kFC2_taE|kQ@lDJe7y(DpkB(9P~Z%Oo(M1M(K zD~anQF;EgWO5!F-43@+YN!%(4O%jGA5|T(sVuU0{N@BDmZkNQJk{Bb2agw-O68A`A zk|d@`;yy`Clf(m(m?4Q-l9(fjha~ZcB<4zDo+KWZ!~#haOQKW~<&vnBM71PpB~dSl zg_2k#i6xR)CW+;eSRsj(l6Y1U&r9M(NxUS9S0u4U60b?(4N1HuiFYLNo+Q>u;sZ&1 zD2b0H@u?&}m&BKn_*xR*O5%G-{3wZ^CGo2yewW0blK5Ma1(Iwb$sHuQqa=5ds zB(IWWZ%Ou*WPeFsE6M95IZ%=}O7bR24wmE)N!}_+O_GKr6Ov3xa)cyDN^-O$ZS0uSclCMef4N1Nw z$#*3Ao+Q^v@&ieJD9Mi{`Kcs7m*kg{{92OVO7eS2{wT?xCHbo)f0yK+lKfjz1(IqZ zsU0M>qoj6{)Gm_RO;USEs*R-flGNUk+E-HTCDlPv2TJN-Np+OeVUjvRQk^7qw4{!e z)bWx!K~i=}IVI(mlvh%INu4CAQzUhoq&iC~B&mp`Vv_12scw=wOH$n>)k9J}C3U`} zE|k>8lDbqOM(Llhgx}njxuKlA0r_ha~lgq~=O$ zo}?a^)B;HrOR7{-<&vtDRJEjPB~>q}g_2q%sU?zHCaL9;S|O>Gl6qEB&r9k>NxdYg zS0uGYQm;ws4N1Kvsdpsxo}|`E>H|rAD5;Mn^{J#jm(-V%`dU)oO6q$_{V1uQCH1SM ze$RNMPsUKBGoTA}g>G;roCRk?cQ^-nz`4*9&V%#e0=N(^f{Wo2xD+mfUT`^F0awCR za5eOXKF}BXL4UXgu7v?`9b69s;Rd)72Ek2mGYp1XU?ke$KeTB07Xy?B~S`wP!1JP2~|)HHBbw6P!A2T5T1lZuo#xW zQdkC0!E$&SR=_i`5>~;p@Ekl3FTjhi8eW2z;T3ol*1%eL4PJ*g;7xc7-iCMJU3d@P zhjp+XK7bAIA$$ZM!zb`5dOV|Ng!H&=xc7mN@7uXecgWX{d*b~}7Ti6TQ!QQYB>bK{+2s!a_2>I=e2T|U+zlCT}xz4D;d*G#!Qnj@5ULsR2mMJr3$||{cFS++3x%VNtw@mK+ zN$xvI?t4(~`$VR;lc^WV)LNNVAk$(pZJbPdS*HCh_wO##Pn7AJOn*{l6v&LI%(z)* zjFcJA%gnYi^JJMhQf59avv!qPewo!zW=)h?ugmO0nSGqhzDZ`+$?T70&K@%70-2MN zIrC-Cck-ZL9vm(Y-XjmLm4^NRdd`bELLhYM+w2 zU8L?@shcKs%cXuNsb44!J*A}a#{S7Ecr{8MrG-Zvh)F2x?YwYCCjdpWu>z09eL_ddFonuYJoiUoh*0D zazmCck>#Ju)3aoSM^+?c#Zq}@M|q}Jp7}>sMrGwVS^280+E-Q`C94L?s-&!XT2{R# z&wAxqk!P37bGyrPH^_4}@_bKue!4urT%P|*Uf5q=xI$jIQ(kycUieL349SaQ>O6k~jC3H!qSm z`^%f9^5#-`^K*I2DR0H)t;gi8FXZk0yDOnJ!RbsvVLFrV32%J zDIfeP8$z;SplrBbHoPwzzLF2U@}VvtE|ZUTm5;j1M}~Z~R6agTJ{}++7t1Gm$R~%$ zCuhkg6XlaN@~L}-gDh;znsoBEpk*!D?HI3>pgljLKnm$g{O!s%S7|n_4-f9L4Y_u3 zzpMM&uDM!0S4%(X#1s4Ql&yX@4mtg%!GrqryXBTsoo=7K)6k&<`krbJxWl2SFKY96 zLQ$LB<&W6{o~YC2a7H7sV9*l_MqHgTfU1vxOr* zm(A@CyKVk}J7)9xqkg-~;qZH-p=ND(&9vb!OE%aY=6Uc$V=;dy;InxG{)o*T42Nt% zr{86Z`C|5%!{Z3V!tQ2mc-yq$A1gL^9iGf-@P?cLZ_pXDc|s0{%^eBZZ2_m#Ve>~l z_F&lU4ZB0mtO;&+zWJ~&V?(0w$~IU3=lS4p`5fka@Oi_5K#Zvnu?KAKsNH4rN4)$k z>LQZ?w7Kk|g4!6@43`K+4 z6Onged}G?s`pPy}{^yI~%g#x!E9?xhHf+J5H)eA?ViB7^=E07TI~KM3-66Z*->eBg znkMXQ=`^_PK67ole9@@K?`K^oeF!_lwoo`6wfXFxKse%X1tPI zX~1s}dHKN|A@qSI;g9<4wy-1M@wi-WZ_E+P+ThDK9~QSXjo8!5iD0&QGe-D>4t`|h zG3*NaSQict(=mir1OjfiJ?yjx-Oa9x#XFfcw6$^~9FD9nTO+v^V6oOUlKg8$e; zZoAhOM8Y{i&REc!6H1>i&(&DGyJG(y+Z{n? z#GW(3o9{I2XWFoz6&oBbM^>YJVGq|LW^+aO>D?Yr&=v|reKudz74t^J;Yiq(yB2xp zrUS1b5ac{KolaZGHElS+ z%AEAr&9&(WAwz0e2Am!@dsf89o)u+nhP+6FE9Q=b|MeeSdFNy&(};ttoCu%OycTZ0 z3@;&MbFz2Y+`bqm!p9csh(@BJSlHzadvjv#%C~zjKF+k^5Gyvg?4GPjd0Ziv-yN_a zo-EEl7?F(lgDeqO*lxGG@uYm&S($f2*i9P_wQ@0>E|<&PG5oPu$d5+HLM|l`F~2Po z@r7-^SU4OExqOkRJ2xqv_IxYDV;XU|l@sC5id4X3j|4+X5h8XwJ7*|n^W#C;0xpN0 zodbs|l2dC}AfF84t2?f8_DfJ2=PH-3y8!Swp8Pa z3~s-N?IIXpen#=I@o2oBaBk1w-{zZ^=b1*FXl3u@r_7uPyqI9j?RMH+c3da|oq#Rq z4uotWhcgy-*aM!R&(o|#Tx^=)`2TPo^6J#(rV%bHMmU^)Q?PwrkHd>{+8mAuGa?#w z;NXW`_!M@hGwSs^A{#|Ic{h#TrV$=XMi69Xt_HI%5<@y|u>hCE?Q`PYD?i`miuywi zk1MQX)eOIVd6(xkrV&0XOXGj%+vdF*15FzOR!#)^7E!$H<`WT%Z#IoM*@_XafY%IugHg9H;6)@nzA%Z1w14f4dTb8VGT`(2!sJb| zS0leObE|2@saA||djlSG19e4^>2M%o3&hmV?`C#}B1D1CkjHP2#+>-PxyUoGXBjt* zINgd7j{n`f%xlC5(}#wGl;xqM-i+T$W06Nr)=^131f0A5do$&+26&U}(R#8&I3Pq*3tI|g6Uu*>{08}6C~^m z;_`=aFr#4yX(PnlycpiRKKA{l5ocO4!eP%wJkhYzZ})kFwy4*IQ27E}21iiEV0ITS zuQP<(pEbgjcWKNrjX2xNtaRWrWUhuI8uarY(v_|NMi6}AN?-(f>T>y12olR_MBc0M zuxZ0NR&4Ou%_LpOp`4eHo6JxUZ^o%Ig)tTSMBR2Lk&w&p&za!PYr{O#hI6gh;092d6sO*u1!l`U0#JKH*L7!$~Jxe zv!BnVVK>i&-|Ke9*g1$dy`)53j)*N73Lq0P@>VgsJ?aYNlE?ppZ&_oSagmi%L4L}# z!sYh{f-C@X01njB?`w|m2p=AFxhrVW=^33;48yWiZ!ea=|OsnW%c zkP7}tAKO^4?4)+GHx8f28I0t@4R2n@ZmDU-Wme9F&tp25u3*#=A!%j{I!MyF3CdLv zj7#GSBiOEB(D`rn*z3=?ZLBbDxZILrXDCex3hb?W59WW-UWL7aOS8 zZ(}8@qK1ljJS-9)fq69Qj)jB&AwTrKX~Q*EY;fhW`4rOFBi%%tLGq<;@((t@Cls+c zNRWi=o-m$OZvV`C9zHZ}7+`T)nnAFG{Da>SAr0auS*X^6Ex@K_bGm~r5AIbUI?9rYu$%sghDiabx2H8(aJratN#P+j~dH=1n<@F=JHf^}U zl0;-}AP0pP?IJ7UjxrwtK}v4y-!`W|;*9yjR9=J4UyC1169!p14KBOGljYgd## z!y60O0wFujw%y}pu4bLOyhi+G8gYx26G1lLJP}S`BoYXzl0rl+P6vMrI(_^t>JE7* zYQ!A>)_?Qau%v})!%!%SK>}HyvTQMQv zGq-P*2qO~~v{CQGaqyDX4>)`{m)<~tnd_%3pjkg=Nn6u|xTRf-9n;)9gD$U^91v|0 zQ8M~&ioiHiZluBy3p%_Jc8qW?^z`S;7B1P>v?6J3Qf4QFs;Gs$(WuRCcVUDVr3^Wp z9-A*5^n1L7ec?dPh`bl$0MmxyR&4NQW1TSaK)mI)d7aEe{1`i>*C zr2$;|e5oZJO&i3@!f*z%(M~Ynb-G=oVq5{LTW%MA6lnmv4HKyFD6I_rD-ih-bxV#k zjTmKRR(ibV?(GVM@ew?PH@OHMRxxWmfIptwi9B&|~E^pA(4qsNDP zi!Y03>!R31iY^p!1bwXIoI~fxJ1gC$6?a*h5pJJpgddr9hdKTBnA*2|4zl?%+&j{9 zc7G(|Bvq74MmPg`e266h(}=NFE(dX6=0wDz2n7C;EgU8><&H2dLX>sbG6=XrVY@rv z`d6;=xz|fhGi?}e#Rg9xtCd7FjxhZYGyssB@=@Ihxq=j&qQQV87z$F7{C9cgwIOWU zFu~Hw@SE2n;`VxcoC{lo9xhc`L9c@pz1%L3D@YnS6bU!$TQBKinlRCl2@cbQAeBW| z7?*)889S#V;^H*WGUK&JqFy>P@MQj-llf-D*`^7TEnSIhMI-EShUiQp3zV*dyAjGz zgl*hwC#rG!qBz(&Z!T}ub4gFrhI_5p;PdDDBFN(7HnJ)LDuvEP2t*>x1_wE*5Sd%Y zzngb{8!j?!m}+Th2JG1ymybR!YKxRQgOs4ds&UGvnsp*R0`Gv!9|-4?A$crNm~KTXao&7p z%GB=0U5NQ26gpKRg4_rmz6!aV-dK#q>cP3qI<|Qe5li};R?M_?D#$XJ>B^v!%#Z5T z@ghtt4$8p6Ah`gVEA2j#=*~bOr&D=P#r38Uv#l8647lit%J{Zq%4xzN)Wg}wuT*D& zjD(F81t}5g&~9o`&9u5Mxydx*K`SCbZZ2bj>Kmk|(`oa%?M%#&kNDfoJPmn#p&$W> z&+g1^pLx&2P}78mtt?Q7-D8Fs?jS8W9)diQVko4W0yOfd987zd-bO!rdT!s!YlC6h z@Te6V@Egqq8VNewt`K@1^t(|BwTp&A%nVn6%(~wZ3zGt)t=R+iHC;nz#_?&E6 zv=C9ypgjaXpOS_>NTSl83w82top+fwJYmHK2OX`M6A_8=UnesW?~xP13Br%@lZU{I zBJPdG=m^N3h`jURZqtS$D>gU@FEciT$urQ#=d{I?G`Pvo+UUFt(g_`jc?b+c5sIVD zEzQZM4JB6e!HocAY(O(ve^gTtBj%(lMyD%%>9jEg34MZIZ@`h$sJvY&OQxAdlvz0u zY|iGzAgUtTe;V=zd<#q)>bAZO`6?Mp%1j#?tgH*=Fq$Goz~`shOu9PkX5Xa8 zQzdNa##jA?gj^na+?rjS)us_oS~?MKdXX}Fx08S-VyE7zS_yfZ=@?P}7jV+!8jF%Z zY+j@qOdA$kvB8_|YxFtYG%(W5=%tSgt>#?N0)wXGI-@D1(M2pAY4BMZ>PB&&OQJ zE{nW(1T0x&+OW!s4LGdk+6)BgFbz^z^r?v%0;QZ_jP5lWx0sV5whR0RZ@}lL67Ow(X})Kg@PeiJ@W1k5yn%et z_Xg95)s~EKxy(>2995m9Q7?IGvek$qC3w`s=A^UJ&fQFYm+#+1NWSirC7+r`ylmxS zuqkFPMleQ{?^KRdhyO zbf`|-C>|C4`LtQOq7EmOhA0Kk?7DE}b*#TPZCGo?25vma*bs@u0uDS!b_#WSj7mTR z)SY!SO5sMuXb_0yM9PtOKKx?Z@Vb@Q+vUvm0Fb&5hPhG2=EHYEq*Th-L!cFPM%?%@ z4TH9Xe6#XT(~38(oC&AfW4g656u?EiMJIx4MMsy2{UZ*N#x7M>!ukKV0-sMI zmKK^eylrJ=a8DsCKfQg^Y8(he9Jq4)=&FFh&aIk`12kjfT2tqV=Cm@e5j&bjylce> z`mN18rN>MEWKi8Z<|QXXOFoLlH6Sw;b-4UNnnMT;n`<6hx~pl#`<9IGXMO9S+Zpkw zdou#uMMwvmx+j56-9`XFz{5w}Op`St@20V|jcLSsD^ucsw?Omh)Y5%S8#Y+6fsHF$ z%izvN8l8Q3aHk0-B#nAG;+! z6uENxLR8OhG-6lx1K3?8ud^2;@2ot;wBZv=6M~gt%4IYbu*cM006|qwa>rCxr%T-- zK?55-!Q2Dgym!6y2-AqqES(59b1l6*ogVJ5q#?&ftWU(}V-Mp(u{8Waf^zQg^tp38 zSKbqGjA_FcmQIArWu~RP9uG5=lyxjhU5opSDezGMrZt5m1oa%MDLIMAo2XoRf@#E8 zRwUc)^=9up_LF;{Yt6w;I?Blp6N!@*;{Paa(YwPQ68U%I$QSi3b(vOtV`&ffn=?YS z@^M=XlQHOK59fvzoNHQ+y@bRrhu7tCg#T?$$+K%L^_wPqXK6;*UFM9SoT&V3l0xcX z03_(R8mc)ZMhiT3#;7~|@9i>qXT+(d4L?}10k1JLDd}|QE;3evBf@QLgqC5NKEIq@t;TJ0_oFOa@tht+{Esrp3JJ-5u(fHN2Mx$>Tf3r!pTvT`E+cRlF&r^IEZ5&u{@5j>^A zTpOfhV>DUPjo_!V)a^qe0z4wZ#(lp$r6K4Gxtfo;mR^;yAz5fer94>^B0+Bdw};hE zp&|_xWYB<)R7JgX!_$Eq`?t$BuR`=QO=xN5G&lopbI(xC?i6^CMyIN$`S1UI7$n~V%m`I40 z4AuyDe-rQ#aN*(8*~*n+n$V0+b6alX%rBHF(}vxx=mWPEnxUtq?0MdWG0HSz&;Jib z_Z6CRf?h(Bgrr2m6m!rB{*MO~kQkuX*c0Ja2_B}BU7&fV#8lIU z{jAtP+e2n;1POj!w5riNrtZw3qYih1epk}ic5c`S2fY85JM;EsES+K6u)h@>9Mp6( zMi73Js8%tr7r%~MZV{>&&#MSW=v?yRQ`-N%5jgFnDt5u%#a@w|^k7XzR6qfHi2(vc zN-zl`itf(YSg>R7<=XYydskX|ulC-17aQ+)cApJt$HPYM`{!QtGdXOs`|O;j%>15d zk6~ixAWYz~@%`|rNg>?rTHq)h(-@%%nks`qJv|e1ULtmx)U4$L5@|S|GfeCnWO4Kf z+(wM{ef4F-!|p+Nz#?L-GUO2AR>P-}?nb$W5EZGEm?18MsS=k?d7tGzu84wak>O#_ zK!ZVmiZ?4WG?gnMnN3zm^JH*%Aufn+Bwar)E}2bV5~U2xzAqu7d8)!Nv3HP;=-XgK z?1);!!;t?x4-s{Eli^`#5FSX~G!i>2Gl!xvq;@7z`U^+}w!;*I@0UF(o4z>kWpoo+ zyWt@egonP3MMMq$mf;~G&}OGEk(Cjr!~2GXr2l+3L|hi17#>mrt<3~K-Z(pyoss~I z2G*+$T@(8~a60?<{K}+~h zNGVLiCXx*Dri5T9Ih}%vzI=$d>-)~|uwM`!hzv68A}59PiyU0OI9S>4P$UzZ4DkqY zIXP^K$=%6_9;fr_&xVHs0u4qI7E!+^GAM0@eAL`u0(JO-50+$|P)a(*+2SZb)FCM& z&dT2n69)z9hy==V8XibqB&Cg#85u+jVWmY{lLkOc09Kh05fe$#!=4w!7#`At@IZE$ z#{w>_bUdtN@1{Ao9e_NK|x664llSg3tmDR6;;^ClQv9st8dYkFbmm zOGLzO*wpYaA_xzmIKPZ)QVJ$>D!EV-Kpns=7p4RDnXF98s1m%Ak(?fNv$bF=!^2@g zmL~oSf1?wia!FDo-MwIY!^FrSOe7MI;m3aC=Os!dhg6INwaJj2l8#}Hpt_vQY%H1y zIHCQ85lL7t*x4{KI>@B#lk$!@A@(pV92sOnkf!Ia%~YzHX5nhgPS!m5c)YI}*(?mg z0+O@wF(iR1{cecJ!w|#6*dSw}eeB5x5<4^EFkIr@N@d3v(t?Ru#4lyVWw9*SjiWbw z9wJ5?FNilx92JC#R6j6-&|0i9aU}31l5UM$%p?IF#Yv-7!!3jfBHQ$xqNKMA)l!!8m%0jwf;e;TwGR3b@$hJF;kx3??Q3nHW zIQCK;pQ%})6!K(9*-z=%dq=d#EXXlDoD{4Z43fgfnnG;|au770l8SsJ^XckH0nTJ3 zWG4`o5xpA@Gc4o=>4rW<;YaRcDM=<3_PJ07*g*?9dOy1GQTrY(2D zha#ew;|&-2!FnRe=~(7>@_a=HP9Q2R~%z zXh&eIP17JM(tYEI@`IC%4xJHsUKSW8rUqG_9VMreaP;R;0g##m>S5DDG8tKv-O9|Q zQUa+8*{WT9c^yem&M+)Y57G~K&dgZkfZM2WmNEpVKVphnXaw4lC^k$K24R9sK_AkQ9g>-*Dmz)rhEknDjn{qFoh%DqpYU*M? zqzY5CIeEU}VRn#iz$osG1W{SIG!fKP;M0IY4Ub6y>Epm)dXhDQR*TBQ#fF7BL1rWs zGmUtlglbZJJdWp3JQ+IFUf242*&LF>zzR2uYn#mEN^?bv`SwY5vt(=*XDOwXy zqqdT>05FNVAhcE{vO7WZ9MN3MOVUT2lGhj>&JNTOA<&CA8U*>0qec}~l8@<$6s;gb z48E2qAX%1u7mgmj zw%|6yg9PD$J-62lcnF9aBOZoLHr+rnIAfuO*-1pE@;6a@%aZ{jL+iT?4^EK5pv1bd z#o#;12@$bJMuHaG((-TV)J_~iehvnyY$`mFe`ywHV#HnN{f3EigRIUZzZxF(oO06f zaI(=Mk&t8wA{i;k54tDuJC!mK6nF7?h&U-9HY}VUs2`}!;v)!xO36&YlcdLGu;arn zlK?xolH#dOj#mdeUNkB7gkfS{kO@IbquF&5WuA#82AxfsDKkPPB`XEPSV}6VcZ9Uu zR#YCIH9TAtq$9|V@;d@)h+zz~6gCl%E!Gd$B1P^Fv0Ev6oJvxMy*A=#ykwZTBnYyl zQjBjRB^%_yr3M7ncR;3i64~aF8cP z-E;Q;NjSJvf2V@+abyre#5hqgliirlL_);1QEr%+AB2g%rMX5{8#RWBD}yZ1KAF!W zPKidt!qtJ+2Ju0jw2Vtnpei5{V_J<76p>7&hAdKs2&l}?&c+y`M?*zhpKXSRYlBQn z$_aNU4GIt>kt&t!Rv0EFM1zGW*1-OU!y_ot2jK8|htG^Me9D4v4HLHqVuB1210~|JIopZMJuQUJ_E!(TO3lc^ z9Dox%4(ArN+B&dh#0C13Vd9P;Qv%Pf*AZw8{21y-$~Ck;<8{$~JXBDP9S@MLL_n~;#2L2aSs$zu`ClneJWJiHu)2kJrk zxz|`JIaG(b(pg&MDw8tP*sispFT0D(Y|>?L%=(Bjg1vU(!G?!dgYXa{<=@wu$v`D4 z;AgP6QYoq7)|3ap=Z%qud~ifnR35So4-11SOp*A55*9qjslcj*MSj#O%ue7yr zwBeyF2oIqIzseO^ifW3LJ>zTEqjfopk1!?O?Zi>;3KtJf1p=i=EQ{I=CmSAWg3L*>0DN^p z3J4xv4UW+;B@R6Xz@&k(vv5UINEfTsa-(r1XuoiRVWKVw6X+~smP$*?;s{I4u*KU5 zqy^02IEcr$lFeze*`&~i_N zn4r`aN(8G+2NMxz#B{?$QxG0HifvQr4#y`6jVW3lk_a8lb2(Z$1y_ewZp0kZp|m3I zI2RTf9$JF%5K8baYf<>o zjb#jJ5jsNDIM+udgoce#z?LF#Da=lk2Pb+)AB?$%iPwU31feO$7?Yeqq84=^+2SSB z5h<9*$XCIFpFw1PHfJ4k5Omaz5W~Y8L3kja(RdN4?v%hOne4pdH3=Sz2(Kqa1iYV# z8$2CX||&c_lL? zgZyJ0&uQf6`~47cLfmS2_$0_!FctlX49?jiJPDPVq@F%9RuI<|xhC#71$Q(6hfv?B zOx$Uh_$)|A^eI~@Vl2eM`wS0X1mYpl-}e%!M}0ANHW@_u>R>P|_&79KY&d=q3o^sN>^_irUUB0SDg5FlR4%Z`Jjgk<8uVwqr(W&A$*V% zp9xclx-1qL9)1eK166_zlFFvGIAREEAUWV_fl8l)%sRE0ib-u1!; z!^7`ERz?!x5JqK?<&FZ+!dB}R^o=9K6=NOA5t*tpn5%@QN1YO_hKWCetc(y zA(K!Ttztw(MiPO99CAc_N+Ji=6A7UOG@`QbhGAh@kbWT5!PqE+?7kyg=ic?0I43s9 zgh=sIbkfQCNG7#(NE|^yIxF2;J{&5;<{y`HI<=KMRz}1l5*L1Cc<3L5hdv#)oE9lW zXW{3Dhc$!Dhop|$PHCx3K8)oQzeh>|V@ZclV8t1I6v;@UBzyGv@Qq<%KoAx>5>qHG zl}=O+r!-Q>7%<1Ki)|$DM<->zw9}=9~3wvM~W;B zHooy1q@>Z51Rwyh5SBU1Q#vCuvD7fJUXXrB^9wtXXpKRXpjK*jvhB^HPzFXAe7@xQ z5~`#Nwgc2gWZ^Hv!UjS50r!NTsigZ|;v(n*Ow|0~UrY>E2nV9!X2R**=@6L++nh!H z4HFv$VM33(Gsv1MLU;+73uN1~)gr`~QfH*-kbsXjE1u}{4p&Y}By;VewG9)40x>}b zgvSJqJ?eB&&^aTE)G@+qH8X`MQ@pH1Y*6={BQtzK8PVOlXamEwwm25qn}|!^CERm_Q+zT_+1sbLGgL!p@6e|IEXF@8{P7ZsYp^{(Qbx^?Sgaz zp(h>-oV}Fm|037t#YmIBgi`PAD@81KIK;Z6mU$_TVn-wyCUy=o7F0*^`XM7dL@h)tbL?smn3#do$q2k7*OTKT z)6xjch}sXs3=6vk>Ie3=WX_ zQ}QIkLPC&{Nb!?|*v=(n#{*m9G$VzWf0Dj4iP_>TpZF}m1L?ILP%7ey0E@;O9+HAg zNkp{|uBnHal^KsI#5>4_`G8@Dq6l#a@DwengvHjM4iQ!NWWz*Ckd6RA7(t0&nLq@b z&G?kmY)y4YH&!Pplkl7nrH!#*`aDD&jA@34v>+XUL(O-$CMQskf_=7z?NhC<6y^G$3=X;UP0fM^Ne742GT+8Xu3i=4cH1A&yd8 z)E(zCH3@qNL9g84^ANEXz@iHc6WKvJqE9it5l#4uE;Bp~57ZIKzTUz%$EkA^5so8a z2@pX!dSDd*pB2N5;Hb##4!dzgx9_5>3=<=QbOd$>gDQ#V#n-NN0NgObOg*h4hk6<5 zRDfsuO*zrj4&QUcS$VzT;jkb)5Pst+&m2OMaCd9DH!aIRbq@3 z3=g9NO$efue3LD4O9|Onqcm($y`8SGX0;{|z5~F{NeV?DjC&0eM+WK$jvMnvBO#q* zYm+#^6-y8{I!rXA$Pi;orjnj1ibG*}v{J;5c+l`LHqidNZ$;oE20Jf$%y4m3pq}7J z4l^&Q)5@6*>G&4$H&PXWT3;EMXGm=1D2ptuDja=EJZ*S5CKwNXoK6nW4_ICRvpLk7 zrZ@zXA%!FjLU409nlLGagvY4U@&&`gaY3df;oM#~;J!)C;+Qq!)pWy?!`auVlw%-X z1`{2koWor@mM7~el9}#R!^8#MqDo1b8BcG;-Qhhf5`*w{cOG;UYIkPpI|78xP7$rDu^Nq_#@J2}ArVRVy52 zC!{B5Wf4O{98c6KQEzz23o<2=LmljGNDl?6L0WLB)7d)8-5`A8_ z7$znJ>Ie*hUPq)8yO!b}#g5GyAQ4ALq!E)(3^>3t2TL7F&VZSS2C~-;5BWiO=u^mZ z#B-Jwy<>Qo9Ax8{L`s+&Ges%NY)sX9W(trNuY!7>iD$!5Ndz6H%CzOj>O|~@4-E?i zLFNO2K?YYQr)7q)QP=p z>fF%-1P5vP0rf871J|PxINt;>IQp9cL;if=?4L-2>TAQr^dK{W=ojA;pAKZvqqj3N z^_)sQnVzEjq}9daC?|rA{O{;1;|Ie-VUXeA2vdJ$WU#S94h$h!4O1bNmH>6QI4C2M zNCDY+VoW=FA}Lau&Z1up6Q>1Xf;c)Or>McMxhRR$M#NO=oiD_(5rmUb>N+JSGm~?e z{NYH6s5bsIOcV!M8>#;BU!4Dzk-&NDL*f&W4opyB4K+;=Q$%KPjtb_&s1C=){R|7U zg7gDXrT&?8_$>&eBkG#+LF(Ib6Z3IC;*4ixDE_2je^EAFiw77cW(Q${xCk>CDM)3? zTu}>=GaJDXq;QcY&)kU5%qHD9JCQ0&9Xv!b)Gc1$Ffk{{0;SZvUnL?VkqQmiBFMhx z)f7!opqn)$2L~556GG|P%WFJQUMIo=T|CHeaaNE8N}irspq%B)S;zQQw8l3J6axwS zFe(+`nZ_GQxZ(1w#z+8n@#cnyvx7{_6hFK(3t2$5aYPfx>M$*-$&a}Z^8}~U69&zZ z=_wuSGa?Jy7#6G`-9Y^bPiq9p5Q&Je7Y{Z(NDv;_avFq9suG856W@zVi{%NtB9n}T zn!({qnS?}BTd2c26tN$6H9R;$c;JLH-y9Lrh(Zc%Qw{<{2=&(3_z`r=gke9LLyejE zj$L>}9`-UkoEwaX4wnX%|25HD^8i3HSp=6-DiT@6c{;2TavHH2M3WFh4G-rBkr1g# zWYKyvf{Bmyh2U0B>eTWnfV)&Z#50rHG8k|PQixwJA|kELM8m|qAWRU1Zm>*{db$yH z#^N-?#6>|yqfh6UMywjL_&~$MB|$_bAi}R3Ld}>E=!Gy}@_oTk*pf3+)FGXQRVab_ zbOeHTOo_Be!;xvYxGYFdAg>Lq<3Jn6h7DgL5v2%hg26ex6rSSZxG5!`GKJCQ)FFn4 z`9XNVCSqg+CR$FC!FEkqE7e?jEPw`zP^eFn8ac&rxs@#9`W$I^xH1qA?76(9!7&V^ z+;f-@SvzQODiL5mMp$vQE(dy$lAe&>;n;}C!x+QE)j^g9(HUkeLRcNrLWv3+6jy?t zG_sMZA@~w7^rv%xMn{N9D53^G#xQYhkdDB1YYbE&PIk^t#t}|kDa;XRz&Vb917{LW z!=YD6;M)${ZN!c^(eQA65FW@K^HBr?!LbNLh@`9KIz%Qo&Od}zb~ZJBQ*$_3Bs!eR zGd$cFgaBWdsSLylHILzNLU6qkwmCdo1}y5gE-c(^%;h@g{wYebMz zQxT6-T|CurachvCAj;G%Pm1PJwv$~qdmfb&ObY}Qd1cH{4TX-Q7+r^)iX^6H8Xj&B zvNS@;wCwJHaiDPUdOB-?ddkcQP(H^ratc-kMMOd%UtEtq50NGIEW^YdK{_HiWGdA>?EwU6sFLM=ejgF znh;qDuB84m)=TnrAipCb7WG+d87A%t!bIO{J*Px6=PxcbOxzcQi4gU2jl|Y)41&G^ zGa!9XHTEezZ#SFM3*$+0Bne5GOH;UFCWfHzEFZ=kR+;Q%BvA}-mJ<6WRAUTO~Z2vQ~Vz+SxEfLF!5xtjxZ`b$f0l%52jmukKy6zAUyPKLPW$e|28~48$^GS1LB`6ON~N; z0@TTcXI`yj09%aOoJUR!DrWTr$|Q8m%81s8M-3Ox2kD6rC;E6(f^8K%5OfTHLu6xD z_X<|vTj8bs1rwk7-2AP&23T}Hm5QR;ssV0wckSsbJ-(v=G8AFKMNX6Af z$z3+8X8Re@ioN)G!^F#hOd`Iu5DiHgeyu{M`2l2`0&j`zBtIR+nM3d^XXg1lL=+LP z7#3a)!UD zfx-;LFwqelfQ6W%awA6^ks_g+E@rRcB4W9##dU^@vLJ)O>1SR~kQTtP#z2`YY(SXE zH29WuUxJ}2xy11{ISDDt_rH;FWwT+SBFJE%wG4){F>pRD#+SQ0y`LhokZpNc+M)MSSMjri4<4HT#0Liphg1kNRKA}*B^|C z3*&9WL`{&6=#%p`vhMuA@K6_|BdA4TCPZ8c#yHI7)V$V{$l3F<|K%)?#PoQAxUgMi zFHhWwyfi*FOf&@Ph>nH9?lw6m4%crAXVI(e98{S=f&gd2<7*_|FJXD;ab!gImEoZ& zNJp>-H^vC^m+<9K!zLw5i$&t%Ac=~Q046KDG9t+cKK3U>WEsOSZ=N-DK*ZlV{J#-b#vg`<*MjiSx0Mme$F(HZ@bE?u9w-=MRt7OTR5WIb z!9g9Yhg5omxH4=sT8oVu>kj9^MPW12y-JC4!6y&e{gZB@r{G{ziApM+#3WDUMhM$XJLfte0$Nc=#aD zQ261`sd3DOIF>;Um4q?TQAU+;fOM87z8|uAi1LhTnp(28Vd0}d2%;loh~nSKYDF*< z5J5zdHk6iwPeo7BBn})m=Vk#z41?3ctEujz1{vyhaBv2(uh<}PJ}2RXi#{zA3=iJ~;h|3zGb5S_m!ujV zz6&xb(cV772ST&AA{U<;a7ap>4*+V-kmqEVY%0|+ue+TRaWD=rO#Bd}BRHnQOiE&U z3H2sFB|A|O6rcg?IYt>yqDtVTfRwn5=#^ZSWEdWP3c>^7g5IP|<(wrluE_+TWGnkU zRw&vW%Vk_Vr`0nnnVP=FhzRGF3^zRd5=2x|ug7RDO>E@^AN=lQV3Qz0f@db(kffE5 zNEP8Um#7}kC5IapmImsEz8s_)F$R3ek%ouggYeL|(>qji#%us>2yGM-yJQ@6H2>b` zcK&gcob#uC9wX=cWruPHZZf5?xFmmK_QZmc!lL1M)28JY&FS923EY2@-@u7-&N6M_ zWU*qjfk9m!J-Q%&cK64}b9aG0emDP^08NDQp-IqWXo^^|V)YZNzgTOCwWe5W>8+)&Q~A6DwO{pB8JlScfVTI}}XJpHWgUsUW|oc=V*~Go}=bFDNM< zF+@3!Vt!HXz-{M@o;0aAza+xDH=R&8ZCc*U;{1u7+HRyr{1G}MCZ^x? zJNSBYpfjPf#9CXdb;MfNW@mgxX5sXiMft@vkW-X5J->L^;Dq?OllW&`?%3QTax)8y z@((WTuIKY2QxIb!BK{aC}Eox((XK0;RWi14R?&p~ z%)*KJxdV6Y(thgPxHCd=lO{||jhm15Nj*_v5o%N&E7~^+;RCp zdNN?&;wgo*bzC#)z@og#jPKSx?{QZf--1=!^N%zzV#etO#RcQ1<+J>HzG7P59HvmV z-xb`mZLh7Q&tk3>_4?-taF|m#ZDPTU$-OZ+yC`qw;RQ4Di#xB-hjfLi*n3#4t?i1= ze|k*+bZ1OV?3x}ObGm-oN83lsmQV9h(S4AfrI{D#Rd@D2$HntvZ7bGxItyNeUJ`42 zu?A}wZ=IDttt8Lu-NUdTmA}Rt;1O)rqyE zSUZWev;MXLqL0=XBGxWq?JBW{>$lmh$4JfW_6^3OgqSr$|K`SVg>$kBiuJ+F!Wkt+ zNLH1=+xK{)xL{)b_`IThXBSK?nbHV9ufeja!`I;}>BLcE_f^mI_&Fu{#iIuf%)R!e z`9GhOy_NI!_16q~;*M`5_E3H1E%VIVy*;zbrt;n`Lq_d?=QTr$e$Kk!0iNmJRqxTp zho;BZIGBqMBzBZoyGQBq+<_yG)mgglh^*|x3QG3%CP0=Mm3@!MpPW}bt9Vr5jGTgL z`JU8Y{{4p-Jr+Tke*qU?do0B+`I3vT#M(=&y><3|1AQyjK4N9{T?YL`BY)}(R0jPF z{Q~_8ErouAeuw@Li@C9{SVP5%6DuTEyjTgo3|hwH$fB}X^Vy$IR|X}j_(|3u8LOQP zDg!OJGN=rdk<>*7m2KQj26?hbWsv)ScM(*!6`i}SjuE3?wl%bkSSezq>g9G2@+VEK z{a3mOD%+XHck^GoOAKO2tYJtYeev!phQ!*>F7F|N1`Rr(+tMlR6e=4A%SfTJ{d$uqYveZF@mb@c_g=R4Vdd@L99H2; zp|S(bGY9qdOz6y{H`?#Xe&zgS!;f8h{DH{Y?oy~MgZE{7ogSl7s4UBsLYbZvqT`YK zbbEKXpF42>6_7#^1y3g(S$4QTbw`SoqmcGL0?RtT@ko6m*k!F__`YMIanf%su?`Vy zgk7=o!AuMNZ|8%Lc*Xrk=SPn-%q|IoDtoB!vXf{mmxpvaRd%vihwJAlVvStE?Nk}t zpEA^~*Fe5lqqKp^VvSy*?Nk|CqOu}=oIO(6G-x`+-l(h)nhBjI))8VIDb^UV#)>sg ztfTbSVyHxyn75rOo2~yA>u9l#W&CwFHH($^U%#0u6El2e4Bs(2*ShX8;&hJ@il3O0 zl$SRl@*bn?Ji6-wx_NUQ9c@ZK=ZSTkozYzsf#l0B(_2-FT>@Py*70JUpqH0J^Tj$* ztdc&f)H0BK*)944RB9QJz6?lT2Ba?o(w710%Wi^h7V9Ljn2@<*F&*>78ZXuaqf*Om z<8f7~ta5rn-Po+NW&y`2S%I~UDAJ;#1g7wi`2DOEQdi|{hRX-&;f50P2FiI;?tsV@g~Rqgc0zSB|zR2hw}|?8?P%Vx2G6 z1pyeyNXvOlwf@#I_F?8xtIz~F` z!0>X==v87}t(Qkb$B1=}Sl6v|tyqr3pj=V93TU-;m7nZt#cMqQ9n;mx=@W+J_(u(O%dyQv2GCSM*S^bit?$RM!ZR^n^y&mSgzXxG-7#iZ`$p(W7m1= z(kIfb3x1n7@t3du$n`X0IaW*e8MXyI&13iH-M7vDldhJ^F5AY%g^Nk@%JyW?$Eh+0fh9qQ>^FvE`Tnjk!$n? zDu6D70Q=?hp(~&(p{t;)#kxzZyT!Uktb4_}PptdJdcYSz*YUUto*T^PO?#b-bclHeB}$E z7ij!t|HW(!)YA1>bW2xv3AC7IDzq7uHA|o}s9Y?*#*<<_rN6C&syqqAw|QojkU+YP zPzl7>=_yUxUOngJQ@_Z0=*E9%eb+BJ^#~(@TFo1kJf`s5*RJu!ON{Ts#4 zTh@yNdY$*Z<@LCW$;;n#CD3y|CjXC{xymv1d-HZ%pjX#<`>Fq@&%}C3;rh&XVKpX3 zI|{?D+gU!OFZUkrJ{7*>`~ASJisZ|`7wc91{86k0D~ROFF~XPs<~OiZtcBXZ?_w=l zF(kh%CbnWNeH?hsl#Hza%~$k;`a^3#IPMpVwM48kv6!M2VpZy`10c|R#X266uULDucLv`h zW|ZU?&B&XUJ2Jl{Z(?3aUhb&8l7iE5S{6;uE9v;H@3bGDUouLg0%qn-$j{23R4}7J zea3@*XML|NA6_{7@ch&Br{U;4E!V%uo`Kh|C=b_bZtl3k^rE7?Is2QKg52E9ycvZv z4$K{Bb#|zyM)s$V$)BWQ73%06GmF@a>G`?oUK~IHo?Y`R^P4#%W=tx~&E<=Xn=>=N zIEwFmm(Codc)O$2Q2vCJzcJ@kY|m)y$mCT$P{DRcho+u!(aW8noyEe^@ulj4S)JRD z5B2gDqYco+i~{x9`vat(xtweJx8JMVYOmNGruOm~X1`Rir&x_*H7Ub;LpbT0#rmSp z=%s?4Qbn4+0Q6G9mZ^d*Qw3Y5iXZsh z4lthw@#&(MHx;>ODE(6>qvD3xtW2!H8o9m13RE0L z?;fjzq{GgJsp1&1-Vy6vy*v)W%>15MAFOovQjtsJH``80o2UIS}>kA)g)g5+>GA*I4yxjOxVX?`DYk+wQ^h>7z7p$eoqZQU*i^m|dqCf1 z5Syin>-7aHgV;4yuxqMd*Hl3uQ^hq9&W?)f#QIjO@5BQ0V88_N{3O=Tz6`pN$5jU1 zY(8)0)0IKLsQ6jR4|~nkPX^uZ%b*9u`n9VJdZ?QWisIO)c#_V2M#o4;{V9k|24>*j z_3~NhIkEl_YuU;dK`+zz0`JA12zu2OL4SG+BDP|YIyV05A%X_&QqWzOR?t$7wxsfg z?NUV*R4v5h+OcBy)8FFzsHk(LklkPGHC72JWHv+5thd+)VVUMb5Qefc>b+F>4CeLnomm;9A4sXM8PU&LNtKbMNV z!3yrAD*ojDWqt#HiM=5WR5F`3TA`g(C7Y$n_4IMJN0n#ZJu24~d!X2Z z#NJr!O~l?*?9KF6d?1w@@YN=HJE_Wn`fsr}7kf+3g>NVQFSzh4w>HC9xsBLc=+3Dp z!-HSBD}UL;oAt4kyK%9**jtOe4Kl8B zPiQZ(w-r0F&x)>cD2=4(3s7{G_$ewu-<5#wN{Ej0^3m(UFBFh`e+>^9rbb0QDQR>_Rz~?pku|}Q|x_Kx}vKjqNwr|@5Qd7 ztHdV%w%B_anOixY#cl81Q_&4Lr<-7_oJ>nNBV0vS3HGi8a#x-z_7Ji66?-U(u9AqM z%ITh>ixWGvDk!>2!je>JRRX(vDy@U}JHEc^(&0Zn_E7r!1=)Z7<|(?$Gt4uGYMS=qk_ir|$V;C%Y!W z%i*Vo2fq@eU3m$=S8Y{!vDm5ld8ycGE2yn10oIjQ`3+nt_AqVWYO(iQF>Q4{ci*Ou zs|vaSBI2m>Cg^797U)*7_ZRyBu@4mcAh8b?J6&(px9HkIVQceJdL}*3q}XBm8(E0iu&^k19EQ4y z$0%3DkHju!g}v5z!6$Vvr{ z>>w+NYjQsocDw3yjOx^J`XhI>+d)>c32=QGmG6r^wyR?ONdFW-v3^PCe&bJquekVH zY;^0NceQ@@%t`9C|t4zMcBpGmGFVW`Rwd%5% z*sA{83`-nGTWnP<)KBc=#Xdpo6ZN+s`YQ5&NO-YN5}R0q|NDfOs`X(Rty;y7p{IuY zZuk#JE&VF{t@*E1hc~_@{S8m6RHRqffev2L@ZY6xu%^i36en%L9D<~tSY ztr^T+-5HzhV^xm+TkM(koo4q~{J*e!tU5x+3E5J0Bs50s)5I=PH9VxV9*j?(J3KS{ zbdubL4bxQDVZ*v9z1)E#yWF2Nci6BoQ)cR2_~C|U#_w?inTmx|^T!qCk(H^AE;mhf z@LqckKA~X7G%^S$p43T+cAl2U_#7S!hsTLsBK9l=fTzVVs+yH>+F5K%c^2DCqbBaymR>s-AwJKk14g0K`EVdi=88v6SYASaZ>Ek+Y*fLaMrLUR+6+$y1 zI`vGk&k}pC*k_AxCj`|4&RZ(IM164GUk6+0`Y> zAe7`~8RVx<96$bVf;OwpqlL@q=gsfqA1Z~gvRBQ6E`$L7RTo2Hh*+bl)5UhgE*1M+ zvCk8mZNmk;Tf_CjfXd&!CU zox84kdv3CLC_X=pv#z?{*9C9Krv${?U3wwp`ImW1Qd+lfw|{5x5K5doVOnAFtfKtE zJBJ1r%osdo&a6`lW}LBaaY^)Fr_SlVvhQSg6pt!Su41E9#YTy(-X(f@ zFLa;Smx_H)pK)^4Lp1V~z5twD^)SR%rHZXe)nm}(&=b&;VqYfq*nKWEai{J<+_})qMT^)sh<&5Zg*K>N?3={Cb*01Qs<&wTUH`>z zdvKY6R!z>V((M3P;g(+D@}QBob^i*V@WdC|l49deq0gYt#lB7K+r|Eu{+3Na)mI*3 zzC-LgR|&+dc@m14f9ehW9y#@@8F^b}XTPvuvyHbZSp2;~%<4zbXV_=-MA@(Je#$3l zduJ}baQ7RhZI#-X(+gt$gJ;#1z-W7j`7akS-|Zo0I$n)`xAcOT|50*gw*jkOD<-y@ z_$+tMRS)1|ZLyI#_cQd>>%t-be&C zpx6(I{jk`8_D98j%*dZ=yaFnBs<$8Rt7sAfy@l-N(}Wh#^=_A_F;0n;nBFhw={mTKM5xGz4) z6Fkp)f~T5Iiwd6SdJ{aOCU>95htLvse^>BSkKp1^2;0vKV!tT%O9-Cokq~h>x>bK! z>{nI=!Bc${EF(m!aX<7FA~#M>xVikv^o$p$PuX_UvT3QF;Hf^&Jac?+&;0RZ(g#-! z9(D7zmyFpv_1cSO_7ptTcpa)w(XKLrry8%rD6tn9!Bd@~g6Fv&f~R|rPokLuubJ5D z$y`hkdy&|Sb<&*bNscA|NOG{-s8(aYD>+W%q6jL6N+9+b)$B8>XNz4X%5a6)m10+k zT`hKvFFDTSag`i%&F49Mx{{+-g+{&pcyslW9P?B>u!X6J9JL8^q9nh ze%-G7JO*V~|65y98NqI<`hEzV*CsZA>oxuDgAma(Dmh*k8Y;_qI4AnbgYiwh6r6)Pw`$v+ao`%}>1&TQu zphgIEUEK_|K&=qti-r3Gu|E|1Be6dg`xCK0)hAx#QR8&4CQj3pAfV!y-NgRPbGm<_ zlH+Gja;!#9_v+7l$pNJQysP8@(g%_pKhn{^=osm!{{;Ok_LpLRrI)`#OU3?L>>pKf zM6GxAx9)@Pv+u8%*qVO&VqMu-_-inZ*2Ieajo9Cc{T;up=?|^pt@rQ6{$W*E?=|be zGV8r&{odB@&CVW4m;X3?>D|xnefY@A7&7p*idD@<=9z)LJ=0h{X#S$xvmU*5?dqkI zzrJDHo=Bkvm|nBF8Kas_J$Uw$foE9I6`r;90?)ejc+IvnvxC=+yVI%J-W40a1QQ!I z#Ol=eu{t%oak0DD%#z=jF*SR7V&nIJA~tG<(vS;-5dt-FPzZ{L5}-sV2?84bA@-kQ z|0VV^kr0UR|ZR;R{|)j?QDfBmth{usF00gf6!R;Ol!$QoV5Mh%!f zh}ftZOXmWXU9nL!j*Fv2))E<@lYm&Anqx)Q7TIv6i;Wskb4{MUSOo<3_?lek6p?jA z))iS#e>)zU;ED}dUu1(-LTsE0%PKae_9g-jIP#{ShwOaFD_7n!ewq zcb_Tj?U~}_iE~E1dsy5fi|-t`##^`j*^AgH;(fEcF>7w6&p90&ztzveTrUijozDQD;Hd~h$) zhiu@Qw@i<(L4040n++_~xdgDptZ^<)&BWGx$i+t@Lqzt~8S{yYHe~2OLK|Pv z&`eHj;;BfPo_hP zyGfBW6&qQr-6o}WEh9E+2Z*G05gWDZ1``{#gJNQ9!M(27sNI+g6vr@;{g?!`n?Z>5 z{Y5fXI@+kErcbR4nOWJj;OE-ypzTEt5IImpi(J+YhIaJU`@tgVtHOG(Rd~*Nuidk^ zwOcWDqdgyZV07hmuQ#l5{)bna?El(*%rh9Rd&-C#*1z@1v%;gsKXc>*nOBUsv6sY^ zT7Y_OfG_8?k1&nKNoFe2SXdR88nmabCbzMmdJ3C zLv+UEcw%G3KM@g8dM}Q zPUI-PEP-Z;94$gL+)B1>)SgM>E@V~#0e-HX3!N=;j0hW}BQskuA0L^soNTl^hLRG>R08%+z_%47G@yCNg{FOAb(Tt=hQNyixlG^d|I{ z2$HK z&wSb2GcR0t#wDX3%+7t}<$2dEdvDs+y-1F4c;ENhRjhHXFjxDXD>=?EOTP9;Tu(Bm zr|T)_weF+6l!yN?ExE$ucUO3v6{RKJRc+{fiMoDf`e}^dg{z$gR3fMZzl-zg)K^cPpyZ z;L^ISpsgXGZXF1>4uo3=!gWMSMa~sDPvm@&3-nf?ZXHn9k6*3>z+iipc_J6l*VGY` zd;b?=OY8PEgIPCJgu%=mcvI(4LyrFG8fw^a6|aGZ9anA`VqdTHYz<!xtmRQgrbU0nfms>qEZH|gaxXu8PFB5tYJl^S?dS488pycfGN zyv{RG-(nLcNoZBlW-lg_F zo;vMTTECs&t4^!CP2>UnWIX<@ifRRpzN=HUbFbgPJt7Zk1NVtMv|^eLbY1s^KCbNm zv+ID_b-?U8V0PVO(BmQxi##IosK{d?Tt1<TKP!&~qYBiaaaQ;;On< zk=K-o|L)Y;x`jHDx;hp?n78Yeh&&~NE`LTf-|)_wk6`@5@uyD6Eu2}B%W-&m`d;z4 z!m;jwVueLf(r62M7T+T!VdT+=9YIs5IxTxQc6Q#(2~+Y4W{jB5>1D%)IyQ?O2i(7f)qHu9Giy;TKg6Vxp7yvPfBNvum;~#S)EB6Bd<%LTVna~(F7zJsKJ9YXZu(ORChl= z=hNLjE>=}qrau~2yX|A$Prg9=S!799eTr4Tvp$VkYjKA@?Kh~GnsN2~xxT*+62o2} z3-uF0jaBI78qk^|l_K>kee+nqE{$)fFJ?X0vz@44A7VVKM5;w<^tb4mdJRJvB2p_- zw<_qs`Ym8t`P#BKeRld?*WY{iF^4Ta|M=_Pp1R%ks4Df1*KcE<*|xW5MsD}~rT4y) zp7rE04O{GV-KNDobzuDtw6T*vMuR5HR)bBwvdwb2es9&GIYS(nz zL-`W?xAVcHZTBCYTRpIAtKEcNeFlwX@sR5H`b?2G^fO!J%@x$~_3Q!a5Az#fGw_x+ zfW`dn71HtbM{xHs`Z$Wa{zzyHG!`N(rT!@BXpwhB-W7RInP+@3S7P$EIHI=nK$; z^+5l65Pv<0zutmuNT9IDmm*(@d@b^g$hRWjiF|MLVEwr~jvlN(-+U?(clF>8ssexF zM>ux1(}VR_`E!LW_>WyB2*EL3^k9^1mU^&%J#x^S1h;X)Rt)V*xM6I)sv`DaWWZ8C za3yhGiR2ld7J7NW@OF}m0PTV$!oZz8|zZ`lgeKkTW&KST(g`oE7PuYU@bRSmM| z=;?snY4dN-eDS*BLvI~3?$d#D=Q&0VK4+eJzPD#Wo9AAi|3T)j^FtdCxM`D*ukA$* zzQp@p^~Z?#7Y=W(STf%GiFu~Tp z$E_cjTkGGK@H#3DKa{XrMm=hNfBmQ2{f$1Zn&>m=bLb1`ONfw^`mZIto`lzzFmh-^ z32!9ffqLt=(04j8Mrr-%4bmV9Z{nF?!z2DDbk<+~h%J-w#yxaayr;AB$?Z=J{Y};J zhW;_J4QtWOt|D5-#hNrHVGTNL7yzv;;mssGRAo??v~#MCt5Vb#+ORndZLcpt(>37bXux>ifX%)En|%W|`-W|y z?IgUFgtwOPHWJ=e!dz}I;T`k|HS=SpS54Qjllj!^-6TBNwV;M~QcX8xwX>i$3^g;X zAx^?OcF}YV3Hqlyb(hzf*y{Cunr{P^^9GGD*ICxEAGE)Ocb4!jdU+spkc4-Y@a{Ux zR;u~5A&bU`doOm)rwt@HBd&HcLboi!(SzM5@kp9cv$`tG2I5#6MngwPcn=BhDdD~J zw_xgqv97`l?=4}R|Nr+2vq9r!P?!xT^rrkqE!}ug_=Qn(UU=oS{hAwIyxUWl4JVst za(jE`%-g^Gb>ObUGoJeG&yl-bGV<}B3bSE6?;}D*huT$h4diE`<_JernH;;KJr0&` znBg@O+c1rb=@MohhIGahdSWB~ABhc6cEj2F0u=(ML$jeXpgGW)5D2{RZep2_GQg1NHJ|=oSehInr0Y*w6)ixA$UCY~Tw)Y#bbL691cK9?@pB zJuK}Fpz4N)C7dDQObKV{Z!xnsJm!gwYzZTsRspf0@iHnlz|K8!_Ai6)-2H^Bb3T7& zQQ7lvZFj%APa3)RMf1!{y*(59;|mT4Ik>`z|{uK(+%%H??UfE??WF*7~OKDgvUsDtc1r&SdYhU z_z3zK`ou%F4WDV(Ncd<8A1h&k!Z62N@xK6V8-DNy@<$2xJRdvcmVJuLPfZM^bt%8p zU1|SHU;R!$yV7GR7c_SqEvoeR1Nu|K$4mHhl^$KHce~}CwEe{RNq+;K8)IW)8`m)H zH}>PAzl2Ya@QJkFxF)oggin(2EN#C}zKq88Xk-(80Sc!P9Nh?fZrl)JaW;aT8wWvv z^^+x>E8$ZloG0P&5}qL8iN=Q0xEYUwY#Y^rte;!)sWzN&zW$i3KZ;j78%`sN+f`AG zfX+!>R8-?0`lmZPqgwrUL}c4IlunJ;G15_wgF+IXBH;qPB+jG}>~N}tr>}Gs)tE-( z`+F~TRa7Hk;HapnMqoA`sOE%eJF0l(`+Zr)(D@IxB+WjuXn?1s8poMuj_U21 z^n16t{+inl?te$jvM+~UJ#b`CaNCGQyb& zayt4-I@J|C^SQV}!le>ES0@2^oQ+pYn3v33`GN-=-gvYB;u~FyX!v~3BHDNhUt*Gk zFX+u8y30r1=kcAiq@gPcj~nlTKsk-~NcchtUnJp+^|x568}Ii7&m|JRbd?Z1kHWGF z9);~mCypAs@2pt`6UWaf$uAx~aNt_U$NltE!ia{aKUt77b>6ct8o~3Vc?J`9&u8Xm z-FtE4;6v8A`N;Px`pq9mz;gG9q{e4?-wR%+ySwVf=Uu^bxi5IAdZ*pq-FVyy9ycy9 zb5CIqsH*dymiW`MOu||6^*VpK0vxKi*A(v%iJ9odMkL#3p4SF5I_}us=1b}Wt)mm_`HgxM9|B;lL& zR$z4Fd(itHMsEDjn~=9i_%;du=wjrb{ueNEeIwypdzgQ{>aKC)Crr#wi~Bna z`vZOT3;paa!Ed?~w3I5`Il(N*7~rD8V%bj~_oN zHNVU2y5E=R-8W%E!ld}WF&Z~wh;HhqY$45624Qycj;w+=H9mw=Dg~xK11uK zb!cdiz5spIL{vx`-2}vL0%A9@z?%k27-@8`gzuB^{Stma!vB`=gZjkAJZdyt z(`N3!W1AFWqv1FaTb0`*`s0PwPQx|rWaeel&JupOi;Lx#pr%oel&%;Rjvn>?Hx+ccYN zcT--WLZeE5w5@iV@}{saIUEUBc9k6G1(Y0@(7BiUli*S=E|YMzgllvX0F|47%Al5p zl`lE2rSTiQ7kiT9dRKDP`IGo2l^n!1c8}KI{DkiF7`W7Qm$sxbLiyHDR3K2QNy5!~ z1>R|5N~z>%k#OrOAvqp`WtAKc_a+6t9`)HH`>c8B3D2Ck&1Mx3o&A-O9FLi29`Eg$ z3a4=H?qwNAJyP=hB}oUbb5<{s<0;;!ChHE#@r)}u+M{%O_a1+lW)^tO#5TRc#j6s2 zUBYi@=P&dm$D991a#YYzgT6o|M0Fvt78KN&$e+>bz zKaudKdifpny@WrL@HZ+sR%)@oreA2>HCF4&268t6xtoC8pG)`)34f`-#b({~r?=j} zlJM87!g_CBgT7+DH?P^-+P&+~0ka0+|191}mO&b6m|Gq+d?dD|eK0qHwp)`Yi zn^U1QXc$DWMl-=0e@Ga2$zKv)CQghvv3e_k8_fqn2YY+%<_x#*oqpo1Db4}9*LE;M zD-ZwO89>b>S-QvdG>_!ljuNN8I1~rW9T?v^^(U1>JjS1yUsU+FsWaVNP43wpart>E ziTO!?6It9$uy*s&43UbZ=26f{Sb!0|JO(;eoVCQ+sYje~^9lS>BRbp%PvqhxaR!L9 zwmt|{Zazhvb;Q}R&l~CHd>V0Mo>5WFlc34a6bPK$3_NZI9yd=DXI*jD6K8#KHV|h+ zaW)cXpn=29h42R)ZdO#SpT&GC9Ciljk4^N)4yzp;ZYIFQ6)eq`IK=mL7A#@?(~57T zo9EG~R3Gss!G&C0B+jPdY^IX{sN8(1IGc;J?Mhc_%~#U+wfbVzS2ITG=BuG=#Mwfe zEydYNe|sHty{pumt;N}9l~8K8!Llkf@-llGYqvOMvm3@fa`+h+m%Tdq-k&j4yYUar z42Sy+n7!vS2YfSn%h)>(yYia9KKLo|*&%3|?grlGdwJgj+EwTtt<}(czwR8I?R-`A zAgajOzK1FrwAZxm>f|vVe$uq08|mgJRH-?GqqMYgeN@da@Zy&}E@GQst>L3bB#E=iL<*ndx*2AID3h+ zw>bOg6Lmal&~&q|EfqY?d~*8`7fm}uRqza3?a*{HW_M5UyerPWT?G%}++76EI)B9Y ziSzx}?j_N$`Ez>pD;*>q_Aj6>#fcL~qxhOZ*UjIE6E9Bc%9lJp()h3XVwEx2w3~m1 zei0`@oJ4Vw^tS-)=HEQYlPpfksvvn66VE}}wQc7jSqB5hyBtVp|S{4ucMd7~jLhIb0n6F-lSS zu+FGFiQM*%aD5i71V*6+#J>-?u2?ozZdIOovIVW8QXJKPvS3A%&jex#Tlo!7Kn4yip}cj+^xYR?yR1{MIl5WNy}+a z5mYSB(c&B<4!fA+#5rD^6LeP3f=-9nHM_HV4*xz=oD;=4S)8lfX??Xgu0Q#|dwuJGc-m<`-1g~%bs-GcFp-zH@&?0eWic_SMV5O$@ zw1D$ls{I!e_f1x&bDA*$KFF6~I&8lJn5B_sTD2MQU`rF!47G@ZL@E(ymj1R4YWGm$ z>Eg^@B~T&=-9>!w_J;VDj2QRP;>1xKT>AVk@2vOwE%gQ^0^QwbKJ4w8r?*Hu@$AhG zyW{eq*N>^)co}gr-S?+0pU@AVYgYlBbXVE(nG5gcaH&4=<_P=K?qcIxp8UaUCbk8G zddv6XoF&d&oiSkcihaa6TdXhoE;fFPiEZttFHj-yJM;(iC-fJzj6cRevErN~4u%z5 ztN1x#aU5|9Kl7Pf9rukNUW#IU#S01X!B0&(W)%+hY%6WR;H zB!EE-g>{Mkb_fK9$E)gK7rSg#Sn#b$u*|lwHMzIN+wl0(iML!edg4ouy?X9X_r>h& zE%??n^9&n`o(8EY`|aGasPwR^yAC?z&+A5Cvw6=2-+BP=J6O9)2jxId#FAtZa9h}# z!_(mQ4!O~Kh$}a)^yEgwZDA*z+dA6JJOwnlU1#1{e^QPU=Nd)3I=KAT`EeH}D_HOz z?of?=+zM1~1uD0qL2nl47IAJB=QeR}7w2DkE6BOE7y?==JZ=Rlx6T&l4sq@g zhvccJ#XBr^f{(mp9);ft+1q3Z|30Y>5$XoiEOP;^;BStye-t)6`#8f zA3Y}7(PNUGS5`ZRPwQj8EPGs>uE!*|KBa$RN3(*sy!Ayo_Z2$Todhp&@v=BiiSx8h zf>)sh;yfeHODkW$meF{XzF3zl2KiQidTXUPnAn~Z=Xw2YHB{s2*B8VgKK}nc-m$eA zmQ}yD^rkD9j$iZr%g;LG;TunX=Cw0+pRvH`S2hLiGq3gb%tu!}GI+q^;WDOLU2??q^m{cH3cOzTIq@~PK~3(H%v@Z#)w)u`8g zFVe=Z|G$i`t>5@lSY=dKP5p!ZiG|;5b+yjwdTG}-x_28;zI7R2xU=1=Ek>NO9(Jp? z{xPv_Y8=;F+tv`LTtC+mr(%T^bKAPyJxCu%+qSI-tq*MgZ3r=2+6Icl)UFbzTAUhj zYQ@oFtZf@Zn?Rd-in(ob{>}EZUYtfLU0W4%={i!n-haPhZX0Zds%=Mc8hW=|#pNeV zOiY>hH?a+EyV5^uU)P1uwj;DVt%=j5mq7Hky~Jr2=W7*K|J-iXwl6Jetc?4%pkHUUwh=|sMifoke$f69pt|iq=pb?0#d%Gf*Ts25 zoHxaJOPsfjovJN^$I*{%S>`i`Pgg&_qpI;e{qf~$rytvn^k>@`ao+7BT-uJ(Kdrca zYy&U1X5A^aBC{LUZ#rasL+)A}uwN0Y&0`JAHm%nWa5?`E;JaN6E zR+P3vnkm+1P^fK~(%Uelw-t%=i8!B%^O^p(1e)ck+0VuKVpUMHZF6B+1?SnlsmveN zzx`j~vxdJrul4z}?tQ%dS5M8h+2$GP?U|?d%`852%i;Nt+%hxtXTv3BJ=JVmDepU9 zyNWJWyH(qHu7c$BW>oA7+pXFz;mOOrW@6he<>E4Na9)3_GX_(*+O59(Cw8m0Yia0K zeSwM%f@0dh*=@k=vlJ*|k zh7G(8FpTl5bPXw8bCr-9Z@{ujjW>If0DqnS&SkHyH!^h7t@kWz-)NjB7GczHQ(&#n zyxZF|XYW>U{(3ow-aP*#=k1%;I!9AO84V;nUrp>w=yQ}10is=8m-zl;cHHk(k-NPD=8i0V&iel<^Ot{Rr_{k{Mxsd z(k&GlAKTeVm5?}hQc>RYxZJV1N91M}7UdsaFg|zeoZ^!F>AB0PkefTM z@TihWq2#}{Vs)Du?K{z}yD~J2ZQ6H+c9GJprF0v;+zr}YO1G8L6ctika(LrYy@HMj z;}b(kol}PYKk~j0{0;Sa#}MDXuas^lrQ0j-aZpG~caYL#<-Jc8b=nE0X~&lBYT0(8 zYT7~T?SS-lKzchMy?uY^04W_Tr8`RLPExwFl+u5@O6hLs<@SSk)Od&5Gu(g2wkt^A zO-grny+fsYs+LV$?Yu+nzKy>92r1p8i@0kat4m?U!Fl`fbo5C&Mmp*zKqpG+UQ)`j z$g%AwL%CAAkCeviBv`4=q4tS1K1E-QCT!1#z=!RVr4(hzJRJJ}$h!{sD2nf&Lj(j1 zRmBP-O=<$6gY@166lsQ#91sWzq)-%v2eflNBB+2A1qB2wXfD0?atSJ3 z|KGQ}r?~Jw9%YbrelpYPG8WuWbakfB4i`z*=XWC%A%QBU){_iE5r;UBlnoW zn_3dtl`&t&RV;D*7zq8SSIN?WEFHPSEd`d5r4w16`sb{(3Yo0q0+>S}^rN8fqgDgZ z_fgRIQEP#>$kLfCUC09Z=|+|($D+3y_t1}l|R<` z*kNV2lckq4>+Eu2ojaYvMlYD2scGvGSppx(qi#ql<1gfom`R4%vLq*)UH*>PMXh z&X8pwSq711Fdv07jzTh4_e01s^p;?+Xk0S07gWCcG-9HtcmH_%C0?GuwW^YlN19RN>=TGe)o5q9PCM7E z@&Bh#r%U>gNKE^H9UF=1VMC*eU|I1C;=bHf$JV*x)uF zOO|nDfg+edmgmUg$ERYAj?FuOd`um+Mr^=|H7ccR@Z1U8}z)t zo4;LOTPL7h2cH1n>#VI~djwTg57o?XDbaG`E!1v++hnp0mc|Biu5qHRA$DML0?A?q zC)yB7gJpOulW*pccpJR&HUzb3meJMp1J{O#LdEJo9uYA6v!Yii{f~Z+E+YBR3 zh^I849$Zl|yH1Zs_s#q9RMe?y(8#V9%?AI!ErP3x8wCRa#KT&i*Y&s!TAzI^FL==7 zH6HeLv5mGDkikoOPMRdQy{Os77Y#{ni-a0MUape7m}Rk99DPrxsp4PBj;|E5EM%i& z;Q^PM(Xl~=+gOqppXIeJB@15P?0Uf~aO!KuskW75S4bKzCtvsJ1lw-Z&tBBC)sBx)rv+$^H8#EF|1Z8pH7H=7}?ZwTn%(`^rK|?fGk`2;_7R&yq0Y@Gs_#@ z7#X$V0zd-MP|(o`aEX2bXa+O~S^#i1en^&&$nr5+wvz?4yOS)tI7MqDHE1KcjrO-G z+80~U#wR*$e9E+OsNB&;ba#U`qI-~Kw-aqd_jaL;lAcb89)y}6idxnBKOGJKbTq_q^qXWkPL>m7IZ2l9$a0D-9OW1d zi5v}|HqVB${*8u)=26BOvf!=2n$IQgf5GPxz13)_=xt=tVjR~xP2~E_4+stoj|?-{ zYv5fkD5TzBdp=Hk&fneOUa!!Q2)zFNnIQ9=mgX6e!Tu3Jp&{Dd6mvv`Ijr8_Pma6x zqwQ#!ooHS5^=Q9LSmUrPB{{{n}pKs=cThRxR z(KlQGTe3sIVc-Y=2YB??z)|2BS$-i)6j^L!i6%=7Sz^f&$0@!=Qitt3sr_w=K7}o8 zU%YPn6500Ult0^Nb97NuSb{SH#qn1gc;-Wc=`=Xnm<6HL9%ezJQ&H0y+(_K)X+Szz zlE{+GyO}^1SyIT7#RxqJ46>-Us-Z5w#I=8O7X*^581}%l5_G zt=YcZ5^B7d6^p53^t{t=61~6hTbIU&sf!XGL7?m!Qq zCs}aMTqesEvS1$P5BB;vEvwST=cbocY2$spWmVd=zVT&Md^%o#SrxzPQ;XYf1Uy|c z2x~-SNJP*KbDy~Z=9z45``UMj1x|XZd-}m~i(wGIPpGBx= zw!twA0pxZMGUVOGfQ5wWBs@_zuF@C`HDaue(iH5dB-9|GCYScI=JOD0-Hgv8W;rri z!v#Ra#lTx1vl76tBL<_5nAZV}HeyzjP@9B0B-~5FeI(pZLR}Ib;1q8nsiFH~FyLTU zY0P?T8b5d-xf<52%Gd$6;Y zghxntlzRcxf6Nyo)FYu$nfp9q4kGif(3~vTVh#a^fg>c;C*d&?8t~DtfuovW6CNi4 zFAx3qgYII!!zHs|!wAG(u*D3yoV{^ZpHIHn)A`;$!O=Yp!NyL1P6OlMo+fqJnvY|a z42WEE;^>r9KR*HW>pIC7a~5f%xT>JgSR%*#!V+0%tP8elIxAdNSv*q0%l^0SOJvexS1)Im_lT9kqclJU^#XU_!amK_#HS8 zTp*z(39U$IO@cQGJ|wguq3vcQW1irV0B<4pwe6qS@)I$FFMqV>kDfYj)E^ld85Usf z6&h&n6BrZ`8rCv=YUmu^?G-xP9Ogg8i~*1PIap;Nfb{{^SaAOm84L)S9TXlkDcBtD zSKYmcVE=ickr937VssylOmNOa9&_mt88I~!>chj=0l31xp}~PcAyYhE;G8i3nS+Bu z%;CiZNo-ZaO2t+qp`8Ob}Y5;~F4z07GN_EBWsfC~me#MT4q10amfBy=I6D<4I}$2QbyqZk+ z3W#mti2^>D*mce7Sp)j7to2O8ol~z2)@dV_o&KB#qY-!7xNPaWCnvdoi}xSzdiufl z=DzDr8?gwXiRC~Ut&K2SfY<<`#|=-h#CAnC-Sup=DVA8&C}^XXP8-*Jbg_8H>+6t5 z3n6HnJDx)%ySqwbHId9pRZrzYXR#x2U88Va#r1FO(ygk7bv z(}7?To+4o+33$N)#*@%o*8jf#jg53L%WM)xTtol1?ikqqx}gHG&!c``)O(sKb~bkA zBR3L8F{!)+EFb~x8(KE{H+C^{6dk2mup^N03<;yTG)cE(&)$q3i+u$dy~YK=j>W=T zAG-ut3M>O4j$@&TV^@-Z4vAqKy5o2fCXj&fnIETEg`|f5ja{w%ZHi@04E;M%*T0k4 zj?E}{`Zsoyqql7)0pXCvndXBVv||WJiT#Azh+BOpu#1EM5(0U5H}EM5xVfj7y&XfK zdF+>5Fk7sBz<%HW36n{fLc&x&3WXedNVj7_B;X0he_#H_vLByq5}fkxHmOC%mZras z@BPvCrCYoIvA>$XVaM2M&uJi?-P4#(zjUc%P~WdDlOFh`-8)D9JlL@_NXz8!kiW4% zX!19>1Ow!1FKoyr*2tz}ckIMyb}Zxuvq?tEG(8(rYzlT#Ntj8(EbcMs`mj0dW`@nN zxya~OE`Uh@(JQg=kjEAPb^zKq7Lqvj90}nhM34|k0yuXL33Ex9XUN~!-;tbE&;?_A z30qD6KF^FXpFgB>Cx7GMW7j5ZACZX`5&Tn(Tm2``fH z67M1=B@PY^SSz8-c_Z!tWc~;j42Fn%5O@f9m;`7fB4H69g+z|4r}M^Q5)d`|@AF1n zV_Y&gAg+lg4yfXF$x^jZfB#M4(;AyQKJc>68*$ByG|+&0avJ?dEegW?kF z52)eJ8*!~ro)1?Q?r44Xy$hA-`~Ij#dzb~dtM-iYg@@rGPNHpQ$`Tn~rA zf}k1Y-1GVvU%BhwxBAZQM8jVm1yw<+$enh~v14BrGLi841ftSV00b&1-z>Bp?8QM2>^o zIBqh25bWD365b#YV&`=dC;TtWr^L-PS}G1&;dPe3&JS2?4`_J%v~BG(+35jm*A|UL z9clU(%pV8+8#f1-3(Nz!0$%{oh2S$?L&BRRtmQfs-XdWgr+`F`TL3Hs2v`Ix2H-Y+ zn}p9vI7>nyiFcCNgv6dqP0p9;&Ch}JWtz=S?`U?NKJmTw^vS5HVP=2LCo$STD5AfA zNMNwp&u?VVlo0>m9wC8z@Ve6{u9u{}UYakd&E$5@kET0ay0`WSJD)eXL+cL3!XjK& zRM#8A+uX5zJEym9xfbi=sENs~eT!%3+F(%laU6o9Spg{gxFsa4C*d8o0ucFF3tf2k zW`+=PuOp+kxd3ioxXa^K18aacfwjO}z&aA%BVhvx8%fwi0z~l^65i(&>ygwLLd3nN z{cVcdh;1VhKG25{+gJjkPC*t59kJI969QI9H97fo#8zxiSaYRlCJKQ2CYI>Pu za_z~dkryA+WCa9w-1oo_Bw#r72?@JdR{R8<)nx@nMSE@uS;2aqWksAPiO{D-Zq4d7 zy5G0LFX`T_RgDS_S&?X@fh*iyR`_Nwp0eP0@7e1f*u4Dsgzc|;kQJ#Y&xn-K{9$qF znjZM9glc!KaVYyZJJ&e(6G;5H0usI;VIS{81a}l@% zTn4THSAjoBz@YO>63|Nzk#Lv9*j3eSrNRDwt{B6b-3R)jWe9g3Rj6Z%XcjJio z>IQej*C64j6L-YdcHxdHzFv;7s|t%egk8lyh}zZUJeocJAplYyckQ>l3mqR{kA&kS zd{^e=5#JD*LyT+PFTRoP96q5thvS>#S3swo^z`6ZjkjGoay(>qd>hUQBoW^l@CJNH zI7Px~63*~Zc%tJ`6L|hy_?`p|-~as)NqiSvGN>cIt0x+$ZM*nuj|Y1#TjO>UXjg0)b0EmeAXMr&Q zMgj5TfbjstfBbVK*hq*bA%=ul65>dRCn14TOhi&ccEls@P@@ntwvZhN)nwL4;g5oH zCp+S2I;dk72}#b>5n)ir+jlZ$pcdzNdCj|*ntz3bD}-cv?1_cnR-ftG6XxT*1*lmz zBJnQ*FOdL$6qc1V#V-Wl5=bW@x6IuT@gg!;xnRD%B>>SR@d^nUBxI7n3sJ^fftU50 zKAVJFVj;@-6}V)+=~sHXfo)>HZoRJd=q~k7$WMrDw!*mSUpLac;VI34HRtoEcJ6y% zZ^P3+x33oWiiey2O_aCJ(MD@^rp+^$7TTVfHs2G|R)4~^wKpQCEqYEmeQeg~18Y$t z7ku|N(+AeeeJ(IGAaVvG#|N83rbJA2&E_MVy2EinA7f`b2}LBF<4yw?IFDL>y(#+G zi;NC(0Zay;0iOe30Q-RbzySc7<2Mq1C*eE^n9RRO!X*+eJCw&^BxmKp5hA=jimm3s zyu!@!2R_8A0(>)>Bu~r3ucbU01!eFpG9H?5^p21A|FK*Nqnxx9OCUHR=OqR!Z}8toz5CKYj3UMCj*;tKnyz;?Emt;D&dX3t>m2e4h;MF;K~<<@4I?=I1;x z$7SU4hog9MbAlNj)cn09AY&GbNmVB zKwc#LlV$yc-vkfMF$=L%io^m?PnSWK@p}0CObN1s(t%1Req& z1|9((B@yM;Ah9NiwMeW@VjU8-6!nqR5FQDREwn9!hj^bRJj4f>IU1Ea;gNtC5{)?$ zd`QHyl*OFW2@vMY9HxYJUS72k9M9W|=ni%1c91|_GRPa= zJW1k%BtFEuJ%FAhK1^bRGM63+{gC+}E*Mmi&>t883?%Up645j2@zKG+5S>8klla)J zKp+XDaLIhjJne}L7TfzTkMJF`=apm4V&`;zg;%Bpfh0U@q#5HW4Rz{UG-rA5wUTXo z-R@i8@8V7%3FDE6pWa5=3`oLrJOd&=Zrt_>{(Rdvbi3_qj9=~A+K?9sK}JqIa!J7Y zgktw{Cp{9D zI|yV2iEW(;1c53yB0Un`LglVUrE1Kv4m)p?*p9^Z+zBu-mGCZ!9Z2j}_RPV30hK?cy$fe_-pt^xbR3?HwAl-{pZh_MyBl^)}L(15ccTIi56_<65f$ zx!&(zBO8Z{TB8lPs6iV&ZZMlu$OhV1?=h#bbB4rTB=+VW1D<5v(dVXUBMKQMask{$ zY(O*+1H=MxKs=B@VqX&bk=UQa0VKlY3?gwbr$|Clhu%ol{x&6~V+-9eMAsd|m^Q|i zKiyI2pp7CDo!?@e@Y@a2#uZdFRIlC%u43m85{Hxc6goj7TqcPau8bh@*)pe%#7fA# zDi;ibNURK00q!7iB#EO)e439|1K_uTgHwEl#L>3`Z6wyhC4)8+YkQ)AkT*uI-g0X2 z67Mt8-0vyPrk;V{G`rC6%l(ylzj2899lRLTKG9$ zi)=f>fAF8{RkTCF9dMijEF5bwB*IoqbPKRZ?1EFf8K)+8CD9*A5+R5ul`6m@u@}xB z$jLY1kKRBZpfAu5fW%D%-2{*rNTQj<$s|r8aVnoW2pEhXI#~}eP8^1P+!8?~PKUBX ze6hHn#4rE*@x_S{z*=i2jwNv#2Uv_R{y?X1+rJlMXkXIu3nQ^~0v?(O*Va*(6dE|M zWl4)EBtC~~orLDm2*3|J69HUFFo`p8Jxl-rKp=qj2_aD?@m=PjQN^#)r~S3#CVECr zo@@^D^BZEGF$0gC+)#{!zWk?o@?`((Mpq|d<&?x3{41C+rvteBP!ebIZV1+SXiDNN zTCkq4`yZ{bpBRCR=5qlsiHV41Nkj-sB0^Xa=K>JsiO}PTFOV2UVmOHrBu0`ro5VRJ z&NZ}m;!8-*H~&Ioy9irNd(UJ0`2v54jbN@vxda^Bx03EQ{r0SEfQZMaUpktG7VNpk4PjE7m>J_@5JrE4&4-6NEB`fQ*5a5M2~9xhv%k_ zh+5h6u1)>VKX`lB+%bkJ-iM#b<{Opc?mV0}Z0CsM>xX8qZr>n4T(lZ1e!9*zCLToE zBYK5n1ag#FfsZfv}SsA`L{6BytG3Mj98ebCJYVB)-m_;4*N9LQO-`;hbl|aTye7h>6DL(gHh92MV~r$8^`tui^olo0Tub6x zV2vc)X-SCdU;)35#J6t+)<`nMc#=mkKE1;3<*)1+Hbwoc?qee_-Lpz(jid+hGx@hX zr$-Kb0=jFbZ3nu#GE8OX4E*dMpAu^H4xFrD)X8z=5Vd?CP>NQ z+uUQ4ngUOd_#TNHc(=Ju8yjziHj;dhQ70|{w2{;XK!{0_F96Y=)E?*nK&x*eaWjcq zNPM3}czU*yxXqxAq%KGf+DKyE&fD(TYP9hoGsegK@kP0#jU;&1HQGoTOyWmQw2_2h zb0^xUS&uabYYn=6kcZ%=q-Rj8Q0{s!7>%80N!(824(+NCOG)E;!Q9Dz67W z*{9XE{U3(>v}9A12kL-lJ!z3q=^AyAMjZ%f)TrZHm0oOQo+LXuA0);B9+|&878yFd zATLQ1!`y>jh2`-h@gT-wJR+RnG}dy&sN?-={rv;{9Gg)8Kn$~nhKG(om^u%*cstTO zg@YxoJLq!l7b|c9ui?syKYWn{n|RpGH;@FCoy3xxPfdc{KEhkrov%ve8%SD@vzfBk zH;}|h`L}bw+W>3?KyhD_c$CCrB%)h?OX6`p75?oc__vcj(0v0*+qfA>gns*u#4OD@ zkPQj=pI^)>=~G9i!3}xR?b&1f34%6l+IMt*xt(i+eu1ij)YcYEOyZolst=HO%5A~K zq(k`TD?XK5;xKT8#M306;axbq*&F@+&3L1eP9P(`KFzqD#152p5`5rErvU_KCm}dH z=?4<=|Bod8MB-TzeMmrm~ zO#W&E8?@rM=0G~B0F_(BZN#l^2MS4yB{7b7&jG)Z2#b?c_O|UJGQXl1tlPHBnr%yP z(Ci;<+Y;SvTh)0kT|W6XFH>@5&IxRiToJe(s6=8ii76ze@=NAYg5y+1{S`Zdfcb|FEfnQ%9G&(*V5GSlxEM5!^WQP+VhUxrvkTr z)$%2*hUhw&PQD-Iv9v~Od$Daxen7KrnI%+uG251m*c4q@=`>aRtA@r`$&EWFV(9HD~9D(|I8qLHkk~|VXZWvsj=Uu4h z6u$j!eTBY7Nhe9lqYcUE zEO|081(*s10g%$kP|(S6JO4rApCoyaWFn~oNw<+y(J)-ep}0O6uH;$9HXK_vT+;3Q zQJFt#mOI0h48OQW9?1(xs^nz2k{9t;#SB+TE50QwsNI(xy+Fl|m82>p-NC)!72s8p zs*+TldqJ5-ekMaRC%?`Gvt?NcyaucysTxUll5`gzeFIpn*&FF@lJ2=B?9F;yGTWPX zJlT$|TOWS4=_f-6eAdvE+Ohp?e&_>ZsbsW=mIfYg_pwx4b;6Jjd-Ytj>b`gC7rqnN z-h;h?cu&?MRbXKF(e>mH*vLyYbbC|UN7s{gASFkS{AIQf>M@k0S|wytmhU@sWjyHY z)|U?!Vif!~1NNoqt= zW0IQi(F?#uor0Q@^u(<|K`FRmrjrztCp!5iH1ECa^nt%ymh_2?s~m;^ai*Y@ibfiY zXWS`h?354V#|`M8z3SODZ&q8HpWseGDUkjt)wrq*3QDP}Q4p4Sgdf4{n#;bq-0vwh zkPWME2L+|n(kQ593EB8nzo|Dp7gN_M(CxbI90_gZ)NfNBHNJ9Rd?TfSb1K)L)fhhu zk4b7$Jf#UqZK1DIo*>DWrEMuzI8SMb^IJPIXhl*x&H&oDeW?U`3S8YO?7(KPPzrqB zDNyVw5b7xq>M0QFDV<5`KvGANI+29GyO7kCPwfhH(^^nlk}d^89bO@+8%f>uh!JW0 z|AJE}#o@+I8BEfXEYF?Si)hCSJhTq*^=>n1Qt@>qT$_0~s%r%IUTz)Eink+4>fz=U zN`YKYaX7nE;OtI$mZY8}VVOiz3Y^_3<4EdF(zt(Y*it4Ulc{_yFl;IQz$7352n3+K zQ*c+NOd+WcNqtG`M^b;129Pw6q(Pj5qqiT|U`h!#w(Qvk^$pfy6s4hT*v9CF?Yc{z zx-V$zzGmuwXIa#gdB&}t@;pgHoC)GZ{;HU`F2S&+SWwXtDwW4`DFPspG>oL-yek6= zNl%e9y37q*3Y_67%ei2fu#_dhQeYWLBS=Db9mPi>zf)G~hV5yRp1CCq8~erCu&woE zq?VtVGtKX|L3V4>-eyOBxGUH&Y;PNB)_Y3xT9Z*PUaZyY`Ik3MirV`54|O~kHm-|J zTvZOkwox-|&l(n~l#eo`Y(q9$C<@ZCODN?d&9IFvA)7KZY!1hF3cM;4*ln~q5kJe# zZIlAZox-kdb{n1PMHIs%c7P;5H@8vBA$)VhI5p)kNfY_huSoJQomGO&PGRw^StaQ0 z6zJ^~=nQ1UXJXviF}22BpaYeR-j?lX64(4?S<@B!L;yJm)l zMfg>}&#Wypj_Qsu_nbH2uhS877p|=N{^ZNVX=%9$HeS^ZnBSx6R zXQGucp;`T*dBY}84mU?!qwLxNp~1oaGsDe+e`iyCjqp@>*SXvf(G39!_xz+(QW(K=V+2YMI`de9U zAe-w>*}7;x+)%9f%pC*F*Nu}+t&1Q15c&w)@YDzN8kmot&$|x;@D#jA(rUKhPVv2M z+Isu}Pe%j=`wf1+t)E|SbAVBK*S&5R4VwBG%53Pko(9-?oTQgXTEN%S2*AK~AxUri zV_})v9GSG`0w5DpTL2iFq_zSuiID0I_yBE4B9a!7w3s9dNdifbHWH`sMN&gprgFGE zJSV9fngd}e>%!8?!g5u)6PBrc_+A1*rS>IBaT1oP1Nf`Ig{3KVFifBxOCzZqOH=(R z*M9I6G8)Cr#0@_JfUtX+q*r+NY2X=>UL|QM_k%JG-A%=`LF#jQ!J0ENb%G|Cmgq{y zYeWu=^nLzrGmfs;k6}uxHhy7t!FVNgGJx?4RO)h)R`AgvV45ybSCWJWO#c0Kf>L=R z0unVf%#+-_cT1}wJ9CExZ;^ub2hX|`s!P<=NF&W`Pia#6M@DSCG+bTmW+lhBK)c#iU{sle!F84q*I}ieB*+N$W^@o22z5y+hKwB)!Ke z@DS=>EQA>ZjfHr00T$Yzv(P4Hp&jLqg*G`@XfsJ0ommL6LB(0f2!6Px-!^pzD*6*{ zBX0Gbz%G)IE8ezkO5F{7O49ozeaxMpOs9@gF@#C|k_%>*z^p;)egH$54@lZd(l$PN z5ICfB$A=_gFm?-Y$2YiS=8kVY@xZjaoo`o~)ng?6-tVoSc7A{v9`@U&o;1>64#VAV zyJSz`xH~%xsxuh?92YMLZrk+6_OubqgVFm+l{gAeUu+c`x8Z&>;g3cICm9W%D zstwu1>e*<++f;3}bZMtfLDvifE;a^8O?GrV%(KjQ?s)0^6@~|u;3zvb5*S4lD$#=e zv|xbqiI^qOO{kuSt4*=vDlu@>hPK}n(Sk#4ZO@Uk$8F@0`a8b4V4RwIo}|5e>P3=1 zE7iy$6@!E{sDEwbkc!blDn<)wu-R!QpaOtN?9WO1f~0*UVNMI3^Gl2z(ryPZT1cy` zj~vqOz~5C#!Zg>{Bq4MMBZn&_UH$Km9MWoWQ*FS{s}0lv?gh~K4v}=2q$4DK#RG`v zi;ptBJ9>B|ZUA0-9ESCR{f6Rw$FuR0qp%tN5ysB&u%H=1e3Z4c7Qm_h@ig9}G$q6w zcwJ%bSACWH=mkp$>%)$be#8BGg@&0i{P4TpB{(8ST?+R0_K?rWdEpV}8GfVY&BQ9m z{mc>kN8hl}8AHr?uT$VCf4m=RWN_#lzv?eK)kSs` zI4X3y`R^B2qB!GJF13V;dAxY}9rb}yoAzz}+g!&vp7sdZx4uphdZX)&{S}xd?J=MM zNk>USD4NS%n}$(K8c&`uMWrr|le7VySY1*&_#F;jbq#vA^I!z0R`g=rEl9ostg=StNl_%(_-FtSsB4L6l3@A%eJznT9hVF( zk%qY&cU=(mqF?3-pFv(5#=lnO^pi&#=vpEz)JQYaQ<_oxCwZrb4U1fQF|Ot(Z)G%b zABUucqdbgZ^frpnwM3kzC2ruM&9wQ*Wr3cHCMD8d(nd2z#A+#@L`)Nqi|n`-5jzq| zNhBq6e^IokYboVsqOQ|0-bmBJlb8Z9@JPeJBMk$OGz>h_Rsyd9t4K;EDUGCbk}^oj zBq@ue?9I3?xINO0fkzq-Jb3>tY_-6V9OjEW{i>$ zok?Sxt{F-jb)B{gm5ON(y+eM2o!ulMSfqeE!5&~QN$?w=D{~)68pa!G2OR|;(C-8+ zD9)-n4WkaIYN^PBs;*IgfvfR5h7>0_Cng$9n51EzBn^h>SCW1s>32Sg*^)Gt|1C&5 zPtt{3f_{F&B{Th;^+YB08*exyz1jPbC9n3bv*g{@(+v8FGSb*QrCD?8Y)d(zXXtAS zR?mt$6%U`1Yt(gGEXqsJD_tj!c#SwN8Do&NLvTEy+Fge-#l|3Mkm%a@A+0uqsB_=T zGWy;F5~jrvI&lV}6KBU4fB&}g`F7{5T-)_mT|0MV{UkfFe(aB2PyQQ+fxIYm!`xliax6sq*xJ1~a7(BKZL)(n{Cfp;~%Xo(>_N{w%i&u-eQo5ggfaV-sI7TlG5?(ofDwtukS;{A21MGdMq zX^Fd8Opic$bM!XS=3~-l^L&il&@hYX^I#Tbys_P78SolacDS;`OUQ|goGNz5&O$b@ za+4BrD$99>V#Ych@?JC68c{j-6eMoLY za$AypNp8nqZv|KuPd4l^VvL|J<@O|ZM7y#%ei}maKObn2{+XkpJ}0>Y+g~Ril=j$e z>wwm6+j@7njt?sR0BY+XYFV>yoD(1ITz63d^YEWy+|^Ie}p^ zDg#vj$aN6+Fp`J!QRw*$=y?nv<)=s#`Z1aVa>kb zh2qSwrVKB(lu!{ama>>l%D^3|*`$nyBqJ=N!NIlNk)d0VWkyqE*9^zmusEL0&46Tn z*3GbFw8E+0#;F;tNgjhF8L$ImOJ!Ixpp-LM|MEaD1CludW7iCfT{AiXoq;YSgUiN~ zJb~orNcJOnBA?pLi-Rmp8QpcmlF?J|b^Z%CkUUv4EK~j$3`@pfZZR0#j3K~KU>Go* zWQfTCk^@OLv$g3|e3XUQGXz^21F-2q!NJ!ZWBFCD?>>)&@Ur3=_*M6IDxmdz|49h` zDQsPa}deXxHC^Dd3xzOb12Sc53|;pXJTg-5C((;5V{$WBnOi`gX9pBLrI=V z@+|JmbAY+PJfkzepm*jlk|Rj*<=(8c`=98|f}>?clEd9(lD_t5;N*@zf#$Zw-h1lW zpem{g%2<;o8CLAP3?Skr1A#UfO91%0Gf)C*dp5~)NS;gbJd&SBnUE$KD}a>%Jm48n z&>61-ZvYU^FOd8i$=gXjPI4N_f0FV58&4-Or@fuEwb{ozu&sCNVpr)Bp@}I}Eke`B zr)}UQ=kuJhGv+6eojJhyH0OtWT064yZ5>d&a$K%Xe^#Hb&ezvDJEu~8IX7?bHfHY* z*R5(OiHwb0)%*t=W6hbn zJe~{Yo)-hahn^8fGJ4%BB)`f>6M#fr94;Yw=`A4+SpwgK>&o;b^k(NbY4hsV0b%cc z{cY%`DzyR(aR}+JrOEY_rb_-W>C&tLMW6rn`hZpy=VW*ghXp9F2zh921m`|0^5y#E zX3ZU%Ik`R3gCcjO)(gnyvYw5uF)wKvbEU2^y=v}&#zaQ08q+14Op})>v!Zb|nH8`D zU;QeQd5z6Xc=4Gw-nbds$i$c+vlbTs63Dz0xC^)&K)q*H2WkK{Nd~8{A^A;`*OCmc z$2yYV-i&0Am#44!`dg6r$5cCY3|RRFv&;w=sMtSojJZD`RiMPIX2;vnK{rw-91aE>#mq` zcUs@0s~dao-CN(A#lsIcm%aI%W~-+(FI4~!I6cRdt%lgwS-D{t?_!u zMvEyyFUhJ8JVtUl$r-$hyOf72nK#26S%?A8(qu50BdZzE9B2Ww1X=-*##!DZXOWyu zat_J4B)Y&GVvGiem@$JKJj99g{#=E&+za-kD*Wc9l- z=Exd~$~9!LDQg&ZhLa4o_?0`s2w)`1zma^o%mqglRCCsN?!Dg_Juu1 z)GTwskpz>A6F1k3<0|EVvv^Kr9b-@wE%%RjZ1V`2vPg{Lz>{+LSxNkzK)Hj%;vlBPZs_ zhGxGJ=E%Ow%ajeVtT9LS-Pi$7G$ExaIzcvE*V#2md4iPIWiB|fp_;QF@ zo9}lYxBI@|+xQW1R_l>FqBe70{40kJ&hAZ0 zdk*SZ&5F`3s3*HW3TA&X2lY4>rpg{fN=LUii0q*_b+~bA_ApX9AxZXAq;xJ-97Hza zuCw_XI1VEF8DKO3shbUjn+=7VJ&u$vq;w^v8!1nc(w&qZd@7`FHl(g2S~T0A|0bm; zDZNqG90u|H|3Vl<_H?5$vx7Vtj$PNa= zkR2&~co)$o*^#95C1oO$h;sp2kbqWzzyEdOQM2bEllhJUp2yA$r1T@DKNs*KI?*yx z2HeatDcOsWk(CR8smith0w4ksAOldr*(xamNkK;)Ov(^aU~|zWc7$kApkC@nn~{HVyr49xUEz)B{@<$JjXgd(BSy-C&JJ zA)6RI8&kFoJJF>0lQM~W3?ev~HUe&nHj z6jG*=5=6>02W=qELZgj*V{6A&qmAjz7&G`|Zuz4PII%UAk$r^}yoav1%0RgHjnGC; zB`;IX9o$A}^_d&-WDcLQcE9I9OXt)CFr1x53hZMz z?)RKJz`gqYjsVNZTj74sf#T--J?9Zm_wHwkf6V0_{hKQLPJZ8g-zR7E`#p!(E8#Sc zc}kNtcYSBc(xcrwNxL5#bhP%n?)Q66L!@PuthG@i-Hk9ucOx9*ATg}2G~I(6!G&RS zS|S^7JsWLcoYPvPjd>-|MzP+N)86QKIUPuOfi>**+mNA~hRx}MqPpR@reV*~g1Hc; zIZ%)acT}^(Mx=4A5s>SO2g(1z}cDvhA_<;2n+%S1497l;~a>Pg`~jk zw}_O*q*zE1_|&I>5nOkAEN{-!T0JTvDYBtq5Bx7^*c?Aci%ld2@rAAuQ;UA}_VM-i zzOIJN2}E^GK`Uup5CI-J$WB3yOcPT9a5nVc26qjs#lva^Tvx;9%s?hH9R-A7CzKQ` zDKB#Yv$U7@DzDtk%X@R?Afp9b0E|)2TmY&$2Vyzr1zUwk9W(Rqc&%$qlclwRyi4?oR$1l={0N) z!Z>o)p;EP8wiY{(#cz;;S8tng-Uil_vWArPWp9i&BJ=mTU^Y8U58UKiNO_Z#wWRRN zx^q4Nw(7=c9VxfO%er%R;*#00?DAw-eyiO)yyM~_n?FmQ^yddFFE%%f(Wge5J)Y9s zH$HyGvf6{&EK6#*e|qi}%v!s;TXLY&bN1_Pq{;o9eVW{VrvxkFYK)E`o1;cH>}$zE zhz^E~@7-WFCy^4)WxdCIhn-WTY$Rn9_ZWnFd;^Z!d{eXmZ*opN7r;H@7XYd`2VyxV z8i)a)lyl-pL1%fNln+SRN(zQrACmGBr$|6j2W=#4f17eru?215W#7ygJNRQ?`J;^j z2W`N`z1^8M&fOqwTtY=(A0zYIVY?<56p-Ztg@0pR(NPe}QcX`@VszPS~>Ou3cy zg0*`gw~}@*?7p#1oO>6tslnNRXL9cba8Kt}Ck2kQy`+4`MWDc|y`eSp3|KV8G-LJQ}@1$Ug3lcZK)N341qsTKJm z{@X7I$Q|iuGkCO4xIK`jKk79((7S_w#}36F^>VQ}xo~agjzc{&PvnjQ;8;3A%6Ggw z9+*H1%tt2kgwu;pJK{mjNza?ZLa+NIrE6*a$T84S+9d1*kaC(7eq(no6!cN>-uJYi zH<$L0UVNH69T|ml0WdVV@GIv+L+3&|=Y|4sI_E++=VC1V11Ud}@)Id%N%@(SUr2Gh zu{+lYkEb%aPO{KjsD-`K6Bmpk`LuEo*Y1X7&e*qtlim}$ygf=XTP=mbl# z1Cbm{3cs;C7a`KQD@lQ`G_}kXZSHDh{uUR^)?*C-ZJi4(n?On;DM@@3A=0^T>oz5s zl$2Y-rfk9`vrU2j&)ufHJ7U^{&5jNHe0|gVrhQg0dy8RH*z3({Se^ThA3CySWMoj_ zqzgz~}b_E!gr!qfH)c%121MLvJJ9ifbX#N}6F)e)n*vPjA19`hAw10&NMTF~U5 z)5dXR#P(35jT6{`hR%g_&OHU32B4dBzb7S^lsr=MNhu%&TvbR)5n4r~iJy$E5h9)I z2$5FKF=PCO57n#u(MF1cHd0CX)k)FjX1LHsN$*R}%|{y)I(k6?cF+R9lX9MWK@o6{ zlnbQ%QTDuX0hwRnf|(&M0ua}^mr1!u$|X`R^U$#yqdWuvaCFz7np+m{O6HrMYJoaR;*Gp}kxgAa8%@&Y-OrL%MTjEv#x-BNTujpD zK}~D(0W4^~bLx3{4UDhc-!_`p*g2Jpe#vWw>uQ1PD(=J0Ye{M)H~pLEjZ@ngr{?*P zS{eE`uPv!nN~M4EI^gUlIXOgaUPqu4&>83gKpf|FBlQkatCCuc)H_K9z1+>GLL%ou zBIotg^>1Ep{N0Dtdq}N8YClc?_9u0~e_#LR4KcAiFVq}Bwf_^Lz!9An1WW@Uj`N_2^Jb8GAF20~T9?!ZNPUph zhe&;xQ-mVv;~GqPVa7HB+eV~5qPb>Ne)G24tlYU~@)kIH+d@(wb*2-zzHh{%o2R0p zIrM{vTzOXDWm4;t`WWxN3M?VD0jUkS%ay5XCJ!rzZ&B{6Mpx%S=7gYMc~ zH|M*F(J$iN*c^A8_Yr<3o5PPinZud!J-XjEXUOvPBR^Z)?BK{$59V+u((X2DoISdE zpJ;Zh`3=_i7f5+P&&HIu4?Fuwh1F@r)rt%G!_$L*`3rJ5t*l`Zw=1l4H1>_r0-YqUERrwF7^2;*UP% zPXFe?O|GesyaZA^I@3n73vHC7fAg|XyBzzW@kTawa!Bn=DzBTEmj~pN+LhEN%bqvR zA@koI1^=pvIwt+HUO0O1;fhJibl%9n3qKRQk$<-*-bk63ES#>{Gi)QhyP#-V z4G#;h=hr~m+Io#^`Zphh1pV7r=Z(_n-+XwY^_~YoQ`4#E<-_5uedVry^B;3g<)W7I z8{xV*>VoxeKFEF$Z^1r;Sx=T?ZT0*XIKP!615nry&Y(4^LrbNK^V{O=&YT=lH{Tb4 zmpQ*Z0J)qGm7L#+RLH^Mq&`LJ2vSFqI*Lz)XwHXd&hMtH;(SnXKKdN0W<04YG*!Hk z)Yt#}syKfjHz5DyLBL>O2rv|Yw#`SqJVWYeQlV zlR0>iZ>Ofk+~t1N2f66%zrbdQLuQxd~tX_9>c!2-RppYr`x(E0N2b;})QzHGt z{PFHAb6~wDP3yJj#-HB$Rab9a{I|58ua$b;Ds{aB$DkQGKAnw#)~QCwFmO~?&fkjHbb?rV&&;}0Qdp>;c`O8S1PHHgs0{GtZ z!GbeL4J~sGk-r+5BeGlXw`+6_5u#}b(jgl@);X|jik;b zbrz{%e1yB-7F|PxlNxbLXb6lSG(E80lOFhf=E;5Y-Wa&_?I$OV*%>>%nxP?f8EHQ8 zlx9oT!P*^v>XE86@1J}s`-d6sV~>3J-t&w5-t#rzyEtavQKb9=RBjQs5x2S>C?r)Rl_MqdF}TS8l~kEjwd`5vA~M%J_vrNe97aA~^a+oL zV(91!`$0Ju+-?DvK3q`2%Txd-x<)z$w_&Fua6741QsKIJ1*B6@8K|O@&a0&2WfA}W zV;BYZ;F9mbb-^F+J_mTkZ}7l}cMTf7>Vs|zGVlLnqE0#mwTv_ve7L9CQ8RdKyZ8Im zS@>@6F}I0|$(?ixP{#!rd2mZ>1D67AWfOJT^(*}U={*(&2r}0OI{6SuFowmZ2MQ1{ z!#dezHD+A>6F{@S-f2OLF_3tTR0MH0=x+H2zs$?4L3g2^_DAvjT00lz+J!K1DQJg8 zJa9VxGA-oSBNVhJb+y~XK>-~71zn6&3oyQ4!>3|k|7NL%NCiD`c7INeK|n!Ipcl{^ z=mYcx`jNVp)VD}oN9x<8!g2QwpE>{-2n^DPNCg--6ky2tE~y(xjn;-pF{H-+_lHOY zqm8C2z$oawYfK!N1I!qETxa5-0IvK3hbzATQ8Wb*)9;bG5u8>q5rE9yMCw82w40we zD1bsQn2J_q1}&HjOd)kMsatqA$jfx%eNx}2g`5Ae87&A!Ml8G8j21wx7eK8SgaP3| z1P}?#CiMeSx01Sz)DKDhh}4fs-OefIBI)BAOa(6(+ZVBIL@I(g*@Eukj|1gy;-Elw z^framoz5KeGJjQiGg<(FUa$(4s&#^u*a0zpLMlQlO$Dz5Z;<*ase8-Zj26J-U$EX$ z@H$<*@6pBkPaon(Oy*dS62*G~(+qpzS-fL`C{w`}06q6JQa>m43qHCP*rwajeWdQc zCG6-fTr%5Hk3zg}Xy&<|akYj-u4(f2 zhOpLwAXnFz&H{M+3l8WtuG>*m1=twNNTRk&9XM0)6|y;|XJaaW+%ACJK1Awa?lExh zABPw}LJR%>Ic-2_7yQfxaC4ppptuX5xC=0QQt%`26L6N)uSorxRFr;<)Ne@rmek{h z`Yzx=8L01qXk#0Tt){+DFk^hjA5rB_eHUanXd{!<9@^2YoHz= zy0td4*VHNYmm8jAu|I%p9@ewbc*FjX#v52il6j*v69;xjbPNlcjZQt!-q`4r?h^<0 zW{&=w>M6;V}>yS`q$op)WlNhUprj=_FkME z*2WH>zr7oP;Bk9*0OHu*lhhHI-D1ZuxC+c1UD9B(lA)u7B!YlHt@X(I*neOD+D8~oWykDDrf2=@?cI8kZ`;Y&(ZBZ5sGqTVPczv^Vh0ln;3|&E zw2uQYv64g9+nH2uUjN#msOBpYv4B)NsqkMEk$R3)FzIicA{99Ti>Wm2z} zx&F1kfz0333)b97b})E6saI}HjoF#VHgYy>`1qoEi_!HTr2a`(FWzG&f-u73{#FxN z@x02v??(es(nc8Fv9Y2XZ5?;vYcvQ{JOon!?M+)dVd zm^OYuQU`4qUTFI-IM#@))iv6%)@0gvxct#ZvV%5K$XdghHqvj9Hu6x>EJHQg$j43r zS!$ogQJ%U}C>WPX_o<~#cW0C%+g5?Svh>wRRspO3OazN+8vb;URaelLV`-~E1%{-f`O6G1&I?5Wk~oq6ku;NImxxxy+&8c1jNH21vGe}0>v z`z>F2&(bsJyEnu#oUZqK;ho5X{ngw?h0xN78@EEbVpUMD3j2Y{aMPFQU?{AE#P{pD zXzI5RMS(RQ(OCmId35*lO$gbp{bomK46B)Jr*2pHn9(B(8<4d=KO^~iZzS^aDxTaS zkd5RnD!8y2uCE1>unKm(&abc~Ss!;(!G+#9wT*FVp$}ObB1vIevNkG}3NA!EOraxu zys#s7;8iX}_;?}YaUoQ3VK=fiCTkP2HYMv5WNk)P7R-g9+QJ?{PhABU;wQqpV}&{L zChK5L1rI?b{^y^bEF8+Mi94`x7%&`oimYgfR%C6>lGy33lpMe^Gkji1z*N70*>n7Z zN_u-_*Wy7Qh;DJbk1`-MB+#!E>6;W!?>qnLkf6DJW@GZTQ>W2f_}_1ybnRczpGeW{jrp5bF%utewf)g;UH#Qo}M9 zhHHPD3OPIkma(gD8J}d!II!GV#=?aT9wM@KbEYT@f3?A@wDYosR#fz>s8p>Jyo{Y! z$l9H(J-8Dr0hW@rCt0<}amzFkz3??;{)S$#Ca4QvXF+Z4We|1UUWiSoJierf*}`?m z21zsnTZkz1!u7yAWbH%NzGUskw>JYd!h*U#SqIz_26ihhnGGyEy4@bm{P~NzYUiW< zcCUM9SwyQwF=Gt_3-PU`+3qRL<5efj`X;CQd)CIkUsyM*`cobZ>@Jk|sZrxBs0(*% zrg2aSHD27f?Q?WIW)|m;cTi_jZ8o*=FmgY_GpJVB-eEj(8k~rddE#^y-_~x+3KYT> zU3eVF*)FF2M$(_mTPMi+l)GJorY<~VoLYFAtRwi;@5wr{bawG9&SnR*X6$~(&M!a| zU<0Co7_yEc>(gX?hODE>`Yc(;uw9G;;(-LiE+*mcWU_)=pCju$%`QGq)))Q<45Q{< z=DQ{rfOIa*C+j$}jwkB`HjEvL+a~Xh^Ft?13-Ajw2b=xF&DRZN^s7G5LnLK~`NL+L z!{Br7)G0J%c$hgHW)8uUet|*ZGyNlAaOZ@EO%DzYovHm{4)ZhK4ecBh+WK!BJ7<=D z#&xg7)foPYpZPm_g=RN%@q4*bohPfGyWPBmZy?xp%Djx7D`cHWR)40r}D^!EwMdDMc)1 zd0XAs*2I=)RID69X$|I&IpuCfr3h|uEf}Qe5wcEqqOT$?PNej9v#1Fw7Y=W&6BISY z4ixkZvWB1&6g3B0kTsO7v&!5NRpf)reH{h2(T7QJx$w&q(h)2RsV+Avd7M;)fj|+D z4tQW%gb_gzMg&C|5rmO7oU9Ri6egmmhi*3`$vXR1u$x63)&jd(G{BP$oKUr4T&-q3 zl0T|)rtW>cCA>hE2c|`XjWk0%rTMDTn@c`T>-+R8V~4f+`b;|JSX~FEMHm_sjnr#g z8&VdH(Cp@1-EN}Rp;S=ku2Gc5>}C-Zxz_OtnOU4W-h^Uy^9;spXFC2BdE|T|eBZ_M za3QdwDY(iYTxIcrWzjUUy00x+1le80x|~lfg8t^UC5vW~wRCGs79kX*hyy&>fEGmp zvw=ClTwopmGq{kf(58#Xx|pmMvI>0aeBedkCEb7)EyUkANhGUG)-N>!dXTJ#|N92C zNHvH|zH zUir@lm_?k?2V6mHD4DW002=}BZhUMD@IF~zCF>HhVkonWtjo!|f~;7)Qa6wg;F_WQ z$k=ZGKk}{vK8mXQW+%OUNo6c9y92q_R+FbN<^yMO{_I*8IyK@mix zC>;^0Dn&pO*iW)`yr5+vXM3t!-Ob~3Z`-kW{%=G=4d+dGq++jyg4@&`Bbf}s?fk1Zvb8vsG12!JmD$(;hF zoe}^90zs6#l#)Rm%P4s{C4WT8D=7J6E)jyFl?>QYIO78o+i@Gj-&jGiqAq5fllqb0+5KRg~?V;8-Opt-4lou)STLu+-`>GX zc-%W#s}|y!=M)6IQ-(P!7)r^zxB@8e-GvHSr6gc)_;!ZkPD#WHBzOvxcM6nu3Y2%s z%an{R+Dpk_Q8EnbHp-*JCIfTuurr)Yo-V{jP6lj{Glzf@QFcPbf*n-5q%vP0LbUOP1d|WY+vH6e7ZMS+? zcdOShJm0M!&q!S2=(yMetPm@#Vgsbtsq?ziy-a zN9=yVFkKpHF8l{m-C|1qo|2F8D)-n2l>7rF|NXB+WGNq^lC^xQ*d(t2J_c3-p8%_X z)xa7`K2FIeDETBMpQ27%-qvT&H`M07s;t1lWu#85- zhMY|~X~%A|QK(;%)_ELO>!d>Cry7EvTYAE99Ykbrvg?rg6n;c3iN4-k zhYm;Gh$pobN^qc?i6^x+&<1ErqCbfNBnI-<_5frzTn90T#NgsUJgF?<`C{nijYNF+ zewMwjN%IfIE%Um~m+O&9JgLuFWqNum)BLUxAAh*9d9RNv9O~28Z&!jR@uc=bdwtBa zZMY7py_tB#P>Xm{p90mR+Y6xj)B&g_#;nGc8ikc;5^*K+tFTjJ4dxK)mXHIc+pB$g(z42fk)EJxy%e>4`JWsRvCodJ;lkDR#&=ak7`@t^_b^7>>JU>%WR6ND^bU4 z?kYYhh}9!WRK&!^1(B>f!>&hZ#JIT{lQuRQv{Cs6Y2yo2v%`5b+p+Q`iB(Cg#s{|( z*hS)_BsTxoZcgggsDzK*Ac1eNvJcn~8~_di-vWn7tWM%%B-S7i_Mj$-wMY!N+?>?! zP@IJZ=alpE2Q1mm5o_~DUH*8w#JM@C=bW_h3yF1HY2&vWq>aDOsaNHfYV=( z#QMCN0;H1IfW*c{FF3MLd5*K;Z1Y+`NY1zxa`7W#No?dza0H~eT@Go!KDM+#t_f6= z<_Gu#0VFmd@d*-}^41_A*d(AQNyPIS|NU5HS}7bd2q>+zH!^we%;#vYw^|99WDcf9%66SFq2Oz;w`OuGkV?=w5yV2(5->_c!g zb23LR3yww}f}<#>H*r6E6>&%q(8d5vdju<$NNh=BD-6K2DyDcrHsrq#wxrcSMfJD= zh?lg-fto-qARK_iPOAgdC9w^OP^s-mY)@hb5<8OE$zq|j1}F~pNo!;+n_y|MP-iBf zuKdxv#IaCXYm0@_&~sf}SSYRijj>SLGw9sze2)06KMQmt@fi}I<<%a*b0lKRb4AWV zX)mJkzRrewn=I7bWTCWvCJXiO#zIp?_i-GJng(%A%r`Lrly}-d5_^*PJc%#x);M6W z$wIwIL}F|)V4;_A$jm4S-WVljYTwg`m$o=R`{JD|L!a7l&|)Fh^IT?>w=xeV_S>4W zzxlF{;#*DpRH~KZ>Gq_JLD{ipr<*MFs=-2iEEY=Z$1K#tgN59Cd=jdGfHnusWUNdf zu^)*%A!OR?CUYRM@g|rRO#9Ge4qMtX^xAU3SduuH#3APA z#J#0HE9G(dt;VjO^10%(k6iJzwImKBkuw_8J_FW~7*FEJB6ok%Hly-w+%R9^TY#;= z=Om6G@g)*@LdP@+?X>OYbq^=GSWM`cwik!Y*YH=~uHjzGE=4{5aLewi!$!Aj9oVy< zb=~i?%Ix=6=3*t^g|AlZxLREP_nj|R`8L+eb^k5eJHlOs3!NvkOFImvC2`aZUiS!) zr#S=U9Ij16fE*&mnbCMH`Z$D^IkA|3_0QG-Ofm1c<^Srub8P-bqVYEDH#t<{(yzYN^;`ozT~PUD0{@eP=^ zTmDJ7bmXrXnH%W{KNiPLKV;Up>~sw8S8B7g+r zHj{@^9iT1`A8RN<5c5z%OzCadY931a|0jl0Gd@u;8R^Xd-1VMC;#+*?WAmT+`VHNt z;C7vm+jXsbOi~i&)=umh7c;u%fcWS!H3wo#Ou|FGzUqye?NXWem<{u1Uiv8o5VF9Pm`o~#h2Zj1)<{8pCxe)iF3JNcjJ9P z;=G%AA5c0%Cp4(hR}yvONX#e*8yUZ4qX|oqPRo;19 zYflZAz69+dWNv6U7GLRzjYE8`zQG><7$sMk)!5QkV&xMOq1bsQ$n@1FZ+v!Bynz^b z`ZjKWSzrUO5!eJkucvPTAk)(!(_y;SlemGzjU;X&aWjcqtf)`=b`*#2md-J9Uhcxu z@ZGjDWqiRO-;}thPx`k`-az0UZ`#f;a}cc0&l|S%V^?`Y+{V07T4?8Pc}}5Y&!A%s z>i7{Wr%BvS;+H%S&H_J?xP!#6irjBYKaa}ssHow$r6Ut2{deF3i91Q$MdEJ0<{|OZ zFPYao0upcUzu>Xv zfBx0Bt0;uWMl7l{(#tguUnAY&JV%Jl^KGlI%^=xX7*!}iaBP8-n`9s?pAlqMV}yM& z0uAceR{(Y78(|sn-wb`0fiB2^+&@6#K~9QI;9xpGpWU;W@rT;*iZ5Q0p0Bj*QAc6`(3m zjl}OrJWAsCBpxI22NI9-u2AL~5abyUwiT-JUe!gol{&)&_8sLtDaz#u5EOL^>GyG*s zpcT*>XhY&z5_3qpnaYweqrCxdho1!#4`~s;}c@=09u6U<3)6fi5-fk$$0+I zZX<^$#SM#z=p2(YC_cLV@Ywi7=eB<~MMSh8J}Q1lK~I#sB-9$|sr=I$g@@-)PjySE zt#3Sk$GbJS-u&Jfo$!0Rau0z@Gdcq>(_qt|c@;|i0LI@rq9fc3|7wDijGm|nF>=Gi zW;~CT7Xaw>49N5h$n*@z^o+hF;wI&hyEplm|F$I-RbvFE(X*8~wMk8Yyenl*aDPD|5>A)a&@ zL+6@clQR?may*2u=#HuHeBbd) zY3f&}&yAZKZd&S$g;tqG-pWinyL!^H@7kqrlIn$L#hktDX{n9Ac%QopHkH+R#uCHC z+AR~CF^%u6q!i>2WqgE^E6r+b87r{zF^Rb(=JBBU1Xx9)gQUCuJ#`==pRtu2fI81u z2SBc8K&59urDs5;XF#QAY$3^qBpXQrNxmfck>pQOfRj45p*T~=c5BHhovA|#?&wK)%{S-QunJ2R;@FYp-Bt1q_4U!(`t%!|h_Ar^J zCP}r51M_4e{e_t)6B+5AEK+06&vn*L@1So<>hbNy(_3)F99qbXu*&rJR_5JHN6#jF z*y+zt+Egk#wAsi;UYI8eb;NR4fofQ=WX2fGQ`=&my@h+&DRU@F#+%jHGKXPhI7xL$ z;>jR0N0`)6|E8#86e=3e4KNXm23`in0MOT&uL5I%aU?Y$sUb;?NNP+{6Ox`F36nt@ zLM3yewVY%vr(kIa7EA|85>EyxS(8DQpt(9S6(@D5B)LuonK{Fxj;p>-0fHrS4o<;* zbgDrcbFngyBv1uU2AR14SV&R}lG-tC6ln&0=3-R7lpE$NdkKJmPUZ(BwIrz(Nv(P7 zhrlxPdT&Eg+hTFObNrpJ_toC6-TkYN9V&OMbIigg=6yRhxH7_h#`VrAHeBX2Z)Ns{ zMQy))s&jj~?U(4;TkkpQ<$8z4&)jUDBOguy$=n2bC8@o2y3FKcvcuH|5pc`WAY$LNNjv$+sqnh%jKE-%p=a?Pa)pq zaZ5k*7!L3_ig3Vj*K;&J7t72OBzaBlkQsE|q%=`s=U*zIE z=zayx1Bhp5BA%Uj0r-QY9wa?S5)AJ1B)vcqPY9U_d7KGVocR~)e!wvkO41`brIiLoTigMT3CPu z%|cK;s~I}g7z9sY(=}t(^r1Od@F{NuzixBG*}%a|Pi-X*5YM7YA#c z)encv7a`1HsP8O1XVQfvyxSVS4!*lax4ZXvJa$bmtFdK4ZfCtj(pZwl z@vun*cc>(drwP?~*!(;0fY8n&Zh)BpiaQI6I}3_CYaB2hm;g*9X#z?3B$6hPG?}C+ zB)!HZCZVX4J6<#Xwq;Gl65R2+$sN;}J7$zT?$DjwF@q$eP98$1SShkuNOp1Ij?y-E z;5k%Ce%b7|yN`nT=;=kMz#xwWSb^T2PSP7Z3Lt5+-X$rSB(2EhcNU*welpXz;Fn?r zVmoUYNg_!SNitvX2xw=mFfVw8B(+#v@N03%e8EFfdtSU#?}!}ecdYfn#XG3}-pxo+ zF)#S_R+$an%B+rFz3J}KU6y^2Q*UzJf%mNTa=~v#d!L)<$mH3r2G8o|1@F^&F?jaQ zvmQL_eyVq(nmtxEEWfjM8@w^|2CLbRl1L{pN6Z1N93*KLNpJCp0ll&2c>AU_2UK|0 z8E$}w$Pd7A-~@0II0gI&KyuF}X%0zqNrJ~XpQHsOE#wksQPjyB=ZwE?S-)Zl-dJSv z#=FcLAD2AdKwRCB)LHNt-f`s(B&N9VMnRe*2OaI;bHryo7sw;&J(3n<6`^ojHtzo{ zA<4)cEK;vM8!A0Jgc}AyWCsF}>)DX&?~?@IeJO7Z1;R|)_>iP!#ep`m%i@qh8`I;{-$6J}r@4Wrs&QYD8pR)7lym1w_{NYI( z*^uhl70h#F&_?zH25o#~>4fZuSe~u$ppDWGec;9%*_BaKHLE6Oj_j%ibF3_&CiiM; zqGWBe8e4WPtb~(<+XKi#v}M;ZnPbh(Fh_PHRMd0jT3_sN=OH zeM-`2B&{Q9JxLo#+Gxf5vRj~dCG6G8TDHN`i1%$`(%>9I=_`{tN>IEn`&o-Qvb&MA z*@Zc>A=;TaY}q|oX*ic8ZQ)x5_`t1#x7-IpU+mT&9n0*I-4BQ$>2s2{@oFS6fTS-- z+Fj(LBYPk!AHoeYPYeR$fWahfC+SO)cJNjNrL%{b?6H%iUB!Yul5oh(1S7pM!SSCP zMh1M^dGfMZT^7CFZie-0wCtCyGGn}zSvy8La_8wbn-{IvcxYq09+kbY$5^yC!Fi65 zi-Pn)2@j3%{oL${IOnk>?e%h3r8EV*pY7LCV!BzA;jd)lF(&vcUpv`jBJSp|Si^ZDzl1?UN-S;^U!#v*+Oe7obS~hr+TK zlJu=do*}>UGkdYMYc>qtA!y`mSh~Z7$}`M{#?8hIB1YIRdl^=i1CY7dD}axIl_VV@ z={u5+lJq@E$4L6&eQaI@tOnMYPx53#eewx7PSQz|@8m~$ybb3R>wKXyq8?R79(S0@uC(a_zfEtKkE7^eC{K32fB7QPK&`ukjdG*NIFH5 zG1m8BbuUS$Ny=tEa*0CLF_ZtoBOBC-beqHS|K+$L#j~AKJo^AvAjQv+be2acqtDO@*^uJdXSie7phAjgLyBiZif5k$AjPvG#k0{hKa+Hhq+dw-m8A0|{YKL7 zPJ{XrinBqrqYKIiJJEgcCQrr$HZif^HM_(q1-;H306t`PaJcXpx;$Tee zWicROOzmE!cyhOxs0VttYWit~+rH7N{dK!3#qE|9w|kZ1IxU@WX={t7OLk_(Et*!p zhNm&LLyFriDQ>ghZyM8d)0pnAYH<04C%hO_H=eTNIWV{_R-cAx;OKr15#@i9m&Lz3rzh)gfWW2o@|4gus9Wvey z8E=P-w>JeKk^@{=$8O2^tGDeJ;Z(l_6eT7o|_Qlwn!`ytM-@XLkCG*-+0PcW&8OisP`~b-nNPdvyhe&>y zcY#x2N9^1A?7kgd0~Ehpk>pA^X)O4g{Vxc9`$p#(+e9*w5U(Myqv{W+bG;kk_RrB> zU!a@s;0Ejh3O5~cyk4M}bU>y;w_nEeI!x#h+rHz^L* zD~EMHtXEE`H%qkbqmiwje!NSY58CZIG5W{bs+-m;$GRt(bBDJwYUgRYJ{#F8WP@0) zkI=Q(Tua)pbRU;EEjNq~ttL@-rk4X0G`Ei2CI8Mw|Vd z#{(Ij)0gCDN$$qS6JfmKQ0{&+uQ<$!K}86G8wM;V7AsKMIZ)X-h?eIJ2B5EVhLYTa zD%dYcBUFB`ByCC-55K#Q9sGJ)hi zE(R=T5`R^A1C}!#9WC-X;FrG#+M*?J$`;$C?2W9zIF+-CgTSv#?wVItG z$Hb3JYW;Fj%Ifl0~8=_J+gRvwJEEZ<)LmV=j!DZe|TGy9;e>qg|_``cM zbI0`^JZh9>2BG4OG9P;@v+nYhkJ|TdH)2hlv-L-J)iKAhyAzj#*niGi?kesKChj$c z@rt{#4&R7^Tg+N)Ih(MundBiP59RT))p*6BJnUv(ahS6M6@9}EFa<0D# z(A7C#0bi3moaA_tN09sy$q6JUlAL4(ZF2UbID$4g2dyRBU%vM$kK~Wh{4uG-1#NPm z{Y}z<=RV4nG?40YL!|K=I`+?iio~8#$b)f1yqwy^5)*_9C+QKcU%Tu?gQ3Wxd>Xk&T2Sz z8`^TY>6%;7wYd8MR>3iGP6-QT=j1NAaEYgT2<6-w*tMp$YwqJDzkwpTwMb4blu*vC zi@lq0aj4(idO&@k0RRP^3*np#FH0m@A{j?Z zXOXTIH;Uo!W&?xDJmR`>w9JurqizLX13Y6dSMe&6zl zFXg^~Z+i2tVAb4Sz>6fmP4aABg<8i9F7lk4nZYG@04g#9;IOp0Q9v{R&7K~kIJQK>b}ZZjOu4V4r>&$HTkce>Oe1*-$^1&`T*&oY$n_6M z{;&=*KQODKq0igQ;+X%B1qt-r*{EhdSHrY02bc?BI4vW2ImsXK zR!H_-M8;X5uORv3;$X3J-^U@d#fGHxwAfvv7v4VU!;X)tYvN`soY@CQ%+F)wLd+Xw zmU}C6oGwfZs?%28(%^-tqZ>Ej&WDG^M&3^DDyzp0Q;P>Z5F+@bfF93pYS%eO9#f0! z$lJtUz2}2jh<$7aVXY1}#%#ny-xD2k-4Wq$Lnj*aOn9ip^vA^Ep)unT0y_K=niex@VTf=aFqHV_P1_z75(q&y4Xqf25W?+Cb8Yp(pajko=n~ZH(ow^3g_c z&Q&$+8{|a|=S@cMzU~|aQ?P6Aissj+re8K-sGUn&|?@uR|HwTBz7yMjr7w?3p`k#KdNv9Sc{+M-se(vz` z)&;-7D#MbzexEMgYmOWl7d>E1QcPmkQl&y0-g(CHN!yW=`n|Aj$6~FQmkXZH#S-%z z8ID8VV#9I3o2(7Tq4gi^ICwrTD8=-#n;|oI>f} zynWdF2p5N_&D#$g0FVcghdhuxh~vD&Bv0`#sQoNii+Pw7xtsutttodbRWeg)2x;zx=FQtQJzt$I?h>zuhrZ?tvytyf!9Op6dxIl&gzmF-wp97el&rX-D3t0!>MaO zY{bxrQhoEw@;dczyqW@jnAe9D8rF@u?)~n(KXEcHn^&-ThRib)$OLf(NFgPdlt(-w zUwLp5@|-S09$bXHOj1Hf3FU%t5%xSvN*GO8#4P`>W)wg;-sW(+2oAUi4gv55`~bKJ zjsPH#l-o$Tos>IBDMdm5!P!BL)+ zJ6&kiaf2>`qY_Sm(?xK=MQ~Ih zM^egLhG*mw*sq5%YOkN{>VS*jaJmQ%xCjoo2#zMC+)v5_q*Q=naKJ@ym@b0yASn+O z2gTs9Tm*+#7vYbL--5P9cR9ZKr}J;uu9{>8z8sc|;PC1qME%xy`U}%r?_S=${Rd-C z#Cw^5)BzX4k>5pd7%qZR@dkSwE`r19A~@h8IG!h^5-E5ww#@+-Vb63@s@zOMrUNd5 z!|5V8`eOwyf@1&>1w;dI5gf6kR3)VvDHx#DNqLNv8l*h#qz%hOa9A#a!|5U@HJLGx zmr2SKC66|oE`nnWDYaZ_!`($FAhO_?j8owB5FAsm@){|%NvXqw03L#48Yy*2sbBQ8 z0T02Un%2&w4aJ}hWP-BnE$sbP$1GICs+}DT$6LVLz-&?)kkXJ8&g*m_g6^1SI2uZ0 zQi?@hrvrgyb~GGt<~*H-NrTj*t){gYJ#paF5q(zl!2~QEFL&@Y!DW_uD|7dS+JCR# z)@=4`W#4(R?9&?VI=jcq9qQl2KI87a+4X~FlaYvMQH-y_YK>Wx2II{$cXqVZS$=DxIC3#&Od*TS(IE$l@h zb}gLK20FeX1&N&QyTUhc9I$qE>?frSiZ~9E(zZ~pg#(dv#|bVDf58EN!2y54@jY-1 z_yK^w(2kV$q;w#qBPpFo>CC&H1Wo}zny!W84E{b#N*7YPkuu$IEs{yWn+tDs*TQju zPZeKne*hPOOQduq7JxK|1P$}Gr;U+$_qC!dzs)9 zh>Gq&6NoDcK0!b*5CVh(VZdzwyo_F?yhuuKQu>h6my~{_M3|yM@F|Vrm9SS?Ysty% z99LBO^Tz=G7*^6mgW&U!Nv49&!=yy!=Wc=167t6tZLi<~IO{HZ++GHtz; z>G<=H?~Omw`S!V=?tQLRuZ7J$%)Q{#0d;gX&k+kO!KafUu#kCb#1-fAtiO-FSAbt8 z_;g3fo>n!8D+)f(aa>WstHN)nnm#BQVOAsf^u-D;*b$^)&Pu@tt^sB*Qxa}s4kE!P z78MQW2ADSn0)v1!U@$NQ7zzv{C6SaQQbv+8ij>i$yiCd%E)kESxC{*5NU)YkSi*~b z#mLT4#xieAHF=|a_xOequ${sZu-3W#IStsXaMW353O(+cSE{G)4=bKt>?c!Ndce@F`DZ*v>BiSrlm zJY3N3Ko1fEXhJ)h(B5_E?=lb0=17HdbIw@88a{H@`d93sVdkK-+U*F*5RBbN+S zyz$=k9pv4{j2s*{{Noj2u23Il0jhiDQNhh#y+JLB0A78eCVryB~uc z?I4fGJcb;s(iQ*&0ubjmh;v&A z0C8>$BV{2epu=}ad6$&;NLftE5=)fZSkpt4+bnTzD~okQl)uk*bt!+WDRH9QR>2yZ zwg*Z1z=dIK75S@wjH_+`*H=Y34f7((ZI7aNYgnVeRvjydrG7{XUhgf~9tUcYvYeDv zMJ~#1by0akZWsp8Ru6zmw;=%c5h*K3!3)6!TO$CvokjUdQjn{<;^{x|Mf8DGGS3}Yh{)38t$*Sby35|o^9J;rKWb#CqCWE(=6KB zp^lE+Rj`9B%55DCA%dwmSxwvar$Us|n1V#P?OBxUVO7J{)z;mxu4@aZrbs6w5^TNE za6j`X1RDgt4Sx7KQr7c;ivaqQvVoL?|DJYYP{}ZEfN2K;-!>3{uD3zg+Xe&B^|qm; zY$Rn9DUbF8;ZPZFQ@HvmL5caXA^S0z9uWfv*m6g}B4sxzdq~;KTi*s|o3w+tFkZ`33}|N&`if}>%Fr_w@PgyQ*|9bNq&&{j3 zHwrf^4BCMiFv=iL$g@nBjqB9A5<2J1uRQSGo>jiy;)QmWqCKepe`p7@Gyh16^)hjv zrNcoxwYn8ZJF8F)ZUGq87_?(N6000AY3G{N{AVU45^Pr;1W2wquA}&K=K$YE%3;3o z&>4q~fBCe&ZHKiFD>f8&6IHf7__1H1NWR1+!S*#NM?ECGZ9jHBXznW54v_LaB)kn$ z{#c4N~5Af|MUf!9522agr1$`X71MQ^1e-5wWI( zw?WDyAy+v~%2}LG&RfbsZtksqZ$YsA;XIiaNjbv;-Zj6*c)3q_Oyh?28^&BaZ(p$e zjqbXFZpO1@f{m-1W&4XQoAowu&p^-rY_v+a*BUEAc~bs#;RNBvGHL_?-ilDw8U#XRte|%hro4+*W2~S&Pnt3bp$AW;-T|Q{@?3-1~mw!Ah z$mVI-gqCQp4R;lvlvc*`2}%}h8}3f+#;sw{;e;UtKA#{6olv@~Sq&%M3xb(ZW4HA5 zZp^sN6}jgy<+CONW~wp5q(V?n1tF4D#2y79id0*n%!&Z9EU*M-vm!t>3sB7hRI>opEFc;#3?o$_)t6L1QvFE{ zAT^M8jR!^mkj%)36@)|}iPRucZzHuD+ZFXuQXjkZ4T~_2&)H)9yz#&UU?M=I29p{> zYAC5;Y;B%!3ER{`*k(lHnBjN=I%?GD$hf5IMrtBTJ>^mw4^WS=9+Zy46WkGnsNivz z3c|;>ZP|JhGFh86;at`xO`hjN_$NFCt(AX&%-sEa$L>v<42+5x6cah3Nt2|6F%gkN zaf=xF$q~ci6JjFpICoUcL%rjM4@KlZx^KR^+!T>84ZZUQ1{51mVLZBtm&v5!t>*5# zBAPE~yenUq3ZRmD2dSla6^Z|N{6sB%6OW$=0+hY5h#O#YI2)J)%mwBFh|>!Q&kGAl zEkkNqQp=HgC#iRldN--}a0!U-s|J+CHFN#@SXLqRUc-Q@_rZXwRZ5&|D6Dew*lJSC zyBbi$^YcfftlK{D3B6ACCkUI-sSx7kAlQPHt)$*h>H|CowgF#|T7lF`MQ=cNp>me) zh5_A;6=->3FR2fb`VgrPvjP1YK!6?rDYYW0j}!|7$`=tE&?DZA;r=p9dd{id@t4_+ zo=UhY{6wB*K)<)j9P?JDZd_8;>gSrbS|50z+_Ey=n|U#yxJw|whv0K$1f+yh>=~++ zP0Qy~sA;7H;T&o?Z`ESh&tEwnrB=OuE&0u-Ge~dnitDhuYz;d+iS1JvIf-Ah7E9x& zu|tN_#As5h!`wETf}}|N%U>rHylIk|t2`V$As5v+P$a*D=j%i2;~tjS*Vjkz^*47F zd|@qXg86)5FKZRb68nZ=@6ucx=G7OWa^Eljc`UxS132TprAQ4YwKl1BNUck1JyPrQ zu4RC-_z|(DCHB3G|0cBosf|nrPle-t>)T=9hpZFj`!J~uui@a;u2V0%@pTod9oU|uM zMFyqdTgPw<)hBPpE%Zg0+_xDw02}4o7-#}K0W<}k1fBw(CiN*&@!5>j=A^bDwI!*o zxI}XlwcJ8qh+(#BzHP9CRcmcpwYF^4x|KMq=KHL3gmojejSIc_8p0hKppZ!nEQx(1 z_#E+B?+f%JwH>K=DYxL;ABZHi1F42TR+P_T3%;?aob%z0h6ftHj@t2teI4I;RFlZn zzzq6A=li|{B#_#fR8V$T-kJoAG>zjkq&{05jHB;Z95PcSG`nXA^hn5~5%a!iw|idD zu5#Niw7AVQj=mGEGUTny7mdF8V&CdckE}dZsrnQMH_FSqJ?~%Oaf5Gz7WK| z5X8O^#J&*3zVm?vq`p9EFH&D5wKu7KNbO5%KQ6HdMV+*P+y{d;5NT%Gh%jj*l4)aT z$)k-=oV2lu)c&rtfjIb$h+*GN=;*EJRO9M}GWOj<>Ht!sco2LJY$Fv?CYFs;(bC3F zRKCaA@Gg@!Vs4x^_M;jWR|ahyz{)}3TT%y-I*8Obrj5e@YgcIM!K4l;7PN5!hs?Br z__`-;lsfu+iho#(KAU!bbD-Y+0U$cQ+v0oLDs#qLnMGUwOxzvTc0J9XoSC!#czG|h z@iXf9mAeW&VbI1e25k&0fHv|;SKo`yfp>}2c#bB0vKbY6M3a0kqp1{ZchRt^q`u^- zVG+jm<(M{h6?`*EP2goVsfmTtuz5a$pCN%+m?Ejf4@c-{0|dYqfGkFoXe6nlNF7b; z%cPFMu6_YPAb@B$n@&GyVLwDxULkcXsd(!yqDgB=U3=@RSif@CIrBrP0g00CBGY_l zS)G{r*L@6F@VgfsbU)4$6NTTMz9?v6K zsYL1oQjt3;_*F5j7u}5Y@~eT0>Tv_GMSe(B@q^6vs|6tJ?N=M91HdbqMCxQxr;z#@ zsjrhdmDFh;pcq81Uju8|$XfEWlbl?nPUnwg{+MN2uZKO7UK5dc%Za=#@%Fj|%zWrA zF*e`*l3OQp*RQp6K(-+j36%Nx#jiboRd~_s_Y69@J37@El+R)XI$9)E;z7^@fSi#@ zRg2tu`5|2H*Vox_Z_|45lY$)JuZkam0Dr-6@Dlu@P|ZND<~{ro4a5Mkq-vz-h1UbFR@Nh)U7{_o#X@f(3dhV}A$$(tqm@Pu%?tz(O_dg)4|x4pIH8`FCEC0S)y zz#4E4X%NlgfFKey@Qxa0_AXO-xE4_$8yF8QcKVh6q4r`$1j%DS!%S z08Z{aQsbp+bcoW5$J~)enm$R`nXyZL*j3xZ>Ny(!P(1H;*^IJmd zVprN&dV{pF5}mr5&k>*XPXOrX_euSLSJwb*NnJ|nvZAMr4XB(I6H748v-8_zgf%}j z2XP_8ntt0+5Q^DkjW4mX1K3IGa#BAcbp^A=ZUE|t0;R~8G_IDkWD)<8;%Cj+cL zCg0g?W~b5OHxCTo*Y-QSc!V{tA78#)hV{D#Yb=Ovy7fTcP9Mx%+O*85@~hLlu*UZ& zd)(@9*1Ue0!40nRs_S=nev@>@IqaZ!#<>o=bLLmJJ-^e0t*&4F=32^~g)ZVq{={Li zKDHha7X1Dq^)nBB>~{sbrkcA7ekr7`gFg04BXxbD^s!%-5Ars+IE&tFzz*a9xd4l2 z2dNuK-AL*tQa6(d_irn9^@oJ^7XV*VAN!*cj`4m@>KCM*H1zSQ|Aip0KN7$VTJcA) zdmGE+O8IY8HsB{`Ylk-qkB+T#?I&ji|8nRmgu#t_kVZ{7Oa8d4x836&q|Y&tjMQDE z?k05)skjC86{%m7YR#M}_}4^nt|r`C*1^)SKsc)FPibQ}FMG%Ae!G!7X(+g{w7l z=H4B~H9jG);LH^N-Y9KEn_+DH;XnH$;_Tm#)bB_=N-Ac~6#V-Gk){bcMk;vszb{<< z2jQ2)ocOb#_An=Ry?ty-$6q?OTKw1xpB%3~;eFEt`46?qAmiJ!OogS@wdKd#4&KuG z*qqv3aycL0jqCkKpuI%1#|`1?pJ13E=ggUVcd&5HyIvBH{}|`MGdU`sdGbfx*`zNx z-+24wBirO{Xv-ra<39;U!MZnpM8+Q;>lqJ=<3A0%ay|t|Wc;U-dX|^Tr2bSWi{r0g z?^#@&%?JdqKLoG84$J_M5AFXZsXvo?j?`aB{gu@7r2fXcB3kVKHjhBd;>^W5MDp*X z@>GKe$Y{@#_QI_nknvyQJY|ra7d!(pM&4-cIs?M5pEv5i4E?hb{e0JA{IMMP2;h!{ z;JZlbB~(u8pZp~huKy}vHGrVjU!(<-_6TWs#hrVw#yQX3btZD?95ZYfViE=97kRyt ziQnXUC-WM?s78&i`wlk2A3ECK($RwdMyx=*{7ow7K>BYny*RvV?_W2weNmr;2dH_Ubp0^L6aNF~jOG#hCGZ$+xMe}-ZGG+)yEiiP#d!y&Wv zb9l344FeNOtNtAu%qew8$m!ml_+3PYe1rhOEE51fz|;DT%PoE2jsES{ZFumT50Cxw z^H5Lg7Z89tf~|8D5NPNPEx-tr;eFH0_WZ`_Js#H2&4>ozumj4N)fh%Jpfnp%Ey(iY zS{Lfo)k45MsOCQB(IBE7P@c39(l8~Z5OBW{G}bUB>6XwOztSKpl0G94t%F^HgtihQ#G@g=D<0&b% z5;rBK5b%V>8v#v8bD5G-2zc6!H%$JxX8vD58+0xL%?51*w8ct0((Wb=Q&I{69e|Fc z-Ah`LPe~~RJcG(1xw&B@`V-KNqd%H8C1qjn+XwVQHAd_iJQILGbO6M7Kp)cXC+z{! zFeRlB&<}t-NBBp3khJ13C8ZDmUB~PbfOxkjlgwK@_sI>Fn~i^`Q`I8}=dGA%vCm+u z%n)y7vJ;nFdNZ<3la*acMPAxv=i8+2v@sm*AxLfXIEQ}%Mi{hVO-Whk9v_X8ub9;c z0SH6~j3KQOX~;$t0$w#~qsmRu2BD(q+yK+YBw#Wy1$Yg39heGCBdscF)kp(>R445* z(rS=~DJg{jR_m1v2mz9{RIsc<8YZM<#^5O_HET-B67<|n0Onvc+@pZGq`6E z4Bjo&>p+_ysNbXhJrBNX(Z*h@%vavZ9P`UO+-ZF49`tS7nxC9sgC|EkXk#DRLzMa- z+Bjg)#?>h)3)$m%W-{Ohvl<})k?4S9q&-C%-ZL%)95-pB*-g>L8B~Nwvq>9gvGNn} zGjI<01^5*>Pg--*T9DR~v{t0GCan!=ZJ9QHM^PtjTr~a`0yruS+GuCeMhB*i=S(l9 zB+&*EQcT*&Ce3w*oq*gMqm4j6A0ZIB*Px9+f2;(M28GcHgCH;nfGggaw5~;duPN|$ zR9@O_*r1KTQU+~wF(q?hZ&9E}2OcnKqdRFm zii58c$m1Hc5m?z91=QH4uKxM&u6djCLThEbSf!Ck8-dlVGLL#Ivv7*Cq12TYyFY06 z!lm(f`Q2d>RM9`P>{w{7R&WjSw6R1iAF~h$9BJ#y4%vU4=k!P9NSC zTDxzd;)sC=g9ox&<~U+tXP^tv6@ZKmd=}_NT0hbvNb65pBxwUki{f38_YwFU(9?_~ z2EKs5dyy7RS}bYvj6mXi(iYtMfyBT8=3o&5qezSKxOHW|H!ikzRPB1P*LnUta3K1J zbvEmoz$hRNwUIWESBC&YNgG7kBqpeves7!*I07{$I$L`QD+#2b!NJ^G5+0)YkhCE* z@q>Tufd{^ViY9RbuyBE|0%L)3z<2-;QwB~1h&24HVWbTwEuORyq`gF10+*PKqLxhz zeBJn42%Lsx719z-o5*h;*Cv)Yn;1C5Iof8DmgGuJNK|o&+!f$~2QENIzr*K<&-y}O z5ox1H8_lbX_egu0v{#DWCN4$g%bg8>Xhx&P7}2O3cyF8#h+ul)r(6wNKSb37ku(yx zmb6z%8%rAAUoHfG2COq};&{@E!~4sHK+f}KoA|jm`}Rxb?PX`z@6>(r{i~+y%?~|g z*~INunJ>MSnRssY$%*q@*fw--*(-bMVm$TXVH0+7uowhhd4nB<(et82RsM;|El9mK$IaI1ZcuP6DTZAA!@r z8PZ-SZ7OMS#ix_@25HHpi65XC0(OBvTgzXp<#{ZPz@5a5q439?5*P3fyyB#d6w+i@ z+DLb!jRM{qCj{pD7_*a@qaY7mj_|%pnubvjWCH}!bkb%PId237qVf=&P9DXaw-pp@ zXz3YP<@=R|dl{M#R0<`_aW!Cwpwd7Ype$)`k~WL9w|FZutAmh8!Y=sRq|Gi4S~>{Y zo_Qmvf;SGhv)-FqpV-hflcw(3^W>1$mrULWde|yc(Oa3v{yuwPPEy<7X102#UXRY1 zlRSANs507PJ?`Xu# z0Z0=GLVP-?BLHz6)R{CG%EhEDA?I+@f;3SzX)64GWKI5Zj<}z5I{oy6;!m0~w0O;++RF3@Z?)D@ntP z!-b#`KDLZiq^%<9u77Rgf<~dD@!SAxTo7W~K?r3BjRByUgCLcIAeDp0k+zz&HKak$ zd`jA9q#^TSy=CKqCZafOUC<l{gz0gjl;d5@C!sx-yNSniv0b zQ@a3Z95e@=J0G3OLMLc0Fpsp&q;26<$mXDhq-`Z_2M>ZGy{8?t7?m&OhS>@&0hmj` zDW8+JjkGU#E27*%%S_v}owP5Dg>71eLuT8w+MAvEJ!--`O?S4fw|3Bg&j(GaJIJz4 zEZw=xXWq&zU)R6w@(sd8} zy$-&Ev=gLZWSs*01Vb+emoeGrN77Cg2lffR7l#Zc2`=xAN&3{h^u_FVJKX-cIPSK| ze~y`NvQMz3rh~nz={b(skJYQvEN*R9`#vwE`=9k>pWuhlUL~`~4Uak)vjoATK5Nm& zky1<>mpy3X5Q^Mx9d32!z%!Lo{;z6UUj^49?HuQmj#5#`BcC+5E{+1hYL|S{;0C1q z>Y;;!8)H|bZy5Qc!A(dz4;>ubl(gRprGtZ;VehtF90n=4InV-V3A6$bV-9XZ+V7-Y zAngy*E|PYMv_E-QNao=7JOWJ}9NdZjCJomb1|-X19gmFN`Z74Ur}K;>RO$L;)XwTb*=WzthJ0Eo`kvI_;u4YV}^|!8kvMQ&KPS0W0I0$60WVj zgL~sF^~2d^;tK8q;8$G158>4a0I~fP(r@!n-*`U)p3Df3X%HKI-Pw17qfyB~X9F=< z!5BcQ9$r8$1P?NA!lvKMP1s=Mm;{gF24Eh8;{k-YgAv&dP5=^tBw!?I8Kh;BmPH!w zDT1AINXxa%V=&JV1+y5;IVQXui=|;6^I#cuAN~j}app02s&il?+U9UEkHN|ORpHHJ zu#QfBlg|;K^%=lS(ru&*ygCbbi*#SogNs~M2hT(0i@0I7VDkZJ_~3=4`;qQXdH`=_ zHUxJg;-d$W9#kys8bafSU1PQH@tj1N^NGvLec!>c_3lT6VLz@zNP#m&gI8E(KK53o z<$b+&j~dl!z|ziB&#W2H1CwyLtLk6`)q~e^SD`aF#ukiOyniG;#IkFJoYf|HBT8&(rXk-JBQT6-iGvsAP%VyGyoa`jR5HKkS3(V?x5mYq@&u}q}SnH zn*vV)Pnp^|q#6EhPI_I^8)pJM(K4*L#AgUgMsCr0e((934pY#T- zrCldk4!@a6mNDn?%}uggr%?fuEW1U9Lb~JUJcq%<6C;Oo#P8x|PtqHCJd_;L3*YqN zUBPT2F9N+uZ%ldQU%?0>g^VM; zm5aFxnaE!iUL}W2MW?=jPBjL>G^{}6v?0AM4}xSsB)uK!9g5uAg=naJrrEF|{X%9K z(hqZ2!qWNp+}je|8`#H#d)>$T98|M_tKsVzvGWk9?~wVVW9WAxy)$n`vPsAy)7n84 zb}bgxj=ey(c8I=vTDyun<&Qg*>h#8@I|7qCFIa*{wOMS3a1slb`N&(DEuTCtk1p5l zs|6<}j(>4`Puw|m7uz8#QFb+V6}p&JatLzD(IL+k(Bt{7-FoN1V`gz3c$@jF_k4W* znHu@(w8*YIZg;K2{eJLEVQXX|$aK+rn`vF;GWx3vD>$Gal*9dZ&te4M9|3qhb8+DwliJ(6@xV+2Dv;eR2@6!N?COkE%yQ%**dYLq|9 zRJ-2T_yL2XB8DXn>>e{b`nt~syLbJc=(fLkDDoNmi}V4!yi9r&^GuPo0<|8J$*nM% zr2`qHN0T1It64xc={RrWxXpj{n)ksey9q&0T;+w0Xkny3lxnbC#(3(Ik z0D3!#^pT{G;;nUnx~63sP5R5l!7_z5!6C!Sgu;dJv`jG_qQyV^H1k`yW>~)~C(dZ5 zWeSDMV3c{`$0cF?P-}pTcEwx<~cI7KxivN3%p`krs<=g z1*%|bu71(+Q6q;T>f9-2_`sw=ZmbdtIUm}^s)h|*XlKK~jV+*>|Ij<(LLtLVmBs|; zI*5CjU%^C<`F1RxPeGHqb!DEy5f{08X| zjN1(x_$BE(Z+&MmbfR?@Ly7ccHi9m5MVSfrG2yYb8-`ye;VASq^v^W(v%x~IV+FNI zsE}D`I)ILoNngq=G}^_;HXa+B5IHP7BLCzZ?Q!QNVR+=wh%UJ4GAgD`e8RBEBx~iF zgt%dGytP$K6lM}lh=}MuByI$k7>Ii^(Q%29iHR}81`HkZJl-Z9KQif`IY`~FCK-pN zIS*OEib}ddy2^))_vY-vszwv4{cGzP`Zg+B#0{|ZoDD$BheE=KLc)h4ZXSxbc_`xM zI_Wb=pGo?gq|YM#Ez;k1T2EZrhSh|_V=Ujt(y*Sh*>KL~kM~QS^<3o~va3mVeHmrw zr~Fku_i$m@)o5sq9bTfLp__3IKIfCfr+o{smGpU}^ZUF*w*g;}zJT<_MQ=WLq4KY| zVK$Vzfjt2H01Svlq`$*kzXrZB&F8zMzgH~GCtpQuK96`ag`|Yu+PBuKEJoh9P?J@qsKa&JKVSPE7NCn?b~X?p;#~G6Anq}kIr*+(hM9gF#^XvLkHo6 z$5Mqi3Jx5Ho$OZC9|A_Pzq<>8MO42_eeHH1eE#3&T zp*XZ)n6I_;$I{@9HB1?w^2fFk#~Wd#EZzt!P5N3F!4g)^jW-HNX$-p$om+v=5zczp z{lEjHe@6N`UVRY2&4~4+Z)Dmi(pLtS`c8t_b5Eg&4IP5LI%HFT7sp+s->^+Q&Ln4O_1Q6s7Ly$WR zGCK_FIt-rwSEPSU`ZuKSBYi*V2Y6SA?XY-YgsG;(psvHm@8X8p z=6nh40FapS3+ca-exA2N9fu)g&e=r2k^XzJutW!N$ZUxYdb27s=G`6j{@|`vr<{Cu zSF1Aj9n@*qp=JGrCq7F^?P9~bA>D6qgduJp#sPh{M4U|&#!1Pf z|6y68LOypIb_OLmS)Hpf3>vbXx{!Y92CMlU)m${I5yCEDOBY0h=|Ke)QL$kG1Vp;n zC>F$uqJn@O1r-JUb7y9Cn@KSFz8?*IXD2f|@4neLZ_YjM&Yd?X&a}aD8cToH#kvmu zjTz&2ds1<+|!)&+20h; z{yxQX`aNY*1AC9l?wOlcI_{HiE#CCwe*^04Xtp@>hJOd<4FR(oUI3kq}7&ZrDTr-blht|9<`J&v|^fOK$O>0+a!_lMqHiI0+G~hF|DZG=4&{ z10mYnt_b@&O0Kb|R~P~A<0#F}%`VM$4+Zzh?U-MfU0l}Rk*$Y-d6|V*8rUne)w^hN zZ^tA@LGS#++p?T1T?%o-r8s+Zfg>wxU{QzS;_R~P29%YQI>u*ZWp&CfEGlf5Wu4|4 zvToxeVr`b_@5n1~K0aO5^5dU%#;z_WRkU&Br2}vX*laRtCc<{o$h9$%@bBXi~WNHae6RaW{^GBv3 zC2CP(vj3ANHTyqBLL+xVU&CLyND1~GbuQs4Y^m-KK0@*S>(RO!(W<(Xco8cbNN7Sr zQ|<+ufR{+Pl7y>kUP^3(@tsD+hLqUBQbM@ObZo1BLSVSrvC0C&{;$Ifr|ala05;52^klKlrW?7{ywAgC!@l)B{l5x+q$=3sJCzFXLXH{ zjQ>aYnJhm(_9Z|14!Ldkrcphmb#eEEM*Cw@8LyFy|EDPXx!K~nl)yuQkP_zfpMF(s z@nbOawPD8MkMW5A2@+b7(3*S9H+tkkXj7fYh5tzyI>Qw(3t&9rk70;Eh9UkKhWKL` z;{Pk~8wqVmxQ2vlNw|)L>q%%w!VTsS#QzTzXWlqxECaC6haf_Gri_mK(Wll8K?0Bt zqz^#?t{|a<8*c;zdhkXik&A#ZKT7~Vv&ys)fZ<3$1PPr;=*+8809;%b61vqmZ3Nh1 zJjtk7r;UI_oi@4}v{BVid_WVJxth&@AObKP3BV{M;3^WjlhA{Np1c*&`heyJZS*3c z_r*XP0j+Szpnw33M7;B8<_%xDGVSGVb)U}vcI|;4562j^5pa!J1|t#gGIy`J>(<{E zbV*l&d)-_1)BAWb#4`XA&<^!=Fk75yBcQ!b8+|KjahDNDKsU4F`4hB|d&ld=Up7gQ_$h2^fvN^SL+%838!}#v%b2iv(aS5-QvqcpjNk!?+bdi$)AZ+U^IE30 z$;+!iNCzMUA25yk9iJXH#mng=WO+Sw5HJ(p%;8;`eju^~AhJi1kj<-e^}EBu=<3`Z z4p<075?2716mT!F2)GYG!g;_F09rRdBq4`{ToN24;KX8Bik^_qC1eyerEGwv|7{6i zWeh2Mt083z*d=ok1L@mYTkc%FpuBoy-M zT3{UsMI=nD@nCuYWOBe3u9&?B!uA2kXbE_kgb5_vMnW-f-3n|od`Srjr5A-SL2zI9 zC9nDN3+w&r-Z135zQMCwE&b!6#k)v~k;Y%z52O#=|$zGyAsLvTszW)%GkSniS(!CO1B?&QGR*5B7 zuY_>CA%_f}a{cNn=U2x_n94VZS6qd=X&ptLAkOc85kYz0MgF{T)DFN&xaw0?q;FNq~2qLBdQDW|05}oCB{D zSO>7+*W?*qClE;~>~-dna5vhToz9m3g3}4q1uU905OKhHUQWlD`04Mo)q5O-=~xK!W1tsscOnS5vnj~569 z?mZGZH2>9|pgqmpunjxql;ngB2dPGcagA)1f)?~0;e0a@mRHJV-5`6 z%f|`58aNl22OvZoI3HL5+yg8m;c*gHlkfxyPm=Hy2~U&o43}7hqRBceflJJ#h$R&6 z8bjee$F#Az)+yXTgsyd!5xAU$XWeN7!`=&`jn!yqWS(8YmJ!3J%-jFm0GRuWz$VFL*pnKrfqI}F;`L;_}9 z`TxJ`H;@y?nKs_=MFFSoYrn5=;~wXQKK*;m&OC`c8GfubaIaZrpRY1E{61;W_3b(i zn(=7&M?QLF0-l)l47voejRQuD8?=FR7RcL|E1?Y+4I7AXF?T%Y8$djT2%^D(hfxDd zS7!oa;O8W4^OCNCN3bgtG4E;#JW9fLUP2k~sFHLIgh&qjiHoxyMIv|Lcfj|+55SMW zNfLIFu#1FONZ3sRh5)bet_b@EBJ3M@+LW%p;s@oC@Hz>5NF2!8RUGtR(5_b2=lntz zYh9oo32%__rtdVybo|Rj_Yq#(U+6r%M;_vjYft8*l zd`iM++zBAJt$j#1Ou`p6?kKJOVSJFY;sJ)EM4}(->z~`{^mR|&%JsDs5o&7|n}JKT z4hKd6BT4v@gd-#z<*lQDY{OB0MZ&R*!BJW{O9zh9is-nvzLt-r9r@|XE&~_JhnqHN zHvg8ue#M7axAxHn z(nNH9ZGC`*U)*V9`32GjpBhA+4cd4ND;VtjM#35H1d!WS$nD=rI9v0yfzY+p3|;GC zQL8>H@^VB1daelfvt}iQs_%5(AyI@ePVI zZG2}gf54JyL$vZoFn`3=KHB)*NgIEV801bH=P!&lg6jKOf*SHU!dVY$09;C92#KM* z3S}LHvtlDre+_tzzG)!{k~}DsE5?-_1Z^G!Z61W0!$=G#F@m?+fH32Fk0cQe^#6ao z2eCZI^&S-G>)QSLl3v@Ex9NNOsrDZii9uZ#8`pbKf>|cfSDF3OKRo)yyY1gwv2)0o z_0w+u(OV`2L8u2ccAleDU6_eTkbp3=1U13=&Lc6_hcF9zqTFME5!4(dSg<>pBPd;G zj(CGPU=3UiTa|EiP#c)J)_Fi}v2qQG2_)i$;+CN64CY9x4s!%`grS~X0hlAG6VMsx z0(1qs0T9VSJxEL@F@?lb5*v}&n8YR|Hsum5pUr??P+$FTOVEv2V#h1>fS!0YGe?_R z7tjm3#bl14;Ur$=#vDP=>=!al3Ccr5Lo6H2F$ODRNo+=9bM6GU0^>+bBQc}K1xFB6 zbC6Rt^FvKRP|b%(OgG)%>!Z<$r(aoVCx&Vcx|5HesRpV!=nh~iiJ2s}Ah9KHy$hIT z5Kt=;TVE6eGzW*w1T@zdnGCzdaiH@pec#x0@Aqr(o%NMDP6?WCmVt)%7AZ?_IzRl| z%-NNi7H2NFAy*onl>{0+-zCv9-3 z8p0#!87x5?m{*e-qZ@zpuYI(EBx`+~610iLuI{t}&3-|&u?vmL*&Djxcm*rFN$gG{ zX1TNky#~BaVowrpWZI}%!2#7A#Qspf-uGkWE#Peudy&|i#6H|r-USf2#$%%*^z=nB zFJ=%DruFOn6JOVEyY_SMd?ctt9u4R_dC2akkRHx)iJ;HSG6<1-U+>ey3pRc_r2FVK zg9z8v(EkL&$Q*!YT@3KzJ}u$cD*3~SDdS?812c}Vwcr3{O3c@PWsKWXE8oi+xT zwDEUlT)!E@WvvIEgMLRf5W<5=9KzWyllj;C`6acV9-;r?p@D+y z_*sJM;v3g{2f_77yxHsCL2v`?%Ho*s9Ry!W;xJxfsDjsgXIU$qPBSqG>N$+ zmh1NpmXdfsA4Gh9E+&7=&&zidm-Nf)GG%Q3=={=>9{OuXCKMHyW?91>x%s6<#dun$ z)X}l5$Dg}nnvoI*KYQfJHH-cAT}hTT$zj;~Ya>sO)iuAkq_n@IWI|CPKSpJZDeIS) zSK=uBo4P}DiV6y{C*awwzs!`loZeutt$uogq2h9U-!({cw8_nBo$DH1_dKHrTnFn> zZE#31#B%VJutp-!Y8i}#kzlA2NaX2EDb=6+AUFdSTjH!Tfdyv*Pzz&79LuY%3@?^n z9WNGq9Sn8m3gDB1uLs%zHvsK{4nRi$KI>Kzp|J``98Y2)iA5w%;1WD-py|beyX${j zf>}$$i``~;F}%W?#Jg&p7Yjyk+vsheiefi13D&0{T*;3cxq=@((*JwD5+QgL8ajv1 z5uf#J02gN|i4%D>7jTd`iNq;2E`Ecdtb-A5{*#)63v_CpY;tN9pXd)pW=HU3HUqa8 zTnbDCaKvRK-cI5jymbmtW;jEr;yW(}@f$oHhs;Duz8qV^>GQLX)akWbUe|x={`QVx zhBFMFWtN%ktIRiFbbmJY)js1lZnPhW>(IQVw=)bzd^=bVexr#wSu=RP?!~5EV2dwC zNlq%!d(0B72qY4TGq}e{ppC0YoLQYG7K4|<5Rx(s+PEJp4*(AW%YfwoJFkaGoJHbn z66cUOm&AD_-c90sGujsX2#Q1W20PbTOY70L1;l?gcx5oh05zqFm$ZHyF}7cn??1m-g$x8^D_+ zE+%mai2`rk3vkNE)g+1}N*Bci{~ivRFZhGLF5da?L@ZeTcDK#57w7HSdNK|#4rTQl z{GnL}v2Ablo3?V-&wHBpUZI}Y(RszStuUtd9PI`lf(n-v+s5{0OB|#ki-=vf|DL5aV3e5khqF>g+va4L=Fit^lu0>G#Xue zl*GqLd_~v4yZ;NhGa>QjnF>J;%41&gSIex3b_Hr`ImPvmz}WGebqX4 zQ!nzzj#}rdLJ;lNulmeTxS7P4dFxmJv1fKwTS(k`F}SLb2{>f9 zs*u}!xt*4ZrA4nL9d4PsrFF!pX?vb9TvbS^S!SZIGJ|)n_-WyUKAYxFUn{)VscELS zs|tZe54poQM|z+p_ZURO_xPWTx(_c2;60%X-~V zo>IG6kIr3s<(D=y-Y?SGoRPlSjgB$dB@;{jnos*`GtgkZfyBkrg+O2%{g(O5z272Z z#P|xr=v5Bz%ov43^?IBsM8uDfv7PtkZx_9vKL9jE4|@`yl3&rY(2G8SAF&zOlZ@o2$SD<2$hhR z&{SK{%sK&W#>&eizDMFgZt<-Er1SeE{>%h)v+HCunJxbAWxqaN@7u>wP}Fy5hY1s! zjV{V9Yv%Q)-Yjb~H`^_zVi)Y*1yQ%s0tdf(p`>vWmy}k|U-1f#^fl+N*o~D}N&JAs z5BXO>hljjD;zuO@^v``MLfIkja|HEpFJ;BdzLaClygY=Z?n}R5H+qCWeyn}I^tiJZpCA!00e7XVZ}}@1UmA+= zqd8N}C5L^?R1@+uTJ;w`NqpK*0jEhkO5#_%`YZ4oiN{FP=Vz_ayB;Cu{4Ajsu9!LM zJXUbzp>;?+P9lER*Vr0b7l6uVXZj6^-(C#PH1u*DGMs7X6}}u}a>BONr-pVJ_vEQ< zrB4qn!R!`1?h6ex%V5aiJ??ueWY6SNpLKcX$*Z3DU|Hsj72eJ?6cPE*FykEQ&NS4f zJJatCFK7vk;N*xOyqsxJVq1@EJ~S4V?4~6S8HL8{{`6!ema6GbJ&&RhDsE~Vg(b8x zR*)WXip10CbD^y8!92fIhj~KNVW=%v0OkqJ01yoiZ2>^uheFkdLe+=1A@Nrd(ZA1- z_&bSzka(8Fb0+hIaux{~CzJ;Ryku3cGtYUDj#P&~{A(Tagd$w8`_Ir`B>A~9PpB^N zU6^Ocq(7M_V!aRM2_1x19m*$(Py1kC2uT)_>hdZie&{fg>XD?+)m)?V&WC2f_-JRv zqx3L}gsCt&Ybg|=b0{CFzK<|UP~ERQJ90is=rM0*t6PC_KmkdYlGKo-%Xn)cP^5F1 zbU8^^TofFJGoy3ZWM6!A>FJ@1e!Q(qn>nv#Ph9YoyxZik+s!f%_1+w|r*of^i_Z30 zRQ||_pi}8LJ>`SL?m{~tIR2-S51r1;BLz5_CkGscX7^0+a`A1UbIs1ja_gXb=X0v` z(0fQi-eJ;K)WrWhPuP7piY3_YD#b$ul0v+sc&LnBRby96s6tXG#C51flC4ToJQOkR zP+SeV6c0tPI~2k0(B%M|;hy#|Nns>~lN3QxBuP;uMMH{*LaFmSo1x$#zQr1fNH=%L z7?R>h(jU)~{u7U9g+6bd&CnM}iuE00N>6JudUUIn72IJBeGyHx3C*mN$Of#yT09JL z3qz)dZYIf2lJ{d&#`95Wj*Og)T-WEmJUh%b*x2c`za1+(NJ=1y6AD9jVK}##q$HYF z`j16&=o>J^mFlkQO|0wz5bzG&2S7oGLO6%MO;R#RDI}$m)QF_UBsC!k35AAhI$$ml ziq>7#2UxPJl8{nJ5+@W&W7F&Hb1BYaTsJ7Ju zE+HwCq!uJ`LZPhzaH-*@T9JgC5C8v+W}7LSZ9Zjl_cP~vd@FaqePgFt=|b-2rG}fb zh2UpGp4%{*@OD!Vbh@F{s;I6HZIZUPc)X;zzqgyRA-lyEWwtmAWLu=}rp$!Gs^%fv z>?oOJn6cOru#!m9wIp#up)J{x--5o_1W-0G{${4uLzOMmMz<)QZ7;}@^0v)IS=J|6XPd>rRUXINX2&alpe!Yan8 zZIfUIDJi-coi^}-ShTA%q44j_xTss(G_&KGddT&wna(~ri=@Gz8;FHM|R2)3$&lyky%$*VyjGH}@I4T5O9*x|w%{m>E_jb!(Hbw;rd4RJB1V z+Y~?rGyp+t+ftIy;f9kmf~1ioWsx+BcZDjpK@8iL8S2)?wLU~rHc8O9m@)@}<_Abx z@$Zi`+Ym};jbX7p2|NWn4Ln2AXp(YB$|VUmz!6q)4dG^FOdX${Uzk-~Hu2W{!YNrL zxdoL>rS4ul-6Oi(->}oHq%^y@wDDwQNnYa`56-go@(zAu#;ww^6AQ=L^NNb??HwgK z*%KhT?Co>--RzF6F%z?kv+;sbN3I>Q<*VEAXS#9J)->1Ok~USZwZh}~?33%zLL1O0 zb-v^#dr@zzG0c}6flVZhC20n0?e4C1WwxA(3GNFDaz|%PEG)!S{JB{rW#dN|6{NRp z(-xzL3wV>N4QVj8?apJ^ij{37<&$(PAHxnmOC3Lw#?hj+|5)$aknUo8iz{HqjWD|n z0{|Ozzikh&7uW~vCkau6@gxbqb7#*sHXfY>z$#ltY#(91ORRp!AR zCzL^#^*A~I@QLqZo8nCmUdd2lSHK335cnL0`5RHZX?hf|&fcGK!t;pAd_?g)NGHsO z(h-Ik{SI?jxbC^h7-GQ`;!-f=8JF@j69+R1&ZCLP3Zf1(Nt(q6mk8b%Mbd0qwErLT zMi|26VQE|eSRkwkfDu3#gnt->f7sPPGoU$1b4Z#?(mayxCTTuN@c#FhfQ5DPW(lTmU*9x8x+1B<*5|6NDAukePiDiT57!`~T|S$+58K z@;Qlu(lcl=kNKH>So3okpE)tD<`g%&Vt4n0PnY*vbN9;KKBn9aD@9p^&;JzsVUu*) zSZdG)S{<~3Hut0r7gZm2r`hpX=8SRgcnFlUc&zgiBEVrYfmy(8S^zQfAW6$eT8>db zd-PoXm(+g7DCZw9>VLS_;*5-&wRrN@A{btbLL3nPD2ir%4@Dk^PWrIdkRc43KTI)p zwS=KRtmIwM2_C7^kRj}T?ENqo$2cGiz6UFlYg4j=y^fZqU+PNv+ z%&A!uO2-!SJEC&%q*K=9?EKOS^=+25y_Zm?Nh5Rg5)NpJQ_$BUF?(;0C8?(x_ z$WF^{QNit&u&>ZuC(z8g==uUH$6<~nOrU59`x^L$q%91^% zVTi7W{p73wQacP%dn-wJL$xLBXZ;yAX?t~^VGBFsX9>4(1+1g+fMyu|A zq6382A!!FmJ4xC_68hq9lF$=hLy7RZC~A(s!t3jQTf$k%rjqo!G5&g!b=1LHH~tC_ zVQRod8y-rM`vbAz+@=?Bza<=EIy`~T5zcyeJODAhhorr{ng}G3w2!2>YFtN!Lu7|v zX;iF71H+r@(ZK!YU|{!a-~>$N?CI4#XfHe+W?HftD5h|vpM)d*Bpi2Iz(Mbj^e%60 z1++GF6jChTyBKs-csm?2G*LKGUA%RaBX`B_?)PK&%vi!9wZkE` zKP2fR?lE}%4c_}LeOw*d2uBn>Jew4=*O4o8~G1<}Tx zXx!;&RGl{N!pby~z9Q)ucLD-tkOX)2br(s#TS8a!M!XagasA1(^ocmRjYwDF)X3fSKD#K}85^|);A;=P&C zt1mU*-y6QdEQ1E~rkdvMzwfm2)sBxovnstu))VQYe9#86WWq5J&|6%mjYoCbI9Um8 zxJcRXr=1<|8IpeHn<{Jg6nbgcaOm;ywb-tw4E;pYrm&BLjy&z9VZ%4z8%{>Su9onP zB>lom$fIAYq+!FiVsBjnLzsqd1GWP@fSmyJaX6&NZzLfc_&Z5|kaU)$bG+-T0K&@Q zuNxzzaA@IhxXbe-*C83V^4F8xhUB*Yeia-3p7Wd?BpK<4o+8tj8#%+#!jYX>fr<_P z2o1!U&V;DO%AsMf4Th2%HkDhA_M-V&wG*`g>>w5q~ zI~@8t{3L)Jmhhi}QzSPa`BIV_l6)D-my>)2$^K6N^(%_A|2ktXIWdL(mmI(!Jnf+z zUF*V!5e>{P8G&XCbn{;km-AN~zPQ8$1`0+l{`8?f!iN#TewGLupCg?0h!7x@5l=Gew~?%GO~95!-SNmcjEIZD@kBJi zA;a-RH1*{~o;{|K{oRgxR~%gb(Bx%D$k3}1SDR(<5UIE0Irn_aOOF?Hox7(0y9<t88 z3?w;$h2&I{8=15bF$Bdy8xb6z=H)F|>a@Y{nU6rr&j_v%3*~1YUb|ZRK|zB4)wNJT}AZGaHx#%q2OEi+x;V zZv^kEhiN{B=5g}n~atw)YhPC-%0#A1g%DZ`#$X#aCfe;$@?;wjd_`HsnM&%oZ2 zUs!-_@7xg=BC#VrM0@C>pBo1w0KFT$O>z&tak}tUX#a@MfWsvBB-ueSF=@I5vNJO{ zQl6HRnUT?IbOmFK2#ENIW5%Uwi8zXtuSo7ia&Knk4{6B;QE#O(gdxc>u`+ov!&e6la&r87I6vi>2ldc2xbg8uzZyO@5=ve#)7)2?+aupk4tcWk;Ldp z^pP2;ucdL0^x$12fkUk@)Bc^&pf?EFvf9EsN|;Ofh* z#FD3(E-=&GFk^}Aij{68!&Pw_WMmJ6ImT9pIU=FqBUzO*b3{VSM?%a;_6H#5BL@P5 zfWai^lYA@5<47(bc|6I5Bo~>?5owC~NEY*8j>r*M>dY~LNrR_xl&94`<{0Z_4z%2D z?#zK46=n`gB$8AD5OOk>Bo|Y?EaP+fYu0(5U7-{^PIh($X!%HJ`BIX3GRMd%KpDx{ zGPUOU1JU!y8C)?l#WY|#KqOBlc?!v8ymclp%ixdONxtKv;149b=v;7*FD{5}|H_-6 zz1VHptQGGrKS*?&$sdc%GWYo^^U>YU&TsKf#|5*0`Q!ecWqZE#!5;$J0eW7)>Um1y zNJ;09JDpd(%KU*;QIEIG1lc-zp6v%vc)4kb)qUhLoj;~mV#(9YDwKTOFk^}2OZ+jC zXOKLTJI!i?KW0^nKi0qyCmQMe@hn!J1D*$70M-KQ07&}TB+nrkBe{7b-%av-k{9sd zY(P=-7JB4M`rnqwm$6JG`5yfix_mG5hnb34i&B^)Uvu)u>m)C9=Z`%GfBY3otVDUd zi-tbP=ZMex0pLB77m<7)uf7j_K=NXeYd#e*@(_$4HYzsU>1X=ou*BJkzu?P3@V*?% zuJr83$6)Cjw#00695?}dO|nF?OfqL9Mt%!?XK;{8@T=);09WUOBrhYG(-60A zU(Qt{4Uyxb`X6`vp#R}AdaITj-w!sqaco>29f+c$uE$M;MF>k;pbi?d4nm8 zqlTh5cd}vTayXW{Fy6>M?Ir%$UF(E#)EH-P8%y#gcXAoWU%B2StJtwc6{B${@;TzO zUIIW5Zzh>D5ThmmP^eo-)+c|g(H#4zsW3jxs91MwQFrN%ZL8tf>Qr%l^QhS{b2pn| zLY)K51t5^Nle~lEoxF8E042-O?p-8fTG{{qv-nYna?ZkuJ8isvfwb`!8uwjiCwLnx?~r_uWaJrIq9Bi>Adex5KdteRbQB`ZQJ-?f+zm1C zkNN~aeCb1yKO*^K-uf8;$;{XLCnO)bD6V%7UGuej+}E}1w>;#s#Us1#UbCR^hs9m@ z1)0}7i*+vZt*&nvd#B88(Z+_zY8Le1bA4A-yfn_opYAQ{<;Nm~~h zQrC5#%iW869A7kAC^`to$13>9DVlp8HAM%Le9TJ)N89jCxUs7x8bbLv?~0i5i7Kh! z=osvc2(PY!qY)8~Mj$vEf#7I60971~TlN@FeM9oMB!5Tp_ay%S6&wvBiiSvzPBm0; zG*oeP6Ow-<`4lNuR>4XTDZ&4K6&#(xrwW%~bSBUOXi4%(l7Au@8G)XU&a}Z(=Gmk9 z)kXX$eb$8RvVx-Q+zRhOWm#|We#9R0%X*v1;yH{aAb~6&_q>V=vkUN8eHI>EpO9Ue zGd62-QSrEfqM`}zJ4ue{pDug=k{NdArHAr0mqrmIEwf}sIi0bFWyZvcrX z(U9lS{Q#))XsGgN+|4>e^6w=7LGoFW&yjqd6hAI85Jk-pQ}hu1Z%Z_XtW!zB%#HA- zN?ra4FkEUa3Nc0JItk1{iu>*VXgzvebtN8MgoZBWbHrzT0&p8C^+@5I#b^lg=u%SZ zlX59{f*Mug(Pc0`)u>qa6VV7hA0nke#SHJ+-Dkkc9Ja#O|4d*OFq@Qyq+CYI<-8Tr zJbIq)n3XF?@xK@xbF>+*j`kU@eyY#@gLTvT9^Ksd+>_tXtN_C?M+^9w>~=(7j#(V= zjPlmE-Ctf8m-ouh()Ji`c!rmv6_hPE8=PHgG$L(%NeQgD!Cigga%Z<=UU7G+=yA-! zei#VV+200eOAR&hmnq(qPsNlFwc(WJ!it~-F8_z`)g zU){}rlM+ixJc6R^R{s+-J4Wj%DBPrPlM?5Zbdq5{Yv{;MZ|$fcgChDpSoi?Vtn&*b zd-VG-M~a>K1<4%IACZzk3bLI%QZz7y4N^4H(@;Tnb_LHGMt=$;pF1n~3@e98NhBqS zEBHdso>Y>nlRX)Ypmp?*TmkzeM6aXqh-CCP0OHos-vQqPKai3_3OrLIQW}%egp{VF zT*)O)qG+-XOEgE7S(p8SCHB3_@M6u_i?ywFUM$9fD~A<&OkGm0c4LW{`utVZy;zJt ztXR>g+{7-=VxEG7Tt-=@%+UpfZ=-HD>1{@iluHMZzf{;Bq zuJY{37(2{xCt)`hlK>%_6(r{xj>G+v&V=++e-gik>G;KWiV{3F>qto7;X%$4i>Kb>CTvTFw?<#;t=JIX-~>^q+HKErlUa{?W#i?G2LP4 zMy>!P5Yq$b2|y9YKnTY`2**GO$MhrR22xOU2U0qc(utJLq;%mDH=(FW8!?6uw#0B$ z8?@2YppEWK8v|+|ZDc!XV>BtqhIA1qF^&tQjRG`uk+Tzw$4Vh7JxJ-vod8-m23oim zDSc|5HW1^EDRWjl*`N))XW&9(0J?lo^3OyV%+n|k`NWsJ@ z|Nk&_3=%tZ3Rvii0{ZSqy=KC;t`k>W`*oMWuiSu{Tlo>?7${}E%wk_ zo?5WSIxMW+B;9kTRT<5u}VHC5v}OMn}wg;6+2a#%#pjn@AZ&N)9Q{>)I71*Z=!NLNPn} zRPj~33wVW;Y*I#hYuGk=7Vzk{>21<-T&EBBl%o2L)HLkZI&ZY=ejbCDm^V<_KJH_D z;k^Rv0d}EkQgU$&ymdc-D0U1)HOB7KNYR*F2D)ZfXJ$^#E6yIDmNg*j#;i_7#g5+j zqqB_pUb39eC-!lSACI}dFC;P)10^2gRN^rQu>vKYM+#>o#(bz}6e-opNR0UmhB)G^ zd%VL~`5gEH_!2k*90k52C7+aANf}2<0V(520p}tk(Gr6o^`9P(gU}GlF-QwxkB59j zc6P=5acAxGc)uCMV~IIKihD+4%vt`b>OwiTo}VSQ0iPqB_1H^*`lOVQQp&5B0*IST zBn7W@tKp{;Vmv*?)f5MfaK5YdL{{uoFw@*HqkFtqJk zS>Ps=W0BC}MjL^+6Kg!wO!Zd!c&a%z2Q7_=m(eG4u>$Y4kd%A57mNYMlCp@D#Wk*! zW1-4pCm0p$Vd7YQYHtN8khl>1{JLC);aW8Pkm zCrWRx8QorO|G<*sjl)m&`3PfYPo*5Y0QKE#ws<|h9+A}n-cT>F#UZ$3O~Gx6m9Qd{ zQceo887;A@Avf-?P6Bi6gD|v;kCRzo8L%9Hkmk3>#PSJU2|Pl|1Ef4i$}&=xld^)8 zhe&ytOFW9APToLJn&n39lURZ`RvNsqih1MN+Q%E~nH;zwUnJ!bciuooiyLoL^3Ijm z?Xa?o&k>)K9l%af9wp^5UWGu8-A&5lq&!pea^p=H-_I3uM}Q2E-3#m^1%s?7NO_XC zLWaj;c*ocKQ=}k?_aeC7S)cRu{-LjH_l?JrQ+{dDx!L+nv8ce4h`x_~^-?NT0Hx`dVm7KPG`&RuAoKU|2 zfE)3gyEzYG6KCv7TeJBF0) zq`X4PS$({Ij+FEN{_%QT3ZE)mlyRv*BLMeMc8~(L*u}&4z25m3=`CDF$pgzKIC>+E z14$J<%*>0d{&?jt=0VMJ`R=bjyWm|{#YKhudflw7fyHHbM{r+$)9q^~8`KZJ!(%+F+fJd|WwO!61)S;xrF@AJGKHk%1ZZfx&^(f3M%F4oT z;h#}bVQ|1BRlKbp32|h!X^~ygi`wFv;nZ*dpZPov8AWkvI76iD=G6=!layCU`JDOu zcDJ9{(&Z=qbsGLUTgFVbX!`NlrCG*G_w16frA9mAC*7D`T;eFk4jm`vjB`{xU9RVq z-Wo@Cjq|A6V5Kc7uaWXPAN93*%DM7JbyCjbI>1m5t^mR!t|QP1z|bWQLzlR&KsTT} zDQ}VjYTHW+Jkfqq-Xi5~Lxx!5%%Mvh4_zQd;`(99xueQE{BeLkJ~O09Ro?heVKU6W z=XDTq!%PZ~Lo5?-`gURWxRLzTN|$+=E^!WF^hs7cr*)5Wpi##`s(=ZCju5PMbM*&V12Z zip0%AeLQ?&4Z%-g#?65aA>~t3Lmb(L!QR}Hl@0dd7NR8IFK|kcxJ9}YIedX;WSG$m zGnP07D=H~pkn$z>m~uVkTscyml=HadF!UH#z_h`Vf-Q4@SP47=un2%$K1#}0q#PsV zI4LJc`I?k(oU~z%T;h1-!nE-;mO5>G%Z%|ofBatiXk&wuHa3#-ojYx8_MnZxH=MLV z^&asN`H0(zR^9FF1-q~U?S*WQANgFp3c!(^B;{0%M?T^(Vu^dpsMxp|_UjkJPew1c z#Jz)yLHXJ1Vh9Qx@9F>Ehoz6%68EhS03_bTA@SxkDZh~ND{n;p35=eK63sDEoui=p6ir`(CGxKPqW-SI2bP+4-Q2cDr}JGyE0q5!N4q^bpKw zyn7&7Fe7Aln%2W@M~)!tLvYqtu;Fn+sD##5|5Eed;}K<6~$x75|1HEJccas$ZC%d1HwtIN9rY{)+ZH5 za4D$`c~?C886O28e$LNe#>e6Z<&kk4ii#v@oCZwBiv@mFI7=5UrS2g}5#0qLX$kgDfmyU%3Q%2`3%7LE$i zZ%t|-saCE4VSKy-Sq-YryG-K|#*goYp2E&7zC8d@9N!V>1atksiCCWNDU(u{U^e7X7Mbc;l$!iEgY|h@!`VMNdAcCk4Cl5nZ-N9`0+QB z8s$zC!@2WST?5DGpmFo~9PwGt1stTtkjfF$_%Xm(QsYQXu5k?M?sH>MHAu|96ix1!rKGI&p>^%jdP^C{rFkz_SF>A1I5pU z+gDS)-Ts3`o?hY}SXyLSVqX@2FZ(jJaV3^K%^-FkuNr17@zBKa3aL#=y^=ePW-!N9 z)nX3B?&FyPbmmx&6?Rckf)3K;d8|2WhbzURCtg!yt*4epKMF& z4K>dkdth8w!Q2@jiR1SH`$@fq)N4t-j<-Vh#iP?Qb6ig|y_xex#AThdrs1N4&9QCng z*3Z!wdLUnIuLtri@pEy$p}$fq&qa<$dV4(Q-8e_j@!#sS(XkTRaFM|AKRY`fR18Fs z>sP-zzxs{TE*!zvkn(|lo~&~gM{yq8S>nFigl7DTer)$6wVRj3wb#Wr2>$S{7CXdf zcV5;fwMUgCt{n>59>m3=TkV$vR{;J%0DyC7x02eE)Lx|aCbbW#pwNE2E7Y(ZYS@nB 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 z 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