diff --git a/ChocolArm64/Instruction/AInstEmitSimdMove.cs b/ChocolArm64/Instruction/AInstEmitSimdMove.cs index 95fe59499..d67946a97 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdMove.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdMove.cs @@ -339,9 +339,12 @@ namespace ChocolArm64.Instruction EmitVectorExtractZx(Context, (Index & 1) == 0 ? Op.Rn : Op.Rm, Elem, Op.Size); - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + EmitVectorInsertTmp(Context, Index, Op.Size); } + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); @@ -363,9 +366,12 @@ namespace ChocolArm64.Instruction EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem, Op.Size); - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + EmitVectorInsertTmp(Context, Index, Op.Size); } + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); @@ -387,9 +393,12 @@ namespace ChocolArm64.Instruction EmitVectorExtractZx(Context, (Index & 1) == 0 ? Op.Rn : Op.Rm, Elem, Op.Size); - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + EmitVectorInsertTmp(Context, Index, Op.Size); } + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); diff --git a/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs b/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs index f574b46f3..2860dc2e2 100644 --- a/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs +++ b/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs @@ -20,7 +20,7 @@ namespace Ryujinx.Audio.OpenAL public int SourceId { get; private set; } public int SampleRate { get; private set; } - + public ALFormat Format { get; private set; } private ReleaseCallback Callback; @@ -153,7 +153,7 @@ namespace Ryujinx.Audio.OpenAL ShouldCallReleaseCallback = true; } } - + private void SyncQueuedTags() { AL.GetSource(SourceId, ALGetSourcei.BuffersQueued, out int QueuedCount); @@ -249,11 +249,6 @@ namespace Ryujinx.Audio.OpenAL private ALFormat GetALFormat(int Channels, AudioFormat Format) { - if (Channels < 1 || Channels > 2) - { - throw new ArgumentOutOfRangeException(nameof(Channels)); - } - if (Channels == 1) { switch (Format) @@ -262,7 +257,7 @@ namespace Ryujinx.Audio.OpenAL case AudioFormat.PcmInt16: return ALFormat.Mono16; } } - else /* if (Channels == 2) */ + else if (Channels == 2) { switch (Format) { @@ -270,6 +265,18 @@ namespace Ryujinx.Audio.OpenAL case AudioFormat.PcmInt16: return ALFormat.Stereo16; } } + else if (Channels == 6) + { + switch (Format) + { + case AudioFormat.PcmInt8: return ALFormat.Multi51Chn8Ext; + case AudioFormat.PcmInt16: return ALFormat.Multi51Chn16Ext; + } + } + else + { + throw new ArgumentOutOfRangeException(nameof(Channels)); + } throw new ArgumentException(nameof(Format)); } @@ -288,7 +295,7 @@ namespace Ryujinx.Audio.OpenAL { return Td.ContainsBuffer(Tag); } - + return false; } @@ -298,7 +305,7 @@ namespace Ryujinx.Audio.OpenAL { return Td.GetReleasedBuffers(MaxCount); } - + return null; } diff --git a/Ryujinx.Graphics/Gal/GalTextureFormat.cs b/Ryujinx.Graphics/Gal/GalTextureFormat.cs index 83ef229d7..5980579b6 100644 --- a/Ryujinx.Graphics/Gal/GalTextureFormat.cs +++ b/Ryujinx.Graphics/Gal/GalTextureFormat.cs @@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Gal BC3 = 0x26, BC4 = 0x27, BC5 = 0x28, + ZF32 = 0x2f, Astc2D4x4 = 0x40, Astc2D5x5 = 0x41, Astc2D6x6 = 0x42, diff --git a/Ryujinx.Graphics/Gal/IGalRasterizer.cs b/Ryujinx.Graphics/Gal/IGalRasterizer.cs index 2598efb61..0c5d37e40 100644 --- a/Ryujinx.Graphics/Gal/IGalRasterizer.cs +++ b/Ryujinx.Graphics/Gal/IGalRasterizer.cs @@ -2,6 +2,9 @@ namespace Ryujinx.Graphics.Gal { public interface IGalRasterizer { + void LockCaches(); + void UnlockCaches(); + void ClearBuffers(GalClearBufferFlags Flags); bool IsVboCached(long Key, long DataSize); @@ -46,9 +49,9 @@ namespace Ryujinx.Graphics.Gal void CreateIbo(long Key, byte[] Buffer); - void SetVertexArray(int VbIndex, int Stride, long VboKey, GalVertexAttrib[] Attribs); + void SetVertexArray(int Stride, long VboKey, GalVertexAttrib[] Attribs); - void SetIndexArray(long Key, int Size, GalIndexFormat Format); + void SetIndexArray(int Size, GalIndexFormat Format); void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType); diff --git a/Ryujinx.Graphics/Gal/IGalTexture.cs b/Ryujinx.Graphics/Gal/IGalTexture.cs index 6379e73af..2ab411990 100644 --- a/Ryujinx.Graphics/Gal/IGalTexture.cs +++ b/Ryujinx.Graphics/Gal/IGalTexture.cs @@ -2,6 +2,9 @@ namespace Ryujinx.Graphics.Gal { public interface IGalTexture { + void LockCache(); + void UnlockCache(); + void Create(long Key, byte[] Data, GalTexture Texture); bool TryGetCachedTexture(long Key, long DataSize, out GalTexture Texture); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs index 06d76b8bd..01ebf9820 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs @@ -36,6 +36,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL private DeleteValue DeleteValueCallback; + private Queue DeletePending; + + private bool Locked; + public OGLCachedResource(DeleteValue DeleteValueCallback) { if (DeleteValueCallback == null) @@ -48,11 +52,33 @@ namespace Ryujinx.Graphics.Gal.OpenGL Cache = new Dictionary(); SortedCache = new LinkedList(); + + DeletePending = new Queue(); + } + + public void Lock() + { + Locked = true; + } + + public void Unlock() + { + Locked = false; + + while (DeletePending.TryDequeue(out T Value)) + { + DeleteValueCallback(Value); + } + + ClearCacheIfNeeded(); } public void AddOrUpdate(long Key, T Value, long Size) { - ClearCacheIfNeeded(); + if (!Locked) + { + ClearCacheIfNeeded(); + } LinkedListNode Node = SortedCache.AddLast(Key); @@ -60,7 +86,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL if (Cache.TryGetValue(Key, out CacheBucket Bucket)) { - DeleteValueCallback(Bucket.Value); + if (Locked) + { + DeletePending.Enqueue(Bucket.Value); + } + else + { + DeleteValueCallback(Bucket.Value); + } SortedCache.Remove(Bucket.Node); @@ -78,6 +111,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL { Value = Bucket.Value; + SortedCache.Remove(Bucket.Node); + + LinkedListNode Node = SortedCache.AddLast(Key); + + Cache[Key] = new CacheBucket(Value, Bucket.DataSize, Node); + return true; } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs index 505921951..3c8431638 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs @@ -139,6 +139,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalTextureFormat.G8R8: return (PixelFormat.Rg, PixelType.UnsignedByte); case GalTextureFormat.R16: return (PixelFormat.Red, PixelType.HalfFloat); case GalTextureFormat.R8: return (PixelFormat.Red, PixelType.UnsignedByte); + case GalTextureFormat.ZF32: return (PixelFormat.DepthComponent, PixelType.Float); + } throw new NotImplementedException(Format.ToString()); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs index a4ec7f87c..0dc56966b 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs @@ -71,6 +71,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL IndexBuffer = new IbInfo(); } + public void LockCaches() + { + VboCache.Lock(); + IboCache.Lock(); + } + + public void UnlockCaches() + { + VboCache.Unlock(); + IboCache.Unlock(); + } + public void ClearBuffers(GalClearBufferFlags Flags) { ClearBufferMask Mask = ClearBufferMask.ColorBufferBit; @@ -223,7 +235,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw); } - public void SetVertexArray(int VbIndex, int Stride, long VboKey, GalVertexAttrib[] Attribs) + public void SetVertexArray(int Stride, long VboKey, GalVertexAttrib[] Attribs) { if (!VboCache.TryGetValue(VboKey, out int VboHandle)) { @@ -270,7 +282,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - public void SetIndexArray(long Key, int Size, GalIndexFormat Format) + public void SetIndexArray(int Size, GalIndexFormat Format) { IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs index c50bdd71b..5caca6ecd 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -26,6 +26,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL TextureCache = new OGLCachedResource(DeleteTexture); } + public void LockCache() + { + TextureCache.Lock(); + } + + public void UnlockCache() + { + TextureCache.Unlock(); + } + private static void DeleteTexture(TCE CachedTexture) { GL.DeleteTexture(CachedTexture.Handle); diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs index b9f9cc497..2bacd71b3 100644 --- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs @@ -73,6 +73,8 @@ namespace Ryujinx.HLE.Gpu.Engines private void VertexEndGl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { + LockCaches(); + SetFrameBuffer(Vmm, 0); long[] Keys = UploadShaders(Vmm); @@ -90,6 +92,20 @@ namespace Ryujinx.HLE.Gpu.Engines UploadTextures(Vmm, Keys); UploadUniforms(Vmm); UploadVertexArrays(Vmm); + + UnlockCaches(); + } + + private void LockCaches() + { + Gpu.Renderer.Rasterizer.LockCaches(); + Gpu.Renderer.Texture.LockCache(); + } + + private void UnlockCaches() + { + Gpu.Renderer.Rasterizer.UnlockCaches(); + Gpu.Renderer.Texture.UnlockCache(); } private void ClearBuffers(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) @@ -570,7 +586,7 @@ namespace Ryujinx.HLE.Gpu.Engines Gpu.Renderer.Rasterizer.CreateIbo(IboKey, Data); } - Gpu.Renderer.Rasterizer.SetIndexArray(IboKey, IbSize, IndexFormat); + Gpu.Renderer.Rasterizer.SetIndexArray(IbSize, IndexFormat); } List[] Attribs = new List[32]; @@ -634,7 +650,7 @@ namespace Ryujinx.HLE.Gpu.Engines Gpu.Renderer.Rasterizer.CreateVbo(VboKey, Data); } - Gpu.Renderer.Rasterizer.SetVertexArray(Index, Stride, VboKey, Attribs[Index].ToArray()); + Gpu.Renderer.Rasterizer.SetVertexArray(Stride, VboKey, Attribs[Index].ToArray()); } GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff); diff --git a/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs index 8d1617893..ca77b5d74 100644 --- a/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs @@ -28,16 +28,26 @@ namespace Ryujinx.HLE.Gpu.Texture { switch (Texture.Format) { - case GalTextureFormat.R32G32B32A32: return Texture.Width * Texture.Height * 16; - case GalTextureFormat.R16G16B16A16: return Texture.Width * Texture.Height * 8; - case GalTextureFormat.A8B8G8R8: return Texture.Width * Texture.Height * 4; - case GalTextureFormat.R16_G16: return Texture.Width * Texture.Height * 4; - case GalTextureFormat.R32: return Texture.Width * Texture.Height * 4; - case GalTextureFormat.A1B5G5R5: return Texture.Width * Texture.Height * 2; - case GalTextureFormat.B5G6R5: return Texture.Width * Texture.Height * 2; - case GalTextureFormat.G8R8: return Texture.Width * Texture.Height * 2; - case GalTextureFormat.R16: return Texture.Width * Texture.Height * 2; - case GalTextureFormat.R8: return Texture.Width * Texture.Height; + case GalTextureFormat.R32G32B32A32: + return Texture.Width * Texture.Height * 16; + + case GalTextureFormat.R16G16B16A16: + return Texture.Width * Texture.Height * 8; + + case GalTextureFormat.A8B8G8R8: + case GalTextureFormat.R32: + case GalTextureFormat.R16_G16: + case GalTextureFormat.ZF32: + return Texture.Width * Texture.Height * 4; + + case GalTextureFormat.A1B5G5R5: + case GalTextureFormat.B5G6R5: + case GalTextureFormat.G8R8: + case GalTextureFormat.R16: + return Texture.Width * Texture.Height * 2; + + case GalTextureFormat.R8: + return Texture.Width * Texture.Height; case GalTextureFormat.BC1: case GalTextureFormat.BC4: diff --git a/Ryujinx.HLE/Gpu/Texture/TextureReader.cs b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs index 9e8cc754c..edf4be390 100644 --- a/Ryujinx.HLE/Gpu/Texture/TextureReader.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs @@ -26,6 +26,7 @@ namespace Ryujinx.HLE.Gpu.Texture case GalTextureFormat.BC3: return Read16Bpt4x4(Memory, Texture); case GalTextureFormat.BC4: return Read8Bpt4x4 (Memory, Texture); case GalTextureFormat.BC5: return Read16Bpt4x4(Memory, Texture); + case GalTextureFormat.ZF32: return Read4Bpp (Memory, Texture); case GalTextureFormat.Astc2D4x4: return Read16Bpt4x4(Memory, Texture); } diff --git a/Ryujinx.HLE/OsHle/Services/Aud/IAudioOutManager.cs b/Ryujinx.HLE/OsHle/Services/Aud/IAudioOutManager.cs index 54ffa6d90..8c78d1d49 100644 --- a/Ryujinx.HLE/OsHle/Services/Aud/IAudioOutManager.cs +++ b/Ryujinx.HLE/OsHle/Services/Aud/IAudioOutManager.cs @@ -14,6 +14,10 @@ namespace Ryujinx.HLE.OsHle.Services.Aud { private const string DefaultAudioOutput = "DeviceOut"; + private const int DefaultSampleRate = 48000; + + private const int DefaultChannelsCount = 2; + private Dictionary m_Commands; public override IReadOnlyDictionary Commands => m_Commands; @@ -122,7 +126,12 @@ namespace Ryujinx.HLE.OsHle.Services.Aud int SampleRate = Context.RequestData.ReadInt32(); int Channels = Context.RequestData.ReadInt32(); - if (SampleRate != 48000) + if (SampleRate == 0) + { + SampleRate = DefaultSampleRate; + } + + if (SampleRate != DefaultSampleRate) { Context.Ns.Log.PrintWarning(LogClass.Audio, "Invalid sample rate!"); @@ -133,7 +142,7 @@ namespace Ryujinx.HLE.OsHle.Services.Aud if (Channels == 0) { - Channels = 2; + Channels = DefaultChannelsCount; } KEvent ReleaseEvent = new KEvent(); @@ -145,7 +154,7 @@ namespace Ryujinx.HLE.OsHle.Services.Aud IAalOutput AudioOut = Context.Ns.AudioOut; - int Track = AudioOut.OpenTrack(SampleRate, 2, Callback, out AudioFormat Format); + int Track = AudioOut.OpenTrack(SampleRate, Channels, Callback, out AudioFormat Format); MakeObject(Context, new IAudioOut(AudioOut, ReleaseEvent, Track));