Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
11aae9cfbc | ||
|
b96794e72b | ||
|
f1d1670b0b | ||
|
b8de72de8f | ||
|
eebc39228d | ||
|
9daf029f35 | ||
|
51a27032f0 | ||
|
a6a67a2b7a | ||
|
c6d05301aa | ||
|
647de4cd31 | ||
|
f82309fa2d | ||
|
7d8e198c33 | ||
|
3d98e1361b | ||
|
141cf61ff7 | ||
|
3fe3598d41 | ||
|
59cdf310bd | ||
|
4e34170a84 | ||
|
d540af5dc0 | ||
|
f7c7b66fc0 | ||
|
28ba55598d | ||
|
9719b6a112 | ||
|
f70236f947 | ||
|
eafadf10c7 | ||
|
9b06ee7736 | ||
|
baba2c2467 | ||
|
286e5d39b2 | ||
|
dc529c1181 | ||
|
c7cf1cbc35 | ||
|
d8e487d018 | ||
|
5fdc46ac7f | ||
|
1e5b45f580 | ||
|
62585755fd | ||
|
56621615b1 | ||
|
2099a3e84b | ||
|
7d26e4ac7b | ||
|
8d41402fa6 | ||
|
5af8ce7c38 | ||
|
77c4291c34 | ||
|
6e92b7a378 | ||
|
9b852c7481 | ||
|
c40c3905e2 | ||
|
a6cd044f0f | ||
|
f5a1de6ac5 | ||
|
2aeb5b00e3 | ||
|
60ba7b71f2 | ||
|
7c1d2bbb98 | ||
|
beacf8c1c8 | ||
|
0dbe45ae37 | ||
|
2b50e52e48 | ||
|
49eadbc209 | ||
|
2df16ded9b |
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
|
17
.github/workflows/build.yml
vendored
17
.github/workflows/build.yml
vendored
@@ -48,21 +48,22 @@ jobs:
|
|||||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||||
RYUJINX_BASE_VERSION: "1.1.0"
|
RYUJINX_BASE_VERSION: "1.1.0"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-dotnet@v1
|
- uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 6.0.x
|
dotnet-version: 7.0.x
|
||||||
- name: Ensure NuGet Source
|
- name: Ensure NuGet Source
|
||||||
uses: fabriciomurta/ensure-nuget-source@v1
|
uses: fabriciomurta/ensure-nuget-source@v1
|
||||||
- name: Get git short hash
|
- name: Get git short hash
|
||||||
id: 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
|
||||||
|
shell: bash
|
||||||
- name: Clear
|
- name: Clear
|
||||||
run: dotnet clean && dotnet nuget locals all --clear
|
run: dotnet clean && dotnet nuget locals all --clear
|
||||||
- name: Build
|
- 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
|
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
|
- name: Test
|
||||||
run: dotnet test -c "${{ matrix.configuration }}"
|
run: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||||
- name: Publish Ryujinx
|
- 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
|
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'
|
if: github.event_name == 'pull_request'
|
||||||
@@ -73,19 +74,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
|
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'
|
if: github.event_name == 'pull_request'
|
||||||
- name: Upload Ryujinx artifact
|
- name: Upload Ryujinx artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||||
path: publish
|
path: publish
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
- name: Upload Ryujinx.Headless.SDL2 artifact
|
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||||
path: publish_sdl2_headless
|
path: publish_sdl2_headless
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
- name: Upload Ryujinx.Ava artifact
|
- name: Upload Ryujinx.Ava artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||||
path: publish_ava
|
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'
|
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@v3
|
- uses: actions/github-script@v6
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const {owner, repo} = context.repo;
|
const {owner, repo} = context.repo;
|
||||||
@@ -16,7 +16,7 @@ jobs:
|
|||||||
const pull_head_sha = '${{github.event.workflow_run.head_sha}}';
|
const pull_head_sha = '${{github.event.workflow_run.head_sha}}';
|
||||||
|
|
||||||
const issue_number = await (async () => {
|
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 await (const {data} of github.paginate.iterator(pulls)) {
|
||||||
for (const pull of data) {
|
for (const pull of data) {
|
||||||
if (pull.head.sha === pull_head_sha) {
|
if (pull.head.sha === pull_head_sha) {
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
return core.error(`No matching pull request found`);
|
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) {
|
if (!artifacts.length) {
|
||||||
return core.error(`No artifacts found`);
|
return core.error(`No artifacts found`);
|
||||||
}
|
}
|
||||||
@@ -57,12 +57,12 @@ jobs:
|
|||||||
body += hidden_headless_artifacts;
|
body += hidden_headless_artifacts;
|
||||||
body += hidden_debug_artifacts;
|
body += hidden_debug_artifacts;
|
||||||
|
|
||||||
const {data: comments} = await github.issues.listComments({repo, owner, issue_number});
|
const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number});
|
||||||
const existing_comment = comments.find((c) => c.user.login === 'github-actions[bot]');
|
const existing_comment = comments.find((c) => c.user.login === 'github-actions[bot]');
|
||||||
if (existing_comment) {
|
if (existing_comment) {
|
||||||
core.info(`Updating comment ${existing_comment.id}`);
|
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 {
|
} else {
|
||||||
core.info(`Creating a comment`);
|
core.info(`Creating a comment`);
|
||||||
await github.issues.createComment({repo, owner, issue_number, body});
|
await github.rest.issues.createComment({repo, owner, issue_number, body});
|
||||||
}
|
}
|
||||||
|
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -25,10 +25,10 @@ jobs:
|
|||||||
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
|
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-dotnet@v1
|
- uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 6.0.x
|
dotnet-version: 7.0.x
|
||||||
- name: Ensure NuGet Source
|
- name: Ensure NuGet Source
|
||||||
uses: fabriciomurta/ensure-nuget-source@v1
|
uses: fabriciomurta/ensure-nuget-source@v1
|
||||||
- name: Clear
|
- name: Clear
|
||||||
@@ -36,8 +36,8 @@ jobs:
|
|||||||
- name: Get version info
|
- name: Get version info
|
||||||
id: version_info
|
id: version_info
|
||||||
run: |
|
run: |
|
||||||
echo "::set-output name=build_version::${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}"
|
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||||
echo "::set-output name=git_short_hash::$(git rev-parse --short "${{ github.sha }}")"
|
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: Configure for release
|
- name: Configure for release
|
||||||
run: |
|
run: |
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
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("<<<<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("<<<<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("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("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetVfp("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, OpCode32SimdDupGP.Create, OpCode32SimdDupGP.CreateT32);
|
SetVfp("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, OpCode32SimdDupGP.Create, OpCode32SimdDupGP.CreateT32);
|
||||||
SetVfp("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
SetVfp("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
@@ -1616,20 +1616,34 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void Frinta_S(ArmEmitterContext context)
|
public static void Frinta_S(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41ScalarRoundOpF(context, FPRoundingMode.ToNearestAway);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
EmitScalarUnaryOpF(context, (op1) =>
|
EmitScalarUnaryOpF(context, (op1) =>
|
||||||
{
|
{
|
||||||
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
|
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Frinta_V(ArmEmitterContext context)
|
public static void Frinta_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41VectorRoundOpF(context, FPRoundingMode.ToNearestAway);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
EmitVectorUnaryOpF(context, (op1) =>
|
EmitVectorUnaryOpF(context, (op1) =>
|
||||||
{
|
{
|
||||||
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
|
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Frinti_S(ArmEmitterContext context)
|
public static void Frinti_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
@@ -3516,9 +3530,18 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand n = GetVec(op.Rn);
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
|
Operand res;
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundsd : Intrinsic.X86Roundss;
|
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundsd : Intrinsic.X86Roundss;
|
||||||
|
|
||||||
Operand res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
|
res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = EmitSse41RoundToNearestWithTiesToAwayOpF(context, n, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
if ((op.Size & 1) != 0)
|
if ((op.Size & 1) != 0)
|
||||||
{
|
{
|
||||||
@@ -3538,9 +3561,18 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand n = GetVec(op.Rn);
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
|
Operand res;
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundpd : Intrinsic.X86Roundps;
|
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundpd : Intrinsic.X86Roundps;
|
||||||
|
|
||||||
Operand res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
|
res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = EmitSse41RoundToNearestWithTiesToAwayOpF(context, n, scalar: false);
|
||||||
|
}
|
||||||
|
|
||||||
if (op.RegisterSize == RegisterSize.Simd64)
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
{
|
{
|
||||||
|
@@ -163,34 +163,76 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void Fcvtas_Gp(ArmEmitterContext context)
|
public static void Fcvtas_Gp(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41Fcvts_Gp(context, FPRoundingMode.ToNearestAway, isFixed: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
EmitFcvt_s_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
|
EmitFcvt_s_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fcvtas_S(ArmEmitterContext context)
|
public static void Fcvtas_S(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearestAway, scalar: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: true);
|
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fcvtas_V(ArmEmitterContext context)
|
public static void Fcvtas_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearestAway, scalar: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: false);
|
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fcvtau_Gp(ArmEmitterContext context)
|
public static void Fcvtau_Gp(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41Fcvtu_Gp(context, FPRoundingMode.ToNearestAway, isFixed: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
EmitFcvt_u_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
|
EmitFcvt_u_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fcvtau_S(ArmEmitterContext context)
|
public static void Fcvtau_S(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearestAway, scalar: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: true);
|
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fcvtau_V(ArmEmitterContext context)
|
public static void Fcvtau_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearestAway, scalar: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: false);
|
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fcvtl_V(ArmEmitterContext context)
|
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.X86Mulps, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
|
||||||
|
}
|
||||||
|
|
||||||
Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes);
|
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.X86Mulpd, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
|
||||||
|
}
|
||||||
|
|
||||||
Operand nLong = EmitSse2CvtDoubleToInt64OpF(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.X86Mulps, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
@@ -1369,7 +1432,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulpd, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulpd, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
@@ -1424,7 +1494,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32
|
Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32
|
||||||
? context.AddIntrinsicInt (Intrinsic.X86Cvtss2si, nRes)
|
? context.AddIntrinsicInt (Intrinsic.X86Cvtss2si, nRes)
|
||||||
@@ -1464,7 +1541,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32
|
Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32
|
||||||
? context.AddIntrinsicInt (Intrinsic.X86Cvtsd2si, nRes)
|
? context.AddIntrinsicInt (Intrinsic.X86Cvtsd2si, nRes)
|
||||||
@@ -1512,7 +1596,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
@@ -1567,7 +1658,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
|
@@ -203,6 +203,9 @@ namespace ARMeilleure.Instructions
|
|||||||
FPRoundingMode roundMode;
|
FPRoundingMode roundMode;
|
||||||
switch (rm)
|
switch (rm)
|
||||||
{
|
{
|
||||||
|
case 0b00:
|
||||||
|
roundMode = FPRoundingMode.ToNearestAway;
|
||||||
|
break;
|
||||||
case 0b01:
|
case 0b01:
|
||||||
roundMode = FPRoundingMode.ToNearest;
|
roundMode = FPRoundingMode.ToNearest;
|
||||||
break;
|
break;
|
||||||
@@ -228,7 +231,7 @@ namespace ARMeilleure.Instructions
|
|||||||
bool unsigned = op.Opc == 0;
|
bool unsigned = op.Opc == 0;
|
||||||
int rm = op.Opc2 & 3;
|
int rm = op.Opc2 & 3;
|
||||||
|
|
||||||
if (Optimizations.UseSse41 && rm != 0b00)
|
if (Optimizations.UseSse41)
|
||||||
{
|
{
|
||||||
EmitSse41ConvertInt32(context, RMToRoundMode(rm), !unsigned);
|
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).
|
// VRINTA/M/N/P (floating-point).
|
||||||
public static void Vrint_RM(ArmEmitterContext context)
|
public static void Vrint_RM(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
@@ -267,15 +338,21 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
int rm = op.Opc2 & 3;
|
int rm = op.Opc2 & 3;
|
||||||
|
|
||||||
if (Optimizations.UseSse2 && rm != 0b00)
|
if (Optimizations.UseSse41)
|
||||||
{
|
{
|
||||||
EmitScalarUnaryOpSimd32(context, (m) =>
|
EmitScalarUnaryOpSimd32(context, (m) =>
|
||||||
{
|
{
|
||||||
Intrinsic inst = (op.Size & 1) == 0 ? Intrinsic.X86Roundss : Intrinsic.X86Roundsd;
|
|
||||||
|
|
||||||
FPRoundingMode roundMode = RMToRoundMode(rm);
|
FPRoundingMode roundMode = RMToRoundMode(rm);
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
Intrinsic inst = (op.Size & 1) == 0 ? Intrinsic.X86Roundss : Intrinsic.X86Roundsd;
|
||||||
return context.AddIntrinsic(inst, m, Const(X86GetRoundControl(roundMode)));
|
return context.AddIntrinsic(inst, m, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return EmitSse41RoundToNearestWithTiesToAwayOpF(context, m, scalar: true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -304,9 +381,19 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
// VRINTA (vector).
|
// VRINTA (vector).
|
||||||
public static void Vrinta_V(ArmEmitterContext context)
|
public static void Vrinta_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||||
|
{
|
||||||
|
return EmitSse41RoundToNearestWithTiesToAwayOpF(context, m, scalar: false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, m));
|
EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, m));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VRINTM (vector).
|
// VRINTM (vector).
|
||||||
public static void Vrintm_V(ArmEmitterContext context)
|
public static void Vrintm_V(ArmEmitterContext context)
|
||||||
@@ -413,7 +500,14 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, n, n, Const((int)CmpCondition.OrderedQ));
|
Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, n, n, Const((int)CmpCondition.OrderedQ));
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n);
|
nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n);
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
@@ -464,7 +558,14 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, n, Const((int)CmpCondition.OrderedQ));
|
Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, n, Const((int)CmpCondition.OrderedQ));
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n);
|
nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n);
|
||||||
|
|
||||||
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
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 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
|
#endregion
|
||||||
|
|
||||||
#region "X86 SSE Intrinsics"
|
#region "X86 SSE Intrinsics"
|
||||||
@@ -243,19 +251,44 @@ namespace ARMeilleure.Instructions
|
|||||||
throw new ArgumentException($"Invalid rounding mode \"{roundMode}\".");
|
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 =
|
Debug.Assert(n.Type == OperandType.V128);
|
||||||
(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);
|
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.).
|
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);
|
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)
|
public static Operand ExtractElement(ArmEmitterContext context, int reg, int size, bool signed)
|
||||||
{
|
{
|
||||||
return EmitVectorExtract32(context, reg >> (4 - size), reg & ((16 >> size) - 1), size, signed);
|
return EmitVectorExtract32(context, reg >> (4 - size), reg & ((16 >> size) - 1), size, signed);
|
||||||
|
@@ -2,9 +2,10 @@ namespace ARMeilleure.State
|
|||||||
{
|
{
|
||||||
public enum FPRoundingMode
|
public enum FPRoundingMode
|
||||||
{
|
{
|
||||||
ToNearest = 0,
|
ToNearest = 0, // With ties to even.
|
||||||
TowardsPlusInfinity = 1,
|
TowardsPlusInfinity = 1,
|
||||||
TowardsMinusInfinity = 2,
|
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 OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\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 ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
@@ -455,13 +455,16 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
public void InvalidateJitCacheRegion(ulong address, ulong size)
|
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>();
|
ulong[] overlapAddresses = Array.Empty<ulong>();
|
||||||
|
|
||||||
int overlapsCount = Functions.GetOverlaps(address, size, ref overlapAddresses);
|
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++)
|
for (int index = 0; index < overlapsCount; index++)
|
||||||
{
|
{
|
||||||
ulong overlapAddress = overlapAddresses[index];
|
ulong overlapAddress = overlapAddresses[index];
|
||||||
|
@@ -36,8 +36,8 @@
|
|||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
As of September 2022, Ryujinx has been tested on approximately 3,600 titles; over 3,400 boot past menus and into gameplay, with roughly 2,700 of those being considered playable. You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
|
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.
|
||||||
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!
|
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
|
## Usage
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ The latest automatic build for Windows, macOS, and Linux can be found on the [Of
|
|||||||
If you wish to build the emulator yourself, follow these steps:
|
If you wish to build the emulator yourself, follow these steps:
|
||||||
|
|
||||||
### Step 1
|
### Step 1
|
||||||
Install the X64 version of [.NET 6.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/6.0).
|
Install the X64 version of [.NET 7.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/7.0).
|
||||||
|
|
||||||
### Step 2
|
### Step 2
|
||||||
Either use `git clone https://github.com/Ryujinx/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
|
Either use `git clone https://github.com/Ryujinx/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
|
||||||
@@ -90,7 +90,7 @@ Ryujinx system files are stored in the `Ryujinx` folder. This folder is located
|
|||||||
|
|
||||||
- **GPU**
|
- **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**
|
- **Input**
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<RuntimeIdentifiers>win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@@ -150,7 +150,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputHeader">The splitter header.</param>
|
/// <param name="inputHeader">The splitter header.</param>
|
||||||
/// <param name="input">The raw data after the splitter header.</param>
|
/// <param name="input">The raw data after the splitter header.</param>
|
||||||
private void UpdateState(ref SplitterInParameterHeader inputHeader, ref ReadOnlySpan<byte> input)
|
private void UpdateState(scoped ref SplitterInParameterHeader inputHeader, ref ReadOnlySpan<byte> input)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < inputHeader.SplitterCount; i++)
|
for (int i = 0; i < inputHeader.SplitterCount; i++)
|
||||||
{
|
{
|
||||||
@@ -177,7 +177,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputHeader">The splitter header.</param>
|
/// <param name="inputHeader">The splitter header.</param>
|
||||||
/// <param name="input">The raw data after the splitter header.</param>
|
/// <param name="input">The raw data after the splitter header.</param>
|
||||||
private void UpdateData(ref SplitterInParameterHeader inputHeader, ref ReadOnlySpan<byte> input)
|
private void UpdateData(scoped ref SplitterInParameterHeader inputHeader, ref ReadOnlySpan<byte> input)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < inputHeader.SplitterDestinationCount; i++)
|
for (int i = 0; i < inputHeader.SplitterDestinationCount; i++)
|
||||||
{
|
{
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@ using Ryujinx.Ava.Ui.Windows;
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -64,8 +65,7 @@ namespace Ryujinx.Ava
|
|||||||
if (result == UserResult.Yes)
|
if (result == UserResult.Yes)
|
||||||
{
|
{
|
||||||
var path = Process.GetCurrentProcess().MainModule.FileName;
|
var path = Process.GetCurrentProcess().MainModule.FileName;
|
||||||
var info = new ProcessStartInfo() { FileName = path, UseShellExecute = false };
|
var proc = Process.Start(path, CommandLineState.Arguments);
|
||||||
var proc = Process.Start(info);
|
|
||||||
desktop.Shutdown();
|
desktop.Shutdown();
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
@@ -587,10 +587,12 @@
|
|||||||
"SettingsTabGraphicsPreferredGpu": "Preferred GPU",
|
"SettingsTabGraphicsPreferredGpu": "Preferred GPU",
|
||||||
"SettingsTabGraphicsPreferredGpuTooltip": "Select the graphics card that will be used with the Vulkan graphics backend.\n\nDoes not affect the GPU that OpenGL will use.\n\nSet to the GPU flagged as \"dGPU\" if unsure. If there isn't one, leave untouched.",
|
"SettingsTabGraphicsPreferredGpuTooltip": "Select the graphics card that will be used with the Vulkan graphics backend.\n\nDoes not affect the GPU that OpenGL will use.\n\nSet to the GPU flagged as \"dGPU\" if unsure. If there isn't one, leave untouched.",
|
||||||
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
|
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
|
||||||
"SettingsGpuBackendRestartMessage": "Graphics Backend or Gpu settings have been modified. This will require a restart to be applied",
|
"SettingsGpuBackendRestartMessage": "Graphics Backend or GPU settings have been modified. This will require a restart to be applied",
|
||||||
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?",
|
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?",
|
||||||
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
||||||
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
||||||
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||||
"VolumeShort": "Vol"
|
"VolumeShort": "Vol",
|
||||||
|
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
||||||
|
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure."
|
||||||
}
|
}
|
||||||
|
@@ -49,8 +49,8 @@
|
|||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Apre la finestra di gestione aggiornamenti del gioco",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Apre la finestra di gestione aggiornamenti del gioco",
|
||||||
"GameListContextMenuManageDlc": "Gestici DLC",
|
"GameListContextMenuManageDlc": "Gestici DLC",
|
||||||
"GameListContextMenuManageDlcToolTip": "Apre la finestra di gestione DLC",
|
"GameListContextMenuManageDlcToolTip": "Apre la finestra di gestione DLC",
|
||||||
"GameListContextMenuOpenModsDirectory": "Apri cartella delle mods",
|
"GameListContextMenuOpenModsDirectory": "Apri cartella delle mod",
|
||||||
"GameListContextMenuOpenModsDirectoryToolTip": "Apre la cartella che contiene le mods dell'applicazione",
|
"GameListContextMenuOpenModsDirectoryToolTip": "Apre la cartella che contiene le mod dell'applicazione",
|
||||||
"GameListContextMenuCacheManagement": "Gestione della cache",
|
"GameListContextMenuCacheManagement": "Gestione della cache",
|
||||||
"GameListContextMenuCacheManagementPurgePptc": "Pulisci PPTC cache",
|
"GameListContextMenuCacheManagementPurgePptc": "Pulisci PPTC cache",
|
||||||
"GameListContextMenuCacheManagementPurgePptcToolTip": "Elimina la PPTC cache dell'applicazione",
|
"GameListContextMenuCacheManagementPurgePptcToolTip": "Elimina la PPTC cache dell'applicazione",
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
"SettingsTabGeneralRemove": "Rimuovi",
|
"SettingsTabGeneralRemove": "Rimuovi",
|
||||||
"SettingsTabSystem": "Sistema",
|
"SettingsTabSystem": "Sistema",
|
||||||
"SettingsTabSystemCore": "Core",
|
"SettingsTabSystemCore": "Core",
|
||||||
"SettingsTabSystemSystemRegion": "Regione di sistema:",
|
"SettingsTabSystemSystemRegion": "Regione del sistema:",
|
||||||
"SettingsTabSystemSystemRegionJapan": "Giappone",
|
"SettingsTabSystemSystemRegionJapan": "Giappone",
|
||||||
"SettingsTabSystemSystemRegionUSA": "Stati Uniti d'America",
|
"SettingsTabSystemSystemRegionUSA": "Stati Uniti d'America",
|
||||||
"SettingsTabSystemSystemRegionEurope": "Europa",
|
"SettingsTabSystemSystemRegionEurope": "Europa",
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
"SettingsTabSystemSystemRegionChina": "Cina",
|
"SettingsTabSystemSystemRegionChina": "Cina",
|
||||||
"SettingsTabSystemSystemRegionKorea": "Corea",
|
"SettingsTabSystemSystemRegionKorea": "Corea",
|
||||||
"SettingsTabSystemSystemRegionTaiwan": "Taiwan",
|
"SettingsTabSystemSystemRegionTaiwan": "Taiwan",
|
||||||
"SettingsTabSystemSystemLanguage": "Lingua di sistema:",
|
"SettingsTabSystemSystemLanguage": "Lingua del sistema:",
|
||||||
"SettingsTabSystemSystemLanguageJapanese": "Giapponese",
|
"SettingsTabSystemSystemLanguageJapanese": "Giapponese",
|
||||||
"SettingsTabSystemSystemLanguageAmericanEnglish": "Inglese americano",
|
"SettingsTabSystemSystemLanguageAmericanEnglish": "Inglese americano",
|
||||||
"SettingsTabSystemSystemLanguageFrench": "Francese",
|
"SettingsTabSystemSystemLanguageFrench": "Francese",
|
||||||
@@ -107,8 +107,8 @@
|
|||||||
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Spagnolo latino americano",
|
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Spagnolo latino americano",
|
||||||
"SettingsTabSystemSystemLanguageSimplifiedChinese": "Cinese semplificato",
|
"SettingsTabSystemSystemLanguageSimplifiedChinese": "Cinese semplificato",
|
||||||
"SettingsTabSystemSystemLanguageTraditionalChinese": "Cinese tradizionale",
|
"SettingsTabSystemSystemLanguageTraditionalChinese": "Cinese tradizionale",
|
||||||
"SettingsTabSystemSystemTimeZone": "Fuso orario di sistema:",
|
"SettingsTabSystemSystemTimeZone": "Fuso orario del sistema:",
|
||||||
"SettingsTabSystemSystemTime": "Data e ora di sistema:",
|
"SettingsTabSystemSystemTime": "Data e ora del sistema:",
|
||||||
"SettingsTabSystemEnableVsync": "Attiva VSync",
|
"SettingsTabSystemEnableVsync": "Attiva VSync",
|
||||||
"SettingsTabSystemEnablePptc": "Attiva PPTC (Profiled Persistent Translation Cache)",
|
"SettingsTabSystemEnablePptc": "Attiva PPTC (Profiled Persistent Translation Cache)",
|
||||||
"SettingsTabSystemEnableFsIntegrityChecks": "Attiva controlli d'integrità FS",
|
"SettingsTabSystemEnableFsIntegrityChecks": "Attiva controlli d'integrità FS",
|
||||||
@@ -155,7 +155,7 @@
|
|||||||
"SettingsTabLoggingEnableTraceLogs": "Attiva Trace Logs",
|
"SettingsTabLoggingEnableTraceLogs": "Attiva Trace Logs",
|
||||||
"SettingsTabLoggingEnableGuestLogs": "Attiva Guest Logs",
|
"SettingsTabLoggingEnableGuestLogs": "Attiva Guest Logs",
|
||||||
"SettingsTabLoggingEnableFsAccessLogs": "Attiva Fs Access 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)",
|
"SettingsTabLoggingDeveloperOptions": "Opzioni da sviluppatore (AVVISO: Ridurrà le prestazioni)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "Livello di log OpenGL:",
|
"SettingsTabLoggingOpenglLogLevel": "Livello di log OpenGL:",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "Nessuno",
|
"SettingsTabLoggingOpenglLogLevelNone": "Nessuno",
|
||||||
@@ -240,7 +240,7 @@
|
|||||||
"ControllerSettingsRightSR": "SR",
|
"ControllerSettingsRightSR": "SR",
|
||||||
"ControllerSettingsExtraButtonsLeft": "Tasto sinitro",
|
"ControllerSettingsExtraButtonsLeft": "Tasto sinitro",
|
||||||
"ControllerSettingsExtraButtonsRight": "Tasto destro",
|
"ControllerSettingsExtraButtonsRight": "Tasto destro",
|
||||||
"ControllerSettingsMisc": "Miscellanee",
|
"ControllerSettingsMisc": "Varie",
|
||||||
"ControllerSettingsTriggerThreshold": "Sensibilità dei grilletti:",
|
"ControllerSettingsTriggerThreshold": "Sensibilità dei grilletti:",
|
||||||
"ControllerSettingsMotion": "Movimento",
|
"ControllerSettingsMotion": "Movimento",
|
||||||
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "Usa sensore compatibile con CemuHook",
|
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "Usa sensore compatibile con CemuHook",
|
||||||
@@ -261,7 +261,7 @@
|
|||||||
"UserProfilesClose": "Chiudi",
|
"UserProfilesClose": "Chiudi",
|
||||||
"ProfileImageSelectionTitle": "Selezione dell'immagine profilo",
|
"ProfileImageSelectionTitle": "Selezione dell'immagine profilo",
|
||||||
"ProfileImageSelectionHeader": "Scegli un'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",
|
"ProfileImageSelectionImportImage": "Importa file immagine",
|
||||||
"ProfileImageSelectionSelectAvatar": "Seleziona avatar dal firmware",
|
"ProfileImageSelectionSelectAvatar": "Seleziona avatar dal firmware",
|
||||||
"InputDialogTitle": "Input Dialog",
|
"InputDialogTitle": "Input Dialog",
|
||||||
@@ -293,7 +293,7 @@
|
|||||||
"ControllerSettingsRumbleStrongMultiplier": "Moltiplicatore vibrazione forte",
|
"ControllerSettingsRumbleStrongMultiplier": "Moltiplicatore vibrazione forte",
|
||||||
"ControllerSettingsRumbleWeakMultiplier": "Moltiplicatore vibrazione debole",
|
"ControllerSettingsRumbleWeakMultiplier": "Moltiplicatore vibrazione debole",
|
||||||
"DialogMessageSaveNotAvailableMessage": "Non ci sono dati di salvataggio per {0} [{1:x16}]",
|
"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",
|
"DialogConfirmationTitle": "Ryujinx - Conferma",
|
||||||
"DialogUpdaterTitle": "Ryujinx - Updater",
|
"DialogUpdaterTitle": "Ryujinx - Updater",
|
||||||
"DialogErrorTitle": "Ryujinx - Errore",
|
"DialogErrorTitle": "Ryujinx - Errore",
|
||||||
@@ -318,7 +318,7 @@
|
|||||||
"DialogUpdaterDownloadingMessage": "Download dell'aggiornamento...",
|
"DialogUpdaterDownloadingMessage": "Download dell'aggiornamento...",
|
||||||
"DialogUpdaterExtractionMessage": "Estrazione dell'aggiornamento...",
|
"DialogUpdaterExtractionMessage": "Estrazione dell'aggiornamento...",
|
||||||
"DialogUpdaterRenamingMessage": "Rinominazione dell'aggiornamento...",
|
"DialogUpdaterRenamingMessage": "Rinominazione dell'aggiornamento...",
|
||||||
"DialogUpdaterAddingFilesMessage": "Aggiunta nuovo aggiornamento...",
|
"DialogUpdaterAddingFilesMessage": "Aggiunta del nuovo aggiornamento...",
|
||||||
"DialogUpdaterCompleteMessage": "Aggiornamento completato!",
|
"DialogUpdaterCompleteMessage": "Aggiornamento completato!",
|
||||||
"DialogUpdaterRestartMessage": "Vuoi riavviare Ryujinx adesso?",
|
"DialogUpdaterRestartMessage": "Vuoi riavviare Ryujinx adesso?",
|
||||||
"DialogUpdaterArchNotSupportedMessage": "Non stai usando un'architettura di sistema supportata!",
|
"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.",
|
"DialogThemeRestartMessage": "Il tema è stato salvato. E' richiesto un riavvio per applicare un tema.",
|
||||||
"DialogThemeRestartSubMessage": "Vuoi riavviare?",
|
"DialogThemeRestartSubMessage": "Vuoi riavviare?",
|
||||||
"DialogFirmwareInstallEmbeddedMessage": "Vuoi installare il firmware incorporato in questo gioco? (Firmware {0})",
|
"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",
|
"DialogFirmwareNoFirmwareInstalledMessage": "Nessun firmware installato",
|
||||||
"DialogFirmwareInstalledMessage": "Il firmware {0} è stato installato",
|
"DialogFirmwareInstalledMessage": "Il firmware {0} è stato installato",
|
||||||
"DialogOpenSettingsWindowLabel": "Apri finestra delle impostazioni",
|
"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?",
|
"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}",
|
"DialogShaderDeletionErrorMessage": "Errore nell'eliminazione della Shader cache a {0}: {1}",
|
||||||
"DialogRyujinxErrorMessage": "Ryujinx ha incontrato un errore",
|
"DialogRyujinxErrorMessage": "Ryujinx ha incontrato un errore",
|
||||||
"DialogInvalidTitleIdErrorMessage": "Errore UI: Il gioco selezionato non ha un title ID valido",
|
"DialogInvalidTitleIdErrorMessage": "Errore UI: Il gioco selezionato non ha un ID titolo valido",
|
||||||
"DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Un firmware di sistema valido non è stato trovato in {0}.",
|
"DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Un firmware del sistema valido non è stato trovato in {0}.",
|
||||||
"DialogFirmwareInstallerFirmwareInstallTitle": "Installa firmware {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}.",
|
"DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nQuesta sostituirà l'attuale versione di sistema {0}.",
|
||||||
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nVuoi continuare?",
|
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nVuoi continuare?",
|
||||||
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installazione del firmware...",
|
"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",
|
"DialogUserProfileDeletionWarningMessage": "Non ci sarebbero altri profili da aprire se il profilo selezionato viene cancellato",
|
||||||
"DialogUserProfileDeletionConfirmMessage": "Vuoi eliminare il profilo selezionato?",
|
"DialogUserProfileDeletionConfirmMessage": "Vuoi eliminare il profilo selezionato?",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "Le attuali impostazioni del controller sono state aggiornate.",
|
"DialogControllerSettingsModifiedConfirmMessage": "Le attuali impostazioni del controller sono state aggiornate.",
|
||||||
@@ -557,4 +557,40 @@
|
|||||||
"SettingsXamlThemeFile" : "File del tema xaml",
|
"SettingsXamlThemeFile" : "File del tema xaml",
|
||||||
"SettingsTabHotkeysResScaleUpHotkey": "Aumentare la risoluzione:",
|
"SettingsTabHotkeysResScaleUpHotkey": "Aumentare la risoluzione:",
|
||||||
"SettingsTabHotkeysResScaleDownHotkey": "Diminuire 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.",
|
"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",
|
"SettingsAppRequiredRestartMessage": "Wymagane Zrestartowanie Ryujinx",
|
||||||
"SettingsGpuBackendRestartMessage": "Zmieniono ustawienia Backendu Graficznego lub GPU. Będzie to wymagało ponownego uruchomienia",
|
"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ś"
|
||||||
}
|
}
|
||||||
|
@@ -556,5 +556,7 @@
|
|||||||
"SettingsSelectThemeFileDialogTitle" : "Selecionar arquivo do tema",
|
"SettingsSelectThemeFileDialogTitle" : "Selecionar arquivo do tema",
|
||||||
"SettingsXamlThemeFile" : "Arquivo de tema Xaml",
|
"SettingsXamlThemeFile" : "Arquivo de tema Xaml",
|
||||||
"SettingsTabHotkeysResScaleUpHotkey": "Aumentar a resolução:",
|
"SettingsTabHotkeysResScaleUpHotkey": "Aumentar a resolução:",
|
||||||
"SettingsTabHotkeysResScaleDownHotkey": "Diminuir a resolução:"
|
"SettingsTabHotkeysResScaleDownHotkey": "Diminuir a resolução:",
|
||||||
|
"SettingsEnableMacroHLE": "Habilitar emulação de alto nível para Macros",
|
||||||
|
"SettingsEnableMacroHLETooltip": "Habilita emulação de alto nível de códigos Macro da GPU.\n\nMelhora a performance, mas pode causar problemas gráficos em alguns jogos.\n\nEm caso de dúvida, deixe ATIVADO."
|
||||||
}
|
}
|
||||||
|
@@ -278,7 +278,7 @@ namespace Ryujinx.Modules
|
|||||||
{
|
{
|
||||||
string ryuName = Path.GetFileName(Environment.ProcessPath);
|
string ryuName = Path.GetFileName(Environment.ProcessPath);
|
||||||
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
||||||
string ryuArg = string.Join(" ", Environment.GetCommandLineArgs().Skip(1).ToArray());
|
var ryuArg = Environment.GetCommandLineArgs().Skip(1);
|
||||||
|
|
||||||
if (!OperatingSystem.IsWindows())
|
if (!OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
|
@@ -13,6 +13,7 @@ using Ryujinx.Common.SystemInfo;
|
|||||||
using Ryujinx.Modules;
|
using Ryujinx.Modules;
|
||||||
using Ryujinx.Ui.Common;
|
using Ryujinx.Ui.Common;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -26,7 +27,6 @@ namespace Ryujinx.Ava
|
|||||||
public static double ActualScaleFactor { get; set; }
|
public static double ActualScaleFactor { get; set; }
|
||||||
public static string Version { get; private set; }
|
public static string Version { get; private set; }
|
||||||
public static string ConfigurationPath { get; private set; }
|
public static string ConfigurationPath { get; private set; }
|
||||||
public static string CommandLineProfile { get; set; }
|
|
||||||
public static bool PreviewerDetached { get; private set; }
|
public static bool PreviewerDetached { get; private set; }
|
||||||
|
|
||||||
public static RenderTimer RenderTimer { get; private set; }
|
public static RenderTimer RenderTimer { get; private set; }
|
||||||
@@ -87,46 +87,8 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
private static void Initialize(string[] args)
|
private static void Initialize(string[] args)
|
||||||
{
|
{
|
||||||
// Parse Arguments.
|
// Parse arguments
|
||||||
string launchPathArg = null;
|
CommandLineState.ParseArguments(args);
|
||||||
string baseDirPathArg = null;
|
|
||||||
bool startFullscreenArg = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < args.Length; ++i)
|
|
||||||
{
|
|
||||||
string arg = args[i];
|
|
||||||
|
|
||||||
if (arg == "-r" || arg == "--root-data-dir")
|
|
||||||
{
|
|
||||||
if (i + 1 >= args.Length)
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
baseDirPathArg = args[++i];
|
|
||||||
}
|
|
||||||
else if (arg == "-p" || arg == "--profile")
|
|
||||||
{
|
|
||||||
if (i + 1 >= args.Length)
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandLineProfile = args[++i];
|
|
||||||
}
|
|
||||||
else if (arg == "-f" || arg == "--fullscreen")
|
|
||||||
{
|
|
||||||
startFullscreenArg = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
launchPathArg = arg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete backup files after updating.
|
// Delete backup files after updating.
|
||||||
Task.Run(Updater.CleanupUpdate);
|
Task.Run(Updater.CleanupUpdate);
|
||||||
@@ -138,7 +100,7 @@ namespace Ryujinx.Ava
|
|||||||
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
|
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
|
||||||
|
|
||||||
// Setup base data directory.
|
// Setup base data directory.
|
||||||
AppDataManager.Initialize(baseDirPathArg);
|
AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
|
||||||
|
|
||||||
// Initialize the configuration.
|
// Initialize the configuration.
|
||||||
ConfigurationState.Initialize();
|
ConfigurationState.Initialize();
|
||||||
@@ -173,9 +135,9 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (launchPathArg != null)
|
if (CommandLineState.LaunchPathArg != null)
|
||||||
{
|
{
|
||||||
MainWindow.DeferLoadApplication(launchPathArg, startFullscreenArg);
|
MainWindow.DeferLoadApplication(CommandLineState.LaunchPathArg, CommandLineState.StartFullscreenArg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +177,19 @@ namespace Ryujinx.Ava
|
|||||||
Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}");
|
Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if graphics backend was overridden
|
||||||
|
if (CommandLineState.OverrideGraphicsBackend != null)
|
||||||
|
{
|
||||||
|
if (CommandLineState.OverrideGraphicsBackend.ToLower() == "opengl")
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.OpenGl;
|
||||||
|
}
|
||||||
|
else if (CommandLineState.OverrideGraphicsBackend.ToLower() == "vulkan")
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.Vulkan;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PrintSystemInfo()
|
private static void PrintSystemInfo()
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
@@ -8,11 +8,13 @@
|
|||||||
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
||||||
<RootNamespace>Ryujinx.Ava</RootNamespace>
|
<RootNamespace>Ryujinx.Ava</RootNamespace>
|
||||||
<ApplicationIcon>Ryujinx.ico</ApplicationIcon>
|
<ApplicationIcon>Ryujinx.ico</ApplicationIcon>
|
||||||
|
<TieredPGO>true</TieredPGO>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
|
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
|
||||||
<PublishSingleFile>true</PublishSingleFile>
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
<PublishTrimmed>true</PublishTrimmed>
|
<PublishTrimmed>true</PublishTrimmed>
|
||||||
|
<TrimMode>partial</TrimMode>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -34,7 +36,7 @@
|
|||||||
<PackageReference Include="Silk.NET.Vulkan" Version="2.10.1" />
|
<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.EXT" Version="2.10.1" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" 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="SharpZipLib" Version="1.3.3" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@@ -4,6 +4,7 @@ using Avalonia.Controls.ApplicationLifetimes;
|
|||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using FluentAvalonia.Core;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Ui.Models;
|
using Ryujinx.Ava.Ui.Models;
|
||||||
@@ -27,7 +28,10 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
string secondaryButton,
|
string secondaryButton,
|
||||||
string closeButton,
|
string closeButton,
|
||||||
int iconSymbol,
|
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;
|
UserResult result = UserResult.None;
|
||||||
|
|
||||||
@@ -110,12 +114,19 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
|
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
|
||||||
{
|
{
|
||||||
result = UserResult.No;
|
result = UserResult.No;
|
||||||
|
contentDialog.PrimaryButtonClick -= deferCloseAction;
|
||||||
});
|
});
|
||||||
contentDialog.CloseButtonCommand = MiniCommand.Create(() =>
|
contentDialog.CloseButtonCommand = MiniCommand.Create(() =>
|
||||||
{
|
{
|
||||||
result = UserResult.Cancel;
|
result = UserResult.Cancel;
|
||||||
|
contentDialog.PrimaryButtonClick -= deferCloseAction;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (deferResetEvent != null)
|
||||||
|
{
|
||||||
|
contentDialog.PrimaryButtonClick += deferCloseAction;
|
||||||
|
}
|
||||||
|
|
||||||
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
|
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
|
||||||
|
|
||||||
overlay?.Close();
|
overlay?.Close();
|
||||||
@@ -143,35 +154,20 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
Func<Window, Task> doWhileDeferred = null)
|
Func<Window, Task> doWhileDeferred = null)
|
||||||
{
|
{
|
||||||
bool startedDeferring = false;
|
bool startedDeferring = false;
|
||||||
|
|
||||||
UserResult result = UserResult.None;
|
UserResult result = UserResult.None;
|
||||||
|
|
||||||
ContentDialog contentDialog = new ContentDialog
|
return await ShowContentDialog(
|
||||||
{
|
title,
|
||||||
Title = title,
|
primaryText,
|
||||||
PrimaryButtonText = primaryButton,
|
secondaryText,
|
||||||
SecondaryButtonText = secondaryButton,
|
primaryButton,
|
||||||
CloseButtonText = closeButton,
|
secondaryButton,
|
||||||
Content = CreateDialogTextContent(primaryText, secondaryText, iconSymbol),
|
closeButton,
|
||||||
PrimaryButtonCommand = MiniCommand.Create(() =>
|
iconSymbol,
|
||||||
{
|
primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok,
|
||||||
result = primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok;
|
deferResetEvent,
|
||||||
}),
|
doWhileDeferred,
|
||||||
};
|
DeferClose);
|
||||||
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;
|
|
||||||
|
|
||||||
async void DeferClose(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
async void DeferClose(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||||
{
|
{
|
||||||
@@ -180,7 +176,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
contentDialog.PrimaryButtonClick -= DeferClose;
|
sender.PrimaryButtonClick -= DeferClose;
|
||||||
|
|
||||||
startedDeferring = true;
|
startedDeferring = true;
|
||||||
|
|
||||||
@@ -188,7 +184,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
|
|
||||||
result = primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok;
|
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
|
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
|
@@ -21,14 +21,10 @@ using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
|||||||
using Ryujinx.Input;
|
using Ryujinx.Input;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using Ryujinx.Ui.Common.Configuration.System;
|
using Ryujinx.Ui.Common.Configuration.System;
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using TimeZone = Ryujinx.Ava.Ui.Models.TimeZone;
|
using TimeZone = Ryujinx.Ava.Ui.Models.TimeZone;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.ViewModels
|
namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
@@ -138,6 +134,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
public bool ExpandDramSize { get; set; }
|
public bool ExpandDramSize { get; set; }
|
||||||
public bool EnableShaderCache { get; set; }
|
public bool EnableShaderCache { get; set; }
|
||||||
public bool EnableTextureRecompression { get; set; }
|
public bool EnableTextureRecompression { get; set; }
|
||||||
|
public bool EnableMacroHLE { get; set; }
|
||||||
public bool EnableFileLog { get; set; }
|
public bool EnableFileLog { get; set; }
|
||||||
public bool EnableStub { get; set; }
|
public bool EnableStub { get; set; }
|
||||||
public bool EnableInfo { get; set; }
|
public bool EnableInfo { get; set; }
|
||||||
@@ -295,8 +292,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
if (_validTzRegions.Contains(location))
|
if (_validTzRegions.Contains(location))
|
||||||
{
|
{
|
||||||
TimeZone = location;
|
TimeZone = location;
|
||||||
|
|
||||||
OnPropertyChanged(nameof(TimeZone));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,6 +336,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
ExpandDramSize = config.System.ExpandRam;
|
ExpandDramSize = config.System.ExpandRam;
|
||||||
EnableShaderCache = config.Graphics.EnableShaderCache;
|
EnableShaderCache = config.Graphics.EnableShaderCache;
|
||||||
EnableTextureRecompression = config.Graphics.EnableTextureRecompression;
|
EnableTextureRecompression = config.Graphics.EnableTextureRecompression;
|
||||||
|
EnableMacroHLE = config.Graphics.EnableMacroHLE;
|
||||||
EnableFileLog = config.Logger.EnableFileLog;
|
EnableFileLog = config.Logger.EnableFileLog;
|
||||||
EnableStub = config.Logger.EnableStub;
|
EnableStub = config.Logger.EnableStub;
|
||||||
EnableInfo = config.Logger.EnableInfo;
|
EnableInfo = config.Logger.EnableInfo;
|
||||||
@@ -424,6 +420,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
config.Graphics.EnableVsync.Value = EnableVsync;
|
config.Graphics.EnableVsync.Value = EnableVsync;
|
||||||
config.Graphics.EnableShaderCache.Value = EnableShaderCache;
|
config.Graphics.EnableShaderCache.Value = EnableShaderCache;
|
||||||
config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression;
|
config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression;
|
||||||
|
config.Graphics.EnableMacroHLE.Value = EnableMacroHLE;
|
||||||
config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex;
|
config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex;
|
||||||
config.System.EnablePtc.Value = EnablePptc;
|
config.System.EnablePtc.Value = EnablePptc;
|
||||||
config.System.EnableInternetAccess.Value = EnableInternetAccess;
|
config.System.EnableInternetAccess.Value = EnableInternetAccess;
|
||||||
|
@@ -164,7 +164,7 @@
|
|||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
CommandParameter="pl_PL"
|
CommandParameter="pl_PL"
|
||||||
Header="Polish" />
|
Header="Polski" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
CommandParameter="ru_RU"
|
CommandParameter="ru_RU"
|
||||||
|
@@ -23,6 +23,7 @@ using Ryujinx.Modules;
|
|||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
using Ryujinx.Ui.Common;
|
using Ryujinx.Ui.Common;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
@@ -432,7 +433,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
// Consider removing this at some point in the future when we don't need to worry about old saves.
|
// Consider removing this at some point in the future when we don't need to worry about old saves.
|
||||||
VirtualFileSystem.FixExtraData(LibHacHorizonManager.RyujinxClient);
|
VirtualFileSystem.FixExtraData(LibHacHorizonManager.RyujinxClient);
|
||||||
|
|
||||||
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, Program.CommandLineProfile);
|
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, CommandLineState.Profile);
|
||||||
|
|
||||||
VirtualFileSystem.ReloadKeySet();
|
VirtualFileSystem.ReloadKeySet();
|
||||||
|
|
||||||
@@ -525,6 +526,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
||||||
GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
|
GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
|
||||||
GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression;
|
GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression;
|
||||||
|
GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadHotKeys()
|
public void LoadHotKeys()
|
||||||
|
@@ -568,6 +568,10 @@
|
|||||||
ToolTip.Tip="{locale:Locale SettingsEnableTextureRecompressionTooltip}">
|
ToolTip.Tip="{locale:Locale SettingsEnableTextureRecompressionTooltip}">
|
||||||
<TextBlock Text="{locale:Locale SettingsEnableTextureRecompression}" />
|
<TextBlock Text="{locale:Locale SettingsEnableTextureRecompression}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding EnableMacroHLE}"
|
||||||
|
ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
|
||||||
|
</CheckBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock VerticalAlignment="Center"
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
@@ -37,7 +37,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Load();
|
Load();
|
||||||
|
|
||||||
FuncMultiValueConverter<string, string> converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()));
|
FuncMultiValueConverter<string, string> converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()).Trim());
|
||||||
MultiBinding tzMultiBinding = new() { Converter = converter };
|
MultiBinding tzMultiBinding = new() { Converter = converter };
|
||||||
tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
|
tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
|
||||||
tzMultiBinding.Bindings.Add(new Binding("Location"));
|
tzMultiBinding.Bindings.Add(new Binding("Location"));
|
||||||
|
@@ -53,5 +53,11 @@ namespace Ryujinx.Common
|
|||||||
|
|
||||||
writer.Write(data);
|
writer.Write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Write(this BinaryWriter writer, UInt128 value)
|
||||||
|
{
|
||||||
|
writer.Write((ulong)value);
|
||||||
|
writer.Write((ulong)(value >> 64));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -129,7 +129,7 @@ namespace Ryujinx.Common
|
|||||||
|
|
||||||
private static (Assembly, string) ResolveManifestPath(string filename)
|
private static (Assembly, string) ResolveManifestPath(string filename)
|
||||||
{
|
{
|
||||||
var segments = filename.Split(new[] { '/' }, 2, StringSplitOptions.RemoveEmptyEntries);
|
var segments = filename.Split('/', 2, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
if (segments.Length >= 2)
|
if (segments.Length >= 2)
|
||||||
{
|
{
|
||||||
|
@@ -7,19 +7,19 @@ namespace Ryujinx.Common.Utilities
|
|||||||
public static class SpanHelpers
|
public static class SpanHelpers
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static Span<T> CreateSpan<T>(ref T reference, int length)
|
public static Span<T> CreateSpan<T>(scoped ref T reference, int length)
|
||||||
{
|
{
|
||||||
return MemoryMarshal.CreateSpan(ref reference, length);
|
return MemoryMarshal.CreateSpan(ref reference, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static Span<T> AsSpan<T>(ref T reference) where T : unmanaged
|
public static Span<T> AsSpan<T>(scoped ref T reference) where T : unmanaged
|
||||||
{
|
{
|
||||||
return CreateSpan(ref reference, 1);
|
return CreateSpan(ref reference, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static Span<TSpan> AsSpan<TStruct, TSpan>(ref TStruct reference)
|
public static Span<TSpan> AsSpan<TStruct, TSpan>(scoped ref TStruct reference)
|
||||||
where TStruct : unmanaged where TSpan : unmanaged
|
where TStruct : unmanaged where TSpan : unmanaged
|
||||||
{
|
{
|
||||||
return CreateSpan(ref Unsafe.As<TStruct, TSpan>(ref reference),
|
return CreateSpan(ref Unsafe.As<TStruct, TSpan>(ref reference),
|
||||||
@@ -27,25 +27,25 @@ namespace Ryujinx.Common.Utilities
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static Span<byte> AsByteSpan<T>(ref T reference) where T : unmanaged
|
public static Span<byte> AsByteSpan<T>(scoped ref T reference) where T : unmanaged
|
||||||
{
|
{
|
||||||
return CreateSpan(ref Unsafe.As<T, byte>(ref reference), Unsafe.SizeOf<T>());
|
return CreateSpan(ref Unsafe.As<T, byte>(ref reference), Unsafe.SizeOf<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ReadOnlySpan<T> CreateReadOnlySpan<T>(ref T reference, int length)
|
public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref T reference, int length)
|
||||||
{
|
{
|
||||||
return MemoryMarshal.CreateReadOnlySpan(ref reference, length);
|
return MemoryMarshal.CreateReadOnlySpan(ref reference, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ReadOnlySpan<T> AsReadOnlySpan<T>(ref T reference) where T : unmanaged
|
public static ReadOnlySpan<T> AsReadOnlySpan<T>(scoped ref T reference) where T : unmanaged
|
||||||
{
|
{
|
||||||
return CreateReadOnlySpan(ref reference, 1);
|
return CreateReadOnlySpan(ref reference, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ReadOnlySpan<TSpan> AsReadOnlySpan<TStruct, TSpan>(ref TStruct reference)
|
public static ReadOnlySpan<TSpan> AsReadOnlySpan<TStruct, TSpan>(scoped ref TStruct reference)
|
||||||
where TStruct : unmanaged where TSpan : unmanaged
|
where TStruct : unmanaged where TSpan : unmanaged
|
||||||
{
|
{
|
||||||
return CreateReadOnlySpan(ref Unsafe.As<TStruct, TSpan>(ref reference),
|
return CreateReadOnlySpan(ref Unsafe.As<TStruct, TSpan>(ref reference),
|
||||||
@@ -53,7 +53,7 @@ namespace Ryujinx.Common.Utilities
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ReadOnlySpan<byte> AsReadOnlyByteSpan<T>(ref T reference) where T : unmanaged
|
public static ReadOnlySpan<byte> AsReadOnlyByteSpan<T>(scoped ref T reference) where T : unmanaged
|
||||||
{
|
{
|
||||||
return CreateReadOnlySpan(ref Unsafe.As<T, byte>(ref reference), Unsafe.SizeOf<T>());
|
return CreateReadOnlySpan(ref Unsafe.As<T, byte>(ref reference), Unsafe.SizeOf<T>());
|
||||||
}
|
}
|
||||||
|
17
Ryujinx.Common/Utilities/UInt128Utils.cs
Normal file
17
Ryujinx.Common/Utilities/UInt128Utils.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Common.Utilities
|
||||||
|
{
|
||||||
|
public static class UInt128Utils
|
||||||
|
{
|
||||||
|
public static UInt128 FromHex(string hex)
|
||||||
|
{
|
||||||
|
return new UInt128((ulong)Convert.ToInt64(hex.Substring(0, 16), 16), (ulong)Convert.ToInt64(hex.Substring(16), 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UInt128 CreateRandom()
|
||||||
|
{
|
||||||
|
return new UInt128((ulong)Random.Shared.NextInt64(), (ulong)Random.Shared.NextInt64());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -34,13 +34,14 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
int firstIndex,
|
int firstIndex,
|
||||||
int firstVertex,
|
int firstVertex,
|
||||||
int firstInstance);
|
int firstInstance);
|
||||||
|
void DrawIndexedIndirect(BufferRange indirectBuffer);
|
||||||
|
void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
|
||||||
|
void DrawIndirect(BufferRange indirectBuffer);
|
||||||
|
void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
|
||||||
void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion);
|
void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion);
|
||||||
|
|
||||||
void EndTransformFeedback();
|
void EndTransformFeedback();
|
||||||
|
|
||||||
void MultiDrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
|
|
||||||
void MultiDrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
|
|
||||||
|
|
||||||
void SetAlphaTest(bool enable, float reference, CompareOp op);
|
void SetAlphaTest(bool enable, float reference, CompareOp op);
|
||||||
|
|
||||||
void SetBlendState(int index, BlendDescriptor blend);
|
void SetBlendState(int index, BlendDescriptor blend);
|
||||||
|
@@ -141,16 +141,20 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
|
DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawIndexed] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawIndexed] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||||
DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
|
DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
|
||||||
|
_lookup[(int)CommandType.DrawIndexedIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||||
|
DrawIndexedIndirectCommand.Run(ref GetCommand<DrawIndexedIndirectCommand>(memory), threaded, renderer);
|
||||||
|
_lookup[(int)CommandType.DrawIndexedIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||||
|
DrawIndexedIndirectCountCommand.Run(ref GetCommand<DrawIndexedIndirectCountCommand>(memory), threaded, renderer);
|
||||||
|
_lookup[(int)CommandType.DrawIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||||
|
DrawIndirectCommand.Run(ref GetCommand<DrawIndirectCommand>(memory), threaded, renderer);
|
||||||
|
_lookup[(int)CommandType.DrawIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||||
|
DrawIndirectCountCommand.Run(ref GetCommand<DrawIndirectCountCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||||
DrawTextureCommand.Run(ref GetCommand<DrawTextureCommand>(memory), threaded, renderer);
|
DrawTextureCommand.Run(ref GetCommand<DrawTextureCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.EndHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.EndHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||||
EndHostConditionalRenderingCommand.Run(renderer);
|
EndHostConditionalRenderingCommand.Run(renderer);
|
||||||
_lookup[(int)CommandType.EndTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.EndTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||||
EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
|
EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.MultiDrawIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
|
||||||
MultiDrawIndirectCountCommand.Run(ref GetCommand<MultiDrawIndirectCountCommand>(memory), threaded, renderer);
|
|
||||||
_lookup[(int)CommandType.MultiDrawIndexedIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
|
||||||
MultiDrawIndexedIndirectCountCommand.Run(ref GetCommand<MultiDrawIndexedIndirectCountCommand>(memory), threaded, renderer);
|
|
||||||
_lookup[(int)CommandType.SetAlphaTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetAlphaTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||||
SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
|
SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetBlendState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetBlendState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||||
|
@@ -52,11 +52,13 @@
|
|||||||
DispatchCompute,
|
DispatchCompute,
|
||||||
Draw,
|
Draw,
|
||||||
DrawIndexed,
|
DrawIndexed,
|
||||||
|
DrawIndexedIndirect,
|
||||||
|
DrawIndexedIndirectCount,
|
||||||
|
DrawIndirect,
|
||||||
|
DrawIndirectCount,
|
||||||
DrawTexture,
|
DrawTexture,
|
||||||
EndHostConditionalRendering,
|
EndHostConditionalRendering,
|
||||||
EndTransformFeedback,
|
EndTransformFeedback,
|
||||||
MultiDrawIndirectCount,
|
|
||||||
MultiDrawIndexedIndirectCount,
|
|
||||||
SetAlphaTest,
|
SetAlphaTest,
|
||||||
SetBlendState,
|
SetBlendState,
|
||||||
SetDepthBias,
|
SetDepthBias,
|
||||||
|
@@ -0,0 +1,18 @@
|
|||||||
|
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||||
|
{
|
||||||
|
struct DrawIndexedIndirectCommand : IGALCommand
|
||||||
|
{
|
||||||
|
public CommandType CommandType => CommandType.DrawIndexedIndirect;
|
||||||
|
private BufferRange _indirectBuffer;
|
||||||
|
|
||||||
|
public void Set(BufferRange indirectBuffer)
|
||||||
|
{
|
||||||
|
_indirectBuffer = indirectBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Run(ref DrawIndexedIndirectCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||||
|
{
|
||||||
|
renderer.Pipeline.DrawIndexedIndirect(threaded.Buffers.MapBufferRange(command._indirectBuffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,8 +1,8 @@
|
|||||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||||
{
|
{
|
||||||
struct MultiDrawIndexedIndirectCountCommand : IGALCommand
|
struct DrawIndexedIndirectCountCommand : IGALCommand
|
||||||
{
|
{
|
||||||
public CommandType CommandType => CommandType.MultiDrawIndexedIndirectCount;
|
public CommandType CommandType => CommandType.DrawIndexedIndirectCount;
|
||||||
private BufferRange _indirectBuffer;
|
private BufferRange _indirectBuffer;
|
||||||
private BufferRange _parameterBuffer;
|
private BufferRange _parameterBuffer;
|
||||||
private int _maxDrawCount;
|
private int _maxDrawCount;
|
||||||
@@ -16,9 +16,9 @@
|
|||||||
_stride = stride;
|
_stride = stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Run(ref MultiDrawIndexedIndirectCountCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
public static void Run(ref DrawIndexedIndirectCountCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||||
{
|
{
|
||||||
renderer.Pipeline.MultiDrawIndexedIndirectCount(
|
renderer.Pipeline.DrawIndexedIndirectCount(
|
||||||
threaded.Buffers.MapBufferRange(command._indirectBuffer),
|
threaded.Buffers.MapBufferRange(command._indirectBuffer),
|
||||||
threaded.Buffers.MapBufferRange(command._parameterBuffer),
|
threaded.Buffers.MapBufferRange(command._parameterBuffer),
|
||||||
command._maxDrawCount,
|
command._maxDrawCount,
|
@@ -0,0 +1,18 @@
|
|||||||
|
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||||
|
{
|
||||||
|
struct DrawIndirectCommand : IGALCommand
|
||||||
|
{
|
||||||
|
public CommandType CommandType => CommandType.DrawIndirect;
|
||||||
|
private BufferRange _indirectBuffer;
|
||||||
|
|
||||||
|
public void Set(BufferRange indirectBuffer)
|
||||||
|
{
|
||||||
|
_indirectBuffer = indirectBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Run(ref DrawIndirectCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||||
|
{
|
||||||
|
renderer.Pipeline.DrawIndirect(threaded.Buffers.MapBufferRange(command._indirectBuffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,8 +1,8 @@
|
|||||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||||
{
|
{
|
||||||
struct MultiDrawIndirectCountCommand : IGALCommand
|
struct DrawIndirectCountCommand : IGALCommand
|
||||||
{
|
{
|
||||||
public CommandType CommandType => CommandType.MultiDrawIndirectCount;
|
public CommandType CommandType => CommandType.DrawIndirectCount;
|
||||||
private BufferRange _indirectBuffer;
|
private BufferRange _indirectBuffer;
|
||||||
private BufferRange _parameterBuffer;
|
private BufferRange _parameterBuffer;
|
||||||
private int _maxDrawCount;
|
private int _maxDrawCount;
|
||||||
@@ -16,9 +16,9 @@
|
|||||||
_stride = stride;
|
_stride = stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Run(ref MultiDrawIndirectCountCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
public static void Run(ref DrawIndirectCountCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||||
{
|
{
|
||||||
renderer.Pipeline.MultiDrawIndirectCount(
|
renderer.Pipeline.DrawIndirectCount(
|
||||||
threaded.Buffers.MapBufferRange(command._indirectBuffer),
|
threaded.Buffers.MapBufferRange(command._indirectBuffer),
|
||||||
threaded.Buffers.MapBufferRange(command._parameterBuffer),
|
threaded.Buffers.MapBufferRange(command._parameterBuffer),
|
||||||
command._maxDrawCount,
|
command._maxDrawCount,
|
@@ -83,6 +83,30 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DrawIndexedIndirect(BufferRange indirectBuffer)
|
||||||
|
{
|
||||||
|
_renderer.New<DrawIndexedIndirectCommand>().Set(indirectBuffer);
|
||||||
|
_renderer.QueueCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||||
|
{
|
||||||
|
_renderer.New<DrawIndexedIndirectCountCommand>().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||||
|
_renderer.QueueCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawIndirect(BufferRange indirectBuffer)
|
||||||
|
{
|
||||||
|
_renderer.New<DrawIndirectCommand>().Set(indirectBuffer);
|
||||||
|
_renderer.QueueCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||||
|
{
|
||||||
|
_renderer.New<DrawIndirectCountCommand>().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||||
|
_renderer.QueueCommand();
|
||||||
|
}
|
||||||
|
|
||||||
public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
|
public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
|
||||||
{
|
{
|
||||||
_renderer.New<DrawTextureCommand>().Set(Ref(texture), Ref(sampler), srcRegion, dstRegion);
|
_renderer.New<DrawTextureCommand>().Set(Ref(texture), Ref(sampler), srcRegion, dstRegion);
|
||||||
@@ -101,18 +125,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MultiDrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
|
||||||
{
|
|
||||||
_renderer.New<MultiDrawIndirectCountCommand>().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
|
||||||
_renderer.QueueCommand();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MultiDrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
|
||||||
{
|
|
||||||
_renderer.New<MultiDrawIndexedIndirectCountCommand>().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
|
||||||
_renderer.QueueCommand();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
||||||
{
|
{
|
||||||
_renderer.New<SetAlphaTestCommand>().Set(enable, reference, op);
|
_renderer.New<SetAlphaTestCommand>().Set(enable, reference, op);
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
@@ -94,6 +94,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
|||||||
{
|
{
|
||||||
var memoryManager = _channel.MemoryManager;
|
var memoryManager = _channel.MemoryManager;
|
||||||
|
|
||||||
|
// Since we're going to change the state, make sure any pending instanced draws are done.
|
||||||
|
_3dEngine.PerformDeferredDraws();
|
||||||
|
|
||||||
|
// Make sure all pending uniform buffer data is written to memory.
|
||||||
_3dEngine.FlushUboDirty();
|
_3dEngine.FlushUboDirty();
|
||||||
|
|
||||||
uint qmdAddress = _state.State.SendPcasA;
|
uint qmdAddress = _state.State.SendPcasA;
|
||||||
|
@@ -62,10 +62,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_hleFunction == MacroHLEFunctionName.MultiDrawElementsIndirectCount)
|
|
||||||
{
|
|
||||||
// We don't consume the parameter buffer value, so we don't need to flush it.
|
// We don't consume the parameter buffer value, so we don't need to flush it.
|
||||||
// Doing so improves performance if the value was written by a GPU shader.
|
// Doing so improves performance if the value was written by a GPU shader.
|
||||||
|
if (_hleFunction == MacroHLEFunctionName.DrawElementsIndirect)
|
||||||
|
{
|
||||||
|
context.GPFifo.SetFlushSkips(1);
|
||||||
|
}
|
||||||
|
else if (_hleFunction == MacroHLEFunctionName.MultiDrawElementsIndirectCount)
|
||||||
|
{
|
||||||
context.GPFifo.SetFlushSkips(2);
|
context.GPFifo.SetFlushSkips(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
private const int ColorStructSize = 0x40;
|
private const int ColorStructSize = 0x40;
|
||||||
private const int ZetaLayerCountOffset = 0x1230;
|
private const int ZetaLayerCountOffset = 0x1230;
|
||||||
|
|
||||||
|
private const int IndirectDataEntrySize = 0x10;
|
||||||
|
private const int IndirectIndexedDataEntrySize = 0x14;
|
||||||
|
|
||||||
private readonly GPFifoProcessor _processor;
|
private readonly GPFifoProcessor _processor;
|
||||||
private readonly MacroHLEFunctionName _functionName;
|
private readonly MacroHLEFunctionName _functionName;
|
||||||
|
|
||||||
@@ -27,9 +30,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the HLE macro handler.
|
/// Creates a new instance of the HLE macro handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">GPU context the macro is being executed on</param>
|
/// <param name="processor">GPU GP FIFO command processor</param>
|
||||||
/// <param name="memoryManager">GPU memory manager</param>
|
|
||||||
/// <param name="engine">3D engine where this macro is being called</param>
|
|
||||||
/// <param name="functionName">Name of the HLE macro function to be called</param>
|
/// <param name="functionName">Name of the HLE macro function to be called</param>
|
||||||
public MacroHLE(GPFifoProcessor processor, MacroHLEFunctionName functionName)
|
public MacroHLE(GPFifoProcessor processor, MacroHLEFunctionName functionName)
|
||||||
{
|
{
|
||||||
@@ -55,12 +56,24 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
case MacroHLEFunctionName.ClearDepthStencil:
|
case MacroHLEFunctionName.ClearDepthStencil:
|
||||||
ClearDepthStencil(state, arg0);
|
ClearDepthStencil(state, arg0);
|
||||||
break;
|
break;
|
||||||
|
case MacroHLEFunctionName.DrawArraysInstanced:
|
||||||
|
DrawArraysInstanced(state, arg0);
|
||||||
|
break;
|
||||||
|
case MacroHLEFunctionName.DrawElementsInstanced:
|
||||||
|
DrawElementsInstanced(state, arg0);
|
||||||
|
break;
|
||||||
|
case MacroHLEFunctionName.DrawElementsIndirect:
|
||||||
|
DrawElementsIndirect(state, arg0);
|
||||||
|
break;
|
||||||
case MacroHLEFunctionName.MultiDrawElementsIndirectCount:
|
case MacroHLEFunctionName.MultiDrawElementsIndirectCount:
|
||||||
MultiDrawElementsIndirectCount(state, arg0);
|
MultiDrawElementsIndirectCount(state, arg0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException(_functionName.ToString());
|
throw new NotImplementedException(_functionName.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It should be empty at this point, but clear it just to be safe.
|
||||||
|
Fifo.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -89,7 +102,118 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a indirect multi-draw, with parameters from a GPU buffer.
|
/// Performs a draw.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">GPU state at the time of the call</param>
|
||||||
|
/// <param name="arg0">First argument of the call</param>
|
||||||
|
private void DrawArraysInstanced(IDeviceState state, int arg0)
|
||||||
|
{
|
||||||
|
var topology = (PrimitiveTopology)arg0;
|
||||||
|
|
||||||
|
var count = FetchParam();
|
||||||
|
var instanceCount = FetchParam();
|
||||||
|
var firstVertex = FetchParam();
|
||||||
|
var firstInstance = FetchParam();
|
||||||
|
|
||||||
|
if (ShouldSkipDraw(state, instanceCount.Word))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_processor.ThreedClass.Draw(
|
||||||
|
topology,
|
||||||
|
count.Word,
|
||||||
|
instanceCount.Word,
|
||||||
|
0,
|
||||||
|
firstVertex.Word,
|
||||||
|
firstInstance.Word,
|
||||||
|
indexed: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a indexed draw.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">GPU state at the time of the call</param>
|
||||||
|
/// <param name="arg0">First argument of the call</param>
|
||||||
|
private void DrawElementsInstanced(IDeviceState state, int arg0)
|
||||||
|
{
|
||||||
|
var topology = (PrimitiveTopology)arg0;
|
||||||
|
|
||||||
|
var count = FetchParam();
|
||||||
|
var instanceCount = FetchParam();
|
||||||
|
var firstIndex = FetchParam();
|
||||||
|
var firstVertex = FetchParam();
|
||||||
|
var firstInstance = FetchParam();
|
||||||
|
|
||||||
|
if (ShouldSkipDraw(state, instanceCount.Word))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_processor.ThreedClass.Draw(
|
||||||
|
topology,
|
||||||
|
count.Word,
|
||||||
|
instanceCount.Word,
|
||||||
|
firstIndex.Word,
|
||||||
|
firstVertex.Word,
|
||||||
|
firstInstance.Word,
|
||||||
|
indexed: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a indirect indexed draw, with parameters from a GPU buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">GPU state at the time of the call</param>
|
||||||
|
/// <param name="arg0">First argument of the call</param>
|
||||||
|
private void DrawElementsIndirect(IDeviceState state, int arg0)
|
||||||
|
{
|
||||||
|
var topology = (PrimitiveTopology)arg0;
|
||||||
|
|
||||||
|
var count = FetchParam();
|
||||||
|
var instanceCount = FetchParam();
|
||||||
|
var firstIndex = FetchParam();
|
||||||
|
var firstVertex = FetchParam();
|
||||||
|
var firstInstance = FetchParam();
|
||||||
|
|
||||||
|
ulong indirectBufferGpuVa = count.GpuVa;
|
||||||
|
|
||||||
|
var bufferCache = _processor.MemoryManager.Physical.BufferCache;
|
||||||
|
|
||||||
|
bool useBuffer = bufferCache.CheckModified(_processor.MemoryManager, indirectBufferGpuVa, IndirectIndexedDataEntrySize, out ulong indirectBufferAddress);
|
||||||
|
|
||||||
|
if (useBuffer)
|
||||||
|
{
|
||||||
|
int indexCount = firstIndex.Word + count.Word;
|
||||||
|
|
||||||
|
_processor.ThreedClass.DrawIndirect(
|
||||||
|
topology,
|
||||||
|
indirectBufferAddress,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
IndirectIndexedDataEntrySize,
|
||||||
|
indexCount,
|
||||||
|
Threed.IndirectDrawType.DrawIndexedIndirect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ShouldSkipDraw(state, instanceCount.Word))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_processor.ThreedClass.Draw(
|
||||||
|
topology,
|
||||||
|
count.Word,
|
||||||
|
instanceCount.Word,
|
||||||
|
firstIndex.Word,
|
||||||
|
firstVertex.Word,
|
||||||
|
firstInstance.Word,
|
||||||
|
indexed: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a indirect indexed multi-draw, with parameters from a GPU buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">GPU state at the time of the call</param>
|
/// <param name="state">GPU state at the time of the call</param>
|
||||||
/// <param name="arg0">First argument of the call</param>
|
/// <param name="arg0">First argument of the call</param>
|
||||||
@@ -132,8 +256,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int indirectBufferSize = maxDrawCount * stride;
|
|
||||||
|
|
||||||
ulong indirectBufferGpuVa = 0;
|
ulong indirectBufferGpuVa = 0;
|
||||||
int indexCount = 0;
|
int indexCount = 0;
|
||||||
|
|
||||||
@@ -142,8 +264,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
var count = FetchParam();
|
var count = FetchParam();
|
||||||
var instanceCount = FetchParam();
|
var instanceCount = FetchParam();
|
||||||
var firstIndex = FetchParam();
|
var firstIndex = FetchParam();
|
||||||
var baseVertex = FetchParam();
|
var firstVertex = FetchParam();
|
||||||
var baseInstance = FetchParam();
|
var firstInstance = FetchParam();
|
||||||
|
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
@@ -161,15 +283,32 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// It should be empty at this point, but clear it just to be safe.
|
|
||||||
Fifo.Clear();
|
|
||||||
|
|
||||||
var bufferCache = _processor.MemoryManager.Physical.BufferCache;
|
var bufferCache = _processor.MemoryManager.Physical.BufferCache;
|
||||||
|
|
||||||
var parameterBuffer = bufferCache.GetGpuBufferRange(_processor.MemoryManager, parameterBufferGpuVa, 4);
|
ulong indirectBufferSize = (ulong)maxDrawCount * (ulong)stride;
|
||||||
var indirectBuffer = bufferCache.GetGpuBufferRange(_processor.MemoryManager, indirectBufferGpuVa, (ulong)indirectBufferSize);
|
|
||||||
|
|
||||||
_processor.ThreedClass.MultiDrawIndirectCount(indexCount, topology, indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
ulong indirectBufferAddress = bufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, indirectBufferGpuVa, indirectBufferSize);
|
||||||
|
ulong parameterBufferAddress = bufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, parameterBufferGpuVa, 4);
|
||||||
|
|
||||||
|
_processor.ThreedClass.DrawIndirect(
|
||||||
|
topology,
|
||||||
|
indirectBufferAddress,
|
||||||
|
parameterBufferAddress,
|
||||||
|
maxDrawCount,
|
||||||
|
stride,
|
||||||
|
indexCount,
|
||||||
|
Threed.IndirectDrawType.DrawIndexedIndirectCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the draw should be skipped, because the masked instance count is zero.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">Current GPU state</param>
|
||||||
|
/// <param name="instanceCount">Draw instance count</param>
|
||||||
|
/// <returns>True if the draw should be skipped, false otherwise</returns>
|
||||||
|
private static bool ShouldSkipDraw(IDeviceState state, int instanceCount)
|
||||||
|
{
|
||||||
|
return (Read(state, 0xd1b) & instanceCount) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -189,14 +328,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a GPU method call.
|
/// Reads data from a GPU register.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Current GPU state</param>
|
/// <param name="state">Current GPU state</param>
|
||||||
/// <param name="methAddr">Address, in words, of the method</param>
|
/// <param name="reg">Register offset to read</param>
|
||||||
/// <param name="value">Call argument</param>
|
/// <returns>GPU register value</returns>
|
||||||
private static void Send(IDeviceState state, int methAddr, int value)
|
private static int Read(IDeviceState state, int reg)
|
||||||
{
|
{
|
||||||
state.Write(methAddr * 4, value);
|
return state.Read(reg * 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,9 @@
|
|||||||
None,
|
None,
|
||||||
ClearColor,
|
ClearColor,
|
||||||
ClearDepthStencil,
|
ClearDepthStencil,
|
||||||
|
DrawArraysInstanced,
|
||||||
|
DrawElementsInstanced,
|
||||||
|
DrawElementsIndirect,
|
||||||
MultiDrawElementsIndirectCount
|
MultiDrawElementsIndirectCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -44,17 +44,29 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly TableEntry[] Table = new TableEntry[]
|
private static readonly TableEntry[] _table = new TableEntry[]
|
||||||
{
|
{
|
||||||
new TableEntry(MacroHLEFunctionName.ClearColor, new Hash128(0xA9FB28D1DC43645A, 0xB177E5D2EAE67FB0), 0x28),
|
new TableEntry(MacroHLEFunctionName.ClearColor, new Hash128(0xA9FB28D1DC43645A, 0xB177E5D2EAE67FB0), 0x28),
|
||||||
new TableEntry(MacroHLEFunctionName.ClearDepthStencil, new Hash128(0x1B96CB77D4879F4F, 0x8557032FE0C965FB), 0x24),
|
new TableEntry(MacroHLEFunctionName.ClearDepthStencil, new Hash128(0x1B96CB77D4879F4F, 0x8557032FE0C965FB), 0x24),
|
||||||
|
new TableEntry(MacroHLEFunctionName.DrawArraysInstanced, new Hash128(0x197FB416269DBC26, 0x34288C01DDA82202), 0x48),
|
||||||
|
new TableEntry(MacroHLEFunctionName.DrawElementsInstanced, new Hash128(0x1A501FD3D54EC8E0, 0x6CF570CF79DA74D6), 0x5c),
|
||||||
|
new TableEntry(MacroHLEFunctionName.DrawElementsIndirect, new Hash128(0x86A3E8E903AF8F45, 0xD35BBA07C23860A4), 0x7c),
|
||||||
new TableEntry(MacroHLEFunctionName.MultiDrawElementsIndirectCount, new Hash128(0x890AF57ED3FB1C37, 0x35D0C95C61F5386F), 0x19C)
|
new TableEntry(MacroHLEFunctionName.MultiDrawElementsIndirectCount, new Hash128(0x890AF57ED3FB1C37, 0x35D0C95C61F5386F), 0x19C)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the host supports all features required by the HLE macro.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="caps">Host capabilities</param>
|
||||||
|
/// <param name="name">Name of the HLE macro to be checked</param>
|
||||||
|
/// <returns>True if the host supports the HLE macro, false otherwise</returns>
|
||||||
private static bool IsMacroHLESupported(Capabilities caps, MacroHLEFunctionName name)
|
private static bool IsMacroHLESupported(Capabilities caps, MacroHLEFunctionName name)
|
||||||
{
|
{
|
||||||
if (name == MacroHLEFunctionName.ClearColor ||
|
if (name == MacroHLEFunctionName.ClearColor ||
|
||||||
name == MacroHLEFunctionName.ClearDepthStencil)
|
name == MacroHLEFunctionName.ClearDepthStencil ||
|
||||||
|
name == MacroHLEFunctionName.DrawArraysInstanced ||
|
||||||
|
name == MacroHLEFunctionName.DrawElementsInstanced ||
|
||||||
|
name == MacroHLEFunctionName.DrawElementsIndirect)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -77,15 +89,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
{
|
{
|
||||||
var mc = MemoryMarshal.Cast<int, byte>(code);
|
var mc = MemoryMarshal.Cast<int, byte>(code);
|
||||||
|
|
||||||
for (int i = 0; i < Table.Length; i++)
|
for (int i = 0; i < _table.Length; i++)
|
||||||
{
|
{
|
||||||
ref var entry = ref Table[i];
|
ref var entry = ref _table[i];
|
||||||
|
|
||||||
var hash = XXHash128.ComputeHash(mc.Slice(0, entry.Length));
|
var hash = XXHash128.ComputeHash(mc.Slice(0, entry.Length));
|
||||||
if (hash == entry.Hash)
|
if (hash == entry.Hash)
|
||||||
|
{
|
||||||
|
if (IsMacroHLESupported(caps, entry.Name))
|
||||||
{
|
{
|
||||||
name = entry.Name;
|
name = entry.Name;
|
||||||
return IsMacroHLESupported(caps, name);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -63,7 +63,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
evt.Flush();
|
evt.Flush();
|
||||||
return (memoryManager.Read<ulong>(gpuVa) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
|
return (memoryManager.Read<ulong>(gpuVa, true) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,8 +108,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
evt?.Flush();
|
evt?.Flush();
|
||||||
evt2?.Flush();
|
evt2?.Flush();
|
||||||
|
|
||||||
ulong x = memoryManager.Read<ulong>(gpuVa);
|
ulong x = memoryManager.Read<ulong>(gpuVa, true);
|
||||||
ulong y = memoryManager.Read<ulong>(gpuVa + 16);
|
ulong y = memoryManager.Read<ulong>(gpuVa + 16, true);
|
||||||
|
|
||||||
return (isEqual ? x == y : x != y) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
|
return (isEqual ? x == y : x != y) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||||
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
@@ -9,6 +10,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class DrawManager
|
class DrawManager
|
||||||
{
|
{
|
||||||
|
// Since we don't know the index buffer size for indirect draws,
|
||||||
|
// we must assume a minimum and maximum size and use that for buffer data update purposes.
|
||||||
|
private const int MinIndirectIndexCount = 0x10000;
|
||||||
|
private const int MaxIndirectIndexCount = 0x4000000;
|
||||||
|
|
||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
private readonly GpuChannel _channel;
|
private readonly GpuChannel _channel;
|
||||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||||
@@ -28,6 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
private int _instanceIndex;
|
private int _instanceIndex;
|
||||||
|
|
||||||
|
private const int VertexBufferFirstMethodOffset = 0x35d;
|
||||||
private const int IndexBufferCountMethodOffset = 0x5f8;
|
private const int IndexBufferCountMethodOffset = 0x5f8;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -237,6 +244,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_instanceIndex = 0;
|
_instanceIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateTopology(topology);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the current primitive topology if needed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="topology">New primitive topology</param>
|
||||||
|
private void UpdateTopology(PrimitiveTopology topology)
|
||||||
|
{
|
||||||
if (_drawState.Topology != topology || !_topologySet)
|
if (_drawState.Topology != topology || !_topologySet)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
|
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
|
||||||
@@ -383,28 +399,27 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a indirect multi-draw, with parameters from a GPU buffer.
|
/// Performs a indexed or non-indexed draw.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="engine">3D engine where this method is being called</param>
|
/// <param name="engine">3D engine where this method is being called</param>
|
||||||
/// <param name="topology">Primitive topology</param>
|
/// <param name="topology">Primitive topology</param>
|
||||||
/// <param name="indirectBuffer">GPU buffer with the draw parameters, such as count, first index, etc</param>
|
/// <param name="count">Index count for indexed draws, vertex count for non-indexed draws</param>
|
||||||
/// <param name="parameterBuffer">GPU buffer with the draw count</param>
|
/// <param name="instanceCount">Instance count</param>
|
||||||
/// <param name="maxDrawCount">Maximum number of draws that can be made</param>
|
/// <param name="firstIndex">First index on the index buffer for indexed draws, ignored for non-indexed draws</param>
|
||||||
/// <param name="stride">Distance in bytes between each element on the <paramref name="indirectBuffer"/> array</param>
|
/// <param name="firstVertex">First vertex on the vertex buffer</param>
|
||||||
public void MultiDrawIndirectCount(
|
/// <param name="firstInstance">First instance</param>
|
||||||
|
/// <param name="indexed">True if the draw is indexed, false otherwise</param>
|
||||||
|
public void Draw(
|
||||||
ThreedClass engine,
|
ThreedClass engine,
|
||||||
int indexCount,
|
|
||||||
PrimitiveTopology topology,
|
PrimitiveTopology topology,
|
||||||
BufferRange indirectBuffer,
|
int count,
|
||||||
BufferRange parameterBuffer,
|
int instanceCount,
|
||||||
int maxDrawCount,
|
int firstIndex,
|
||||||
int stride)
|
int firstVertex,
|
||||||
|
int firstInstance,
|
||||||
|
bool indexed)
|
||||||
{
|
{
|
||||||
engine.Write(IndexBufferCountMethodOffset * 4, indexCount);
|
UpdateTopology(topology);
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
|
|
||||||
_drawState.Topology = topology;
|
|
||||||
_topologySet = true;
|
|
||||||
|
|
||||||
ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable(
|
ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable(
|
||||||
_context,
|
_context,
|
||||||
@@ -418,21 +433,133 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_drawState.FirstIndex = _state.State.IndexBufferState.First;
|
if (indexed)
|
||||||
_drawState.IndexCount = indexCount;
|
|
||||||
|
|
||||||
engine.UpdateState();
|
|
||||||
|
|
||||||
if (_drawState.DrawIndexed)
|
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.MultiDrawIndexedIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
_drawState.FirstIndex = firstIndex;
|
||||||
|
_drawState.IndexCount = count;
|
||||||
|
_state.State.FirstVertex = (uint)firstVertex;
|
||||||
|
engine.ForceStateDirty(IndexBufferCountMethodOffset * 4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.MultiDrawIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
_state.State.VertexBufferDrawState.First = firstVertex;
|
||||||
|
_state.State.VertexBufferDrawState.Count = count;
|
||||||
|
engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
_state.State.FirstInstance = (uint)firstInstance;
|
||||||
|
|
||||||
|
_drawState.DrawIndexed = indexed;
|
||||||
|
_drawState.HasConstantBufferDrawParameters = true;
|
||||||
|
|
||||||
|
engine.UpdateState();
|
||||||
|
|
||||||
|
if (indexed)
|
||||||
|
{
|
||||||
|
_context.Renderer.Pipeline.DrawIndexed(count, instanceCount, firstIndex, firstVertex, firstInstance);
|
||||||
|
_state.State.FirstVertex = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_context.Renderer.Pipeline.Draw(count, instanceCount, firstVertex, firstInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
_state.State.FirstInstance = 0;
|
||||||
|
|
||||||
|
_drawState.DrawIndexed = false;
|
||||||
|
_drawState.HasConstantBufferDrawParameters = false;
|
||||||
|
|
||||||
|
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||||
|
{
|
||||||
|
_context.Renderer.Pipeline.EndHostConditionalRendering();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a indirect draw, with parameters from a GPU buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="engine">3D engine where this method is being called</param>
|
||||||
|
/// <param name="topology">Primitive topology</param>
|
||||||
|
/// <param name="indirectBufferAddress">Address of the buffer with the draw parameters, such as count, first index, etc</param>
|
||||||
|
/// <param name="parameterBufferAddress">Address of the buffer with the draw count</param>
|
||||||
|
/// <param name="maxDrawCount">Maximum number of draws that can be made</param>
|
||||||
|
/// <param name="stride">Distance in bytes between each entry on the data pointed to by <paramref name="indirectBufferAddress"/></param>
|
||||||
|
/// <param name="indexCount">Maximum number of indices that the draw can consume</param>
|
||||||
|
/// <param name="drawType">Type of the indirect draw, which can be indexed or non-indexed, with or without a draw count</param>
|
||||||
|
public void DrawIndirect(
|
||||||
|
ThreedClass engine,
|
||||||
|
PrimitiveTopology topology,
|
||||||
|
ulong indirectBufferAddress,
|
||||||
|
ulong parameterBufferAddress,
|
||||||
|
int maxDrawCount,
|
||||||
|
int stride,
|
||||||
|
int indexCount,
|
||||||
|
IndirectDrawType drawType)
|
||||||
|
{
|
||||||
|
UpdateTopology(topology);
|
||||||
|
|
||||||
|
ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable(
|
||||||
|
_context,
|
||||||
|
_channel.MemoryManager,
|
||||||
|
_state.State.RenderEnableAddress,
|
||||||
|
_state.State.RenderEnableCondition);
|
||||||
|
|
||||||
|
if (renderEnable == ConditionalRenderEnabled.False)
|
||||||
|
{
|
||||||
|
_drawState.DrawIndexed = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicalMemory memory = _channel.MemoryManager.Physical;
|
||||||
|
|
||||||
|
bool hasCount = (drawType & IndirectDrawType.Count) != 0;
|
||||||
|
bool indexed = (drawType & IndirectDrawType.Indexed) != 0;
|
||||||
|
|
||||||
|
if (indexed)
|
||||||
|
{
|
||||||
|
indexCount = Math.Clamp(indexCount, MinIndirectIndexCount, MaxIndirectIndexCount);
|
||||||
|
_drawState.FirstIndex = 0;
|
||||||
|
_drawState.IndexCount = indexCount;
|
||||||
|
engine.ForceStateDirty(IndexBufferCountMethodOffset * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
_drawState.DrawIndexed = indexed;
|
||||||
|
_drawState.DrawIndirect = true;
|
||||||
|
_drawState.HasConstantBufferDrawParameters = true;
|
||||||
|
|
||||||
|
engine.UpdateState();
|
||||||
|
|
||||||
|
if (hasCount)
|
||||||
|
{
|
||||||
|
var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferAddress, (ulong)maxDrawCount * (ulong)stride);
|
||||||
|
var parameterBuffer = memory.BufferCache.GetBufferRange(parameterBufferAddress, 4);
|
||||||
|
|
||||||
|
if (indexed)
|
||||||
|
{
|
||||||
|
_context.Renderer.Pipeline.DrawIndexedIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_context.Renderer.Pipeline.DrawIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferAddress, (ulong)stride);
|
||||||
|
|
||||||
|
if (indexed)
|
||||||
|
{
|
||||||
|
_context.Renderer.Pipeline.DrawIndexedIndirect(indirectBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_context.Renderer.Pipeline.DrawIndirect(indirectBuffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_drawState.DrawIndexed = false;
|
_drawState.DrawIndexed = false;
|
||||||
|
_drawState.DrawIndirect = false;
|
||||||
|
_drawState.HasConstantBufferDrawParameters = false;
|
||||||
|
|
||||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||||
{
|
{
|
||||||
|
@@ -22,6 +22,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DrawIndexed;
|
public bool DrawIndexed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if the next draw will be a indirect draw.
|
||||||
|
/// </summary>
|
||||||
|
public bool DrawIndirect;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if any of the currently used vertex shaders reads the instance ID.
|
/// Indicates if any of the currently used vertex shaders reads the instance ID.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -32,6 +37,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsAnyVbInstanced;
|
public bool IsAnyVbInstanced;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
|
||||||
|
/// </summary>
|
||||||
|
public bool HasConstantBufferDrawParameters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Primitive topology for the next draw.
|
/// Primitive topology for the next draw.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
38
Ryujinx.Graphics.Gpu/Engine/Threed/IndirectDrawType.cs
Normal file
38
Ryujinx.Graphics.Gpu/Engine/Threed/IndirectDrawType.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indirect draw type, which can be indexed or non-indexed, with or without a draw count.
|
||||||
|
/// </summary>
|
||||||
|
enum IndirectDrawType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Non-indexed draw without draw count.
|
||||||
|
/// </summary>
|
||||||
|
DrawIndirect = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indexed draw without draw count.
|
||||||
|
/// </summary>
|
||||||
|
DrawIndexedIndirect = Indexed,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Non-indexed draw with draw count.
|
||||||
|
/// </summary>
|
||||||
|
DrawIndirectCount = Count,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indexed draw with draw count.
|
||||||
|
/// </summary>
|
||||||
|
DrawIndexedIndirectCount = Indexed | Count,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indexed flag.
|
||||||
|
/// </summary>
|
||||||
|
Indexed = 1 << 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draw count flag.
|
||||||
|
/// </summary>
|
||||||
|
Count = 1 << 1
|
||||||
|
}
|
||||||
|
}
|
@@ -34,10 +34,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
private ProgramPipelineState _pipeline;
|
private ProgramPipelineState _pipeline;
|
||||||
|
|
||||||
|
private bool _vsUsesDrawParameters;
|
||||||
private bool _vtgWritesRtLayer;
|
private bool _vtgWritesRtLayer;
|
||||||
private byte _vsClipDistancesWritten;
|
private byte _vsClipDistancesWritten;
|
||||||
|
|
||||||
private bool _prevDrawIndexed;
|
private bool _prevDrawIndexed;
|
||||||
|
private bool _prevDrawIndirect;
|
||||||
private IndexType _prevIndexType;
|
private IndexType _prevIndexType;
|
||||||
private uint _prevFirstVertex;
|
private uint _prevFirstVertex;
|
||||||
private bool _prevTfEnable;
|
private bool _prevTfEnable;
|
||||||
@@ -210,7 +212,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
// of the shader for the new state.
|
// of the shader for the new state.
|
||||||
if (_shaderSpecState != null)
|
if (_shaderSpecState != null)
|
||||||
{
|
{
|
||||||
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState(), false))
|
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState(), _vsUsesDrawParameters, false))
|
||||||
{
|
{
|
||||||
ForceShaderUpdate();
|
ForceShaderUpdate();
|
||||||
}
|
}
|
||||||
@@ -237,6 +239,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_prevDrawIndexed = _drawState.DrawIndexed;
|
_prevDrawIndexed = _drawState.DrawIndexed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some draw parameters are used to restrict the vertex buffer size,
|
||||||
|
// but they can't be used on indirect draws because their values are unknown in this case.
|
||||||
|
// When switching between indirect and non-indirect draw, we need to
|
||||||
|
// make sure the vertex buffer sizes are still correct.
|
||||||
|
if (_drawState.DrawIndirect != _prevDrawIndirect)
|
||||||
|
{
|
||||||
|
_updateTracker.ForceDirty(VertexBufferStateIndex);
|
||||||
|
}
|
||||||
|
|
||||||
// In some cases, the index type is also used to guess the
|
// In some cases, the index type is also used to guess the
|
||||||
// vertex buffer size, so we must update it if the type changed too.
|
// vertex buffer size, so we must update it if the type changed too.
|
||||||
if (_drawState.DrawIndexed &&
|
if (_drawState.DrawIndexed &&
|
||||||
@@ -938,6 +949,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
_drawState.IsAnyVbInstanced = false;
|
_drawState.IsAnyVbInstanced = false;
|
||||||
|
|
||||||
|
bool drawIndexed = _drawState.DrawIndexed;
|
||||||
|
bool drawIndirect = _drawState.DrawIndirect;
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
||||||
{
|
{
|
||||||
var vertexBuffer = _state.State.VertexBufferState[index];
|
var vertexBuffer = _state.State.VertexBufferState[index];
|
||||||
@@ -965,14 +979,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
ulong vbSize = endAddress.Pack() - address + 1;
|
ulong vbSize = endAddress.Pack() - address + 1;
|
||||||
ulong size;
|
ulong size;
|
||||||
|
|
||||||
if (_drawState.IbStreamer.HasInlineIndexData || _drawState.DrawIndexed || stride == 0 || instanced)
|
if (_drawState.IbStreamer.HasInlineIndexData || drawIndexed || stride == 0 || instanced)
|
||||||
{
|
{
|
||||||
// This size may be (much) larger than the real vertex buffer size.
|
// This size may be (much) larger than the real vertex buffer size.
|
||||||
// Avoid calculating it this way, unless we don't have any other option.
|
// Avoid calculating it this way, unless we don't have any other option.
|
||||||
|
|
||||||
size = vbSize;
|
size = vbSize;
|
||||||
|
|
||||||
if (stride > 0 && indexTypeSmall && _drawState.DrawIndexed && !instanced)
|
if (stride > 0 && indexTypeSmall && drawIndexed && !drawIndirect && !instanced)
|
||||||
{
|
{
|
||||||
// If the index type is a small integer type, then we might be still able
|
// If the index type is a small integer type, then we might be still able
|
||||||
// to reduce the vertex buffer size based on the maximum possible index value.
|
// to reduce the vertex buffer size based on the maximum possible index value.
|
||||||
@@ -1207,6 +1221,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
byte oldVsClipDistancesWritten = _vsClipDistancesWritten;
|
byte oldVsClipDistancesWritten = _vsClipDistancesWritten;
|
||||||
|
|
||||||
_drawState.VsUsesInstanceId = gs.Shaders[1]?.Info.UsesInstanceId ?? false;
|
_drawState.VsUsesInstanceId = gs.Shaders[1]?.Info.UsesInstanceId ?? false;
|
||||||
|
_vsUsesDrawParameters = gs.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||||
_vsClipDistancesWritten = gs.Shaders[1]?.Info.ClipDistancesWritten ?? 0;
|
_vsClipDistancesWritten = gs.Shaders[1]?.Info.ClipDistancesWritten ?? 0;
|
||||||
|
|
||||||
if (oldVsClipDistancesWritten != _vsClipDistancesWritten)
|
if (oldVsClipDistancesWritten != _vsClipDistancesWritten)
|
||||||
@@ -1222,6 +1237,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
|
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates bindings consumed by the shader stage on the texture and buffer managers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stage">Shader stage to have the bindings updated</param>
|
||||||
|
/// <param name="info">Shader stage bindings info</param>
|
||||||
private void UpdateStageBindings(int stage, ShaderProgramInfo info)
|
private void UpdateStageBindings(int stage, ShaderProgramInfo info)
|
||||||
{
|
{
|
||||||
_currentProgramInfo[stage] = info;
|
_currentProgramInfo[stage] = info;
|
||||||
@@ -1340,7 +1360,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_state.State.AlphaTestEnable,
|
_state.State.AlphaTestEnable,
|
||||||
_state.State.AlphaTestFunc,
|
_state.State.AlphaTestFunc,
|
||||||
_state.State.AlphaTestRef,
|
_state.State.AlphaTestRef,
|
||||||
ref attributeTypes);
|
ref attributeTypes,
|
||||||
|
_drawState.HasConstantBufferDrawParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -497,6 +497,50 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a indexed or non-indexed draw.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="topology">Primitive topology</param>
|
||||||
|
/// <param name="count">Index count for indexed draws, vertex count for non-indexed draws</param>
|
||||||
|
/// <param name="instanceCount">Instance count</param>
|
||||||
|
/// <param name="firstIndex">First index on the index buffer for indexed draws, ignored for non-indexed draws</param>
|
||||||
|
/// <param name="firstVertex">First vertex on the vertex buffer</param>
|
||||||
|
/// <param name="firstInstance">First instance</param>
|
||||||
|
/// <param name="indexed">True if the draw is indexed, false otherwise</param>
|
||||||
|
public void Draw(
|
||||||
|
PrimitiveTopology topology,
|
||||||
|
int count,
|
||||||
|
int instanceCount,
|
||||||
|
int firstIndex,
|
||||||
|
int firstVertex,
|
||||||
|
int firstInstance,
|
||||||
|
bool indexed)
|
||||||
|
{
|
||||||
|
_drawManager.Draw(this, topology, count, instanceCount, firstIndex, firstVertex, firstInstance, indexed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a indirect draw, with parameters from a GPU buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="topology">Primitive topology</param>
|
||||||
|
/// <param name="indirectBufferAddress">Address of the buffer with the draw parameters, such as count, first index, etc</param>
|
||||||
|
/// <param name="parameterBufferAddress">Address of the buffer with the draw count</param>
|
||||||
|
/// <param name="maxDrawCount">Maximum number of draws that can be made</param>
|
||||||
|
/// <param name="stride">Distance in bytes between each entry on the data pointed to by <paramref name="indirectBufferAddress"/></param>
|
||||||
|
/// <param name="indexCount">Maximum number of indices that the draw can consume</param>
|
||||||
|
/// <param name="drawType">Type of the indirect draw, which can be indexed or non-indexed, with or without a draw count</param>
|
||||||
|
public void DrawIndirect(
|
||||||
|
PrimitiveTopology topology,
|
||||||
|
ulong indirectBufferAddress,
|
||||||
|
ulong parameterBufferAddress,
|
||||||
|
int maxDrawCount,
|
||||||
|
int stride,
|
||||||
|
int indexCount,
|
||||||
|
IndirectDrawType drawType)
|
||||||
|
{
|
||||||
|
_drawManager.DrawIndirect(this, topology, indirectBufferAddress, parameterBufferAddress, maxDrawCount, stride, indexCount, drawType);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears the current color and depth-stencil buffers.
|
/// Clears the current color and depth-stencil buffers.
|
||||||
/// Which buffers should be cleared can also specified with the arguments.
|
/// Which buffers should be cleared can also specified with the arguments.
|
||||||
@@ -507,25 +551,5 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
{
|
{
|
||||||
_drawManager.Clear(this, argument, layerCount);
|
_drawManager.Clear(this, argument, layerCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs a indirect multi-draw, with parameters from a GPU buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="indexCount">Index Buffer Count</param>
|
|
||||||
/// <param name="topology">Primitive topology</param>
|
|
||||||
/// <param name="indirectBuffer">GPU buffer with the draw parameters, such as count, first index, etc</param>
|
|
||||||
/// <param name="parameterBuffer">GPU buffer with the draw count</param>
|
|
||||||
/// <param name="maxDrawCount">Maximum number of draws that can be made</param>
|
|
||||||
/// <param name="stride">Distance in bytes between each element on the <paramref name="indirectBuffer"/> array</param>
|
|
||||||
public void MultiDrawIndirectCount(
|
|
||||||
int indexCount,
|
|
||||||
PrimitiveTopology topology,
|
|
||||||
BufferRange indirectBuffer,
|
|
||||||
BufferRange parameterBuffer,
|
|
||||||
int maxDrawCount,
|
|
||||||
int stride)
|
|
||||||
{
|
|
||||||
_drawManager.MultiDrawIndirectCount(this, indexCount, topology, indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -708,11 +708,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool dataMatches = _currentData != null && data.SequenceEqual(_currentData);
|
bool dataMatches = _currentData != null && data.SequenceEqual(_currentData);
|
||||||
_currentData = data.ToArray();
|
|
||||||
if (dataMatches)
|
if (dataMatches)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_currentData = data.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -413,10 +413,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void UpdateCachedBuffer(
|
private void UpdateCachedBuffer(
|
||||||
int stageIndex,
|
int stageIndex,
|
||||||
ref int cachedTextureBufferIndex,
|
scoped ref int cachedTextureBufferIndex,
|
||||||
ref int cachedSamplerBufferIndex,
|
scoped ref int cachedSamplerBufferIndex,
|
||||||
ref ReadOnlySpan<int> cachedTextureBuffer,
|
scoped ref ReadOnlySpan<int> cachedTextureBuffer,
|
||||||
ref ReadOnlySpan<int> cachedSamplerBuffer,
|
scoped ref ReadOnlySpan<int> cachedSamplerBuffer,
|
||||||
int textureBufferIndex,
|
int textureBufferIndex,
|
||||||
int samplerBufferIndex)
|
int samplerBufferIndex)
|
||||||
{
|
{
|
||||||
|
@@ -710,7 +710,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
break;
|
break;
|
||||||
case Target.Texture2DMultisample:
|
case Target.Texture2DMultisample:
|
||||||
case Target.Texture2DMultisampleArray:
|
case Target.Texture2DMultisampleArray:
|
||||||
if (rhs.Target == Target.Texture2D || rhs.Target == Target.Texture2DArray)
|
// We don't support copy between multisample and non-multisample depth-stencil textures
|
||||||
|
// because there's no way to emulate that since most GPUs don't support writing a
|
||||||
|
// custom stencil value into the texture, among several other API limitations.
|
||||||
|
|
||||||
|
if ((rhs.Target == Target.Texture2D || rhs.Target == Target.Texture2DArray) &&
|
||||||
|
!rhs.FormatInfo.Format.IsDepthOrStencil())
|
||||||
{
|
{
|
||||||
return TextureViewCompatibility.CopyOnly;
|
return TextureViewCompatibility.CopyOnly;
|
||||||
}
|
}
|
||||||
|
@@ -27,6 +27,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
private Buffer[] _bufferOverlaps;
|
private Buffer[] _bufferOverlaps;
|
||||||
|
|
||||||
private readonly Dictionary<ulong, BufferCacheEntry> _dirtyCache;
|
private readonly Dictionary<ulong, BufferCacheEntry> _dirtyCache;
|
||||||
|
private readonly Dictionary<ulong, BufferCacheEntry> _modifiedCache;
|
||||||
|
|
||||||
public event Action NotifyBuffersModified;
|
public event Action NotifyBuffersModified;
|
||||||
|
|
||||||
@@ -45,6 +46,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
_bufferOverlaps = new Buffer[OverlapsBufferInitialCapacity];
|
_bufferOverlaps = new Buffer[OverlapsBufferInitialCapacity];
|
||||||
|
|
||||||
_dirtyCache = new Dictionary<ulong, BufferCacheEntry>();
|
_dirtyCache = new Dictionary<ulong, BufferCacheEntry>();
|
||||||
|
|
||||||
|
// There are a lot more entries on the modified cache, so it is separate from the one for ForceDirty.
|
||||||
|
_modifiedCache = new Dictionary<ulong, BufferCacheEntry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -145,6 +149,30 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
result.Buffer.ForceDirty(result.Address, size);
|
result.Buffer.ForceDirty(result.Address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the given buffer range has been GPU modifed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
|
||||||
|
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
||||||
|
/// <param name="size">Size in bytes of the buffer</param>
|
||||||
|
/// <returns>True if modified, false otherwise</returns>
|
||||||
|
public bool CheckModified(MemoryManager memoryManager, ulong gpuVa, ulong size, out ulong outAddr)
|
||||||
|
{
|
||||||
|
if (!_modifiedCache.TryGetValue(gpuVa, out BufferCacheEntry result) ||
|
||||||
|
result.EndGpuAddress < gpuVa + size ||
|
||||||
|
result.UnmappedSequence != result.Buffer.UnmappedSequence)
|
||||||
|
{
|
||||||
|
ulong address = TranslateAndCreateBuffer(memoryManager, gpuVa, size);
|
||||||
|
result = new BufferCacheEntry(address, gpuVa, GetBuffer(address, size));
|
||||||
|
|
||||||
|
_modifiedCache[gpuVa] = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
outAddr = result.Address;
|
||||||
|
|
||||||
|
return result.Buffer.IsModified(result.Address, size);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new buffer for the specified range, if needed.
|
/// Creates a new buffer for the specified range, if needed.
|
||||||
/// If a buffer where this range can be fully contained already exists,
|
/// If a buffer where this range can be fully contained already exists,
|
||||||
@@ -326,18 +354,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
buffer.SignalModified(address, size);
|
buffer.SignalModified(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a buffer sub-range for a given GPU memory range.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
|
|
||||||
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
|
||||||
/// <param name="size">Size in bytes of the buffer</param>
|
|
||||||
/// <returns>The buffer sub-range for the given range</returns>
|
|
||||||
public BufferRange GetGpuBufferRange(MemoryManager memoryManager, ulong gpuVa, ulong size)
|
|
||||||
{
|
|
||||||
return GetBufferRange(TranslateAndCreateBuffer(memoryManager, gpuVa, size), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a buffer sub-range starting at a given memory address.
|
/// Gets a buffer sub-range starting at a given memory address.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -129,6 +129,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
return _oldSpecState.ConstantBufferUse[_stageIndex];
|
return _oldSpecState.ConstantBufferUse[_stageIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool QueryHasConstantBufferDrawParameters()
|
||||||
|
{
|
||||||
|
return _oldSpecState.GraphicsState.HasConstantBufferDrawParameters;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public InputTopology QueryPrimitiveTopology()
|
public InputTopology QueryPrimitiveTopology()
|
||||||
{
|
{
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 3732;
|
private const uint CodeGenVersion = 3747;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
@@ -159,6 +159,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
/// Bit mask of the render target components written by the fragment stage.
|
/// Bit mask of the render target components written by the fragment stage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int FragmentOutputMap;
|
public int FragmentOutputMap;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if the vertex shader accesses draw parameters.
|
||||||
|
/// </summary>
|
||||||
|
public bool UsesDrawParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly DiskCacheGuestStorage _guestStorage;
|
private readonly DiskCacheGuestStorage _guestStorage;
|
||||||
@@ -771,6 +776,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
images,
|
images,
|
||||||
dataInfo.Stage,
|
dataInfo.Stage,
|
||||||
dataInfo.UsesInstanceId,
|
dataInfo.UsesInstanceId,
|
||||||
|
dataInfo.UsesDrawParameters,
|
||||||
dataInfo.UsesRtLayer,
|
dataInfo.UsesRtLayer,
|
||||||
dataInfo.ClipDistancesWritten,
|
dataInfo.ClipDistancesWritten,
|
||||||
dataInfo.FragmentOutputMap);
|
dataInfo.FragmentOutputMap);
|
||||||
@@ -796,6 +802,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
dataInfo.ImagesCount = (ushort)info.Images.Count;
|
dataInfo.ImagesCount = (ushort)info.Images.Count;
|
||||||
dataInfo.Stage = info.Stage;
|
dataInfo.Stage = info.Stage;
|
||||||
dataInfo.UsesInstanceId = info.UsesInstanceId;
|
dataInfo.UsesInstanceId = info.UsesInstanceId;
|
||||||
|
dataInfo.UsesDrawParameters = info.UsesDrawParameters;
|
||||||
dataInfo.UsesRtLayer = info.UsesRtLayer;
|
dataInfo.UsesRtLayer = info.UsesRtLayer;
|
||||||
dataInfo.ClipDistancesWritten = info.ClipDistancesWritten;
|
dataInfo.ClipDistancesWritten = info.ClipDistancesWritten;
|
||||||
dataInfo.FragmentOutputMap = info.FragmentOutputMap;
|
dataInfo.FragmentOutputMap = info.FragmentOutputMap;
|
||||||
|
@@ -139,6 +139,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
return useMask;
|
return useMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool QueryHasConstantBufferDrawParameters()
|
||||||
|
{
|
||||||
|
return _state.GraphicsState.HasConstantBufferDrawParameters;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public InputTopology QueryPrimitiveTopology()
|
public InputTopology QueryPrimitiveTopology()
|
||||||
{
|
{
|
||||||
|
@@ -77,6 +77,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Array32<AttributeType> AttributeTypes;
|
public Array32<AttributeType> AttributeTypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool HasConstantBufferDrawParameters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new GPU graphics state.
|
/// Creates a new GPU graphics state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -93,6 +98,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <param name="alphaTestCompare">When alpha test is enabled, indicates the comparison that decides if the fragment should be discarded</param>
|
/// <param name="alphaTestCompare">When alpha test is enabled, indicates the comparison that decides if the fragment should be discarded</param>
|
||||||
/// <param name="alphaTestReference">When alpha test is enabled, indicates the value to compare with the fragment output alpha</param>
|
/// <param name="alphaTestReference">When alpha test is enabled, indicates the value to compare with the fragment output alpha</param>
|
||||||
/// <param name="attributeTypes">Type of the vertex attributes consumed by the shader</param>
|
/// <param name="attributeTypes">Type of the vertex attributes consumed by the shader</param>
|
||||||
|
/// <param name="hasConstantBufferDrawParameters">Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0</param>
|
||||||
public GpuChannelGraphicsState(
|
public GpuChannelGraphicsState(
|
||||||
bool earlyZForce,
|
bool earlyZForce,
|
||||||
PrimitiveTopology topology,
|
PrimitiveTopology topology,
|
||||||
@@ -106,7 +112,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
bool alphaTestEnable,
|
bool alphaTestEnable,
|
||||||
CompareOp alphaTestCompare,
|
CompareOp alphaTestCompare,
|
||||||
float alphaTestReference,
|
float alphaTestReference,
|
||||||
ref Array32<AttributeType> attributeTypes)
|
ref Array32<AttributeType> attributeTypes,
|
||||||
|
bool hasConstantBufferDrawParameters)
|
||||||
{
|
{
|
||||||
EarlyZForce = earlyZForce;
|
EarlyZForce = earlyZForce;
|
||||||
Topology = topology;
|
Topology = topology;
|
||||||
@@ -121,6 +128,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
AlphaTestCompare = alphaTestCompare;
|
AlphaTestCompare = alphaTestCompare;
|
||||||
AlphaTestReference = alphaTestReference;
|
AlphaTestReference = alphaTestReference;
|
||||||
AttributeTypes = attributeTypes;
|
AttributeTypes = attributeTypes;
|
||||||
|
HasConstantBufferDrawParameters = hasConstantBufferDrawParameters;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -350,7 +350,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.HashTable
|
|||||||
/// <param name="item">The item on the table, if found, otherwise unmodified</param>
|
/// <param name="item">The item on the table, if found, otherwise unmodified</param>
|
||||||
/// <param name="data">The data on the table, if found, otherwise unmodified</param>
|
/// <param name="data">The data on the table, if found, otherwise unmodified</param>
|
||||||
/// <returns>Table lookup result</returns>
|
/// <returns>Table lookup result</returns>
|
||||||
public SearchResult TryFindItem(ref SmartDataAccessor dataAccessor, int size, ref T item, ref byte[] data)
|
public SearchResult TryFindItem(scoped ref SmartDataAccessor dataAccessor, int size, scoped ref T item, scoped ref byte[] data)
|
||||||
{
|
{
|
||||||
if (_count == 0)
|
if (_count == 0)
|
||||||
{
|
{
|
||||||
|
@@ -91,7 +91,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.HashTable
|
|||||||
/// <param name="item">The item on the table, if found, otherwise unmodified</param>
|
/// <param name="item">The item on the table, if found, otherwise unmodified</param>
|
||||||
/// <param name="data">The data on the table, if found, otherwise unmodified</param>
|
/// <param name="data">The data on the table, if found, otherwise unmodified</param>
|
||||||
/// <returns>Table lookup result</returns>
|
/// <returns>Table lookup result</returns>
|
||||||
public PartitionHashTable<T>.SearchResult TryFindItem(ref SmartDataAccessor dataAccessor, ref T item, ref byte[] data)
|
public PartitionHashTable<T>.SearchResult TryFindItem(scoped ref SmartDataAccessor dataAccessor, scoped ref T item, scoped ref byte[] data)
|
||||||
{
|
{
|
||||||
return _table.TryFindItem(ref dataAccessor, Size, ref item, ref data);
|
return _table.TryFindItem(ref dataAccessor, Size, ref item, ref data);
|
||||||
}
|
}
|
||||||
|
@@ -520,7 +520,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return gpShaders.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, true);
|
bool usesDrawParameters = gpShaders.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||||
|
|
||||||
|
return gpShaders.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, usesDrawParameters, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -35,7 +35,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
{
|
{
|
||||||
foreach (var entry in _entries)
|
foreach (var entry in _entries)
|
||||||
{
|
{
|
||||||
if (entry.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, true))
|
bool usesDrawParameters = entry.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||||
|
|
||||||
|
if (entry.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, usesDrawParameters, true))
|
||||||
{
|
{
|
||||||
program = entry;
|
program = entry;
|
||||||
return true;
|
return true;
|
||||||
|
@@ -481,9 +481,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <param name="channel">GPU channel</param>
|
/// <param name="channel">GPU channel</param>
|
||||||
/// <param name="poolState">Texture pool state</param>
|
/// <param name="poolState">Texture pool state</param>
|
||||||
/// <param name="graphicsState">Graphics state</param>
|
/// <param name="graphicsState">Graphics state</param>
|
||||||
|
/// <param name="usesDrawParameters">Indicates whether the vertex shader accesses draw parameters</param>
|
||||||
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
||||||
/// <returns>True if the state matches, false otherwise</returns>
|
/// <returns>True if the state matches, false otherwise</returns>
|
||||||
public bool MatchesGraphics(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelGraphicsState graphicsState, bool checkTextures)
|
public bool MatchesGraphics(
|
||||||
|
GpuChannel channel,
|
||||||
|
GpuChannelPoolState poolState,
|
||||||
|
GpuChannelGraphicsState graphicsState,
|
||||||
|
bool usesDrawParameters,
|
||||||
|
bool checkTextures)
|
||||||
{
|
{
|
||||||
if (graphicsState.ViewportTransformDisable != GraphicsState.ViewportTransformDisable)
|
if (graphicsState.ViewportTransformDisable != GraphicsState.ViewportTransformDisable)
|
||||||
{
|
{
|
||||||
@@ -520,6 +526,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (usesDrawParameters && graphicsState.HasConstantBufferDrawParameters != GraphicsState.HasConstantBufferDrawParameters)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return Matches(channel, poolState, checkTextures, isCompute: false);
|
return Matches(channel, poolState, checkTextures, isCompute: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,11 +563,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
private static void UpdateCachedBuffer(
|
private static void UpdateCachedBuffer(
|
||||||
GpuChannel channel,
|
GpuChannel channel,
|
||||||
bool isCompute,
|
bool isCompute,
|
||||||
ref int cachedTextureBufferIndex,
|
scoped ref int cachedTextureBufferIndex,
|
||||||
ref int cachedSamplerBufferIndex,
|
scoped ref int cachedSamplerBufferIndex,
|
||||||
ref ReadOnlySpan<int> cachedTextureBuffer,
|
scoped ref ReadOnlySpan<int> cachedTextureBuffer,
|
||||||
ref ReadOnlySpan<int> cachedSamplerBuffer,
|
scoped ref ReadOnlySpan<int> cachedSamplerBuffer,
|
||||||
ref int cachedStageIndex,
|
scoped ref int cachedStageIndex,
|
||||||
int textureBufferIndex,
|
int textureBufferIndex,
|
||||||
int samplerBufferIndex,
|
int samplerBufferIndex,
|
||||||
int stageIndex)
|
int stageIndex)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -7,7 +7,9 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
|
|||||||
{
|
{
|
||||||
unsafe class FFmpegContext : IDisposable
|
unsafe class FFmpegContext : IDisposable
|
||||||
{
|
{
|
||||||
private readonly FFCodec.AVCodec_decode _decodeFrame;
|
private unsafe delegate int AVCodec_decode(AVCodecContext* avctx, void* outdata, int* got_frame_ptr, AVPacket* avpkt);
|
||||||
|
|
||||||
|
private readonly AVCodec_decode _decodeFrame;
|
||||||
private static readonly FFmpegApi.av_log_set_callback_callback _logFunc;
|
private static readonly FFmpegApi.av_log_set_callback_callback _logFunc;
|
||||||
private readonly AVCodec* _codec;
|
private readonly AVCodec* _codec;
|
||||||
private AVPacket* _packet;
|
private AVPacket* _packet;
|
||||||
@@ -53,17 +55,17 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
|
|||||||
// libavcodec 59.24 changed AvCodec to move its private API and also move the codec function to an union.
|
// libavcodec 59.24 changed AvCodec to move its private API and also move the codec function to an union.
|
||||||
if (avCodecMajorVersion > 59 || (avCodecMajorVersion == 59 && avCodecMinorVersion > 24))
|
if (avCodecMajorVersion > 59 || (avCodecMajorVersion == 59 && avCodecMinorVersion > 24))
|
||||||
{
|
{
|
||||||
_decodeFrame = Marshal.GetDelegateForFunctionPointer<FFCodec.AVCodec_decode>(((FFCodec*)_codec)->CodecCallback);
|
_decodeFrame = Marshal.GetDelegateForFunctionPointer<AVCodec_decode>(((FFCodec<AVCodec>*)_codec)->CodecCallback);
|
||||||
}
|
}
|
||||||
// libavcodec 59.x changed AvCodec private API layout.
|
// libavcodec 59.x changed AvCodec private API layout.
|
||||||
else if (avCodecMajorVersion == 59)
|
else if (avCodecMajorVersion == 59)
|
||||||
{
|
{
|
||||||
_decodeFrame = Marshal.GetDelegateForFunctionPointer<FFCodec.AVCodec_decode>(((FFCodecLegacy<AVCodec>*)_codec)->Decode);
|
_decodeFrame = Marshal.GetDelegateForFunctionPointer<AVCodec_decode>(((FFCodecLegacy<AVCodec501>*)_codec)->Decode);
|
||||||
}
|
}
|
||||||
// libavcodec 58.x and lower
|
// libavcodec 58.x and lower
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_decodeFrame = Marshal.GetDelegateForFunctionPointer<FFCodec.AVCodec_decode>(((FFCodecLegacy<AVCodecLegacy>*)_codec)->Decode);
|
_decodeFrame = Marshal.GetDelegateForFunctionPointer<AVCodec_decode>(((FFCodecLegacy<AVCodec>*)_codec)->Decode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
public unsafe IntPtr PrivClass;
|
public unsafe IntPtr PrivClass;
|
||||||
public IntPtr Profiles;
|
public IntPtr Profiles;
|
||||||
public unsafe byte* WrapperName;
|
public unsafe byte* WrapperName;
|
||||||
|
public IntPtr ChLayouts;
|
||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
||||||
{
|
{
|
||||||
struct AVCodecLegacy
|
struct AVCodec501
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649
|
||||||
public unsafe byte* Name;
|
public unsafe byte* Name;
|
||||||
@@ -20,7 +20,6 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
public unsafe IntPtr PrivClass;
|
public unsafe IntPtr PrivClass;
|
||||||
public IntPtr Profiles;
|
public IntPtr Profiles;
|
||||||
public unsafe byte* WrapperName;
|
public unsafe byte* WrapperName;
|
||||||
public IntPtr ChLayouts;
|
|
||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -9,7 +9,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
public unsafe IntPtr AvClass;
|
public unsafe IntPtr AvClass;
|
||||||
public int LogLevelOffset;
|
public int LogLevelOffset;
|
||||||
public int CodecType;
|
public int CodecType;
|
||||||
public unsafe AVCodecLegacy* Codec;
|
public unsafe AVCodec* Codec;
|
||||||
public AVCodecID CodecId;
|
public AVCodecID CodecId;
|
||||||
public uint CodecTag;
|
public uint CodecTag;
|
||||||
public IntPtr PrivData;
|
public IntPtr PrivData;
|
||||||
|
@@ -2,12 +2,10 @@
|
|||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
||||||
{
|
{
|
||||||
struct FFCodec
|
struct FFCodec<T> where T: struct
|
||||||
{
|
{
|
||||||
public unsafe delegate int AVCodec_decode(AVCodecContext* avctx, void* outdata, int* got_frame_ptr, AVPacket* avpkt);
|
|
||||||
|
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649
|
||||||
public AVCodec Base;
|
public T Base;
|
||||||
public int CapsInternalOrCbType;
|
public int CapsInternalOrCbType;
|
||||||
public int PrivDataSize;
|
public int PrivDataSize;
|
||||||
public IntPtr UpdateThreadContext;
|
public IntPtr UpdateThreadContext;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -34,5 +34,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
GL.ActiveTexture(TextureUnit.Texture0 + unit);
|
GL.ActiveTexture(TextureUnit.Texture0 + unit);
|
||||||
GL.BindTexture(target, Handle);
|
GL.BindTexture(target, Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ClearBinding(int unit)
|
||||||
|
{
|
||||||
|
GL.ActiveTexture(TextureUnit.Texture0 + unit);
|
||||||
|
GL.BindTextureUnit(unit, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -139,7 +139,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
|
|
||||||
if (!destinationView.Target.IsMultisample() && Target.IsMultisample())
|
if (!destinationView.Target.IsMultisample() && Target.IsMultisample())
|
||||||
{
|
{
|
||||||
_renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, srcLayer, dstLayer,1);
|
_renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, srcLayer, dstLayer, 1);
|
||||||
}
|
}
|
||||||
else if (destinationView.Target.IsMultisample() && !Target.IsMultisample())
|
else if (destinationView.Target.IsMultisample() && !Target.IsMultisample())
|
||||||
{
|
{
|
||||||
|
@@ -586,6 +586,95 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DrawIndexedIndirect(BufferRange indirectBuffer)
|
||||||
|
{
|
||||||
|
if (!_program.IsLinked)
|
||||||
|
{
|
||||||
|
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreDrawVbUnbounded();
|
||||||
|
|
||||||
|
_vertexArray.SetRangeOfIndexBuffer();
|
||||||
|
|
||||||
|
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
||||||
|
|
||||||
|
GL.DrawElementsIndirect(_primitiveType, _elementsType, (IntPtr)indirectBuffer.Offset);
|
||||||
|
|
||||||
|
_vertexArray.RestoreIndexBuffer();
|
||||||
|
|
||||||
|
PostDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||||
|
{
|
||||||
|
if (!_program.IsLinked)
|
||||||
|
{
|
||||||
|
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreDrawVbUnbounded();
|
||||||
|
|
||||||
|
_vertexArray.SetRangeOfIndexBuffer();
|
||||||
|
|
||||||
|
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
||||||
|
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
|
||||||
|
|
||||||
|
GL.MultiDrawElementsIndirectCount(
|
||||||
|
_primitiveType,
|
||||||
|
(All)_elementsType,
|
||||||
|
(IntPtr)indirectBuffer.Offset,
|
||||||
|
(IntPtr)parameterBuffer.Offset,
|
||||||
|
maxDrawCount,
|
||||||
|
stride);
|
||||||
|
|
||||||
|
_vertexArray.RestoreIndexBuffer();
|
||||||
|
|
||||||
|
PostDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawIndirect(BufferRange indirectBuffer)
|
||||||
|
{
|
||||||
|
if (!_program.IsLinked)
|
||||||
|
{
|
||||||
|
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreDrawVbUnbounded();
|
||||||
|
|
||||||
|
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
||||||
|
|
||||||
|
GL.DrawArraysIndirect(_primitiveType, (IntPtr)indirectBuffer.Offset);
|
||||||
|
|
||||||
|
PostDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||||
|
{
|
||||||
|
if (!_program.IsLinked)
|
||||||
|
{
|
||||||
|
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreDrawVbUnbounded();
|
||||||
|
|
||||||
|
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
||||||
|
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
|
||||||
|
|
||||||
|
GL.MultiDrawArraysIndirectCount(
|
||||||
|
_primitiveType,
|
||||||
|
(IntPtr)indirectBuffer.Offset,
|
||||||
|
(IntPtr)parameterBuffer.Offset,
|
||||||
|
maxDrawCount,
|
||||||
|
stride);
|
||||||
|
|
||||||
|
PostDraw();
|
||||||
|
}
|
||||||
|
|
||||||
public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
|
public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
|
||||||
{
|
{
|
||||||
if (texture is TextureView view && sampler is Sampler samp)
|
if (texture is TextureView view && sampler is Sampler samp)
|
||||||
@@ -683,57 +772,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
_tfEnabled = false;
|
_tfEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MultiDrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
|
||||||
{
|
|
||||||
if (!_program.IsLinked)
|
|
||||||
{
|
|
||||||
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PreDrawVbUnbounded();
|
|
||||||
|
|
||||||
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
|
||||||
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
|
|
||||||
|
|
||||||
GL.MultiDrawArraysIndirectCount(
|
|
||||||
_primitiveType,
|
|
||||||
(IntPtr)indirectBuffer.Offset,
|
|
||||||
(IntPtr)parameterBuffer.Offset,
|
|
||||||
maxDrawCount,
|
|
||||||
stride);
|
|
||||||
|
|
||||||
PostDraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MultiDrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
|
||||||
{
|
|
||||||
if (!_program.IsLinked)
|
|
||||||
{
|
|
||||||
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PreDrawVbUnbounded();
|
|
||||||
|
|
||||||
_vertexArray.SetRangeOfIndexBuffer();
|
|
||||||
|
|
||||||
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
|
||||||
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
|
|
||||||
|
|
||||||
GL.MultiDrawElementsIndirectCount(
|
|
||||||
_primitiveType,
|
|
||||||
(All)_elementsType,
|
|
||||||
(IntPtr)indirectBuffer.Offset,
|
|
||||||
(IntPtr)parameterBuffer.Offset,
|
|
||||||
maxDrawCount,
|
|
||||||
stride);
|
|
||||||
|
|
||||||
_vertexArray.RestoreIndexBuffer();
|
|
||||||
|
|
||||||
PostDraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
||||||
{
|
{
|
||||||
if (!enable)
|
if (!enable)
|
||||||
@@ -919,6 +957,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
|
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
{
|
{
|
||||||
|
GL.BindImageTexture(binding, 0, 0, true, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1275,6 +1314,10 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
((TextureBase)texture).Bind(binding);
|
((TextureBase)texture).Bind(binding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TextureBase.ClearBinding(binding);
|
||||||
|
}
|
||||||
|
|
||||||
Sampler glSampler = (Sampler)sampler;
|
Sampler glSampler = (Sampler)sampler;
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -10,12 +10,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
public StructuredFunction CurrentFunction { get; set; }
|
public StructuredFunction CurrentFunction { get; set; }
|
||||||
|
|
||||||
|
public StructuredProgramInfo Info { get; }
|
||||||
|
|
||||||
public ShaderConfig Config { get; }
|
public ShaderConfig Config { get; }
|
||||||
|
|
||||||
public OperandManager OperandManager { get; }
|
public OperandManager OperandManager { get; }
|
||||||
|
|
||||||
private readonly StructuredProgramInfo _info;
|
|
||||||
|
|
||||||
private readonly StringBuilder _sb;
|
private readonly StringBuilder _sb;
|
||||||
|
|
||||||
private int _level;
|
private int _level;
|
||||||
@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
public CodeGenContext(StructuredProgramInfo info, ShaderConfig config)
|
public CodeGenContext(StructuredProgramInfo info, ShaderConfig config)
|
||||||
{
|
{
|
||||||
_info = info;
|
Info = info;
|
||||||
Config = config;
|
Config = config;
|
||||||
|
|
||||||
OperandManager = new OperandManager();
|
OperandManager = new OperandManager();
|
||||||
@@ -72,19 +72,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
public StructuredFunction GetFunction(int id)
|
public StructuredFunction GetFunction(int id)
|
||||||
{
|
{
|
||||||
return _info.Functions[id];
|
return Info.Functions[id];
|
||||||
}
|
|
||||||
|
|
||||||
public TransformFeedbackOutput GetTransformFeedbackOutput(int location, int component)
|
|
||||||
{
|
|
||||||
int index = (AttributeConsts.UserAttributeBase / 4) + location * 4 + component;
|
|
||||||
return _info.TransformFeedbackOutputs[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public TransformFeedbackOutput GetTransformFeedbackOutput(int location)
|
|
||||||
{
|
|
||||||
int index = location / 4;
|
|
||||||
return _info.TransformFeedbackOutputs[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateIndentation()
|
private void UpdateIndentation()
|
||||||
|
@@ -46,6 +46,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (context.Config.Stage == ShaderStage.Vertex)
|
||||||
|
{
|
||||||
|
context.AppendLine("#extension GL_ARB_shader_draw_parameters : enable");
|
||||||
|
}
|
||||||
|
|
||||||
context.AppendLine("#extension GL_ARB_shader_viewport_layer_array : enable");
|
context.AppendLine("#extension GL_ARB_shader_viewport_layer_array : enable");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +215,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline)
|
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline)
|
||||||
{
|
{
|
||||||
var tfOutput = context.GetTransformFeedbackOutput(AttributeConsts.PositionX);
|
var tfOutput = context.Info.GetTransformFeedbackOutput(AttributeConsts.PositionX);
|
||||||
if (tfOutput.Valid)
|
if (tfOutput.Valid)
|
||||||
{
|
{
|
||||||
context.AppendLine($"layout (xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}) out gl_PerVertex");
|
context.AppendLine($"layout (xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}) out gl_PerVertex");
|
||||||
@@ -520,7 +525,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
private static void DeclareInputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
private static void DeclareInputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
||||||
{
|
{
|
||||||
foreach (int attr in attrs.OrderBy(x => x))
|
foreach (int attr in attrs.Order())
|
||||||
{
|
{
|
||||||
DeclareInputAttributePerPatch(context, attr);
|
DeclareInputAttributePerPatch(context, attr);
|
||||||
}
|
}
|
||||||
@@ -603,6 +608,31 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
string name = $"{DefaultNames.OAttributePrefix}{attr}{suffix}";
|
string name = $"{DefaultNames.OAttributePrefix}{attr}{suffix}";
|
||||||
|
|
||||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline)
|
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline)
|
||||||
|
{
|
||||||
|
int attrOffset = AttributeConsts.UserAttributeBase + attr * 16;
|
||||||
|
int components = context.Config.LastInPipeline ? context.Info.GetTransformFeedbackOutputComponents(attrOffset) : 1;
|
||||||
|
|
||||||
|
if (components > 1)
|
||||||
|
{
|
||||||
|
string type = components switch
|
||||||
|
{
|
||||||
|
2 => "vec2",
|
||||||
|
3 => "vec3",
|
||||||
|
4 => "vec4",
|
||||||
|
_ => "float"
|
||||||
|
};
|
||||||
|
|
||||||
|
string xfb = string.Empty;
|
||||||
|
|
||||||
|
var tfOutput = context.Info.GetTransformFeedbackOutput(attrOffset);
|
||||||
|
if (tfOutput.Valid)
|
||||||
|
{
|
||||||
|
xfb = $", xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}";
|
||||||
|
}
|
||||||
|
|
||||||
|
context.AppendLine($"layout (location = {attr}{xfb}) out {type} {name};");
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
for (int c = 0; c < 4; c++)
|
for (int c = 0; c < 4; c++)
|
||||||
{
|
{
|
||||||
@@ -610,7 +640,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
string xfb = string.Empty;
|
string xfb = string.Empty;
|
||||||
|
|
||||||
var tfOutput = context.GetTransformFeedbackOutput(attr, c);
|
var tfOutput = context.Info.GetTransformFeedbackOutput(attrOffset + c * 4);
|
||||||
if (tfOutput.Valid)
|
if (tfOutput.Valid)
|
||||||
{
|
{
|
||||||
xfb = $", xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}";
|
xfb = $", xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}";
|
||||||
@@ -619,6 +649,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
context.AppendLine($"layout (location = {attr}, component = {c}{xfb}) out float {name}_{swzMask};");
|
context.AppendLine($"layout (location = {attr}, component = {c}{xfb}) out float {name}_{swzMask};");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
context.AppendLine($"layout (location = {attr}) out vec4 {name};");
|
context.AppendLine($"layout (location = {attr}) out vec4 {name};");
|
||||||
@@ -627,7 +658,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
private static void DeclareUsedOutputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
private static void DeclareUsedOutputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
||||||
{
|
{
|
||||||
foreach (int attr in attrs.OrderBy(x => x))
|
foreach (int attr in attrs.Order())
|
||||||
{
|
{
|
||||||
DeclareOutputAttributePerPatch(context, attr);
|
DeclareOutputAttributePerPatch(context, attr);
|
||||||
}
|
}
|
||||||
|
@@ -134,7 +134,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
if (assignment.Destination is AstOperand operand && operand.Type.IsAttribute())
|
if (assignment.Destination is AstOperand operand && operand.Type.IsAttribute())
|
||||||
{
|
{
|
||||||
bool perPatch = operand.Type == OperandType.AttributePerPatch;
|
bool perPatch = operand.Type == OperandType.AttributePerPatch;
|
||||||
dest = OperandManager.GetOutAttributeName(operand.Value, context.Config, perPatch);
|
dest = OperandManager.GetOutAttributeName(context, operand.Value, perPatch);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
|||||||
}
|
}
|
||||||
else if (node is AstOperand operand)
|
else if (node is AstOperand operand)
|
||||||
{
|
{
|
||||||
return context.OperandManager.GetExpression(operand, context.Config);
|
return context.OperandManager.GetExpression(context, operand);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\".");
|
throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\".");
|
||||||
|
@@ -205,7 +205,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
|||||||
if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
|
if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
|
||||||
{
|
{
|
||||||
int attrOffset = baseAttr.Value + (operand.Value << 2);
|
int attrOffset = baseAttr.Value + (operand.Value << 2);
|
||||||
return OperandManager.GetAttributeName(attrOffset, context.Config, perPatch: false, isOutAttr: false, indexExpr);
|
return OperandManager.GetAttributeName(context, attrOffset, perPatch: false, isOutAttr: false, indexExpr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -332,7 +332,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
|||||||
if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
|
if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
|
||||||
{
|
{
|
||||||
int attrOffset = baseAttr.Value + (operand.Value << 2);
|
int attrOffset = baseAttr.Value + (operand.Value << 2);
|
||||||
attrName = OperandManager.GetAttributeName(attrOffset, context.Config, perPatch: false, isOutAttr: true);
|
attrName = OperandManager.GetAttributeName(context, attrOffset, perPatch: false, isOutAttr: true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -48,6 +48,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
{ AttributeConsts.TessCoordY, new BuiltInAttribute("gl_TessCoord.y", VariableType.F32) },
|
{ AttributeConsts.TessCoordY, new BuiltInAttribute("gl_TessCoord.y", VariableType.F32) },
|
||||||
{ AttributeConsts.InstanceId, new BuiltInAttribute("gl_InstanceID", VariableType.S32) },
|
{ AttributeConsts.InstanceId, new BuiltInAttribute("gl_InstanceID", VariableType.S32) },
|
||||||
{ AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", VariableType.S32) },
|
{ AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", VariableType.S32) },
|
||||||
|
{ AttributeConsts.BaseInstance, new BuiltInAttribute("gl_BaseInstanceARB", VariableType.S32) },
|
||||||
|
{ AttributeConsts.BaseVertex, new BuiltInAttribute("gl_BaseVertexARB", VariableType.S32) },
|
||||||
|
{ AttributeConsts.InstanceIndex, new BuiltInAttribute("gl_InstanceIndex", VariableType.S32) },
|
||||||
|
{ AttributeConsts.VertexIndex, new BuiltInAttribute("gl_VertexIndex", VariableType.S32) },
|
||||||
|
{ AttributeConsts.DrawIndex, new BuiltInAttribute("gl_DrawIDARB", VariableType.S32) },
|
||||||
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) },
|
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) },
|
||||||
|
|
||||||
// Special.
|
// Special.
|
||||||
@@ -99,15 +104,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetExpression(AstOperand operand, ShaderConfig config)
|
public string GetExpression(CodeGenContext context, AstOperand operand)
|
||||||
{
|
{
|
||||||
return operand.Type switch
|
return operand.Type switch
|
||||||
{
|
{
|
||||||
OperandType.Argument => GetArgumentName(operand.Value),
|
OperandType.Argument => GetArgumentName(operand.Value),
|
||||||
OperandType.Attribute => GetAttributeName(operand.Value, config, perPatch: false),
|
OperandType.Attribute => GetAttributeName(context, operand.Value, perPatch: false),
|
||||||
OperandType.AttributePerPatch => GetAttributeName(operand.Value, config, perPatch: true),
|
OperandType.AttributePerPatch => GetAttributeName(context, operand.Value, perPatch: true),
|
||||||
OperandType.Constant => NumberFormatter.FormatInt(operand.Value),
|
OperandType.Constant => NumberFormatter.FormatInt(operand.Value),
|
||||||
OperandType.ConstantBuffer => GetConstantBufferName(operand, config),
|
OperandType.ConstantBuffer => GetConstantBufferName(operand, context.Config),
|
||||||
OperandType.LocalVariable => _locals[operand],
|
OperandType.LocalVariable => _locals[operand],
|
||||||
OperandType.Undefined => DefaultNames.UndefinedName,
|
OperandType.Undefined => DefaultNames.UndefinedName,
|
||||||
_ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".")
|
_ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".")
|
||||||
@@ -149,13 +154,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
return GetVec4Indexed(GetUbName(stage, slotExpr) + $"[{offsetExpr} >> 2]", offsetExpr + " & 3", indexElement);
|
return GetVec4Indexed(GetUbName(stage, slotExpr) + $"[{offsetExpr} >> 2]", offsetExpr + " & 3", indexElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetOutAttributeName(int value, ShaderConfig config, bool perPatch)
|
public static string GetOutAttributeName(CodeGenContext context, int value, bool perPatch)
|
||||||
{
|
{
|
||||||
return GetAttributeName(value, config, perPatch, isOutAttr: true);
|
return GetAttributeName(context, value, perPatch, isOutAttr: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetAttributeName(int value, ShaderConfig config, bool perPatch, bool isOutAttr = false, string indexExpr = "0")
|
public static string GetAttributeName(CodeGenContext context, int value, bool perPatch, bool isOutAttr = false, string indexExpr = "0")
|
||||||
{
|
{
|
||||||
|
ShaderConfig config = context.Config;
|
||||||
|
|
||||||
if ((value & AttributeConsts.LoadOutputMask) != 0)
|
if ((value & AttributeConsts.LoadOutputMask) != 0)
|
||||||
{
|
{
|
||||||
isOutAttr = true;
|
isOutAttr = true;
|
||||||
@@ -188,6 +195,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
}
|
}
|
||||||
else if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
|
else if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
|
||||||
{
|
{
|
||||||
|
int attrOffset = value;
|
||||||
value -= AttributeConsts.UserAttributeBase;
|
value -= AttributeConsts.UserAttributeBase;
|
||||||
|
|
||||||
string prefix = isOutAttr
|
string prefix = isOutAttr
|
||||||
@@ -211,14 +219,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
((config.LastInVertexPipeline && isOutAttr) ||
|
((config.LastInVertexPipeline && isOutAttr) ||
|
||||||
(config.Stage == ShaderStage.Fragment && !isOutAttr)))
|
(config.Stage == ShaderStage.Fragment && !isOutAttr)))
|
||||||
{
|
{
|
||||||
string name = $"{prefix}{(value >> 4)}_{swzMask}";
|
int components = config.LastInPipeline ? context.Info.GetTransformFeedbackOutputComponents(attrOffset) : 1;
|
||||||
|
string name = components > 1 ? $"{prefix}{(value >> 4)}" : $"{prefix}{(value >> 4)}_{swzMask}";
|
||||||
|
|
||||||
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||||
{
|
{
|
||||||
name += isOutAttr ? "[gl_InvocationID]" : $"[{indexExpr}]";
|
name += isOutAttr ? "[gl_InvocationID]" : $"[{indexExpr}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
return name;
|
return components > 1 ? name + '.' + swzMask : name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
private const uint SpirvVersionRevision = 0;
|
private const uint SpirvVersionRevision = 0;
|
||||||
private const uint SpirvVersionPacked = (SpirvVersionMajor << 16) | (SpirvVersionMinor << 8) | SpirvVersionRevision;
|
private const uint SpirvVersionPacked = (SpirvVersionMajor << 16) | (SpirvVersionMinor << 8) | SpirvVersionRevision;
|
||||||
|
|
||||||
private readonly StructuredProgramInfo _info;
|
public StructuredProgramInfo Info { get; }
|
||||||
|
|
||||||
public ShaderConfig Config { get; }
|
public ShaderConfig Config { get; }
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
GeneratorPool<Instruction> instPool,
|
GeneratorPool<Instruction> instPool,
|
||||||
GeneratorPool<LiteralInteger> integerPool) : base(SpirvVersionPacked, instPool, integerPool)
|
GeneratorPool<LiteralInteger> integerPool) : base(SpirvVersionPacked, instPool, integerPool)
|
||||||
{
|
{
|
||||||
_info = info;
|
Info = info;
|
||||||
Config = config;
|
Config = config;
|
||||||
|
|
||||||
if (config.Stage == ShaderStage.Geometry)
|
if (config.Stage == ShaderStage.Geometry)
|
||||||
@@ -262,6 +262,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
Instruction ioVariable, elemIndex;
|
Instruction ioVariable, elemIndex;
|
||||||
|
|
||||||
|
Instruction invocationId = null;
|
||||||
|
|
||||||
|
if (Config.Stage == ShaderStage.TessellationControl && isOutAttr)
|
||||||
|
{
|
||||||
|
invocationId = Load(TypeS32(), Inputs[AttributeConsts.InvocationId]);
|
||||||
|
}
|
||||||
|
|
||||||
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
||||||
|
|
||||||
if (isUserAttr &&
|
if (isUserAttr &&
|
||||||
@@ -273,7 +280,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
||||||
var vecIndex = Constant(TypeU32(), (attr - AttributeConsts.UserAttributeBase) >> 4);
|
var vecIndex = Constant(TypeU32(), (attr - AttributeConsts.UserAttributeBase) >> 4);
|
||||||
|
|
||||||
if (AttributeInfo.IsArrayAttributeSpirv(Config.Stage, isOutAttr))
|
bool isArray = AttributeInfo.IsArrayAttributeSpirv(Config.Stage, isOutAttr);
|
||||||
|
|
||||||
|
if (invocationId != null && isArray)
|
||||||
|
{
|
||||||
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, index, vecIndex, elemIndex);
|
||||||
|
}
|
||||||
|
else if (invocationId != null)
|
||||||
|
{
|
||||||
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, vecIndex, elemIndex);
|
||||||
|
}
|
||||||
|
else if (isArray)
|
||||||
{
|
{
|
||||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, vecIndex, elemIndex);
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, vecIndex, elemIndex);
|
||||||
}
|
}
|
||||||
@@ -300,6 +317,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
{
|
{
|
||||||
attrOffset = attr;
|
attrOffset = attr;
|
||||||
type = elemType;
|
type = elemType;
|
||||||
|
|
||||||
|
if (Config.LastInPipeline && isOutAttr)
|
||||||
|
{
|
||||||
|
int components = Info.GetTransformFeedbackOutputComponents(attr);
|
||||||
|
|
||||||
|
if (components > 1)
|
||||||
|
{
|
||||||
|
attrOffset &= ~0xf;
|
||||||
|
type = AggregateType.Vector | AggregateType.FP32;
|
||||||
|
attrInfo = new AttributeInfo(attrOffset, (attr - attrOffset) / 4, components, type, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ioVariable = isOutAttr ? Outputs[attrOffset] : Inputs[attrOffset];
|
ioVariable = isOutAttr ? Outputs[attrOffset] : Inputs[attrOffset];
|
||||||
@@ -307,13 +336,30 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
bool isIndexed = AttributeInfo.IsArrayAttributeSpirv(Config.Stage, isOutAttr) && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr));
|
bool isIndexed = AttributeInfo.IsArrayAttributeSpirv(Config.Stage, isOutAttr) && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr));
|
||||||
|
|
||||||
if ((type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
if ((type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
||||||
|
{
|
||||||
|
if (invocationId != null)
|
||||||
|
{
|
||||||
|
return isIndexed
|
||||||
|
? AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, index)
|
||||||
|
: AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return isIndexed ? AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index) : ioVariable;
|
return isIndexed ? AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index) : ioVariable;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
||||||
|
|
||||||
if (isIndexed)
|
if (invocationId != null && isIndexed)
|
||||||
|
{
|
||||||
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, index, elemIndex);
|
||||||
|
}
|
||||||
|
else if (invocationId != null)
|
||||||
|
{
|
||||||
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, elemIndex);
|
||||||
|
}
|
||||||
|
else if (isIndexed)
|
||||||
{
|
{
|
||||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, elemIndex);
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, elemIndex);
|
||||||
}
|
}
|
||||||
@@ -327,12 +373,29 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
{
|
{
|
||||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||||
|
|
||||||
|
Instruction invocationId = null;
|
||||||
|
|
||||||
|
if (Config.Stage == ShaderStage.TessellationControl && isOutAttr)
|
||||||
|
{
|
||||||
|
invocationId = Load(TypeS32(), Inputs[AttributeConsts.InvocationId]);
|
||||||
|
}
|
||||||
|
|
||||||
elemType = AggregateType.FP32;
|
elemType = AggregateType.FP32;
|
||||||
var ioVariable = isOutAttr ? OutputsArray : InputsArray;
|
var ioVariable = isOutAttr ? OutputsArray : InputsArray;
|
||||||
var vecIndex = ShiftRightLogical(TypeS32(), attrIndex, Constant(TypeS32(), 2));
|
var vecIndex = ShiftRightLogical(TypeS32(), attrIndex, Constant(TypeS32(), 2));
|
||||||
var elemIndex = BitwiseAnd(TypeS32(), attrIndex, Constant(TypeS32(), 3));
|
var elemIndex = BitwiseAnd(TypeS32(), attrIndex, Constant(TypeS32(), 3));
|
||||||
|
|
||||||
if (AttributeInfo.IsArrayAttributeSpirv(Config.Stage, isOutAttr))
|
bool isArray = AttributeInfo.IsArrayAttributeSpirv(Config.Stage, isOutAttr);
|
||||||
|
|
||||||
|
if (invocationId != null && isArray)
|
||||||
|
{
|
||||||
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, index, vecIndex, elemIndex);
|
||||||
|
}
|
||||||
|
else if (invocationId != null)
|
||||||
|
{
|
||||||
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, vecIndex, elemIndex);
|
||||||
|
}
|
||||||
|
else if (isArray)
|
||||||
{
|
{
|
||||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, vecIndex, elemIndex);
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, vecIndex, elemIndex);
|
||||||
}
|
}
|
||||||
@@ -485,18 +548,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
return _functions[funcIndex];
|
return _functions[funcIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransformFeedbackOutput GetTransformFeedbackOutput(int location, int component)
|
|
||||||
{
|
|
||||||
int index = (AttributeConsts.UserAttributeBase / 4) + location * 4 + component;
|
|
||||||
return _info.TransformFeedbackOutputs[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public TransformFeedbackOutput GetTransformFeedbackOutput(int location)
|
|
||||||
{
|
|
||||||
int index = location / 4;
|
|
||||||
return _info.TransformFeedbackOutputs[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instruction GetType(AggregateType type, int length = 1)
|
public Instruction GetType(AggregateType type, int length = 1)
|
||||||
{
|
{
|
||||||
if (type.HasFlag(AggregateType.Array))
|
if (type.HasFlag(AggregateType.Array))
|
||||||
|
@@ -440,12 +440,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
{
|
{
|
||||||
PixelImap iq = PixelImap.Unused;
|
PixelImap iq = PixelImap.Unused;
|
||||||
|
|
||||||
if (context.Config.Stage == ShaderStage.Fragment &&
|
if (context.Config.Stage == ShaderStage.Fragment)
|
||||||
attr >= AttributeConsts.UserAttributeBase &&
|
{
|
||||||
attr < AttributeConsts.UserAttributeEnd)
|
if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
|
||||||
{
|
{
|
||||||
iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType();
|
iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AttributeInfo attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr: false);
|
||||||
|
AggregateType elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||||
|
|
||||||
|
if (attrInfo.IsBuiltin && (elemType == AggregateType.S32 || elemType == AggregateType.U32))
|
||||||
|
{
|
||||||
|
iq = PixelImap.Constant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DeclareInputOrOutput(context, attr, perPatch, isOutAttr: false, iq);
|
DeclareInputOrOutput(context, attr, perPatch, isOutAttr: false, iq);
|
||||||
}
|
}
|
||||||
@@ -473,6 +484,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
|
var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
|
||||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
|
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
|
||||||
|
|
||||||
|
if (context.Config.Stage == ShaderStage.TessellationControl)
|
||||||
|
{
|
||||||
|
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive));
|
||||||
|
}
|
||||||
|
|
||||||
var spvType = context.TypePointer(StorageClass.Output, attrType);
|
var spvType = context.TypePointer(StorageClass.Output, attrType);
|
||||||
var spvVar = context.Variable(spvType, StorageClass.Output);
|
var spvVar = context.Variable(spvType, StorageClass.Output);
|
||||||
|
|
||||||
@@ -511,7 +527,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
((isOutAttr && context.Config.LastInVertexPipeline) ||
|
((isOutAttr && context.Config.LastInVertexPipeline) ||
|
||||||
(!isOutAttr && context.Config.Stage == ShaderStage.Fragment)))
|
(!isOutAttr && context.Config.Stage == ShaderStage.Fragment)))
|
||||||
{
|
{
|
||||||
DeclareInputOrOutput(context, attr, (attr >> 2) & 3, isOutAttr, iq);
|
DeclareTransformFeedbackInputOrOutput(context, attr, isOutAttr, iq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,6 +559,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.Config.Stage == ShaderStage.TessellationControl && isOutAttr && !perPatch)
|
||||||
|
{
|
||||||
|
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive));
|
||||||
|
}
|
||||||
|
|
||||||
var spvType = context.TypePointer(storageClass, attrType);
|
var spvType = context.TypePointer(storageClass, attrType);
|
||||||
var spvVar = context.Variable(spvType, storageClass);
|
var spvVar = context.Variable(spvType, storageClass);
|
||||||
|
|
||||||
@@ -562,7 +583,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline && isOutAttr)
|
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline && isOutAttr)
|
||||||
{
|
{
|
||||||
var tfOutput = context.GetTransformFeedbackOutput(attrInfo.BaseValue);
|
var tfOutput = context.Info.GetTransformFeedbackOutput(attrInfo.BaseValue);
|
||||||
if (tfOutput.Valid)
|
if (tfOutput.Valid)
|
||||||
{
|
{
|
||||||
context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
|
context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
|
||||||
@@ -585,15 +606,22 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||||
|
|
||||||
if (!isOutAttr)
|
if (!isOutAttr &&
|
||||||
{
|
!perPatch &&
|
||||||
if (!perPatch &&
|
|
||||||
(context.Config.PassthroughAttributes & (1 << location)) != 0 &&
|
(context.Config.PassthroughAttributes & (1 << location)) != 0 &&
|
||||||
context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||||
{
|
{
|
||||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (attr >= AttributeConsts.FragmentOutputColorBase && attr < AttributeConsts.FragmentOutputColorEnd)
|
||||||
|
{
|
||||||
|
int location = (attr - AttributeConsts.FragmentOutputColorBase) / 16;
|
||||||
|
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isOutAttr)
|
||||||
|
{
|
||||||
switch (iq)
|
switch (iq)
|
||||||
{
|
{
|
||||||
case PixelImap.Constant:
|
case PixelImap.Constant:
|
||||||
@@ -604,29 +632,40 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (attr >= AttributeConsts.FragmentOutputColorBase && attr < AttributeConsts.FragmentOutputColorEnd)
|
|
||||||
{
|
|
||||||
int location = (attr - AttributeConsts.FragmentOutputColorBase) / 16;
|
|
||||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.AddGlobalVariable(spvVar);
|
context.AddGlobalVariable(spvVar);
|
||||||
dict.Add(attrInfo.BaseValue, spvVar);
|
dict.Add(attrInfo.BaseValue, spvVar);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeclareInputOrOutput(CodeGenContext context, int attr, int component, bool isOutAttr, PixelImap iq = PixelImap.Unused)
|
private static void DeclareTransformFeedbackInputOrOutput(CodeGenContext context, int attr, bool isOutAttr, PixelImap iq = PixelImap.Unused)
|
||||||
{
|
{
|
||||||
var dict = isOutAttr ? context.Outputs : context.Inputs;
|
var dict = isOutAttr ? context.Outputs : context.Inputs;
|
||||||
var attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr);
|
var attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr);
|
||||||
|
|
||||||
|
bool hasComponent = true;
|
||||||
|
int component = (attr >> 2) & 3;
|
||||||
|
int components = 1;
|
||||||
|
var type = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||||
|
|
||||||
|
if (context.Config.LastInPipeline && isOutAttr)
|
||||||
|
{
|
||||||
|
components = context.Info.GetTransformFeedbackOutputComponents(attr);
|
||||||
|
|
||||||
|
if (components > 1)
|
||||||
|
{
|
||||||
|
attr &= ~0xf;
|
||||||
|
type = AggregateType.Vector | AggregateType.FP32;
|
||||||
|
hasComponent = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dict.ContainsKey(attr))
|
if (dict.ContainsKey(attr))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||||
var attrType = context.GetType(attrInfo.Type & AggregateType.ElementTypeMask);
|
var attrType = context.GetType(type, components);
|
||||||
|
|
||||||
if (AttributeInfo.IsArrayAttributeSpirv(context.Config.Stage, isOutAttr) && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
|
if (AttributeInfo.IsArrayAttributeSpirv(context.Config.Stage, isOutAttr) && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
|
||||||
{
|
{
|
||||||
@@ -634,6 +673,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)arraySize));
|
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)arraySize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.Config.Stage == ShaderStage.TessellationControl && isOutAttr)
|
||||||
|
{
|
||||||
|
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive));
|
||||||
|
}
|
||||||
|
|
||||||
var spvType = context.TypePointer(storageClass, attrType);
|
var spvType = context.TypePointer(storageClass, attrType);
|
||||||
var spvVar = context.Variable(spvType, storageClass);
|
var spvVar = context.Variable(spvType, storageClass);
|
||||||
|
|
||||||
@@ -641,11 +685,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
int location = (attr - AttributeConsts.UserAttributeBase) / 16;
|
int location = (attr - AttributeConsts.UserAttributeBase) / 16;
|
||||||
|
|
||||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||||
|
|
||||||
|
if (hasComponent)
|
||||||
|
{
|
||||||
context.Decorate(spvVar, Decoration.Component, (LiteralInteger)component);
|
context.Decorate(spvVar, Decoration.Component, (LiteralInteger)component);
|
||||||
|
}
|
||||||
|
|
||||||
if (isOutAttr)
|
if (isOutAttr)
|
||||||
{
|
{
|
||||||
var tfOutput = context.GetTransformFeedbackOutput(location, component);
|
var tfOutput = context.Info.GetTransformFeedbackOutput(attr);
|
||||||
if (tfOutput.Valid)
|
if (tfOutput.Valid)
|
||||||
{
|
{
|
||||||
context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
|
context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
|
||||||
@@ -689,8 +737,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
AttributeConsts.ClipDistance0 => BuiltIn.ClipDistance,
|
AttributeConsts.ClipDistance0 => BuiltIn.ClipDistance,
|
||||||
AttributeConsts.PointCoordX => BuiltIn.PointCoord,
|
AttributeConsts.PointCoordX => BuiltIn.PointCoord,
|
||||||
AttributeConsts.TessCoordX => BuiltIn.TessCoord,
|
AttributeConsts.TessCoordX => BuiltIn.TessCoord,
|
||||||
AttributeConsts.InstanceId => BuiltIn.InstanceId, // FIXME: Invalid
|
AttributeConsts.InstanceId => BuiltIn.InstanceId,
|
||||||
AttributeConsts.VertexId => BuiltIn.VertexId, // FIXME: Invalid
|
AttributeConsts.VertexId => BuiltIn.VertexId,
|
||||||
|
AttributeConsts.BaseInstance => BuiltIn.BaseInstance,
|
||||||
|
AttributeConsts.BaseVertex => BuiltIn.BaseVertex,
|
||||||
|
AttributeConsts.InstanceIndex => BuiltIn.InstanceIndex,
|
||||||
|
AttributeConsts.VertexIndex => BuiltIn.VertexIndex,
|
||||||
|
AttributeConsts.DrawIndex => BuiltIn.DrawIndex,
|
||||||
AttributeConsts.FrontFacing => BuiltIn.FrontFacing,
|
AttributeConsts.FrontFacing => BuiltIn.FrontFacing,
|
||||||
AttributeConsts.FragmentOutputDepth => BuiltIn.FragDepth,
|
AttributeConsts.FragmentOutputDepth => BuiltIn.FragDepth,
|
||||||
AttributeConsts.ThreadKill => BuiltIn.HelperInvocation,
|
AttributeConsts.ThreadKill => BuiltIn.HelperInvocation,
|
||||||
|
@@ -62,11 +62,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
context.AddCapability(Capability.TransformFeedback);
|
context.AddCapability(Capability.TransformFeedback);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
|
if (config.Stage == ShaderStage.Fragment)
|
||||||
|
{
|
||||||
|
if (context.Info.Inputs.Contains(AttributeConsts.Layer))
|
||||||
|
{
|
||||||
|
context.AddCapability(Capability.Geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
|
||||||
{
|
{
|
||||||
context.AddCapability(Capability.FragmentShaderPixelInterlockEXT);
|
context.AddCapability(Capability.FragmentShaderPixelInterlockEXT);
|
||||||
context.AddExtension("SPV_EXT_fragment_shader_interlock");
|
context.AddExtension("SPV_EXT_fragment_shader_interlock");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (config.Stage == ShaderStage.Geometry)
|
else if (config.Stage == ShaderStage.Geometry)
|
||||||
{
|
{
|
||||||
context.AddCapability(Capability.Geometry);
|
context.AddCapability(Capability.Geometry);
|
||||||
@@ -81,6 +89,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
{
|
{
|
||||||
context.AddCapability(Capability.Tessellation);
|
context.AddCapability(Capability.Tessellation);
|
||||||
}
|
}
|
||||||
|
else if (config.Stage == ShaderStage.Vertex)
|
||||||
|
{
|
||||||
|
context.AddCapability(Capability.DrawParameters);
|
||||||
|
}
|
||||||
|
|
||||||
context.AddExtension("SPV_KHR_shader_ballot");
|
context.AddExtension("SPV_KHR_shader_ballot");
|
||||||
context.AddExtension("SPV_KHR_subgroup_vote");
|
context.AddExtension("SPV_KHR_subgroup_vote");
|
||||||
|
@@ -6,5 +6,9 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
|
|
||||||
public const int MaxAttributes = 16;
|
public const int MaxAttributes = 16;
|
||||||
public const int AllAttributesMask = (int)(uint.MaxValue >> (32 - MaxAttributes));
|
public const int AllAttributesMask = (int)(uint.MaxValue >> (32 - MaxAttributes));
|
||||||
|
|
||||||
|
public const int NvnBaseVertexByteOffset = 0x640;
|
||||||
|
public const int NvnBaseInstanceByteOffset = 0x644;
|
||||||
|
public const int NvnDrawIndexByteOffset = 0x648;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -377,6 +377,8 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||||||
|
|
||||||
if (lastOp.Name == InstName.Brx && block.Successors.Count == (hasNext ? 1 : 0))
|
if (lastOp.Name == InstName.Brx && block.Successors.Count == (hasNext ? 1 : 0))
|
||||||
{
|
{
|
||||||
|
HashSet<ulong> visited = new HashSet<ulong>();
|
||||||
|
|
||||||
InstBrx opBrx = new InstBrx(lastOp.RawOpCode);
|
InstBrx opBrx = new InstBrx(lastOp.RawOpCode);
|
||||||
ulong baseOffset = lastOp.GetAbsoluteAddress();
|
ulong baseOffset = lastOp.GetAbsoluteAddress();
|
||||||
|
|
||||||
@@ -392,12 +394,17 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||||||
for (int i = 0; i < cbOffsetsCount; i++)
|
for (int i = 0; i < cbOffsetsCount; i++)
|
||||||
{
|
{
|
||||||
uint targetOffset = config.ConstantBuffer1Read(cbBaseOffset + i * 4);
|
uint targetOffset = config.ConstantBuffer1Read(cbBaseOffset + i * 4);
|
||||||
Block target = getBlock(baseOffset + targetOffset);
|
ulong targetAddress = baseOffset + targetOffset;
|
||||||
|
|
||||||
|
if (visited.Add(targetAddress))
|
||||||
|
{
|
||||||
|
Block target = getBlock(targetAddress);
|
||||||
target.Predecessors.Add(block);
|
target.Predecessors.Add(block);
|
||||||
block.Successors.Add(target);
|
block.Successors.Add(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return hasNewTarget;
|
return hasNewTarget;
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user