Compare commits

...

18 Commits

Author SHA1 Message Date
riperiperi
9719b6a112 Vulkan: Use dynamic state for blend constants (#3793) 2022-10-25 23:49:23 +00:00
VocalFan
f70236f947 Updated Compatibility info and GPU info (Vulkan, SPIRV, and Texture Recompression) (#3568)
* Updated Compatibility info and GPU info (Vulkan, SPIRV, and Texture Recompression)

* Added Mutant's changes.

Co-authored-by: MutantAura <44103205+MutantAura@users.noreply.github.com>

* Five to four.

* Fixed github's terrible conflict diffs

Co-authored-by: MutantAura <44103205+MutantAura@users.noreply.github.com>
2022-10-24 16:40:39 +00:00
merry
eafadf10c7 Ryujinx.Tests.Unicorn: Implement IDisposable (#3794)
Dispose unicorn when done
2022-10-23 23:51:54 +00:00
Mary-nyan
9b06ee7736 Attempt to fix issues since github-script v6 upgrade 2022-10-23 17:15:15 +02:00
Emmanuel Hansen
baba2c2467 Avalonia: Use overlay dialog for controller applet (#3777)
* use overlay dialog for controller applet

* Update Ryujinx.Ava/Ui/Controls/ContentDialogHelper.cs

Co-authored-by: riperiperi <rhy3756547@hotmail.com>

Co-authored-by: riperiperi <rhy3756547@hotmail.com>
2022-10-23 11:15:45 +02:00
dependabot[bot]
286e5d39b2 nuget: bump SPB from 0.0.4-build24 to 0.0.4-build27 (#3791)
Bumps [SPB](https://github.com/Thog/SPB) from 0.0.4-build24 to 0.0.4-build27.
- [Release notes](https://github.com/Thog/SPB/releases)
- [Commits](https://github.com/Thog/SPB/commits)

---
updated-dependencies:
- dependency-name: SPB
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-22 10:32:12 +02:00
TSRBerry
dc529c1181 ci: Add updates for nuget packages to dependabot (#3786) 2022-10-21 14:23:16 +02:00
TSRBerry
c7cf1cbc35 CI: Update workflows (#3774)
* ci: Update workflows

* gha: Add no-build switch to test action
2022-10-21 10:31:38 +02:00
TSRBerry
d8e487d018 gha: Add dependabot.yml (#3778) 2022-10-21 10:16:28 +02:00
gdkchan
5fdc46ac7f Vulkan: Fix vertex position Z conversion with geometry shader passthrough (#3781)
* Vulkan: Fix vertex position Z conversion with geometry shader passthrough

* Shader cache version bump
2022-10-21 04:48:21 +00:00
Mortus06
1e5b45f580 Avalonia: update it_IT.json (#3742)
* Avalonia: update it_IT.json

* Fixed ; instead of :

* Update it_IT.json

port di #3766

* Update Ryujinx.Ava/Assets/Locales/it_IT.json

Co-authored-by: Antonio Brugnolo <36473846+AntoSkate@users.noreply.github.com>

* Grammar fix

Co-authored-by: Lorenzo Giannini <55211569+Lorenzo0310200@users.noreply.github.com>
Co-authored-by: Antonio Brugnolo <36473846+AntoSkate@users.noreply.github.com>
2022-10-19 09:30:28 +00:00
LDj3SNuD
62585755fd Do not clear the rejit queue when overlaps count is equal to 0. (#3721)
* Do not clear the rejit queue when overlaps count is equal to 0.

* Ptc and PtcProfiler must be invalidated.

* Revert "Ptc and PtcProfiler must be invalidated."

This reverts commit f5b0ad9d7d.

* Fix #3710 slow path due to #3701.
2022-10-19 02:08:34 +00:00
WilliamWsyHK
56621615b1 Implement the GetSessionCacheMode in SSL servuce (#3735) 2022-10-19 01:27:11 +00:00
Carl Ouellette
2099a3e84b Manage state of NfcManager (#3678)
* Manage state of NfcManager

Very basic state management but works with Hyrule Warriors Definitive Edition. Partially fixes #2122

* Fixes changes from review
2022-10-19 01:14:31 +00:00
gdkchan
7d26e4ac7b Fix mapping leaks caused by UnmapView not working on Linux (#3650)
* Add test for UnmapView mapping leaks

* Throw when UnmapView fails on Linux

* Fix UnmapView

* Remove throw
2022-10-19 01:02:45 +00:00
merry
8d41402fa6 A32: Implement VCVTT, VCVTB (#3710)
* A32: Implement VCVTT, VCVTB

* A32: F16C implementation of VCVTT/VCVTB
2022-10-19 02:36:04 +02:00
LDj3SNuD
5af8ce7c38 A64: Add fast path for Fcvtas_Gp/S/V, Fcvtau_Gp/S/V and Frinta_S/V in… (#3712)
* A64: Add fast path for Fcvtas_Gp/S/V, Fcvtau_Gp/S/V and Frinta_S/V instructions;

they use "Round to Nearest with Ties to Away" rounding mode not supported in x86.

All instructions involved have been tested locally in both release and debug modes, in both lowcq and highcq.

The titles Mario Strikers and Super Smash Bros. U. use these instructions intensively.

* Update Ptc.cs

* A32: Add fast path for Vcvta_RM, Vrinta_RM and Vrinta_V instructions aswell.
2022-10-19 00:21:33 +00:00
Luna
77c4291c34 Avalonia: Update Polish Translation (#3722)
* Add new string

You need the period there otherwise it could be read as "Głoś" -> "Preach"

* Update MainWindow.axaml

Updating to bring it in line with the other languages naming themselves in their respective languages

* Update pl_PL.json

realizing that period isn't necessary considering the string's usage (which to be fair, I should have checked when I added it)

* Update pl_PL.json

* Add Updater Message
2022-10-19 00:10:28 +00:00
37 changed files with 751 additions and 144 deletions

24
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
labels:
- "infra"
reviewers:
- marysaka
commit-message:
prefix: "ci"
- package-ecosystem: nuget
directory: /
open-pull-requests-limit: 5
schedule:
interval: daily
labels:
- "infra"
reviewers:
- marysaka
commit-message:
prefix: nuget

View File

@@ -48,21 +48,21 @@ jobs:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.1.0"
steps:
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
- name: Ensure NuGet Source
uses: fabriciomurta/ensure-nuget-source@v1
- name: Get git short hash
id: git_short_hash
run: echo "::set-output name=result::$(git rev-parse --short "${{ github.sha }}")"
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
- name: Clear
run: dotnet clean && dotnet nuget locals all --clear
- name: Build
run: dotnet build -c "${{ matrix.configuration }}" /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER
- name: Test
run: dotnet test -c "${{ matrix.configuration }}"
run: dotnet test --no-build -c "${{ matrix.configuration }}"
- name: Publish Ryujinx
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained
if: github.event_name == 'pull_request'
@@ -73,19 +73,19 @@ jobs:
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava /p:Version="1.0.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava
if: github.event_name == 'pull_request'
- name: Upload Ryujinx artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish
if: github.event_name == 'pull_request'
- name: Upload Ryujinx.Headless.SDL2 artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish_sdl2_headless
if: github.event_name == 'pull_request'
- name: Upload Ryujinx.Ava artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish_ava

View File

@@ -8,7 +8,7 @@ jobs:
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v3
- uses: actions/github-script@v6
with:
script: |
const {owner, repo} = context.repo;
@@ -16,7 +16,7 @@ jobs:
const pull_head_sha = '${{github.event.workflow_run.head_sha}}';
const issue_number = await (async () => {
const pulls = await github.pulls.list({owner, repo});
const pulls = await github.rest.pulls.list({owner, repo});
for await (const {data} of github.paginate.iterator(pulls)) {
for (const pull of data) {
if (pull.head.sha === pull_head_sha) {
@@ -31,7 +31,7 @@ jobs:
return core.error(`No matching pull request found`);
}
const {data: {artifacts}} = await github.actions.listWorkflowRunArtifacts({owner, repo, run_id});
const {data: {artifacts}} = await github.rest.actions.listWorkflowRunArtifacts({owner, repo, run_id});
if (!artifacts.length) {
return core.error(`No artifacts found`);
}
@@ -57,12 +57,12 @@ jobs:
body += hidden_headless_artifacts;
body += hidden_debug_artifacts;
const {data: comments} = await github.issues.listComments({repo, owner, issue_number});
const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number});
const existing_comment = comments.find((c) => c.user.login === 'github-actions[bot]');
if (existing_comment) {
core.info(`Updating comment ${existing_comment.id}`);
await github.issues.updateComment({repo, owner, comment_id: existing_comment.id, body});
await github.rest.issues.updateComment({repo, owner, comment_id: existing_comment.id, body});
} else {
core.info(`Creating a comment`);
await github.issues.createComment({repo, owner, issue_number, body});
await github.rest.issues.createComment({repo, owner, issue_number, body});
}

View File

@@ -25,8 +25,8 @@ jobs:
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
steps:
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
- name: Ensure NuGet Source
@@ -36,8 +36,8 @@ jobs:
- name: Get version info
id: version_info
run: |
echo "::set-output name=build_version::${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}"
echo "::set-output name=git_short_hash::$(git rev-parse --short "${{ github.sha }}")"
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
run: |

View File

@@ -0,0 +1,44 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdCvtTB : OpCode32, IOpCode32Simd
{
public int Vd { get; }
public int Vm { get; }
public bool Op { get; } // Convert to Half / Convert from Half
public bool T { get; } // Top / Bottom
public int Size { get; } // Double / Single
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtTB(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtTB(inst, address, opCode, true);
public OpCode32SimdCvtTB(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
Op = ((opCode >> 16) & 0x1) != 0;
T = ((opCode >> 7) & 0x1) != 0;
Size = ((opCode >> 8) & 0x1);
RegisterSize = Size == 1 ? RegisterSize.Int64 : RegisterSize.Int32;
if (Size == 1)
{
if (Op)
{
Vm = ((opCode >> 1) & 0x10) | ((opCode >> 0) & 0xf);
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
}
else
{
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf);
}
}
else
{
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
}
}
}
}

View File

@@ -828,6 +828,7 @@ namespace ARMeilleure.Decoders
SetVfp("<<<<11101x11110xxxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // FP32 to int.
SetVfp("<<<<11101x111000xxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // Int to FP32.
SetVfp("111111101x1111xxxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_RM, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // The many FP32 to int encodings (fp).
SetVfp("<<<<11101x11001xxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_TB, OpCode32SimdCvtTB.Create, OpCode32SimdCvtTB.CreateT32);
SetVfp("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
SetVfp("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, OpCode32SimdDupGP.Create, OpCode32SimdDupGP.CreateT32);
SetVfp("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);

View File

@@ -1617,18 +1617,32 @@ namespace ARMeilleure.Instructions
public static void Frinta_S(ArmEmitterContext context)
{
EmitScalarUnaryOpF(context, (op1) =>
if (Optimizations.UseSse41)
{
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
});
EmitSse41ScalarRoundOpF(context, FPRoundingMode.ToNearestAway);
}
else
{
EmitScalarUnaryOpF(context, (op1) =>
{
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
});
}
}
public static void Frinta_V(ArmEmitterContext context)
{
EmitVectorUnaryOpF(context, (op1) =>
if (Optimizations.UseSse41)
{
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
});
EmitSse41VectorRoundOpF(context, FPRoundingMode.ToNearestAway);
}
else
{
EmitVectorUnaryOpF(context, (op1) =>
{
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
});
}
}
public static void Frinti_S(ArmEmitterContext context)
@@ -3516,9 +3530,18 @@ namespace ARMeilleure.Instructions
Operand n = GetVec(op.Rn);
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundsd : Intrinsic.X86Roundss;
Operand res;
Operand res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundsd : Intrinsic.X86Roundss;
res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
}
else
{
res = EmitSse41RoundToNearestWithTiesToAwayOpF(context, n, scalar: true);
}
if ((op.Size & 1) != 0)
{
@@ -3538,9 +3561,18 @@ namespace ARMeilleure.Instructions
Operand n = GetVec(op.Rn);
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundpd : Intrinsic.X86Roundps;
Operand res;
Operand res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundpd : Intrinsic.X86Roundps;
res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
}
else
{
res = EmitSse41RoundToNearestWithTiesToAwayOpF(context, n, scalar: false);
}
if (op.RegisterSize == RegisterSize.Simd64)
{

View File

@@ -164,32 +164,74 @@ namespace ARMeilleure.Instructions
public static void Fcvtas_Gp(ArmEmitterContext context)
{
EmitFcvt_s_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
if (Optimizations.UseSse41)
{
EmitSse41Fcvts_Gp(context, FPRoundingMode.ToNearestAway, isFixed: false);
}
else
{
EmitFcvt_s_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
}
}
public static void Fcvtas_S(ArmEmitterContext context)
{
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: true);
if (Optimizations.UseSse41)
{
EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearestAway, scalar: true);
}
else
{
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: true);
}
}
public static void Fcvtas_V(ArmEmitterContext context)
{
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: false);
if (Optimizations.UseSse41)
{
EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearestAway, scalar: false);
}
else
{
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: false);
}
}
public static void Fcvtau_Gp(ArmEmitterContext context)
{
EmitFcvt_u_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
if (Optimizations.UseSse41)
{
EmitSse41Fcvtu_Gp(context, FPRoundingMode.ToNearestAway, isFixed: false);
}
else
{
EmitFcvt_u_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
}
}
public static void Fcvtau_S(ArmEmitterContext context)
{
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: true);
if (Optimizations.UseSse41)
{
EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearestAway, scalar: true);
}
else
{
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: true);
}
}
public static void Fcvtau_V(ArmEmitterContext context)
{
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: false);
if (Optimizations.UseSse41)
{
EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearestAway, scalar: false);
}
else
{
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: false);
}
}
public static void Fcvtl_V(ArmEmitterContext context)
@@ -1223,7 +1265,14 @@ namespace ARMeilleure.Instructions
nRes = context.AddIntrinsic(Intrinsic.X86Mulps, nRes, fpScaledMask);
}
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
}
else
{
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
}
Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes);
@@ -1265,7 +1314,14 @@ namespace ARMeilleure.Instructions
nRes = context.AddIntrinsic(Intrinsic.X86Mulpd, nRes, fpScaledMask);
}
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
}
else
{
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
}
Operand nLong = EmitSse2CvtDoubleToInt64OpF(context, nRes, scalar);
@@ -1314,7 +1370,14 @@ namespace ARMeilleure.Instructions
nRes = context.AddIntrinsic(Intrinsic.X86Mulps, nRes, fpScaledMask);
}
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
}
else
{
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
}
Operand zero = context.VectorZero();
@@ -1369,7 +1432,14 @@ namespace ARMeilleure.Instructions
nRes = context.AddIntrinsic(Intrinsic.X86Mulpd, nRes, fpScaledMask);
}
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
}
else
{
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
}
Operand zero = context.VectorZero();
@@ -1424,7 +1494,14 @@ namespace ARMeilleure.Instructions
nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask);
}
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
}
else
{
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
}
Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32
? context.AddIntrinsicInt (Intrinsic.X86Cvtss2si, nRes)
@@ -1464,7 +1541,14 @@ namespace ARMeilleure.Instructions
nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask);
}
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
}
else
{
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
}
Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32
? context.AddIntrinsicInt (Intrinsic.X86Cvtsd2si, nRes)
@@ -1512,7 +1596,14 @@ namespace ARMeilleure.Instructions
nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask);
}
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
}
else
{
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
}
Operand zero = context.VectorZero();
@@ -1567,7 +1658,14 @@ namespace ARMeilleure.Instructions
nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask);
}
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
}
else
{
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
}
Operand zero = context.VectorZero();

View File

@@ -203,6 +203,9 @@ namespace ARMeilleure.Instructions
FPRoundingMode roundMode;
switch (rm)
{
case 0b00:
roundMode = FPRoundingMode.ToNearestAway;
break;
case 0b01:
roundMode = FPRoundingMode.ToNearest;
break;
@@ -228,7 +231,7 @@ namespace ARMeilleure.Instructions
bool unsigned = op.Opc == 0;
int rm = op.Opc2 & 3;
if (Optimizations.UseSse41 && rm != 0b00)
if (Optimizations.UseSse41)
{
EmitSse41ConvertInt32(context, RMToRoundMode(rm), !unsigned);
}
@@ -258,6 +261,74 @@ namespace ARMeilleure.Instructions
}
}
public static void Vcvt_TB(ArmEmitterContext context)
{
OpCode32SimdCvtTB op = (OpCode32SimdCvtTB)context.CurrOp;
if (Optimizations.UseF16c)
{
Debug.Assert(!Optimizations.ForceLegacySse);
if (op.Op)
{
Operand res = ExtractScalar(context, op.Size == 1 ? OperandType.FP64 : OperandType.FP32, op.Vm);
if (op.Size == 1)
{
res = context.AddIntrinsic(Intrinsic.X86Cvtsd2ss, context.VectorZero(), res);
}
res = context.AddIntrinsic(Intrinsic.X86Vcvtps2ph, res, Const(X86GetRoundControl(FPRoundingMode.ToNearest)));
res = context.VectorExtract16(res, 0);
InsertScalar16(context, op.Vd, op.T, res);
}
else
{
Operand res = context.VectorCreateScalar(ExtractScalar16(context, op.Vm, op.T));
res = context.AddIntrinsic(Intrinsic.X86Vcvtph2ps, res);
if (op.Size == 1)
{
res = context.AddIntrinsic(Intrinsic.X86Cvtss2sd, context.VectorZero(), res);
}
res = context.VectorExtract(op.Size == 1 ? OperandType.I64 : OperandType.I32, res, 0);
InsertScalar(context, op.Vd, res);
}
}
else
{
if (op.Op)
{
// Convert to half.
Operand src = ExtractScalar(context, op.Size == 1 ? OperandType.FP64 : OperandType.FP32, op.Vm);
MethodInfo method = op.Size == 1
? typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert))
: typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert));
context.StoreToContext();
Operand res = context.Call(method, src);
context.LoadFromContext();
InsertScalar16(context, op.Vd, op.T, res);
}
else
{
// Convert from half.
Operand src = ExtractScalar16(context, op.Vm, op.T);
MethodInfo method = op.Size == 1
? typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert))
: typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert));
context.StoreToContext();
Operand res = context.Call(method, src);
context.LoadFromContext();
InsertScalar(context, op.Vd, res);
}
}
}
// VRINTA/M/N/P (floating-point).
public static void Vrint_RM(ArmEmitterContext context)
{
@@ -267,15 +338,21 @@ namespace ARMeilleure.Instructions
int rm = op.Opc2 & 3;
if (Optimizations.UseSse2 && rm != 0b00)
if (Optimizations.UseSse41)
{
EmitScalarUnaryOpSimd32(context, (m) =>
{
Intrinsic inst = (op.Size & 1) == 0 ? Intrinsic.X86Roundss : Intrinsic.X86Roundsd;
FPRoundingMode roundMode = RMToRoundMode(rm);
return context.AddIntrinsic(inst, m, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
Intrinsic inst = (op.Size & 1) == 0 ? Intrinsic.X86Roundss : Intrinsic.X86Roundsd;
return context.AddIntrinsic(inst, m, Const(X86GetRoundControl(roundMode)));
}
else
{
return EmitSse41RoundToNearestWithTiesToAwayOpF(context, m, scalar: true);
}
});
}
else
@@ -305,7 +382,17 @@ namespace ARMeilleure.Instructions
// VRINTA (vector).
public static void Vrinta_V(ArmEmitterContext context)
{
EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, m));
if (Optimizations.UseSse41)
{
EmitVectorUnaryOpSimd32(context, (m) =>
{
return EmitSse41RoundToNearestWithTiesToAwayOpF(context, m, scalar: false);
});
}
else
{
EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, m));
}
}
// VRINTM (vector).
@@ -413,7 +500,14 @@ namespace ARMeilleure.Instructions
Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, n, n, Const((int)CmpCondition.OrderedQ));
nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n);
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
}
else
{
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
}
Operand zero = context.VectorZero();
@@ -464,7 +558,14 @@ namespace ARMeilleure.Instructions
Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, n, Const((int)CmpCondition.OrderedQ));
nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n);
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
if (roundMode != FPRoundingMode.ToNearestAway)
{
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
}
else
{
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
}
Operand zero = context.VectorZero();

View File

@@ -33,6 +33,14 @@ namespace ARMeilleure.Instructions
};
public static readonly long ZeroMask = 128L << 56 | 128L << 48 | 128L << 40 | 128L << 32 | 128L << 24 | 128L << 16 | 128L << 8 | 128L << 0;
public static ulong X86GetGf2p8LogicalShiftLeft(int shift)
{
ulong identity = (0b00000001UL << 56) | (0b00000010UL << 48) | (0b00000100UL << 40) | (0b00001000UL << 32) |
(0b00010000UL << 24) | (0b00100000UL << 16) | (0b01000000UL << 8) | (0b10000000UL << 0);
return shift >= 0 ? identity >> (shift * 8) : identity << (-shift * 8);
}
#endregion
#region "X86 SSE Intrinsics"
@@ -243,19 +251,44 @@ namespace ARMeilleure.Instructions
throw new ArgumentException($"Invalid rounding mode \"{roundMode}\".");
}
public static ulong X86GetGf2p8LogicalShiftLeft(int shift)
public static Operand EmitSse41RoundToNearestWithTiesToAwayOpF(ArmEmitterContext context, Operand n, bool scalar)
{
ulong identity =
(0b00000001UL << 56) |
(0b00000010UL << 48) |
(0b00000100UL << 40) |
(0b00001000UL << 32) |
(0b00010000UL << 24) |
(0b00100000UL << 16) |
(0b01000000UL << 8) |
(0b10000000UL << 0);
Debug.Assert(n.Type == OperandType.V128);
return shift >= 0 ? identity >> (shift * 8) : identity << (-shift * 8);
Operand nCopy = context.Copy(n);
Operand rC = Const(X86GetRoundControl(FPRoundingMode.TowardsZero));
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
if ((op.Size & 1) == 0)
{
Operand signMask = scalar ? X86GetScalar(context, int.MinValue) : X86GetAllElements(context, int.MinValue);
signMask = context.AddIntrinsic(Intrinsic.X86Pand, signMask, nCopy);
// 0x3EFFFFFF == BitConverter.SingleToInt32Bits(0.5f) - 1
Operand valueMask = scalar ? X86GetScalar(context, 0x3EFFFFFF) : X86GetAllElements(context, 0x3EFFFFFF);
valueMask = context.AddIntrinsic(Intrinsic.X86Por, valueMask, signMask);
nCopy = context.AddIntrinsic(scalar ? Intrinsic.X86Addss : Intrinsic.X86Addps, nCopy, valueMask);
nCopy = context.AddIntrinsic(scalar ? Intrinsic.X86Roundss : Intrinsic.X86Roundps, nCopy, rC);
}
else
{
Operand signMask = scalar ? X86GetScalar(context, long.MinValue) : X86GetAllElements(context, long.MinValue);
signMask = context.AddIntrinsic(Intrinsic.X86Pand, signMask, nCopy);
// 0x3FDFFFFFFFFFFFFFL == BitConverter.DoubleToInt64Bits(0.5d) - 1L
Operand valueMask = scalar ? X86GetScalar(context, 0x3FDFFFFFFFFFFFFFL) : X86GetAllElements(context, 0x3FDFFFFFFFFFFFFFL);
valueMask = context.AddIntrinsic(Intrinsic.X86Por, valueMask, signMask);
nCopy = context.AddIntrinsic(scalar ? Intrinsic.X86Addsd : Intrinsic.X86Addpd, nCopy, valueMask);
nCopy = context.AddIntrinsic(scalar ? Intrinsic.X86Roundsd : Intrinsic.X86Roundpd, nCopy, rC);
}
return nCopy;
}
public static Operand EmitCountSetBits8(ArmEmitterContext context, Operand op) // "size" is 8 (SIMD&FP Inst.).

View File

@@ -70,6 +70,22 @@ namespace ARMeilleure.Instructions
context.Copy(vec, insert);
}
public static Operand ExtractScalar16(ArmEmitterContext context, int reg, bool top)
{
return context.VectorExtract16(GetVecA32(reg >> 2), ((reg & 3) << 1) | (top ? 1 : 0));
}
public static void InsertScalar16(ArmEmitterContext context, int reg, bool top, Operand value)
{
Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.I32);
Operand vec, insert;
vec = GetVecA32(reg >> 2);
insert = context.VectorInsert16(vec, value, ((reg & 3) << 1) | (top ? 1 : 0));
context.Copy(vec, insert);
}
public static Operand ExtractElement(ArmEmitterContext context, int reg, int size, bool signed)
{
return EmitVectorExtract32(context, reg >> (4 - size), reg & ((16 >> size) - 1), size, signed);

View File

@@ -2,9 +2,10 @@ namespace ARMeilleure.State
{
public enum FPRoundingMode
{
ToNearest = 0,
ToNearest = 0, // With ties to even.
TowardsPlusInfinity = 1,
TowardsMinusInfinity = 2,
TowardsZero = 3
TowardsZero = 3,
ToNearestAway = 4 // With ties to away.
}
}

View File

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

View File

@@ -455,13 +455,16 @@ namespace ARMeilleure.Translation
public void InvalidateJitCacheRegion(ulong address, ulong size)
{
// If rejit is running, stop it as it may be trying to rejit a function on the invalidated region.
ClearRejitQueue(allowRequeue: true);
ulong[] overlapAddresses = Array.Empty<ulong>();
int overlapsCount = Functions.GetOverlaps(address, size, ref overlapAddresses);
if (overlapsCount != 0)
{
// If rejit is running, stop it as it may be trying to rejit a function on the invalidated region.
ClearRejitQueue(allowRequeue: true);
}
for (int index = 0; index < overlapsCount; index++)
{
ulong overlapAddress = overlapAddresses[index];

View File

@@ -36,8 +36,8 @@
## Compatibility
As of October 2022, Ryujinx has been tested on approximately 3,600 titles; over 3,500 boot past menus and into gameplay, with roughly 3,000 of those being considered playable. You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
As of October 2022, Ryujinx has been tested on approximately 3,700 titles; over 3,500 boot past menus and into gameplay, with roughly 3,000 of those being considered playable.
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
## Usage
@@ -90,7 +90,7 @@ Ryujinx system files are stored in the `Ryujinx` folder. This folder is located
- **GPU**
The GPU emulator emulates the Switch's Maxwell GPU using the OpenGL API (version 4.5 minimum) through a custom build of OpenTK. There are currently four graphics enhancements available to the end user in Ryujinx: disk shader caching, resolution scaling, aspect ratio adjustment and anisotropic filtering. These enhancements can be adjusted or toggled as desired in the GUI.
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum) or Vulkan APIs through a custom build of OpenTK or Silk.NET respectively. There are currently four graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Aspect Ratio Adjustment, and Anisotropic Filtering. These enhancements can be adjusted or toggled as desired in the GUI.
- **Input**

View File

@@ -49,8 +49,8 @@
"GameListContextMenuManageTitleUpdatesToolTip": "Apre la finestra di gestione aggiornamenti del gioco",
"GameListContextMenuManageDlc": "Gestici DLC",
"GameListContextMenuManageDlcToolTip": "Apre la finestra di gestione DLC",
"GameListContextMenuOpenModsDirectory": "Apri cartella delle mods",
"GameListContextMenuOpenModsDirectoryToolTip": "Apre la cartella che contiene le mods dell'applicazione",
"GameListContextMenuOpenModsDirectory": "Apri cartella delle mod",
"GameListContextMenuOpenModsDirectoryToolTip": "Apre la cartella che contiene le mod dell'applicazione",
"GameListContextMenuCacheManagement": "Gestione della cache",
"GameListContextMenuCacheManagementPurgePptc": "Pulisci PPTC cache",
"GameListContextMenuCacheManagementPurgePptcToolTip": "Elimina la PPTC cache dell'applicazione",
@@ -81,7 +81,7 @@
"SettingsTabGeneralRemove": "Rimuovi",
"SettingsTabSystem": "Sistema",
"SettingsTabSystemCore": "Core",
"SettingsTabSystemSystemRegion": "Regione di sistema:",
"SettingsTabSystemSystemRegion": "Regione del sistema:",
"SettingsTabSystemSystemRegionJapan": "Giappone",
"SettingsTabSystemSystemRegionUSA": "Stati Uniti d'America",
"SettingsTabSystemSystemRegionEurope": "Europa",
@@ -89,7 +89,7 @@
"SettingsTabSystemSystemRegionChina": "Cina",
"SettingsTabSystemSystemRegionKorea": "Corea",
"SettingsTabSystemSystemRegionTaiwan": "Taiwan",
"SettingsTabSystemSystemLanguage": "Lingua di sistema:",
"SettingsTabSystemSystemLanguage": "Lingua del sistema:",
"SettingsTabSystemSystemLanguageJapanese": "Giapponese",
"SettingsTabSystemSystemLanguageAmericanEnglish": "Inglese americano",
"SettingsTabSystemSystemLanguageFrench": "Francese",
@@ -107,8 +107,8 @@
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Spagnolo latino americano",
"SettingsTabSystemSystemLanguageSimplifiedChinese": "Cinese semplificato",
"SettingsTabSystemSystemLanguageTraditionalChinese": "Cinese tradizionale",
"SettingsTabSystemSystemTimeZone": "Fuso orario di sistema:",
"SettingsTabSystemSystemTime": "Data e ora di sistema:",
"SettingsTabSystemSystemTimeZone": "Fuso orario del sistema:",
"SettingsTabSystemSystemTime": "Data e ora del sistema:",
"SettingsTabSystemEnableVsync": "Attiva VSync",
"SettingsTabSystemEnablePptc": "Attiva PPTC (Profiled Persistent Translation Cache)",
"SettingsTabSystemEnableFsIntegrityChecks": "Attiva controlli d'integrità FS",
@@ -155,7 +155,7 @@
"SettingsTabLoggingEnableTraceLogs": "Attiva Trace Logs",
"SettingsTabLoggingEnableGuestLogs": "Attiva Guest Logs",
"SettingsTabLoggingEnableFsAccessLogs": "Attiva Fs Access Logs",
"SettingsTabLoggingFsGlobalAccessLogMode": "Modalità di log accesso globale Fs:",
"SettingsTabLoggingFsGlobalAccessLogMode": "Modalità log accesso globale Fs:",
"SettingsTabLoggingDeveloperOptions": "Opzioni da sviluppatore (AVVISO: Ridurrà le prestazioni)",
"SettingsTabLoggingOpenglLogLevel": "Livello di log OpenGL:",
"SettingsTabLoggingOpenglLogLevelNone": "Nessuno",
@@ -240,7 +240,7 @@
"ControllerSettingsRightSR": "SR",
"ControllerSettingsExtraButtonsLeft": "Tasto sinitro",
"ControllerSettingsExtraButtonsRight": "Tasto destro",
"ControllerSettingsMisc": "Miscellanee",
"ControllerSettingsMisc": "Varie",
"ControllerSettingsTriggerThreshold": "Sensibilità dei grilletti:",
"ControllerSettingsMotion": "Movimento",
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "Usa sensore compatibile con CemuHook",
@@ -261,7 +261,7 @@
"UserProfilesClose": "Chiudi",
"ProfileImageSelectionTitle": "Selezione dell'immagine profilo",
"ProfileImageSelectionHeader": "Scegli un'immagine profilo",
"ProfileImageSelectionNote": "Puoi importare un'immagine profilo personalizzata o selezionare un avatar dal firmware di sistema",
"ProfileImageSelectionNote": "Puoi importare un'immagine profilo personalizzata o selezionare un avatar dal firmware del sistema",
"ProfileImageSelectionImportImage": "Importa file immagine",
"ProfileImageSelectionSelectAvatar": "Seleziona avatar dal firmware",
"InputDialogTitle": "Input Dialog",
@@ -293,7 +293,7 @@
"ControllerSettingsRumbleStrongMultiplier": "Moltiplicatore vibrazione forte",
"ControllerSettingsRumbleWeakMultiplier": "Moltiplicatore vibrazione debole",
"DialogMessageSaveNotAvailableMessage": "Non ci sono dati di salvataggio per {0} [{1:x16}]",
"DialogMessageSaveNotAvailableCreateSaveMessage": "Vuoi creare dei dat di salvataggio per questo gioco?",
"DialogMessageSaveNotAvailableCreateSaveMessage": "Vuoi creare dei dati di salvataggio per questo gioco?",
"DialogConfirmationTitle": "Ryujinx - Conferma",
"DialogUpdaterTitle": "Ryujinx - Updater",
"DialogErrorTitle": "Ryujinx - Errore",
@@ -318,7 +318,7 @@
"DialogUpdaterDownloadingMessage": "Download dell'aggiornamento...",
"DialogUpdaterExtractionMessage": "Estrazione dell'aggiornamento...",
"DialogUpdaterRenamingMessage": "Rinominazione dell'aggiornamento...",
"DialogUpdaterAddingFilesMessage": "Aggiunta nuovo aggiornamento...",
"DialogUpdaterAddingFilesMessage": "Aggiunta del nuovo aggiornamento...",
"DialogUpdaterCompleteMessage": "Aggiornamento completato!",
"DialogUpdaterRestartMessage": "Vuoi riavviare Ryujinx adesso?",
"DialogUpdaterArchNotSupportedMessage": "Non stai usando un'architettura di sistema supportata!",
@@ -331,7 +331,7 @@
"DialogThemeRestartMessage": "Il tema è stato salvato. E' richiesto un riavvio per applicare un tema.",
"DialogThemeRestartSubMessage": "Vuoi riavviare?",
"DialogFirmwareInstallEmbeddedMessage": "Vuoi installare il firmware incorporato in questo gioco? (Firmware {0})",
"DialogFirmwareInstallEmbeddedSuccessMessage": "Non è stato trovato alcun firmware installato, ma Ryujinx è riuscito di installare il firmware {0} dal gioco fornito.\nL'emulatore si avvierà adesso.",
"DialogFirmwareInstallEmbeddedSuccessMessage": "Non è stato trovato alcun firmware installato, ma Ryujinx è riuscito ad installare il firmware {0} dal gioco fornito.\nL'emulatore si avvierà adesso.",
"DialogFirmwareNoFirmwareInstalledMessage": "Nessun firmware installato",
"DialogFirmwareInstalledMessage": "Il firmware {0} è stato installato",
"DialogOpenSettingsWindowLabel": "Apri finestra delle impostazioni",
@@ -355,14 +355,14 @@
"DialogShaderDeletionMessage": "Stai per eliminare la Shader cache per :\n\n{0}\n\nSei sicuro di voler proseguire?",
"DialogShaderDeletionErrorMessage": "Errore nell'eliminazione della Shader cache a {0}: {1}",
"DialogRyujinxErrorMessage": "Ryujinx ha incontrato un errore",
"DialogInvalidTitleIdErrorMessage": "Errore UI: Il gioco selezionato non ha un title ID valido",
"DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Un firmware di sistema valido non è stato trovato in {0}.",
"DialogInvalidTitleIdErrorMessage": "Errore UI: Il gioco selezionato non ha un ID titolo valido",
"DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Un firmware del sistema valido non è stato trovato in {0}.",
"DialogFirmwareInstallerFirmwareInstallTitle": "Installa firmware {0}",
"DialogFirmwareInstallerFirmwareInstallMessage": "La versione di sistema {0} sarà installata.",
"DialogFirmwareInstallerFirmwareInstallMessage": "La versione del sistema {0} sarà installata.",
"DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nQuesta sostituirà l'attuale versione di sistema {0}.",
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nVuoi continuare?",
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installazione del firmware...",
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "La versione di sistema {0} è stata installata.",
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "La versione del sistema {0} è stata installata.",
"DialogUserProfileDeletionWarningMessage": "Non ci sarebbero altri profili da aprire se il profilo selezionato viene cancellato",
"DialogUserProfileDeletionConfirmMessage": "Vuoi eliminare il profilo selezionato?",
"DialogControllerSettingsModifiedConfirmMessage": "Le attuali impostazioni del controller sono state aggiornate.",
@@ -557,4 +557,40 @@
"SettingsXamlThemeFile" : "File del tema xaml",
"SettingsTabHotkeysResScaleUpHotkey": "Aumentare la risoluzione:",
"SettingsTabHotkeysResScaleDownHotkey": "Diminuire la risoluzione:"
"AvatarWindowTitle": "Gestisci account - Avatar"
"Amiibo": "Amiibo",
"Unknown": "Sconosciuto",
"Usage": "Utilizzo",
"Writable": "Scrivibile",
"SelectDlcDialogTitle": "Seleziona file dei DLC",
"SelectUpdateDialogTitle": "Seleziona file di aggiornamento",
"UserProfileWindowTitle": "Gestisci profili degli utenti",
"CheatWindowTitle": "Gestisci cheat dei giochi",
"DlcWindowTitle": "Gestisci DLC dei giochi",
"UpdateWindowTitle": "Gestisci aggiornamenti dei giochi",
"CheatWindowHeading": "Cheat disponibiili per {0} [{1}]",
"DlcWindowHeading": "DLC disponibili per {0} [{1}]",
"UserProfilesEditProfile": "Modifica selezionati",
"Cancel": "Annulla",
"Save": "Salva",
"Discard": "Scarta",
"UserProfilesSetProfileImage": "Imposta immagine profilo",
"UserProfileEmptyNameError": "È richiesto un nome",
"UserProfileNoImageError": "Dev'essere impostata un'immagine profilo",
"GameUpdateWindowHeading": "Aggiornamenti disponibili per {0} [{1}]",
"UserProfilesName": "Name:",
"UserProfilesUserId": "User Id:",
"SettingsTabGraphicsBackend": "Backend grafica",
"SettingsTabGraphicsBackendTooltip": "Backend grafica da usare",
"SettingsEnableTextureRecompression": "Abilita Ricompressione Texture",
"SettingsEnableTextureRecompressionTooltip": "Comprime alcune texture per ridurre l'utilizzo della VRAM.\n\nL'utilizzo è consigliato con GPU con meno di 4GB di VRAM.\n\nLascia su OFF se non sei sicuro.",
"SettingsTabGraphicsPreferredGpu": "GPU preferita",
"SettingsTabGraphicsPreferredGpuTooltip": "Seleziona la scheda grafica che verrà usata con la backend grafica Vulkan.\n\nNon influenza la GPU che userà OpenGL.\n\nImposta la GPU contrassegnata come \"dGPU\" se non sei sicuro. Se non ce n'è una, lascia intatta quest'impostazione.",
"SettingsAppRequiredRestartMessage": "È richiesto un riavvio di Ryujinx",
"SettingsGpuBackendRestartMessage": "Le impostazioni della backend grafica o della GPU sono state modificate. Questo richiederà un riavvio perché le modifiche siano applicate",
"SettingsGpuBackendRestartSubMessage": "Vuoi riavviare ora?",
"RyujinxUpdaterMessage": "Vuoi aggiornare Ryujinx all'ultima versione?",
"SettingsTabHotkeysVolumeUpHotkey": "Aumentare il volume:",
"SettingsTabHotkeysVolumeDownHotkey": "Diminuire il volume:",
"VolumeShort": "Vol"
}

View File

@@ -588,5 +588,9 @@
"SettingsTabGraphicsPreferredGpuTooltip": "Wybierz kartę graficzną, która będzie używana z backendem graficznym Vulkan.\n\nNie wpływa na GPU używane przez OpenGL.\n\nW razie wątpliwości ustaw flagę GPU jako \"dGPU\". Jeśli żadnej nie ma, pozostaw nietknięte.",
"SettingsAppRequiredRestartMessage": "Wymagane Zrestartowanie Ryujinx",
"SettingsGpuBackendRestartMessage": "Zmieniono ustawienia Backendu Graficznego lub GPU. Będzie to wymagało ponownego uruchomienia",
"SettingsGpuBackendRestartSubMessage": "Czy chcesz zrestartować teraz?"
"SettingsGpuBackendRestartSubMessage": "Czy chcesz zrestartować teraz?",
"RyujinxUpdaterMessage": "Czy chcesz zaktualizować Ryujinx do najnowszej wersji?",
"SettingsTabHotkeysVolumeUpHotkey": "Zwiększ Głośność:",
"SettingsTabHotkeysVolumeDownHotkey": "Zmniejsz Głośność:",
"VolumeShort": "Głoś"
}

View File

@@ -34,7 +34,7 @@
<PackageReference Include="Silk.NET.Vulkan" Version="2.10.1" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.10.1" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.10.1" />
<PackageReference Include="SPB" Version="0.0.4-build24" />
<PackageReference Include="SPB" Version="0.0.4-build27" />
<PackageReference Include="SharpZipLib" Version="1.3.3" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
</ItemGroup>

View File

@@ -4,6 +4,7 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
using Avalonia.Threading;
using FluentAvalonia.Core;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Ui.Models;
@@ -27,7 +28,10 @@ namespace Ryujinx.Ava.Ui.Controls
string secondaryButton,
string closeButton,
int iconSymbol,
UserResult primaryButtonResult = UserResult.Ok)
UserResult primaryButtonResult = UserResult.Ok,
ManualResetEvent deferResetEvent = null,
Func<Window, Task> doWhileDeferred = null,
TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null)
{
UserResult result = UserResult.None;
@@ -110,12 +114,19 @@ namespace Ryujinx.Ava.Ui.Controls
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
{
result = UserResult.No;
contentDialog.PrimaryButtonClick -= deferCloseAction;
});
contentDialog.CloseButtonCommand = MiniCommand.Create(() =>
{
result = UserResult.Cancel;
contentDialog.PrimaryButtonClick -= deferCloseAction;
});
if (deferResetEvent != null)
{
contentDialog.PrimaryButtonClick += deferCloseAction;
}
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
overlay?.Close();
@@ -143,35 +154,20 @@ namespace Ryujinx.Ava.Ui.Controls
Func<Window, Task> doWhileDeferred = null)
{
bool startedDeferring = false;
UserResult result = UserResult.None;
ContentDialog contentDialog = new ContentDialog
{
Title = title,
PrimaryButtonText = primaryButton,
SecondaryButtonText = secondaryButton,
CloseButtonText = closeButton,
Content = CreateDialogTextContent(primaryText, secondaryText, iconSymbol),
PrimaryButtonCommand = MiniCommand.Create(() =>
{
result = primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok;
}),
};
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
{
contentDialog.PrimaryButtonClick -= DeferClose;
result = UserResult.No;
});
contentDialog.CloseButtonCommand = MiniCommand.Create(() =>
{
contentDialog.PrimaryButtonClick -= DeferClose;
result = UserResult.Cancel;
});
contentDialog.PrimaryButtonClick += DeferClose;
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
return result;
return await ShowContentDialog(
title,
primaryText,
secondaryText,
primaryButton,
secondaryButton,
closeButton,
iconSymbol,
primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok,
deferResetEvent,
doWhileDeferred,
DeferClose);
async void DeferClose(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
@@ -180,7 +176,7 @@ namespace Ryujinx.Ava.Ui.Controls
return;
}
contentDialog.PrimaryButtonClick -= DeferClose;
sender.PrimaryButtonClick -= DeferClose;
startedDeferring = true;
@@ -188,7 +184,7 @@ namespace Ryujinx.Ava.Ui.Controls
result = primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok;
contentDialog.PrimaryButtonClick -= DeferClose;
sender.PrimaryButtonClick -= DeferClose;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(() =>

View File

@@ -164,7 +164,7 @@
<MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="pl_PL"
Header="Polish" />
Header="Polski" />
<MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="ru_RU"

View File

@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 3759;
private const uint CodeGenVersion = 3781;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";

View File

@@ -306,7 +306,10 @@ namespace Ryujinx.Graphics.Shader.Translation
config._perPatchAttributeLocations = locationsMap;
}
if (config.Stage != ShaderStage.Fragment)
// We don't consider geometry shaders using the geometry shader passthrough feature
// as being the last because when this feature is used, it can't actually modify any of the outputs,
// so the stage that comes before it is the last one that can do modifications.
if (config.Stage != ShaderStage.Fragment && (config.Stage != ShaderStage.Geometry || !config.GpPassthrough))
{
LastInVertexPipeline = false;
}

View File

@@ -535,10 +535,11 @@ namespace Ryujinx.Graphics.Vulkan
vkBlend = new PipelineColorBlendAttachmentState();
}
_newState.BlendConstantR = blend.BlendConstant.Red;
_newState.BlendConstantG = blend.BlendConstant.Green;
_newState.BlendConstantB = blend.BlendConstant.Blue;
_newState.BlendConstantA = blend.BlendConstant.Alpha;
DynamicState.SetBlendConstants(
blend.BlendConstant.Red,
blend.BlendConstant.Green,
blend.BlendConstant.Blue,
blend.BlendConstant.Alpha);
SignalStateChange();
}

View File

@@ -135,11 +135,6 @@ namespace Ryujinx.Graphics.Vulkan
// It is assumed that Dynamic State is enabled when this conversion is used.
pipeline.BlendConstantA = state.BlendDescriptors[0].BlendConstant.Alpha;
pipeline.BlendConstantB = state.BlendDescriptors[0].BlendConstant.Blue;
pipeline.BlendConstantG = state.BlendDescriptors[0].BlendConstant.Green;
pipeline.BlendConstantR = state.BlendDescriptors[0].BlendConstant.Red;
pipeline.CullMode = state.CullEnable ? state.CullMode.Convert() : CullModeFlags.CullModeNone;
pipeline.DepthBoundsTestEnable = false; // Not implemented.

View File

@@ -19,21 +19,34 @@ namespace Ryujinx.Graphics.Vulkan
private uint _frontWriteMask;
private uint _frontReference;
private Array4<float> _blendConstants;
public int ViewportsCount;
public Array16<Viewport> Viewports;
private enum DirtyFlags
{
None = 0,
DepthBias = 1 << 0,
Scissor = 1 << 1,
Stencil = 1 << 2,
Viewport = 1 << 3,
All = DepthBias | Scissor | Stencil | Viewport
Blend = 1 << 0,
DepthBias = 1 << 1,
Scissor = 1 << 2,
Stencil = 1 << 3,
Viewport = 1 << 4,
All = Blend | DepthBias | Scissor | Stencil | Viewport
}
private DirtyFlags _dirty;
public void SetBlendConstants(float r, float g, float b, float a)
{
_blendConstants[0] = r;
_blendConstants[1] = g;
_blendConstants[2] = b;
_blendConstants[3] = a;
_dirty |= DirtyFlags.Blend;
}
public void SetDepthBias(float slopeFactor, float constantFactor, float clamp)
{
_depthBiasSlopeFactor = slopeFactor;
@@ -87,6 +100,11 @@ namespace Ryujinx.Graphics.Vulkan
public void ReplayIfDirty(Vk api, CommandBuffer commandBuffer)
{
if (_dirty.HasFlag(DirtyFlags.Blend))
{
RecordBlend(api, commandBuffer);
}
if (_dirty.HasFlag(DirtyFlags.DepthBias))
{
RecordDepthBias(api, commandBuffer);
@@ -110,6 +128,11 @@ namespace Ryujinx.Graphics.Vulkan
_dirty = DirtyFlags.None;
}
private void RecordBlend(Vk api, CommandBuffer commandBuffer)
{
api.CmdSetBlendConstants(commandBuffer, _blendConstants.AsSpan());
}
private void RecordDepthBias(Vk api, CommandBuffer commandBuffer)
{
api.CmdSetDepthBias(commandBuffer, _depthBiasConstantFactor, _depthBiasClamp, _depthBiasSlopeFactor);

View File

@@ -499,7 +499,7 @@ namespace Ryujinx.Graphics.Vulkan
colorBlendState.BlendConstants[3] = BlendConstantA;
bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
int dynamicStatesCount = supportsExtDynamicState ? 8 : 7;
int dynamicStatesCount = supportsExtDynamicState ? 9 : 8;
DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount];
@@ -510,10 +510,11 @@ namespace Ryujinx.Graphics.Vulkan
dynamicStates[4] = DynamicState.StencilCompareMask;
dynamicStates[5] = DynamicState.StencilWriteMask;
dynamicStates[6] = DynamicState.StencilReference;
dynamicStates[7] = DynamicState.BlendConstants;
if (supportsExtDynamicState)
{
dynamicStates[7] = DynamicState.VertexInputBindingStrideExt;
dynamicStates[8] = DynamicState.VertexInputBindingStrideExt;
}
var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo()

View File

@@ -5,22 +5,48 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.NfcManager
class INfc : IpcService
{
private NfcPermissionLevel _permissionLevel;
private State _state;
public INfc(NfcPermissionLevel permissionLevel)
{
_permissionLevel = permissionLevel;
_state = State.NonInitialized;
}
[CommandHipc(0)]
[CommandHipc(400)] // 4.0.0+
// Initialize()
// Initialize(u64, u64, pid, buffer<unknown, 5>)
public ResultCode Initialize(ServiceCtx context)
{
_state = State.Initialized;
Logger.Stub?.PrintStub(LogClass.ServiceNfc, new { _permissionLevel });
return ResultCode.Success;
}
[CommandHipc(1)]
[CommandHipc(401)] // 4.0.0+
// Finalize()
public ResultCode Finalize(ServiceCtx context)
{
_state = State.NonInitialized;
Logger.Stub?.PrintStub(LogClass.ServiceNfc, new { _permissionLevel });
return ResultCode.Success;
}
[CommandHipc(2)]
[CommandHipc(402)] // 4.0.0+
// GetState() -> u32
public ResultCode GetState(ServiceCtx context)
{
context.ResponseData.Write((int)_state);
return ResultCode.Success;
}
[CommandHipc(3)]
[CommandHipc(403)] // 4.0.0+
// IsNfcEnabled() -> b8

View File

@@ -0,0 +1,8 @@
namespace Ryujinx.HLE.HOS.Services.Nfc.NfcManager
{
enum State
{
NonInitialized,
Initialized
}
}

View File

@@ -349,7 +349,11 @@ namespace Ryujinx.HLE.HOS.Services.Ssl.SslService
// GetSessionCacheMode() -> nn::ssl::sf::SessionCacheMode
public ResultCode GetSessionCacheMode(ServiceCtx context)
{
throw new ServiceNotImplementedException(this, context);
context.ResponseData.Write((uint)_sessionCacheMode);
Logger.Stub?.PrintStub(LogClass.ServiceSsl, new { _sessionCacheMode });
return ResultCode.Success;
}
[CommandHipc(19)]

View File

@@ -92,5 +92,31 @@ namespace Ryujinx.Memory.Tests
}
}
}
[Test]
public void Test_AliasMapLeak()
{
if (OperatingSystem.IsMacOS())
{
// Memory aliasing tests fail on CI at the moment.
return;
}
ulong pageSize = 4096;
ulong size = 100000 * pageSize; // The mappings limit on Linux is usually around 65K, so let's make sure we are above that.
using MemoryBlock backing = new MemoryBlock(pageSize, MemoryAllocationFlags.Mirrorable);
using MemoryBlock toAlias = new MemoryBlock(size, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible);
for (ulong offset = 0; offset < size; offset += pageSize)
{
toAlias.MapView(backing, 0, offset, pageSize);
toAlias.Write(offset, 0xbadc0de);
Assert.AreEqual(0xbadc0de, backing.Read<int>(0));
toAlias.UnmapView(backing, offset, pageSize);
}
}
}
}

View File

@@ -177,7 +177,7 @@ namespace Ryujinx.Memory
public static void UnmapView(IntPtr location, ulong size)
{
mmap(location, size, MmapProts.PROT_NONE, MmapFlags.MAP_FIXED, -1, 0);
mmap(location, size, MmapProts.PROT_NONE, MmapFlags.MAP_FIXED | MmapFlags.MAP_PRIVATE | MmapFlags.MAP_ANONYMOUS | MmapFlags.MAP_NORESERVE, -1, 0);
}
}
}

View File

@@ -3,9 +3,10 @@ using System;
namespace Ryujinx.Tests.Unicorn
{
public class UnicornAArch32
public class UnicornAArch32 : IDisposable
{
internal readonly IntPtr uc;
private bool _isDisposed = false;
public IndexedProperty<int, uint> R
{
@@ -107,7 +108,22 @@ namespace Ryujinx.Tests.Unicorn
~UnicornAArch32()
{
Interface.Checked(Native.Interface.uc_close(uc));
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
Interface.Checked(Native.Interface.uc_close(uc));
_isDisposed = true;
}
}
public void RunForCount(ulong count)

View File

@@ -3,9 +3,10 @@ using System;
namespace Ryujinx.Tests.Unicorn
{
public class UnicornAArch64
public class UnicornAArch64 : IDisposable
{
internal readonly IntPtr uc;
private bool _isDisposed = false;
public IndexedProperty<int, ulong> X
{
@@ -96,7 +97,22 @@ namespace Ryujinx.Tests.Unicorn
~UnicornAArch64()
{
Interface.Checked(Native.Interface.uc_close(uc));
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
Interface.Checked(Native.Interface.uc_close(uc));
_isDisposed = true;
}
}
public void RunForCount(ulong count)

View File

@@ -80,6 +80,12 @@ namespace Ryujinx.Tests.Cpu
[TearDown]
public void Teardown()
{
if (_unicornAvailable)
{
_unicornEmu.Dispose();
_unicornEmu = null;
}
_memory.DecrementReferenceCount();
_context.Dispose();
_ram.Dispose();

View File

@@ -76,6 +76,12 @@ namespace Ryujinx.Tests.Cpu
[TearDown]
public void Teardown()
{
if (_unicornAvailable)
{
_unicornEmu.Dispose();
_unicornEmu = null;
}
_memory.DecrementReferenceCount();
_context.Dispose();
_ram.Dispose();

View File

@@ -339,6 +339,93 @@ namespace Ryujinx.Tests.Cpu
CompareAgainstUnicorn();
}
[Explicit]
[Test, Pairwise, Description("VCVT<top>.F16.F32 <Sd>, <Dm>")]
public void Vcvt_F32_F16([Values(0u, 1u, 2u, 3u)] uint rd,
[Values(0u, 1u, 2u, 3u)] uint rm,
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s0,
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s1,
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s2,
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s3,
[Values] bool top)
{
uint opcode = 0xeeb30a40; // VCVTB.F16.F32 S0, D0
if (top)
{
opcode |= 1 << 7;
}
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
V128 v0 = MakeVectorE0E1E2E3(s0, s1, s2, s3);
SingleOpcode(opcode, v0: v0);
CompareAgainstUnicorn();
}
[Explicit]
[Test, Pairwise, Description("VCVT<top>.F16.F64 <Sd>, <Dm>")]
public void Vcvt_F64_F16([Values(0u, 1u, 2u, 3u)] uint rd,
[Values(0u, 1u)] uint rm,
[ValueSource(nameof(_1D_F_))] ulong d0,
[ValueSource(nameof(_1D_F_))] ulong d1,
[Values] bool top)
{
uint opcode = 0xeeb30b40; // VCVTB.F16.F64 S0, D0
if (top)
{
opcode |= 1 << 7;
}
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
V128 v0 = MakeVectorE0E1(d0, d1);
SingleOpcode(opcode, v0: v0);
CompareAgainstUnicorn();
}
[Explicit]
[Test, Pairwise, Description("VCVT<top>.F<size>.F16 <Vd>, <Sm>")]
public void Vcvt_F16_Fx([Values(0u, 1u, 2u, 3u)] uint rd,
[Values(0u, 1u, 2u, 3u)] uint rm,
[ValueSource(nameof(_1D_F_))] ulong d0,
[ValueSource(nameof(_1D_F_))] ulong d1,
[Values] bool top,
[Values] bool sz)
{
uint opcode = 0xeeb20a40; // VCVTB.F32.F16 S0, S0
if (top)
{
opcode |= 1 << 7;
}
if (sz)
{
opcode |= 1 << 8;
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
}
else
{
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
}
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
V128 v0 = MakeVectorE0E1(d0, d1);
SingleOpcode(opcode, v0: v0);
CompareAgainstUnicorn();
}
#endif
}
}

View File

@@ -23,7 +23,7 @@
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="OpenTK.Graphics" Version="4.7.2" />
<PackageReference Include="SPB" Version="0.0.4-build24" />
<PackageReference Include="SPB" Version="0.0.4-build27" />
<PackageReference Include="SharpZipLib" Version="1.3.3" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
</ItemGroup>