Merge branch 'master' into spu-giga-crash-fix

This commit is contained in:
Elad 2025-02-20 17:37:41 +02:00 committed by GitHub
commit 7c02f7e78b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 786 additions and 290 deletions

13
.ci/build-linux-aarch64.sh Normal file → Executable file
View file

@ -12,9 +12,16 @@ git submodule -q update --init $(awk '/path/ && !/llvm/ && !/opencv/ { print $3
mkdir build && cd build || exit 1
export CC="${CLANG_BINARY}"
export CXX="${CLANGXX_BINARY}"
export LINKER="${LLD_BINARY}"
if [ "$COMPILER" = "gcc" ]; then
# These are set in the dockerfile
export CC="${GCC_BINARY}"
export CXX="${GXX_BINARY}"
export LINKER=gold
else
export CC="${CLANG_BINARY}"
export CXX="${CLANGXX_BINARY}"
export LINKER="${LLD_BINARY}"
fi
export CFLAGS="$CFLAGS -fuse-ld=${LINKER}"
export CXXFLAGS="$CXXFLAGS -fuse-ld=${LINKER}"

View file

@ -103,16 +103,24 @@ COMM_HASH=$(git rev-parse --short=8 HEAD)
# Format the above into filenames
if [ -n "$PR_NUMBER" ]; then
AVVER="${COMM_TAG}-${COMM_HASH}"
BUILD="rpcs3-v${AVVER}_win64.7z"
BUILD_RAW="rpcs3-v${AVVER}_win64"
BUILD="${BUILD_RAW}.7z"
else
AVVER="${COMM_TAG}-${COMM_COUNT}"
BUILD="rpcs3-v${AVVER}-${COMM_HASH}_win64.7z"
BUILD_RAW="rpcs3-v${AVVER}-${COMM_HASH}_win64"
BUILD="${BUILD_RAW}.7z"
fi
# BRANCH is used for experimental build warnings for pr builds, used in main_window.cpp.
# BUILD is the name of the release artifact
# BUILD_RAW is just filename
# AVVER is used for GitHub releases, it is the version number.
BRANCH="${REPO_NAME}/${REPO_BRANCH}"
echo "BRANCH=$BRANCH" > .ci/ci-vars.env
echo "BUILD=$BUILD" >> .ci/ci-vars.env
echo "AVVER=$AVVER" >> .ci/ci-vars.env
# SC2129
{
echo "BRANCH=$BRANCH"
echo "BUILD=$BUILD"
echo "BUILD_RAW=$BUILD_RAW"
echo "AVVER=$AVVER"
} >> .ci/ci-vars.env

165
.github/workflows/rpcs3.yml vendored Normal file
View file

@ -0,0 +1,165 @@
name: Build RPCS3
on:
push:
paths-ignore:
- '.cirrus.yml'
- '.azure-pipelines.yml'
- 'README.md'
pull_request:
paths-ignore:
- '.cirrus.yml'
- '.azure-pipelines.yml'
- 'README.md'
workflow_dispatch:
concurrency:
group: ${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true
env:
BUILD_REPOSITORY_NAME: ${{ github.repository }}
BUILD_SOURCEBRANCHNAME: ${{ github.ref_name }}
BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/build
jobs:
Linux_Build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:1.0"
build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: clang
- os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:1.0"
build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: gcc
- os: ubuntu-24.04-arm
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.0"
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
compiler: clang
runs-on: ${{ matrix.os }}
env:
CCACHE_DIR: ${{ github.workspace }}/ccache
CI_HAS_ARTIFACTS: true
DEPLOY_APPIMAGE: true
APPDIR: "/rpcs3/build/appdir"
ARTDIR: "/root/artifacts"
RELEASE_MESSAGE: "/rpcs3/GitHubReleaseMessage.txt"
COMPILER: ${{ matrix.compiler }}
steps:
- name: Checkout repository
uses: actions/checkout@main
with:
fetch-depth: 0
- name: Setup Cache
uses: actions/cache@main
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ runner.os }}-ccache-${{ matrix.compiler }}
- name: Docker setup and build
run: |
docker pull --quiet ${{ matrix.docker_img }}
docker run \
-v $PWD:/rpcs3 \
--env-file .ci/docker.env \
-v ${{ env.CCACHE_DIR }}:/root/.ccache \
-v ${{ github.workspace }}/artifacts:/root/artifacts \
${{ matrix.docker_img }} \
${{ matrix.build_sh }}
- name: Upload artifacts
#TODO: Upload artifact to release repository
#condition for release
#if: |
# github.event_name != 'pull_request' &&
# github.repository == 'RPCS3/rpcs3' &&
# github.ref == 'refs/heads/master' &&
# matrix.compiler == 'clang'
uses: actions/upload-artifact@main
with:
name: RPCS3 for Linux (${{ runner.arch }}, ${{ matrix.compiler }})
path: ${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}/*.AppImage
compression-level: 0
Windows_Build:
runs-on: windows-2025
env:
COMPILER: msvc
QT_VER_MAIN: '6'
QT_VER: '6.8.1'
QT_VER_MSVC: 'msvc2022'
QT_DATE: '202411221531'
VULKAN_VER: '1.3.268.0'
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
CACHE_DIR: ./cache
steps:
- name: Checkout repository
uses: actions/checkout@main
with:
fetch-depth: 0
- name: Setup env
run: |
echo "QTDIR=C:\Qt\${{ env.QT_VER }}\${{ env.QT_VER_MSVC }}_64" >> ${{ github.env }}
echo "VULKAN_SDK=C:\VulkanSDK\${{ env.VULKAN_VER }}" >> ${{ github.env }}
- name: Get Cache Keys
shell: bash
run: .ci/get_keys-windows.sh
- name: Setup Cache
uses: actions/cache@main
with:
path: ${{ env.CACHE_DIR }}
key: "${{ runner.os }}-${{ env.COMPILER }}-${{ env.QT_VER }}-${{ env.VULKAN_SDK_SHA }}-${{ hashFiles('llvm.lock') }}-${{ hashFiles('glslang.lock') }}"
restore-keys: ${{ runner.os }}-${{ env.COMPILER }}
- name: Download and unpack dependencies
shell: bash
run: .ci/setup-windows.sh
- name: Export Variables
shell: bash
run: |
while IFS='=' read -r key val; do
# Skip lines that are empty or start with '#'
[[ -z "$key" || "$key" =~ ^# ]] && continue
echo "$key=$val" >> "${{ github.env }}"
done < .ci/ci-vars.env
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@main
- name: Compile RPCS3
run: msbuild rpcs3.sln /p:Configuration=Release /p:Platform=x64
- name: Pack up build artifacts
shell: bash
run: |
mkdir -p ${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}
.ci/deploy-windows.sh
- name: Upload artifacts (7z)
#TODO: Upload artifact to release repository
#condition for release
#if: |
# github.event_name != 'pull_request' &&
# github.repository == 'RPCS3/rpcs3' &&
# github.ref == 'refs/heads/master'
uses: actions/upload-artifact@main
with:
name: RPCS3 for Windows (MSVC)
# 7z
# 7z.sha256
path: |
${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}/${{ env.BUILD }}
${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}/${{ env.BUILD }}.sha256
compression-level: 0
if-no-files-found: error

4
.gitmodules vendored
View file

@ -28,10 +28,6 @@
path = 3rdparty/pugixml
url = ../../zeux/pugixml.git
ignore = dirty
[submodule "3rdparty/xxHash"]
path = 3rdparty/xxHash
url = ../../Cyan4973/xxHash.git
ignore = dirty
[submodule "3rdparty/yaml-cpp"]
path = 3rdparty/yaml-cpp/yaml-cpp
url = ../../RPCS3/yaml-cpp.git

View file

@ -97,19 +97,6 @@ target_link_libraries(3rdparty_glslang INTERFACE SPIRV)
add_subdirectory(yaml-cpp)
# xxHash
if (USE_SYSTEM_XXHASH)
pkg_check_modules(XXHASH REQUIRED IMPORTED_TARGET libxxhash)
add_library(xxhash INTERFACE)
target_link_libraries(xxhash INTERFACE PkgConfig::XXHASH)
else()
set(XXHASH_BUNDLED_MODE ON)
set(XXHASH_BUILD_XXHSUM OFF)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Make xxHash build static libs")
add_subdirectory(xxHash/cmake_unofficial EXCLUDE_FROM_ALL)
target_include_directories(xxhash INTERFACE xxHash)
endif()
# OpenGL
find_package(OpenGL REQUIRED OPTIONAL_COMPONENTS EGL)
@ -364,7 +351,6 @@ add_library(3rdparty::flatbuffers ALIAS 3rdparty_flatbuffers)
add_library(3rdparty::pugixml ALIAS pugixml)
add_library(3rdparty::glslang ALIAS 3rdparty_glslang)
add_library(3rdparty::yaml-cpp ALIAS yaml-cpp)
add_library(3rdparty::xxhash ALIAS xxhash)
add_library(3rdparty::hidapi ALIAS 3rdparty_hidapi)
add_library(3rdparty::libpng ALIAS ${LIBPNG_TARGET})
add_library(3rdparty::opengl ALIAS 3rdparty_opengl)

170
3rdparty/bcdec/bcdec.hpp vendored Normal file
View file

@ -0,0 +1,170 @@
// Based on https://github.com/iOrange/bcdec/blob/963c5e56b7a335e066cff7d16a3de75f4e8ad366/bcdec.h
// provides functions to decompress blocks of BC compressed images
//
// ------------------------------------------------------------------------------
//
// MIT LICENSE
// ===========
// Copyright (c) 2022 Sergii Kudlai
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// ------------------------------------------------------------------------------
#pragma once
#include <util/types.hpp>
static void bcdec__color_block(const u8* compressedBlock, u8* dstColors, int destinationPitch, bool onlyOpaqueMode) {
u16 c0, c1;
u32 refColors[4]; /* 0xAABBGGRR */
u32 colorIndices;
u32 r0, g0, b0, r1, g1, b1, r, g, b;
c0 = *reinterpret_cast<const u16*>(compressedBlock);
c1 = *(reinterpret_cast<const u16*>(compressedBlock) + 1);
/* Unpack 565 ref colors */
r0 = (c0 >> 11) & 0x1F;
g0 = (c0 >> 5) & 0x3F;
b0 = c0 & 0x1F;
r1 = (c1 >> 11) & 0x1F;
g1 = (c1 >> 5) & 0x3F;
b1 = c1 & 0x1F;
/* Expand 565 ref colors to 888 */
r = (r0 * 527 + 23) >> 6;
g = (g0 * 259 + 33) >> 6;
b = (b0 * 527 + 23) >> 6;
refColors[0] = 0xFF000000 | (r << 16) | (g << 8) | b;
r = (r1 * 527 + 23) >> 6;
g = (g1 * 259 + 33) >> 6;
b = (b1 * 527 + 23) >> 6;
refColors[1] = 0xFF000000 | (r << 16) | (g << 8) | b;
if (c0 > c1 || onlyOpaqueMode)
{ /* Standard BC1 mode (also BC3 color block uses ONLY this mode) */
/* color_2 = 2/3*color_0 + 1/3*color_1
color_3 = 1/3*color_0 + 2/3*color_1 */
r = ((2 * r0 + r1) * 351 + 61) >> 7;
g = ((2 * g0 + g1) * 2763 + 1039) >> 11;
b = ((2 * b0 + b1) * 351 + 61) >> 7;
refColors[2] = 0xFF000000 | (r << 16) | (g << 8) | b;
r = ((r0 + r1 * 2) * 351 + 61) >> 7;
g = ((g0 + g1 * 2) * 2763 + 1039) >> 11;
b = ((b0 + b1 * 2) * 351 + 61) >> 7;
refColors[3] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
else
{ /* Quite rare BC1A mode */
/* color_2 = 1/2*color_0 + 1/2*color_1;
color_3 = 0; */
r = ((r0 + r1) * 1053 + 125) >> 8;
g = ((g0 + g1) * 4145 + 1019) >> 11;
b = ((b0 + b1) * 1053 + 125) >> 8;
refColors[2] = 0xFF000000 | (r << 16) | (g << 8) | b;
refColors[3] = 0x00000000;
}
colorIndices = *reinterpret_cast<const u32*>(compressedBlock + 4);
/* Fill out the decompressed color block */
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
int idx = colorIndices & 0x03;
*reinterpret_cast<u32*>(dstColors + j * 4) = refColors[idx];
colorIndices >>= 2;
}
dstColors += destinationPitch;
}
}
static void bcdec__sharp_alpha_block(const u16* alpha, u8* decompressed, int destinationPitch) {
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
decompressed[j * 4] = ((alpha[i] >> (4 * j)) & 0x0F) * 17;
}
decompressed += destinationPitch;
}
}
static void bcdec__smooth_alpha_block(const u8* compressedBlock, u8* decompressed, int destinationPitch) {
u8 alpha[8];
u64 block = *reinterpret_cast<const u64*>(compressedBlock);
u64 indices;
alpha[0] = block & 0xFF;
alpha[1] = (block >> 8) & 0xFF;
if (alpha[0] > alpha[1])
{
/* 6 interpolated alpha values. */
alpha[2] = (6 * alpha[0] + alpha[1]) / 7; /* 6/7*alpha_0 + 1/7*alpha_1 */
alpha[3] = (5 * alpha[0] + 2 * alpha[1]) / 7; /* 5/7*alpha_0 + 2/7*alpha_1 */
alpha[4] = (4 * alpha[0] + 3 * alpha[1]) / 7; /* 4/7*alpha_0 + 3/7*alpha_1 */
alpha[5] = (3 * alpha[0] + 4 * alpha[1]) / 7; /* 3/7*alpha_0 + 4/7*alpha_1 */
alpha[6] = (2 * alpha[0] + 5 * alpha[1]) / 7; /* 2/7*alpha_0 + 5/7*alpha_1 */
alpha[7] = ( alpha[0] + 6 * alpha[1]) / 7; /* 1/7*alpha_0 + 6/7*alpha_1 */
}
else
{
/* 4 interpolated alpha values. */
alpha[2] = (4 * alpha[0] + alpha[1]) / 5; /* 4/5*alpha_0 + 1/5*alpha_1 */
alpha[3] = (3 * alpha[0] + 2 * alpha[1]) / 5; /* 3/5*alpha_0 + 2/5*alpha_1 */
alpha[4] = (2 * alpha[0] + 3 * alpha[1]) / 5; /* 2/5*alpha_0 + 3/5*alpha_1 */
alpha[5] = ( alpha[0] + 4 * alpha[1]) / 5; /* 1/5*alpha_0 + 4/5*alpha_1 */
alpha[6] = 0x00;
alpha[7] = 0xFF;
}
indices = block >> 16;
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
decompressed[j * 4] = alpha[indices & 0x07];
indices >>= 3;
}
decompressed += destinationPitch;
}
}
static inline void bcdec_bc1(const u8* compressedBlock, u8* decompressedBlock, int destinationPitch) {
bcdec__color_block(compressedBlock, decompressedBlock, destinationPitch, false);
}
static inline void bcdec_bc2(const u8* compressedBlock, u8* decompressedBlock, int destinationPitch) {
bcdec__color_block(compressedBlock + 8, decompressedBlock, destinationPitch, true);
bcdec__sharp_alpha_block(reinterpret_cast<const u16*>(compressedBlock), decompressedBlock + 3, destinationPitch);
}
static inline void bcdec_bc3(const u8* compressedBlock, u8* decompressedBlock, int destinationPitch) {
bcdec__color_block(compressedBlock + 8, decompressedBlock, destinationPitch, true);
bcdec__smooth_alpha_block(compressedBlock, decompressedBlock + 3, destinationPitch);
}

1
3rdparty/xxHash vendored

@ -1 +0,0 @@
Subproject commit e626a72bc2321cd320e953a0ccf1584cad60f363

View file

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{939FE206-1182-ABC3-1234-FEAB88E98404}</ProjectGuid>
</PropertyGroup>
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default_macros.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_default.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_debug.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_release.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="xxHash/xxhash.c" />
</ItemGroup>
<ItemGroup>
<Text Include="LICENSE" />
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="xxHash/xxhash.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -3,7 +3,7 @@
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IncludePath>.\;..\;..\3rdparty\asmjit\asmjit\src;..\..\3rdparty\yaml-cpp\yaml-cpp\include;..\3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\stb;..\3rdparty\openal\openal-soft\include\AL;..\3rdparty\pugixml\src;..\3rdparty\hidapi\hidapi;..\3rdparty\Optional;..\3rdparty\xxhash</IncludePath>
<IncludePath>.\;..\;..\3rdparty\asmjit\asmjit\src;..\..\3rdparty\yaml-cpp\yaml-cpp\include;..\3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\stb;..\3rdparty\openal\openal-soft\include\AL;..\3rdparty\pugixml\src;..\3rdparty\hidapi\hidapi</IncludePath>
<OutDir>$(SolutionDir)build\lib\$(Configuration)-$(Platform)\</OutDir>
<LibraryPath>$(SolutionDir)build\lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath)</LibraryPath>
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
@ -23,7 +23,7 @@
<AdditionalOptions>/utf-8 /Zc:throwingNew- /constexpr:steps16777216 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<AdditionalDependencies>xxhash.lib;ws2_32.lib;Iphlpapi.lib;Bcrypt.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;Iphlpapi.lib;Bcrypt.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>..\3rdparty\ffmpeg\lib\windows\x86_64</AdditionalLibraryDirectories>
<StackReserveSize>8388608</StackReserveSize>
<StackCommitSize>1048576</StackCommitSize>

View file

@ -10,7 +10,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emucore", "rpcs3\emucore.vc
{3C67A2FF-4710-402A-BE3E-31B0CB0576DF} = {3C67A2FF-4710-402A-BE3E-31B0CB0576DF}
{5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0} = {5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0}
{8846A9AA-5539-4C91-8301-F54260E1A07A} = {8846A9AA-5539-4C91-8301-F54260E1A07A}
{939FE206-1182-ABC3-1234-FEAB88E98404} = {939FE206-1182-ABC3-1234-FEAB88E98404}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llvm_build", "3rdparty\llvm\llvm_build.vcxproj", "{8BC303AB-25BE-4276-8E57-73F171B2D672}"
@ -67,8 +66,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxpro
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidapi", "3rdparty\hidapi\hidapi.vcxproj", "{A107C21C-418A-4697-BB10-20C3AA60E2E4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxhash", "3rdparty\xxhash.vcxproj", "{939FE206-1182-ABC3-1234-FEAB88E98404}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "3rdparty\libusb\libusb_static.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wolfssl", "3rdparty\wolfssl\wolfssl.vcxproj", "{73973223-5EE8-41CA-8E88-1D60E89A237B}"
@ -161,10 +158,6 @@ Global
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.Build.0 = Debug|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.ActiveCfg = Release|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.Build.0 = Release|x64
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug|x64.ActiveCfg = Debug|x64
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug|x64.Build.0 = Debug|x64
{939FE206-1182-ABC3-1234-FEAB88E98404}.Release|x64.ActiveCfg = Release|x64
{939FE206-1182-ABC3-1234-FEAB88E98404}.Release|x64.Build.0 = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64
@ -236,7 +229,6 @@ Global
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
{FDC361C5-7734-493B-8CFB-037308B35122} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{A107C21C-418A-4697-BB10-20C3AA60E2E4} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{939FE206-1182-ABC3-1234-FEAB88E98404} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{349EE8F9-7D25-4909-AAF5-FF3FADE72187} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{73973223-5EE8-41CA-8E88-1D60E89A237B} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}

View file

@ -641,7 +641,7 @@ target_link_libraries(rpcs3_emu
3rdparty::vulkan 3rdparty::glew
3rdparty::libusb 3rdparty::wolfssl
PRIVATE
3rdparty::glslang 3rdparty::xxhash
3rdparty::glslang
)
if(APPLE)

View file

@ -8,6 +8,7 @@
#include <Emu/Cell/lv2/sys_event.h>
#include <numeric>
#include <cmath>
#include "3rdparty/OpenAL/openal-soft/include/AL/alext.h"
@ -575,6 +576,28 @@ bool microphone_device::has_data() const
return mic_registered && mic_opened && mic_started && (rbuf_raw.has_data() || rbuf_dsp.has_data());
}
f32 microphone_device::calculate_energy_level()
{
const auto& buffer = device_type == microphone_handler::real_singstar ? ::at32(devices, 0).buf : temp_buf;
const size_t num_samples = buffer.size() / sizeof(s16);
f64 sum_squares = 0.0;
for (usz i = 0; i < num_samples; i++)
{
const be_t<s16> sample = read_from_ptr<be_t<s16>>(buffer, i * sizeof(s16));
const f64 normalized_sample = static_cast<f64>(sample) / -std::numeric_limits<s16>::min();
sum_squares += normalized_sample * normalized_sample;
}
const f32 rms = std::sqrt(sum_squares / num_samples);
const f32 decibels_max = 90.0f;
const f32 decibels_relative = 20.0f * std::log10(std::max(rms, 0.00001f));
const f32 decibels = decibels_max + (decibels_relative * 0.5f);
return std::clamp(decibels, 40.0f, decibels_max);
}
u32 microphone_device::capture_audio()
{
ensure(sample_size > 0);
@ -1089,7 +1112,7 @@ error_code cellMicGetSignalState(s32 dev_num, CellMicSignalState sig_state, vm::
*fval = 1.0f; // No gain applied
break;
case CELLMIC_SIGSTATE_MICENG:
*fval = 40.0f; // 40 decibels
*fval = device.calculate_energy_level();
break;
case CELLMIC_SIGSTATE_SPKENG:
*fval = 10.0f; // 10 decibels

View file

@ -289,6 +289,8 @@ public:
void update_audio();
bool has_data() const;
f32 calculate_energy_level();
bool is_registered() const { return mic_registered; }
bool is_opened() const { return mic_opened; }
bool is_started() const { return mic_started; }

View file

@ -854,6 +854,10 @@ namespace np
room_msg_cb_ctx = 0;
room_msg_cb_arg = {};
presence_self.pr_status = {};
presence_self.pr_data = {};
presence_self.advertised = false;
if (g_cfg.net.psn_status == np_psn_status::psn_rpcn)
{
rpcn_log.notice("Setting RPCN state to disconnected!");
@ -1157,21 +1161,23 @@ namespace np
auto notifications = rpcn->get_notifications();
for (auto& notif : notifications)
{
vec_stream noti_data(notif.second);
switch (notif.first)
{
case rpcn::NotificationType::UserJoinedRoom: notif_user_joined_room(notif.second); break;
case rpcn::NotificationType::UserLeftRoom: notif_user_left_room(notif.second); break;
case rpcn::NotificationType::RoomDestroyed: notif_room_destroyed(notif.second); break;
case rpcn::NotificationType::UpdatedRoomDataInternal: notif_updated_room_data_internal(notif.second); break;
case rpcn::NotificationType::UpdatedRoomMemberDataInternal: notif_updated_room_member_data_internal(notif.second); break;
case rpcn::NotificationType::RoomMessageReceived: notif_room_message_received(notif.second); break;
case rpcn::NotificationType::SignalingHelper: notif_signaling_helper(notif.second); break;
case rpcn::NotificationType::MemberJoinedRoomGUI: notif_member_joined_room_gui(notif.second); break;
case rpcn::NotificationType::MemberLeftRoomGUI: notif_member_left_room_gui(notif.second); break;
case rpcn::NotificationType::RoomDisappearedGUI: notif_room_disappeared_gui(notif.second); break;
case rpcn::NotificationType::RoomOwnerChangedGUI: notif_room_owner_changed_gui(notif.second); break;
case rpcn::NotificationType::UserKickedGUI: notif_user_kicked_gui(notif.second); break;
case rpcn::NotificationType::QuickMatchCompleteGUI: notif_quickmatch_complete_gui(notif.second); break;
case rpcn::NotificationType::UserJoinedRoom: notif_user_joined_room(noti_data); break;
case rpcn::NotificationType::UserLeftRoom: notif_user_left_room(noti_data); break;
case rpcn::NotificationType::RoomDestroyed: notif_room_destroyed(noti_data); break;
case rpcn::NotificationType::UpdatedRoomDataInternal: notif_updated_room_data_internal(noti_data); break;
case rpcn::NotificationType::UpdatedRoomMemberDataInternal: notif_updated_room_member_data_internal(noti_data); break;
case rpcn::NotificationType::RoomMessageReceived: notif_room_message_received(noti_data); break;
case rpcn::NotificationType::SignalingHelper: notif_signaling_helper(noti_data); break;
case rpcn::NotificationType::MemberJoinedRoomGUI: notif_member_joined_room_gui(noti_data); break;
case rpcn::NotificationType::MemberLeftRoomGUI: notif_member_left_room_gui(noti_data); break;
case rpcn::NotificationType::RoomDisappearedGUI: notif_room_disappeared_gui(noti_data); break;
case rpcn::NotificationType::RoomOwnerChangedGUI: notif_room_owner_changed_gui(noti_data); break;
case rpcn::NotificationType::UserKickedGUI: notif_user_kicked_gui(noti_data); break;
case rpcn::NotificationType::QuickMatchCompleteGUI: notif_quickmatch_complete_gui(noti_data); break;
default: fmt::throw_exception("Unknown notification(%d) received!", notif.first); break;
}
}
@ -1536,7 +1542,7 @@ namespace np
}
}
if (send_update && is_psn_active)
if (is_psn_active && (!presence_self.advertised || send_update))
{
std::lock_guard lock(mutex_rpcn);
@ -1545,6 +1551,7 @@ namespace np
return;
}
presence_self.advertised = true;
rpcn->send_presence(presence_self.pr_com_id, presence_self.pr_title, presence_self.pr_status, presence_self.pr_comment, presence_self.pr_data);
}
}

View file

@ -293,22 +293,22 @@ namespace np
bool error_and_disconnect(const std::string& error_msg);
// Notification handlers
void notif_user_joined_room(std::vector<u8>& data);
void notif_user_left_room(std::vector<u8>& data);
void notif_room_destroyed(std::vector<u8>& data);
void notif_updated_room_data_internal(std::vector<u8>& data);
void notif_updated_room_member_data_internal(std::vector<u8>& data);
void notif_signaling_helper(std::vector<u8>& data);
void notif_room_message_received(std::vector<u8>& data);
void notif_user_joined_room(vec_stream& noti);
void notif_user_left_room(vec_stream& noti);
void notif_room_destroyed(vec_stream& noti);
void notif_updated_room_data_internal(vec_stream& noti);
void notif_updated_room_member_data_internal(vec_stream& noti);
void notif_signaling_helper(vec_stream& noti);
void notif_room_message_received(vec_stream& noti);
void generic_gui_notification_handler(std::vector<u8>& data, std::string_view name, s32 notification_type);
void generic_gui_notification_handler(vec_stream& noti, std::string_view name, s32 notification_type);
void notif_member_joined_room_gui(std::vector<u8>& data);
void notif_member_left_room_gui(std::vector<u8>& data);
void notif_room_disappeared_gui(std::vector<u8>& data);
void notif_room_owner_changed_gui(std::vector<u8>& data);
void notif_user_kicked_gui(std::vector<u8>& data);
void notif_quickmatch_complete_gui(std::vector<u8>& data);
void notif_member_joined_room_gui(vec_stream& noti);
void notif_member_left_room_gui(vec_stream& noti);
void notif_room_disappeared_gui(vec_stream& noti);
void notif_room_owner_changed_gui(vec_stream& noti);
void notif_user_kicked_gui(vec_stream& noti);
void notif_quickmatch_complete_gui(vec_stream& noti);
// Reply handlers
void reply_get_world_list(u32 req_id, rpcn::ErrorType error, vec_stream& reply);
@ -509,6 +509,7 @@ namespace np
std::string pr_status;
std::string pr_comment;
std::vector<u8> pr_data;
atomic_t<bool> advertised = false;
} presence_self;
player_history& get_player_and_set_timestamp(const SceNpId& npid, u64 timestamp);

View file

@ -13,9 +13,8 @@ LOG_CHANNEL(rpcn_log, "rpcn");
namespace np
{
void np_handler::notif_user_joined_room(std::vector<u8>& data)
void np_handler::notif_user_joined_room(vec_stream& noti)
{
vec_stream noti(data);
const auto* notification = noti.get_flatbuffer<NotificationUserJoinedRoom>();
if (noti.is_error())
@ -72,9 +71,8 @@ namespace np
}
}
void np_handler::notif_user_left_room(std::vector<u8>& data)
void np_handler::notif_user_left_room(vec_stream& noti)
{
vec_stream noti(data);
u64 room_id = noti.get<u64>();
const auto* update_info = noti.get_flatbuffer<RoomMemberUpdateInfo>();
@ -112,9 +110,8 @@ namespace np
}
}
void np_handler::notif_room_destroyed(std::vector<u8>& data)
void np_handler::notif_room_destroyed(vec_stream& noti)
{
vec_stream noti(data);
u64 room_id = noti.get<u64>();
const auto* update_info = noti.get_flatbuffer<RoomUpdateInfo>();
@ -146,9 +143,8 @@ namespace np
}
}
void np_handler::notif_updated_room_data_internal(std::vector<u8>& data)
void np_handler::notif_updated_room_data_internal(vec_stream& noti)
{
vec_stream noti(data);
SceNpMatching2RoomId room_id = noti.get<u64>();
const auto* update_info = noti.get_flatbuffer<RoomDataInternalUpdateInfo>();
@ -182,9 +178,8 @@ namespace np
}
}
void np_handler::notif_updated_room_member_data_internal(std::vector<u8>& data)
void np_handler::notif_updated_room_member_data_internal(vec_stream& noti)
{
vec_stream noti(data);
SceNpMatching2RoomId room_id = noti.get<u64>();
const auto* update_info = noti.get_flatbuffer<RoomMemberDataInternalUpdateInfo>();
@ -221,9 +216,8 @@ namespace np
}
}
void np_handler::notif_room_message_received(std::vector<u8>& data)
void np_handler::notif_room_message_received(vec_stream& noti)
{
vec_stream noti(data);
u64 room_id = noti.get<u64>();
u16 member_id = noti.get<u16>();
const auto* message_info = noti.get_flatbuffer<RoomMessageInfo>();
@ -254,29 +248,28 @@ namespace np
}
}
void np_handler::notif_signaling_helper(std::vector<u8>& data)
void np_handler::notif_signaling_helper(vec_stream& noti)
{
vec_stream noti(data);
const u32 addr_p2p = noti.get<u32>();
const u32 port_p2p = noti.get<u16>();
const std::string str_npid = noti.get_string(false);
const auto* matching_info = noti.get_flatbuffer<MatchingSignalingInfo>();
if (noti.is_error())
if (noti.is_error() || !matching_info->addr() || !matching_info->npid() || !matching_info->addr()->ip())
{
rpcn_log.error("Received faulty SignalingHelper notification");
return;
}
SceNpId npid_p2p;
string_to_npid(str_npid, npid_p2p);
string_to_npid(matching_info->npid()->string_view(), npid_p2p);
const u32 addr_p2p = register_ip(matching_info->addr()->ip());
const u16 port_p2p = matching_info->addr()->port();
auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
sigh.send_information_packets(addr_p2p, port_p2p, npid_p2p);
}
void np_handler::generic_gui_notification_handler(std::vector<u8>& data, std::string_view name, s32 notification_type)
void np_handler::generic_gui_notification_handler(vec_stream& noti, std::string_view name, s32 notification_type)
{
vec_stream noti(data);
const auto* update_info = noti.get_flatbuffer<MatchingRoomStatus>();
if (noti.is_error())
@ -329,36 +322,35 @@ namespace np
ctx->queue_callback(req_id, notification_type, 0);
}
void np_handler::notif_member_joined_room_gui(std::vector<u8>& data)
void np_handler::notif_member_joined_room_gui(vec_stream& noti)
{
return generic_gui_notification_handler(data, "MemberJoinedRoomGUI", SCE_NP_MATCHING_EVENT_ROOM_UPDATE_NEW_MEMBER);
return generic_gui_notification_handler(noti, "MemberJoinedRoomGUI", SCE_NP_MATCHING_EVENT_ROOM_UPDATE_NEW_MEMBER);
}
void np_handler::notif_member_left_room_gui(std::vector<u8>& data)
void np_handler::notif_member_left_room_gui(vec_stream& noti)
{
return generic_gui_notification_handler(data, "MemberLeftRoomGUI", SCE_NP_MATCHING_EVENT_ROOM_UPDATE_MEMBER_LEAVE);
return generic_gui_notification_handler(noti, "MemberLeftRoomGUI", SCE_NP_MATCHING_EVENT_ROOM_UPDATE_MEMBER_LEAVE);
}
void np_handler::notif_room_disappeared_gui(std::vector<u8>& data)
void np_handler::notif_room_disappeared_gui(vec_stream& noti)
{
return generic_gui_notification_handler(data, "RoomDisappearedGUI", SCE_NP_MATCHING_EVENT_ROOM_DISAPPEARED);
return generic_gui_notification_handler(noti, "RoomDisappearedGUI", SCE_NP_MATCHING_EVENT_ROOM_DISAPPEARED);
}
void np_handler::notif_room_owner_changed_gui(std::vector<u8>& data)
void np_handler::notif_room_owner_changed_gui(vec_stream& noti)
{
return generic_gui_notification_handler(data, "RoomOwnerChangedGUI", SCE_NP_MATCHING_EVENT_ROOM_UPDATE_OWNER_CHANGE);
return generic_gui_notification_handler(noti, "RoomOwnerChangedGUI", SCE_NP_MATCHING_EVENT_ROOM_UPDATE_OWNER_CHANGE);
}
void np_handler::notif_user_kicked_gui(std::vector<u8>& data)
void np_handler::notif_user_kicked_gui(vec_stream& noti)
{
return generic_gui_notification_handler(data, "UserKickedGUI", SCE_NP_MATCHING_EVENT_ROOM_KICKED);
return generic_gui_notification_handler(noti, "UserKickedGUI", SCE_NP_MATCHING_EVENT_ROOM_KICKED);
}
void gui_epilog(const shared_ptr<matching_ctx>& ctx);
void np_handler::notif_quickmatch_complete_gui(std::vector<u8>& data)
void np_handler::notif_quickmatch_complete_gui(vec_stream& noti)
{
vec_stream noti(data);
const auto* update_info = noti.get_flatbuffer<MatchingRoomStatus>();
if (noti.is_error())

View file

@ -252,7 +252,7 @@ namespace np
case rpcn::ErrorType::RoomPasswordMismatch: error_code = SCE_NP_MATCHING2_SERVER_ERROR_PASSWORD_MISMATCH; break;
case rpcn::ErrorType::RoomGroupFull: error_code = SCE_NP_MATCHING2_SERVER_ERROR_GROUP_FULL; break;
case rpcn::ErrorType::RoomGroupJoinLabelNotFound: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_GROUP; break;
default: fmt::throw_exception("Unexpected error in reply to JoinRoom: %d", static_cast<u8>(error)); ;
default: fmt::throw_exception("Unexpected error in reply to JoinRoom: %d", static_cast<u8>(error));
}
if (error_code != 0)
@ -334,8 +334,9 @@ namespace np
switch (error)
{
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::NotFound: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; // Unsure if this should return another error(missing user in room has no appropriate error code)
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
default: fmt::throw_exception("Unexpected error in reply to LeaveRoom: %d", static_cast<u8>(error)); ;
default: fmt::throw_exception("Unexpected error in reply to LeaveRoom: %d", static_cast<u8>(error));
}
if (error_code != CELL_OK)
@ -549,7 +550,7 @@ namespace np
{
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
default: fmt::throw_exception("Unexpected error in reply to GetRoomDataInternal: %d", static_cast<u8>(error)); ;
default: fmt::throw_exception("Unexpected error in reply to GetRoomDataInternal: %d", static_cast<u8>(error));
}
cb_info_opt->queue_callback(req_id, 0, error_code, 0);
@ -583,7 +584,7 @@ namespace np
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
case rpcn::ErrorType::NotFound: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_USER; break;
default: fmt::throw_exception("Unexpected error in reply to GetRoomMemberDataInternal: %d", static_cast<u8>(error)); ;
default: fmt::throw_exception("Unexpected error in reply to GetRoomMemberDataInternal: %d", static_cast<u8>(error));
}
if (error_code != CELL_OK)
@ -1081,7 +1082,7 @@ namespace np
case rpcn::ErrorType::NotFound: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_STORE_NOT_FOUND); break;
case rpcn::ErrorType::ScoreInvalid: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_SCORE); break;
case rpcn::ErrorType::ScoreHasData: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_GAME_DATA_ALREADY_EXISTS); break;
default: fmt::throw_exception("Unexpected error in reply to RecordScoreData: %d", static_cast<u8>(error)); ;
default: fmt::throw_exception("Unexpected error in reply to RecordScoreData: %d", static_cast<u8>(error));
}
}
@ -1134,7 +1135,7 @@ namespace np
{
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::NotFound: score_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_GAME_DATA_MASTER_NOT_FOUND); return;
default: fmt::throw_exception("Unexpected error in reply to GetScoreData: %d", static_cast<u8>(error)); ;
default: fmt::throw_exception("Unexpected error in reply to GetScoreData: %d", static_cast<u8>(error));
}
auto* tdata = std::get_if<tdata_get_score_data>(&score_trans->tdata);

View file

@ -599,7 +599,11 @@ namespace rpcn
duration = std::min(duration, duration_ipv6);
}
sem_rpcn.try_acquire_for(duration);
// Expected to fail unless rpcn is terminated
// The check is there to nuke a msvc warning
if (!sem_rpcn.try_acquire_for(duration))
{
}
}
}
}

View file

@ -6,33 +6,33 @@
#include "Emu/RSX/RSXThread.h"
#include "Emu/Memory/vm.h"
#include "xxhash.h"
namespace rsx
{
namespace capture
{
void insert_mem_block_in_map(std::unordered_set<u64>& mem_changes, frame_capture_data::memory_block&& block, frame_capture_data::memory_block_data&& data)
void insert_mem_block_in_map(u64& indexer, std::unordered_set<u64>& mem_changes, frame_capture_data::memory_block&& block, frame_capture_data::memory_block_data&& data)
{
if (!data.data.empty())
{
u64 data_hash = XXH64(data.data.data(), data.data.size(), 0);
const auto [it, inserted] = frame_capture.memory_data_map.try_emplace(data, 0);
u64& data_hash = it->second;
if (inserted)
{
data_hash = ++indexer;
}
block.data_state = data_hash;
auto it = frame_capture.memory_data_map.find(data_hash);
if (it != frame_capture.memory_data_map.end())
{
if (it->second.data != data.data)
// screw this
fmt::throw_exception("Memory map hash collision detected...cant capture");
}
else
frame_capture.memory_data_map.insert(std::make_pair(data_hash, std::move(data)));
const auto [block_it, inserted_block] = frame_capture.memory_map.try_emplace(block, 0);
u64& block_hash = block_it->second;
if (inserted_block)
{
block_hash = ++indexer;
}
u64 block_hash = XXH64(&block, sizeof(frame_capture_data::memory_block), 0);
mem_changes.insert(block_hash);
if (frame_capture.memory_map.find(block_hash) == frame_capture.memory_map.end())
frame_capture.memory_map.insert(std::make_pair(block_hash, std::move(block)));
}
}
@ -48,6 +48,7 @@ namespace rsx
// shove the mem_changes onto the last issued command
std::unordered_set<u64>& mem_changes = frame_capture.replay_commands.back().memory_state;
u64& mem_indexer = frame_capture.memory_indexer;
// capture fragment shader mem
const auto [program_offset, program_location] = method_registers.shader_program_address();
@ -63,7 +64,7 @@ namespace rsx
frame_capture_data::memory_block_data block_data;
block_data.data.resize(ucode_size + program_start);
std::memcpy(block_data.data.data(), vm::base(addr), ucode_size + program_start);
insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data));
insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data));
// vertex shader is passed in registers, so it can be ignored
@ -90,7 +91,7 @@ namespace rsx
frame_capture_data::memory_block_data block_data;
block_data.data.resize(texSize);
std::memcpy(block_data.data.data(), vm::base(texaddr), texSize);
insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data));
insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data));
}
// save vertex texture mem
@ -116,7 +117,7 @@ namespace rsx
frame_capture_data::memory_block_data block_data;
block_data.data.resize(texSize);
std::memcpy(block_data.data.data(), vm::base(texaddr), texSize);
insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data));
insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data));
}
// save vertex buffer memory
@ -154,7 +155,7 @@ namespace rsx
frame_capture_data::memory_block_data block_data;
block_data.data.resize(bufferSize);
std::memcpy(block_data.data.data(), vm::base(addr + (range.first * vertStride)), bufferSize);
insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data));
insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data));
}
while (method_registers.current_draw_clause.next());
}
@ -193,7 +194,7 @@ namespace rsx
frame_capture_data::memory_block_data block_data;
block_data.data.resize(bufferSize);
std::memcpy(block_data.data.data(), vm::base(idxAddr), bufferSize);
insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data));
insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data));
switch (index_type)
{
@ -256,7 +257,7 @@ namespace rsx
frame_capture_data::memory_block_data block_data;
block_data.data.resize(bufferSize);
std::memcpy(block_data.data.data(), vm::base(addr + (min_index * vertStride)), bufferSize);
insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data));
insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data));
}
}
}
@ -308,7 +309,7 @@ namespace rsx
frame_capture_data::memory_block_data block_data;
block_data.data.resize(src_size);
std::memcpy(block_data.data.data(), pixels_src, src_size);
insert_mem_block_in_map(replay_command.memory_state, std::move(block), std::move(block_data));
insert_mem_block_in_map(frame_capture.memory_indexer, replay_command.memory_state, std::move(block), std::move(block_data));
capture_display_tile_state(rsx, replay_command);
}
@ -340,14 +341,17 @@ namespace rsx
src += in_pitch;
}
insert_mem_block_in_map(replay_command.memory_state, std::move(block), std::move(block_data));
insert_mem_block_in_map(frame_capture.memory_indexer, replay_command.memory_state, std::move(block), std::move(block_data));
capture_display_tile_state(rsx, replay_command);
}
void capture_display_tile_state(thread* rsx, frame_capture_data::replay_command& replay_command)
{
u64& mem_indexer = frame_capture.memory_indexer;
frame_capture_data::display_buffers_state dbstate;
dbstate.count = rsx->display_buffers_count;
// should this only happen on flip?
for (u32 i = 0; i < rsx->display_buffers_count; ++i)
{
@ -358,9 +362,13 @@ namespace rsx
dbstate.buffers[i].pitch = db.pitch;
}
const u64 dbnum = XXH64(&dbstate, sizeof(frame_capture_data::display_buffers_state), 0);
if (frame_capture.display_buffers_map.find(dbnum) == frame_capture.display_buffers_map.end())
frame_capture.display_buffers_map.insert(std::make_pair(dbnum, std::move(dbstate)));
const auto [db_it, db_inserted] = frame_capture.display_buffers_map.try_emplace(dbstate, 0);
u64& dbnum = db_it->second;
if (db_inserted)
{
dbnum = ++mem_indexer;
}
// todo: hook tile call sys_rsx call or something
frame_capture_data::tile_state tilestate;
@ -386,10 +394,13 @@ namespace rsx
zcstate.status1 = rsx->zculls[i].bound ? u32{zc.status1} : 0;
}
const u64 tsnum = XXH64(&tilestate, sizeof(frame_capture_data::tile_state), 0);
const auto [ts_it, ts_inserted] = frame_capture.tile_map.try_emplace(tilestate, 0);
u64& tsnum = ts_it->second;
if (frame_capture.tile_map.find(tsnum) == frame_capture.tile_map.end())
frame_capture.tile_map.insert(std::make_pair(tsnum, std::move(tilestate)));
if (ts_inserted)
{
tsnum = ++mem_indexer;
}
replay_command.display_buffer_state = dbnum;
replay_command.tile_state = tsnum;

View file

@ -106,26 +106,26 @@ namespace rsx
// apply memory needed for command
for (const auto& state : replay_cmd.memory_state)
{
auto it = frame->memory_map.find(state);
auto it = std::find_if(frame->memory_map.begin(), frame->memory_map.end(), FN(x.second == state));
if (it == frame->memory_map.end())
fmt::throw_exception("requested memory state for command not found in memory_map");
const auto& memblock = it->second;
auto it_data = frame->memory_data_map.find(it->second.data_state);
const auto& memblock = it->first;
auto it_data = std::find_if(frame->memory_data_map.begin(), frame->memory_data_map.end(), FN(x.second == memblock.data_state));
if (it_data == frame->memory_data_map.end())
fmt::throw_exception("requested memory data state for command not found in memory_data_map");
const auto& data_block = it_data->second;
const auto& data_block = it_data->first;
std::memcpy(vm::base(get_address(memblock.offset, memblock.location)), data_block.data.data(), data_block.data.size());
}
if (replay_cmd.display_buffer_state != 0 && replay_cmd.display_buffer_state != cs.display_buffer_hash)
{
auto it = frame->display_buffers_map.find(replay_cmd.display_buffer_state);
auto it = std::find_if(frame->display_buffers_map.begin(), frame->display_buffers_map.end(), FN(x.second == replay_cmd.display_buffer_state));
if (it == frame->display_buffers_map.end())
fmt::throw_exception("requested display buffer for command not found");
const auto& dbstate = it->second;
const auto& dbstate = it->first;
for (u32 i = 0; i < dbstate.count; ++i)
{
const auto& buf = dbstate.buffers[i];
@ -136,16 +136,17 @@ namespace rsx
sys_rsx_context_attribute(context_id, 0x104, i,
u64{dbstate.buffers[i].width} << 32 | dbstate.buffers[i].height, u64{dbstate.buffers[i].pitch} << 32 | dbstate.buffers[i].offset, 0);
}
cs.display_buffer_hash = replay_cmd.display_buffer_state;
}
if (replay_cmd.tile_state != 0 && replay_cmd.tile_state != cs.tile_hash)
{
auto it = frame->tile_map.find(replay_cmd.tile_state);
auto it = std::find_if(frame->tile_map.begin(), frame->tile_map.end(), FN(x.second == replay_cmd.tile_state));
if (it == frame->tile_map.end())
fmt::throw_exception("requested tile state command not found");
const auto& tstate = it->second;
const auto& tstate = it->first;
for (u32 i = 0; i < limits::tiles_count; ++i)
{
const auto& ti = tstate.tiles[i];

View file

@ -11,7 +11,7 @@ namespace rsx
enum : u32
{
c_fc_magic = "RRC"_u32,
c_fc_version = 0x5,
c_fc_version = 0x6,
};
struct frame_capture_data
@ -92,19 +92,60 @@ namespace rsx
u32 version = c_fc_version;
u32 LE_format = std::endian::little == std::endian::native;
// hashmap of holding various states for tile
std::unordered_map<u64, tile_state> tile_map;
// hashmap of various memory 'changes' that can be applied to ps3 memory
std::unordered_map<u64, memory_block> memory_map;
// hashmap of memory blocks that can be applied, this is split from above for size decrease
std::unordered_map<u64, memory_block_data> memory_data_map;
// display buffer state map
std::unordered_map<u64, display_buffers_state> display_buffers_map;
// actual command queue to hold everything above
struct bitwise_hasher
{
template <typename T>
usz operator()(const T& key) const noexcept
{
if constexpr (!!(requires (const T& a) { a.data[0]; }))
{
return std::hash<std::string_view>{}(std::string_view{ reinterpret_cast<const char*>(key.data.data()), key.data.size() * sizeof(key.data[0]) });
}
return std::hash<std::string_view>{}(std::string_view{ reinterpret_cast<const char*>(&key), sizeof(key) });
}
template <typename T>
bool operator()(const T& keya, const T& keyb) const noexcept
{
if constexpr (!!(requires (const T& a) { a.data[0]; }))
{
if (keya.data.size() != keyb.data.size())
{
return false;
}
return std::equal(keya.data.begin(), keya.data.end(), keyb.data.begin());
}
return std::equal(reinterpret_cast<const char*>(&keya), reinterpret_cast<const char*>(&keya) + sizeof(T), reinterpret_cast<const char*>(&keyb));
}
};
template <typename T, typename V>
using uno_bit_map = std::unordered_map<T, V, bitwise_hasher, bitwise_hasher>;
// Hashmap of holding various states for tile
uno_bit_map<tile_state, u64> tile_map;
// Hashmap of various memory 'changes' that can be applied to ps3 memory
uno_bit_map<memory_block, u64> memory_map;
// Hashmap of memory blocks that can be applied, this is split from above for size decrease
uno_bit_map<memory_block_data, u64> memory_data_map;
// Display buffer state map
uno_bit_map<display_buffers_state, u64> display_buffers_map;
// Actual command queue to hold everything above
std::vector<replay_command> replay_commands;
// Initial registers state at the beginning of the capture
rsx::rsx_state reg_state;
// Indexer for memory blocks
u64 memory_indexer = 0x1234;
void reset()
{
magic = c_fc_magic;

View file

@ -3,6 +3,7 @@
#include "TextureUtils.h"
#include "../RSXThread.h"
#include "../rsx_utils.h"
#include "3rdparty/bcdec/bcdec.hpp"
#include "util/asm.hpp"
@ -497,6 +498,63 @@ struct copy_rgb655_block_swizzled
}
};
struct copy_decoded_bc1_block
{
static void copy_mipmap_level(std::span<u32> dst, std::span<const u64> src, u16 width_in_block, u16 row_count, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block)
{
u32 src_offset = 0, dst_offset = 0, destinationPitch = dst_pitch_in_block * 4;
for (u32 row = 0; row < row_count * depth; row++)
{
for (u32 col = 0; col < width_in_block; col++) {
const u8* compressedBlock = reinterpret_cast<const u8*>(&src[src_offset + col]);
u8* decompressedBlock = reinterpret_cast<u8*>(&dst[dst_offset + col * 4]);
bcdec_bc1(compressedBlock, decompressedBlock, destinationPitch);
}
src_offset += src_pitch_in_block;
dst_offset += destinationPitch;
}
}
};
struct copy_decoded_bc2_block
{
static void copy_mipmap_level(std::span<u32> dst, std::span<const u128> src, u16 width_in_block, u16 row_count, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block)
{
u32 src_offset = 0, dst_offset = 0, destinationPitch = dst_pitch_in_block * 4;
for (u32 row = 0; row < row_count * depth; row++)
{
for (u32 col = 0; col < width_in_block; col++) {
const u8* compressedBlock = reinterpret_cast<const u8*>(&src[src_offset + col]);
u8* decompressedBlock = reinterpret_cast<u8*>(&dst[dst_offset + col * 4]);
bcdec_bc2(compressedBlock, decompressedBlock, destinationPitch);
}
src_offset += src_pitch_in_block;
dst_offset += destinationPitch;
}
}
};
struct copy_decoded_bc3_block
{
static void copy_mipmap_level(std::span<u32> dst, std::span<const u128> src, u16 width_in_block, u16 row_count, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block)
{
u32 src_offset = 0, dst_offset = 0, destinationPitch = dst_pitch_in_block * 4;
for (u32 row = 0; row < row_count * depth; row++)
{
for (u32 col = 0; col < width_in_block; col++) {
const u8* compressedBlock = reinterpret_cast<const u8*>(&src[src_offset + col]);
u8* decompressedBlock = reinterpret_cast<u8*>(&dst[dst_offset + col * 4]);
bcdec_bc3(compressedBlock, decompressedBlock, destinationPitch);
}
src_offset += src_pitch_in_block;
dst_offset += destinationPitch;
}
}
};
namespace
{
/**
@ -952,6 +1010,12 @@ namespace rsx
case CELL_GCM_TEXTURE_COMPRESSED_DXT1:
{
if (!caps.supports_dxt)
{
copy_decoded_bc1_block::copy_mipmap_level(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u64>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
break;
}
const bool is_3d = depth > 1;
const bool is_po2 = utils::is_power_of_2(src_layout.width_in_texel) && utils::is_power_of_2(src_layout.height_in_texel);
@ -981,8 +1045,22 @@ namespace rsx
}
case CELL_GCM_TEXTURE_COMPRESSED_DXT23:
{
if (!caps.supports_dxt)
{
copy_decoded_bc2_block::copy_mipmap_level(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u128>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
break;
}
[[fallthrough]];
}
case CELL_GCM_TEXTURE_COMPRESSED_DXT45:
{
if (!caps.supports_dxt)
{
copy_decoded_bc3_block::copy_mipmap_level(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u128>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
break;
}
const bool is_3d = depth > 1;
const bool is_po2 = utils::is_power_of_2(src_layout.width_in_texel) && utils::is_power_of_2(src_layout.height_in_texel);
@ -1094,7 +1172,7 @@ namespace rsx
return result;
}
bool is_compressed_host_format(u32 texture_format)
bool is_compressed_host_format(const texture_uploader_capabilities& caps, u32 texture_format)
{
switch (texture_format)
{
@ -1129,7 +1207,7 @@ namespace rsx
case CELL_GCM_TEXTURE_COMPRESSED_DXT1:
case CELL_GCM_TEXTURE_COMPRESSED_DXT23:
case CELL_GCM_TEXTURE_COMPRESSED_DXT45:
return true;
return caps.supports_dxt;
}
fmt::throw_exception("Unknown format 0x%x", texture_format);
}

View file

@ -227,6 +227,7 @@ namespace rsx
bool supports_vtc_decoding;
bool supports_hw_deswizzle;
bool supports_zero_copy;
bool supports_dxt;
usz alignment;
};
@ -252,7 +253,7 @@ namespace rsx
u8 get_format_block_size_in_bytes(rsx::surface_color_format format);
u8 get_format_block_size_in_bytes(rsx::surface_depth_format2 format);
bool is_compressed_host_format(u32 format); // Returns true for host-compressed formats (DXT)
bool is_compressed_host_format(const texture_uploader_capabilities& caps, u32 format); // Returns true for host-compressed formats (DXT)
u8 get_format_sample_count(rsx::surface_antialiasing antialias);
u32 get_max_depth_value(rsx::surface_depth_format2 format);
bool is_depth_stencil_format(rsx::surface_depth_format2 format);

View file

@ -70,6 +70,7 @@ namespace gl
GLenum get_sized_internal_format(u32 texture_format)
{
const bool supports_dxt = get_driver_caps().EXT_texture_compression_s3tc_supported;
switch (texture_format)
{
case CELL_GCM_TEXTURE_B8: return GL_R8;
@ -92,9 +93,9 @@ namespace gl
case CELL_GCM_TEXTURE_D1R5G5B5: return GL_BGR5_A1;
case CELL_GCM_TEXTURE_D8R8G8B8: return GL_BGRA8;
case CELL_GCM_TEXTURE_Y16_X16_FLOAT: return GL_RG16F;
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : GL_BGRA8;
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT3_EXT : GL_BGRA8;
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : GL_BGRA8;
case CELL_GCM_TEXTURE_COMPRESSED_HILO8: return GL_RG8;
case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: return GL_RG8_SNORM;
case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: return GL_BGRA8;
@ -105,6 +106,7 @@ namespace gl
std::tuple<GLenum, GLenum> get_format_type(u32 texture_format)
{
const bool supports_dxt = get_driver_caps().EXT_texture_compression_s3tc_supported;
switch (texture_format)
{
case CELL_GCM_TEXTURE_B8: return std::make_tuple(GL_RED, GL_UNSIGNED_BYTE);
@ -127,9 +129,9 @@ namespace gl
case CELL_GCM_TEXTURE_D1R5G5B5: return std::make_tuple(GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV);
case CELL_GCM_TEXTURE_D8R8G8B8: return std::make_tuple(GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV);
case CELL_GCM_TEXTURE_Y16_X16_FLOAT: return std::make_tuple(GL_RG, GL_HALF_FLOAT);
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return std::make_tuple(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return std::make_tuple(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return std::make_tuple(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return std::make_tuple(supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : GL_BGRA, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return std::make_tuple(supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT3_EXT : GL_BGRA, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return std::make_tuple(supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : GL_BGRA, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_HILO8: return std::make_tuple(GL_RG, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: return std::make_tuple(GL_RG, GL_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: return std::make_tuple(GL_BGRA, GL_UNSIGNED_BYTE);
@ -587,6 +589,7 @@ namespace gl
.supports_vtc_decoding = false,
.supports_hw_deswizzle = driver_caps.ARB_compute_shader_supported,
.supports_zero_copy = false,
.supports_dxt = driver_caps.EXT_texture_compression_s3tc_supported,
.alignment = 4
};
@ -596,7 +599,7 @@ namespace gl
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, GL_NONE);
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);
if (rsx::is_compressed_host_format(format)) [[likely]]
if (rsx::is_compressed_host_format(caps, format)) [[likely]]
{
caps.supports_vtc_decoding = driver_caps.vendor_NVIDIA;
unpack_settings.apply();
@ -687,13 +690,13 @@ namespace gl
if (driver_caps.ARB_compute_shader_supported)
{
u64 row_pitch = rsx::align2<u64, u64>(layout.width_in_block * block_size_in_bytes, caps.alignment);
if (!rsx::is_compressed_host_format(format))
{
// Handle emulated compressed formats with host unpack (R8G8 compressed)
row_pitch = std::max<u64>(row_pitch, dst->pitch());
}
image_linear_size = row_pitch * layout.height_in_block * layout.depth;
// We're in the "else" branch, so "is_compressed_host_format()" is always false.
// Handle emulated compressed formats with host unpack (R8G8 compressed)
row_pitch = std::max<u64>(row_pitch, dst->pitch());
// FIXME: Double-check this logic; it seems like we should always use texels both here and for row_pitch.
image_linear_size = row_pitch * layout.height_in_texel * layout.depth;
compute_scratch_mem = { nullptr, g_compute_decode_buffer.alloc(static_cast<u32>(image_linear_size), 256) };
compute_scratch_mem.first = reinterpret_cast<void*>(static_cast<uintptr_t>(compute_scratch_mem.second));
@ -815,7 +818,8 @@ namespace gl
// Calculate staging buffer size
rsx::simple_array<std::byte> data_upload_buf;
if (rsx::is_compressed_host_format(gcm_format))
rsx::texture_uploader_capabilities caps { .supports_dxt = gl::get_driver_caps().EXT_texture_compression_s3tc_supported };
if (rsx::is_compressed_host_format(caps, gcm_format))
{
const auto& desc = subresources_layout[0];
const u32 texture_data_sz = desc.width_in_block * desc.height_in_block * desc.depth * rsx::get_format_block_size_in_bytes(gcm_format);

View file

@ -33,7 +33,7 @@ namespace gl
void capabilities::initialize()
{
int find_count = 18;
int find_count = 19;
int ext_count = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &ext_count);
@ -178,6 +178,13 @@ namespace gl
find_count--;
continue;
}
if (check(ext_name, "GL_EXT_texture_compression_s3tc"))
{
EXT_texture_compression_s3tc_supported = true;
find_count--;
continue;
}
}
// Set GLSL version

View file

@ -41,6 +41,7 @@ namespace gl
bool NV_depth_buffer_float_supported = false;
bool NV_fragment_shader_barycentric_supported = false;
bool ARB_shader_texture_image_samples = false;
bool EXT_texture_compression_s3tc_supported = false;
bool vendor_INTEL = false; // has broken GLSL compiler
bool vendor_AMD = false; // has broken ARB_multidraw

View file

@ -80,6 +80,7 @@ namespace vk
case vk::driver_vendor::LAVAPIPE:
case vk::driver_vendor::V3DV:
case vk::driver_vendor::PANVK:
case vk::driver_vendor::ARM_MALI:
// TODO: Actually bench this. Using 32 for now to match other common configurations.
case vk::driver_vendor::DOZEN:
// Actual optimal size depends on the D3D device. Use 32 since it should work well on both AMD and NVIDIA

View file

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "VKFormats.h"
#include "VKHelpers.h"
#include "vkutils/device.h"
#include "vkutils/image.h"
@ -193,6 +194,7 @@ namespace vk
VkFormat get_compatible_sampler_format(const gpu_formats_support& support, u32 format)
{
const bool supports_dxt = vk::get_current_renderer()->get_texture_compression_bc_support();
switch (format)
{
#ifndef __APPLE__
@ -213,9 +215,9 @@ namespace vk
#endif
case CELL_GCM_TEXTURE_B8: return VK_FORMAT_R8_UNORM;
case CELL_GCM_TEXTURE_A8R8G8B8: return VK_FORMAT_B8G8R8A8_UNORM;
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return VK_FORMAT_BC2_UNORM_BLOCK;
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return VK_FORMAT_BC3_UNORM_BLOCK;
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return supports_dxt ? VK_FORMAT_BC1_RGBA_UNORM_BLOCK : VK_FORMAT_B8G8R8A8_UNORM;
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return supports_dxt ? VK_FORMAT_BC2_UNORM_BLOCK : VK_FORMAT_B8G8R8A8_UNORM;
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return supports_dxt ? VK_FORMAT_BC3_UNORM_BLOCK : VK_FORMAT_B8G8R8A8_UNORM;
case CELL_GCM_TEXTURE_G8B8: return VK_FORMAT_R8G8_UNORM;
case CELL_GCM_TEXTURE_DEPTH24_D8: return support.d24_unorm_s8? VK_FORMAT_D24_UNORM_S8_UINT : VK_FORMAT_D32_SFLOAT_S8_UINT;
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: return VK_FORMAT_D32_SFLOAT_S8_UINT;

View file

@ -145,6 +145,9 @@ namespace vk
case driver_vendor::PANVK:
// Needs more testing
break;
case driver_vendor::ARM_MALI:
// Needs more testing
break;
default:
rsx_log.warning("Unsupported device: %s", gpu_name);
}

View file

@ -188,6 +188,7 @@ namespace vk
case driver_vendor::V3DV:
case driver_vendor::HONEYKRISP:
case driver_vendor::PANVK:
case driver_vendor::ARM_MALI:
break;
}

View file

@ -929,7 +929,7 @@ namespace vk
return *pcmd;
}
static const std::pair<u32, u32> calculate_upload_pitch(int format, u32 heap_align, vk::image* dst_image, const rsx::subresource_layout& layout)
static const std::pair<u32, u32> calculate_upload_pitch(int format, u32 heap_align, vk::image* dst_image, const rsx::subresource_layout& layout, const rsx::texture_uploader_capabilities& caps)
{
u32 block_in_pixel = rsx::get_format_block_size_in_texel(format);
u8 block_size_in_bytes = rsx::get_format_block_size_in_bytes(format);
@ -950,7 +950,7 @@ namespace vk
// We have row_pitch in source coordinates. But some formats have a software decode step which can affect this packing!
// For such formats, the packed pitch on src does not match packed pitch on dst
if (!rsx::is_compressed_host_format(format))
if (!rsx::is_compressed_host_format(caps, format))
{
const auto host_texel_width = vk::get_format_texel_width(dst_image->format());
const auto host_packed_pitch = host_texel_width * layout.width_in_texel;
@ -977,7 +977,8 @@ namespace vk
VkImageAspectFlags flags, vk::data_heap &upload_heap, u32 heap_align, rsx::flags32_t image_setup_flags)
{
const bool requires_depth_processing = (dst_image->aspect() & VK_IMAGE_ASPECT_STENCIL_BIT) || (format == CELL_GCM_TEXTURE_DEPTH16_FLOAT);
rsx::texture_uploader_capabilities caps{ .alignment = heap_align };
auto pdev = vk::get_current_renderer();
rsx::texture_uploader_capabilities caps{ .supports_dxt = pdev->get_texture_compression_bc_support(), .alignment = heap_align };
rsx::texture_memory_info opt{};
bool check_caps = true;
@ -997,11 +998,11 @@ namespace vk
for (const rsx::subresource_layout &layout : subresource_layout)
{
const auto [row_pitch, upload_pitch_in_texel] = calculate_upload_pitch(format, heap_align, dst_image, layout);
const auto [row_pitch, upload_pitch_in_texel] = calculate_upload_pitch(format, heap_align, dst_image, layout, caps);
caps.alignment = row_pitch;
// Calculate estimated memory utilization for this subresource
image_linear_size = row_pitch * layout.height_in_block * layout.depth;
image_linear_size = row_pitch * layout.depth * (rsx::is_compressed_host_format(caps, format) ? layout.height_in_block : layout.height_in_texel);
// Only do GPU-side conversion if occupancy is good
if (check_caps)

View file

@ -55,7 +55,8 @@ namespace vk
NVK,
V3DV,
HONEYKRISP,
PANVK
PANVK,
ARM_MALI
};
driver_vendor get_driver_vendor();

View file

@ -134,6 +134,10 @@ namespace vk
// So far only AMD is known to remap image view and border color together. Mark as not required.
custom_border_color_support.require_border_color_remap = get_driver_vendor() != driver_vendor::AMD;
}
// v3dv and PanVK support BC1-BC3 which is all we require, support is reported as false since not all formats are supported
optional_features_support.texture_compression_bc = features.textureCompressionBC
|| get_driver_vendor() == driver_vendor::V3DV || get_driver_vendor() == driver_vendor::PANVK;
}
void physical_device::get_physical_device_properties(bool allow_extensions)
@ -303,9 +307,13 @@ namespace vk
}
if (gpu_name.find("Panfrost") != umax)
{
{ // e.g. "Mali-G610 (Panfrost)"
return driver_vendor::PANVK;
}
else if (gpu_name.find("Mali") != umax)
{ // e.g. "Mali-G610", hence "else"
return driver_vendor::ARM_MALI;
}
return driver_vendor::unknown;
}
@ -336,6 +344,8 @@ namespace vk
return driver_vendor::HONEYKRISP;
case VK_DRIVER_ID_MESA_PANVK:
return driver_vendor::PANVK;
case VK_DRIVER_ID_ARM_PROPRIETARY:
return driver_vendor::ARM_MALI;
default:
// Mobile?
return driver_vendor::unknown;
@ -471,8 +481,7 @@ namespace vk
// Enable hardware features manually
// Currently we require:
// 1. Anisotropic sampling
// 2. DXT support
// 3. Indexable storage buffers
// 2. Indexable storage buffers
VkPhysicalDeviceFeatures enabled_features{};
if (pgpu->shader_types_support.allow_float16)
{
@ -566,7 +575,7 @@ namespace vk
// enabled_features.shaderCullDistance = VK_TRUE; // Alt notation of clip distance
enabled_features.samplerAnisotropy = VK_TRUE;
enabled_features.textureCompressionBC = VK_TRUE;
enabled_features.textureCompressionBC = pgpu->optional_features_support.texture_compression_bc;
enabled_features.shaderStorageBufferArrayDynamicIndexing = VK_TRUE;
// Optionally disable unsupported stuff
@ -659,19 +668,6 @@ namespace vk
enabled_features.logicOp = VK_FALSE;
}
if (!pgpu->features.textureCompressionBC && pgpu->get_driver_vendor() == driver_vendor::V3DV)
{
// v3dv supports BC1-BC3 which is all we require, support is reported as false since not all formats are supported
rsx_log.error("Your GPU running on the V3DV driver does not support full texture block compression. Graphics may not render correctly.");
enabled_features.textureCompressionBC = VK_FALSE;
}
if (!pgpu->features.textureCompressionBC && pgpu->get_driver_vendor() == driver_vendor::PANVK)
{
rsx_log.error("Your GPU running on the PANVK driver does not support full texture block compression. Graphics may not render correctly.");
enabled_features.textureCompressionBC = VK_FALSE;
}
VkDeviceCreateInfo device = {};
device.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device.pNext = nullptr;

View file

@ -92,6 +92,7 @@ namespace vk
bool synchronization_2 = false;
bool unrestricted_depth_range = false;
bool extended_device_fault = false;
bool texture_compression_bc = false;
} optional_features_support;
friend class render_device;
@ -190,6 +191,7 @@ namespace vk
bool get_barycoords_support() const { return pgpu->optional_features_support.barycentric_coords; }
bool get_synchronization2_support() const { return pgpu->optional_features_support.synchronization_2; }
bool get_extended_device_fault_support() const { return pgpu->optional_features_support.extended_device_fault; }
bool get_texture_compression_bc_support() const { return pgpu->optional_features_support.texture_compression_bc; }
u64 get_descriptor_update_after_bind_support() const { return pgpu->descriptor_indexing_support.update_after_bind_mask; }
u32 get_descriptor_max_draw_calls() const { return pgpu->descriptor_max_draw_calls; }

View file

@ -6,7 +6,7 @@
namespace utils
{
template <typename T>
concept FastRandomAccess = requires (T& obj)
concept FastRandomAccess = requires (const T& obj)
{
std::data(obj)[std::size(obj)];
};
@ -24,13 +24,13 @@ namespace utils
};
template <typename T>
concept TupleAlike = requires ()
concept TupleAlike = (!FastRandomAccess<T>) && requires ()
{
std::tuple_size<std::remove_cv_t<T>>::value;
std::tuple_size<std::remove_cvref_t<T>>::value;
};
template <typename T>
concept ListAlike = requires (T& obj) { obj.insert(obj.end(), std::declval<typename T::value_type>()); };
concept ListAlike = requires (std::remove_cvref_t<T>& obj) { obj.insert(obj.end(), std::declval<typename T::value_type>()); };
struct serial;
@ -249,6 +249,15 @@ public:
return raw_serialize(std::addressof(obj), sizeof(obj));
}
template <typename T>
static constexpr usz c_tup_size = std::tuple_size_v<std::conditional_t<TupleAlike<T>, std::remove_cvref_t<T>, std::tuple<>>>;
template <typename T>
static std::remove_cvref_t<T>& as_nonconst(T&& arg) noexcept
{
return const_cast<std::remove_cvref_t<T>&>(static_cast<const T&>(arg));
}
// std::vector, std::basic_string
// Discourage using std::pair/tuple with vectors because it eliminates the possibility of bitwise optimization
template <typename T> requires FastRandomAccess<T> && ListAlike<T> && (!TupleAlike<typename T::value_type>)
@ -327,9 +336,24 @@ public:
{
for (auto&& value : obj)
{
if (!serialize(value))
if constexpr (c_tup_size<decltype(*std::data(obj))> == 2)
{
return false;
if (!serialize(as_nonconst(std::get<0>(value))))
{
return false;
}
if (!serialize(as_nonconst(std::get<1>(value))))
{
return false;
}
}
else
{
if (!serialize(value))
{
return false;
}
}
}
@ -347,9 +371,24 @@ public:
for (auto&& value : obj)
{
if (!serialize(value))
if constexpr (c_tup_size<decltype(value)> == 2)
{
return false;
if (!serialize(as_nonconst(std::get<0>(value))))
{
return false;
}
if (!serialize(as_nonconst(std::get<1>(value))))
{
return false;
}
}
else
{
if (!serialize(value))
{
return false;
}
}
}
@ -412,7 +451,7 @@ public:
}
// std::pair, std::tuple
template <typename T> requires TupleAlike<T> && (!FastRandomAccess<T>)
template <typename T> requires TupleAlike<T>
bool serialize(T& obj)
{
return serialize_tuple(obj);
@ -423,7 +462,7 @@ public:
bool operator()(Args&&... args) noexcept
{
return ((AUDIT(!std::is_const_v<std::remove_reference_t<Args>> || is_writing())
, serialize(const_cast<std::remove_cvref_t<Args>&>(static_cast<const Args&>(args)))), ...);
, serialize(as_nonconst(args))), ...);
}
// Code style utility, for when utils::serial is a pointer for example
@ -519,30 +558,48 @@ public:
AUDIT(!is_writing());
using type = std::remove_const_t<T>;
using not_tuple_t = std::conditional_t<TupleAlike<T>, char, type>;
if constexpr (Bitcopy<T>)
{
u8 buf[sizeof(type)]{};
u8 buf[sizeof(not_tuple_t)]{};
ensure(raw_serialize(buf, sizeof(buf)));
return std::bit_cast<type>(buf);
}
else if constexpr (std::is_constructible_v<type, stx::exact_t<serial&>>)
{
return type(stx::exact_t<serial&>(*this));
}
else if constexpr (std::is_constructible_v<type>)
{
type value{};
ensure(serialize(value));
return value;
return std::bit_cast<not_tuple_t>(buf);
}
else if constexpr (TupleAlike<T>)
{
static_assert(std::tuple_size_v<type> == 2, "Unimplemented tuple serialization!");
constexpr usz tup_size = c_tup_size<type>;
auto first = operator std::remove_cvref_t<decltype(std::get<0>(std::declval<type&>()))>();
return type{ std::move(first)
, operator std::remove_cvref_t<decltype(std::get<1>(std::declval<type&>()))> };
static_assert(tup_size == 2 || tup_size == 4, "Unimplemented tuple serialization!");
using first_t = std::remove_cvref_t<decltype(std::get<std::min<usz>(0, tup_size - 1)>(std::declval<type&>()))>;
using second_t = std::remove_cvref_t<decltype(std::get<std::min<usz>(1, tup_size - 1)>(std::declval<type&>()))>;
using third_t = std::remove_cvref_t<decltype(std::get<std::min<usz>(2, tup_size - 1)>(std::declval<type&>()))>;
using fourth_t = std::remove_cvref_t<decltype(std::get<std::min<usz>(3, tup_size - 1)>(std::declval<type&>()))>;
first_t first = this->operator first_t();
if constexpr (tup_size == 4)
{
second_t second = this->operator second_t();
third_t third = this->operator third_t();
return type{ std::move(first), std::move(second), std::move(third), this->operator fourth_t() };
}
else
{
return type{ std::move(first), this->operator second_t() };
}
}
else if constexpr (std::is_constructible_v<type, stx::exact_t<serial&>>)
{
return not_tuple_t(stx::exact_t<serial&>(*this));
}
else if constexpr (std::is_constructible_v<type>)
{
not_tuple_t value{};
ensure(serialize(value));
return value;
}
}