Merge branch 'Ryujinx:master' into master

This commit is contained in:
Logan Stromberg 2022-03-29 16:01:13 -07:00 committed by GitHub
commit f8502758a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
70 changed files with 1297 additions and 507 deletions

View file

@ -36,15 +36,20 @@ jobs:
return core.error(`No artifacts found`); return core.error(`No artifacts found`);
} }
let body = `Download the artifacts for this pull request:\n`; let body = `Download the artifacts for this pull request:\n`;
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less (SDL2)</summary>\n`;
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`; let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
for (const art of artifacts) { for (const art of artifacts) {
if(art.name.includes('Debug')) { if(art.name.includes('Debug')) {
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else if(art.name.includes('headless-sdl2')) {
hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else { } else {
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} }
} }
hidden_headless_artifacts += `\n</details>`;
hidden_debug_artifacts += `\n</details>`; hidden_debug_artifacts += `\n</details>`;
body += hidden_headless_artifacts;
body += hidden_debug_artifacts; body += hidden_debug_artifacts;
const {data: comments} = await github.issues.listComments({repo, owner, issue_number}); const {data: comments} = await github.issues.listComments({repo, owner, issue_number});

View file

@ -130,11 +130,6 @@ namespace ARMeilleure.Instructions
bool ordered = (accType & AccessType.Ordered) != 0; bool ordered = (accType & AccessType.Ordered) != 0;
bool exclusive = (accType & AccessType.Exclusive) != 0; bool exclusive = (accType & AccessType.Exclusive) != 0;
if (ordered)
{
EmitBarrier(context);
}
Operand address = context.Copy(GetIntOrSP(context, op.Rn)); Operand address = context.Copy(GetIntOrSP(context, op.Rn));
Operand t = GetIntOrZR(context, op.Rt); Operand t = GetIntOrZR(context, op.Rt);
@ -163,6 +158,11 @@ namespace ARMeilleure.Instructions
{ {
EmitStoreExclusive(context, address, t, exclusive, op.Size, op.Rs, a32: false); EmitStoreExclusive(context, address, t, exclusive, op.Size, op.Rs, a32: false);
} }
if (ordered)
{
EmitBarrier(context);
}
} }
private static void EmitBarrier(ArmEmitterContext context) private static void EmitBarrier(ArmEmitterContext context)

View file

@ -146,13 +146,13 @@ namespace ARMeilleure.Instructions
var exclusive = (accType & AccessType.Exclusive) != 0; var exclusive = (accType & AccessType.Exclusive) != 0;
var ordered = (accType & AccessType.Ordered) != 0; var ordered = (accType & AccessType.Ordered) != 0;
if ((accType & AccessType.Load) != 0)
{
if (ordered) if (ordered)
{ {
EmitBarrier(context); EmitBarrier(context);
} }
if ((accType & AccessType.Load) != 0)
{
if (size == DWordSizeLog2) if (size == DWordSizeLog2)
{ {
// Keep loads atomic - make the call to get the whole region and then decompose it into parts // Keep loads atomic - make the call to get the whole region and then decompose it into parts
@ -219,6 +219,11 @@ namespace ARMeilleure.Instructions
Operand value = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt)); Operand value = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt));
EmitStoreExclusive(context, address, value, exclusive, size, op.Rd, a32: true); EmitStoreExclusive(context, address, value, exclusive, size, op.Rd, a32: true);
} }
if (ordered)
{
EmitBarrier(context);
}
} }
} }

View file

@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 3179; //! To be incremented manually for each change to the ARMeilleure project. private const uint InternalVersion = 3193; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0"; private const string ActualDir = "0";
private const string BackupDir = "1"; private const string BackupDir = "1";

View file

@ -1,7 +1,7 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.Gpu.Engine.Threed; using Ryujinx.Graphics.Gpu.Engine.Threed;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -330,10 +330,94 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
{ {
// TODO: Implement remap functionality. // TODO: Implement remap functionality.
// Buffer to buffer copy. // Buffer to buffer copy.
bool srcIsPitchKind = memoryManager.GetKind(srcGpuVa).IsPitch();
bool dstIsPitchKind = memoryManager.GetKind(dstGpuVa).IsPitch();
if (!srcIsPitchKind && dstIsPitchKind)
{
CopyGobBlockLinearToLinear(memoryManager, srcGpuVa, dstGpuVa, size);
}
else if (srcIsPitchKind && !dstIsPitchKind)
{
CopyGobLinearToBlockLinear(memoryManager, srcGpuVa, dstGpuVa, size);
}
else
{
memoryManager.Physical.BufferCache.CopyBuffer(memoryManager, srcGpuVa, dstGpuVa, size); memoryManager.Physical.BufferCache.CopyBuffer(memoryManager, srcGpuVa, dstGpuVa, size);
} }
} }
} }
}
/// <summary>
/// Copies block linear data with block linear GOBs to a block linear destination with linear GOBs.
/// </summary>
/// <param name="memoryManager">GPU memory manager</param>
/// <param name="srcGpuVa">Source GPU virtual address</param>
/// <param name="dstGpuVa">Destination GPU virtual address</param>
/// <param name="size">Size in bytes of the copy</param>
private static void CopyGobBlockLinearToLinear(MemoryManager memoryManager, ulong srcGpuVa, ulong dstGpuVa, ulong size)
{
if (((srcGpuVa | dstGpuVa | size) & 0xf) == 0)
{
for (ulong offset = 0; offset < size; offset += 16)
{
Vector128<byte> data = memoryManager.Read<Vector128<byte>>(ConvertGobLinearToBlockLinearAddress(srcGpuVa + offset), true);
memoryManager.Write(dstGpuVa + offset, data);
}
}
else
{
for (ulong offset = 0; offset < size; offset++)
{
byte data = memoryManager.Read<byte>(ConvertGobLinearToBlockLinearAddress(srcGpuVa + offset), true);
memoryManager.Write(dstGpuVa + offset, data);
}
}
}
/// <summary>
/// Copies block linear data with linear GOBs to a block linear destination with block linear GOBs.
/// </summary>
/// <param name="memoryManager">GPU memory manager</param>
/// <param name="srcGpuVa">Source GPU virtual address</param>
/// <param name="dstGpuVa">Destination GPU virtual address</param>
/// <param name="size">Size in bytes of the copy</param>
private static void CopyGobLinearToBlockLinear(MemoryManager memoryManager, ulong srcGpuVa, ulong dstGpuVa, ulong size)
{
if (((srcGpuVa | dstGpuVa | size) & 0xf) == 0)
{
for (ulong offset = 0; offset < size; offset += 16)
{
Vector128<byte> data = memoryManager.Read<Vector128<byte>>(srcGpuVa + offset, true);
memoryManager.Write(ConvertGobLinearToBlockLinearAddress(dstGpuVa + offset), data);
}
}
else
{
for (ulong offset = 0; offset < size; offset++)
{
byte data = memoryManager.Read<byte>(srcGpuVa + offset, true);
memoryManager.Write(ConvertGobLinearToBlockLinearAddress(dstGpuVa + offset), data);
}
}
}
/// <summary>
/// Calculates the GOB block linear address from a linear address.
/// </summary>
/// <param name="address">Linear address</param>
/// <returns>Block linear address</returns>
private static ulong ConvertGobLinearToBlockLinearAddress(ulong address)
{
// y2 y1 y0 x5 x4 x3 x2 x1 x0 -> x5 y2 y1 x4 y0 x3 x2 x1 x0
return (address & ~0x1f0UL) |
((address & 0x40) >> 2) |
((address & 0x10) << 1) |
((address & 0x180) >> 1) |
((address & 0x20) << 3);
}
/// <summary> /// <summary>
/// Performs a buffer to buffer, or buffer to texture copy, then optionally releases a semaphore. /// Performs a buffer to buffer, or buffer to texture copy, then optionally releases a semaphore.

View file

@ -7,7 +7,6 @@ using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
using Ryujinx.Memory;
using Ryujinx.Memory.Range; using Ryujinx.Memory.Range;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -255,6 +255,49 @@ namespace Ryujinx.Graphics.Gpu.Memory
} }
} }
/// <summary>
/// Writes data to GPU mapped memory, stopping at the first unmapped page at the memory region, if any.
/// </summary>
/// <param name="va">GPU virtual address to write the data into</param>
/// <param name="data">The data to be written</param>
public void WriteMapped(ulong va, ReadOnlySpan<byte> 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.Slice(0, 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));
}
}
}
}
/// <summary> /// <summary>
/// Maps a given range of pages to the specified CPU virtual address. /// Maps a given range of pages to the specified CPU virtual address.
/// </summary> /// </summary>
@ -264,7 +307,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="pa">CPU virtual address to map into</param> /// <param name="pa">CPU virtual address to map into</param>
/// <param name="va">GPU virtual address to be mapped</param> /// <param name="va">GPU virtual address to be mapped</param>
/// <param name="size">Size in bytes of the mapping</param> /// <param name="size">Size in bytes of the mapping</param>
public void Map(ulong pa, ulong va, ulong size) /// <param name="kind">Kind of the resource located at the mapping</param>
public void Map(ulong pa, ulong va, ulong size, PteKind kind)
{ {
lock (_pageTable) lock (_pageTable)
{ {
@ -272,7 +316,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
for (ulong offset = 0; offset < size; offset += PageSize) for (ulong offset = 0; offset < size; offset += PageSize)
{ {
SetPte(va + offset, pa + offset); SetPte(va + offset, PackPte(pa + offset, kind));
} }
} }
} }
@ -462,14 +506,37 @@ namespace Ryujinx.Graphics.Gpu.Memory
return PteUnmapped; return PteUnmapped;
} }
ulong baseAddress = GetPte(va); ulong pte = GetPte(va);
if (baseAddress == PteUnmapped) if (pte == PteUnmapped)
{ {
return PteUnmapped; return PteUnmapped;
} }
return baseAddress + (va & PageMask); return UnpackPaFromPte(pte) + (va & PageMask);
}
/// <summary>
/// Gets the kind of a given memory page.
/// This might indicate the type of resource that can be allocated on the page, and also texture tiling.
/// </summary>
/// <param name="va">GPU virtual address</param>
/// <returns>Kind of the memory page</returns>
public PteKind GetKind(ulong va)
{
if (!ValidateAddress(va))
{
return PteKind.Invalid;
}
ulong pte = GetPte(va);
if (pte == PteUnmapped)
{
return PteKind.Invalid;
}
return UnpackKindFromPte(pte);
} }
/// <summary> /// <summary>
@ -512,5 +579,36 @@ namespace Ryujinx.Graphics.Gpu.Memory
_pageTable[l0][l1] = pte; _pageTable[l0][l1] = pte;
} }
/// <summary>
/// Creates a page table entry from a physical address and kind.
/// </summary>
/// <param name="pa">Physical address</param>
/// <param name="kind">Kind</param>
/// <returns>Page table entry</returns>
private static ulong PackPte(ulong pa, PteKind kind)
{
return pa | ((ulong)kind << 56);
}
/// <summary>
/// Unpacks kind from a page table entry.
/// </summary>
/// <param name="pte">Page table entry</param>
/// <returns>Kind</returns>
private static PteKind UnpackKindFromPte(ulong pte)
{
return (PteKind)(pte >> 56);
}
/// <summary>
/// Unpacks physical address from a page table entry.
/// </summary>
/// <param name="pte">Page table entry</param>
/// <returns>Physical address</returns>
private static ulong UnpackPaFromPte(ulong pte)
{
return pte & 0xffffffffffffffUL;
}
} }
} }

View file

@ -340,6 +340,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
return _cpuMemory.BeginSmartGranularTracking(address, size, granularity); return _cpuMemory.BeginSmartGranularTracking(address, size, granularity);
} }
/// <summary>
/// Checks if the page at a given address is mapped on CPU memory.
/// </summary>
/// <param name="address">CPU virtual address of the page to check</param>
/// <returns>True if mapped, false otherwise</returns>
public bool IsMapped(ulong address)
{
return _cpuMemory.IsMapped(address);
}
/// <summary> /// <summary>
/// Release our reference to the CPU memory manager. /// Release our reference to the CPU memory manager.
/// </summary> /// </summary>

View file

@ -0,0 +1,268 @@
namespace Ryujinx.Graphics.Gpu.Memory
{
/// <summary>
/// Kind of the resource at the given memory mapping.
/// </summary>
public enum PteKind : byte
{
Invalid = 0xff,
Pitch = 0x00,
Z16 = 0x01,
Z162C = 0x02,
Z16MS22C = 0x03,
Z16MS42C = 0x04,
Z16MS82C = 0x05,
Z16MS162C = 0x06,
Z162Z = 0x07,
Z16MS22Z = 0x08,
Z16MS42Z = 0x09,
Z16MS82Z = 0x0a,
Z16MS162Z = 0x0b,
Z162CZ = 0x36,
Z16MS22CZ = 0x37,
Z16MS42CZ = 0x38,
Z16MS82CZ = 0x39,
Z16MS162CZ = 0x5f,
Z164CZ = 0x0c,
Z16MS24CZ = 0x0d,
Z16MS44CZ = 0x0e,
Z16MS84CZ = 0x0f,
Z16MS164CZ = 0x10,
S8Z24 = 0x11,
S8Z241Z = 0x12,
S8Z24MS21Z = 0x13,
S8Z24MS41Z = 0x14,
S8Z24MS81Z = 0x15,
S8Z24MS161Z = 0x16,
S8Z242CZ = 0x17,
S8Z24MS22CZ = 0x18,
S8Z24MS42CZ = 0x19,
S8Z24MS82CZ = 0x1a,
S8Z24MS162CZ = 0x1b,
S8Z242CS = 0x1c,
S8Z24MS22CS = 0x1d,
S8Z24MS42CS = 0x1e,
S8Z24MS82CS = 0x1f,
S8Z24MS162CS = 0x20,
S8Z244CSZV = 0x21,
S8Z24MS24CSZV = 0x22,
S8Z24MS44CSZV = 0x23,
S8Z24MS84CSZV = 0x24,
S8Z24MS164CSZV = 0x25,
V8Z24MS4VC12 = 0x26,
V8Z24MS4VC4 = 0x27,
V8Z24MS8VC8 = 0x28,
V8Z24MS8VC24 = 0x29,
V8Z24MS4VC121ZV = 0x2e,
V8Z24MS4VC41ZV = 0x2f,
V8Z24MS8VC81ZV = 0x30,
V8Z24MS8VC241ZV = 0x31,
V8Z24MS4VC122CS = 0x32,
V8Z24MS4VC42CS = 0x33,
V8Z24MS8VC82CS = 0x34,
V8Z24MS8VC242CS = 0x35,
V8Z24MS4VC122CZV = 0x3a,
V8Z24MS4VC42CZV = 0x3b,
V8Z24MS8VC82CZV = 0x3c,
V8Z24MS8VC242CZV = 0x3d,
V8Z24MS4VC122ZV = 0x3e,
V8Z24MS4VC42ZV = 0x3f,
V8Z24MS8VC82ZV = 0x40,
V8Z24MS8VC242ZV = 0x41,
V8Z24MS4VC124CSZV = 0x42,
V8Z24MS4VC44CSZV = 0x43,
V8Z24MS8VC84CSZV = 0x44,
V8Z24MS8VC244CSZV = 0x45,
Z24S8 = 0x46,
Z24S81Z = 0x47,
Z24S8MS21Z = 0x48,
Z24S8MS41Z = 0x49,
Z24S8MS81Z = 0x4a,
Z24S8MS161Z = 0x4b,
Z24S82CS = 0x4c,
Z24S8MS22CS = 0x4d,
Z24S8MS42CS = 0x4e,
Z24S8MS82CS = 0x4f,
Z24S8MS162CS = 0x50,
Z24S82CZ = 0x51,
Z24S8MS22CZ = 0x52,
Z24S8MS42CZ = 0x53,
Z24S8MS82CZ = 0x54,
Z24S8MS162CZ = 0x55,
Z24S84CSZV = 0x56,
Z24S8MS24CSZV = 0x57,
Z24S8MS44CSZV = 0x58,
Z24S8MS84CSZV = 0x59,
Z24S8MS164CSZV = 0x5a,
Z24V8MS4VC12 = 0x5b,
Z24V8MS4VC4 = 0x5c,
Z24V8MS8VC8 = 0x5d,
Z24V8MS8VC24 = 0x5e,
YUVB8C12Y = 0x60,
YUVB8C22Y = 0x61,
YUVB10C12Y = 0x62,
YUVB10C22Y = 0x6b,
YUVB12C12Y = 0x6c,
YUVB12C22Y = 0x6d,
Z24V8MS4VC121ZV = 0x63,
Z24V8MS4VC41ZV = 0x64,
Z24V8MS8VC81ZV = 0x65,
Z24V8MS8VC241ZV = 0x66,
Z24V8MS4VC122CS = 0x67,
Z24V8MS4VC42CS = 0x68,
Z24V8MS8VC82CS = 0x69,
Z24V8MS8VC242CS = 0x6a,
Z24V8MS4VC122CZV = 0x6f,
Z24V8MS4VC42CZV = 0x70,
Z24V8MS8VC82CZV = 0x71,
Z24V8MS8VC242CZV = 0x72,
Z24V8MS4VC122ZV = 0x73,
Z24V8MS4VC42ZV = 0x74,
Z24V8MS8VC82ZV = 0x75,
Z24V8MS8VC242ZV = 0x76,
Z24V8MS4VC124CSZV = 0x77,
Z24V8MS4VC44CSZV = 0x78,
Z24V8MS8VC84CSZV = 0x79,
Z24V8MS8VC244CSZV = 0x7a,
ZF32 = 0x7b,
ZF321Z = 0x7c,
ZF32MS21Z = 0x7d,
ZF32MS41Z = 0x7e,
ZF32MS81Z = 0x7f,
ZF32MS161Z = 0x80,
ZF322CS = 0x81,
ZF32MS22CS = 0x82,
ZF32MS42CS = 0x83,
ZF32MS82CS = 0x84,
ZF32MS162CS = 0x85,
ZF322CZ = 0x86,
ZF32MS22CZ = 0x87,
ZF32MS42CZ = 0x88,
ZF32MS82CZ = 0x89,
ZF32MS162CZ = 0x8a,
X8Z24X16V8S8MS4VC12 = 0x8b,
X8Z24X16V8S8MS4VC4 = 0x8c,
X8Z24X16V8S8MS8VC8 = 0x8d,
X8Z24X16V8S8MS8VC24 = 0x8e,
X8Z24X16V8S8MS4VC121CS = 0x8f,
X8Z24X16V8S8MS4VC41CS = 0x90,
X8Z24X16V8S8MS8VC81CS = 0x91,
X8Z24X16V8S8MS8VC241CS = 0x92,
X8Z24X16V8S8MS4VC121ZV = 0x97,
X8Z24X16V8S8MS4VC41ZV = 0x98,
X8Z24X16V8S8MS8VC81ZV = 0x99,
X8Z24X16V8S8MS8VC241ZV = 0x9a,
X8Z24X16V8S8MS4VC121CZV = 0x9b,
X8Z24X16V8S8MS4VC41CZV = 0x9c,
X8Z24X16V8S8MS8VC81CZV = 0x9d,
X8Z24X16V8S8MS8VC241CZV = 0x9e,
X8Z24X16V8S8MS4VC122CS = 0x9f,
X8Z24X16V8S8MS4VC42CS = 0xa0,
X8Z24X16V8S8MS8VC82CS = 0xa1,
X8Z24X16V8S8MS8VC242CS = 0xa2,
X8Z24X16V8S8MS4VC122CSZV = 0xa3,
X8Z24X16V8S8MS4VC42CSZV = 0xa4,
X8Z24X16V8S8MS8VC82CSZV = 0xa5,
X8Z24X16V8S8MS8VC242CSZV = 0xa6,
ZF32X16V8S8MS4VC12 = 0xa7,
ZF32X16V8S8MS4VC4 = 0xa8,
ZF32X16V8S8MS8VC8 = 0xa9,
ZF32X16V8S8MS8VC24 = 0xaa,
ZF32X16V8S8MS4VC121CS = 0xab,
ZF32X16V8S8MS4VC41CS = 0xac,
ZF32X16V8S8MS8VC81CS = 0xad,
ZF32X16V8S8MS8VC241CS = 0xae,
ZF32X16V8S8MS4VC121ZV = 0xb3,
ZF32X16V8S8MS4VC41ZV = 0xb4,
ZF32X16V8S8MS8VC81ZV = 0xb5,
ZF32X16V8S8MS8VC241ZV = 0xb6,
ZF32X16V8S8MS4VC121CZV = 0xb7,
ZF32X16V8S8MS4VC41CZV = 0xb8,
ZF32X16V8S8MS8VC81CZV = 0xb9,
ZF32X16V8S8MS8VC241CZV = 0xba,
ZF32X16V8S8MS4VC122CS = 0xbb,
ZF32X16V8S8MS4VC42CS = 0xbc,
ZF32X16V8S8MS8VC82CS = 0xbd,
ZF32X16V8S8MS8VC242CS = 0xbe,
ZF32X16V8S8MS4VC122CSZV = 0xbf,
ZF32X16V8S8MS4VC42CSZV = 0xc0,
ZF32X16V8S8MS8VC82CSZV = 0xc1,
ZF32X16V8S8MS8VC242CSZV = 0xc2,
ZF32X24S8 = 0xc3,
ZF32X24S81CS = 0xc4,
ZF32X24S8MS21CS = 0xc5,
ZF32X24S8MS41CS = 0xc6,
ZF32X24S8MS81CS = 0xc7,
ZF32X24S8MS161CS = 0xc8,
ZF32X24S82CSZV = 0xce,
ZF32X24S8MS22CSZV = 0xcf,
ZF32X24S8MS42CSZV = 0xd0,
ZF32X24S8MS82CSZV = 0xd1,
ZF32X24S8MS162CSZV = 0xd2,
ZF32X24S82CS = 0xd3,
ZF32X24S8MS22CS = 0xd4,
ZF32X24S8MS42CS = 0xd5,
ZF32X24S8MS82CS = 0xd6,
ZF32X24S8MS162CS = 0xd7,
S8 = 0x2a,
S82S = 0x2b,
Generic16Bx2 = 0xfe,
C322C = 0xd8,
C322CBR = 0xd9,
C322CBA = 0xda,
C322CRA = 0xdb,
C322BRA = 0xdc,
C32MS22C = 0xdd,
C32MS22CBR = 0xde,
C32MS24CBRA = 0xcc,
C32MS42C = 0xdf,
C32MS42CBR = 0xe0,
C32MS42CBA = 0xe1,
C32MS42CRA = 0xe2,
C32MS42BRA = 0xe3,
C32MS44CBRA = 0x2c,
C32MS8MS162C = 0xe4,
C32MS8MS162CRA = 0xe5,
C642C = 0xe6,
C642CBR = 0xe7,
C642CBA = 0xe8,
C642CRA = 0xe9,
C642BRA = 0xea,
C64MS22C = 0xeb,
C64MS22CBR = 0xec,
C64MS24CBRA = 0xcd,
C64MS42C = 0xed,
C64MS42CBR = 0xee,
C64MS42CBA = 0xef,
C64MS42CRA = 0xf0,
C64MS42BRA = 0xf1,
C64MS44CBRA = 0x2d,
C64MS8MS162C = 0xf2,
C64MS8MS162CRA = 0xf3,
C1282C = 0xf4,
C1282CR = 0xf5,
C128MS22C = 0xf6,
C128MS22CR = 0xf7,
C128MS42C = 0xf8,
C128MS42CR = 0xf9,
C128MS8MS162C = 0xfa,
C128MS8MS162CR = 0xfb,
X8C24 = 0xfc,
PitchNoSwizzle = 0xfd,
SmSkedMessage = 0xca,
SmHostMessage = 0xcb
}
static class PteKindExtensions
{
/// <summary>
/// Checks if the kind is pitch.
/// </summary>
/// <param name="kind">Kind to check</param>
/// <returns>True if pitch, false otherwise</returns>
public static bool IsPitch(this PteKind kind)
{
return kind == PteKind.Pitch || kind == PteKind.PitchNoSwizzle;
}
}
}

View file

@ -1,13 +0,0 @@
namespace Ryujinx.Graphics.Gpu.Memory
{
/// <summary>
/// Name of a GPU resource.
/// </summary>
public enum ResourceName
{
Buffer,
Texture,
TexturePool,
SamplerPool
}
}

View file

@ -15,11 +15,13 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
public Plane UPlane => new Plane((IntPtr)Frame->data[1], UvStride * UvHeight); public Plane UPlane => new Plane((IntPtr)Frame->data[1], UvStride * UvHeight);
public Plane VPlane => new Plane((IntPtr)Frame->data[2], UvStride * UvHeight); public Plane VPlane => new Plane((IntPtr)Frame->data[2], UvStride * UvHeight);
public FrameField Field => Frame->interlaced_frame != 0 ? FrameField.Interlaced : FrameField.Progressive;
public int Width => Frame->width; public int Width => Frame->width;
public int Height => Frame->height; public int Height => Frame->height;
public int Stride => Frame->linesize[0]; public int Stride => Frame->linesize[0];
public int UvWidth => (Frame->width + 1) >> 1; public int UvWidth => (Width + 1) >> 1;
public int UvHeight => (Frame->height + 1) >> 1; public int UvHeight => (Height + 1) >> 1;
public int UvStride => Frame->linesize[1]; public int UvStride => Frame->linesize[1];
public Surface(int width, int height) public Surface(int width, int height)

View file

@ -486,8 +486,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Idct8(tempIn, tempOut); Idct8(tempIn, tempOut);
for (j = 0; j < 8; ++j) for (j = 0; j < 8; ++j)
{ {
dest[j * stride + i] = ClipPixelAdd(dest[j * stride + i], dest[j * stride + i] = ClipPixelAdd(dest[j * stride + i], BitUtils.RoundPowerOfTwo(tempOut[j], 5));
BitUtils.RoundPowerOfTwo(tempOut[j], 5));
} }
} }
} }

View file

@ -15,6 +15,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public unsafe Plane UPlane => new Plane((IntPtr)UBuffer.ToPointer(), UBuffer.Length); public unsafe Plane UPlane => new Plane((IntPtr)UBuffer.ToPointer(), UBuffer.Length);
public unsafe Plane VPlane => new Plane((IntPtr)VBuffer.ToPointer(), VBuffer.Length); public unsafe Plane VPlane => new Plane((IntPtr)VBuffer.ToPointer(), VBuffer.Length);
public FrameField Field => FrameField.Progressive;
public int Width { get; } public int Width { get; }
public int Height { get; } public int Height { get; }
public int AlignedWidth { get; } public int AlignedWidth { get; }

View file

@ -31,7 +31,24 @@ namespace Ryujinx.Graphics.Nvdec
if (decoder.Decode(ref info, outputSurface, bitstream)) if (decoder.Decode(ref info, outputSurface, bitstream))
{ {
SurfaceWriter.Write(rm.Gmm, outputSurface, lumaOffset, chromaOffset); if (outputSurface.Field == FrameField.Progressive)
{
SurfaceWriter.Write(
rm.Gmm,
outputSurface,
lumaOffset + pictureInfo.LumaFrameOffset,
chromaOffset + pictureInfo.ChromaFrameOffset);
}
else
{
SurfaceWriter.WriteInterlaced(
rm.Gmm,
outputSurface,
lumaOffset + pictureInfo.LumaTopFieldOffset,
chromaOffset + pictureInfo.ChromaTopFieldOffset,
lumaOffset + pictureInfo.LumaBottomFieldOffset,
chromaOffset + pictureInfo.ChromaBottomFieldOffset);
}
} }
rm.Cache.Put(outputSurface); rm.Cache.Put(outputSurface);

View file

@ -38,6 +38,55 @@ namespace Ryujinx.Graphics.Nvdec.Image
surface.UvHeight); surface.UvHeight);
} }
public static void WriteInterlaced(
MemoryManager gmm,
ISurface surface,
uint lumaTopOffset,
uint chromaTopOffset,
uint lumaBottomOffset,
uint chromaBottomOffset)
{
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);
WriteLuma(
lumaTop.Memory.Span,
surface.YPlane.AsSpan(),
surface.Stride * 2,
surface.Width,
surface.Height / 2);
WriteLuma(
lumaBottom.Memory.Span,
surface.YPlane.AsSpan().Slice(surface.Stride),
surface.Stride * 2,
surface.Width,
surface.Height / 2);
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);
WriteChroma(
chromaTop.Memory.Span,
surface.UPlane.AsSpan(),
surface.VPlane.AsSpan(),
surface.UvStride * 2,
surface.UvWidth,
surface.UvHeight / 2);
WriteChroma(
chromaBottom.Memory.Span,
surface.UPlane.AsSpan().Slice(surface.UvStride),
surface.VPlane.AsSpan().Slice(surface.UvStride),
surface.UvStride * 2,
surface.UvWidth,
surface.UvHeight / 2);
}
private static void WriteLuma(Span<byte> dst, ReadOnlySpan<byte> src, int srcStride, int width, int height) private static void WriteLuma(Span<byte> dst, ReadOnlySpan<byte> src, int srcStride, int width, int height)
{ {
LayoutConverter.ConvertLinearToBlockLinear(dst, width, height, srcStride, 1, 2, src); LayoutConverter.ConvertLinearToBlockLinear(dst, width, height, srcStride, 1, 2, src);

View file

@ -26,10 +26,10 @@ namespace Ryujinx.Graphics.Nvdec.Types.H264
public uint Transform8x8ModeFlag; public uint Transform8x8ModeFlag;
public uint LumaPitch; public uint LumaPitch;
public uint ChromaPitch; public uint ChromaPitch;
public uint LumaTopOffset; public uint LumaTopFieldOffset;
public uint LumaBottomOffset; public uint LumaBottomFieldOffset;
public uint LumaFrameOffset; public uint LumaFrameOffset;
public uint ChromaTopOffset; public uint ChromaTopFieldOffset;
public uint ChromaBottomFieldOffset; public uint ChromaBottomFieldOffset;
public uint ChromaFrameOffset; public uint ChromaFrameOffset;
public uint HistBufferSize; public uint HistBufferSize;

View file

@ -612,7 +612,7 @@ namespace Ryujinx.Graphics.OpenGL
_program?.Bind(); _program?.Bind();
_unit0Sampler?.Bind(0); _unit0Sampler?.Bind(0);
GL.ViewportArray(0, 1, _viewportArray); RestoreViewport0();
Enable(EnableCap.CullFace, _cullEnable); Enable(EnableCap.CullFace, _cullEnable);
Enable(EnableCap.StencilTest, _stencilTestEnable); Enable(EnableCap.StencilTest, _stencilTestEnable);
@ -1478,6 +1478,11 @@ namespace Ryujinx.Graphics.OpenGL
_currentComponentMasks |= componentMaskAtIndex; _currentComponentMasks |= componentMaskAtIndex;
} }
public void RestoreClipControl()
{
GL.ClipControl(_clipOrigin, _clipDepthMode);
}
public void RestoreScissor0Enable() public void RestoreScissor0Enable()
{ {
if ((_scissorEnables & 1u) != 0) if ((_scissorEnables & 1u) != 0)
@ -1494,6 +1499,14 @@ namespace Ryujinx.Graphics.OpenGL
} }
} }
public void RestoreViewport0()
{
if (_viewportArray.Length > 0)
{
GL.ViewportArray(0, 1, _viewportArray);
}
}
public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual) public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual)
{ {
if (value is CounterQueueEvent) if (value is CounterQueueEvent)

View file

@ -27,11 +27,12 @@ namespace Ryujinx.Graphics.OpenGL
{ {
GL.Disable(EnableCap.FramebufferSrgb); GL.Disable(EnableCap.FramebufferSrgb);
CopyTextureToFrameBufferRGB(0, GetCopyFramebufferHandleLazy(), (TextureView)texture, crop); CopyTextureToFrameBufferRGB(0, GetCopyFramebufferHandleLazy(), (TextureView)texture, crop, swapBuffersCallback);
GL.Enable(EnableCap.FramebufferSrgb); GL.Enable(EnableCap.FramebufferSrgb);
swapBuffersCallback(); // Restore unpack alignment to 4, as performance overlays such as RTSS may change this to load their resources.
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4);
} }
public void SetSize(int width, int height) public void SetSize(int width, int height)
@ -40,7 +41,7 @@ namespace Ryujinx.Graphics.OpenGL
_height = height; _height = height;
} }
private void CopyTextureToFrameBufferRGB(int drawFramebuffer, int readFramebuffer, TextureView view, ImageCrop crop) private void CopyTextureToFrameBufferRGB(int drawFramebuffer, int readFramebuffer, TextureView view, ImageCrop crop, Action swapBuffersCallback)
{ {
(int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers(); (int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers();
@ -139,11 +140,20 @@ namespace Ryujinx.Graphics.OpenGL
((Pipeline)_renderer.Pipeline).RestoreComponentMask(i); ((Pipeline)_renderer.Pipeline).RestoreComponentMask(i);
} }
// Set clip control, viewport and the framebuffer to the output to placate overlays and OBS capture.
GL.ClipControl(ClipOrigin.LowerLeft, ClipDepthMode.NegativeOneToOne);
GL.Viewport(0, 0, _width, _height);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, drawFramebuffer);
swapBuffersCallback();
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle); GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle); GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);
((Pipeline)_renderer.Pipeline).RestoreClipControl();
((Pipeline)_renderer.Pipeline).RestoreScissor0Enable(); ((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard(); ((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
((Pipeline)_renderer.Pipeline).RestoreViewport0();
if (viewConverted != view) if (viewConverted != view)
{ {

View file

@ -48,38 +48,10 @@ namespace Ryujinx.Graphics.Vic
int one = 1 << (mtx.MatrixRShift + 8); int one = 1 << (mtx.MatrixRShift + 8);
Vector128<int> col1 = Vector128.Create(mtx.MatrixCoeff00, mtx.MatrixCoeff10, mtx.MatrixCoeff20, 0);
// NOTE: This is buggy on .NET 5.0.100, we use a workaround for now (see https://github.com/dotnet/runtime/issues/44704) Vector128<int> col2 = Vector128.Create(mtx.MatrixCoeff01, mtx.MatrixCoeff11, mtx.MatrixCoeff21, 0);
// TODO: Uncomment this when fixed. Vector128<int> col3 = Vector128.Create(mtx.MatrixCoeff02, mtx.MatrixCoeff12, mtx.MatrixCoeff22, one);
//Vector128<int> col1 = Vector128.Create(mtx.MatrixCoeff00, mtx.MatrixCoeff10, mtx.MatrixCoeff20, 0); Vector128<int> col4 = Vector128.Create(mtx.MatrixCoeff03, mtx.MatrixCoeff13, mtx.MatrixCoeff23, 0);
//Vector128<int> col2 = Vector128.Create(mtx.MatrixCoeff01, mtx.MatrixCoeff11, mtx.MatrixCoeff21, 0);
//Vector128<int> col3 = Vector128.Create(mtx.MatrixCoeff02, mtx.MatrixCoeff12, mtx.MatrixCoeff22, one);
//Vector128<int> col4 = Vector128.Create(mtx.MatrixCoeff03, mtx.MatrixCoeff13, mtx.MatrixCoeff23, 0);
Vector128<int> col1 = new Vector128<int>();
Vector128<int> col2 = new Vector128<int>();
Vector128<int> col3 = new Vector128<int>();
Vector128<int> col4 = new Vector128<int>();
col1 = Sse41.Insert(col1, mtx.MatrixCoeff00, 0);
col1 = Sse41.Insert(col1, mtx.MatrixCoeff10, 1);
col1 = Sse41.Insert(col1, mtx.MatrixCoeff20, 2);
col1 = Sse41.Insert(col1, 0, 3);
col2 = Sse41.Insert(col2, mtx.MatrixCoeff01, 0);
col2 = Sse41.Insert(col2, mtx.MatrixCoeff11, 1);
col2 = Sse41.Insert(col2, mtx.MatrixCoeff21, 2);
col2 = Sse41.Insert(col2, 0, 3);
col3 = Sse41.Insert(col3, mtx.MatrixCoeff02, 0);
col3 = Sse41.Insert(col3, mtx.MatrixCoeff12, 1);
col3 = Sse41.Insert(col3, mtx.MatrixCoeff22, 2);
col3 = Sse41.Insert(col3, one, 3);
col4 = Sse41.Insert(col4, mtx.MatrixCoeff03, 0);
col4 = Sse41.Insert(col4, mtx.MatrixCoeff13, 1);
col4 = Sse41.Insert(col4, mtx.MatrixCoeff23, 2);
col4 = Sse41.Insert(col4, 0, 3);
Vector128<int> rShift = Vector128.CreateScalar(mtx.MatrixRShift); Vector128<int> rShift = Vector128.CreateScalar(mtx.MatrixRShift);
Vector128<ushort> clMin = Vector128.Create((ushort)slot.SlotConfig.SoftClampLow); Vector128<ushort> clMin = Vector128.Create((ushort)slot.SlotConfig.SoftClampLow);

View file

@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Vic.Image
/// If the required buffer is larger than this, it won't be /// If the required buffer is larger than this, it won't be
/// added to the pool to avoid long term high memory usage. /// added to the pool to avoid long term high memory usage.
/// </summary> /// </summary>
private const int MaxBufferSize = 2048 * 1280; private const int MaxBufferSize = 2048 * 2048;
private struct PoolItem private struct PoolItem
{ {

View file

@ -2,16 +2,85 @@
namespace Ryujinx.Graphics.Vic.Image namespace Ryujinx.Graphics.Vic.Image
{ {
ref struct RentedBuffer
{
public static RentedBuffer Empty => new RentedBuffer(Span<byte>.Empty, -1);
public Span<byte> Data;
public int Index;
public RentedBuffer(Span<byte> data, int index)
{
Data = data;
Index = index;
}
public void Return(BufferPool<byte> pool)
{
if (Index != -1)
{
pool.Return(Index);
}
}
}
ref struct InputSurface ref struct InputSurface
{ {
public ReadOnlySpan<byte> Buffer0; public ReadOnlySpan<byte> Buffer0;
public ReadOnlySpan<byte> Buffer1; public ReadOnlySpan<byte> Buffer1;
public ReadOnlySpan<byte> Buffer2; public ReadOnlySpan<byte> Buffer2;
public int Buffer0Index;
public int Buffer1Index;
public int Buffer2Index;
public int Width; public int Width;
public int Height; public int Height;
public int UvWidth; public int UvWidth;
public int UvHeight; public int UvHeight;
public void Initialize()
{
Buffer0Index = -1;
Buffer1Index = -1;
Buffer2Index = -1;
}
public void SetBuffer0(RentedBuffer buffer)
{
Buffer0 = buffer.Data;
Buffer0Index = buffer.Index;
}
public void SetBuffer1(RentedBuffer buffer)
{
Buffer1 = buffer.Data;
Buffer1Index = buffer.Index;
}
public void SetBuffer2(RentedBuffer buffer)
{
Buffer2 = buffer.Data;
Buffer2Index = buffer.Index;
}
public void Return(BufferPool<byte> pool)
{
if (Buffer0Index != -1)
{
pool.Return(Buffer0Index);
}
if (Buffer1Index != -1)
{
pool.Return(Buffer1Index);
}
if (Buffer2Index != -1)
{
pool.Return(Buffer2Index);
}
}
} }
} }

View file

@ -1,5 +1,5 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
using Ryujinx.Graphics.Vic.Types; using Ryujinx.Graphics.Vic.Types;
using System; using System;
@ -12,24 +12,32 @@ namespace Ryujinx.Graphics.Vic.Image
{ {
static class SurfaceReader static class SurfaceReader
{ {
public static Surface Read(ResourceManager rm, ref SlotSurfaceConfig config, ref PlaneOffsets offsets) public static Surface Read(
ResourceManager rm,
ref SlotConfig config,
ref SlotSurfaceConfig surfaceConfig,
ref Array8<PlaneOffsets> offsets)
{ {
switch (config.SlotPixelFormat) switch (surfaceConfig.SlotPixelFormat)
{ {
case PixelFormat.Y8___V8U8_N420: return ReadNv12(rm, ref config, ref offsets); case PixelFormat.Y8___V8U8_N420: return ReadNv12(rm, ref config, ref surfaceConfig, ref offsets);
} }
Logger.Error?.Print(LogClass.Vic, $"Unsupported pixel format \"{config.SlotPixelFormat}\"."); Logger.Error?.Print(LogClass.Vic, $"Unsupported pixel format \"{surfaceConfig.SlotPixelFormat}\".");
int lw = config.SlotLumaWidth + 1; int lw = surfaceConfig.SlotLumaWidth + 1;
int lh = config.SlotLumaHeight + 1; int lh = surfaceConfig.SlotLumaHeight + 1;
return new Surface(rm.SurfacePool, lw, lh); return new Surface(rm.SurfacePool, lw, lh);
} }
private unsafe static Surface ReadNv12(ResourceManager rm, ref SlotSurfaceConfig config, ref PlaneOffsets offsets) private unsafe static Surface ReadNv12(
ResourceManager rm,
ref SlotConfig config,
ref SlotSurfaceConfig surfaceConfig,
ref Array8<PlaneOffsets> offsets)
{ {
InputSurface input = ReadSurface(rm.Gmm, ref config, ref offsets, 1, 2); InputSurface input = ReadSurface(rm, ref config, ref surfaceConfig, ref offsets, 1, 2);
int width = input.Width; int width = input.Width;
int height = input.Height; int height = input.Height;
@ -160,6 +168,8 @@ namespace Ryujinx.Graphics.Vic.Image
} }
} }
input.Return(rm.BufferPool);
return output; return output;
} }
@ -170,84 +180,227 @@ namespace Ryujinx.Graphics.Vic.Image
} }
private static InputSurface ReadSurface( private static InputSurface ReadSurface(
MemoryManager gmm, ResourceManager rm,
ref SlotSurfaceConfig config, ref SlotConfig config,
ref PlaneOffsets offsets, ref SlotSurfaceConfig surfaceConfig,
ref Array8<PlaneOffsets> offsets,
int bytesPerPixel, int bytesPerPixel,
int planes) int planes)
{ {
InputSurface surface = new InputSurface(); InputSurface surface = new InputSurface();
int gobBlocksInY = 1 << config.SlotBlkHeight; surface.Initialize();
bool linear = config.SlotBlkKind == 0; int gobBlocksInY = 1 << surfaceConfig.SlotBlkHeight;
int lw = config.SlotLumaWidth + 1; bool linear = surfaceConfig.SlotBlkKind == 0;
int lh = config.SlotLumaHeight + 1;
int cw = config.SlotChromaWidth + 1; int lw = surfaceConfig.SlotLumaWidth + 1;
int ch = config.SlotChromaHeight + 1; int lh = surfaceConfig.SlotLumaHeight + 1;
int cw = surfaceConfig.SlotChromaWidth + 1;
int ch = surfaceConfig.SlotChromaHeight + 1;
// Interlaced inputs have double the height when deinterlaced.
int heightShift = config.FrameFormat.IsField() ? 1 : 0;
surface.Width = lw; surface.Width = lw;
surface.Height = lh; surface.Height = lh << heightShift;
surface.UvWidth = cw; surface.UvWidth = cw;
surface.UvHeight = ch; surface.UvHeight = ch << heightShift;
if (planes > 0) if (planes > 0)
{ {
surface.Buffer0 = ReadBuffer(gmm, offsets.LumaOffset, linear, lw, lh, bytesPerPixel, gobBlocksInY); surface.SetBuffer0(ReadBuffer(rm, ref config, ref offsets, linear, 0, lw, lh, bytesPerPixel, gobBlocksInY));
} }
if (planes > 1) if (planes > 1)
{ {
surface.Buffer1 = ReadBuffer(gmm, offsets.ChromaUOffset, linear, cw, ch, planes == 2 ? 2 : 1, gobBlocksInY); surface.SetBuffer1(ReadBuffer(rm, ref config, ref offsets, linear, 1, cw, ch, planes == 2 ? 2 : 1, gobBlocksInY));
} }
if (planes > 2) if (planes > 2)
{ {
surface.Buffer2 = ReadBuffer(gmm, offsets.ChromaVOffset, linear, cw, ch, 1, gobBlocksInY); surface.SetBuffer2(ReadBuffer(rm, ref config, ref offsets, linear, 2, cw, ch, 1, gobBlocksInY));
} }
return surface; return surface;
} }
private static ReadOnlySpan<byte> ReadBuffer( private static RentedBuffer ReadBuffer(
MemoryManager gmm, ResourceManager rm,
uint offset, ref SlotConfig config,
ref Array8<PlaneOffsets> offsets,
bool linear, bool linear,
int plane,
int width,
int height,
int bytesPerPixel,
int gobBlocksInY)
{
FrameFormat frameFormat = config.FrameFormat;
bool isLuma = plane == 0;
bool isField = frameFormat.IsField();
bool isTopField = frameFormat.IsTopField(isLuma);
int stride = GetPitch(width, bytesPerPixel);
uint offset = GetOffset(ref offsets[0], plane);
int dstStart = 0;
int dstStride = stride;
if (isField)
{
dstStart = isTopField ? 0 : stride;
dstStride = stride * 2;
}
RentedBuffer buffer;
if (linear)
{
buffer = ReadBufferLinear(rm, offset, width, height, dstStart, dstStride, bytesPerPixel);
}
else
{
buffer = ReadBufferBlockLinear(rm, offset, width, height, dstStart, dstStride, bytesPerPixel, gobBlocksInY);
}
if (isField || frameFormat.IsInterlaced())
{
RentedBuffer prevBuffer = RentedBuffer.Empty;
RentedBuffer nextBuffer = RentedBuffer.Empty;
if (config.PrevFieldEnable)
{
prevBuffer = ReadBufferNoDeinterlace(rm, ref offsets[1], linear, plane, width, height, bytesPerPixel, gobBlocksInY);
}
if (config.NextFieldEnable)
{
nextBuffer = ReadBufferNoDeinterlace(rm, ref offsets[2], linear, plane, width, height, bytesPerPixel, gobBlocksInY);
}
int w = width * bytesPerPixel;
switch (config.DeinterlaceMode)
{
case DeinterlaceMode.Weave:
Scaler.DeinterlaceWeave(buffer.Data, prevBuffer.Data, w, stride, isTopField);
break;
case DeinterlaceMode.BobField:
Scaler.DeinterlaceBob(buffer.Data, w, stride, isTopField);
break;
case DeinterlaceMode.Bob:
bool isCurrentTop = isLuma ? config.IsEven : config.ChromaEven;
Scaler.DeinterlaceBob(buffer.Data, w, stride, isCurrentTop ^ frameFormat.IsInterlacedBottomFirst());
break;
case DeinterlaceMode.NewBob:
case DeinterlaceMode.Disi1:
Scaler.DeinterlaceMotionAdaptive(buffer.Data, prevBuffer.Data, nextBuffer.Data, w, stride, isTopField);
break;
case DeinterlaceMode.WeaveLumaBobFieldChroma:
if (isLuma)
{
Scaler.DeinterlaceWeave(buffer.Data, prevBuffer.Data, w, stride, isTopField);
}
else
{
Scaler.DeinterlaceBob(buffer.Data, w, stride, isTopField);
}
break;
default:
Logger.Error?.Print(LogClass.Vic, $"Unsupported deinterlace mode \"{config.DeinterlaceMode}\".");
break;
}
prevBuffer.Return(rm.BufferPool);
nextBuffer.Return(rm.BufferPool);
}
return buffer;
}
private static uint GetOffset(ref PlaneOffsets offsets, int plane)
{
return plane switch
{
0 => offsets.LumaOffset,
1 => offsets.ChromaUOffset,
2 => offsets.ChromaVOffset,
_ => throw new ArgumentOutOfRangeException(nameof(plane))
};
}
private static RentedBuffer ReadBufferNoDeinterlace(
ResourceManager rm,
ref PlaneOffsets offsets,
bool linear,
int plane,
int width, int width,
int height, int height,
int bytesPerPixel, int bytesPerPixel,
int gobBlocksInY) int gobBlocksInY)
{ {
int stride = GetPitch(width, bytesPerPixel); int stride = GetPitch(width, bytesPerPixel);
uint offset = GetOffset(ref offsets, plane);
if (linear) if (linear)
{ {
return gmm.GetSpan(ExtendOffset(offset), stride * height); return ReadBufferLinear(rm, offset, width, height, 0, stride, bytesPerPixel);
} }
return ReadBuffer(gmm, offset, width, height, stride, bytesPerPixel, gobBlocksInY); return ReadBufferBlockLinear(rm, offset, width, height, 0, stride, bytesPerPixel, gobBlocksInY);
} }
private static ReadOnlySpan<byte> ReadBuffer( private static RentedBuffer ReadBufferLinear(
MemoryManager gmm, ResourceManager rm,
uint offset, uint offset,
int width, int width,
int height, int height,
int dstStart,
int dstStride,
int bytesPerPixel)
{
int srcStride = GetPitch(width, bytesPerPixel);
int inSize = srcStride * height;
ReadOnlySpan<byte> src = rm.Gmm.GetSpan(ExtendOffset(offset), inSize);
int outSize = dstStride * height;
int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer);
Span<byte> dst = buffer;
dst = dst.Slice(0, outSize);
for (int y = 0; y < height; y++)
{
src.Slice(y * srcStride, srcStride).CopyTo(dst.Slice(dstStart + y * dstStride, srcStride));
}
return new RentedBuffer(dst, bufferIndex);
}
private static RentedBuffer ReadBufferBlockLinear(
ResourceManager rm,
uint offset,
int width,
int height,
int dstStart,
int dstStride, int dstStride,
int bytesPerPixel, int bytesPerPixel,
int gobBlocksInY) int gobBlocksInY)
{ {
int inSize = GetBlockLinearSize(width, height, bytesPerPixel, gobBlocksInY); int inSize = GetBlockLinearSize(width, height, bytesPerPixel, gobBlocksInY);
ReadOnlySpan<byte> src = gmm.GetSpan(ExtendOffset(offset), inSize); ReadOnlySpan<byte> src = rm.Gmm.GetSpan(ExtendOffset(offset), inSize);
Span<byte> dst = new byte[dstStride * height]; int outSize = dstStride * height;
int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer);
Span<byte> dst = buffer;
dst = dst.Slice(0, outSize);
LayoutConverter.ConvertBlockLinearToLinear(dst, width, height, dstStride, bytesPerPixel, gobBlocksInY, src); LayoutConverter.ConvertBlockLinearToLinear(dst.Slice(dstStart), width, height, dstStride, bytesPerPixel, gobBlocksInY, src);
return dst; return new RentedBuffer(dst, bufferIndex);
} }
} }
} }

View file

@ -433,7 +433,7 @@ namespace Ryujinx.Graphics.Vic.Image
{ {
if (linear) if (linear)
{ {
rm.Gmm.Write(ExtendOffset(offset), src); rm.Gmm.WriteMapped(ExtendOffset(offset), src);
return; return;
} }
@ -456,7 +456,7 @@ namespace Ryujinx.Graphics.Vic.Image
LayoutConverter.ConvertLinearToBlockLinear(dst, width, height, dstStride, bytesPerPixel, gobBlocksInY, src); LayoutConverter.ConvertLinearToBlockLinear(dst, width, height, dstStride, bytesPerPixel, gobBlocksInY, src);
rm.Gmm.Write(ExtendOffset(offset), dst); rm.Gmm.WriteMapped(ExtendOffset(offset), dst);
rm.BufferPool.Return(dstIndex); rm.BufferPool.Return(dstIndex);
} }

View file

@ -0,0 +1,124 @@
using System;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Ryujinx.Graphics.Vic
{
static class Scaler
{
public static void DeinterlaceWeave(Span<byte> data, ReadOnlySpan<byte> prevData, int width, int fieldSize, bool isTopField)
{
// Prev I Curr I Curr P
// TTTTTTTT BBBBBBBB TTTTTTTT
// -------- -------- BBBBBBBB
if (isTopField)
{
for (int offset = 0; offset < data.Length; offset += fieldSize * 2)
{
prevData.Slice(offset >> 1, width).CopyTo(data.Slice(offset + fieldSize, width));
}
}
else
{
for (int offset = 0; offset < data.Length; offset += fieldSize * 2)
{
prevData.Slice(offset >> 1, width).CopyTo(data.Slice(offset, width));
}
}
}
public static void DeinterlaceBob(Span<byte> data, int width, int fieldSize, bool isTopField)
{
// Curr I Curr P
// TTTTTTTT TTTTTTTT
// -------- TTTTTTTT
if (isTopField)
{
for (int offset = 0; offset < data.Length; offset += fieldSize * 2)
{
data.Slice(offset, width).CopyTo(data.Slice(offset + fieldSize, width));
}
}
else
{
for (int offset = 0; offset < data.Length; offset += fieldSize * 2)
{
data.Slice(offset + fieldSize, width).CopyTo(data.Slice(offset, width));
}
}
}
public unsafe static void DeinterlaceMotionAdaptive(
Span<byte> data,
ReadOnlySpan<byte> prevData,
ReadOnlySpan<byte> nextData,
int width,
int fieldSize,
bool isTopField)
{
// Very simple motion adaptive algorithm.
// If the pixel changed between previous and next frame, use Bob, otherwise use Weave.
//
// Example pseudo code:
// C_even = (P_even == N_even) ? P_even : C_odd
// Where: C is current frame, P is previous frame and N is next frame, and even/odd are the fields.
//
// Note: This does not fully match the hardware algorithm.
// The motion adaptive deinterlacing implemented on hardware is considerably more complex,
// and hard to implement accurately without proper documentation as for example, the
// method used for motion estimation is unknown.
int start = isTopField ? fieldSize : 0;
int otherFieldOffset = isTopField ? -fieldSize : fieldSize;
fixed (byte* pData = data, pPrevData = prevData, pNextData = nextData)
{
for (int offset = start; offset < data.Length; offset += fieldSize * 2)
{
int refOffset = (offset - start) >> 1;
int x = 0;
if (Avx2.IsSupported)
{
for (; x < (width & ~0x1f); x += 32)
{
Vector256<byte> prevPixels = Avx.LoadVector256(pPrevData + refOffset + x);
Vector256<byte> nextPixels = Avx.LoadVector256(pNextData + refOffset + x);
Vector256<byte> bob = Avx.LoadVector256(pData + offset + otherFieldOffset + x);
Vector256<byte> diff = Avx2.CompareEqual(prevPixels, nextPixels);
Avx.Store(pData + offset + x, Avx2.BlendVariable(bob, prevPixels, diff));
}
}
else if (Sse41.IsSupported)
{
for (; x < (width & ~0xf); x += 16)
{
Vector128<byte> prevPixels = Sse2.LoadVector128(pPrevData + refOffset + x);
Vector128<byte> nextPixels = Sse2.LoadVector128(pNextData + refOffset + x);
Vector128<byte> bob = Sse2.LoadVector128(pData + offset + otherFieldOffset + x);
Vector128<byte> diff = Sse2.CompareEqual(prevPixels, nextPixels);
Sse2.Store(pData + offset + x, Sse41.BlendVariable(bob, prevPixels, diff));
}
}
for (; x < width; x++)
{
byte prevPixel = prevData[refOffset + x];
byte nextPixel = nextData[refOffset + x];
if (nextPixel != prevPixel)
{
data[offset + x] = data[offset + otherFieldOffset + x];
}
else
{
data[offset + x] = prevPixel;
}
}
}
}
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.Vic.Types
{
enum DeinterlaceMode
{
Weave,
BobField,
Bob,
NewBob,
Disi1,
WeaveLumaBobFieldChroma
}
}

View file

@ -0,0 +1,79 @@
namespace Ryujinx.Graphics.Vic.Types
{
enum FrameFormat
{
Progressive,
InterlacedTopFieldFirst,
InterlacedBottomFieldFirst,
TopField,
BottomField,
SubPicProgressive,
SubPicInterlacedTopFieldFirst,
SubPicInterlacedBottomFieldFirst,
SubPicTopField,
SubPicBottomField,
TopFieldChromaBottom,
BottomFieldChromaTop,
SubPicTopFieldChromaBottom,
SubPicBottomFieldChromaTop
}
static class FrameFormatExtensions
{
public static bool IsField(this FrameFormat frameFormat)
{
switch (frameFormat)
{
case FrameFormat.TopField:
case FrameFormat.BottomField:
case FrameFormat.SubPicTopField:
case FrameFormat.SubPicBottomField:
case FrameFormat.TopFieldChromaBottom:
case FrameFormat.BottomFieldChromaTop:
case FrameFormat.SubPicTopFieldChromaBottom:
case FrameFormat.SubPicBottomFieldChromaTop:
return true;
}
return false;
}
public static bool IsInterlaced(this FrameFormat frameFormat)
{
switch (frameFormat)
{
case FrameFormat.InterlacedTopFieldFirst:
case FrameFormat.InterlacedBottomFieldFirst:
case FrameFormat.SubPicInterlacedTopFieldFirst:
case FrameFormat.SubPicInterlacedBottomFieldFirst:
return true;
}
return false;
}
public static bool IsInterlacedBottomFirst(this FrameFormat frameFormat)
{
return frameFormat == FrameFormat.InterlacedBottomFieldFirst ||
frameFormat == FrameFormat.SubPicInterlacedBottomFieldFirst;
}
public static bool IsTopField(this FrameFormat frameFormat, bool isLuma)
{
switch (frameFormat)
{
case FrameFormat.TopField:
case FrameFormat.SubPicTopField:
return true;
case FrameFormat.TopFieldChromaBottom:
case FrameFormat.SubPicTopFieldChromaBottom:
return isLuma;
case FrameFormat.BottomFieldChromaTop:
case FrameFormat.SubPicBottomFieldChromaTop:
return !isLuma;
}
return false;
}
}
}

View file

@ -27,7 +27,7 @@
public bool PrevMotionFieldEnable => _word0.Extract(13); public bool PrevMotionFieldEnable => _word0.Extract(13);
public bool PpMotionFieldEnable => _word0.Extract(14); public bool PpMotionFieldEnable => _word0.Extract(14);
public bool CombMotionFieldEnable => _word0.Extract(15); public bool CombMotionFieldEnable => _word0.Extract(15);
public int FrameFormat => _word0.Extract(16, 4); public FrameFormat FrameFormat => (FrameFormat)_word0.Extract(16, 4);
public int FilterLengthY => _word0.Extract(20, 2); public int FilterLengthY => _word0.Extract(20, 2);
public int FilterLengthX => _word0.Extract(22, 2); public int FilterLengthX => _word0.Extract(22, 2);
public int Panoramic => _word0.Extract(24, 12); public int Panoramic => _word0.Extract(24, 12);
@ -36,7 +36,7 @@
public int FilterDetail => _word1.Extract(74, 10); public int FilterDetail => _word1.Extract(74, 10);
public int ChromaNoise => _word1.Extract(84, 10); public int ChromaNoise => _word1.Extract(84, 10);
public int ChromaDetail => _word1.Extract(94, 10); public int ChromaDetail => _word1.Extract(94, 10);
public int DeinterlaceMode => _word1.Extract(104, 4); public DeinterlaceMode DeinterlaceMode => (DeinterlaceMode)_word1.Extract(104, 4);
public int MotionAccumWeight => _word1.Extract(108, 3); public int MotionAccumWeight => _word1.Extract(108, 3);
public int NoiseIir => _word1.Extract(111, 11); public int NoiseIir => _word1.Extract(111, 11);
public int LightLevel => _word1.Extract(122, 4); public int LightLevel => _word1.Extract(122, 4);

View file

@ -43,9 +43,9 @@ namespace Ryujinx.Graphics.Vic
continue; continue;
} }
var offsets = _state.State.SetSurfacexSlotx[i][0]; ref var offsets = ref _state.State.SetSurfacexSlotx[i];
using Surface src = SurfaceReader.Read(_rm, ref slot.SlotSurfaceConfig, ref offsets); using Surface src = SurfaceReader.Read(_rm, ref slot.SlotConfig, ref slot.SlotSurfaceConfig, ref offsets);
Blender.BlendOne(output, src, ref slot); Blender.BlendOne(output, src, ref slot);
} }

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Graphics.Video
{
public enum FrameField
{
Progressive,
Interlaced
}
}

View file

@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Video
Plane UPlane { get; } Plane UPlane { get; }
Plane VPlane { get; } Plane VPlane { get; }
FrameField Field { get; }
int Width { get; } int Width { get; }
int Height { get; } int Height { get; }
int Stride { get; } int Stride { get; }

View file

@ -1,19 +0,0 @@
namespace Ryujinx.HLE.FileSystem.Content
{
static class ContentPath
{
public const string SystemContent = "@SystemContent";
public const string UserContent = "@UserContent";
public const string SdCardContent = "@SdCardContent";
public const string SdCard = "@SdCard";
public const string CalibFile = "@CalibFile";
public const string Safe = "@Safe";
public const string User = "@User";
public const string System = "@System";
public const string Host = "@Host";
public const string GamecardApp = "@GcApp";
public const string GamecardContents = "@GcS00000001";
public const string GamecardUpdate = "@upp";
public const string RegisteredUpdate = "@RegUpdate";
}
}

View file

@ -1,91 +0,0 @@
using System;
using System.IO;
using static Ryujinx.HLE.FileSystem.VirtualFileSystem;
namespace Ryujinx.HLE.FileSystem.Content
{
internal static class LocationHelper
{
public static string GetRealPath(VirtualFileSystem fileSystem, string switchContentPath)
{
string basePath = fileSystem.GetBasePath();
switch (switchContentPath)
{
case ContentPath.SystemContent:
return Path.Combine(basePath, SystemNandPath, "Contents");
case ContentPath.UserContent:
return Path.Combine(basePath, UserNandPath, "Contents");
case ContentPath.SdCardContent:
return Path.Combine(fileSystem.GetSdCardPath(), "Nintendo", "Contents");
case ContentPath.System:
return Path.Combine(basePath, SystemNandPath);
case ContentPath.User:
return Path.Combine(basePath, UserNandPath);
default:
throw new NotSupportedException($"Content Path `{switchContentPath}` is not supported.");
}
}
public static string GetContentPath(ContentStorageId contentStorageId)
{
switch (contentStorageId)
{
case ContentStorageId.NandSystem:
return ContentPath.SystemContent;
case ContentStorageId.NandUser:
return ContentPath.UserContent;
case ContentStorageId.SdCard:
return ContentPath.SdCardContent;
default:
throw new NotSupportedException($"Content Storage `{contentStorageId}` is not supported.");
}
}
public static string GetContentRoot(StorageId storageId)
{
switch (storageId)
{
case StorageId.NandSystem:
return ContentPath.SystemContent;
case StorageId.NandUser:
return ContentPath.UserContent;
case StorageId.SdCard:
return ContentPath.SdCardContent;
default:
throw new NotSupportedException($"Storage Id `{storageId}` is not supported.");
}
}
public static StorageId GetStorageId(string contentPathString)
{
string cleanedPath = contentPathString.Split(':')[0];
switch (cleanedPath)
{
case ContentPath.SystemContent:
case ContentPath.System:
return StorageId.NandSystem;
case ContentPath.UserContent:
case ContentPath.User:
return StorageId.NandUser;
case ContentPath.SdCardContent:
return StorageId.SdCard;
case ContentPath.Host:
return StorageId.Host;
case ContentPath.GamecardApp:
case ContentPath.GamecardContents:
case ContentPath.GamecardUpdate:
return StorageId.GameCard;
default:
return StorageId.None;
}
}
}
}

View file

@ -1,9 +0,0 @@
namespace Ryujinx.HLE.FileSystem.Content
{
public enum ContentStorageId
{
NandSystem,
NandUser,
SdCard
}
}

View file

@ -1,15 +0,0 @@
namespace Ryujinx.HLE.FileSystem.Content
{
enum TitleType
{
SystemPrograms = 0x01,
SystemDataArchive = 0x02,
SystemUpdate = 0x03,
FirmwarePackageA = 0x04,
FirmwarePackageB = 0x05,
RegularApplication = 0x80,
Update = 0x81,
AddOnContent = 0x82,
DeltaTitle = 0x83
}
}

View file

@ -20,7 +20,7 @@ using System.IO.Compression;
using System.Linq; using System.Linq;
using Path = System.IO.Path; using Path = System.IO.Path;
namespace Ryujinx.HLE.FileSystem.Content namespace Ryujinx.HLE.FileSystem
{ {
public class ContentManager public class ContentManager
{ {
@ -110,8 +110,8 @@ namespace Ryujinx.HLE.FileSystem.Content
try try
{ {
contentPathString = LocationHelper.GetContentRoot(storageId); contentPathString = ContentPath.GetContentPath(storageId);
contentDirectory = LocationHelper.GetRealPath(_virtualFileSystem, contentPathString); contentDirectory = ContentPath.GetRealPath(_virtualFileSystem, contentPathString);
registeredDirectory = Path.Combine(contentDirectory, "registered"); registeredDirectory = Path.Combine(contentDirectory, "registered");
} }
catch (NotSupportedException) catch (NotSupportedException)
@ -367,8 +367,7 @@ namespace Ryujinx.HLE.FileSystem.Content
{ {
LocationEntry locationEntry = GetLocation(titleId, contentType, storageId); LocationEntry locationEntry = GetLocation(titleId, contentType, storageId);
return locationEntry.ContentPath != null ? return locationEntry.ContentPath != null ? ContentPath.GetStorageId(locationEntry.ContentPath) : StorageId.None;
LocationHelper.GetStorageId(locationEntry.ContentPath) : StorageId.None;
} }
} }
@ -493,8 +492,8 @@ namespace Ryujinx.HLE.FileSystem.Content
public void InstallFirmware(string firmwareSource) public void InstallFirmware(string firmwareSource)
{ {
string contentPathString = LocationHelper.GetContentRoot(StorageId.NandSystem); string contentPathString = ContentPath.GetContentPath(StorageId.BuiltInSystem);
string contentDirectory = LocationHelper.GetRealPath(_virtualFileSystem, contentPathString); string contentDirectory = ContentPath.GetRealPath(_virtualFileSystem, contentPathString);
string registeredDirectory = Path.Combine(contentDirectory, "registered"); string registeredDirectory = Path.Combine(contentDirectory, "registered");
string temporaryDirectory = Path.Combine(contentDirectory, "temp"); string temporaryDirectory = Path.Combine(contentDirectory, "temp");
@ -998,9 +997,9 @@ namespace Ryujinx.HLE.FileSystem.Content
foreach (var entry in updateNcas) foreach (var entry in updateNcas)
{ {
foreach (var nca in entry.Value) foreach (var (type, path) in entry.Value)
{ {
extraNcas += nca.path + Environment.NewLine; extraNcas += path + Environment.NewLine;
} }
} }
@ -1019,7 +1018,7 @@ namespace Ryujinx.HLE.FileSystem.Content
lock (_lock) lock (_lock)
{ {
var locationEnties = _locationEntries[StorageId.NandSystem]; var locationEnties = _locationEntries[StorageId.BuiltInSystem];
foreach (var entry in locationEnties) foreach (var entry in locationEnties)
{ {

View file

@ -0,0 +1,82 @@
using LibHac.Fs;
using LibHac.Ncm;
using Ryujinx.Common.Configuration;
using System;
using static Ryujinx.HLE.FileSystem.VirtualFileSystem;
using Path = System.IO.Path;
namespace Ryujinx.HLE.FileSystem
{
internal static class ContentPath
{
public const string SystemContent = "@SystemContent";
public const string UserContent = "@UserContent";
public const string SdCardContent = "@SdCardContent";
public const string SdCard = "@Sdcard";
public const string CalibFile = "@CalibFile";
public const string Safe = "@Safe";
public const string User = "@User";
public const string System = "@System";
public const string Host = "@Host";
public const string GamecardApp = "@GcApp";
public const string GamecardContents = "@GcS00000001";
public const string GamecardUpdate = "@upp";
public const string RegisteredUpdate = "@RegUpdate";
public const string Nintendo = "Nintendo";
public const string Contents = "Contents";
public static string GetRealPath(VirtualFileSystem fileSystem, string switchContentPath)
{
return switchContentPath switch
{
SystemContent => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath, Contents),
UserContent => Path.Combine(AppDataManager.BaseDirPath, UserNandPath, Contents),
SdCardContent => Path.Combine(fileSystem.GetSdCardPath(), Nintendo, Contents),
System => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath),
User => Path.Combine(AppDataManager.BaseDirPath, UserNandPath),
_ => throw new NotSupportedException($"Content Path \"`{switchContentPath}`\" is not supported.")
};
}
public static string GetContentPath(ContentStorageId contentStorageId)
{
return contentStorageId switch
{
ContentStorageId.System => SystemContent,
ContentStorageId.User => UserContent,
ContentStorageId.SdCard => SdCardContent,
_ => throw new NotSupportedException($"Content Storage Id \"`{contentStorageId}`\" is not supported.")
};
}
public static string GetContentPath(StorageId storageId)
{
return storageId switch
{
StorageId.BuiltInSystem => SystemContent,
StorageId.BuiltInUser => UserContent,
StorageId.SdCard => SdCardContent,
_ => throw new NotSupportedException($"Storage Id \"`{storageId}`\" is not supported.")
};
}
public static StorageId GetStorageId(string contentPathString)
{
return contentPathString.Split(':')[0] switch
{
SystemContent or
System => StorageId.BuiltInSystem,
UserContent or
User => StorageId.BuiltInUser,
SdCardContent => StorageId.SdCard,
Host => StorageId.Host,
GamecardApp or
GamecardContents or
GamecardUpdate => StorageId.GameCard,
_ => StorageId.None
};
}
}
}

View file

@ -8,7 +8,6 @@ namespace Ryujinx.HLE.FileSystem
{ {
public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator
{ {
public Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem, public Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem,
ref SharedRef<IFileSystem> baseFileSystem, IEncryptedFileSystemCreator.KeyId idIndex, ref SharedRef<IFileSystem> baseFileSystem, IEncryptedFileSystemCreator.KeyId idIndex,
in EncryptionSeed encryptionSeed) in EncryptionSeed encryptionSeed)
@ -18,7 +17,7 @@ namespace Ryujinx.HLE.FileSystem
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
} }
// Todo: Reenable when AesXtsFileSystem is fixed // TODO: Reenable when AesXtsFileSystem is fixed.
outEncryptedFileSystem = SharedRef<IFileSystem>.CreateMove(ref baseFileSystem); outEncryptedFileSystem = SharedRef<IFileSystem>.CreateMove(ref baseFileSystem);
return Result.Success; return Result.Success;

View file

@ -1,6 +1,6 @@
using LibHac.FsSystem; using LibHac.FsSystem;
namespace Ryujinx.HLE.FileSystem.Content namespace Ryujinx.HLE.FileSystem
{ {
public struct LocationEntry public struct LocationEntry
{ {

View file

@ -1,12 +0,0 @@
namespace Ryujinx.HLE.FileSystem
{
enum SaveDataType : byte
{
SystemSaveData,
SaveData,
BcatDeliveryCacheStorage,
DeviceSaveData,
TemporaryStorage,
CacheStorage
}
}

View file

@ -1,27 +0,0 @@
using Ryujinx.HLE.HOS.Services.Account.Acc;
namespace Ryujinx.HLE.FileSystem
{
struct SaveInfo
{
public ulong TitleId { get; private set; }
public long SaveId { get; private set; }
public SaveDataType SaveDataType { get; private set; }
public SaveSpaceId SaveSpaceId { get; private set; }
public UserId UserId { get; private set; }
public SaveInfo(
ulong titleId,
long saveId,
SaveDataType saveDataType,
SaveSpaceId saveSpaceId,
UserId userId = new UserId())
{
TitleId = titleId;
SaveId = saveId;
SaveDataType = saveDataType;
SaveSpaceId = saveSpaceId;
UserId = userId;
}
}
}

View file

@ -1,10 +0,0 @@
namespace Ryujinx.HLE.FileSystem
{
enum SaveSpaceId
{
NandSystem,
NandUser,
SdCard,
TemporaryStorage
}
}

View file

@ -1,12 +0,0 @@
namespace Ryujinx.HLE.FileSystem
{
public enum StorageId
{
None,
Host,
GameCard,
NandSystem,
NandUser,
SdCard
}
}

View file

@ -1,8 +1,7 @@
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System.IO; using System.IO;
using System.Text;
namespace Ryujinx.HLE.FileSystem.Content namespace Ryujinx.HLE.FileSystem
{ {
public class SystemVersion public class SystemVersion
{ {

View file

@ -13,7 +13,6 @@ using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using System; using System;
using System.Buffers.Text; using System.Buffers.Text;
@ -28,20 +27,29 @@ namespace Ryujinx.HLE.FileSystem
{ {
public class VirtualFileSystem : IDisposable public class VirtualFileSystem : IDisposable
{ {
public const string NandPath = AppDataManager.DefaultNandDir; public static string SafeNandPath = Path.Combine(AppDataManager.DefaultNandDir, "safe");
public const string SdCardPath = AppDataManager.DefaultSdcardDir; public static string SystemNandPath = Path.Combine(AppDataManager.DefaultNandDir, "system");
public static string UserNandPath = Path.Combine(AppDataManager.DefaultNandDir, "user");
public static string SafeNandPath = Path.Combine(NandPath, "safe");
public static string SystemNandPath = Path.Combine(NandPath, "system");
public static string UserNandPath = Path.Combine(NandPath, "user");
private static bool _isInitialized = false;
public KeySet KeySet { get; private set; } public KeySet KeySet { get; private set; }
public EmulatedGameCard GameCard { get; private set; } public EmulatedGameCard GameCard { get; private set; }
public EmulatedSdCard SdCard { get; private set; } public EmulatedSdCard SdCard { get; private set; }
public ModLoader ModLoader { get; private set; } public ModLoader ModLoader { get; private set; }
public Stream RomFs { get; private set; }
private static bool _isInitialized = false;
public static VirtualFileSystem CreateInstance()
{
if (_isInitialized)
{
throw new InvalidOperationException("VirtualFileSystem can only be instantiated once!");
}
_isInitialized = true;
return new VirtualFileSystem();
}
private VirtualFileSystem() private VirtualFileSystem()
{ {
@ -49,8 +57,6 @@ namespace Ryujinx.HLE.FileSystem
ModLoader = new ModLoader(); // Should only be created once ModLoader = new ModLoader(); // Should only be created once
} }
public Stream RomFs { get; private set; }
public void LoadRomFs(string fileName) public void LoadRomFs(string fileName)
{ {
RomFs = new FileStream(fileName, FileMode.Open, FileAccess.Read); RomFs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
@ -79,7 +85,7 @@ namespace Ryujinx.HLE.FileSystem
string fullPath = Path.GetFullPath(Path.Combine(basePath, fileName)); string fullPath = Path.GetFullPath(Path.Combine(basePath, fileName));
if (!fullPath.StartsWith(GetBasePath())) if (!fullPath.StartsWith(AppDataManager.BaseDirPath))
{ {
return null; return null;
} }
@ -87,14 +93,8 @@ namespace Ryujinx.HLE.FileSystem
return fullPath; return fullPath;
} }
internal string GetBasePath() => AppDataManager.BaseDirPath; internal string GetSdCardPath() => MakeFullPath(AppDataManager.DefaultSdcardDir);
internal string GetSdCardPath() => MakeFullPath(SdCardPath); public string GetNandPath() => MakeFullPath(AppDataManager.DefaultNandDir);
public string GetNandPath() => MakeFullPath(NandPath);
public string GetFullPartitionPath(string partitionPath)
{
return MakeFullPath(partitionPath);
}
public string SwitchPathToSystemPath(string switchPath) public string SwitchPathToSystemPath(string switchPath)
{ {
@ -110,7 +110,7 @@ namespace Ryujinx.HLE.FileSystem
public string SystemPathToSwitchPath(string systemPath) public string SystemPathToSwitchPath(string systemPath)
{ {
string baseSystemPath = GetBasePath() + Path.DirectorySeparatorChar; string baseSystemPath = AppDataManager.BaseDirPath + Path.DirectorySeparatorChar;
if (systemPath.StartsWith(baseSystemPath)) if (systemPath.StartsWith(baseSystemPath))
{ {
@ -136,8 +136,7 @@ namespace Ryujinx.HLE.FileSystem
switch (path) switch (path)
{ {
case ContentPath.SdCard: case ContentPath.SdCard:
case "@Sdcard": path = AppDataManager.DefaultSdcardDir;
path = SdCardPath;
break; break;
case ContentPath.User: case ContentPath.User:
path = UserNandPath; path = UserNandPath;
@ -146,7 +145,7 @@ namespace Ryujinx.HLE.FileSystem
path = SystemNandPath; path = SystemNandPath;
break; break;
case ContentPath.SdCardContent: case ContentPath.SdCardContent:
path = Path.Combine(SdCardPath, "Nintendo", "Contents"); path = Path.Combine(AppDataManager.DefaultSdcardDir, "Nintendo", "Contents");
break; break;
case ContentPath.UserContent: case ContentPath.UserContent:
path = Path.Combine(UserNandPath, "Contents"); path = Path.Combine(UserNandPath, "Contents");
@ -156,27 +155,19 @@ namespace Ryujinx.HLE.FileSystem
break; break;
} }
string fullPath = Path.Combine(GetBasePath(), path); string fullPath = Path.Combine(AppDataManager.BaseDirPath, path);
if (isDirectory) if (isDirectory && !Directory.Exists(fullPath))
{
if (!Directory.Exists(fullPath))
{ {
Directory.CreateDirectory(fullPath); Directory.CreateDirectory(fullPath);
} }
}
return fullPath; return fullPath;
} }
public DriveInfo GetDrive()
{
return new DriveInfo(Path.GetPathRoot(GetBasePath()));
}
public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient) public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient)
{ {
LocalFileSystem serverBaseFs = new LocalFileSystem(GetBasePath()); LocalFileSystem serverBaseFs = new LocalFileSystem(AppDataManager.BaseDirPath);
fsServerClient = horizon.CreatePrivilegedHorizonClient(); fsServerClient = horizon.CreatePrivilegedHorizonClient();
var fsServer = new FileSystemServer(fsServerClient); var fsServer = new FileSystemServer(fsServerClient);
@ -505,7 +496,7 @@ namespace Ryujinx.HLE.FileSystem
bool canFixBySaveDataId = extraData.Attribute.StaticSaveDataId == 0 && info.StaticSaveDataId != 0; bool canFixBySaveDataId = extraData.Attribute.StaticSaveDataId == 0 && info.StaticSaveDataId != 0;
bool hasEmptyOwnerId = extraData.OwnerId == 0 && info.Type != LibHac.Fs.SaveDataType.System; bool hasEmptyOwnerId = extraData.OwnerId == 0 && info.Type != SaveDataType.System;
if (!canFixByProgramId && !canFixBySaveDataId && !hasEmptyOwnerId) if (!canFixByProgramId && !canFixBySaveDataId && !hasEmptyOwnerId)
{ {
@ -523,7 +514,7 @@ namespace Ryujinx.HLE.FileSystem
// The rest of the extra data can't be created from the save data info. // The rest of the extra data can't be created from the save data info.
// On user saves the owner ID will almost certainly be the same as the program ID. // On user saves the owner ID will almost certainly be the same as the program ID.
if (info.Type != LibHac.Fs.SaveDataType.System) if (info.Type != SaveDataType.System)
{ {
extraData.OwnerId = info.ProgramId.Value; extraData.OwnerId = info.ProgramId.Value;
} }
@ -580,11 +571,6 @@ namespace Ryujinx.HLE.FileSystem
} }
}; };
public void Unload()
{
RomFs?.Dispose();
}
public void Dispose() public void Dispose()
{ {
Dispose(true); Dispose(true);
@ -594,20 +580,8 @@ namespace Ryujinx.HLE.FileSystem
{ {
if (disposing) if (disposing)
{ {
Unload(); RomFs?.Dispose();
} }
}
public static VirtualFileSystem CreateInstance()
{
if (_isInitialized)
{
throw new InvalidOperationException("VirtualFileSystem can only be instantiated once!");
}
_isInitialized = true;
return new VirtualFileSystem();
} }
} }
} }

View file

@ -3,7 +3,6 @@ using Ryujinx.Audio.Integration;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;

View file

@ -2,10 +2,10 @@
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Services.Am.AppletAE; using Ryujinx.HLE.HOS.Services.Am.AppletAE;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using System; using System;
@ -106,7 +106,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
private string GetMessageText(uint module, uint description, string key) private string GetMessageText(uint module, uint description, string key)
{ {
string binaryTitleContentPath = _horizon.ContentManager.GetInstalledContentPath(ErrorMessageBinaryTitleId, StorageId.NandSystem, NcaContentType.Data); string binaryTitleContentPath = _horizon.ContentManager.GetInstalledContentPath(ErrorMessageBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data);
using (LibHac.Fs.IStorage ncaFileStream = new LocalStorage(_horizon.Device.FileSystem.SwitchPathToSystemPath(binaryTitleContentPath), FileAccess.Read, FileMode.Open)) using (LibHac.Fs.IStorage ncaFileStream = new LocalStorage(_horizon.Device.FileSystem.SwitchPathToSystemPath(binaryTitleContentPath), FileAccess.Read, FileMode.Open))
{ {

View file

@ -10,7 +10,7 @@ using Ryujinx.Audio.Integration;
using Ryujinx.Audio.Output; using Ryujinx.Audio.Output;
using Ryujinx.Audio.Renderer.Device; using Ryujinx.Audio.Renderer.Device;
using Ryujinx.Audio.Renderer.Server; using Ryujinx.Audio.Renderer.Server;
using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Process;
@ -238,6 +238,7 @@ namespace Ryujinx.HLE.HOS
SurfaceFlinger = new SurfaceFlinger(device); SurfaceFlinger = new SurfaceFlinger(device);
InitializeAudioRenderer(); InitializeAudioRenderer();
InitializeServices();
} }
private void InitializeAudioRenderer() private void InitializeAudioRenderer()
@ -288,7 +289,7 @@ namespace Ryujinx.HLE.HOS
AudioManager.Start(); AudioManager.Start();
} }
public void InitializeServices() private void InitializeServices()
{ {
SmServer = new ServerBase(KernelContext, "SmServer", () => new IUserInterface(KernelContext)); SmServer = new ServerBase(KernelContext, "SmServer", () => new IUserInterface(KernelContext));

View file

@ -1,4 +1,4 @@
using Ryujinx.HLE.FileSystem; using LibHac.Ncm;
namespace Ryujinx.HLE.HOS.Services.Arp namespace Ryujinx.HLE.HOS.Services.Arp
{ {
@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Arp
{ {
TitleId = 0x00, TitleId = 0x00,
Version = 0x00, Version = 0x00,
BaseGameStorageId = (byte)StorageId.NandSystem, BaseGameStorageId = (byte)StorageId.BuiltInSystem,
UpdateGameStorageId = (byte)StorageId.None UpdateGameStorageId = (byte)StorageId.None
}; };
} }
@ -35,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Arp
{ {
TitleId = context.Device.Application.TitleId, TitleId = context.Device.Application.TitleId,
Version = 0x00, Version = 0x00,
BaseGameStorageId = (byte)StorageId.NandSystem, BaseGameStorageId = (byte)StorageId.BuiltInSystem,
UpdateGameStorageId = (byte)StorageId.None UpdateGameStorageId = (byte)StorageId.None
}; };
} }

View file

@ -2,7 +2,6 @@ using LibHac;
using LibHac.Common; using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Shim; using LibHac.Fs.Shim;
using LibHac.FsSrv;
using LibHac.FsSrv.Impl; using LibHac.FsSrv.Impl;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm; using LibHac.Ncm;
@ -19,7 +18,6 @@ using static Ryujinx.HLE.Utilities.StringUtils;
using IFileSystem = LibHac.FsSrv.Sf.IFileSystem; using IFileSystem = LibHac.FsSrv.Sf.IFileSystem;
using IStorage = LibHac.FsSrv.Sf.IStorage; using IStorage = LibHac.FsSrv.Sf.IStorage;
using RightsId = LibHac.Fs.RightsId; using RightsId = LibHac.Fs.RightsId;
using StorageId = Ryujinx.HLE.FileSystem.StorageId;
namespace Ryujinx.HLE.HOS.Services.Fs namespace Ryujinx.HLE.HOS.Services.Fs
{ {

View file

@ -55,9 +55,11 @@ namespace Ryujinx.HLE.HOS.Services.Hid
_storage = storage; _storage = storage;
SharedMemory = SharedMemory.Create(); SharedMemory = SharedMemory.Create();
InitDevices();
} }
public void InitDevices() private void InitDevices()
{ {
DebugPad = new DebugPadDevice(_device, true); DebugPad = new DebugPadDevice(_device, true);
Touchscreen = new TouchDevice(_device, true); Touchscreen = new TouchDevice(_device, true);

View file

@ -1,4 +1,4 @@
using Ryujinx.HLE.FileSystem; using LibHac.Ncm;
using Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager; using Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager;
namespace Ryujinx.HLE.HOS.Services.Ncm.Lr namespace Ryujinx.HLE.HOS.Services.Ncm.Lr

View file

@ -1,6 +1,6 @@
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using System.Text; using System.Text;
using static Ryujinx.HLE.Utilities.StringUtils; using static Ryujinx.HLE.Utilities.StringUtils;

View file

@ -1,5 +1,5 @@
using Ryujinx.Common.Logging; using LibHac.Ncm;
using Ryujinx.HLE.FileSystem; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Arp; using Ryujinx.HLE.HOS.Services.Arp;
using Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface; using Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface;

View file

@ -232,7 +232,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
ulong virtualAddress = arguments.Offset + arguments.BufferOffset; ulong virtualAddress = arguments.Offset + arguments.BufferOffset;
physicalAddress += arguments.BufferOffset; physicalAddress += arguments.BufferOffset;
_asContext.Gmm.Map(physicalAddress, virtualAddress, arguments.MappingSize); _asContext.Gmm.Map(physicalAddress, virtualAddress, arguments.MappingSize, (PteKind)arguments.Kind);
return NvInternalResult.Success; return NvInternalResult.Success;
} }
@ -282,7 +282,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
{ {
if (_asContext.ValidateFixedBuffer(arguments.Offset, size, pageSize)) if (_asContext.ValidateFixedBuffer(arguments.Offset, size, pageSize))
{ {
_asContext.Gmm.Map(physicalAddress, arguments.Offset, size); _asContext.Gmm.Map(physicalAddress, arguments.Offset, size, (PteKind)arguments.Kind);
} }
else else
{ {
@ -301,7 +301,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
_memoryAllocator.AllocateRange(va, size, freeAddressStartPosition); _memoryAllocator.AllocateRange(va, size, freeAddressStartPosition);
} }
_asContext.Gmm.Map(physicalAddress, va, size); _asContext.Gmm.Map(physicalAddress, va, size, (PteKind)arguments.Kind);
arguments.Offset = va; arguments.Offset = va;
} }
@ -366,26 +366,30 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
for (int index = 0; index < arguments.Length; index++) for (int index = 0; index < arguments.Length; index++)
{ {
ulong mapOffs = (ulong)arguments[index].MapOffset << 16; ref RemapArguments argument = ref arguments[index];
ulong gpuVa = (ulong)arguments[index].GpuOffset << 16; ulong gpuVa = (ulong)argument.GpuOffset << 16;
ulong size = (ulong)arguments[index].Pages << 16; ulong size = (ulong)argument.Pages << 16;
int nvmapHandle = argument.NvMapHandle;
if (arguments[index].NvMapHandle == 0) if (nvmapHandle == 0)
{ {
gmm.Unmap(gpuVa, size); gmm.Unmap(gpuVa, size);
} }
else else
{ {
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments[index].NvMapHandle); ulong mapOffs = (ulong)argument.MapOffset << 16;
PteKind kind = (PteKind)argument.Kind;
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, nvmapHandle);
if (map == null) if (map == null)
{ {
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments[index].NvMapHandle:x8}!"); Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid NvMap handle 0x{nvmapHandle:x8}!");
return NvInternalResult.InvalidInput; return NvInternalResult.InvalidInput;
} }
gmm.Map(mapOffs + map.Address, gpuVa, size); gmm.Map(mapOffs + map.Address, gpuVa, size, kind);
} }
} }

View file

@ -251,7 +251,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + (uint)map.Size) <= uint.MaxValue) if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + (uint)map.Size) <= uint.MaxValue)
{ {
_host1xContext.MemoryAllocator.AllocateRange(va, (uint)map.Size, freeAddressStartPosition); _host1xContext.MemoryAllocator.AllocateRange(va, (uint)map.Size, freeAddressStartPosition);
_host1xContext.Smmu.Map(map.Address, va, (uint)map.Size); _host1xContext.Smmu.Map(map.Address, va, (uint)map.Size, PteKind.Pitch); // FIXME: This should not use the GMMU.
map.DmaMapAddress = va; map.DmaMapAddress = va;
} }
else else

View file

@ -45,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Services.Olsc
return ResultCode.NullArgument; return ResultCode.NullArgument;
} }
if (_saveDataBackupSettingDatabase[userId]) if (_saveDataBackupSettingDatabase.TryGetValue(userId, out bool enabled) && enabled)
{ {
context.ResponseData.Write((byte)1); // TODO: Determine value. context.ResponseData.Write((byte)1); // TODO: Determine value.
} }

View file

@ -2,11 +2,11 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Services.Sdb.Pl.Types; using Ryujinx.HLE.HOS.Services.Sdb.Pl.Types;
using System; using System;
@ -63,7 +63,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
{ {
if (contentManager.TryGetFontTitle(name, out ulong fontTitle) && contentManager.TryGetFontFilename(name, out string fontFilename)) if (contentManager.TryGetFontTitle(name, out ulong fontTitle) && contentManager.TryGetFontFilename(name, out string fontFilename))
{ {
string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.NandSystem, NcaContentType.Data); string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.BuiltInSystem, NcaContentType.Data);
string fontPath = _device.FileSystem.SwitchPathToSystemPath(contentPath); string fontPath = _device.FileSystem.SwitchPathToSystemPath(contentPath);
if (!string.IsNullOrWhiteSpace(fontPath)) if (!string.IsNullOrWhiteSpace(fontPath))

View file

@ -3,9 +3,9 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System; using System;
@ -290,7 +290,7 @@ namespace Ryujinx.HLE.HOS.Services.Settings
{ {
const ulong SystemVersionTitleId = 0x0100000000000809; const ulong SystemVersionTitleId = 0x0100000000000809;
string contentPath = device.System.ContentManager.GetInstalledContentPath(SystemVersionTitleId, StorageId.NandSystem, NcaContentType.Data); string contentPath = device.System.ContentManager.GetInstalledContentPath(SystemVersionTitleId, StorageId.BuiltInSystem, NcaContentType.Data);
if (string.IsNullOrWhiteSpace(contentPath)) if (string.IsNullOrWhiteSpace(contentPath))
{ {

View file

@ -1,5 +1,4 @@
using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Services.Spl.Types; using Ryujinx.HLE.HOS.Services.Spl.Types;

View file

@ -3,13 +3,13 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Services.Ssl.Types; using Ryujinx.HLE.HOS.Services.Ssl.Types;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -82,7 +82,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
public string GetCertStoreTitleContentPath() public string GetCertStoreTitleContentPath()
{ {
return _contentManager.GetInstalledContentPath(CertStoreTitleId, StorageId.NandSystem, NcaContentType.Data); return _contentManager.GetInstalledContentPath(CertStoreTitleId, StorageId.BuiltInSystem, NcaContentType.Data);
} }
public bool HasCertStoreTitle() public bool HasCertStoreTitle()

View file

@ -3,12 +3,12 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Services.Time.Clock; using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System; using System;
@ -241,7 +241,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
public string GetTimeZoneBinaryTitleContentPath() public string GetTimeZoneBinaryTitleContentPath()
{ {
return _contentManager.GetInstalledContentPath(TimeZoneBinaryTitleId, StorageId.NandSystem, NcaContentType.Data); return _contentManager.GetInstalledContentPath(TimeZoneBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data);
} }
public bool HasTimeZoneBinaryTitle() public bool HasTimeZoneBinaryTitle()

View file

@ -14,25 +14,15 @@ namespace Ryujinx.HLE
public class Switch : IDisposable public class Switch : IDisposable
{ {
public HLEConfiguration Configuration { get; } public HLEConfiguration Configuration { get; }
public IHardwareDeviceDriver AudioDeviceDriver { get; } public IHardwareDeviceDriver AudioDeviceDriver { get; }
public MemoryBlock Memory { get; }
internal MemoryBlock Memory { get; }
public GpuContext Gpu { get; } public GpuContext Gpu { get; }
public VirtualFileSystem FileSystem { get; }
public VirtualFileSystem FileSystem => Configuration.VirtualFileSystem;
public Horizon System { get; } public Horizon System { get; }
public ApplicationLoader Application { get; } public ApplicationLoader Application { get; }
public PerformanceStatistics Statistics { get; } public PerformanceStatistics Statistics { get; }
public Hid Hid { get; } public Hid Hid { get; }
public TamperMachine TamperMachine { get; } public TamperMachine TamperMachine { get; }
public IHostUiHandler UiHandler { get; } public IHostUiHandler UiHandler { get; }
public bool EnableDeviceVsync { get; set; } = true; public bool EnableDeviceVsync { get; set; } = true;
@ -55,46 +45,26 @@ namespace Ryujinx.HLE
} }
Configuration = configuration; Configuration = configuration;
FileSystem = Configuration.VirtualFileSystem;
UiHandler = Configuration.HostUiHandler;
UiHandler = configuration.HostUiHandler; AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(Configuration.AudioDeviceDriver);
Memory = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), MemoryAllocationFlags.Reserve);
AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(configuration.AudioDeviceDriver); Gpu = new GpuContext(Configuration.GpuRenderer);
Memory = new MemoryBlock(configuration.MemoryConfiguration.ToDramSize(), MemoryAllocationFlags.Reserve);
Gpu = new GpuContext(configuration.GpuRenderer);
System = new Horizon(this); System = new Horizon(this);
System.InitializeServices();
Statistics = new PerformanceStatistics(); Statistics = new PerformanceStatistics();
Hid = new Hid(this, System.HidStorage); Hid = new Hid(this, System.HidStorage);
Hid.InitDevices();
Application = new ApplicationLoader(this); Application = new ApplicationLoader(this);
TamperMachine = new TamperMachine(); TamperMachine = new TamperMachine();
Initialize();
}
private void Initialize()
{
System.State.SetLanguage(Configuration.SystemLanguage); System.State.SetLanguage(Configuration.SystemLanguage);
System.State.SetRegion(Configuration.Region); System.State.SetRegion(Configuration.Region);
EnableDeviceVsync = Configuration.EnableVsync; EnableDeviceVsync = Configuration.EnableVsync;
System.State.DockedMode = Configuration.EnableDockedMode; System.State.DockedMode = Configuration.EnableDockedMode;
System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default; System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default;
System.EnablePtc = Configuration.EnablePtc; System.EnablePtc = Configuration.EnablePtc;
System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel; System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode; System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
} }
@ -132,7 +102,6 @@ namespace Ryujinx.HLE
{ {
Gpu.ProcessShaderCacheQueue(); Gpu.ProcessShaderCacheQueue();
Gpu.Renderer.PreFrame(); Gpu.Renderer.PreFrame();
Gpu.GPFifo.DispatchCalls(); Gpu.GPFifo.DispatchCalls();
} }
@ -182,7 +151,7 @@ namespace Ryujinx.HLE
{ {
System.Dispose(); System.Dispose();
AudioDeviceDriver.Dispose(); AudioDeviceDriver.Dispose();
FileSystem.Unload(); FileSystem.Dispose();
Memory.Dispose(); Memory.Dispose();
} }
} }

View file

@ -20,7 +20,6 @@ using Ryujinx.Graphics.OpenGL;
using Ryujinx.Headless.SDL2.OpenGL; using Ryujinx.Headless.SDL2.OpenGL;
using Ryujinx.HLE; using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.Input; using Ryujinx.Input;
@ -29,7 +28,6 @@ using Ryujinx.Input.SDL2;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;

View file

@ -188,7 +188,7 @@ namespace Ryujinx.Memory.Tests
Assert.False(alignedAfterTriggers); Assert.False(alignedAfterTriggers);
} }
[Test, Timeout(1000)] [Test, Explicit, Timeout(1000)]
public void Multithreading() public void Multithreading()
{ {
// Multithreading sanity test // Multithreading sanity test

View file

@ -1,5 +1,5 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.FileSystem;
using Ryujinx.Ui.Widgets; using Ryujinx.Ui.Widgets;
using System; using System;
using System.IO; using System.IO;

View file

@ -1,18 +1,10 @@
using System; using ARMeilleure.Translation;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using ARMeilleure.Translation;
using ARMeilleure.Translation.PTC; using ARMeilleure.Translation.PTC;
using Gtk; using Gtk;
using LibHac.Common; using LibHac.Common;
using LibHac.Common.Keys; using LibHac.Common.Keys;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Ns; using LibHac.Ns;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.Dummy; using Ryujinx.Audio.Backends.Dummy;
@ -29,7 +21,6 @@ using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.OpenGL; using Ryujinx.Graphics.OpenGL;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
@ -42,9 +33,14 @@ using Ryujinx.Ui.Applet;
using Ryujinx.Ui.Helper; using Ryujinx.Ui.Helper;
using Ryujinx.Ui.Widgets; using Ryujinx.Ui.Widgets;
using Ryujinx.Ui.Windows; using Ryujinx.Ui.Windows;
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using GUI = Gtk.Builder.ObjectAttribute; using GUI = Gtk.Builder.ObjectAttribute;
using PtcLoadingState = ARMeilleure.Translation.PTC.PtcLoadingState; using PtcLoadingState = ARMeilleure.Translation.PTC.PtcLoadingState;
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
@ -1283,7 +1279,7 @@ namespace Ryujinx.Ui
private void Load_Mii_Edit_Applet(object sender, EventArgs args) private void Load_Mii_Edit_Applet(object sender, EventArgs args)
{ {
string contentPath = _contentManager.GetInstalledContentPath(0x0100000000001009, StorageId.NandSystem, NcaContentType.Program); string contentPath = _contentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program);
LoadApplication(contentPath); LoadApplication(contentPath);
} }

View file

@ -3,10 +3,10 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -115,7 +115,7 @@ namespace Ryujinx.Ui.Windows
return; return;
} }
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.NandSystem, NcaContentType.Data); string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath); string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
if (!string.IsNullOrWhiteSpace(avatarPath)) if (!string.IsNullOrWhiteSpace(avatarPath))

View file

@ -105,9 +105,9 @@ namespace Ryujinx.Ui.Windows
#pragma warning restore CS0649, IDE0044 #pragma warning restore CS0649, IDE0044
public SettingsWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.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.Ui.Windows.SettingsWindow.glade"), virtualFileSystem, contentManager) { }
private SettingsWindow(MainWindow parent, Builder builder, VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : base(builder.GetObject("_settingsWin").Handle) private SettingsWindow(MainWindow parent, Builder builder, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : base(builder.GetObject("_settingsWin").Handle)
{ {
Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Ryujinx.png"); Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Ryujinx.png");

View file

@ -1,6 +1,5 @@
using Gtk; using Gtk;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.Ui.Widgets; using Ryujinx.Ui.Widgets;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;