Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9719b6a112 | ||
|
f70236f947 | ||
|
eafadf10c7 | ||
|
9b06ee7736 | ||
|
baba2c2467 | ||
|
286e5d39b2 | ||
|
dc529c1181 | ||
|
c7cf1cbc35 | ||
|
d8e487d018 | ||
|
5fdc46ac7f | ||
|
1e5b45f580 | ||
|
62585755fd | ||
|
56621615b1 | ||
|
2099a3e84b | ||
|
7d26e4ac7b | ||
|
8d41402fa6 | ||
|
5af8ce7c38 | ||
|
77c4291c34 |
24
.github/dependabot.yml
vendored
Normal file
24
.github/dependabot.yml
vendored
Normal 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
|
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
@@ -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
|
||||
|
12
.github/workflows/nightly_pr_comment.yml
vendored
12
.github/workflows/nightly_pr_comment.yml
vendored
@@ -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});
|
||||
}
|
||||
|
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -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: |
|
||||
|
44
ARMeilleure/Decoders/OpCode32SimdCvtTB.cs
Normal file
44
ARMeilleure/Decoders/OpCode32SimdCvtTB.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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.).
|
||||
|
@@ -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);
|
||||
|
@@ -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.
|
||||
}
|
||||
}
|
||||
|
@@ -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";
|
||||
|
@@ -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];
|
||||
|
@@ -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**
|
||||
|
||||
|
@@ -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"
|
||||
}
|
||||
|
@@ -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ś"
|
||||
}
|
||||
|
@@ -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>
|
||||
|
@@ -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(() =>
|
||||
|
@@ -164,7 +164,7 @@
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="pl_PL"
|
||||
Header="Polish" />
|
||||
Header="Polski" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="ru_RU"
|
||||
|
@@ -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";
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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.
|
||||
|
@@ -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);
|
||||
|
@@ -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()
|
||||
|
@@ -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
|
||||
|
8
Ryujinx.HLE/HOS/Services/Nfc/NfcManager/Types/State.cs
Normal file
8
Ryujinx.HLE/HOS/Services/Nfc/NfcManager/Types/State.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Nfc.NfcManager
|
||||
{
|
||||
enum State
|
||||
{
|
||||
NonInitialized,
|
||||
Initialized
|
||||
}
|
||||
}
|
@@ -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)]
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -80,6 +80,12 @@ namespace Ryujinx.Tests.Cpu
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.Dispose();
|
||||
_unicornEmu = null;
|
||||
}
|
||||
|
||||
_memory.DecrementReferenceCount();
|
||||
_context.Dispose();
|
||||
_ram.Dispose();
|
||||
|
@@ -76,6 +76,12 @@ namespace Ryujinx.Tests.Cpu
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.Dispose();
|
||||
_unicornEmu = null;
|
||||
}
|
||||
|
||||
_memory.DecrementReferenceCount();
|
||||
_context.Dispose();
|
||||
_ram.Dispose();
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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>
|
||||
|
Reference in New Issue
Block a user