Compare commits

...

19 Commits

Author SHA1 Message Date
gdkchan
44862dce3e Stub unsupported BSD socket options (#5670)
* Stub unsupported BSD socket options

* Span.Clear
2023-09-19 19:35:56 +02:00
Emmanuel Hansen
e601419bd4 make cheat list binding public (#5697) 2023-09-19 16:51:56 +00:00
Emmanuel Hansen
d6bc0de785 use compiled bidning for localizations (#5684) 2023-09-18 22:20:59 +02:00
Emmanuel Hansen
9f26fd3600 remove some usages of reflection binding (#5686) 2023-09-18 22:09:22 +02:00
gdkchan
88df636c87 Replace ShaderOutputLayer with equivalent ShaderViewportIndexLayerEXT capability (#5683) 2023-09-16 18:49:13 +02:00
gdkchan
7ccff037e8 Fix some Vulkan validation errors (mostly related to barriers) (#5603)
* Replace image barriers inside render pass with more generic memory barrier

* Remove forceStorage since it was creating images with storage bit for formats that are not StorageImage compatible

* Add missing flags on subpass dependency

* Don't call vkCmdSetScissor with a scissor count of 0

* One semaphore per swapchain image

* Remove compute stage from read to write barriers

* Try to improve Pipeline.Barrier nonsense

* Set PipelineStateFlags based on supported stages
2023-09-14 19:58:11 +02:00
gdkchan
a745913329 Fix gl_Layer to geometry shader change not writing gl_Layer (#5682)
* Fix gl_Layer to geometry shader change not writing gl_Layer

* Shader cache version bump
2023-09-14 14:53:53 -03:00
Ac_K
e6700b314f lbl: Migrate service to Horizon (#5628)
* lbl: Migrate service to Horizon

* Fix formatting

* Addresses gdkchan's feedback

* Fix comments
2023-09-14 09:50:19 +02:00
gdkchan
e2cfe6fe44 Fix shader GlobalToStorage pass when base address comes from local or shared memory (#5668)
* Fix shader GlobalToStorage pass when base address comes from local or shared memory

* Shader cache version bump
2023-09-11 01:22:18 +00:00
Marco Carvalho
210f475484 Replacing 'Assembly.GetExecutingAssembly()' with 'Type.Assembly' (#5545) 2023-09-07 14:10:58 +02:00
gdkchan
ddb6493896 Delete ResourceAccess (#5626)
* Delete ResourceAccess

* Set write flag for vertex/geometry as compute output buffers
2023-09-05 22:59:21 +02:00
siegmund-heiss-ich
f631933e60 Add macOS Headless release workflow (#5272)
* Add macOS Headless release workflow

* Add MACH-O check before applying signature

* Rename script for consistency

* Remove redundant compiler flag

* Fix release.yml arguments + names

* Update headless.sh to include changes of pr #5398
2023-09-05 01:28:44 +02:00
gdkchan
5ff6ea6d82 Fix ShaderTools GpuAcessor default values (#5646) 2023-09-05 01:16:09 +02:00
gdkchan
c2d9c6955d Fix layer size for 3D textures with NPOT depth (#5640) 2023-09-04 20:14:08 -03:00
TSRBerry
fbe0c211c1 Use poetry run instead of spawning a shell (#5653) 2023-09-05 00:55:04 +02:00
dependabot[bot]
db0f3c0b74 ci: bump actions/checkout from 3 to 4 (#5650)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-04 22:16:17 +02:00
TSRBerry
34447d7359 Fix overwriting .ryujinx-mako directory (#5651) 2023-09-04 19:14:20 +02:00
TSRBerry
5f771f5661 Update reviewers using Ryujinx-Mako command (#5635)
* Update reviewers using Ryujinx-Mako command

* Fix worklflow step 'uses' path
2023-09-04 11:39:25 +00:00
riperiperi
93cd327873 Vulkan: Device Local and higher invocation count for buffer conversions (#5623)
Just some simple changes to the buffer conversion shaders. (stride conversion, D32S8 to D24S8)

The first change is using a device local buffer for converted vertex buffers, since they're only read/written on the GPU. These paths don't trigger on NVIDIA, but if you force them to use it demonstrates the full extent writing to host owned memory from compute absolutely destroys them. AMD GPUs are less heavily affected by this issue, but since the game in question was writing 230MB from compute, I imagine it should have some effect.

The second change is allowing the buffer conversion shaders to scale their work group count. While dividing the work between 32 invocations works OK for M1 macs, it's not so great for anything with more cores like AMD GPUs, which should be able to do a lot more parallel copies. Now, it scales by roughly 100 elements per invocation.

Some stride change cases could be improved further by either limiting vertex buffer size somehow (reading the index buffer could help, but is always risky) or only updating regions that changed, rather than invalidating the whole thing.
2023-09-02 17:58:15 -03:00
67 changed files with 923 additions and 496 deletions

View File

@@ -1,87 +0,0 @@
from pathlib import Path
from typing import List, Set
from github import Auth, Github
from github.Repository import Repository
from github.GithubException import GithubException
import os
import sys
import yaml
def add_reviewers(
reviewers: Set[str], team_reviewers: Set[str], new_entries: List[str]
):
for reviewer in new_entries:
if reviewer.startswith("@"):
team_reviewers.add(reviewer[1:])
else:
reviewers.add(reviewer)
def update_reviewers(config, repo: Repository, pr_id: int) -> int:
pull_request = repo.get_pull(pr_id)
if not pull_request:
sys.stderr.writable(f"Unknown PR #{pr_id}\n")
return 1
if pull_request.draft:
print("Not assigning reviewers for draft PRs")
return 0
pull_request_author = pull_request.user.login
reviewers = set()
team_reviewers = set()
for label in pull_request.labels:
if label.name in config:
add_reviewers(reviewers, team_reviewers, config[label.name])
if "default" in config:
add_reviewers(reviewers, team_reviewers, config["default"])
if pull_request_author in reviewers:
reviewers.remove(pull_request_author)
try:
reviewers = list(reviewers)
team_reviewers = list(team_reviewers)
print(
f"Attempting to assign reviewers ({reviewers}) and team_reviewers ({team_reviewers})"
)
pull_request.create_review_request(reviewers, team_reviewers)
return 0
except GithubException as e:
sys.stderr.write(f"Cannot assign review request for PR #{pr_id}: {e}\n")
return 1
if __name__ == "__main__":
if len(sys.argv) != 7:
sys.stderr.write("usage: <app_id> <private_key_env_name> <installation_id> <repo_path> <pr_id> <config_path>\n")
sys.exit(1)
app_id = int(sys.argv[1])
private_key = os.environ[sys.argv[2]]
installation_id = int(sys.argv[3])
repo_path = sys.argv[4]
pr_id = int(sys.argv[5])
config_path = Path(sys.argv[6])
auth = Auth.AppAuth(app_id, private_key).get_installation_auth(installation_id)
g = Github(auth=auth)
repo = g.get_repo(repo_path)
if not repo:
sys.stderr.write("Repository not found!\n")
sys.exit(1)
if not config_path.exists():
sys.stderr.write(f'Config "{config_path}" not found!\n')
sys.exit(1)
with open(config_path, "r") as f:
config = yaml.safe_load(f)
sys.exit(update_reviewers(config, repo, pr_id))

View File

@@ -35,7 +35,7 @@ jobs:
fail-fast: false fail-fast: false
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-dotnet@v3 - uses: actions/setup-dotnet@v3
with: with:
@@ -108,7 +108,7 @@ jobs:
configuration: [ Debug, Release ] configuration: [ Debug, Release ]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-dotnet@v3 - uses: actions/setup-dotnet@v3
with: with:
@@ -135,9 +135,13 @@ jobs:
id: git_short_hash id: git_short_hash
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
- name: Publish macOS - name: Publish macOS Ryujinx.Ava
run: | run: |
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER" ./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- name: Publish macOS Ryujinx.Headless.SDL2
run: |
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- name: Upload Ryujinx.Ava artifact - name: Upload Ryujinx.Ava artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -145,3 +149,10 @@ jobs:
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish_ava/*.tar.gz" path: "publish_ava/*.tar.gz"
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
- name: Upload Ryujinx.Headless.SDL2 artifact
uses: actions/upload-artifact@v3
with:
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish_headless/*.tar.gz"
if: github.event_name == 'pull_request'

View File

@@ -23,7 +23,7 @@ jobs:
format: format:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -24,7 +24,7 @@ jobs:
RYUJINX_VERSION: "${{ inputs.ryujinx_version }}" RYUJINX_VERSION: "${{ inputs.ryujinx_version }}"
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
path: Ryujinx path: Ryujinx
@@ -38,7 +38,7 @@ jobs:
run: | run: |
echo "git_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "git_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
repository: flathub/org.ryujinx.Ryujinx repository: flathub/org.ryujinx.Ryujinx
token: ${{ secrets.RYUJINX_BOT_PAT }} token: ${{ secrets.RYUJINX_BOT_PAT }}

View File

@@ -12,14 +12,24 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
# Grab sources to get update_reviewers.py and reviewers.yml # Grab sources to get latest labeler.yml
- name: Fetch sources - name: Fetch sources
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
# Ensure we pin the source origin as pull_request_target run under forks. # Ensure we pin the source origin as pull_request_target run under forks.
fetch-depth: 0 fetch-depth: 0
repository: Ryujinx/Ryujinx repository: Ryujinx/Ryujinx
ref: master ref: master
- name: Checkout Ryujinx-Mako
uses: actions/checkout@v4
with:
repository: Ryujinx/Ryujinx-Mako
ref: master
path: '.ryujinx-mako'
- name: Setup Ryujinx-Mako
uses: ./.ryujinx-mako/.github/actions/setup-mako
- name: Update labels based on changes - name: Update labels based on changes
uses: actions/labeler@v4 uses: actions/labeler@v4
@@ -27,11 +37,11 @@ jobs:
sync-labels: true sync-labels: true
dot: true dot: true
- run: pip3 install PyGithub
- name: Assign reviewers - name: Assign reviewers
run: | run: |
python3 .github/update_reviewers.py ${{ secrets.MAKO_APP_ID }} "MAKO_PRIVATE_KEY" ${{ secrets.MAKO_INSTALLATION_ID }} ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml poetry -n -C .ryujinx-mako run ryujinx-mako update-reviewers ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml
shell: bash shell: bash
env: env:
MAKO_APP_ID: ${{ secrets.MAKO_APP_ID }}
MAKO_PRIVATE_KEY: ${{ secrets.MAKO_PRIVATE_KEY }} MAKO_PRIVATE_KEY: ${{ secrets.MAKO_PRIVATE_KEY }}
MAKO_INSTALLATION_ID: ${{ secrets.MAKO_INSTALLATION_ID }}

View File

@@ -62,7 +62,7 @@ jobs:
DOTNET_RUNTIME_IDENTIFIER: win10-x64 DOTNET_RUNTIME_IDENTIFIER: win10-x64
RELEASE_ZIP_OS_NAME: win_x64 RELEASE_ZIP_OS_NAME: win_x64
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-dotnet@v3 - uses: actions/setup-dotnet@v3
with: with:
@@ -150,7 +150,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }} timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-dotnet@v3 - uses: actions/setup-dotnet@v3
with: with:
@@ -188,15 +188,19 @@ jobs:
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash shell: bash
- name: Publish macOS - name: Publish macOS Ryujinx.Ava
run: | run: |
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release ./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
- name: Publish macOS Ryujinx.Headless.SDL2
run: |
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
- name: Pushing new release - name: Pushing new release
uses: ncipollo/release-action@v1 uses: ncipollo/release-action@v1
with: with:
name: ${{ steps.version_info.outputs.build_version }} name: ${{ steps.version_info.outputs.build_version }}
artifacts: "publish_ava/*.tar.gz" artifacts: "publish_ava/*.tar.gz, publish_headless/*.tar.gz"
tag: ${{ steps.version_info.outputs.build_version }} tag: ${{ steps.version_info.outputs.build_version }}
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)." body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
omitBodyDuringUpdate: true omitBodyDuringUpdate: true

View File

@@ -0,0 +1,111 @@
#!/bin/bash
set -e
if [ "$#" -lt 7 ]; then
echo "usage <BASE_DIR> <TEMP_DIRECTORY> <OUTPUT_DIRECTORY> <ENTITLEMENTS_FILE_PATH> <VERSION> <SOURCE_REVISION_ID> <CONFIGURATION> <EXTRA_ARGS>"
exit 1
fi
mkdir -p "$1"
mkdir -p "$2"
mkdir -p "$3"
BASE_DIR=$(readlink -f "$1")
TEMP_DIRECTORY=$(readlink -f "$2")
OUTPUT_DIRECTORY=$(readlink -f "$3")
ENTITLEMENTS_FILE_PATH=$(readlink -f "$4")
VERSION=$5
SOURCE_REVISION_ID=$6
CONFIGURATION=$7
EXTRA_ARGS=$8
if [ "$VERSION" == "1.1.0" ];
then
RELEASE_TAR_FILE_NAME=sdl2-ryujinx-headless-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.tar
else
RELEASE_TAR_FILE_NAME=sdl2-ryujinx-headless-$VERSION-macos_universal.tar
fi
ARM64_OUTPUT="$TEMP_DIRECTORY/publish_arm64"
X64_OUTPUT="$TEMP_DIRECTORY/publish_x64"
UNIVERSAL_OUTPUT="$OUTPUT_DIRECTORY/publish"
EXECUTABLE_SUB_PATH=Ryujinx.Headless.SDL2
rm -rf "$TEMP_DIRECTORY"
mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
dotnet restore
dotnet build -c "$CONFIGURATION" src/Ryujinx.Headless.SDL2
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
# Get rid of libsoundio from arm64 builds as we don't have a arm64 variant
# TODO: remove this once done
rm -rf "$TEMP_DIRECTORY/publish_arm64/libsoundio.dylib"
rm -rf "$OUTPUT_DIRECTORY"
mkdir -p "$OUTPUT_DIRECTORY"
# Let's copy one of the two different outputs and remove the executable
cp -R "$ARM64_OUTPUT/" "$UNIVERSAL_OUTPUT"
rm "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH"
# Make it libraries universal
python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_OUTPUT" "$X64_OUTPUT" "$UNIVERSAL_OUTPUT" "**/*.dylib"
if ! [ -x "$(command -v lipo)" ];
then
if ! [ -x "$(command -v llvm-lipo-14)" ];
then
LIPO=llvm-lipo
else
LIPO=llvm-lipo-14
fi
else
LIPO=lipo
fi
# Make the executable universal
$LIPO "$ARM64_OUTPUT/$EXECUTABLE_SUB_PATH" "$X64_OUTPUT/$EXECUTABLE_SUB_PATH" -output "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH" -create
# Now sign it
if ! [ -x "$(command -v codesign)" ];
then
if ! [ -x "$(command -v rcodesign)" ];
then
echo "Cannot find rcodesign on your system, please install rcodesign."
exit 1
fi
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
echo "Using rcodesign for ad-hoc signing"
for FILE in "$UNIVERSAL_OUTPUT"/*; do
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$FILE"
fi
done
else
echo "Using codesign for ad-hoc signing"
for FILE in "$UNIVERSAL_OUTPUT"/*; do
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$FILE"
fi
done
fi
echo "Creating archive"
pushd "$OUTPUT_DIRECTORY"
tar --exclude "publish/Ryujinx.Headless.SDL2" -cvf "$RELEASE_TAR_FILE_NAME" publish 1> /dev/null
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
rm "$RELEASE_TAR_FILE_NAME"
popd
echo "Done"

View File

@@ -1,6 +1,7 @@
using Avalonia.Data; using Avalonia.Data.Core;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions; using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings;
using System; using System;
namespace Ryujinx.Ava.Common.Locale namespace Ryujinx.Ava.Common.Locale
@@ -18,11 +19,20 @@ namespace Ryujinx.Ava.Common.Locale
{ {
LocaleKeys keyToUse = Key; LocaleKeys keyToUse = Key;
ReflectionBindingExtension binding = new($"[{keyToUse}]") var builder = new CompiledBindingPathBuilder();
{
Mode = BindingMode.OneWay, builder.SetRawSource(LocaleManager.Instance)
Source = LocaleManager.Instance, .Property(new ClrPropertyInfo("Item",
}; obj => (LocaleManager.Instance[keyToUse]),
null,
typeof(string)), (weakRef, iPropInfo) =>
{
return PropertyInfoAccessorFactory.CreateInpcPropertyAccessor(weakRef, iPropInfo);
});
var path = builder.Build();
var binding = new CompiledBindingExtension(path);
return binding.ProvideValue(serviceProvider); return binding.ProvideValue(serviceProvider);
} }

View File

@@ -6,9 +6,11 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="{locale:Locale ErrorWindowTitle}" Title="{locale:Locale ErrorWindowTitle}"
xmlns:views="using:Ryujinx.Ava.UI.Applet"
Width="450" Width="450"
Height="340" Height="340"
CanResize="False" CanResize="False"
x:DataType="views:ErrorAppletWindow"
SizeToContent="Height" SizeToContent="Height"
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True"> Focusable="True">
@@ -38,7 +40,7 @@
Grid.Column="1" Grid.Column="1"
Margin="10" Margin="10"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Text="{ReflectionBinding Message}" Text="{Binding Message}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<StackPanel <StackPanel
Name="ButtonStack" Name="ButtonStack"
@@ -49,4 +51,4 @@
Orientation="Horizontal" Orientation="Horizontal"
Spacing="10" /> Spacing="10" />
</Grid> </Grid>
</Window> </Window>

View File

@@ -4,7 +4,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:Ryujinx.Ava.UI.Controls"
Width="400" Width="400"
x:DataType="views:SwkbdAppletDialog"
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True"> Focusable="True">
<Grid <Grid
@@ -34,13 +36,13 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Margin="5" Margin="5"
Text="{ReflectionBinding MainText}" Text="{Binding MainText}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Margin="5" Margin="5"
Text="{ReflectionBinding SecondaryText}" Text="{Binding SecondaryText}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBox <TextBox
Name="Input" Name="Input"
@@ -50,7 +52,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Focusable="True" Focusable="True"
KeyUp="Message_KeyUp" KeyUp="Message_KeyUp"
Text="{ReflectionBinding Message}" Text="{Binding Message}"
TextInput="Message_TextInput" TextInput="Message_TextInput"
TextWrapping="Wrap" TextWrapping="Wrap"
UseFloatingWatermark="True" /> UseFloatingWatermark="True" />

View File

@@ -46,7 +46,7 @@
<Setter Property="CornerRadius" Value="4" /> <Setter Property="CornerRadius" Value="4" />
</Style> </Style>
<Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator"> <Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator">
<Setter Property="MinHeight" Value="{ReflectionBinding $parent[UserControl].DataContext.GridItemSelectorSize}" /> <Setter Property="MinHeight" Value="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).GridItemSelectorSize}" />
</Style> </Style>
</ListBox.Styles> </ListBox.Styles>
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
@@ -56,10 +56,10 @@
Margin="10" Margin="10"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Classes.huge="{ReflectionBinding $parent[UserControl].DataContext.IsGridHuge}" Classes.huge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridHuge}"
Classes.large="{ReflectionBinding $parent[UserControl].DataContext.IsGridLarge}" Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}"
Classes.normal="{ReflectionBinding $parent[UserControl].DataContext.IsGridMedium}" Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}"
Classes.small="{ReflectionBinding $parent[UserControl].DataContext.IsGridSmall}" Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}"
ClipToBounds="True" ClipToBounds="True"
CornerRadius="4"> CornerRadius="4">
<Grid> <Grid>
@@ -78,7 +78,7 @@
Margin="0,10,0,0" Margin="0,10,0,0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
IsVisible="{ReflectionBinding $parent[UserControl].DataContext.ShowNames}"> IsVisible="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).ShowNames}">
<TextBlock <TextBlock
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
@@ -101,4 +101,4 @@
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -42,7 +42,7 @@
</ListBox.ItemsPanel> </ListBox.ItemsPanel>
<ListBox.Styles> <ListBox.Styles>
<Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator"> <Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator">
<Setter Property="MinHeight" Value="{ReflectionBinding $parent[UserControl].DataContext.ListItemSelectorSize}" /> <Setter Property="MinHeight" Value="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).ListItemSelectorSize}" />
</Style> </Style>
</ListBox.Styles> </ListBox.Styles>
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
@@ -67,10 +67,10 @@
Grid.RowSpan="3" Grid.RowSpan="3"
Grid.Column="0" Grid.Column="0"
Margin="0" Margin="0"
Classes.huge="{ReflectionBinding $parent[UserControl].DataContext.IsGridHuge}" Classes.huge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridHuge}"
Classes.large="{ReflectionBinding $parent[UserControl].DataContext.IsGridLarge}" Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}"
Classes.normal="{ReflectionBinding $parent[UserControl].DataContext.IsGridMedium}" Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}"
Classes.small="{ReflectionBinding $parent[UserControl].DataContext.IsGridSmall}" Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" /> Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<Border <Border
Grid.Column="2" Grid.Column="2"
@@ -157,4 +157,4 @@
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -11,6 +11,7 @@
Height="500" Height="500"
MinWidth="500" MinWidth="500"
MinHeight="500" MinHeight="500"
x:DataType="window:CheatWindow"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True"> Focusable="True">
@@ -40,7 +41,7 @@
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
LineHeight="18" LineHeight="18"
Text="{ReflectionBinding Heading}" Text="{Binding Heading}"
TextAlignment="Center" TextAlignment="Center"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
@@ -61,7 +62,7 @@
MinWidth="160" MinWidth="160"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{ReflectionBinding BuildId}" Text="{Binding BuildId}"
IsReadOnly="True" /> IsReadOnly="True" />
<Border <Border
Grid.Row="3" Grid.Row="3"
@@ -77,7 +78,7 @@
MinHeight="300" MinHeight="300"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
ItemsSource="{ReflectionBinding LoadedCheats}"> ItemsSource="{Binding LoadedCheats}">
<TreeView.Styles> <TreeView.Styles>
<Styles> <Styles>
<Style Selector="TreeViewItem:empty /template/ ItemsPresenter"> <Style Selector="TreeViewItem:empty /template/ ItemsPresenter">
@@ -120,18 +121,18 @@
Name="SaveButton" Name="SaveButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding Save}" Command="{Binding Save}"
IsVisible="{ReflectionBinding !NoCheatsFound}"> IsVisible="{Binding !NoCheatsFound}">
<TextBlock Text="{locale:Locale SettingsButtonSave}" /> <TextBlock Text="{locale:Locale SettingsButtonSave}" />
</Button> </Button>
<Button <Button
Name="CancelButton" Name="CancelButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding Close}"> Command="{Binding Close}">
<TextBlock Text="{locale:Locale InputDialogCancel}" /> <TextBlock Text="{locale:Locale InputDialogCancel}" />
</Button> </Button>
</DockPanel> </DockPanel>
</DockPanel> </DockPanel>
</Grid> </Grid>
</window:StyleableWindow> </window:StyleableWindow>

View File

@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.UI.Windows
private readonly string _enabledCheatsPath; private readonly string _enabledCheatsPath;
public bool NoCheatsFound { get; } public bool NoCheatsFound { get; }
private AvaloniaList<CheatsList> LoadedCheats { get; } public AvaloniaList<CheatsList> LoadedCheats { get; }
public string Heading { get; } public string Heading { get; }
public string BuildId { get; } public string BuildId { get; }

View File

@@ -39,14 +39,14 @@
Name="EnableAllButton" Name="EnableAllButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding EnableAll}"> Command="{Binding EnableAll}">
<TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" /> <TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" />
</Button> </Button>
<Button <Button
Name="DisableAllButton" Name="DisableAllButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding DisableAll}"> Command="{Binding DisableAll}">
<TextBlock Text="{locale:Locale DlcManagerDisableAllButton}" /> <TextBlock Text="{locale:Locale DlcManagerDisableAllButton}" />
</Button> </Button>
</StackPanel> </StackPanel>
@@ -157,14 +157,14 @@
Name="AddButton" Name="AddButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding Add}"> Command="{Binding Add}">
<TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" /> <TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" />
</Button> </Button>
<Button <Button
Name="RemoveAllButton" Name="RemoveAllButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding RemoveAll}"> Command="{Binding RemoveAll}">
<TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" /> <TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" />
</Button> </Button>
</StackPanel> </StackPanel>
@@ -189,4 +189,4 @@
</StackPanel> </StackPanel>
</Panel> </Panel>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -15,14 +15,6 @@ namespace Ryujinx.Graphics.GAL
BufferImage, BufferImage,
} }
public enum ResourceAccess : byte
{
None = 0,
Read = 1,
Write = 2,
ReadWrite = Read | Write,
}
[Flags] [Flags]
public enum ResourceStages : byte public enum ResourceStages : byte
{ {
@@ -81,19 +73,17 @@ namespace Ryujinx.Graphics.GAL
public int Binding { get; } public int Binding { get; }
public ResourceType Type { get; } public ResourceType Type { get; }
public ResourceStages Stages { get; } public ResourceStages Stages { get; }
public ResourceAccess Access { get; }
public ResourceUsage(int binding, ResourceType type, ResourceStages stages, ResourceAccess access) public ResourceUsage(int binding, ResourceType type, ResourceStages stages)
{ {
Binding = binding; Binding = binding;
Type = type; Type = type;
Stages = stages; Stages = stages;
Access = access;
} }
public override int GetHashCode() public override int GetHashCode()
{ {
return HashCode.Combine(Binding, Type, Stages, Access); return HashCode.Combine(Binding, Type, Stages);
} }
public override bool Equals(object obj) public override bool Equals(object obj)
@@ -103,7 +93,7 @@ namespace Ryujinx.Graphics.GAL
public bool Equals(ResourceUsage other) public bool Equals(ResourceUsage other)
{ {
return Binding == other.Binding && Type == other.Type && Stages == other.Stages && Access == other.Access; return Binding == other.Binding && Type == other.Type && Stages == other.Stages;
} }
public static bool operator ==(ResourceUsage left, ResourceUsage right) public static bool operator ==(ResourceUsage left, ResourceUsage right)

View File

@@ -490,10 +490,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
/// </summary> /// </summary>
/// <param name="offset">Offset of the range</param> /// <param name="offset">Offset of the range</param>
/// <param name="size">Size of the range in bytes</param> /// <param name="size">Size of the range in bytes</param>
/// <param name="write">Indicates if the buffer contents will be modified</param>
/// <returns>Range</returns> /// <returns>Range</returns>
public BufferRange GetVertexDataBufferRange(int offset, int size) public BufferRange GetVertexDataBufferRange(int offset, int size, bool write)
{ {
return new BufferRange(_vertexDataBuffer.Handle, offset, size); return new BufferRange(_vertexDataBuffer.Handle, offset, size, write);
} }
/// <summary> /// <summary>
@@ -501,10 +502,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
/// </summary> /// </summary>
/// <param name="offset">Offset of the range</param> /// <param name="offset">Offset of the range</param>
/// <param name="size">Size of the range in bytes</param> /// <param name="size">Size of the range in bytes</param>
/// <param name="write">Indicates if the buffer contents will be modified</param>
/// <returns>Range</returns> /// <returns>Range</returns>
public BufferRange GetGeometryVertexDataBufferRange(int offset, int size) public BufferRange GetGeometryVertexDataBufferRange(int offset, int size, bool write)
{ {
return new BufferRange(_geometryVertexDataBuffer.Handle, offset, size); return new BufferRange(_geometryVertexDataBuffer.Handle, offset, size, write);
} }
/// <summary> /// <summary>
@@ -512,10 +514,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
/// </summary> /// </summary>
/// <param name="offset">Offset of the range</param> /// <param name="offset">Offset of the range</param>
/// <param name="size">Size of the range in bytes</param> /// <param name="size">Size of the range in bytes</param>
/// <param name="write">Indicates if the buffer contents will be modified</param>
/// <returns>Range</returns> /// <returns>Range</returns>
public BufferRange GetGeometryIndexDataBufferRange(int offset, int size) public BufferRange GetGeometryIndexDataBufferRange(int offset, int size, bool write)
{ {
return new BufferRange(_geometryIndexDataBuffer.Handle, offset, size); return new BufferRange(_geometryIndexDataBuffer.Handle, offset, size, write);
} }
/// <summary> /// <summary>

View File

@@ -202,7 +202,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
_context.Renderer.Pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(vertexInfoBinding, vertexInfoRange) }); _context.Renderer.Pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(vertexInfoBinding, vertexInfoRange) });
int vertexDataBinding = _vertexAsCompute.Reservations.VertexOutputStorageBufferBinding; int vertexDataBinding = _vertexAsCompute.Reservations.VertexOutputStorageBufferBinding;
BufferRange vertexDataRange = _vacContext.GetVertexDataBufferRange(_vertexDataOffset, _vertexDataSize); BufferRange vertexDataRange = _vacContext.GetVertexDataBufferRange(_vertexDataOffset, _vertexDataSize, write: true);
_context.Renderer.Pipeline.SetStorageBuffers(stackalloc[] { new BufferAssignment(vertexDataBinding, vertexDataRange) }); _context.Renderer.Pipeline.SetStorageBuffers(stackalloc[] { new BufferAssignment(vertexDataBinding, vertexDataRange) });
_vacContext.VertexInfoBufferUpdater.Commit(); _vacContext.VertexInfoBufferUpdater.Commit();
@@ -245,9 +245,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
int geometryVbBinding = _geometryAsCompute.Reservations.GeometryVertexOutputStorageBufferBinding; int geometryVbBinding = _geometryAsCompute.Reservations.GeometryVertexOutputStorageBufferBinding;
int geometryIbBinding = _geometryAsCompute.Reservations.GeometryIndexOutputStorageBufferBinding; int geometryIbBinding = _geometryAsCompute.Reservations.GeometryIndexOutputStorageBufferBinding;
BufferRange vertexDataRange = _vacContext.GetVertexDataBufferRange(_vertexDataOffset, _vertexDataSize); BufferRange vertexDataRange = _vacContext.GetVertexDataBufferRange(_vertexDataOffset, _vertexDataSize, write: false);
BufferRange vertexBuffer = _vacContext.GetGeometryVertexDataBufferRange(_geometryVertexDataOffset, _geometryVertexDataSize); BufferRange vertexBuffer = _vacContext.GetGeometryVertexDataBufferRange(_geometryVertexDataOffset, _geometryVertexDataSize, write: true);
BufferRange indexBuffer = _vacContext.GetGeometryIndexDataBufferRange(_geometryIndexDataOffset, _geometryIndexDataSize); BufferRange indexBuffer = _vacContext.GetGeometryIndexDataBufferRange(_geometryIndexDataOffset, _geometryIndexDataSize, write: true);
_context.Renderer.Pipeline.SetStorageBuffers(stackalloc[] _context.Renderer.Pipeline.SetStorageBuffers(stackalloc[]
{ {
@@ -293,8 +293,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
if (_geometryAsCompute != null) if (_geometryAsCompute != null)
{ {
BufferRange vertexBuffer = _vacContext.GetGeometryVertexDataBufferRange(_geometryVertexDataOffset, _geometryVertexDataSize); BufferRange vertexBuffer = _vacContext.GetGeometryVertexDataBufferRange(_geometryVertexDataOffset, _geometryVertexDataSize, write: false);
BufferRange indexBuffer = _vacContext.GetGeometryIndexDataBufferRange(_geometryIndexDataOffset, _geometryIndexDataSize); BufferRange indexBuffer = _vacContext.GetGeometryIndexDataBufferRange(_geometryIndexDataOffset, _geometryIndexDataSize, write: false);
_context.Renderer.Pipeline.SetProgram(_vertexPassthroughProgram); _context.Renderer.Pipeline.SetProgram(_vertexPassthroughProgram);
_context.Renderer.Pipeline.SetIndexBuffer(indexBuffer, IndexType.UInt); _context.Renderer.Pipeline.SetIndexBuffer(indexBuffer, IndexType.UInt);
@@ -310,7 +310,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
} }
else else
{ {
BufferRange vertexDataRange = _vacContext.GetVertexDataBufferRange(_vertexDataOffset, _vertexDataSize); BufferRange vertexDataRange = _vacContext.GetVertexDataBufferRange(_vertexDataOffset, _vertexDataSize, write: false);
_context.Renderer.Pipeline.SetProgram(_vertexPassthroughProgram); _context.Renderer.Pipeline.SetProgram(_vertexPassthroughProgram);
_context.Renderer.Pipeline.SetStorageBuffers(stackalloc[] { new BufferAssignment(vertexDataBinding, vertexDataRange) }); _context.Renderer.Pipeline.SetStorageBuffers(stackalloc[] { new BufferAssignment(vertexDataBinding, vertexDataRange) });

View File

@@ -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 = 5551; private const uint CodeGenVersion = 5682;
private const string SharedTocFileName = "shared.toc"; private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data"; private const string SharedDataFileName = "shared.data";

View File

@@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
} }
AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1); AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1);
AddUsage(SupportBufferStages, ResourceType.UniformBuffer, ResourceAccess.Read, UniformSetIndex, 0, 1); AddUsage(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1);
ResourceReservationCounts rrc = new(!context.Capabilities.SupportsTransformFeedback && tfEnabled, vertexAsCompute); ResourceReservationCounts rrc = new(!context.Capabilities.SupportsTransformFeedback && tfEnabled, vertexAsCompute);
@@ -73,16 +73,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
// TODO: Handle that better? Maybe we should only set the binding that are really needed on each shader. // TODO: Handle that better? Maybe we should only set the binding that are really needed on each shader.
ResourceStages stages = vertexAsCompute ? ResourceStages.Compute | ResourceStages.Vertex : VtgStages; ResourceStages stages = vertexAsCompute ? ResourceStages.Compute | ResourceStages.Vertex : VtgStages;
PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, ResourceAccess.Read, UniformSetIndex, 1, rrc.ReservedConstantBuffers - 1); PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, UniformSetIndex, 1, rrc.ReservedConstantBuffers - 1);
PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, ResourceAccess.ReadWrite, StorageSetIndex, 0, rrc.ReservedStorageBuffers); PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, StorageSetIndex, 0, rrc.ReservedStorageBuffers);
PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, ResourceAccess.Read, TextureSetIndex, 0, rrc.ReservedTextures); PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, TextureSetIndex, 0, rrc.ReservedTextures);
PopulateDescriptorAndUsages(stages, ResourceType.BufferImage, ResourceAccess.ReadWrite, ImageSetIndex, 0, rrc.ReservedImages); PopulateDescriptorAndUsages(stages, ResourceType.BufferImage, ImageSetIndex, 0, rrc.ReservedImages);
} }
private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, ResourceAccess access, int setIndex, int start, int count) private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count)
{ {
AddDescriptor(stages, type, setIndex, start, count); AddDescriptor(stages, type, setIndex, start, count);
AddUsage(stages, type, access, setIndex, start, count); AddUsage(stages, type, setIndex, start, count);
} }
/// <summary> /// <summary>
@@ -174,15 +174,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary> /// </summary>
/// <param name="stages">Shader stages where the resource is used</param> /// <param name="stages">Shader stages where the resource is used</param>
/// <param name="type">Type of the resource</param> /// <param name="type">Type of the resource</param>
/// <param name="access">How the resource is accessed by the shader stages where it is used</param>
/// <param name="setIndex">Descriptor set number where the resource will be bound</param> /// <param name="setIndex">Descriptor set number where the resource will be bound</param>
/// <param name="binding">Binding number where the resource will be bound</param> /// <param name="binding">Binding number where the resource will be bound</param>
/// <param name="count">Number of resources bound at the binding location</param> /// <param name="count">Number of resources bound at the binding location</param>
private void AddUsage(ResourceStages stages, ResourceType type, ResourceAccess access, int setIndex, int binding, int count) private void AddUsage(ResourceStages stages, ResourceType type, int setIndex, int binding, int count)
{ {
for (int index = 0; index < count; index++) for (int index = 0; index < count; index++)
{ {
_resourceUsages[setIndex].Add(new ResourceUsage(binding + index, type, stages, access)); _resourceUsages[setIndex].Add(new ResourceUsage(binding + index, type, stages));
} }
} }
@@ -200,8 +199,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
_resourceUsages[setIndex].Add(new ResourceUsage( _resourceUsages[setIndex].Add(new ResourceUsage(
buffer.Binding, buffer.Binding,
isStorage ? ResourceType.StorageBuffer : ResourceType.UniformBuffer, isStorage ? ResourceType.StorageBuffer : ResourceType.UniformBuffer,
stages, stages));
buffer.Flags.HasFlag(BufferUsageFlags.Write) ? ResourceAccess.ReadWrite : ResourceAccess.Read));
} }
} }
@@ -225,8 +223,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
_resourceUsages[setIndex].Add(new ResourceUsage( _resourceUsages[setIndex].Add(new ResourceUsage(
texture.Binding, texture.Binding,
type, type,
stages, stages));
texture.Flags.HasFlag(TextureUsageFlags.ImageStore) ? ResourceAccess.ReadWrite : ResourceAccess.Read));
} }
} }

View File

@@ -89,6 +89,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
context.AddCapability(Capability.DrawParameters); context.AddCapability(Capability.DrawParameters);
} }
if (context.Definitions.Stage != ShaderStage.Fragment &&
context.Definitions.Stage != ShaderStage.Geometry &&
context.Definitions.Stage != ShaderStage.Compute &&
(context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Output, IoVariable.Layer)) ||
context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Output, IoVariable.ViewportIndex))))
{
context.AddExtension("SPV_EXT_shader_viewport_index_layer");
context.AddCapability(Capability.ShaderViewportIndexLayerEXT);
}
if (context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Output, IoVariable.ViewportMask))) if (context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Output, IoVariable.ViewportMask)))
{ {
context.AddExtension("SPV_NV_viewport_array2"); context.AddExtension("SPV_NV_viewport_array2");
@@ -277,14 +287,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
localSizeZ); localSizeZ);
} }
if (context.Definitions.Stage != ShaderStage.Fragment &&
context.Definitions.Stage != ShaderStage.Geometry &&
context.Definitions.Stage != ShaderStage.Compute &&
context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Output, IoVariable.Layer)))
{
context.AddCapability(Capability.ShaderLayer);
}
if (context.Definitions.TransformFeedbackEnabled && context.Definitions.LastInVertexPipeline) if (context.Definitions.TransformFeedbackEnabled && context.Definitions.LastInVertexPipeline)
{ {
context.AddExecutionMode(spvFunc, ExecutionMode.Xfb); context.AddExecutionMode(spvFunc, ExecutionMode.Xfb);

View File

@@ -128,7 +128,26 @@ namespace Ryujinx.Graphics.Shader
/// <returns>GPU graphics state</returns> /// <returns>GPU graphics state</returns>
GpuGraphicsState QueryGraphicsState() GpuGraphicsState QueryGraphicsState()
{ {
return default; return new GpuGraphicsState(
false,
InputTopology.Points,
false,
TessPatchType.Triangles,
TessSpacing.EqualSpacing,
false,
false,
false,
false,
false,
1f,
AlphaTestOp.Always,
0f,
default,
true,
default,
false,
false,
false);
} }
/// <summary> /// <summary>

View File

@@ -1126,7 +1126,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
// so we want to get the byte offset back, since each one of those word // so we want to get the byte offset back, since each one of those word
// offsets are a new "local variable" which will not match. // offsets are a new "local variable" which will not match.
if (operation.GetSource(0).AsgOp is Operation shiftRightOp && if (operation.GetSource(1).AsgOp is Operation shiftRightOp &&
shiftRightOp.Inst == Instruction.ShiftRightU32 && shiftRightOp.Inst == Instruction.ShiftRightU32 &&
shiftRightOp.GetSource(1).Type == OperandType.Constant && shiftRightOp.GetSource(1).Type == OperandType.Constant &&
shiftRightOp.GetSource(1).Value == 2) shiftRightOp.GetSource(1).Value == 2)
@@ -1158,9 +1158,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
private static bool TryGetLocalMemoryOffset(Operation operation, out int constOffset) private static bool TryGetLocalMemoryOffset(Operation operation, out int constOffset)
{ {
if (operation.GetSource(0).Type == OperandType.Constant) Operand offset = operation.GetSource(1);
if (offset.Type == OperandType.Constant)
{ {
constOffset = operation.GetSource(0).Value; constOffset = offset.Value;
return true; return true;
} }

View File

@@ -576,6 +576,11 @@ namespace Ryujinx.Graphics.Shader.Translation
int outputAttributesMask = AttributeUsage.UsedOutputAttributes; int outputAttributesMask = AttributeUsage.UsedOutputAttributes;
int layerOutputAttr = LayerOutputAttribute; int layerOutputAttr = LayerOutputAttribute;
if (LayerOutputWritten)
{
outputAttributesMask |= 1 << ((layerOutputAttr - AttributeConsts.UserAttributeBase) / 16);
}
OutputTopology outputTopology; OutputTopology outputTopology;
int maxOutputVertices; int maxOutputVertices;

View File

@@ -38,6 +38,7 @@ namespace Ryujinx.Graphics.Texture
bool is3D = depth > 1 || gobBlocksInZ > 1; bool is3D = depth > 1 || gobBlocksInZ > 1;
int layerSize = 0; int layerSize = 0;
int layerSizeAligned = 0;
int[] allOffsets = new int[is3D ? Calculate3DOffsetCount(levels, depth) : levels * layers * depth]; int[] allOffsets = new int[is3D ? Calculate3DOffsetCount(levels, depth) : levels * layers * depth];
int[] mipOffsets = new int[levels]; int[] mipOffsets = new int[levels];
@@ -91,6 +92,8 @@ namespace Ryujinx.Graphics.Texture
sliceSizes[level] = totalBlocksOfGobsInY * robSize; sliceSizes[level] = totalBlocksOfGobsInY * robSize;
levelSizes[level] = totalBlocksOfGobsInZ * sliceSizes[level]; levelSizes[level] = totalBlocksOfGobsInZ * sliceSizes[level];
layerSizeAligned += levelSizes[level];
if (is3D) if (is3D)
{ {
int gobSize = mipGobBlocksInY * GobSize; int gobSize = mipGobBlocksInY * GobSize;
@@ -130,28 +133,32 @@ namespace Ryujinx.Graphics.Texture
depthLevelOffset += d; depthLevelOffset += d;
} }
int totalSize;
if (layers > 1) if (layers > 1)
{ {
layerSize = AlignLayerSize( layerSizeAligned = AlignLayerSize(
layerSize, layerSizeAligned,
height, height,
depth, depth,
blockHeight, blockHeight,
gobBlocksInY, gobBlocksInY,
gobBlocksInZ, gobBlocksInZ,
gobBlocksInTileX); gobBlocksInTileX);
}
int totalSize; if (layerSizeAligned < gpuLayerSize)
{
if (layerSize < gpuLayerSize) totalSize = (layers - 1) * gpuLayerSize + layerSizeAligned;
{ layerSizeAligned = gpuLayerSize;
totalSize = (layers - 1) * gpuLayerSize + layerSize; }
layerSize = gpuLayerSize; else
{
totalSize = layerSizeAligned * layers;
}
} }
else else
{ {
totalSize = layerSize * layers; totalSize = layerSize;
} }
if (!is3D) if (!is3D)
@@ -159,7 +166,7 @@ namespace Ryujinx.Graphics.Texture
for (int layer = 0; layer < layers; layer++) for (int layer = 0; layer < layers; layer++)
{ {
int baseIndex = layer * levels; int baseIndex = layer * levels;
int baseOffset = layer * layerSize; int baseOffset = layer * layerSizeAligned;
for (int level = 0; level < levels; level++) for (int level = 0; level < levels; level++)
{ {
@@ -168,7 +175,7 @@ namespace Ryujinx.Graphics.Texture
} }
} }
return new SizeInfo(mipOffsets, allOffsets, sliceSizes, levelSizes, depth, levels, layerSize, totalSize, is3D); return new SizeInfo(mipOffsets, allOffsets, sliceSizes, levelSizes, depth, levels, layerSizeAligned, totalSize, is3D);
} }
public static SizeInfo GetLinearTextureSize(int stride, int height, int blockHeight) public static SizeInfo GetLinearTextureSize(int stride, int height, int blockHeight)

View File

@@ -967,7 +967,7 @@ namespace Ryujinx.Graphics.Vulkan
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder)) if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
{ {
holder = _gd.BufferManager.Create(_gd, (size * 2 + 3) & ~3); holder = _gd.BufferManager.Create(_gd, (size * 2 + 3) & ~3, baseType: BufferAllocationType.DeviceLocal);
_gd.PipelineInternal.EndRenderPass(); _gd.PipelineInternal.EndRenderPass();
_gd.HelperShader.ConvertI8ToI16(_gd, cbs, this, holder, offset, size); _gd.HelperShader.ConvertI8ToI16(_gd, cbs, this, holder, offset, size);
@@ -993,7 +993,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
int alignedStride = (stride + (alignment - 1)) & -alignment; int alignedStride = (stride + (alignment - 1)) & -alignment;
holder = _gd.BufferManager.Create(_gd, (size / stride) * alignedStride); holder = _gd.BufferManager.Create(_gd, (size / stride) * alignedStride, baseType: BufferAllocationType.DeviceLocal);
_gd.PipelineInternal.EndRenderPass(); _gd.PipelineInternal.EndRenderPass();
_gd.HelperShader.ChangeStride(_gd, cbs, this, holder, offset, size, stride, alignedStride); _gd.HelperShader.ChangeStride(_gd, cbs, this, holder, offset, size, stride, alignedStride);
@@ -1023,7 +1023,7 @@ namespace Ryujinx.Graphics.Vulkan
int convertedCount = pattern.GetConvertedCount(indexCount); int convertedCount = pattern.GetConvertedCount(indexCount);
holder = _gd.BufferManager.Create(_gd, convertedCount * 4); holder = _gd.BufferManager.Create(_gd, convertedCount * 4, baseType: BufferAllocationType.DeviceLocal);
_gd.PipelineInternal.EndRenderPass(); _gd.PipelineInternal.EndRenderPass();
_gd.HelperShader.ConvertIndexBuffer(_gd, cbs, this, holder, pattern, indexSize, offset, indexCount); _gd.HelperShader.ConvertIndexBuffer(_gd, cbs, this, holder, pattern, indexSize, offset, indexCount);

View File

@@ -257,14 +257,22 @@ namespace Ryujinx.Graphics.Vulkan
if (realIndex != -1) if (realIndex != -1)
{ {
_colors[realIndex].Storage?.InsertReadToWriteBarrier(cbs, AccessFlags.ColorAttachmentWriteBit, PipelineStageFlags.ColorAttachmentOutputBit); _colors[realIndex].Storage?.InsertReadToWriteBarrier(
cbs,
AccessFlags.ColorAttachmentWriteBit,
PipelineStageFlags.ColorAttachmentOutputBit,
insideRenderPass: true);
} }
} }
} }
public void InsertClearBarrierDS(CommandBufferScoped cbs) public void InsertClearBarrierDS(CommandBufferScoped cbs)
{ {
_depthStencil?.Storage?.InsertReadToWriteBarrier(cbs, AccessFlags.DepthStencilAttachmentWriteBit, PipelineStageFlags.LateFragmentTestsBit); _depthStencil?.Storage?.InsertReadToWriteBarrier(
cbs,
AccessFlags.DepthStencilAttachmentWriteBit,
PipelineStageFlags.LateFragmentTestsBit,
insideRenderPass: true);
} }
} }
} }

View File

@@ -41,6 +41,7 @@ namespace Ryujinx.Graphics.Vulkan
public readonly bool SupportsPreciseOcclusionQueries; public readonly bool SupportsPreciseOcclusionQueries;
public readonly bool SupportsPipelineStatisticsQuery; public readonly bool SupportsPipelineStatisticsQuery;
public readonly bool SupportsGeometryShader; public readonly bool SupportsGeometryShader;
public readonly bool SupportsTessellationShader;
public readonly bool SupportsViewportArray2; public readonly bool SupportsViewportArray2;
public readonly bool SupportsHostImportedMemory; public readonly bool SupportsHostImportedMemory;
public readonly bool SupportsDepthClipControl; public readonly bool SupportsDepthClipControl;
@@ -77,6 +78,7 @@ namespace Ryujinx.Graphics.Vulkan
bool supportsPreciseOcclusionQueries, bool supportsPreciseOcclusionQueries,
bool supportsPipelineStatisticsQuery, bool supportsPipelineStatisticsQuery,
bool supportsGeometryShader, bool supportsGeometryShader,
bool supportsTessellationShader,
bool supportsViewportArray2, bool supportsViewportArray2,
bool supportsHostImportedMemory, bool supportsHostImportedMemory,
bool supportsDepthClipControl, bool supportsDepthClipControl,
@@ -112,6 +114,7 @@ namespace Ryujinx.Graphics.Vulkan
SupportsPreciseOcclusionQueries = supportsPreciseOcclusionQueries; SupportsPreciseOcclusionQueries = supportsPreciseOcclusionQueries;
SupportsPipelineStatisticsQuery = supportsPipelineStatisticsQuery; SupportsPipelineStatisticsQuery = supportsPipelineStatisticsQuery;
SupportsGeometryShader = supportsGeometryShader; SupportsGeometryShader = supportsGeometryShader;
SupportsTessellationShader = supportsTessellationShader;
SupportsViewportArray2 = supportsViewportArray2; SupportsViewportArray2 = supportsViewportArray2;
SupportsHostImportedMemory = supportsHostImportedMemory; SupportsHostImportedMemory = supportsHostImportedMemory;
SupportsDepthClipControl = supportsDepthClipControl; SupportsDepthClipControl = supportsDepthClipControl;

View File

@@ -5,7 +5,6 @@ using Ryujinx.Graphics.Shader.Translation;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Numerics; using System.Numerics;
using CompareOp = Ryujinx.Graphics.GAL.CompareOp; using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
using Format = Ryujinx.Graphics.GAL.Format; using Format = Ryujinx.Graphics.GAL.Format;
@@ -27,6 +26,7 @@ namespace Ryujinx.Graphics.Vulkan
class HelperShader : IDisposable class HelperShader : IDisposable
{ {
private const int UniformBufferAlignment = 256; private const int UniformBufferAlignment = 256;
private const int ConvertElementsPerWorkgroup = 32 * 100; // Work group size of 32 times 100 elements.
private const string ShaderBinariesPath = "Ryujinx.Graphics.Vulkan/Shaders/SpirvBinaries"; private const string ShaderBinariesPath = "Ryujinx.Graphics.Vulkan/Shaders/SpirvBinaries";
private readonly PipelineHelperShader _pipeline; private readonly PipelineHelperShader _pipeline;
@@ -894,7 +894,7 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetStorageBuffers(1, sbRanges); _pipeline.SetStorageBuffers(1, sbRanges);
_pipeline.SetProgram(_programStrideChange); _pipeline.SetProgram(_programStrideChange);
_pipeline.DispatchCompute(1, 1, 1); _pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1);
gd.BufferManager.Delete(bufferHandle); gd.BufferManager.Delete(bufferHandle);
@@ -1742,7 +1742,7 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetStorageBuffers(1, sbRanges); _pipeline.SetStorageBuffers(1, sbRanges);
_pipeline.SetProgram(_programConvertD32S8ToD24S8); _pipeline.SetProgram(_programConvertD32S8ToD24S8);
_pipeline.DispatchCompute(1, 1, 1); _pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1);
gd.BufferManager.Delete(bufferHandle); gd.BufferManager.Delete(bufferHandle);

View File

@@ -149,10 +149,22 @@ namespace Ryujinx.Graphics.Vulkan
DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit, DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
}; };
PipelineStageFlags pipelineStageFlags = PipelineStageFlags.VertexShaderBit | PipelineStageFlags.FragmentShaderBit;
if (Gd.Capabilities.SupportsGeometryShader)
{
pipelineStageFlags |= PipelineStageFlags.GeometryShaderBit;
}
if (Gd.Capabilities.SupportsTessellationShader)
{
pipelineStageFlags |= PipelineStageFlags.TessellationControlShaderBit | PipelineStageFlags.TessellationEvaluationShaderBit;
}
Gd.Api.CmdPipelineBarrier( Gd.Api.CmdPipelineBarrier(
CommandBuffer, CommandBuffer,
PipelineStageFlags.FragmentShaderBit, pipelineStageFlags,
PipelineStageFlags.FragmentShaderBit, pipelineStageFlags,
0, 0,
1, 1,
memoryBarrier, memoryBarrier,

View File

@@ -9,8 +9,12 @@ namespace Ryujinx.Graphics.Vulkan
{ {
static class PipelineConverter static class PipelineConverter
{ {
private const AccessFlags SubpassSrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit | AccessFlags.ColorAttachmentWriteBit; private const AccessFlags SubpassAccessMask =
private const AccessFlags SubpassDstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit | AccessFlags.ShaderReadBit; AccessFlags.MemoryReadBit |
AccessFlags.MemoryWriteBit |
AccessFlags.ShaderReadBit |
AccessFlags.ColorAttachmentWriteBit |
AccessFlags.DepthStencilAttachmentWriteBit;
public static unsafe DisposableRenderPass ToRenderPass(this ProgramPipelineState state, VulkanRenderer gd, Device device) public static unsafe DisposableRenderPass ToRenderPass(this ProgramPipelineState state, VulkanRenderer gd, Device device)
{ {
@@ -132,8 +136,8 @@ namespace Ryujinx.Graphics.Vulkan
0, 0,
PipelineStageFlags.AllGraphicsBit, PipelineStageFlags.AllGraphicsBit,
PipelineStageFlags.AllGraphicsBit, PipelineStageFlags.AllGraphicsBit,
SubpassSrcAccessMask, SubpassAccessMask,
SubpassDstAccessMask, SubpassAccessMask,
0); 0);
} }
@@ -146,8 +150,8 @@ namespace Ryujinx.Graphics.Vulkan
0, 0,
PipelineStageFlags.AllGraphicsBit, PipelineStageFlags.AllGraphicsBit,
PipelineStageFlags.AllGraphicsBit, PipelineStageFlags.AllGraphicsBit,
SubpassSrcAccessMask, SubpassAccessMask,
SubpassDstAccessMask, SubpassAccessMask,
0); 0);
} }

View File

@@ -146,7 +146,10 @@ namespace Ryujinx.Graphics.Vulkan
private void RecordScissor(Vk api, CommandBuffer commandBuffer) private void RecordScissor(Vk api, CommandBuffer commandBuffer)
{ {
api.CmdSetScissor(commandBuffer, 0, (uint)ScissorsCount, _scissors.AsSpan()); if (ScissorsCount != 0)
{
api.CmdSetScissor(commandBuffer, 0, (uint)ScissorsCount, _scissors.AsSpan());
}
} }
private readonly void RecordStencilMasks(Vk api, CommandBuffer commandBuffer) private readonly void RecordStencilMasks(Vk api, CommandBuffer commandBuffer)

View File

@@ -8,15 +8,13 @@ namespace Ryujinx.Graphics.Vulkan
public readonly int Count; public readonly int Count;
public readonly ResourceType Type; public readonly ResourceType Type;
public readonly ResourceStages Stages; public readonly ResourceStages Stages;
public readonly ResourceAccess Access;
public ResourceBindingSegment(int binding, int count, ResourceType type, ResourceStages stages, ResourceAccess access) public ResourceBindingSegment(int binding, int count, ResourceType type, ResourceStages stages)
{ {
Binding = binding; Binding = binding;
Count = count; Count = count;
Type = type; Type = type;
Stages = stages; Stages = stages;
Access = access;
} }
} }
} }

View File

@@ -34,22 +34,12 @@ namespace Ryujinx.Graphics.Vulkan
_ => throw new ArgumentException($"Invalid resource type \"{type}\"."), _ => throw new ArgumentException($"Invalid resource type \"{type}\"."),
}; };
ResourceAccess access = IsReadOnlyType(type) ? ResourceAccess.Read : ResourceAccess.ReadWrite;
_resourceDescriptors[setIndex].Add(new ResourceDescriptor(binding, 1, type, stages)); _resourceDescriptors[setIndex].Add(new ResourceDescriptor(binding, 1, type, stages));
_resourceUsages[setIndex].Add(new ResourceUsage(binding, type, stages, access)); _resourceUsages[setIndex].Add(new ResourceUsage(binding, type, stages));
return this; return this;
} }
private static bool IsReadOnlyType(ResourceType type)
{
return type == ResourceType.UniformBuffer ||
type == ResourceType.Sampler ||
type == ResourceType.TextureAndSampler ||
type == ResourceType.BufferTexture;
}
public ResourceLayout Build() public ResourceLayout Build()
{ {
var descriptors = new ResourceDescriptorCollection[TotalSets]; var descriptors = new ResourceDescriptorCollection[TotalSets];

View File

@@ -162,8 +162,7 @@ namespace Ryujinx.Graphics.Vulkan
currentDescriptor.Binding, currentDescriptor.Binding,
currentCount, currentCount,
currentDescriptor.Type, currentDescriptor.Type,
currentDescriptor.Stages, currentDescriptor.Stages));
ResourceAccess.ReadWrite));
} }
currentDescriptor = descriptor; currentDescriptor = descriptor;
@@ -181,8 +180,7 @@ namespace Ryujinx.Graphics.Vulkan
currentDescriptor.Binding, currentDescriptor.Binding,
currentCount, currentCount,
currentDescriptor.Type, currentDescriptor.Type,
currentDescriptor.Stages, currentDescriptor.Stages));
ResourceAccess.ReadWrite));
} }
segments[setIndex] = currentSegments.ToArray(); segments[setIndex] = currentSegments.ToArray();
@@ -206,16 +204,9 @@ namespace Ryujinx.Graphics.Vulkan
{ {
ResourceUsage usage = setUsages[setIndex].Usages[index]; ResourceUsage usage = setUsages[setIndex].Usages[index];
// If the resource is not accessed, we don't need to update it.
if (usage.Access == ResourceAccess.None)
{
continue;
}
if (currentUsage.Binding + currentCount != usage.Binding || if (currentUsage.Binding + currentCount != usage.Binding ||
currentUsage.Type != usage.Type || currentUsage.Type != usage.Type ||
currentUsage.Stages != usage.Stages || currentUsage.Stages != usage.Stages)
currentUsage.Access != usage.Access)
{ {
if (currentCount != 0) if (currentCount != 0)
{ {
@@ -223,8 +214,7 @@ namespace Ryujinx.Graphics.Vulkan
currentUsage.Binding, currentUsage.Binding,
currentCount, currentCount,
currentUsage.Type, currentUsage.Type,
currentUsage.Stages, currentUsage.Stages));
currentUsage.Access));
} }
currentUsage = usage; currentUsage = usage;
@@ -242,8 +232,7 @@ namespace Ryujinx.Graphics.Vulkan
currentUsage.Binding, currentUsage.Binding,
currentCount, currentCount,
currentUsage.Type, currentUsage.Type,
currentUsage.Stages, currentUsage.Stages));
currentUsage.Access));
} }
segments[setIndex] = currentSegments.ToArray(); segments[setIndex] = currentSegments.ToArray();

View File

@@ -29,7 +29,7 @@ void main()
int sourceOffset = stride_arguments_data.w; int sourceOffset = stride_arguments_data.w;
int strideRemainder = targetStride - sourceStride; int strideRemainder = targetStride - sourceStride;
int invocations = int(gl_WorkGroupSize.x); int invocations = int(gl_WorkGroupSize.x * gl_NumWorkGroups.x);
int copiesRequired = bufferSize / sourceStride; int copiesRequired = bufferSize / sourceStride;
@@ -39,7 +39,7 @@ void main()
int allInvocationCopies = copiesRequired / invocations; int allInvocationCopies = copiesRequired / invocations;
// - Extra remainder copy that this invocation performs. // - Extra remainder copy that this invocation performs.
int index = int(gl_LocalInvocationID.x); int index = int(gl_GlobalInvocationID.x);
int extra = (index < (copiesRequired % invocations)) ? 1 : 0; int extra = (index < (copiesRequired % invocations)) ? 1 : 0;
int copyCount = allInvocationCopies + extra; int copyCount = allInvocationCopies + extra;

View File

@@ -23,7 +23,7 @@ layout (std430, set = 1, binding = 2) buffer out_s
void main() void main()
{ {
// Determine what slice of the stride copies this invocation will perform. // Determine what slice of the stride copies this invocation will perform.
int invocations = int(gl_WorkGroupSize.x); int invocations = int(gl_WorkGroupSize.x * gl_NumWorkGroups.x);
int copiesRequired = pixelCount; int copiesRequired = pixelCount;
@@ -33,7 +33,7 @@ void main()
int allInvocationCopies = copiesRequired / invocations; int allInvocationCopies = copiesRequired / invocations;
// - Extra remainder copy that this invocation performs. // - Extra remainder copy that this invocation performs.
int index = int(gl_LocalInvocationID.x); int index = int(gl_GlobalInvocationID.x);
int extra = (index < (copiesRequired % invocations)) ? 1 : 0; int extra = (index < (copiesRequired % invocations)) ? 1 : 0;
int copyCount = allInvocationCopies + extra; int copyCount = allInvocationCopies + extra;

View File

@@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Vulkan
var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples); var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples);
var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample, forceStorage: true); var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample);
var flags = ImageCreateFlags.CreateMutableFormatBit; var flags = ImageCreateFlags.CreateMutableFormatBit;
@@ -291,7 +291,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
public static ImageUsageFlags GetImageUsage(Format format, Target target, bool supportsMsStorage, bool forceStorage = false) public static ImageUsageFlags GetImageUsage(Format format, Target target, bool supportsMsStorage)
{ {
var usage = DefaultUsageFlags; var usage = DefaultUsageFlags;
@@ -304,7 +304,7 @@ namespace Ryujinx.Graphics.Vulkan
usage |= ImageUsageFlags.ColorAttachmentBit; usage |= ImageUsageFlags.ColorAttachmentBit;
} }
if (((forceStorage && !format.IsDepthOrStencil()) || format.IsImageCompatible()) && (supportsMsStorage || !target.IsMultisample())) if (format.IsImageCompatible() && (supportsMsStorage || !target.IsMultisample()))
{ {
usage |= ImageUsageFlags.StorageBit; usage |= ImageUsageFlags.StorageBit;
} }
@@ -440,25 +440,27 @@ namespace Ryujinx.Graphics.Vulkan
_lastModificationStage = stage; _lastModificationStage = stage;
} }
public void InsertReadToWriteBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags) public void InsertReadToWriteBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags, bool insideRenderPass)
{ {
if (_lastReadAccess != AccessFlags.None) var lastReadStage = _lastReadStage;
{
ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
TextureView.InsertImageBarrier( if (insideRenderPass)
{
// We can't have barrier from compute inside a render pass,
// as it is invalid to specify compute in the subpass dependency stage mask.
lastReadStage &= ~PipelineStageFlags.ComputeShaderBit;
}
if (lastReadStage != PipelineStageFlags.None)
{
TextureView.InsertMemoryBarrier(
_gd.Api, _gd.Api,
cbs.CommandBuffer, cbs.CommandBuffer,
_imageAuto.Get(cbs).Value,
_lastReadAccess, _lastReadAccess,
dstAccessFlags, dstAccessFlags,
_lastReadStage, lastReadStage,
dstStageFlags, dstStageFlags);
aspectFlags,
0,
0,
_info.GetLayers(),
_info.Levels);
_lastReadAccess = AccessFlags.None; _lastReadAccess = AccessFlags.None;
_lastReadStage = PipelineStageFlags.None; _lastReadStage = PipelineStageFlags.None;
@@ -472,21 +474,13 @@ namespace Ryujinx.Graphics.Vulkan
if (_lastModificationAccess != AccessFlags.None) if (_lastModificationAccess != AccessFlags.None)
{ {
ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags(); TextureView.InsertMemoryBarrier(
TextureView.InsertImageBarrier(
_gd.Api, _gd.Api,
cbs.CommandBuffer, cbs.CommandBuffer,
_imageAuto.Get(cbs).Value,
_lastModificationAccess, _lastModificationAccess,
dstAccessFlags, dstAccessFlags,
_lastModificationStage, _lastModificationStage,
dstStageFlags, dstStageFlags);
aspectFlags,
0,
0,
_info.GetLayers(),
_info.Levels);
_lastModificationAccess = AccessFlags.None; _lastModificationAccess = AccessFlags.None;
} }

View File

@@ -435,6 +435,34 @@ namespace Ryujinx.Graphics.Vulkan
ImageAspectFlags.ColorBit); ImageAspectFlags.ColorBit);
} }
public static unsafe void InsertMemoryBarrier(
Vk api,
CommandBuffer commandBuffer,
AccessFlags srcAccessMask,
AccessFlags dstAccessMask,
PipelineStageFlags srcStageMask,
PipelineStageFlags dstStageMask)
{
MemoryBarrier memoryBarrier = new()
{
SType = StructureType.MemoryBarrier,
SrcAccessMask = srcAccessMask,
DstAccessMask = dstAccessMask,
};
api.CmdPipelineBarrier(
commandBuffer,
srcStageMask,
dstStageMask,
DependencyFlags.None,
1,
memoryBarrier,
0,
null,
0,
null);
}
public static unsafe void InsertImageBarrier( public static unsafe void InsertImageBarrier(
Vk api, Vk api,
CommandBuffer commandBuffer, CommandBuffer commandBuffer,

View File

@@ -327,6 +327,7 @@ namespace Ryujinx.Graphics.Vulkan
features2.Features.OcclusionQueryPrecise, features2.Features.OcclusionQueryPrecise,
_physicalDevice.PhysicalDeviceFeatures.PipelineStatisticsQuery, _physicalDevice.PhysicalDeviceFeatures.PipelineStatisticsQuery,
_physicalDevice.PhysicalDeviceFeatures.GeometryShader, _physicalDevice.PhysicalDeviceFeatures.GeometryShader,
_physicalDevice.PhysicalDeviceFeatures.TessellationShader,
_physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"), _physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"),
_physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName), _physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName),
supportsDepthClipControl && featuresDepthClipControl.DepthClipControl, supportsDepthClipControl && featuresDepthClipControl.DepthClipControl,

View File

@@ -22,8 +22,10 @@ namespace Ryujinx.Graphics.Vulkan
private Image[] _swapchainImages; private Image[] _swapchainImages;
private Auto<DisposableImageView>[] _swapchainImageViews; private Auto<DisposableImageView>[] _swapchainImageViews;
private Semaphore _imageAvailableSemaphore; private Semaphore[] _imageAvailableSemaphores;
private Semaphore _renderFinishedSemaphore; private Semaphore[] _renderFinishedSemaphores;
private int _frameIndex;
private int _width; private int _width;
private int _height; private int _height;
@@ -48,14 +50,6 @@ namespace Ryujinx.Graphics.Vulkan
_surface = surface; _surface = surface;
CreateSwapchain(); CreateSwapchain();
var semaphoreCreateInfo = new SemaphoreCreateInfo
{
SType = StructureType.SemaphoreCreateInfo,
};
gd.Api.CreateSemaphore(device, semaphoreCreateInfo, null, out _imageAvailableSemaphore).ThrowOnError();
gd.Api.CreateSemaphore(device, semaphoreCreateInfo, null, out _renderFinishedSemaphore).ThrowOnError();
} }
private void RecreateSwapchain() private void RecreateSwapchain()
@@ -69,7 +63,22 @@ namespace Ryujinx.Graphics.Vulkan
} }
// Destroy old Swapchain. // Destroy old Swapchain.
_gd.Api.DeviceWaitIdle(_device); _gd.Api.DeviceWaitIdle(_device);
unsafe
{
for (int i = 0; i < _imageAvailableSemaphores.Length; i++)
{
_gd.Api.DestroySemaphore(_device, _imageAvailableSemaphores[i], null);
}
for (int i = 0; i < _renderFinishedSemaphores.Length; i++)
{
_gd.Api.DestroySemaphore(_device, _renderFinishedSemaphores[i], null);
}
}
_gd.SwapchainApi.DestroySwapchain(_device, oldSwapchain, Span<AllocationCallbacks>.Empty); _gd.SwapchainApi.DestroySwapchain(_device, oldSwapchain, Span<AllocationCallbacks>.Empty);
CreateSwapchain(); CreateSwapchain();
@@ -151,6 +160,25 @@ namespace Ryujinx.Graphics.Vulkan
{ {
_swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format); _swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format);
} }
var semaphoreCreateInfo = new SemaphoreCreateInfo
{
SType = StructureType.SemaphoreCreateInfo,
};
_imageAvailableSemaphores = new Semaphore[imageCount];
for (int i = 0; i < _imageAvailableSemaphores.Length; i++)
{
_gd.Api.CreateSemaphore(_device, semaphoreCreateInfo, null, out _imageAvailableSemaphores[i]).ThrowOnError();
}
_renderFinishedSemaphores = new Semaphore[imageCount];
for (int i = 0; i < _renderFinishedSemaphores.Length; i++)
{
_gd.Api.CreateSemaphore(_device, semaphoreCreateInfo, null, out _renderFinishedSemaphores[i]).ThrowOnError();
}
} }
private unsafe Auto<DisposableImageView> CreateSwapchainImageView(Image swapchainImage, VkFormat format) private unsafe Auto<DisposableImageView> CreateSwapchainImageView(Image swapchainImage, VkFormat format)
@@ -185,6 +213,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
return new SurfaceFormatKHR(VkFormat.B8G8R8A8Unorm, ColorSpaceKHR.PaceSrgbNonlinearKhr); return new SurfaceFormatKHR(VkFormat.B8G8R8A8Unorm, ColorSpaceKHR.PaceSrgbNonlinearKhr);
} }
var formatToReturn = availableFormats[0]; var formatToReturn = availableFormats[0];
if (colorSpacePassthroughEnabled) if (colorSpacePassthroughEnabled)
{ {
@@ -212,6 +241,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
} }
return formatToReturn; return formatToReturn;
} }
@@ -265,6 +295,7 @@ namespace Ryujinx.Graphics.Vulkan
_gd.PipelineInternal.AutoFlush.Present(); _gd.PipelineInternal.AutoFlush.Present();
uint nextImage = 0; uint nextImage = 0;
int semaphoreIndex = _frameIndex++ % _imageAvailableSemaphores.Length;
while (true) while (true)
{ {
@@ -272,7 +303,7 @@ namespace Ryujinx.Graphics.Vulkan
_device, _device,
_swapchain, _swapchain,
ulong.MaxValue, ulong.MaxValue,
_imageAvailableSemaphore, _imageAvailableSemaphores[semaphoreIndex],
new Fence(), new Fence(),
ref nextImage); ref nextImage);
@@ -411,12 +442,12 @@ namespace Ryujinx.Graphics.Vulkan
_gd.CommandBufferPool.Return( _gd.CommandBufferPool.Return(
cbs, cbs,
stackalloc[] { _imageAvailableSemaphore }, stackalloc[] { _imageAvailableSemaphores[semaphoreIndex] },
stackalloc[] { PipelineStageFlags.ColorAttachmentOutputBit }, stackalloc[] { PipelineStageFlags.ColorAttachmentOutputBit },
stackalloc[] { _renderFinishedSemaphore }); stackalloc[] { _renderFinishedSemaphores[semaphoreIndex] });
// TODO: Present queue. // TODO: Present queue.
var semaphore = _renderFinishedSemaphore; var semaphore = _renderFinishedSemaphores[semaphoreIndex];
var swapchain = _swapchain; var swapchain = _swapchain;
Result result; Result result;
@@ -593,14 +624,21 @@ namespace Ryujinx.Graphics.Vulkan
{ {
unsafe unsafe
{ {
_gd.Api.DestroySemaphore(_device, _renderFinishedSemaphore, null);
_gd.Api.DestroySemaphore(_device, _imageAvailableSemaphore, null);
for (int i = 0; i < _swapchainImageViews.Length; i++) for (int i = 0; i < _swapchainImageViews.Length; i++)
{ {
_swapchainImageViews[i].Dispose(); _swapchainImageViews[i].Dispose();
} }
for (int i = 0; i < _imageAvailableSemaphores.Length; i++)
{
_gd.Api.DestroySemaphore(_device, _imageAvailableSemaphores[i], null);
}
for (int i = 0; i < _renderFinishedSemaphores.Length; i++)
{
_gd.Api.DestroySemaphore(_device, _renderFinishedSemaphores[i], null);
}
_gd.SwapchainApi.DestroySwapchain(_device, _swapchain, null); _gd.SwapchainApi.DestroySwapchain(_device, _swapchain, null);
} }

View File

@@ -68,15 +68,15 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
int ryujinxLogoSize = 32; int ryujinxLogoSize = 32;
string ryujinxIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Logo_Ryujinx.png"; string ryujinxIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Logo_Ryujinx.png";
_ryujinxLogo = LoadResource(Assembly.GetExecutingAssembly(), ryujinxIconPath, ryujinxLogoSize, ryujinxLogoSize); _ryujinxLogo = LoadResource(typeof(SoftwareKeyboardRendererBase).Assembly, ryujinxIconPath, ryujinxLogoSize, ryujinxLogoSize);
string padAcceptIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnA.png"; string padAcceptIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnA.png";
string padCancelIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnB.png"; string padCancelIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnB.png";
string keyModeIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_KeyF6.png"; string keyModeIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_KeyF6.png";
_padAcceptIcon = LoadResource(Assembly.GetExecutingAssembly(), padAcceptIconPath, 0, 0); _padAcceptIcon = LoadResource(typeof(SoftwareKeyboardRendererBase).Assembly, padAcceptIconPath, 0, 0);
_padCancelIcon = LoadResource(Assembly.GetExecutingAssembly(), padCancelIconPath, 0, 0); _padCancelIcon = LoadResource(typeof(SoftwareKeyboardRendererBase).Assembly, padCancelIconPath, 0, 0);
_keyModeIcon = LoadResource(Assembly.GetExecutingAssembly(), keyModeIconPath, 0, 0); _keyModeIcon = LoadResource(typeof(SoftwareKeyboardRendererBase).Assembly, keyModeIconPath, 0, 0);
Color panelColor = ToColor(uiTheme.DefaultBackgroundColor, 255); Color panelColor = ToColor(uiTheme.DefaultBackgroundColor, 255);
Color panelTransparentColor = ToColor(uiTheme.DefaultBackgroundColor, 150); Color panelTransparentColor = ToColor(uiTheme.DefaultBackgroundColor, 150);

View File

@@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Settings.Types;
using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService; using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Lbl;
using System; using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
@@ -15,7 +16,6 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
private readonly Apm.ManagerServer _apmManagerServer; private readonly Apm.ManagerServer _apmManagerServer;
private readonly Apm.SystemManagerServer _apmSystemManagerServer; private readonly Apm.SystemManagerServer _apmSystemManagerServer;
private readonly Lbl.LblControllerServer _lblControllerServer;
private bool _vrModeEnabled; private bool _vrModeEnabled;
#pragma warning disable CS0414, IDE0052 // Remove unread private member #pragma warning disable CS0414, IDE0052 // Remove unread private member
@@ -34,7 +34,6 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
_apmManagerServer = new Apm.ManagerServer(context); _apmManagerServer = new Apm.ManagerServer(context);
_apmSystemManagerServer = new Apm.SystemManagerServer(context); _apmSystemManagerServer = new Apm.SystemManagerServer(context);
_lblControllerServer = new Lbl.LblControllerServer(context);
_acquiredSleepLockEvent = new KEvent(context.Device.System.KernelContext); _acquiredSleepLockEvent = new KEvent(context.Device.System.KernelContext);
} }
@@ -215,13 +214,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
_vrModeEnabled = vrModeEnabled; _vrModeEnabled = vrModeEnabled;
using var lblApi = new LblApi();
if (vrModeEnabled) if (vrModeEnabled)
{ {
_lblControllerServer.EnableVrMode(); lblApi.EnableVrMode().AbortOnFailure();
} }
else else
{ {
_lblControllerServer.DisableVrMode(); lblApi.DisableVrMode().AbortOnFailure();
} }
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used. // TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.

View File

@@ -23,14 +23,14 @@ namespace Ryujinx.HLE.HOS.Services
public IpcService(ServerBase server = null) public IpcService(ServerBase server = null)
{ {
CmifCommands = Assembly.GetExecutingAssembly().GetTypes() CmifCommands = typeof(IpcService).Assembly.GetTypes()
.Where(type => type == GetType()) .Where(type => type == GetType())
.SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public)) .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public))
.SelectMany(methodInfo => methodInfo.GetCustomAttributes(typeof(CommandCmifAttribute)) .SelectMany(methodInfo => methodInfo.GetCustomAttributes(typeof(CommandCmifAttribute))
.Select(command => (((CommandCmifAttribute)command).Id, methodInfo))) .Select(command => (((CommandCmifAttribute)command).Id, methodInfo)))
.ToDictionary(command => command.Id, command => command.methodInfo); .ToDictionary(command => command.Id, command => command.methodInfo);
TipcCommands = Assembly.GetExecutingAssembly().GetTypes() TipcCommands = typeof(IpcService).Assembly.GetTypes()
.Where(type => type == GetType()) .Where(type => type == GetType())
.SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public)) .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public))
.SelectMany(methodInfo => methodInfo.GetCustomAttributes(typeof(CommandTipcAttribute)) .SelectMany(methodInfo => methodInfo.GetCustomAttributes(typeof(CommandTipcAttribute))

View File

@@ -1,92 +0,0 @@
namespace Ryujinx.HLE.HOS.Services.Lbl
{
abstract class ILblController : IpcService
{
public ILblController(ServiceCtx context) { }
protected abstract void SetCurrentBrightnessSettingForVrMode(float currentBrightnessSettingForVrMode);
protected abstract float GetCurrentBrightnessSettingForVrMode();
internal abstract void EnableVrMode();
internal abstract void DisableVrMode();
protected abstract bool IsVrModeEnabled();
[CommandCmif(17)]
// SetBrightnessReflectionDelayLevel(float, float)
public ResultCode SetBrightnessReflectionDelayLevel(ServiceCtx context)
{
return ResultCode.Success;
}
[CommandCmif(18)]
// GetBrightnessReflectionDelayLevel(float) -> float
public ResultCode GetBrightnessReflectionDelayLevel(ServiceCtx context)
{
context.ResponseData.Write(0.0f);
return ResultCode.Success;
}
[CommandCmif(21)]
// SetCurrentAmbientLightSensorMapping(unknown<0xC>)
public ResultCode SetCurrentAmbientLightSensorMapping(ServiceCtx context)
{
return ResultCode.Success;
}
[CommandCmif(22)]
// GetCurrentAmbientLightSensorMapping() -> unknown<0xC>
public ResultCode GetCurrentAmbientLightSensorMapping(ServiceCtx context)
{
return ResultCode.Success;
}
[CommandCmif(24)] // 3.0.0+
// SetCurrentBrightnessSettingForVrMode(float)
public ResultCode SetCurrentBrightnessSettingForVrMode(ServiceCtx context)
{
float currentBrightnessSettingForVrMode = context.RequestData.ReadSingle();
SetCurrentBrightnessSettingForVrMode(currentBrightnessSettingForVrMode);
return ResultCode.Success;
}
[CommandCmif(25)] // 3.0.0+
// GetCurrentBrightnessSettingForVrMode() -> float
public ResultCode GetCurrentBrightnessSettingForVrMode(ServiceCtx context)
{
float currentBrightnessSettingForVrMode = GetCurrentBrightnessSettingForVrMode();
context.ResponseData.Write(currentBrightnessSettingForVrMode);
return ResultCode.Success;
}
[CommandCmif(26)] // 3.0.0+
// EnableVrMode()
public ResultCode EnableVrMode(ServiceCtx context)
{
EnableVrMode();
return ResultCode.Success;
}
[CommandCmif(27)] // 3.0.0+
// DisableVrMode()
public ResultCode DisableVrMode(ServiceCtx context)
{
DisableVrMode();
return ResultCode.Success;
}
[CommandCmif(28)] // 3.0.0+
// IsVrModeEnabled() -> bool
public ResultCode IsVrModeEnabled(ServiceCtx context)
{
context.ResponseData.Write(IsVrModeEnabled());
return ResultCode.Success;
}
}
}

View File

@@ -1,54 +0,0 @@
namespace Ryujinx.HLE.HOS.Services.Lbl
{
[Service("lbl")]
class LblControllerServer : ILblController
{
private bool _vrModeEnabled;
private float _currentBrightnessSettingForVrMode;
public LblControllerServer(ServiceCtx context) : base(context) { }
protected override void SetCurrentBrightnessSettingForVrMode(float currentBrightnessSettingForVrMode)
{
if (float.IsNaN(currentBrightnessSettingForVrMode) || float.IsInfinity(currentBrightnessSettingForVrMode))
{
_currentBrightnessSettingForVrMode = 0.0f;
return;
}
_currentBrightnessSettingForVrMode = currentBrightnessSettingForVrMode;
}
protected override float GetCurrentBrightnessSettingForVrMode()
{
if (float.IsNaN(_currentBrightnessSettingForVrMode) || float.IsInfinity(_currentBrightnessSettingForVrMode))
{
return 0.0f;
}
return _currentBrightnessSettingForVrMode;
}
internal override void EnableVrMode()
{
_vrModeEnabled = true;
// NOTE: Service check _vrModeEnabled field value in a thread and then change the screen brightness.
// Since we don't support that. It's fine to do nothing.
}
internal override void DisableVrMode()
{
_vrModeEnabled = false;
// NOTE: Service check _vrModeEnabled field value in a thread and then change the screen brightness.
// Since we don't support that. It's fine to do nothing.
}
protected override bool IsVrModeEnabled()
{
return _vrModeEnabled;
}
}
}

View File

@@ -6,6 +6,7 @@ using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Ipc; using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.Horizon;
using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Common;
using System; using System;
using System.Buffers; using System.Buffers;
@@ -172,6 +173,13 @@ namespace Ryujinx.HLE.HOS.Services
_selfProcess = KernelStatic.GetCurrentProcess(); _selfProcess = KernelStatic.GetCurrentProcess();
_selfThread = KernelStatic.GetCurrentThread(); _selfThread = KernelStatic.GetCurrentThread();
HorizonStatic.Register(
default,
_context.Syscall,
_selfProcess.CpuMemory,
_selfThread.ThreadContext,
(int)_selfThread.ThreadContext.GetX(1));
if (SmObjectFactory != null) if (SmObjectFactory != null)
{ {
_context.Syscall.ManageNamedPort(out int serverPortHandle, "sm:", 50); _context.Syscall.ManageNamedPort(out int serverPortHandle, "sm:", 50);

View File

@@ -28,7 +28,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
static IUserInterface() static IUserInterface()
{ {
_services = Assembly.GetExecutingAssembly().GetTypes() _services = typeof(IUserInterface).Assembly.GetTypes()
.SelectMany(type => type.GetCustomAttributes(typeof(ServiceAttribute), true) .SelectMany(type => type.GetCustomAttributes(typeof(ServiceAttribute), true)
.Select(service => (((ServiceAttribute)service).Name, type))) .Select(service => (((ServiceAttribute)service).Name, type)))
.ToDictionary(service => service.Name, service => service.type); .ToDictionary(service => service.Name, service => service.type);

View File

@@ -299,11 +299,21 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
try try
{ {
LinuxError result = WinSockHelper.ValidateSocketOption(option, level, write: false);
if (result != LinuxError.SUCCESS)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Invalid GetSockOpt Option: {option} Level: {level}");
return result;
}
if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName)) if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName))
{ {
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt Option: {option} Level: {level}"); Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt Option: {option} Level: {level}");
optionValue.Clear();
return LinuxError.EOPNOTSUPP; return LinuxError.SUCCESS;
} }
byte[] tempOptionValue = new byte[optionValue.Length]; byte[] tempOptionValue = new byte[optionValue.Length];
@@ -324,11 +334,20 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
try try
{ {
LinuxError result = WinSockHelper.ValidateSocketOption(option, level, write: true);
if (result != LinuxError.SUCCESS)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Invalid SetSockOpt Option: {option} Level: {level}");
return result;
}
if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName)) if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName))
{ {
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt Option: {option} Level: {level}"); Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt Option: {option} Level: {level}");
return LinuxError.EOPNOTSUPP; return LinuxError.SUCCESS;
} }
int value = optionValue.Length >= 4 ? MemoryMarshal.Read<int>(optionValue) : MemoryMarshal.Read<byte>(optionValue); int value = optionValue.Length >= 4 ? MemoryMarshal.Read<int>(optionValue) : MemoryMarshal.Read<byte>(optionValue);

View File

@@ -183,6 +183,104 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ BsdSocketOption.TcpKeepCnt, SocketOptionName.TcpKeepAliveRetryCount }, { BsdSocketOption.TcpKeepCnt, SocketOptionName.TcpKeepAliveRetryCount },
}; };
[Flags]
private enum OptionDir
{
Get = 1 << 0,
Set = 1 << 1,
GetSet = Get | Set,
}
private static readonly Dictionary<BsdSocketOption, OptionDir> _validSoSocketOptionMap = new()
{
{ BsdSocketOption.SoDebug, OptionDir.GetSet },
{ BsdSocketOption.SoAcceptConn, OptionDir.Get },
{ BsdSocketOption.SoReuseAddr, OptionDir.GetSet },
{ BsdSocketOption.SoKeepAlive, OptionDir.GetSet },
{ BsdSocketOption.SoDontRoute, OptionDir.GetSet },
{ BsdSocketOption.SoBroadcast, OptionDir.GetSet },
{ BsdSocketOption.SoUseLoopBack, OptionDir.GetSet },
{ BsdSocketOption.SoLinger, OptionDir.GetSet },
{ BsdSocketOption.SoOobInline, OptionDir.GetSet },
{ BsdSocketOption.SoReusePort, OptionDir.GetSet },
{ BsdSocketOption.SoTimestamp, OptionDir.GetSet },
{ BsdSocketOption.SoNoSigpipe, OptionDir.GetSet },
{ BsdSocketOption.SoAcceptFilter, OptionDir.GetSet },
{ BsdSocketOption.SoSndBuf, OptionDir.GetSet },
{ BsdSocketOption.SoRcvBuf, OptionDir.GetSet },
{ BsdSocketOption.SoSndLoWat, OptionDir.GetSet },
{ BsdSocketOption.SoRcvLoWat, OptionDir.GetSet },
{ BsdSocketOption.SoSndTimeo, OptionDir.GetSet },
{ BsdSocketOption.SoRcvTimeo, OptionDir.GetSet },
{ BsdSocketOption.SoError, OptionDir.Get },
{ BsdSocketOption.SoType, OptionDir.Get },
{ BsdSocketOption.SoLabel, OptionDir.Get },
{ BsdSocketOption.SoPeerLabel, OptionDir.Get },
{ BsdSocketOption.SoListenQLimit, OptionDir.Get },
{ BsdSocketOption.SoListenQLen, OptionDir.Get },
{ BsdSocketOption.SoListenIncQLen, OptionDir.Get },
{ BsdSocketOption.SoSetFib, OptionDir.Set },
{ BsdSocketOption.SoUserCookie, OptionDir.Set },
{ BsdSocketOption.SoProtocol, OptionDir.Get },
{ BsdSocketOption.SoBinTime, OptionDir.GetSet },
{ BsdSocketOption.SoNoOffload, OptionDir.Set },
{ BsdSocketOption.SoNoDdp, OptionDir.Set },
{ BsdSocketOption.SoReusePortLb, OptionDir.GetSet },
};
private static readonly Dictionary<BsdSocketOption, OptionDir> _validIpSocketOptionMap = new()
{
{ BsdSocketOption.IpOptions, OptionDir.GetSet },
{ BsdSocketOption.IpHdrIncl, OptionDir.GetSet },
{ BsdSocketOption.IpTos, OptionDir.GetSet },
{ BsdSocketOption.IpTtl, OptionDir.GetSet },
{ BsdSocketOption.IpRecvOpts, OptionDir.GetSet },
{ BsdSocketOption.IpRecvRetOpts, OptionDir.GetSet },
{ BsdSocketOption.IpRecvDstAddr, OptionDir.GetSet },
{ BsdSocketOption.IpRetOpts, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastIf, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastTtl, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastLoop, OptionDir.GetSet },
{ BsdSocketOption.IpAddMembership, OptionDir.GetSet },
{ BsdSocketOption.IpDropMembership, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastVif, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpOn, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpOff, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpVifOn, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpVifOff, OptionDir.GetSet },
{ BsdSocketOption.IpPortRange, OptionDir.GetSet },
{ BsdSocketOption.IpRecvIf, OptionDir.GetSet },
{ BsdSocketOption.IpIpsecPolicy, OptionDir.GetSet },
{ BsdSocketOption.IpOnesBcast, OptionDir.GetSet },
{ BsdSocketOption.IpBindany, OptionDir.GetSet },
{ BsdSocketOption.IpBindMulti, OptionDir.GetSet },
{ BsdSocketOption.IpRssListenBucket, OptionDir.GetSet },
{ BsdSocketOption.IpOrigDstAddr, OptionDir.GetSet },
{ BsdSocketOption.IpRecvTtl, OptionDir.GetSet },
{ BsdSocketOption.IpMinTtl, OptionDir.GetSet },
{ BsdSocketOption.IpDontFrag, OptionDir.GetSet },
{ BsdSocketOption.IpRecvTos, OptionDir.GetSet },
{ BsdSocketOption.IpAddSourceMembership, OptionDir.GetSet },
{ BsdSocketOption.IpDropSourceMembership, OptionDir.GetSet },
{ BsdSocketOption.IpBlockSource, OptionDir.GetSet },
{ BsdSocketOption.IpUnblockSource, OptionDir.GetSet },
};
private static readonly Dictionary<BsdSocketOption, OptionDir> _validTcpSocketOptionMap = new()
{
{ BsdSocketOption.TcpNoDelay, OptionDir.GetSet },
{ BsdSocketOption.TcpMaxSeg, OptionDir.GetSet },
{ BsdSocketOption.TcpNoPush, OptionDir.GetSet },
{ BsdSocketOption.TcpNoOpt, OptionDir.GetSet },
{ BsdSocketOption.TcpMd5Sig, OptionDir.GetSet },
{ BsdSocketOption.TcpInfo, OptionDir.GetSet },
{ BsdSocketOption.TcpCongestion, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepInit, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepIdle, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepIntvl, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepCnt, OptionDir.GetSet },
};
public static LinuxError ConvertError(WsaError errorCode) public static LinuxError ConvertError(WsaError errorCode)
{ {
if (OperatingSystem.IsMacOS()) if (OperatingSystem.IsMacOS())
@@ -221,5 +319,29 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
return table.TryGetValue(option, out name); return table.TryGetValue(option, out name);
} }
public static LinuxError ValidateSocketOption(BsdSocketOption option, SocketOptionLevel level, bool write)
{
var table = level switch
{
SocketOptionLevel.Socket => _validSoSocketOptionMap,
SocketOptionLevel.IP => _validIpSocketOptionMap,
SocketOptionLevel.Tcp => _validTcpSocketOptionMap,
_ => null,
};
OptionDir dir = write ? OptionDir.Set : OptionDir.Get;
if (table == null || !table.TryGetValue(option, out OptionDir validDir))
{
return LinuxError.ENOPROTOOPT;
}
else if ((validDir & dir) != dir)
{
return LinuxError.EOPNOTSUPP;
}
return LinuxError.SUCCESS;
}
} }
} }

View File

@@ -17,7 +17,6 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using static SDL2.SDL; using static SDL2.SDL;
@@ -122,7 +121,7 @@ namespace Ryujinx.Headless.SDL2
private void SetWindowIcon() private void SetWindowIcon()
{ {
Stream iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Ryujinx.Headless.SDL2.Ryujinx.bmp"); Stream iconStream = typeof(WindowBase).Assembly.GetManifestResourceStream("Ryujinx.Headless.SDL2.Ryujinx.bmp");
byte[] iconBytes = new byte[iconStream!.Length]; byte[] iconBytes = new byte[iconStream!.Length];
if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length) if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length)

View File

@@ -6,8 +6,8 @@ namespace Ryujinx.Horizon.Bcat
{ {
internal class BcatIpcServer internal class BcatIpcServer
{ {
private const int BcatMaxSessionsCount = 8; private const int MaxSessionsCount = 8;
private const int BcatTotalMaxSessionsCount = BcatMaxSessionsCount * 4; private const int TotalMaxSessionsCount = MaxSessionsCount * 4;
private const int PointerBufferSize = 0x400; private const int PointerBufferSize = 0x400;
private const int MaxDomains = 64; private const int MaxDomains = 64;
@@ -17,7 +17,7 @@ namespace Ryujinx.Horizon.Bcat
private SmApi _sm; private SmApi _sm;
private BcatServerManager _serverManager; private BcatServerManager _serverManager;
private static readonly ManagerOptions _bcatManagerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
internal void Initialize() internal void Initialize()
{ {
@@ -26,13 +26,13 @@ namespace Ryujinx.Horizon.Bcat
_sm = new SmApi(); _sm = new SmApi();
_sm.Initialize().AbortOnFailure(); _sm.Initialize().AbortOnFailure();
_serverManager = new BcatServerManager(allocator, _sm, MaxPortsCount, _bcatManagerOptions, BcatTotalMaxSessionsCount); _serverManager = new BcatServerManager(allocator, _sm, MaxPortsCount, _managerOptions, TotalMaxSessionsCount);
#pragma warning disable IDE0055 // Disable formatting #pragma warning disable IDE0055 // Disable formatting
_serverManager.RegisterServer((int)BcatPortIndex.Admin, ServiceName.Encode("bcat:a"), BcatMaxSessionsCount); _serverManager.RegisterServer((int)BcatPortIndex.Admin, ServiceName.Encode("bcat:a"), MaxSessionsCount);
_serverManager.RegisterServer((int)BcatPortIndex.Manager, ServiceName.Encode("bcat:m"), BcatMaxSessionsCount); _serverManager.RegisterServer((int)BcatPortIndex.Manager, ServiceName.Encode("bcat:m"), MaxSessionsCount);
_serverManager.RegisterServer((int)BcatPortIndex.User, ServiceName.Encode("bcat:u"), BcatMaxSessionsCount); _serverManager.RegisterServer((int)BcatPortIndex.User, ServiceName.Encode("bcat:u"), MaxSessionsCount);
_serverManager.RegisterServer((int)BcatPortIndex.System, ServiceName.Encode("bcat:s"), BcatMaxSessionsCount); _serverManager.RegisterServer((int)BcatPortIndex.System, ServiceName.Encode("bcat:s"), MaxSessionsCount);
#pragma warning restore IDE0055 #pragma warning restore IDE0055
} }

View File

@@ -4,7 +4,7 @@ using System;
namespace Ryujinx.Horizon namespace Ryujinx.Horizon
{ {
static class HorizonStatic public static class HorizonStatic
{ {
[ThreadStatic] [ThreadStatic]
private static HorizonOptions _options; private static HorizonOptions _options;

View File

@@ -0,0 +1,130 @@
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Lbl;
using Ryujinx.Horizon.Sdk.Sf;
namespace Ryujinx.Horizon.Lbl.Ipc
{
partial class LblController : ILblController
{
private bool _vrModeEnabled;
private float _currentBrightnessSettingForVrMode;
[CmifCommand(17)]
public Result SetBrightnessReflectionDelayLevel(float unknown0, float unknown1)
{
// NOTE: Stubbed in system module.
return Result.Success;
}
[CmifCommand(18)]
public Result GetBrightnessReflectionDelayLevel(out float unknown1, float unknown0)
{
// NOTE: Stubbed in system module.
unknown1 = 0.0f;
return Result.Success;
}
[CmifCommand(19)]
public Result SetCurrentBrightnessMapping(float unknown0, float unknown1, float unknown2)
{
// NOTE: Stubbed in system module.
return Result.Success;
}
[CmifCommand(20)]
public Result GetCurrentBrightnessMapping(out float unknown0, out float unknown1, out float unknown2)
{
// NOTE: Stubbed in system module.
unknown0 = 0.0f;
unknown1 = 0.0f;
unknown2 = 0.0f;
return Result.Success;
}
[CmifCommand(21)]
public Result SetCurrentAmbientLightSensorMapping(float unknown0, float unknown1, float unknown2)
{
// NOTE: Stubbed in system module.
return Result.Success;
}
[CmifCommand(22)]
public Result GetCurrentAmbientLightSensorMapping(out float unknown0, out float unknown1, out float unknown2)
{
// NOTE: Stubbed in system module.
unknown0 = 0.0f;
unknown1 = 0.0f;
unknown2 = 0.0f;
return Result.Success;
}
[CmifCommand(24)]
public Result SetCurrentBrightnessSettingForVrMode(float currentBrightnessSettingForVrMode)
{
if (float.IsNaN(currentBrightnessSettingForVrMode) || float.IsInfinity(currentBrightnessSettingForVrMode))
{
_currentBrightnessSettingForVrMode = 0.0f;
}
else
{
_currentBrightnessSettingForVrMode = currentBrightnessSettingForVrMode;
}
return Result.Success;
}
[CmifCommand(25)]
public Result GetCurrentBrightnessSettingForVrMode(out float currentBrightnessSettingForVrMode)
{
if (float.IsNaN(_currentBrightnessSettingForVrMode) || float.IsInfinity(_currentBrightnessSettingForVrMode))
{
currentBrightnessSettingForVrMode = 0.0f;
}
else
{
currentBrightnessSettingForVrMode = _currentBrightnessSettingForVrMode;
}
return Result.Success;
}
[CmifCommand(26)]
public Result EnableVrMode()
{
_vrModeEnabled = true;
// NOTE: The service checks _vrModeEnabled field value in a thread and then changes the screen brightness.
// Since we don't support that, it's fine to do nothing.
return Result.Success;
}
[CmifCommand(27)]
public Result DisableVrMode()
{
_vrModeEnabled = false;
// NOTE: The service checks _vrModeEnabled field value in a thread and then changes the screen brightness.
// Since we don't support that, it's fine to do nothing.
return Result.Success;
}
[CmifCommand(28)]
public Result IsVrModeEnabled(out bool vrModeEnabled)
{
vrModeEnabled = _vrModeEnabled;
return Result.Success;
}
}
}

View File

@@ -0,0 +1,43 @@
using Ryujinx.Horizon.Lbl.Ipc;
using Ryujinx.Horizon.Sdk.Sf.Hipc;
using Ryujinx.Horizon.Sdk.Sm;
namespace Ryujinx.Horizon.Lbl
{
class LblIpcServer
{
private const int MaxSessionsCount = 5;
private const int PointerBufferSize = 0;
private const int MaxDomains = 0;
private const int MaxDomainObjects = 0;
private const int MaxPortsCount = 1;
private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
private SmApi _sm;
private ServerManager _serverManager;
public void Initialize()
{
HeapAllocator allocator = new();
_sm = new SmApi();
_sm.Initialize().AbortOnFailure();
_serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _managerOptions, MaxSessionsCount);
_serverManager.RegisterObjectForServer(new LblController(), ServiceName.Encode("lbl"), MaxSessionsCount);
}
public void ServiceRequests()
{
_serverManager.ServiceRequests();
}
public void Shutdown()
{
_serverManager.Dispose();
}
}
}

View File

@@ -0,0 +1,17 @@
namespace Ryujinx.Horizon.Lbl
{
class LblMain : IService
{
public static void Main(ServiceTable serviceTable)
{
LblIpcServer ipcServer = new();
ipcServer.Initialize();
serviceTable.SignalServiceReady();
ipcServer.ServiceRequests();
ipcServer.Shutdown();
}
}
}

View File

@@ -6,14 +6,14 @@ namespace Ryujinx.Horizon.LogManager
{ {
class LmIpcServer class LmIpcServer
{ {
private const int LogMaxSessionsCount = 42; private const int MaxSessionsCount = 42;
private const int PointerBufferSize = 0x400; private const int PointerBufferSize = 0x400;
private const int MaxDomains = 31; private const int MaxDomains = 31;
private const int MaxDomainObjects = 61; private const int MaxDomainObjects = 61;
private const int MaxPortsCount = 1; private const int MaxPortsCount = 1;
private static readonly ManagerOptions _logManagerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
private SmApi _sm; private SmApi _sm;
private ServerManager _serverManager; private ServerManager _serverManager;
@@ -25,9 +25,9 @@ namespace Ryujinx.Horizon.LogManager
_sm = new SmApi(); _sm = new SmApi();
_sm.Initialize().AbortOnFailure(); _sm.Initialize().AbortOnFailure();
_serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _logManagerOptions, LogMaxSessionsCount); _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _managerOptions, MaxSessionsCount);
_serverManager.RegisterObjectForServer(new LogService(), ServiceName.Encode("lm"), LogMaxSessionsCount); _serverManager.RegisterObjectForServer(new LogService(), ServiceName.Encode("lm"), MaxSessionsCount);
} }
public void ServiceRequests() public void ServiceRequests()

View File

@@ -6,14 +6,14 @@ namespace Ryujinx.Horizon.MmNv
{ {
class MmNvIpcServer class MmNvIpcServer
{ {
private const int MmNvMaxSessionsCount = 9; private const int MaxSessionsCount = 40;
private const int PointerBufferSize = 0; private const int PointerBufferSize = 0;
private const int MaxDomains = 0; private const int MaxDomains = 0;
private const int MaxDomainObjects = 0; private const int MaxDomainObjects = 0;
private const int MaxPortsCount = 1; private const int MaxPortsCount = 1;
private static readonly ManagerOptions _mmNvOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
private SmApi _sm; private SmApi _sm;
private ServerManager _serverManager; private ServerManager _serverManager;
@@ -25,9 +25,9 @@ namespace Ryujinx.Horizon.MmNv
_sm = new SmApi(); _sm = new SmApi();
_sm.Initialize().AbortOnFailure(); _sm.Initialize().AbortOnFailure();
_serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _mmNvOptions, MmNvMaxSessionsCount); _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _managerOptions, MaxSessionsCount);
_serverManager.RegisterObjectForServer(new Request(), ServiceName.Encode("mm:u"), MmNvMaxSessionsCount); _serverManager.RegisterObjectForServer(new Request(), ServiceName.Encode("mm:u"), MaxSessionsCount);
} }
public void ServiceRequests() public void ServiceRequests()

View File

@@ -6,15 +6,15 @@ namespace Ryujinx.Horizon.Prepo
{ {
class PrepoIpcServer class PrepoIpcServer
{ {
private const int PrepoMaxSessionsCount = 12; private const int MaxSessionsCount = 12;
private const int PrepoTotalMaxSessionsCount = PrepoMaxSessionsCount * 6; private const int TotalMaxSessionsCount = MaxSessionsCount * 6;
private const int PointerBufferSize = 0x80; private const int PointerBufferSize = 0x80;
private const int MaxDomains = 64; private const int MaxDomains = 64;
private const int MaxDomainObjects = 16; private const int MaxDomainObjects = 16;
private const int MaxPortsCount = 6; private const int MaxPortsCount = 6;
private static readonly ManagerOptions _prepoManagerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
private SmApi _sm; private SmApi _sm;
private PrepoServerManager _serverManager; private PrepoServerManager _serverManager;
@@ -26,15 +26,15 @@ namespace Ryujinx.Horizon.Prepo
_sm = new SmApi(); _sm = new SmApi();
_sm.Initialize().AbortOnFailure(); _sm.Initialize().AbortOnFailure();
_serverManager = new PrepoServerManager(allocator, _sm, MaxPortsCount, _prepoManagerOptions, PrepoTotalMaxSessionsCount); _serverManager = new PrepoServerManager(allocator, _sm, MaxPortsCount, _managerOptions, TotalMaxSessionsCount);
#pragma warning disable IDE0055 // Disable formatting #pragma warning disable IDE0055 // Disable formatting
_serverManager.RegisterServer((int)PrepoPortIndex.Admin, ServiceName.Encode("prepo:a"), PrepoMaxSessionsCount); // 1.0.0-5.1.0 _serverManager.RegisterServer((int)PrepoPortIndex.Admin, ServiceName.Encode("prepo:a"), MaxSessionsCount); // 1.0.0-5.1.0
_serverManager.RegisterServer((int)PrepoPortIndex.Admin2, ServiceName.Encode("prepo:a2"), PrepoMaxSessionsCount); // 6.0.0+ _serverManager.RegisterServer((int)PrepoPortIndex.Admin2, ServiceName.Encode("prepo:a2"), MaxSessionsCount); // 6.0.0+
_serverManager.RegisterServer((int)PrepoPortIndex.Manager, ServiceName.Encode("prepo:m"), PrepoMaxSessionsCount); _serverManager.RegisterServer((int)PrepoPortIndex.Manager, ServiceName.Encode("prepo:m"), MaxSessionsCount);
_serverManager.RegisterServer((int)PrepoPortIndex.User, ServiceName.Encode("prepo:u"), PrepoMaxSessionsCount); _serverManager.RegisterServer((int)PrepoPortIndex.User, ServiceName.Encode("prepo:u"), MaxSessionsCount);
_serverManager.RegisterServer((int)PrepoPortIndex.System, ServiceName.Encode("prepo:s"), PrepoMaxSessionsCount); _serverManager.RegisterServer((int)PrepoPortIndex.System, ServiceName.Encode("prepo:s"), MaxSessionsCount);
_serverManager.RegisterServer((int)PrepoPortIndex.Debug, ServiceName.Encode("prepo:d"), PrepoMaxSessionsCount); // 1.0.0 _serverManager.RegisterServer((int)PrepoPortIndex.Debug, ServiceName.Encode("prepo:d"), MaxSessionsCount); // 1.0.0
#pragma warning restore IDE0055 #pragma warning restore IDE0055
} }

View File

@@ -0,0 +1,20 @@
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Sf;
namespace Ryujinx.Horizon.Sdk.Lbl
{
interface ILblController : IServiceObject
{
Result SetBrightnessReflectionDelayLevel(float unknown0, float unknown1);
Result GetBrightnessReflectionDelayLevel(out float unknown1, float unknown0);
Result SetCurrentBrightnessMapping(float unknown0, float unknown1, float unknown2);
Result GetCurrentBrightnessMapping(out float unknown0, out float unknown1, out float unknown2);
Result SetCurrentAmbientLightSensorMapping(float unknown0, float unknown1, float unknown2);
Result GetCurrentAmbientLightSensorMapping(out float unknown0, out float unknown1, out float unknown2);
Result SetCurrentBrightnessSettingForVrMode(float currentBrightnessSettingForVrMode);
Result GetCurrentBrightnessSettingForVrMode(out float currentBrightnessSettingForVrMode);
Result EnableVrMode();
Result DisableVrMode();
Result IsVrModeEnabled(out bool vrModeEnabled);
}
}

View File

@@ -0,0 +1,43 @@
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Sm;
using System;
namespace Ryujinx.Horizon.Sdk.Lbl
{
public class LblApi : IDisposable
{
private const string LblName = "lbl";
private int _sessionHandle;
public LblApi()
{
using var smApi = new SmApi();
smApi.Initialize();
smApi.GetServiceHandle(out _sessionHandle, ServiceName.Encode(LblName)).AbortOnFailure();
}
public Result EnableVrMode()
{
return ServiceUtil.SendRequest(out _, _sessionHandle, 26, sendPid: false, ReadOnlySpan<byte>.Empty);
}
public Result DisableVrMode()
{
return ServiceUtil.SendRequest(out _, _sessionHandle, 27, sendPid: false, ReadOnlySpan<byte>.Empty);
}
public void Dispose()
{
if (_sessionHandle != 0)
{
HorizonStatic.Syscall.CloseHandle(_sessionHandle);
_sessionHandle = 0;
}
GC.SuppressFinalize(this);
}
}
}

View File

@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.Horizon.Sdk.Sm namespace Ryujinx.Horizon.Sdk.Sm
{ {
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct ServiceName public readonly struct ServiceName
{ {
public static ServiceName Invalid { get; } = new(0); public static ServiceName Invalid { get; } = new(0);

View File

@@ -5,7 +5,7 @@ using System;
namespace Ryujinx.Horizon.Sdk.Sm namespace Ryujinx.Horizon.Sdk.Sm
{ {
class SmApi public class SmApi : IDisposable
{ {
private const string SmName = "sm:"; private const string SmName = "sm:";
@@ -109,5 +109,17 @@ namespace Ryujinx.Horizon.Sdk.Sm
return ServiceUtil.SendRequest(out _, _portHandle, 4, sendPid: true, data); return ServiceUtil.SendRequest(out _, _portHandle, 4, sendPid: true, data);
} }
public void Dispose()
{
if (_portHandle != 0)
{
HorizonStatic.Syscall.CloseHandle(_portHandle);
_portHandle = 0;
}
GC.SuppressFinalize(this);
}
} }
} }

View File

@@ -1,4 +1,5 @@
using Ryujinx.Horizon.Bcat; using Ryujinx.Horizon.Bcat;
using Ryujinx.Horizon.Lbl;
using Ryujinx.Horizon.LogManager; using Ryujinx.Horizon.LogManager;
using Ryujinx.Horizon.MmNv; using Ryujinx.Horizon.MmNv;
using Ryujinx.Horizon.Prepo; using Ryujinx.Horizon.Prepo;
@@ -23,10 +24,11 @@ namespace Ryujinx.Horizon
entries.Add(new ServiceEntry(T.Main, this, options)); entries.Add(new ServiceEntry(T.Main, this, options));
} }
RegisterService<LmMain>();
RegisterService<PrepoMain>();
RegisterService<BcatMain>(); RegisterService<BcatMain>();
RegisterService<LblMain>();
RegisterService<LmMain>();
RegisterService<MmNvMain>(); RegisterService<MmNvMain>();
RegisterService<PrepoMain>();
_totalServices = entries.Count; _totalServices = entries.Count;